int mcd_playtracks(struct mcd_softc *sc, struct ioc_play_track *p) { struct mcd_mbox mbx; int a = p->start_track; int z = p->end_track; int error; if (sc->debug) printf("%s: playtracks: from %d:%d to %d:%d\n", device_xname(sc->sc_dev), a, p->start_index, z, p->end_index); if (a < bcd2bin(sc->volinfo.trk_low) || a > bcd2bin(sc->volinfo.trk_high) || a > z || z < bcd2bin(sc->volinfo.trk_low) || z > bcd2bin(sc->volinfo.trk_high)) return EINVAL; if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0) return error; mbx.cmd.opcode = MCD_CMDREADSINGLESPEED; mbx.cmd.length = sizeof(mbx.cmd.data.play); mbx.cmd.data.play.start_msf[0] = sc->toc[a].toc.absolute_pos[0]; mbx.cmd.data.play.start_msf[1] = sc->toc[a].toc.absolute_pos[1]; mbx.cmd.data.play.start_msf[2] = sc->toc[a].toc.absolute_pos[2]; mbx.cmd.data.play.end_msf[0] = sc->toc[z+1].toc.absolute_pos[0]; mbx.cmd.data.play.end_msf[1] = sc->toc[z+1].toc.absolute_pos[1]; mbx.cmd.data.play.end_msf[2] = sc->toc[z+1].toc.absolute_pos[2]; sc->lastpb = mbx.cmd; mbx.res.length = 0; return mcd_send(sc, &mbx, 1); }
int mcd_getqchan(struct mcd_softc *sc, union mcd_qchninfo *q, int qchn) { struct mcd_mbox mbx; int error; if (qchn == CD_TRACK_INFO) { if ((error = mcd_setmode(sc, MCD_MD_TOC)) != 0) return error; } else { if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0) return error; } if (qchn == CD_MEDIA_CATALOG) { if ((error = mcd_setupc(sc, MCD_UPC_ENABLE)) != 0) return error; } else { if ((error = mcd_setupc(sc, MCD_UPC_DISABLE)) != 0) return error; } mbx.cmd.opcode = MCD_CMDGETQCHN; mbx.cmd.length = 0; mbx.res.length = sizeof(mbx.res.data.qchninfo); if ((error = mcd_send(sc, &mbx, 1)) != 0) return error; *q = mbx.res.data.qchninfo; return 0; }
int mcd_playblocks(struct mcd_softc *sc, struct ioc_play_blocks *p) { struct mcd_mbox mbx; int error; if (sc->debug) printf("%s: playblocks: blkno %d length %d\n", device_xname(sc->sc_dev), p->blk, p->len); if (p->blk > sc->disksize || p->len > sc->disksize || (p->blk + p->len) > sc->disksize) return 0; if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0) return error; mbx.cmd.opcode = MCD_CMDREADSINGLESPEED; mbx.cmd.length = sizeof(mbx.cmd.data.play); hsg2msf(p->blk, mbx.cmd.data.play.start_msf); hsg2msf(p->blk + p->len, mbx.cmd.data.play.end_msf); sc->lastpb = mbx.cmd; mbx.res.length = 0; return mcd_send(sc, &mbx, 1); }
int mcd_get_parms(struct mcd_softc *sc) { struct mcd_mbox mbx; daddr_t size; int error; /* Send volume info command. */ mbx.cmd.opcode = MCD_CMDGETVOLINFO; mbx.cmd.length = 0; mbx.res.length = sizeof(mbx.res.data.volinfo); if ((error = mcd_send(sc, &mbx, 1)) != 0) return error; if (mbx.res.data.volinfo.trk_low == 0x00 && mbx.res.data.volinfo.trk_high == 0x00) return EINVAL; /* Volinfo is OK. */ sc->volinfo = mbx.res.data.volinfo; sc->blksize = MCD_BLKSIZE_COOKED; size = msf2hsg(sc->volinfo.vol_msf, 0); sc->disksize = size * (MCD_BLKSIZE_COOKED / DEV_BSIZE); return 0; }
int mcd_playmsf(struct mcd_softc *sc, struct ioc_play_msf *p) { struct mcd_mbox mbx; int error; if (sc->debug) printf("%s: playmsf: from %d:%d.%d to %d:%d.%d\n", device_xname(sc->sc_dev), p->start_m, p->start_s, p->start_f, p->end_m, p->end_s, p->end_f); if ((p->start_m * 60 * 75 + p->start_s * 75 + p->start_f) >= (p->end_m * 60 * 75 + p->end_s * 75 + p->end_f)) return EINVAL; if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0) return error; mbx.cmd.opcode = MCD_CMDREADSINGLESPEED; mbx.cmd.length = sizeof(mbx.cmd.data.play); mbx.cmd.data.play.start_msf[0] = bin2bcd(p->start_m); mbx.cmd.data.play.start_msf[1] = bin2bcd(p->start_s); mbx.cmd.data.play.start_msf[2] = bin2bcd(p->start_f); mbx.cmd.data.play.end_msf[0] = bin2bcd(p->end_m); mbx.cmd.data.play.end_msf[1] = bin2bcd(p->end_s); mbx.cmd.data.play.end_msf[2] = bin2bcd(p->end_f); sc->lastpb = mbx.cmd; mbx.res.length = 0; return mcd_send(sc, &mbx, 1); }
static int mcd_volinfo(struct mcd_softc *sc) { /* Just return if we already have it */ if (sc->data.flags & MCDVOLINFO) return (0); /*MCD_TRACE("mcd_volinfo: enter\n",0,0,0,0);*/ /* send volume info command */ if (mcd_send(sc, MCD_CMDGETVOLINFO,MCD_RETRYS) < 0) return (EIO); /* get data */ if (mcd_get(sc, (char*) &sc->data.volinfo,sizeof(struct mcd_volinfo)) < 0) { device_printf(sc->dev, "mcd_volinfo: error read data\n"); return (EIO); } if (sc->data.volinfo.trk_low > 0 && sc->data.volinfo.trk_high >= sc->data.volinfo.trk_low ) { sc->data.flags |= MCDVOLINFO; /* volinfo is OK */ return (0); } return (EINVAL); }
int mcd_eject(struct mcd_softc *sc) { struct mcd_mbox mbx; mbx.cmd.opcode = MCD_CMDEJECTDISK; mbx.cmd.length = 0; mbx.res.length = 0; return mcd_send(sc, &mbx, 0); }
int mcd_getstat(struct mcd_softc *sc) { struct mcd_mbox mbx; mbx.cmd.opcode = MCD_CMDGETSTAT; mbx.cmd.length = 0; mbx.res.length = 0; return mcd_send(sc, &mbx, 1); }
int mcd_setlock(struct mcd_softc *sc, int mode) { struct mcd_mbox mbx; mbx.cmd.opcode = MCD_CMDSETLOCK; mbx.cmd.length = sizeof(mbx.cmd.data.lockmode); mbx.cmd.data.lockmode.mode = mode; mbx.res.length = 0; return mcd_send(sc, &mbx, 1); }
int mcd_hard_reset(struct mcd_softc *sc) { struct mcd_mbox mbx; mcd_soft_reset(sc); mbx.cmd.opcode = MCD_CMDRESET; mbx.cmd.length = 0; mbx.res.length = 0; return mcd_send(sc, &mbx, 0); }
void mcdattach(struct device *parent, struct device *self, void *aux) { struct mcd_softc *sc = (void *)self; struct isa_attach_args *ia = aux; bus_space_tag_t iot = ia->ia_iot; bus_space_handle_t ioh; struct mcd_mbox mbx; /* Map i/o space */ if (bus_space_map(iot, ia->ia_io[0].ir_addr, MCD_NPORT, 0, &ioh)) { printf(": can't map i/o space\n"); return; } mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); sc->sc_iot = iot; sc->sc_ioh = ioh; sc->probe = 0; sc->debug = 0; if (!mcd_find(iot, ioh, sc)) { printf(": mcd_find failed\n"); return; } bufq_alloc(&sc->buf_queue, "disksort", BUFQ_SORT_RAWBLOCK); callout_init(&sc->sc_pintr_ch, 0); /* * Initialize and attach the disk structure. */ disk_init(&sc->sc_dk, device_xname(&sc->sc_dev), &mcddkdriver); disk_attach(&sc->sc_dk); printf(": model %s\n", sc->type != 0 ? sc->type : "unknown"); (void) mcd_setlock(sc, MCD_LK_UNLOCK); mbx.cmd.opcode = MCD_CMDCONFIGDRIVE; mbx.cmd.length = sizeof(mbx.cmd.data.config) - 1; mbx.cmd.data.config.subcommand = MCD_CF_IRQENABLE; mbx.cmd.data.config.data1 = 0x01; mbx.res.length = 0; (void) mcd_send(sc, &mbx, 0); mcd_soft_reset(sc); sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq, IST_EDGE, IPL_BIO, mcdintr, sc); }
int mcd_resume(struct mcd_softc *sc) { struct mcd_mbox mbx; int error; if (sc->audio_status != CD_AS_PLAY_PAUSED) return EINVAL; if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0) return error; mbx.cmd = sc->lastpb; mbx.res.length = 0; return mcd_send(sc, &mbx, 1); }
int mcd_stop(struct mcd_softc *sc) { struct mcd_mbox mbx; int error; if (sc->debug) printf("%s: mcd_stop: stopping play\n", device_xname(sc->sc_dev)); mbx.cmd.opcode = MCD_CMDSTOPAUDIO; mbx.cmd.length = 0; mbx.res.length = 0; if ((error = mcd_send(sc, &mbx, 1)) != 0) return error; sc->audio_status = CD_AS_PLAY_COMPLETED; return 0; }
static int mcd_stop(struct mcd_softc *sc) { /* Verify current status */ if (sc->data.audio_status != CD_AS_PLAY_IN_PROGRESS && sc->data.audio_status != CD_AS_PLAY_PAUSED && sc->data.audio_status != CD_AS_PLAY_COMPLETED) { if (sc->data.debug) device_printf(sc->dev, "stop attempted when not playing, audio status %d\n", sc->data.audio_status); return (EINVAL); } if (sc->data.audio_status == CD_AS_PLAY_IN_PROGRESS) if (mcd_send(sc, MCD_CMDSTOPAUDIO, MCD_RETRYS) < 0) return (EIO); sc->data.audio_status = CD_AS_PLAY_COMPLETED; return (0); }
int mcd_setmode(struct mcd_softc *sc, int mode) { struct mcd_mbox mbx; int error; if (sc->lastmode == mode) return 0; if (sc->debug) printf("%s: setting mode to %d\n", device_xname(sc->sc_dev), mode); sc->lastmode = MCD_MD_UNKNOWN; mbx.cmd.opcode = MCD_CMDSETMODE; mbx.cmd.length = sizeof(mbx.cmd.data.datamode); mbx.cmd.data.datamode.mode = mode; mbx.res.length = 0; if ((error = mcd_send(sc, &mbx, 1)) != 0) return error; sc->lastmode = mode; return 0; }
static int mcd_getqchan(struct mcd_softc *sc, struct mcd_qchninfo *q) { if (mcd_send(sc, MCD_CMDGETQCHN, MCD_RETRYS) < 0) return (-1); if (mcd_get(sc, (char *) q, sizeof(struct mcd_qchninfo)) < 0) return (-1); if (sc->data.debug) { device_printf(sc->dev, "getqchan control=0x%x addr_type=0x%x trk=%d ind=%d ttm=%d:%d.%d dtm=%d:%d.%d\n", q->control, q->addr_type, bcd2bin(q->trk_no), bcd2bin(q->idx_no), bcd2bin(q->trk_size_msf[0]), bcd2bin(q->trk_size_msf[1]), bcd2bin(q->trk_size_msf[2]), bcd2bin(q->hd_pos_msf[0]), bcd2bin(q->hd_pos_msf[1]), bcd2bin(q->hd_pos_msf[2])); } return (0); }
int mcd_setupc(struct mcd_softc *sc, int upc) { struct mcd_mbox mbx; int error; if (sc->lastupc == upc) return 0; if (sc->debug) printf("%s: setting upc to %d\n", device_xname(sc->sc_dev), upc); sc->lastupc = MCD_UPC_UNKNOWN; mbx.cmd.opcode = MCD_CMDCONFIGDRIVE; mbx.cmd.length = sizeof(mbx.cmd.data.config) - 1; mbx.cmd.data.config.subcommand = MCD_CF_READUPC; mbx.cmd.data.config.data1 = upc; mbx.res.length = 0; if ((error = mcd_send(sc, &mbx, 1)) != 0) return error; sc->lastupc = upc; return 0; }
static int mcd_read_toc(struct mcd_softc *sc) { struct ioc_toc_header th; struct mcd_qchninfo q; int rc, trk, idx, retry; /* Only read TOC if needed */ if (sc->data.flags & MCDTOC) return (0); if (sc->data.debug) device_printf(sc->dev, "reading toc header\n"); if ((rc = mcd_toc_header(sc, &th)) != 0) return (rc); if (mcd_send(sc, MCD_CMDSTOPAUDIO, MCD_RETRYS) < 0) return (EIO); if (mcd_setmode(sc, MCD_MD_TOC) != 0) return (EIO); if (sc->data.debug) device_printf(sc->dev, "get_toc reading qchannel info\n"); for(trk=th.starting_track; trk<=th.ending_track; trk++) sc->data.toc[trk].idx_no = 0; trk = th.ending_track - th.starting_track + 1; for(retry=0; retry<600 && trk>0; retry++) { if (mcd_getqchan(sc, &q) < 0) break; idx = bcd2bin(q.idx_no); if (idx>=th.starting_track && idx<=th.ending_track && q.trk_no==0) { if (sc->data.toc[idx].idx_no == 0) { sc->data.toc[idx] = q; trk--; } } } if (mcd_setmode(sc, MCD_MD_COOKED) != 0) return (EIO); if (trk != 0) return (ENXIO); /* add a fake last+1 */ idx = th.ending_track + 1; sc->data.toc[idx].control = sc->data.toc[idx-1].control; sc->data.toc[idx].addr_type = sc->data.toc[idx-1].addr_type; sc->data.toc[idx].trk_no = 0; sc->data.toc[idx].idx_no = MCD_LASTPLUS1; sc->data.toc[idx].hd_pos_msf[0] = sc->data.volinfo.vol_msf[0]; sc->data.toc[idx].hd_pos_msf[1] = sc->data.volinfo.vol_msf[1]; sc->data.toc[idx].hd_pos_msf[2] = sc->data.volinfo.vol_msf[2]; if (sc->data.debug) { int i; for (i = th.starting_track; i <= idx; i++) device_printf(sc->dev, "trk %d idx %d pos %d %d %d\n", i, sc->data.toc[i].idx_no > 0x99 ? sc->data.toc[i].idx_no : bcd2bin(sc->data.toc[i].idx_no), bcd2bin(sc->data.toc[i].hd_pos_msf[0]), bcd2bin(sc->data.toc[i].hd_pos_msf[1]), bcd2bin(sc->data.toc[i].hd_pos_msf[2])); } sc->data.flags |= MCDTOC; return (0); }
/* * Find the board and fill in the softc. */ int mcd_find(bus_space_tag_t iot, bus_space_handle_t ioh, struct mcd_softc *sc) { int i; struct mcd_mbox mbx; sc->sc_iot = iot; sc->sc_ioh = ioh; /* Send a reset. */ bus_space_write_1(iot, ioh, MCD_RESET, 0); delay(1000000); /* Get any pending status and throw away. */ for (i = 10; i; i--) bus_space_read_1(iot, ioh, MCD_STATUS); delay(1000); /* Send get status command. */ mbx.cmd.opcode = MCD_CMDGETSTAT; mbx.cmd.length = 0; mbx.res.length = 0; if (mcd_send(sc, &mbx, 0) != 0) return 0; /* Get info about the drive. */ mbx.cmd.opcode = MCD_CMDCONTINFO; mbx.cmd.length = 0; mbx.res.length = sizeof(mbx.res.data.continfo); if (mcd_send(sc, &mbx, 0) != 0) return 0; /* * The following is code which is not guaranteed to work for all * drives, because the meaning of the expected 'M' is not clear * (M_itsumi is an obvious assumption, but I don't trust that). * Also, the original hack had a bogus condition that always * returned true. * * Note: Which models support interrupts? >=LU005S? */ sc->readcmd = MCD_CMDREADSINGLESPEED; switch (mbx.res.data.continfo.code) { case 'M': if (mbx.res.data.continfo.version <= 2) sc->type = "LU002S"; else if (mbx.res.data.continfo.version <= 5) sc->type = "LU005S"; else sc->type = "LU006S"; break; case 'F': sc->type = "FX001"; break; case 'D': sc->type = "FX001D"; sc->readcmd = MCD_CMDREADDOUBLESPEED; break; default: /* * mcd_send() says the response looked OK but the * drive type is unknown. If mcd_promisc, match anyway. */ if (mcd_promisc != 0) return 0; #ifdef MCDDEBUG printf("%s: unrecognized drive version %c%02x; will try to use it anyway\n", device_xname(sc->sc_dev), mbx.res.data.continfo.code, mbx.res.data.continfo.version); #endif sc->type = 0; break; } return 1; }