Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / wodim / wm_packet.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
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).
6  *
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.
10  *
11  */
12
13 /* @(#)wm_packet.c      1.25 04/03/01 Copyright 1995, 1997, 2001-2004 J. Schilling */
14 /*
15  *      CDR write method abtraction layer
16  *      packet writing intercace routines
17  *
18  *      Copyright (c) 1995, 1997, 2001-2004 J. Schilling
19  */
20 /*
21  * This program is free software; you can redistribute it and/or modify
22  * it under the terms of the GNU General Public License version 2
23  * as published by the Free Software Foundation.
24  *
25  * This program is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28  * GNU General Public License for more details.
29  *
30  * You should have received a copy of the GNU General Public License along with
31  * this program; see the file COPYING.  If not, write to the Free Software
32  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
33  */
34
35 #include <mconfig.h>
36 #include <stdio.h>
37 #include <stdxlib.h>
38 #include <unixstd.h>
39 #include <timedefs.h>
40 #include <standard.h>
41 #include <utypes.h>
42 #include <schily.h>
43
44 #include <usal/scsitransp.h>
45 #include "wodim.h"
46 #include "xio.h"
47
48 extern  int     debug;
49 extern  int     verbose;
50 extern  int     lverbose;
51
52 extern  char    *buf;                   /* The transfer buffer */
53
54 int     write_packet_data(SCSI *usalp, cdr_t *dp, track_t *trackp);
55
56 int
57 write_packet_data(SCSI *usalp, cdr_t *dp, track_t *trackp)
58 {
59         int     track = trackp->trackno;
60         int     f = -1;
61         int     isaudio;
62         long    startsec;
63         Llong   bytes_read = 0;
64         Llong   bytes   = 0;
65         Llong   savbytes = 0;
66         int     count;
67         Llong   tracksize;
68         int     secsize;
69         int     secspt;
70         int     bytespt;
71         long    amount;
72         int     pad;
73         int     retried;
74         long    nextblock;
75         int     bytes_to_read;
76         BOOL    neednl  = FALSE;
77         BOOL    islast  = FALSE;
78         char    *bp     = buf;
79         struct timeval tlast;
80         struct timeval tcur;
81         float   secsps = 75.0;
82 long bsize;
83 long bfree;
84 #define BCAP
85 #ifdef  BCAP
86 int per;
87 #ifdef  XBCAP
88 int oper = -1;
89 #endif
90 #endif
91
92         if (dp->cdr_dstat->ds_flags & DSF_DVD)
93                 secsps = 676.27;
94
95         usalp->silent++;
96         if ((*dp->cdr_buffer_cap)(usalp, &bsize, &bfree) < 0)
97                 bsize = -1L;
98         if (bsize == 0)         /* If we have no (known) buffer, we cannot */
99                 bsize = -1L;    /* retrieve the buffer fill ratio          */
100         else
101                 dp->cdr_dstat->ds_buflow = 0;
102         usalp->silent--;
103
104         if (trackp->xfp != NULL)
105                 f = xfileno(trackp->xfp);
106
107         isaudio = is_audio(trackp);
108         tracksize = trackp->tracksize;
109         startsec = trackp->trackstart;
110
111         secsize = trackp->secsize;
112         secspt = trackp->secspt;
113         bytespt = secsize * secspt;
114
115         pad = !isaudio && is_pad(trackp);       /* Pad only data tracks */
116
117         if (debug) {
118                 printf("secsize:%d secspt:%d bytespt:%d audio:%d pad:%d\n",
119                         secsize, secspt, bytespt, isaudio, pad);
120         }
121
122         if (lverbose) {
123                 if (tracksize > 0)
124                         printf("\rTrack %02d:    0 of %4lld MB written.",
125                                 track, tracksize >> 20);
126                 else
127                         printf("\rTrack %02d:    0 MB written.", track);
128                 flush();
129                 neednl = TRUE;
130         }
131
132         gettimeofday(&tlast, (struct timezone *)0);
133         do {
134                 bytes_to_read = bytespt;
135                 if (tracksize > 0) {
136                         if ((tracksize - bytes_read) > bytespt)
137                                 bytes_to_read = bytespt;
138                         else
139                                 bytes_to_read = tracksize - bytes_read;
140                 }
141                                         /* XXX next wr addr ??? */
142                 count = get_buf(f, trackp, startsec, &bp, bytes_to_read);
143                 if (count < 0)
144                         comerr("read error on input file\n");
145                 if (count == 0)
146                         break;
147                 bytes_read += count;
148                 if (tracksize >= 0 && bytes_read >= tracksize) {
149                         count -= bytes_read - tracksize;
150                         if (trackp->padsecs == 0 || (bytes_read/secsize) >= 300)
151                                 islast = TRUE;
152                 }
153
154                 if (count < bytespt) {
155                         if (debug) {
156                                 printf("\nNOTICE: reducing block size for last record.\n");
157                                 neednl = FALSE;
158                         }
159
160                         if ((amount = count % secsize) != 0) {
161                                 amount = secsize - amount;
162                                 fillbytes(&bp[count], amount, '\0');
163                                 count += amount;
164                                 printf("\nWARNING: padding up to secsize.\n");
165                                 neednl = FALSE;
166                         }
167                         if (is_packet(trackp) && trackp->pktsize > 0) {
168                                 if (count < bytespt) {
169                                         amount = bytespt - count;
170                                         count += amount;
171                                         printf("\nWARNING: padding remainder of packet.\n");
172                                         neednl = FALSE;
173                                 }
174                         }
175                         bytespt = count;
176                         secspt = count / secsize;
177                         if (trackp->padsecs == 0 || (bytes_read/secsize) >= 300)
178                                 islast = TRUE;
179                 }
180
181                 retried = 0;
182                 retry:
183                 /* XXX Fixed-packet writes can be very slow*/
184                 if (is_packet(trackp) && trackp->pktsize > 0)
185                         usal_settimeout(usalp, 100);
186                 /* XXX */
187                 if (is_packet(trackp) && trackp->pktsize == 0) {
188                         if ((*dp->cdr_next_wr_address)(usalp, trackp, &nextblock) == 0) {
189                                 /*
190                                  * Some drives (e.g. Ricoh MPS6201S) do not
191                                  * increment the Next Writable Address value to
192                                  * point to the beginning of a new packet if
193                                  * their write buffer has underflowed.
194                                  */
195                                 if (retried && nextblock == startsec) {
196                                         startsec += 7;
197                                 } else {
198                                         startsec = nextblock;
199                                 }
200                         }
201                 }
202
203                 amount =  write_secs(usalp, dp, bp, startsec, bytespt, secspt, islast);
204                 if (amount < 0) {
205                         if (is_packet(trackp) && trackp->pktsize == 0 && !retried) {
206                                 printf("%swrite track data: error after %lld bytes, retry with new packet\n",
207                                         neednl?"\n":"", bytes);
208                                 retried = 1;
209                                 neednl = FALSE;
210                                 goto retry;
211                         }
212                         printf("%swrite track data: error after %lld bytes\n",
213                                                         neednl?"\n":"", bytes);
214                         return (-1);
215                 }
216                 bytes += amount;
217                 startsec += amount / secsize;
218
219                 if (lverbose && (bytes >= (savbytes + 0x100000))) {
220                         int     fper;
221                         int     nsecs = (bytes - savbytes) / secsize;
222                         float   fspeed;
223
224                         gettimeofday(&tcur, (struct timezone *)0);
225                         printf("\rTrack %02d: %4lld", track, bytes >> 20);
226                         if (tracksize > 0)
227                                 printf(" of %4lld MB", tracksize >> 20);
228                         else
229                                 printf(" MB");
230                         printf(" written");
231                         fper = fifo_percent(TRUE);
232                         if (fper >= 0)
233                                 printf(" (fifo %3d%%)", fper);
234 #ifdef  BCAP
235                         if (bsize > 0) {                        /* buffer size known */
236                                 usalp->silent++;
237                                 per = (*dp->cdr_buffer_cap)(usalp, (long *)0, &bfree);
238                                 usalp->silent--;
239                                 if (per >= 0) {
240                                         per = 100*(bsize - bfree) / bsize;
241                                         if (per < 5)
242                                                 dp->cdr_dstat->ds_buflow++;
243                                         if (per < (int)dp->cdr_dstat->ds_minbuf &&
244                                             (startsec*secsize) > bsize) {
245                                                 dp->cdr_dstat->ds_minbuf = per;
246                                         }
247                                         printf(" [buf %3d%%]", per);
248 #ifdef  BCAPDBG
249                                         printf(" %3ld %3ld", bsize >> 10, bfree >> 10);
250 #endif
251                                 }
252                         }
253 #endif
254
255                         tlast.tv_sec = tcur.tv_sec - tlast.tv_sec;
256                         tlast.tv_usec = tcur.tv_usec - tlast.tv_usec;
257                         while (tlast.tv_usec < 0) {
258                                 tlast.tv_usec += 1000000;
259                                 tlast.tv_sec -= 1;
260                         }
261                         fspeed = (nsecs / secsps) /
262                                 (tlast.tv_sec * 1.0 + tlast.tv_usec * 0.000001);
263                         if (fspeed > 999.0)
264                                 fspeed = 999.0;
265                         printf(" %5.1fx", fspeed);
266                         printf(".");
267                         savbytes = (bytes >> 20) << 20;
268                         flush();
269                         neednl = TRUE;
270                         tlast = tcur;
271                 }
272         } while (tracksize < 0 || bytes_read < tracksize);
273
274         if ((bytes / secsize) < 300) {
275                 if ((trackp->padsecs + (bytes / secsize)) < 300)
276                         trackp->padsecs = 300 - (bytes / secsize);
277         }
278         if (trackp->padsecs > 0) {
279                 Llong   padbytes;
280
281                 /*
282                  * pad_track() is based on secsize. Compute the amount of bytes
283                  * assumed by pad_track().
284                  */
285                 padbytes = (Llong)trackp->padsecs * secsize;
286
287                 if (neednl) {
288                         printf("\n");
289                         neednl = FALSE;
290                 }
291                 if ((padbytes >> 20) > 0) {
292                         neednl = TRUE;
293                 } else if (lverbose) {
294                         printf("Track %02d: writing %3lld KB of pad data.\n",
295                                                 track, (Llong)(padbytes >> 10));
296                         neednl = FALSE;
297                 }
298                 pad_track(usalp, dp, trackp, startsec, padbytes,
299                                         TRUE, &savbytes);
300                 bytes += savbytes;
301                 startsec += savbytes / secsize;
302         }
303         printf("%sTrack %02d: Total bytes read/written: %lld/%lld (%lld sectors).\n",
304                 neednl?"\n":"", track, bytes_read, bytes, bytes/secsize);
305         return (0);
306 }