⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 devpcmcia.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "../port/error.h"#include "io.h"/* * BUG: insertion events are detected by polling. *      Should look into the compaq docs to see if *      there's an interrupt for card insertion *      there's probably one. */static PCMslot	slot[2];int nslot = 2;struct {	Ref;	Rendez	event;		// where to wait for card events	int	evreader;	// there's a reader for events} pcmcia;enum{	Qdir,	Qmem,	Qattr,	Qctl,	Qevs,	Nents = 3,};enum{	/*	 *  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 */};static void increfp(PCMslot*);static void decrefp(PCMslot*);static void slotmap(int, ulong, ulong, ulong);static void slottiming(int, int, int, int, int);static void slotinfo(Ureg*, void*);#define TYPE(c)		(((ulong)c->qid.path)&0xff)#define PATH(s,t)	(((s)<<8)|(t))static PCMslot*slotof(Chan *c){	ulong x;	x = c->qid.path;	return slot + ((x>>8)&0xff);}static intpcmgen(Chan *c, char *, Dirtab * , int, int i, Dir *dp){	int slotno;	Qid qid;	long len;	PCMslot *sp;	if(i == DEVDOTDOT){		mkqid(&qid, Qdir, 0, QTDIR);		devdir(c, qid, "#y", 0, eve, 0555, dp);		return 1;	}	if(i >= Nents*nslot + 1)		return -1;	if(i == Nents*nslot){		len = 0;		qid.path = PATH(0, Qevs);		snprint(up->genbuf, sizeof up->genbuf, "pcmevs");		goto found;	}	slotno = i/Nents;	sp = slot + slotno;	len = 0;	switch(i%Nents){	case 0:		qid.path = PATH(slotno, Qmem);		snprint(up->genbuf, sizeof up->genbuf, "pcm%dmem", slotno);		len = sp->memlen;		break;	case 1:		qid.path = PATH(slotno, Qattr);		snprint(up->genbuf, sizeof up->genbuf, "pcm%dattr", slotno);		len = sp->memlen;		break;	case 2:		qid.path = PATH(slotno, Qctl);		snprint(up->genbuf, sizeof up->genbuf, "pcm%dctl", slotno);		break;	}found:	qid.vers = 0;	qid.type = QTFILE;	devdir(c, qid, up->genbuf, len, eve, 0660, dp);	return 1;}static intbitno(ulong x){	int i;	for(i = 0; i < 8*sizeof(x); i++)		if((1<<i) & x)			break;	return i;}/* *  set up the cards, default timing is 300 ns */static voidpcmciareset(void){	/* staticly map the whole area */	slotmap(0, PHYSPCM0REGS, PYHSPCM0ATTR, PYHSPCM0MEM);	slotmap(1, PHYSPCM1REGS, PYHSPCM1ATTR, PYHSPCM1MEM);	/* set timing to the default, 300 */	slottiming(0, 300, 300, 300, 0);	slottiming(1, 300, 300, 300, 0);	/* if there's no pcmcia sleave, no interrupts */	if(gpioregs->level & GPIO_OPT_IND_i)		return;	/* sleave there, interrupt on card removal */	intrenable(GPIOrising, bitno(GPIO_CARD_IND1_i), slotinfo, nil, "pcmcia slot1 status");	intrenable(GPIOrising, bitno(GPIO_CARD_IND0_i), slotinfo, nil, "pcmcia slot0 status");}static Chan*pcmciaattach(char *spec){	return devattach('y', spec);}static Walkqid*pcmciawalk(Chan *c, Chan *nc, char **name, int nname){	return devwalk(c, nc, name, nname, 0, 0, pcmgen);}static intpcmciastat(Chan *c, uchar *db, int n){	return devstat(c, db, n, 0, 0, pcmgen);}static Chan*pcmciaopen(Chan *c, int omode){	PCMslot *slotp;	if(c->qid.type & QTDIR){		if(omode != OREAD)			error(Eperm);	} else {		slotp = slotof(c);		increfp(slotp);	}	c->mode = openmode(omode);	c->flag |= COPEN;	c->offset = 0;	return c;}static voidpcmciaclose(Chan *c){	if(c->flag & COPEN)		if((c->qid.type & QTDIR) == 0)			decrefp(slotof(c));}/* a memmove using only bytes */static voidmemmoveb(uchar *to, uchar *from, int n){	while(n-- > 0)		*to++ = *from++;}/* a memmove using only shorts & bytes */static voidmemmoves(uchar *to, uchar *from, int n){	ushort *t, *f;	if((((ulong)to) & 1) || (((ulong)from) & 1) || (n & 1)){		while(n-- > 0)			*to++ = *from++;	} else {		n = n/2;		t = (ushort*)to;		f = (ushort*)from;		while(n-- > 0)			*t++ = *f++;	}}static longpcmread(void *a, long n, ulong off, PCMslot *sp, uchar *start, ulong len){	rlock(sp);	if(waserror()){		runlock(sp);		nexterror();	}	if(off > len)		return 0;	if(off + n > len)		n = len - off;	memmoveb(a, start+off, n);	runlock(sp);	poperror();	return n;}static longpcmctlread(void *a, long n, ulong off, PCMslot *sp){	char *p, *buf, *e;	buf = p = malloc(READSTR);	if(waserror()){		free(buf);		nexterror();	}	e = p + READSTR;	buf[0] = 0;	if(sp->occupied){		p = seprint(p, e, "occupied\n");		if(sp->verstr[0])			p = seprint(p, e, "version %s\n", sp->verstr);	}	USED(p);	n = readstr(off, a, n, buf);	free(buf);	poperror();	return n;}static intinserted(void *){	if (slot[0].inserted)		return 1;	if (slot[1].inserted)		return 2;	return 0;}static longpcmevsread(void *a, long n, ulong off){	int i;	char *buf = nil;	char *e;	if (pcmcia.evreader)		error("At most one reader");	off = 0;	pcmcia.evreader++;	if (waserror()){		free(buf);		pcmcia.evreader--;		nexterror();	}	while((i = inserted(nil)) == 0){		slotinfo(nil, nil);		tsleep(&pcmcia.event, inserted, nil, 500);	}	pcmcia.evreader--;	slot[i-1].inserted = 0;	buf = malloc(READSTR);	e = buf + READSTR;	buf[0] = 0;	seprint(buf, e, "#y/pcm%dctl\n", i-1);	n = readstr(off, a, n, buf);	free(buf);	poperror();	return n;}static longpcmciaread(Chan *c, void *a, long n, vlong off){	PCMslot *sp;	ulong offset = off;	sp = slotof(c);	switch(TYPE(c)){	case Qdir:		return devdirread(c, a, n, 0, 0, pcmgen);	case Qmem:		if(!sp->occupied)			error(Eio);		return pcmread(a, n, offset, sp, sp->mem, 64*OneMeg);	case Qattr:		if(!sp->occupied)			error(Eio);		return pcmread(a, n, offset, sp, sp->attr, OneMeg);	case Qevs:		return pcmevsread(a, n, offset);	case Qctl:		return pcmctlread(a, n, offset, sp);	}	error(Ebadarg);	return -1;	/* not reached */}static longpcmwrite(void *a, long n, ulong off, PCMslot *sp, uchar *start, ulong len){	rlock(sp);	if(waserror()){		runlock(sp);		nexterror();	}	if(off > len)		error(Eio);	if(off + n > len)		error(Eio);	memmoveb(start+off, a, n);	poperror();	runlock(sp);	return n;}static longpcmctlwrite(char *p, long n, ulong, PCMslot *sp){	Cmdbuf *cmd;	uchar *cp;	int index, i, dtx;	Rune r;	DevConf cf;	Devport port;	cmd = parsecmd(p, n);	if(strcmp(cmd->f[0], "configure") == 0){		wlock(sp);		if(waserror()){			wunlock(sp);			nexterror();		}		/* see if driver exists and is configurable */		if(cmd->nf < 3)			error(Ebadarg);		p = cmd->f[1];		if(*p++ != '#')			error(Ebadarg);		p += chartorune(&r, p);		dtx = devno(r, 1);		if(dtx < 0)			error("no such device type");		if(devtab[dtx]->config == nil)			error("not a dynamicly configurable device");		/* set pcmcia card configuration */		index = 0;		if(sp->def != nil)			index = sp->def->index;		if(cmd->nf > 3){			i = atoi(cmd->f[3]);			if(i < 0 || i >= sp->nctab)				error("bad configuration index");			index = i;		}		if(sp->cfg[0].cpresent & (1<<Rconfig)){			cp = sp->attr;			cp += sp->cfg[0].caddr + Rconfig;			*cp = index;		}		/* configure device */		memset(&cf, 0, sizeof cf);		kstrdup(&cf.type, cmd->f[2]);		cf.mem = (ulong)sp->mem;		cf.ports = &port;		cf.ports[0].port = (ulong)sp->regs;		cf.ports[0].size = 0;		cf.nports = 1;		cf.itype = GPIOfalling;		cf.intnum = bitno(sp == slot ? GPIO_CARD_IRQ0_i : GPIO_CARD_IRQ1_i);		if(devtab[dtx]->config(1, p, &cf) < 0)			error("couldn't configure device");		sp->dev = devtab[dtx];		wunlock(sp);		poperror();		/* don't let the power turn off */		increfp(sp);	}else if(strcmp(cmd->f[0], "remove") == 0){		/* see if driver exists and is configurable */		if(cmd->nf != 2)			error(Ebadarg);		p = cmd->f[1];		if(*p++ != '#')			error(Ebadarg);		p += chartorune(&r, p);		dtx = devno(r, 1);		if(dtx < 0)			error("no such device type");		if(devtab[dtx]->config == nil)			error("not a dynamicly configurable device");		if(devtab[dtx]->config(0, p, nil) < 0)			error("couldn't unconfigure device");		/* let the power turn off */		decrefp(sp);	}	free(cmd);	return 0;}static longpcmciawrite(Chan *c, void *a, long n, vlong off){	PCMslot *sp;	ulong offset = off;	sp = slotof(c);	switch(TYPE(c)){	case Qmem:		if(!sp->occupied)			error(Eio);		return pcmwrite(a, n, offset, sp, sp->mem, 64*OneMeg);	case Qattr:		if(!sp->occupied)			error(Eio);		return pcmwrite(a, n, offset, sp, sp->attr, OneMeg);	case Qevs:		break;	case Qctl:		if(!sp->occupied)			error(Eio);		return pcmctlwrite(a, n, offset, sp);	}	error(Ebadarg);	return -1;	/* not reached */}/* * power up/down pcmcia */voidpcmciapower(int on){	PCMslot *sp;	/* if there's no pcmcia sleave, no interrupts */iprint("pcmciapower %d\n", on);	if (on){		/* set timing to the default, 300 */		slottiming(0, 300, 300, 300, 0);		slottiming(1, 300, 300, 300, 0);		/* if there's no pcmcia sleave, no interrupts */		if(gpioregs->level & GPIO_OPT_IND_i){			iprint("pcmciapower: no sleeve\n");			return;		}		for (sp = slot; sp < slot + nslot; sp++){			if (sp->dev){				increfp(sp);				iprint("pcmciapower: %s\n", sp->verstr);				delay(10000);				if (sp->dev->power)					sp->dev->power(on);			}		}	}else{		if(gpioregs->level & GPIO_OPT_IND_i){			iprint("pcmciapower: no sleeve\n");			return;		}		for (sp = slot; sp < slot + nslot; sp++){			if (sp->dev){				if (sp->dev->power)					sp->dev->power(on);				decrefp(sp);			}			sp->occupied = 0;			sp->cisread = 0;		}		egpiobits(EGPIO_exp_nvram_power|EGPIO_exp_full_power, 0);	}}Dev pcmciadevtab = {	'y',	"pcmcia",	pcmciareset,	devinit,	devshutdown,	pcmciaattach,	pcmciawalk,	pcmciastat,	pcmciaopen,	devcreate,	pcmciaclose,	pcmciaread,	devbread,	pcmciawrite,	devbwrite,	devremove,	devwstat,	pcmciapower,};/* see what's there */static voidslotinfo(Ureg*, void*){	ulong x = gpioregs->level;	if(x & GPIO_OPT_IND_i){		/* no expansion pack */		slot[0].occupied = slot[0].inserted = 0;		slot[1].occupied = slot[1].inserted = 0;	} else {		if(x & GPIO_CARD_IND0_i){			slot[0].occupied = slot[0].inserted = 0;			slot[0].cisread = 0;		} else {			if(slot[0].occupied == 0){				slot[0].inserted = 1;				slot[0].cisread = 0;			}			slot[0].occupied = 1;		}		if(x & GPIO_CARD_IND1_i){			slot[1].occupied = slot[1].inserted = 0;			slot[1].cisread = 0;		} else {			if(slot[1].occupied == 0){				slot[1].inserted = 1;				slot[1].cisread = 0;			}			slot[1].occupied = 1;		}		if (inserted(nil))			wakeup(&pcmcia.event);	}}/* use reference card to turn cards on and off */static voidincrefp(PCMslot *sp){	wlock(sp);	if(waserror()){		wunlock(sp);		nexterror();	}iprint("increfp %ld\n", sp - slot);	if(incref(&pcmcia) == 1){iprint("increfp full power\n");		egpiobits(EGPIO_exp_nvram_power|EGPIO_exp_full_power, 1);		delay(200);		egpiobits(EGPIO_pcmcia_reset, 1);		delay(100);		egpiobits(EGPIO_pcmcia_reset, 0);		delay(500);	}	incref(&sp->ref);	slotinfo(nil, nil);	if(sp->occupied && sp->cisread == 0) {		pcmcisread(sp);	}	wunlock(sp);	poperror();}static voiddecrefp(PCMslot *sp){iprint("decrefp %ld\n", sp - slot);	decref(&sp->ref);	if(decref(&pcmcia) == 0){iprint("increfp power down\n");		egpiobits(EGPIO_exp_nvram_power|EGPIO_exp_full_power, 0);	}}/* *  the regions are staticly mapped */static voidslotmap(int slotno, ulong regs, ulong attr, ulong mem){	PCMslot *sp;	sp = &slot[slotno];	sp->slotno = slotno;	sp->memlen = 64*OneMeg;	sp->verstr[0] = 0;	sp->mem = mapmem(mem, 64*OneMeg, 0);	sp->memmap.ca = 0;	sp->memmap.cea = 64*MB;	sp->memmap.isa = (ulong)mem;	sp->memmap.len = 64*OneMeg;	sp->memmap.attr = 0;	sp->attr = mapmem(attr, OneMeg, 0);	sp->attrmap.ca = 0;	sp->attrmap.cea = MB;	sp->attrmap.isa = (ulong)attr;	sp->attrmap.len = OneMeg;	sp->attrmap.attr = 1;	sp->regs = mapspecial(regs, 32*1024);}PCMmap*pcmmap(int slotno, ulong, int, int attr){	if(slotno > nslot)		panic("pcmmap");	if(attr)		return &slot[slotno].attrmap;	else		return &slot[slotno].memmap;}voidpcmunmap(int, PCMmap*){}/* *  setup card timings *    times are in ns *    count = ceiling[access-time/(2*3*T)] - 1, where T is a processor cycle * */static intns2count(int ns){	ulong y;	/* get 100 times cycle time */	y = 100000000/(conf.hz/1000);	/* get 10 times ns/(cycle*6) */	y = (1000*ns)/(6*y);	/* round up */	y += 9;	y /= 10;	/* subtract 1 */	return y-1;}static voidslottiming(int slotno, int tio, int tattr, int tmem, int fast){	ulong x;	x = 0;	if(fast)		x |= 1<<MECR_fast0;	x |= ns2count(tio) << MECR_io0;	x |= ns2count(tattr) << MECR_attr0;	x |= ns2count(tmem) << MECR_mem0;	if(slotno == 0){		x |= memconfregs->mecr & 0xffff0000;	} else {		x <<= 16;		x |= memconfregs->mecr & 0xffff;	}	memconfregs->mecr = x;}/* For compat with ../pc devices. Don't use it for the bitsy  */intpcmspecial(char*, ISAConf*){	return -1;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -