[inferno-kirkwood] 4 new revisions pushed by mechiel@ueber.net on 2010-03-29 17:39 GMT

1 view
Skip to first unread message

inferno-...@googlecode.com

unread,
Mar 29, 2010, 1:39:30 PM3/29/10
to inferno-kirk...@googlegroups.com
4 new revisions:

Revision: b62d001a0d
Author: Mechiel Lukkien <mec...@ueber.net>
Date: Mon Mar 29 07:16:41 2010
Log: introduce devbs.c, hot-pluggable block storage. change devsdio.c to
k...
http://code.google.com/p/inferno-kirkwood/source/detail?r=b62d001a0d

Revision: eedd513098
Author: Mechiel Lukkien <mec...@ueber.net>
Date: Mon Mar 29 08:40:57 2010
Log: devbs.c improvements....
http://code.google.com/p/inferno-kirkwood/source/detail?r=eedd513098

Revision: 483ef6195d
Author: Mechiel Lukkien <mec...@ueber.net>
Date: Mon Mar 29 10:29:30 2010
Log: understand plan 9-style partitions.
http://code.google.com/p/inferno-kirkwood/source/detail?r=483ef6195d

Revision: 22b3a6c999
Author: Mechiel Lukkien <mec...@ueber.net>
Date: Mon Mar 29 10:38:56 2010
Log: remove the old devsdio.c; add useful rctl() for kwsdio.c
http://code.google.com/p/inferno-kirkwood/source/detail?r=22b3a6c999

==============================================================================
Revision: b62d001a0d
Author: Mechiel Lukkien <mec...@ueber.net>
Date: Mon Mar 29 07:16:41 2010
Log: introduce devbs.c, hot-pluggable block storage. change devsdio.c to
kwsdio.c and use devbs.c.

devsd.c is not used because its use of scsi stuff is annoying: sd
cards and sata drives are not scsi.

this is not complete, but partitions for the sd card are set up and
one can read from them. devsata.c will change to this at some point
as well.
http://code.google.com/p/inferno-kirkwood/source/detail?r=b62d001a0d

Added:
/bs.h
/devbs.c
/kwsdio.c
/part.c
/part.h
Modified:
/main.c
/misc/init
/mkfile
/sheeva

=======================================
--- /dev/null
+++ /bs.h Mon Mar 29 07:16:41 2010
@@ -0,0 +1,21 @@
+typedef struct Store Store;
+
+struct Store
+{
+ int num;
+ char name[4+1]; /* "bs%02d", num */
+ void *ctlr;
+
+ /* set by init, used by devbs.c */
+ Part *parts; /* first is always "data" for whole disk */
+ int nparts;
+ vlong size;
+
+ void (*init)(Store *d); /* init controller */
+ void (*diskinit)(Store *d); /* find disk and set size */
+ int (*rctl)(Store *d, char *s);
+ int (*wctl)(Store *d, char *s);
+ long (*io)(void *d, int iswrite, void *buf, long n, vlong off);
+};
+
+extern void blockdiskadd(Store *);
=======================================
--- /dev/null
+++ /devbs.c Mon Mar 29 07:16:41 2010
@@ -0,0 +1,389 @@
+/*
+ * hot-pluggable block storage devices
+ *
+ * todo:
+ * - rctl,wctl
+ * - locking
+ * - get rid of disks[100]
+ * - allow bs-specific and device-specific ctl ops
+ * - understand plan 9 partition table
+ * - more checks for sanity in part.c (e.g. is within size of disk)
+ * - only allow one open per Part ("data" can have more, it is special
anyway)
+ * - hotplug & events, make event-file per Qdiskpart too.
+ * - think about returning a type of device, eg "ata", "sdcard"
+ * - think about raw command access.
+ * - think about allowing setting of block size and required alignment.
+ * - add hooks so devices can tell they have gone/arrived.
+ * - invalidate open files after reinit of device.
+ * - think of way to update the partition table. for now, write to the
data file, then reinit the device.
+ */
+
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+#include "part.h"
+#include "bs.h"
+
+static char Enodisk[] = "no such disk";
+static char Enopart[] = "no such partition";
+
+#define QTYPE(v) ((int)((v)>>0 & 0xff))
+#define QDISK(v) ((int)((v)>>8 & 0xff))
+#define QPART(v) ((int)((v)>>16 & 0xff))
+#define QPATH(p,d,t) ((p)<<16 | (d)<<8 | (t)<<0)
+enum{
+ Qdir, Qbsctl, Qbsevent,
+ Qdiskdir, Qdiskctl, Qdiskpart,
+};
+static
+Dirtab bstab[] = {
+ ".", {Qdir,0,QTDIR}, 0, 0555,
+ "bsctl", {Qbsctl}, 0, 0664,
+ "bsevent", {Qbsevent}, 0, 0444,
+ "xxx", {Qdiskdir,0,QTDIR}, 0, 0554,
+ "ctl", {Qdiskctl}, 0, 0664,
+ "xxx", {Qdiskpart}, 0, 0660,
+};
+
+static QLock disksl;
+static Store *disks[100]; /* indexed by Store.num */
+
+static Store*
+diskget(int num)
+{
+ if(num >= 0 && num < nelem(disks) && disks[num] != nil)
+ return disks[num];
+ return nil;
+}
+
+static Store*
+xdiskget(int num)
+{
+ Store *d;
+ d = diskget(num);
+ if(d == nil)
+ error(Enodisk);
+ return d;
+}
+
+static Part*
+partget(Store *d, int i)
+{
+ if(i < 0 || i >= d->nparts)
+ return nil;
+ return &d->parts[i];
+}
+
+static Part*
+xpartget(Store *d, int i)
+{
+ Part *p;
+ p = partget(d, i);
+ if(p == nil)
+ error(Enopart);
+ return p;
+}
+
+static void
+partdata(Part *p, vlong size)
+{
+ p->index = 0;
+ p->typ = 0;
+ strcpy(p->name, "data");
+ p->s = 0;
+ p->e = size;
+ p->size = size;
+ strcpy(p->uid, eve);
+ p->perm = 0660;
+}
+
+static long
+io(Store *d, Part *p, int iswrite, void *buf, long n, vlong off)
+{
+ vlong s, e;
+
+ if(off < 0 || n < 0)
+ error(Ebadarg);
+ s = off;
+ e = off+n;
+ if(s > p->size)
+ s = p->size;
+ if(e > p->size)
+ e = p->size;
+ s += p->s;
+ e += p->s;
+ return d->io(d, iswrite, buf, e-s, s);
+}
+
+static int
+bsgen(Chan *c, char *, Dirtab *, int, int i, Dir *dp)
+{
+ Dirtab *t;
+ Store *d;
+ Part *p;
+
+//print("bsgen, c->qid.path %#llux, i %d\n", c->qid.path, i);
+
+ if(i == DEVDOTDOT) {
+ switch(QTYPE(c->qid.path)) {
+ case Qdir:
+ case Qdiskdir:
+ t = &bstab[Qdir];
+ devdir(c, t->qid, t->name, t->length, eve, t->perm, dp);
+ return 1;
+ }
+ panic("devdotdot on non-dir qid.path %#llux\n", c->qid.path);
+ }
+
+ switch(QTYPE(c->qid.path)) {
+ default:
+ panic("bsgen on non-dir qid.path %#llux\n", c->qid.path);
+
+ case Qdir:
+ case Qbsctl:
+ case Qbsevent:
+ if(i == 0 || i == 1) {
+ t = &bstab[Qbsctl+i];
+ devdir(c, t->qid, t->name, t->length, eve, t->perm, dp);
+ return 1;
+ }
+ i -= 2;
+ if(i >= nelem(disks))
+ return -1;
+ d = diskget(i);
+ if(d == nil)
+ return 0;
+ t = &bstab[Qdiskdir];
+ devdir(c, (Qid){QPATH(0,d->num,Qdiskdir),0,QTDIR}, d->name, t->length,
eve, t->perm, dp);
+ return 1;
+
+ case Qdiskdir:
+ case Qdiskctl:
+ case Qdiskpart:
+ d = diskget(QDISK(c->qid.path));
+ if(d == nil)
+ return -1;
+ if(i == 0) {
+ t = &bstab[Qdiskctl+i];
+ devdir(c, (Qid){QPATH(0,d->num,Qdiskctl+i),0,QTFILE}, t->name,
t->length, eve, t->perm, dp);
+ return 1;
+ }
+ i -= 1;
+ if(i >= d->nparts)
+ return -1;
+ p = &d->parts[i];
+ devdir(c, (Qid){QPATH(i,d->num,Qdiskpart),0,QTFILE}, p->name, p->size,
p->uid, p->perm, dp);
+ return 1;
+ }
+ return -1;
+}
+
+
+static void
+bsreset(void)
+{
+ print("bsreset\n");
+}
+
+static void
+bsinit(void)
+{
+ int i;
+ Store *d;
+
+ print("bsinit\n");
+ for(i = 0; i < nelem(disks); i++) {
+ d = diskget(i);
+ if(d != nil) {
+ if(waserror()) {
+ // xxx mark disk as bad/not yet initialized
+ continue;
+ }
+ d->init(d);
+ poperror();
+ }
+ }
+}
+
+static Chan*
+bsattach(char* spec)
+{
+ return devattach('n', spec);
+}
+
+static Walkqid*
+bswalk(Chan *c, Chan *nc, char **name, int nname)
+{
+ return devwalk(c, nc, name, nname, nil, 0, bsgen);
+}
+
+static int
+bsstat(Chan* c, uchar *db, int n)
+{
+ return devstat(c, db, n, nil, 0, bsgen);
+}
+
+static Chan*
+bsopen(Chan* c, int omode)
+{
+ return devopen(c, omode, nil, 0, bsgen);
+}
+
+static int
+bswstat(Chan* c, uchar *dp, int n)
+{
+ USED(c, dp);
+ error(Eperm);
+ return n;
+}
+
+static void
+bsclose(Chan* c)
+{
+ USED(c);
+}
+
+static long
+bsread(Chan* c, void* a, long n, vlong off)
+{
+ Store *d;
+ Part *p;
+
+ switch(QTYPE(c->qid.path)){
+ case Qdir:
+ case Qdiskdir:
+ return devdirread(c, a, n, nil, 0, bsgen);
+ case Qbsctl:
+ // xxx should print info about initialized disks. perhaps only
registered too.
+ error("not yet");
+ case Qbsevent:
+ error("not yet");
+ case Qdiskctl:
+ error("not yet");
+ case Qdiskpart:
+ d = xdiskget(QDISK(c->qid.path));
+ p = xpartget(d, QPART(c->qid.path));
+ n = io(d, p, 0, a, n, off);
+ break;
+
+ default:
+ n = 0;
+ break;
+ }
+ return n;
+}
+
+enum {
+ CMinit,
+};
+static Cmdtab bsctl[] =
+{
+ CMinit, "init", 2,
+};
+
+static long
+bswrite(Chan* c, void* a, long n, vlong off)
+{
+ Cmdbuf *cb;
+ Cmdtab *ct;
+ Store *d;
+ Part *p;
+ ulong num;
+
+ qlock(&disksl);
+ if(waserror()) {
+ qunlock(&disksl);
+ nexterror();
+ }
+
+ switch(QTYPE(c->qid.path)){
+ case Qbsctl:
+ if(!iseve())
+ error(Eperm);
+
+ cb = parsecmd(a, n);
+ if(waserror()) {
+ free(cb);
+ nexterror();
+ }
+ ct = lookupcmd(cb, bsctl, nelem(bsctl));
+ switch(ct->index) {
+ case CMinit:
+ num = strtoul(cb->f[1], nil, 10);
+ d = diskget(num);
+ if(d == nil)
+ error(Enodisk);
+ d->diskinit(d);
+
+ d->parts = smalloc(sizeof d->parts[0]);
+ partdata(&d->parts[0], d->size);
+ if(waserror()) {
+ free(d->parts);
+ d->parts = nil;
+ nexterror();
+ }
+ d->nparts = partinit(d->io, d, &d->parts);
+ if(d->nparts < 0)
+ error("partinit");
+ poperror();
+
+ d->num = num;
+ break;
+ }
+ poperror();
+ free(cb);
+ break;
+
+ case Qbsevent:
+ error("not yet");
+
+ case Qdiskpart:
+ d = xdiskget(QDISK(c->qid.path));
+ p = xpartget(d, QPART(c->qid.path));
+ n = io(d, p, 0, a, n, off);
+ break;
+ default:
+ error(Ebadusefd);
+ }
+
+ poperror();
+ qunlock(&disksl);
+ return n;
+}
+
+Dev bsdevtab = {
+ 'n',
+ "bs",
+
+ bsreset,
+ bsinit,
+ devshutdown,
+ bsattach,
+ bswalk,
+ bsstat,
+ bsopen,
+ devcreate,
+ bsclose,
+ bsread,
+ devbread,
+ bswrite,
+ devbwrite,
+ devremove,
+ bswstat,
+};
+
+void
+blockdiskadd(Store *d)
+{
+ iprint("blockdiskadd, num %d \n", d->num);
+
+ qlock(&disksl);
+ if(diskget(d->num) != nil)
+ panic("disk.num %d already registered", d->num);
+ disks[d->num] = d;
+ snprint(d->name, sizeof d->name, "bs%02d", d->num);
+ qunlock(&disksl);
+}
=======================================
--- /dev/null
+++ /kwsdio.c Mon Mar 29 07:16:41 2010
@@ -0,0 +1,867 @@
+/*
+ * only memory cards are supported (not sdio). only sd cards for now, mmc
cards seem obsolete anyway.
+ *
+ * todo:
+ * - don't crash when proc doing read/write is killed.
+ * - hook into devsd.c?
+ * - look at effects of csd.eraseblk and csd.erasesecsize on erase() and
possibly pre-write-erase.
+ * - wait reading dat[0] in hoststate for r1b responses?
+ * - read scr register and use it to determine if card supports 4bit data
bus
+ * - see if we can detect device inserts/ejects? yes, by sd_cd gpio pin
(on mpp47).
+ * - ctl commands for erasing?
+ * - erase before writing big buffer?
+ */
+
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+#include "io.h"
+#include "sdcard.h"
+#include "part.h"
+#include "bs.h"
+
+
+#define DEBUG 0
+#define dprint if(DEBUG)print
+
+char Enocard[] = "no card";
+
+enum {
+ /* keep in sync with errstrs[] */
+ SDOk = 0,
+ SDTimeout = -1,
+ SDCardbusy = -2,
+ SDError = -3,
+ SDInterrupted = -4,
+ SDBadstatus = -5, /* status in r1(b) response indicated error, see
card.status */
+
+ /* expected response to command */
+ R0 = 0,
+ R1,
+ R1b,
+ R2,
+ R3,
+ R6,
+ R7,
+
+ /* flags for sdcmd and sdcmddma */
+ Fapp = 1<<0, /* app-specific command */
+ Fappdata= 1<<1, /* app-specific data command */
+ Fdmad2h = 1<<2, /* dma from device to host */
+ Fdmah2d = 1<<3, /* dma from host to device */
+ Fmulti = 1<<4, /* multiple blocks, use auto cmd 12 to stop transfer */
+};
+
+enum {
+ /* transfer mode */
+ /* note: the doc bits is contradictory on these bits. comments below
indicate actual behaviour. */
+ TMdatawrite = 1<<1, /* write data after response, for write commands */
+ TMautocmd12 = 1<<2, /* hardware sends cmd12 */
+ TMxfertohost = 1<<4, /* data flows from sd to host */
+ TMswwrite = 1<<6, /* software-controlled, not dma */
+
+ /* cmd */
+ Respnone = 0<<0,
+ Resp136 = 1<<0,
+ Resp48 = 2<<0,
+ Resp48busy = 3<<0,
+
+ CMDdatacrccheck = 1<<2,
+ CMDcmdcrccheck = 1<<3,
+ CMDcmdindexcheck= 1<<4,
+ CMDdatapresent = 1<<5,
+ CMDunexpresp = 1<<7,
+ CMDshift = 8,
+
+ /* hoststate */
+ HScmdinhibit = 1<<0,
+ HScardbusy = 1<<1,
+ HSdatshift = 3,
+ HStxactive = 1<<8,
+ HSrxactive = 1<<9,
+ HSfifofull = 1<<12,
+ HSfifoempty = 1<<13,
+ HSacmd12active = 1<<14,
+
+ /* hostctl */
+ HCpushpull = 1<<0,
+ HCcardmask = 3<<1,
+ HCcardmemonly = 0<<1,
+ HCcardioonly = 1<<1,
+ HCcardiomem = 2<<1,
+ HCcardmmc = 3<<1,
+ HCbigendian = 1<<3,
+ HClsbfirst = 1<<4,
+ HCdatawidth4 = 1<<9,
+ HChighspeed = 1<<10,
+#define HCtimeout(x) (((x) & MASK(4))<<11)
+ HCtimeoutenable = 1<<15,
+
+ /* swreset */
+ SRresetall = 1<<8,
+
+ /* st, status */
+ Scmdcomplete = 1<<0,
+ Sxfercomplete = 1<<1,
+ Sblockgapevent = 1<<2,
+ Sdmaintr = 1<<3,
+ Stxready = 1<<4,
+ Srxready = 1<<5,
+ Scardintr = 1<<8,
+ Sreadwaiton = 1<<9,
+ Sfifo8wfull = 1<<10,
+ Sfifo8wavail = 1<<11,
+ Ssuspended = 1<<12,
+ Sautocmd12done = 1<<13,
+ Sunexpresp = 1<<14,
+ Serror = 1<<15,
+
+ /* est, error status */
+ Ecmdtimeout = 1<<0,
+ Ecmdcrc = 1<<1,
+ Ecmdendbit = 1<<2,
+ Ecmdindex = 1<<3,
+ Edatatimeout = 1<<4,
+ Erddatacrc = 1<<5,
+ Erddataend = 1<<6,
+ Eautocmd12 = 1<<8,
+ Ecmdstartbit = 1<<9,
+ Exfersize = 1<<10,
+ Eresptbit = 1<<11,
+ Ecrcendbit = 1<<12,
+ Ecrcstartbit = 1<<13,
+ Ecrcstatus = 1<<14,
+
+ /* autocmd12 index */
+ AIcheckbusy = 1<<0,
+ AIcheckindex = 1<<1,
+ AIcmdshift = 8,
+};
+
+enum {
+ /* sd commands */
+ CMDRead = 17,
+ CMDReadmulti = 18,
+ CMDWrite = 24,
+ CMDWritemulti = 25,
+
+ ACMDGetscr = 51,
+
+
+ CMD8pattern = 0xaa,
+ CMD8patternmask = MASK(8),
+ CMD8voltage = 1<<8,
+ CMD8voltagemask = MASK(4)<<8,
+
+ ACMD41voltagewindow = MASK(23-15+1)<<15,
+ ACMD41sdhcsupported = 1<<30,
+ ACMD41ready = 1<<31,
+
+
+ /* sd status, in R1 & R1b responses */
+ SDappcmd = 1<<5, /* next command will be interpreted as app specific */
+ SDreadyfordata = 1<<8, /* buffer empty signal on bus */
+ SDstateshift = 9,
+ SDstatewidth = 4,
+ SDnoecc = 1<<14, /* command executed without ecc */
+ SDerror = 1<<19, /* general/unknown error */
+ SDccerror = 1<<20, /* internal card controller error */
+ SDbadcmd = 1<<22, /* invalid command */
+ SDblocklenerr = 1<<29, /* block length invalid */
+
+ /* bits we consider as error. some indicate conditions we don't (yet)
handle. */
+ SDbad = 1<<3|1<<13|1<<14|1<<15|1<<16|MASK(13)<<19,
+};
+
+
+static Card card;
+static Rendez cmdr;
+static QLock sdl;
+
+/* for bits in st, est, acmd12st registers */
+static const char *statusstrs[] = {
+"cmdcomplete", "xfercomplete", "blockgapevent", "dmaintr",
+"txready", "rxready", "", "",
+"cardintr", "readwaiton", "fifo8wfull", "fifo8wavail",
+"suspended", "autocmd12done", "unexpresp", "errorintr",
+};
+
+static const char *errstatusstrs[] = {
+"cmdtimeout", "cmdcrc", "cmdendbit", "cmdindex",
+"datatimeout", "rddatacrc", "rddataend", "",
+"autocmd12", "cmdstartbit", "xfersize", "resptbit",
+"crcendbit", "crcstartbit", "crcstatus",
+};
+
+static const char *acmd12ststrs[] = {
+"acmd12notexe", "acmd12timeout", "acmd12crcerr", "acmd12endbiterr",
+"acmd12indexerr", "acmd12resptbi", "acmd12respstartbiterr",
+};
+
+static const char *sdstatusstrs[] = {
+"tm0", "tm1", "apprsvd", "akeseqerr",
+"sdiorsvd", "appcmd", "rsvd6", "rsvd7",
+"readyfordata", "st9", "st10", "st11",
+"st12", "erasereset", "noecc", "wperaseskip",
+"csdoverwrite", "rsvd17", "rsvd18", "error",
+"ccerror", "eccfail", "badcmd", "cmdcrcerr",
+"lockerr", "locked", "wpviolation", "eraseparam",
+"eraseseqerr", "blocklenerr", "addrerr", "outofrange",
+};
+
+static char*
+mkstr(char *p, char *e, ulong v, char **s, int ns)
+{
+ int i;
+ for(i = 0; i < ns; i++)
+ if(v & 1<<i)
+ p = seprint(p, e, " %q", s[i]);
+ return p;
+}
+
+static char*
+statusstr(char *p, char *e, ulong v)
+{
+ return mkstr(p, e, v, statusstrs, nelem(statusstrs));
+}
+
+static char*
+errstatusstr(char *p, char *e, ulong v)
+{
+ return mkstr(p, e, v, errstatusstrs, nelem(errstatusstrs));
+}
+
+static char*
+acmd12ststr(char *p, char *e, ulong v)
+{
+ return mkstr(p, e, v, acmd12ststrs, nelem(acmd12ststrs));
+}
+
+static char *
+sdstatusstr(char *p, char *e, ulong v)
+{
+ return mkstr(p, e, v, sdstatusstrs, nelem(sdstatusstrs));
+}
+
+static const char *statestrs[] = {
+"idle", "ready", "ident", "stby",
+"tran", "data", "rcv", "prg",
+"dis", "", "", "",
+"", "", "", "",
+};
+
+static void
+printstatus(char *s, ulong st, ulong est, ulong acmd12st)
+{
+ char *p, *e;
+
+ if(!DEBUG)
+ return;
+
+ p = up->genbuf;
+ e = p+sizeof (up->genbuf);
+
+ p = statusstr(p, e, st);
+ p = seprint(p, e, ";");
+ p = errstatusstr(p, e, est);
+ p = seprint(p, e, ";");
+ p = acmd12ststr(p, e, acmd12st);
+ USED(p);
+
+ print("status: %s%s\n", s, up->genbuf);
+}
+
+
+static const char *errstrs[] = {
+"success", "timeout", "card busy", "error", "interrupted", "badstatus",
+};
+
+static void
+errorsd(char *s, int v)
+{
+ char buf[ERRMAX];
+ char * p = buf;
+ char * const e = buf+sizeof buf;
+
+ p = seprint(p, e, "%s", s);
+ if(v != SDOk)
+ p = seprint(p, e, ": %s", errstrs[-v]);
+ if(v == SDBadstatus)
+ p = seprint(p, e, " (r1status %#lux)", card.status);
+ if(v == SDError) {
+ p = seprint(p, e, " (est %#lux", card.status);
+ p = errstatusstr(p, e, card.status);
+ p = seprint(p, e, ")");
+ }
+ USED(p);
+ error(buf);
+}
+
+static int
+sdiodone(void *p)
+{
+ SdioReg *r = SDIOREG;
+ ulong v = *(ulong *)p;
+
+ if(r->st & v) {
+ r->stirq = 0;
+ return 1;
+ }
+ return 0;
+}
+
+/* keep in sync with R* contants */
+static const ulong resptypes[] = {
+Respnone, Resp48, Resp48busy, Resp136, Resp48, Resp48, Resp48,
+};
+static int
+sdcmd(Card *c, ulong cmd, ulong arg, int rt, ulong fl)
+{
+ SdioReg *r = SDIOREG;
+ int i, s;
+ ulong acmd;
+ ulong cmdopts, mode;
+ ulong need, v;
+ uvlong w;
+
+ print("sdcmd, cmd %lud, arg %lud, fl %#lux\n", cmd, arg, fl);
+
+ i = 0;
+ for(;;) {
+ if((r->hoststate & (HScmdinhibit|HScardbusy)) == 0)
+ break;
+ if(i++ >= 50)
+ return SDCardbusy;
+ tsleep(&up->sleep, return0, nil, i);
+ }
+
+ if(fl & (Fapp|Fappdata)) {
+ acmd = 55;
+ if(fl & Fappdata)
+ acmd = 56;
+ s = sdcmd(c, acmd, card.rca<<16, R1, 0);
+ if(s < 0)
+ return s;
+ if((c->resp[2]>>8 & SDappcmd) == 0)
+ return SDBadstatus;
+ }
+
+ /* clear status */
+ r->st = ~0;
+ r->est = ~0;
+ r->acmd12st = ~0;
+ // xxx remove?
+ printstatus("before cmd: ", r->st, r->est, r->acmd12st);
+
+ /* prepare args & execute command */
+ r->arglo = arg>>0 & MASK(16);
+ r->arghi = arg>>16 & MASK(16);
+ cmdopts = CMDunexpresp;
+ mode = 0;
+ if(fl & Fdmad2h)
+ mode |= TMxfertohost;
+ if(fl & Fdmah2d)
+ mode |= TMdatawrite;
+ if(fl & Fmulti) {
+ mode |= TMautocmd12;
+ r->acmd12arglo = 0;
+ r->acmd12arghi = 0;
+ r->acmd12idx = AIcheckbusy|AIcheckindex|12<<AIcmdshift;
+ }
+ if(fl & (Fdmad2h|Fdmah2d))
+ cmdopts |= CMDdatapresent;
+ if(fl & Fdmad2h)
+ cmdopts |= CMDdatacrccheck;
+ if(rt != R0 && rt != R3)
+ cmdopts |= CMDcmdcrccheck;
+ if(rt != R0 && rt != R2 && rt != R3)
+ cmdopts |= CMDcmdindexcheck;
+ r->mode = mode;
+ r->cmd = cmd<<CMDshift|cmdopts|resptypes[rt];
+
+ /* Scmdcomplete/Sdma and errors signal completion */
+ s = 0;
+ need = Scmdcomplete;
+ if(fl & (Fdmad2h|Fdmah2d))
+ need = Sdmaintr;
+ r->stirq = need|Sunexpresp|Serror;
+ r->estirq = ~0;
+
+ while(waserror())
+ s = SDInterrupted;
+ v = r->stirq;
+ tsleep(&cmdr, sdiodone, &v, 5000);
+ poperror();
+ if(s == SDInterrupted)
+ return s;
+
+ if(r->st & (Sunexpresp|Serror)) {
+ card.status = r->est;
+ return SDError;
+ }
+ if((r->st & need) == 0)
+ return SDTimeout;
+
+ printstatus("success", r->st, r->est, r->acmd12st);
+
+ /* fetch the response */
+ memset(c->resp, 0, sizeof c->resp);
+ switch(resptypes[rt]) {
+ case Respnone:
+ break;
+ case Resp136:
+ c->resp[0] = (uvlong)r->resp[0]>>10;
+
+ w = 0;
+ w |= (uvlong)r->resp[4]>>10;
+ w |= (uvlong)r->resp[3]<<(70-64);
+ w |= (uvlong)r->resp[2]<<(86-64);
+ w |= (uvlong)r->resp[1]<<(102-64);
+ w |= (uvlong)r->resp[0]<<(118-64);
+ c->resp[1] = w;
+
+ w = r->crc7<<1;
+ w |= ((uvlong)r->resp[7] & MASK(14))<<8;
+ w |= (uvlong)r->resp[6]<<22;
+ w |= (uvlong)r->resp[5]<<38;
+ w |= (uvlong)r->resp[4]<<54;
+ c->resp[2] = w;
+
+ break;
+ case Resp48:
+ case Resp48busy:
+ w = r->crc7<<1;
+ w |= ((uvlong)r->resp[2] & MASK(6))<<8;
+ w |= (uvlong)r->resp[1]<<14;
+ w |= (uvlong)r->resp[0]<<30;
+ c->resp[0] = 0;
+ c->resp[1] = 0;
+ c->resp[2] = w;
+ break;
+ }
+
+ if(rt == R1 || rt == R1b) {
+ c->status = c->resp[2]>>8;
+ if(c->status & SDbad)
+ return SDBadstatus;
+ }
+ return 0;
+}
+
+static int
+sdcmddma(Card *c, ulong cmd, ulong arg, void *a, int blsz, int nbl, int
resp, ulong fl)
+{
+ SdioReg *r = SDIOREG;
+
+ dcwbinv(a, blsz*nbl);
+ r->dmaaddrlo = (ulong)a & MASK(16);
+ r->dmaaddrhi = (ulong)a>>16 & MASK(16);
+ r->blksize = blsz;
+ r->blkcount = nbl;
+ dprint("sdcmddma, a %#lux, dmaddrlo %#lux dmaadrhi %#lux blksize %d
blkcount %d cmdarg %#lux\n",
+ a, (ulong)a & MASK(16), (ulong)a>>16 & MASK(16), blsz, nbl, arg);
+ return sdcmd(c, cmd, arg, resp, fl);
+}
+
+static void
+sdclock(ulong v)
+{
+ SDIOREG->clockdiv = ((100*1000*1000)/v)-1;
+ delay(1);
+}
+
+static void
+sdinit(void)
+{
+ int i, s;
+ ulong v;
+ SdioReg *r = SDIOREG;
+
+ sdclock(400*1000);
+ r->hostctl &= ~HChighspeed;
+
+ /* force card to idle state */
+ s = sdcmd(&card, 0, 0, R0, 0);
+ if(s < 0)
+ errorsd("reset failed", s);
+
+ /*
+ * "send interface command". only >=2.00 cards will respond.
+ * we send a check pattern and supported voltage range.
+ */
+ card.mmc = 0;
+ card.sd2 = 0;
+ card.sdhc = 0;
+ card.rca = 0;
+ s = sdcmd(&card, 8, CMD8voltage|CMD8pattern, R7, 0);
+ switch(s) {
+ case SDOk:
+ card.sd2 = 1;
+ v = card.resp[2]>>8;
+ if((v & CMD8patternmask) != CMD8pattern)
+ error("check pattern mismatch");
+ if((v & CMD8voltagemask) != CMD8voltage)
+ error("voltage not supported");
+ break;
+
+ case SDTimeout:
+ case SDError: /* "no response" from spec can result in error too
apparently */
+ /* sd 1.x or not an sd memory card */
+ s = sdcmd(&card, 0, 0, R0, 0);
+ if(s < 0)
+ errorsd("reset failed", s);
+ break;
+ default:
+ errorsd("voltage exchange failed", s);
+ }
+
+ /*
+ * "send host capacity support information".
+ * we send supported voltages & our sdhc support.
+ * mmc cards won't respond. sd cards will power up and indicate
+ * if they support sdhc.
+ */
+ i = 0;
+ for(;;) {
+ v = ACMD41voltagewindow;
+ if(card.sd2)
+ v |= ACMD41sdhcsupported;
+ s = sdcmd(&card, 41, v, R3, Fapp);
+ if(s < 0) {
+ if(s == SDTimeout && !card.sd2)
+ card.mmc = 1;
+ errorsd("exchange voltage/sdhc support info", s);
+ }
+ v = card.resp[2]>>8;
+ if((v & ACMD41voltagewindow) == 0)
+ error("voltage not supported");
+ if(v & ACMD41ready) {
+ card.sdhc = (v & ACMD41sdhcsupported) != 0;
+ break;
+ }
+
+ if(i++ >= 100)
+ error("sd card failed to power up");
+ tsleep(&up->sleep, return0, nil, 10);
+ }
+ dprint("acmd41 done, mmc %d, sd2 %d, sdhc %d\n", card.mmc, card.sd2,
card.sdhc);
+ if(card.mmc)
+ error("mmc cards not yet supported"); // xxx p14 says this involves
sending cmd1
+
+ s = sdcmd(&card, 2, 0, R2, 0);
+ if(s < 0)
+ errorsd("card identification", s);
+ if(parsecid(&card.cid, card.resp) < 0)
+ error("bad cid register");
+
+ i = 0;
+ for(;;) {
+ s = sdcmd(&card, 3, 0, R6, 0);
+ if(s < 0)
+ errorsd("getting relative address", s);
+ card.rca = card.resp[2]>>24 & MASK(16);
+ v = card.resp[2]>>8 & MASK(16);
+ dprint("have card rca %ux, status %lux\n", card.rca, v);
+ USED(v);
+ if(card.rca != 0)
+ break;
+ if(i++ == 10)
+ error("card insists on invalid rca 0");
+ }
+
+ s = sdcmd(&card, 9, card.rca<<16, R2, 0);
+ if(s < 0)
+ errorsd("get csd", s);
+ if(parsecsd(&card.csd, card.resp) < 0)
+ error("bad csd register");
+
+ if(card.csd.vers == 0) {
+ card.bs = 1<<card.csd.rbl;
+ card.size = card.csd.size+1;
+ card.size *= 1<<(card.csd.v0.sizemult+2);
+ card.size *= 1<<card.csd.rbl;
+ print("csd0, block length read/write %d/%d, size %lld bytes,
eraseblock %d\n",
+ 1<<card.csd.rbl,
+ 1<<card.csd.wbl,
+ card.size,
+ (1<<card.csd.wbl)*(card.csd.erasesecsz+1));
+ } else {
+ card.bs = 512;
+ card.size = (vlong)(card.csd.size+1)*card.bs*1024;
+ print("csd1, fixed 512 block length, size %lld bytes, eraseblock fixed
512\n", card.size);
+ }
+
+ if(card.sdhc) {
+ dprint("enabling sdhc & setting clock to 50mhz\n");
+ sdclock(50*1000*1000);
+ r->hostctl |= HChighspeed;
+ } else {
+ dprint("leaving sdhc off & setting clock to 25mhz\n");
+ sdclock(25*1000*1000);
+ }
+
+ s = sdcmd(&card, 7, card.rca<<16, R1b, 0);
+ if(s < 0)
+ errorsd("selecting card", s);
+
+ /* xxx have to check with scr register if 4bit buswidth is supported by
card. have not been able to read it though... */
+ s = sdcmd(&card, 6, 1<<1, R1, Fapp);
+ if(s < 0)
+ errorsd("setting buswidth to 4-bit", s);
+
+ s = sdcmd(&card, 16, 512, R1, 0);
+ if(s < 0)
+ errorsd("setting 512 byte blocksize", s);
+
+ card.valid = 1;
+ print("%s", cardstr(&card, up->genbuf, sizeof (up->genbuf)));
+}
+
+static int
+sdstatus(uchar *p)
+{
+ return sdcmddma(&card, 13, 0, p, 64, 1, R1, Fapp|Fdmad2h);
+}
+
+static int
+erase(vlong offset, long n)
+{
+ vlong e;
+ int s;
+
+ e = offset+n;
+ if(card.sdhc) {
+ e -= 512;
+ offset /= 512;
+ e /= 512;
+ } else
+ e -= 1;
+
+ s = sdcmd(&card, 32, offset, R1, 0); /* first addr to erase */
+ if(s >= 0)
+ s = sdcmd(&card, 33, e, R1, 0); /* last addr to erase (inclusive) */
+ if(s >= 0)
+ s = sdcmd(&card, 38, 0, R1b, 0); /* start erasing */
+ return s;
+}
+
+static long
+sdio(uchar *a, long n, vlong offset, int iswrite)
+{
+ ulong cmd, arg, fl, h, nn;
+ int s;
+
+ qlock(&sdl);
+ if(waserror()) {
+ qunlock(&sdl);
+ nexterror();
+ }
+
+ if(card.valid == 0)
+ error(Enocard);
+
+ /* xxx we should cover this case with a buffer, and then use the same
code to allow non-sector-aligned reads? */
+ if((ulong)a % 4 != 0)
+ error("bad buffer alignment...");
+
+ if(offset & (512-1))
+ error("not sector aligned");
+ if(n & (512-1))
+ error("not multiple of sector size");
+
+ cmd = CMDReadmulti;
+ fl = Fdmad2h;
+ if(iswrite) {
+ cmd = CMDWritemulti;
+ fl = Fdmah2d;
+ }
+
+ h = 0;
+ for(;;) {
+ if(card.sdhc)
+ arg = (offset+h)/512;
+ else
+ arg = offset+h;
+ nn = n;
+ if(nn > 512*1024)
+ nn = 512*1024;
+ if(iswrite) {
+ s = sdcmd(&card, 23, nn/512, R1, Fapp);
+ if(s < 0)
+ errorsd("erase before write", s);
+ }
+ s = sdcmddma(&card, cmd, arg, a+h, 512, nn/512, R1, fl|Fmulti);
+ if(s < 0)
+ errorsd("io", s);
+ h += nn;
+ if(h >= n)
+ break;
+
+ /* give others a chance */
+ if(waserror()) {
+ qlock(&sdl);
+ nexterror();
+ }
+ qunlock(&sdl);
+ poperror();
+ qlock(&sdl);
+ }
+
+ poperror();
+ qunlock(&sdl);
+ return n;
+}
+
+static void
+sdiointr(Ureg*, void*)
+{
+ SdioReg *r = SDIOREG;
+
+ /* disable interrupt, st & est are unchanged, caller reads & clears them
before next cmd. */
+ r->stirq = 0;
+ r->estirq = 0;
+ intrclear(Irqlo, IRQ0sdio);
+ wakeup(&cmdr);
+}
+
+static void
+sdioreset(void)
+{
+ SdioReg *r = SDIOREG;
+
+ /* disable all interrupts. dma interrupt will be enabled as required.
all bits lead to IRQ0sdio. */
+ intrdisable(Irqlo, IRQ0sdio, sdiointr, nil, "sdio");
+ r->stirq = 0;
+ r->estirq = 0;
+}
+
+static void
+sdioinit(Store *d)
+{
+ SdioReg *r = SDIOREG;
+
+ intrdisable(Irqlo, IRQ0sdio, sdiointr, nil, "sdio");
+
+ card.valid = 0;
+
+ /* reset the bus, forcing all cards to idle state */
+ r->swreset = SRresetall;
+ tsleep(&up->sleep, return0, nil, 50);
+
+ sdclock(25*1000*1000);
+
+ /* configure host controller */
+ r->hostctl = HCpushpull|HCcardmemonly|HCbigendian|HCdatawidth4|
HCtimeout(15)|HCtimeoutenable;
+
+ /* clear status */
+ r->st = ~0;
+ r->est = ~0;
+
+ /* enable most status reporting */
+ r->stena = ~(Stxready|Sfifo8wavail);
+ r->estena = ~0;
+
+ /* disable all interrupts. dma interrupt will be enabled as required.
all bits lead to IRQ0sdio. */
+ r->stirq = 0;
+ r->estirq = 0;
+ intrenable(Irqlo, IRQ0sdio, sdiointr, nil, "sdio");
+}
+
+/*
+ case Qctl:
+ cardstr(&card, up->genbuf, sizeof (up->genbuf));
+ n = readstr(offset, a, n, up->genbuf);
+ break;
+*/
+/*
+ case Qinfo:
+ if(card.valid == 0)
+ error(Enocard);
+ p = buf = smalloc(READSTR);
+ e = p+READSTR;
+ p = cidstr(p, e, &card.cid);
+ p = csdstr(p, e, &card.csd);
+ USED(p);
+ n = readstr(offset, a, n, buf);
+ free(buf);
+ break;
+*/
+/*
+ case Qstatus:
+ p = buf = smalloc(READSTR);
+ e = p+READSTR;
+
+ p = seprint(p, e, "st: ");
+ p = statusstr(p, e, r->st);
+ p = seprint(p, e, "\nest: ");
+ p = errstatusstr(p, e, r->est);
+ p = seprint(p, e, "\nacmd12st: ");
+ p = acmd12ststr(p, e, r->acmd12st);
+
+ p = seprint(p, e, "\nstena: ");
+ p = statusstr(p, e, r->stena);
+ p = seprint(p, e, "\nestena: ");
+ p = errstatusstr(p, e, r->estena);
+
+ p = seprint(p, e, "\nstirq: ");
+ p = statusstr(p, e, r->stirq);
+ p = seprint(p, e, "\nestirq: ");
+ p = errstatusstr(p, e, r->estirq);
+
+ p = seprint(p, e, "\nhoststate %#lux\n", r->hoststate);
+ USED(p);
+
+ n = readstr(offset, a, n, buf);
+ free(buf);
+*/
+
+static int
+sdiorctl(Store *d, char *s)
+{
+ USED(d, s);
+ print("sdiorctl\n");
+ return -1;
+}
+
+static int
+sdiowctl(Store *d, char *s)
+{
+ USED(d, s);
+ print("sdiowctl\n");
+ return -1;
+}
+
+static long
+sdioio(void *dd, int iswrite, void *buf, long n, vlong off)
+{
+ USED(dd);
+ return sdio(buf, n, off, iswrite);
+}
+
+static void
+sdiodiskinit(Store *d)
+{
+ sdinit();
+ d->size = card.size;
+}
+
+
+static Store sdiodisk = {
+ .init = sdioinit,
+ .diskinit = sdiodiskinit,
+ .rctl = sdiorctl,
+ .wctl = sdiowctl,
+ .io = sdioio,
+};
+
+void
+kwsdiolink(void)
+{
+ print("kwsdiolink\n");
+ sdioreset();
+ sdiodisk.num = 2;
+ blockdiskadd(&sdiodisk);
+}
=======================================
--- /dev/null
+++ /part.c Mon Mar 29 07:16:41 2010
@@ -0,0 +1,55 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+#include "part.h"
+
+static ulong
+g32(uchar *p)
+{
+ return (ulong)p[3]<<24 | (ulong)p[2]<<16 | (ulong)p[1]<<8 |
(ulong)p[0]<<0;
+}
+
+int
+partinit(long (*r)(void *, int, void *, long, vlong), void *disk, Part
**partsp)
+{
+ uchar buf[512+63];
+ uchar *p = (void*)(((ulong)buf+63)&~63);
+ long n;
+ int i, o;
+ Part part;
+ int nparts = 1;
+ Part *parts = *partsp;
+
+ n = r(disk, 0, p, 512, 0);
+ if(n != 512)
+ error("reading mbr");
+
+ if(p[510] != 0x55 || p[511] != 0xaa)
+ error("missing mbr signature");
+
+ for(i = 0; i < 4; i++) {
+ o = 446+i*16;
+ part.typ = p[o+0x4];
+ if(part.typ == 0)
+ continue;
+ part.index = nparts;
+ snprint(part.name, sizeof part.name, "p%02d", i);
+ part.s = (vlong)g32(p+o+0x8)*512;
+ part.size = (vlong)g32(p+o+0xc)*512;
+ part.e = part.s+part.size;
+ strcpy(part.uid, eve);
+ part.perm = 0660;
+ print("part, index %d, typ 0x%ux, name %s, s %lld, e %lld, size %lld\n",
+ (int)part.index, (uint)part.typ, part.name, part.s, part.e, part.size);
+ parts = realloc(parts, sizeof parts[0]*(nparts+1));
+ if(parts == nil)
+ error(Enomem);
+ *partsp = parts;
+ memmove(&parts[nparts++], &part, sizeof part);
+ }
+
+ return nparts;
+}
=======================================
--- /dev/null
+++ /part.h Mon Mar 29 07:16:41 2010
@@ -0,0 +1,16 @@
+typedef struct Part Part;
+
+struct Part
+{
+ uchar index; /* in partition table */
+ uchar typ; /* type from partition table */
+ char name[32]; /* name, "p%02d" for those from mbr */
+ vlong s; /* start,end,size in bytes */
+ vlong e;
+ vlong size;
+
+ char uid[KNAMELEN];
+ ulong perm;
+};
+
+int partinit(long (*read)(void *disk, int iswrite, void *buf, long n,
vlong off), void *disk, Part **parts);
=======================================
--- /main.c Tue Mar 16 15:41:07 2010
+++ /main.c Mon Mar 29 07:16:41 2010
@@ -294,7 +294,6 @@
iprint("kbdinit\n");
kbdinit();

- iprint("prints\n");
print("%ld MHz, id %08lux\n", (m->cpuhz+500000)/1000000, cpuidget());
print("\nInferno %s\n", VERSION);
print("Vita Nuova\n");
=======================================
--- /misc/init Thu Mar 11 07:54:44 2010
+++ /misc/init Mon Mar 29 07:16:41 2010
@@ -2,7 +2,7 @@
load std
autoload=(std)

-bind -a '#o' /dev # sdio
+bind -a '#n' /dev # bs
bind -a '#φ' /dev # efuse
bind -a '#T' /dev # sheeva
bind -a '#B' /dev # boot
@@ -19,9 +19,6 @@
#echo dynamic | run /netrc

echo watchdog off > /dev/sheevactl
-echo debug off > /dev/sdioctl
-#echo init > /dev/sdioctl
-#cat /dev/sdioctl

#echo dossrv
#dossrv -f /dev/sdio -m /n/dos
=======================================
--- /mkfile Sun Feb 21 08:39:58 2010
+++ /mkfile Mon Mar 29 07:16:41 2010
@@ -39,6 +39,8 @@
dat.h\
fns.h\
io.h\
+ part.h\
+ bs.h\

CFLAGS=-wFV -I$ROOT/Inferno/$OBJTYPE/include -I$ROOT/include
-I$ROOT/libinterp
KERNDATE=`{$NDATE}
=======================================
--- /sheeva Wed Mar 17 09:41:13 2010
+++ /sheeva Mon Mar 29 07:16:41 2010
@@ -18,10 +18,11 @@
boot
flash
ftl
- sdio sdcard
+# sdio sdcard
sheeva
efuse
sata
+ bs part

ip
il
@@ -38,6 +39,7 @@
# cesa
# flashnand nand
kwnand
+ kwsdio sdcard

lib
interp

==============================================================================
Revision: eedd513098
Author: Mechiel Lukkien <mec...@ueber.net>
Date: Mon Mar 29 08:40:57 2010
Log: devbs.c improvements.

- rctl,wctl from device is implemented, for file "bsXX/devctl".
- no longer have 100 element array for disks, now just allocated.
- part.c has more sanity checks.
- only one open fd per non-data Part.
- add files "bsXX/raw" and "bsXX/event" for future use.
http://code.google.com/p/inferno-kirkwood/source/detail?r=eedd513098

Modified:
/bs.h
/devbs.c
/kwsdio.c
/part.c
/part.h

=======================================
--- /bs.h Mon Mar 29 07:16:41 2010
+++ /bs.h Mon Mar 29 08:40:57 2010
@@ -13,9 +13,9 @@

void (*init)(Store *d); /* init controller */
void (*diskinit)(Store *d); /* find disk and set size */
- int (*rctl)(Store *d, char *s);
- int (*wctl)(Store *d, char *s);
+ long (*rctl)(Store *d, void *s, long n, vlong off);
+ long (*wctl)(Store *d, void *s, long n);
long (*io)(void *d, int iswrite, void *buf, long n, vlong off);
};

-extern void blockdiskadd(Store *);
+extern void blockstoreadd(Store *);
=======================================
--- /devbs.c Mon Mar 29 07:16:41 2010
+++ /devbs.c Mon Mar 29 08:40:57 2010
@@ -2,13 +2,8 @@
* hot-pluggable block storage devices
*
* todo:
- * - rctl,wctl
* - locking
- * - get rid of disks[100]
- * - allow bs-specific and device-specific ctl ops
* - understand plan 9 partition table
- * - more checks for sanity in part.c (e.g. is within size of disk)
- * - only allow one open per Part ("data" can have more, it is special
anyway)
* - hotplug & events, make event-file per Qdiskpart too.
* - think about returning a type of device, eg "ata", "sdcard"
* - think about raw command access.
@@ -16,6 +11,7 @@
* - add hooks so devices can tell they have gone/arrived.
* - invalidate open files after reinit of device.
* - think of way to update the partition table. for now, write to the
data file, then reinit the device.
+ * - wstat, to change owner/perm
*/

#include "u.h"
@@ -36,25 +32,29 @@
#define QPATH(p,d,t) ((p)<<16 | (d)<<8 | (t)<<0)
enum{
Qdir, Qbsctl, Qbsevent,
- Qdiskdir, Qdiskctl, Qdiskpart,
+ Qdiskdir, Qdiskctl, Qdiskdevctl, Qdiskraw, Qdiskevent, Qdiskpart,
};
static
Dirtab bstab[] = {
".", {Qdir,0,QTDIR}, 0, 0555,
- "bsctl", {Qbsctl}, 0, 0664,
- "bsevent", {Qbsevent}, 0, 0444,
- "xxx", {Qdiskdir,0,QTDIR}, 0, 0554,
- "ctl", {Qdiskctl}, 0, 0664,
+ "bsctl", {Qbsctl}, 0, 0660,
+ "bsevent", {Qbsevent}, 0, 0440,
+ "xxx", {Qdiskdir,0,QTDIR}, 0, 0555,
+ "ctl", {Qdiskctl}, 0, 0660,
+ "devctl", {Qdiskdevctl}, 0, 0660,
+ "raw", {Qdiskraw}, 0, 0660,
+ "event", {Qdiskevent}, 0, 0440,
"xxx", {Qdiskpart}, 0, 0660,
};

static QLock disksl;
-static Store *disks[100]; /* indexed by Store.num */
+static Store **disks = nil; /* indexed by Store.num */
+static int maxdisk = 0; /* highest index of disk */

static Store*
diskget(int num)
{
- if(num >= 0 && num < nelem(disks) && disks[num] != nil)
+ if(num >= 0 && num <= maxdisk && disks[num] != nil)
return disks[num];
return nil;
}
@@ -68,6 +68,45 @@
error(Enodisk);
return d;
}
+
+static void
+partdata(Part *p, vlong size)
+{
+ p->index = 0;
+ p->typ = 0;
+ strcpy(p->name, "data");
+ p->s = 0;
+ p->e = size;
+ p->size = size;
+ strcpy(p->uid, eve);
+ p->perm = 0660;
+ p->isopen = 0;
+}
+
+static void
+diskinit(int num)
+{
+ Store *d;
+
+ d = diskget(num);
+ if(d == nil)
+ error(Enodisk);
+ d->diskinit(d);
+
+ d->parts = smalloc(sizeof d->parts[0]);
+ partdata(&d->parts[0], d->size);
+ if(waserror()) {
+ free(d->parts);
+ d->parts = nil;
+ nexterror();
+ }
+ d->nparts = partinit(d->io, d, d->size, &d->parts);
+ if(d->nparts < 0)
+ error("partinit");
+ poperror();
+
+ d->num = num;
+}

static Part*
partget(Store *d, int i)
@@ -86,19 +125,6 @@
error(Enopart);
return p;
}
-
-static void
-partdata(Part *p, vlong size)
-{
- p->index = 0;
- p->typ = 0;
- strcpy(p->name, "data");
- p->s = 0;
- p->e = size;
- p->size = size;
- strcpy(p->uid, eve);
- p->perm = 0660;
-}

static long
io(Store *d, Part *p, int iswrite, void *buf, long n, vlong off)
@@ -151,7 +177,7 @@
return 1;
}
i -= 2;
- if(i >= nelem(disks))
+ if(i > maxdisk)
return -1;
d = diskget(i);
if(d == nil)
@@ -162,16 +188,19 @@

case Qdiskdir:
case Qdiskctl:
+ case Qdiskdevctl:
+ case Qdiskraw:
+ case Qdiskevent:
case Qdiskpart:
d = diskget(QDISK(c->qid.path));
if(d == nil)
return -1;
- if(i == 0) {
+ if(i >= 0 && i < Qdiskevent-Qdiskctl+1) {
t = &bstab[Qdiskctl+i];
devdir(c, (Qid){QPATH(0,d->num,Qdiskctl+i),0,QTFILE}, t->name,
t->length, eve, t->perm, dp);
return 1;
}
- i -= 1;
+ i -= Qdiskevent-Qdiskctl+1;
if(i >= d->nparts)
return -1;
p = &d->parts[i];
@@ -194,17 +223,16 @@
int i;
Store *d;

- print("bsinit\n");
- for(i = 0; i < nelem(disks); i++) {
+ for(i = 0; i <= maxdisk; i++) {
d = diskget(i);
- if(d != nil) {
- if(waserror()) {
- // xxx mark disk as bad/not yet initialized
- continue;
- }
- d->init(d);
- poperror();
- }
+ if(d == nil)
+ continue;
+ if(waserror()) {
+ // xxx mark disk as bad/not yet initialized
+ continue;
+ }
+ d->init(d);
+ poperror();
}
}

@@ -229,7 +257,21 @@
static Chan*
bsopen(Chan* c, int omode)
{
- return devopen(c, omode, nil, 0, bsgen);
+ Store *d;
+ Part *p = nil;
+
+ if(QTYPE(c->qid.path) == Qdiskpart) {
+ d = xdiskget(QDISK(c->qid.path));
+ p = xpartget(d, QPART(c->qid.path));
+ if(p->index == 0)
+ p = nil;
+ else if(p->isopen)
+ error(Einuse);
+ }
+ c = devopen(c, omode, nil, 0, bsgen);
+ if(p != nil)
+ p->isopen++;
+ return c;
}

static int
@@ -243,7 +285,16 @@
static void
bsclose(Chan* c)
{
- USED(c);
+ Store *d;
+ Part *p;
+
+ if(QTYPE(c->qid.path) == Qdiskpart && c->flag&COPEN &&
QPART(c->qid.path) != 0) {
+ d = xdiskget(QDISK(c->qid.path));
+ p = xpartget(d, QPART(c->qid.path));
+ if(p->isopen != 1)
+ panic("devclose on part.isopen != 1");
+ p->isopen = 0;
+ }
}

static long
@@ -263,6 +314,16 @@
error("not yet");
case Qdiskctl:
error("not yet");
+ case Qdiskdevctl:
+ d = xdiskget(QDISK(c->qid.path));
+ p = xpartget(d, 0);
+ devpermcheck(p->uid, p->perm, OREAD);
+ n = d->rctl(d, a, n, off);
+ break;
+ case Qdiskraw:
+ error("not implemented");
+ case Qdiskevent:
+ error("not yet");
case Qdiskpart:
d = xdiskget(QDISK(c->qid.path));
p = xpartget(d, QPART(c->qid.path));
@@ -279,10 +340,15 @@
enum {
CMinit,
};
-static Cmdtab bsctl[] =
-{
+static Cmdtab bsctl[] = {
CMinit, "init", 2,
};
+enum {
+ CMdiskinit,
+};
+static Cmdtab bsdiskctl[] = {
+ CMdiskinit, "init", 1,
+};

static long
bswrite(Chan* c, void* a, long n, vlong off)
@@ -291,7 +357,7 @@
Cmdtab *ct;
Store *d;
Part *p;
- ulong num;
+ int num;

qlock(&disksl);
if(waserror()) {
@@ -312,25 +378,8 @@
ct = lookupcmd(cb, bsctl, nelem(bsctl));
switch(ct->index) {
case CMinit:
- num = strtoul(cb->f[1], nil, 10);
- d = diskget(num);
- if(d == nil)
- error(Enodisk);
- d->diskinit(d);
-
- d->parts = smalloc(sizeof d->parts[0]);
- partdata(&d->parts[0], d->size);
- if(waserror()) {
- free(d->parts);
- d->parts = nil;
- nexterror();
- }
- d->nparts = partinit(d->io, d, &d->parts);
- if(d->nparts < 0)
- error("partinit");
- poperror();
-
- d->num = num;
+ num = atoi(cb->f[1]);
+ diskinit(num);
break;
}
poperror();
@@ -340,6 +389,41 @@
case Qbsevent:
error("not yet");

+ case Qdiskctl:
+ d = xdiskget(QDISK(c->qid.path));
+ p = partget(d, 0);
+ if(p != nil)
+ devpermcheck(p->uid, p->perm, OWRITE);
+ else if(!iseve())
+ error(Eperm);
+
+ cb = parsecmd(a, n);
+ if(waserror()) {
+ free(cb);
+ nexterror();
+ }
+ ct = lookupcmd(cb, bsdiskctl, nelem(bsdiskctl));
+ switch(ct->index) {
+ case CMdiskinit:
+ diskinit(d->num);
+ break;
+ }
+ poperror();
+ free(cb);
+ break;
+
+ case Qdiskdevctl:
+ if(off != 0)
+ error(Ebadarg);
+ d = xdiskget(QDISK(c->qid.path));
+ p = xpartget(d, 0);
+ devpermcheck(p->uid, p->perm, OWRITE);
+ n = d->wctl(d, a, n);
+ break;
+
+ case Qdiskraw:
+ error("not implemented");
+
case Qdiskpart:
d = xdiskget(QDISK(c->qid.path));
p = xpartget(d, QPART(c->qid.path));
@@ -376,13 +460,22 @@
};

void
-blockdiskadd(Store *d)
-{
- iprint("blockdiskadd, num %d \n", d->num);
-
+blockstoreadd(Store *d)
+{
qlock(&disksl);
+ if(d->num > 99)
+ panic("bad block store num %d", d->num);
if(diskget(d->num) != nil)
panic("disk.num %d already registered", d->num);
+
+ if(d->num > maxdisk) {
+ disks = realloc(disks, sizeof disks[0]*(d->num+1));
+ if(disks == nil)
+ panic("no memory");
+ while(maxdisk < d->num)
+ disks[maxdisk++] = nil;
+ }
+
disks[d->num] = d;
snprint(d->name, sizeof d->name, "bs%02d", d->num);
qunlock(&disksl);
=======================================
--- /kwsdio.c Mon Mar 29 07:16:41 2010
+++ /kwsdio.c Mon Mar 29 08:40:57 2010
@@ -258,6 +258,7 @@
{
char *p, *e;

+ USED(s);
if(!DEBUG)
return;

@@ -739,7 +740,7 @@
}

static void
-sdioinit(Store *d)
+sdioinit(Store *)
{
SdioReg *r = SDIOREG;

@@ -818,18 +819,18 @@
free(buf);
*/

-static int
-sdiorctl(Store *d, char *s)
-{
- USED(d, s);
+static long
+sdiorctl(Store *d, void *s, long n, vlong off)
+{
+ USED(d, s, n, off);
print("sdiorctl\n");
return -1;
}

-static int
-sdiowctl(Store *d, char *s)
-{
- USED(d, s);
+static long
+sdiowctl(Store *d, void *s, long n)
+{
+ USED(d, s, n);
print("sdiowctl\n");
return -1;
}
@@ -850,11 +851,11 @@


static Store sdiodisk = {
- .init = sdioinit,
- .diskinit = sdiodiskinit,
- .rctl = sdiorctl,
- .wctl = sdiowctl,
- .io = sdioio,
+.init = sdioinit,
+.diskinit = sdiodiskinit,
+.rctl = sdiorctl,
+.wctl = sdiowctl,
+.io = sdioio,
};

void
@@ -863,5 +864,5 @@
print("kwsdiolink\n");
sdioreset();
sdiodisk.num = 2;
- blockdiskadd(&sdiodisk);
-}
+ blockstoreadd(&sdiodisk);
+}
=======================================
--- /part.c Mon Mar 29 07:16:41 2010
+++ /part.c Mon Mar 29 08:40:57 2010
@@ -13,15 +13,16 @@
}

int
-partinit(long (*r)(void *, int, void *, long, vlong), void *disk, Part
**partsp)
+partinit(long (*r)(void *, int, void *, long, vlong), void *disk, vlong
size, Part **partsp)
{
uchar buf[512+63];
uchar *p = (void*)(((ulong)buf+63)&~63);
long n;
- int i, o;
+ int i, j, o;
Part part;
int nparts = 1;
Part *parts = *partsp;
+ vlong js, je;

n = r(disk, 0, p, 512, 0);
if(n != 512)
@@ -42,6 +43,18 @@
part.e = part.s+part.size;
strcpy(part.uid, eve);
part.perm = 0660;
+ part.isopen = 0;
+
+ if(part.e > size)
+ error("partition beyond end of disk");
+ /* do not allow overlapping partitions, note that first Part is whole
disk */
+ for(j = 1; j < nparts; j++) {
+ js = parts[j].s;
+ je = parts[j].e;
+ if(js >= part.s && js < part.e || je > part.s && je <= part.e)
+ error("overlapping partitions");
+ }
+
print("part, index %d, typ 0x%ux, name %s, s %lld, e %lld, size %lld\n",
(int)part.index, (uint)part.typ, part.name, part.s, part.e, part.size);
parts = realloc(parts, sizeof parts[0]*(nparts+1));
=======================================
--- /part.h Mon Mar 29 07:16:41 2010
+++ /part.h Mon Mar 29 08:40:57 2010
@@ -11,6 +11,7 @@

char uid[KNAMELEN];
ulong perm;
+ int isopen; /* only for non-data Part */
};

-int partinit(long (*read)(void *disk, int iswrite, void *buf, long n,
vlong off), void *disk, Part **parts);
+int partinit(long (*read)(void *disk, int iswrite, void *buf, long n,
vlong off), void *disk, vlong size, Part **parts);

==============================================================================
Revision: 483ef6195d
Author: Mechiel Lukkien <mec...@ueber.net>
Date: Mon Mar 29 10:29:30 2010
Log: understand plan 9-style partitions.
http://code.google.com/p/inferno-kirkwood/source/detail?r=483ef6195d

Modified:
/devbs.c
/part.c

=======================================
--- /devbs.c Mon Mar 29 08:40:57 2010
+++ /devbs.c Mon Mar 29 10:29:30 2010
@@ -3,7 +3,7 @@
*
* todo:
* - locking
- * - understand plan 9 partition table
+ * - understand extended partitions
* - hotplug & events, make event-file per Qdiskpart too.
* - think about returning a type of device, eg "ata", "sdcard"
* - think about raw command access.
=======================================
--- /part.c Mon Mar 29 08:40:57 2010
+++ /part.c Mon Mar 29 10:29:30 2010
@@ -6,23 +6,123 @@
#include "../port/error.h"
#include "part.h"

+static char Elongname[] = "partition name too long";
+
static ulong
g32(uchar *p)
{
return (ulong)p[3]<<24 | (ulong)p[2]<<16 | (ulong)p[1]<<8 |
(ulong)p[0]<<0;
}
+
+static int
+haspartname(Part *p, int np, char *s)
+{
+ int i;
+ for(i = 0; i < np; i++)
+ if(strcmp(p[i].name, s) == 0)
+ return 1;
+ return 0;
+}
+
+static void
+partgenname(Part *pp, Part *parts, int nparts, char *first, char *next)
+{
+ int i;
+ char *p = pp->name;
+ char *e = p+sizeof pp->name;
+
+ if(!haspartname(parts, nparts, first)) {
+ if(seprint(p, e, "%s", first) == e)
+ error(Elongname);
+ return;
+ }
+
+ p = seprint(p, e, "%s.", next);
+ for(i = 0;; i++) {
+ if(seprint(p, e, "%d", i) == e)
+ error(Elongname);
+ if(!haspartname(parts, nparts, pp->name))
+ break;
+ }
+}
+
+static void
+partname(Part *p, Part *parts, int nparts, int i)
+{
+ switch(p->typ) {
+ case 0x39: /* plan 9 */
+ partgenname(p, parts, nparts, "plan9", "plan9");
+ break;
+ case 0x01: /* dos fat-12 */
+ case 0x04: /* dos fat-16 */
+ case 0x06: /* dos > 32mb */
+ case 0x0b: /* fat32 */
+ case 0x0c: /* fat32-l */
+ case 0x0e: /* dos fat-16 */
+ partgenname(p, parts, nparts, "9fat", "dos");
+ break;
+ default:
+ snprint(p->name, sizeof p->name, "p%d", i);
+ }
+}
+
+static void
+partcheck(Part *p, Part *parts, int nparts, vlong size)
+{
+ int i;
+ vlong js, je;
+
+ if(p->e > size)
+ error("partition beyond end of disk");
+ if(p->s > p->e)
+ error("bad partition, start > end");
+
+ /* do not allow overlapping partitions, note that first Part is whole
disk */
+ for(i = 1; i < nparts; i++) {
+ js = parts[i].s;
+ je = parts[i].e;
+ if(js >= p->s && js < p->e || je > p->s && je <= p->e)
+ error("overlapping partitions");
+ }
+}
+
+static void
+partclear(Part *p)
+{
+ strcpy(p->uid, eve);
+ p->perm = 0660;
+ p->isopen = 0;
+}
+
+static Part*
+partalloc(Part *p, int np)
+{
+ p = realloc(p, sizeof p[0]*(np+1));
+ if(p == nil)
+ error(Enomem);
+ return p;
+}
+
+static void
+printpartadd(Part *p)
+{
+ print("partadd, index %d, typ 0x%02ux, name %s, s %lld, e %lld,
size %lld\n",
+ (int)p->index, (uint)p->typ, p->name, p->s, p->e, p->size);
+}

int
partinit(long (*r)(void *, int, void *, long, vlong), void *disk, vlong
size, Part **partsp)
{
- uchar buf[512+63];
+ uchar buf[512+63+1];
uchar *p = (void*)(((ulong)buf+63)&~63);
long n;
- int i, j, o;
- Part part;
+ int i, end, o;
+ Part *pp;
int nparts = 1;
Part *parts = *partsp;
- vlong js, je;
+ char *s, *e;
+ char *f[3];
+ int nf;

n = r(disk, 0, p, 512, 0);
if(n != 512)
@@ -31,37 +131,61 @@
if(p[510] != 0x55 || p[511] != 0xaa)
error("missing mbr signature");

+ /* partitions from mbr partition table */
for(i = 0; i < 4; i++) {
o = 446+i*16;
- part.typ = p[o+0x4];
- if(part.typ == 0)
+
+ *partsp = parts = partalloc(parts, nparts);
+ pp = &parts[nparts];
+ partclear(pp);
+ pp->index = nparts;
+ pp->typ = p[o+0x4];
+ if(pp->typ == 0)
continue;
- part.index = nparts;
- snprint(part.name, sizeof part.name, "p%02d", i);
- part.s = (vlong)g32(p+o+0x8)*512;
- part.size = (vlong)g32(p+o+0xc)*512;
- part.e = part.s+part.size;
- strcpy(part.uid, eve);
- part.perm = 0660;
- part.isopen = 0;
-
- if(part.e > size)
- error("partition beyond end of disk");
- /* do not allow overlapping partitions, note that first Part is whole
disk */
- for(j = 1; j < nparts; j++) {
- js = parts[j].s;
- je = parts[j].e;
- if(js >= part.s && js < part.e || je > part.s && je <= part.e)
- error("overlapping partitions");
- }
-
- print("part, index %d, typ 0x%ux, name %s, s %lld, e %lld, size %lld\n",
- (int)part.index, (uint)part.typ, part.name, part.s, part.e, part.size);
- parts = realloc(parts, sizeof parts[0]*(nparts+1));
- if(parts == nil)
- error(Enomem);
- *partsp = parts;
- memmove(&parts[nparts++], &part, sizeof part);
+ partname(pp, parts, nparts, i);
+ pp->s = (vlong)g32(p+o+0x8)*512;
+ pp->size = (vlong)g32(p+o+0xc)*512;
+ pp->e = pp->s+pp->size;
+
+ partcheck(pp, parts, nparts, size);
+ nparts++;
+ printpartadd(pp);
+ }
+
+ /* set up partitions in the plan 9 parts */
+ end = nparts;
+ for(i = 1; i < end; i++) {
+ pp = &parts[i];
+ if(pp->typ != 0x39 || pp->size < 2*512)
+ continue;
+
+ n = r(disk, 0, p, 512, pp->s+512);
+ if(n != 512)
+ error("reading plan 9 partition table");
+ p[512] = 0;
+ s = (char*)p;
+ while(s < (char*)p+512) {
+ e = strchr(s, '\n');
+ if(e == nil)
+ break;
+ *e = 0;
+ nf = tokenize(s, f, nelem(f));
+ if(nf != 3)
+ error("bad plan 9 partition table");
+ s = e+1;
+
+ *partsp = parts = partalloc(parts, nparts);
+ pp = &parts[nparts];
+ partclear(pp);
+ pp->index = nparts;
+ partgenname(pp, parts, nparts, f[0], f[0]);
+ pp->s = (vlong)strtoull(f[1], nil, 0)*512;
+ pp->e = (vlong)strtoull(f[2], nil, 0)*512;
+ pp->size = pp->e-pp->s;
+ partcheck(pp, parts, nparts, size);
+ nparts++;
+ printpartadd(pp);
+ }
}

return nparts;

==============================================================================
Revision: 22b3a6c999
Author: Mechiel Lukkien <mec...@ueber.net>
Date: Mon Mar 29 10:38:56 2010
Log: remove the old devsdio.c; add useful rctl() for kwsdio.c
http://code.google.com/p/inferno-kirkwood/source/detail?r=22b3a6c999

Deleted:
/devsdio.c
Modified:
/kwsdio.c
/sdcard.c
/sdcard.h

=======================================
--- /devsdio.c Sun Mar 28 15:22:01 2010
+++ /dev/null
@@ -1,970 +0,0 @@
-/*
- * only memory cards are supported (not sdio). only sd cards for now, mmc
cards seem obsolete anyway.
- *
- * todo:
- * - don't crash when proc doing read/write is killed.
- * - hook into devsd.c?
- * - wait reading dat[0] in hoststate for r1b responses?
- * - read scr register and use it to determine if card supports 4bit data
bus
- * - see if we can detect device inserts/ejects? yes, by sd_cd gpio pin
(on mpp47).
- * - ctl commands for erasing?
- * - erase before writing big buffer?
- */
-
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "../port/error.h"
-#include "io.h"
-#include "sdcard.h"
-
-#define DEBUG 0
-#define dprint if(DEBUG)print
-
-char Enocard[] = "no card";
-
-enum {
- /* keep in sync with errstrs[] */
- SDOk = 0,
- SDTimeout = -1,
- SDCardbusy = -2,
- SDError = -3,
- SDInterrupted = -4,
- SDBadstatus = -5, /* status in r1(b) response indicated error, see
card.status */
-
- /* expected response to command */
- R0 = 0,
- R1,
- R1b,
- R2,
- R3,
- R6,
- R7,
-
- /* flags for sdcmd and sdcmddma */
- Fapp = 1<<0, /* app-specific command */
- Fappdata= 1<<1, /* app-specific data command */
- Fdmad2h = 1<<2, /* dma from device to host */
- Fdmah2d = 1<<3, /* dma from host to device */
- Fmulti = 1<<4, /* multiple blocks, use auto cmd 12 to stop transfer */
-};
-
-enum {
- /* transfer mode */
- /* note: the doc bits is contradictory on these bits. comments below
indicate actual behaviour. */
- TMdatawrite = 1<<1, /* write data after response, for write commands */
- TMautocmd12 = 1<<2, /* hardware sends cmd12 */
- TMxfertohost = 1<<4, /* data flows from sd to host */
- TMswwrite = 1<<6, /* software-controlled, not dma */
-
- /* cmd */
- Respnone = 0<<0,
- Resp136 = 1<<0,
- Resp48 = 2<<0,
- Resp48busy = 3<<0,
-
- CMDdatacrccheck = 1<<2,
- CMDcmdcrccheck = 1<<3,
- CMDcmdindexcheck= 1<<4,
- CMDdatapresent = 1<<5,
- CMDunexpresp = 1<<7,
- CMDshift = 8,
-
- /* hoststate */
- HScmdinhibit = 1<<0,
- HScardbusy = 1<<1,
- HSdatshift = 3,
- HStxactive = 1<<8,
- HSrxactive = 1<<9,
- HSfifofull = 1<<12,
- HSfifoempty = 1<<13,
- HSacmd12active = 1<<14,
-
- /* hostctl */
- HCpushpull = 1<<0,
- HCcardmask = 3<<1,
- HCcardmemonly = 0<<1,
- HCcardioonly = 1<<1,
- HCcardiomem = 2<<1,
- HCcardmmc = 3<<1,
- HCbigendian = 1<<3,
- HClsbfirst = 1<<4,
- HCdatawidth4 = 1<<9,
- HChighspeed = 1<<10,
-#define HCtimeout(x) (((x) & MASK(4))<<11)
- HCtimeoutenable = 1<<15,
-
- /* swreset */
- SRresetall = 1<<8,
-
- /* st, status */
- Scmdcomplete = 1<<0,
- Sxfercomplete = 1<<1,
- Sblockgapevent = 1<<2,
- Sdmaintr = 1<<3,
- Stxready = 1<<4,
- Srxready = 1<<5,
- Scardintr = 1<<8,
- Sreadwaiton = 1<<9,
- Sfifo8wfull = 1<<10,
- Sfifo8wavail = 1<<11,
- Ssuspended = 1<<12,
- Sautocmd12done = 1<<13,
- Sunexpresp = 1<<14,
- Serror = 1<<15,
-
- /* est, error status */
- Ecmdtimeout = 1<<0,
- Ecmdcrc = 1<<1,
- Ecmdendbit = 1<<2,
- Ecmdindex = 1<<3,
- Edatatimeout = 1<<4,
- Erddatacrc = 1<<5,
- Erddataend = 1<<6,
- Eautocmd12 = 1<<8,
- Ecmdstartbit = 1<<9,
- Exfersize = 1<<10,
- Eresptbit = 1<<11,
- Ecrcendbit = 1<<12,
- Ecrcstartbit = 1<<13,
- Ecrcstatus = 1<<14,
-
- /* autocmd12 index */
- AIcheckbusy = 1<<0,
- AIcheckindex = 1<<1,
- AIcmdshift = 8,
-};
-
-enum {
- /* sd commands */
- CMDRead = 17,
- CMDReadmulti = 18,
- CMDWrite = 24,
- CMDWritemulti = 25,
-
- ACMDGetscr = 51,
-
-
- CMD8pattern = 0xaa,
- CMD8patternmask = MASK(8),
- CMD8voltage = 1<<8,
- CMD8voltagemask = MASK(4)<<8,
-
- ACMD41voltagewindow = MASK(23-15+1)<<15,
- ACMD41sdhcsupported = 1<<30,
- ACMD41ready = 1<<31,
-
-
- /* sd status, in R1 & R1b responses */
- SDappcmd = 1<<5, /* next command will be interpreted as app specific */
- SDreadyfordata = 1<<8, /* buffer empty signal on bus */
- SDstateshift = 9,
- SDstatewidth = 4,
- SDnoecc = 1<<14, /* command executed without ecc */
- SDerror = 1<<19, /* general/unknown error */
- SDccerror = 1<<20, /* internal card controller error */
- SDbadcmd = 1<<22, /* invalid command */
- SDblocklenerr = 1<<29, /* block length invalid */
-
- /* bits we consider as error. some indicate conditions we don't (yet)
handle. */
- SDbad = 1<<3|1<<13|1<<14|1<<15|1<<16|MASK(13)<<19,
-};
-
-
-static Card card;
-static Rendez cmdr;
-static QLock sdl;
-
-enum {
- Qdir, Qctl, Qinfo, Qdata, Qstatus,
-};
-static
-Dirtab sdiotab[] = {
- ".", {Qdir, 0, QTDIR}, 0, 0555,
- "sdioctl", {Qctl}, 0, 0666,
- "sdioinfo", {Qinfo}, 0, 0444,
- "sdio", {Qdata}, 0, 0666,
- "sdiostatus", {Qstatus}, 0, 0444,
-};
-
-
-/* for bits in st, est, acmd12st registers */
-static const char *statusstrs[] = {
-"cmdcomplete", "xfercomplete", "blockgapevent", "dmaintr",
-"txready", "rxready", "", "",
-"cardintr", "readwaiton", "fifo8wfull", "fifo8wavail",
-"suspended", "autocmd12done", "unexpresp", "errorintr",
-};
-
-static const char *errstatusstrs[] = {
-"cmdtimeout", "cmdcrc", "cmdendbit", "cmdindex",
-"datatimeout", "rddatacrc", "rddataend", "",
-"autocmd12", "cmdstartbit", "xfersize", "resptbit",
-"crcendbit", "crcstartbit", "crcstatus",
-};
-
-static const char *acmd12ststrs[] = {
-"acmd12notexe", "acmd12timeout", "acmd12crcerr", "acmd12endbiterr",
-"acmd12indexerr", "acmd12resptbi", "acmd12respstartbiterr",
-};
-
-static const char *sdstatusstrs[] = {
-"tm0", "tm1", "apprsvd", "akeseqerr",
-"sdiorsvd", "appcmd", "rsvd6", "rsvd7",
-"readyfordata", "st9", "st10", "st11",
-"st12", "erasereset", "noecc", "wperaseskip",
-"csdoverwrite", "rsvd17", "rsvd18", "error",
-"ccerror", "eccfail", "badcmd", "cmdcrcerr",
-"lockerr", "locked", "wpviolation", "eraseparam",
-"eraseseqerr", "blocklenerr", "addrerr", "outofrange",
-};
-
-static char*
-mkstr(char *p, char *e, ulong v, char **s, int ns)
-{
- int i;
- for(i = 0; i < ns; i++)
- if(v & 1<<i)
- p = seprint(p, e, " %q", s[i]);
- return p;
-}
-
-static char*
-statusstr(char *p, char *e, ulong v)
-{
- return mkstr(p, e, v, statusstrs, nelem(statusstrs));
-}
-
-static char*
-errstatusstr(char *p, char *e, ulong v)
-{
- return mkstr(p, e, v, errstatusstrs, nelem(errstatusstrs));
-}
-
-static char*
-acmd12ststr(char *p, char *e, ulong v)
-{
- return mkstr(p, e, v, acmd12ststrs, nelem(acmd12ststrs));
-}
-
-static char *
-sdstatusstr(char *p, char *e, ulong v)
-{
- return mkstr(p, e, v, sdstatusstrs, nelem(sdstatusstrs));
-}
-
-static const char *statestrs[] = {
-"idle", "ready", "ident", "stby",
-"tran", "data", "rcv", "prg",
-"dis", "", "", "",
-"", "", "", "",
-};
-
-static void
-printstatus(char *s, ulong st, ulong est, ulong acmd12st)
-{
- char *p, *e;
-
- if(!DEBUG)
- return;
-
- p = up->genbuf;
- e = p+sizeof (up->genbuf);
-
- p = statusstr(p, e, st);
- p = seprint(p, e, ";");
- p = errstatusstr(p, e, est);
- p = seprint(p, e, ";");
- p = acmd12ststr(p, e, acmd12st);
- USED(p);
-
- print("status: %s%s\n", s, up->genbuf);
-}
-
-
-static const char *errstrs[] = {
-"success", "timeout", "card busy", "error", "interrupted", "badstatus",
-};
-
-static void
-errorsd(char *s, int v)
-{
- char buf[ERRMAX];
- char * p = buf;
- char * const e = buf+sizeof buf;
-
- p = seprint(p, e, "%s", s);
- if(v != SDOk)
- p = seprint(p, e, ": %s", errstrs[-v]);
- if(v == SDBadstatus)
- p = seprint(p, e, " (r1status %#lux)", card.status);
- if(v == SDError) {
- p = seprint(p, e, " (est %#lux", card.status);
- p = errstatusstr(p, e, card.status);
- p = seprint(p, e, ")");
- }
- USED(p);
- error(buf);
-}
-
-static int
-sdiodone(void *p)
-{
- SdioReg *r = SDIOREG;
- ulong v = *(ulong *)p;
-
- if(r->st & v) {
- r->stirq = 0;
- return 1;
- }
- return 0;
-}
-
-/* keep in sync with R* contants */
-static const ulong resptypes[] = {
-Respnone, Resp48, Resp48busy, Resp136, Resp48, Resp48, Resp48,
-};
-static int
-sdcmd(Card *c, ulong cmd, ulong arg, int rt, ulong fl)
-{
- SdioReg *r = SDIOREG;
- int i, s;
- ulong acmd;
- ulong cmdopts, mode;
- ulong need, v;
- uvlong w;
-
- print("sdcmd, cmd %lud, arg %lud, fl %#lux\n", cmd, arg, fl);
-
- i = 0;
- for(;;) {
- if((r->hoststate & (HScmdinhibit|HScardbusy)) == 0)
- break;
- if(i++ >= 50)
- return SDCardbusy;
- tsleep(&up->sleep, return0, nil, i);
- }
-
- if(fl & (Fapp|Fappdata)) {
- acmd = 55;
- if(fl & Fappdata)
- acmd = 56;
- s = sdcmd(c, acmd, card.rca<<16, R1, 0);
- if(s < 0)
- return s;
- if((c->resp[2]>>8 & SDappcmd) == 0)
- return SDBadstatus;
- }
-
- /* clear status */
- r->st = ~0;
- r->est = ~0;
- r->acmd12st = ~0;
- // xxx remove?
- printstatus("before cmd: ", r->st, r->est, r->acmd12st);
-
- /* prepare args & execute command */
- r->arglo = arg>>0 & MASK(16);
- r->arghi = arg>>16 & MASK(16);
- cmdopts = CMDunexpresp;
- mode = 0;
- if(fl & Fdmad2h)
- mode |= TMxfertohost;
- if(fl & Fdmah2d)
- mode |= TMdatawrite;
- if(fl & Fmulti) {
- mode |= TMautocmd12;
- r->acmd12arglo = 0;
- r->acmd12arghi = 0;
- r->acmd12idx = AIcheckbusy|AIcheckindex|12<<AIcmdshift;
- }
- if(fl & (Fdmad2h|Fdmah2d))
- cmdopts |= CMDdatapresent;
- if(fl & Fdmad2h)
- cmdopts |= CMDdatacrccheck;
- if(rt != R0 && rt != R3)
- cmdopts |= CMDcmdcrccheck;
- if(rt != R0 && rt != R2 && rt != R3)
- cmdopts |= CMDcmdindexcheck;
- r->mode = mode;
- r->cmd = cmd<<CMDshift|cmdopts|resptypes[rt];
-
- /* Scmdcomplete/Sdma and errors signal completion */
- s = 0;
- need = Scmdcomplete;
- if(fl & (Fdmad2h|Fdmah2d))
- need = Sdmaintr;
- r->stirq = need|Sunexpresp|Serror;
- r->estirq = ~0;
-
- while(waserror())
- s = SDInterrupted;
- v = r->stirq;
- tsleep(&cmdr, sdiodone, &v, 5000);
- poperror();
- if(s == SDInterrupted)
- return s;
-
- if(r->st & (Sunexpresp|Serror)) {
- card.status = r->est;
- return SDError;
- }
- if((r->st & need) == 0)
- return SDTimeout;
-
- printstatus("success", r->st, r->est, r->acmd12st);
-
- /* fetch the response */
- memset(c->resp, 0, sizeof c->resp);
- switch(resptypes[rt]) {
- case Respnone:
- break;
- case Resp136:
- c->resp[0] = (uvlong)r->resp[0]>>10;
-
- w = 0;
- w |= (uvlong)r->resp[4]>>10;
- w |= (uvlong)r->resp[3]<<(70-64);
- w |= (uvlong)r->resp[2]<<(86-64);
- w |= (uvlong)r->resp[1]<<(102-64);
- w |= (uvlong)r->resp[0]<<(118-64);
- c->resp[1] = w;
-
- w = r->crc7<<1;
- w |= ((uvlong)r->resp[7] & MASK(14))<<8;
- w |= (uvlong)r->resp[6]<<22;
- w |= (uvlong)r->resp[5]<<38;
- w |= (uvlong)r->resp[4]<<54;
- c->resp[2] = w;
-
- break;
- case Resp48:
- case Resp48busy:
- w = r->crc7<<1;
- w |= ((uvlong)r->resp[2] & MASK(6))<<8;
- w |= (uvlong)r->resp[1]<<14;
- w |= (uvlong)r->resp[0]<<30;
- c->resp[0] = 0;
- c->resp[1] = 0;
- c->resp[2] = w;
- break;
- }
-
- if(rt == R1 || rt == R1b) {
- c->status = c->resp[2]>>8;
- if(c->status & SDbad)
- return SDBadstatus;
- }
- return 0;
-}
-
-static int
-sdcmddma(Card *c, ulong cmd, ulong arg, void *a, int blsz, int nbl, int
resp, ulong fl)
-{
- SdioReg *r = SDIOREG;
-
- dcwbinv(a, blsz*nbl);
- r->dmaaddrlo = (ulong)a & MASK(16);
- r->dmaaddrhi = (ulong)a>>16 & MASK(16);
- r->blksize = blsz;
- r->blkcount = nbl;
- dprint("sdcmddma, a %#lux, dmaddrlo %#lux dmaadrhi %#lux blksize %d
blkcount %d cmdarg %#lux\n",
- a, (ulong)a & MASK(16), (ulong)a>>16 & MASK(16), blsz, nbl, arg);
- return sdcmd(c, cmd, arg, resp, fl);
-}
-
-static void
-sdclock(ulong v)
-{
- SDIOREG->clockdiv = ((100*1000*1000)/v)-1;
- delay(1);
-}
-
-static void
-sdinit(void)
-{
- int i, s;
- ulong v;
- SdioReg *r = SDIOREG;
-
- sdclock(400*1000);
- r->hostctl &= ~HChighspeed;
-
- /* force card to idle state */
- s = sdcmd(&card, 0, 0, R0, 0);
- if(s < 0)
- errorsd("reset failed", s);
-
- /*
- * "send interface command". only >=2.00 cards will respond.
- * we send a check pattern and supported voltage range.
- */
- card.mmc = 0;
- card.sd2 = 0;
- card.sdhc = 0;
- card.rca = 0;
- s = sdcmd(&card, 8, CMD8voltage|CMD8pattern, R7, 0);
- switch(s) {
- case SDOk:
- card.sd2 = 1;
- v = card.resp[2]>>8;
- if((v & CMD8patternmask) != CMD8pattern)
- error("check pattern mismatch");
- if((v & CMD8voltagemask) != CMD8voltage)
- error("voltage not supported");
- break;
-
- case SDTimeout:
- case SDError: /* "no response" from spec can result in error too
apparently */
- /* sd 1.x or not an sd memory card */
- s = sdcmd(&card, 0, 0, R0, 0);
- if(s < 0)
- errorsd("reset failed", s);
- break;
- default:
- errorsd("voltage exchange failed", s);
- }
-
- /*
- * "send host capacity support information".
- * we send supported voltages & our sdhc support.
- * mmc cards won't respond. sd cards will power up and indicate
- * if they support sdhc.
- */
- i = 0;
- for(;;) {
- v = ACMD41voltagewindow;
- if(card.sd2)
- v |= ACMD41sdhcsupported;
- s = sdcmd(&card, 41, v, R3, Fapp);
- if(s < 0) {
- if(s == SDTimeout && !card.sd2)
- card.mmc = 1;
- errorsd("exchange voltage/sdhc support info", s);
- }
- v = card.resp[2]>>8;
- if((v & ACMD41voltagewindow) == 0)
- error("voltage not supported");
- if(v & ACMD41ready) {
- card.sdhc = (v & ACMD41sdhcsupported) != 0;
- break;
- }
-
- if(i++ >= 100)
- error("sd card failed to power up");
- tsleep(&up->sleep, return0, nil, 10);
- }
- dprint("acmd41 done, mmc %d, sd2 %d, sdhc %d\n", card.mmc, card.sd2,
card.sdhc);
- if(card.mmc)
- error("mmc cards not yet supported"); // xxx p14 says this involves
sending cmd1
-
- s = sdcmd(&card, 2, 0, R2, 0);
- if(s < 0)
- errorsd("card identification", s);
- if(parsecid(&card.cid, card.resp) < 0)
- error("bad cid register");
-
- i = 0;
- for(;;) {
- s = sdcmd(&card, 3, 0, R6, 0);
- if(s < 0)
- errorsd("getting relative address", s);
- card.rca = card.resp[2]>>24 & MASK(16);
- v = card.resp[2]>>8 & MASK(16);
- dprint("have card rca %ux, status %lux\n", card.rca, v);
- USED(v);
- if(card.rca != 0)
- break;
- if(i++ == 10)
- error("card insists on invalid rca 0");
- }
-
- s = sdcmd(&card, 9, card.rca<<16, R2, 0);
- if(s < 0)
- errorsd("get csd", s);
- if(parsecsd(&card.csd, card.resp) < 0)
- error("bad csd register");
-
- if(card.csd.vers == 0) {
- card.bs = 1<<card.csd.rbl;
- card.size = card.csd.size+1;
- card.size *= 1<<(card.csd.v0.sizemult+2);
- card.size *= 1<<card.csd.rbl;
- print("csd0, block length read/write %d/%d, size %lld bytes,
eraseblock %d\n",
- 1<<card.csd.rbl,
- 1<<card.csd.wbl,
- card.size,
- (1<<card.csd.wbl)*(card.csd.erasesecsz+1));
- } else {
- card.bs = 512;
- card.size = (vlong)(card.csd.size+1)*card.bs*1024;
- print("csd1, fixed 512 block length, size %lld bytes, eraseblock fixed
512\n", card.size);
- }
-
- if(card.sdhc) {
- dprint("enabling sdhc & setting clock to 50mhz\n");
- sdclock(50*1000*1000);
- r->hostctl |= HChighspeed;
- } else {
- dprint("leaving sdhc off & setting clock to 25mhz\n");
- sdclock(25*1000*1000);
- }
-
- s = sdcmd(&card, 7, card.rca<<16, R1b, 0);
- if(s < 0)
- errorsd("selecting card", s);
-
- /* xxx have to check with scr register if 4bit buswidth is supported by
card. have not been able to read it though... */
- s = sdcmd(&card, 6, 1<<1, R1, Fapp);
- if(s < 0)
- errorsd("setting buswidth to 4-bit", s);
-
- s = sdcmd(&card, 16, 512, R1, 0);
- if(s < 0)
- errorsd("setting 512 byte blocksize", s);
-
- sdiotab[Qdata].length = card.size;
- card.valid = 1;
- print("%s", cardstr(&card, up->genbuf, sizeof (up->genbuf)));
-}
-
-static int
-sdstatus(uchar *p)
-{
- return sdcmddma(&card, 13, 0, p, 64, 1, R1, Fapp|Fdmad2h);
-}
-
-static int
-erase(vlong offset, long n)
-{
- vlong e;
- int s;
-
- e = offset+n;
- if(card.sdhc) {
- e -= 512;
- offset /= 512;
- e /= 512;
- } else
- e -= 1;
-
- s = sdcmd(&card, 32, offset, R1, 0); /* first addr to erase */
- if(s >= 0)
- s = sdcmd(&card, 33, e, R1, 0); /* last addr to erase (inclusive) */
- if(s >= 0)
- s = sdcmd(&card, 38, 0, R1b, 0); /* start erasing */
- return s;
-}
-
-static long
-sdio(uchar *a, long n, vlong offset, int iswrite)
-{
- ulong cmd, arg, fl, h, nn;
- int s;
-
- if(card.valid == 0)
- error(Enocard);
-
- /* xxx we should cover this case with a buffer, and then use the same
code to allow non-sector-aligned reads? */
- if((ulong)a % 4 != 0)
- error("bad buffer alignment...");
-
- if(offset & (512-1))
- error("not sector aligned");
- if(n & (512-1))
- error("not multiple of sector size");
-
- cmd = CMDReadmulti;
- fl = Fdmad2h;
- if(iswrite) {
- cmd = CMDWritemulti;
- fl = Fdmah2d;
- }
-
- h = 0;
- for(;;) {
- if(card.sdhc)
- arg = (offset+h)/512;
- else
- arg = offset+h;
- nn = n;
- if(nn > 512*1024)
- nn = 512*1024;
- if(iswrite) {
- s = sdcmd(&card, 23, nn/512, R1, Fapp);
- if(s < 0)
- errorsd("erase before write", s);
- }
- s = sdcmddma(&card, cmd, arg, a+h, 512, nn/512, R1, fl|Fmulti);
- if(s < 0)
- errorsd("io", s);
- h += nn;
- if(h >= n)
- break;
-
- /* give others a chance */
- if(waserror()) {
- qlock(&sdl);
- nexterror();
- }
- qunlock(&sdl);
- poperror();
- qlock(&sdl);
- }
- return n;
-}
-
-static void
-sdiointr(Ureg*, void*)
-{
- SdioReg *r = SDIOREG;
-
- /* disable interrupt, st & est are unchanged, caller reads & clears them
before next cmd. */
- r->stirq = 0;
- r->estirq = 0;
- intrclear(Irqlo, IRQ0sdio);
- wakeup(&cmdr);
-}
-
-static void
-sdioreset(void)
-{
- SdioReg *r = SDIOREG;
-
- /* disable all interrupts. dma interrupt will be enabled as required.
all bits lead to IRQ0sdio. */
- intrdisable(Irqlo, IRQ0sdio, sdiointr, nil, "sdio");
- r->stirq = 0;
- r->estirq = 0;
-}
-
-static void
-sdioinit(void)
-{
- SdioReg *r = SDIOREG;
-
- intrdisable(Irqlo, IRQ0sdio, sdiointr, nil, "sdio");
-
- card.valid = 0;
-
- /* reset the bus, forcing all cards to idle state */
- r->swreset = SRresetall;
- tsleep(&up->sleep, return0, nil, 50);
-
- sdclock(25*1000*1000);
-
- /* configure host controller */
- r->hostctl = HCpushpull|HCcardmemonly|HCbigendian|HCdatawidth4|
HCtimeout(15)|HCtimeoutenable;
-
- /* clear status */
- r->st = ~0;
- r->est = ~0;
-
- /* enable most status reporting */
- r->stena = ~(Stxready|Sfifo8wavail);
- r->estena = ~0;
-
- /* disable all interrupts. dma interrupt will be enabled as required.
all bits lead to IRQ0sdio. */
- r->stirq = 0;
- r->estirq = 0;
- intrenable(Irqlo, IRQ0sdio, sdiointr, nil, "sdio");
-}
-
-static Chan*
-sdioattach(char* spec)
-{
- return devattach('o', spec);
-}
-
-static Walkqid*
-sdiowalk(Chan *c, Chan *nc, char **name, int nname)
-{
- return devwalk(c, nc, name, nname, sdiotab, nelem(sdiotab), devgen);
-}
-
-static int
-sdiostat(Chan* c, uchar *db, int n)
-{
- return devstat(c, db, n, sdiotab, nelem(sdiotab), devgen);
-}
-
-static Chan*
-sdioopen(Chan* c, int omode)
-{
- return devopen(c, omode, sdiotab, nelem(sdiotab), devgen);
-}
-
-static void
-sdioclose(Chan* c)
-{
- USED(c);
-}
-
-static long
-sdioread(Chan* c, void* a, long n, vlong offset)
-{
- char *buf, *p, *e;
- SdioReg *r = SDIOREG;
-
- qlock(&sdl);
- if(waserror()) {
- qunlock(&sdl);
- nexterror();
- }
-
- switch((ulong)c->qid.path){
- case Qdir:
- n = devdirread(c, a, n, sdiotab, nelem(sdiotab), devgen);
- break;
- case Qctl:
- cardstr(&card, up->genbuf, sizeof (up->genbuf));
- n = readstr(offset, a, n, up->genbuf);
- break;
- case Qinfo:
- if(card.valid == 0)
- error(Enocard);
- p = buf = smalloc(READSTR);
- e = p+READSTR;
- p = cidstr(p, e, &card.cid);
- p = csdstr(p, e, &card.csd);
- USED(p);
- n = readstr(offset, a, n, buf);
- free(buf);
- break;
- case Qdata:
- n = sdio(a, n, offset, 0);
- break;
- case Qstatus:
- p = buf = smalloc(READSTR);
- e = p+READSTR;
-
- p = seprint(p, e, "st: ");
- p = statusstr(p, e, r->st);
- p = seprint(p, e, "\nest: ");
- p = errstatusstr(p, e, r->est);
- p = seprint(p, e, "\nacmd12st: ");
- p = acmd12ststr(p, e, r->acmd12st);
-
- p = seprint(p, e, "\nstena: ");
- p = statusstr(p, e, r->stena);
- p = seprint(p, e, "\nestena: ");
- p = errstatusstr(p, e, r->estena);
-
- p = seprint(p, e, "\nstirq: ");
- p = statusstr(p, e, r->stirq);
- p = seprint(p, e, "\nestirq: ");
- p = errstatusstr(p, e, r->estirq);
-
- p = seprint(p, e, "\nhoststate %#lux\n", r->hoststate);
- USED(p);
-
- n = readstr(offset, a, n, buf);
- free(buf);
-
- break;
- default:
- n = 0;
- break;
- }
-
- qunlock(&sdl);
- poperror();
-
- return n;
-}
-
-enum {
- CMreset, CMinit, CMclean, CMerase,
-};
-static Cmdtab sdioctl[] =
-{
- CMreset, "reset", 1,
- CMinit, "init", 1,
- CMclean, "clean", 1,
- CMerase, "erase", 3,
-};
-
-static long
-sdiowrite(Chan* c, void* a, long n, vlong offset)
-{
- Cmdbuf *cb;
- Cmdtab *ct;
- SdioReg *r = SDIOREG;
- vlong eoff;
- long en;
- int s;
-
- qlock(&sdl);
- if(waserror()) {
- qunlock(&sdl);
- nexterror();
- }
-
- switch((ulong)c->qid.path){
- case Qctl:
- if(!iseve())
- error(Eperm);
-
- cb = parsecmd(a, n);
- if(waserror()) {
- free(cb);
- nexterror();
- }
- ct = lookupcmd(cb, sdioctl, nelem(sdioctl));
- switch(ct->index) {
- case CMreset:
- sdioinit();
- break;
- case CMinit:
- sdinit();
- break;
- case CMclean:
- r->st = ~0;
- r->est = ~0;
- r->acmd12st = ~0;
- break;
- case CMerase:
- eoff = strtoll(cb->f[1], nil, 0);
- en = strtol(cb->f[2], nil, 0);
- s = erase(eoff, en);
- if(s < 0)
- errorsd("erase", s);
- break;
- }
- poperror();
- free(cb);
- break;
- case Qdata:
- n = sdio(a, n, offset, 1);
- break;
- default:
- error(Ebadusefd);
- }
-
- qunlock(&sdl);
- poperror();
-
- return n;
-}
-
-Dev sdiodevtab = {
- 'o',
- "sdio",
-
- sdioreset,
- sdioinit,
- devshutdown,
- sdioattach,
- sdiowalk,
- sdiostat,
- sdioopen,
- devcreate,
- sdioclose,
- sdioread,
- devbread,
- sdiowrite,
- devbwrite,
- devremove,
- devwstat,
-};
=======================================
--- /kwsdio.c Mon Mar 29 08:40:57 2010
+++ /kwsdio.c Mon Mar 29 10:38:56 2010
@@ -618,7 +618,9 @@
errorsd("setting 512 byte blocksize", s);

card.valid = 1;
- print("%s", cardstr(&card, up->genbuf, sizeof (up->genbuf)));
+
+ cardstr(up->genbuf, up->genbuf+sizeof (up->genbuf), &card);
+ print("%s", up->genbuf);
}

static int
@@ -771,25 +773,6 @@
intrenable(Irqlo, IRQ0sdio, sdiointr, nil, "sdio");
}

-/*
- case Qctl:
- cardstr(&card, up->genbuf, sizeof (up->genbuf));
- n = readstr(offset, a, n, up->genbuf);
- break;
-*/
-/*
- case Qinfo:
- if(card.valid == 0)
- error(Enocard);
- p = buf = smalloc(READSTR);
- e = p+READSTR;
- p = cidstr(p, e, &card.cid);
- p = csdstr(p, e, &card.csd);
- USED(p);
- n = readstr(offset, a, n, buf);
- free(buf);
- break;
-*/
/*
case Qstatus:
p = buf = smalloc(READSTR);
@@ -820,11 +803,43 @@
*/

static long
-sdiorctl(Store *d, void *s, long n, vlong off)
-{
- USED(d, s, n, off);
- print("sdiorctl\n");
- return -1;
+sdiorctl(Store *d, void *a, long n, vlong off)
+{
+ char *buf;
+ char *p, *e;
+
+ USED(d);
+
+ qlock(&sdl);
+ if(waserror()) {
+ qunlock(&sdl);
+ nexterror();
+ }
+
+ if(card.valid == 0)
+ error(Enocard);
+
+ buf = smalloc(READSTR);
+ if(waserror()) {
+ free(buf);
+ nexterror();
+ }
+
+ p = buf;
+ e = buf+READSTR;
+ p = cardstr(p, e, &card);
+ p = cidstr(p, e, &card.cid);
+ p = csdstr(p, e, &card.csd);
+ USED(p);
+ n = readstr(off, a, n, buf);
+
+ poperror();
+ free(buf);
+
+ poperror();
+ qunlock(&sdl);
+
+ return n;
}

static long
=======================================
--- /sdcard.c Sun Mar 28 15:22:01 2010
+++ /sdcard.c Mon Mar 29 10:38:56 2010
@@ -198,9 +198,9 @@
}

char*
-cardstr(Card *c, char *buf, int n)
-{
- snprint(buf, n,
+cardstr(char *p, char *e, Card *c)
+{
+ return seprint(p, e,
"card %s\n"
"type %s\n"
"size %lld bytes\n"
@@ -215,7 +215,6 @@
c->cid.year, c->cid.mon,
c->cid.rev,
c->cid.serial);
- return buf;
}

int
=======================================
--- /sdcard.h Sun Mar 28 15:22:01 2010
+++ /sdcard.h Mon Mar 29 10:38:56 2010
@@ -88,5 +88,5 @@
int parsecsd(Csd *c, uvlong *r);
char* csdstr(char *p, char *e, Csd *c);
char* cardtype(Card *c);
-char* cardstr(Card *c, char *buf, int n);
+char* cardstr(char *p, char *e, Card *c);
int parsescr(Scr *s, uvlong *r);
Reply all
Reply to author
Forward
0 new messages