Coherent4.2.10/conf/haicd/src/haicd.c
/*
* haicd.c -- Device module for CD-ROM.
*
* Copyright (c) 1993, Christopher Sean Hilton - All rights reserved
*
* $Id$
*
* $Log$
*/
static char rcsid[] = "#(@) haicd.c $Revision$";
#define LOCAL static
#define Register register
#define _KERNEL 1
#include <errno.h>
#include <stddef.h>
#include <sys/cdrom.h>
#include <sys/cmn_err.h>
#include <sys/coherent.h>
#include <sys/file.h>
#include <sys/haiscsi.h>
#include <sys/inode.h>
#include <sys/sched.h>
#include <sys/stat.h>
/***********************************************************************
* SCSI Command Opcodes.
*/
#define INQUIRY 0x12
#define STARTSTOPUNIT 0x1b
#define IMMEDIATE 0x0001
#define STARTUNIT 0x0002
#define EJECT 0x0004
#define READCAPACITY 0x25
#define G1READ 0x28
#define READSUBCHNL 0x42
#define READTOC 0x43
#define PLAYMSF 0x47
#define PLAYTRKIND 0x48
#define PAUSERESUME 0x4b
#pragma align 1
typedef struct readcap_s *readcap_p;
typedef struct readcap_s {
unsigned long blockcount;
unsigned long blocksize;
} readcap_t;
typedef struct msf_s *msf_p;
typedef struct msf_s {
unsigned char reserved,
minutes,
seconds,
frame;
} msf_t;
typedef struct toc_entry_s *toc_entry_p;
typedef struct toc_entry_s {
unsigned char reserved0;
unsigned char adrcontrol;
unsigned char tracknumber;
unsigned char reserved1;
union {
msf_t msf;
unsigned long lba;
} address;
} toc_entry_t;
typedef struct toc_data_s *toc_data_p;
typedef struct toc_data_s {
unsigned short datalength;
unsigned char firsttrack;
unsigned char lasttrack;
toc_entry_t toc_entries[100];
} toc_data_t;
typedef struct subchnlq_s *subchnlq_p;
typedef struct subchnlq_s {
unsigned char sq_reserved,
sq_audiostatus;
unsigned short sq_datalength;
unsigned char sq_dataformat,
sq_adrcontrol,
sq_track,
sq_index;
union {
msf_t msf;
unsigned long lba;
} sq_absaddr;
union {
msf_t msf;
unsigned long lba;
} sq_reladdr;
} subchnlq_t;
#pragma align
/***********************************************************************
* CD-ROM control structure.
*/
typedef struct cdrctrl_s *cdrctrl_p;
typedef struct cdrctrl_s {
haft_t * haft; /* Host adapter function table */
short inuse; /* In use flag */
srb_t srb; /* SCSI request block: this device */
readcap_t cdrsize; /* Results of Read Capacity Command */
toc_data_p toclba; /* Results of Read TOC Command (lba) */
toc_data_p tocmsf; /* Results of Read TOC Command (msf) */
} cdrctrl_t;
cdrctrl_p cdrdevs[MAXDEVS] = {
NULL, /* ID 0 */
NULL, /* ID 1 */
NULL, /* ID 2 */
NULL, /* ID 3 */
NULL, /* ID 4 */
NULL, /* ID 5 */
NULL, /* ID 6 */
NULL /* ID 7 */
};
LOCAL void cd_open __PROTO((dev_t, int));
LOCAL void cd_close __PROTO((dev_t));
LOCAL void cd_ioctl __PROTO((dev_t, int, char *));
LOCAL int cd_load __PROTO((haft_t *, int));
LOCAL void cd_read __PROTO((dev_t, IO *));
static dca_t dca = {
cd_open, /* Open */
cd_close, /* Close */
hainonblk, /* Block */
cd_read, /* Read */
NULL, /* Write */
cd_ioctl, /* Ioctl */
cd_load, /* Load */
NULL, /* Unload */
NULL /* Poll */
};
dca_p cdrdca =&dca;
extern int ukcopy __PROTO((vaddr_t, void *, size_t));
extern int kucopy __PROTO((void *, vaddr_t, size_t));
/***********************************************************************
* cd_load() -- Load entry point for CD-ROM drives.
*
* Allocate space for the control structure and the CD-ROM drive's
* buffer (very small buffer).
*/
#if __USE_PROTO__
LOCAL int cd_load(haft_t * haft, int id)
#else
LOCAL int
cd_load(haft, id)
haft_t * haft;
int id;
#endif
{
cdrctrl_p c;
if (!haft) {
cmn_err(CE_WARN,
"haicd: No host adapter function table - load failed");
return 0;
}
c = kalloc(sizeof(cdrctrl_t));
if (!c) {
cmn_err(CE_WARN, "CD-ROM Module load failed, no memory.");
return 0;
}
memset(c, 0, sizeof(cdrctrl_t));
c->haft = haft;
c->srb.target = id;
c->srb.lun = 0;
cdrdevs[id] = c;
cmn_err(CE_CONT, "%d: HAI CD-ROM device module: v1.9\n", id);
return 1;
} /* cd_load() */
/***********************************************************************
* checkmedia() -- Check for new media in the drive.
*
* Use the Test Unit Read SCSI Command to check for new or any media
* in the drive.
*/
#if __USE_PROTO__
LOCAL int checkmedia(cdrctrl_p c)
#else
LOCAL int
checkmedia(c)
cdrctrl_p c;
#endif
{
register srb_p r = &(c->srb);
r->buf.space = PHYS_ADDR | WATCH_REQACK;
r->buf.ba_phys = NULL;
r->buf.size = 0;
r->xferdir = 0;
r->timeout = 6;
memset(&(r->cdb.g0), 0, sizeof(cdb_t)); /* Test Unit Ready */
memset(r->sensebuf, 0, sizeof(r->sensebuf));
doscsi(c->haft, r, 4, pritape, slpriSigCatch, "cdrchkmda");
return (r->status == ST_GOOD);
} /* checkmedia() */
/***********************************************************************
* iscdromdev() -- Check the Inquiry bytes to make sure this is
* a CD-ROM Drive.
*
* Get the first 16 bytes of inquiry information for this drive to
* make sure that the device out there on the bus is a CD-ROM Device.
* Used during initializaion.
*/
#if __USE_PROTO__
LOCAL int iscdromdev(cdrctrl_p c)
#else
LOCAL int
iscdromdev(c)
cdrctrl_p c;
#endif
{
register srb_p r = &(c->srb);
unsigned char inqbuf[16];
memset(inqbuf, 0, sizeof(inqbuf));
r->buf.space = KRNL_ADDR | WATCH_REQACK;
r->buf.ba_virt = (vaddr_t) inqbuf;
r->xferdir = DMAREAD;
memset(&(r->cdb), 0, sizeof(cdb_t));
r->cdb.g0.opcode = INQUIRY;
r->cdb.g0.xfr_len = r->buf.size = sizeof(inqbuf);
doscsi(c->haft, r, 4, pritape, slpriSigCatch, "cdropen");
return (r->status == ST_GOOD && (inqbuf[0] & 0x1f) == 0x05);
} /* iscdromdev() */
/***********************************************************************
* readcapacity() -- Read the Capacity of the CD in the drive.
*
* Use the Read Capacity command to get the number of blocks on the
* CD ROM and the size of each block. This information can be accessed
* by user programs through the HAICD_READCAP I/O Control command.
*/
#if __USE_PROTO__
LOCAL int readcapacity(cdrctrl_p c)
#else
LOCAL int
readcapacity(c)
cdrctrl_p c;
#endif
{
register srb_p r = &(c->srb);
r->buf.space = KRNL_ADDR | WATCH_REQACK;
r->buf.ba_virt = (vaddr_t) &(c->cdrsize);
r->buf.size = sizeof(c->cdrsize);
memset(&(r->cdb), 0, sizeof(cdb_t));
r->cdb.g1.opcode = READCAPACITY;
doscsi(c->haft, r, 4, pritape, slpriSigCatch, "cdropen");
if (r->status != ST_GOOD)
return 0;
else {
flip(c->cdrsize.blockcount);
flip(c->cdrsize.blocksize);
return 1;
}
} /* readcapacity() */
/***********************************************************************
* readtoclba() -- Read the Disk's Table of Contents.
*
* Read the CD's TOC into a kalloced buffer. The buffer only stays
* around while the Drive is openned and is allocated just large enough
* to hold the TOC info for this disk. This information is returned
* by the HAICD_READTOC I/O control command.
*/
#if __USE_PROTO__
LOCAL toc_data_p readtoclba(cdrctrl_p c)
#else
LOCAL toc_data_p
readtoclba(c)
cdrctrl_p c;
#endif
{
register srb_p r = &(c->srb);
register int entries;
static toc_data_t toclba;
toc_data_p p;
toc_entry_p q;
r->buf.space = KRNL_ADDR | WATCH_REQACK;
r->buf.ba_virt = (caddr_t) &toclba;
memset(&(r->cdb), 0, sizeof(cdb_t));
r->cdb.g1.opcode = READTOC;
r->cdb.g1.xfr_len = r->buf.size = sizeof(toclba);
flip(r->cdb.g1.xfr_len);
doscsi(c->haft, r, 4, pritape, slpriSigCatch, "cdropen");
if (r->status != ST_GOOD)
return NULL;
flip(toclba.datalength);
if (!toclba.datalength) {
cmn_err(CE_WARN, "haicd: Bad or empty table of contents.");
return NULL;
}
if (!(p = kalloc(toclba.datalength)))
return NULL;
entries = (toclba.datalength - 2) / sizeof(toc_entry_t);
q = toclba.toc_entries;
while (entries-- > 0) {
flip(q->address. lba);
++q;
}
memcpy(p, &toclba, toclba.datalength + sizeof(toclba.datalength));
return (c->toclba = p);
} /* readtoclba() */
/***********************************************************************
* readtocmsf() -- Read the Disk's Table of Contents.
*
* Read the CD's TOC into a kalloced buffer. The buffer only stays
* around while the Drive is openned and is allocated just large enough
* to hold the TOC info for this disk. This information is returned
* by the HAICD_READTOC I/O control command.
*/
#if __USE_PROTO__
LOCAL toc_data_p readtocmsf(cdrctrl_p c)
#else
LOCAL toc_data_p
readtocmsf(c)
cdrctrl_p c;
#endif
{
register srb_p r = &(c->srb);
static toc_data_t tocmsf;
toc_data_p p;
r->buf.space = KRNL_ADDR | WATCH_REQACK;
r->buf.ba_virt = (caddr_t) &tocmsf;
memset(&(r->cdb), 0, sizeof(cdb_t));
r->cdb.g1.opcode = READTOC;
r->cdb.g1.lun = 2;
r->cdb.g1.xfr_len = r->buf.size = sizeof(tocmsf);
flip(r->cdb.g1.xfr_len);
doscsi(c->haft, r, 4, pritape, slpriSigCatch, "cdropen");
if (r->status != ST_GOOD)
return NULL;
flip(tocmsf.datalength);
if (!tocmsf.datalength) {
cmn_err(CE_WARN, "haicd: Bad or empty table of contents.");
return NULL;
}
if (!(p = kalloc(tocmsf.datalength)))
return NULL;
memcpy(p, &tocmsf, tocmsf.datalength + sizeof(tocmsf.datalength));
return (c->tocmsf = p);
} /* readtocmsf() */
/***********************************************************************
* cd_open() -- Open entry point for CD-ROM drives.
*
* Check to make sure that there is a CD-ROM in the drive and if so
* read the TOC.
*/
#if __USE_PROTO__
LOCAL void cd_open(dev_t dev, int mode)
#else
LOCAL void
cd_open(dev, mode)
dev_t dev;
int mode;
#endif
{
register cdrctrl_p c = cdrdevs[tid(dev)];
register srb_p r;
int s;
s = sphi();
if (!c) {
set_user_error (ENXIO);
goto exit;
}
if (c->inuse || mode != IPR) {
set_user_error (EACCES);
goto exit;
}
c->inuse = 1;
r = &(c->srb);
r->dev = dev;
r->target = tid(dev);
r->lun = lun(dev);
if (!checkmedia(c)) {
if (printerror(r, "cdrom: <Door open - Check media>"))
set_user_error (ENXIO);
goto openfailed;
}
if (!iscdromdev(c)) {
if (r->status == ST_GOOD) {
cmn_err(CE_WARN,
"(%d, %d) haicd: Device is not a CD-ROM",
major(r->dev),
minor(r->dev));
set_user_error (ENXIO);
}
else {
if (printerror(r, "cdrom: <Error on inquiry>"))
set_user_error (EIO);
}
goto openfailed;
}
if (!readcapacity(c)) {
if (printerror(r, "cdrom: <Error on read capacity>"))
set_user_error (EIO);
goto openfailed;
}
if (!readtoclba(c)) {
if (printerror(r, "cdrom: <Error on read table of contents>"))
set_user_error (EIO);
goto openfailed;
}
if (!readtocmsf(c)) {
if (printerror(r, "cdrom: <Error on read table of contents>"))
set_user_error (EIO);
goto openfailed;
}
/*******************************************************************
* Success!
*/
goto exit;
openfailed:
c->inuse = 0;
exit:
spl(s);
} /* cd_open() */
/***********************************************************************
* cd_close() -- Close routine for CD-ROM drive.
*/
#if __USE_PROTO__
LOCAL void cd_close(dev_t dev)
#else
LOCAL void cd_close(dev)
dev_t dev;
#endif
{
register cdrctrl_p c = cdrdevs[tid(dev)];
if (!c)
set_user_error (ENXIO);
else {
kfree(c->tocmsf);
kfree(c->toclba);
c->inuse = 0;
}
} /* cd_close() */
/***********************************************************************
* cd_read() -- Read entry point for CD-ROM Devices.
*
* Read a block from the CD-ROM drive.
*/
#if __USE_PROTO__
LOCAL void cd_read(dev_t dev, IO *iop)
#else
LOCAL void
cd_read(dev, iop)
dev_t dev;
IO *iop;
#endif
{
register cdrctrl_p c = cdrdevs[tid(dev)];
register srb_p r = &(c->srb);
register g1cmd_p g1 = &(r->cdb.g1);
unsigned long startblock,
blockcount;
if (!c) {
set_user_error (EINVAL);
return;
}
if (iop->io_seek % c->cdrsize.blocksize || iop->io_ioc % c->cdrsize.blocksize) {
set_user_error (EINVAL);
return;
}
startblock = iop->io_seek / c->cdrsize.blocksize;
if (startblock > c->cdrsize.blockcount) {
set_user_error (EINVAL);
return;
}
blockcount = iop->io_ioc / c->cdrsize.blocksize;
if (startblock + blockcount > c->cdrsize.blockcount) {
blockcount = c->cdrsize.blockcount - startblock;
if (!blockcount) {
iop->io_ioc -= blockcount * c->cdrsize.blocksize;
return;
}
}
memset(g1, 0, sizeof(cdb_t));
g1->opcode = G1READ;
g1->lun = (r->lun << 5);
g1->lba = startblock;
flip(g1->lba);
g1->xfr_len = blockcount;
flip(g1->xfr_len);
r->target = tid(dev);
r->lun = lun(dev);
r->timeout = 4;
switch (iop->io_seg) {
case IOSYS:
r->buf.space = KRNL_ADDR;
r->buf.ba_virt = iop->io.vbase;
break;
case IOUSR:
r->buf.space = USER_ADDR;
r->buf.ba_virt = iop->io.vbase;
break;
case IOPHY:
r->buf.space = PHYS_ADDR;
r->buf.ba_phys = iop->io.pbase;
break;
}
r->buf.size = (blockcount * c->cdrsize.blocksize);
r->xferdir = DMAREAD;
doscsi(c->haft, r, 1, pritape, slpriSigCatch, "cdrread");
switch (r->status) {
case ST_GOOD:
iop->io_ioc -= r->buf.size;
break;
case ST_CHKCOND:
printsense(r->dev, "Read failed", (extsense_p) r->sensebuf);
set_user_error (EIO);
break;
case ST_USRABRT:
break;
default:
cmn_err(CE_WARN,
"(%d, %d) haicd: Read failed: status (0x%x)",
major(r->dev),
minor(r->dev),
r->status);
set_user_error (EIO);
break;
}
return;
} /* cd_read() */
#if __USE_PROTO__
LOCAL int cd_pauseresume(register cdrctrl_p c, int pauseflag)
#else
LOCAL int
cd_pauseresume(c, pauseflag)
register cdrctrl_p c;
int pauseflag;
#endif
{
register srb_p r = &(c->srb);
register char *g2 = (char *) &(r->cdb. g1);
r->buf.space = PHYS_ADDR | WATCH_REQACK;
r->buf.ba_phys = NULL;
r->buf.size = 0;
r->xferdir = 0;
r->timeout = 6;
memset(g2, 0, sizeof(cdb_t));
g2[0] = PAUSERESUME;
g2[8] = (pauseflag == 0) ? 0 : 1;
doscsi(c->haft, r, 2, pritape, slpriSigCatch, "cdrioctl");
return (r->status == ST_GOOD);
} /* cd_pauseresume() */
#if __USE_PROTO__
LOCAL int cd_playmsf(register cdrctrl_p c, caddr_t uvec)
#else
LOCAL int
cd_playmsf(c, uvec)
register cdrctrl_p c;
caddr_t uvec;
#endif
{
register srb_p r = &(c->srb);
register char *g2 = (char *) &(r->cdb. g1);
struct cdrom_msf play_addr;
if (!ukcopy(uvec, &play_addr, sizeof(struct cdrom_msf)))
return 0;
r->buf.space = PHYS_ADDR | WATCH_REQACK;
r->buf.ba_phys = NULL;
r->buf.size = 0;
r->xferdir = 0;
r->timeout = 6;
memset(g2, 0, sizeof(cdb_t));
g2[0] = PLAYMSF;
g2[3] = play_addr. cdmsf_min0;
g2[4] = play_addr. cdmsf_sec0;
g2[5] = play_addr. cdmsf_frame0;
g2[6] = play_addr. cdmsf_min1;
g2[7] = play_addr. cdmsf_sec1;
g2[8] = play_addr. cdmsf_frame1;
doscsi(c->haft, r, 2, pritape, slpriSigCatch, "cdrioctl");
if (r->status != ST_GOOD) {
set_user_error(EIO);
return 0;
}
else
return 1;
} /* cd_playmsf() */
#if __USE_PROTO__
LOCAL int cd_playtrkind(register cdrctrl_p c, struct cdrom_ti *cdti)
#else
LOCAL int cd_playtrkind(c, cdti)
register cdrctrl_p c;
struct cdrom_ti *cdti;
#endif
{
register srb_p r = &(c->srb);
register char *g2 = (char *) &(r->cdb. g1);
r->buf.space = PHYS_ADDR | WATCH_REQACK;
r->buf.ba_phys = NULL;
r->buf.size = 0;
r->xferdir = 0;
r->timeout = 6;
memset(g2, 0, sizeof(cdb_t));
g2[0] = PLAYTRKIND;
g2[4] = cdti->cdti_trk0;
g2[5] = cdti->cdti_ind0;
g2[7] = cdti->cdti_trk1;
g2[8] = cdti->cdti_ind1;
doscsi(c->haft, r, 2, pritape, slpriSigCatch, "cdrioctl");
if (r->status != ST_GOOD) {
set_user_error(EIO);
return 0;
}
else
return 1;
} /* cd_playtrkind() */
#if __USE_PROTO__
LOCAL int cd_startstop(register cdrctrl_p c, int opflags)
#else
LOCAL int cd_startstop(c, opflags)
register cdrctrl_p c;
int opflags;
#endif
{
register srb_p r = &(c->srb);
register g0cmd_p g0 = &(r->cdb. g0);
r->buf.space = PHYS_ADDR | WATCH_REQACK;
r->buf.ba_phys = NULL;
r->buf.size = 0;
r->xferdir = 0;
r->timeout = 6;
memset(g0, 0, sizeof(cdb_t));
g0->opcode = STARTSTOPUNIT;
if (opflags & IMMEDIATE)
g0->lun_lba |= 1;
if (opflags & STARTUNIT)
g0->xfr_len |= 1;
/***************************************************************
* Because of the way I read the table of contents into memory
* and hold it until the drive is closed, Do not implement the
* Eject command right now. This prevents the bug of someone
* openning up the Drive with one CD and then changing the
* media via an eject command. This does nothing to prevent
* the user from using the front panel eject button to do
* the same thing.
*/
#if 0
if (opflags & EJECT)
g0->xfr_len |= 2;
#endif
doscsi(c->haft, r, 2, pritape, slpriSigCatch, "cdrioctl");
return (r->status == ST_GOOD);
} /* cd_startstop() */
#if __USE_PROTO__
LOCAL int cd_readtocentry(register cdrctrl_p c, struct cdrom_tocentry *cdte)
#else
LOCAL int cd_readtocentry(c, cdte)
register cdrctrl_p c;
struct cdrom_tocentry *cdte;
#endif
{
int entries;
toc_entry_p lba,
msf;
entries = (c->toclba->datalength - 2) / 8;
lba = c->toclba->toc_entries;
msf = c->tocmsf->toc_entries;
while (entries--) {
if (lba->tracknumber == cdte->cdte_track) {
cdte->cdte_adr = (lba->adrcontrol >> 4) & 0x0f;
cdte->cdte_ctrl = (lba->adrcontrol & 0x0f);
if (cdte->cdte_format == CDROM_LBA) {
cdte->cdte_addr.lba = lba->address.lba;
}
else if (cdte->cdte_format == CDROM_MSF) {
cdte->cdte_addr.msf.minute = msf->address.msf.minutes;
cdte->cdte_addr.msf.second = msf->address.msf.seconds;
cdte->cdte_addr.msf.frame = msf->address.msf.frame;
}
else {
set_user_error(ENXIO);
return 0;
}
return 1;
}
++lba;
++msf;
}
set_user_error(ENXIO);
return 0;
} /* cd_readtocentry() */
#if __USE_PROTO__
LOCAL int cd_subchnl(register cdrctrl_p c, struct cdrom_subchnl *cdsc)
#else
LOCAL int cd_subchnl(c, cdsc)
register cdrctrl_p c;
struct cdrom_subchnl *cdsc;
#endif
{
register srb_p r = &(c->srb);
register char *g2 = (char *) &(r->cdb. g1);
subchnlq_t sq;
r->buf.space = KRNL_ADDR | WATCH_REQACK;
r->buf.ba_virt = (caddr_t) &sq;
r->buf.size = sizeof(subchnlq_t);
memset(g2, 0, sizeof(cdb_t));
g2[0] = READSUBCHNL;
if (cdsc->cdsc_format == CDROM_MSF)
g2[1] |= 0x02; /* Specify M/S/F format */
g2[2] = 0x40; /* Specify Subchannel Q data required */
g2[3] = 1; /* Subchannel Q data format (CD-ROM position) */
g2[7] = 0x00;
g2[8] = sizeof(subchnlq_t);
doscsi(c->haft, r, 4, pritape, slpriSigCatch, "cdropen");
if (r->status != ST_GOOD) {
set_user_error(EIO);
return 0;
}
cdsc->cdsc_audiostatus = sq. sq_audiostatus;
cdsc->cdsc_adr = (sq.sq_adrcontrol >> 4) & 0x0f;
cdsc->cdsc_ctrl = (sq.sq_adrcontrol & 0x0f);
cdsc->cdsc_trk = sq. sq_track;
cdsc->cdsc_ind = sq. sq_index;
if (cdsc->cdsc_format == CDROM_MSF) {
cdsc->cdsc_absaddr.msf.minute = sq.sq_absaddr.msf.minutes;
cdsc->cdsc_absaddr.msf.second = sq.sq_absaddr.msf.seconds;
cdsc->cdsc_absaddr.msf.frame = sq.sq_absaddr.msf.frame;
cdsc->cdsc_reladdr.msf.minute = sq.sq_reladdr.msf.minutes;
cdsc->cdsc_reladdr.msf.second = sq.sq_reladdr.msf.seconds;
cdsc->cdsc_reladdr.msf.frame = sq.sq_reladdr.msf.frame;
}
else {
cdsc->cdsc_absaddr.lba = sq. sq_absaddr. lba;
flip(cdsc->cdsc_absaddr.lba);
cdsc->cdsc_reladdr.lba = sq. sq_reladdr. lba;
flip(cdsc->cdsc_reladdr.lba);
}
return 1;
} /* cd_subchnl() */
/***********************************************************************
* cd_ioctl() -- I/O Control routine for CD-ROM drives.
*/
#if __USE_PROTO__
LOCAL void cd_ioctl(dev_t dev, int cmd, char *vec)
#else
LOCAL void
cd_ioctl(dev, cmd, vec)
dev_t dev;
int cmd;
char *vec;
#endif
{
register cdrctrl_p c = cdrdevs[tid(dev)];
struct cdrom_ti cdti;
struct cdrom_tochdr cdth;
struct cdrom_tocentry cdte;
struct cdrom_subchnl cdsc;
if (!c) {
set_user_error (ENXIO);
return;
}
switch (cmd) {
case CDROMPAUSE: /* pause */
if (!cd_pauseresume(c, 0))
set_user_error(EIO);
return;
case CDROMRESUME: /* resume */
if (!cd_pauseresume(c, 1))
set_user_error(EIO);
return;
case CDROMPLAYMSF: /* play audio */
cd_playmsf(c, vec);
return;
case CDROMPLAYTRKIND: /* play track */
if (!ukcopy(vec, &cdti, sizeof(struct cdrom_ti)))
return;
cd_playtrkind(c, &cdti);
return;
case CDROMREADTOCHDR: /* read the TOC header */
cdth.cdth_trk0 = c->toclba->firsttrack;
cdth.cdth_trk1 = c->toclba->lasttrack;
kucopy(&cdth, vec, sizeof(struct cdrom_tochdr));
return;
case CDROMREADTOCENTRY: /* read a TOC entry */
if (!ukcopy(vec, &cdte, sizeof(struct cdrom_tocentry)))
return;
if (!cd_readtocentry(c, &cdte))
return;
kucopy(&cdte, vec, sizeof(struct cdrom_tocentry));
return;
case CDROMSTOP: /* stop the drive motor */
if (!cd_startstop(c, 0))
set_user_error(EIO);
return;
case CDROMSTART: /* turn the motor on */
if (!cd_startstop(c, STARTUNIT))
set_user_error(EIO);
return;
case CDROMEJECT: /* eject CD-ROM media */
if (!cd_startstop(c, EJECT))
set_user_error(EIO);
return;
case CDROMVOLCTRL: /* volume control */
return;
case CDROMSUBCHNL: /* read sub-channel data */
if (!ukcopy(vec, &cdsc, sizeof(struct cdrom_subchnl)))
return;
if (!cd_subchnl(c, &cdsc))
return;
kucopy(&cdsc, vec, sizeof(struct cdrom_subchnl));
return;
case CDROMREADMODE1: /* read type-1 data */
return;
case CDROMREADMODE2: /* read type-2 data */
default:
set_user_error(ENXIO);
return;
}
} /* cd_ioctl() */
/* End of file */