summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjoerg <joerg@FreeBSD.org>1997-05-04 15:24:23 +0000
committerjoerg <joerg@FreeBSD.org>1997-05-04 15:24:23 +0000
commit8cea5b917d62db9701a7fe2a45c9032aec48325d (patch)
treea2408a8a297df1fa5ba68bcc7ee4bc36c2fc2521
parent60343a746abd65c1fe9040ea648287d56be4b871 (diff)
downloadFreeBSD-src-8cea5b917d62db9701a7fe2a45c9032aec48325d.zip
FreeBSD-src-8cea5b917d62db9701a7fe2a45c9032aec48325d.tar.gz
This mega-commit brings the following:
. It makes cd9660 root f/s working again. . It makes CD9660 a new-style option. . It adds support to mount an ISO9660 multi-session CD-ROM as the root filesystem (the last session actually, but that's what is expected behaviour). Sigh. The CDIOREADTOCENTRYS did a copyout() of its own, and thus has been unusable for me for this work. Too bad it didn't simply stuff the max 100 entries into the struct ioc_read_toc_entry, but relied on a user supplied data buffer instead. :-( I now had to reinvent the wheel, and created a CDIOREADTOCENTRY ioctl command that can be used in a kernel context. While doing this, i noticed the following bogosities in existing CD-ROM drivers: wcd: This driver is likely to be totally bogus when someone tries two succeeding CDIOREADTOCENTRYS (or now CDIOREADTOCENTRY) commands with requesting MSF format, since it apparently operates on an internal table. scd: This driver apparently returns just a single TOC entry only for the CDIOREADTOCENTRYS command. I have only been able to test the CDIOREADTOCENTRY command with the cd(4) driver. I hereby request the respective maintainers of the other CD-ROM drivers to verify my code for their driver. When it comes to merging this CD-ROM multisession stuff into RELENG_2_2 i will only consider drivers where i've got a confirmation that it actually works.
-rw-r--r--sys/amd64/amd64/autoconf.c62
-rw-r--r--sys/conf/NOTES9
-rw-r--r--sys/conf/options14
-rw-r--r--sys/dev/mcd/mcd.c54
-rw-r--r--sys/dev/scd/scd.c44
-rw-r--r--sys/fs/cd9660/cd9660_vfsops.c76
-rw-r--r--sys/fs/cd9660/iso.h4
-rw-r--r--sys/i386/conf/LINT9
-rw-r--r--sys/i386/conf/NOTES9
-rw-r--r--sys/i386/i386/autoconf.c62
-rw-r--r--sys/i386/isa/matcd/matcd.c78
-rw-r--r--sys/i386/isa/mcd.c54
-rw-r--r--sys/i386/isa/scd.c44
-rw-r--r--sys/i386/isa/wcd.c35
-rw-r--r--sys/isofs/cd9660/cd9660_vfsops.c76
-rw-r--r--sys/isofs/cd9660/iso.h4
-rw-r--r--sys/scsi/cd.c59
-rw-r--r--sys/sys/cdio.h10
18 files changed, 623 insertions, 80 deletions
diff --git a/sys/amd64/amd64/autoconf.c b/sys/amd64/amd64/autoconf.c
index 7fad268..d18fb01 100644
--- a/sys/amd64/amd64/autoconf.c
+++ b/sys/amd64/amd64/autoconf.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)autoconf.c 7.1 (Berkeley) 5/9/91
- * $Id: autoconf.c,v 1.65 1997/04/26 11:45:02 peter Exp $
+ * $Id: autoconf.c,v 1.66 1997/04/26 18:57:34 peter Exp $
*/
/*
@@ -46,6 +46,7 @@
* and the drivers are initialized.
*/
#include "opt_smp.h"
+#include "opt_cd9660.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -101,9 +102,17 @@ static void setroot __P((void));
#ifdef CD9660
+#include <sys/fcntl.h>
+#include <sys/proc.h>
+#include <sys/stat.h>
+#include <machine/clock.h>
#include <isofs/cd9660/iso.h>
-/* We need to try out all our potential CDROM drives, so we need a table. */
+/*
+ * XXX All this CD-ROM root stuff is fairly messy. Ick.
+ *
+ * We need to try out all our potential CDROM drives, so we need a table.
+ */
static struct {
char *name;
int major;
@@ -112,25 +121,44 @@ static struct {
{ "mcd", 7 },
{ "scd", 16 },
{ "matcd", 17 },
+ { "wcd", 19 },
{ 0, 0}
};
-static int find_cdrom_root __P((void *));
+static int find_cdrom_root __P((void));
static int
-find_cdrom_root(dummy)
- void *dummy;
+find_cdrom_root()
{
- int i,j,k;
-
- for (j = 0 ; j < 2; j++)
- for (k = 0 ; try_cdrom[k].name ; k++) {
- rootdev = makedev(try_cdrom[k].major,j*8);
- printf("trying rootdev=0x%lx (%s%d)\n",
- rootdev, try_cdrom[k].name,j);
- i = (*cd9660_mountroot)();
- if (!i) return i;
+ int i, j, error;
+ struct bdevsw *bd;
+ dev_t orootdev;
+
+#if CD9660_ROOTDELAY > 0
+ DELAY(CD9660_ROOTDELAY * 1000000);
+#endif
+ orootdev = rootdev;
+ for (i = 0 ; i < 2; i++)
+ for (j = 0 ; try_cdrom[j].name ; j++) {
+ if (try_cdrom[j].major >= nblkdev)
+ continue;
+ rootdev = makedev(try_cdrom[j].major, i * 8);
+ bd = bdevsw[major(rootdev)];
+ if (bd == NULL || bd->d_open == NULL)
+ continue;
+ if (bootverbose)
+ printf("trying %s%d as rootdev (0x%x)\n",
+ try_cdrom[j].name, i, rootdev);
+ error = (bd->d_open)(rootdev, FREAD, S_IFBLK, curproc);
+ if (error == 0) {
+ if (bd->d_close != NULL)
+ (bd->d_close)(rootdev, FREAD, S_IFBLK,
+ curproc);
+ return 0;
+ }
}
+
+ rootdev = orootdev;
return EINVAL;
}
#endif /* CD9660 */
@@ -233,7 +261,11 @@ configure(dummy)
if ((boothowto & RB_CDROM)) {
if (bootverbose)
printf("Considering CD-ROM root f/s.\n");
- mountrootfsname = "cd9660";
+ /* NB: find_cdrom_root() sets rootdev if successful. */
+ if (find_cdrom_root() == 0)
+ mountrootfsname = "cd9660";
+ else if (bootverbose)
+ printf("No CD-ROM available as root f/s.\n");
}
#endif
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
index 026e9d5..7fc4aa7 100644
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -2,7 +2,7 @@
# LINT -- config file for checking all the sources, tries to pull in
# as much of the source tree as it can.
#
-# $Id: LINT,v 1.328 1997/04/26 11:44:55 peter Exp $
+# $Id: LINT,v 1.329 1997/04/28 00:24:26 fsmp Exp $
#
# NB: You probably don't want to try running a kernel built from this
# file. Instead, you should start from GENERIC, and add options from
@@ -439,6 +439,13 @@ options QUOTA #enable disk quotas
#options UMAPFS_DIAGNOSTIC
#options UNION_DIAGNOSTIC
+# In particular multi-session CD-Rs might require a huge amount of
+# time in order to "settle". If we are about mounting them as the
+# root f/s, we gotta wait a little.
+#
+# The number is supposed to be in seconds.
+options "CD9660_ROOTDELAY=20"
+
# Add some error checking code to the null_bypass routine
# in the NULL filesystem
#options SAFETY
diff --git a/sys/conf/options b/sys/conf/options
index 4fe0c0a..ff394b4 100644
--- a/sys/conf/options
+++ b/sys/conf/options
@@ -1,4 +1,4 @@
-# $Id$
+# $Id: options,v 1.29 1997/02/22 09:28:14 peter Exp $
# Format:
# Option name filename
@@ -29,6 +29,18 @@ PORTAL opt_dontuse.h
PROCFS opt_dontuse.h
UMAPFS opt_dontuse.h
+# The cd9660 static filesystem has one slightly bogus static dependency
+# in sys/i386/i386/autoconf.c. If this filesystem is statically
+# compiled into the kernel, code for mounting a CD-ROM root filesystem
+# will be enabled. This is purposely unavailable for the LKM-based
+# version.
+CD9660
+
+# In particular multi-session CD-Rs might require a huge amount of
+# time in order to "settle". If we are about mounting them as the
+# root f/s, we gotta wait a little.
+CD9660_ROOTDELAY opt_cd9660.h
+
# The union static file system has bogus static dependencies, so it isn't
# hidden yet.
UNION
diff --git a/sys/dev/mcd/mcd.c b/sys/dev/mcd/mcd.c
index 6a7adb3..f7eecb8 100644
--- a/sys/dev/mcd/mcd.c
+++ b/sys/dev/mcd/mcd.c
@@ -40,7 +40,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: mcd.c,v 1.87 1997/03/24 11:23:55 bde Exp $
+ * $Id: mcd.c,v 1.88 1997/04/20 17:26:54 bde Exp $
*/
static const char COPYRIGHT[] = "mcd-driver (C)1993 by H.Veit & B.Moore";
@@ -195,6 +195,7 @@ static int mcd_subchan(int unit, struct ioc_read_subchannel *sc);
static int mcd_toc_header(int unit, struct ioc_toc_header *th);
static int mcd_read_toc(int unit);
static int mcd_toc_entrys(int unit, struct ioc_read_toc_entry *te);
+static int mcd_toc_entry(int unit, struct ioc_read_toc_single_entry *te);
static int mcd_stop(int unit);
static int mcd_eject(int unit);
static int mcd_inject(int unit);
@@ -1427,6 +1428,57 @@ mcd_read_toc(int unit)
}
static int
+mcd_toc_entry(int unit, struct ioc_read_toc_single_entry *te)
+{
+ struct mcd_data *cd = mcd_data + unit;
+ struct ioc_toc_header th;
+ int rc, trk;
+
+ if (te->address_format != CD_MSF_FORMAT
+ && te->address_format != CD_LBA_FORMAT)
+ return EINVAL;
+
+ /* Copy the toc header */
+ if ((rc = mcd_toc_header(unit, &th)) != 0)
+ return rc;
+
+ /* verify starting track */
+ trk = te->track;
+ if (trk == 0)
+ trk = th.starting_track;
+ else if (trk == MCD_LASTPLUS1)
+ trk = th.ending_track + 1;
+ else if (trk < th.starting_track || trk > th.ending_track + 1)
+ return EINVAL;
+
+ /* Make sure we have a valid toc */
+ if ((rc=mcd_read_toc(unit)) != 0)
+ return rc;
+
+ /* Copy the TOC data. */
+ if (cd->toc[trk].idx_no == 0)
+ return EIO;
+
+ te->entry.control = cd->toc[trk].control;
+ te->entry.addr_type = cd->toc[trk].addr_type;
+ te->entry.track =
+ cd->toc[trk].idx_no > 0x99 ? cd->toc[trk].idx_no :
+ bcd2bin(cd->toc[trk].idx_no);
+ switch (te->address_format) {
+ case CD_MSF_FORMAT:
+ te->entry.addr.msf.unused = 0;
+ te->entry.addr.msf.minute = bcd2bin(cd->toc[trk].hd_pos_msf[0]);
+ te->entry.addr.msf.second = bcd2bin(cd->toc[trk].hd_pos_msf[1]);
+ te->entry.addr.msf.frame = bcd2bin(cd->toc[trk].hd_pos_msf[2]);
+ break;
+ case CD_LBA_FORMAT:
+ te->entry.addr.lba = htonl(msf2hsg(cd->toc[trk].hd_pos_msf, 0));
+ break;
+ }
+ return 0;
+}
+
+static int
mcd_toc_entrys(int unit, struct ioc_read_toc_entry *te)
{
struct mcd_data *cd = mcd_data + unit;
diff --git a/sys/dev/scd/scd.c b/sys/dev/scd/scd.c
index 33d77f8..acd1968 100644
--- a/sys/dev/scd/scd.c
+++ b/sys/dev/scd/scd.c
@@ -41,7 +41,7 @@
*/
-/* $Id: scd.c,v 1.28 1997/03/24 11:24:01 bde Exp $ */
+/* $Id: scd.c,v 1.29 1997/04/20 17:26:55 bde Exp $ */
/* Please send any comments to micke@dynas.se */
@@ -180,6 +180,7 @@ static int read_subcode(int unit, struct sony_subchannel_position_data *sc);
/* for xcdplayer */
static int scd_toc_header(int unit, struct ioc_toc_header *th);
static int scd_toc_entrys(int unit, struct ioc_read_toc_entry *te);
+static int scd_toc_entry(int unit, struct ioc_read_toc_single_entry *te);
#define SCD_LASTPLUS1 170 /* don't ask, xcdplayer passes this in */
static int scd_probe(struct isa_device *dev);
@@ -456,6 +457,8 @@ scdioctl(dev_t dev, int cmd, caddr_t addr, int flags, struct proc *p)
return scd_toc_header (unit, (struct ioc_toc_header *) addr);
case CDIOREADTOCENTRYS:
return scd_toc_entrys (unit, (struct ioc_read_toc_entry*) addr);
+ case CDIOREADTOCENTRY:
+ return scd_toc_entry (unit, (struct ioc_read_toc_single_entry*) addr);
case CDIOCSETPATCH:
case CDIOCGETVOL:
case CDIOCSETVOL:
@@ -1517,6 +1520,45 @@ scd_toc_entrys (int unit, struct ioc_read_toc_entry *te)
}
+static int
+scd_toc_entry (int unit, struct ioc_read_toc_single_entry *te)
+{
+ struct scd_data *cd = scd_data + unit;
+ struct cd_toc_entry toc_entry;
+ int rc, i;
+
+ if (!(cd->flags & SCDTOC) && (rc = read_toc(unit)) != 0) {
+ print_error(unit, rc);
+ return EIO;
+ }
+
+ /* find the toc to copy*/
+ i = te->track;
+ if (i == SCD_LASTPLUS1)
+ i = cd->last_track + 1;
+
+ /* verify starting track */
+ if (i < cd->first_track || i > cd->last_track+1)
+ return EINVAL;
+
+ /* copy the toc data */
+ toc_entry.control = cd->toc[i].ctl;
+ toc_entry.addr_type = te->address_format;
+ toc_entry.track = i;
+ if (te->address_format == CD_MSF_FORMAT) {
+ toc_entry.addr.msf.unused = 0;
+ toc_entry.addr.msf.minute = bcd2bin(cd->toc[i].start_msf[0]);
+ toc_entry.addr.msf.second = bcd2bin(cd->toc[i].start_msf[1]);
+ toc_entry.addr.msf.frame = bcd2bin(cd->toc[i].start_msf[2]);
+ }
+
+ /* copy the data back */
+ bcopy(&toc_entry, &te->entry, sizeof(struct cd_toc_entry));
+
+ return 0;
+}
+
+
static scd_devsw_installed = 0;
static void scd_drvinit(void *unused)
diff --git a/sys/fs/cd9660/cd9660_vfsops.c b/sys/fs/cd9660/cd9660_vfsops.c
index a875434..a61ccfc 100644
--- a/sys/fs/cd9660/cd9660_vfsops.c
+++ b/sys/fs/cd9660/cd9660_vfsops.c
@@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)cd9660_vfsops.c 8.18 (Berkeley) 5/22/95
- * $Id: cd9660_vfsops.c,v 1.23 1997/04/29 15:52:53 joerg Exp $
+ * $Id: cd9660_vfsops.c,v 1.24 1997/04/29 17:11:51 joerg Exp $
*/
#include <sys/param.h>
@@ -48,6 +48,8 @@
#include <miscfs/specfs/specdev.h>
#include <sys/mount.h>
#include <sys/buf.h>
+#include <sys/cdio.h>
+#include <sys/conf.h>
#include <sys/fcntl.h>
#include <sys/errno.h>
#include <sys/malloc.h>
@@ -94,40 +96,77 @@ VFS_SET(cd9660_vfsops, cd9660, MOUNT_CD9660, VFCF_READONLY);
* Called by vfs_mountroot when iso is going to be mounted as root.
*/
+static int iso_get_ssector __P((dev_t dev, struct proc *p));
static int iso_mountfs __P((struct vnode *devvp, struct mount *mp,
struct proc *p, struct iso_args *argp));
+static int iso_mountroot __P((struct mount *mp, struct proc *p));
-int
-cd9660_mountroot()
+/*
+ * Try to find the start of the last data track on this CD-ROM. This
+ * is used to mount the last session of a multi-session CD. Bail out
+ * and return 0 if we fail, this is always a safe bet.
+ */
+static int
+iso_get_ssector(dev, p)
+ dev_t dev;
+ struct proc *p;
{
+ struct ioc_toc_header h;
+ struct ioc_read_toc_single_entry t;
+ int i;
+ struct bdevsw *bd;
+ d_ioctl_t *ioctlp;
+
+ bd = bdevsw[major(dev)];
+ ioctlp = bd->d_ioctl;
+ if (ioctlp == NULL)
+ return 0;
+
+ if (ioctlp(dev, CDIOREADTOCHEADER, (caddr_t)&h, FREAD, p) == -1)
+ return 0;
+
+ for (i = h.ending_track; i >= 0; i--) {
+ t.address_format = CD_LBA_FORMAT;
+ t.track = i;
+ if (ioctlp(dev, CDIOREADTOCENTRY, (caddr_t)&t, FREAD, p) == -1)
+ return 0;
+ if ((t.entry.control & 4) != 0)
+ /* found a data track */
+ break;
+ }
+
+ if (i < 0)
+ return 0;
+
+ return ntohl(t.entry.addr.lba);
+}
+
+static int
+iso_mountroot(mp, p)
struct mount *mp;
- struct proc *p = curproc; /* XXX */
+ struct proc *p;
+{
struct iso_args args;
int error;
-
+
/*
* Get vnode for rootdev.
*/
if ((error = bdevvp(swapdev, &swapdev_vp)) ||
(error = bdevvp(rootdev, &rootvp))) {
- printf("cd9660_mountroot: can't setup bdevvp's");
+ printf("iso_mountroot: can't setup bdevvp's");
return (error);
}
- if (error = vfs_rootmountalloc("cd9660", "root_device", &mp))
- return (error);
args.flags = ISOFSMNT_ROOT;
- if (error = iso_mountfs(rootvp, mp, p, &args)) {
- mp->mnt_vfc->vfc_refcount--;
- vfs_unbusy(mp, p);
- free(mp, M_MOUNT);
+ args.ssector = iso_get_ssector(rootdev, p);
+ if (bootverbose)
+ printf("iso_mountroot(): using session at block %d\n",
+ args.ssector);
+ if (error = iso_mountfs(rootvp, mp, p, &args))
return (error);
- }
- simple_lock(&mountlist_slock);
- CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
- simple_unlock(&mountlist_slock);
+
(void)cd9660_statfs(mp, &mp->mnt_stat, p);
- vfs_unbusy(mp, p);
return (0);
}
@@ -150,6 +189,9 @@ cd9660_mount(mp, path, data, ndp, p)
int error;
struct iso_mnt *imp = 0;
+ if ((mp->mnt_flag & MNT_ROOTFS) != 0)
+ return (iso_mountroot(mp, p));
+
if ((error = copyin(data, (caddr_t)&args, sizeof (struct iso_args))))
return (error);
diff --git a/sys/fs/cd9660/iso.h b/sys/fs/cd9660/iso.h
index d7fc579..2437534 100644
--- a/sys/fs/cd9660/iso.h
+++ b/sys/fs/cd9660/iso.h
@@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)iso.h 8.6 (Berkeley) 5/10/95
- * $Id$
+ * $Id: iso.h,v 1.13 1997/02/22 09:38:52 peter Exp $
*/
#define ISODCL(from, to) (to - from + 1)
@@ -215,7 +215,7 @@ int cd9660_init __P((struct vfsconf *));
#define cd9660_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \
size_t, struct proc *)))eopnotsupp)
-int cd9660_mountroot __P((void));
+int cd9660_mountroot __P((int ssector));
extern vop_t **cd9660_vnodeop_p;
extern vop_t **cd9660_specop_p;
diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT
index 026e9d5..7fc4aa7 100644
--- a/sys/i386/conf/LINT
+++ b/sys/i386/conf/LINT
@@ -2,7 +2,7 @@
# LINT -- config file for checking all the sources, tries to pull in
# as much of the source tree as it can.
#
-# $Id: LINT,v 1.328 1997/04/26 11:44:55 peter Exp $
+# $Id: LINT,v 1.329 1997/04/28 00:24:26 fsmp Exp $
#
# NB: You probably don't want to try running a kernel built from this
# file. Instead, you should start from GENERIC, and add options from
@@ -439,6 +439,13 @@ options QUOTA #enable disk quotas
#options UMAPFS_DIAGNOSTIC
#options UNION_DIAGNOSTIC
+# In particular multi-session CD-Rs might require a huge amount of
+# time in order to "settle". If we are about mounting them as the
+# root f/s, we gotta wait a little.
+#
+# The number is supposed to be in seconds.
+options "CD9660_ROOTDELAY=20"
+
# Add some error checking code to the null_bypass routine
# in the NULL filesystem
#options SAFETY
diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES
index 026e9d5..7fc4aa7 100644
--- a/sys/i386/conf/NOTES
+++ b/sys/i386/conf/NOTES
@@ -2,7 +2,7 @@
# LINT -- config file for checking all the sources, tries to pull in
# as much of the source tree as it can.
#
-# $Id: LINT,v 1.328 1997/04/26 11:44:55 peter Exp $
+# $Id: LINT,v 1.329 1997/04/28 00:24:26 fsmp Exp $
#
# NB: You probably don't want to try running a kernel built from this
# file. Instead, you should start from GENERIC, and add options from
@@ -439,6 +439,13 @@ options QUOTA #enable disk quotas
#options UMAPFS_DIAGNOSTIC
#options UNION_DIAGNOSTIC
+# In particular multi-session CD-Rs might require a huge amount of
+# time in order to "settle". If we are about mounting them as the
+# root f/s, we gotta wait a little.
+#
+# The number is supposed to be in seconds.
+options "CD9660_ROOTDELAY=20"
+
# Add some error checking code to the null_bypass routine
# in the NULL filesystem
#options SAFETY
diff --git a/sys/i386/i386/autoconf.c b/sys/i386/i386/autoconf.c
index 7fad268..d18fb01 100644
--- a/sys/i386/i386/autoconf.c
+++ b/sys/i386/i386/autoconf.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)autoconf.c 7.1 (Berkeley) 5/9/91
- * $Id: autoconf.c,v 1.65 1997/04/26 11:45:02 peter Exp $
+ * $Id: autoconf.c,v 1.66 1997/04/26 18:57:34 peter Exp $
*/
/*
@@ -46,6 +46,7 @@
* and the drivers are initialized.
*/
#include "opt_smp.h"
+#include "opt_cd9660.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -101,9 +102,17 @@ static void setroot __P((void));
#ifdef CD9660
+#include <sys/fcntl.h>
+#include <sys/proc.h>
+#include <sys/stat.h>
+#include <machine/clock.h>
#include <isofs/cd9660/iso.h>
-/* We need to try out all our potential CDROM drives, so we need a table. */
+/*
+ * XXX All this CD-ROM root stuff is fairly messy. Ick.
+ *
+ * We need to try out all our potential CDROM drives, so we need a table.
+ */
static struct {
char *name;
int major;
@@ -112,25 +121,44 @@ static struct {
{ "mcd", 7 },
{ "scd", 16 },
{ "matcd", 17 },
+ { "wcd", 19 },
{ 0, 0}
};
-static int find_cdrom_root __P((void *));
+static int find_cdrom_root __P((void));
static int
-find_cdrom_root(dummy)
- void *dummy;
+find_cdrom_root()
{
- int i,j,k;
-
- for (j = 0 ; j < 2; j++)
- for (k = 0 ; try_cdrom[k].name ; k++) {
- rootdev = makedev(try_cdrom[k].major,j*8);
- printf("trying rootdev=0x%lx (%s%d)\n",
- rootdev, try_cdrom[k].name,j);
- i = (*cd9660_mountroot)();
- if (!i) return i;
+ int i, j, error;
+ struct bdevsw *bd;
+ dev_t orootdev;
+
+#if CD9660_ROOTDELAY > 0
+ DELAY(CD9660_ROOTDELAY * 1000000);
+#endif
+ orootdev = rootdev;
+ for (i = 0 ; i < 2; i++)
+ for (j = 0 ; try_cdrom[j].name ; j++) {
+ if (try_cdrom[j].major >= nblkdev)
+ continue;
+ rootdev = makedev(try_cdrom[j].major, i * 8);
+ bd = bdevsw[major(rootdev)];
+ if (bd == NULL || bd->d_open == NULL)
+ continue;
+ if (bootverbose)
+ printf("trying %s%d as rootdev (0x%x)\n",
+ try_cdrom[j].name, i, rootdev);
+ error = (bd->d_open)(rootdev, FREAD, S_IFBLK, curproc);
+ if (error == 0) {
+ if (bd->d_close != NULL)
+ (bd->d_close)(rootdev, FREAD, S_IFBLK,
+ curproc);
+ return 0;
+ }
}
+
+ rootdev = orootdev;
return EINVAL;
}
#endif /* CD9660 */
@@ -233,7 +261,11 @@ configure(dummy)
if ((boothowto & RB_CDROM)) {
if (bootverbose)
printf("Considering CD-ROM root f/s.\n");
- mountrootfsname = "cd9660";
+ /* NB: find_cdrom_root() sets rootdev if successful. */
+ if (find_cdrom_root() == 0)
+ mountrootfsname = "cd9660";
+ else if (bootverbose)
+ printf("No CD-ROM available as root f/s.\n");
}
#endif
diff --git a/sys/i386/isa/matcd/matcd.c b/sys/i386/isa/matcd/matcd.c
index 945152a..0ed243f 100644
--- a/sys/i386/isa/matcd/matcd.c
+++ b/sys/i386/isa/matcd/matcd.c
@@ -76,7 +76,7 @@
Dedicated to: My family, my Grandfather,
and Max, my Golden Retriever
-Thanks to: Jordon Hubbard (jkh) for getting me ramped-up to 2.x system
+Thanks to: Jordan Hubbard (jkh) for getting me ramped-up to 2.x system
quickly enough to make the 2.1 release. He put up with
plenty of silly questions and might get the post of
ambassador some day.
@@ -337,7 +337,7 @@ static char MATCDVERSION[]="Version 1(26) 18-Oct-95";
static char MATCDCOPYRIGHT[] = "Matsushita CD-ROM driver, Copr. 1994,1995 Frank Durda IV";
/* The proceeding strings may not be changed*/
-/* $Id: matcd.c,v 1.24 1997/03/24 11:24:22 bde Exp $ */
+/* $Id: matcd.c,v 1.25 1997/04/20 18:02:40 bde Exp $ */
/*---------------------------------------------------------------------------
Include declarations
@@ -572,6 +572,9 @@ static int matcd_toc_header(int ldrive, int cdrive, int controller,
static int matcd_toc_entries(int ldrive, int cdrive,
int controller,
struct ioc_read_toc_entry *ioc_entry);
+static int matcd_toc_entry(int ldrive, int cdrive,
+ int controller,
+ struct ioc_read_toc_single_entry *ioc_entry);
static int matcd_read_subq(int ldrive, int cdrive, int controller,
struct ioc_read_subchannel * sqp);
static int matcd_igot(struct ioc_capability * sqp);
@@ -1099,6 +1102,10 @@ int matcdioctl(dev_t dev, int command, caddr_t addr,
return(matcd_toc_entries(ldrive, cdrive, controller,
(struct ioc_read_toc_entry *) addr));
+ case CDIOREADTOCENTRY:
+ return(matcd_toc_entry(ldrive, cdrive, controller,
+ (struct ioc_read_toc_single_entry *) addr));
+
case CDIOCREADSUBCHANNEL:
return(matcd_read_subq(ldrive, cdrive, controller,
(struct ioc_read_subchannel *) addr));
@@ -2503,6 +2510,73 @@ static int matcd_toc_entries(int ldrive, int cdrive, int controller,
}
/*---------------------------------------------------------------------------
+ matcd_toc_entriy - Read a single TOC entry
+---------------------------------------------------------------------------*/
+
+static int matcd_toc_entry(int ldrive, int cdrive, int controller,
+ struct ioc_read_toc_single_entry * ioc_entry)
+{
+ struct matcd_data *cd;
+ struct cd_toc_entry *from;
+ struct cd_toc_entry *to;
+ int trk,origtrk,i,z,port;
+ unsigned char cmd[MAXCMDSIZ];
+ unsigned char data[5];
+
+ cd=&matcd_data[ldrive];
+ port=cd->iobase;
+
+ if ((cd->flags & MATCDLABEL)==0)
+ return(EIO); /*Refuse after chg error*/
+
+ zero_cmd(cmd);
+ cmd[0]=READTOC;
+
+ origtrk=trk=ioc_entry->track;
+ if (trk == 0xaa)
+ /* leadout */
+ trk=cd->volinfo.trk_high-1;
+ cmd[2]=trk+1;
+ lockbus(controller, ldrive); /*Request bus*/
+ matcd_slowcmd(port,ldrive,cdrive,cmd);
+ i=waitforit(10*TICKRES,DTEN,port,"mats1");
+ matcd_pread(port, 8, data); /*Read data returned*/
+ z=get_stat(port,ldrive); /*Read status byte*/
+ if ((z & MATCD_ST_ERROR)) { /*Something went wrong*/
+ i=get_error(port, ldrive, cdrive);
+ unlockbus(controller, ldrive); /*Release bus*/
+ return(EIO);
+ }
+ unlockbus(controller, ldrive); /*Release bus*/
+
+#ifdef DEBUGIOCTL
+ printf("Track %d addr/ctrl %x m %x s %x f %x\n",data[2],
+ data[1],data[4],data[5],data[6]);
+#endif /*DEBUGIOCTL*/
+
+ ioc_entry->entry.control=data[1]; /*Track type*/
+ ioc_entry->entry.addr_type=ioc_entry->address_format;/*Type*/
+ ioc_entry->entry.track=data[2]; /*Track #, can be Out of Order*/
+ if (ioc_entry->address_format == CD_MSF_FORMAT) {
+ ioc_entry->entry.addr.msf.unused=0;
+ ioc_entry->entry.addr.msf.minute=data[4]; /*Min*/
+ ioc_entry->entry.addr.msf.second=data[5]; /*Sec*/
+ ioc_entry->entry.addr.msf.frame=data[6]; /*Frame*/
+ }
+ if (origtrk == 0xaa) {
+ /* Handle leadout */
+ ioc_entry->entry.control=data[2]; /*Copy from last valid track*/
+ ioc_entry->entry.track=0xaa; /*Lead-out*/
+ ioc_entry->entry.addr.msf.unused=0; /*Fill*/
+ ioc_entry->entry.addr.msf.minute=cd->volinfo.vol_msf[0];
+ ioc_entry->entry.addr.msf.second=cd->volinfo.vol_msf[1];
+ ioc_entry->entry.addr.msf.frame=cd->volinfo.vol_msf[2];
+ }
+ return(0);
+
+}
+
+/*---------------------------------------------------------------------------
matcd_subq - Read the Sub-Q packet - (where are we?)
This call gives a snapshot state of where the optical
diff --git a/sys/i386/isa/mcd.c b/sys/i386/isa/mcd.c
index 6a7adb3..f7eecb8 100644
--- a/sys/i386/isa/mcd.c
+++ b/sys/i386/isa/mcd.c
@@ -40,7 +40,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: mcd.c,v 1.87 1997/03/24 11:23:55 bde Exp $
+ * $Id: mcd.c,v 1.88 1997/04/20 17:26:54 bde Exp $
*/
static const char COPYRIGHT[] = "mcd-driver (C)1993 by H.Veit & B.Moore";
@@ -195,6 +195,7 @@ static int mcd_subchan(int unit, struct ioc_read_subchannel *sc);
static int mcd_toc_header(int unit, struct ioc_toc_header *th);
static int mcd_read_toc(int unit);
static int mcd_toc_entrys(int unit, struct ioc_read_toc_entry *te);
+static int mcd_toc_entry(int unit, struct ioc_read_toc_single_entry *te);
static int mcd_stop(int unit);
static int mcd_eject(int unit);
static int mcd_inject(int unit);
@@ -1427,6 +1428,57 @@ mcd_read_toc(int unit)
}
static int
+mcd_toc_entry(int unit, struct ioc_read_toc_single_entry *te)
+{
+ struct mcd_data *cd = mcd_data + unit;
+ struct ioc_toc_header th;
+ int rc, trk;
+
+ if (te->address_format != CD_MSF_FORMAT
+ && te->address_format != CD_LBA_FORMAT)
+ return EINVAL;
+
+ /* Copy the toc header */
+ if ((rc = mcd_toc_header(unit, &th)) != 0)
+ return rc;
+
+ /* verify starting track */
+ trk = te->track;
+ if (trk == 0)
+ trk = th.starting_track;
+ else if (trk == MCD_LASTPLUS1)
+ trk = th.ending_track + 1;
+ else if (trk < th.starting_track || trk > th.ending_track + 1)
+ return EINVAL;
+
+ /* Make sure we have a valid toc */
+ if ((rc=mcd_read_toc(unit)) != 0)
+ return rc;
+
+ /* Copy the TOC data. */
+ if (cd->toc[trk].idx_no == 0)
+ return EIO;
+
+ te->entry.control = cd->toc[trk].control;
+ te->entry.addr_type = cd->toc[trk].addr_type;
+ te->entry.track =
+ cd->toc[trk].idx_no > 0x99 ? cd->toc[trk].idx_no :
+ bcd2bin(cd->toc[trk].idx_no);
+ switch (te->address_format) {
+ case CD_MSF_FORMAT:
+ te->entry.addr.msf.unused = 0;
+ te->entry.addr.msf.minute = bcd2bin(cd->toc[trk].hd_pos_msf[0]);
+ te->entry.addr.msf.second = bcd2bin(cd->toc[trk].hd_pos_msf[1]);
+ te->entry.addr.msf.frame = bcd2bin(cd->toc[trk].hd_pos_msf[2]);
+ break;
+ case CD_LBA_FORMAT:
+ te->entry.addr.lba = htonl(msf2hsg(cd->toc[trk].hd_pos_msf, 0));
+ break;
+ }
+ return 0;
+}
+
+static int
mcd_toc_entrys(int unit, struct ioc_read_toc_entry *te)
{
struct mcd_data *cd = mcd_data + unit;
diff --git a/sys/i386/isa/scd.c b/sys/i386/isa/scd.c
index 33d77f8..acd1968 100644
--- a/sys/i386/isa/scd.c
+++ b/sys/i386/isa/scd.c
@@ -41,7 +41,7 @@
*/
-/* $Id: scd.c,v 1.28 1997/03/24 11:24:01 bde Exp $ */
+/* $Id: scd.c,v 1.29 1997/04/20 17:26:55 bde Exp $ */
/* Please send any comments to micke@dynas.se */
@@ -180,6 +180,7 @@ static int read_subcode(int unit, struct sony_subchannel_position_data *sc);
/* for xcdplayer */
static int scd_toc_header(int unit, struct ioc_toc_header *th);
static int scd_toc_entrys(int unit, struct ioc_read_toc_entry *te);
+static int scd_toc_entry(int unit, struct ioc_read_toc_single_entry *te);
#define SCD_LASTPLUS1 170 /* don't ask, xcdplayer passes this in */
static int scd_probe(struct isa_device *dev);
@@ -456,6 +457,8 @@ scdioctl(dev_t dev, int cmd, caddr_t addr, int flags, struct proc *p)
return scd_toc_header (unit, (struct ioc_toc_header *) addr);
case CDIOREADTOCENTRYS:
return scd_toc_entrys (unit, (struct ioc_read_toc_entry*) addr);
+ case CDIOREADTOCENTRY:
+ return scd_toc_entry (unit, (struct ioc_read_toc_single_entry*) addr);
case CDIOCSETPATCH:
case CDIOCGETVOL:
case CDIOCSETVOL:
@@ -1517,6 +1520,45 @@ scd_toc_entrys (int unit, struct ioc_read_toc_entry *te)
}
+static int
+scd_toc_entry (int unit, struct ioc_read_toc_single_entry *te)
+{
+ struct scd_data *cd = scd_data + unit;
+ struct cd_toc_entry toc_entry;
+ int rc, i;
+
+ if (!(cd->flags & SCDTOC) && (rc = read_toc(unit)) != 0) {
+ print_error(unit, rc);
+ return EIO;
+ }
+
+ /* find the toc to copy*/
+ i = te->track;
+ if (i == SCD_LASTPLUS1)
+ i = cd->last_track + 1;
+
+ /* verify starting track */
+ if (i < cd->first_track || i > cd->last_track+1)
+ return EINVAL;
+
+ /* copy the toc data */
+ toc_entry.control = cd->toc[i].ctl;
+ toc_entry.addr_type = te->address_format;
+ toc_entry.track = i;
+ if (te->address_format == CD_MSF_FORMAT) {
+ toc_entry.addr.msf.unused = 0;
+ toc_entry.addr.msf.minute = bcd2bin(cd->toc[i].start_msf[0]);
+ toc_entry.addr.msf.second = bcd2bin(cd->toc[i].start_msf[1]);
+ toc_entry.addr.msf.frame = bcd2bin(cd->toc[i].start_msf[2]);
+ }
+
+ /* copy the data back */
+ bcopy(&toc_entry, &te->entry, sizeof(struct cd_toc_entry));
+
+ return 0;
+}
+
+
static scd_devsw_installed = 0;
static void scd_drvinit(void *unused)
diff --git a/sys/i386/isa/wcd.c b/sys/i386/isa/wcd.c
index 702c7f2..39d030f 100644
--- a/sys/i386/isa/wcd.c
+++ b/sys/i386/isa/wcd.c
@@ -766,6 +766,41 @@ int wcdioctl (dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
return copyout (toc->tab + starting_track -
toc->hdr.starting_track, te->data, len);
}
+ case CDIOREADTOCENTRY: {
+ struct ioc_read_toc_single_entry *te =
+ (struct ioc_read_toc_single_entry*) addr;
+ struct toc *toc = &t->toc;
+ struct toc buf;
+ u_char track = te->track;
+
+ if (! t->toc.hdr.ending_track)
+ return (EIO);
+
+ if (te->address_format != CD_MSF_FORMAT
+ && te->address_format != CD_LBA_FORMAT)
+ return EINVAL;
+
+ if (track == 0)
+ track = toc->hdr.starting_track;
+ else if (track == 170) /* Handle leadout request */
+ track = toc->hdr.ending_track + 1;
+ else if (track < toc->hdr.starting_track ||
+ track > toc->hdr.ending_track + 1)
+ return (EINVAL);
+
+ /* Convert to MSF format, if needed. */
+ if (te->address_format == CD_MSF_FORMAT) {
+ struct cd_toc_entry *e;
+
+ buf = t->toc;
+ toc = &buf;
+ e = toc->tab + (track - toc->hdr.starting_track);
+ lba2msf (ntohl(e->addr.lba), &e->addr.msf.minute,
+ &e->addr.msf.second, &e->addr.msf.frame);
+ }
+ bcopy(toc->tab + track - toc->hdr.starting_track,
+ &te->entry, sizeof(struct cd_toc_entry));
+ }
case CDIOCREADSUBCHANNEL: {
struct ioc_read_subchannel *args =
(struct ioc_read_subchannel*) addr;
diff --git a/sys/isofs/cd9660/cd9660_vfsops.c b/sys/isofs/cd9660/cd9660_vfsops.c
index a875434..a61ccfc 100644
--- a/sys/isofs/cd9660/cd9660_vfsops.c
+++ b/sys/isofs/cd9660/cd9660_vfsops.c
@@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)cd9660_vfsops.c 8.18 (Berkeley) 5/22/95
- * $Id: cd9660_vfsops.c,v 1.23 1997/04/29 15:52:53 joerg Exp $
+ * $Id: cd9660_vfsops.c,v 1.24 1997/04/29 17:11:51 joerg Exp $
*/
#include <sys/param.h>
@@ -48,6 +48,8 @@
#include <miscfs/specfs/specdev.h>
#include <sys/mount.h>
#include <sys/buf.h>
+#include <sys/cdio.h>
+#include <sys/conf.h>
#include <sys/fcntl.h>
#include <sys/errno.h>
#include <sys/malloc.h>
@@ -94,40 +96,77 @@ VFS_SET(cd9660_vfsops, cd9660, MOUNT_CD9660, VFCF_READONLY);
* Called by vfs_mountroot when iso is going to be mounted as root.
*/
+static int iso_get_ssector __P((dev_t dev, struct proc *p));
static int iso_mountfs __P((struct vnode *devvp, struct mount *mp,
struct proc *p, struct iso_args *argp));
+static int iso_mountroot __P((struct mount *mp, struct proc *p));
-int
-cd9660_mountroot()
+/*
+ * Try to find the start of the last data track on this CD-ROM. This
+ * is used to mount the last session of a multi-session CD. Bail out
+ * and return 0 if we fail, this is always a safe bet.
+ */
+static int
+iso_get_ssector(dev, p)
+ dev_t dev;
+ struct proc *p;
{
+ struct ioc_toc_header h;
+ struct ioc_read_toc_single_entry t;
+ int i;
+ struct bdevsw *bd;
+ d_ioctl_t *ioctlp;
+
+ bd = bdevsw[major(dev)];
+ ioctlp = bd->d_ioctl;
+ if (ioctlp == NULL)
+ return 0;
+
+ if (ioctlp(dev, CDIOREADTOCHEADER, (caddr_t)&h, FREAD, p) == -1)
+ return 0;
+
+ for (i = h.ending_track; i >= 0; i--) {
+ t.address_format = CD_LBA_FORMAT;
+ t.track = i;
+ if (ioctlp(dev, CDIOREADTOCENTRY, (caddr_t)&t, FREAD, p) == -1)
+ return 0;
+ if ((t.entry.control & 4) != 0)
+ /* found a data track */
+ break;
+ }
+
+ if (i < 0)
+ return 0;
+
+ return ntohl(t.entry.addr.lba);
+}
+
+static int
+iso_mountroot(mp, p)
struct mount *mp;
- struct proc *p = curproc; /* XXX */
+ struct proc *p;
+{
struct iso_args args;
int error;
-
+
/*
* Get vnode for rootdev.
*/
if ((error = bdevvp(swapdev, &swapdev_vp)) ||
(error = bdevvp(rootdev, &rootvp))) {
- printf("cd9660_mountroot: can't setup bdevvp's");
+ printf("iso_mountroot: can't setup bdevvp's");
return (error);
}
- if (error = vfs_rootmountalloc("cd9660", "root_device", &mp))
- return (error);
args.flags = ISOFSMNT_ROOT;
- if (error = iso_mountfs(rootvp, mp, p, &args)) {
- mp->mnt_vfc->vfc_refcount--;
- vfs_unbusy(mp, p);
- free(mp, M_MOUNT);
+ args.ssector = iso_get_ssector(rootdev, p);
+ if (bootverbose)
+ printf("iso_mountroot(): using session at block %d\n",
+ args.ssector);
+ if (error = iso_mountfs(rootvp, mp, p, &args))
return (error);
- }
- simple_lock(&mountlist_slock);
- CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
- simple_unlock(&mountlist_slock);
+
(void)cd9660_statfs(mp, &mp->mnt_stat, p);
- vfs_unbusy(mp, p);
return (0);
}
@@ -150,6 +189,9 @@ cd9660_mount(mp, path, data, ndp, p)
int error;
struct iso_mnt *imp = 0;
+ if ((mp->mnt_flag & MNT_ROOTFS) != 0)
+ return (iso_mountroot(mp, p));
+
if ((error = copyin(data, (caddr_t)&args, sizeof (struct iso_args))))
return (error);
diff --git a/sys/isofs/cd9660/iso.h b/sys/isofs/cd9660/iso.h
index d7fc579..2437534 100644
--- a/sys/isofs/cd9660/iso.h
+++ b/sys/isofs/cd9660/iso.h
@@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)iso.h 8.6 (Berkeley) 5/10/95
- * $Id$
+ * $Id: iso.h,v 1.13 1997/02/22 09:38:52 peter Exp $
*/
#define ISODCL(from, to) (to - from + 1)
@@ -215,7 +215,7 @@ int cd9660_init __P((struct vfsconf *));
#define cd9660_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \
size_t, struct proc *)))eopnotsupp)
-int cd9660_mountroot __P((void));
+int cd9660_mountroot __P((int ssector));
extern vop_t **cd9660_vnodeop_p;
extern vop_t **cd9660_specop_p;
diff --git a/sys/scsi/cd.c b/sys/scsi/cd.c
index f643c37..00df2f7 100644
--- a/sys/scsi/cd.c
+++ b/sys/scsi/cd.c
@@ -14,7 +14,7 @@
*
* Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
*
- * $Id: cd.c,v 1.81 1997/03/24 11:24:54 bde Exp $
+ * $Id: cd.c,v 1.82 1997/04/02 09:05:38 jmg Exp $
*/
#include "opt_bounce.h"
@@ -834,6 +834,63 @@ cd_ioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p,
error = copyout(data.entries, te->data, len);
}
break;
+ case CDIOREADTOCENTRY:
+ {
+ struct {
+ struct ioc_toc_header header;
+ struct cd_toc_entry entry;
+ } data;
+ struct ioc_read_toc_single_entry *te =
+ (struct ioc_read_toc_single_entry *) addr;
+ struct ioc_toc_header *th;
+ u_int32_t track;
+
+ if (te->address_format != CD_MSF_FORMAT
+ && te->address_format != CD_LBA_FORMAT) {
+ error = EINVAL;
+ break;
+ }
+
+ th = &data.header;
+ error = cd_read_toc(unit, 0, 0,
+ (struct cd_toc_entry *)th, sizeof (*th));
+ if (error)
+ break;
+
+ if (sc_link->quirks & CD_Q_BCD_TRACKS) {
+ /* we are going to have to convert the BCD
+ * encoding on the cd to what is expected
+ */
+ th->starting_track =
+ bcd2bin(th->starting_track);
+ th->ending_track = bcd2bin(th->ending_track);
+ }
+
+ track = te->track;
+ if (track == 0)
+ track = th->starting_track;
+ else if (track == LEADOUT)
+ /* OK */;
+ else if (track < th->starting_track ||
+ track > th->ending_track + 1) {
+ error = EINVAL;
+ break;
+ }
+
+ error = cd_read_toc(unit, te->address_format,
+ track,
+ (struct cd_toc_entry *)&data,
+ sizeof data);
+ if (error)
+ break;
+
+ if (sc_link->quirks & CD_Q_BCD_TRACKS)
+ data.entry.track = bcd2bin(data.entry.track);
+
+ bcopy(&data.entry, &te->entry,
+ sizeof(struct cd_toc_entry));
+ }
+ break;
case CDIOCSETPATCH:
{
struct ioc_patch *arg = (struct ioc_patch *) addr;
diff --git a/sys/sys/cdio.h b/sys/sys/cdio.h
index 5edc4ba..c037998 100644
--- a/sys/sys/cdio.h
+++ b/sys/sys/cdio.h
@@ -1,7 +1,7 @@
/*
* 16 Feb 93 Julian Elischer (julian@dialix.oz.au)
*
- * $Id$
+ * $Id: cdio.h,v 1.16 1997/02/22 09:44:53 peter Exp $
*/
/*
@@ -158,6 +158,14 @@ struct ioc_read_toc_entry {
#define CDIOREADTOCENTRYS _IOWR('c',5,struct ioc_read_toc_entry)
+struct ioc_read_toc_single_entry {
+ u_char address_format;
+ u_char track;
+ struct cd_toc_entry entry;
+};
+#define CDIOREADTOCENTRY _IOWR('c',6,struct ioc_read_toc_single_entry)
+
+
struct ioc_patch
{
u_char patch[4]; /* one for each channel */
OpenPOWER on IntegriCloud