5 #include "../port/lib.h"
11 #include "../port/error.h"
13 #include "../port/sd.h"
16 extern SDifc* sdifc[];
18 static char Echange[] = "media or partition has changed";
20 static char devletters[] = "0123456789"
21 "abcdefghijklmnopqrstuvwxyz"
22 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
24 static SDev *devs[sizeof devletters-1];
25 static QLock devslock;
34 Qtopdir = 1, /* top level directory */
38 Qunitdir, /* directory per unit */
57 UnitSHIFT = (PartLOG+TypeLOG),
62 DevSHIFT = (UnitLOG+PartLOG+TypeLOG),
67 #define TYPE(q) ((((ulong)(q).path)>>TypeSHIFT) & TypeMASK)
68 #define PART(q) ((((ulong)(q).path)>>PartSHIFT) & PartMASK)
69 #define UNIT(q) ((((ulong)(q).path)>>UnitSHIFT) & UnitMASK)
70 #define DEV(q) ((((ulong)(q).path)>>DevSHIFT) & DevMASK)
71 #define QID(d,u, p, t) (((d)<<DevSHIFT)|((u)<<UnitSHIFT)|\
72 ((p)<<PartSHIFT)|((t)<<TypeSHIFT))
76 sdaddpart(SDunit* unit, char* name, uvlong start, uvlong end)
82 * Check name not already used
83 * and look for a free slot.
85 if(unit->part != nil){
87 for(i = 0; i < unit->npart; i++){
94 if(strcmp(name, pp->name) == 0){
95 if(pp->start == start && pp->end == end)
102 if((unit->part = malloc(sizeof(SDpart)*SDnpart)) == nil)
104 unit->npart = SDnpart;
109 * If no free slot found then increase the
110 * array size (can't get here with unit->part == nil).
113 if(unit->npart >= NPart)
115 if((pp = malloc(sizeof(SDpart)*(unit->npart+SDnpart))) == nil)
117 memmove(pp, unit->part, sizeof(SDpart)*unit->npart);
120 partno = unit->npart;
121 unit->npart += SDnpart;
125 * Check size and extent are valid.
127 if(start > end || end > unit->sectors)
129 pp = &unit->part[partno];
132 kstrdup(&pp->name, name);
133 kstrdup(&pp->user, eve);
139 sddelpart(SDunit* unit, char* name)
145 * Look for the partition to delete.
146 * Can't delete if someone still has it open.
149 for(i = 0; i < unit->npart; i++){
150 if(strcmp(name, pp->name) == 0)
156 if(strcmp(up->user, pp->user) && !iseve())
163 sdincvers(SDunit *unit)
169 for(i = 0; i < unit->npart; i++){
170 unit->part[i].valid = 0;
171 unit->part[i].vers++;
177 sdinitpart(SDunit* unit)
181 char *f[4], *p, *q, buf[10];
183 if(unit->sectors > 0){
184 unit->sectors = unit->secsize = 0;
188 if(unit->inquiry[0] & 0xC0)
190 switch(unit->inquiry[0] & 0x1F){
192 case 0x04: /* WORM */
193 case 0x05: /* CD-ROM */
200 if(unit->dev->ifc->online)
201 unit->dev->ifc->online(unit);
204 sdaddpart(unit, "data", 0, unit->sectors);
207 * Use partitions passed from boot program,
209 * sdC0part=dos 63 123123/plan9 123123 456456
210 * This happens before /boot sets hostname so the
211 * partitions will have the null-string for user.
212 * The gen functions patch it up.
214 snprint(buf, sizeof buf, "%spart", unit->name);
215 for(p = getconf(buf); p != nil; p = q){
216 if(q = strchr(p, '/'))
218 nf = tokenize(p, f, nelem(f));
222 start = strtoull(f[1], 0, 0);
223 end = strtoull(f[2], 0, 0);
225 sdaddpart(unit, f[0], start, end);
239 p = strchr(devletters, idno);
251 if((i = sdindex(idno)) < 0)
262 sdgetunit(SDev* sdev, int subno)
268 * Associate a unit with a given device and sub-unit
269 * number on that device.
270 * The device will be probed if it has not already been
271 * successfully accessed.
273 qlock(&sdev->unitlock);
274 if(subno > sdev->nunit){
275 qunlock(&sdev->unitlock);
279 unit = sdev->unit[subno];
282 * Probe the unit only once. This decision
283 * may be a little severe and reviewed later.
285 if(sdev->unitflg[subno]){
286 qunlock(&sdev->unitlock);
289 if((unit = malloc(sizeof(SDunit))) == nil){
290 qunlock(&sdev->unitlock);
293 sdev->unitflg[subno] = 1;
295 snprint(buf, sizeof(buf), "%s%d", sdev->name, subno);
296 kstrdup(&unit->name, buf);
297 kstrdup(&unit->user, eve);
302 if(sdev->enabled == 0 && sdev->ifc->enable)
303 sdev->ifc->enable(sdev);
307 * No need to lock anything here as this is only
308 * called before the unit is made available in the
311 if(unit->dev->ifc->verify(unit) == 0){
312 qunlock(&sdev->unitlock);
316 sdev->unit[subno] = unit;
318 qunlock(&sdev->unitlock);
329 * Probe all known controller types and register any devices found.
331 for(i = 0; sdifc[i] != nil; i++){
332 if(sdifc[i]->pnp == nil || (sdev = sdifc[i]->pnp()) == nil)
339 sdadddevs(SDev *sdev)
344 for(; sdev; sdev=next){
347 sdev->unit = (SDunit**)malloc(sdev->nunit * sizeof(SDunit*));
348 sdev->unitflg = (int*)malloc(sdev->nunit * sizeof(int));
349 if(sdev->unit == nil || sdev->unitflg == nil){
350 print("sdadddevs: out of memory\n");
355 sdev->ifc->clear(sdev);
359 id = sdindex(sdev->idno);
361 print("sdadddevs: bad id number %d (%C)\n", id, id);
365 for(i=0; i<nelem(devs); i++){
366 if(devs[j = (id+i)%nelem(devs)] == nil){
367 sdev->idno = devletters[j];
369 snprint(sdev->name, sizeof sdev->name, "sd%c", devletters[j]);
374 if(i == nelem(devs)){
375 print("sdadddevs: out of device letters\n");
382 // sdrmdevs(SDev *sdev)
386 // snprint(buf, sizeof buf, "%c", sdev->idno);
391 sd2gen(Chan* c, int i, Dir* dp)
401 sdev = sdgetdev(DEV(c->qid));
403 unit = sdev->unit[UNIT(c->qid)];
408 mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qctl),
410 perm = &unit->ctlperm;
411 if(emptystr(perm->user)){
412 kstrdup(&perm->user, eve);
415 devdir(c, q, "ctl", 0, perm->user, perm->perm, dp);
420 mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qraw),
422 perm = &unit->rawperm;
423 if(emptystr(perm->user)){
424 kstrdup(&perm->user, eve);
425 perm->perm = DMEXCL|0600;
427 devdir(c, q, "raw", 0, perm->user, perm->perm, dp);
432 pp = &unit->part[PART(c->qid)];
433 l = (pp->end - pp->start) * unit->secsize;
434 mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qpart),
435 unit->vers+pp->vers, QTFILE);
436 if(emptystr(pp->user))
437 kstrdup(&pp->user, eve);
438 devdir(c, q, pp->name, l, pp->user, pp->perm, dp);
448 sd1gen(Chan* c, int i, Dir* dp)
454 mkqid(&q, QID(0, 0, 0, Qtopctl), 0, QTFILE);
455 devdir(c, q, "sdctl", 0, eve, 0640, dp);
462 sdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp)
471 switch(TYPE(c->qid)){
474 mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR);
475 sprint(up->genbuf, "#%C", sddevtab.dc);
476 devdir(c, q, up->genbuf, 0, eve, 0555, dp);
480 if(s+Qtopbase < Qunitdir)
481 return sd1gen(c, s+Qtopbase, dp);
482 s -= (Qunitdir-Qtopbase);
485 for(i=0; i<nelem(devs); i++){
487 if(s < devs[i]->nunit)
493 if(i == nelem(devs)){
494 /* Run off the end of the list */
499 if((sdev = devs[i]) == nil){
507 if((unit = sdev->unit[s]) == nil)
508 if((unit = sdgetunit(sdev, s)) == nil){
513 mkqid(&q, QID(sdev->idno, s, 0, Qunitdir), 0, QTDIR);
514 if(emptystr(unit->user))
515 kstrdup(&unit->user, eve);
516 devdir(c, q, unit->name, 0, unit->user, unit->perm, dp);
522 mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR);
523 sprint(up->genbuf, "#%C", sddevtab.dc);
524 devdir(c, q, up->genbuf, 0, eve, 0555, dp);
528 if((sdev = sdgetdev(DEV(c->qid))) == nil){
529 devdir(c, c->qid, "unavailable", 0, eve, 0, dp);
533 unit = sdev->unit[UNIT(c->qid)];
537 * Check for media change.
538 * If one has already been detected, sectors will be zero.
539 * If there is one waiting to be detected, online
541 * Online is a bit of a large hammer but does the job.
543 if(unit->sectors == 0
544 || (unit->dev->ifc->online && unit->dev->ifc->online(unit) > 1))
549 r = sd2gen(c, i, dp);
555 if(unit->part == nil || i >= unit->npart){
566 l = (pp->end - pp->start) * unit->secsize;
567 mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), i, Qpart),
568 unit->vers+pp->vers, QTFILE);
569 if(emptystr(pp->user))
570 kstrdup(&pp->user, eve);
571 devdir(c, q, pp->name, l, pp->user, pp->perm, dp);
578 if((sdev = sdgetdev(DEV(c->qid))) == nil){
579 devdir(c, q, "unavailable", 0, eve, 0, dp);
582 unit = sdev->unit[UNIT(c->qid)];
584 r = sd2gen(c, TYPE(c->qid), dp);
589 return sd1gen(c, TYPE(c->qid), dp);
606 c = devattach(sddevtab.dc, spec);
607 mkqid(&c->qid, QID(0, 0, 0, Qtopdir), 0, QTDIR);
611 if(spec[0] != 's' || spec[1] != 'd')
614 subno = strtol(&spec[3], &p, 0);
618 if((sdev=sdgetdev(idno)) == nil)
620 if(sdgetunit(sdev, subno) == nil){
625 c = devattach(sddevtab.dc, spec);
626 mkqid(&c->qid, QID(sdev->idno, subno, 0, Qunitdir), 0, QTDIR);
627 c->dev = (sdev->idno << UnitLOG) + subno;
633 sdwalk(Chan* c, Chan* nc, char** name, int nname)
635 return devwalk(c, nc, name, nname, nil, 0, sdgen);
639 sdstat(Chan* c, uchar* db, int n)
641 return devstat(c, db, n, nil, 0, sdgen);
645 sdopen(Chan* c, int omode)
652 c = devopen(c, omode, 0, 0, sdgen);
653 if((tp = TYPE(c->qid)) != Qctl && tp != Qraw && tp != Qpart)
656 sdev = sdgetdev(DEV(c->qid));
660 unit = sdev->unit[UNIT(c->qid)];
662 switch(TYPE(c->qid)){
664 c->qid.vers = unit->vers;
667 c->qid.vers = unit->vers;
668 if(tas(&unit->rawinuse) != 0){
673 unit->state = Rawcmd;
683 pp = &unit->part[PART(c->qid)];
684 c->qid.vers = unit->vers+pp->vers;
699 if(c->qid.type & QTDIR)
701 if(!(c->flag & COPEN))
704 switch(TYPE(c->qid)){
708 sdev = sdgetdev(DEV(c->qid));
710 unit = sdev->unit[UNIT(c->qid)];
719 sdbio(Chan* c, int write, char* a, long len, uvlong off)
727 ulong max, nb, offset;
730 sdev = sdgetdev(DEV(c->qid));
735 unit = sdev->unit[UNIT(c->qid)];
742 /* notification of media change; go around again */
743 if(strcmp(up->errstr, Eio) == 0 && unit->sectors == 0 && nchange++ == 0){
748 /* other errors; give up */
753 pp = &unit->part[PART(c->qid)];
754 if(unit->vers+pp->vers != c->qid.vers)
758 * Check the request is within bounds.
759 * Removeable drives are locked throughout the I/O
760 * in case the media changes unexpectedly.
761 * Non-removeable drives are not locked during the I/O
762 * to allow the hardware to optimise if it can; this is
763 * a little fast and loose.
764 * It's assumed that non-removeable media parameters
765 * (sectors, secsize) can't change once the drive has
766 * been brought online.
768 bno = (off/unit->secsize) + pp->start;
769 nb = ((off+len+unit->secsize-1)/unit->secsize) + pp->start - bno;
770 max = SDmaxio/unit->secsize;
775 if(bno >= pp->end || nb == 0){
783 if(!(unit->inquiry[1] & 0x80)){
788 b = sdmalloc(nb*unit->secsize);
793 if(!(unit->inquiry[1] & 0x80))
794 decref(&sdev->r); /* gadverdamme! */
798 offset = off%unit->secsize;
799 if(offset+len > nb*unit->secsize)
800 len = nb*unit->secsize - offset;
802 if(offset || (len%unit->secsize)){
803 l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
806 if(l < (nb*unit->secsize)){
807 nb = l/unit->secsize;
808 l = nb*unit->secsize - offset;
813 memmove(b+offset, a, len);
814 l = unit->dev->ifc->bio(unit, 0, 1, b, nb, bno);
819 else if(len > l - offset)
823 l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
828 else if(len > l - offset)
830 memmove(a, b+offset, len);
835 if(unit->inquiry[1] & 0x80){
845 sdrio(SDreq* r, void* a, long n)
849 if(n >= SDmaxio || n < 0)
854 if((data = sdmalloc(n)) == nil)
868 if(r->unit->dev->ifc->rio(r) != SDok)
871 if(!r->write && r->rlen > 0)
872 memmove(a, data, r->rlen);
881 * SCSI simulation for non-SCSI devices
884 sdsetsense(SDreq *r, int status, int key, int asc, int ascq)
890 unit->sense[2] = key;
891 unit->sense[12] = asc;
892 unit->sense[13] = ascq;
895 if(status == SDcheck && !(r->flags & SDnosense)){
896 /* request sense case from sdfakescsi */
897 len = sizeof unit->sense;
898 if(len > sizeof r->sense-1)
899 len = sizeof r->sense-1;
900 memmove(r->sense, unit->sense, len);
904 r->flags |= SDvalidsense;
911 sdmodesense(SDreq *r, uchar *cmd, void *info, int ilen)
917 * Fake a vendor-specific request with page code 0,
918 * return the drive info.
920 if((cmd[2] & 0x3F) != 0 && (cmd[2] & 0x3F) != 0x3F)
921 return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
922 len = (cmd[7]<<8)|cmd[8];
926 return sdsetsense(r, SDcheck, 0x05, 0x1A, 0);
927 if(r->data == nil || r->dlen < len)
928 return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
934 memmove(data+8, info, ilen);
936 return sdsetsense(r, SDok, 0, 0, 0);
940 sdfakescsi(SDreq *r, void *info, int ilen)
951 * Rewrite read(6)/write(6) into read(10)/write(10).
954 case 0x08: /* read */
955 case 0x0A: /* write */
962 cmd[3] = cmd[1] & 0x0F;
970 * Map SCSI commands into ATA commands for discs.
971 * Fail any command with a LUN except INQUIRY which
972 * will return 'logical unit not supported'.
974 if((cmd[1]>>5) && cmd[0] != 0x12)
975 return sdsetsense(r, SDcheck, 0x05, 0x25, 0);
979 return sdsetsense(r, SDcheck, 0x05, 0x20, 0);
981 case 0x00: /* test unit ready */
982 return sdsetsense(r, SDok, 0, 0, 0);
984 case 0x03: /* request sense */
985 if(cmd[4] < sizeof unit->sense)
988 len = sizeof unit->sense;
989 if(r->data && r->dlen >= len){
990 memmove(r->data, unit->sense, len);
993 return sdsetsense(r, SDok, 0, 0, 0);
995 case 0x12: /* inquiry */
996 if(cmd[4] < sizeof unit->inquiry)
999 len = sizeof unit->inquiry;
1000 if(r->data && r->dlen >= len){
1001 memmove(r->data, unit->inquiry, len);
1004 return sdsetsense(r, SDok, 0, 0, 0);
1006 case 0x1B: /* start/stop unit */
1008 * nop for now, can use power management later.
1010 return sdsetsense(r, SDok, 0, 0, 0);
1012 case 0x25: /* read capacity */
1013 if((cmd[1] & 0x01) || cmd[2] || cmd[3])
1014 return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
1015 if(r->data == nil || r->dlen < 8)
1016 return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
1019 * Read capacity returns the LBA of the last sector.
1021 len = unit->sectors - 1;
1032 r->rlen = p - (uchar*)r->data;
1033 return sdsetsense(r, SDok, 0, 0, 0);
1035 case 0x9E: /* long read capacity */
1036 if((cmd[1] & 0x01) || cmd[2] || cmd[3])
1037 return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
1038 if(r->data == nil || r->dlen < 8)
1039 return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
1041 * Read capcity returns the LBA of the last sector.
1043 len = unit->sectors - 1;
1058 r->rlen = p - (uchar*)r->data;
1059 return sdsetsense(r, SDok, 0, 0, 0);
1061 case 0x5A: /* mode sense */
1062 return sdmodesense(r, cmd, info, ilen);
1064 case 0x28: /* read */
1065 case 0x2A: /* write */
1066 case 0x88: /* read16 */
1067 case 0x8a: /* write16 */
1073 sdread(Chan *c, void *a, long n, vlong off)
1080 int i, l, m, status;
1083 switch(TYPE(c->qid)){
1087 m = 64*1024; /* room for register dumps */
1088 p = buf = malloc(m);
1092 for(i = 0; i < nelem(devs); i++){
1094 if(sdev && sdev->ifc->rtopctl)
1095 p = sdev->ifc->rtopctl(sdev, p, e);
1098 n = readstr(off, a, n, buf);
1104 return devdirread(c, a, n, 0, 0, sdgen);
1107 sdev = sdgetdev(DEV(c->qid));
1111 unit = sdev->unit[UNIT(c->qid)];
1112 m = 16*1024; /* room for register dumps */
1114 l = snprint(p, m, "inquiry %.48s\n",
1115 (char*)unit->inquiry+8);
1118 * If there's a device specific routine it must
1119 * provide all information pertaining to night geometry
1120 * and the garscadden trains.
1122 if(unit->dev->ifc->rctl)
1123 l += unit->dev->ifc->rctl(unit, p+l, m-l);
1124 if(unit->sectors == 0)
1127 if(unit->dev->ifc->rctl == nil)
1128 l += snprint(p+l, m-l,
1129 "geometry %llud %lud\n",
1130 unit->sectors, unit->secsize);
1132 for(i = 0; i < unit->npart; i++){
1134 l += snprint(p+l, m-l,
1135 "part %s %llud %llud\n",
1136 pp->name, pp->start, pp->end);
1140 qunlock(&unit->ctl);
1142 l = readstr(offset, a, n, p);
1147 sdev = sdgetdev(DEV(c->qid));
1151 unit = sdev->unit[UNIT(c->qid)];
1154 qunlock(&unit->raw);
1158 if(unit->state == Rawdata){
1159 unit->state = Rawstatus;
1160 i = sdrio(unit->req, a, n);
1162 else if(unit->state == Rawstatus){
1163 status = unit->req->status;
1164 unit->state = Rawcmd;
1167 i = readnum(0, a, n, status, NUMSIZE);
1170 qunlock(&unit->raw);
1176 return sdbio(c, 0, a, n, off);
1180 static void legacytopctl(Cmdbuf*);
1183 sdwrite(Chan* c, void* a, long n, vlong off)
1194 switch(TYPE(c->qid)){
1198 cb = parsecmd(a, n);
1204 error("empty control message");
1208 if(strcmp(f0, "config") == 0){
1209 /* wormhole into ugly legacy interface */
1216 * "ata arg..." invokes sdifc[i]->wtopctl(nil, cb),
1217 * where sdifc[i]->name=="ata" and cb contains the args.
1221 for(i=0; sdifc[i]; i++){
1222 if(strcmp(sdifc[i]->name, f0) == 0){
1229 * "sd1 arg..." invokes sdifc[i]->wtopctl(sdev, cb),
1230 * where sdifc[i] and sdev match controller letter "1",
1231 * and cb contains the args.
1233 if(f0[0]=='s' && f0[1]=='d' && f0[2] && f0[3] == 0){
1234 if((sdev = sdgetdev(f0[2])) != nil){
1239 error("unknown interface");
1248 ifc->wtopctl(sdev, cb);
1259 cb = parsecmd(a, n);
1260 sdev = sdgetdev(DEV(c->qid));
1263 unit = sdev->unit[UNIT(c->qid)];
1267 qunlock(&unit->ctl);
1272 if(unit->vers != c->qid.vers)
1277 if(strcmp(cb->f[0], "part") == 0){
1280 if(unit->sectors == 0 && !sdinitpart(unit))
1282 start = strtoull(cb->f[2], 0, 0);
1283 end = strtoull(cb->f[3], 0, 0);
1284 sdaddpart(unit, cb->f[1], start, end);
1286 else if(strcmp(cb->f[0], "delpart") == 0){
1287 if(cb->nf != 2 || unit->part == nil)
1289 sddelpart(unit, cb->f[1]);
1291 else if(unit->dev->ifc->wctl)
1292 unit->dev->ifc->wctl(unit, cb);
1295 qunlock(&unit->ctl);
1302 sdev = sdgetdev(DEV(c->qid));
1305 unit = sdev->unit[UNIT(c->qid)];
1308 qunlock(&unit->raw);
1312 switch(unit->state){
1314 if(n < 6 || n > sizeof(req->cmd))
1316 if((req = malloc(sizeof(SDreq))) == nil)
1319 memmove(req->cmd, a, n);
1321 req->flags = SDnosense;
1325 unit->state = Rawdata;
1329 unit->state = Rawcmd;
1335 unit->state = Rawstatus;
1336 unit->req->write = 1;
1337 n = sdrio(unit->req, a, n);
1339 qunlock(&unit->raw);
1344 return sdbio(c, 1, a, n, off);
1351 sdwstat(Chan* c, uchar* dp, int n)
1359 if(c->qid.type & QTDIR)
1362 sdev = sdgetdev(DEV(c->qid));
1365 unit = sdev->unit[UNIT(c->qid)];
1370 qunlock(&unit->ctl);
1375 switch(TYPE(c->qid)){
1379 perm = &unit->ctlperm;
1382 perm = &unit->rawperm;
1385 pp = &unit->part[PART(c->qid)];
1386 if(unit->vers+pp->vers != c->qid.vers)
1392 if(strcmp(up->user, perm->user) && !iseve())
1395 d = smalloc(sizeof(Dir)+n);
1396 n = convM2D(dp, n, &d[0], (char*)&d[1]);
1399 if(!emptystr(d[0].uid))
1400 kstrdup(&perm->user, d[0].uid);
1401 if(d[0].mode != ~0UL)
1402 perm->perm = (perm->perm & ~0777) | (d[0].mode & 0777);
1405 qunlock(&unit->ctl);
1412 configure(char* spec, DevConf* cf)
1418 if(sdindex(*spec) < 0)
1419 error("bad sd spec");
1421 if((p = strchr(cf->type, '/')) != nil)
1424 for(i = 0; sdifc[i] != nil; i++)
1425 if(strcmp(sdifc[i]->name, cf->type) == 0)
1428 error("sd type not found");
1432 if(sdifc[i]->probe == nil)
1433 error("sd type cannot probe");
1435 sdev = sdifc[i]->probe(cf);
1436 for(s=sdev; s; s=s->next)
1443 unconfigure(char* spec)
1449 if((i = sdindex(*spec)) < 0)
1453 if((sdev = devs[i]) == nil){
1464 /* make sure no interrupts arrive anymore before removing resources */
1465 if(sdev->enabled && sdev->ifc->disable)
1466 sdev->ifc->disable(sdev);
1468 for(i = 0; i != sdev->nunit; i++){
1469 if(unit = sdev->unit[i]){
1476 if(sdev->ifc->clear)
1477 sdev->ifc->clear(sdev);
1483 sdconfig(int on, char* spec, DevConf* cf)
1486 return configure(spec, cf);
1487 return unconfigure(spec);
1514 * This is wrong for so many reasons. This code must go.
1516 typedef struct Confdata Confdata;
1524 parseswitch(Confdata* cd, char* option)
1526 if(!strcmp("on", option))
1528 else if(!strcmp("off", option))
1535 parsespec(Confdata* cd, char* option)
1537 if(strlen(option) > 1)
1543 getnewport(DevConf* dc)
1547 p = (Devport *)malloc((dc->nports + 1) * sizeof(Devport));
1549 memmove(p, dc->ports, dc->nports * sizeof(Devport));
1553 p = &dc->ports[dc->nports++];
1555 p->port = (ulong)-1;
1560 parseport(Confdata* cd, char* option)
1565 if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].port != (ulong)-1)
1566 p = getnewport(&cd->cf);
1568 p = &cd->cf.ports[cd->cf.nports-1];
1569 p->port = strtol(option, &e, 0);
1570 if(e == nil || *e != '\0')
1575 parsesize(Confdata* cd, char* option)
1580 if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].size != -1)
1581 p = getnewport(&cd->cf);
1583 p = &cd->cf.ports[cd->cf.nports-1];
1584 p->size = (int)strtol(option, &e, 0);
1585 if(e == nil || *e != '\0')
1590 parseirq(Confdata* cd, char* option)
1594 cd->cf.intnum = strtoul(option, &e, 0);
1595 if(e == nil || *e != '\0')
1600 parsetype(Confdata* cd, char* option)
1602 cd->cf.type = option;
1607 void (*parse)(Confdata*, char*);
1609 "switch", parseswitch,
1618 legacytopctl(Cmdbuf *cb)
1624 memset(&cd, 0, sizeof cd);
1626 for(i=0; i<cb->nf; i+=2){
1630 for(j=0; j<nelem(options); j++)
1631 if(strcmp(opt, options[j].name) == 0){
1632 options[j].parse(&cd, cb->f[i+1]);
1635 if(j == nelem(options))
1638 /* this has been rewritten to accomodate sdaoe */
1639 if(cd.on < 0 || cd.spec == 0)
1641 if(cd.on && cd.cf.type == nil)
1643 sdconfig(cd.on, cd.spec, &cd.cf);