static int mcd_pause(struct mcd_softc *sc) { struct mcd_qchninfo q; int rc; /* Verify current status */ if (sc->data.audio_status != CD_AS_PLAY_IN_PROGRESS && sc->data.audio_status != CD_AS_PLAY_PAUSED) { if (sc->data.debug) device_printf(sc->dev, "pause attempted when not playing, audio status %d\n", sc->data.audio_status); return (EINVAL); } /* Get the current position */ if (mcd_getqchan(sc, &q) < 0) return (EIO); /* Copy it into lastpb */ sc->data.lastpb.start_msf[0] = q.hd_pos_msf[0]; sc->data.lastpb.start_msf[1] = q.hd_pos_msf[1]; sc->data.lastpb.start_msf[2] = q.hd_pos_msf[2]; /* Stop playing */ if ((rc=mcd_stop(sc)) != 0) return (rc); /* Set the proper status and exit */ sc->data.audio_status = CD_AS_PLAY_PAUSED; return (0); }
int mcd_pause(struct mcd_softc *sc) { union mcd_qchninfo q; int error; /* Verify current status. */ if (sc->audio_status != CD_AS_PLAY_IN_PROGRESS) { printf("%s: pause: attempted when not playing\n", device_xname(sc->sc_dev)); return EINVAL; } /* Get the current position. */ if ((error = mcd_getqchan(sc, &q, CD_CURRENT_POSITION)) != 0) return error; /* Copy it into lastpb. */ sc->lastpb.data.seek.start_msf[0] = q.current.absolute_pos[0]; sc->lastpb.data.seek.start_msf[1] = q.current.absolute_pos[1]; sc->lastpb.data.seek.start_msf[2] = q.current.absolute_pos[2]; /* Stop playing. */ if ((error = mcd_stop(sc)) != 0) return error; /* Set the proper status and exit. */ sc->audio_status = CD_AS_PLAY_PAUSED; return 0; }
int mcd_read_toc(struct mcd_softc *sc) { struct ioc_toc_header th; union mcd_qchninfo q; int error, trk, idx, retry; if ((error = mcd_toc_header(sc, &th)) != 0) return error; if ((error = mcd_stop(sc)) != 0) return error; if (sc->debug) printf("%s: read_toc: reading qchannel info\n", device_xname(sc->sc_dev)); for (trk = th.starting_track; trk <= th.ending_track; trk++) sc->toc[trk].toc.idx_no = 0x00; trk = th.ending_track - th.starting_track + 1; for (retry = 300; retry && trk > 0; retry--) { if (mcd_getqchan(sc, &q, CD_TRACK_INFO) != 0) break; if (q.toc.trk_no != 0x00 || q.toc.idx_no == 0x00) continue; idx = bcd2bin(q.toc.idx_no); if (idx < MCD_MAXTOCS && sc->toc[idx].toc.idx_no == 0x00) { sc->toc[idx] = q; trk--; } } /* Inform the drive that we're finished so it turns off the light. */ if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0) return error; if (trk != 0) return EINVAL; /* Add a fake last+1 for mcd_playtracks(). */ idx = th.ending_track + 1; sc->toc[idx].toc.control = sc->toc[idx-1].toc.control; sc->toc[idx].toc.addr_type = sc->toc[idx-1].toc.addr_type; sc->toc[idx].toc.trk_no = 0x00; sc->toc[idx].toc.idx_no = 0xaa; sc->toc[idx].toc.absolute_pos[0] = sc->volinfo.vol_msf[0]; sc->toc[idx].toc.absolute_pos[1] = sc->volinfo.vol_msf[1]; sc->toc[idx].toc.absolute_pos[2] = sc->volinfo.vol_msf[2]; return 0; }
static int mcd_subchan(struct mcd_softc *sc, struct ioc_read_subchannel *sch) { struct mcd_qchninfo q; struct cd_sub_channel_info data; int lba; if (sc->data.debug) device_printf(sc->dev, "subchan af=%d, df=%d\n", sch->address_format, sch->data_format); if (sch->address_format != CD_MSF_FORMAT && sch->address_format != CD_LBA_FORMAT) return (EINVAL); if (sch->data_format != CD_CURRENT_POSITION && sch->data_format != CD_MEDIA_CATALOG) return (EINVAL); if (mcd_setmode(sc, MCD_MD_COOKED) != 0) return (EIO); if (mcd_getqchan(sc, &q) < 0) return (EIO); data.header.audio_status = sc->data.audio_status; data.what.position.data_format = sch->data_format; switch (sch->data_format) { case CD_MEDIA_CATALOG: data.what.media_catalog.mc_valid = 1; data.what.media_catalog.mc_number[0] = '\0'; break; case CD_CURRENT_POSITION: data.what.position.control = q.control; data.what.position.addr_type = q.addr_type; data.what.position.track_number = bcd2bin(q.trk_no); data.what.position.index_number = bcd2bin(q.idx_no); switch (sch->address_format) { case CD_MSF_FORMAT: data.what.position.reladdr.msf.unused = 0; data.what.position.reladdr.msf.minute = bcd2bin(q.trk_size_msf[0]); data.what.position.reladdr.msf.second = bcd2bin(q.trk_size_msf[1]); data.what.position.reladdr.msf.frame = bcd2bin(q.trk_size_msf[2]); data.what.position.absaddr.msf.unused = 0; data.what.position.absaddr.msf.minute = bcd2bin(q.hd_pos_msf[0]); data.what.position.absaddr.msf.second = bcd2bin(q.hd_pos_msf[1]); data.what.position.absaddr.msf.frame = bcd2bin(q.hd_pos_msf[2]); break; case CD_LBA_FORMAT: lba = msf2hsg(q.trk_size_msf, 1); /* * Pre-gap has index number of 0, and decreasing MSF * address. Must be converted to negative LBA, per * SCSI spec. */ if (data.what.position.index_number == 0) lba = -lba; data.what.position.reladdr.lba = htonl(lba); data.what.position.absaddr.lba = htonl(msf2hsg(q.hd_pos_msf, 0)); break; } break; } return copyout(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len)); }
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); }
int mcd_read_subchannel(struct mcd_softc *sc, struct ioc_read_subchannel *ch, struct cd_sub_channel_info *info) { int len = ch->data_len; union mcd_qchninfo q; daddr_t lba; int error; if (sc->debug) printf("%s: subchan: af=%d df=%d\n", device_xname(sc->sc_dev), ch->address_format, ch->data_format); if (len > sizeof(*info) || len < sizeof(info->header)) return EINVAL; if (ch->address_format != CD_MSF_FORMAT && ch->address_format != CD_LBA_FORMAT) return EINVAL; if (ch->data_format != CD_CURRENT_POSITION && ch->data_format != CD_MEDIA_CATALOG) return EINVAL; if ((error = mcd_getqchan(sc, &q, ch->data_format)) != 0) return error; info->header.audio_status = sc->audio_status; info->what.media_catalog.data_format = ch->data_format; switch (ch->data_format) { case CD_MEDIA_CATALOG: info->what.media_catalog.mc_valid = 1; #if 0 info->what.media_catalog.mc_number = #endif break; case CD_CURRENT_POSITION: info->what.position.track_number = bcd2bin(q.current.trk_no); info->what.position.index_number = bcd2bin(q.current.idx_no); switch (ch->address_format) { case CD_MSF_FORMAT: info->what.position.reladdr.addr[0] = 0; info->what.position.reladdr.addr[1] = bcd2bin(q.current.relative_pos[0]); info->what.position.reladdr.addr[2] = bcd2bin(q.current.relative_pos[1]); info->what.position.reladdr.addr[3] = bcd2bin(q.current.relative_pos[2]); info->what.position.absaddr.addr[0] = 0; info->what.position.absaddr.addr[1] = bcd2bin(q.current.absolute_pos[0]); info->what.position.absaddr.addr[2] = bcd2bin(q.current.absolute_pos[1]); info->what.position.absaddr.addr[3] = bcd2bin(q.current.absolute_pos[2]); break; case CD_LBA_FORMAT: lba = msf2hsg(q.current.relative_pos, 1); /* * Pre-gap has index number of 0, and decreasing MSF * address. Must be converted to negative LBA, per * SCSI spec. */ if (info->what.position.index_number == 0x00) lba = -lba; info->what.position.reladdr.addr[0] = lba >> 24; info->what.position.reladdr.addr[1] = lba >> 16; info->what.position.reladdr.addr[2] = lba >> 8; info->what.position.reladdr.addr[3] = lba; lba = msf2hsg(q.current.absolute_pos, 0); info->what.position.absaddr.addr[0] = lba >> 24; info->what.position.absaddr.addr[1] = lba >> 16; info->what.position.absaddr.addr[2] = lba >> 8; info->what.position.absaddr.addr[3] = lba; break; } break; } return 0; }