Emulate the Linux DVD_* ioctls(2). This gets us 90% of the way to running the

LiViD DVD player.  (See forthcoming mail to current-users.)
XXX NOTE: We should do something to probe capabilities, rather than allowing
these ioctls on any device.
This commit is contained in:
mycroft 1999-10-29 15:02:56 +00:00
parent ee08428d1c
commit e45ef6abcd
4 changed files with 516 additions and 3 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: linux_cdrom.c,v 1.4 1998/10/03 20:28:03 christos Exp $ */
/* $NetBSD: linux_cdrom.c,v 1.5 1999/10/29 15:02:56 mycroft Exp $ */
/*
* Copyright (c) 1997 The NetBSD Foundation, Inc.
@ -41,6 +41,7 @@
#include <sys/mount.h>
#include <sys/proc.h>
#include <sys/cdio.h>
#include <sys/dvdio.h>
#include <sys/syscallargs.h>
@ -93,6 +94,9 @@ linux_ioctl_cdrom(p, uap, retval)
struct ioc_read_subchannel t_subchannel;
struct ioc_vol t_vol;
dvd_struct ds;
dvd_authinfo dai;
fdp = p->p_fd;
if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
(fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
@ -331,6 +335,43 @@ linux_ioctl_cdrom(p, uap, retval)
ncom = CDIOCRESET;
break;
case LINUX_DVD_READ_STRUCT:
error = copyin(SCARG(uap, data), &ds, sizeof ds);
if (error)
return (error);
error = ioctlf(fp, DVD_READ_STRUCT, (caddr_t)&ds, p);
if (error)
return (error);
error = copyout(&ds, SCARG(uap, data), sizeof ds);
if (error)
return (error);
return (0);
case LINUX_DVD_WRITE_STRUCT:
error = copyin(SCARG(uap, data), &ds, sizeof ds);
if (error)
return (error);
error = ioctlf(fp, DVD_WRITE_STRUCT, (caddr_t)&ds, p);
if (error)
return (error);
error = copyout(&ds, SCARG(uap, data), sizeof ds);
if (error)
return (error);
return (0);
case LINUX_DVD_AUTH:
error = copyin(SCARG(uap, data), &dai, sizeof dai);
if (error)
return (error);
error = ioctlf(fp, DVD_AUTH, (caddr_t)&dai, p);
if (error)
return (error);
error = copyout(&dai, SCARG(uap, data), sizeof dai);
if (error)
return (error);
return (0);
default:
DPRINTF(("linux_ioctl: unimplemented ioctl %08lx\n", com));
return EINVAL;

View File

@ -1,4 +1,4 @@
/* $NetBSD: linux_cdrom.h,v 1.3 1998/10/03 20:17:40 christos Exp $ */
/* $NetBSD: linux_cdrom.h,v 1.4 1999/10/29 15:02:56 mycroft Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -55,6 +55,11 @@
#define LINUX_CDROMVOLREAD 0x5313 /* (struct linux_cdrom_volctrl) */
#define LINUX_CDROMPLAYBLK 0x5317 /* (struct linux_cdrom_blk) */
/* DVD-ROM Specific ioctls */
#define LINUX_DVD_READ_STRUCT 0x5390 /* Read structure */
#define LINUX_DVD_WRITE_STRUCT 0x5391 /* Write structure */
#define LINUX_DVD_AUTH 0x5392 /* Authentication */
struct linux_cdrom_blk {
unsigned from;
unsigned short len;

View File

@ -1,4 +1,4 @@
/* $NetBSD: cd.c,v 1.131 1999/10/17 09:44:48 ragge Exp $ */
/* $NetBSD: cd.c,v 1.132 1999/10/29 15:02:57 mycroft Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -70,6 +70,7 @@
#include <sys/disklabel.h>
#include <sys/disk.h>
#include <sys/cdio.h>
#include <sys/dvdio.h>
#include <sys/scsiio.h>
#include <sys/proc.h>
#include <sys/conf.h>
@ -126,6 +127,13 @@ int cd_read_subchannel __P((struct cd_softc *, int, int, int,
int cd_read_toc __P((struct cd_softc *, int, int, void *, int, int));
int cd_get_parms __P((struct cd_softc *, int));
int cd_load_toc __P((struct cd_softc *, struct cd_toc *));
int dvd_auth __P((struct cd_softc *, dvd_authinfo *));
int dvd_read_physical __P((struct cd_softc *, dvd_struct *));
int dvd_read_copyright __P((struct cd_softc *, dvd_struct *));
int dvd_read_disckey __P((struct cd_softc *, dvd_struct *));
int dvd_read_bca __P((struct cd_softc *, dvd_struct *));
int dvd_read_manufact __P((struct cd_softc *, dvd_struct *));
int dvd_read_struct __P((struct cd_softc *, dvd_struct *));
extern struct cfdriver cd_cd;
@ -831,6 +839,8 @@ cdioctl(dev, cmd, addr, flag, p)
case CDIOCRESET:
case SCIOCRESET:
case CDIOCLOADUNLOAD:
case DVD_AUTH:
case DVD_READ_STRUCT:
if (part == RAW_PART)
break;
/* FALLTHROUGH */
@ -1099,6 +1109,10 @@ cdioctl(dev, cmd, addr, flag, p)
return ((*cd->sc_ops->cdo_load_unload)(cd, args->options,
args->slot));
case DVD_AUTH:
return (dvd_auth(cd, (dvd_authinfo *)addr));
case DVD_READ_STRUCT:
return (dvd_read_struct(cd, (dvd_struct *)addr));
}
default:
@ -1453,3 +1467,285 @@ cddump(dev, blkno, va, size)
/* Not implemented. */
return (ENXIO);
}
#define dvd_copy_key(dst, src) memcpy((dst), (src), sizeof(dvd_key))
#define dvd_copy_challenge(dst, src) memcpy((dst), (src), sizeof(dvd_challenge))
int
dvd_auth(cd, a)
struct cd_softc *cd;
dvd_authinfo *a;
{
struct scsipi_generic cmd;
u_int8_t buf[20];
int error;
memset(cmd.bytes, 0, 15);
memset(buf, 0, sizeof(buf));
switch (a->type) {
case DVD_LU_SEND_AGID:
cmd.opcode = GPCMD_REPORT_KEY;
cmd.bytes[8] = 8;
cmd.bytes[9] = 0 | (0 << 6);
error = scsipi_command(cd->sc_link, &cmd, 16, buf, 8,
CDRETRIES, 30000, NULL, XS_CTL_DATA_IN);
if (error)
return (error);
a->lsa.agid = buf[7] >> 6;
return (0);
case DVD_LU_SEND_CHALLENGE:
cmd.opcode = GPCMD_REPORT_KEY;
cmd.bytes[8] = 16;
cmd.bytes[9] = 1 | (a->lsc.agid << 6);
error = scsipi_command(cd->sc_link, &cmd, 16, buf, 16,
CDRETRIES, 30000, NULL, XS_CTL_DATA_IN);
if (error)
return (error);
dvd_copy_challenge(a->lsc.chal, &buf[4]);
return (0);
case DVD_LU_SEND_KEY1:
cmd.opcode = GPCMD_REPORT_KEY;
cmd.bytes[8] = 12;
cmd.bytes[9] = 2 | (a->lsk.agid << 6);
error = scsipi_command(cd->sc_link, &cmd, 16, buf, 12,
CDRETRIES, 30000, NULL, XS_CTL_DATA_IN);
if (error)
return (error);
dvd_copy_key(a->lsk.key, &buf[4]);
return (0);
case DVD_LU_SEND_TITLE_KEY:
cmd.opcode = GPCMD_REPORT_KEY;
_lto4b(a->lstk.lba, &cmd.bytes[1]);
cmd.bytes[8] = 12;
cmd.bytes[9] = 4 | (a->lstk.agid << 6);
error = scsipi_command(cd->sc_link, &cmd, 16, buf, 12,
CDRETRIES, 30000, NULL, XS_CTL_DATA_IN);
if (error)
return (error);
a->lstk.cpm = (buf[4] >> 7) & 1;
a->lstk.cp_sec = (buf[4] >> 6) & 1;
a->lstk.cgms = (buf[4] >> 4) & 3;
dvd_copy_key(a->lstk.title_key, &buf[5]);
return (0);
case DVD_LU_SEND_ASF:
cmd.opcode = GPCMD_REPORT_KEY;
cmd.bytes[8] = 8;
cmd.bytes[9] = 5 | (a->lsasf.agid << 6);
error = scsipi_command(cd->sc_link, &cmd, 16, buf, 8,
CDRETRIES, 30000, NULL, XS_CTL_DATA_IN);
if (error)
return (error);
a->lsasf.asf = buf[7] & 1;
return (0);
case DVD_HOST_SEND_CHALLENGE:
cmd.opcode = GPCMD_SEND_KEY;
cmd.bytes[8] = 16;
cmd.bytes[9] = 1 | (a->hsc.agid << 6);
buf[1] = 14;
dvd_copy_challenge(&buf[4], a->hsc.chal);
error = scsipi_command(cd->sc_link, &cmd, 16, buf, 16,
CDRETRIES, 30000, NULL, XS_CTL_DATA_OUT|XS_CTL_DATA_IN);
if (error)
return (error);
a->type = DVD_LU_SEND_KEY1;
return (0);
case DVD_HOST_SEND_KEY2:
cmd.opcode = GPCMD_SEND_KEY;
cmd.bytes[8] = 12;
cmd.bytes[9] = 3 | (a->hsk.agid << 6);
buf[1] = 10;
dvd_copy_key(&buf[4], a->hsk.key);
error = scsipi_command(cd->sc_link, &cmd, 16, buf, 12,
CDRETRIES, 30000, NULL, XS_CTL_DATA_OUT|XS_CTL_DATA_IN);
if (error) {
a->type = DVD_AUTH_FAILURE;
return (error);
}
a->type = DVD_AUTH_ESTABLISHED;
return (0);
case DVD_INVALIDATE_AGID:
cmd.opcode = GPCMD_REPORT_KEY;
cmd.bytes[9] = 0x3f | (a->lsa.agid << 6);
error = scsipi_command(cd->sc_link, &cmd, 16, buf, 16,
CDRETRIES, 30000, NULL, 0);
if (error)
return (error);
return (0);
default:
return (ENOTTY);
}
}
int
dvd_read_physical(cd, s)
struct cd_softc *cd;
dvd_struct *s;
{
struct scsipi_generic cmd;
u_int8_t buf[4 + 4 * 20], *bufp;
int error;
struct dvd_layer *layer;
int i;
memset(cmd.bytes, 0, 15);
memset(buf, 0, sizeof(buf));
cmd.opcode = GPCMD_READ_DVD_STRUCTURE;
cmd.bytes[6] = s->type;
_lto2b(sizeof(buf), &cmd.bytes[7]);
cmd.bytes[5] = s->physical.layer_num;
error = scsipi_command(cd->sc_link, &cmd, 16, buf, sizeof(buf),
CDRETRIES, 30000, NULL, XS_CTL_DATA_IN);
if (error)
return (error);
for (i = 0, bufp = &buf[4], layer = &s->physical.layer[0]; i < 4;
i++, bufp += 20, layer++) {
memset(layer, 0, sizeof(*layer));
layer->book_version = bufp[0] & 0xf;
layer->book_type = bufp[0] >> 4;
layer->min_rate = bufp[1] & 0xf;
layer->disc_size = bufp[1] >> 4;
layer->layer_type = bufp[2] & 0xf;
layer->track_path = (bufp[2] >> 4) & 1;
layer->nlayers = (bufp[2] >> 5) & 3;
layer->track_density = bufp[3] & 0xf;
layer->linear_density = bufp[3] >> 4;
layer->start_sector = _3btol(&bufp[5]);
layer->end_sector = _3btol(&bufp[9]);
layer->end_sector_l0 = _3btol(&bufp[13]);
layer->bca = bufp[16] >> 7;
}
return (0);
}
int
dvd_read_copyright(cd, s)
struct cd_softc *cd;
dvd_struct *s;
{
struct scsipi_generic cmd;
u_int8_t buf[8];
int error;
memset(cmd.bytes, 0, 15);
memset(buf, 0, sizeof(buf));
cmd.opcode = GPCMD_READ_DVD_STRUCTURE;
cmd.bytes[6] = s->type;
_lto2b(sizeof(buf), &cmd.bytes[7]);
cmd.bytes[5] = s->copyright.layer_num;
error = scsipi_command(cd->sc_link, &cmd, 16, buf, sizeof(buf),
CDRETRIES, 30000, NULL, XS_CTL_DATA_IN);
if (error)
return (error);
s->copyright.cpst = buf[4];
s->copyright.rmi = buf[5];
return (0);
}
int
dvd_read_disckey(cd, s)
struct cd_softc *cd;
dvd_struct *s;
{
struct scsipi_generic cmd;
u_int8_t buf[4 + 2048];
int error;
memset(cmd.bytes, 0, 15);
memset(buf, 0, sizeof(buf));
cmd.opcode = GPCMD_READ_DVD_STRUCTURE;
cmd.bytes[6] = s->type;
_lto2b(sizeof(buf), &cmd.bytes[7]);
cmd.bytes[9] = s->disckey.agid << 6;
error = scsipi_command(cd->sc_link, &cmd, 16, buf, sizeof(buf),
CDRETRIES, 30000, NULL, XS_CTL_DATA_IN);
if (error)
return (error);
memcpy(s->disckey.value, &buf[4], 2048);
return (0);
}
int
dvd_read_bca(cd, s)
struct cd_softc *cd;
dvd_struct *s;
{
struct scsipi_generic cmd;
u_int8_t buf[4 + 188];
int error;
memset(cmd.bytes, 0, 15);
memset(buf, 0, sizeof(buf));
cmd.opcode = GPCMD_READ_DVD_STRUCTURE;
cmd.bytes[6] = s->type;
_lto2b(sizeof(buf), &cmd.bytes[7]);
error = scsipi_command(cd->sc_link, &cmd, 16, buf, sizeof(buf),
CDRETRIES, 30000, NULL, XS_CTL_DATA_IN);
if (error)
return (error);
s->bca.len = _2btol(&buf[0]);
if (s->bca.len < 12 || s->bca.len > 188)
return (EIO);
memcpy(s->bca.value, &buf[4], s->bca.len);
return (0);
}
int
dvd_read_manufact(cd, s)
struct cd_softc *cd;
dvd_struct *s;
{
struct scsipi_generic cmd;
u_int8_t buf[4 + 2048];
int error;
memset(cmd.bytes, 0, 15);
memset(buf, 0, sizeof(buf));
cmd.opcode = GPCMD_READ_DVD_STRUCTURE;
cmd.bytes[6] = s->type;
_lto2b(sizeof(buf), &cmd.bytes[7]);
error = scsipi_command(cd->sc_link, &cmd, 16, buf, sizeof(buf),
CDRETRIES, 30000, NULL, XS_CTL_DATA_IN);
if (error)
return (error);
s->manufact.len = _2btol(&buf[0]);
if (s->manufact.len < 0 || s->manufact.len > 2048)
return (EIO);
memcpy(s->manufact.value, &buf[4], s->manufact.len);
return (0);
}
int
dvd_read_struct(cd, s)
struct cd_softc *cd;
dvd_struct *s;
{
switch (s->type) {
case DVD_STRUCT_PHYSICAL:
return (dvd_read_physical(cd, s));
case DVD_STRUCT_COPYRIGHT:
return (dvd_read_copyright(cd, s));
case DVD_STRUCT_DISCKEY:
return (dvd_read_disckey(cd, s));
case DVD_STRUCT_BCA:
return (dvd_read_bca(cd, s));
case DVD_STRUCT_MANUFACT:
return (dvd_read_manufact(cd, s));
default:
return (EINVAL);
}
}

171
sys/sys/dvdio.h Normal file
View File

@ -0,0 +1,171 @@
#include <sys/types.h>
#include <sys/ioccom.h>
/* DVD-ROM Specific ioctls */
#define DVD_READ_STRUCT _IOWR('d', 0, dvd_struct)
#define DVD_WRITE_STRUCT _IOWR('d', 1, dvd_struct)
#define DVD_AUTH _IOWR('d', 2, dvd_authinfo)
#define GPCMD_READ_DVD_STRUCTURE 0xad
#define GPCMD_SEND_DVD_STRUCTURE 0xad
#define GPCMD_REPORT_KEY 0xa4
#define GPCMD_SEND_KEY 0xa3
/* DVD struct types */
#define DVD_STRUCT_PHYSICAL 0x00
#define DVD_STRUCT_COPYRIGHT 0x01
#define DVD_STRUCT_DISCKEY 0x02
#define DVD_STRUCT_BCA 0x03
#define DVD_STRUCT_MANUFACT 0x04
struct dvd_layer {
u_int8_t book_version : 4;
u_int8_t book_type : 4;
u_int8_t min_rate : 4;
u_int8_t disc_size : 4;
u_int8_t layer_type : 4;
u_int8_t track_path : 1;
u_int8_t nlayers : 2;
u_int8_t track_density : 4;
u_int8_t linear_density : 4;
u_int8_t bca : 1;
u_int8_t start_sector;
u_int8_t end_sector;
u_int8_t end_sector_l0;
};
struct dvd_physical {
u_int8_t type;
u_int8_t layer_num;
struct dvd_layer layer[4];
};
struct dvd_copyright {
u_int8_t type;
u_int8_t layer_num;
u_int8_t cpst;
u_int8_t rmi;
};
struct dvd_disckey {
u_int8_t type;
unsigned agid : 2;
u_int8_t value[2048];
};
struct dvd_bca {
u_int8_t type;
int len;
u_int8_t value[188];
};
struct dvd_manufact {
u_int8_t type;
u_int8_t layer_num;
int len;
u_int8_t value[2048];
};
typedef union {
u_int8_t type;
struct dvd_physical physical;
struct dvd_copyright copyright;
struct dvd_disckey disckey;
struct dvd_bca bca;
struct dvd_manufact manufact;
} dvd_struct;
/*
* DVD authentication ioctl
*/
/* Authentication states */
#define DVD_LU_SEND_AGID 0
#define DVD_HOST_SEND_CHALLENGE 1
#define DVD_LU_SEND_KEY1 2
#define DVD_LU_SEND_CHALLENGE 3
#define DVD_HOST_SEND_KEY2 4
/* Termination states */
#define DVD_AUTH_ESTABLISHED 5
#define DVD_AUTH_FAILURE 6
/* Other functions */
#define DVD_LU_SEND_TITLE_KEY 7
#define DVD_LU_SEND_ASF 8
#define DVD_INVALIDATE_AGID 9
/* State data */
typedef u_int8_t dvd_key[5]; /* 40-bit value, MSB is first elem. */
typedef u_int8_t dvd_challenge[10]; /* 80-bit value, MSB is first elem. */
struct dvd_lu_send_agid {
u_int8_t type;
unsigned agid : 2;
};
struct dvd_host_send_challenge {
u_int8_t type;
unsigned agid : 2;
dvd_challenge chal;
};
struct dvd_send_key {
u_int8_t type;
unsigned agid : 2;
dvd_key key;
};
struct dvd_lu_send_challenge {
u_int8_t type;
unsigned agid : 2;
dvd_challenge chal;
};
#define DVD_CPM_NO_COPYRIGHT 0
#define DVD_CPM_COPYRIGHTED 1
#define DVD_CP_SEC_NONE 0
#define DVD_CP_SEC_EXIST 1
#define DVD_CGMS_UNRESTRICTED 0
#define DVD_CGMS_SINGLE 2
#define DVD_CGMS_RESTRICTED 3
struct dvd_lu_send_title_key {
u_int8_t type;
unsigned agid : 2;
dvd_key title_key;
int lba;
unsigned cpm : 1;
unsigned cp_sec : 1;
unsigned cgms : 2;
};
struct dvd_lu_send_asf {
u_int8_t type;
unsigned agid : 2;
unsigned asf : 1;
};
typedef union {
u_int8_t type;
struct dvd_lu_send_agid lsa;
struct dvd_host_send_challenge hsc;
struct dvd_send_key lsk;
struct dvd_lu_send_challenge lsc;
struct dvd_send_key hsk;
struct dvd_lu_send_title_key lstk;
struct dvd_lu_send_asf lsasf;
} dvd_authinfo;