diff options
Diffstat (limited to 'wodim/drv_simul.c')
-rw-r--r-- | wodim/drv_simul.c | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/wodim/drv_simul.c b/wodim/drv_simul.c new file mode 100644 index 0000000..f7f7e06 --- /dev/null +++ b/wodim/drv_simul.c @@ -0,0 +1,393 @@ +/* + * 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. + * + */ + +/* @(#)drv_simul.c 1.48 05/05/16 Copyright 1998-2005 J. Schilling */ +/* + * Simulation device driver + * + * Copyright (c) 1998-2005 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. + */ + +#ifndef DEBUG +#define DEBUG +#endif +#include <mconfig.h> + +#include <stdio.h> +#include <standard.h> +#include <stdxlib.h> +#include <unixstd.h> +#include <errno.h> +#include <strdefs.h> +#include <timedefs.h> +#include <utypes.h> +#include <btorder.h> +#include <schily.h> + +/*#include <usalio.h>*/ +#include <usal/scsidefs.h> +#include <usal/scsireg.h> +#include <usal/scsitransp.h> + +#include <libport.h> + +#include "wodim.h" + +extern int silent; +extern int verbose; +extern int lverbose; + +static int simul_load(SCSI *usalp, cdr_t *); +static int simul_unload(SCSI *usalp, cdr_t *); +static cdr_t *identify_simul(SCSI *usalp, cdr_t *, struct scsi_inquiry *); +static int init_simul(SCSI *usalp, cdr_t *dp); +static int getdisktype_simul(SCSI *usalp, cdr_t *dp); +static int speed_select_simul(SCSI *usalp, cdr_t *dp, int *speedp); +static int next_wr_addr_simul(SCSI *usalp, track_t *trackp, long *ap); +static int cdr_write_simul(SCSI *usalp, caddr_t bp, long sectaddr, long size, + int blocks, BOOL islast); +static int open_track_simul(SCSI *usalp, cdr_t *dp, track_t *trackp); +static int close_track_simul(SCSI *usalp, cdr_t *dp, track_t *trackp); +static int open_session_simul(SCSI *usalp, cdr_t *dp, track_t *trackp); +static int fixate_simul(SCSI *usalp, cdr_t *dp, track_t *trackp); +static void tv_sub(struct timeval *tvp1, struct timeval *tvp2); + +static int simul_load(SCSI *usalp, cdr_t *dp) +{ + return (0); +} + +static int simul_unload(SCSI *usalp, cdr_t *dp) +{ + return (0); +} + +cdr_t cdr_cdr_simul = { + 0, 0, + CDR_TAO|CDR_SAO|CDR_PACKET|CDR_RAW|CDR_RAW16|CDR_RAW96P|CDR_RAW96R|CDR_SRAW96P|CDR_SRAW96R|CDR_TRAYLOAD|CDR_SIMUL, + CDR_CDRW_ALL, + 40, 372, + "cdr_simul", + "simulation CD-R driver for timing/speed tests", + 0, + (dstat_t *)0, + identify_simul, + drive_attach, + init_simul, + getdisktype_simul, + simul_load, + simul_unload, + buf_dummy, + cmd_dummy, /* recovery_needed */ + (int(*)(SCSI *, cdr_t *, int))cmd_dummy, /* recover */ + speed_select_simul, + select_secsize, + next_wr_addr_simul, + (int(*)(SCSI *, Ulong))cmd_ill, /* reserve_track */ + cdr_write_simul, + (int(*)(track_t *, void *, BOOL))cmd_dummy, /* gen_cue */ + (int(*)(SCSI *usalp, cdr_t *, track_t *))cmd_dummy, /* send_cue */ + (int(*)(SCSI *, cdr_t *, track_t *))cmd_dummy, /* leadin */ + open_track_simul, + close_track_simul, + open_session_simul, + cmd_dummy, + cmd_dummy, /* abort */ + read_session_offset, + fixate_simul, + cmd_dummy, /* stats */ + blank_dummy, + format_dummy, + (int(*)(SCSI *, caddr_t, int, int))NULL, /* no OPC */ + cmd_dummy, /* opt1 */ + cmd_dummy, /* opt2 */ +}; + +cdr_t cdr_dvd_simul = { + 0, 0, + CDR_TAO|CDR_SAO|CDR_PACKET|CDR_RAW|CDR_RAW16|CDR_RAW96P|CDR_RAW96R|CDR_SRAW96P|CDR_SRAW96R|CDR_DVD|CDR_TRAYLOAD|CDR_SIMUL, + CDR_CDRW_ALL, + 2, 1000, + "dvd_simul", + "simulation DVD-R driver for timing/speed tests", + 0, + (dstat_t *)0, + identify_simul, + drive_attach, + init_simul, + getdisktype_simul, + simul_load, + simul_unload, + buf_dummy, + cmd_dummy, /* recovery_needed */ + (int(*)(SCSI *, cdr_t *, int))cmd_dummy, /* recover */ + speed_select_simul, + select_secsize, + next_wr_addr_simul, + (int(*)(SCSI *, Ulong))cmd_ill, /* reserve_track */ + cdr_write_simul, + (int(*)(track_t *, void *, BOOL))cmd_dummy, /* gen_cue */ + (int(*)(SCSI *usalp, cdr_t *, track_t *))cmd_dummy, /* send_cue */ + (int(*)(SCSI *, cdr_t *, track_t *))cmd_dummy, /* leadin */ + open_track_simul, + close_track_simul, + open_session_simul, + cmd_dummy, + cmd_dummy, /* abort */ + read_session_offset, + fixate_simul, + cmd_dummy, /* stats */ + blank_dummy, + format_dummy, + (int(*)(SCSI *, caddr_t, int, int))NULL, /* no OPC */ + cmd_dummy, /* opt1 */ + cmd_dummy, /* opt2 */ +}; + +static cdr_t * +identify_simul(SCSI *usalp, cdr_t *dp, struct scsi_inquiry *ip) +{ + return (dp); +} + +static long simul_nwa; +static int simul_speed = 1; +static int simul_dummy; +static int simul_isdvd; +static int simul_bufsize = 1024; +static Uint sleep_rest; +static Uint sleep_max; +static Uint sleep_min; + +static int +init_simul(SCSI *usalp, cdr_t *dp) +{ + return (speed_select_simul(usalp, dp, NULL)); +} + +static int +getdisktype_simul(SCSI *usalp, cdr_t *dp) +{ + dstat_t *dsp = dp->cdr_dstat; + + if (strcmp(dp->cdr_drname, cdr_cdr_simul.cdr_drname) == 0) { + dsp->ds_maxblocks = 333000; + simul_isdvd = FALSE; + } else { + dsp->ds_maxblocks = 2464153; /* 4.7 GB */ +/* dsp->ds_maxblocks = 1927896;*/ /* 3.95 GB */ + dsp->ds_flags |= DSF_DVD; + simul_isdvd = TRUE; + } + return (drive_getdisktype(usalp, dp)); +} + + +static int +speed_select_simul(SCSI *usalp, cdr_t *dp, int *speedp) +{ + long val; + char *p; + BOOL dummy = (dp->cdr_cmdflags & F_DUMMY) != 0; + + if (speedp) + simul_speed = *speedp; + simul_dummy = dummy; + + if ((p = getenv("CDR_SIMUL_BUFSIZE")) != NULL) { + if (getnum(p, &val) == 1) + simul_bufsize = val / 1024; + } + + /* + * sleep_max is the time to empty the drive's buffer in µs. + * sector size is from 2048 bytes to 2352 bytes. + * If sector size is 2048 bytes, 1k takes 6.666 ms. + * If sector size is 2352 bytes, 1k takes 5.805 ms. + * We take the 6 ms as an average between both values. + * simul_bufsize is the number of kilobytes in drive buffer. + */ + sleep_max = 6 * 1000 * simul_bufsize / simul_speed; + + /* + * DVD single speed is 1385 * 1000 Bytes/s (676.27 sectors/s) + */ + if ((dp->cdr_flags & CDR_DVD) != 0) + sleep_max = 739 * simul_bufsize / simul_speed; + + if (lverbose) { + printf("Simulation drive buffer size: %d KB\n", simul_bufsize); + printf("Maximum reserve time in drive buffer: %d.%3.3d ms for speed %dx\n", + sleep_max / 1000, + sleep_max % 1000, + simul_speed); + } + return (0); +} + +static int +next_wr_addr_simul(SCSI *usalp, track_t *trackp, long *ap) +{ + /* + * This will most likely not 100% correct for TAO CDs + * but it is better than returning 0 in all cases. + */ + if (ap) + *ap = simul_nwa; + return (0); +} + + +static int +cdr_write_simul(SCSI *usalp, caddr_t bp /* address of buffer */, + long sectaddr /* disk address (sector) to put */, + long size /* number of bytes to transfer */, + int blocks /* sector count */, + BOOL islast /* last write for track */) +{ + Uint sleep_time; + Uint sleep_diff; + + struct timeval tv1; + static struct timeval tv2; + + if (lverbose > 1 && islast) + printf("\nWriting last record for this track.\n"); + + simul_nwa += blocks; + + gettimeofday(&tv1, (struct timezone *)0); + if (tv2.tv_sec != 0) { /* Already did gettimeofday(&tv2) */ + tv_sub(&tv1, &tv2); + if (sleep_rest != 0) { + sleep_diff = tv1.tv_sec * 1000000 + tv1.tv_usec; + + if (sleep_min > (sleep_rest - sleep_diff)) + sleep_min = (sleep_rest - sleep_diff); + + if (sleep_diff > sleep_rest) { + printf("Buffer underrun: actual delay was %d.%3.3d ms, max delay was %d.%3.3d ms.\n", + sleep_diff / 1000, + sleep_diff % 1000, + sleep_rest / 1000, + sleep_rest % 1000); + if (!simul_dummy) + return (-1); + } + /* + * If we spent time outside the write function + * subtract this time. + */ + sleep_diff = tv1.tv_sec * 1000000 + tv1.tv_usec; + if (sleep_rest >= sleep_diff) + sleep_rest -= sleep_diff; + else + sleep_rest = 0; + } + } + /* + * Speed 1 ist 150 Sektoren/s + * Bei DVD 767.27 Sektoren/s + */ + sleep_time = 1000000 * blocks / 75 / simul_speed; + if (simul_isdvd) + sleep_time = 1000000 * blocks / 676 / simul_speed; + + sleep_time += sleep_rest; + + if (sleep_time > sleep_max) { + int mod; + long rsleep; + + sleep_rest = sleep_max; + sleep_time -= sleep_rest; + mod = sleep_time % 20000; + sleep_rest += mod; + sleep_time -= mod; + if (sleep_time > 0) { + gettimeofday(&tv1, (struct timezone *)0); + usleep(sleep_time); + gettimeofday(&tv2, (struct timezone *)0); + tv2.tv_sec -= tv1.tv_sec; + tv2.tv_usec -= tv1.tv_usec; + rsleep = tv2.tv_sec * 1000000 + tv2.tv_usec; + sleep_rest -= rsleep - sleep_time; + } + } else { + sleep_rest = sleep_time; + } + + gettimeofday(&tv2, (struct timezone *)0); + return (size); +} + +static int +open_track_simul(SCSI *usalp, cdr_t *dp, track_t *trackp) +{ + sleep_min = 999 * 1000000; + return (0); +} + +static int +close_track_simul(SCSI *usalp, cdr_t *dp, track_t *trackp) +{ + if (lverbose) { + printf("Remaining reserve time in drive buffer: %d.%3.3d ms\n", + sleep_rest / 1000, + sleep_rest % 1000); + printf("Minimum reserve time in drive buffer: %d.%3.3d ms\n", + sleep_min / 1000, + sleep_min % 1000); + } + usleep(sleep_rest); + sleep_rest = 0; + return (0); +} + +static int +open_session_simul(SCSI *usalp, cdr_t *dp, track_t *trackp) +{ + simul_nwa = 0L; + return (0); +} + +static int +fixate_simul(SCSI *usalp, cdr_t *dp, track_t *trackp) +{ + return (0); +} + +static void +tv_sub(struct timeval *tvp1, struct timeval *tvp2) +{ + tvp1->tv_sec -= tvp2->tv_sec; + tvp1->tv_usec -= tvp2->tv_usec; + + while (tvp1->tv_usec < 0) { + tvp1->tv_usec += 1000000; + tvp1->tv_sec -= 1; + } +} |