| plan 9 kernel history: overview | file list | diff list |
bitsy/devflash.c (diff list | history)
| 2000/1031/sys/src/9/bitsy/devflash.c:15,17 – 2000/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,42 – 2000/1111/sys/src/9/bitsy/devflash.c:30,35 (short | long) | ||
| 2000/1107 | /* * common flash memory interface */ | |
| 2000/1107/sys/src/9/bitsy/devflash.c:70,74 – 2000/1111/sys/src/9/bitsy/devflash.c:63,185 | ||
| 2000/1107 | struct CFIgeom { 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 */ }; #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,23 – 2000/1117/sys/src/9/bitsy/devflash.c:6,11 (short | long) | ||
| 2000/1031 | #include "io.h" #include "../port/error.h" | |
| 2000/1107 |
| |
| 2000/1111/sys/src/9/bitsy/devflash.c:27,94 – 2000/1117/sys/src/9/bitsy/devflash.c:15,133 | ||
| 2000/1107 | * sectors for each request erase request. */ | |
| 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 | { | |
| 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 | }; | |
| 2000/1117 | /* this defines a particular access algorithm */ typedef struct FlashAlg FlashAlg; struct FlashAlg | |
| 2000/1107 | { | |
| 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 | }; | |
| 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 | { | |
| 2000/1111 |
| |
| 2000/1117 | { 1, "Intel/Sharp Extended", ise_id, ise_erase, ise_write }, { 2, "AMD/Fujitsu Standard", afs_id, afs_erase, afs_write }, | |
| 2000/1111 | }; | |
| 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 |
| |
| 2000/1117 | /* * common flash interface */ static uchar cfigetc(int off) | |
| 2000/1111 | { | |
| 2000/1117 | uchar rv; | |
| 2000/1111 |
| |
| 2000/1117 | flash.p[0x55] = mirror(0x98); rv = flash.p[off]; flash.p[0x55] = mirror(0xFF); return rv; | |
| 2000/1111 | } | |
| 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,124 – 2000/1117/sys/src/9/bitsy/devflash.c:134,168 | ||
| 2000/1111 | enum { | |
| 2000/1117 | Qfctl=1, Qfdata, | |
| 2000/1111 | }; Dirtab flashdir[]={ | |
| 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(); | |
| 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) { | |
| 2000/1117 | return devattach('F', spec); | |
| 2000/1111 | } static int | |
| 2000/1111/sys/src/9/bitsy/devflash.c:150,165 – 2000/1117/sys/src/9/bitsy/devflash.c:194,378 | ||
| 2000/1111 | static long flashread(Chan* c, void* a, long n, vlong off) { | |
| 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 | |
| 2000/1117 | flashwrite(Chan* c, void* a, long n, vlong off) | |
| 2000/1111 | { | |
| 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,185 – 2000/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,51 – 2000/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,148 – 2000/1207/sys/src/9/bitsy/devflash.c:137,265 | ||
| 2000/1111 | enum { | |
| 2000/1117 |
| |
| 2000/1207 | Qtopdir, Q2nddir, Qfctl, Qfpart, Maxpart= 8, | |
| 2000/1111 | }; | |
| 2000/1117 |
| |
| 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,162 – 2000/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,180 – 2000/1207/sys/src/9/bitsy/devflash.c:287,299 | ||
| 2000/1111 | static int flashwalk(Chan* c, char* name) { | |
| 2000/1207 | return devwalk(c, name, nil, 0, gen); | |
| 2000/1111 | } static void flashstat(Chan* c, char* dp) { | |
| 2000/1207 | devstat(c, dp, nil, 0, gen); | |
| 2000/1111 | } static Chan* | |
| 2000/1117/sys/src/9/bitsy/devflash.c:183,189 – 2000/1207/sys/src/9/bitsy/devflash.c:302,308 | ||
| 2000/1111 | omode = openmode(omode); if(strcmp(up->user, eve)!=0) error(Eperm); | |
| 2000/1207 | return devopen(c, omode, nil, 0, gen); | |
| 2000/1111 | } static void | |
| 2000/1117/sys/src/9/bitsy/devflash.c:196,205 – 2000/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) | |
| 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,231 – 2000/1207/sys/src/9/bitsy/devflash.c:333,356 | ||
| 2000/1117 | n = readstr(off, a, n, buf); free(buf); 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(); break; | |
| 2000/1117/sys/src/9/bitsy/devflash.c:247,253 – 2000/1207/sys/src/9/bitsy/devflash.c:372,378 | ||
| 2000/1117 | error("writing over boot loader disallowed"); } | |
| 2000/1207 | static ulong | |
| 2000/1117 | blockstart(ulong addr) { FlashRegion *r, *e; | |
| 2000/1117/sys/src/9/bitsy/devflash.c:264,270 – 2000/1207/sys/src/9/bitsy/devflash.c:389,395 | ||
| 2000/1117 | return (ulong)-1; } | |
| 2000/1207 | static ulong | |
| 2000/1117 | blockend(ulong addr) { FlashRegion *r, *e; | |
| 2000/1117/sys/src/9/bitsy/devflash.c:285,291 – 2000/1207/sys/src/9/bitsy/devflash.c:410,417 | ||
| 2000/1117 | flashctlwrite(char *p, long n) { Cmdbuf *cmd; | |
| 2000/1207 | ulong off; FPart *fp; | |
| 2000/1117 | cmd = parsecmd(p, n); wlock(&flash); | |
| 2000/1117/sys/src/9/bitsy/devflash.c:294,306 – 2000/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); | |
| 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,332 – 2000/1207/sys/src/9/bitsy/devflash.c:470,484 | ||
| 2000/1117 | } static long | |
| 2000/1207 | flashdatawrite(Chan *c, uchar *p, long n, long off) | |
| 2000/1117 | { uchar *end; int m; | |
| 2000/1207 | long ooff; | |
| 2000/1117 | uchar *op = p; | |
| 2000/1207 | FPart *fp; | |
| 2000/1117 |
| |
| 2000/1207 | fp = FPART(c->qid.path); | |
| 2000/1117 | wlock(&flash); if(waserror()){ | |
| 2000/1117/sys/src/9/bitsy/devflash.c:334,343 – 2000/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,377 – 2000/1207/sys/src/9/bitsy/devflash.c:529,541 | ||
| 2000/1117 | if(!iseve()) error(Eperm); | |
| 2000/1207 | switch(FTYPE(c->qid.path)){ | |
| 2000/1117 | default: panic("flashwrite"); case Qfctl: return flashctlwrite(a, n); | |
| 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,76 – 2000/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,134 – 2000/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; } | |
| 2000/1209 | flash.wb = malloc(flash.wbsize>1024 ? flash.wbsize : 1024); | |
| 2000/1117 | } | |
| 2000/1111 | /* | |
| 2000/1207/sys/src/9/bitsy/devflash.c:506,512 – 2000/1209/sys/src/9/bitsy/devflash.c:511,520 | ||
| 2000/1117 | m = blockend(off) - off; if(m > end - p) m = end - p; | |
| 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,567 – 2000/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,603 – 2000/1209/sys/src/9/bitsy/devflash.c:611,626 | ||
| 2000/1117 | { char err[ERRLEN]; | |
| 2000/1209 | if(status & (ISEs_lockerr)){ sprint(err, "flash%d: block locked %lux", bank, status); | |
| 2000/1117 | error(err); } | |
| 2000/1209 | if(status & (ISEs_powererr)){ sprint(err, "flash%d: low prog voltage %lux", bank, status); | |
| 2000/1117 | error(err); } | |
| 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,621 – 2000/1209/sys/src/9/bitsy/devflash.c:638,644 | ||
| 2000/1117 | start = m->ticks; do { x = flash.p[addr]; | |
| 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,633 – 2000/1209/sys/src/9/bitsy/devflash.c:650,656 | ||
| 2000/1117 | ise_reset(); } /* | |
| 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,680 – 2000/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 | */ | |
| 2000/1209 | static ulong ise_wbwrite(ulong *p, int n, ulong off, ulong baddr, ulong *status) | |
| 2000/1117 | { | |
| 2000/1209 | ulong x, start; | |
| 2000/1117 | int i; | |
| 2000/1209 | int s; | |
| 2000/1117 |
| |
| 2000/1209 | s = splhi(); | |
| 2000/1117 | /* request write buffer mode */ | |
| 2000/1209 | flash.p[baddr] = mirror(0xe8); | |
| 2000/1117 | /* look at extended status reg for status */ | |
| 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 */ | |
| 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 */ | |
| 2000/1209 | flash.p[baddr] = mirror(n-1); | |
| 2000/1117 | for(i = 0; i < n; i++) flash.p[off+i] = *p++; /* program from buffer */ | |
| 2000/1209 | flash.p[baddr] = mirror(0xd0); splx(s); | |
| 2000/1117 |
| |
| 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,696 – 2000/1209/sys/src/9/bitsy/devflash.c:722,736 | ||
| 2000/1117 | { ulong *p, *end; int i, wbsize; | |
| 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; | |
| 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,721 – 2000/1209/sys/src/9/bitsy/devflash.c:755,761 | ||
| 2000/1117 | if(i > end - p) i = end - p; | |
| 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,735 – 2000/1209/sys/src/9/bitsy/devflash.c:762,767 | ||
| 2000/1117 | p += i; i = wbsize; } | |
| 2000/1209/sys/src/9/bitsy/devflash.c:653,667 – 2000/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, | |
| 2000/1211 | * subsequent reads will yield the status register. | |
| 2000/1117 | * | |
| 2000/1211 | * returns the status, even on timeouts. | |
| 2000/1209 | * | |
| 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,74 – 2000/1213/sys/src/9/bitsy/devflash.c:68,73 (short | long) | ||
| 2000/1117 | ulong nr; /* number of regions */ uchar bootprotect; FlashRegion r[32]; | |
| 2000/1111 | ||
| 2000/1209 | enum | |
| 2000/1211/sys/src/9/bitsy/devflash.c:133,139 – 2000/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 |
| |
| 2000/1117 | } | |
| 2000/1111 | /* | |
| 2000/1211/sys/src/9/bitsy/devflash.c:145,151 – 2000/1213/sys/src/9/bitsy/devflash.c:143,149 | ||
| 2000/1207 | Qtopdir, Q2nddir, Qfctl, | |
| 2000/1213 | Qfdata, | |
| 2000/1207 | Maxpart= 8, | |
| 2000/1111 | }; | |
| 2000/1211/sys/src/9/bitsy/devflash.c:154,160 – 2000/1213/sys/src/9/bitsy/devflash.c:152,158 | ||
| 2000/1207 | typedef struct FPart FPart; struct FPart { | |
| 2000/1213 | char name[NAMELEN-4]; | |
| 2000/1207 | ulong start; ulong end; | |
| 2000/1111 | }; | |
| 2000/1211/sys/src/9/bitsy/devflash.c:168,174 – 2000/1213/sys/src/9/bitsy/devflash.c:166,172 | ||
| 2000/1207 | gen(Chan *c, Dirtab*, int, int i, Dir *dp) { Qid q; | |
| 2000/1213 | char buf[NAMELEN]; | |
| 2000/1207 | FPart *fp; q.vers = 0; | |
| 2000/1211/sys/src/9/bitsy/devflash.c:191,215 – 2000/1213/sys/src/9/bitsy/devflash.c:189,214 | ||
| 2000/1207 | return 1; } | |
| 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; | |
| 2000/1213 | if(i >= 2*Maxpart) | |
| 2000/1207 | return -1; | |
| 2000/1213 | fp = &part[i>>1]; | |
| 2000/1207 | if(fp->name[0] == 0) return 0; | |
| 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,245 – 2000/1213/sys/src/9/bitsy/devflash.c:228,253 | ||
| 2000/1207 | } static void | |
| 2000/1213 | addpart(FPart *fp, char *name, ulong start, ulong end) | |
| 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); } 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,268 – 2000/1213/sys/src/9/bitsy/devflash.c:263,271 | ||
| 2000/1207 | } static void | |
| 2000/1213 | rempart(FPart *fp) | |
| 2000/1207 | { | |
| 2000/1213 | fp->name[0] = 0; | |
| 2000/1207 | } | |
| 2000/1111 | void | |
| 2000/1211/sys/src/9/bitsy/devflash.c:280,286 – 2000/1213/sys/src/9/bitsy/devflash.c:283,289 | ||
| 2000/1117 | } flash.bootprotect = 1; | |
| 2000/1207 |
| |
| 2000/1213 | addpart(nil, "flash", 0, flash.size); | |
| 2000/1111 | } static Chan* | |
| 2000/1211/sys/src/9/bitsy/devflash.c:315,327 – 2000/1213/sys/src/9/bitsy/devflash.c:318,378 | ||
| 2000/1111 | { } | |
| 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 |
| |
| 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,363 – 2000/1213/sys/src/9/bitsy/devflash.c:379,388 | ||
| 2000/1117 | default: error(Eperm); case Qfctl: | |
| 2000/1213 | n = flashctlread(FPART(c->qid.path), a, n, off); | |
| 2000/1117 | break; | |
| 2000/1207 |
| |
| 2000/1117 |
| |
| 2000/1207 |
| |
| 2000/1117 |
| |
| 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,423 – 2000/1213/sys/src/9/bitsy/devflash.c:437,450 | ||
| 2000/1117 | } static long | |
| 2000/1213 | flashctlwrite(FPart *fp, char *p, long n) | |
| 2000/1117 | { Cmdbuf *cmd; | |
| 2000/1207 | ulong off; | |
| 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,440 – 2000/1213/sys/src/9/bitsy/devflash.c:452,461 | ||
| 2000/1117 | nexterror(); } if(strcmp(cmd->f[0], "erase") == 0){ | |
| 2000/1207 |
| |
| 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,449 – 2000/1213/sys/src/9/bitsy/devflash.c:464,470 | ||
| 2000/1207 | bootprotect(off); (*flash.alg->erase)(off); break; | |
| 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,465 – 2000/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); | |
| 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 |
| |
| 2000/1207 |
| |
| 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,493 – 2000/1213/sys/src/9/bitsy/devflash.c:494,516 | ||
| 2000/1117 | } static long | |
| 2000/1207 |
| |
| 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 |
| |
| 2000/1207 |
| |
| 2000/1213 | uchar *buf; | |
| 2000/1117 | ||
| 2000/1207 |
| |
| 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,503 – 2000/1213/sys/src/9/bitsy/devflash.c:519,525 | ||
| 2000/1207 | if(!iseve()) error(Eperm); | |
| 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,512 – 2000/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,531 – 2000/1213/sys/src/9/bitsy/devflash.c:557,575 | ||
| 2000/1117 | m = end - p; | |
| 2000/1209 | if(m > Maxwchunk) m = Maxwchunk; | |
| 2000/1213 | (*flash.alg->write)(p, m, off); | |
| 2000/1117 | off += m; } /* make sure write succeeded */ | |
| 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(); | |
| 2000/1213 | return on; | |
| 2000/1117 | } | |
| 2000/1111 | static long | |
| 2000/1211/sys/src/9/bitsy/devflash.c:541,549 – 2000/1213/sys/src/9/bitsy/devflash.c:585,595 | ||
| 2000/1117 | default: panic("flashwrite"); case Qfctl: | |
| 2000/1207 |
| |
| 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,158 – 2001/0529/sys/src/9/bitsy/devflash.c:152,158 (short | long) | ||
| 2000/1207 | typedef struct FPart FPart; struct FPart { | |
| 2000/1213 |
| |
| 2001/0529 | char *name; | |
| 2000/1207 | ulong start; ulong end; | |
| 2000/1111 | }; | |
| 2000/1213/sys/src/9/bitsy/devflash.c:163,187 – 2001/0529/sys/src/9/bitsy/devflash.c:163,188 | ||
| 2000/1207 | #define FPART(q) (&part[(q) >>8]) static int | |
| 2001/0529 | gen(Chan *c, char*, Dirtab*, int, int i, Dir *dp) | |
| 2000/1207 | { Qid q; | |
| 2000/1213 |
| |
| 2001/0529 | char buf[KNAMELEN]; | |
| 2000/1207 | FPart *fp; q.vers = 0; /* top level directory contains the name of the network */ | |
| 2001/0529 | if(c->qid.path == Qtopdir){ | |
| 2000/1207 | switch(i){ case DEVDOTDOT: | |
| 2001/0529 | q.path = Qtopdir; q.type = QTDIR; devdir(c, q, "#F", 0, eve, DMDIR|0555, dp); | |
| 2000/1207 | break; case 0: | |
| 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,212 – 2001/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: | |
| 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 |
| |
| 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,239 – 2001/0529/sys/src/9/bitsy/devflash.c:236,241 | ||
| 2000/1207 | { int i; | |
| 2000/1213 |
| |
| 2000/1213/sys/src/9/bitsy/devflash.c:257,263 – 2001/0529/sys/src/9/bitsy/devflash.c:259,265 | ||
| 2000/1207 | if(i == Maxpart) error("no more partitions"); fp = &part[i]; | |
| 2001/0529 | kstrdup(&fp->name, name); | |
| 2000/1207 | fp->start = start; fp->end = end; } | |
| 2000/1213/sys/src/9/bitsy/devflash.c:265,271 – 2001/0529/sys/src/9/bitsy/devflash.c:267,277 | ||
| 2000/1207 | static void | |
| 2000/1213 | rempart(FPart *fp) | |
| 2000/1207 | { | |
| 2000/1213 |
| |
| 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,307 – 2001/0529/sys/src/9/bitsy/devflash.c:298,313 | ||
| 2000/1117 | return devattach('F', spec); | |
| 2000/1111 | } | |
| 2001/0529 | static Walkqid* flashwalk(Chan *c, Chan *nc, char **name, int nname) | |
| 2000/1111 | { | |
| 2000/1207 |
| |
| 2001/0529 | return devwalk(c, nc, name, nname, nil, 0, gen); | |
| 2000/1111 | } | |
| 2001/0529 | static int flashstat(Chan *c, uchar *db, int n) | |
| 2000/1111 | { | |
| 2000/1207 |
| |
| 2001/0529 | return devstat(c, db, n, nil, 0, gen); | |
| 2000/1111 | } static Chan* | |
| 2000/1213/sys/src/9/bitsy/devflash.c:353,359 – 2001/0529/sys/src/9/bitsy/devflash.c:359,365 | ||
| 2000/1213 | runlock(&flash); nexterror(); } | |
| 2001/0529 | if(fp->name == nil) | |
| 2000/1213 | error("partition vanished"); if(!iseve()) error(Eperm); | |
| 2000/1213/sys/src/9/bitsy/devflash.c:373,381 – 2001/0529/sys/src/9/bitsy/devflash.c:379,390 | ||
| 2000/1213 | static long flashread(Chan* c, void* a, long n, vlong off) { | |
| 2000/1117 |
| |
| 2001/0529 | int t; if(c->qid.type == QTDIR) | |
| 2000/1207 | return devdirread(c, a, n, nil, 0, gen); | |
| 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,520 – 2001/0529/sys/src/9/bitsy/devflash.c:523,529 | ||
| 2000/1117 | nexterror(); } | |
| 2000/1207 |
| |
| 2001/0529 | if(fp->name == nil) | |
| 2000/1207 | error("partition vanished"); if(!iseve()) error(Eperm); | |
| 2000/1213/sys/src/9/bitsy/devflash.c:575,587 – 2001/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 |
| |
| 2001/0529 | int t; if(c->qid.type == QTDIR) | |
| 2000/1117 | error(Eperm); if(!iseve()) error(Eperm); | |
| 2000/1207 |
| |
| 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,607 – 2001/0529/sys/src/9/bitsy/devflash.c:613,618 | ||
| 2000/1111 | devreset, flashinit, flashattach, | |
| 2000/1213/sys/src/9/bitsy/devflash.c:655,661 – 2001/0529/sys/src/9/bitsy/devflash.c:666,672 | ||
| 2000/1117 | static void ise_error(int bank, ulong status) { | |
| 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,230 – 2001/0605/sys/src/9/bitsy/devflash.c:224,230 (short | long) | ||
| 2000/1207 | int i; for(i = 0; i < Maxpart; i++) | |
| 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,260 – 2001/0605/sys/src/9/bitsy/devflash.c:254,260 | ||
| 2000/1207 | if(fp != nil) error(Eexist); for(i = 0; i < Maxpart; i++) | |
| 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,158 – 2001/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,172 – 2001/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 |
| |
| 2000/1207 | FPart *fp; q.vers = 0; | |
| 2001/0605/sys/src/9/bitsy/devflash.c:208,217 – 2001/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 { | |
| 2001/0529 | q.type = QTFILE; | |
| 2000/1213 |
| |
| 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,240 – 2001/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,265 – 2001/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,277 – 2001/0614/sys/src/9/bitsy/devflash.c:269,282 | ||
| 2000/1207 | static void | |
| 2000/1213 | rempart(FPart *fp) | |
| 2000/1207 | { | |
| 2001/0529 |
| |
| 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,622 – 2002/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,344 – 2002/0404/sys/src/9/bitsy/devflash.c:338,344 (short | long) | ||
| 2000/1117 | ||
| 2000/1213 | buf = smalloc(1024); e = buf + 1024; | |
| 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++) | |