/*
* This file has been modified for the cdrkit suite.
*
* The behaviour and appearence of the program code below can differ to a major
* extent from the version distributed by the original author(s).
*
* For details, see Changelog file distributed with the cdrkit package. If you
* received this file from another source then ask the distributing person for
* a log of modifications.
*
*/
/* @(#)wm_packet.c 1.25 04/03/01 Copyright 1995, 1997, 2001-2004 J. Schilling */
/*
* CDR write method abtraction layer
* packet writing intercace routines
*
* Copyright (c) 1995, 1997, 2001-2004 J. Schilling
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; see the file COPYING. If not, write to the Free Software
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <mconfig.h>
#include <stdio.h>
#include <stdxlib.h>
#include <unixstd.h>
#include <timedefs.h>
#include <standard.h>
#include <utypes.h>
#include <schily.h>
#include <usal/scsitransp.h>
#include "wodim.h"
#include "xio.h"
extern int debug;
extern int verbose;
extern int lverbose;
extern char *buf; /* The transfer buffer */
int write_packet_data(SCSI *usalp, cdr_t *dp, track_t *trackp);
int
write_packet_data(SCSI *usalp, cdr_t *dp, track_t *trackp)
{
int track = trackp->trackno;
int f = -1;
int isaudio;
long startsec;
Llong bytes_read = 0;
Llong bytes = 0;
Llong savbytes = 0;
int count;
Llong tracksize;
int secsize;
int secspt;
int bytespt;
long amount;
int pad;
int retried;
long nextblock;
int bytes_to_read;
BOOL neednl = FALSE;
BOOL islast = FALSE;
char *bp = buf;
struct timeval tlast;
struct timeval tcur;
float secsps = 75.0;
long bsize;
long bfree;
#define BCAP
#ifdef BCAP
int per;
#ifdef XBCAP
int oper = -1;
#endif
#endif
if (dp->cdr_dstat->ds_flags & DSF_DVD)
secsps = 676.27;
usalp->silent++;
if ((*dp->cdr_buffer_cap)(usalp, &bsize, &bfree) < 0)
bsize = -1L;
if (bsize == 0) /* If we have no (known) buffer, we cannot */
bsize = -1L; /* retrieve the buffer fill ratio */
else
dp->cdr_dstat->ds_buflow = 0;
usalp->silent--;
if (trackp->xfp != NULL)
f = xfileno(trackp->xfp);
isaudio = is_audio(trackp);
tracksize = trackp->tracksize;
startsec = trackp->trackstart;
secsize = trackp->secsize;
secspt = trackp->secspt;
bytespt = secsize * secspt;
pad = !isaudio && is_pad(trackp); /* Pad only data tracks */
if (debug) {
printf("secsize:%d secspt:%d bytespt:%d audio:%d pad:%d\n",
secsize, secspt, bytespt, isaudio, pad);
}
if (lverbose) {
if (tracksize > 0)
printf("\rTrack %02d: 0 of %4lld MB written.",
track, tracksize >> 20);
else
printf("\rTrack %02d: 0 MB written.", track);
flush();
neednl = TRUE;
}
gettimeofday(&tlast, (struct timezone *)0);
do {
bytes_to_read = bytespt;
if (tracksize > 0) {
if ((tracksize - bytes_read) > bytespt)
bytes_to_read = bytespt;
else
bytes_to_read = tracksize - bytes_read;
}
/* XXX next wr addr ??? */
count = get_buf(f, trackp, startsec, &bp, bytes_to_read);
if (count < 0)
comerr("read error on input file\n");
if (count == 0)
break;
bytes_read += count;
if (tracksize >= 0 && bytes_read >= tracksize) {
count -= bytes_read - tracksize;
if (trackp->padsecs == 0 || (bytes_read/secsize) >= 300)
islast = TRUE;
}
if (count < bytespt) {
if (debug) {
printf("\nNOTICE: reducing block size for last record.\n");
neednl = FALSE;
}
if ((amount = count % secsize) != 0) {
amount = secsize - amount;
fillbytes(&bp[count], amount, '\0');
count += amount;
printf("\nWARNING: padding up to secsize.\n");
neednl = FALSE;
}
if (is_packet(trackp) && trackp->pktsize > 0) {
if (count < bytespt) {
amount = bytespt - count;
count += amount;
printf("\nWARNING: padding remainder of packet.\n");
neednl = FALSE;
}
}
bytespt = count;
secspt = count / secsize;
if (trackp->padsecs == 0 || (bytes_read/secsize) >= 300)
islast = TRUE;
}
retried = 0;
retry:
/* XXX Fixed-packet writes can be very slow*/
if (is_packet(trackp) && trackp->pktsize > 0)
usal_settimeout(usalp, 100);
/* XXX */
if (is_packet(trackp) && trackp->pktsize == 0) {
if ((*dp->cdr_next_wr_address)(usalp, trackp, &nextblock) == 0) {
/*
* Some drives (e.g. Ricoh MPS6201S) do not
* increment the Next Writable Address value to
* point to the beginning of a new packet if
* their write buffer has underflowed.
*/
if (retried && nextblock == startsec) {
startsec += 7;
} else {
startsec = nextblock;
}
}
}
amount = write_secs(usalp, dp, bp, startsec, bytespt, secspt, islast);
if (amount < 0) {
if (is_packet(trackp) && trackp->pktsize == 0 && !retried) {
printf("%swrite track data: error after %lld bytes, retry with new packet\n",
neednl?"\n":"", bytes);
retried = 1;
neednl = FALSE;
goto retry;
}
printf("%swrite track data: error after %lld bytes\n",
neednl?"\n":"", bytes);
return (-1);
}
bytes += amount;
startsec += amount / secsize;
if (lverbose && (bytes >= (savbytes + 0x100000))) {
int fper;
int nsecs = (bytes - savbytes) / secsize;
float fspeed;
gettimeofday(&tcur, (struct timezone *)0);
printf("\rTrack %02d: %4lld", track, bytes >> 20);
if (tracksize > 0)
printf(" of %4lld MB", tracksize >> 20);
else
printf(" MB");
printf(" written");
fper = fifo_percent(TRUE);
if (fper >= 0)
printf(" (fifo %3d%%)", fper);
#ifdef BCAP
if (bsize > 0) { /* buffer size known */
usalp->silent++;
per = (*dp->cdr_buffer_cap)(usalp, (long *)0, &bfree);
usalp->silent--;
if (per >= 0) {
per = 100*(bsize - bfree) / bsize;
if (per < 5)
dp->cdr_dstat->ds_buflow++;
if (per < (int)dp->cdr_dstat->ds_minbuf &&
(startsec*secsize) > bsize) {
dp->cdr_dstat->ds_minbuf = per;
}
printf(" [buf %3d%%]", per);
#ifdef BCAPDBG
printf(" %3ld %3ld", bsize >> 10, bfree >> 10);
#endif
}
}
#endif
tlast.tv_sec = tcur.tv_sec - tlast.tv_sec;
tlast.tv_usec = tcur.tv_usec - tlast.tv_usec;
while (tlast.tv_usec < 0) {
tlast.tv_usec += 1000000;
tlast.tv_sec -= 1;
}
fspeed = (nsecs / secsps) /
(tlast.tv_sec * 1.0 + tlast.tv_usec * 0.000001);
if (fspeed > 999.0)
fspeed = 999.0;
printf(" %5.1fx", fspeed);
printf(".");
savbytes = (bytes >> 20) << 20;
flush();
neednl = TRUE;
tlast = tcur;
}
} while (tracksize < 0 || bytes_read < tracksize);
if ((bytes / secsize) < 300) {
if ((trackp->padsecs + (bytes / secsize)) < 300)
trackp->padsecs = 300 - (bytes / secsize);
}
if (trackp->padsecs > 0) {
Llong padbytes;
/*
* pad_track() is based on secsize. Compute the amount of bytes
* assumed by pad_track().
*/
padbytes = (Llong)trackp->padsecs * secsize;
if (neednl) {
printf("\n");
neednl = FALSE;
}
if ((padbytes >> 20) > 0) {
neednl = TRUE;
} else if (lverbose) {
printf("Track %02d: writing %3lld KB of pad data.\n",
track, (Llong)(padbytes >> 10));
neednl = FALSE;
}
pad_track(usalp, dp, trackp, startsec, padbytes,
TRUE, &savbytes);
bytes += savbytes;
startsec += savbytes / secsize;
}
printf("%sTrack %02d: Total bytes read/written: %lld/%lld (%lld sectors).\n",
neednl?"\n":"", track, bytes_read, bytes, bytes/secsize);
return (0);
}