www.pudn.com > cdrecord.zip > drv_simul.c


/* @(#)drv_simul.c	1.4 98/09/05 Copyright 1998 J. Schilling */
#ifndef lint
static	char sccsid[] =
	"@(#)drv_simul.c	1.4 98/09/05 Copyright 1998 J. Schilling";
#endif
/*
 *	Simulation device driver
 *
 *	Copyright (c) 1998 J. Schilling
 */
/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * 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, 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#define	DEBUG
#include 

#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 


#include "cdrecord.h"

extern	int	silent;
extern	int	verbose;
extern	int	lverbose;

LOCAL	int	simul_load		__PR((void));
LOCAL	int	simul_unload		__PR((void));
LOCAL	cdr_t	*identify_simul		__PR((cdr_t *, struct scsi_inquiry *));
LOCAL	int	getdisktype_simul	__PR((cdr_t *dp, dstat_t *dsp));
LOCAL	int	speed_select_simul	__PR((int speed, int dummy));
LOCAL	int	next_wr_addr_simul	__PR((int track, track_t *trackp, long *ap));
LOCAL	int	cdr_write_simul		__PR((caddr_t bp, long sectaddr, long size, int blocks, BOOL islast));
LOCAL	int	open_track_simul	__PR((cdr_t *dp, int track, track_t *trackp));
LOCAL	int	close_track_simul	__PR((int track, track_t *trackp));
LOCAL	int	open_session_simul	__PR((int tracks, track_t *trackp, int toctype, int multi));
LOCAL	int	fixate_simul		__PR((int onp, int dummy, int toctype, int tracks, track_t *trackp));
LOCAL	void	tv_sub			__PR((struct timeval *tvp1, struct timeval *tvp2));

LOCAL int
simul_load()
{
	return (0);
}

LOCAL int
simul_unload()
{
	return (0);
}

cdr_t	cdr_cdr_simul = {
	0,
	CDR_TAO|CDR_DAO|CDR_PACKET,
	"cdr_simul",
	"simulation CD-R driver for timing/speed tests",
	0,
	identify_simul,
	drive_attach,
	getdisktype_simul,
	simul_load,
	simul_unload,
	recovery_needed,
	recover,
	speed_select_simul,
	select_secsize,
	next_wr_addr_simul,
	reserve_track,
	cdr_write_simul,
	open_track_simul,
	close_track_simul,
	open_session_simul,
	cmd_dummy,
	read_session_offset,
	fixate_simul,
	blank_dummy,
};

cdr_t	cdr_dvd_simul = {
	0,
	CDR_TAO|CDR_DAO|CDR_PACKET,
	"dvd_simul",
	"simulation DVD-R driver for timing/speed tests",
	0,
	identify_simul,
	drive_attach,
	getdisktype_simul,
	simul_load,
	simul_unload,
	recovery_needed,
	recover,
	speed_select_simul,
	select_secsize,
	next_wr_addr_simul,
	reserve_track,
	cdr_write_simul,
	open_track_simul,
	close_track_simul,
	open_session_simul,
	cmd_dummy,
	read_session_offset,
	fixate_simul,
	blank_dummy,
};

LOCAL cdr_t *
identify_simul(dp, ip)
	cdr_t			*dp;
	struct scsi_inquiry	*ip;
{
	return (dp);
}

LOCAL	int	simul_speed;
LOCAL	int	simul_dummy;
LOCAL	int	simul_isdvd;
LOCAL	int	simul_bufsize = 1024;
LOCAL	Uint	sleep_rest;
LOCAL	Uint	sleep_max;
LOCAL	Uint	sleep_min;

LOCAL int
getdisktype_simul(dp, dsp)
	cdr_t	*dp;
	dstat_t	*dsp;
{
	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 */
		simul_isdvd = TRUE;
	}
	return (drive_getdisktype(dp, dsp));
}


LOCAL int
speed_select_simul(speed, dummy)
	int	speed;
	int	dummy;
{
	long	val;
	char	*p;

	simul_speed = speed;
	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;
	if (lverbose) {
		printf("Simulation drive buffer size: %d KB\n", simul_bufsize);
		printf("Mamimum reserve time in drive buffer: %d.%3.3d ms\n",
					sleep_max / 1000,
					sleep_max % 1000);
	}
	return (0);
}

LOCAL int
next_wr_addr_simul(track, trackp, ap)
	int	track;
	track_t	*trackp;
	long	*ap;
{
	if (ap)
		*ap = 0L;
	return (0);
}

LOCAL int
cdr_write_simul(bp, sectaddr, size, blocks, islast)
	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");

	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
	 */
	sleep_time = 1000000 * blocks / 75 / simul_speed;
	sleep_time += sleep_rest;
	if (sleep_time > sleep_max) {
		int	mod;

		sleep_rest = sleep_max;
		sleep_time -= sleep_rest;
		mod = sleep_time % 20000;
		sleep_rest += mod;
		sleep_time -= mod;
		if (sleep_time > 0)
			usleep(sleep_time);
	} else {
		sleep_rest = sleep_time;
	}

	gettimeofday(&tv2, (struct timezone *)0);
	return (size);
}

LOCAL int
open_track_simul(dp, track, trackp)
	cdr_t	*dp;
	int	track;
	track_t *trackp;
{
	sleep_min = 999 * 1000000;
	return (0);
}

LOCAL int
close_track_simul(track, trackp)
	int	track;
	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);
}

LOCAL int
open_session_simul(tracks, trackp, toctype, multi)
	int	tracks;
	track_t	*trackp;
	int	toctype;
	int	multi;
{
	return (0);
}

LOCAL int
fixate_simul(onp, dummy, toctype, tracks, trackp)
	int	onp;
	int	dummy;
	int	toctype;
	int	tracks;
	track_t	*trackp;
{
	return (0);
}

LOCAL void
tv_sub(tvp1, tvp2)
	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;
	}
}