1 #ifndef _LARGEFILE_SOURCE
2 #define _LARGEFILE_SOURCE
3 #endif
4 #ifndef _LARGEFILE64_SOURCE
5 #define _LARGEFILE64_SOURCE
6 #endif
7 #ifndef _FILE_OFFSET_BITS
8 #define _FILE_OFFSET_BITS 64
9 #endif
10 #if defined(__linux)
11 /* ... and "engage" glibc large file support */
12 #ifndef _GNU_SOURCE
13 #define _GNU_SOURCE
14 #endif
15 #endif
16 
17 #include "transport.hxx"
18 
19 #include <time.h>
20 #include <sys/types.h>
21 
22 #define SIGS_BLOCK	1
23 #define SIGS_UNBLOCK	0
24 extern "C" void sigs_mask (int);
25 extern "C" void atsignals (void (*)(void));
26 
27 #define	DVD_1X	1352	// 1385 * 1000 / 1024
28 #define BD_1X	4390	// 4495.5 * 1000 / 1024
29 
30 static int		media_written=0,next_track=1,
31 			is_dao=0,quickgrown=0,do_reload=1,
32 			_1x=DVD_1X,_64k=0,bdr_plus_pow=0;
33 static unsigned int	stdnap=(256*1000)/DVD_1X,// measured in milliseconds
34 			buf_size=512;		// measured in KBs
35 static class __velocity__ {
36     private:
37 	int value;
38     public:
operator =(int v)39 	int operator=(int v)	{ if (v>=_1x)	stdnap=(buf_size*500)/v;
40 				  else		stdnap=(buf_size*500)/_1x;
41 				  return value = v;
42 				}
operator int()43 	operator int()		{ return value; }
44 } velocity;
45 
46 static void         *ioctl_handle=(void *)-1;
47 #ifndef ioctl_fd
48 #define ioctl_fd ((long)ioctl_handle)
49 #endif
50 
51 static unsigned int  next_wr_addr=1;	// it starts as boolean
52 static unsigned int  dao_blocks=0;
53 static unsigned int  cap2kstart=0;
54 static unsigned char formats[260],disc_info[32];
55 
56 extern "C" {
57 extern int	dvd_compat,test_write,no_reload,mmc_profile,_argc,
58 		wrvfy,no_opc,spare;
59 extern double	speed_factor;
60 extern char	*ioctl_device,**_argv;
61 }
62 
63 extern "C"
__1x(void)64 int __1x (void) { return _1x; }
65 
66 extern "C"
fumount(int fd)67 int fumount (int fd)
68 { Scsi_Command cmd;
69   return cmd.umount(fd);
70 }
71 
72 extern "C"
media_reload(char * name=NULL,struct stat * sb=NULL,unsigned int cap2k=0)73 int media_reload (char *name=NULL,struct stat *sb=NULL,unsigned int cap2k=0)
74 {   if (name==NULL)
75     {	Scsi_Command cmd(ioctl_handle);
76 
77 	pioneer_stop (cmd);
78 
79 #if defined(RELOAD_NEVER_NEEDED)
80 #undef RELOAD_NEVER_NEEDED
81 #define RELOAD_NEVER_NEEDED 1
82 #else
83 #define RELOAD_NEVER_NEEDED 0
84 #endif
85 	if (RELOAD_NEVER_NEEDED || no_reload>0)
86 	{   cmd[0] = 0x1E;	// ALLOW MEDIA REMOVAL
87 	    cmd[5] = 0;
88 	    cmd.transport ();
89 
90 	    return (errno=0);
91 	}
92 #if !RELOAD_NEVER_NEEDED
93 
94 	char fdstr[12],cap2kstr[12];
95 	int n;
96 
97 	if ((n=fcntl (ioctl_fd,F_GETFD))<0) n=0;
98 	fcntl (ioctl_fd,F_SETFD,n&~FD_CLOEXEC);
99 
100 	sprintf (fdstr,"%ld",ioctl_fd);
101 	sprintf (cap2kstr,"%u",cap2kstart);
102 	execlp(_argv[0],no_reload<0?"-eject":"-reload",
103 			fdstr,ioctl_device,cap2kstr,(void *)NULL);
104     }
105     else
106     {
107 	{ Scsi_Command  cmd;
108 	  unsigned char c[8];
109 	  unsigned int  cap2kend;
110 
111 	    if (!cmd.associate (name,sb)) return 1;
112 
113 	    cmd[0] = 0x25;	// READ CAPACITY
114 	    cmd[9] = 0;
115 	    if (!cmd.transport (READ,c,sizeof(c)))
116 		cap2kend = c[0]<<24|c[1]<<16|c[2]<<8|c[3];
117 	    else
118 		cap2kend = (unsigned int)-1;
119 
120 	    if (cmd.is_reload_needed(cap2k==cap2kend))
121 	    {	fprintf (stderr,"%s: reloading tray\n",name);
122 		cmd[0] = 0x1E;		// ALLOW MEDIA REMOVAL
123 		cmd[5] = 0;
124 		if (cmd.transport ()) return 1;
125 
126 		while (1)	// Pioneer DVR-x05 needs this...
127 		{   cmd[0] = 0x1B;	// START/STOP UNIT
128 		    cmd[1] = 0x1;	// "IMMED"
129 		    cmd[4] = 0x2;	// "Eject"
130 		    cmd[5] = 0;
131 		    if (cmd.transport() == 0x20407) // "OP IN PROGRESS"
132 		    {	poll (NULL,0,333);
133 			continue;
134 		    }
135 		    break;
136 		}
137 		// yes, once again, non-"IMMED"...
138 		cmd[0] = 0x1B;		// START/STOP UNIT
139 		cmd[4] = 0x2;		// "Eject"
140 		cmd[5] = 0;
141 		if (cmd.transport()) return 1;
142 	    }
143 #if defined(__sun) || defined(sun)
144 	    else if (volmgt_running())
145 	    {	setuid(getuid());
146 		execl("/usr/bin/volrmmount","volrmmount","-i",name,(void*)NULL);
147 		return 0;	// not normally reached
148 	    }
149 	    else if (1)
150 	    {	char srlink[256],*dsk;
151 		static char dev[]="/dev/dsk/";
152 		int len;
153 
154 		/* this basically handles /dev/rsrN link */
155 		if ((len=readlink(name,srlink,sizeof(srlink)-1))>0 &&
156 		    (srlink[len]='\0',(dsk=strstr(srlink,"dsk/"))!=NULL))
157 		{   name=(char *)alloca(sizeof(dev)+strlen(dsk+4)+1);
158 		    strcpy(name,dev), strcat(name,dsk+4);
159 		}
160 		setuid(getuid());
161 		execl("/usr/bin/rmmount","rmmount",name,(void*)NULL);
162 		return 0;	// not reached on SunOS 5.11
163 	    }
164 #endif
165 	    else return 0;	// m-m-m-m! patched kernel:-)
166 	}
167 	if (no_reload>=0)
168 	{ Scsi_Command cmd;
169 	    if (cmd.associate (name,sb))
170 	    {	cmd[0] = 0x1B;		// START/STOP UNIT
171 		cmd[1] = 0x1;		// "IMMED"
172 		cmd[4] = 0x3;		// "Load"
173 		cmd[5] = 0;
174 		cmd.transport ();
175 	    }
176 	    errno=0;	// ignore all errors on load
177 	}
178 	return 0;
179 #endif
180     }
181 
182   return 1;
183 }
184 
185 extern "C"
get_mmc_profile(void * fd)186 int get_mmc_profile (void *fd)
187 { Scsi_Command cmd(fd);
188   unsigned char buf[8],inq[128];
189   int profile=0,once=1,blank=0,err;
190   unsigned int len;
191 
192 #if defined(__APPLE__) && defined(__MACH__)
193   // The reason for Mac OS X specific MMCIO appearing here and there
194   // is that raw SCSI requires exclusive access, while I'm not ready
195   // to give it up yet...
196 
197     // I don't call INQUIRY, because kernel ensures that
198     // MMCDeviceInterface is attached to an MMC device...
199     if ((err=MMCIO(fd,GetConfiguration,0,0,buf,sizeof(buf))))
200 	sperror ("GET CONFIGURATION",err),
201 	exit (FATAL_START(errno));
202 
203     profile = buf[6]<<8|buf[7];
204 #else
205     // INQUIRY is considered to be "non-intrusive" in a sense that
206     // it won't interfere with any other operation nor clear sense
207     // data, which might be important to retain for security reasons.
208 
209     cmd[0] = 0x12;	// INQUIRY
210     cmd[4] = 36;
211     cmd[5] = 0;
212     if ((err=cmd.transport(READ,inq,36)))
213 	sperror ("INQUIRY",err),
214 	exit (FATAL_START(errno));
215 
216     // make sure we're talking to MMC unit, for security reasons...
217     if ((inq[0]&0x1F) != 5)
218 	fprintf (stderr,":-( not an MMC unit!\n"),
219 	exit (FATAL_START(EINVAL));
220 
221     do {
222 	cmd[0] = 0x46;
223 	cmd[8] = sizeof(buf);
224 	cmd[9] = 0;
225 	if ((err=cmd.transport(READ,buf,sizeof(buf))))
226 	    sperror ("GET CONFIGURATION",err),
227 	    fprintf (stderr,":-( non-MMC unit?\n"),
228 	    exit (FATAL_START(errno));
229 
230         if ((profile = buf[6]<<8|buf[7]) || !once) break;
231 
232 	// no media?
233 	cmd[0] = 0;	// TEST UNIT READY
234 	cmd[5] = 0;
235 	if ((cmd.transport()&0xFFF00) != 0x23A00) break;
236 
237 	// try to load tray...
238 	cmd[0] = 0x1B;	// START/STOP UNIT
239 	cmd[4] = 0x3;	// "Load"
240 	cmd[5] = 0;
241 	if ((err=cmd.transport ()))
242 	    sperror ("LOAD TRAY",err),
243 	    exit (FATAL_START(errno));
244 
245 #if 1
246 	wait_for_unit (cmd);
247 #else
248 	// consume sense data, most likely "MEDIA MAY HAVE CHANGED"
249 	cmd[0] = 0;	// TEST UNIT READY
250 	cmd[5] = 0;
251 	if ((err=cmd.transport ()) == -1)
252 	    sperror ("TEST UNIT READY",err),
253 	    exit (FATAL_START(errno));
254 #endif
255     } while (once--);
256 #endif	// !Mac OS X
257 
258     if (profile==0 || (profile&0x70)==0)	// no or non-DVD/BD media...
259 	return profile;
260 
261     if ((profile&0xF0) == 0x40)
262     { unsigned char header[16];
263 
264 	_1x = BD_1X;
265 	_64k = 1;
266 
267 	if (profile==0x41)	// BD-R SRM
268 	{   // Check for POW feature...
269 #if defined(__APPLE__) && defined(__MACH__)
270 	    err = MMCIO(fd,GetConfiguration,2,0x38,header,16);
271 #else
272 	    cmd[0] = 0x46;	// GET CONFIGURATION
273 	    cmd[1] = 2;		// ask for the only feature...
274 	    cmd[3] = 0x38;	// the "BD-R Pseudo-Overwrite" one
275 	    cmd[8] = 16;	// The feature should be there, right?
276 	    cmd[9] = 0;
277 	    err = cmd.transport (READ,header,16);
278 #endif
279 	    if (err==0 &&
280 		(header[0]<<24|header[1]<<16|header[2]<<8|header[3])>=12 &&
281 		(header[8+2]&1)==1)
282 		bdr_plus_pow=1;
283 	}
284 
285     }
286 
287 #if defined(__APPLE__) && defined(__MACH__)
288     err = MMCIO(fd,ReadDiscInformation,disc_info,sizeof(disc_info));
289 #else
290     cmd[0] = 0x51;	// READ DISC INFORMATION
291     cmd[8] = sizeof(disc_info);
292     cmd[9] = 0;
293     err = cmd.transport (READ,disc_info,sizeof(disc_info));
294 #endif
295     if (err)
296 	sperror ("READ DISC INFORMATION",err),
297 	exit (FATAL_START(errno));
298 
299     // see if it's blank media
300     if ((disc_info[2]&3) == 0)	blank=0x10000;
301 
302     if (profile != 0x1A && profile != 0x2A &&		// DVD+RW
303 	profile != 0x13 && profile != 0x12 &&		// DVD-R[AM]
304 	profile != 0x43 && !(profile == 0x41 && blank))	// BD-R[E]
305 	return blank|profile;
306 
307 #if defined(__APPLE__) && defined(__MACH__)
308     err = MMCIO(fd,ReadFormatCapacities,formats,12);
309 #else
310     cmd[0] = 0x23;	// READ FORMAT CAPACITIES
311     cmd[8] = 12;
312     cmd[9] = 0;
313     err = cmd.transport (READ,formats,12);
314 #endif
315     if (err)
316 	sperror ("READ FORMAT CAPACITIES",err),
317 	exit (FATAL_START(errno));
318 
319     len = formats[3];
320     if (len&7 || len<16)
321 	fprintf (stderr,":-( FORMAT allocaion length isn't sane"),
322 	exit (FATAL_START(EINVAL));
323 
324 #if defined(__APPLE__) && defined(__MACH__)
325     err = MMCIO(fd,ReadFormatCapacities,formats,4+len);
326 #else
327     cmd[0] = 0x23;	// READ FORMAT CAPACITIES
328     cmd[7] = (4+len)>>8;
329     cmd[8] = (4+len)&0xFF;
330     cmd[9] = 0;
331     err = cmd.transport (READ,formats,4+len);
332 #endif
333     if (err)
334 	sperror ("READ FORMAT CAPACITIES",err),
335 	exit (FATAL_START(errno));
336 
337     if (len != formats[3])
338 	fprintf (stderr,":-( parameter length inconsistency\n"),
339 	exit(FATAL_START(EINVAL));
340 
341     // see if it's not formatted
342     if ((formats[8]&3) != 2) blank = 0x10000;
343 
344   return blank|profile;
345 }
346 
get_2k_capacity(Scsi_Command & cmd,void * fd=NULL)347 static unsigned int get_2k_capacity (Scsi_Command &cmd,void *fd=NULL)
348 { unsigned char	buf[32];
349   unsigned int	ret=0;
350   unsigned int	nwa,free_blocks;
351   int		i,obligatory,len,err;
352 
353     obligatory=0x00;
354     switch (mmc_profile&0xFFFF)
355     {	case 0x1A:		// DVD+RW
356 	    obligatory=0x26;
357 	case 0x13:		// DVD-RW Restricted Overwrite
358 	    for (i=8,len=formats[3];i<len;i+=8)
359 		if ((formats [4+i+4]>>2) == obligatory) break;
360 
361 	    if (i==len)
362 	    {	fprintf (stderr,":-( can't locate obligatory format descriptor\n");
363 		return 0;
364 	    }
365 
366 	    ret  = formats[4+i+0]<<24;
367 	    ret |= formats[4+i+1]<<16;
368 	    ret |= formats[4+i+2]<<8;
369 	    ret |= formats[4+i+3];
370 	    nwa = formats[4+5]<<16|formats[4+6]<<8|formats[4+7];
371 	    if (nwa>2048)	ret *= nwa/2048;
372 	    else if (nwa<2048)	ret /= 2048/nwa;
373 	    break;
374 
375 	case 0x12:		// DVD-RAM
376 	    // As for the moment of this writing I don't format DVD-RAM.
377 	    // Therefore I just pull formatted capacity for now...
378 	    ret  = formats[4+0]<<24;
379 	    ret |= formats[4+1]<<16;
380 	    ret |= formats[4+2]<<8;
381 	    ret |= formats[4+3];
382 	    nwa = formats[4+5]<<16|formats[4+6]<<8|formats[4+7];
383 	    if (nwa>2048)	ret *= nwa/2048;
384 	    else if (nwa<2048)	ret /= 2048/nwa;
385 	    break;
386 
387 	case 0x11:		// DVD-R
388 	case 0x14:		// DVD-RW Sequential
389 	case 0x15:		// DVD-R Dual Layer Sequential
390 	case 0x16:		// DVD-R Dual Layer Jump
391 	case 0x1B:		// DVD+R
392 	case 0x2B:		// DVD+R Double Layer
393 	case 0x41:		// BD-R SRM
394 #if defined(__APPLE__) && defined(__MACH__)
395 	    if (fd)
396 		err = MMCIO(fd,ReadTrackInformation,1,next_track,buf,sizeof(buf));
397 	    else
398 #endif
399 	    {	cmd[0] = 0x52;	// READ TRACK INFORMATION
400 		cmd[1] = 1;
401 		cmd[4] = next_track>>8;
402 		cmd[5] = next_track&0xFF;	// last track, set up earlier
403 		cmd[8] = sizeof(buf);
404 		cmd[9] = 0;
405 		err = cmd.transport (READ,buf,sizeof(buf));
406 	    }
407 	    if (err)
408 	    {	sperror ("READ TRACK INFORMATION",err);
409 		return 0;
410 	    }
411 
412 	    nwa = 0;
413 	    if (buf[7]&1)	// NWA_V
414 	    {	nwa  = buf[12]<<24;
415 		nwa |= buf[13]<<16;
416 		nwa |= buf[14]<<8;
417 		nwa |= buf[15];
418 	    }
419 	    free_blocks  = buf[16]<<24;
420 	    free_blocks |= buf[17]<<16;
421 	    free_blocks |= buf[18]<<8;
422 	    free_blocks |= buf[19];
423 	    ret = nwa + free_blocks;
424 	    break;
425 
426 	case 0x43:		// BD-RE
427 	    // just pull formatted capacity for now...
428 	    ret  = formats[4+0]<<24;
429 	    ret |= formats[4+1]<<16;
430 	    ret |= formats[4+2]<<8;
431 	    ret |= formats[4+3];
432 	    break;
433 
434 	default:
435 	    break;
436     }
437 
438   return ret;
439 }
440 
441 extern "C"
get_capacity(void * fd)442 off64_t get_capacity (void *fd)
443 { Scsi_Command	cmd(fd);
444   return (off64_t)get_2k_capacity(cmd,fd)*2048;
445 }
446 
447 extern "C"
get_buffer_stats(void * fd)448 float get_buffer_stats (void *fd)
449 { Scsi_Command		cmd(fd);
450   unsigned char		bcap[12];
451   unsigned int		bsize,bfree;
452   int			err;
453 
454     cmd[0] = 0x5C;              // READ BUFFER CAPACITY
455     cmd[8] = sizeof(bcap);
456     cmd[9] = 0;
457     if ((err=cmd.transport (READ,bcap,sizeof(bcap))))
458 	return -1.0f;
459 
460     bsize = bcap[4]<<24|bcap[5]<<16|bcap[6]<<8|bcap[7];
461     bfree = bcap[8]<<24|bcap[9]<<16|bcap[10]<<8|bcap[11];
462 
463   return bsize ? (1.0f - (float)bfree/(float)bsize) : 0.0f;
464 }
465 
poor_mans_pwrite64(int fd,const void * _buff,size_t size,off64_t foff)466 ssize_t poor_mans_pwrite64 (int fd,const void *_buff,size_t size,off64_t foff)
467 { Scsi_Command		cmd(ioctl_handle);	/* screw first argument */
468   unsigned char		bcap[12];
469   const unsigned char  *buff=(const unsigned char *)_buff;
470   unsigned int		lba,nbl,bsize,bfree;
471   int			retries=0,errcode;
472   static int		dao_toggle=-1;
473 
474     if (foff&0x7FFF || size&0x7FFF)	// 32K block size
475 	return (errno=EINVAL,-1);
476 
477     lba = (unsigned int)(foff/2048);
478     nbl = (unsigned int)(size/2048);
479 
480     if (!media_written && next_wr_addr)
481     {	if ((lba+nbl) <= next_wr_addr)
482 	    return size;
483 	else if (next_wr_addr > lba)
484 	    nbl  -= (next_wr_addr-lba),
485 	    size -= (next_wr_addr-lba)<<11,
486 	    buff += (next_wr_addr-lba)<<11,
487 	    lba   = next_wr_addr;
488     }
489 #if defined(__sun) || defined(sun)
490     else    next_wr_addr = lba;
491 #endif
492 
493     if (dao_toggle<0) dao_toggle=is_dao;
494 
495     { static unsigned int first_wr_addr=0;
496 
497 	if (!media_written)
498 	{   sigs_mask (SIGS_BLOCK); first_wr_addr = lba;	}
499 	else if (lba >= (first_wr_addr+buf_size/2)) // measured in 2KBs!
500 	{   sigs_mask (SIGS_UNBLOCK);			}
501     }
502 
503     if (dao_blocks!=0 && (lba+nbl)>dao_blocks)
504 	nbl = dao_blocks-lba;
505 
506     while (1)
507     {	cmd[0] = wrvfy?0x2E:0x2A;	// WRITE [AND VERIFY] (10)
508 	cmd[2] = (lba>>24)&0xff;	// Logical Block Addrss
509 	cmd[3] = (lba>>16)&0xff;
510 	cmd[4] = (lba>>8)&0xff;
511 	cmd[5] = lba&0xff;
512 	cmd[7] = (nbl>>8)&0xff;
513 	cmd[8] = nbl&0xff;
514 	cmd[9] = 0;
515 #if 0
516 	cmd[0] = 0xAA;			// WRITE(12)
517 	cmd[2] = (lba>>24)&0xff;	// Logical Block Addrss
518 	cmd[3] = (lba>>16)&0xff;
519 	cmd[4] = (lba>>8)&0xff;
520 	cmd[5] = lba&0xff;
521 	cmd[8] = (nbl>>8)&0xff;
522 	cmd[9] = nbl&0xff;
523 	cmd[10] = 0x80;			// "Streaming"
524 	cmd[11] = 0;
525 #endif
526 	//
527 	// First writes can be long, especially in DAO mode...
528 	// I wish I could complement this with "if (lba==0),"
529 	// but some units might choose to fill the buffer before
530 	// they take the first nap...
531 	//
532 	cmd.timeout(dao_toggle?180:60);
533 	//
534 	// It should also be noted that under Linux these values
535 	// (if actually respected by kernel!) can turn out bogus.
536 	// The problem is that I scale them to milliseconds as
537 	// documentation requires/implies, while kernel treats
538 	// them as "jiffies." I could/should have used HZ macro
539 	// (or sysconf(_SC_CLK_TCK)), but recent kernels maintain
540 	// own higher HZ value and disrespects the user-land one.
541 	// Sending them down as milliseconds is just safer...
542 	//
543 	if (!(errcode=cmd.transport (WRITE,(void *)buff,size)))
544 	    break;
545 
546 	//--- WRITE failed ---//
547 #if defined(__sun) || defined(sun)
548 	//
549 	// Solaris can slice USB WRITEs to multiple ones. Here I try
550 	// to find out which slice has failed. I expect we get here
551 	// only when we re-enter the loop...
552 	//
553 	if (lba==next_wr_addr &&
554 	    errcode==0x52102)		// "INVALID ADDRESS FOR WRITE"
555 	{ unsigned char track[32];
556 
557 	    cmd[0] = 0x52;		// READ TRACK INFORMATION
558 	    cmd[1] = 1;
559 	    cmd[4] = next_track>>8;
560 	    cmd[5] = next_track&0xFF;
561 	    cmd[8] = sizeof(track);
562 	    cmd[9] = 0;
563 	    if (!cmd.transport (READ,track,sizeof(track)))
564 	    {	if (track[7]&1)	// NWA_V
565 		{   next_wr_addr  = track[12]<<24;
566 		    next_wr_addr |= track[13]<<16;
567 		    next_wr_addr |= track[14]<<8;
568 		    next_wr_addr |= track[15];
569 		    if (lba<next_wr_addr && (lba+nbl)>next_wr_addr)
570 		    {	nbl  -= next_wr_addr-lba,
571 			size -= (next_wr_addr-lba)<<11,
572 			buff += (next_wr_addr-lba)<<11,
573 			lba   = next_wr_addr;
574 			continue;
575 		    }
576 		}
577 	    }
578 	}
579 #endif
580 
581 	if (errcode==0x20408)		// "LONG WRITE IN PROGRESS"
582 	{   // Apparently only Pioneer units do this...
583 	    if (velocity == 0)
584 	    {	if (handle_events(cmd) & (1<<6))
585 		    continue;
586 		goto sync_cache;
587 	    }
588 
589 	    cmd[0] = 0x5C;		// READ BUFFER CAPACITY
590 	    cmd[8] = sizeof(bcap);
591 	    cmd[9] = 0;
592 	    if (cmd.transport (READ,bcap,sizeof(bcap)))
593 		bfree=0, bsize=buf_size;
594 	    else
595 	    {	bsize = bcap[4]<<24|bcap[5]<<16|bcap[6]<<8|bcap[7];
596 		bfree = bcap[8]<<24|bcap[9]<<16|bcap[10]<<8|bcap[11];
597 		bsize /= 1024, bfree /= 1024;	// xlate to KB
598 	    }
599 	    // check for sanity and drain 1/2 of the buffer
600 	    if (bsize < buf_size/2)	bsize = buf_size/2;
601 	    else			bsize /= 2;
602 	    if (bfree > bsize)		bfree = bsize;
603 
604 	    int msecs=0;
605 
606 	    if ((msecs=(bsize-bfree)*1000) > velocity)
607 	    {	msecs /= velocity;
608 		retries++;
609 		if (dao_toggle) dao_toggle=-1;
610 	    }
611 	    else	// lots of free buffer reported?
612 	    {	if (dao_toggle)
613 		{   dao_toggle=-1;
614 		    if ((handle_events(cmd) & (1<<6)))
615 			continue;
616 		    msecs = bsize*1000;
617 		    msecs /= velocity;
618 		}
619 		else if (!retries++)	continue;
620 		// Pioneer units seem to return bogus values at high
621 		// velocities now and then... I reserve for 4 ECC
622 		// blocks, which is ~6 ms at 16x. But note that some
623 		// OSes, Linux 2.4 among then, will nap for 10 or 20.
624 		msecs = (4*32*1000)/velocity;
625 	    }
626 
627 	    // Retry values were increased because high-speed units
628 	    // start recordings at only portion of velocity and it
629 	    // takes more retries to write lead-in... Another common
630 	    // reason for stucks are recalibrations at zone edges...
631 	    if (retries > (dao_toggle?768:192))
632 		fprintf (stderr,":-? the LUN appears to be stuck "
633 				"writing LBA=%xh, keep retrying in %dms\n",
634 				lba,msecs),
635 		retries=1;
636 
637 	    if (msecs>=0)
638 	    {	poll (NULL,0,msecs);
639 		continue;
640 	    }
641 
642 	    lba |= 0x80000000;		// signal insane bfree...
643 	}
644 	else if (lba==0 && errcode==0x20401)	// "IN PROCESS OF BECOMING READY"
645 	{   if ((handle_events(cmd) & (1<<6)))
646 		continue;
647 	    if (++retries > 3)
648 	    {	fprintf (stderr,":-! the LUN is still in process of becoming ready, "
649 		    		    "retrying in 5 secs...\n"),
650 		retries=0;
651 		sigs_mask (SIGS_UNBLOCK);
652 		poll (NULL,0,5000);
653 	    }
654 	    else
655 	    	sigs_mask (SIGS_UNBLOCK),
656 		poll (NULL,0,stdnap);
657 	    continue;
658 	}
659 	else if (errcode==0x20404 ||	// "FORMAT IN PROGRESS"
660 		 errcode==0x20407 ||	// "OPERATION IN PROGRESS"
661 		 errcode==0x52C00)	// "COMMAND SEQUENCE ERROR"
662 	{   // Happens under automounter control? In general I recommend
663 	    // to disable it! This code is a tribute to users who disregard
664 	    // the instructions...
665 	sync_cache:
666 	    // should I check if lba+nbl is multiple of 64K in BD case?
667 	    cmd[0] = 0x35;	// SYNC CACHE
668 	    cmd[9] = 0;
669 	    if (!cmd.transport())
670 	    {	if (++retries > 1)
671 	    	{   fprintf (stderr,":-! the LUN appears to be stuck at %xh, "
672 		    		    "retrying in 5 secs...\n",lba),
673 		    retries=0;
674 		    sigs_mask (SIGS_UNBLOCK);
675 		    poll (NULL,0,5000);
676 		}
677 		else if (errcode==0x52C00)
678 		    fprintf (stderr,":-! \"COMMAND SEQUENCE ERROR\"@LBA=%xh. "
679 				    "Is media being read?\n",lba);
680 		continue;
681 	    }
682 	    lba |= 0x40000000;	// signal "can't SYNC CACHE"
683 	}
684 	{ char cmdname[64];
685 	    sprintf (cmdname,"WRITE@LBA=%xh",lba),
686 	    sperror (cmdname,errcode);
687 	}
688 	if (lba==0)
689 	{   if (ASC(errcode)==0x30)
690 		fprintf (stderr,":-( media is not formatted or unsupported.\n");
691 	    else if ((mmc_profile&0xFFFF)==0x14 /*&& ASC(errcode)==0x64*/)
692 		fprintf (stderr,":-( attempt to re-run with "
693 				"-dvd-compat -dvd-compat to engage DAO or "
694 				"apply full blanking procedure\n");
695 	}
696 #if 1	// safety net: leave DL sessions open and resumable...
697 	if ((mmc_profile&0xFFFF)==0x2B && errcode!=0x52100) media_written=0;
698 #endif
699 	return -1;
700     }
701 
702     next_wr_addr = lba+nbl;
703     media_written = 1;
704 
705     if (dao_toggle<0) dao_toggle=0;
706 
707   return size;
708 }
709 
710 // spare == -1	"format without spare"
711 // spare == 0	"format with minimal spare"
712 // spare >  0	"format with default descriptor"
bd_r_format(Scsi_Command & cmd)713 static void bd_r_format (Scsi_Command &cmd)
714 { int err,i,len;
715   unsigned char descr[12],*f;
716 
717     if (spare < 0)	return;	// no format -> no spare area:-)
718 
719     len = formats[3];
720 
721     if (spare == 0)	// locate descriptor with maximum capacity
722     { unsigned int max,cap;
723       int j;
724 
725 	i = 0;
726 	for (max=0,j=8;j<len;j+=8)
727 	{   f = formats+4+j;
728 	    if ((f[4]>>2) == 0x32)
729 	    {	cap = f[0]<<24|f[1]<<16|f[2]<<8|f[3];
730 		if (max < cap) max=cap,i=j;
731 	    }
732 	}
733 	if (i==0)
734 	    fprintf (stderr,":-( can't locate format 0x32 descriptor\n"),
735 	    exit (FATAL_START(errno=EMEDIUMTYPE));
736     }
737     else
738 	i = 8;	// grab default descriptor
739 
740     memset (descr,0,sizeof(descr));
741     descr[1]=0x02;	// "IMMED" flag
742     descr[3]=0x08;	// "Descriptor Lenght" (LSB)
743     memcpy (descr+4,formats+4+i,5);
744     descr[4+4]&=~3;	// ensure "Format Subtype" is set to SRM+POW
745 
746     f = descr+4;
747     fprintf (stderr,"%s: pre-formatting blank BD-R for %.1fGB...\n",
748 		    ioctl_device,(f[0]<<24|f[1]<<16|f[2]<<8|f[3])*2048.0/1e9);
749 
750     cmd[0] = 0x04;	// FORMAT UNIT
751     cmd[1] = 0x11;	// "FmtData" and "Format Code"
752     cmd[5] = 0;
753     if ((err=cmd.transport(WRITE,descr,sizeof(descr))))
754 	sperror ("FORMAT UNIT",err),
755 	exit (FATAL_START(errno));
756 
757     wait_for_unit (cmd);
758 
759     bdr_plus_pow = 1;
760 
761     cmd[0] = 0x35;	// FLUSH CACHE
762     cmd[9] = 0;
763     cmd.transport();
764 }
765 
bd_re_format(Scsi_Command & cmd)766 static void bd_re_format (Scsi_Command &cmd)
767 { int err,i,len;
768   unsigned char descr[12],*f;
769 
770     len = formats[3];
771 
772     if (spare == 0)	// locate descriptor with maximum capacity
773     { unsigned int max,cap;
774       int j;
775 
776 	i = 0;
777 	for (max=0,j=8;j<len;j+=8)
778 	{   f = formats+4+j;
779 	    if ((f[4]>>2) == 0x30)
780 	    {	cap = f[0]<<24|f[1]<<16|f[2]<<8|f[3];
781 		if (max < cap) max=cap,i=j;
782 	    }
783 	}
784 	if (i==0)
785 	    fprintf (stderr,":-( can't locate format 0x30 descriptor\n"),
786 	    exit (FATAL_START(errno=EMEDIUMTYPE));
787     }
788     else if (spare < 0)	// locate descriptor 0x31
789     {	for (i=8;i<len;i+=8)
790 	    if ((formats[4+i+4]>>2) == 0x31) break;
791 	if (i==len)
792 	    fprintf (stderr,":-( can't locate format 0x31 descriptor\n"),
793 	    exit (FATAL_START(errno=EMEDIUMTYPE));
794     }
795     else
796 	i = 8;	// grab default descriptor
797 
798     memset (descr,0,sizeof(descr));
799     descr[1]=0x02;	// "IMMED" flag
800     descr[3]=0x08;	// "Descriptor Lenght" (LSB)
801     memcpy (descr+4,formats+4+i,5);
802 
803     f = descr+4;
804     fprintf (stderr,"%s: pre-formatting blank BD-RE for %.1fGB...\n",
805 		    ioctl_device,(f[0]<<24|f[1]<<16|f[2]<<8|f[3])*2048.0/1e9);
806 
807     cmd[0] = 0x04;	// FORMAT UNIT
808     cmd[1] = 0x11;	// "FmtData" and "Format Code"
809     cmd[5] = 0;
810     if ((err=cmd.transport(WRITE,descr,sizeof(descr))))
811 	sperror ("FORMAT UNIT",err),
812 	exit(FATAL_START(errno));
813 
814     wait_for_unit (cmd);
815 
816     cmd[0] = 0x35;	// FLUSH CACHE
817     cmd[9] = 0;
818     cmd.transport();
819 }
820 
plus_rw_format(Scsi_Command & cmd)821 static void plus_rw_format (Scsi_Command &cmd)
822 { int err,i,len;
823   unsigned char descr[12];
824 
825     if ((formats[4+4]&3) == 1)	// Unformatted media
826     {	fprintf (stderr,"%s: pre-formatting blank DVD+RW...\n",ioctl_device);
827 
828 	for (i=8,len=formats[3];i<len;i+=8)
829 	    if ((formats [4+i+4]>>2) == 0x26) break;
830 
831 	if (i==len)
832 	    fprintf (stderr,":-( can't locate DVD+RW format descriptor\n"),
833 	    exit(FATAL_START(EMEDIUMTYPE));
834 
835 	memset (descr,0,sizeof(descr));
836 	descr[1]=0x02;		// "IMMED" flag
837 	descr[3]=0x08;		// "Descriptor Length" (LSB)
838 	memcpy (descr+4,formats+4+i,4);
839 	descr[8]=0x26<<2;	// "Format type" 0x26
840 
841 	cmd[0] = 0x04;		// FORMAT UNIT
842 	cmd[1] = 0x11;		// "FmtData" and "Format Code"
843 	cmd[5] = 0;
844 	if ((err=cmd.transport(WRITE,descr,sizeof(descr))))
845 	    sperror ("FORMAT UNIT",err),
846 	    exit(FATAL_START(errno));
847 
848 	wait_for_unit (cmd);
849 
850 	cmd[0] = 0x35;		// FLUSH CACHE
851 	cmd[9] = 0;
852 	if ((err=cmd.transport()))
853 	    sperror ("FLUSH CACHE",err),
854 	    exit(FATAL_START(errno));
855     }
856 }
857 
plus_rw_restart_format(Scsi_Command & cmd,off64_t size)858 static int plus_rw_restart_format (Scsi_Command &cmd, off64_t size)
859 { unsigned char descr[12];
860   unsigned int lead_out,blocks;
861   int err,i,len;
862 
863     if (!dvd_compat && size!=0)
864     {	blocks = (unsigned int)(size/2048);
865 	blocks += 15, blocks &= ~15;
866 
867 	lead_out = 0;
868 	lead_out |= formats[4+0], lead_out <<= 8;
869 	lead_out |= formats[4+1], lead_out <<= 8;
870 	lead_out |= formats[4+2], lead_out <<= 8;
871 	lead_out |= formats[4+3];
872 
873 	if (blocks<=lead_out)   // no need to resume format...
874 	    return 0;
875     }
876 
877     fprintf (stderr,"%s: restarting DVD+RW format...\n",ioctl_device);
878 
879     for (i=8,len=formats[3];i<len;i+=8)
880 	if ((formats [4+i+4]>>2) == 0x26) break;
881 
882     if (i==len)
883 	fprintf (stderr,":-( can't locate DVD+RW format descriptor\n"),
884 	exit(FATAL_START(EMEDIUMTYPE));
885 
886     memset (descr,0,sizeof(descr));
887     descr[1]=0x02;		// "IMMED" flag
888     descr[3]=0x08;		// "Descriptor Length" (LSB)
889 #if 1
890     memcpy (descr+4,formats+4+i,4);
891 #else
892     memset (descr+4,-1,4);
893 #endif
894     descr[8]=0x26<<2;		// "Format type" 0x26
895     descr[11]=1;		// "Restart Format"
896 
897     cmd[0] = 0x04;		// FORMAT UNIT
898     cmd[1] = 0x11;		// "FmtData" and "Format Code"
899     cmd[5] = 0;
900     if ((err=cmd.transport(WRITE,descr,sizeof(descr))))
901     {	sperror ("RESTART FORMAT",err);
902 	return 1;
903     }
904 
905     wait_for_unit(cmd);
906 
907   return 0;
908 }
909 
910 extern "C"
plusminus_r_C_parm(void * fd,char * C_parm)911 int plusminus_r_C_parm (void *fd,char *C_parm)
912 { unsigned int next_session, prev_session,err;
913   Scsi_Command cmd(fd);
914   unsigned char buf[36];
915 
916     if ((disc_info[2]&3) != 1)
917 	fprintf (stderr,":-( media is not appendable\n"),
918 	exit(FATAL_START(EMEDIUMTYPE));
919 
920     // allow to resume even --v-- incomplete sessions //
921     if (((disc_info[2]>>2)&3) > 1)
922 	fprintf (stderr,":-( last session is not empty\n"),
923 	exit(FATAL_START(EMEDIUMTYPE));
924 
925     if (mmc_profile==0x41 && bdr_plus_pow)
926 	next_track = disc_info[6]|disc_info[11]<<8;
927     else
928 	next_track = disc_info[5]|disc_info[10]<<8;
929 
930 #if defined(__APPLE__) && defined(__MACH__)
931     err = MMCIO(fd,ReadTrackInformation,1,next_track,buf,sizeof(buf));
932 #else
933     cmd[0] = 0x52;		// READ TRACK INFORMATION
934     cmd[1] = 1;
935     cmd[4] = next_track>>8;
936     cmd[5] = next_track;	// ask for last track
937     cmd[8] = sizeof(buf);
938     cmd[9] = 0;
939     err = cmd.transport (READ,buf,sizeof(buf));
940 #endif
941     if (err)
942     {	sperror ("READ TRACK INFORMATION",err);
943 	if (ASC(err)==0x24) // hp dvd200i returns 24 if media is full
944 	    fprintf (stderr,":-( media must be full already\n");
945 	exit (FATAL_START(errno));
946     }
947 
948     if (mmc_profile==0x41 && bdr_plus_pow && buf[7]&1)		// NWA_V
949     {	next_session  = buf[12]<<24;
950 	next_session |= buf[13]<<16;
951 	next_session |= buf[14]<<8;
952 	next_session |= buf[15];
953     }
954     else
955     {	next_session  = buf[8]<<24;	// Track Start Address
956 	next_session |= buf[9]<<16;
957 	next_session |= buf[10]<<8;
958 	next_session |= buf[11];
959     }
960 
961     if (mmc_profile==0x41 && bdr_plus_pow)
962 	prev_session=0;
963     else
964     {	//
965 	// All manuals say the data is fabricated, presumably implying
966 	// that one should use another command. But we stick to this one
967 	// because kernel uses this very command to mount multi-session
968 	// discs.
969 	//
970 #if defined(__APPLE__) && defined(__MACH__)
971 	err = MMCIO(fd,ReadTableOfContents,0,1,0,buf,12);
972 #else
973 	cmd[0] = 0x43;		// READ TOC
974 	cmd[2] = 1;		// "Session info"
975 	cmd[8] = 12;
976 	cmd[9] = 0;
977 	err = cmd.transport (READ,buf,12);
978 #endif
979 	if (err)
980 	    sperror ("READ SESSION INFO",err),
981 	    exit (FATAL_START(errno));
982 
983 	prev_session  = buf[8]<<24;
984 	prev_session |= buf[9]<<16;
985 	prev_session |= buf[10]<<8;
986 	prev_session |= buf[11];
987     }
988 
989     sprintf (C_parm,"%d,%d",prev_session+16,next_session);
990 
991   return next_session;
992 }
993 
pull_page2A(Scsi_Command & cmd)994 static unsigned char *pull_page2A (Scsi_Command &cmd)
995 { unsigned char *page2A,header[12];
996   unsigned int   len,bdlen;
997   int            err;
998 
999     cmd[0] = 0x5A;		// MODE SENSE
1000     cmd[1] = 0x08;		// "Disable Block Descriptors"
1001     cmd[2] = 0x2A;		// "Capabilities and Mechanical Status"
1002     cmd[8] = sizeof(header);	// header only to start with
1003     cmd[9] = 0;
1004     if ((err=cmd.transport(READ,header,sizeof(header))))
1005 	sperror ("MODE SENSE#2A",err), exit(FATAL_START(errno));
1006 
1007     len   = (header[0]<<8|header[1])+2;
1008     bdlen = header[6]<<8|header[7];
1009 
1010     if (bdlen)	// should never happen as we set "DBD" above
1011     {	if (len < (8+bdlen+30))
1012 	    fprintf (stderr,":-( LUN is impossible to bear with...\n"),
1013 	    exit(FATAL_START(EINVAL));
1014     }
1015     else if (len < (8+2+(unsigned int)header[9]))// SANYO does this.
1016 	len = 8+2+header[9];
1017 
1018     page2A = (unsigned char *)malloc(len);
1019     if (page2A == NULL)
1020 	fprintf (stderr,":-( memory exhausted\n"), exit(FATAL_START(ENOMEM));
1021 
1022     cmd[0] = 0x5A;		// MODE SENSE
1023     cmd[1] = 0x08;		// "Disable Block Descriptors"
1024     cmd[2] = 0x2A;		// "Capabilities and Mechanical Status"
1025     cmd[7] = len>>8;
1026     cmd[8] = len;		// real length this time
1027     cmd[9] = 0;
1028     if ((err=cmd.transport(READ,page2A,len)))
1029 	sperror ("MODE SENSE#2A",err),
1030 	exit(FATAL_START(errno));
1031 
1032     len -= 2;
1033     if (len < ((unsigned int)page2A[0]<<8|page2A[1]))	// paranoia:-)
1034 	page2A[0] = len>>8, page2A[1] = len;
1035 
1036   return page2A;
1037 }
1038 
pull_velocity(Scsi_Command & cmd,unsigned char * d)1039 static int pull_velocity (Scsi_Command &cmd,unsigned char *d)
1040 { unsigned int len;
1041   int v,err;
1042   class autofree perf;
1043 
1044 #if 0	// 8x AccessTek derivatives, such as OptoRite DD0405
1045     if ((d[4]&2) == 0)	return -1;
1046 #endif
1047 
1048     len = (d[0]<<24|d[1]<<16|d[2]<<8|d[3])-4;
1049     if (len%16)		return -1;
1050     if (len==0)		return -1;	// LG GCA-4040N:-(
1051 
1052     len += 8;
1053     if (len == (8+16))
1054     {	velocity = d[8+ 4]<<24|d[8+ 5]<<16|d[8+ 6]<<8|d[8+ 7];
1055 	v =        d[8+12]<<24|d[8+13]<<16|d[8+14]<<8|d[8+15];
1056 	if (v>velocity) velocity=v;	// CAV?
1057     }
1058     else	// ZCLV
1059     { unsigned int n = (len-8)/16;
1060       unsigned char *p;
1061 
1062 	perf = (unsigned char *)malloc (len);
1063 	if (perf == NULL)
1064 	    fprintf (stderr,":-( memory exhausted\n"),
1065 	    exit(FATAL_START(ENOMEM));
1066 
1067 	cmd[0]=0xAC;	// GET PERFORMANCE
1068 	cmd[1]=4;	// ask for "Overall Write Performance"
1069 	cmd[8]=n>>8;
1070 	cmd[9]=n;	// real number of descriptors
1071 	cmd[10]=0;	// ask for descriptor in effect
1072 	cmd[11]=0;
1073 	if ((err=cmd.transport(READ,perf,len)))
1074 	    sperror ("GET CURRENT PERFORMANCE",err),
1075 	    exit (FATAL_START(errno));
1076 
1077 	// Pick the highest speed...
1078 	for (p=perf+8,len-=8;len;p+=16,len-=16)
1079 	{   v=p[ 4]<<24|p[ 5]<<16|p[ 6]<<8|p[ 7];
1080 	    if (v > velocity) velocity = v;
1081 	    v=p[12]<<24|p[13]<<16|p[14]<<8|p[15];
1082 	    if (v > velocity) velocity = v;	// ZCAV?
1083 	}
1084     }
1085 
1086   return 0;
1087 }
1088 
set_speed_B6h(Scsi_Command & cmd,unsigned int dvdplus,unsigned char * page2A)1089 static int set_speed_B6h (Scsi_Command &cmd,unsigned int dvdplus,
1090 			  unsigned char *page2A)
1091 { unsigned int len;
1092   int err;
1093   unsigned char d[8+16];
1094   class autofree perf;
1095 
1096     cmd[0]=0xAC;		// GET PERFORMACE
1097     cmd[9]=1;			// start with one descriptor
1098     cmd[10]=0x3;		// ask for "Write Speed Descriptor"
1099     cmd[11]=0;
1100     if ((err=cmd.transport(READ,d,sizeof(d))))
1101     {	sperror ("GET PERFORMANCE",err);
1102 	fprintf (stderr,":-( falling down to SET CD SPEED\n");
1103 	return -1;
1104     }
1105 
1106     len = (d[0]<<24|d[1]<<16|d[2]<<8|d[3])-4;
1107 
1108     if (len%16)			// insane length
1109     {	fprintf (stderr,":-( GET PERFORMANCE: insane Performance Data Length\n");
1110 	return -1;
1111     }
1112 
1113     perf = (unsigned char *)malloc(len+=8);
1114     if (perf == NULL)
1115 	fprintf (stderr,":-( memory exhausted\n"),
1116 	exit(FATAL_START(ENOMEM));
1117 
1118     if (len == sizeof(d))
1119 	memcpy (perf,d,sizeof(d));
1120     else
1121     { unsigned int n=(len-8)/16;
1122 
1123 	cmd[0]=0xAC;		// GET PERFORMANCE
1124 	cmd[8]=n>>8;
1125 	cmd[9]=n;		// real number of descriptors
1126 	cmd[10]=0x3;		// ask for "Write Speed Descriptor"
1127 	cmd[11]=0;
1128 	if ((err=cmd.transport(READ,perf,len)))
1129 	    sperror ("GET PERFORMANCE",err),
1130 	    exit (FATAL_START(errno));
1131     }
1132 
1133     int targetv=0,errp=0;
1134     do {
1135 	memset (d,0,sizeof(d));
1136 	cmd[0]=0xAC;		// GET PERFORMANCE
1137 	cmd[1]=4;		// ask for "Overall Write performance"
1138 	cmd[9]=1;
1139 	cmd[10]=0;		// ask for descriptor in effect
1140 	cmd[11]=0;
1141 	if (errp || (errp=cmd.transport(READ,d,sizeof(d))))
1142 #if 0
1143 	    sperror ("GET CURRENT PERFORMANCE",errp),
1144 	    exit (FATAL_START(errno));	// well, if it passed above, we
1145 					// expect it to pass this too...
1146 #else	// Pioneer doesn't report current speed through GET PERFORMANCE:-(
1147 	{   emulated_err:
1148 
1149 	    if (page2A == NULL)	return -1;
1150 
1151 	    unsigned int  plen,hlen;
1152 
1153 	    plen = (page2A[0]<<8|page2A[1]) + 2;
1154 	    hlen = 8 + (page2A[6]<<8|page2A[7]);
1155 
1156 	    unsigned char * const p = page2A + hlen;
1157 
1158 	    if (plen<(hlen+32) || p[1]<(32-2))
1159 		return -1;	// well, SET CD SPEED wouldn't work...
1160 
1161 	    velocity = p[28]<<8|p[29];
1162 	}
1163 #endif
1164 	else if ((errp = pull_velocity (cmd,d)) < 0)
1165 		goto emulated_err;
1166 
1167 	if (speed_factor != 0.0)
1168 	{ int i,j=len-8,v,v0,v1,minv,closesti,closestv=0;
1169 	  unsigned char *wsdp=perf+8;
1170 
1171 	    for (minv=0x7fffffff,i=0;i<j;i+=16)
1172 	    {	v=wsdp[i+12]<<24|wsdp[i+13]<<16|wsdp[i+14]<<8|wsdp[i+15];
1173 		if (v<minv) minv=v;
1174 	    } // minv will be treated as 1x
1175 
1176 	    // New generation units offer minimum velocities other than 1x
1177 	    if      (minv>(15*_1x))	speed_factor /= 16.0;
1178 	    else if (minv>(11*_1x))	speed_factor /= 12.0;
1179 	    else if (minv>(7*_1x))	speed_factor /= 8.0;
1180 	    else if (minv>(5*_1x))	speed_factor /= 6.0;
1181 	    else if (minv>(3*_1x))	speed_factor /= 4.0;
1182 	    else if (dvdplus && minv>(2*DVD_1X))
1183 		// 2.4x is like 1x for DVD+, but it turned out that there're
1184 		// units, most notably "DVDRW IDE1004," burning DVD+ at
1185 		// lower speed, so I have to watch out for it...
1186 		speed_factor /= 2.4;
1187 	    else if (minv>=(2*_1x))
1188 		speed_factor /= 2.0;
1189 
1190 	    v0=(int)(speed_factor*minv + 0.5);
1191 	    for (closesti=0,minv=0x7fffffff,i=0;i<j;i+=16)
1192 	    {	v1=wsdp[i+12]<<24|wsdp[i+13]<<16|wsdp[i+14]<<8|wsdp[i+15];
1193 		v=abs(v0-v1);
1194 		if (v<minv) minv=v, closesti=i, closestv=v1;
1195 	    } // currenti is index of descriptor with *closest* velocity
1196 
1197 	    targetv=closestv;
1198 	    speed_factor=0.0;
1199 
1200 	    if (velocity==targetv)
1201 		break;	// already in shape, nothing to do...
1202 
1203 	    unsigned char pd[28];
1204 
1205 	    memset (pd,0,sizeof(pd));	// setup "Performance Descriptor"
1206 
1207 	    pd[0]=*(wsdp+closesti);	// copy "WRC" and other flags
1208 #if 0
1209 	    memset(pd+8,0xFF,4);
1210 #else	    // I might have to copy the value from current descriptor...
1211 	    unsigned int cap=get_2k_capacity(cmd)-1;
1212 
1213 	    pd[8]=cap>>24;
1214 	    pd[9]=cap>>16;
1215 	    pd[10]=cap>>8;
1216 	    pd[11]=cap;
1217 #endif
1218 	    memcpy(pd+12,wsdp+closesti+8,4);	// copy "Read Speed"
1219 	    memcpy(pd+20,wsdp+closesti+12,4);	// copy "Write Speed"
1220 	    pd[18]=pd[26]=1000>>8;		// set both "Read Time" and
1221 	    pd[19]=pd[27]=1000&0xFF;		// "Write Time" to 1000ms
1222 
1223 	    cmd[0]=0xB6;		// SET STREAMING
1224 	    cmd[10]=sizeof(pd);
1225 	    cmd[11]=0;
1226 	    if ((err=cmd.transport (WRITE,pd,sizeof(pd))))
1227 		sperror ("SET STREAMING",err),
1228 		exit (FATAL_START(errno));
1229 
1230 	    // I pull the Page 2A in either case, because unit might
1231 	    // have provided irrelevant information (Plextor). Not to
1232 	    // mention cases when it simply failed to reply to GET
1233 	    // CURRENT PERFORMANCE (Pioneer, LG).
1234 
1235 	    unsigned int plen  = (page2A[0]<<8|page2A[1]) + 2;
1236 
1237 	    cmd[0] = 0x5A;	// MODE SENSE
1238 	    cmd[1] = 0x08;	// "Disable Block Descriptors"
1239 	    cmd[2] = 0x2A;	// "Capabilities and Mechanical Status"
1240 	    cmd[7] = plen>>8;
1241 	    cmd[8] = plen;	// real length this time
1242 	    cmd[9] = 0;
1243 	    if ((err=cmd.transport(READ,page2A,plen)))
1244 		sperror ("MODE SENSE#2A",err),
1245 		exit(FATAL_START(errno));
1246 	}
1247 	else if (targetv)
1248 	{   if (targetv!=velocity)
1249 	    {	if (errp==0)	// check Page 2A for speed then...
1250 		{   errp=-1; continue;   }
1251 		if (velocity==0 || velocity>=_1x)
1252 		{   fprintf(stderr,":-? Failed to change write speed: %d->%d\n",
1253 					(int)velocity,targetv);
1254 		    if (velocity<targetv)	velocity=targetv;
1255 		}
1256 		else
1257 		{   fprintf(stderr,":-( Failed to change write speed: %d->%d\n",
1258 					(int)velocity,targetv);
1259 		    exit (FATAL_START(EINVAL));
1260 		}
1261 	    }
1262 	    break;
1263 	}
1264     } while (targetv);
1265 
1266   return targetv;
1267 }
1268 
set_speed_BBh(Scsi_Command & cmd,unsigned char * page2A)1269 static int set_speed_BBh (Scsi_Command &cmd,unsigned char *page2A)
1270 { unsigned int   plen,hlen;
1271   int err;
1272 
1273     plen  = (page2A[0]<<8|page2A[1]) + 2;
1274     hlen = 8 + (page2A[6]<<8|page2A[7]);
1275 
1276     unsigned char * const p = page2A + hlen;
1277 
1278     if (plen<(hlen+32) || p[1]<(32-2))
1279 	return -1;
1280 
1281     int targetv=0;
1282     do {
1283 	velocity = p[28]<<8|p[29];
1284 
1285 	if (speed_factor != 0.0)
1286 	{ int i,j,v,v0,v1,minv,closesti,closestv=0;
1287 	  unsigned char *wsdp=p+32;
1288 
1289 	    j=(p[30]<<8|p[31])*4;
1290 	    for (minv=0x7fffffff,i=0;i<j;i+=4)
1291 	    {	v=wsdp[i+2]<<8|wsdp[i+3];
1292 		if (v<minv) minv=v;
1293 	    } // minv will be treated as 1x
1294 
1295 	    v0=(int)(speed_factor*minv + 0.5);
1296 	    for (closesti=0,minv=0x7fffffff,i=0;i<j;i+=4)
1297 	    {	v1=wsdp[i+2]<<8|wsdp[i+3];
1298 		v=abs(v0-v1);
1299 		if (v<minv) minv=v, closesti=i, closestv=v1;
1300 	    } // currenti is index of descriptor with *closest* velocity
1301 
1302 	    targetv=closestv;
1303 	    speed_factor=0.0;
1304 
1305 	    if (velocity==targetv)
1306 		break;	// already in shape, nothing to do...
1307 
1308 	    cmd[0]=0xBB;		// SET CD SPEED
1309 	    cmd[1]=wsdp[closesti+1];	// Rotation Control
1310 	    cmd[2]=cmd[3]=0xff;		// Read Speed
1311 	    cmd[4]=wsdp[closesti+2];	// Write Speed
1312 	    cmd[5]=wsdp[closesti+3];
1313 	    cmd[11]=0;
1314 	    if ((err=cmd.transport()))
1315 		sperror ("SET CD SPEED",err),
1316 		exit (FATAL_START(errno));
1317 
1318 	    cmd[0] = 0x5A;	// MODE SENSE
1319 	    cmd[1] = 0x08;	// "Disable Block Descriptors"
1320 	    cmd[2] = 0x2A;	// "Capabilities and Mechanical Status"
1321 	    cmd[7] = plen>>8;
1322 	    cmd[8] = plen;	// real length this time
1323 	    cmd[9] = 0;
1324 	    if ((err=cmd.transport(READ,page2A,plen)))
1325 		sperror ("MODE SENSE#2A",err),
1326 		exit(FATAL_START(errno));
1327 	}
1328 	else if (targetv)
1329 	{   if (targetv!=velocity)
1330 		fprintf (stderr,":-( Failed to change write speed: %d->%d\n",
1331 				(int)velocity,targetv),
1332 		exit (FATAL_START(EINVAL));
1333 	    break;
1334 	}
1335     } while (targetv);
1336 
1337   return targetv;
1338 }
1339 
plusminus_pages_setup(Scsi_Command & cmd,int profile)1340 static int plusminus_pages_setup (Scsi_Command &cmd,int profile)
1341 { unsigned int   plen,hlen,dvddash=0,dvdplus=0;
1342   unsigned char  header[16],p32;
1343   int            err;
1344   class autofree page2A;
1345 
1346     switch (profile)
1347     {	case 0x1A:	// DVD+RW
1348 	    p32 = 0;
1349 	    dvdplus=1;
1350 	    break;
1351 	case 0x1B:	// DVD+R
1352 	    //
1353 	    // Even though MMC-4 draft explicitely exempts DVD+RW/+R media
1354 	    // from those being affected by Page 05h settings, some
1355 	    // firmwares apparently pay attention to Multi-session flag
1356 	    // when finalizing DVD+R media. Well, we probably can't blame
1357 	    // vendors as specification is still a work in progress, not to
1358 	    // mention that it was published after DVD+R was introduced to
1359 	    // the market.
1360 	    //
1361 	    p32 = dvd_compat?0x02:0xC0;
1362 	    dvdplus=1;
1363 	    break;
1364 	case 0x13:	// DVD-RW Restricted Overwrite
1365 	    p32 = 0xC0;	// NB! Test Write in not option here
1366 	    dvddash = 1;
1367 	    break;
1368 	case 0x11:	// DVD-R Sequential
1369 	case 0x14:	// DVD-RW Sequential
1370 	case 0x15:	// DVD-R Dual Layer Sequential
1371 	    p32 = 0xC0;
1372 	    if (next_track==1) do
1373 	    {	if (dvd_compat >= (profile==0x14?2:256))
1374 		{   is_dao = 1,
1375 		    fprintf (stderr,"%s: engaging DVD-%s DAO upon user request...\n",
1376 				    ioctl_device,profile==0x14?"RW":"R");
1377 		    break;
1378 		}
1379 
1380 		// Try to figure out if we have to go for DAO...
1381 		cmd[0] = 0x46;	// GET CONFIGURATION
1382 		cmd[1] = 2;	// ask for the only feature...
1383 		cmd[3] = 0x21;	// the "Incremental Streaming Writable" one
1384 		cmd[8] = 16;	// The feature should be there, right?
1385 		cmd[9] = 0;
1386 		if ((err=cmd.transport (READ,header,16)))
1387 		    sperror ("GET FEATURE 21h",err),
1388 		    exit(FATAL_START(errno));
1389 
1390 		hlen = header[0]<<24|header[1]<<16|header[2]<<8|header[3];
1391 		// See if Feature 21h is "current," if not, engage DAO...
1392 		if (hlen>=12 && (header[8+2]&1)==0)
1393 		{   is_dao = dvd_compat = 1;
1394 		    fprintf (stderr,"%s: FEATURE 21h is not on, engaging DAO...\n",
1395 				    ioctl_device);
1396 		    break;
1397 		}
1398 	    } while (0);
1399 
1400 	    if (is_dao)		p32 |=2;	// DAO
1401 
1402 	    if (profile==0x15 || // DVD-R DL Seq has no notion of multi-session
1403 		dvd_compat)	p32 &= 0x3F;	// Single-session
1404 
1405 	    if (test_write)
1406 		p32 |= 0x10;	// Test Write for debugging purposes
1407 
1408 	    dvddash=1;
1409 	    break;
1410 	case 0x16:	// DVD-R Dual Layer Jump
1411 	    p32 = 0xC0;
1412 	    p32 |= 4;	// Jump
1413 	    if (test_write)
1414 		p32 |= 0x10;	// Test Write for debugging purposes
1415 
1416 	    dvddash=1;
1417 	    break;
1418 	default:
1419 	    p32 = 0;
1420 	    break;
1421     }
1422 
1423     if (dvddash || p32)	page05_setup (cmd,profile,p32);
1424 
1425     page2A = pull_page2A (cmd);
1426 
1427     plen = (page2A[0]<<8|page2A[1]) + 2;
1428     hlen = 8 + (page2A[6]<<8|page2A[7]);
1429 
1430     unsigned char * const p = page2A + hlen;
1431 
1432     if (plen<(hlen+14) || p[1]<(14-2))	// no "Buffer Size Supported"
1433 	buf_size = 512;			// bogus value
1434     else
1435     	buf_size = (p[12]<<8|p[13]);
1436     if (buf_size<512)			// bogus value
1437 	buf_size = 512;
1438 
1439     // GET PERFORMANCE/SET STREAMING are listed as mandatory, so that
1440     // this is actually the most likely path...
1441     if (set_speed_B6h (cmd,dvdplus,page2A) >= 0)
1442 	goto opc;
1443 
1444     if (plen<(hlen+30) || p[1]<(30-2))	// no "Current Write Speed" present
1445     {	if (dvddash)
1446 	{   fprintf (stderr,":-( \"Current Write Speed\" descriptor "
1447 			    "is not present, faking 1x...\n"),
1448 	    velocity = _1x;
1449 	    speed_factor = 0.0;
1450 	}
1451 	else
1452 	    velocity = 0;
1453     }
1454     else do
1455     {	velocity = p[28]<<8|p[29];
1456 
1457 	// Some units, most notably NEC and derivatives, were observed
1458 	// to report CD-R descriptors...
1459 	if (velocity < DVD_1X)			// must be bogus
1460 	{   velocity=0;
1461 	    break;
1462 	}
1463 
1464 	if (plen<(hlen+32) || p[1]<(32-2))	// no write descriptors
1465 	    break;
1466 
1467 	int            n = p[30]<<8|p[31],minv=1<<16;
1468 	unsigned char *p_= p+32;
1469 	for (;n--;p_+=4)
1470 	{   int v=p_[2]<<8|p_[3];
1471 	    if (v==0) continue;		// Lite-On returns zeros here...
1472 	    if (v<_1x)			// must be bogus
1473 		velocity=0;
1474 	    if (v < minv)
1475 		minv = v;
1476 	}
1477 	if (dvdplus && minv>2*_1x)
1478 	    // See corresponding comment in set_speed_B6h()
1479 	    speed_factor /= 2.4;
1480 
1481     } while (0);
1482 
1483     if (speed_factor != 0.0 &&
1484 	(velocity==0 || set_speed_BBh (cmd,page2A)<0) )
1485 	fprintf (stderr,":-( can't control writing velocity, "
1486 			"-speed option is ignored\n");
1487 opc:
1488 
1489     if (!dvddash || test_write || no_opc) return 0;
1490 
1491     // See if OPC is required...
1492     cmd[0] = 0x51;	// READ DISC INFORMATION
1493     cmd[8] = 8;
1494     cmd[9] = 0;
1495     if ((err=cmd.transport (READ,header,8)))
1496 	sperror ("READ DISC INFORMATION",err),
1497 	exit(FATAL_START(errno));
1498 
1499     if ((header[0]<<8|header[1]) <= 0x20)
1500     {	cmd[0] = 0x54;	// SEND OPC INFORMATION
1501 	cmd[1] = 1;	// "Perform OPC"
1502 	cmd[9] = 0;
1503 	cmd.timeout(120);	// NEC units can be slooo...w
1504 	if ((err=cmd.transport())) do
1505 	{   if (err==0x17301)	// "POWER CALIBRATION AREA ALMOST FULL"
1506 	    {	fprintf (stderr,":-! WARNING: Power Calibration Area "
1507 	    			    "is almost full\n");
1508 		break;
1509 	    }
1510 	    sperror ("PERFORM OPC",err);
1511 	    if ((err&0x0FF00)==0x07300 && (err&0xF0000)!=0x10000)
1512 		exit(FATAL_START(errno));
1513 	    /*
1514 	     * The rest of errors are ignored, most notably observed:
1515 	     * 0x52000, "INVALID COMMAND"		Panasonic LD-F321
1516 	     * 0x52700, "WRITE PROTECTED"		Plextor PX-712A
1517 	     * 0x52C00, "COMMAND SEQUENCE ERROR"	Plextor PX-716UF
1518 	     * 0x53002, "MEDIA NOT SUPPORTED"		Toshiba TS-H542A
1519 	     */
1520 	} while (0);
1521     }
1522 
1523     handle_events(cmd);
1524 
1525   return 0;
1526 }
1527 
minus_rw_quickgrow(Scsi_Command & cmd,off64_t size)1528 static int minus_rw_quickgrow (Scsi_Command &cmd,off64_t size)
1529 { unsigned char	format[12];
1530   unsigned int	lead_out,blocks,type;
1531   int		i,len,err;
1532 
1533     type = formats[4+4]&3;
1534 
1535     if (type==2 && size!=0)
1536     {	blocks = (unsigned int)(size/2048);
1537 	blocks += 15, blocks &= ~15;
1538 
1539 	lead_out = 0;
1540 	lead_out |= formats[4+0], lead_out <<= 8;
1541 	lead_out |= formats[4+1], lead_out <<= 8;
1542 	lead_out |= formats[4+2], lead_out <<= 8;
1543 	lead_out |= formats[4+3];
1544 
1545 	if (blocks<=lead_out)	// no need to grow the session...
1546 	    return 0;
1547     }
1548 
1549     // look for Quick Grow descriptor...
1550     for (i=8,len=formats[3];i<len;i+=8)
1551 	if ((formats [4+i+4]>>2) == 0x13) break;
1552 
1553     if (i==len)			// no Quick Grow descriptor
1554     {	if (type != 2)
1555 	    quickgrown=1;	// in reality quick formatted...
1556 	return 0;
1557     }
1558     else
1559     {	blocks = 0;
1560 	blocks |= formats[i+0], blocks <<= 8;
1561 	blocks |= formats[i+1], blocks <<= 8;
1562 	blocks |= formats[i+2], blocks <<= 8;
1563 	blocks |= formats[i+3];
1564 	if (type==2 && blocks==0)	// nowhere no grow...
1565 	    return 0;
1566     }
1567 
1568     quickgrown=1;
1569     fprintf (stderr,"%s: \"Quick Grow\" session...\n",ioctl_device);
1570 
1571     memset (format,0,sizeof(format));
1572     format [1] = 2;		// "IMMED"
1573     format [3] = 8;		// "Length"
1574     format [8] = 0x13<<2;	// "Quick Grow"
1575     format [11] = 16;
1576 
1577     cmd[0] = 0x4;		// FORMAT UNIT
1578     cmd[1] = 0x11;
1579     cmd[5] = 0;
1580     if ((err=cmd.transport (WRITE,format,sizeof(format))))
1581     {	sperror ("QUICK GROW",err);
1582 	return 1;
1583     }
1584 
1585   return wait_for_unit (cmd);
1586 }
1587 
minus_r_reserve_track(Scsi_Command & cmd,off64_t size)1588 static int minus_r_reserve_track (Scsi_Command &cmd,off64_t size)
1589 { int          err;
1590   unsigned int blocks;
1591 
1592     blocks = (unsigned int)(size/2048);
1593     if (is_dao)	dao_blocks = blocks;
1594     else	blocks += 15, blocks &= ~15;
1595 
1596     fprintf (stderr,"%s: reserving %u blocks",ioctl_device,blocks);
1597     if (is_dao && blocks<380000)
1598 	fprintf (stderr,"\b, warning for short DAO recording"),
1599 	poll (NULL,0,5000);
1600     fprintf (stderr,"\n");
1601 
1602 
1603     cmd[0] = 0x53;		// RESERVE TRACK
1604     cmd[5] = blocks>>24;
1605     cmd[6] = blocks>>16;
1606     cmd[7] = blocks>>8;
1607     cmd[8] = blocks;
1608     cmd[9] = 0;
1609     if ((err=cmd.transport ()))
1610     {	sperror ("RESERVE TRACK",err);
1611 	return 1;
1612     }
1613 
1614   return 0;
1615 }
1616 
plus_r_dl_split(Scsi_Command & cmd,off64_t size)1617 static void plus_r_dl_split (Scsi_Command &cmd,off64_t size)
1618 { int           err;
1619   unsigned int  blocks,split;
1620   unsigned char dvd_20[4+8];
1621 
1622     cmd[0] = 0xAD;	// READ DVD STRUCTURE
1623     cmd[7] = 0x20;	// "DVD+R Double Layer Boundary Information"
1624     cmd[9] = sizeof(dvd_20);
1625     cmd[11] = 0;
1626     if ((err=cmd.transport(READ,dvd_20,sizeof(dvd_20))))
1627     	sperror ("READ DVD+R DL BOUNDARY INFORMATION",err),
1628 	exit (FATAL_START(errno));
1629 
1630     if ((dvd_20[0]<<8|dvd_20[1]) < 10)
1631 	fprintf (stderr,":-( insane DVD+R DL BI structure length\n"),
1632 	exit (FATAL_START(EINVAL));
1633 
1634     if (dvd_20[4]&0x80)
1635     {	fprintf (stderr,":-? L0 Data Zone Capacity is set already\n");
1636 	return;
1637     }
1638 
1639     split = dvd_20[8]<<24|dvd_20[9]<<16|dvd_20[10]<<8|dvd_20[11];
1640 
1641     blocks = (unsigned int)(size/2048);
1642     blocks += 15, blocks &= ~15;
1643 
1644     if (blocks <= split)
1645 	fprintf (stderr,":-( more than 50%% of space will be *wasted*!\n"
1646 			"    use single layer media for this recording\n"),
1647 	exit (FATAL_START(EMEDIUMTYPE));
1648 
1649     blocks /= 16;
1650     blocks += 1;
1651     blocks /= 2;
1652     blocks *= 16;
1653 
1654     fprintf (stderr,"%s: splitting layers at %u blocks\n",
1655 		    ioctl_device,blocks);
1656 
1657     memset (dvd_20,0,sizeof(dvd_20));
1658     dvd_20[1]  = sizeof(dvd_20)-2;
1659     dvd_20[8]  = blocks>>24;
1660     dvd_20[9]  = blocks>>16;
1661     dvd_20[10] = blocks>>8;
1662     dvd_20[11] = blocks;
1663 
1664     cmd[0] = 0xBF;	// SEND DVD STRUCTURE
1665     cmd[7] = 0x20;	// "DVD+R Double Layer Recording Information"
1666     cmd[9] = sizeof(dvd_20);
1667     cmd[11] = 0;
1668     cmd.timeout(180);	// Lite-on seems to fire off calibration here
1669     if ((err=cmd.transport(WRITE,dvd_20,sizeof(dvd_20))))
1670 	sperror ("SEND DVD+R DOUBLE LAYER RECORDING INFORMATION",err),
1671 	exit (FATAL_START(errno));
1672 
1673 }
1674 
flush_cache(Scsi_Command & cmd,int even_sync=1)1675 static int flush_cache (Scsi_Command &cmd, int even_sync=1)
1676 { int err;
1677 
1678     cmd[0] = 0x35;		// FLUSH CACHE
1679     cmd[1] = 0x02;		// "IMMED"
1680     cmd[9] = 0;
1681     if (!(err=cmd.transport()))
1682 	wait_for_unit (cmd);
1683     else
1684 	sperror ("FLUSH CACHE",err);
1685 
1686     if (even_sync)		// Pioneer apparently needs this,
1687     {				// non-IMMED FLUSH that is...
1688 	cmd[0] = 0x35;		// FLUSH CACHE
1689 	cmd[9] = 0;
1690 	if (is_dao) cmd.timeout (15*60);
1691 	if ((err=cmd.transport()))
1692 	{   sperror ("SYNCHRONOUS FLUSH CACHE",err);
1693 	    return err;
1694 	}
1695     }
1696 
1697   return 0;
1698 }
1699 
1700 //
1701 // atexit/signal handlers
1702 //
1703 extern "C"
no_r_finalize()1704 void no_r_finalize ()
1705 {   while (media_written)
1706     { Scsi_Command cmd(ioctl_handle);
1707 
1708 	fprintf (stderr,"%s: flushing cache\n",ioctl_device);
1709 	if (flush_cache (cmd))	break;
1710 
1711 	pioneer_stop (cmd);
1712 
1713 	media_written = 0;
1714 	errno = EINTR;
1715     }
1716     _exit (errno);
1717 }
1718 
1719 extern "C"
plus_rw_finalize()1720 void plus_rw_finalize ()
1721 { int saved_errno = errno;
1722 
1723     sigs_mask(SIGS_BLOCK);
1724     while (media_written)
1725     { Scsi_Command cmd(ioctl_handle);
1726       int err;
1727 
1728 	fprintf (stderr,"%s: flushing cache\n",ioctl_device);
1729 	if (flush_cache (cmd))	break;
1730 
1731 	if (!dvd_compat)
1732 	{   fprintf (stderr,"%s: stopping de-icing\n",ioctl_device);
1733 	    cmd[0] = 0x5B;	// CLOSE TRACK/SESSION
1734 	    cmd[1] = 0x01;	// "IMMED"
1735 	    cmd[2] = 0;		// "Stop De-Icing"
1736 	    cmd[9] = 0;
1737 	    if ((err=cmd.transport()))
1738 		sperror ("STOP DE-ICING",err);
1739 
1740 	    if (wait_for_unit (cmd)) break;
1741 	}
1742 
1743 	fprintf (stderr,"%s: writing lead-out\n",ioctl_device);
1744 	cmd[0] = 0x5B;		// CLOSE TRACK/SESSION
1745 	cmd[1] = 0x01;		// "IMMED"
1746 	cmd[2] = 0x02;		// "Close session"
1747 	cmd[9] = 0;
1748 	if ((err=cmd.transport()))
1749 	    sperror ("CLOSE SESSION",err);
1750 
1751 	if (wait_for_unit (cmd)) break;
1752 
1753 	media_written = 0;
1754 	next_wr_addr = 0;
1755 
1756 	if (do_reload && media_reload())
1757 	    perror (":-( unable to reload tray");// not actually reached
1758 
1759 	errno = saved_errno;
1760     }
1761     _exit (errno);
1762 }
1763 
1764 extern "C"
bd_re_finalize()1765 void bd_re_finalize ()
1766 { int saved_errno = errno;
1767 
1768     sigs_mask(SIGS_BLOCK);
1769     while (media_written)
1770     { Scsi_Command cmd(ioctl_handle);
1771 
1772 	fprintf (stderr,"%s: flushing cache\n",ioctl_device);
1773 	if (flush_cache (cmd))	break;
1774 
1775 	media_written = 0;
1776 	next_wr_addr = 0;
1777 
1778 	if (do_reload && media_reload())
1779 	    perror (":-( unable to reload tray");// not actually reached
1780 
1781 	errno = saved_errno;
1782     }
1783     _exit (errno);
1784 }
1785 
1786 extern "C"
plus_r_finalize()1787 void plus_r_finalize ()
1788 { int saved_errno = errno;
1789 
1790     sigs_mask(SIGS_BLOCK);
1791     while (media_written)
1792     { Scsi_Command cmd(ioctl_handle);
1793       int          mode,err;
1794 
1795 	fprintf (stderr,"%s: flushing cache\n",ioctl_device);
1796 	if (flush_cache(cmd))	break;
1797 
1798 	fprintf (stderr,"%s: closing track\n",ioctl_device);
1799 	cmd[0] = 0x5B;		// CLOSE TRACK/SESSION
1800 	cmd[1] = 0x01;		// "IMMED"
1801 	cmd[2] = 0x01;		// "Close Track"
1802 	cmd[4] = next_track>>8;
1803 	cmd[5] = next_track;
1804 	cmd[9] = 0;
1805 	if ((err=cmd.transport()))
1806 	    sperror ("CLOSE TRACK",err), saved_errno = errno;
1807 
1808 	if (wait_for_unit (cmd)) break;
1809 
1810 	if (dvd_compat)
1811 	    // HP dvd520n insists on "finalize with minimum radius"
1812 	    // with DVD+R DL ---------------vv
1813 	    mode = ((mmc_profile&0xFFFF)==0x2B)?0x05:0x06,
1814 	    fprintf (stderr,"%s: closing disc\n",ioctl_device);
1815 	else
1816 	    mode = 0x02,
1817 	    fprintf (stderr,"%s: closing session\n",ioctl_device);
1818 
1819 	while (1)	// Pioneer DVR-K04RA
1820 	{   cmd[0] = 0x5B;		// CLOSE TRACK/SESSION
1821 	    cmd[1] = 0x01;		// "IMMED"
1822 	    cmd[2] = mode;		// "Close session"
1823 	    cmd[9] = 0;
1824 	    err = cmd.transport();
1825 	    if (err == 0x20407)		// "OP IN PROGRESS"
1826 	    {	poll (NULL,0,stdnap);
1827 		continue;
1828 	    }
1829 	    else if (err)
1830 		sperror (dvd_compat?"CLOSE DISC":"CLOSE SESSION",err),
1831 		saved_errno = errno;
1832 	    break;
1833 	}
1834 
1835 	if (wait_for_unit (cmd)) break;
1836 
1837 	media_written = 0;
1838 
1839 	if (do_reload && media_reload())
1840 	    perror (":-( unable to reload tray");// not actually reached
1841 
1842 	errno = saved_errno;
1843     }
1844     _exit (errno);
1845 }
1846 
1847 extern "C"
minus_rw_finalize()1848 void minus_rw_finalize ()
1849 { int saved_errno = errno;
1850 
1851     sigs_mask(SIGS_BLOCK);
1852     while (media_written)
1853     { Scsi_Command cmd(ioctl_handle);
1854       int err;
1855 
1856 	fprintf (stderr,"%s: flushing cache\n",ioctl_device);
1857 	if (flush_cache(cmd))	break;
1858 
1859 	if (quickgrown)
1860 	{   fprintf (stderr,"%s: writing lead-out\n",ioctl_device);
1861 	    cmd[0] = 0x5B;		// CLOSE TRACK/SESSION
1862 	    cmd[1] = 0x01;		// "IMMED"
1863 	    cmd[2] = 0x02;		// "Close Session"
1864 	    cmd[9] = 0;
1865 	    if ((err=cmd.transport()))
1866 		sperror ("CLOSE SESSION",err), saved_errno = errno;
1867 
1868 	    if (wait_for_unit (cmd)) break;
1869 
1870 	    quickgrown=0;
1871 	}
1872 
1873 	media_written = 0;
1874 	next_wr_addr = 0;
1875 
1876 	if (do_reload)
1877 	{   if (media_reload())
1878 		perror (":-( unable to reload tray");// not actually reached
1879 	}
1880 	else return;	// Restricted Overwrite is just ugly!
1881 
1882 	errno = saved_errno;
1883     }
1884     _exit (errno);
1885 }
1886 
1887 extern "C"
minus_r_finalize()1888 void minus_r_finalize ()
1889 { int saved_errno = errno;
1890 
1891     sigs_mask(SIGS_BLOCK);
1892     while (media_written)
1893     { Scsi_Command cmd(ioctl_handle);
1894       int err;
1895 
1896 	fprintf (stderr,"%s: flushing cache\n",ioctl_device);
1897 	if (flush_cache(cmd,!is_dao))	break;
1898 
1899 	if (!is_dao)
1900 	{   fprintf (stderr,"%s: updating RMA\n",ioctl_device);
1901 	    cmd[0] = 0x5B;	// CLOSE TRACK/SESSION
1902 	    cmd[1] = 0x01;	// "IMMED"
1903 	    cmd[2] = 0x01;	// "Close Track"
1904 	    cmd[4] = next_track>>8;
1905 	    cmd[5] = next_track;
1906 	    cmd[9] = 0;
1907 	    if ((err=cmd.transport()))
1908 		sperror ("CLOSE TRACK",err), saved_errno = errno;
1909 
1910 	    if (wait_for_unit (cmd)) break;
1911 
1912 	    fprintf (stderr,"%s: closing %s\n",ioctl_device,
1913 			    dvd_compat?"disc":"session");
1914 
1915 	    while (1)	// Pioneer DVR-K04RA
1916 	    {	cmd[0] = 0x5B;	// CLOSE TRACK/SESSION
1917 		cmd[1] = 0x01;	// "IMMED"
1918 		cmd[2] = 0x02;	// "Close Session"
1919 		cmd[9] = 0;
1920 		err = cmd.transport();
1921 		if (err == 0x20407)		// "OP IN PROGRESS"
1922 		{   poll (NULL,0,stdnap);
1923 		    continue;
1924 		}
1925 		else if (err)
1926 		    sperror (dvd_compat?"CLOSE DISC":"CLOSE SESSION",err),
1927 		    saved_errno = errno;
1928 		break;
1929 	    }
1930 
1931 	    if (wait_for_unit (cmd)) break;
1932 	}
1933 
1934 	media_written = 0;
1935 
1936 	if (do_reload && media_reload())
1937 	    perror (":-( unable to reload tray");// not actually reached
1938 
1939 	errno = saved_errno;
1940     }
1941     _exit (errno);
1942 }
1943 
1944 extern "C"
bd_r_finalize()1945 void bd_r_finalize ()
1946 { int saved_errno = errno;
1947 
1948     sigs_mask(SIGS_BLOCK);
1949     while (media_written)
1950     { Scsi_Command  cmd(ioctl_handle);
1951       int           err;
1952 
1953 	fprintf (stderr,"%s: flushing cache\n",ioctl_device);
1954 	if (flush_cache(cmd))	break;
1955 
1956 	fprintf (stderr,"%s: closing track\n",ioctl_device);
1957 	cmd[0] = 0x5B;		// CLOSE TRACK/SESSION
1958 	cmd[1] = 0x01;		// "IMMED"
1959 	cmd[2] = 0x01;		// "Close Track"
1960 	cmd[4] = next_track>>8;
1961 	cmd[5] = next_track;
1962 	cmd[9] = 0;
1963 	if ((err=cmd.transport()))
1964 	    sperror ("CLOSE TRACK",err), saved_errno = errno;
1965 
1966 	if (wait_for_unit (cmd)) break;
1967 
1968 	if (!bdr_plus_pow)
1969 	{   fprintf (stderr,"%s: closing session\n",ioctl_device);
1970 	    while (1)	// Pioneer DVR-K04RA
1971 	    {	cmd[0] = 0x5B;		// CLOSE TRACK/SESSION
1972 		cmd[1] = 0x01;		// "IMMED"
1973 		cmd[2] = 0x02;		// "Close session"
1974 		cmd[9] = 0;
1975 		err = cmd.transport();
1976 		if (err == 0x20407)		// "OP IN PROGRESS"
1977 		{   poll (NULL,0,stdnap);
1978 		    continue;
1979 		}
1980 		else if (err)
1981 		    sperror ("CLOSE SESSION",err), saved_errno = errno;
1982 		break;
1983 	    }
1984 
1985 	    if (wait_for_unit (cmd)) break;
1986  	}
1987 
1988 	media_written = 0;
1989 
1990 	if (do_reload && media_reload())
1991 	    perror (":-( unable to reload tray");// not actually reached
1992 
1993 	errno = saved_errno;
1994     }
1995     _exit (errno);
1996 }
1997 
1998 extern "C"
ram_reload()1999 void ram_reload ()
2000 { int saved_errno = errno;
2001     sigs_mask(SIGS_BLOCK);
2002     if (media_written && do_reload) media_reload();
2003     _exit (saved_errno);
2004 }
2005 
2006 //
2007 // poor_mans_setup takes care of a lot of things.
2008 // It's invoked right before first write and if necessary/applicable
2009 // prepares Page 05, reserves track, sets up atexit and signal handlers.
2010 //
2011 
2012 typedef ssize_t (*pwrite64_t)(int,const void *,size_t,off64_t);
2013 
2014 extern "C"
poor_mans_setup(void * fd,off64_t leadout)2015 pwrite64_t poor_mans_setup (void *fd,off64_t leadout)
2016 { Scsi_Command cmd(ioctl_handle=fd);
2017   int err,profile=mmc_profile&0xFFFF;
2018 
2019     // We might have loaded media ourselves, in which case we
2020     // should lock the door...
2021     cmd[0] = 0x1E;  // PREVENT/ALLOW MEDIA REMOVAL
2022     cmd[4] = 1;     // "Prevent"
2023     cmd[5] = 0;
2024     if ((err=cmd.transport ()))
2025 	sperror ("PREVENT MEDIA REMOVAL",err),
2026 	exit (FATAL_START(errno));
2027 
2028     handle_events(cmd);
2029 
2030     // This actually belongs in get_mmc_profile, but the trouble
2031     // is that Mac OS X does not implement ReadCapacity method and
2032     // therefore we have to do it here, after we went exclusive...
2033     if (!(mmc_profile&0x10000))	// non-blank media
2034     { unsigned char c[8];
2035 
2036 	cmd[0] = 0x25;	// READ CAPACITY
2037 	cmd[9] = 0;
2038 	if (!cmd.transport (READ,c,sizeof(c)))
2039 	    cap2kstart = c[0]<<24|c[1]<<16|c[2]<<8|c[3];
2040     }
2041 
2042     switch (profile)
2043     {	case 0x1A:	// DVD+RW
2044 	    switch (disc_info[7]&3)	// Background formatting
2045 	    {	case 0:	// blank
2046 			plus_rw_format (cmd);
2047 			break;
2048 		case 1:	// suspended
2049 			plus_rw_restart_format (cmd,leadout);
2050 			break;
2051 		case 2:	// in progress
2052 		case 3: // complete
2053 			break;
2054 	    }
2055 
2056 	    plusminus_pages_setup (cmd,profile);
2057 	    atexit (plus_rw_finalize);
2058 	    atsignals (plus_rw_finalize);
2059 	    break;
2060 	case 0x1B:	// DVD+R
2061 	case 0x2B:	// DVD+R Double Layer
2062 	    plusminus_pages_setup(cmd,profile);
2063 	    if (profile==0x2B && next_track==1 && dvd_compat && leadout)
2064 		plus_r_dl_split (cmd,leadout);
2065 	    atexit (plus_r_finalize);
2066 	    if (next_wr_addr)
2067 	    {	atsignals (no_r_finalize);
2068 		next_wr_addr=(unsigned int)-1;
2069 	    }
2070 	    else atsignals (plus_r_finalize);
2071 	    break;
2072 	case 0x13:	// DVD-RW Restricted Overwrite
2073 	    plusminus_pages_setup (cmd,profile);
2074 	    //
2075 	    // A side note. Quick Grow can't be performed earlier,
2076 	    // as then reading is not possible.
2077 	    //
2078 	    minus_rw_quickgrow (cmd,leadout);
2079 	    atexit (minus_rw_finalize);
2080 	    atsignals (minus_rw_finalize);
2081 	    break;
2082 	case 0x11:	// DVD-R Sequential
2083 	case 0x14:	// DVD-RW Sequential
2084 	case 0x15:	// DVD-R Dual Layer Sequential
2085 	    plusminus_pages_setup (cmd,profile);
2086 	    if ((profile==0x15) && leadout)
2087 	    {	unsigned char dvd_10[4+16];
2088 		unsigned int layer_size,data_size=(unsigned int)(leadout/2048);
2089 
2090 		cmd[0] = 0xAD;	// READ DVD STRUCTURE
2091 		cmd[7] = 0x10;
2092 		cmd[9] = sizeof(dvd_10);
2093 		cmd[11] = 0;
2094 		if ((err=cmd.transport(READ,dvd_10,sizeof(dvd_10))))
2095 		    sperror("READ DVD STRUCTURE #10h",err),
2096 		    exit(FATAL_START(errno));
2097 
2098 		layer_size  = dvd_10[4+13]<<16,
2099 		layer_size |= dvd_10[4+14]<<8,
2100 		layer_size |= dvd_10[4+15];
2101 
2102 		if (data_size <= layer_size)
2103 		    fprintf (stderr,":-( more than 50%% of space will be *wasted*!\n"
2104 				    "    use single layer media for this recording\n"),
2105 		    exit(FATAL_START(EMEDIUMTYPE));
2106 	    }
2107 	    if (is_dao && leadout)
2108 		minus_r_reserve_track(cmd,leadout);
2109 	    atexit (minus_r_finalize);
2110 	    if (next_wr_addr)
2111 	    {	atsignals (no_r_finalize);
2112 		next_wr_addr=(unsigned int)-1;
2113 	    }
2114 	    else atsignals (minus_r_finalize);
2115 	    break;
2116 	case 0x12:	// DVD-RAM
2117 	    // exclusively for speed settings...
2118 	    plusminus_pages_setup (cmd,profile);
2119 	    atexit (ram_reload);
2120 	    atsignals (ram_reload);
2121 	    break;
2122 	case 0x41:	// BD-R SRM
2123 	    if ((disc_info[2]&3) == 0)	// blank
2124 		bd_r_format (cmd);
2125 	    // exclusively for speed settings...
2126 	    plusminus_pages_setup (cmd,profile);
2127 	    atexit (bd_r_finalize);
2128 	    if (next_wr_addr)
2129 	    {	atsignals (no_r_finalize);
2130 		next_wr_addr=(unsigned int)-1;
2131 	    }
2132 	    else atsignals (bd_r_finalize);
2133 	    break;
2134 	case 0x43:	// BR-RE
2135 	    if ((disc_info[2]&3) == 0)	// blank
2136 		bd_re_format (cmd);
2137 	    // exclusively for speed settings...
2138 	    plusminus_pages_setup (cmd,profile);
2139 	    atexit(bd_re_finalize);
2140 	    atsignals(bd_re_finalize);
2141 	    break;
2142 	case 0x42:	// BD-R RRM is not supported yet...
2143 	case 0x16:	// DVD-R Dual Layer Jump not supported for reasons
2144 			// discussed at web-page...
2145 	default:
2146 	    fprintf (stderr,":-( mounted media[%X] is not supported\n",profile),
2147 	    exit(FATAL_START(EMEDIUMTYPE));
2148 	    break;
2149     }
2150 
2151     if (velocity)
2152 	fprintf (stderr,"%s: \"Current Write Speed\" is %.1fx%dKBps.\n",
2153 			ioctl_device,velocity/(double)_1x,_1x);
2154 
2155     if (next_wr_addr==(unsigned int)-1) do
2156     { unsigned char track[32];
2157 
2158 	next_wr_addr = 0;
2159 
2160 	cmd[0] = 0x52;	// READ TRACK INFORMATION
2161 	cmd[1] = 1;
2162 	cmd[4] = next_track>>8;
2163 	cmd[5] = next_track&0xFF;	// last track, set up earlier
2164 	cmd[8] = sizeof(track);
2165 	cmd[9] = 0;
2166 	if (cmd.transport (READ,track,sizeof(track)))
2167 	    break;
2168 
2169 	if (track[7]&1)	// NWA_V
2170 	{   next_wr_addr  = track[12]<<24;
2171 	    next_wr_addr |= track[13]<<16;
2172 	    next_wr_addr |= track[14]<<8;
2173 	    next_wr_addr |= track[15];
2174 	}
2175 
2176 	if (next_wr_addr != // track start
2177 	    (unsigned int)(track[8]<<24|track[9]<<16|track[10]<<8|track[11]))
2178 	    fprintf (stderr,":-? resuming track#%d from LBA#%d\n",
2179 			    next_track,next_wr_addr);
2180 
2181     } while (0);
2182     else next_wr_addr = 0;
2183 
2184   return poor_mans_pwrite64;
2185 }
2186 
2187 extern "C"
poor_man_rewritable(void * fd,void * buf)2188 int poor_man_rewritable (void *fd, void *buf)
2189 { Scsi_Command	cmd(fd);
2190   int		err,profile=mmc_profile&0xFFFF;
2191 
2192     if (profile!=0x13 &&	// not DVD-RW Restricted Overwrite
2193 	profile!=0x12 &&	// nor DVD-RAM
2194 	profile!=0x1A &&	// nor DVD+RW
2195 	profile!=0x2A &&	// nor DVD+RW Double Layer
2196 	!(profile==0x41 && bdr_plus_pow) && // nor BD-R SRM+POW
2197 	profile!=0x42 &&	// nor BD-R RRM
2198 	profile!=0x43)		// nor BD-RE
2199 	return 0;
2200 
2201     if (profile==0x13)		// DVD-RW Restricted Overwrite
2202     {	// Yet another restriction of Restricted Overwrite mode?
2203 	// Pioneer DVR-x05 can't read a bit otherwise...
2204 	do_reload=0;
2205 	minus_rw_finalize ();	// with do_reload==0!
2206 	do_reload=1;
2207     }
2208     else if (profile==0x1A ||		// DVD+RW
2209 	     profile==0x2A ||		// DVD+RW Double Layer
2210 	     (profile&=0xF0)==0x40)	// BD-R[E]
2211     {	fprintf (stderr,"%s: flushing cache\n",ioctl_device);
2212 	if (flush_cache(cmd))	exit (errno);
2213     }
2214 
2215     cmd[0] = 0x28;	// READ(10)
2216     cmd[5] = 16;	// LBA#16, volume descriptor set
2217     cmd[8] = 16;	// 32KB
2218     cmd[9] = 0;
2219     if ((err=cmd.transport (READ,buf,16*2048)))
2220 	sperror ("READ@LBA=10h",err),
2221 	exit(errno);
2222 
2223   return 1;
2224 }
2225