static int mmcsetpage6(Drive *drive, int page, void *v) { uchar cmd[6], *p, *pagedata; int len, n; if (vflag) print("mmcsetpage6 called!\n"); pagedata = v; assert(pagedata[0] == page); len = Mode6parmhdrlen + Modepaghdrlen + pagedata[1]; p = emalloc(len); memmove(p + Mode6parmhdrlen, pagedata, pagedata[1]); memset(cmd, 0, sizeof(cmd)); cmd[0] = ScmdMselect6; cmd[1] = 0x10; /* format not vendor-specific */ cmd[4] = len; n = scsi(drive, cmd, sizeof(cmd), p, len, Swrite); free(p); if(n < len) return -1; return 0; }
/* * issue the SCSI command via scsi(2). lun must already be in cmd[1]. */ static int doscsi(Target* tp, int rw, uchar* cmd, int cbytes, void* data, int* dbytes) { int lun, db = 0; uchar reqcmd[6], reqdata[Nsense], dummy[1]; Scsi *sc; sc = tp->sc; if (sc == nil) panic("doscsi: nil tp->sc"); lun = cmd[1] >> 5; /* save lun in case we need it for reqsense */ /* cope with zero arguments */ if (dbytes != nil) db = *dbytes; if (data == nil) data = dummy; if (scsi(sc, cmd, cbytes, data, db, rw) >= 0) return STok; /* cmd failed, get whatever sense data we can */ memset(reqcmd, 0, sizeof reqcmd); reqcmd[0] = CMDreqsense; reqcmd[1] = lun<<5; reqcmd[4] = Nsense; memset(reqdata, 0, sizeof reqdata); if (scsicmd(sc, reqcmd, sizeof reqcmd, reqdata, sizeof reqdata, Sread) < 0) return STharderr; /* translate sense data to ST* codes */ return sense2stcode(reqdata); }
static int mmcsetpage10(Drive *drive, int page, void *v) { uint8_t cmd[10], *p, *pagedata; int len, n; /* allocate parameter list, copy in mode page, fill in header */ pagedata = v; assert(pagedata[0] == page); len = Mode10parmhdrlen + Modepaghdrlen + pagedata[1]; p = emalloc(len); memmove(p + Mode10parmhdrlen, pagedata, pagedata[1]); /* parameter list header */ p[0] = 0; p[1] = len - 2; /* set up CDB */ initcdb(cmd, sizeof cmd, ScmdMselect10); cmd[1] = 0x10; /* format not vendor-specific */ cmd[8] = len; n = scsi(&drive->scsi, cmd, sizeof(cmd), p, len, Swrite); free(p); if(n < len) return -1; return 0; }
static int mmcgetpage10(Drive *drive, int page, void *v) { uchar cmd[10], resp[512]; int n, r; memset(cmd, 0, sizeof(cmd)); cmd[0] = ScmdMsense10; cmd[2] = page; cmd[8] = 255; /* allocation length: buffer size */ // print("get: sending cmd\n"); // hexdump(cmd, 10); n = scsi(drive, cmd, sizeof(cmd), resp, sizeof(resp), Sread); if(n < Mode10parmhdrlen) return -1; r = (resp[6]<<8) | resp[7]; /* block descriptor length */ n -= Mode10parmhdrlen + r; if(n < 0) return -1; if(n > Pagesz) n = Pagesz; memmove(v, &resp[Mode10parmhdrlen + r], n); // print("get: got cmd\n"); // hexdump(cmd, 10); // print("page\n"); // hexdump(v, n); return n; }
int mmcstatus(Drive *drive) { uchar cmd[12]; initcdb(cmd, sizeof cmd, ScmdCDstatus); /* mechanism status */ return scsi(drive, cmd, sizeof(cmd), nil, 0, Sread); }
static int start(Drive *drive, int code) { uint8_t cmd[6]; initcdb(cmd, sizeof cmd, ScmdStart); cmd[4] = code; return scsi(&drive->scsi, cmd, sizeof(cmd), cmd, 0, Snone); }
int stop(Drive *d) { uchar cmd[12]; memset(cmd, 0, sizeof cmd); cmd[0] = 0x4E; return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone); }
static int start(Drive *drive, int code) { uchar cmd[6]; initcdb(cmd, sizeof cmd, ScmdStart); cmd[4] = code; return scsi(drive, cmd, sizeof(cmd), cmd, 0, Snone); }
static void ping(Drive *d) { uchar cmd[12]; memset(cmd, 0, sizeof cmd); cmd[0] = 0x43; scsi(d->scsi, cmd, sizeof(cmd), nil, 0, Snone); }
static int status(Drive *d) { uchar cmd[12]; memset(cmd, 0, sizeof cmd); cmd[0] = 0xBD; return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone); }
int resume(Drive *d) { uchar cmd[12]; memset(cmd, 0, sizeof cmd); cmd[0] = 0x4B; cmd[8] = 0x01; return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone); }
int eject(Drive *d) { uchar cmd[12]; memset(cmd, 0, sizeof cmd); cmd[0] = 0x1B; cmd[1] = 1; cmd[4] = 2; return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone); }
/* t is a track number on disc, i is an index into drive->track[] for result */ static int mmctrackinfo(Drive *drive, int t, int i) { int n, type, bs; uint32_t beg, size; uint8_t tmode; uint8_t cmd[10], resp[255]; Track *track; initcdb(cmd, sizeof cmd, ScmdRtrackinfo); cmd[1] = 1; /* address below is logical track # */ cmd[2] = t>>24; cmd[3] = t>>16; cmd[4] = t>>8; cmd[5] = t; cmd[7] = sizeof(resp)>>8; cmd[8] = sizeof(resp); n = scsi(&drive->scsi, cmd, sizeof(cmd), resp, sizeof(resp), Sread); if(n < 28) { if(vflag) print("trackinfo %d fails n=%d: %r\n", t, n); return -1; } tmode = resp[5] & 0x0D; // dmode = resp[6] & 0x0F; gettypebs(tmode, t, i, &type, &bs); beg = bige(&resp[8]); size = bige(&resp[24]); track = &drive->track[i]; track->mtime = drive->changetime; track->beg = beg; track->end = beg + size; track->type = type; track->bs = bs; track->size = (int64_t)(size-2) * bs; /* -2: skip lead out */ if(resp[6] & (1<<6)) { /* blank? */ track->type = TypeBlank; drive->writeok = Yes; } if(vflag) print(" start %lu end %lu", beg, beg + size - 1); gettracknwa(drive, t, beg, resp); if (vflag) print("\n"); return 0; }
static int getdevtype(Drive *drive) { int n; uchar cmd[6], resp[Pagesz]; initcdb(cmd, sizeof cmd, ScmdInq); cmd[3] = sizeof resp >> 8; cmd[4] = sizeof resp; n = scsi(drive, cmd, sizeof(cmd), resp, sizeof resp, Sread); if (n < 8) return -1; return resp[0] & 037; }
void konamigq_state::konamigq(machine_config &config) { /* basic machine hardware */ CXD8530BQ(config, m_maincpu, XTAL(67'737'600)); m_maincpu->set_addrmap(AS_PROGRAM, &konamigq_state::konamigq_map); m_maincpu->subdevice<psxdma_device>("dma")->install_read_handler(5, psxdma_device::read_delegate(&konamigq_state::scsi_dma_read, this)); m_maincpu->subdevice<psxdma_device>("dma")->install_write_handler(5, psxdma_device::write_delegate(&konamigq_state::scsi_dma_write, this)); m_maincpu->subdevice<ram_device>("ram")->set_default_size("4M"); M68000(config, m_soundcpu, XTAL(32'000'000)/4); /* 8MHz - measured */ m_soundcpu->set_addrmap(AS_PROGRAM, &konamigq_state::konamigq_sound_map); TMS57002(config, m_dasp, XTAL(48'000'000)/2); /* 24MHz - measured */ m_dasp->set_addrmap(AS_DATA, &konamigq_state::konamigq_dasp_map); m_dasp->set_periodic_int(FUNC(konamigq_state::tms_sync), attotime::from_hz(48000)); MB89371(config, "mb89371", 0); EEPROM_93C46_16BIT(config, "eeprom").default_data(konamigq_def_eeprom, 128); scsi_port_device &scsi(SCSI_PORT(config, "scsi", 0)); scsi.set_slot_device(1, "harddisk", SCSIHD, DEVICE_INPUT_DEFAULTS_NAME(SCSI_ID_0)); AM53CF96(config, m_am53cf96, 0); m_am53cf96->set_scsi_port("scsi"); m_am53cf96->irq_handler().set("maincpu:irq", FUNC(psxirq_device::intin10)); /* video hardware */ CXD8538Q(config, "gpu", XTAL(53'693'175), 0x200000, subdevice<psxcpu_device>("maincpu")).set_screen("screen"); SCREEN(config, "screen", SCREEN_TYPE_RASTER); /* sound hardware */ SPEAKER(config, "lspeaker").front_left(); SPEAKER(config, "rspeaker").front_right(); K056800(config, m_k056800, XTAL(18'432'000)); m_k056800->int_callback().set_inputline(m_soundcpu, M68K_IRQ_1); k054539_device &k054539_1(K054539(config, "k054539_1", XTAL(18'432'000))); k054539_1.set_addrmap(0, &konamigq_state::konamigq_k054539_map); k054539_1.timer_handler().set(FUNC(konamigq_state::k054539_irq_gen)); k054539_1.add_route(0, "lspeaker", 1.0); k054539_1.add_route(1, "rspeaker", 1.0); k054539_device &k054539_2(K054539(config, "k054539_2", XTAL(18'432'000))); k054539_2.set_addrmap(0, &konamigq_state::konamigq_k054539_map); k054539_2.add_route(0, "lspeaker", 1.0); k054539_2.add_route(1, "rspeaker", 1.0); }
static int playmsf(Drive *d, Msf start, Msf end) { uchar cmd[12]; memset(cmd, 0, sizeof cmd); cmd[0] = 0x47; cmd[3] = start.m; cmd[4] = start.s; cmd[5] = start.f; cmd[6] = end.m; cmd[7] = end.s; cmd[8] = end.f; return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone); }
static int getbdstruct(Drive *drive) { int n; uchar cmd[12], resp[4100]; initcdb(cmd, sizeof cmd, ScmdReadDVD); /* actually, read disc structure */ cmd[1] = 1; /* media type: bd */ cmd[7] = 0; /* format code: disc info */ cmd[8] = sizeof resp >> 8; /* allocation length */ cmd[9] = sizeof resp; n = scsi(drive, cmd, sizeof(cmd), resp, sizeof resp, Sread); /* * resp[0..1] is resp length. * resp[4+8..4+8+2] is bd type (disc type identifier): * BDO|BDW|BDR, MMC-6 §6.22.3.3.1. The above command should * fail on DVD drives, but some seem to ignore media type * and return successfully, so verify that it's a BD drive. */ if (n < 4+8+3 || resp[4+8] != 'B' || resp[4+8+1] != 'D') return -1; if (vflag) fprint(2, "read disc structure (bd) succeeded\n"); drive->erasable = drive->recordable = 0; switch (resp[4+8+2]) { case 'O': drive->blank = 0; drive->blankset = 1; break; case 'R': /* Recordable */ drive->recordable = 1; break; case 'W': /* reWritable */ drive->erasable = 1; break; default: fprint(2, "%s: unknown bd type BD%c\n", argv0, resp[4+8+2]); return -1; } drive->erasableset = drive->recordableset = 1; drive->mmctype = Mmcbd; return 0; }
static int mmcreaddiscinfo(Drive *drive, void *data, int nbytes) { uchar cmd[10]; int n; memset(cmd, 0, sizeof(cmd)); cmd[0] = ScmdRdiscinfo; cmd[7] = nbytes>>8; cmd[8] = nbytes; n = scsi(drive, cmd, sizeof(cmd), data, nbytes, Sread); if(n < 24) { if(n >= 0) werrstr("rdiscinfo returns %d", n); return -1; } return n; }
/* this may fail for blank media */ static int mmcreadtoc(Drive *drive, int type, int track, void *data, int nbytes) { uint8_t cmd[10]; initcdb(cmd, sizeof cmd, ScmdRTOC); cmd[1] = type; /* msf bit & reserved */ cmd[2] = Tocfmttoc; cmd[6] = track; /* track/session */ cmd[7] = nbytes>>8; cmd[8] = nbytes; /* * printing iounit(drive->scsi.rawfd) here yields * iounit(3) = 0; # for local access * iounit(3) = 65512; # for remote access via /mnt/term */ return scsi(&drive->scsi, cmd, sizeof(cmd), data, nbytes, Sread); }
static int getdvdstruct(Drive *drive) { int n, cat; uchar cmd[12], resp[Pagesz]; initcdb(cmd, sizeof cmd, ScmdReadDVD); /* actually, read disc structure */ cmd[1] = 0; /* media type: dvd */ cmd[7] = 0; /* format code: physical format */ cmd[8] = sizeof resp >> 8; /* allocation length */ cmd[9] = sizeof resp; n = scsi(drive, cmd, sizeof(cmd), resp, sizeof resp, Sread); if (n < 7) return -1; // print("dvd structure:\n"); // hexdump(resp, n); /* resp[0..1] is resp length */ cat = (resp[4] & 0xf0) >> 4; /* disk category, MMC-6 §6.22.3.2.1 */ if (vflag) fprint(2, "dvd type is %s\n", dvdtype[cat]); drive->dvdtype = dvdtype[cat]; /* write parameters mode page may suffice to compute writeok for dvd */ drive->erasable = drive->recordable = 0; /* * the layer-type field is a *bit array*, * though an enumeration of types would make more sense, * since the types are exclusive, not orthogonal. */ if (resp[6] & (1<<2)) /* rewritable? */ drive->erasable = 1; else if (resp[6] & (1<<1)) /* recordable once? */ drive->recordable = 1; else { /* factory-pressed disk */ drive->blank = 0; drive->blankset = 1; } drive->erasableset = drive->recordableset = 1; drive->mmctype = (cat >= 8? Mmcdvdplus: Mmcdvdminus); return 0; }
static int playstatus(Drive *d, Cdstatus *stat) { uchar cmd[12], resp[16]; memset(cmd, 0, sizeof cmd); cmd[0] = 0x42; cmd[1] = 0x02; cmd[2] = 0x40; cmd[3] = 0x01; cmd[7] = sizeof(resp)>>8; cmd[8] = sizeof(resp); if(scsi(d->scsi, cmd, sizeof(cmd), resp, sizeof(resp), Sread) < 0) return -1; switch(resp[1]){ case 0x11: stat->state = Splaying; break; case 0x12: stat->state = Spaused; break; case 0x13: stat->state = Scompleted; break; case 0x14: stat->state = Serror; break; case 0x00: /* not supported */ case 0x15: /* no current status to return */ default: stat->state = Sunknown; break; } stat->track = resp[6]; stat->index = resp[7]; stat->abs = rdmsf(resp+9); stat->rel = rdmsf(resp+13); return 0; }
static int mmcsetpage10(Drive *drive, int page, void *v) { uchar cmd[10], *p, *pagedata; int len, n; /* allocate parameter list, copy in mode page, fill in header */ pagedata = v; assert(pagedata[0] == page); len = Mode10parmhdrlen + Modepaghdrlen + pagedata[1]; p = emalloc(len); memmove(p + Mode10parmhdrlen, pagedata, pagedata[1]); /* parameter list header */ p[0] = 0; p[1] = len - 2; /* set up CDB */ memset(cmd, 0, sizeof(cmd)); cmd[0] = ScmdMselect10; cmd[1] = 0x10; /* format not vendor-specific */ cmd[8] = len; // print("set: sending cmd\n"); // hexdump(cmd, 10); // print("parameter list header\n"); // hexdump(p, Mode10parmhdrlen); // print("page\n"); // hexdump(p + Mode10parmhdrlen, len - Mode10parmhdrlen); n = scsi(drive, cmd, sizeof(cmd), p, len, Swrite); // print("set: got cmd\n"); // hexdump(cmd, 10); free(p); if(n < len) return -1; return 0; }
static int mmcgetpage6(Drive *drive, int page, void *v) { uint8_t cmd[6], resp[512]; int n; initcdb(cmd, sizeof cmd, ScmdMsense6); cmd[2] = page; cmd[4] = 255; /* allocation length */ n = scsi(&drive->scsi, cmd, sizeof(cmd), resp, sizeof(resp), Sread); if(n < Mode6parmhdrlen) return -1; n -= Mode6parmhdrlen + resp[3]; if(n < 0) return -1; if(n > Pagesz) n = Pagesz; memmove(v, &resp[Mode6parmhdrlen + resp[3]], n); return n; }
static int getdiscinfo(Drive *drive, uint8_t resp[], int resplen) { int n; uint8_t cmd[10]; initcdb(cmd, sizeof cmd, ScmdRdiscinfo); cmd[7] = resplen>>8; cmd[8] = resplen; n = scsi(&drive->scsi, cmd, sizeof(cmd), resp, resplen, Sread); if(n < 24) { if(n >= 0) werrstr("rdiscinfo returns %d", n); else if (vflag) fprint(2, "read disc info failed\n"); return -1; } if (vflag) fprint(2, "read disc info succeeded\n"); assert((resp[2] & 0340) == 0); /* data type 0 */ drive->erasable = ((resp[2] & 0x10) != 0); /* -RW? */ return n; }
static int mmcgetpage10(Drive *drive, int page, void *v) { uint8_t cmd[10], resp[512]; int n, r; initcdb(cmd, sizeof cmd, ScmdMsense10); cmd[2] = page; cmd[8] = 255; /* allocation length: buffer size */ n = scsi(&drive->scsi, cmd, sizeof(cmd), resp, sizeof(resp), Sread); if(n < Mode10parmhdrlen) return -1; r = (resp[6]<<8) | resp[7]; /* block descriptor length */ n -= Mode10parmhdrlen + r; if(n < 0) return -1; if(n > Pagesz) n = Pagesz; memmove(v, &resp[Mode10parmhdrlen + r], n); return n; }
static int mmcgetpage6(Drive *drive, int page, void *v) { uchar cmd[6], resp[512]; int n; memset(cmd, 0, sizeof(cmd)); cmd[0] = ScmdMsense6; cmd[2] = page; cmd[4] = 255; /* allocation length */ n = scsi(drive, cmd, sizeof(cmd), resp, sizeof(resp), Sread); if(n < Mode6parmhdrlen) return -1; n -= Mode6parmhdrlen + resp[3]; if(n < 0) return -1; if(n > Pagesz) n = Pagesz; memmove(v, &resp[Mode6parmhdrlen + resp[3]], n); return n; }
static int getconfcmd(Drive *drive, uint8_t *resp, int respsz) { int n; uint32_t datalen; uint8_t cmd[10]; initcdb(cmd, sizeof cmd, Scmdgetconf); cmd[3] = 0; /* start with profile list feature */ cmd[7] = respsz >> 8; cmd[8] = respsz; n = scsi(&drive->scsi, cmd, sizeof cmd, resp, respsz, Sread); if (n < 0) { if(vflag) fprint(2, "get config cmd failed\n"); return -1; } if (n < 4) return -1; datalen = GETBELONG(resp+0); if (datalen < 8) return -1; return datalen; }
/* t is a track number on disc, i is an index into drive->track[] for result */ static int mmctrackinfo(Drive *drive, int t, int i) { int n, type, bs; ulong beg, size; uchar tmode; uchar cmd[10], resp[255]; Mmcaux *aux; aux = drive->aux; memset(cmd, 0, sizeof(cmd)); cmd[0] = ScmdRtrackinfo; cmd[1] = 1; /* address below is logical track # */ cmd[2] = t>>24; cmd[3] = t>>16; cmd[4] = t>>8; cmd[5] = t; cmd[7] = sizeof(resp)>>8; cmd[8] = sizeof(resp); n = scsi(drive, cmd, sizeof(cmd), resp, sizeof(resp), Sread); if(n < 28) { if(vflag) print("trackinfo %d fails n=%d: %r\n", t, n); return -1; } beg = bige(&resp[8]); size = bige(&resp[24]); tmode = resp[5] & 0x0D; // dmode = resp[6] & 0x0F; if(vflag) print("track %d type %d (%s)", t, tmode, (tmode < nelem(tracktype)? tracktype[tmode]: "**GOK**")); type = TypeNone; bs = BScdda; switch(tmode){ case Tmcdda: type = TypeAudio; bs = BScdda; break; case Tm2audio: /* 2 audio channels, with pre-emphasis 50/15 μs */ if(vflag) print("audio channels with preemphasis on track %d " "(u%.3d)\n", t, i); type = TypeNone; break; case Tmunintr: /* data track, recorded uninterrupted */ case Tmintr: /* data track, recorded interrupted */ /* treat Tmintr (5) as cdrom; it's probably dvd or bd */ type = TypeData; bs = BScdrom; break; default: if(vflag) print("unknown track type %d\n", tmode); break; } drive->track[i].mtime = drive->changetime; drive->track[i].beg = beg; drive->track[i].end = beg+size; drive->track[i].type = type; drive->track[i].bs = bs; drive->track[i].size = (vlong)(size-2) * bs; /* -2: skip lead out */ if(resp[6] & (1<<6)) { /* blank? */ drive->track[i].type = TypeBlank; drive->writeok = 1; } if(vflag) print(" start %lud end %lud", beg, beg + size - 1); /* resp[6] & (1<<7) of zero: invisible track */ /* t == getinvistrack(): invisible track */ if(t == Invistrack || resp[7] & 1) { /* invis or nwa valid? */ aux->mmcnwa = bige(&resp[12]); if ((long)aux->mmcnwa < 0) /* implausible? */ aux->mmcnwa = 0; if (vflag) print(" nwa %lud", aux->mmcnwa); } if (vflag) print("\n"); return 0; }
/* not a Drive, so that we don't accidentally touch Drive.toc */ int gettoc(Scsi *s, Toc *t) { int i, n; uchar cmd[12]; uchar resp[1024]; Again: memset(t, 0, sizeof(*t)); memset(cmd, 0, sizeof cmd); cmd[0] = 0x43; cmd[1] = 0x02; cmd[7] = sizeof(resp)>>8; cmd[8] = sizeof(resp); s->changetime = 1; /* scsi sets nchange, changetime */ if(scsi(s, cmd, sizeof cmd, resp, sizeof(resp), Sread) < 4) return -1; if(s->changetime == 0) { t->ntrack = 0; werrstr("no media"); return -1; } if(t->nchange == s->nchange && t->changetime != 0) return 0; t->nchange = s->nchange; t->changetime = s->changetime; if(t->ntrack > MTRACK) t->ntrack = MTRACK; DPRINT(2, "%d %d\n", resp[3], resp[2]); t->ntrack = resp[3]-resp[2]+1; t->track0 = resp[2]; n = ((resp[0]<<8) | resp[1])+2; if(n < 4+8*(t->ntrack+1)) { werrstr("bad read0 %d %d", n, 4+8*(t->ntrack+1)); return -1; } for(i=0; i<=t->ntrack; i++) /* <=: track[ntrack] = end */ t->track[i].start = rdmsf(resp+4+i*8+5); for(i=0; i<t->ntrack; i++) t->track[i].end = t->track[i+1].start; memset(cmd, 0, sizeof cmd); cmd[0] = 0x43; cmd[7] = sizeof(resp)>>8; cmd[8] = sizeof(resp); if(scsi(s, cmd, sizeof cmd, resp, sizeof(resp), Sread) < 4) return -1; if(s->changetime != t->changetime || s->nchange != t->nchange) { fprint(2, "disk changed underfoot; repeating\n"); goto Again; } n = ((resp[0]<<8) | resp[1])+2; if(n < 4+8*(t->ntrack+1)) { werrstr("bad read"); return -1; } for(i=0; i<=t->ntrack; i++) t->track[i].bstart = rdlba(resp+4+i*8+5); for(i=0; i<t->ntrack; i++) t->track[i].bend = t->track[i+1].bstart; return 0; }
static int getbdstruct(Drive *drive) { int n; uint8_t cmd[12], resp[4+4096]; uint8_t *di, *body; initcdb(cmd, sizeof cmd, ScmdReadDVD); /* actually, read disc structure */ cmd[1] = 1; /* media type: bd */ /* cmd[6] is layer #, 0 is first */ cmd[7] = 0; /* format code: disc info */ cmd[8] = sizeof resp >> 8; /* allocation length */ cmd[9] = (int8_t)sizeof resp; n = scsi(&drive->scsi, cmd, sizeof(cmd), resp, sizeof resp, Sread); if(n < 0) { if(vflag) fprint(2, "read disc structure (bd) cmd failed\n"); return -1; } /* * resp[0..1] is resp length (4100); 2 & 3 are reserved. * there may be multiple disc info structs of 112 bytes each. * disc info (di) starts at 4. di[0..7] are header, followed by body. * body[0..2] is bd type (disc type identifier): * BDO|BDW|BDR, MMC-6 §6.22.3.3.1. The above scsi command should * fail on DVD drives, but some seem to ignore media type * and return successfully, so verify that it's a BD drive. */ di = resp + 4; body = di + 8; n -= 4 + 8; if (n < 3 || di[0] != 'D' || di[1] != 'I' || body[0] != 'B' || body[1] != 'D') { if(vflag) fprint(2, "it's not a bd\n"); return -1; } if (vflag) fprint(2, "read disc structure (bd) succeeded; di format %d\n", di[2]); drive->erasable = drive->recordable = No; switch (body[2]) { case 'O': /* read-Only */ break; case 'R': /* Recordable */ drive->recordable = Yes; break; case 'W': /* reWritable */ drive->erasable = Yes; break; default: fprint(2, "%s: unknown bd type BD%c\n", argv0, body[2]); return -1; } /* printed getbdstruct: di bytes 98 di units/layers 32 */ // fprint(2, "getbdstruct: di bytes %d di units/layers %d\n", di[6], di[3]); drive->mmctype = Mmcbd; return 0; }