From 8170d8cccf8cc00bca8328e44d160340a75b4427 Mon Sep 17 00:00:00 2001 From: drochner Date: Thu, 8 Apr 2004 17:40:06 +0000 Subject: -add some NetBSD CD reading support -depend on devel/popt and audio/libcddb, this makes that the frontend utilities are built --- misc/libcdio/Makefile | 8 +- misc/libcdio/PLIST | 4 +- misc/libcdio/files/_cdio_netbsd.c | 497 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 507 insertions(+), 2 deletions(-) create mode 100644 misc/libcdio/files/_cdio_netbsd.c diff --git a/misc/libcdio/Makefile b/misc/libcdio/Makefile index 433d9c747ab..1db16dfc69f 100644 --- a/misc/libcdio/Makefile +++ b/misc/libcdio/Makefile @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.3 2004/02/14 18:26:28 jmmv Exp $ +# $NetBSD: Makefile,v 1.4 2004/04/08 17:40:06 drochner Exp $ # DISTNAME= libcdio-0.65 @@ -16,4 +16,10 @@ PKGCONFIG_OVERRIDE+= libcdio.pc.in PKGCONFIG_OVERRIDE+= libiso9660.pc.in GNU_CONFIGURE= yes +# XXX we just replace the freebsd module so save patches +pre-patch: + ${CP} ${FILESDIR}/_cdio_netbsd.c ${WRKSRC}/lib/_cdio_freebsd.c + +.include "../../devel/popt/buildlink2.mk" +.include "../../audio/libcddb/buildlink2.mk" .include "../../mk/bsd.pkg.mk" diff --git a/misc/libcdio/PLIST b/misc/libcdio/PLIST index 78ad6055318..36357c417e4 100644 --- a/misc/libcdio/PLIST +++ b/misc/libcdio/PLIST @@ -1,4 +1,6 @@ -@comment $NetBSD: PLIST,v 1.1.1.1 2004/01/17 14:38:22 recht Exp $ +@comment $NetBSD: PLIST,v 1.2 2004/04/08 17:40:06 drochner Exp $ +bin/cd-info +bin/cd-read include/cdio/cd_types.h include/cdio/cdio.h include/cdio/iso9660.h diff --git a/misc/libcdio/files/_cdio_netbsd.c b/misc/libcdio/files/_cdio_netbsd.c new file mode 100644 index 00000000000..9320b452ef0 --- /dev/null +++ b/misc/libcdio/files/_cdio_netbsd.c @@ -0,0 +1,497 @@ +/* $NetBSD: _cdio_netbsd.c,v 1.1 2004/04/08 17:40:06 drochner Exp $ */ + +/* + * Copyright (c) 2003 + * Matthias Drochner. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * XXX This is for NetBSD but uses "freebsd" function names to plug + * nicely into the existing libcdio. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "cdio_assert.h" +#include "cdio_private.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __i386__ +#define DEFAULT_CDIO_DEVICE "/dev/rcd0d" +#else +#define DEFAULT_CDIO_DEVICE "/dev/rcd0c" +#endif + +#define TOTAL_TRACKS (_obj->tochdr.ending_track \ + - _obj->tochdr.starting_track + 1) +#define FIRST_TRACK_NUM (_obj->tochdr.starting_track) + +typedef struct { + generic_img_private_t gen; + + bool toc_valid; + struct ioc_toc_header tochdr; + struct cd_toc_entry tocent[100]; + + bool sessionformat_valid; + int sessionformat[100]; /* format of the session the track is in */ +} _img_private_t; + +static int +_cdio_read_audio_sectors(void *user_data, void *data, lsn_t lsn, + unsigned int nblocks) +{ + scsireq_t req; + _img_private_t *_obj = user_data; + + memset(&req, 0, sizeof(req)); + req.cmd[0] = 0xbe; + req.cmd[1] = 0; + req.cmd[2] = (lsn >> 24) & 0xff; + req.cmd[3] = (lsn >> 16) & 0xff; + req.cmd[4] = (lsn >> 8) & 0xff; + req.cmd[5] = (lsn >> 0) & 0xff; + req.cmd[6] = (nblocks >> 16) & 0xff; + req.cmd[7] = (nblocks >> 8) & 0xff; + req.cmd[8] = (nblocks >> 0) & 0xff; + req.cmd[9] = 0x78; + req.cmdlen = 10; + + req.datalen = nblocks * CDIO_CD_FRAMESIZE_RAW; + req.databuf = data; + req.timeout = 10000; + req.flags = SCCMD_READ; + + if (ioctl(_obj->gen.fd, SCIOCCOMMAND, &req) < 0) { + perror("SCIOCCOMMAND"); + return 1; + } + if (req.retsts != SCCMD_OK) { + fprintf(stderr, "SCIOCCOMMAND sts %d\n", req.retsts); + return 1; + } + + return 0; +} + +static int +_cdio_read_mode2_sector(void *user_data, void *data, lsn_t lsn, + bool mode2_form2) +{ + scsireq_t req; + _img_private_t *_obj = user_data; + char buf[M2RAW_SECTOR_SIZE] = { 0, }; + + memset(&req, 0, sizeof(req)); + req.cmd[0] = 0xbe; + req.cmd[1] = 0; + req.cmd[2] = (lsn >> 24) & 0xff; + req.cmd[3] = (lsn >> 16) & 0xff; + req.cmd[4] = (lsn >> 8) & 0xff; + req.cmd[5] = (lsn >> 0) & 0xff; + req.cmd[6] = 0; + req.cmd[7] = 0; + req.cmd[8] = 1; + req.cmd[9] = 0x58; /* subheader + userdata + ECC */ + req.cmdlen = 10; + + req.datalen = M2RAW_SECTOR_SIZE; + req.databuf = buf; + req.timeout = 10000; + req.flags = SCCMD_READ; + + if (ioctl(_obj->gen.fd, SCIOCCOMMAND, &req) < 0) { + perror("SCIOCCOMMAND"); + return 1; + } + if (req.retsts != SCCMD_OK) { + fprintf(stderr, "SCIOCCOMMAND sts %d\n", req.retsts); + return 1; + } + + if (mode2_form2) + memcpy(data, buf, M2RAW_SECTOR_SIZE); + else + memcpy(data, buf + CDIO_CD_SUBHEADER_SIZE, CDIO_CD_FRAMESIZE); + + return 0; +} + +static int +_cdio_read_mode2_sectors(void *user_data, void *data, lsn_t lsn, + bool mode2_form2, unsigned int nblocks) +{ + int i, res; + char *buf = data; + + for (i = 0; i < nblocks; i++) { + res = _cdio_read_mode2_sector(user_data, buf, lsn, mode2_form2); + if (res) + return res; + + buf += (mode2_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE); + lsn++; + } + + return 0; +} + +static uint32_t +_cdio_stat_size(void *user_data) +{ + _img_private_t *_obj = user_data; + struct ioc_read_toc_entry req; + struct cd_toc_entry tocent; + + req.address_format = CD_LBA_FORMAT; + req.starting_track = 0xaa; + req.data_len = sizeof(tocent); + req.data = &tocent; + + if (ioctl(_obj->gen.fd, CDIOREADTOCENTRIES, &req) < 0) { + perror("ioctl(CDIOREADTOCENTRY) leadout"); + exit(EXIT_FAILURE); + } + + return (tocent.addr.lba); +} + +static int +_cdio_set_arg(void *user_data, const char key[], const char value[]) +{ + _img_private_t *_obj = user_data; + + if (!strcmp(key, "source")) { + if (!value) + return -2; + + free(_obj->gen.source_name); + _obj->gen.source_name = strdup(value); + } else if (!strcmp(key, "access-mode")) { + if (strcmp(value, "READ_CD")) + cdio_error("unknown access type: %s ignored.", value); + } else + return -1; + + return 0; +} + +static bool +_cdio_read_toc(_img_private_t *_obj) +{ + int res; + struct ioc_read_toc_entry req; + + res = ioctl(_obj->gen.fd, CDIOREADTOCHEADER, &_obj->tochdr); + if (res < 0) { + cdio_error("error in ioctl(CDIOREADTOCHEADER): %s\n", + strerror(errno)); + return false; + } + + req.address_format = CD_MSF_FORMAT; + req.starting_track = FIRST_TRACK_NUM; + req.data_len = (TOTAL_TRACKS + 1) /* leadout! */ + * sizeof(struct cd_toc_entry); + req.data = _obj->tocent; + + res = ioctl(_obj->gen.fd, CDIOREADTOCENTRIES, &req); + if (res < 0) { + cdio_error("error in ioctl(CDROMREADTOCENTRIES): %s\n", + strerror(errno)); + return false; + } + + _obj->toc_valid = 1; + return true; +} + +static int +_cdio_read_discinfo(_img_private_t *_obj) +{ + scsireq_t req; +#define FULLTOCBUF (4 + 1000*11) + unsigned char buf[FULLTOCBUF] = { 0, }; + int i, j; + + memset(&req, 0, sizeof(req)); + req.cmd[0] = 0x43; /* READ TOC/PMA/ATIP */ + req.cmd[1] = 0x02; + req.cmd[2] = 0x02; /* full TOC */ + req.cmd[3] = 0; + req.cmd[4] = 0; + req.cmd[5] = 0; + req.cmd[6] = 0; + req.cmd[7] = FULLTOCBUF / 256; + req.cmd[8] = FULLTOCBUF % 256; + req.cmd[9] = 0; + req.cmdlen = 10; + + req.datalen = FULLTOCBUF; + req.databuf = buf; + req.timeout = 10000; + req.flags = SCCMD_READ; + + if (ioctl(_obj->gen.fd, SCIOCCOMMAND, &req) < 0) { + perror("SCIOCCOMMAND"); + return 1; + } + if (req.retsts != SCCMD_OK) { + fprintf(stderr, "SCIOCCOMMAND sts %d\n", req.retsts); + return 1; + } +#if 1 + printf("discinfo:"); + for (i = 0; i < 4; i++) + printf(" %02x", buf[i]); + printf("\n"); + for (i = 0; i < buf[1] - 2; i++) { + printf(" %02x", buf[i + 4]); + if (!((i + 1) % 11)) + printf("\n"); + } +#endif + + for (i = 4; i < req.datalen_used; i += 11) { + if (buf[i + 3] == 0xa0) { /* POINT */ + /* XXX: assume entry 0xa1 follows */ + for (j = buf[i + 8] - 1; j <= buf[i + 11 + 8] - 1; j++) + _obj->sessionformat[j] = buf[i + 9]; + } + } + + _obj->sessionformat_valid = true; + return 0; +} + +static int +_cdio_eject_media(void *user_data) { + + _img_private_t *_obj = user_data; + int fd, res, ret = 0; + + fd = open(_obj->gen.source_name, O_RDONLY|O_NONBLOCK); + if (fd < 0) + return 2; + + res = ioctl(fd, CDIOCALLOW); + if (res < 0) { + cdio_error("ioctl(fd, CDIOCALLOW) failed: %s\n", + strerror(errno)); + /* go on... */ + } + res = ioctl(fd, CDIOCEJECT); + if (res < 0) { + cdio_error("ioctl(CDIOCEJECT) failed: %s\n", + strerror(errno)); + ret = 1; + } + + return ret; +} + +static const char * +_cdio_get_arg(void *user_data, const char key[]) +{ + _img_private_t *_obj = user_data; + + if (!strcmp(key, "source")) { + return _obj->gen.source_name; + } else if (!strcmp(key, "access-mode")) { + return "READ_CD"; + } + + return NULL; +} + +static track_t +_cdio_get_first_track_num(void *user_data) +{ + _img_private_t *_obj = user_data; + int res; + + if (!_obj->toc_valid) { + res = _cdio_read_toc(_obj); + if (!res) + return CDIO_INVALID_TRACK; + } + + return FIRST_TRACK_NUM; +} + +static track_t +_cdio_get_num_tracks(void *user_data) +{ + _img_private_t *_obj = user_data; + int res; + + if (!_obj->toc_valid) { + res = _cdio_read_toc(_obj); + if (!res) + return CDIO_INVALID_TRACK; + } + + return TOTAL_TRACKS; +} + +static track_format_t +_cdio_get_track_format(void *user_data, track_t track_num) +{ + _img_private_t *_obj = user_data; + int res; + + if (!_obj->toc_valid) { + res = _cdio_read_toc(_obj); + if (!res) + return CDIO_INVALID_TRACK; + } + + if (track_num > TOTAL_TRACKS || track_num == 0) + return TRACK_FORMAT_ERROR; + + if (_obj->tocent[track_num - 1].control & 0x04) { + if (!_obj->sessionformat_valid) { + res = _cdio_read_discinfo(_obj); + if (res) + return CDIO_INVALID_TRACK; + } + + if (_obj->sessionformat[track_num - 1] == 0x10) + return TRACK_FORMAT_CDI; + else if (_obj->sessionformat[track_num - 1] == 0x20) + return TRACK_FORMAT_XA; + else + return TRACK_FORMAT_DATA; + } else + return TRACK_FORMAT_AUDIO; +} + +static bool +_cdio_get_track_green(void *user_data, track_t track_num) +{ + + return (_cdio_get_track_format(user_data, track_num) + == TRACK_FORMAT_XA); +} + +static bool +_cdio_get_track_msf(void *user_data, track_t track_num, msf_t *msf) +{ + _img_private_t *_obj = user_data; + int res; + + if (!msf) + return false; + + if (!_obj->toc_valid) { + res = _cdio_read_toc(_obj); + if (!res) + return CDIO_INVALID_TRACK; + } + + if (track_num == CDIO_CDROM_LEADOUT_TRACK) + track_num = TOTAL_TRACKS + 1; + + if (track_num > TOTAL_TRACKS + 1 || track_num == 0) + return false; + + msf->m = to_bcd8(_obj->tocent[track_num - 1].addr.msf.minute); + msf->s = to_bcd8(_obj->tocent[track_num - 1].addr.msf.second); + msf->f = to_bcd8(_obj->tocent[track_num - 1].addr.msf.frame); + + return true; +} + +char * +cdio_get_default_device_freebsd() +{ + return strdup(DEFAULT_CDIO_DEVICE); +} + +static cdio_funcs _funcs = { + .eject_media = _cdio_eject_media, + .free = cdio_generic_free, + .get_arg = _cdio_get_arg, + .get_default_device = cdio_get_default_device_freebsd, + .get_first_track_num= _cdio_get_first_track_num, + .get_num_tracks = _cdio_get_num_tracks, + .get_track_format = _cdio_get_track_format, + .get_track_green = _cdio_get_track_green, + .get_track_lba = NULL, + .get_track_msf = _cdio_get_track_msf, + .lseek = cdio_generic_lseek, + .read = cdio_generic_read, + .read_audio_sectors = _cdio_read_audio_sectors, + .read_mode2_sector = _cdio_read_mode2_sector, + .read_mode2_sectors = _cdio_read_mode2_sectors, + .set_arg = _cdio_set_arg, + .stat_size = _cdio_stat_size +}; + +CdIo * +cdio_open_freebsd(const char *source_name) +{ + CdIo *ret; + _img_private_t *_data; + + _data = _cdio_malloc(sizeof(_img_private_t)); + _data->gen.init = false; + _data->gen.fd = -1; + _data->toc_valid = false; + _data->sessionformat_valid = false; + + _cdio_set_arg(_data, "source", + (source_name ? source_name : DEFAULT_CDIO_DEVICE)); + + ret = cdio_new(_data, &_funcs); + if (!ret) + return NULL; + + if (cdio_generic_init(_data)) { + return ret; + } else { + cdio_generic_free(_data); + return NULL; + } +} + +bool +cdio_have_freebsd(void) +{ + return true; +} -- cgit v1.2.3