--- sys/dev/ata/atapi-cd.c.orig Sat Oct 29 19:40:44 2005 +++ sys/dev/ata/atapi-cd.c Sat Oct 29 19:45:30 2005 @@ -53,6 +53,11 @@ #include #include +extern int atapicd_aggresive_toc; +extern int atapicd_multiblock; + +#define ACD_F_MULTIBLOCK (G_PF_IGNOREOFFSET|G_PF_IGNOREBOUNDARY) + /* prototypes */ static void acd_detach(struct ata_device *); static void acd_start(struct ata_device *); @@ -92,6 +97,7 @@ static int acd_read_format_caps(struct acd_softc *, struct cdr_format_capacities *); static int acd_format(struct acd_softc *, struct cdr_format_params *); static int acd_test_ready(struct ata_device *); +static int acd_get_blocksize(off_t, u_int32_t); /* internal vars */ static u_int32_t acd_lun_map = 0; @@ -117,6 +123,7 @@ } ata_set_name(atadev, "acd", cdp->lun); + ata_controlcmd(atadev, ATA_ATAPI_RESET, 0, 0, 0); acd_get_cap(cdp); /* if this is a changer device, allocate the neeeded lun's */ @@ -539,12 +546,15 @@ pp->sectorsize = (cdp->toc.tab[track - 1].control & 4) ? 2048 : 2352; pp->mediasize = ntohl(cdp->toc.tab[track].addr.lba) - ntohl(cdp->toc.tab[track - 1].addr.lba); + pp->mediasize *= pp->sectorsize; } else { pp->sectorsize = cdp->block_size; - pp->mediasize = cdp->disk_size; + if ((pp->flags & ACD_F_MULTIBLOCK) == ACD_F_MULTIBLOCK) + pp->mediasize = (off_t)cdp->disk_size * 2352; + else + pp->mediasize = (off_t)cdp->disk_size * cdp->block_size; } - pp->mediasize *= pp->sectorsize; return 0; } @@ -680,9 +690,11 @@ bcopy(&cdp->toc, toc, sizeof(struct toc)); entry = toc->tab + (toc->hdr.ending_track + 1 - toc->hdr.starting_track) + 1; - while (--entry >= toc->tab) + while (--entry >= toc->tab) { lba2msf(ntohl(entry->addr.lba), &entry->addr.msf.minute, &entry->addr.msf.second, &entry->addr.msf.frame); + entry->addr_type = CD_MSF_FORMAT; + } } error = copyout(toc->tab + starting_track - toc->hdr.starting_track, te->data, len); @@ -1017,6 +1029,7 @@ acd_geom_start(struct bio *bp) { struct acd_softc *cdp = bp->bio_to->geom->softc; + int blocksize; if (cdp->device->flags & ATA_D_DETACHING) { g_io_deliver(bp, ENXIO); @@ -1033,6 +1046,16 @@ return; } + /* Concurrent access with different blocksize */ + if (bp->bio_to->index == 0 && + (cdp->pp[0]->flags & ACD_F_MULTIBLOCK) == ACD_F_MULTIBLOCK) { + blocksize = bp->bio_to->sectorsize; + if (blocksize < 2048 || blocksize > 2352 || bp->bio_length % blocksize) + blocksize = acd_get_blocksize(bp->bio_length, cdp->block_size); + bp->bio_to->sectorsize = blocksize; + cdp->pp[0]->sectorsize = blocksize; + } + /* GEOM classes must do their own request limiting */ if (bp->bio_length <= cdp->iomax) { mtx_lock(&cdp->queue_mtx); @@ -1071,7 +1094,7 @@ struct ata_request *request; u_int32_t lba, lastlba, count; int8_t ccb[16]; - int track, blocksize; + int track, ntracks, blocksize; if (cdp->changer_info) { int i; @@ -1114,22 +1137,56 @@ bzero(ccb, sizeof(ccb)); track = bp->bio_to->index; + ntracks = cdp->toc.hdr.ending_track - cdp->toc.hdr.starting_track + 1; + blocksize = cdp->pp[track]->sectorsize; + lba = 0; if (track) { - blocksize = (cdp->toc.tab[track - 1].control & 4) ? 2048 : 2352; + /* Don't let other than BIO_READ on individual track */ + if (bp->bio_cmd != BIO_READ) { + g_io_deliver(bp, EINVAL); + return; + } lastlba = ntohl(cdp->toc.tab[track].addr.lba); - lba = bp->bio_offset / blocksize; lba += ntohl(cdp->toc.tab[track - 1].addr.lba); } else { - blocksize = cdp->block_size; - lastlba = cdp->disk_size; - lba = bp->bio_offset / blocksize; + if ((cdp->pp[0]->flags & ACD_F_MULTIBLOCK) == ACD_F_MULTIBLOCK) { + if (blocksize < 2048 || blocksize > 2352 || bp->bio_length % blocksize) + blocksize = acd_get_blocksize(bp->bio_length, cdp->block_size); + cdp->pp[0]->sectorsize = blocksize; + bp->bio_to->sectorsize = blocksize; + } else + blocksize = cdp->block_size; + /* Limit BIO_READ until last readable track */ + if (bp->bio_cmd == BIO_READ) + lastlba = ntohl(cdp->toc.tab[ntracks].addr.lba); + else + lastlba = cdp->disk_size; } + lba += bp->bio_offset / blocksize; count = bp->bio_length / blocksize; + /* Reject zero count / non-integral operation */ + if (count < 1 || bp->bio_length % blocksize || + bp->bio_offset % blocksize) { + g_io_deliver(bp, EINVAL); + return; + } + + /* Reject request past the end of media */ + if (bp->bio_offset > cdp->pp[track]->mediasize) { + g_io_deliver(bp, EIO); + return; + } + if (bp->bio_cmd == BIO_READ) { + /* Reject invalid offset */ + if (bp->bio_offset < 0) { + g_io_deliver(bp, EIO); + return; + } /* if transfer goes beyond range adjust it to be within limits */ if (lba + count > lastlba) { /* if we are entirely beyond EOM return EOF */ @@ -1217,18 +1274,38 @@ int track, ntracks, len; u_int32_t sizes[2]; int8_t ccb[16]; + u_int8_t dinfo[34]; struct g_provider *pp; - if (acd_test_ready(cdp->device)) + if (cdp->pp[0] != NULL) { + if (atapicd_multiblock) + cdp->pp[0]->flags |= ACD_F_MULTIBLOCK; + else + cdp->pp[0]->flags &= ~ACD_F_MULTIBLOCK; + } + + if (atapicd_aggresive_toc) { + bzero(&cdp->toc, sizeof(cdp->toc)); + bzero(ccb, sizeof(ccb)); + cdp->disk_size = -1; /* hack for GEOM SOS */ + } + track = 1; + + if (acd_test_ready(cdp->device)) { + if (atapicd_aggresive_toc) + goto flush_geoms; return; + } - if (!(cdp->device->flags & ATA_D_MEDIA_CHANGED)) + if (!atapicd_aggresive_toc && !(cdp->device->flags & ATA_D_MEDIA_CHANGED)) return; cdp->device->flags &= ~ATA_D_MEDIA_CHANGED; - bzero(&cdp->toc, sizeof(cdp->toc)); - bzero(ccb, sizeof(ccb)); - cdp->disk_size = -1; /* hack for GEOM SOS */ + if (!atapicd_aggresive_toc) { + bzero(&cdp->toc, sizeof(cdp->toc)); + bzero(ccb, sizeof(ccb)); + cdp->disk_size = -1; /* hack for GEOM SOS */ + } len = sizeof(struct ioc_toc_header) + sizeof(struct cd_toc_entry); ccb[0] = ATAPI_READ_TOC; @@ -1237,11 +1314,15 @@ if (ata_atapicmd(cdp->device, ccb, (caddr_t)&cdp->toc, len, ATA_R_READ | ATA_R_QUIET, 30)) { bzero(&cdp->toc, sizeof(cdp->toc)); + if (atapicd_aggresive_toc) + goto flush_geoms; return; } ntracks = cdp->toc.hdr.ending_track - cdp->toc.hdr.starting_track + 1; if (ntracks <= 0 || ntracks > MAXTRK) { bzero(&cdp->toc, sizeof(cdp->toc)); + if (atapicd_aggresive_toc) + goto flush_geoms; return; } @@ -1253,20 +1334,38 @@ if (ata_atapicmd(cdp->device, ccb, (caddr_t)&cdp->toc, len, ATA_R_READ | ATA_R_QUIET, 30)) { bzero(&cdp->toc, sizeof(cdp->toc)); + if (atapicd_aggresive_toc) + goto flush_geoms; return; } cdp->toc.hdr.len = ntohs(cdp->toc.hdr.len); cdp->block_size = (cdp->toc.tab[0].control & 4) ? 2048 : 2352; acd_set_ioparm(cdp); + /* writable / appendable media capacity */ bzero(ccb, sizeof(ccb)); - ccb[0] = ATAPI_READ_CAPACITY; - if (ata_atapicmd(cdp->device, ccb, (caddr_t)sizes, sizeof(sizes), + bzero(dinfo, sizeof(dinfo)); + ccb[0] = ATAPI_READ_DISK_INFO; + ccb[7] = sizeof(dinfo) >> 8; + ccb[8] = sizeof(dinfo); + if ((cdp->cap.media & (MST_WRITE_CDR | MST_WRITE_CDRW | + MST_WRITE_DVDR | MST_WRITE_DVDRAM)) + && !ata_atapicmd(cdp->device, ccb, (caddr_t)dinfo, sizeof(dinfo), + ATA_R_READ | ATA_R_QUIET, 30) + && (dinfo[21] != 0xff || dinfo[22] != 0xff || dinfo[23] != 0xff)) { + cdp->disk_size = msf2lba(dinfo[21], dinfo[22], dinfo[23]); + } else { + bzero(ccb, sizeof(ccb)); + ccb[0] = ATAPI_READ_CAPACITY; + if (ata_atapicmd(cdp->device, ccb, (caddr_t)sizes, sizeof(sizes), ATA_R_READ | ATA_R_QUIET, 30)) { - bzero(&cdp->toc, sizeof(cdp->toc)); - return; + bzero(&cdp->toc, sizeof(cdp->toc)); + if (atapicd_aggresive_toc) + goto flush_geoms; + return; + } + cdp->disk_size = ntohl(sizes[0]) + 1; } - cdp->disk_size = ntohl(sizes[0]) + 1; for (track = 1; track <= ntracks; track ++) { if (cdp->pp[track] != NULL) @@ -1276,6 +1375,7 @@ cdp->pp[track] = pp; g_error_provider(pp, 0); } +flush_geoms: for (; track < MAXTRK; track ++) { if (cdp->pp[track] == NULL) continue; @@ -2027,4 +2127,27 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; return ata_atapicmd(atadev, ccb, NULL, 0, 0, 30); +} + +static int +acd_get_blocksize(off_t length, u_int32_t blocksize) +{ + /* + * Determine correct blocksize from bio length + * + * 2048 / 2056 / 2324 / 2332 / 2336 / 2352 + */ + if (length >= 2352 && !(length % 2352)) + return 2352; + else if (length >= 2336 && !(length % 2336)) + return 2336; + else if (length >= 2332 && !(length % 2332)) + return 2332; + else if (length >= 2324 && !(length % 2324)) + return 2324; + else if (length >= 2056 && !(length % 2056)) + return 2056; + else if (length >= 2048 && !(length % 2048)) + return 2048; + return blocksize; /* return default blocksize */ } --- sys/dev/ata/ata-all.c.orig Sun Apr 10 16:05:06 2005 +++ sys/dev/ata/ata-all.c Sun Apr 10 16:06:52 2005 @@ -81,6 +81,10 @@ devclass_t ata_devclass; uma_zone_t ata_zone; int ata_wc = 1; +#ifdef DEV_ATAPICD +int atapicd_aggresive_toc = 0; +int atapicd_multiblock = 1; +#endif /* local vars */ static struct intr_config_hook *ata_delayed_attach = NULL; @@ -99,6 +103,16 @@ TUNABLE_INT("hw.ata.atapi_dma", &atapi_dma); SYSCTL_INT(_hw_ata, OID_AUTO, atapi_dma, CTLFLAG_RDTUN, &atapi_dma, 0, "ATAPI device DMA mode control"); +#ifdef DEV_ATAPICD +TUNABLE_INT("hw.ata.atapicd_aggresive_toc", &atapicd_aggresive_toc); +SYSCTL_INT(_hw_ata, OID_AUTO, atapicd_aggresive_toc, CTLFLAG_RW, + &atapicd_aggresive_toc, 0, + "ATAPI CDROM aggresive TOC read"); +TUNABLE_INT("hw.ata.atapicd_multiblock", &atapicd_multiblock); +SYSCTL_INT(_hw_ata, OID_AUTO, atapicd_multiblock, CTLFLAG_RW, + &atapicd_multiblock, 0, + "ATAPI CDROM multiple blocksize access"); +#endif /* * newbus device interface related functions --- sys/dev/ata/ata-chipset.c.orig Fri Apr 1 02:20:23 2005 +++ sys/dev/ata/ata-chipset.c Fri Mar 11 15:53:43 2005 @@ -90,6 +90,7 @@ static int ata_nvidia_chipinit(device_t); static int ata_via_chipinit(device_t); static void ata_via_family_setmode(struct ata_device *, int); +static int ata_via_check_80pin(struct ata_device *, int); static void ata_via_southbridge_fixup(device_t); static int ata_promise_chipinit(device_t); static int ata_promise_mio_allocate(device_t, struct ata_channel *); @@ -125,6 +126,8 @@ static int ata_serialize(struct ata_channel *, int); static int ata_mode2idx(int); +static u_int32_t via_80pin = 0; + /* generic or unknown ATA chipset init code */ int ata_generic_ident(device_t dev) @@ -2824,6 +2827,8 @@ ata_via_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); + u_int32_t reg50; + int i; if (ata_setup_interrupt(dev)) return ENXIO; @@ -2859,6 +2864,39 @@ pci_write_config(dev, 0x68, DEV_BSIZE, 2); ctlr->setmode = ata_via_family_setmode; + + via_80pin = 0; + + switch (ctlr->chip->max_dma) { + case ATA_UDMA4: + reg50 = pci_read_config(dev, 0x50, 4); + for (i = 24; i >= 0; i -= 8) { + if (((reg50 >> (1 & 16)) & 8) && + ((reg50 >> i) & 0x20) && (((reg50 >> i) & 7) < 2)) { + via_80pin |= (1 << (1 - (i >> 4))); + } + } + break; + case ATA_UDMA5: + reg50 = pci_read_config(dev, 0x50, 4); + for (i = 24; i >= 0; i -= 8) { + if (((reg50 >> i) & 0x10) || + (((reg50 >> i) & 0x20) && (((reg50 >> i) & 7) < 4))) { + via_80pin |= (1 << (1 - (i >> 4))); + } + } + break; + case ATA_UDMA6: + reg50 = pci_read_config(dev, 0x50, 4); + for (i = 24; i >= 0; i -= 8) { + if (((reg50 >> i) & 0x10) || + (((reg50 >> i) & 0x20) && (((reg50 >> i) & 7) < 6))) { + via_80pin |= (1 << (1 - (i >> 4))); + } + } + break; + } + return 0; } @@ -2918,8 +2956,10 @@ mode = ATA_UDMA2; } } - else + else if (ctlr->chip->cfg1 == AMDNVIDIA) mode = ata_check_80pin(atadev, mode); + else + mode = ata_via_check_80pin(atadev, mode); if (ctlr->chip->cfg2 & NVIDIA) reg += 0x10; @@ -2941,6 +2981,19 @@ pci_write_config(parent, reg, 0x8b, 1); atadev->mode = mode; } +} + +static int +ata_via_check_80pin(struct ata_device *atadev, int mode) +{ + if (mode > ATA_UDMA2) { + if (!((via_80pin >> atadev->channel->unit) & 1)) { + ata_prtdev(atadev,"DMA limited to UDMA33, non-ATA66 cable or device\n"); + mode = ATA_UDMA2; + } else if (!atadev->param->hwres) + mode = ATA_UDMA2; + } + return mode; } /* misc functions */ --- sys/geom/geom.h.orig Sun Apr 10 15:17:01 2005 +++ sys/geom/geom.h Sun Apr 10 15:57:18 2005 @@ -189,6 +189,8 @@ #define G_PF_CANDELETE 0x1 #define G_PF_WITHER 0x2 #define G_PF_ORPHAN 0x4 +#define G_PF_IGNOREOFFSET 0x8 +#define G_PF_IGNOREBOUNDARY 0x10 /* Two fields for the implementing class to use */ void *private; --- sys/geom/geom_dev.c.orig Sun Apr 10 15:15:36 2005 +++ sys/geom/geom_dev.c Sun Apr 10 15:56:31 2005 @@ -342,8 +342,9 @@ KASSERT(cp->acr || cp->acw, ("Consumer with zero access count in g_dev_strategy")); - if ((bp->bio_offset % cp->provider->sectorsize) != 0 || - (bp->bio_bcount % cp->provider->sectorsize) != 0) { + if (!(cp->provider->flags & G_PF_IGNOREBOUNDARY) && + ((bp->bio_offset % cp->provider->sectorsize) != 0 || + (bp->bio_bcount % cp->provider->sectorsize) != 0)) { biofinish(bp, NULL, EINVAL); return; } --- sys/geom/geom_io.c.orig Sun Apr 10 15:20:04 2005 +++ sys/geom/geom_io.c Sun Apr 10 16:00:47 2005 @@ -217,17 +217,21 @@ /* Zero sectorsize is a probably lack of media */ if (pp->sectorsize == 0) return (ENXIO); - /* Reject I/O not on sector boundary */ - if (bp->bio_offset % pp->sectorsize) - return (EINVAL); - /* Reject I/O not integral sector long */ - if (bp->bio_length % pp->sectorsize) - return (EINVAL); + if (!(pp->flags & G_PF_IGNOREBOUNDARY)) { + /* Reject I/O not on sector boundary */ + if (bp->bio_offset % pp->sectorsize) + return (EINVAL); + /* Reject I/O not integral sector long */ + if (bp->bio_length % pp->sectorsize) + return (EINVAL); + } /* Reject requests before or past the end of media. */ - if (bp->bio_offset < 0) - return (EIO); - if (bp->bio_offset > pp->mediasize) - return (EIO); + if (!(pp->flags & G_PF_IGNOREOFFSET)) { + if (bp->bio_offset < 0) + return (EIO); + if (bp->bio_offset > pp->mediasize) + return (EIO); + } break; default: break; --- usr.sbin/cdcontrol/cdcontrol.c.orig Wed Feb 16 02:29:43 2005 +++ usr.sbin/cdcontrol/cdcontrol.c Wed Feb 16 02:33:13 2005 @@ -73,6 +73,7 @@ #define STATUS_AUDIO 0x1 #define STATUS_MEDIA 0x2 #define STATUS_VOLUME 0x4 +#define SESSION_SECTORS (152*75) struct cmdtab { int command; @@ -1004,6 +1005,12 @@ e[1].addr.msf.frame); else next = ntohl(e[1].addr.lba); + if (e[1].track < 100) { + if (!(e->control & 4) && (e[1].control & 4)) + next -= SESSION_SECTORS; + else if ((e->control & 4) != (e[1].control & 4)) + next -= 150; + } len = next - block; /* Take into account a start offset time. */ lba2msf (len - 150, &m, &s, &f); --- usr.sbin/burncd/burncd.c.orig Tue Mar 29 16:47:00 2005 +++ usr.sbin/burncd/burncd.c Tue Mar 29 16:52:48 2005 @@ -47,6 +47,16 @@ #define BLOCKS 16 +#define WAVE_HEADER_SIZE 44 +#define RIFF_MAGIC "RIFF" +#define WAVE_MAGIC "WAVE" +#define FMT_MAGIC "fmt " +#define DATA_MAGIC "data" +#define WAVE_VALID_EXT ".wav" +#define WAVE_VALID_RATE ((u_int32_t)44100) +#define WAVE_VALID_SAMPLE ((u_int16_t)16) +#define WAVE_VALID_CHANNELS ((u_int16_t)2) + struct track_info { int file; char file_name[MAXPATHLEN + 1]; @@ -59,7 +69,8 @@ static struct track_info tracks[100]; static int global_fd_for_cleanup, quiet, verbose, saved_block_size, notracks; -void add_track(char *, int, int, int); +u_int is_wavefile(char *, int, int); +void add_track(char *, int, int, int, int); void do_DAO(int fd, int, int); void do_TAO(int fd, int, int, int); void do_format(int, int, char *); @@ -76,6 +87,7 @@ int dao = 0, eject = 0, fixate = 0, list = 0, multi = 0, preemp = 0; int nogap = 0, speed = 4 * 177, test_write = 0, force = 0; int block_size = 0, block_type = 0, cdopen = 0, dvdrw = 0; + int wave_check = 0; const char *dev; if ((dev = getenv("CDROM")) == NULL) @@ -166,7 +178,11 @@ if (!strcasecmp(argv[arg], "msinfo")) { struct ioc_read_toc_single_entry entry; struct ioc_toc_header header; + struct cdr_track dummy_track; + bzero(&dummy_track, sizeof(dummy_track)); + if (ioctl(fd, CDRIOCINITTRACK, &dummy_track) < 0) + err(EX_IOERR, "ioctl(CDRIOCINITTRACK)"); if (ioctl(fd, CDIOREADTOCHEADER, &header) < 0) err(EX_IOERR, "ioctl(CDIOREADTOCHEADER)"); bzero(&entry, sizeof(struct ioc_read_toc_single_entry)); @@ -177,7 +193,9 @@ if (ioctl(fd, CDRIOCNEXTWRITEABLEADDR, &addr) < 0) err(EX_IOERR, "ioctl(CDRIOCNEXTWRITEABLEADDR)"); fprintf(stdout, "%d,%d\n", - ntohl(entry.entry.addr.lba), addr); + (entry.entry.control & 4) + ? ntohl(entry.entry.addr.lba) + : 0, addr); break; } @@ -222,29 +240,40 @@ arg++; continue; } - if (!strcasecmp(argv[arg], "audio") || !strcasecmp(argv[arg], "raw")) { + if (!strcasecmp(argv[arg], "raw")) { + block_type = CDR_DB_RAW; + block_size = 2352; + wave_check = 0; + continue; + } + if (!strcasecmp(argv[arg], "audio")) { block_type = CDR_DB_RAW; block_size = 2352; + wave_check = 1; continue; } if (!strcasecmp(argv[arg], "data") || !strcasecmp(argv[arg], "mode1")) { block_type = CDR_DB_ROM_MODE1; block_size = 2048; + wave_check = 0; continue; } if (!strcasecmp(argv[arg], "mode2")) { block_type = CDR_DB_ROM_MODE2; block_size = 2336; + wave_check = 0; continue; } if (!strcasecmp(argv[arg], "xamode1")) { block_type = CDR_DB_XA_MODE1; block_size = 2048; + wave_check = 0; continue; } if (!strcasecmp(argv[arg], "xamode2")) { block_type = CDR_DB_XA_MODE2_F2; block_size = 2324; + wave_check = 0; continue; } if (!strcasecmp(argv[arg], "vcd")) { @@ -252,12 +281,14 @@ block_size = 2352; dao = 1; nogap = 1; + wave_check = 0; continue; } if (!strcasecmp(argv[arg], "dvdrw")) { block_type = CDR_DB_ROM_MODE1; block_size = 2048; dvdrw = 1; + wave_check = 0; continue; } @@ -275,7 +306,8 @@ continue; if ((eol = strchr(file_buf, '\n'))) *eol = '\0'; - add_track(file_buf, block_size, block_type, nogap); + add_track(file_buf, block_size, block_type, nogap, + wave_check); } if (feof(fp)) fclose(fp); @@ -283,7 +315,8 @@ err(EX_IOERR, "fgets(%s)", file_buf); } else - add_track(argv[arg], block_size, block_type, nogap); + add_track(argv[arg], block_size, block_type, nogap, + wave_check); } if (notracks) { if (dvdrw && notracks > 1) @@ -319,8 +352,42 @@ exit(EX_OK); } +#define BYTES2ULONG(b) ((u_int32_t) \ + (((b)[0] & 0xff) | \ + ((b)[1] << 8 & 0xff00) | \ + ((b)[2] << 16 & 0xff0000) | \ + ((b)[3] << 24 & 0xff000000))) + +#define BYTES2USHORT(b) ((u_int16_t) \ + (((b)[0] & 0xff) | \ + ((b)[1] << 8 & 0xff00))) + +u_int +is_wavefile(char *name, int file, int block_type) +{ + char *ext; + u_int8_t hdr[WAVE_HEADER_SIZE]; + + ext = strrchr(name, '.'); + if (block_type == CDR_DB_RAW && ext != NULL + && !strcasecmp(ext, WAVE_VALID_EXT)) { + if (read(file, &hdr, WAVE_HEADER_SIZE) == WAVE_HEADER_SIZE + && !strncmp((char *)hdr, RIFF_MAGIC, strlen(RIFF_MAGIC)) + && !strncmp((char *)hdr + 8, WAVE_MAGIC, strlen(WAVE_MAGIC)) + && !strncmp((char *)hdr + 12, FMT_MAGIC, strlen(FMT_MAGIC)) + && !strncmp((char *)hdr + 36, DATA_MAGIC, strlen(DATA_MAGIC)) + && BYTES2USHORT(hdr + 22) == WAVE_VALID_CHANNELS + && BYTES2ULONG(hdr + 24) == WAVE_VALID_RATE + && BYTES2USHORT(hdr + 34) == WAVE_VALID_SAMPLE) + return WAVE_HEADER_SIZE; + else + lseek(file, 0, SEEK_SET); + } + return 0; +} + void -add_track(char *name, int block_size, int block_type, int nogap) +add_track(char *name, int block_size, int block_type, int nogap, int wave_check) { struct stat sb; int file; @@ -343,18 +410,18 @@ if (file == STDIN_FILENO) tracks[notracks].file_size = -1; else - tracks[notracks].file_size = sb.st_size; + tracks[notracks].file_size = (u_int)sb.st_size + - ((wave_check && (u_int)sb.st_size > WAVE_HEADER_SIZE) + ? is_wavefile(name, file, block_type) + : 0); tracks[notracks].block_size = block_size; tracks[notracks].block_type = block_type; - if (nogap && notracks) + if (notracks && (nogap || + (tracks[notracks - (notracks > 0)].block_type == block_type))) tracks[notracks].pregap = 0; - else { - if (tracks[notracks - (notracks > 0)].block_type == block_type) - tracks[notracks].pregap = 150; - else - tracks[notracks].pregap = 255; - } + else + tracks[notracks].pregap = 150; if (verbose) { int pad = 0; @@ -379,6 +446,7 @@ struct cdr_cue_entry cue[100]; int format = CDR_SESS_CDROM; int addr, i, j = 0; + char buf[2352*BLOCKS]; int bt2ctl[16] = { 0x0, -1, -1, -1, -1, -1, -1, -1, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, -1, -1 }; @@ -391,6 +459,12 @@ if (verbose) fprintf(stderr, "next writeable LBA %d\n", addr); + if (addr != -150) { + addr = -150; + if (verbose) + fprintf(stderr, "resetting next writable LBA!\n"); + } + cue_ent(&cue[j++], bt2ctl[tracks[0].block_type], 0x01, 0x00, 0x0, (bt2df[tracks[0].block_type] & 0xf0) | (tracks[0].block_type < 8 ? 0x01 : 0x04), 0x00, addr); @@ -403,40 +477,20 @@ if (tracks[i].block_type >= CDR_DB_XA_MODE1) format = CDR_SESS_CDROM_XA; - if (i == 0) { - addr += tracks[i].pregap; - tracks[i].addr = addr; - - cue_ent(&cue[j++], bt2ctl[tracks[i].block_type], - 0x01, i+1, 0x1, bt2df[tracks[i].block_type], + if (tracks[i].pregap) { + cue_ent(&cue[j++],bt2ctl[tracks[i].block_type], + 0x01, i+1, 0x0, + bt2df[tracks[i].block_type], 0x00, addr); - - } - else { - if (tracks[i].pregap) { - if (tracks[i].block_type > 0x7) { - cue_ent(&cue[j++],bt2ctl[tracks[i].block_type], - 0x01, i+1, 0x0, - (bt2df[tracks[i].block_type] & 0xf0) | - (tracks[i].block_type < 8 ? 0x01 :0x04), - 0x00, addr); - } - else - cue_ent(&cue[j++],bt2ctl[tracks[i].block_type], - 0x01, i+1, 0x0, - bt2df[tracks[i].block_type], - 0x00, addr); - } - tracks[i].addr = tracks[i - 1].addr + - roundup_blocks(&tracks[i - 1]); - - cue_ent(&cue[j++], bt2ctl[tracks[i].block_type], - 0x01, i+1, 0x1, bt2df[tracks[i].block_type], - 0x00, addr + tracks[i].pregap); - - if (tracks[i].block_type > 0x7) - addr += tracks[i].pregap; + addr += tracks[i].pregap; } + tracks[i].addr = addr; + if (verbose) + fprintf(stderr, "track %d: addr=%d pregap=%d\n", + i+1, tracks[i].addr, tracks[i].pregap); + cue_ent(&cue[j++], bt2ctl[tracks[i].block_type], + 0x01, i+1, 0x1, bt2df[tracks[i].block_type], + 0x00, addr); addr += roundup_blocks(&tracks[i]); } @@ -464,7 +518,45 @@ if (ioctl(fd, CDRIOCSENDCUE, &sheet) < 0) err(EX_IOERR, "ioctl(CDRIOCSENDCUE)"); + bzero(buf, sizeof(buf)); for (i = 0; i < notracks; i++) { + if (tracks[i].pregap > 0) { + int total, write_size, res, retry_pregap; + + if (ioctl(fd, CDRIOCSETBLOCKSIZE, &tracks[i].block_size) < 0) + err(EX_IOERR, "ioctl(CDRIOCSETBLOCKSIZE)"); + if (lseek(fd, (tracks[i].addr - tracks[i].pregap) * + tracks[i].block_size, SEEK_SET) == -1) + err(EX_IOERR, "lseek"); + total = tracks[i].pregap * tracks[i].block_size; + if (i == 0 && (tracks[i].addr - tracks[i].pregap) < 0) + retry_pregap = total; + else + retry_pregap = -1; + if (verbose) + fprintf(stderr, + "writing pregap addr = %d total = %d blocks / %d bytes\n", + tracks[i].addr - tracks[i].pregap, + tracks[i].pregap, total); + while (total > 0) { + write_size = MIN(tracks[i].block_size * BLOCKS, total); + if ((res = write(fd, buf, write_size)) != write_size) { + /* XXX workaround for FreeBSD 5+ GEOM */ + if (res == -1 && retry_pregap == total) { + if (lseek(fd, tracks[i].addr * tracks[i].block_size, + SEEK_SET) == -1) + err(EX_IOERR, "lseek"); + retry_pregap = -1; + continue; + } + fprintf(stderr, + "pregap: only wrote %d of %d bytes err=%d\n", + res, write_size, errno); + break; + } + total -= write_size; + } + } if (write_file(fd, &tracks[i])) err(EX_IOERR, "write_file"); }