summaryrefslogtreecommitdiff
path: root/wodim/drv_simul.c
diff options
context:
space:
mode:
Diffstat (limited to 'wodim/drv_simul.c')
-rw-r--r--wodim/drv_simul.c393
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;
+ }
+}