2 * This file has been modified for the cdrkit suite.
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
13 /* @(#)drv_simul.c 1.48 05/05/16 Copyright 1998-2005 J. Schilling */
15 * Simulation device driver
17 * Copyright (c) 1998-2005 J. Schilling
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License version 2
22 * as published by the Free Software Foundation.
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
29 * You should have received a copy of the GNU General Public License along with
30 * this program; see the file COPYING. If not, write to the Free Software
31 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
50 /*#include <usalio.h>*/
51 #include <usal/scsidefs.h>
52 #include <usal/scsireg.h>
53 #include <usal/scsitransp.h>
63 static int simul_load(SCSI *usalp, cdr_t *);
64 static int simul_unload(SCSI *usalp, cdr_t *);
65 static cdr_t *identify_simul(SCSI *usalp, cdr_t *, struct scsi_inquiry *);
66 static int init_simul(SCSI *usalp, cdr_t *dp);
67 static int getdisktype_simul(SCSI *usalp, cdr_t *dp);
68 static int speed_select_simul(SCSI *usalp, cdr_t *dp, int *speedp);
69 static int next_wr_addr_simul(SCSI *usalp, track_t *trackp, long *ap);
70 static int cdr_write_simul(SCSI *usalp, caddr_t bp, long sectaddr, long size,
71 int blocks, BOOL islast);
72 static int open_track_simul(SCSI *usalp, cdr_t *dp, track_t *trackp);
73 static int close_track_simul(SCSI *usalp, cdr_t *dp, track_t *trackp);
74 static int open_session_simul(SCSI *usalp, cdr_t *dp, track_t *trackp);
75 static int fixate_simul(SCSI *usalp, cdr_t *dp, track_t *trackp);
76 static void tv_sub(struct timeval *tvp1, struct timeval *tvp2);
78 static int simul_load(SCSI *usalp, cdr_t *dp)
83 static int simul_unload(SCSI *usalp, cdr_t *dp)
88 cdr_t cdr_cdr_simul = {
90 CDR_TAO|CDR_SAO|CDR_PACKET|CDR_RAW|CDR_RAW16|CDR_RAW96P|CDR_RAW96R|CDR_SRAW96P|CDR_SRAW96R|CDR_TRAYLOAD|CDR_SIMUL,
94 "simulation CD-R driver for timing/speed tests",
104 cmd_dummy, /* recovery_needed */
105 (int(*)(SCSI *, cdr_t *, int))cmd_dummy, /* recover */
109 (int(*)(SCSI *, Ulong))cmd_ill, /* reserve_track */
111 (int(*)(track_t *, void *, BOOL))cmd_dummy, /* gen_cue */
112 (int(*)(SCSI *usalp, cdr_t *, track_t *))cmd_dummy, /* send_cue */
113 (int(*)(SCSI *, cdr_t *, track_t *))cmd_dummy, /* leadin */
118 cmd_dummy, /* abort */
121 cmd_dummy, /* stats */
124 (int(*)(SCSI *, caddr_t, int, int))NULL, /* no OPC */
125 cmd_dummy, /* opt1 */
126 cmd_dummy, /* opt2 */
129 cdr_t cdr_dvd_simul = {
131 CDR_TAO|CDR_SAO|CDR_PACKET|CDR_RAW|CDR_RAW16|CDR_RAW96P|CDR_RAW96R|CDR_SRAW96P|CDR_SRAW96R|CDR_DVD|CDR_TRAYLOAD|CDR_SIMUL,
135 "simulation DVD-R driver for timing/speed tests",
145 cmd_dummy, /* recovery_needed */
146 (int(*)(SCSI *, cdr_t *, int))cmd_dummy, /* recover */
150 (int(*)(SCSI *, Ulong))cmd_ill, /* reserve_track */
152 (int(*)(track_t *, void *, BOOL))cmd_dummy, /* gen_cue */
153 (int(*)(SCSI *usalp, cdr_t *, track_t *))cmd_dummy, /* send_cue */
154 (int(*)(SCSI *, cdr_t *, track_t *))cmd_dummy, /* leadin */
159 cmd_dummy, /* abort */
162 cmd_dummy, /* stats */
165 (int(*)(SCSI *, caddr_t, int, int))NULL, /* no OPC */
166 cmd_dummy, /* opt1 */
167 cmd_dummy, /* opt2 */
171 identify_simul(SCSI *usalp, cdr_t *dp, struct scsi_inquiry *ip)
176 static long simul_nwa;
177 static int simul_speed = 1;
178 static int simul_dummy;
179 static int simul_isdvd;
180 static int simul_bufsize = 1024;
181 static Uint sleep_rest;
182 static Uint sleep_max;
183 static Uint sleep_min;
186 init_simul(SCSI *usalp, cdr_t *dp)
188 return (speed_select_simul(usalp, dp, NULL));
192 getdisktype_simul(SCSI *usalp, cdr_t *dp)
194 dstat_t *dsp = dp->cdr_dstat;
196 if (strcmp(dp->cdr_drname, cdr_cdr_simul.cdr_drname) == 0) {
197 dsp->ds_maxblocks = 333000;
200 dsp->ds_maxblocks = 2464153; /* 4.7 GB */
201 /* dsp->ds_maxblocks = 1927896;*/ /* 3.95 GB */
202 dsp->ds_flags |= DSF_DVD;
205 return (drive_getdisktype(usalp, dp));
210 speed_select_simul(SCSI *usalp, cdr_t *dp, int *speedp)
214 BOOL dummy = (dp->cdr_cmdflags & F_DUMMY) != 0;
217 simul_speed = *speedp;
220 if ((p = getenv("CDR_SIMUL_BUFSIZE")) != NULL) {
221 if (getnum(p, &val) == 1)
222 simul_bufsize = val / 1024;
226 * sleep_max is the time to empty the drive's buffer in µs.
227 * sector size is from 2048 bytes to 2352 bytes.
228 * If sector size is 2048 bytes, 1k takes 6.666 ms.
229 * If sector size is 2352 bytes, 1k takes 5.805 ms.
230 * We take the 6 ms as an average between both values.
231 * simul_bufsize is the number of kilobytes in drive buffer.
233 sleep_max = 6 * 1000 * simul_bufsize / simul_speed;
236 * DVD single speed is 1385 * 1000 Bytes/s (676.27 sectors/s)
238 if ((dp->cdr_flags & CDR_DVD) != 0)
239 sleep_max = 739 * simul_bufsize / simul_speed;
242 printf("Simulation drive buffer size: %d KB\n", simul_bufsize);
243 printf("Maximum reserve time in drive buffer: %d.%3.3d ms for speed %dx\n",
252 next_wr_addr_simul(SCSI *usalp, track_t *trackp, long *ap)
255 * This will most likely not 100% correct for TAO CDs
256 * but it is better than returning 0 in all cases.
265 cdr_write_simul(SCSI *usalp, caddr_t bp /* address of buffer */,
266 long sectaddr /* disk address (sector) to put */,
267 long size /* number of bytes to transfer */,
268 int blocks /* sector count */,
269 BOOL islast /* last write for track */)
275 static struct timeval tv2;
277 if (lverbose > 1 && islast)
278 printf("\nWriting last record for this track.\n");
282 gettimeofday(&tv1, (struct timezone *)0);
283 if (tv2.tv_sec != 0) { /* Already did gettimeofday(&tv2) */
285 if (sleep_rest != 0) {
286 sleep_diff = tv1.tv_sec * 1000000 + tv1.tv_usec;
288 if (sleep_min > (sleep_rest - sleep_diff))
289 sleep_min = (sleep_rest - sleep_diff);
291 if (sleep_diff > sleep_rest) {
292 printf("
\aBuffer underrun: actual delay was %d.%3.3d ms, max delay was %d.%3.3d ms.\n",
301 * If we spent time outside the write function
302 * subtract this time.
304 sleep_diff = tv1.tv_sec * 1000000 + tv1.tv_usec;
305 if (sleep_rest >= sleep_diff)
306 sleep_rest -= sleep_diff;
312 * Speed 1 ist 150 Sektoren/s
313 * Bei DVD 767.27 Sektoren/s
315 sleep_time = 1000000 * blocks / 75 / simul_speed;
317 sleep_time = 1000000 * blocks / 676 / simul_speed;
319 sleep_time += sleep_rest;
321 if (sleep_time > sleep_max) {
325 sleep_rest = sleep_max;
326 sleep_time -= sleep_rest;
327 mod = sleep_time % 20000;
330 if (sleep_time > 0) {
331 gettimeofday(&tv1, (struct timezone *)0);
333 gettimeofday(&tv2, (struct timezone *)0);
334 tv2.tv_sec -= tv1.tv_sec;
335 tv2.tv_usec -= tv1.tv_usec;
336 rsleep = tv2.tv_sec * 1000000 + tv2.tv_usec;
337 sleep_rest -= rsleep - sleep_time;
340 sleep_rest = sleep_time;
343 gettimeofday(&tv2, (struct timezone *)0);
348 open_track_simul(SCSI *usalp, cdr_t *dp, track_t *trackp)
350 sleep_min = 999 * 1000000;
355 close_track_simul(SCSI *usalp, cdr_t *dp, track_t *trackp)
358 printf("Remaining reserve time in drive buffer: %d.%3.3d ms\n",
361 printf("Minimum reserve time in drive buffer: %d.%3.3d ms\n",
371 open_session_simul(SCSI *usalp, cdr_t *dp, track_t *trackp)
378 fixate_simul(SCSI *usalp, cdr_t *dp, track_t *trackp)
384 tv_sub(struct timeval *tvp1, struct timeval *tvp2)
386 tvp1->tv_sec -= tvp2->tv_sec;
387 tvp1->tv_usec -= tvp2->tv_usec;
389 while (tvp1->tv_usec < 0) {
390 tvp1->tv_usec += 1000000;