📄 mmc.c
字号:
} if(drive->cap & Cwrite) { /* CDR drives are easy */ for(i = first; i <= last; i++) mmctrackinfo(drive, i, i-first); } else { /* * otherwise we need to infer endings from the * beginnings of other tracks. */ for(i = first; i <= last; i++) { memset(resp, 0, sizeof(resp)); if(mmcreadtoc(drive, 0x00, i, resp, sizeof(resp)) < 0) break; t = &drive->track[i-first]; t->mtime = drive->changetime; t->type = TypeData; t->bs = BScdrom; t->beg = bige(resp+8); if(!(resp[5] & 4)) { t->type = TypeAudio; t->bs = BScdda; } } if((long)drive->track[0].beg < 0) /* i've seen negative track 0's */ drive->track[0].beg = 0; tot = 0; memset(resp, 0, sizeof(resp)); if(mmcreadtoc(drive, 0x00, 0xAA, resp, sizeof(resp)) < 0) print("bad\n"); if(resp[6]) tot = bige(resp+8); for(i=last; i>=first; i--) { t = &drive->track[i-first]; t->end = tot; tot = t->beg; if(t->end <= t->beg) { t->beg = 0; t->end = 0; } t->size = (t->end - t->beg - 2) * (vlong)t->bs; /* -2: skip lead out */ } } drive->firsttrack = first; drive->ntrack = last+1-first; return 0;}static intmmcsetbs(Drive *drive, int bs){ uchar *p; Mmcaux *aux; aux = drive->aux; assert(aux->page05ok); p = aux->page05; p[2] = 0x01; /* track-at-once */// if(xflag)// p[2] |= 0x10; /* test-write */ switch(bs){ case BScdrom: p[3] = (p[3] & ~0x07)|0x04; /* data track, uninterrupted */ p[4] = 0x08; /* mode 1 CD-ROM */ p[8] = 0; /* session format CD-DA or CD-ROM */ break; case BScdda: p[3] = (p[3] & ~0x07)|0x00; /* 2 audio channels without pre-emphasis */ p[4] = 0x00; /* raw data */ p[8] = 0; /* session format CD-DA or CD-ROM */ break; case BScdxa: p[3] = (p[3] & ~0x07)|0x04; /* data track, uninterrupted */ p[4] = 0x09; /* mode 2 */ p[8] = 0x20; /* session format CD-ROM XA */ break; default: assert(0); } if(mmcsetpage(drive, 0x05, p) < 0) return -1; return 0;}static longmmcread(Buf *buf, void *v, long nblock, long off){ Drive *drive; int bs; uchar cmd[12]; long n, nn; Otrack *o; o = buf->otrack; drive = o->drive; bs = o->track->bs; off += o->track->beg; if(nblock >= (1<<10)) { werrstr("mmcread too big"); if(vflag) fprint(2, "mmcread too big\n"); return -1; } /* truncate nblock modulo size of track */ if(off > o->track->end - 2) { werrstr("read past end of track"); if(vflag) fprint(2, "end of track (%ld->%ld off %ld)", o->track->beg, o->track->end-2, off); return -1; } if(off == o->track->end - 2) return 0; if(off+nblock > o->track->end - 2) nblock = o->track->end - 2 - off; memset(cmd, 0, sizeof(cmd)); cmd[0] = 0xBE; cmd[2] = off>>24; cmd[3] = off>>16; cmd[4] = off>>8; cmd[5] = off>>0; cmd[6] = nblock>>16; cmd[7] = nblock>>8; cmd[8] = nblock>>0; cmd[9] = 0x10; switch(bs){ case BScdda: cmd[1] = 0x04; break; case BScdrom: cmd[1] = 0x08; break; case BScdxa: cmd[1] = 0x0C; break; default: werrstr("unknown bs %d", bs); return -1; } n = nblock*bs; nn = scsi(drive, cmd, sizeof(cmd), v, n, Sread); if(nn != n) { if(nn != -1) werrstr("short read %ld/%ld", nn, n); if(vflag) print("read off %lud nblock %ld bs %d failed\n", off, nblock, bs); return -1; } return nblock;}static Otrack*mmcopenrd(Drive *drive, int trackno){ Otrack *o; Mmcaux *aux; if(trackno < 0 || trackno >= drive->ntrack) { werrstr("track number out of range"); return nil; } aux = drive->aux; if(aux->nwopen) { werrstr("disk in use for writing"); return nil; } o = emalloc(sizeof(Otrack)); o->drive = drive; o->track = &drive->track[trackno]; o->nchange = drive->nchange; o->omode = OREAD; o->buf = bopen(mmcread, OREAD, o->track->bs, Nblock); o->buf->otrack = o; aux->nropen++; return o;}static longmmcxwrite(Otrack *o, void *v, long nblk){ uchar cmd[10]; Mmcaux *aux; assert(o->omode == OWRITE); aux = o->drive->aux; aux->ntotby += nblk*o->track->bs; aux->ntotbk += nblk; memset(cmd, 0, sizeof(cmd)); cmd[0] = 0x2a; /* write */ cmd[2] = aux->mmcnwa>>24; cmd[3] = aux->mmcnwa>>16; cmd[4] = aux->mmcnwa>>8; cmd[5] = aux->mmcnwa; cmd[7] = nblk>>8; cmd[8] = nblk>>0; if(vflag) print("%lld: write %ld at 0x%lux\n", nsec(), nblk, aux->mmcnwa); aux->mmcnwa += nblk; return scsi(o->drive, cmd, sizeof(cmd), v, nblk*o->track->bs, Swrite);}static longmmcwrite(Buf *buf, void *v, long nblk, long){ return mmcxwrite(buf->otrack, v, nblk);}static Otrack*mmccreate(Drive *drive, int type){ int bs; Mmcaux *aux; Track *t; Otrack *o; aux = drive->aux; if(aux->nropen || aux->nwopen) { werrstr("drive in use"); return nil; } switch(type){ case TypeAudio: bs = BScdda; break; case TypeData: bs = BScdrom; break; default: werrstr("bad type %d", type); return nil; } if(mmctrackinfo(drive, 0xFF, Maxtrack)) { /* the invisible track */ werrstr("CD not writable"); return nil; } if(mmcsetbs(drive, bs) < 0) { werrstr("cannot set bs mode"); return nil; } if(mmctrackinfo(drive, 0xFF, Maxtrack)) { /* the invisible track */ werrstr("CD not writable 2"); return nil; } aux->ntotby = 0; aux->ntotbk = 0; t = &drive->track[drive->ntrack++]; t->size = 0; t->bs = bs; t->beg = aux->mmcnwa; t->end = 0; t->type = type; drive->nameok = 0; o = emalloc(sizeof(Otrack)); o->drive = drive; o->nchange = drive->nchange; o->omode = OWRITE; o->track = t; o->buf = bopen(mmcwrite, OWRITE, bs, Nblock); o->buf->otrack = o; aux->nwopen++; if(vflag) print("mmcinit: nwa = 0x%luX\n", aux->mmcnwa); return o;}voidmmcsynccache(Drive *drive){ uchar cmd[10]; Mmcaux *aux; memset(cmd, 0, sizeof(cmd)); cmd[0] = 0x35; /* flush */ scsi(drive, cmd, sizeof(cmd), cmd, 0, Snone); if(vflag) { aux = drive->aux; print("mmcsynccache: bytes = %ld blocks = %ld, mmcnwa 0x%luX\n", aux->ntotby, aux->ntotbk, aux->mmcnwa); }/* rsc: seems not to work on some drives; mmcclose(1, 0xFF); */}static voidmmcclose(Otrack *o){ Mmcaux *aux; static uchar zero[2*BSmax]; aux = o->drive->aux; if(o->omode == OREAD) aux->nropen--; else if(o->omode == OWRITE) { aux->nwopen--; mmcxwrite(o, zero, 2); /* write lead out */ mmcsynccache(o->drive); o->drive->nchange = -1; /* force reread toc */ } free(o);}static intmmcxclose(Drive *drive, int ts, int trackno){ uchar cmd[10]; /* * ts: 1 == track, 2 == session */ memset(cmd, 0, sizeof(cmd)); cmd[0] = 0x5B; cmd[2] = ts; if(ts == 1) cmd[5] = trackno; return scsi(drive, cmd, sizeof(cmd), cmd, 0, Snone);}static intmmcfixate(Drive *drive){ uchar *p; Mmcaux *aux; if((drive->cap & Cwrite) == 0) { werrstr("not a writer"); return -1; } drive->nchange = -1; /* force reread toc */ aux = drive->aux; p = aux->page05; p[3] = (p[3] & ~0xC0); if(mmcsetpage(drive, 0x05, p) < 0) return -1;/* rsc: seems not to work on some drives; mmcclose(1, 0xFF); */ return mmcxclose(drive, 0x02, 0);}static intmmcsession(Drive *drive){ uchar *p; Mmcaux *aux; drive->nchange = -1; /* force reread toc */ aux = drive->aux; p = aux->page05; p[3] = (p[3] & ~0xC0); if(mmcsetpage(drive, 0x05, p) < 0) return -1;/* rsc: seems not to work on some drives; mmcclose(1, 0xFF); */ return mmcxclose(drive, 0x02, 0);}static intmmcblank(Drive *drive, int quick){ uchar cmd[12]; drive->nchange = -1; /* force reread toc */ memset(cmd, 0, sizeof(cmd)); cmd[0] = 0xA1; /* blank */ /* cmd[1] = 0 means blank the whole disc; = 1 just the header */ cmd[1] = quick ? 0x01 : 0x00; return scsi(drive, cmd, sizeof(cmd), cmd, 0, Snone);}static intstart(Drive *drive, int code){ uchar cmd[6]; memset(cmd, 0, sizeof(cmd)); cmd[0] = 0x1B; cmd[4] = code; return scsi(drive, cmd, sizeof(cmd), cmd, 0, Snone);}static char*e(int status){ if(status < 0) return geterrstr(); return nil;}static char*mmcctl(Drive *drive, int argc, char **argv){ if(argc < 1) return nil; if(strcmp(argv[0], "blank") == 0) return e(mmcblank(drive, 0)); if(strcmp(argv[0], "quickblank") == 0) return e(mmcblank(drive, 1)); if(strcmp(argv[0], "eject") == 0) return e(start(drive, 2)); if(strcmp(argv[0], "ingest") == 0) return e(start(drive, 3)); return "bad arg";}static char*mmcsetspeed(Drive *drive, int r, int w){ char *rv; uchar cmd[12]; memset(cmd, 0, sizeof(cmd)); cmd[0] = 0xBB; cmd[2] = r>>8; cmd[3] = r; cmd[4] = w>>8; cmd[5] = w; rv = e(scsi(drive, cmd, sizeof(cmd), nil, 0, Snone)); mmcgetspeed(drive); return rv;}static Dev mmcdev = { mmcopenrd, mmccreate, bufread, bufwrite, mmcclose, mmcgettoc, mmcfixate, mmcctl, mmcsetspeed,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -