Subject: Changes to the mcd.c driver for audio disks.
To: Jordan K. Hubbard <jkh@freefall.cdrom.com>
From: Dave Burgess <burgess@s069.infonet.net>
List: current-users
Date: 11/11/1994 23:37:48
>
While I have been thwarted in my attempts to get Ada going, I have been
reasonably successful at getting audio CD support built into NetBSD. If
no one but me uses this it was worth it.
As an aside, part of the change that I made is a set of changes to the
mcdreg.h file in preparation for getting DMA support built into the
mcd.c driver and other cool stuff. The audio was more pressing, mainly
because it annoyed me that I couldn't listen to a music CD after I was
through slurping source code off of a CD-ROM. The changes below make
this a real possibility. The cdplayer program I wrote (and several of
you have) interfaces to these patches perfectly, allowing for cool
things like on screen track and time information in near real time.
Here are the patches (against NetBSD 1.0-RDN). FreeBSD readers should
be able to use these changes without many (or maybe any) changes.
*** mcd.c Fri Nov 11 21:17:31 1994
--- /usr/src/sys/arch/i386/isa/mcd.c Fri Nov 11 23:26:33 1994
***************
*** 1,4 ****
--- 1,5 ----
/*
+ * Copyright (c) 1994 David Burgess.
* Copyright (c) 1993, 1994 Charles Hannum.
* Copyright 1993 by Holger Veit (data part)
* Copyright 1993 by Brian Moore (audio part)
***************
*** 37,43 ****
*
* $Id: mcd.c,v 1.16.2.2 1994/08/05 23:00:24 mycroft Exp $
*/
!
/*static char COPYRIGHT[] = "mcd-driver (C)1993 by H.Veit & B.Moore";*/
#include <sys/types.h>
--- 38,49 ----
*
* $Id: mcd.c,v 1.16.2.2 1994/08/05 23:00:24 mycroft Exp $
*/
! /*
! * I have made changes to this software so that it will reliably work
! * with music CDs. During my research, I have also found that this
! * driver should be capable of interacting with Photo CDs as well as
! * the normal ISO9660 and Music CDs. Stay tuned
! */
/*static char COPYRIGHT[] = "mcd-driver (C)1993 by H.Veit & B.Moore";*/
#include <sys/types.h>
***************
*** 91,97 ****
#define MCDDOOROPEN MCD_ST_DOOROPEN /* sensed door open */
/* toc */
! #define MCD_MAXTOCS 104 /* from the Linux driver */
#define MCD_LASTPLUS1 170 /* special toc entry */
struct mcd_mbx {
--- 97,103 ----
#define MCDDOOROPEN MCD_ST_DOOROPEN /* sensed door open */
/* toc */
! #define MCD_MAXTOCS 65 /* from the SCSI cd.c */
#define MCD_LASTPLUS1 170 /* special toc entry */
struct mcd_mbx {
***************
*** 160,165 ****
--- 166,172 ----
int mcd_play __P((struct mcd_softc *, struct mcd_read2 *));
int mcd_pause __P((struct mcd_softc *));
int mcd_resume __P((struct mcd_softc *));
+ void mcd_get_sense __P((struct mcd_softc *));
int mcdprobe();
void mcdattach();
***************
*** 692,698 ****
/* Check flags. */
if (sc->status & (MCDDSKCHNG | MCDDOOROPEN)) {
MCD_TRACE("getstat: sensed DSKCHNG or DOOROPEN\n", 0, 0, 0, 0);
! sc->flags &= ~MCDVALID;
}
if (sc->status & MCDAUDIOBSY)
--- 699,705 ----
/* Check flags. */
if (sc->status & (MCDDSKCHNG | MCDDOOROPEN)) {
MCD_TRACE("getstat: sensed DSKCHNG or DOOROPEN\n", 0, 0, 0, 0);
! sc->flags &= ~(MCDVALID & MCDVOLINFO & MCDTOC);
}
if (sc->status & MCDAUDIOBSY)
***************
*** 1119,1125 ****
{
struct ret_toc {
struct ioc_toc_header th;
! struct cd_toc_entry rt;
} ret_toc;
struct ioc_toc_header th;
int rc, i;
--- 1126,1132 ----
{
struct ret_toc {
struct ioc_toc_header th;
! struct cd_toc_entry rt[MCD_MAXTOCS];
} ret_toc;
struct ioc_toc_header th;
int rc, i;
***************
*** 1129,1166 ****
return rc;
/* Find the TOC to copy. */
! i = te->starting_track;
! if (i == MCD_LASTPLUS1)
i = bcd2bin(sc->volinfo.trk_high) + 1;
! /* Verify starting track. */
! if (i < bcd2bin(sc->volinfo.trk_low) ||
! i > bcd2bin(sc->volinfo.trk_high) + 1)
return EINVAL;
! /* Do we have room? */
! if (te->data_len < sizeof(struct ioc_toc_header) +
! sizeof(struct cd_toc_entry))
return EINVAL;
! /* Copy the TOC header. */
! if (mcd_toc_header(sc, &th) < 0)
return EIO;
! ret_toc.th = th;
! /* Copy the TOC data. */
! ret_toc.rt.control = sc->toc[i].ctrl_adr;
! ret_toc.rt.addr_type = te->address_format;
! ret_toc.rt.track = i;
! if (te->address_format == CD_MSF_FORMAT) {
! ret_toc.rt.addr[1] = sc->toc[i].hd_pos_msf[0];
! ret_toc.rt.addr[2] = sc->toc[i].hd_pos_msf[1];
! ret_toc.rt.addr[3] = sc->toc[i].hd_pos_msf[2];
}
-
/* Copy the data back. */
! copyout(&ret_toc, te->data,
! sizeof(struct cd_toc_entry) + sizeof(struct ioc_toc_header));
return 0;
}
--- 1136,1173 ----
return rc;
/* Find the TOC to copy. */
! for (i = te->starting_track; i < MCD_MAXTOCS; i++) {
! if (i >= MCD_LASTPLUS1)
i = bcd2bin(sc->volinfo.trk_high) + 1;
! /* Verify starting track. */
! if (i < bcd2bin(sc->volinfo.trk_low) ||
! i > bcd2bin(sc->volinfo.trk_high) + 1)
return EINVAL;
! /* Do we have room? */
! if (te->data_len < sizeof(struct ioc_toc_header) +
! sizeof(struct cd_toc_entry))
return EINVAL;
! /* Copy the TOC header. */
! if (mcd_toc_header(sc, &th) < 0)
return EIO;
! ret_toc.th = th;
!
! /* Copy the TOC data. */
! ret_toc.rt[i].control = sc->toc[i].ctrl_adr;
! ret_toc.rt[i].addr_type = te->address_format;
! ret_toc.rt[i].track = i;
! if (te->address_format == CD_MSF_FORMAT) {
! ret_toc.rt[i].addr[1] = sc->toc[i].hd_pos_msf[0];
! ret_toc.rt[i].addr[2] = sc->toc[i].hd_pos_msf[1];
! ret_toc.rt[i].addr[3] = sc->toc[i].hd_pos_msf[2];
! }
}
/* Copy the data back. */
! copyout(ret_toc.rt, te->data, te->data_len);
return 0;
}
***************
*** 1190,1196 ****
printf("%s: getqchan: ctl=%d t=%d i=%d ttm=%d:%d.%d dtm=%d:%d.%d\n",
sc->sc_dev.dv_xname, q->ctrl_adr, q->trk_no, q->idx_no,
q->trk_size_msf[0], q->trk_size_msf[1], q->trk_size_msf[2],
! q->trk_size_msf[0], q->trk_size_msf[1], q->trk_size_msf[2]);
return 0;
}
--- 1197,1203 ----
printf("%s: getqchan: ctl=%d t=%d i=%d ttm=%d:%d.%d dtm=%d:%d.%d\n",
sc->sc_dev.dv_xname, q->ctrl_adr, q->trk_no, q->idx_no,
q->trk_size_msf[0], q->trk_size_msf[1], q->trk_size_msf[2],
! q->hd_pos_msf[0], q->hd_pos_msf[1], q->hd_pos_msf[2]);
return 0;
}
***************
*** 1201,1206 ****
--- 1208,1214 ----
{
struct mcd_qchninfo q;
struct cd_sub_channel_info data;
+ int i;
if (sc->debug)
printf("%s: subchan: af=%d df=%d\n", sc->sc_dev.dv_xname,
***************
*** 1216,1223 ****
data.header.audio_status = sc->audio_status;
data.what.position.data_format = CD_MSF_FORMAT;
data.what.position.track_number = bcd2bin(q.trk_no);
! if (copyout(&data, ch->data, sizeof(struct cd_sub_channel_info)) != 0)
return EFAULT;
return 0;
}
--- 1224,1235 ----
data.header.audio_status = sc->audio_status;
data.what.position.data_format = CD_MSF_FORMAT;
data.what.position.track_number = bcd2bin(q.trk_no);
+ for (i = 0; i < 3; i++) {
+ data.what.position.reladdr[i] = bcd2bin(q.trk_size_msf[i]);
+ data.what.position.absaddr[i] = bcd2bin(q.hd_pos_msf[i]);
+ }
! if (copyout(&data, ch->data, ch->data_len) != 0)
return EFAULT;
return 0;
}
***************
*** 1230,1236 ****
struct mcd_read2 pb;
int a = pt->start_track;
int z = pt->end_track;
! int rc;
if ((rc = mcd_read_toc(sc)) != 0)
return rc;
--- 1242,1248 ----
struct mcd_read2 pb;
int a = pt->start_track;
int z = pt->end_track;
! int rc,i;
if ((rc = mcd_read_toc(sc)) != 0)
return rc;
***************
*** 1242,1253 ****
z < sc->volinfo.trk_low || z > sc->volinfo.trk_high)
return EINVAL;
! pb.start_msf[0] = sc->toc[a].hd_pos_msf[0];
! pb.start_msf[1] = sc->toc[a].hd_pos_msf[1];
! pb.start_msf[2] = sc->toc[a].hd_pos_msf[2];
! pb.end_msf[0] = sc->toc[z+1].hd_pos_msf[0];
! pb.end_msf[1] = sc->toc[z+1].hd_pos_msf[1];
! pb.end_msf[2] = sc->toc[z+1].hd_pos_msf[2];
return mcd_play(sc, &pb);
}
--- 1254,1263 ----
z < sc->volinfo.trk_low || z > sc->volinfo.trk_high)
return EINVAL;
! for (i = 0; i < 3; i ++) {
! pb.start_msf[i] = sc->toc[a].hd_pos_msf[i];
! pb.end_msf[i] = sc->toc[z+1].hd_pos_msf[i];
! }
return mcd_play(sc, &pb);
}
***************
*** 1275,1285 ****
--- 1285,1314 ----
if (sc->debug)
printf("%s: play: retry=%d status=%d\n", sc->sc_dev.dv_xname,
retry, st);
+ if (st & (MCD_ST_BUSY)) {
+ mcd_get_sense(sc);
+ }
if (!retry)
return ENXIO;
sc->audio_status = CD_AS_PLAY_IN_PROGRESS;
return 0;
+ }
+
+ void
+ mcd_get_sense(sc)
+ struct mcd_softc *sc;
+ {
+ u_short iobase = sc->iobase;
+ int retry, st;
+
+ for (retry = MCD_RETRIES; retry; retry--) {
+ outb(iobase + mcd_command, MCD_CMDGETSENSE);
+ if ((st = mcd_getstat(sc, 0)) != -1)
+ break;
+ }
+ printf("%s: getsense: retry=%d sense=%d\n", sc->sc_dev.dv_xname,
+ retry, st);
}
int
*** mcdreg.h Tue Feb 22 05:03:16 1994
--- /usr/src/sys/arch/i386/isa/mcdreg.h Fri Nov 11 21:31:39 1994
***************
*** 64,69 ****
--- 64,72 ----
#define mcd_reset 1
#define mcd_xfer 1
#define mcd_ctl2 2 /* XXX Is this right? */
+ /* This port is not documented in the Mitsumi
+ * stuff that I have...
+ */
#define mcd_config 3
#define MCD_MASK_DMA 0x07 /* bits 2-0 = DMA channel */
***************
*** 78,104 ****
#define MCD_ST_DOOROPEN 0x80
#define MCD_ST_DSKIN 0x40
#define MCD_ST_DSKCHNG 0x20
#define MCD_ST_BUSY 0x04
! #define MCD_ST_AUDIOBSY 0x02
/* commands known by the controller */
#define MCD_CMDRESET 0x00
#define MCD_CMDGETVOLINFO 0x10 /* gets mcd_volinfo */
#define MCD_CMDGETQCHN 0x20 /* gets mcd_qchninfo */
#define MCD_CMDGETSTAT 0x40 /* gets a byte of status */
#define MCD_CMDSETMODE 0x50 /* set transmission mode, needs byte */
! #define MCD_MD_RAW 0x60
! #define MCD_MD_COOKED 0x01
! #define MCD_MD_TOC 0x05
#define MCD_CMDSTOPAUDIO 0x70
#define MCD_CMDGETVOLUME 0x8E /* gets mcd_volume */
#define MCD_CMDSETVOLUME 0xAE /* sets mcd_volume */
#define MCD_CMDREAD1 0xB0 /* read n sectors */
#define MCD_CMDREAD2 0xC0 /* read from-to */
#define MCD_CMDCONTINFO 0xDC /* Get controller info */
#define MCD_CMDEJECTDISK 0xF6
#define MCD_CMDCLOSETRAY 0xF8
#define MCD_CMDLOCKDRV 0xFE /* needs byte */
#define MCD_LK_UNLOCK 0x00
#define MCD_LK_LOCK 0x01
#define MCD_LK_TEST 0x02
--- 81,158 ----
#define MCD_ST_DOOROPEN 0x80
#define MCD_ST_DSKIN 0x40
#define MCD_ST_DSKCHNG 0x20
+ #define MCD_ST_SPINNING 0x10
+ #define MCD_ST_AUDIODISK 0x08 /* Audio Disk is in */
#define MCD_ST_BUSY 0x04
! #define MCD_ST_AUDIOBSY 0x02 /* Audio Disk is Playing */
! #define MCD_ST_CMDCHECK 0x01 /* Command error */
/* commands known by the controller */
+
#define MCD_CMDRESET 0x00
#define MCD_CMDGETVOLINFO 0x10 /* gets mcd_volinfo */
+ #define MCD_CMDGETDISCINFO 0x11 /* gets mcd_disk information */
#define MCD_CMDGETQCHN 0x20 /* gets mcd_qchninfo */
+ #define MCD_CMDGETSENSE 0x30 /* gets sense info */
#define MCD_CMDGETSTAT 0x40 /* gets a byte of status */
#define MCD_CMDSETMODE 0x50 /* set transmission mode, needs byte */
! #define MCD_MD_RAW 0x60 /* resets drive to raw mode */
#define MCD_CMDSTOPAUDIO 0x70
+ #define MCD_CMDSTOPAUDIOTIME 0x80 /* ???? */
#define MCD_CMDGETVOLUME 0x8E /* gets mcd_volume */
+ #define MCD_CMDSETDRIVEMODE 0xA0 /* Set drive mode */
+ #define MCD_CMDREADUPC 0xA2 /* Get UPC info */
#define MCD_CMDSETVOLUME 0xAE /* sets mcd_volume */
#define MCD_CMDREAD1 0xB0 /* read n sectors */
#define MCD_CMDREAD2 0xC0 /* read from-to */
+ #define MCD_CMDSTARTAUDIOMSF 0xC1 /* read audio data */
+ #define MCD_CMDREADFAST 0xC1 /* Read lots of data from the drive */
+ #define MCD_CMDGETDRIVEMODE 0xC2 /* Get the drive mode */
+ #define MCD_CMDREAD 0xC3 /* Read data from the drive */
+ #define MCD_CMDSETINTERLEAVE 0xC8 /* Adjust the interleave */
#define MCD_CMDCONTINFO 0xDC /* Get controller info */
+ #define MCD_CMDSTOP 0xF0 /* Stop everything */
#define MCD_CMDEJECTDISK 0xF6
#define MCD_CMDCLOSETRAY 0xF8
#define MCD_CMDLOCKDRV 0xFE /* needs byte */
+
+ /* Transmission Mode Stuff */
+
+ #define MCD_MD_TESTMODE 0x80 /* 0 = DATALENGTH setting is valid */
+ #define MCD_MD_DATALENGTH 0x40 /* 0 = Read User Data only */
+ /* 1 = Read Raw sectors (2352 bytes) */
+ #define MCD_MD_ECCMODE 0x20 /* 0 = Use secondary correction */
+ /* 1 = Don't use secondary ECC */
+ #define MCD_MD_SPINDOWN 0x08 /* 0 = Spin Up, 1 = Spin Down */
+ #define MCD_MD_GET_TOC 0x04 /* 1 = Get TOC on GETQCHAN */
+ /* 0 = Get UPC on next GETQCHAN */
+ #define MCD_MD_MUTEDATA 0x01 /* 1 = Don't play back Data as
+ audio */
+ #define MCD_MD_TOC 0x05 /* Get TOC and don't play it as audio */
+ #define MCD_MD_COOKED 0x01 /* Not really, this simply means
+ * it doesn't get played on the
+ * speakers */
+
+ /* DMA Enable Stuff */
+ #define MCD_DMA_IRQFLAG 0x10 /* Set data0 for IRQ click */
+
+ #define MCD_DMA_PREIRQ 0x01 /* All of these are for */
+ #define MCD_DMA_POSTIRQ 0x02 /* MCD_DMA_IRQFLAG.. */
+ #define MCD_DMA_ERRIRQ 0x04 /* */
+
+ #define MCD_DMA_TIMEOUT 0x08 /* Set data0 for DMA Timeout */
+ #define MCD_DMA_UPCFLAG 0x04 /* 1 = Next command will be READUPC */
+
+ #define MCD_DMA_DMAMODE 0x02 /* 1 = Data uses DMA */
+ #define MCD_DMA_TRANSFERLENGTH 0x01 /* data0 = MSB, data1 = LSB of
+ block length */
+ struct mcd_dma_mode {
+ u_char dma_mode;
+ u_char data0; /* If dma_mode & 0x10: Use IRQ settings */
+ u_char data1; /* Used if dma_mode & 0x01 */
+ } ;
+
+ /* Lock Stuff */
#define MCD_LK_UNLOCK 0x00
#define MCD_LK_LOCK 0x01
#define MCD_LK_TEST 0x02
***************
*** 126,131 ****
--- 180,190 ----
u_char v0ls;
};
+ struct mcd_holdtime {
+ u_char units_of_ten_seconds;
+ /* If this is 0, the default (12) is used) */
+ };
+
struct mcd_read1 {
bcd_t start_msf[3];
u_char nsec[3];
***************
*** 134,137 ****
--- 193,205 ----
struct mcd_read2 {
bcd_t start_msf[3];
bcd_t end_msf[3];
+ };
+
+ struct mcd_rawsector {
+ u_char sync1[12];
+ u_char header[4];
+ u_char subheader1[4];
+ u_char subheader2[4];
+ u_char data[2048];
+ u_char ecc_bits[280];
};