plan 9 kernel history: overview | file list | diff list

2000/1207/bitsy/devflash.c (diff list | history)

2000/1031/sys/src/9/bitsy/devflash.c:15,172000/1107/sys/src/9/bitsy/devflash.c:15,74 (short | long)
2000/1031    
	ulong	start;		/* byte offsets */ 
	ulong	end; 
}; 
2000/1107    
 
static ulong *flash = (ulong*)FLASHZERO; 
 
/* 
 *  on the bitsy, all 32 bit accesses to flash are mapped to two 16 bit 
 *  accesses, one to the low half of the chip and the other to the high 
 *  half.  Therefore for all command accesses, ushort indices in the 
 *  manuals turn into ulong indices in our code.  Also, by copying all 
 *  16 bit commands to both halves of a 32 bit command, we erase 2 
 *  sectors for each request erase request. 
 */ 
 
/* 
 *  common flash memory interface 
 */ 
enum 
{ 
	CFIidoff=	0x10, 
	CFIsysoff=	0x1B, 
	CFIgeomoff=	0x27, 
}; 
 
struct CFIid 
{ 
	ulong	q; 
	ulong	r; 
	ulong	y; 
	ulong	cmd_set; 
	ulong	vendor_alg; 
	ulong	ext_alg_addr[2]; 
	ulong	alt_cmd_set; 
	ulong	alt_vendor_alg; 
	ulong	alt_ext_ald_addr[2]; 
	 
}; 
 
struct CFIsys 
{ 
	ulong 	vcc_min;	/* 100 mv */ 
	ulong	vcc_max; 
	ulong	vpp_min; 
	ulong	vpp_max; 
	ulong	word_wr_to;		/* 2**n µs */ 
	ulong	buf_wr_to;		/* 2**n µs */ 
	ulong	block_erase_to;		/* 2**n ms */ 
	ulong	chip_erase_to;		/* 2**n ms */ 
	ulong	max_word_wr_to;		/* 2**n µs */ 
	ulong	max_buf_wr_to;		/* 2**n µs */ 
	ulong	max_block_erase_to;	/* 2**n ms */ 
	ulong	max_chip_erase_to;	/* 2**n ms */ 
}; 
 
struct CFIgeom 
{ 
	ulong	size;		/* 2**n bytes */ 
	ulong	 
}; 
2000/1107/sys/src/9/bitsy/devflash.c:30,422000/1111/sys/src/9/bitsy/devflash.c:30,35 (short | long)
2000/1107    
/* 
 *  common flash memory interface 
 */ 
enum 
{ 
	CFIidoff=	0x10, 
	CFIsysoff=	0x1B, 
	CFIgeomoff=	0x27, 
}; 
                 
struct CFIid 
{ 
	ulong	q; 
2000/1107/sys/src/9/bitsy/devflash.c:70,742000/1111/sys/src/9/bitsy/devflash.c:63,185
2000/1107    
struct CFIgeom 
{ 
	ulong	size;		/* 2**n bytes */ 
	ulong	 
2000/1111    
	ulong	dev_code;	/* ??? */ 
	ulong	max_multi;	/* max bytes in a multibyte write */ 
	ulong	nregion;	/* number of erase regions */ 
	ulong	region[1];	/* erase region info */ 
}; 
 
#define mirror(x) (((x)<<16)|(x)) 
 
void 
cfiquery(void) 
{ 
	struct CFIid *id; 
 
	flash[0x55] = mirror(0x98); 
	id = (struct CFIid*)&flash[0x10]; 
	if(id.q != 'q' || id.r != 'r' || id.y != 'y') 
		print("CFI not supported by flash\n"); 
	 
	flash[0x55] = mirror(0xFF); 
} 
 
void 
cfigeom(void) 
{ 
} 
 
/* 
 *  flash device interface 
 */ 
 
enum 
{ 
	Qf0=1, 
	Qf1, 
	Qf2, 
	Qf3, 
}; 
 
Dirtab flashdir[]={ 
	"f0",		{ Qf0, 0 },	0,	0664, 
	"f1",		{ Qf1, 0 },	0,	0664, 
	"f2",		{ Qf2, 0 },	0,	0664, 
	"f3",		{ Qf3, 0 },	0,	0664, 
}; 
 
void 
flashinit(void) 
{ 
	cfiquery(); 
	cfigeom(); 
} 
 
static Chan* 
flashattach(char* spec) 
{ 
	return devattach('r', spec); 
} 
 
static int	  
flashwalk(Chan* c, char* name) 
{ 
	return devwalk(c, name, flashdir, nelem(flashdir), devgen); 
} 
 
static void	  
flashstat(Chan* c, char* dp) 
{ 
	devstat(c, dp, flashdir, nelem(flashdir), devgen); 
} 
 
static Chan* 
flashopen(Chan* c, int omode) 
{ 
	omode = openmode(omode); 
	if(strcmp(up->user, eve)!=0) 
		error(Eperm); 
	return devopen(c, omode, flashdir, nelem(flashdir), devgen); 
} 
 
static void	  
flashclose(Chan*) 
{ 
} 
 
static long	  
flashread(Chan* c, void* a, long n, vlong off) 
{ 
	USED(c, a, off); 
	error("UUO"); 
	return n; 
} 
 
static long	  
flashwrite(Chan* c, void* a, long n, vlong) 
{ 
	USED(c, a, off); 
	error("UUO"); 
	return n; 
} 
 
Dev flashdevtab = { 
	'F', 
	"flash", 
 
	devreset, 
	flashinit, 
	flashattach, 
	devclone, 
	flashwalk, 
	flashstat, 
	flashopen, 
	devcreate, 
	flashclose, 
	flashread, 
	devbread, 
	flashwrite, 
	devbwrite, 
	devremove, 
	devwstat, 
2000/1107    
}; 
2000/1111/sys/src/9/bitsy/devflash.c:6,232000/1117/sys/src/9/bitsy/devflash.c:6,11 (short | long)
2000/1031    
#include	"io.h" 
#include	"../port/error.h" 
 
/* flash partitions */ 
typedef struct FlashPart FlashPart; 
struct FlashPart 
{ 
	QLock; 
	char	name[NAMELEN]; 
	ulong	start;		/* byte offsets */ 
	ulong	end; 
}; 
2000/1107    
                 
static ulong *flash = (ulong*)FLASHZERO; 
                 
/* 
 *  on the bitsy, all 32 bit accesses to flash are mapped to two 16 bit 
 *  accesses, one to the low half of the chip and the other to the high 
2000/1111/sys/src/9/bitsy/devflash.c:27,942000/1117/sys/src/9/bitsy/devflash.c:15,133
2000/1107    
 *  sectors for each request erase request. 
 */ 
 
/* 
 *  common flash memory interface 
 */ 
struct CFIid 
2000/1117    
#define mirror(x) (((x)<<16)|(x)) 
 
/* this defines a contiguous set of erase blocks of one size */ 
typedef struct FlashRegion FlashRegion; 
struct FlashRegion 
2000/1107    
{ 
	ulong	q; 
	ulong	r; 
	ulong	y; 
	ulong	cmd_set; 
	ulong	vendor_alg; 
	ulong	ext_alg_addr[2]; 
	ulong	alt_cmd_set; 
	ulong	alt_vendor_alg; 
	ulong	alt_ext_ald_addr[2]; 
	                 
2000/1117    
	ulong	addr;		/* start of region */ 
	ulong	end;		/* end of region + 1 */ 
	ulong	n;		/* number of blocks */ 
	ulong	size;		/* size of each block */ 
2000/1107    
}; 
 
struct CFIsys 
2000/1117    
/* this defines a particular access algorithm */ 
typedef struct FlashAlg FlashAlg; 
struct FlashAlg 
2000/1107    
{ 
	ulong 	vcc_min;	/* 100 mv */ 
	ulong	vcc_max; 
	ulong	vpp_min; 
	ulong	vpp_max; 
	ulong	word_wr_to;		/* 2**n µs */ 
	ulong	buf_wr_to;		/* 2**n µs */ 
	ulong	block_erase_to;		/* 2**n ms */ 
	ulong	chip_erase_to;		/* 2**n ms */ 
	ulong	max_word_wr_to;		/* 2**n µs */ 
	ulong	max_buf_wr_to;		/* 2**n µs */ 
	ulong	max_block_erase_to;	/* 2**n ms */ 
	ulong	max_chip_erase_to;	/* 2**n ms */ 
2000/1117    
	int	id; 
	char	*name; 
	void	(*identify)(void);	/* identify device */ 
	void	(*erase)(ulong);	/* erase a region */ 
	void	(*write)(void*, long, ulong);	/* write a region */ 
2000/1107    
}; 
 
struct CFIgeom 
2000/1117    
static void	ise_id(void); 
static void	ise_erase(ulong); 
static void	ise_write(void*, long, ulong); 
 
static void	afs_id(void); 
static void	afs_erase(ulong); 
static void	afs_write(void*, long, ulong); 
 
FlashAlg falg[] = 
2000/1107    
{ 
	ulong	size;		/* 2**n bytes */ 
2000/1111    
	ulong	dev_code;	/* ??? */ 
	ulong	max_multi;	/* max bytes in a multibyte write */ 
	ulong	nregion;	/* number of erase regions */ 
	ulong	region[1];	/* erase region info */ 
2000/1117    
	{ 1,	"Intel/Sharp Extended",	ise_id, ise_erase, ise_write	}, 
	{ 2,	"AMD/Fujitsu Standard",	afs_id, afs_erase, afs_write	}, 
2000/1111    
}; 
 
#define mirror(x) (((x)<<16)|(x)) 
2000/1117    
struct 
{ 
	RWlock; 
	ulong		*p; 
	ushort		algid;		/* access algorithm */ 
	FlashAlg	*alg; 
	ushort		manid;		/* manufacturer id */ 
	ushort		devid;		/* device id */ 
	ulong		size;		/* size in bytes */ 
	int		wbsize;		/* size of write buffer */  
	ulong		nr;		/* number of regions */ 
	uchar		bootprotect; 
	FlashRegion	r[32]; 
	ulong		*wb;		/* staging area for write buffer */ 
} flash; 
2000/1111    
 
void 
cfiquery(void) 
2000/1117    
/* 
 *  common flash interface 
 */ 
static uchar 
cfigetc(int off) 
2000/1111    
{ 
	struct CFIid *id; 
2000/1117    
	uchar rv; 
2000/1111    
 
	flash[0x55] = mirror(0x98); 
	id = (struct CFIid*)&flash[0x10]; 
	if(id.q != 'q' || id.r != 'r' || id.y != 'y') 
		print("CFI not supported by flash\n"); 
	                 
	flash[0x55] = mirror(0xFF); 
2000/1117    
	flash.p[0x55] = mirror(0x98); 
	rv = flash.p[off]; 
	flash.p[0x55] = mirror(0xFF); 
	return rv; 
2000/1111    
} 
 
void 
cfigeom(void) 
2000/1117    
static ushort 
cfigets(int off) 
2000/1111    
{ 
2000/1117    
	return (cfigetc(off+1)<<8)|cfigetc(off); 
2000/1111    
} 
 
2000/1117    
static ulong 
cfigetl(int off) 
{ 
	return (cfigetc(off+3)<<24)|(cfigetc(off+2)<<16)| 
		(cfigetc(off+1)<<8)|cfigetc(off); 
} 
 
static void 
cfiquery(void) 
{ 
	uchar q, r, y; 
	ulong x, addr; 
 
	q = cfigetc(0x10); 
	r = cfigetc(0x11); 
	y = cfigetc(0x12); 
	if(q != 'Q' || r != 'R' || y != 'Y'){ 
		print("cfi query failed: %ux %ux %ux\n", q, r, y); 
		return; 
	} 
	flash.algid = cfigetc(0x13); 
	flash.size = 1<<(cfigetc(0x27)+1); 
	flash.wbsize = 1<<(cfigetc(0x2a)+1); 
	flash.nr = cfigetc(0x2c); 
	if(flash.nr > nelem(flash.r)){ 
		print("cfi reports > %d regions\n", nelem(flash.r)); 
		flash.nr = nelem(flash.r); 
	} 
	addr = 0; 
	for(q = 0; q < flash.nr; q++){ 
		x = cfigetl(q+0x2d); 
		flash.r[q].size = 2*256*(x>>16); 
		flash.r[q].n = (x&0xffff)+1; 
		flash.r[q].addr = addr; 
		addr += flash.r[q].size*flash.r[q].n; 
		flash.r[q].end = addr; 
	} 
	flash.wb = malloc(flash.wbsize); 
} 
 
2000/1111    
/* 
 *  flash device interface 
 */ 
2000/1111/sys/src/9/bitsy/devflash.c:95,1242000/1117/sys/src/9/bitsy/devflash.c:134,168
2000/1111    
 
enum 
{ 
	Qf0=1, 
	Qf1, 
	Qf2, 
	Qf3, 
2000/1117    
	Qfctl=1, 
	Qfdata, 
2000/1111    
}; 
 
Dirtab flashdir[]={ 
	"f0",		{ Qf0, 0 },	0,	0664, 
	"f1",		{ Qf1, 0 },	0,	0664, 
	"f2",		{ Qf2, 0 },	0,	0664, 
	"f3",		{ Qf3, 0 },	0,	0664, 
2000/1117    
	"flashctl",		{ Qfctl, 0 },	0,	0664, 
	"flashdata",		{ Qfdata, 0 },	0,	0660, 
2000/1111    
}; 
 
void 
flashinit(void) 
{ 
2000/1117    
	int i; 
 
	flash.p = (ulong*)FLASHZERO; 
2000/1111    
	cfiquery(); 
	cfigeom(); 
2000/1117    
	for(i = 0; i < nelem(falg); i++) 
		if(flash.algid == falg[i].id){ 
			flash.alg = &falg[i]; 
			(*flash.alg->identify)(); 
			break; 
		} 
	flash.bootprotect = 1; 
2000/1111    
} 
 
static Chan* 
flashattach(char* spec) 
{ 
	return devattach('r', spec); 
2000/1117    
	return devattach('F', spec); 
2000/1111    
} 
 
static int	  
2000/1111/sys/src/9/bitsy/devflash.c:150,1652000/1117/sys/src/9/bitsy/devflash.c:194,378
2000/1111    
static long	  
flashread(Chan* c, void* a, long n, vlong off) 
{ 
	USED(c, a, off); 
	error("UUO"); 
2000/1117    
	char *buf, *p, *e; 
	int i; 
 
	if(c->qid.path&CHDIR) 
		return devdirread(c, a, n, flashdir, nelem(flashdir), devgen); 
	switch(c->qid.path){ 
	default: 
		error(Eperm); 
	case Qfctl: 
		buf = smalloc(1024); 
		e = buf + 1024; 
		p = seprint(buf, e, "0x%-9lux 0x%-9lux 0x%-9lux 0x%-9lux\n", flash.size, 
			flash.wbsize, flash.manid, flash.devid); 
		for(i = 0; i < flash.nr; i++) 
			p = seprint(p, e, "0x%-9lux 0x%-9lux 0x%-9lux\n", flash.r[i].addr, 
				flash.r[i].n, flash.r[i].size); 
		n = readstr(off, a, n, buf); 
		free(buf); 
		break; 
	case Qfdata: 
		if(!iseve()) 
			error(Eperm); 
		if(off >= flash.size) 
			return 0; 
		if(off + n > flash.size) 
			n = flash.size - off; 
		rlock(&flash); 
		if(waserror()){ 
			runlock(&flash); 
			nexterror(); 
		} 
		memmove(a, ((uchar*)FLASHZERO)+off, n); 
		runlock(&flash); 
		poperror(); 
		break; 
	} 
2000/1111    
	return n; 
} 
 
2000/1117    
static void 
bootprotect(ulong addr) 
{ 
	FlashRegion *r; 
 
	if(flash.bootprotect == 0) 
		return; 
	if(flash.nr == 0) 
		error("writing over boot loader disallowed"); 
	r = flash.r; 
	if(addr >= r->addr && addr < r->addr + r->size) 
		error("writing over boot loader disallowed"); 
} 
 
ulong 
blockstart(ulong addr) 
{ 
	FlashRegion *r, *e; 
	ulong x; 
 
	r = flash.r; 
	for(e = &flash.r[flash.nr]; r < e; r++) 
		if(addr >= r->addr && addr < r->end){ 
			x = addr - r->addr; 
			x /= r->size; 
			return r->addr + x*r->size; 
		} 
			 
	return (ulong)-1; 
} 
 
ulong 
blockend(ulong addr) 
{ 
	FlashRegion *r, *e; 
	ulong x; 
 
	r = flash.r; 
	for(e = &flash.r[flash.nr]; r < e; r++) 
		if(addr >= r->addr && addr < r->end){ 
			x = addr - r->addr; 
			x /= r->size; 
			return r->addr + (x+1)*r->size; 
		} 
			 
	return (ulong)-1; 
} 
 
static long 
flashctlwrite(char *p, long n) 
{ 
	Cmdbuf *cmd; 
	ulong addr; 
 
	cmd = parsecmd(p, n); 
	wlock(&flash); 
	if(waserror()){ 
		wunlock(&flash); 
		nexterror(); 
	} 
	if(strcmp(cmd->f[0], "erase") == 0){ 
		if(cmd->nf != 2) 
			error(Ebadarg); 
		addr = atoi(cmd->f[1]); 
		if(addr != blockstart(addr)) 
			error("erase must be a block boundary"); 
		bootprotect(addr); 
		(*flash.alg->erase)(addr); 
	} else if(strcmp(cmd->f[0], "protectboot") == 0){ 
		if(cmd->nf == 0 || strcmp(cmd->f[1], "off") != 0) 
			flash.bootprotect = 1; 
		else 
			flash.bootprotect = 0; 
	} else 
		error(Ebadarg); 
	poperror(); 
	wunlock(&flash); 
	free(cmd); 
 
	return n; 
} 
 
static long 
flashdatawrite(uchar *p, long n, long off) 
{ 
	uchar *end; 
	int m; 
	long ooff = off; 
	uchar *op = p; 
 
	if((off & 0x3) || (n & 0x3)) 
		error("only quad writes"); 
	if(off >= flash.size || off+n > flash.size || n <= 0) 
		error(Ebadarg); 
 
	wlock(&flash); 
	if(waserror()){ 
		wunlock(&flash); 
		nexterror(); 
	} 
 
	/* make sure we're not writing the boot sector */ 
	bootprotect(off); 
 
	/* (*flash.alg->write) can't cross blocks */ 
	for(end = p + n; p < end; p += m){ 
		m = blockend(off) - off; 
		if(m > end - p) 
			m = end - p; 
		(*flash.alg->write)(p, m, off); 
		off += m; 
	} 
 
	/* make sure write succeeded */ 
	if(memcmp(op, &flash.p[ooff>>2], n) != 0) 
		error("written bytes don't match"); 
 
	wunlock(&flash); 
	poperror(); 
 
	return n; 
} 
 
2000/1111    
static long	  
flashwrite(Chan* c, void* a, long n, vlong) 
2000/1117    
flashwrite(Chan* c, void* a, long n, vlong off) 
2000/1111    
{ 
	USED(c, a, off); 
	error("UUO"); 
2000/1117    
	if(c->qid.path & CHDIR) 
		error(Eperm); 
 
	if(!iseve()) 
		error(Eperm); 
 
	switch(c->qid.path){ 
	default: 
		panic("flashwrite"); 
	case Qfctl: 
		return flashctlwrite(a, n); 
	case Qfdata: 
		return flashdatawrite(a, n, off); 
	} 
2000/1111    
	return n; 
} 
 
2000/1111/sys/src/9/bitsy/devflash.c:183,1852000/1117/sys/src/9/bitsy/devflash.c:396,615
2000/1111    
	devremove, 
	devwstat, 
2000/1107    
}; 
2000/1117    
 
 
/* intel/sharp extended command set */ 
static void 
ise_reset(void) 
{ 
	flash.p[0x55] = mirror(0xff);	/* reset */ 
} 
static void 
ise_id(void) 
{ 
	ise_reset(); 
	flash.p[0x555] = mirror(0x90);	/* uncover vendor info */ 
	flash.manid = flash.p[00]; 
	flash.devid = flash.p[01]; 
	ise_reset(); 
} 
static void 
ise_clearerror(void) 
{ 
	flash.p[0x100] = mirror(0x50); 
 
} 
static void 
ise_error(int bank, ulong status) 
{ 
	char err[ERRLEN]; 
 
	if(status & (1<<3)){ 
		sprint(err, "flash%d: low prog voltage", bank); 
		error(err); 
	} 
	if(status & (1<<1)){ 
		sprint(err, "flash%d: block locked", bank); 
		error(err); 
	} 
	if(status & (1<<5)){ 
		sprint(err, "flash%d: i/o error", bank); 
		error(err); 
	} 
} 
static void 
ise_erase(ulong addr) 
{ 
	ulong start; 
	ulong x; 
 
	addr >>= 2;	/* convert to ulong offset */ 
 
	flashprogpower(1); 
	flash.p[addr] = mirror(0x20); 
	flash.p[addr] = mirror(0xd0); 
	start = m->ticks; 
	do { 
		x = flash.p[addr]; 
		if((x & mirror(1<<7)) == mirror(1<<7)) 
			break; 
	} while(TK2MS(m->ticks-start) < 1500); 
	flashprogpower(0); 
 
	ise_clearerror(); 
	ise_error(0, x); 
	ise_error(1, x>>16); 
 
	ise_reset(); 
} 
/* 
 *  flash writing goes about 16 times faster if we use 
 *  the write buffer.  We fill the write buffer and then 
 *  issue the write request.  After the write request, 
 *  subsequent reads will yield the status register or, 
 *  since error bits are sticky, another write buffer can 
 *  be filled and written. 
 * 
 *  On timeout, we issue a read status register request so 
 *  that the status register can be read no matter how we 
 *  exit. 
 */ 
static int 
ise_wbwrite(ulong *p, int n, ulong off) 
{ 
	ulong start; 
	int i; 
 
	/* copy out of user space to avoid faults later */ 
	memmove(flash.wb, p, n*4); 
	p = flash.wb; 
 
	/* put flash into write buffer mode */ 
	start = m->ticks; 
	for(;;) { 
		/* request write buffer mode */ 
		flash.p[off] = mirror(0xe8); 
 
		/* look at extended status reg for status */ 
		if((flash.p[off] & mirror(1<<7)) == mirror(1<<7)) 
			break; 
 
		/* didn't work, keep trying for 2 secs */ 
		if(TK2MS(m->ticks-start) > 2000){ 
			/* set up to read status */ 
			flash.p[off] = mirror(0x70); 
			return -1; 
		} 
	} 
 
	/* fill write buffer */ 
	flash.p[off] = mirror(n-1); 
	for(i = 0; i < n; i++) 
		flash.p[off+i] = *p++; 
 
	/* program from buffer */ 
	flash.p[off] = mirror(0xd0); 
 
	/* subsequent reads will return status about the write */ 
 
	return n; 
} 
static void 
ise_write(void *a, long n, ulong off) 
{ 
	ulong *p, *end; 
	int i, wbsize; 
	ulong x, start, ooff; 
 
	/* everything in terms of ulongs */ 
	wbsize = flash.wbsize>>2; 
	off >>= 2; 
	n >>= 2; 
	p = a; 
	ooff = off; 
 
	/* first see if write will succeed */ 
	for(i = 0; i < n; i++) 
		if((p[i] & flash.p[off+i]) != p[i]) 
			error("flash needs erase"); 
 
	if(waserror()){ 
		ise_reset(); 
		flashprogpower(0); 
		nexterror(); 
	} 
	flashprogpower(1); 
 
	/* 
	 *  use the first write to reach 
 	 *  a write buffer boundary.  the intel maunal 
	 *  says writes startng at wb boundaries 
	 *  maximize speed. 
	 */ 
	i = wbsize - (off & (wbsize-1)); 
	for(end = p + n; p < end;){ 
		if(i > end - p) 
			i = end - p; 
 
		if(ise_wbwrite(p, i, off) != i) 
			break; 
 
		off += i; 
		p += i; 
		i = wbsize; 
	} 
 
	/* wait till the programming is done */ 
	start = m->ticks; 
	do { 
		x = flash.p[ooff]; 
		if((x & mirror(1<<7)) == mirror(1<<7)) 
			break; 
	} while(TK2MS(m->ticks-start) < 1000); 
 
	ise_clearerror(); 
	ise_error(0, x); 
	ise_error(1, x>>16); 
 
	ise_reset(); 
	flashprogpower(0); 
	poperror(); 
} 
 
/* amd/fujitsu standard command set 
 *	I don't have an amd chipset to work with 
 *	so I'm loathe to write this yet.  If someone 
 *	else does, please send it to me and I'll 
 *	incorporate it -- presotto@bell-labs.com 
 */ 
static void 
afs_reset(void) 
{ 
	flash.p[0x55] = mirror(0xf0);	/* reset */ 
} 
static void 
afs_id(void) 
{ 
	afs_reset(); 
	flash.p[0x55] = mirror(0xf0);	/* reset */ 
	flash.p[0x555] = mirror(0xaa);	/* query vendor block */ 
	flash.p[0x2aa] = mirror(0x55); 
	flash.p[0x555] = mirror(0x90); 
	flash.manid = flash.p[00]; 
	afs_reset(); 
	flash.p[0x555] = mirror(0xaa);	/* query vendor block */ 
	flash.p[0x2aa] = mirror(0x55); 
	flash.p[0x555] = mirror(0x90); 
	flash.devid = flash.p[01]; 
	afs_reset(); 
} 
static void 
afs_erase(ulong) 
{ 
	error("amd/fujistsu erase not implemented"); 
} 
static void 
afs_write(void*, long, ulong) 
{ 
	error("amd/fujistsu write not implemented"); 
} 
2000/1117/sys/src/9/bitsy/devflash.c:46,512000/1207/sys/src/9/bitsy/devflash.c:46,54 (short | long)
2000/1117    
static void	afs_erase(ulong); 
static void	afs_write(void*, long, ulong); 
 
2000/1207    
static ulong	blockstart(ulong); 
static ulong	blockend(ulong); 
 
2000/1117    
FlashAlg falg[] = 
2000/1107    
{ 
2000/1117    
	{ 1,	"Intel/Sharp Extended",	ise_id, ise_erase, ise_write	}, 
2000/1117/sys/src/9/bitsy/devflash.c:134,1482000/1207/sys/src/9/bitsy/devflash.c:137,265
2000/1111    
 
enum 
{ 
2000/1117    
	Qfctl=1, 
	Qfdata, 
2000/1207    
	Qtopdir, 
	Q2nddir, 
	Qfctl, 
	Qfpart, 
 
	Maxpart= 8, 
2000/1111    
}; 
 
Dirtab flashdir[]={ 
2000/1117    
	"flashctl",		{ Qfctl, 0 },	0,	0664, 
	"flashdata",		{ Qfdata, 0 },	0,	0660, 
2000/1207    
 
typedef struct FPart FPart; 
struct FPart 
{ 
	char	name[NAMELEN]; 
	ulong	start; 
	ulong	end; 
2000/1111    
}; 
2000/1207    
static FPart	part[Maxpart]; 
2000/1111    
 
2000/1207    
#define FQID(p,q)	((p)<<8|(q)) 
#define FTYPE(q)	((q) & 0xff) 
#define FPART(q)	(&part[(q) >>8]) 
 
static int 
gen(Chan *c, Dirtab*, int, int i, Dir *dp) 
{ 
	Qid q; 
	char buf[32]; 
	FPart *fp; 
 
	q.vers = 0; 
 
	/* top level directory contains the name of the network */ 
	if(c->qid.path == CHDIR){ 
		switch(i){ 
		case DEVDOTDOT: 
			q.path = CHDIR; 
			devdir(c, q, ".", 0, eve, CHDIR|0555, dp); 
			break; 
		case 0: 
			q.path = CHDIR | Q2nddir; 
			strcpy(buf, "flash"); 
			devdir(c, q, buf, 0, eve, CHDIR|0555, dp); 
			break; 
		default: 
			return -1; 
		} 
		return 1; 
	} 
 
	/* second level contains ctl plus all partitions */ 
	switch(i) { 
	case DEVDOTDOT: 
		q.path = CHDIR; 
		devdir(c, q, "#F", 0, eve, CHDIR|0555, dp); 
		break; 
	case 0: 
		q.path = Qfctl; 
		devdir(c, q, "ctl", 0, eve, 0666, dp); 
		break; 
	default: 
		i -= 1; 
		if(i >= Maxpart) 
			return -1; 
		fp = &part[i]; 
		if(fp->name[0] == 0) 
			return 0; 
		q.path = FQID(i, Qfpart); 
		devdir(c, q, fp->name, fp->end-fp->start, eve, 0660, dp); 
		break; 
	} 
	return 1; 
} 
 
static FPart* 
findpart(char *name) 
{ 
	int i; 
 
	for(i = 0; i < Maxpart; i++) 
		if(strcmp(name, part[i].name) == 0) 
			break; 
	if(i >= Maxpart) 
		return nil; 
	return &part[i]; 
} 
 
static void 
addpart(char *name, ulong start, ulong end) 
{ 
	int i; 
	FPart *fp; 
 
	if(start >= flash.size || end > flash.size) 
		error(Ebadarg); 
	if(blockstart(start) != start) 
		error("must start on erase boundary"); 
	if(blockstart(end) != end && end != flash.size) 
		error("must end on erase boundary"); 
	fp = findpart(name); 
	if(fp != nil) 
		error(Eexist); 
	for(i = 0; i < Maxpart; i++) 
		if(part[i].name[0] == 0) 
			break; 
	if(i == Maxpart) 
		error("no more partitions"); 
	fp = &part[i]; 
	strncpy(fp->name, name, sizeof(fp->name)-1); 
	fp->start = start; 
	fp->end = end; 
} 
 
static void 
rempart(char *name) 
{ 
	FPart *fp; 
 
	/* can't remove the total partition */ 
	fp = findpart(name); 
	if(fp != nil) 
		fp->name[0] = 0; 
} 
 
2000/1111    
void 
flashinit(void) 
{ 
2000/1117/sys/src/9/bitsy/devflash.c:157,1622000/1207/sys/src/9/bitsy/devflash.c:274,281
2000/1117    
			break; 
		} 
	flash.bootprotect = 1; 
2000/1207    
 
	addpart("whole", 0, flash.size); 
2000/1111    
} 
 
static Chan* 
2000/1117/sys/src/9/bitsy/devflash.c:168,1802000/1207/sys/src/9/bitsy/devflash.c:287,299
2000/1111    
static int	  
flashwalk(Chan* c, char* name) 
{ 
	return devwalk(c, name, flashdir, nelem(flashdir), devgen); 
2000/1207    
	return devwalk(c, name, nil, 0, gen); 
2000/1111    
} 
 
static void	  
flashstat(Chan* c, char* dp) 
{ 
	devstat(c, dp, flashdir, nelem(flashdir), devgen); 
2000/1207    
	devstat(c, dp, nil, 0, gen); 
2000/1111    
} 
 
static Chan* 
2000/1117/sys/src/9/bitsy/devflash.c:183,1892000/1207/sys/src/9/bitsy/devflash.c:302,308
2000/1111    
	omode = openmode(omode); 
	if(strcmp(up->user, eve)!=0) 
		error(Eperm); 
	return devopen(c, omode, flashdir, nelem(flashdir), devgen); 
2000/1207    
	return devopen(c, omode, nil, 0, gen); 
2000/1111    
} 
 
static void	  
2000/1117/sys/src/9/bitsy/devflash.c:196,2052000/1207/sys/src/9/bitsy/devflash.c:315,325
2000/1111    
{ 
2000/1117    
	char *buf, *p, *e; 
	int i; 
2000/1207    
	FPart *fp; 
2000/1117    
 
	if(c->qid.path&CHDIR) 
		return devdirread(c, a, n, flashdir, nelem(flashdir), devgen); 
	switch(c->qid.path){ 
2000/1207    
		return devdirread(c, a, n, nil, 0, gen); 
	switch(FTYPE(c->qid.path)){ 
2000/1117    
	default: 
		error(Eperm); 
	case Qfctl: 
2000/1117/sys/src/9/bitsy/devflash.c:213,2312000/1207/sys/src/9/bitsy/devflash.c:333,356
2000/1117    
		n = readstr(off, a, n, buf); 
		free(buf); 
		break; 
	case Qfdata: 
		if(!iseve()) 
			error(Eperm); 
		if(off >= flash.size) 
			return 0; 
		if(off + n > flash.size) 
			n = flash.size - off; 
2000/1207    
	case Qfpart: 
		fp = FPART(c->qid.path); 
2000/1117    
		rlock(&flash); 
		if(waserror()){ 
			runlock(&flash); 
			nexterror(); 
		} 
		memmove(a, ((uchar*)FLASHZERO)+off, n); 
2000/1207    
		if(fp->name[0] == 0) 
			error("partition vanished"); 
		if(!iseve()) 
			error(Eperm); 
		off += fp->start; 
		if(off >= fp->end) 
			n = 0; 
		if(off+n >= fp->end) 
			n = fp->end - off; 
		if(n > 0) 
			memmove(a, ((uchar*)FLASHZERO)+off, n); 
2000/1117    
		runlock(&flash); 
		poperror(); 
		break; 
2000/1117/sys/src/9/bitsy/devflash.c:247,2532000/1207/sys/src/9/bitsy/devflash.c:372,378
2000/1117    
		error("writing over boot loader disallowed"); 
} 
 
ulong 
2000/1207    
static ulong 
2000/1117    
blockstart(ulong addr) 
{ 
	FlashRegion *r, *e; 
2000/1117/sys/src/9/bitsy/devflash.c:264,2702000/1207/sys/src/9/bitsy/devflash.c:389,395
2000/1117    
	return (ulong)-1; 
} 
 
ulong 
2000/1207    
static ulong 
2000/1117    
blockend(ulong addr) 
{ 
	FlashRegion *r, *e; 
2000/1117/sys/src/9/bitsy/devflash.c:285,2912000/1207/sys/src/9/bitsy/devflash.c:410,417
2000/1117    
flashctlwrite(char *p, long n) 
{ 
	Cmdbuf *cmd; 
	ulong addr; 
2000/1207    
	ulong off; 
	FPart *fp; 
2000/1117    
 
	cmd = parsecmd(p, n); 
	wlock(&flash); 
2000/1117/sys/src/9/bitsy/devflash.c:294,3062000/1207/sys/src/9/bitsy/devflash.c:420,460
2000/1117    
		nexterror(); 
	} 
	if(strcmp(cmd->f[0], "erase") == 0){ 
2000/1207    
		if(cmd->nf < 2) 
			error(Ebadarg); 
		fp = findpart(cmd->f[1]); 
		if(fp == nil) 
			error("no such partition"); 
 
		switch(cmd->nf){ 
		case 3: 
			/* erase a single block */ 
			off = atoi(cmd->f[2]); 
			off += fp->start; 
			if(off >= fp->end) 
				error("region not in partition"); 
			if(off != blockstart(off)) 
				error("erase must be a block boundary"); 
			bootprotect(off); 
			(*flash.alg->erase)(off); 
			break; 
		case 2: 
			/* erase the whole partition */ 
			bootprotect(fp->start); 
			for(off = fp->start; off < fp->end; off = blockend(off)) 
				(*flash.alg->erase)(off); 
			break; 
		default: 
			error(Ebadarg); 
		} 
	} else if(strcmp(cmd->f[0], "add") == 0){ 
		if(cmd->nf != 4) 
			error(Ebadarg); 
		addpart(cmd->f[1], strtoul(cmd->f[2], nil, 0), strtoul(cmd->f[3], nil, 0)); 
	} else if(strcmp(cmd->f[0], "remove") == 0){ 
2000/1117    
		if(cmd->nf != 2) 
			error(Ebadarg); 
		addr = atoi(cmd->f[1]); 
		if(addr != blockstart(addr)) 
			error("erase must be a block boundary"); 
		bootprotect(addr); 
		(*flash.alg->erase)(addr); 
2000/1207    
		rempart(cmd->f[1]); 
2000/1117    
	} else if(strcmp(cmd->f[0], "protectboot") == 0){ 
		if(cmd->nf == 0 || strcmp(cmd->f[1], "off") != 0) 
			flash.bootprotect = 1; 
2000/1117/sys/src/9/bitsy/devflash.c:316,3322000/1207/sys/src/9/bitsy/devflash.c:470,484
2000/1117    
} 
 
static long 
flashdatawrite(uchar *p, long n, long off) 
2000/1207    
flashdatawrite(Chan *c, uchar *p, long n, long off) 
2000/1117    
{ 
	uchar *end; 
	int m; 
	long ooff = off; 
2000/1207    
	long ooff; 
2000/1117    
	uchar *op = p; 
2000/1207    
	FPart *fp; 
2000/1117    
 
	if((off & 0x3) || (n & 0x3)) 
		error("only quad writes"); 
	if(off >= flash.size || off+n > flash.size || n <= 0) 
		error(Ebadarg); 
2000/1207    
	fp = FPART(c->qid.path); 
2000/1117    
 
	wlock(&flash); 
	if(waserror()){ 
2000/1117/sys/src/9/bitsy/devflash.c:334,3432000/1207/sys/src/9/bitsy/devflash.c:486,507
2000/1117    
		nexterror(); 
	} 
 
2000/1207    
	if(fp->name[0] == 0) 
		error("partition vanished"); 
	if(!iseve()) 
		error(Eperm); 
 
	if((off & 0x3) || (n & 0x3)) 
		error("only quad writes"); 
	off += fp->start; 
	if(off >= fp->end || off+n > fp->end || n <= 0) 
		error(Ebadarg); 
 
2000/1117    
	/* make sure we're not writing the boot sector */ 
	bootprotect(off); 
 
	/* (*flash.alg->write) can't cross blocks */ 
2000/1207    
	ooff = off; 
2000/1117    
	for(end = p + n; p < end; p += m){ 
		m = blockend(off) - off; 
		if(m > end - p) 
2000/1117/sys/src/9/bitsy/devflash.c:365,3772000/1207/sys/src/9/bitsy/devflash.c:529,541
2000/1117    
	if(!iseve()) 
		error(Eperm); 
 
	switch(c->qid.path){ 
2000/1207    
	switch(FTYPE(c->qid.path)){ 
2000/1117    
	default: 
		panic("flashwrite"); 
	case Qfctl: 
		return flashctlwrite(a, n); 
	case Qfdata: 
		return flashdatawrite(a, n, off); 
2000/1207    
	case Qfpart: 
		return flashdatawrite(c, a, n, off); 
2000/1117    
	} 
2000/1111    
	return n; 
} 
2000/1207/sys/src/9/bitsy/devflash.c:71,762000/1209/sys/src/9/bitsy/devflash.c:71,81 (short | long)
2000/1117    
	ulong		*wb;		/* staging area for write buffer */ 
} flash; 
2000/1111    
 
2000/1209    
enum 
{ 
	Maxwchunk=	1024,	/* maximum chunk written by one call to falg->write */ 
}; 
 
2000/1117    
/* 
 *  common flash interface 
 */ 
2000/1207/sys/src/9/bitsy/devflash.c:128,1342000/1209/sys/src/9/bitsy/devflash.c:133,139
2000/1117    
		addr += flash.r[q].size*flash.r[q].n; 
		flash.r[q].end = addr; 
	} 
	flash.wb = malloc(flash.wbsize); 
2000/1209    
	flash.wb = malloc(flash.wbsize>1024 ? flash.wbsize : 1024); 
2000/1117    
} 
 
2000/1111    
/* 
2000/1207/sys/src/9/bitsy/devflash.c:506,5122000/1209/sys/src/9/bitsy/devflash.c:511,520
2000/1117    
		m = blockend(off) - off; 
		if(m > end - p) 
			m = end - p; 
		(*flash.alg->write)(p, m, off); 
2000/1209    
		if(m > Maxwchunk) 
			m = Maxwchunk; 
		memmove(flash.wb, p, m); 
		(*flash.alg->write)(flash.wb, m, off); 
2000/1117    
		off += m; 
	} 
 
2000/1207/sys/src/9/bitsy/devflash.c:561,5672000/1209/sys/src/9/bitsy/devflash.c:569,590
2000/1111    
	devwstat, 
2000/1107    
}; 
2000/1117    
 
2000/1209    
enum 
{ 
	/* status register */ 
	ISEs_lockerr=		1<<1, 
	ISEs_powererr=		1<<3, 
	ISEs_progerr=		1<<4, 
	ISEs_eraseerr=		1<<5, 
	ISEs_ready=		1<<7, 
	ISEs_err= (ISEs_lockerr|ISEs_powererr|ISEs_progerr|ISEs_eraseerr), 
2000/1117    
 
2000/1209    
	/* extended status register */ 
	ISExs_bufavail=		1<<7, 
}; 
 
 
 
2000/1117    
/* intel/sharp extended command set */ 
static void 
ise_reset(void) 
2000/1207/sys/src/9/bitsy/devflash.c:588,6032000/1209/sys/src/9/bitsy/devflash.c:611,626
2000/1117    
{ 
	char err[ERRLEN]; 
 
	if(status & (1<<3)){ 
		sprint(err, "flash%d: low prog voltage", bank); 
2000/1209    
	if(status & (ISEs_lockerr)){ 
		sprint(err, "flash%d: block locked %lux", bank, status); 
2000/1117    
		error(err); 
	} 
	if(status & (1<<1)){ 
		sprint(err, "flash%d: block locked", bank); 
2000/1209    
	if(status & (ISEs_powererr)){ 
		sprint(err, "flash%d: low prog voltage %lux", bank, status); 
2000/1117    
		error(err); 
	} 
	if(status & (1<<5)){ 
		sprint(err, "flash%d: i/o error", bank); 
2000/1209    
	if(status & (ISEs_progerr|ISEs_eraseerr)){ 
		sprint(err, "flash%d: i/o error %lux", bank, status); 
2000/1117    
		error(err); 
	} 
} 
2000/1207/sys/src/9/bitsy/devflash.c:615,6212000/1209/sys/src/9/bitsy/devflash.c:638,644
2000/1117    
	start = m->ticks; 
	do { 
		x = flash.p[addr]; 
		if((x & mirror(1<<7)) == mirror(1<<7)) 
2000/1209    
		if((x & mirror(ISEs_ready)) == mirror(ISEs_ready)) 
2000/1117    
			break; 
	} while(TK2MS(m->ticks-start) < 1500); 
	flashprogpower(0); 
2000/1207/sys/src/9/bitsy/devflash.c:627,6332000/1209/sys/src/9/bitsy/devflash.c:650,656
2000/1117    
	ise_reset(); 
} 
/* 
 *  flash writing goes about 16 times faster if we use 
2000/1209    
 *  the flash spec claimes writing goes faster if we use 
2000/1117    
 *  the write buffer.  We fill the write buffer and then 
 *  issue the write request.  After the write request, 
 *  subsequent reads will yield the status register or, 
2000/1207/sys/src/9/bitsy/devflash.c:637,6802000/1209/sys/src/9/bitsy/devflash.c:660,719
2000/1117    
 *  On timeout, we issue a read status register request so 
 *  that the status register can be read no matter how we 
 *  exit. 
2000/1209    
 * 
 *  returns the status. 
2000/1117    
 */ 
static int 
ise_wbwrite(ulong *p, int n, ulong off) 
2000/1209    
static ulong 
ise_wbwrite(ulong *p, int n, ulong off, ulong baddr, ulong *status) 
2000/1117    
{ 
	ulong start; 
2000/1209    
	ulong x, start; 
2000/1117    
	int i; 
2000/1209    
	int s; 
2000/1117    
 
	/* copy out of user space to avoid faults later */ 
	memmove(flash.wb, p, n*4); 
	p = flash.wb; 
                 
	/* put flash into write buffer mode */ 
	start = m->ticks; 
	for(;;) { 
2000/1209    
		s = splhi(); 
2000/1117    
		/* request write buffer mode */ 
		flash.p[off] = mirror(0xe8); 
2000/1209    
		flash.p[baddr] = mirror(0xe8); 
2000/1117    
 
		/* look at extended status reg for status */ 
		if((flash.p[off] & mirror(1<<7)) == mirror(1<<7)) 
2000/1209    
		if((flash.p[baddr] & mirror(1<<7)) == mirror(1<<7)) 
2000/1117    
			break; 
2000/1209    
		splx(s); 
2000/1117    
 
		/* didn't work, keep trying for 2 secs */ 
		if(TK2MS(m->ticks-start) > 2000){ 
			/* set up to read status */ 
			flash.p[off] = mirror(0x70); 
2000/1209    
			flash.p[baddr] = mirror(0x70); 
			*status = flash.p[baddr]; 
			pprint("write buffered cmd timed out\n"); 
2000/1117    
			return -1; 
		} 
	} 
 
	/* fill write buffer */ 
	flash.p[off] = mirror(n-1); 
2000/1209    
	flash.p[baddr] = mirror(n-1); 
2000/1117    
	for(i = 0; i < n; i++) 
		flash.p[off+i] = *p++; 
 
	/* program from buffer */ 
	flash.p[off] = mirror(0xd0); 
2000/1209    
	flash.p[baddr] = mirror(0xd0); 
	splx(s); 
2000/1117    
 
	/* subsequent reads will return status about the write */ 
2000/1209    
	/* wait till the programming is done */ 
	start = m->ticks; 
	for(;;) { 
		x = *status = flash.p[baddr];	/* read status register */ 
		if((x & mirror(ISEs_ready)) == mirror(ISEs_ready)) 
			break; 
		if(TK2MS(m->ticks-start) > 2000){ 
			pprint("read status timed out\n"); 
			return -1; 
		} 
	} 
	if(x & mirror(ISEs_err)) 
		return -1; 
2000/1117    
 
	return n; 
} 
2000/1207/sys/src/9/bitsy/devflash.c:683,6962000/1209/sys/src/9/bitsy/devflash.c:722,736
2000/1117    
{ 
	ulong *p, *end; 
	int i, wbsize; 
	ulong x, start, ooff; 
2000/1209    
	ulong x, baddr; 
2000/1117    
 
	/* everything in terms of ulongs */ 
	wbsize = flash.wbsize>>2; 
2000/1209    
	baddr = blockstart(off); 
2000/1117    
	off >>= 2; 
	n >>= 2; 
	p = a; 
	ooff = off; 
2000/1209    
	baddr >>= 2; 
2000/1117    
 
	/* first see if write will succeed */ 
	for(i = 0; i < n; i++) 
2000/1207/sys/src/9/bitsy/devflash.c:715,7212000/1209/sys/src/9/bitsy/devflash.c:755,761
2000/1117    
		if(i > end - p) 
			i = end - p; 
 
		if(ise_wbwrite(p, i, off) != i) 
2000/1209    
		if(ise_wbwrite(p, i, off, baddr, &x) < 0) 
2000/1117    
			break; 
 
		off += i; 
2000/1207/sys/src/9/bitsy/devflash.c:722,7352000/1209/sys/src/9/bitsy/devflash.c:762,767
2000/1117    
		p += i; 
		i = wbsize; 
	} 
                 
	/* wait till the programming is done */ 
	start = m->ticks; 
	do { 
		x = flash.p[ooff]; 
		if((x & mirror(1<<7)) == mirror(1<<7)) 
			break; 
	} while(TK2MS(m->ticks-start) < 1000); 
 
	ise_clearerror(); 
	ise_error(0, x); 
2000/1209/sys/src/9/bitsy/devflash.c:653,6672000/1211/sys/src/9/bitsy/devflash.c:653,669 (short | long)
2000/1209    
 *  the flash spec claimes writing goes faster if we use 
2000/1117    
 *  the write buffer.  We fill the write buffer and then 
 *  issue the write request.  After the write request, 
 *  subsequent reads will yield the status register or, 
 *  since error bits are sticky, another write buffer can 
 *  be filled and written. 
2000/1211    
 *  subsequent reads will yield the status register. 
2000/1117    
 * 
 *  On timeout, we issue a read status register request so 
 *  that the status register can be read no matter how we 
 *  exit. 
2000/1211    
 *  returns the status, even on timeouts. 
2000/1209    
 * 
 *  returns the status. 
2000/1211    
 *  NOTE: I tried starting back to back buffered writes 
 *	without reading the status in between, as the 
 *	flowchart in the intel data sheet suggests. 
 *	However, it always responded with an illegal 
 *	command sequence, so I must be missing something. 
 *	If someone learns better, please email me, though 
 *	I doubt it will be much faster. -  presotto@bell-labs.com 
2000/1117    
 */ 
2000/1209    
static ulong 
ise_wbwrite(ulong *p, int n, ulong off, ulong baddr, ulong *status) 
2000/1211/sys/src/9/bitsy/devflash.c:68,742000/1213/sys/src/9/bitsy/devflash.c:68,73 (short | long)
2000/1117    
	ulong		nr;		/* number of regions */ 
	uchar		bootprotect; 
	FlashRegion	r[32]; 
	ulong		*wb;		/* staging area for write buffer */ 
} flash; 
2000/1111    
 
2000/1209    
enum 
2000/1211/sys/src/9/bitsy/devflash.c:133,1392000/1213/sys/src/9/bitsy/devflash.c:132,137
2000/1117    
		addr += flash.r[q].size*flash.r[q].n; 
		flash.r[q].end = addr; 
	} 
2000/1209    
	flash.wb = malloc(flash.wbsize>1024 ? flash.wbsize : 1024); 
2000/1117    
} 
 
2000/1111    
/* 
2000/1211/sys/src/9/bitsy/devflash.c:145,1512000/1213/sys/src/9/bitsy/devflash.c:143,149
2000/1207    
	Qtopdir, 
	Q2nddir, 
	Qfctl, 
	Qfpart, 
2000/1213    
	Qfdata, 
2000/1207    
 
	Maxpart= 8, 
2000/1111    
}; 
2000/1211/sys/src/9/bitsy/devflash.c:154,1602000/1213/sys/src/9/bitsy/devflash.c:152,158
2000/1207    
typedef struct FPart FPart; 
struct FPart 
{ 
	char	name[NAMELEN]; 
2000/1213    
	char	name[NAMELEN-4]; 
2000/1207    
	ulong	start; 
	ulong	end; 
2000/1111    
}; 
2000/1211/sys/src/9/bitsy/devflash.c:168,1742000/1213/sys/src/9/bitsy/devflash.c:166,172
2000/1207    
gen(Chan *c, Dirtab*, int, int i, Dir *dp) 
{ 
	Qid q; 
	char buf[32]; 
2000/1213    
	char buf[NAMELEN]; 
2000/1207    
	FPart *fp; 
 
	q.vers = 0; 
2000/1211/sys/src/9/bitsy/devflash.c:191,2152000/1213/sys/src/9/bitsy/devflash.c:189,214
2000/1207    
		return 1; 
	} 
 
	/* second level contains ctl plus all partitions */ 
2000/1213    
	/* second level contains all partitions and their control files */ 
2000/1207    
	switch(i) { 
	case DEVDOTDOT: 
		q.path = CHDIR; 
		devdir(c, q, "#F", 0, eve, CHDIR|0555, dp); 
		break; 
	case 0: 
		q.path = Qfctl; 
		devdir(c, q, "ctl", 0, eve, 0666, dp); 
		break; 
	default: 
		i -= 1; 
		if(i >= Maxpart) 
2000/1213    
		if(i >= 2*Maxpart) 
2000/1207    
			return -1; 
		fp = &part[i]; 
2000/1213    
		fp = &part[i>>1]; 
2000/1207    
		if(fp->name[0] == 0) 
			return 0; 
		q.path = FQID(i, Qfpart); 
		devdir(c, q, fp->name, fp->end-fp->start, eve, 0660, dp); 
2000/1213    
		if(i & 1){ 
			q.path = FQID(i>>1, Qfdata); 
			devdir(c, q, fp->name, fp->end-fp->start, eve, 0660, dp); 
		} else { 
			snprint(buf, sizeof(buf), "%sctl", fp->name); 
			q.path = FQID(i>>1, Qfctl); 
			devdir(c, q, buf, 0, eve, 0660, dp); 
		} 
2000/1207    
		break; 
	} 
	return 1; 
2000/1211/sys/src/9/bitsy/devflash.c:229,2452000/1213/sys/src/9/bitsy/devflash.c:228,253
2000/1207    
} 
 
static void 
addpart(char *name, ulong start, ulong end) 
2000/1213    
addpart(FPart *fp, char *name, ulong start, ulong end) 
2000/1207    
{ 
	int i; 
	FPart *fp; 
 
	if(start >= flash.size || end > flash.size) 
		error(Ebadarg); 
2000/1213    
	if(strlen(name) > NAMELEN-3) 
		error("name too long"); 
	if(fp == nil){ 
		if(start >= flash.size || end > flash.size) 
			error(Ebadarg); 
	} else { 
		start += fp->start; 
		end += fp->start; 
		if(start >= fp->end || end > fp->end) 
			error(Ebadarg); 
	} 
2000/1207    
	if(blockstart(start) != start) 
		error("must start on erase boundary"); 
	if(blockstart(end) != end && end != flash.size) 
		error("must end on erase boundary"); 
2000/1213    
 
2000/1207    
	fp = findpart(name); 
	if(fp != nil) 
		error(Eexist); 
2000/1211/sys/src/9/bitsy/devflash.c:255,2682000/1213/sys/src/9/bitsy/devflash.c:263,271
2000/1207    
} 
 
static void 
rempart(char *name) 
2000/1213    
rempart(FPart *fp) 
2000/1207    
{ 
	FPart *fp; 
                 
	/* can't remove the total partition */ 
	fp = findpart(name); 
	if(fp != nil) 
		fp->name[0] = 0; 
2000/1213    
	fp->name[0] = 0; 
2000/1207    
} 
 
2000/1111    
void 
2000/1211/sys/src/9/bitsy/devflash.c:280,2862000/1213/sys/src/9/bitsy/devflash.c:283,289
2000/1117    
		} 
	flash.bootprotect = 1; 
2000/1207    
 
	addpart("whole", 0, flash.size); 
2000/1213    
	addpart(nil, "flash", 0, flash.size); 
2000/1111    
} 
 
static Chan* 
2000/1211/sys/src/9/bitsy/devflash.c:315,3272000/1213/sys/src/9/bitsy/devflash.c:318,378
2000/1111    
{ 
} 
 
static long	  
flashread(Chan* c, void* a, long n, vlong off) 
2000/1213    
static long 
flashctlread(FPart *fp, void* a, long n, vlong off) 
2000/1111    
{ 
2000/1117    
	char *buf, *p, *e; 
	int i; 
2000/1207    
	FPart *fp; 
2000/1213    
	ulong addr, end; 
2000/1117    
 
2000/1213    
	buf = smalloc(1024); 
	e = buf + 1024; 
	p = seprint(buf, e, "0x%-9lux 0x%-9lux 0x%-9lux 0x%-9lux\n", fp->end-fp->start, 
		flash.wbsize, flash.manid, flash.devid); 
	addr = fp->start; 
	for(i = 0; i < flash.nr && addr < fp->end; i++) 
		if(flash.r[i].addr <= addr && flash.r[i].end > addr){ 
			if(fp->end <= flash.r[i].end) 
				end = fp->end; 
			else 
				end = flash.r[i].end; 
			p = seprint(p, e, "0x%-9lux 0x%-9lux 0x%-9lux\n", addr, 
				(end-addr)/flash.r[i].size, flash.r[i].size); 
			addr = end; 
		} 
	n = readstr(off, a, n, buf); 
	free(buf); 
	return n; 
} 
 
static long 
flashdataread(FPart *fp, void* a, long n, vlong off) 
{ 
	rlock(&flash); 
	if(waserror()){ 
		runlock(&flash); 
		nexterror(); 
	} 
	if(fp->name[0] == 0) 
		error("partition vanished"); 
	if(!iseve()) 
		error(Eperm); 
	off += fp->start; 
	if(off >= fp->end) 
		n = 0; 
	if(off+n >= fp->end) 
		n = fp->end - off; 
	if(n > 0) 
		memmove(a, ((uchar*)FLASHZERO)+off, n); 
	runlock(&flash); 
	poperror(); 
 
	return n; 
} 
 
static long	  
flashread(Chan* c, void* a, long n, vlong off) 
{ 
2000/1117    
	if(c->qid.path&CHDIR) 
2000/1207    
		return devdirread(c, a, n, nil, 0, gen); 
	switch(FTYPE(c->qid.path)){ 
2000/1211/sys/src/9/bitsy/devflash.c:328,3632000/1213/sys/src/9/bitsy/devflash.c:379,388
2000/1117    
	default: 
		error(Eperm); 
	case Qfctl: 
		buf = smalloc(1024); 
		e = buf + 1024; 
		p = seprint(buf, e, "0x%-9lux 0x%-9lux 0x%-9lux 0x%-9lux\n", flash.size, 
			flash.wbsize, flash.manid, flash.devid); 
		for(i = 0; i < flash.nr; i++) 
			p = seprint(p, e, "0x%-9lux 0x%-9lux 0x%-9lux\n", flash.r[i].addr, 
				flash.r[i].n, flash.r[i].size); 
		n = readstr(off, a, n, buf); 
		free(buf); 
2000/1213    
		n = flashctlread(FPART(c->qid.path), a, n, off); 
2000/1117    
		break; 
2000/1207    
	case Qfpart: 
		fp = FPART(c->qid.path); 
2000/1117    
		rlock(&flash); 
		if(waserror()){ 
			runlock(&flash); 
			nexterror(); 
		} 
2000/1207    
		if(fp->name[0] == 0) 
			error("partition vanished"); 
		if(!iseve()) 
			error(Eperm); 
		off += fp->start; 
		if(off >= fp->end) 
			n = 0; 
		if(off+n >= fp->end) 
			n = fp->end - off; 
		if(n > 0) 
			memmove(a, ((uchar*)FLASHZERO)+off, n); 
2000/1117    
		runlock(&flash); 
		poperror(); 
2000/1213    
	case Qfdata: 
		n = flashdataread(FPART(c->qid.path), a, n, off); 
2000/1117    
		break; 
	} 
2000/1111    
	return n; 
2000/1211/sys/src/9/bitsy/devflash.c:412,4232000/1213/sys/src/9/bitsy/devflash.c:437,450
2000/1117    
} 
 
static long 
flashctlwrite(char *p, long n) 
2000/1213    
flashctlwrite(FPart *fp, char *p, long n) 
2000/1117    
{ 
	Cmdbuf *cmd; 
2000/1207    
	ulong off; 
	FPart *fp; 
2000/1117    
 
2000/1213    
	if(fp == nil) 
		panic("flashctlwrite"); 
 
2000/1117    
	cmd = parsecmd(p, n); 
	wlock(&flash); 
	if(waserror()){ 
2000/1211/sys/src/9/bitsy/devflash.c:425,4402000/1213/sys/src/9/bitsy/devflash.c:452,461
2000/1117    
		nexterror(); 
	} 
	if(strcmp(cmd->f[0], "erase") == 0){ 
2000/1207    
		if(cmd->nf < 2) 
			error(Ebadarg); 
		fp = findpart(cmd->f[1]); 
		if(fp == nil) 
			error("no such partition"); 
                 
		switch(cmd->nf){ 
		case 3: 
			/* erase a single block */ 
			off = atoi(cmd->f[2]); 
2000/1213    
		case 2: 
			/* erase a single block in the partition */ 
			off = atoi(cmd->f[1]); 
2000/1207    
			off += fp->start; 
			if(off >= fp->end) 
				error("region not in partition"); 
2000/1211/sys/src/9/bitsy/devflash.c:443,4492000/1213/sys/src/9/bitsy/devflash.c:464,470
2000/1207    
			bootprotect(off); 
			(*flash.alg->erase)(off); 
			break; 
		case 2: 
2000/1213    
		case 1: 
2000/1207    
			/* erase the whole partition */ 
			bootprotect(fp->start); 
			for(off = fp->start; off < fp->end; off = blockend(off)) 
2000/1211/sys/src/9/bitsy/devflash.c:455,4652000/1213/sys/src/9/bitsy/devflash.c:476,484
2000/1207    
	} else if(strcmp(cmd->f[0], "add") == 0){ 
		if(cmd->nf != 4) 
			error(Ebadarg); 
		addpart(cmd->f[1], strtoul(cmd->f[2], nil, 0), strtoul(cmd->f[3], nil, 0)); 
2000/1213    
		addpart(fp, cmd->f[1], strtoul(cmd->f[2], nil, 0), strtoul(cmd->f[3], nil, 0)); 
2000/1207    
	} else if(strcmp(cmd->f[0], "remove") == 0){ 
2000/1117    
		if(cmd->nf != 2) 
			error(Ebadarg); 
2000/1207    
		rempart(cmd->f[1]); 
2000/1213    
		rempart(fp); 
2000/1117    
	} else if(strcmp(cmd->f[0], "protectboot") == 0){ 
		if(cmd->nf == 0 || strcmp(cmd->f[1], "off") != 0) 
			flash.bootprotect = 1; 
2000/1211/sys/src/9/bitsy/devflash.c:475,4932000/1213/sys/src/9/bitsy/devflash.c:494,516
2000/1117    
} 
 
static long 
2000/1207    
flashdatawrite(Chan *c, uchar *p, long n, long off) 
2000/1213    
flashdatawrite(FPart *fp, uchar *p, long n, long off) 
2000/1117    
{ 
	uchar *end; 
	int m; 
2000/1213    
	int on; 
2000/1207    
	long ooff; 
2000/1117    
	uchar *op = p; 
2000/1207    
	FPart *fp; 
2000/1213    
	uchar *buf; 
2000/1117    
 
2000/1207    
	fp = FPART(c->qid.path); 
2000/1213    
	if(fp == nil) 
		panic("flashctlwrite"); 
2000/1117    
 
2000/1213    
	buf = nil; 
2000/1117    
	wlock(&flash); 
	if(waserror()){ 
		wunlock(&flash); 
2000/1213    
		if(buf != nil) 
			free(buf); 
2000/1117    
		nexterror(); 
	} 
 
2000/1211/sys/src/9/bitsy/devflash.c:496,5032000/1213/sys/src/9/bitsy/devflash.c:519,525
2000/1207    
	if(!iseve()) 
		error(Eperm); 
 
	if((off & 0x3) || (n & 0x3)) 
		error("only quad writes"); 
2000/1213    
	/* can't cross partition boundaries */ 
2000/1207    
	off += fp->start; 
	if(off >= fp->end || off+n > fp->end || n <= 0) 
		error(Ebadarg); 
2000/1211/sys/src/9/bitsy/devflash.c:505,5122000/1213/sys/src/9/bitsy/devflash.c:527,556
2000/1117    
	/* make sure we're not writing the boot sector */ 
	bootprotect(off); 
 
2000/1213    
	on = n; 
 
	/* 
	 *  get the data into kernel memory to avoid faults during writing. 
	 *  if write is not on a quad boundary or not a multiple of 4 bytes, 
	 *  extend with data already in flash. 
	 */ 
	buf = smalloc(n+8); 
	m = off & 3; 
	if(m){ 
		*(ulong*)buf = flash.p[(off)>>2]; 
		n += m; 
		off -= m; 
	} 
	if(n & 3){ 
		n -= n & 3; 
		*(ulong*)(&buf[n]) = flash.p[(off+n)>>2]; 
		n += 4; 
	} 
	memmove(&buf[m], p, on); 
 
2000/1117    
	/* (*flash.alg->write) can't cross blocks */ 
2000/1207    
	ooff = off; 
2000/1213    
	p = buf; 
2000/1117    
	for(end = p + n; p < end; p += m){ 
		m = blockend(off) - off; 
		if(m > end - p) 
2000/1211/sys/src/9/bitsy/devflash.c:513,5312000/1213/sys/src/9/bitsy/devflash.c:557,575
2000/1117    
			m = end - p; 
2000/1209    
		if(m > Maxwchunk) 
			m = Maxwchunk; 
		memmove(flash.wb, p, m); 
		(*flash.alg->write)(flash.wb, m, off); 
2000/1213    
		(*flash.alg->write)(p, m, off); 
2000/1117    
		off += m; 
	} 
 
	/* make sure write succeeded */ 
	if(memcmp(op, &flash.p[ooff>>2], n) != 0) 
2000/1213    
	if(memcmp(buf, &flash.p[ooff>>2], n) != 0) 
2000/1117    
		error("written bytes don't match"); 
 
	wunlock(&flash); 
2000/1213    
	free(buf); 
2000/1117    
	poperror(); 
 
	return n; 
2000/1213    
	return on; 
2000/1117    
} 
 
2000/1111    
static long	  
2000/1211/sys/src/9/bitsy/devflash.c:541,5492000/1213/sys/src/9/bitsy/devflash.c:585,595
2000/1117    
	default: 
		panic("flashwrite"); 
	case Qfctl: 
		return flashctlwrite(a, n); 
2000/1207    
	case Qfpart: 
		return flashdatawrite(c, a, n, off); 
2000/1213    
		n = flashctlwrite(FPART(c->qid.path), a, n); 
		break; 
	case Qfdata: 
		n = flashdatawrite(FPART(c->qid.path), a, n, off); 
		break; 
2000/1117    
	} 
2000/1111    
	return n; 
} 
2000/1213/sys/src/9/bitsy/devflash.c:152,1582001/0529/sys/src/9/bitsy/devflash.c:152,158 (short | long)
2000/1207    
typedef struct FPart FPart; 
struct FPart 
{ 
2000/1213    
	char	name[NAMELEN-4]; 
2001/0529    
	char	*name; 
2000/1207    
	ulong	start; 
	ulong	end; 
2000/1111    
}; 
2000/1213/sys/src/9/bitsy/devflash.c:163,1872001/0529/sys/src/9/bitsy/devflash.c:163,188
2000/1207    
#define FPART(q)	(&part[(q) >>8]) 
 
static int 
gen(Chan *c, Dirtab*, int, int i, Dir *dp) 
2001/0529    
gen(Chan *c, char*, Dirtab*, int, int i, Dir *dp) 
2000/1207    
{ 
	Qid q; 
2000/1213    
	char buf[NAMELEN]; 
2001/0529    
	char buf[KNAMELEN]; 
2000/1207    
	FPart *fp; 
 
	q.vers = 0; 
 
	/* top level directory contains the name of the network */ 
	if(c->qid.path == CHDIR){ 
2001/0529    
	if(c->qid.path == Qtopdir){ 
2000/1207    
		switch(i){ 
		case DEVDOTDOT: 
			q.path = CHDIR; 
			devdir(c, q, ".", 0, eve, CHDIR|0555, dp); 
2001/0529    
			q.path = Qtopdir; 
			q.type = QTDIR; 
			devdir(c, q, "#F", 0, eve, DMDIR|0555, dp); 
2000/1207    
			break; 
		case 0: 
			q.path = CHDIR | Q2nddir; 
			strcpy(buf, "flash"); 
			devdir(c, q, buf, 0, eve, CHDIR|0555, dp); 
2001/0529    
			q.path = Q2nddir; 
			q.type = QTDIR; 
			devdir(c, q, "flash", 0, eve, DMDIR|0555, dp); 
2000/1207    
			break; 
		default: 
			return -1; 
2000/1213/sys/src/9/bitsy/devflash.c:192,2122001/0529/sys/src/9/bitsy/devflash.c:193,216
2000/1213    
	/* second level contains all partitions and their control files */ 
2000/1207    
	switch(i) { 
	case DEVDOTDOT: 
		q.path = CHDIR; 
		devdir(c, q, "#F", 0, eve, CHDIR|0555, dp); 
2001/0529    
		q.path = Qtopdir; 
		q.type = QTDIR; 
		devdir(c, q, "#F", 0, eve, DMDIR|0555, dp); 
2000/1207    
		break; 
	default: 
2000/1213    
		if(i >= 2*Maxpart) 
2000/1207    
			return -1; 
2000/1213    
		fp = &part[i>>1]; 
2000/1207    
		if(fp->name[0] == 0) 
2001/0529    
		if(fp->name == nil) 
2000/1207    
			return 0; 
2000/1213    
		if(i & 1){ 
			q.path = FQID(i>>1, Qfdata); 
2001/0529    
			q.type = QTFILE; 
2000/1213    
			devdir(c, q, fp->name, fp->end-fp->start, eve, 0660, dp); 
		} else { 
			snprint(buf, sizeof(buf), "%sctl", fp->name); 
			q.path = FQID(i>>1, Qfctl); 
2001/0529    
			q.type = QTFILE; 
2000/1213    
			devdir(c, q, buf, 0, eve, 0660, dp); 
		} 
2000/1207    
		break; 
2000/1213/sys/src/9/bitsy/devflash.c:232,2392001/0529/sys/src/9/bitsy/devflash.c:236,241
2000/1207    
{ 
	int i; 
 
2000/1213    
	if(strlen(name) > NAMELEN-3) 
		error("name too long"); 
	if(fp == nil){ 
		if(start >= flash.size || end > flash.size) 
			error(Ebadarg); 
2000/1213/sys/src/9/bitsy/devflash.c:257,2632001/0529/sys/src/9/bitsy/devflash.c:259,265
2000/1207    
	if(i == Maxpart) 
		error("no more partitions"); 
	fp = &part[i]; 
	strncpy(fp->name, name, sizeof(fp->name)-1); 
2001/0529    
	kstrdup(&fp->name, name); 
2000/1207    
	fp->start = start; 
	fp->end = end; 
} 
2000/1213/sys/src/9/bitsy/devflash.c:265,2712001/0529/sys/src/9/bitsy/devflash.c:267,277
2000/1207    
static void 
2000/1213    
rempart(FPart *fp) 
2000/1207    
{ 
2000/1213    
	fp->name[0] = 0; 
2001/0529    
	char *p; 
 
	p = fp->name; 
	fp->name = nil; 
	free(p); 
2000/1207    
} 
 
2000/1111    
void 
2000/1213/sys/src/9/bitsy/devflash.c:292,3072001/0529/sys/src/9/bitsy/devflash.c:298,313
2000/1117    
	return devattach('F', spec); 
2000/1111    
} 
 
static int	  
flashwalk(Chan* c, char* name) 
2001/0529    
static Walkqid* 
flashwalk(Chan *c, Chan *nc, char **name, int nname) 
2000/1111    
{ 
2000/1207    
	return devwalk(c, name, nil, 0, gen); 
2001/0529    
	return devwalk(c, nc, name, nname, nil, 0, gen); 
2000/1111    
} 
 
static void	  
flashstat(Chan* c, char* dp) 
2001/0529    
static int	  
flashstat(Chan *c, uchar *db, int n) 
2000/1111    
{ 
2000/1207    
	devstat(c, dp, nil, 0, gen); 
2001/0529    
	return devstat(c, db, n, nil, 0, gen); 
2000/1111    
} 
 
static Chan* 
2000/1213/sys/src/9/bitsy/devflash.c:353,3592001/0529/sys/src/9/bitsy/devflash.c:359,365
2000/1213    
		runlock(&flash); 
		nexterror(); 
	} 
	if(fp->name[0] == 0) 
2001/0529    
	if(fp->name == nil) 
2000/1213    
		error("partition vanished"); 
	if(!iseve()) 
		error(Eperm); 
2000/1213/sys/src/9/bitsy/devflash.c:373,3812001/0529/sys/src/9/bitsy/devflash.c:379,390
2000/1213    
static long	  
flashread(Chan* c, void* a, long n, vlong off) 
{ 
2000/1117    
	if(c->qid.path&CHDIR) 
2001/0529    
	int t; 
 
	if(c->qid.type == QTDIR) 
2000/1207    
		return devdirread(c, a, n, nil, 0, gen); 
	switch(FTYPE(c->qid.path)){ 
2001/0529    
	t = FTYPE(c->qid.path); 
	switch(t){ 
2000/1117    
	default: 
		error(Eperm); 
	case Qfctl: 
2000/1213/sys/src/9/bitsy/devflash.c:514,5202001/0529/sys/src/9/bitsy/devflash.c:523,529
2000/1117    
		nexterror(); 
	} 
 
2000/1207    
	if(fp->name[0] == 0) 
2001/0529    
	if(fp->name == nil) 
2000/1207    
		error("partition vanished"); 
	if(!iseve()) 
		error(Eperm); 
2000/1213/sys/src/9/bitsy/devflash.c:575,5872001/0529/sys/src/9/bitsy/devflash.c:584,599
2000/1111    
static long	  
2000/1117    
flashwrite(Chan* c, void* a, long n, vlong off) 
2000/1111    
{ 
2000/1117    
	if(c->qid.path & CHDIR) 
2001/0529    
	int t; 
 
	if(c->qid.type == QTDIR) 
2000/1117    
		error(Eperm); 
 
	if(!iseve()) 
		error(Eperm); 
 
2000/1207    
	switch(FTYPE(c->qid.path)){ 
2001/0529    
	t = FTYPE(c->qid.path); 
	switch(t){ 
2000/1117    
	default: 
		panic("flashwrite"); 
	case Qfctl: 
2000/1213/sys/src/9/bitsy/devflash.c:601,6072001/0529/sys/src/9/bitsy/devflash.c:613,618
2000/1111    
	devreset, 
	flashinit, 
	flashattach, 
	devclone, 
	flashwalk, 
	flashstat, 
	flashopen, 
2000/1213/sys/src/9/bitsy/devflash.c:655,6612001/0529/sys/src/9/bitsy/devflash.c:666,672
2000/1117    
static void 
ise_error(int bank, ulong status) 
{ 
	char err[ERRLEN]; 
2001/0529    
	char err[64]; 
2000/1117    
 
2000/1209    
	if(status & (ISEs_lockerr)){ 
		sprint(err, "flash%d: block locked %lux", bank, status); 
2001/0529/sys/src/9/bitsy/devflash.c:224,2302001/0605/sys/src/9/bitsy/devflash.c:224,230 (short | long)
2000/1207    
	int i; 
 
	for(i = 0; i < Maxpart; i++) 
		if(strcmp(name, part[i].name) == 0) 
2001/0605    
		if(part[i].name != nil && strcmp(name, part[i].name) == 0) 
2000/1207    
			break; 
	if(i >= Maxpart) 
		return nil; 
2001/0529/sys/src/9/bitsy/devflash.c:254,2602001/0605/sys/src/9/bitsy/devflash.c:254,260
2000/1207    
	if(fp != nil) 
		error(Eexist); 
	for(i = 0; i < Maxpart; i++) 
		if(part[i].name[0] == 0) 
2001/0605    
		if(part[i].name == nil) 
2000/1207    
			break; 
	if(i == Maxpart) 
		error("no more partitions"); 
2001/0605/sys/src/9/bitsy/devflash.c:153,1582001/0614/sys/src/9/bitsy/devflash.c:153,159 (short | long)
2000/1207    
struct FPart 
{ 
2001/0529    
	char	*name; 
2001/0614    
	char	*ctlname; 
2000/1207    
	ulong	start; 
	ulong	end; 
2000/1111    
}; 
2001/0605/sys/src/9/bitsy/devflash.c:166,1722001/0614/sys/src/9/bitsy/devflash.c:167,172
2001/0529    
gen(Chan *c, char*, Dirtab*, int, int i, Dir *dp) 
2000/1207    
{ 
	Qid q; 
2001/0529    
	char buf[KNAMELEN]; 
2000/1207    
	FPart *fp; 
 
	q.vers = 0; 
2001/0605/sys/src/9/bitsy/devflash.c:208,2172001/0614/sys/src/9/bitsy/devflash.c:208,216
2001/0529    
			q.type = QTFILE; 
2000/1213    
			devdir(c, q, fp->name, fp->end-fp->start, eve, 0660, dp); 
		} else { 
			snprint(buf, sizeof(buf), "%sctl", fp->name); 
			q.path = FQID(i>>1, Qfctl); 
2001/0529    
			q.type = QTFILE; 
2000/1213    
			devdir(c, q, buf, 0, eve, 0660, dp); 
2001/0614    
			devdir(c, q, fp->ctlname, 0, eve, 0660, dp); 
2000/1213    
		} 
2000/1207    
		break; 
	} 
2001/0605/sys/src/9/bitsy/devflash.c:235,2402001/0614/sys/src/9/bitsy/devflash.c:234,240
2000/1213    
addpart(FPart *fp, char *name, ulong start, ulong end) 
2000/1207    
{ 
	int i; 
2001/0614    
	char ctlname[64]; 
2000/1207    
 
2000/1213    
	if(fp == nil){ 
		if(start >= flash.size || end > flash.size) 
2001/0605/sys/src/9/bitsy/devflash.c:260,2652001/0614/sys/src/9/bitsy/devflash.c:260,267
2000/1207    
		error("no more partitions"); 
	fp = &part[i]; 
2001/0529    
	kstrdup(&fp->name, name); 
2001/0614    
	snprint(ctlname, sizeof ctlname, "%sctl", name); 
	kstrdup(&fp->ctlname, ctlname); 
2000/1207    
	fp->start = start; 
	fp->end = end; 
} 
2001/0605/sys/src/9/bitsy/devflash.c:267,2772001/0614/sys/src/9/bitsy/devflash.c:269,282
2000/1207    
static void 
2000/1213    
rempart(FPart *fp) 
2000/1207    
{ 
2001/0529    
	char *p; 
2001/0614    
	char *p, *cp; 
2001/0529    
 
	p = fp->name; 
	fp->name = nil; 
2001/0614    
	cp = fp->ctlname; 
	fp->ctlname = nil; 
2001/0529    
	free(p); 
2001/0614    
	free(cp); 
2000/1207    
} 
 
2000/1111    
void 
2001/0614/sys/src/9/bitsy/devflash.c:617,6222002/0109/sys/src/9/bitsy/devflash.c:617,623 (short | long)
2000/1111    
 
	devreset, 
	flashinit, 
2002/0109    
	devshutdown, 
2000/1111    
	flashattach, 
	flashwalk, 
	flashstat, 
2002/0109/sys/src/9/bitsy/devflash.c:338,3442002/0404/sys/src/9/bitsy/devflash.c:338,344 (short | long)
2000/1117    
 
2000/1213    
	buf = smalloc(1024); 
	e = buf + 1024; 
	p = seprint(buf, e, "0x%-9lux 0x%-9lux 0x%-9lux 0x%-9lux\n", fp->end-fp->start, 
2002/0404    
	p = seprint(buf, e, "0x%-9lux 0x%-9x 0x%-9ux 0x%-9ux\n", fp->end-fp->start, 
2000/1213    
		flash.wbsize, flash.manid, flash.devid); 
	addr = fp->start; 
	for(i = 0; i < flash.nr && addr < fp->end; i++) 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)