1 /*
2  *   libdi - CD Audio Device Interface Library
3  *
4  *   Copyright (C) 1993-2004  Ti Kan
5  *   E-mail: xmcd@amb.org
6  *
7  *   This program is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU General Public License as published by
9  *   the Free Software Foundation; either version 2 of the License, or
10  *   (at your option) any later version.
11  *
12  *   This program is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with this program; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21 #ifndef lint
22 static char *_scsipt_c_ident_ = "@(#)scsipt.c	6.278 04/03/17";
23 #endif
24 
25 #include "common_d/appenv.h"
26 #include "common_d/util.h"
27 #include "libdi_d/libdi.h"
28 #include "libdi_d/scsipt.h"
29 #include "cdda_d/cdda.h"
30 
31 #ifdef DI_SCSIPT
32 
33 extern appdata_t	app_data;
34 extern FILE		*errfp;
35 extern di_client_t	*di_clinfo;
36 extern char		**di_devlist;
37 extern sword32_t	di_clip_frames;
38 
39 STATIC bool_t	scsipt_do_start_stop(di_dev_t *, bool_t, bool_t, bool_t),
40 		scsipt_do_pause_resume(di_dev_t *, bool_t),
41 		scsipt_run_ab(curstat_t *),
42 		scsipt_run_sample(curstat_t *),
43 		scsipt_run_prog(curstat_t *),
44 		scsipt_run_repeat(curstat_t *),
45 		scsipt_disc_ready(curstat_t *),
46 		scsipt_chg_ready(curstat_t *),
47 		scsipt_chg_rdstatus(void),
48 		scsipt_chg_start(curstat_t *);
49 STATIC int	scsipt_cfg_vol(int, curstat_t *, bool_t, bool_t);
50 STATIC void	scsipt_stat_poll(curstat_t *),
51 		scsipt_insert_poll(curstat_t *);
52 
53 
54 /* VU module entry jump table */
55 vu_tbl_t	scsipt_vutbl[MAX_VENDORS];
56 
57 /* SCSI command CDB */
58 byte_t		cdb[MAX_CMDLEN];
59 
60 /* Device file descriptors */
61 di_dev_t	*devp = NULL,			/* CD device descriptor */
62 		*chgp = NULL;			/* Medium changer descriptor */
63 
64 
65 STATIC int	scsipt_stat_interval,		/* Status poll interval */
66 		scsipt_ins_interval;		/* Insert poll interval */
67 STATIC long	scsipt_stat_id,			/* Play status poll timer id */
68 		scsipt_insert_id,		/* Disc insert poll timer id */
69 		scsipt_search_id;		/* FF/REW timer id */
70 STATIC bool_t	scsipt_not_open = TRUE,		/* Device not opened yet */
71 		scsipt_stat_polling,		/* Polling play status */
72 		scsipt_insert_polling,		/* Polling disc insert */
73 		scsipt_new_progshuf,		/* New program/shuffle seq */
74 		scsipt_start_search,		/* Start FF/REW play segment */
75 		scsipt_idx_pause,		/* Prev/next index pausing */
76 		scsipt_fake_stop,		/* Force a completion status */
77 		scsipt_playing,			/* Currently playing */
78 		scsipt_paused,			/* Currently paused */
79 		scsipt_bcd_hack,		/* Track numbers in BCD hack */
80 		scsipt_mult_autoplay,		/* Auto-play after disc chg */
81 		scsipt_mult_pause,		/* Pause after disc chg */
82 		scsipt_override_ap,		/* Override auto-play */
83 		scsipt_medmap_valid,		/* med chgr map is valid */
84 		*scsipt_medmap;			/* med chgr map */
85 STATIC sword32_t scsipt_sav_end_addr;		/* Err recov saved end addr */
86 STATIC word32_t	scsipt_next_sam;		/* Next SAMPLE track */
87 STATIC msf_t	scsipt_sav_end_msf;		/* Err recov saved end MSF */
88 STATIC byte_t	scsipt_dev_scsiver,		/* Device SCSI version */
89 		scsipt_sav_end_fmt,		/* Err recov saved end fmt */
90 		scsipt_route_left,		/* Left channel routing */
91 		scsipt_route_right,		/* Right channel routing */
92 		scsipt_cdtext_buf[SZ_RDCDTEXT];	/* CD-TEXT cache buffer */
93 STATIC mcparm_t	scsipt_mcparm;			/* Medium changer parameters */
94 STATIC cdda_client_t scsipt_cdda_client;	/* CDDA client struct */
95 
96 /* VU module init jump table */
97 STATIC vuinit_tbl_t	vuinit[] = {
98 	{ NULL },
99 	{ chin_init },
100 	{ hita_init },
101 	{ nec_init },
102 	{ pion_init },
103 	{ sony_init },
104 	{ tosh_init },
105 	{ pana_init },
106 };
107 
108 
109 /* Request sense key to descriptive string mapping */
110 STATIC req_sense_keymap_t rsense_keymap[] = {
111 	{ 0x0,	"NO SENSE" },
112 	{ 0x1,	"RECOVERED ERROR" },
113 	{ 0x2,	"NOT READY" },
114 	{ 0x3,	"MEDIUM ERROR" },
115 	{ 0x4,	"HARDWARE ERROR" },
116 	{ 0x5,	"ILLEGAL REQUEST" },
117 	{ 0x6,	"UNIT ATTENTION" },
118 	{ 0x7,	"DATA PROTECT" },
119 	{ 0x8,	"BLANK CHECK" },
120 	{ 0x9,	"VENDOR-SPECIFIC" },
121 	{ 0xa,	"COPY ABORTED" },
122 	{ 0xb,	"ABORTED COMMAND" },
123 	{ 0xc,	"EQUAL" },
124 	{ 0xd,	"VOLUME OVERFLOW" },
125 	{ 0xe,	"MISCOMPARE" },
126 	{ 0xf,	"RESERVED" },
127 	{ -1,	NULL }
128 };
129 
130 
131 /***********************
132  *  private functions  *
133  ***********************/
134 
135 
136 /*
137  * scsipt_init_vol
138  *	Initialize volume, balance and channel routing controls
139  *	to match the settings in the hardware, or to the preset
140  *	value, if specified.
141  *
142  * Args:
143  *	s      - Pointer to the curstat_t structure.
144  *	preset - If a preset value is configured, whether to force to
145  *		 the preset.
146  *
147  * Return:
148  *	Nothing.
149  */
150 STATIC void
scsipt_init_vol(curstat_t * s,bool_t preset)151 scsipt_init_vol(curstat_t *s, bool_t preset)
152 {
153 	int	vol;
154 
155 	/* Query current volume/balance settings */
156 	if ((vol = scsipt_cfg_vol(0, s, TRUE, FALSE)) >= 0)
157 		s->level = (byte_t) vol;
158 	else
159 		s->level = 0;
160 
161 	/* Set volume to preset value, if so configured */
162 	if (app_data.startup_vol > 0 && preset) {
163 		s->level_left = s->level_right = 100;
164 
165 		if ((vol = scsipt_cfg_vol(app_data.startup_vol, s,
166 					  FALSE, FALSE)) >= 0)
167 			s->level = (byte_t) vol;
168 	}
169 
170 	/* Initialize sliders */
171 	SET_VOL_SLIDER(s->level);
172 	SET_BAL_SLIDER((int) (s->level_right - s->level_left) / 2);
173 
174 	/* Set up channel routing */
175 	scsipt_route(s);
176 }
177 
178 
179 /*
180  * scsipt_close
181  *	Close SCSI pass-through I/O device.
182  *
183  * Args:
184  *	dp - Device descriptor
185  *
186  * Return:
187  *	Nothing.
188  */
189 STATIC void
scsipt_close(di_dev_t * dp)190 scsipt_close(di_dev_t *dp)
191 {
192 	DBGPRN(DBG_DEVIO)(errfp, "\nClose device: %s\n", dp->path);
193 	pthru_close(dp);
194 }
195 
196 
197 /*
198  * scsipt_open
199  *	Open SCSI pass-through I/O device.
200  *
201  * Args:
202  *	path - The device path name
203  *
204  * Return:
205  *	Pointer to the opened device descriptor
206  *
207  */
208 STATIC di_dev_t *
scsipt_open(char * path)209 scsipt_open(char *path)
210 {
211 	DBGPRN(DBG_DEVIO)(errfp, "\nOpen device: %s\n", path);
212 	return (pthru_open(path));
213 }
214 
215 
216 /***********************
217  *  internal routines  *
218  ***********************/
219 
220 
221 /*
222  * scsipt_rezero_unit
223  *	Send SCSI Rezero Unit command to the device
224  *
225  * Args:
226  *	dp - Device descriptor
227  *	role - Role id to send command for
228  *
229  * Return:
230  *	TRUE - success
231  *	FALSE - failure
232  */
233 bool_t
scsipt_rezero_unit(di_dev_t * dp,int role)234 scsipt_rezero_unit(di_dev_t *dp, int role)
235 {
236 	SCSICDB_RESET(cdb);
237 	cdb[0] = OP_S_REZERO;
238 
239 	return (pthru_send(dp, role,
240 			   cdb, 6, NULL, 0, NULL, 0, OP_NODATA, 20,
241 			   (bool_t) ((app_data.debug & DBG_DEVIO) != 0)));
242 }
243 
244 
245 /*
246  * scsipt_tst_unit_rdy
247  *	Send SCSI Test Unit Ready command to the device
248  *
249  * Args:
250  *	dp     - Device descriptor
251  *	role   - role id for which to send command to
252  *	sensep - Pointer to caller-supplied sense data buffer, or NULL
253  *		 if no sense data is needed.
254  *	prnerr - Whether to display error messages if the command fails.
255  *
256  * Return:
257  *	TRUE - success
258  *	FALSE - failure (drive not ready)
259  */
260 bool_t
scsipt_tst_unit_rdy(di_dev_t * dp,int role,req_sense_data_t * sensep,bool_t prnerr)261 scsipt_tst_unit_rdy(
262 	di_dev_t	*dp,
263 	int		role,
264 	req_sense_data_t *sensep,
265 	bool_t		prnerr
266 )
267 {
268 	bool_t	ret;
269 
270 	SCSICDB_RESET(cdb);
271 	cdb[0] = OP_S_TEST;
272 
273 	ret = pthru_send(
274 		dp, role, cdb, 6, NULL, 0,
275 		(byte_t *) sensep,
276 		(sensep == NULL) ? 0 : sizeof(req_sense_data_t),
277 		OP_NODATA, 20, prnerr
278 	);
279 
280 	return (ret);
281 }
282 
283 
284 /*
285  * scsipt_request_sense
286  *	Send SCSI Request Sense command to the device
287  *
288  * Args:
289  *	dp - Device descriptor
290  *	role - Role id to send command for
291  *	buf - Pointer to data buffer
292  *	len - data buffer size
293  *
294  * Return:
295  *	TRUE - success
296  *	FALSE - failure
297  */
298 bool_t
scsipt_request_sense(di_dev_t * dp,int role,byte_t * buf,size_t len)299 scsipt_request_sense(di_dev_t *dp, int role, byte_t *buf, size_t len)
300 {
301 	SCSICDB_RESET(cdb);
302 	cdb[0] = OP_S_RSENSE;
303 	cdb[4] = (byte_t) (len & 0xff);
304 
305 	return (pthru_send(dp, role, cdb, 6, buf, len, NULL, 0, OP_DATAIN, 5,
306 			   (bool_t) ((app_data.debug & DBG_DEVIO) != 0)));
307 }
308 
309 
310 /*
311  * scsipt_rdsubq
312  *	Send SCSI-2 Read Subchannel command to the device
313  *
314  * Args:
315  *	dp   - Device descriptor
316  *	role - Role id to send command for
317  *	fmt  - Data format desired (SUB_ALL, SUB_CURPOS, SUB_MCN or SUB_ISRC)
318  *	trk  - Track number for which the information is requested
319  *	       (relevant only for fmt == SUB_ISRC)
320  *	sp   - Pointer to the caller-supplied cdstat_t return data buffer
321  *	mcn  - Pointer to the caller-supplied MCN return string buffer.
322  *	       The buffer must be at least 14 bytes long.
323  *	isrc - Pointer to the caller-supplied ISRC return string buffer.
324  *	       The buffer must be at least 13 bytes long.
325  *	prnerr - Whether to output error message if command fails
326  *
327  * Return:
328  *	TRUE - success
329  *	FALSE - failure
330  */
331 bool_t
scsipt_rdsubq(di_dev_t * dp,int role,byte_t fmt,byte_t trk,cdstat_t * sp,char * mcn,char * isrc,bool_t prnerr)332 scsipt_rdsubq(
333 	di_dev_t	*dp,
334 	int		role,
335 	byte_t		fmt,
336 	byte_t		trk,
337 	cdstat_t	*sp,
338 	char		*mcn,
339 	char		*isrc,
340 	bool_t		prnerr
341 )
342 {
343 	byte_t		buf[SZ_RDSUBQ],
344 			*cp;
345 	subq_hdr_t	*h;
346 	subq_00_t	*p0;
347 	subq_01_t	*p1;
348 	subq_02_t	*p2;
349 	subq_03_t	*p3;
350 	int		i,
351 			xfer_len;
352 	char		*fmtstr,
353 			txtstr[STR_BUF_SZ];
354 	bool_t		ret,
355 			bad_data;
356 
357 	/* If the drive doesn't support reading just the current position
358 	 * page, chances are it won't support the other pages either.  So
359 	 * we just read everything in one command.
360 	 */
361 	if (!app_data.curpos_fmt)
362 		fmt = SUB_ALL;
363 
364 	switch (fmt) {
365 	case SUB_ALL:
366 		xfer_len = sizeof(subq_00_t) + sizeof(subq_hdr_t);
367 		fmtstr = "All subchannel data";
368 		break;
369 	case SUB_CURPOS:
370 		xfer_len = sizeof(subq_01_t) + sizeof(subq_hdr_t);
371 		fmtstr = "CD-ROM Current Position";
372 		break;
373 	case SUB_MCN:
374 		if (app_data.mcn_dsbl)
375 			return FALSE;
376 		xfer_len = sizeof(subq_02_t) + sizeof(subq_hdr_t);
377 		fmtstr = "Media Catalog Number";
378 		break;
379 	case SUB_ISRC:
380 		if (app_data.isrc_dsbl)
381 			return FALSE;
382 		xfer_len = sizeof(subq_03_t) + sizeof(subq_hdr_t);
383 		fmtstr = "International Standard Recording Code";
384 		break;
385 	default:
386 		/* Invalid format */
387 		return FALSE;
388 	}
389 
390 	if (xfer_len > SZ_RDSUBQ)
391 		xfer_len = SZ_RDSUBQ;
392 
393 	(void) memset(buf, 0, sizeof(buf));
394 
395 	SCSICDB_RESET(cdb);
396 	cdb[0] = OP_M_RDSUBQ;
397 	cdb[1] = app_data.subq_lba ? 0x00 : 0x02;
398 	cdb[2] = 0x40;
399 	cdb[3] = fmt;
400 	cdb[6] = trk;
401 	cdb[7] = (xfer_len & 0xff00) >> 8;
402 	cdb[8] = xfer_len & 0x00ff;
403 
404 	if ((ret = pthru_send(dp, role, cdb, 10, buf, xfer_len, NULL, 0,
405 			      OP_DATAIN, 5, prnerr)) == FALSE)
406 		return FALSE;
407 
408 	(void) sprintf(txtstr, "Read Subchannel data (%s)", fmtstr);
409 	DBGDUMP(DBG_DEVIO)(txtstr, buf, xfer_len);
410 
411 	h = (subq_hdr_t *)(void *) buf;
412 
413 	/* Check the subchannel data */
414 	cp = (byte_t *) h + sizeof(subq_hdr_t);
415 	switch (*cp) {
416 	case SUB_ALL:
417 	case SUB_CURPOS:
418 		if (sp != NULL) {
419 			p1 = (subq_01_t *)(void *) cp;
420 
421 			/* Hack: to work around firmware anomalies
422 			 * in some drives.
423 			 */
424 			if (p1->trkno >= MAXTRACK &&
425 			    p1->trkno != LEAD_OUT_TRACK) {
426 				sp->status = CDSTAT_NOSTATUS;
427 			}
428 
429 			/* Map SCSI status into cdstat_t */
430 
431 			switch (h->audio_status) {
432 			case AUDIO_PLAYING:
433 				sp->status = CDSTAT_PLAYING;
434 				break;
435 			case AUDIO_PAUSED:
436 				sp->status = CDSTAT_PAUSED;
437 				break;
438 			case AUDIO_COMPLETED:
439 				sp->status = CDSTAT_COMPLETED;
440 				break;
441 			case AUDIO_FAILED:
442 				sp->status = CDSTAT_FAILED;
443 				break;
444 			case AUDIO_NOTVALID:
445 			case AUDIO_NOSTATUS:
446 			default:
447 				sp->status = CDSTAT_NOSTATUS;
448 				break;
449 			}
450 
451 			if (scsipt_bcd_hack) {
452 				/* Hack: BUGLY CD drive firmware */
453 				sp->track = (int) util_bcdtol(p1->trkno);
454 				sp->index = (int) util_bcdtol(p1->idxno);
455 			}
456 			else {
457 				sp->track = (int) p1->trkno;
458 				sp->index = (int) p1->idxno;
459 			}
460 
461 			if (app_data.subq_lba) {
462 				/* LBA mode */
463 				sp->abs_addr.addr = util_xlate_blk((sword32_t)
464 					util_bswap32(p1->abs_addr.logical)
465 				);
466 				util_blktomsf(
467 					sp->abs_addr.addr,
468 					&sp->abs_addr.min,
469 					&sp->abs_addr.sec,
470 					&sp->abs_addr.frame,
471 					MSF_OFFSET
472 				);
473 
474 				sp->rel_addr.addr = util_xlate_blk((sword32_t)
475 					util_bswap32(p1->rel_addr.logical)
476 				);
477 				util_blktomsf(
478 					sp->rel_addr.addr,
479 					&sp->rel_addr.min,
480 					&sp->rel_addr.sec,
481 					&sp->rel_addr.frame,
482 					0
483 				);
484 			}
485 			else {
486 				/* MSF mode */
487 				sp->abs_addr.min = p1->abs_addr.msf.min;
488 				sp->abs_addr.sec = p1->abs_addr.msf.sec;
489 				sp->abs_addr.frame = p1->abs_addr.msf.frame;
490 				util_msftoblk(
491 					sp->abs_addr.min,
492 					sp->abs_addr.sec,
493 					sp->abs_addr.frame,
494 					&sp->abs_addr.addr,
495 					MSF_OFFSET
496 				);
497 
498 				sp->rel_addr.min = p1->rel_addr.msf.min;
499 				sp->rel_addr.sec = p1->rel_addr.msf.sec;
500 				sp->rel_addr.frame = p1->rel_addr.msf.frame;
501 				util_msftoblk(
502 					sp->rel_addr.min,
503 					sp->rel_addr.sec,
504 					sp->rel_addr.frame,
505 					&sp->rel_addr.addr,
506 					0
507 				);
508 			}
509 		}
510 
511 		if (*cp != SUB_ALL)
512 			break;
513 
514 		p0 = (subq_00_t *)(void *) cp;
515 
516 		/* Media catalog number data */
517 		if (mcn != NULL) {
518 			if (p0->mcval != 0) {
519 				/* Sanity check */
520 				bad_data = FALSE;
521 				for (i = 0; i < SZ_MCNDATA; i++) {
522 					if (!isdigit((int) p0->mcn[i])) {
523 						bad_data = TRUE;
524 						break;
525 					}
526 				}
527 				if (!bad_data)
528 					(void) strncpy(mcn, (char *) p0->mcn,
529 						       SZ_MCNDATA);
530 				else
531 					(void) memset(mcn, 0, SZ_MCNDATA);
532 			}
533 			else
534 				(void) memset(mcn, 0, SZ_MCNDATA);
535 		}
536 
537 		/* ISRC data */
538 		if (isrc != NULL) {
539 			if (p0->tcval != 0) {
540 				/* Sanity check */
541 				bad_data = FALSE;
542 				for (i = 0; i < SZ_ISRCDATA; i++) {
543 					if (!isalnum((int) p0->isrc[i])) {
544 						bad_data = TRUE;
545 						break;
546 					}
547 				}
548 				if (!bad_data)
549 					(void) strncpy(isrc, (char *) p0->isrc,
550 						       SZ_ISRCDATA);
551 				else
552 					(void) memset(isrc, 0, SZ_ISRCDATA);
553 			}
554 			else
555 				(void) memset(isrc, 0, SZ_ISRCDATA);
556 		}
557 		break;
558 
559 	case SUB_MCN:
560 		p2 = (subq_02_t *)(void *) cp;
561 		if (*cp != SUB_MCN)
562 			break;
563 
564 		/* Media catalog number data */
565 		if (mcn != NULL) {
566 			if (p2->mcval != 0) {
567 				/* Sanity check */
568 				bad_data = FALSE;
569 				for (i = 0; i < SZ_MCNDATA; i++) {
570 					if (!isdigit((int) p2->mcn[i])) {
571 						bad_data = TRUE;
572 						break;
573 					}
574 				}
575 				if (!bad_data)
576 					(void) strncpy(mcn, (char *) p2->mcn,
577 						       SZ_MCNDATA);
578 				else
579 					(void) memset(mcn, 0, SZ_MCNDATA);
580 			}
581 			else
582 				(void) memset(mcn, 0, SZ_MCNDATA);
583 		}
584 		break;
585 
586 	case SUB_ISRC:
587 		p3 = (subq_03_t *)(void *) cp;
588 		if (*cp != SUB_ISRC)
589 			break;
590 
591 		/* ISRC data */
592 		if (isrc != NULL) {
593 			if (p3->tcval != 0) {
594 				/* Sanity check */
595 				bad_data = FALSE;
596 				for (i = 0; i < SZ_ISRCDATA; i++) {
597 					if (!isalnum((int) p3->isrc[i])) {
598 						bad_data = TRUE;
599 						break;
600 					}
601 				}
602 				if (!bad_data)
603 					(void) strncpy(isrc, (char *) p3->isrc,
604 						       SZ_ISRCDATA);
605 				else
606 					(void) memset(isrc, 0, SZ_ISRCDATA);
607 			}
608 			else
609 				(void) memset(isrc, 0, SZ_ISRCDATA);
610 		}
611 		break;
612 
613 	default:
614 		/* Something is wrong with the data */
615 		DBGPRN(DBG_DEVIO)(errfp,
616 			"scsipt_rdsubq: unexpected data error\n");
617 		ret = FALSE;
618 		break;
619 	}
620 
621 	return (ret);
622 }
623 
624 
625 /*
626  * scsipt_modesense
627  *	Send SCSI Mode Sense command to the device
628  *
629  * Args:
630  *	dp - Device descriptor
631  *	role - Role id to send command for
632  *	buf - Pointer to the return data buffer
633  *	pg_ctrl - Defines the type of parameters to be returned:
634  *		0: Current values
635  *		1: Changeable values
636  *		2: Default values
637  *	pg_code - Specifies which page or pages to return:
638  *		PG_ERRECOV: Error recovery params page
639  *		PG_DISCONN: Disconnect/reconnect params page
640  *		PG_CDROMCTL: CD-ROM params page
641  *		PG_AUDIOCTL: Audio control params page
642  *		PG_ALL: All pages
643  *	xfer_len - Data transfer page length (excluding header and
644  *		block descriptor)
645  *
646  * Return:
647  *	TRUE - success
648  *	FALSE - failure
649  */
650 bool_t
scsipt_modesense(di_dev_t * dp,int role,byte_t * buf,byte_t pg_ctrl,byte_t pg_code,size_t xfer_len)651 scsipt_modesense(
652 	di_dev_t	*dp,
653 	int		role,
654 	byte_t		*buf,
655 	byte_t		pg_ctrl,
656 	byte_t		pg_code,
657 	size_t		xfer_len
658 )
659 {
660 	bool_t	ret;
661 
662 	/* Add header and block desc length */
663 	if (app_data.msen_10)
664 		xfer_len += (app_data.msen_dbd ? 8 : 16);
665 	else
666 		xfer_len += (app_data.msen_dbd ? 4 : 12);
667 
668 	SCSICDB_RESET(cdb);
669 	cdb[0] = app_data.msen_10 ? OP_M_MSENSE : OP_S_MSENSE;
670 	cdb[1] = (byte_t) (app_data.msen_dbd ? 0x08 : 0x00);
671 	cdb[2] = (byte_t) (((pg_ctrl & 0x03) << 6) | (pg_code & 0x3f));
672 	if (app_data.msen_10) {
673 		cdb[7] = (xfer_len & 0xff00) >> 8;
674 		cdb[8] = xfer_len & 0x00ff;
675 	}
676 	else
677 		cdb[4] = (byte_t) xfer_len;
678 
679 	if ((ret = pthru_send(dp, role, cdb, app_data.msen_10 ? 10 : 6, buf,
680 			      xfer_len, NULL, 0, OP_DATAIN,
681 			      5, TRUE)) == TRUE) {
682 		DBGDUMP(DBG_DEVIO)("Mode Sense data", buf, xfer_len);
683 	}
684 
685 	return (ret);
686 }
687 
688 
689 /*
690  * scsipt_modesel
691  *	Send SCSI Mode Select command to the device
692  *
693  * Args:
694  *	dp - Device descriptor
695  *	role - Role id for which to send command for
696  *	buf - Pointer to the data buffer
697  *	pg_code - Specifies which page or pages to return:
698  *		PG_ERRECOV: Error recovery params page
699  *		PG_DISCONN: Disconnect/reconnect params page
700  *		PG_CDROMCTL: CD-ROM params page
701  *		PG_AUDIOCTL: Audio control params page
702  *		PG_ALL: All pages
703  *	xfer_len - Data transfer page length (excluding header and
704  *		block descriptor)
705  *
706  * Return:
707  *	TRUE - success
708  *	FALSE - failure
709  */
710 /*ARGSUSED*/
711 bool_t
scsipt_modesel(di_dev_t * dp,int role,byte_t * buf,byte_t pg_code,size_t xfer_len)712 scsipt_modesel(
713 	di_dev_t	*dp,
714 	int		role,
715 	byte_t		*buf,
716 	byte_t		pg_code,
717 	size_t		xfer_len
718 )
719 {
720 	int			bdesclen;
721 	mode_sense_6_data_t	*ms_data6 = NULL;
722 	mode_sense_10_data_t	*ms_data10 = NULL;
723 
724 	SCSICDB_RESET(cdb);
725 	cdb[0] = app_data.msen_10 ? OP_M_MSELECT : OP_S_MSELECT;
726 	cdb[1] = (xfer_len == 0) ? 0x00 : 0x10;;
727 
728 	/* Add header and block desc length */
729 	if (app_data.msen_10) {
730 		ms_data10 = (mode_sense_10_data_t *)(void *) buf;
731 		bdesclen = (int)
732 			util_bswap16((word16_t) ms_data10->bdescr_len);
733 		xfer_len += (8 + bdesclen);
734 
735 		cdb[7] = (xfer_len & 0xff00) >> 8;
736 		cdb[8] = xfer_len & 0x00ff;
737 	}
738 	else {
739 		ms_data6 = (mode_sense_6_data_t *)(void *) buf;
740 		bdesclen = (int) ms_data6->bdescr_len;
741 		xfer_len += (4 + bdesclen);
742 
743 		cdb[4] = (byte_t) xfer_len;
744 	}
745 
746 	DBGDUMP(DBG_DEVIO)("Mode Select data", buf, xfer_len);
747 
748 	return (
749 		pthru_send(dp, role, cdb, app_data.msen_10 ? 10 : 6, buf,
750 			   xfer_len, NULL, 0, OP_DATAOUT, 5, TRUE)
751 	);
752 }
753 
754 
755 /*
756  * scsipt_inquiry
757  *	Send SCSI Inquiry command to the device
758  *
759  * Args:
760  *	dp - Device descriptor
761  *	role - Role id for which to send command for
762  *	buf - Pointer to the return data buffer
763  *	len - Maximum number of inquiry data bytes to transfer
764  *
765  * Return:
766  *	TRUE - success
767  *	FALSE - failure
768  */
769 bool_t
scsipt_inquiry(di_dev_t * dp,int role,byte_t * buf,size_t len)770 scsipt_inquiry(di_dev_t *dp, int role, byte_t *buf, size_t len)
771 {
772 	bool_t	ret;
773 
774 	SCSICDB_RESET(cdb);
775 	cdb[0] = OP_S_INQUIR;
776 	cdb[4] = (byte_t) len;
777 
778 	if ((ret = pthru_send(dp, role, cdb, 6, buf, len, NULL, 0, OP_DATAIN,
779 			      5, TRUE)) == TRUE) {
780 		DBGDUMP(DBG_DEVIO)("Inquiry data", buf, len);
781 	}
782 
783 	return (ret);
784 }
785 
786 
787 /*
788  * scsipt_rdtoc
789  *	Send Read TOC/PMA/ATIP command to the device
790  *
791  * Args:
792  *	dp - Device descriptor
793  *	role - Role id for which to send command for
794  *	buf - Pointer to the return data buffer
795  *	len - Size of return data buffer
796  *	start - Starting track number for which the TOC data is returned
797  *	fmt - Data to read:
798  *		0 - Track TOC data
799  *		1 - Session data
800  *		2 - Full TOC data
801  *		3 - PMA data
802  *		4 - ATIP data
803  *		5 - CD-TEXT data
804  *	msf - Whether to use MSF or logical block address data format
805  *	prnerr - Whether to output error message if command fails
806  *
807  * Return:
808  *	TRUE - success
809  *	FALSE - failure
810  */
811 bool_t
scsipt_rdtoc(di_dev_t * dp,int role,byte_t * buf,size_t len,int start,int fmt,bool_t msf,bool_t prnerr)812 scsipt_rdtoc(
813 	di_dev_t	*dp,
814 	int		role,
815 	byte_t		*buf,
816 	size_t		len,
817 	int		start,
818 	int		fmt,
819 	bool_t		msf,
820 	bool_t		prnerr
821 )
822 {
823 	size_t		xfer_len,
824 			maxfer_len;
825 	toc_hdr_t	*thdr;
826 	bool_t		ret;
827 
828 	/* Read the TOC header first */
829 	SCSICDB_RESET(cdb);
830 	cdb[0] = OP_M_RDTOC;
831 	cdb[1] = msf ? 0x02 : 0x00;
832 	cdb[2] = (byte_t) (fmt & 0x0f);
833 	cdb[6] = (byte_t) start;
834 	cdb[7] = 0;
835 	cdb[8] = SZ_TOCHDR;
836 
837 	/* Read header first to determine data length */
838 	if (!pthru_send(dp, role, cdb, 10, buf, SZ_TOCHDR, NULL, 0,
839 			OP_DATAIN, 10, prnerr)) {
840 		(void) memset(buf, 0, len);
841 		return FALSE;
842 	}
843 
844 	thdr = (toc_hdr_t *)(void *) buf;
845 
846 	switch (fmt) {
847 	case 0:	/* Read track TOC */
848 		if (start == 0)
849 			start = (int) thdr->first_trk;
850 
851 		xfer_len = SZ_TOCHDR +
852 			(((int) thdr->last_trk - start + 2) * SZ_TOCENT);
853 		break;
854 
855 	default:
856 		/* All other formats */
857 		xfer_len = (int) util_bswap16(thdr->data_len) + 2;
858 		break;
859 	}
860 
861 	/* Check data size against max transfer size of system */
862 	maxfer_len = pthru_maxfer(dp);
863 	if (xfer_len > maxfer_len) {
864 		DBGPRN(DBG_DEVIO)(errfp,
865 			"scsipt_rdtoc: xfer_len (%d) > maxfer_len (%d).\n",
866 			(int) xfer_len, (int) maxfer_len);
867 		(void) memset(buf, 0, len);
868 		return FALSE;
869 	}
870 
871 	if (xfer_len <= SZ_TOCHDR) {
872 		(void) memset(buf, 0, len);
873 		return FALSE;		/* No useful data to read */
874 	}
875 	else if (xfer_len > len)
876 		xfer_len = len;		/* Limit to buffer size */
877 
878 	/* Do the full Read TOC/PMA/ATIP command */
879 	SCSICDB_RESET(cdb);
880 	cdb[0] = OP_M_RDTOC;
881 	cdb[1] = msf ? 0x02 : 0x00;
882 	cdb[2] = (byte_t) (fmt & 0x0f);
883 	cdb[6] = (byte_t) start;
884 	cdb[7] = (xfer_len & 0xff00) >> 8;
885 	cdb[8] = xfer_len & 0x00ff;
886 
887 	ret = pthru_send(dp, role, cdb, 10, buf, xfer_len, NULL, 0,
888 			 OP_DATAIN, 10, prnerr);
889 
890 	if (!ret)
891 		(void) memset(buf, 0, len);
892 	else {
893 		char	*descr_str;
894 
895 		switch (fmt) {
896 		case 0:
897 			descr_str = "Read TOC/PMA/ATIP data (Track TOC)";
898 			break;
899 		case 1:
900 			descr_str = "Read TOC/PMA/ATIP data (Session info)";
901 			break;
902 		case 2:
903 			descr_str = "Read TOC/PMA/ATIP data (Full TOC)";
904 			break;
905 		case 3:
906 			descr_str = "Read TOC/PMA/ATIP data (PMA)";
907 			break;
908 		case 4:
909 			descr_str = "Read TOC/PMA/ATIP data (ATIP)";
910 			break;
911 		case 5:
912 			descr_str = "Read TOC/PMA/ATIP data (CD-TEXT)";
913 			break;
914 		default:
915 			descr_str = "Read TOC/PMA/ATIP data";
916 			break;
917 		}
918 
919 		DBGDUMP(DBG_DEVIO)(descr_str, buf, xfer_len);
920 	}
921 
922 #ifdef __VMS
923 	/* VMS hack */
924 	if (ret) {
925 		int	i;
926 
927 		ret = FALSE;
928 
929 		/* Make sure that the return buffer is not all zeros */
930 		for (i = 0; i < xfer_len; i++) {
931 			if (buf[i] != 0) {
932 				ret = TRUE;
933 				break;
934 			}
935 		}
936 	}
937 #endif
938 
939 	return (ret);
940 }
941 
942 
943 /*
944  * scsipt_playmsf
945  *	Send SCSI-2 Play Audio MSF command to the device
946  *
947  * Args:
948  *	dp - Device descriptor
949  *	role - Role id for which to send command for
950  *	start - Pointer to the starting position MSF data
951  *	end - Pointer to the ending position MSF data
952  *
953  * Return:
954  *	TRUE - success
955  *	FALSE - failure
956  */
957 bool_t
scsipt_playmsf(di_dev_t * dp,int role,msf_t * start,msf_t * end)958 scsipt_playmsf(di_dev_t *dp, int role, msf_t *start, msf_t *end)
959 {
960 	byte_t	sm,
961 		ss,
962 		sf,
963 		em,
964 		es,
965 		ef;
966 
967 	if (!app_data.playmsf_supp)
968 		return FALSE;
969 
970 	/* If the start or end positions are less than the minimum
971 	 * position, patch them to the minimum positions.
972 	 */
973 	if (start->min == 0 && start->sec < 2) {
974 		sm = 0;
975 		ss = 2;
976 		sf = 0;
977 	}
978 	else {
979 		sm = start->min;
980 		ss = start->sec;
981 		sf = start->frame;
982 	}
983 
984 	if (end->min == 0 && end->sec < 2) {
985 		em = 0;
986 		es = 2;
987 		ef = 0;
988 	}
989 	else {
990 		em = end->min;
991 		es = end->sec;
992 		ef = end->frame;
993 	}
994 
995 	/* If start == end, just return success */
996 	if (sm == em && ss == es && sf == ef)
997 		return TRUE;
998 
999 	SCSICDB_RESET(cdb);
1000 	cdb[0] = OP_M_PLAYMSF;
1001 	cdb[3] = sm;
1002 	cdb[4] = ss;
1003 	cdb[5] = sf;
1004 	cdb[6] = em;
1005 	cdb[7] = es;
1006 	cdb[8] = ef;
1007 
1008 	return (
1009 		pthru_send(dp, role, cdb, 10, NULL, 0,
1010 			   NULL, 0, OP_NODATA, 20, TRUE)
1011 	);
1012 }
1013 
1014 
1015 /*
1016  * scsipt_play10
1017  *	Send SCSI-2 Play Audio (10) command to the device
1018  *
1019  * Args:
1020  *	dp - Device descriptor
1021  *	role - Role id for which to send command for
1022  *	start - The starting logical block address
1023  *	len - The number of logical blocks to play (max=0xffff)
1024  *
1025  * Return:
1026  *	TRUE - success
1027  *	FALSE - failure
1028  */
1029 bool_t
scsipt_play10(di_dev_t * dp,int role,sword32_t start,sword32_t len)1030 scsipt_play10(di_dev_t *dp, int role, sword32_t start, sword32_t len)
1031 {
1032 	if (!app_data.play10_supp || len > 0xffff)
1033 		return FALSE;
1034 
1035 	/* Do block size conversion if needed */
1036 	start = util_unxlate_blk(start);
1037 	len = util_unxlate_blk(len);
1038 
1039 	SCSICDB_RESET(cdb);
1040 	cdb[0] = OP_M_PLAY;
1041 	cdb[2] = ((word32_t) start & 0xff000000) >> 24;
1042 	cdb[3] = ((word32_t) start & 0x00ff0000) >> 16;
1043 	cdb[4] = ((word32_t) start & 0x0000ff00) >> 8;
1044 	cdb[5] = ((word32_t) start & 0x000000ff);
1045 	cdb[7] = ((word32_t) len & 0xff00) >> 8;
1046 	cdb[8] = ((word32_t) len & 0x00ff);
1047 
1048 	return (
1049 		pthru_send(dp, role, cdb, 10, NULL, 0, NULL, 0,
1050 			   OP_NODATA, 20, TRUE)
1051 	);
1052 }
1053 
1054 
1055 /*
1056  * scsipt_play12
1057  *	Send SCSI-2 Play Audio (12) command to the device
1058  *
1059  * Args:
1060  *	dp - Device descriptor
1061  *	role - Role id for which to send command for
1062  *	start - The starting logical block address
1063  *	len - The number of logical blocks to play
1064  *
1065  * Return:
1066  *	TRUE - success
1067  *	FALSE - failure
1068  */
1069 bool_t
scsipt_play12(di_dev_t * dp,int role,sword32_t start,sword32_t len)1070 scsipt_play12(di_dev_t *dp, int role, sword32_t start, sword32_t len)
1071 {
1072 	if (!app_data.play12_supp)
1073 		return FALSE;
1074 
1075 	/* Do block size conversion if needed */
1076 	start = util_unxlate_blk(start);
1077 	len = util_unxlate_blk(len);
1078 
1079 	SCSICDB_RESET(cdb);
1080 	cdb[0] = OP_L_PLAY;
1081 	cdb[2] = ((word32_t) start & 0xff000000) >> 24;
1082 	cdb[3] = ((word32_t) start & 0x00ff0000) >> 16;
1083 	cdb[4] = ((word32_t) start & 0x0000ff00) >> 8;
1084 	cdb[5] = ((word32_t) start & 0x000000ff);
1085 	cdb[6] = ((word32_t) len & 0xff000000) >> 24;
1086 	cdb[7] = ((word32_t) len & 0x00ff0000) >> 16;
1087 	cdb[8] = ((word32_t) len & 0x0000ff00) >> 8;
1088 	cdb[9] = ((word32_t) len & 0x000000ff);
1089 
1090 	return (
1091 		pthru_send(dp, role, cdb, 12, NULL, 0, NULL, 0,
1092 			   OP_NODATA, 20, TRUE)
1093 	);
1094 }
1095 
1096 
1097 /*
1098  * scsipt_play_trkidx
1099  *	Send SCSI-2 Play Audio Track/Index command to the device
1100  *
1101  * Args:
1102  *	dp - Device descriptor
1103  *	role - Role id for which to send command for
1104  *	start_trk - Starting track number
1105  *	start_idx - Starting index number
1106  *	end_trk - Ending track number
1107  *	end_idx - Ending index number
1108  *
1109  * Return:
1110  *	TRUE - success
1111  *	FALSE - failure
1112  */
1113 bool_t
scsipt_play_trkidx(di_dev_t * dp,int role,int start_trk,int start_idx,int end_trk,int end_idx)1114 scsipt_play_trkidx(
1115 	di_dev_t	*dp,
1116 	int		role,
1117 	int		start_trk,
1118 	int		start_idx,
1119 	int		end_trk,
1120 	int		end_idx
1121 )
1122 {
1123 	if (!app_data.playti_supp)
1124 		return FALSE;
1125 
1126 	if (scsipt_bcd_hack) {
1127 		/* Hack: BUGLY CD drive firmware */
1128 		start_trk = util_ltobcd(start_trk);
1129 		start_idx = util_ltobcd(start_idx);
1130 		end_trk = util_ltobcd(end_trk);
1131 		end_idx = util_ltobcd(end_idx);
1132 	}
1133 
1134 	SCSICDB_RESET(cdb);
1135 	cdb[0] = OP_M_PLAYTI;
1136 	cdb[4] = (byte_t) start_trk;
1137 	cdb[5] = (byte_t) start_idx;
1138 	cdb[7] = (byte_t) end_trk;
1139 	cdb[8] = (byte_t) end_idx;
1140 
1141 	return (
1142 		pthru_send(dp, role, cdb, 10, NULL, 0, NULL, 0,
1143 			   OP_NODATA, 20, TRUE)
1144 	);
1145 }
1146 
1147 
1148 /*
1149  * scsipt_read_cdda
1150  *	Read CDDA (CD Digital Audio).
1151  *
1152  * Args:
1153  *	devp    - Device descriptor
1154  *	role    - Role id for which to send command to
1155  *	cdda    - Pointer to a caller-supplied cdda_req_t structure, which
1156  *		  contains the address, frame address, and data buffer
1157  *		  pointer.
1158  *	framesz - The size of a CDDA frame in bytes
1159  *	tout    - Command timeout interval (in seconds)
1160  *	sensep  - Pointer to caller-supplied sense data buffer, or NULL
1161  *		  if no sense data is needed.
1162  *
1163  * Return:
1164  *	TRUE  - success
1165  *	FALSE - failure
1166  */
1167 bool_t
scsipt_read_cdda(di_dev_t * devp,int role,cdda_req_t * cdda,size_t framesz,int tout,req_sense_data_t * sensep)1168 scsipt_read_cdda(
1169 	di_dev_t		*devp,
1170 	int			role,
1171 	cdda_req_t		*cdda,
1172 	size_t			framesz,
1173 	int			tout,
1174 	req_sense_data_t	*sensep
1175 )
1176 {
1177 	sword32_t	addr;
1178 	size_t		cmdlen;
1179 
1180 
1181 	if (cdda->addrfmt == READFMT_LBA) {
1182 		addr = cdda->pos.logical;
1183 	}
1184 	else if (cdda->addrfmt == READFMT_MSF) {
1185 		util_msftoblk(
1186 			cdda->pos.msf.min,
1187 			cdda->pos.msf.sec,
1188 			cdda->pos.msf.frame,
1189 			&addr,
1190 			MSF_OFFSET
1191 		);
1192 	}
1193 	else {
1194 		DBGPRN(DBG_DEVIO)(errfp,
1195 		       "scsipt_read_cdda: Invalid addrfmt (0x%x)\n",
1196 		       cdda->addrfmt);
1197 		if (sensep != NULL) {
1198 			memset(sensep, 0, sizeof(req_sense_data_t));
1199 			sensep->valid = 1;
1200 			sensep->key = 0x5;	/* Fake an "illegal request */
1201 		}
1202 		return FALSE;	/* Invalid address format */
1203 	}
1204 
1205 	SCSICDB_RESET(cdb);
1206 	cdb[2] = (addr >> 24) & 0xff;
1207 	cdb[3] = (addr >> 16) & 0xff;
1208 	cdb[4] = (addr >>  8) & 0xff;
1209 	cdb[5] = addr & 0xff;
1210 
1211 	switch (app_data.cdda_scsireadcmd) {
1212 	case CDDA_MMC:
1213 		/* MMC Read CD (12) */
1214 		cmdlen = 12;
1215 		cdb[0] = OP_L_READCD;
1216 		cdb[6] = (cdda->nframes >> 16) & 0xff;
1217 		cdb[7] = (cdda->nframes >>  8) & 0xff;
1218 		cdb[8] = cdda->nframes & 0xff;
1219 		cdb[9] = 0xf8;	/* Specify SYNC, EDC and ECC */
1220 		break;
1221 
1222 	case CDDA_STD:
1223 		/* SCSI Read (10) */
1224 		cmdlen = 10;
1225 		cdb[0] = OP_M_READ;
1226 		cdb[7] = (cdda->nframes >> 8) & 0xff;
1227 		cdb[8] = cdda->nframes & 0xff;
1228 		break;
1229 
1230 #ifndef DEMO_ONLY
1231 	case CDDA_NEC:
1232 		/* NEC Read CD-DA (10) */
1233 		cmdlen = 10;
1234 		cdb[0] = OP_VN_READCDDA;
1235 		cdb[7] = (cdda->nframes >> 8) & 0xff;
1236 		cdb[8] = cdda->nframes & 0xff;
1237 		break;
1238 
1239 	case CDDA_SONY:
1240 		/* Sony Read CD-DA (12) */
1241 		cmdlen = 12;
1242 		cdb[0]  = OP_VS_READCDDA;
1243 		cdb[6]  = (cdda->nframes >> 24) & 0xff;
1244 		cdb[7]  = (cdda->nframes >> 16) & 0xff;
1245 		cdb[8]  = (cdda->nframes >>  8) & 0xff;
1246 		cdb[9]  = cdda->nframes & 0xff;
1247 		cdb[10] = 0x00;	/* No subcode */
1248 		break;
1249 #endif	/* DEMO_ONLY */
1250 
1251 	default:
1252 		/* Invalid configuration */
1253 		DBGPRN(DBG_DEVIO)(errfp,
1254 			"Invalid cddaScsiReadCommand parameter (%d)\n",
1255 			app_data.cdda_scsireadcmd);
1256 		if (sensep != NULL) {
1257 			memset(sensep, 0, sizeof(req_sense_data_t));
1258 			sensep->valid = 1;
1259 			sensep->key = 0x5;	/* Fake an "illegal request */
1260 		}
1261 		return FALSE;
1262 	}
1263 
1264 	return (
1265 		pthru_send(devp, role, cdb, cmdlen, cdda->buf,
1266 			   (size_t) (cdda->nframes * framesz),
1267 			   (byte_t *) sensep,
1268 			   (sensep == NULL) ? 0 : sizeof(req_sense_data_t),
1269 			   OP_DATAIN, tout, TRUE)
1270 	);
1271 }
1272 
1273 
1274 /*
1275  * scsipt_prev_allow
1276  *	Send SCSI Prevent/Allow Medium Removal command to the device
1277  *
1278  * Args:
1279  *	dp - Device descriptor
1280  *	role    - Role id for which to send command to
1281  *	prevent - Whether to prevent or allow medium removal
1282  *
1283  * Return:
1284  *	TRUE - success
1285  *	FALSE - failure
1286  */
1287 bool_t
scsipt_prev_allow(di_dev_t * dp,int role,bool_t prevent)1288 scsipt_prev_allow(di_dev_t *dp, int role, bool_t prevent)
1289 {
1290 	if (!app_data.caddylock_supp)
1291 		return FALSE;
1292 
1293 	SCSICDB_RESET(cdb);
1294 	cdb[0] = OP_S_PREVENT;
1295 	cdb[4] = prevent ? 0x01 : 0x00;
1296 
1297 	return (
1298 		pthru_send(dp, role, cdb, 6, NULL, 0, NULL, 0,
1299 			   OP_NODATA, 5, TRUE)
1300 	);
1301 }
1302 
1303 
1304 /*
1305  * scsipt_start_stop
1306  *	Send SCSI Start/Stop Unit command to the device
1307  *
1308  * Args:
1309  *	dp - Device descriptor
1310  *	role - Role id for which to send command to
1311  *	start - Whether to start unit or stop unit
1312  *	loej - Whether caddy load/eject operation should be performed
1313  *	prnerr - Whether to print error messages if the command fails
1314  *
1315  * Return:
1316  *	TRUE - success
1317  *	FALSE - failure
1318  */
1319 bool_t
scsipt_start_stop(di_dev_t * dp,int role,bool_t start,bool_t loej,bool_t prnerr)1320 scsipt_start_stop(
1321 	di_dev_t	*dp,
1322 	int		role,
1323 	bool_t		start,
1324 	bool_t		loej,
1325 	bool_t		prnerr
1326 )
1327 {
1328 	byte_t		ctl;
1329 	bool_t		ret;
1330 	curstat_t	*s = di_clinfo->curstat_addr();
1331 
1332 	if (!start && PLAYMODE_IS_CDDA(app_data.play_mode)) {
1333 		(void) cdda_stop(dp, s);
1334 
1335 		if (!scsipt_is_enabled(devp, DI_ROLE_MAIN))
1336 			scsipt_enable(dp, DI_ROLE_MAIN);
1337 	}
1338 
1339 	if (start)
1340 		ctl = 0x01;
1341 	else
1342 		ctl = 0x00;
1343 
1344 	if (loej)
1345 		ctl |= 0x02;
1346 
1347 	SCSICDB_RESET(cdb);
1348 	cdb[0] = OP_S_START;
1349 	if (start || loej)
1350 		cdb[1] = 0x1;	/* Set immediate bit */
1351 	cdb[4] = ctl;
1352 
1353 	ret = pthru_send(dp, role, cdb, 6, NULL, 0, NULL, 0,
1354 			 OP_NODATA, 20, prnerr);
1355 
1356 	/* Delay a bit to let the CD load or eject.  This is a hack to
1357 	 * work around firmware bugs in some CD drives.  These drives
1358 	 * don't handle new commands well when the CD is loading/ejecting
1359 	 * with the IMMED bit set in the Start/Stop Unit command.
1360 	 */
1361 	if (ret) {
1362 		if (loej) {
1363 			int	n;
1364 
1365 			n = (app_data.ins_interval + 1000 - 1) / 1000;
1366 			if (start)
1367 				n *= 2;
1368 
1369 			util_delayms(n * 1000);
1370 		}
1371 		else if (start && app_data.spinup_interval > 0)
1372 			util_delayms(app_data.spinup_interval * 1000);
1373 	}
1374 
1375 	return (ret);
1376 }
1377 
1378 
1379 /*
1380  * scsipt_pause_resume
1381  *	Send SCSI-2 Pause/Resume command to the device
1382  *
1383  * Args:
1384  *	dp - Device descriptor
1385  *	role - Role id for which to send command to
1386  *	resume - Whether to resume or pause
1387  *
1388  * Return:
1389  *	TRUE - success
1390  *	FALSE - failure
1391  */
1392 bool_t
scsipt_pause_resume(di_dev_t * dp,int role,bool_t resume)1393 scsipt_pause_resume(di_dev_t *dp, int role, bool_t resume)
1394 {
1395 	curstat_t	*s = di_clinfo->curstat_addr();
1396 
1397 	if (!app_data.pause_supp)
1398 		return FALSE;
1399 
1400 	if (PLAYMODE_IS_CDDA(app_data.play_mode))
1401 		return cdda_pause_resume(dp, s, resume);
1402 
1403 	SCSICDB_RESET(cdb);
1404 	cdb[0] = OP_M_PAUSE;
1405 	cdb[8] = resume ? 0x01 : 0x00;
1406 
1407 	return (
1408 		pthru_send(dp, role, cdb, 10, NULL, 0, NULL, 0,
1409 			   OP_NODATA, 20, TRUE)
1410 	);
1411 }
1412 
1413 
1414 /*
1415  * scsipt_move_medium
1416  *	Move a unit of media from a source element to a destination element
1417  *
1418  * Args:
1419  *	dp - Device descriptor
1420  *	role - Role id for which to send command to
1421  *	te_addr - Transport element address
1422  *	src_addr - Source element address
1423  *	dst_addr - Destination element address
1424  *
1425  * Return:
1426  *	TRUE - success
1427  *	FALSE - failure
1428  */
1429 bool_t
scsipt_move_medium(di_dev_t * dp,int role,word16_t te_addr,word16_t src_addr,word16_t dst_addr)1430 scsipt_move_medium(
1431 	di_dev_t	*dp,
1432 	int		role,
1433 	word16_t	te_addr,
1434 	word16_t	src_addr,
1435 	word16_t	dst_addr
1436 )
1437 {
1438 	bool_t	ret;
1439 
1440 	SCSICDB_RESET(cdb);
1441 	cdb[0] = OP_L_MOVEMED;
1442 	cdb[2] = ((int) (te_addr & 0xff00) >> 8);
1443 	cdb[3] = (te_addr & 0x00ff);
1444 	cdb[4] = ((int) (src_addr & 0xff00) >> 8);
1445 	cdb[5] = (src_addr & 0x00ff);
1446 	cdb[6] = ((int) (dst_addr & 0xff00) >> 8);
1447 	cdb[7] = (dst_addr & 0x00ff);
1448 
1449 	ret = pthru_send(dp, role, cdb, 12, NULL, 0, NULL, 0, OP_NODATA, 30,
1450 			 (bool_t) ((app_data.debug & DBG_DEVIO) != 0));
1451 
1452 	if (ret)
1453 		/* Wait a bit for the changer to load and settle */
1454 		util_delayms((app_data.ins_interval + 1) * 1000);
1455 
1456 	return (ret);
1457 }
1458 
1459 
1460 /*
1461  * scsipt_init_elemstat
1462  *	Request medium changer to check its element status.
1463  *
1464  * Args:
1465  *	dp - Device descriptor
1466  *	role - Role id for which to send command to
1467  *
1468  * Return:
1469  *	TRUE - success
1470  *	FALSE - failure
1471  */
1472 bool_t
scsipt_init_elemstat(di_dev_t * dp,int role)1473 scsipt_init_elemstat(di_dev_t *dp, int role)
1474 {
1475 	SCSICDB_RESET(cdb);
1476 	cdb[0] = OP_S_INITELEMSTAT;
1477 
1478 	return (
1479 		pthru_send(
1480 			dp,
1481 			role,
1482 			cdb,
1483 			6,
1484 			NULL,
1485 			0,
1486 			NULL,
1487 			0,
1488 			OP_NODATA,
1489 			app_data.numdiscs * 10,
1490 			(bool_t) ((app_data.debug & DBG_DEVIO) != 0)
1491 		)
1492 	);
1493 }
1494 
1495 
1496 /*
1497  * scsipt_read_elemstat
1498  *	Read medium changer element status.
1499  *
1500  * Args:
1501  *	dp - Device descriptor
1502  *	role - Role id for which to send command to
1503  *	buf - Data buffer pointer
1504  *	len - Data buffer size
1505  *	nelem - Number of elements requested
1506  *
1507  * Return:
1508  *	TRUE - success
1509  *	FALSE - failure
1510  */
1511 bool_t
scsipt_read_elemstat(di_dev_t * dp,int role,byte_t * buf,size_t len,int nelem)1512 scsipt_read_elemstat(
1513 	di_dev_t	*dp,
1514 	int		role,
1515 	byte_t		*buf,
1516 	size_t		len,
1517 	int		nelem
1518 )
1519 {
1520 	SCSICDB_RESET(cdb);
1521 	cdb[0] = OP_L_READELEMSTAT;
1522 	cdb[1] = 0;		/* Request all element types */
1523 	cdb[2] = 0;		/* Start element address MSB */
1524 	cdb[3] = 0;		/* Start element address LSB */
1525 	cdb[4] = (byte_t) ((nelem & 0xff00) >> 8);  /* Elements count MSB */
1526 	cdb[5] = (byte_t) (nelem & 0x00ff);	    /* Elements count LSB */
1527 	cdb[7] = (byte_t) ((len & 0xff0000) >> 16); /* Alloc length MSB */
1528 	cdb[8] = (byte_t) ((len & 0x00ff00) >> 8);  /* Alloc length */
1529 	cdb[9] = (byte_t) (len & 0x0000ff);	    /* Alloc length LSB */
1530 
1531 	return (
1532 		pthru_send(
1533 			dp,
1534 			role,
1535 			cdb,
1536 			12,
1537 			buf,
1538 			len,
1539 			NULL,
1540 			0,
1541 			OP_DATAIN,
1542 			app_data.numdiscs * 20,
1543 			(bool_t) ((app_data.debug & DBG_DEVIO) != 0)
1544 		)
1545 	);
1546 }
1547 
1548 
1549 /*
1550  * scsipt_disc_present
1551  *	Check if a disc is loaded
1552  *
1553  * Args:
1554  *	dp     - Device descriptor
1555  *	role   - Role id for which to check
1556  *	s      - Pointer to the curstat_t structure
1557  *	sensep - Pointer to caller-supplied sense data buffer, or NULL
1558  *		 if no sense data is needed.
1559  *
1560  * Return:
1561  *	TRUE - ready
1562  *	FALSE - not ready
1563  */
1564 bool_t
scsipt_disc_present(di_dev_t * dp,int role,curstat_t * s,req_sense_data_t * sensep)1565 scsipt_disc_present(
1566 	di_dev_t	*dp,
1567 	int		role,
1568 	curstat_t	*s,
1569 	req_sense_data_t *sensep
1570 )
1571 {
1572 	int			i;
1573 	bool_t			ret = FALSE;
1574 	req_sense_data_t	sense_data;
1575 
1576 	if (app_data.play_notur && s->mode != MOD_STOP &&
1577 	    s->mode != MOD_NODISC && s->mode != MOD_BUSY) {
1578 		/* For those drives that returns failure status to
1579 		 * the Test Unit Ready command during audio playback,
1580 		 * we just silently return success if the drive is
1581 		 * supposed to be playing audio.  Shrug.
1582 		 */
1583 		return TRUE;
1584 	}
1585 
1586 	if (sensep == NULL)
1587 		sensep = &sense_data;
1588 
1589 	for (i = 0; i < 10; i++) {
1590 		/* Send Test Unit Ready command to check
1591 		 * if the drive is ready.
1592 		 */
1593 		ret = scsipt_tst_unit_rdy(
1594 			dp, role, sensep,
1595 			(bool_t) ((app_data.debug & DBG_DEVIO) != 0)
1596 		);
1597 
1598 		if (ret)
1599 			break;
1600 
1601 		if (sensep->key == 0x02 && sensep->code == 0x04) {
1602 			/* Disc is spinning up, wait */
1603 			util_delayms(1000);
1604 		}
1605 	}
1606 
1607 	return (ret);
1608 }
1609 
1610 
1611 /*
1612  * scsipt_do_playaudio
1613  *	General top-level play audio function
1614  *
1615  * Args:
1616  *	dp - Device descriptor
1617  *	addr_fmt - The address formats specified:
1618  *		ADDR_BLK: logical block address
1619  *		ADDR_MSF: MSF address
1620  *		ADDR_TRKIDX: Track/index numbers
1621  *		ADDR_OPTEND: Ending address can be ignored
1622  *	start_addr - Starting logical block address
1623  *	end_addr - Ending logical block address
1624  *	start_msf - Pointer to start address MSF data
1625  *	end_msf - Pointer to end address MSF data
1626  *	trk - Starting track number
1627  *	idx - Starting index number
1628  *
1629  * Return:
1630  *	TRUE - success
1631  *	FALSE - failure
1632  */
1633 STATIC bool_t
scsipt_do_playaudio(di_dev_t * dp,byte_t addr_fmt,sword32_t start_addr,sword32_t end_addr,msf_t * start_msf,msf_t * end_msf,byte_t trk,byte_t idx)1634 scsipt_do_playaudio(
1635 	di_dev_t	*dp,
1636 	byte_t		addr_fmt,
1637 	sword32_t	start_addr,
1638 	sword32_t	end_addr,
1639 	msf_t		*start_msf,
1640 	msf_t		*end_msf,
1641 	byte_t		trk,
1642 	byte_t		idx
1643 )
1644 {
1645 	msf_t		emsf,
1646 			*emsfp = NULL;
1647 	sword32_t	tmp_saddr,
1648 			tmp_eaddr;
1649 	bool_t		ret = FALSE,
1650 			do_playmsf = FALSE,
1651 			do_play12 = FALSE,
1652 			do_play10 = FALSE,
1653 			do_playti = FALSE;
1654 	curstat_t	*s = di_clinfo->curstat_addr();
1655 
1656 	/* Fix addresses: Some CD drives will only allow playing to
1657 	 * the last frame minus a few frames.
1658 	 */
1659 	if ((addr_fmt & ADDR_MSF) && end_msf != NULL) {
1660 		emsf = *end_msf;	/* Structure copy */
1661 		emsfp = &emsf;
1662 
1663 		util_msftoblk(
1664 			start_msf->min,
1665 			start_msf->sec,
1666 			start_msf->frame,
1667 			&tmp_saddr,
1668 			MSF_OFFSET
1669 		);
1670 
1671 		util_msftoblk(
1672 			emsfp->min,
1673 			emsfp->sec,
1674 			emsfp->frame,
1675 			&tmp_eaddr,
1676 			MSF_OFFSET
1677 		);
1678 
1679 		if (tmp_eaddr > s->discpos_tot.addr)
1680 			tmp_eaddr = s->discpos_tot.addr;
1681 
1682 		if (tmp_eaddr >= di_clip_frames)
1683 			tmp_eaddr -= di_clip_frames;
1684 		else
1685 			tmp_eaddr = 0;
1686 
1687 		util_blktomsf(
1688 			tmp_eaddr,
1689 			&emsfp->min,
1690 			&emsfp->sec,
1691 			&emsfp->frame,
1692 			MSF_OFFSET
1693 		);
1694 
1695 		if (tmp_saddr >= tmp_eaddr)
1696 			return FALSE;
1697 
1698 		emsfp->res = start_msf->res = 0;
1699 
1700 		/* Save end address for error recovery */
1701 		scsipt_sav_end_msf = *end_msf;
1702 	}
1703 	if (addr_fmt & ADDR_BLK) {
1704 		if (end_addr > s->discpos_tot.addr)
1705 			end_addr = s->discpos_tot.addr;
1706 
1707 		if (end_addr >= di_clip_frames)
1708 			end_addr -= di_clip_frames;
1709 		else
1710 			end_addr = 0;
1711 
1712 		if (start_addr >= end_addr)
1713 			return FALSE;
1714 
1715 		/* Save end address for error recovery */
1716 		scsipt_sav_end_addr = end_addr;
1717 	}
1718 
1719 	/* Save end address format for error recovery */
1720 	scsipt_sav_end_fmt = addr_fmt;
1721 
1722 	if (PLAYMODE_IS_STD(app_data.play_mode) &&
1723 	    scsipt_vutbl[app_data.vendor_code].playaudio != NULL) {
1724 		ret = scsipt_vutbl[app_data.vendor_code].playaudio(
1725 			addr_fmt,
1726 			start_addr, end_addr,
1727 			start_msf, emsfp,
1728 			trk, idx
1729 		);
1730 	}
1731 
1732 	if (!ret) {
1733 		/* If the device does not claim SCSI-2 compliance, and the
1734 		 * device-specific configuration is not SCSI-2, then don't
1735 		 * attempt to deliver SCSI-2 commands to the device.
1736 		 */
1737 		if (app_data.vendor_code != VENDOR_SCSI2 &&
1738 		    scsipt_dev_scsiver < 2)
1739 			return FALSE;
1740 
1741 		do_playmsf = (addr_fmt & ADDR_MSF) && app_data.playmsf_supp;
1742 		do_play12 = (addr_fmt & ADDR_BLK) && app_data.play12_supp;
1743 		do_play10 = (addr_fmt & ADDR_BLK) && app_data.play10_supp;
1744 		do_playti = (addr_fmt & ADDR_TRKIDX) && app_data.playti_supp;
1745 
1746 		if (do_playmsf || do_play12 || do_play10 || do_playti) {
1747 			if (scsipt_paused) {
1748 				if (app_data.strict_pause_resume) {
1749 					/* Resume first */
1750 					(void) scsipt_do_pause_resume(
1751 						dp, TRUE
1752 					);
1753 				}
1754 			}
1755 			else if (scsipt_playing) {
1756 				if (app_data.play_pause_play) {
1757 					/* Pause first */
1758 					(void) scsipt_do_pause_resume(
1759 						dp, FALSE
1760 					);
1761 				}
1762 			}
1763 			else {
1764 				/* Spin up CD */
1765 				(void) scsipt_do_start_stop(
1766 					dp, TRUE, FALSE,
1767 					(bool_t)
1768 					    ((app_data.debug & DBG_DEVIO) != 0)
1769 				);
1770 			}
1771 		}
1772 	}
1773 
1774 	if (PLAYMODE_IS_CDDA(app_data.play_mode)) {
1775 		if (do_play12 || do_play10) {
1776 			if (scsipt_is_enabled(devp, DI_ROLE_MAIN))
1777 				scsipt_disable(dp, DI_ROLE_MAIN);
1778 
1779 			ret = cdda_play(dp, s, start_addr, end_addr);
1780 		}
1781 		else if (do_playmsf) {
1782 			util_msftoblk(
1783 				start_msf->min,
1784 				start_msf->sec,
1785 				start_msf->frame,
1786 				&start_addr,
1787 				MSF_OFFSET
1788 			);
1789 			util_msftoblk(
1790 				emsfp->min,
1791 				emsfp->sec,
1792 				emsfp->frame,
1793 				&end_addr,
1794 				MSF_OFFSET
1795 			);
1796 			ret = cdda_play(dp, s, start_addr, end_addr);
1797 		}
1798 	}
1799 	else {
1800 		if (!ret && do_playmsf)
1801 			ret = scsipt_playmsf(dp, DI_ROLE_MAIN,
1802 					     start_msf, emsfp);
1803 
1804 		if (!ret && do_play12)
1805 			ret = scsipt_play12(dp, DI_ROLE_MAIN, start_addr,
1806 					    end_addr - start_addr);
1807 
1808 		if (!ret && do_play10)
1809 			ret = scsipt_play10(dp, DI_ROLE_MAIN, start_addr,
1810 					    end_addr - start_addr);
1811 
1812 		if (!ret && do_playti)
1813 			ret = scsipt_play_trkidx(dp, DI_ROLE_MAIN,
1814 						 trk, idx, trk, idx);
1815 	}
1816 
1817 	if (ret) {
1818 		scsipt_playing = TRUE;
1819 		scsipt_paused = FALSE;
1820 	}
1821 
1822 	return (ret);
1823 }
1824 
1825 
1826 /*
1827  * scsipt_do_pause_resume
1828  *	General top-level pause/resume function
1829  *
1830  * Args:
1831  *	dp - Device descriptor
1832  *	resume - Whether to resume or pause
1833  *
1834  * Return:
1835  *	TRUE - success
1836  *	FALSE - failure
1837  */
1838 STATIC bool_t
scsipt_do_pause_resume(di_dev_t * dp,bool_t resume)1839 scsipt_do_pause_resume(di_dev_t *dp, bool_t resume)
1840 {
1841 	bool_t	ret = FALSE;
1842 
1843 	if (scsipt_vutbl[app_data.vendor_code].pause_resume != NULL)
1844 		ret = scsipt_vutbl[app_data.vendor_code].pause_resume(resume);
1845 
1846 	/* If the device does not claim SCSI-2 compliance, and the
1847 	 * device-specific configuration is not SCSI-2, then don't
1848 	 * attempt to deliver SCSI-2 commands to the device.
1849 	 */
1850 	if (!ret && app_data.vendor_code != VENDOR_SCSI2 &&
1851 	    scsipt_dev_scsiver < 2)
1852 		return FALSE;
1853 
1854 	if (!ret && app_data.pause_supp)
1855 		ret = scsipt_pause_resume(dp, DI_ROLE_MAIN, resume);
1856 
1857 	if (!ret && resume) {
1858 		int		i;
1859 		sword32_t	saddr,
1860 				eaddr;
1861 		msf_t		smsf,
1862 				emsf;
1863 		curstat_t	*s = di_clinfo->curstat_addr();
1864 
1865 		/* Resume failed: try restarting playback */
1866 		saddr = s->curpos_tot.addr;
1867 		smsf.min = s->curpos_tot.min;
1868 		smsf.sec = s->curpos_tot.sec;
1869 		smsf.frame = s->curpos_tot.frame;
1870 
1871 		if (s->program || s->shuffle) {
1872 			i = -1;
1873 
1874 			if (s->prog_cnt > 0)
1875 			    i = (int) s->trkinfo[s->prog_cnt - 1].playorder;
1876 
1877 			if (i < 0) {
1878 				if (ret)
1879 					scsipt_paused = !resume;
1880 
1881 				return (ret);
1882 			}
1883 
1884 			eaddr = s->trkinfo[i+1].addr;
1885 			emsf.min = s->trkinfo[i+1].min;
1886 			emsf.sec = s->trkinfo[i+1].sec;
1887 			emsf.frame = s->trkinfo[i+1].frame;
1888 		}
1889 		else {
1890 			eaddr = s->discpos_tot.addr;
1891 			emsf.min = s->discpos_tot.min;
1892 			emsf.sec = s->discpos_tot.sec;
1893 			emsf.frame = s->discpos_tot.frame;
1894 		}
1895 
1896 		ret = scsipt_do_playaudio(dp,
1897 			ADDR_BLK | ADDR_MSF,
1898 			saddr, eaddr, &smsf, &emsf, 0, 0
1899 		);
1900 	}
1901 
1902 	if (ret)
1903 		scsipt_paused = !resume;
1904 
1905 	return (ret);
1906 }
1907 
1908 
1909 /*
1910  * scsipt_do_start_stop
1911  *	General top-level start/stop function
1912  *
1913  * Args:
1914  *	dp - Device descriptor
1915  *	start - Whether to start unit or stop unit
1916  *	loej - Whether caddy load/eject operation should be performed
1917  *	prnerr - Whether to print error messages if the command fails
1918  *		 (SCSI-2 mode only)
1919  *
1920  * Return:
1921  *	TRUE - success
1922  *	FALSE - failure
1923  */
1924 STATIC bool_t
scsipt_do_start_stop(di_dev_t * dp,bool_t start,bool_t loej,bool_t prnerr)1925 scsipt_do_start_stop(di_dev_t *dp, bool_t start, bool_t loej, bool_t prnerr)
1926 {
1927 	bool_t	ret = FALSE;
1928 
1929 	if (app_data.strict_pause_resume && scsipt_paused)
1930 		(void) scsipt_do_pause_resume(dp, TRUE);
1931 
1932 	if (!app_data.load_supp && start && loej)
1933 		return FALSE;
1934 
1935 	if (!app_data.eject_supp)
1936 		loej = 0;
1937 
1938 #if defined(SOL2_VOLMGT) && !defined(DEMO_ONLY)
1939 	/* Sun Hack: Under Solaris 2.x with the Volume Manager
1940 	 * we need to use a special SunOS ioctl to eject the CD.
1941 	 */
1942 	if (app_data.sol2_volmgt && !start && loej)
1943 		ret = sol2_volmgt_eject(dp);
1944 	else
1945 #endif
1946 	{
1947 		if (!start && loej &&
1948 		    scsipt_vutbl[app_data.vendor_code].eject != NULL)
1949 			ret = scsipt_vutbl[app_data.vendor_code].eject();
1950 
1951 		if (!ret &&
1952 		    scsipt_vutbl[app_data.vendor_code].start_stop != NULL)
1953 			ret = scsipt_vutbl[app_data.vendor_code].start_stop(
1954 				start, loej
1955 			);
1956 
1957 		if (!ret)
1958 			ret = scsipt_start_stop(dp, DI_ROLE_MAIN,
1959 						start, loej, prnerr);
1960 	}
1961 
1962 	if (ret && !start)
1963 		scsipt_playing = FALSE;
1964 
1965 	return (ret);
1966 }
1967 
1968 
1969 /*
1970  * scsipt_play_recov
1971  *	Playback interruption recovery handler: Restart playback
1972  *	after skipping some frames.
1973  *
1974  * Args:
1975  *	blk   - Interruption frame address
1976  *	iserr - Whether interruption is due to error
1977  *
1978  * Return:
1979  *	TRUE - success
1980  *	FALSE - failure
1981  */
1982 STATIC bool_t
scsipt_play_recov(sword32_t blk,bool_t iserr)1983 scsipt_play_recov(sword32_t blk, bool_t iserr)
1984 {
1985 	msf_t		recov_start_msf;
1986 	sword32_t	recov_start_addr;
1987 	bool_t		ret;
1988 
1989 	ret = TRUE;
1990 
1991 	recov_start_addr = blk + ERR_SKIPBLKS;
1992 	util_blktomsf(
1993 		recov_start_addr,
1994 		&recov_start_msf.min,
1995 		&recov_start_msf.sec,
1996 		&recov_start_msf.frame,
1997 		MSF_OFFSET
1998 	);
1999 
2000 	/* Check to see if we have skipped past
2001 	 * the end.
2002 	 */
2003 	if (recov_start_msf.min > scsipt_sav_end_msf.min)
2004 		ret = FALSE;
2005 	else if (recov_start_msf.min == scsipt_sav_end_msf.min) {
2006 		if (recov_start_msf.sec > scsipt_sav_end_msf.sec)
2007 			ret = FALSE;
2008 		else if ((recov_start_msf.sec ==
2009 			  scsipt_sav_end_msf.sec) &&
2010 			 (recov_start_msf.frame >
2011 			  scsipt_sav_end_msf.frame)) {
2012 			ret = FALSE;
2013 		}
2014 	}
2015 	if (recov_start_addr >= scsipt_sav_end_addr)
2016 		ret = FALSE;
2017 
2018 	if (ret) {
2019 		/* Restart playback */
2020 		if (iserr) {
2021 			(void) fprintf(errfp,
2022 				"CD audio: %s (%02u:%02u.%02u)\n",
2023 				app_data.str_recoverr,
2024 				recov_start_msf.min,
2025 				recov_start_msf.sec,
2026 				recov_start_msf.frame
2027 			);
2028 		}
2029 
2030 		ret = scsipt_do_playaudio(devp,
2031 			scsipt_sav_end_fmt,
2032 			recov_start_addr, scsipt_sav_end_addr,
2033 			&recov_start_msf, &scsipt_sav_end_msf,
2034 			0, 0
2035 		);
2036 	}
2037 
2038 	return (ret);
2039 }
2040 
2041 
2042 /*
2043  * scsipt_get_playstatus
2044  *	Obtain and update current playback status information
2045  *
2046  * Args:
2047  *	s - Pointer to the curstat_t structure
2048  *
2049  * Return:
2050  *	TRUE - Audio playback is in progress
2051  *	FALSE - Audio playback stopped or command failure
2052  */
2053 STATIC bool_t
scsipt_get_playstatus(curstat_t * s)2054 scsipt_get_playstatus(curstat_t *s)
2055 {
2056 	cdstat_t		cdstat;
2057 	int			trkno,
2058 				idxno;
2059 	bool_t			done,
2060 				ret = FALSE;
2061 	static int		errcnt = 0,
2062 				nostatcnt = 0;
2063 	static sword32_t	errblk = 0;
2064 	static bool_t		in_scsipt_get_playstatus = FALSE;
2065 
2066 
2067 	/* Lock this routine from multiple entry */
2068 	if (in_scsipt_get_playstatus)
2069 		return TRUE;
2070 
2071 	in_scsipt_get_playstatus = TRUE;
2072 
2073 	if (scsipt_vutbl[app_data.vendor_code].get_playstatus != NULL) {
2074 		ret = scsipt_vutbl[app_data.vendor_code].get_playstatus(
2075 			&cdstat
2076 		);
2077 	}
2078 
2079 	/* If the device does not claim SCSI-2 compliance, and the
2080 	 * device-specific configuration is not SCSI-2, then don't
2081 	 * attempt to deliver SCSI-2 commands to the device.
2082 	 */
2083 	if (!ret && app_data.vendor_code != VENDOR_SCSI2 &&
2084 	    scsipt_dev_scsiver < 2) {
2085 		in_scsipt_get_playstatus = FALSE;
2086 		return FALSE;
2087 	}
2088 
2089 	if (!ret) {
2090 		if (PLAYMODE_IS_CDDA(app_data.play_mode)) {
2091 			ret = cdda_getstatus(devp, s, &cdstat);
2092 			if (ret &&
2093 			    (cdstat.level != s->level ||
2094 			     cdstat.level_left  != s->level_left ||
2095 			     cdstat.level_right != s->level_right)) {
2096 				int	vol;
2097 
2098 				/* Update volume & balance level */
2099 				s->level_left = cdstat.level_left;
2100 				s->level_right = cdstat.level_right;
2101 				vol = scsipt_cfg_vol(
2102 					(int) cdstat.level, s, FALSE, FALSE
2103 				);
2104 
2105 				if (vol >= 0) {
2106 					s->level = (byte_t) vol;
2107 					SET_VOL_SLIDER(s->level);
2108 					SET_BAL_SLIDER((int)
2109 						(s->level_right -
2110 						 s->level_left) / 2
2111 					);
2112 				}
2113 
2114 			}
2115 		}
2116 		else
2117 			ret = scsipt_rdsubq(devp, DI_ROLE_MAIN, SUB_CURPOS, 0,
2118 					    &cdstat, NULL, NULL, TRUE);
2119 	}
2120 
2121 	if (!ret) {
2122 		/* Check to see if the disc had been manually ejected */
2123 		if (!scsipt_disc_ready(s)) {
2124 			scsipt_sav_end_addr = 0;
2125 			scsipt_sav_end_msf.min = 0;
2126 			scsipt_sav_end_msf.sec = 0;
2127 			scsipt_sav_end_msf.frame = 0;
2128 			scsipt_sav_end_fmt = 0;
2129 			errcnt = 0;
2130 			errblk = 0;
2131 
2132 			in_scsipt_get_playstatus = FALSE;
2133 			return FALSE;
2134 		}
2135 
2136 		/* Can't get play status for some unknown reason.
2137 		 * Just return success and hope the next poll
2138 		 * succeeds.  We don't want to return FALSE here
2139 		 * because that would stop the poll.
2140 		 */
2141 		in_scsipt_get_playstatus = FALSE;
2142 		return TRUE;
2143 	}
2144 
2145 	trkno = cdstat.track;
2146 	idxno = cdstat.index;
2147 	s->curpos_tot = cdstat.abs_addr;	/* structure copy */
2148 	s->curpos_trk = cdstat.rel_addr;	/* structure copy */
2149 
2150 	s->tot_frm = cdstat.tot_frm;
2151 	s->frm_played = cdstat.frm_played;
2152 	s->frm_per_sec = cdstat.frm_per_sec;
2153 
2154 	/* Update time display */
2155 	DPY_TIME(s, FALSE);
2156 
2157 	if (trkno != s->cur_trk) {
2158 		s->cur_trk = trkno;
2159 		/* Update track number display */
2160 		DPY_TRACK(s);
2161 	}
2162 
2163 	if (idxno != s->cur_idx) {
2164 		s->cur_idx = idxno;
2165 		s->sav_iaddr = s->curpos_tot.addr;
2166 		/* Update index number display */
2167 		DPY_INDEX(s);
2168 	}
2169 
2170 	/* Update play mode display */
2171 	DPY_PLAYMODE(s, FALSE);
2172 
2173 	/* Hack: to work around the fact that some CD drives return
2174 	 * "paused" status after issuing a Stop Unit command.
2175 	 * Just treat the status as completed if we get a paused status
2176 	 * and we don't expect the drive to be paused.
2177 	 */
2178 	if (cdstat.status == CDSTAT_PAUSED && s->mode != MOD_PAUSE &&
2179 	    !scsipt_idx_pause)
2180 		cdstat.status = CDSTAT_COMPLETED;
2181 
2182 	/* Force completion status */
2183 	if (scsipt_fake_stop)
2184 		cdstat.status = CDSTAT_COMPLETED;
2185 
2186 	/* Deal with playback status */
2187 	switch (cdstat.status) {
2188 	case CDSTAT_PLAYING:
2189 	case CDSTAT_PAUSED:
2190 		nostatcnt = 0;
2191 		done = FALSE;
2192 
2193 		/* If we haven't encountered an error for a while, then
2194 		 * clear the error count.
2195 		 */
2196 		if (errcnt > 0 && (s->curpos_tot.addr - errblk) > ERR_CLRTHRESH)
2197 			errcnt = 0;
2198 		break;
2199 
2200 	case CDSTAT_FAILED:
2201 		nostatcnt = 0;
2202 		/* Check to see if the disc had been manually ejected */
2203 		if (!scsipt_disc_ready(s)) {
2204 			scsipt_sav_end_addr = 0;
2205 			scsipt_sav_end_msf.min = 0;
2206 			scsipt_sav_end_msf.sec = 0;
2207 			scsipt_sav_end_msf.frame = 0;
2208 			scsipt_sav_end_fmt = 0;
2209 			errcnt = 0;
2210 			errblk = 0;
2211 
2212 			in_scsipt_get_playstatus = FALSE;
2213 			return FALSE;
2214 		}
2215 
2216 		/* Audio playback stopped due to a disc error.  We will
2217 		 * try to restart the playback by skipping a few frames
2218 		 * and continuing.  This will cause a glitch in the sound
2219 		 * but is better than just stopping.
2220 		 */
2221 		done = FALSE;
2222 
2223 		/* Check for max errors limit */
2224 		if (++errcnt > MAX_RECOVERR) {
2225 			done = TRUE;
2226 			(void) fprintf(errfp, "CD audio: %s\n",
2227 				       app_data.str_maxerr);
2228 		}
2229 
2230 		errblk = s->curpos_tot.addr;
2231 
2232 		if (!done && scsipt_play_recov(errblk, TRUE)) {
2233 			in_scsipt_get_playstatus = FALSE;
2234 			return TRUE;
2235 		}
2236 
2237 		/*FALLTHROUGH*/
2238 
2239 	case CDSTAT_COMPLETED:
2240 	case CDSTAT_NOSTATUS:
2241 	default:
2242 		if (cdstat.status == CDSTAT_NOSTATUS && nostatcnt++ < 20) {
2243 			/* Allow 20 occurrences of nostatus, then stop */
2244 			done = FALSE;
2245 			break;
2246 		}
2247 		nostatcnt = 0;
2248 		done = TRUE;
2249 
2250 		if (!scsipt_fake_stop)
2251 			scsipt_playing = FALSE;
2252 
2253 		scsipt_fake_stop = FALSE;
2254 
2255 		switch (s->mode) {
2256 		case MOD_SAMPLE:
2257 			done = !scsipt_run_sample(s);
2258 			break;
2259 
2260 		case MOD_PLAY:
2261 		case MOD_PAUSE:
2262 			s->curpos_trk.addr = 0;
2263 			s->curpos_trk.min = 0;
2264 			s->curpos_trk.sec = 0;
2265 			s->curpos_trk.frame = 0;
2266 
2267 			if (s->shuffle || s->program)
2268 				done = !scsipt_run_prog(s);
2269 
2270 			if (s->repeat && (s->program || !app_data.multi_play))
2271 				done = !scsipt_run_repeat(s);
2272 
2273 			if (s->repeat && s->segplay == SEGP_AB)
2274 				done = !scsipt_run_ab(s);
2275 
2276 			break;
2277 		}
2278 
2279 		break;
2280 	}
2281 
2282 	if (done) {
2283 		byte_t	omode;
2284 		bool_t	prog;
2285 
2286 		/* Save some old states */
2287 		omode = s->mode;
2288 		prog = (s->program || s->onetrk_prog);
2289 
2290 		/* Reset states */
2291 		di_reset_curstat(s, FALSE, FALSE);
2292 		s->mode = MOD_STOP;
2293 
2294 		/* Cancel a->? if the user didn't select an end point */
2295 		if (s->segplay == SEGP_A) {
2296 			s->segplay = SEGP_NONE;
2297 			DPY_PROGMODE(s, FALSE);
2298 		}
2299 
2300 		scsipt_sav_end_addr = 0;
2301 		scsipt_sav_end_msf.min = scsipt_sav_end_msf.sec =
2302 			scsipt_sav_end_msf.frame = 0;
2303 		scsipt_sav_end_fmt = 0;
2304 		errcnt = 0;
2305 		errblk = 0;
2306 
2307 		if (app_data.multi_play && omode == MOD_PLAY && !prog) {
2308 			bool_t	cont;
2309 
2310 			s->prev_disc = s->cur_disc;
2311 
2312 			if (app_data.reverse) {
2313 				if (s->cur_disc > s->first_disc) {
2314 					/* Play the previous disc */
2315 					s->cur_disc--;
2316 					scsipt_mult_autoplay = TRUE;
2317 				}
2318 				else {
2319 					/* Go to the last disc */
2320 					s->cur_disc = s->last_disc;
2321 
2322 					if (s->repeat) {
2323 						s->rptcnt++;
2324 						scsipt_mult_autoplay = TRUE;
2325 					}
2326 				}
2327 			}
2328 			else {
2329 				if (s->cur_disc < s->last_disc) {
2330 					/* Play the next disc */
2331 					s->cur_disc++;
2332 					scsipt_mult_autoplay = TRUE;
2333 				}
2334 				else {
2335 					/* Go to the first disc.  */
2336 					s->cur_disc = s->first_disc;
2337 
2338 					if (s->repeat) {
2339 						s->rptcnt++;
2340 						scsipt_mult_autoplay = TRUE;
2341 					}
2342 				}
2343 			}
2344 
2345 			if ((cont = scsipt_mult_autoplay) == TRUE) {
2346 				/* Allow recursion from this point */
2347 				in_scsipt_get_playstatus = FALSE;
2348 			}
2349 
2350 			/* Change disc */
2351 			scsipt_chgdisc(s);
2352 
2353 			if (cont)
2354 				return TRUE;
2355 		}
2356 
2357 		s->rptcnt = 0;
2358 		DPY_ALL(s);
2359 
2360 		if (app_data.done_eject) {
2361 			/* Eject the disc */
2362 			scsipt_load_eject(s);
2363 		}
2364 		else {
2365 			/* Spin down the disc */
2366 			(void) scsipt_do_start_stop(devp, FALSE, FALSE, TRUE);
2367 		}
2368 		if (app_data.done_exit) {
2369 			/* Exit */
2370 			di_clinfo->quit(s);
2371 		}
2372 
2373 		in_scsipt_get_playstatus = FALSE;
2374 		return FALSE;
2375 	}
2376 
2377 	in_scsipt_get_playstatus = FALSE;
2378 	return TRUE;
2379 }
2380 
2381 
2382 /*
2383  * scsipt_cfg_vol
2384  *	Audio volume control function
2385  *
2386  * Args:
2387  *	vol - Logical volume value to set to
2388  *	s - Pointer to the curstat_t structure
2389  *	query - If TRUE, query current volume only
2390  *	user - Whether a volume update is due to user action
2391  *
2392  * Return:
2393  *	The current logical volume value, or -1 on failure.
2394  */
2395 STATIC int
scsipt_cfg_vol(int vol,curstat_t * s,bool_t query,bool_t user)2396 scsipt_cfg_vol(int vol, curstat_t *s, bool_t query, bool_t user)
2397 {
2398 	int			vol1,
2399 				vol2;
2400 	mode_sense_6_data_t	*ms_data6 = NULL;
2401 	mode_sense_10_data_t	*ms_data10 = NULL;
2402 	blk_desc_t		*bdesc;
2403 	audio_pg_t		*audiopg;
2404 	int			bdesclen;
2405 	byte_t			buf[SZ_MSENSE];
2406 	bool_t			ret = FALSE;
2407 	static bool_t		muted = FALSE;
2408 
2409 	if (s->mode == MOD_BUSY)
2410 		return -1;
2411 
2412 	if (PLAYMODE_IS_STD(app_data.play_mode) &&
2413 	    scsipt_vutbl[app_data.vendor_code].volume != NULL) {
2414 		vol = scsipt_vutbl[app_data.vendor_code].volume(vol, s, query);
2415 		return (vol);
2416 	}
2417 
2418 	if (PLAYMODE_IS_STD(app_data.play_mode) &&
2419 	    scsipt_vutbl[app_data.vendor_code].mute != NULL) {
2420 		if (!query) {
2421 			if (vol < (int) s->level)
2422 				vol = 0;
2423 			else if (vol > (int) s->level ||
2424 				 (vol != 0 && vol != 100))
2425 				vol = 100;
2426 
2427 			ret = scsipt_vutbl[app_data.vendor_code].mute(
2428 				(bool_t) (vol == 0)
2429 			);
2430 			if (ret)
2431 				muted = (vol == 0);
2432 		}
2433 
2434 		vol = muted ? 0 : MAX_VOL;
2435 
2436 		/* Force volume slider to full mute or max positions */
2437 		if (user)
2438 			SET_VOL_SLIDER(vol);
2439 
2440 		return (vol);
2441 	}
2442 
2443 	if (!app_data.mselvol_supp)
2444 		return 0;
2445 
2446 	if (PLAYMODE_IS_CDDA(app_data.play_mode))
2447 		return (cdda_vol(devp, s, vol, query));
2448 
2449 	(void) memset(buf, 0, sizeof(buf));
2450 
2451 	if (!scsipt_modesense(devp, DI_ROLE_MAIN, buf, 0,
2452 			      PG_AUDIOCTL, SZ_AUDIOCTL))
2453 		return -1;
2454 
2455 	if (app_data.msen_10) {
2456 		ms_data10 = (mode_sense_10_data_t *)(void *) buf;
2457 		bdesc = (blk_desc_t *)(void *) ms_data10->data;
2458 		bdesclen = (int)
2459 			util_bswap16((word16_t) ms_data10->bdescr_len);
2460 		ms_data10->data_len = 0;
2461 		ms_data10->medium = 0;
2462 	}
2463 	else {
2464 		ms_data6 = (mode_sense_6_data_t *)(void *) buf;
2465 		bdesc = (blk_desc_t *)(void *) ms_data6->data;
2466 		bdesclen = (int) ms_data6->bdescr_len;
2467 		ms_data6->data_len = 0;
2468 		ms_data6->medium = 0;
2469 	}
2470 	audiopg = (audio_pg_t *)(void *) ((byte_t *) bdesc + bdesclen);
2471 
2472 	if (bdesclen > 0)
2473 		bdesc->num_blks = 0;
2474 
2475 	if (audiopg->pg_code == PG_AUDIOCTL) {
2476 		if (query) {
2477 			vol1 = util_untaper_vol(
2478 				util_unscale_vol((int) audiopg->p0_vol)
2479 			);
2480 			vol2 = util_untaper_vol(
2481 				util_unscale_vol((int) audiopg->p1_vol)
2482 			);
2483 			scsipt_route_left = (byte_t) audiopg->p0_ch_ctrl;
2484 			scsipt_route_right = (byte_t) audiopg->p1_ch_ctrl;
2485 
2486 			if (vol1 == vol2) {
2487 				s->level_left = s->level_right = 100;
2488 				vol = vol1;
2489 			}
2490 			else if (vol1 > vol2) {
2491 				s->level_left = 100;
2492 				s->level_right = (byte_t)((vol2 * 100) / vol1);
2493 				vol = vol1;
2494 			}
2495 			else {
2496 				s->level_left = (byte_t) ((vol1 * 100) / vol2);
2497 				s->level_right = 100;
2498 				vol = vol2;
2499 			}
2500 			return (vol);
2501 		}
2502 		else {
2503 			audiopg->p0_vol = util_scale_vol(
2504 			    util_taper_vol(vol * (int) s->level_left / 100)
2505 			);
2506 			audiopg->p1_vol = util_scale_vol(
2507 			    util_taper_vol(vol * (int) s->level_right / 100)
2508 			);
2509 
2510 			audiopg->p0_ch_ctrl = scsipt_route_left;
2511 			audiopg->p1_ch_ctrl = scsipt_route_right;
2512 
2513 			audiopg->sotc = 0;
2514 			audiopg->immed = 1;
2515 
2516 			if (scsipt_modesel(devp, DI_ROLE_MAIN, buf,
2517 					   PG_AUDIOCTL, SZ_AUDIOCTL)) {
2518 				/* Success */
2519 				return (vol);
2520 			}
2521 			else if (audiopg->p0_vol != audiopg->p1_vol) {
2522 				/* Set the balance to the center
2523 				 * and retry.
2524 				 */
2525 				audiopg->p0_vol = audiopg->p1_vol =
2526 					util_scale_vol(util_taper_vol(vol));
2527 
2528 				if (scsipt_modesel(devp, DI_ROLE_MAIN,
2529 						   buf, PG_AUDIOCTL,
2530 						   SZ_AUDIOCTL)) {
2531 					/* Success: Warp balance control */
2532 					s->level_left = s->level_right = 100;
2533 					SET_BAL_SLIDER(0);
2534 
2535 					return (vol);
2536 				}
2537 
2538 				/* Still failed: just drop through */
2539 			}
2540 		}
2541 	}
2542 
2543 	return -1;
2544 }
2545 
2546 
2547 /*
2548  * scsipt_vendor_model
2549  *	Query and update CD drive vendor/model/revision information,
2550  *	and check the device type.
2551  *
2552  * Args:
2553  *	s - Pointer to the curstat_t structure
2554  *
2555  * Return:
2556  *	TRUE  - success
2557  *	FALSE - The device is not a CD-ROM or WORM
2558  */
2559 STATIC bool_t
scsipt_vendor_model(curstat_t * s)2560 scsipt_vendor_model(curstat_t *s)
2561 {
2562 	inquiry_data_t	inq;
2563 	int		i;
2564 	char		errstr[ERR_BUF_SZ];
2565 
2566 	i = 0;
2567 	do {
2568 		(void) memset((byte_t *) &inq, 0, sizeof(inq));
2569 
2570 		if (scsipt_inquiry(devp, DI_ROLE_MAIN,
2571 				   (byte_t *) &inq, sizeof(inq)))
2572 			break;
2573 
2574 		util_delayms(1000);
2575 	} while (++i < 3);
2576 
2577 	if (i >= 3)
2578 		/* Can't do inquiry: shrug. */
2579 		return FALSE;
2580 
2581 #ifdef _AIX
2582 	/* Hack: Some versions of AIX 4.x returns
2583 	 * bogus SCSI inquiry data.  Attempt to work
2584 	 * around this.
2585 	 */
2586 	{
2587 		int	j;
2588 		char	*p;
2589 
2590 		p = (char *) &inq;
2591 		for (j = 0; j < 8; j++, p++) {
2592 			if (!isalnum(*p) && !isspace(*p))
2593 				break;
2594 		}
2595 		if (j == 8) {
2596 			/* Fix up inquiry data */
2597 			(void) memset((byte_t *) &inq, 0, sizeof(inq));
2598 
2599 			p = (char *) &inq;
2600 			(void) strncpy(s->vendor, p, 8);
2601 			s->vendor[8] = '\0';
2602 
2603 			p += 8;
2604 			(void) strncpy(s->prod, p, 16);
2605 			s->prod[16] = '\0';
2606 
2607 			(void) strncpy((char *) inq.vendor, s->vendor, 8);
2608 			(void) strncpy((char *) inq.prod, s->prod, 16);
2609 			inq.type = DEV_ROM;
2610 			inq.rmb = 1;
2611 			inq.ver = 2;
2612 		}
2613 	}
2614 #endif	/* AIX */
2615 
2616 	DBGPRN(DBG_DEVIO)(errfp,
2617 		"\nCD drive: vendor=\"%.8s\" prod=\"%.16s\" rev=\"%.4s\"\n",
2618 		inq.vendor, inq.prod, inq.revnum);
2619 
2620 	(void) strncpy(s->vendor, (char *) inq.vendor, 8);
2621 	s->vendor[8] = '\0';
2622 
2623 	(void) strncpy(s->prod, (char *) inq.prod, 16);
2624 	s->prod[16] = '\0';
2625 
2626 	(void) strncpy(s->revnum, (char *) inq.revnum, 4);
2627 	s->revnum[4] = '\0';
2628 
2629 #ifndef OEM_CDROM
2630 	/* Check for errors.
2631 	 * Note: Some OEM drives identify themselves
2632 	 * as a hard disk instead of a CD-ROM drive
2633 	 * (such as the Toshiba CD-ROM XM revision 1971
2634 	 * OEMed by SGI).  In order to use those units
2635 	 * this file must be compiled with -DOEM_CDROM.
2636 	 */
2637 	if ((inq.type != DEV_ROM && inq.type != DEV_WORM) || !inq.rmb){
2638 		/* Not a CD-ROM or a WORM device */
2639 		(void) sprintf(errstr, app_data.str_notrom, s->curdev);
2640 		DI_FATAL(errstr);
2641 		return FALSE;
2642 	}
2643 #endif
2644 
2645 	/* Check for unsupported drives */
2646 	scsipt_dev_scsiver = (byte_t) (inq.ver & 0x07);
2647 	if (app_data.scsiverck &&
2648 	    scsipt_dev_scsiver < 2 && app_data.vendor_code == VENDOR_SCSI2) {
2649 		/* Not SCSI-2 or later */
2650 		(void) sprintf(errstr, app_data.str_notscsi2, s->curdev);
2651 		DI_WARNING(errstr);
2652 	}
2653 
2654 	return TRUE;
2655 }
2656 
2657 
2658 /*
2659  * scsipt_fix_toc
2660  *	CD Table Of Contents post-processing function.  This is to patch
2661  *	the end-of-audio position to handle "enhanced CD" or "CD Extra"
2662  *	multisession CDs.
2663  *
2664  * Args:
2665  *	s - Pointer to the curstat_t structure
2666  *
2667  * Return:
2668  *	Nothing.
2669  */
2670 STATIC void
scsipt_fix_toc(curstat_t * s)2671 scsipt_fix_toc(curstat_t *s)
2672 {
2673 	int			i;
2674 	byte_t			*cp,
2675 				buf[12];
2676 	toc_hdr_t		*h;
2677 	toc_trk_descr_t		*p;
2678 
2679 	/*
2680 	 * Try primitive method first.
2681 	 * Set the end-of-audio to the first data track after the first
2682 	 * track, minus 02:32:00, if applicable.  The 02:32:00 is the
2683 	 * inter-session lead-out and lead-in time plus the 2-second
2684 	 * pre-gap for the last session.
2685 	 */
2686 	for (i = 1; i < (int) s->tot_trks; i++) {
2687 		if (s->trkinfo[i].type == TYP_DATA) {
2688 			s->discpos_tot.addr = s->trkinfo[i].addr;
2689 			s->discpos_tot.addr -= 11400;
2690 			util_blktomsf(
2691 				s->discpos_tot.addr,
2692 				&s->discpos_tot.min,
2693 				&s->discpos_tot.sec,
2694 				&s->discpos_tot.frame,
2695 				MSF_OFFSET
2696 			);
2697 			break;
2698 		}
2699 	}
2700 
2701 	if (app_data.vendor_code != VENDOR_SCSI2)
2702 		return;
2703 
2704 	/* Check if the CD is a multi-session disc */
2705 	if (!scsipt_rdtoc(devp, DI_ROLE_MAIN, buf, sizeof(buf), 0, 1, FALSE,
2706 			  (bool_t) ((app_data.debug & DBG_DEVIO) != 0)))
2707 		return;		/* Drive does not support multi-session */
2708 
2709 	h = (toc_hdr_t *)(void *) buf;
2710 	cp = (byte_t *) h + sizeof(toc_hdr_t);
2711 	if (((int) util_bswap16(h->data_len) + 2) == sizeof(buf) &&
2712 	    h->first_trk != h->last_trk) {
2713 		/* Multi-session disc detected */
2714 		p = (toc_trk_descr_t *)(void *) cp;
2715 
2716 		s->discpos_tot.addr = util_xlate_blk((sword32_t)
2717 			util_bswap32(p->abs_addr.logical)
2718 		);
2719 
2720 		/* Subtract 02:32:00 from the start of last session
2721 		 * and fix up end of audio location.  The 02:32:00
2722 		 * is the inter-session lead-out and lead-in time plus
2723 		 * the 2 second pre-gap for the last session.
2724 		 */
2725 		s->discpos_tot.addr -= 11400;
2726 
2727 		util_blktomsf(
2728 			s->discpos_tot.addr,
2729 			&s->discpos_tot.min,
2730 			&s->discpos_tot.sec,
2731 			&s->discpos_tot.frame,
2732 			MSF_OFFSET
2733 		);
2734 	}
2735 }
2736 
2737 
2738 /*
2739  * scsipt_get_toc
2740  *	Query and update the CD Table Of Contents
2741  *
2742  * Args:
2743  *	s - Pointer to the curstat_t structure
2744  *
2745  * Return:
2746  *	TRUE - success
2747  *	FALSE - failure
2748  */
2749 STATIC bool_t
scsipt_get_toc(curstat_t * s)2750 scsipt_get_toc(curstat_t *s)
2751 {
2752 	int			i,
2753 				ntrks;
2754 	byte_t			*cp,
2755 				*toc_end,
2756 				buf[SZ_RDTOC];
2757 	bool_t			ret = FALSE;
2758 	toc_hdr_t		*h;
2759 	toc_trk_descr_t		*p;
2760 
2761 
2762 	if (scsipt_vutbl[app_data.vendor_code].get_toc != NULL)
2763 		ret = scsipt_vutbl[app_data.vendor_code].get_toc(s);
2764 
2765 	if (ret) {
2766 		scsipt_fix_toc(s);
2767 		return TRUE;
2768 	}
2769 
2770 	/* If the device does not claim SCSI-2 compliance, and the
2771 	 * device-specific configuration is not SCSI-2, then don't
2772 	 * attempt to deliver SCSI-2 commands to the device.
2773 	 */
2774 	if (!ret && app_data.vendor_code != VENDOR_SCSI2 &&
2775 	    scsipt_dev_scsiver < 2)
2776 		return FALSE;
2777 
2778 	(void) memset(buf, 0, sizeof(buf));
2779 
2780 	if (!scsipt_rdtoc(devp, DI_ROLE_MAIN, buf, sizeof(buf), 0,
2781 			  0, (bool_t) !app_data.toc_lba, TRUE))
2782 		return FALSE;
2783 
2784 	/* Fill curstat structure with TOC data */
2785 	h = (toc_hdr_t *)(void *) buf;
2786 	toc_end = (byte_t *) h + util_bswap16(h->data_len) + 2;
2787 
2788 	s->first_trk = h->first_trk;
2789 	s->last_trk = h->last_trk;
2790 
2791 	ntrks = (int) (h->last_trk - h->first_trk) + 1;
2792 
2793 	/* Hack: workaround CD drive firmware bug
2794 	 * Some CD drives return track numbers in BCD
2795 	 * rather than binary.
2796 	 */
2797 	cp = (byte_t *) h + sizeof(toc_hdr_t);
2798 
2799 	for (i = 0; i <= ntrks; i++) {
2800 		int	trk0,
2801 			trk1;
2802 
2803 		p = (toc_trk_descr_t *)(void *) cp;
2804 
2805 		if (p->trkno == LEAD_OUT_TRACK && i != ntrks) {
2806 			trk0 = util_bcdtol(h->first_trk);
2807 			trk1 = util_bcdtol(h->last_trk);
2808 
2809 			if (i == (trk1 - trk0 + 1)) {
2810 				/* BUGLY firmware detected! */
2811 				scsipt_bcd_hack = TRUE;
2812 				s->first_trk = (byte_t) trk0;
2813 				s->last_trk = (byte_t) trk1;
2814 				break;
2815 			}
2816 		}
2817 
2818 		cp += sizeof(toc_trk_descr_t);
2819 	}
2820 
2821 	/*
2822 	 * Fill in TOC data
2823 	 */
2824 	cp = (byte_t *) h + sizeof(toc_hdr_t);
2825 
2826 	for (i = 0; cp < toc_end && i < MAXTRACK; i++) {
2827 		p = (toc_trk_descr_t *)(void *) cp;
2828 
2829 		/* Hack: Work around firmware problem on some drives */
2830 		if (i > 0 && s->trkinfo[i-1].trkno == s->last_trk &&
2831 		    p->trkno != LEAD_OUT_TRACK) {
2832 			(void) memset(buf, 0, sizeof(buf));
2833 
2834 			if (!scsipt_rdtoc(devp, DI_ROLE_MAIN, buf, sizeof(buf),
2835 					  (int) s->last_trk, 0,
2836 					  (bool_t) !app_data.toc_lba, TRUE))
2837 				return FALSE;
2838 
2839 			cp = (byte_t *) h + sizeof(toc_hdr_t) +
2840 			     sizeof(toc_trk_descr_t);
2841 
2842 			toc_end = (byte_t *) h + util_bswap16(h->data_len) + 2;
2843 
2844 			p = (toc_trk_descr_t *)(void *) cp;
2845 		}
2846 
2847 		if (scsipt_bcd_hack)
2848 			/* Hack: BUGLY CD drive firmware */
2849 			s->trkinfo[i].trkno = util_bcdtol(p->trkno);
2850 		else
2851 			s->trkinfo[i].trkno = p->trkno;
2852 
2853 		s->trkinfo[i].type =
2854 			(p->trktype == 0) ? TYP_AUDIO : TYP_DATA;
2855 
2856 		if (app_data.toc_lba) {
2857 			/* LBA mode */
2858 			s->trkinfo[i].addr = util_xlate_blk((sword32_t)
2859 				util_bswap32(p->abs_addr.logical)
2860 			);
2861 			util_blktomsf(
2862 				s->trkinfo[i].addr,
2863 				&s->trkinfo[i].min,
2864 				&s->trkinfo[i].sec,
2865 				&s->trkinfo[i].frame,
2866 				MSF_OFFSET
2867 			);
2868 		}
2869 		else {
2870 			/* MSF mode */
2871 			s->trkinfo[i].min = p->abs_addr.msf.min;
2872 			s->trkinfo[i].sec = p->abs_addr.msf.sec;
2873 			s->trkinfo[i].frame = p->abs_addr.msf.frame;
2874 			util_msftoblk(
2875 				s->trkinfo[i].min,
2876 				s->trkinfo[i].sec,
2877 				s->trkinfo[i].frame,
2878 				&s->trkinfo[i].addr,
2879 				MSF_OFFSET
2880 			);
2881 		}
2882 
2883 		if (p->trkno == LEAD_OUT_TRACK ||
2884 		    s->trkinfo[i-1].trkno == s->last_trk ||
2885 		    i == (MAXTRACK - 1)) {
2886 			s->discpos_tot.min = s->trkinfo[i].min;
2887 			s->discpos_tot.sec = s->trkinfo[i].sec;
2888 			s->discpos_tot.frame = s->trkinfo[i].frame;
2889 			s->tot_trks = (byte_t) i;
2890 			s->discpos_tot.addr = s->trkinfo[i].addr;
2891 
2892 			break;
2893 		}
2894 
2895 		cp += sizeof(toc_trk_descr_t);
2896 	}
2897 
2898 	scsipt_fix_toc(s);
2899 
2900 	return TRUE;
2901 }
2902 
2903 
2904 /*
2905  * scsipt_start_stat_poll
2906  *	Start polling the drive for current playback status
2907  *
2908  * Args:
2909  *	s - Pointer to the curstat_t structure
2910  *
2911  * Return:
2912  *	Nothing.
2913  */
2914 STATIC void
scsipt_start_stat_poll(curstat_t * s)2915 scsipt_start_stat_poll(curstat_t *s)
2916 {
2917 	/* Start poll timer */
2918 	if (di_clinfo->timeout != NULL) {
2919 		scsipt_stat_id = di_clinfo->timeout(
2920 			scsipt_stat_interval,
2921 			scsipt_stat_poll,
2922 			(byte_t *) s
2923 		);
2924 
2925 		if (scsipt_stat_id != 0)
2926 			scsipt_stat_polling = TRUE;
2927 	}
2928 }
2929 
2930 
2931 /*
2932  * scsipt_stop_stat_poll
2933  *	Stop polling the drive for current playback status
2934  *
2935  * Args:
2936  *	Nothing.
2937  *
2938  * Return:
2939  *	Nothing.
2940  */
2941 STATIC void
scsipt_stop_stat_poll(void)2942 scsipt_stop_stat_poll(void)
2943 {
2944 	if (scsipt_stat_polling) {
2945 		/* Stop poll timer */
2946 		if (di_clinfo->untimeout != NULL)
2947 			di_clinfo->untimeout(scsipt_stat_id);
2948 
2949 		scsipt_stat_polling = FALSE;
2950 	}
2951 }
2952 
2953 
2954 /*
2955  * scsipt_start_insert_poll
2956  *	Start polling the drive for disc insertion
2957  *
2958  * Args:
2959  *	s - Pointer to the curstat_t structure
2960  *
2961  * Return:
2962  *	Nothing.
2963  */
2964 STATIC void
scsipt_start_insert_poll(curstat_t * s)2965 scsipt_start_insert_poll(curstat_t *s)
2966 {
2967 	int	delay;
2968 	bool_t	first = TRUE;
2969 
2970 	if (scsipt_insert_polling || app_data.ins_disable ||
2971 	    (s->mode != MOD_BUSY && s->mode != MOD_NODISC))
2972 		return;
2973 
2974 	if (app_data.numdiscs > 1 && app_data.multi_play)
2975 		scsipt_ins_interval =
2976 			app_data.ins_interval / app_data.numdiscs;
2977 	else
2978 		scsipt_ins_interval = app_data.ins_interval;
2979 
2980 	if (scsipt_ins_interval < 500)
2981 		scsipt_ins_interval = 500;
2982 
2983 	if (first) {
2984 		first = FALSE;
2985 		delay = 50;
2986 	}
2987 	else
2988 		delay = scsipt_ins_interval;
2989 
2990 	/* Start poll timer */
2991 	if (di_clinfo->timeout != NULL) {
2992 		scsipt_insert_id = di_clinfo->timeout(
2993 			delay,
2994 			scsipt_insert_poll,
2995 			(byte_t *) s
2996 		);
2997 
2998 		if (scsipt_insert_id != 0)
2999 			scsipt_insert_polling = TRUE;
3000 	}
3001 }
3002 
3003 
3004 /*
3005  * stat_poll
3006  *	The playback status polling function
3007  *
3008  * Args:
3009  *	s - Pointer to the curstat_t structure
3010  *
3011  * Return:
3012  *	Nothing.
3013  */
3014 STATIC void
scsipt_stat_poll(curstat_t * s)3015 scsipt_stat_poll(curstat_t *s)
3016 {
3017 	if (!scsipt_stat_polling)
3018 		return;
3019 
3020 	/* Get current audio playback status */
3021 	if (scsipt_get_playstatus(s)) {
3022 		/* Register next poll interval */
3023 		if (di_clinfo->timeout != NULL) {
3024 			scsipt_stat_id = di_clinfo->timeout(
3025 				scsipt_stat_interval,
3026 				scsipt_stat_poll,
3027 				(byte_t *) s
3028 			);
3029 		}
3030 	}
3031 	else
3032 		scsipt_stat_polling = FALSE;
3033 }
3034 
3035 
3036 /*
3037  * insert_poll
3038  *	The disc insertion polling function
3039  *
3040  * Args:
3041  *	s - Pointer to the curstat_t structure
3042  *
3043  * Return:
3044  *	Nothing.
3045  */
3046 STATIC void
scsipt_insert_poll(curstat_t * s)3047 scsipt_insert_poll(curstat_t *s)
3048 {
3049 	/* Check to see if a disc is inserted */
3050 	if (!scsipt_disc_ready(s)) {
3051 		/* Register next poll interval */
3052 		if (di_clinfo->timeout != NULL) {
3053 			scsipt_insert_id = di_clinfo->timeout(
3054 				scsipt_ins_interval,
3055 				scsipt_insert_poll,
3056 				(byte_t *) s
3057 			);
3058 		}
3059 	}
3060 	else
3061 		scsipt_insert_polling = FALSE;
3062 }
3063 
3064 
3065 /*
3066  * scsipt_disc_ready
3067  *	Check if the disc is loaded and ready for use, and update
3068  *	curstat table.
3069  *
3070  * Args:
3071  *	s - Pointer to the curstat_t structure
3072  *
3073  * Return:
3074  *	TRUE - Disc is ready
3075  *	FALSE - Disc is not ready
3076  */
3077 STATIC bool_t
scsipt_disc_ready(curstat_t * s)3078 scsipt_disc_ready(curstat_t *s)
3079 {
3080 	int		i;
3081 	bool_t		no_disc,
3082 			ret;
3083 	static bool_t	first_open = TRUE,
3084 			in_scsipt_disc_ready = FALSE;
3085 
3086 #ifdef __VMS
3087 	(void) fprintf(errfp, "");	/* HACK */
3088 #endif
3089 
3090 	/* Lock this routine from multiple entry */
3091 	if (in_scsipt_disc_ready)
3092 		return TRUE;
3093 
3094 	in_scsipt_disc_ready = TRUE;
3095 
3096 	/* If device has not been opened, attempt to open it */
3097 	if (scsipt_not_open) {
3098 		/* Check for another copy of the CD player running on
3099 		 * the specified device.
3100 		 */
3101 		if (!s->devlocked && !di_devlock(s, app_data.device)) {
3102 			s->mode = MOD_BUSY;
3103 			DPY_TIME(s, FALSE);
3104 			scsipt_start_insert_poll(s);
3105 			in_scsipt_disc_ready = FALSE;
3106 			return FALSE;
3107 		}
3108 
3109 		s->devlocked = TRUE;
3110 		s->mode = MOD_NODISC;
3111 		DPY_DISC(s);
3112 
3113 		if (app_data.numdiscs > 1 &&
3114 		    app_data.chg_method == CHG_SCSI_MEDCHG &&
3115 		    chgp == NULL) {
3116 			/* Open medium-changer device */
3117 			if ((chgp = scsipt_open(di_devlist[1])) != NULL) {
3118 				if (!scsipt_is_enabled(chgp, DI_ROLE_MAIN))
3119 					scsipt_enable(chgp, DI_ROLE_MAIN);
3120 
3121 				if (!scsipt_chg_start(s)) {
3122 					scsipt_close(chgp);
3123 					chgp = NULL;
3124 				}
3125 			}
3126 			else {
3127 				/* Changer init failed: set to
3128 				 * single-disc mode.
3129 				 */
3130 				DBGPRN(DBG_DEVIO)(errfp, "Open of %s failed\n",
3131 						di_devlist[1]);
3132 				app_data.numdiscs = 1;
3133 				app_data.chg_method = CHG_NONE;
3134 				app_data.multi_play = FALSE;
3135 				app_data.reverse = FALSE;
3136 				s->first_disc = s->last_disc = s->cur_disc = 1;
3137 
3138 				DI_INFO(app_data.str_medchg_noinit);
3139 			}
3140 		}
3141 
3142 		if (chgp != NULL) {
3143 			/* Try to load disc */
3144 			for (i = 0; i < 2; i++) {
3145 				ret = scsipt_move_medium(
3146 					chgp, DI_ROLE_MAIN,
3147 					scsipt_mcparm.mtbase,
3148 					(word16_t) (scsipt_mcparm.stbase +
3149 						    s->cur_disc - 1),
3150 					scsipt_mcparm.dtbase
3151 				);
3152 
3153 				if (ret)
3154 					break;
3155 
3156 				if (scsipt_chg_ready(s))
3157 					(void) scsipt_chg_rdstatus();
3158 			}
3159 		}
3160 
3161 		if ((devp = scsipt_open(s->curdev)) != NULL) {
3162 			scsipt_not_open = FALSE;
3163 
3164 			if (!scsipt_is_enabled(devp, DI_ROLE_MAIN))
3165 				scsipt_enable(devp, DI_ROLE_MAIN);
3166 
3167 			/* Check if a disc is loaded and ready */
3168 			no_disc = !scsipt_disc_present(
3169 				devp, DI_ROLE_MAIN, s, NULL
3170 			);
3171 		}
3172 		else {
3173 			DBGPRN(DBG_DEVIO)(errfp, "Open of %s failed\n",
3174 					s->curdev);
3175 			no_disc = TRUE;
3176 		}
3177 	}
3178 	else {
3179 		/* Just return success if we're playing CDDA */
3180 		if (!scsipt_is_enabled(devp, DI_ROLE_MAIN))
3181 			no_disc = FALSE;
3182 		else if ((no_disc = !scsipt_disc_present(devp, DI_ROLE_MAIN,
3183 							 s, NULL)) == TRUE) {
3184 			/* The disc was manually ejected */
3185 			s->mode = MOD_NODISC;
3186 			di_clear_cdinfo(s, FALSE);
3187 		}
3188 	}
3189 
3190 	if (!no_disc) {
3191 		if (first_open) {
3192 			first_open = FALSE;
3193 
3194 			/* Start up vendor-unique modules */
3195 			if (scsipt_vutbl[app_data.vendor_code].start != NULL)
3196 				scsipt_vutbl[app_data.vendor_code].start();
3197 
3198 			/* Fill in inquiry data */
3199 			if (!scsipt_vendor_model(s)) {
3200 				scsipt_close(devp);
3201 				devp = NULL;
3202 				scsipt_not_open = TRUE;
3203 				in_scsipt_disc_ready = FALSE;
3204 				return FALSE;
3205 			}
3206 
3207 			/* Initialize volume/balance/routing controls */
3208 			scsipt_init_vol(s, TRUE);
3209 		}
3210 		else {
3211 			/* Force to current settings */
3212 			(void) scsipt_cfg_vol(s->level, s, FALSE, FALSE);
3213 
3214 			/* Set up channel routing */
3215 			scsipt_route(s);
3216 		}
3217 	}
3218 
3219 	/* Read disc table of contents if a new disc was detected */
3220 	if (scsipt_not_open || no_disc ||
3221 	    (s->mode == MOD_NODISC && !scsipt_get_toc(s))) {
3222 		if (devp != NULL && app_data.eject_close) {
3223 			scsipt_close(devp);
3224 			devp = NULL;
3225 			scsipt_not_open = TRUE;
3226 		}
3227 
3228 		di_reset_curstat(s, TRUE, (bool_t) !app_data.multi_play);
3229 		DPY_ALL(s);
3230 
3231 		if (app_data.multi_play) {
3232 			/* This requested disc is not there
3233 			 * or not ready.
3234 			 */
3235 			if (app_data.reverse) {
3236 				if (s->cur_disc > s->first_disc) {
3237 					/* Try the previous disc */
3238 					s->cur_disc--;
3239 				}
3240 				else {
3241 					/* Go to the last disc */
3242 					s->cur_disc = s->last_disc;
3243 
3244 					if (scsipt_mult_autoplay) {
3245 					    if (s->repeat)
3246 						s->rptcnt++;
3247 					    else
3248 						scsipt_mult_autoplay = FALSE;
3249 					}
3250 				}
3251 			}
3252 			else {
3253 				if (s->cur_disc < s->last_disc) {
3254 					/* Try the next disc */
3255 					s->cur_disc++;
3256 				}
3257 				else if (!s->chgrscan) {
3258 					/* Go to the first disc */
3259 					s->cur_disc = s->first_disc;
3260 
3261 					if (scsipt_mult_autoplay) {
3262 					    if (s->repeat)
3263 						s->rptcnt++;
3264 					    else
3265 						scsipt_mult_autoplay = FALSE;
3266 					}
3267 				}
3268 				else {
3269 					/* Done scanning - no disc */
3270 					STOPSCAN(s);
3271 				}
3272 			}
3273 
3274 			if (app_data.chg_method == CHG_SCSI_LUN)
3275 				s->curdev = di_devlist[s->cur_disc-1];
3276 		}
3277 
3278 		scsipt_start_insert_poll(s);
3279 		in_scsipt_disc_ready = FALSE;
3280 		return FALSE;
3281 	}
3282 
3283 	if (s->mode != MOD_NODISC) {
3284 		in_scsipt_disc_ready = FALSE;
3285 		return TRUE;
3286 	}
3287 
3288 	/* Load saved track program, if any */
3289 	PROGGET(s);
3290 
3291 	s->mode = MOD_STOP;
3292 	DPY_ALL(s);
3293 
3294 	/* Load CD-TEXT information into cache, if so configured */
3295 	(void) memset(scsipt_cdtext_buf, 0, sizeof(scsipt_cdtext_buf));
3296 	if (!app_data.cdtext_dsbl) {
3297 		(void) scsipt_rdtoc(
3298 			devp, DI_ROLE_MAIN, scsipt_cdtext_buf,
3299 			sizeof(scsipt_cdtext_buf), 0, 5, FALSE,
3300 			(bool_t) ((app_data.debug & DBG_DEVIO) != 0)
3301 		);
3302 	}
3303 
3304 	/* Get Media catalog number of CD, if available */
3305 	if (!app_data.mcn_dsbl) {
3306 		(void) scsipt_rdsubq(
3307 			devp, DI_ROLE_MAIN, SUB_MCN, 0, NULL, s->mcn, NULL,
3308 			(bool_t) ((app_data.debug & DBG_DEVIO) != 0)
3309 		);
3310 	}
3311 
3312 	/* Get ISRC for each track, if available */
3313 	if (!app_data.isrc_dsbl) {
3314 		for (i = 0; i < (int) s->tot_trks; i++) {
3315 			ret = scsipt_rdsubq(
3316 				devp, DI_ROLE_MAIN, SUB_ISRC,
3317 				(byte_t) s->trkinfo[i].trkno,
3318 				NULL, NULL, s->trkinfo[i].isrc,
3319 				(bool_t) ((app_data.debug & DBG_DEVIO) != 0)
3320 			);
3321 			if (!ret) {
3322 				if (i == 0) {
3323 					/* If the command fails with the
3324 					 * first track, then just skip the
3325 					 * rest of the tracks.
3326 					 */
3327 					break;
3328 				}
3329 				else
3330 					continue;
3331 			}
3332 			if (s->trkinfo[i].isrc[0] == '\0') {
3333 				if (i == 0) {
3334 					/* If there is no ISRC data for the
3335 					 * first track, then just skip the
3336 					 * rest of the tracks.
3337 					 */
3338 					break;
3339 				}
3340 				else
3341 					continue;
3342 			}
3343 		}
3344 	}
3345 
3346 	/* Set caddy lock configuration */
3347 	if (app_data.caddylock_supp)
3348 		scsipt_lock(s, app_data.caddy_lock);
3349 
3350 	if (app_data.load_play || scsipt_mult_autoplay) {
3351 		scsipt_mult_autoplay = FALSE;
3352 
3353 		/* Wait a little while for things to settle */
3354 		util_delayms(1000);
3355 
3356 		/* Start auto-play */
3357 		if (!scsipt_override_ap)
3358 			scsipt_play_pause(s);
3359 
3360 		if (scsipt_mult_pause) {
3361 			scsipt_mult_pause = FALSE;
3362 
3363 			if (scsipt_do_pause_resume(devp, FALSE)) {
3364 				scsipt_stop_stat_poll();
3365 				s->mode = MOD_PAUSE;
3366 				DPY_PLAYMODE(s, FALSE);
3367 			}
3368 		}
3369 	}
3370 	else if (app_data.load_spindown) {
3371 		/* Spin down disc in case the user isn't going to
3372 		 * play anything for a while.  This reduces wear and
3373 		 * tear on the drive.
3374 		 */
3375 		(void) scsipt_do_start_stop(devp, FALSE, FALSE, TRUE);
3376 	}
3377 
3378 	in_scsipt_disc_ready = FALSE;
3379 
3380 	/* Load CD information for this disc.
3381 	 * This operation has to be done outside the scope of
3382 	 * in_scsipt_disc_ready because it may recurse
3383 	 * back into this function.
3384 	 */
3385 	(void) di_get_cdinfo(s);
3386 
3387 	return TRUE;
3388 }
3389 
3390 
3391 /*
3392  * scsipt_chg_ready
3393  *	Check if the medium changer is ready for use.
3394  *
3395  * Args:
3396  *	s - Pointer to the curstat_t structure
3397  *
3398  * Return:
3399  *	TRUE - Changer is ready
3400  *	FALSE - Changer is not ready
3401  */
3402 /*ARGSUSED*/
3403 STATIC bool_t
scsipt_chg_ready(curstat_t * s)3404 scsipt_chg_ready(curstat_t *s)
3405 {
3406 	int			i;
3407 	bool_t			ret;
3408 	req_sense_data_t	sense_data;
3409 
3410 	ret = FALSE;
3411 	if (app_data.chg_method != CHG_SCSI_MEDCHG)
3412 		return (ret);
3413 
3414 	for (i = 0; i < 10; i++) {
3415 		ret = scsipt_tst_unit_rdy(
3416 			chgp,
3417 			DI_ROLE_MAIN,
3418 			&sense_data,
3419 			(bool_t) ((app_data.debug & DBG_DEVIO) != 0)
3420 		);
3421 		if (ret)
3422 			break;
3423 
3424 		if (sense_data.key == 0x02) {
3425 			/* Changer is not ready, wait */
3426 			util_delayms(1000);
3427 		}
3428 	}
3429 
3430 	return (ret);
3431 }
3432 
3433 
3434 /*
3435  * scsipt_run_rew
3436  *	Run search-rewind operation
3437  *
3438  * Args:
3439  *	s - Pointer to the curstat_t structure
3440  *
3441  * Return:
3442  *	Nothing.
3443  */
3444 STATIC void
scsipt_run_rew(curstat_t * s)3445 scsipt_run_rew(curstat_t *s)
3446 {
3447 	int			i,
3448 				skip_blks;
3449 	sword32_t		addr,
3450 				end_addr;
3451 	msf_t			smsf,
3452 				emsf;
3453 	static sword32_t	start_addr,
3454 				seq;
3455 
3456 	/* Find out where we are */
3457 	if (!scsipt_get_playstatus(s)) {
3458 		DO_BEEP();
3459 		return;
3460 	}
3461 
3462 	skip_blks = app_data.skip_blks;
3463 	addr = s->curpos_tot.addr;
3464 
3465 	if (scsipt_start_search) {
3466 		scsipt_start_search = FALSE;
3467 		seq = 0;
3468 		i = (int) (addr - skip_blks);
3469 	}
3470 	else {
3471 		if (app_data.skip_spdup > 0 && seq > app_data.skip_spdup)
3472 			/* Speed up search */
3473 			skip_blks *= 3;
3474 
3475 		i = (int) (start_addr - skip_blks);
3476 	}
3477 
3478 	start_addr = (sword32_t) ((i > di_clip_frames) ? i : di_clip_frames);
3479 
3480 	seq++;
3481 
3482 	if (s->shuffle || s->program) {
3483 		if ((i = di_curtrk_pos(s)) < 0)
3484 			i = 0;
3485 
3486 		if (start_addr < s->trkinfo[i].addr)
3487 			start_addr = s->trkinfo[i].addr;
3488 	}
3489 	else if (s->segplay == SEGP_AB && start_addr < s->bp_startpos_tot.addr)
3490 		start_addr = s->bp_startpos_tot.addr;
3491 
3492 	end_addr = start_addr + MAX_SRCH_BLKS;
3493 
3494 	util_blktomsf(
3495 		start_addr,
3496 		&smsf.min,
3497 		&smsf.sec,
3498 		&smsf.frame,
3499 		MSF_OFFSET
3500 	);
3501 	util_blktomsf(
3502 		end_addr,
3503 		&emsf.min,
3504 		&emsf.sec,
3505 		&emsf.frame,
3506 		MSF_OFFSET
3507 	);
3508 
3509 	/* Play next search interval */
3510 	(void) scsipt_do_playaudio(devp,
3511 		ADDR_BLK | ADDR_MSF | ADDR_OPTEND,
3512 		start_addr, end_addr,
3513 		&smsf, &emsf,
3514 		0, 0
3515 	);
3516 
3517 	if (di_clinfo->timeout != NULL) {
3518 		scsipt_search_id = di_clinfo->timeout(
3519 			app_data.skip_pause,
3520 			scsipt_run_rew,
3521 			(byte_t *) s
3522 		);
3523 	}
3524 }
3525 
3526 
3527 /*
3528  * scsipt_stop_rew
3529  *	Stop search-rewind operation
3530  *
3531  * Args:
3532  *	s - Pointer to the curstat_t structure
3533  *
3534  * Return:
3535  *	Nothing.
3536  */
3537 /*ARGSUSED*/
3538 STATIC void
scsipt_stop_rew(curstat_t * s)3539 scsipt_stop_rew(curstat_t *s)
3540 {
3541 	if (di_clinfo->untimeout != NULL)
3542 		di_clinfo->untimeout(scsipt_search_id);
3543 }
3544 
3545 
3546 /*
3547  * scsipt_run_ff
3548  *	Run search-fast-forward operation
3549  *
3550  * Args:
3551  *	s - Pointer to the curstat_t structure
3552  *
3553  * Return:
3554  *	Nothing.
3555  */
3556 STATIC void
scsipt_run_ff(curstat_t * s)3557 scsipt_run_ff(curstat_t *s)
3558 {
3559 	int			i,
3560 				skip_blks;
3561 	sword32_t		addr,
3562 				end_addr;
3563 	msf_t			smsf,
3564 				emsf;
3565 	static sword32_t	start_addr,
3566 				seq;
3567 
3568 	/* Find out where we are */
3569 	if (!scsipt_get_playstatus(s)) {
3570 		DO_BEEP();
3571 		return;
3572 	}
3573 
3574 	skip_blks = app_data.skip_blks;
3575 	addr = s->curpos_tot.addr;
3576 
3577 	if (scsipt_start_search) {
3578 		scsipt_start_search = FALSE;
3579 		seq = 0;
3580 		start_addr = addr + skip_blks;
3581 	}
3582 	else {
3583 		if (app_data.skip_spdup > 0 && seq > app_data.skip_spdup)
3584 			/* Speed up search */
3585 			skip_blks *= 3;
3586 
3587 		start_addr += skip_blks;
3588 	}
3589 
3590 	seq++;
3591 
3592 	if (s->shuffle || s->program) {
3593 		if ((i = di_curtrk_pos(s)) < 0)
3594 			i = s->tot_trks - 1;
3595 		else if (s->cur_idx == 0)
3596 			/* We're in the lead-in: consider this to be
3597 			 * within the previous track.
3598 			 */
3599 			i--;
3600 	}
3601 	else
3602 		i = s->tot_trks - 1;
3603 
3604 	end_addr = start_addr + MAX_SRCH_BLKS;
3605 
3606 	if (end_addr >= s->trkinfo[i+1].addr) {
3607 		end_addr = s->trkinfo[i+1].addr;
3608 		start_addr = end_addr - skip_blks;
3609 	}
3610 
3611 	if (s->segplay == SEGP_AB && end_addr > s->bp_endpos_tot.addr) {
3612 		end_addr = s->bp_endpos_tot.addr;
3613 		start_addr = end_addr - skip_blks;
3614 	}
3615 
3616 	util_blktomsf(
3617 		start_addr,
3618 		&smsf.min,
3619 		&smsf.sec,
3620 		&smsf.frame,
3621 		MSF_OFFSET
3622 	);
3623 	util_blktomsf(
3624 		end_addr,
3625 		&emsf.min,
3626 		&emsf.sec,
3627 		&emsf.frame,
3628 		MSF_OFFSET
3629 	);
3630 
3631 	/* Play next search interval */
3632 	(void) scsipt_do_playaudio(devp,
3633 		ADDR_BLK | ADDR_MSF | ADDR_OPTEND,
3634 		start_addr, end_addr,
3635 		&smsf, &emsf,
3636 		0, 0
3637 	);
3638 
3639 	if (di_clinfo->timeout != NULL) {
3640 		scsipt_search_id = di_clinfo->timeout(
3641 			app_data.skip_pause,
3642 			scsipt_run_ff,
3643 			(byte_t *) s
3644 		);
3645 	}
3646 }
3647 
3648 
3649 /*
3650  * scsipt_stop_ff
3651  *	Stop search-fast-forward operation
3652  *
3653  * Args:
3654  *	s - Pointer to the curstat_t structure
3655  *
3656  * Return:
3657  *	Nothing.
3658  */
3659 /*ARGSUSED*/
3660 STATIC void
scsipt_stop_ff(curstat_t * s)3661 scsipt_stop_ff(curstat_t *s)
3662 {
3663 	if (di_clinfo->untimeout != NULL)
3664 		di_clinfo->untimeout(scsipt_search_id);
3665 }
3666 
3667 
3668 /*
3669  * scsipt_run_ab
3670  *	Run a->b segment play operation
3671  *
3672  * Args:
3673  *	s - Pointer to the curstat_t structure
3674  *
3675  * Return:
3676  *	TRUE - success
3677  *	FALSE - failure
3678  */
3679 /*ARGSUSED*/
3680 STATIC bool_t
scsipt_run_ab(curstat_t * s)3681 scsipt_run_ab(curstat_t *s)
3682 {
3683 	msf_t	start_msf,
3684 		end_msf;
3685 
3686 	if ((s->bp_startpos_tot.addr + app_data.min_playblks) >=
3687 	    s->bp_endpos_tot.addr) {
3688 		DO_BEEP();
3689 		return FALSE;
3690 	}
3691 
3692 	start_msf.min = s->bp_startpos_tot.min;
3693 	start_msf.sec = s->bp_startpos_tot.sec;
3694 	start_msf.frame = s->bp_startpos_tot.frame;
3695 	end_msf.min = s->bp_endpos_tot.min;
3696 	end_msf.sec = s->bp_endpos_tot.sec;
3697 	end_msf.frame = s->bp_endpos_tot.frame;
3698 	s->mode = MOD_PLAY;
3699 	DPY_ALL(s);
3700 	scsipt_start_stat_poll(s);
3701 
3702 	return (
3703 		scsipt_do_playaudio(devp,
3704 			ADDR_BLK | ADDR_MSF,
3705 			s->bp_startpos_tot.addr, s->bp_endpos_tot.addr,
3706 			&start_msf, &end_msf,
3707 			0, 0
3708 		)
3709 	);
3710 }
3711 
3712 
3713 /*
3714  * scsipt_run_sample
3715  *	Run sample play operation
3716  *
3717  * Args:
3718  *	s - Pointer to the curstat_t structure
3719  *
3720  * Return:
3721  *	TRUE - success
3722  *	FALSE - failure
3723  */
3724 STATIC bool_t
scsipt_run_sample(curstat_t * s)3725 scsipt_run_sample(curstat_t *s)
3726 {
3727 	sword32_t	saddr,
3728 			eaddr;
3729 	msf_t		smsf,
3730 			emsf;
3731 
3732 	if (scsipt_next_sam < s->tot_trks) {
3733 		saddr = s->trkinfo[scsipt_next_sam].addr;
3734 		eaddr = saddr + app_data.sample_blks,
3735 
3736 		util_blktomsf(
3737 			saddr,
3738 			&smsf.min,
3739 			&smsf.sec,
3740 			&smsf.frame,
3741 			MSF_OFFSET
3742 		);
3743 		util_blktomsf(
3744 			eaddr,
3745 			&emsf.min,
3746 			&emsf.sec,
3747 			&emsf.frame,
3748 			MSF_OFFSET
3749 		);
3750 
3751 		/* Sample only audio tracks */
3752 		if (s->trkinfo[scsipt_next_sam].type != TYP_AUDIO ||
3753 		    scsipt_do_playaudio(devp, ADDR_BLK | ADDR_MSF,
3754 				        saddr, eaddr, &smsf, &emsf, 0, 0)) {
3755 			scsipt_next_sam++;
3756 			return TRUE;
3757 		}
3758 	}
3759 
3760 	scsipt_next_sam = 0;
3761 	return FALSE;
3762 }
3763 
3764 
3765 /*
3766  * scsipt_run_prog
3767  *	Run program/shuffle play operation
3768  *
3769  * Args:
3770  *	s - Pointer to the curstat_t structure
3771  *
3772  * Return:
3773  *	TRUE - success
3774  *	FALSE - failure
3775  */
3776 STATIC bool_t
scsipt_run_prog(curstat_t * s)3777 scsipt_run_prog(curstat_t *s)
3778 {
3779 	sword32_t	i,
3780 			start_addr,
3781 			end_addr;
3782 	msf_t		start_msf,
3783 			end_msf;
3784 	bool_t		hasaudio,
3785 			ret;
3786 
3787 	if (!s->shuffle && !s->program)
3788 		return FALSE;
3789 
3790 	if (scsipt_new_progshuf) {
3791 		scsipt_new_progshuf = FALSE;
3792 
3793 		if (s->shuffle)
3794 			/* New shuffle sequence needed */
3795 			di_reset_shuffle(s);
3796 		else
3797 			/* Program play: simply reset the count */
3798 			s->prog_cnt = 0;
3799 
3800 		/* Do not allow a program that contains only data tracks */
3801 		hasaudio = FALSE;
3802 		for (i = 0; i < (int) s->prog_tot; i++) {
3803 			if (s->trkinfo[s->trkinfo[i].playorder].type ==
3804 			    TYP_AUDIO) {
3805 				hasaudio = TRUE;
3806 				break;
3807 			}
3808 		}
3809 
3810 		if (!hasaudio) {
3811 			DO_BEEP();
3812 			return FALSE;
3813 		}
3814 	}
3815 
3816 	if (s->prog_cnt >= s->prog_tot)
3817 		/* Done with program/shuffle play cycle */
3818 		return FALSE;
3819 
3820 	if ((i = di_curprog_pos(s)) < 0)
3821 		return FALSE;
3822 
3823 	if (s->trkinfo[i].trkno == LEAD_OUT_TRACK)
3824 		return FALSE;
3825 
3826 	s->prog_cnt++;
3827 	s->cur_trk = s->trkinfo[i].trkno;
3828 	s->cur_idx = 1;
3829 
3830 	start_addr = s->trkinfo[i].addr + s->curpos_trk.addr;
3831 	util_blktomsf(
3832 		start_addr,
3833 		&s->curpos_tot.min,
3834 		&s->curpos_tot.sec,
3835 		&s->curpos_tot.frame,
3836 		MSF_OFFSET
3837 	);
3838 	start_msf.min = s->curpos_tot.min;
3839 	start_msf.sec = s->curpos_tot.sec;
3840 	start_msf.frame = s->curpos_tot.frame;
3841 
3842 	end_addr = s->trkinfo[i+1].addr;
3843 	end_msf.min = s->trkinfo[i+1].min;
3844 	end_msf.sec = s->trkinfo[i+1].sec;
3845 	end_msf.frame = s->trkinfo[i+1].frame;
3846 
3847 	s->curpos_tot.addr = start_addr;
3848 
3849 	if (s->mode != MOD_PAUSE)
3850 		s->mode = MOD_PLAY;
3851 
3852 	DPY_ALL(s);
3853 
3854 	if (s->trkinfo[i].type == TYP_DATA)
3855 		/* Data track: just fake it */
3856 		return TRUE;
3857 
3858 	ret = scsipt_do_playaudio(devp,
3859 		ADDR_BLK | ADDR_MSF,
3860 		start_addr, end_addr,
3861 		&start_msf, &end_msf,
3862 		0, 0
3863 	);
3864 
3865 	if (s->mode == MOD_PAUSE) {
3866 		(void) scsipt_do_pause_resume(devp, FALSE);
3867 
3868 		/* Restore volume */
3869 		scsipt_mute_off(s);
3870 	}
3871 
3872 	return (ret);
3873 }
3874 
3875 
3876 /*
3877  * scsipt_run_repeat
3878  *	Run repeat play operation
3879  *
3880  * Args:
3881  *	s - Pointer to the curstat_t structure
3882  *
3883  * Return:
3884  *	TRUE - success
3885  *	FALSE - failure
3886  */
3887 STATIC bool_t
scsipt_run_repeat(curstat_t * s)3888 scsipt_run_repeat(curstat_t *s)
3889 {
3890 	msf_t	start_msf,
3891 		end_msf;
3892 	bool_t	ret;
3893 
3894 	if (!s->repeat)
3895 		return FALSE;
3896 
3897 	if (s->shuffle || s->program) {
3898 		ret = TRUE;
3899 
3900 		if (s->prog_cnt < s->prog_tot)
3901 			/* Not done with program/shuffle sequence yet */
3902 			return (ret);
3903 
3904 		scsipt_new_progshuf = TRUE;
3905 		s->rptcnt++;
3906 	}
3907 	else {
3908 		s->cur_trk = s->first_trk;
3909 		s->cur_idx = 1;
3910 
3911 		s->curpos_tot.addr = 0;
3912 		s->curpos_tot.min = 0;
3913 		s->curpos_tot.sec = 0;
3914 		s->curpos_tot.frame = 0;
3915 		s->rptcnt++;
3916 		DPY_ALL(s);
3917 
3918 		start_msf.min = s->trkinfo[0].min;
3919 		start_msf.sec = s->trkinfo[0].sec;
3920 		start_msf.frame = s->trkinfo[0].frame;
3921 		end_msf.min = s->discpos_tot.min;
3922 		end_msf.sec = s->discpos_tot.sec;
3923 		end_msf.frame = s->discpos_tot.frame;
3924 
3925 		ret = scsipt_do_playaudio(devp,
3926 			ADDR_BLK | ADDR_MSF,
3927 			s->trkinfo[0].addr, s->discpos_tot.addr,
3928 			&start_msf, &end_msf, 0, 0
3929 		);
3930 
3931 		if (s->mode == MOD_PAUSE) {
3932 			(void) scsipt_do_pause_resume(devp, FALSE);
3933 
3934 			/* Restore volume */
3935 			scsipt_mute_off(s);
3936 		}
3937 
3938 	}
3939 
3940 	return (ret);
3941 }
3942 
3943 
3944 /*
3945  * scsipt_route_val
3946  *	Return the channel routing control value used in the
3947  *	SCSI-2 mode parameter page 0xE (audio parameters).
3948  *
3949  * Args:
3950  *	route_mode - The channel routing mode value.
3951  *	channel - The channel number desired (0=left 1=right).
3952  *
3953  * Return:
3954  *	The routing control value.
3955  */
3956 STATIC byte_t
scsipt_route_val(int route_mode,int channel)3957 scsipt_route_val(int route_mode, int channel)
3958 {
3959 	switch (channel) {
3960 	case 0:
3961 		switch (route_mode) {
3962 		case CHROUTE_NORMAL:
3963 			return 0x1;
3964 		case CHROUTE_REVERSE:
3965 			return 0x2;
3966 		case CHROUTE_L_MONO:
3967 			return 0x1;
3968 		case CHROUTE_R_MONO:
3969 			return 0x2;
3970 		case CHROUTE_MONO:
3971 			return 0x3;
3972 		default:
3973 			/* Invalid value */
3974 			return 0x0;
3975 		}
3976 		/*NOTREACHED*/
3977 
3978 	case 1:
3979 		switch (route_mode) {
3980 		case CHROUTE_NORMAL:
3981 			return 0x2;
3982 		case CHROUTE_REVERSE:
3983 			return 0x1;
3984 		case CHROUTE_L_MONO:
3985 			return 0x1;
3986 		case CHROUTE_R_MONO:
3987 			return 0x2;
3988 		case CHROUTE_MONO:
3989 			return 0x3;
3990 		default:
3991 			/* Invalid value */
3992 			return 0x0;
3993 		}
3994 		/*NOTREACHED*/
3995 
3996 	default:
3997 		/* Invalid value */
3998 		return 0x0;
3999 	}
4000 }
4001 
4002 
4003 /*
4004  * scsipt_chg_rdstatus
4005  *	Get the current changer element status
4006  *
4007  * Args:
4008  *	None
4009  *
4010  * Return:
4011  *	TRUE - success
4012  *	FALSE - failure
4013  */
4014 STATIC bool_t
scsipt_chg_rdstatus(void)4015 scsipt_chg_rdstatus(void)
4016 {
4017 	int		i,
4018 			j,
4019 			firstelem,
4020 			numelem,
4021 			datalen,
4022 			desclen,
4023 			pagelen;
4024 	size_t		alloclen;
4025 	byte_t		*buf,
4026 			*cp;
4027 	elemhdr_t	*h;
4028 	elemstat_t	*s,
4029 			*s_end;
4030 	elemdesc_t	*d,
4031 			*d_end;
4032 
4033 	/* Initialize element status */
4034 	if (!scsipt_init_elemstat(chgp, DI_ROLE_MAIN)) {
4035 		DBGPRN(DBG_DEVIO)(errfp,
4036 			"%s: Initialize Element Status command error\n",
4037 			di_devlist[1]);
4038 		return FALSE;
4039 	}
4040 
4041 	alloclen = (app_data.numdiscs * sizeof(elemdesc_t)) +
4042 		   (4 * SZ_ELEMSTAT) + SZ_ELEMHDR;
4043 
4044 	if ((buf = (byte_t *) MEM_ALLOC("elemstat", alloclen)) == NULL) {
4045 		DI_FATAL(app_data.str_nomemory);
4046 		return FALSE;
4047 	}
4048 
4049 	(void) memset(buf, 0, alloclen);
4050 
4051 	/* Read element status */
4052 	if (!scsipt_read_elemstat(chgp, DI_ROLE_MAIN, buf, alloclen,
4053 				  app_data.numdiscs + 3)) {
4054 		DBGPRN(DBG_DEVIO)(errfp,
4055 			"%s: Read Element Status command error\n",
4056 			di_devlist[1]);
4057 		return FALSE;
4058 	}
4059 
4060 	DBGDUMP(DBG_DEVIO)("Element Status data", buf, alloclen);
4061 
4062 	h = (elemhdr_t *)(void *) buf;
4063 
4064 	firstelem = (int) util_bswap16((word16_t) h->firstelem);
4065 	numelem = (int) util_bswap16((word16_t) h->numelem);
4066 	datalen = (int) util_bswap32((word32_t) h->datalen);
4067 
4068 	/* Sanity check */
4069 	if ((datalen + SZ_ELEMHDR) > alloclen) {
4070 		DBGPRN(DBG_DEVIO)(errfp,
4071 		    "%s: Read Element Status data error: datalen too large\n",
4072 		    di_devlist[1]);
4073 		MEM_FREE(buf);
4074 		return FALSE;
4075 	}
4076 
4077 	if (app_data.debug & DBG_DEVIO) {
4078 		(void) fprintf(errfp, "ELEMENT STATUS HEADER:\n");
4079 		(void) fprintf(errfp, "  First element: %d\n", firstelem);
4080 		(void) fprintf(errfp, "  Num elements: %d\n", numelem);
4081 		(void) fprintf(errfp, "  Byte count: %d\n", datalen);
4082 	}
4083 
4084 	cp = buf + SZ_ELEMHDR;
4085 	s = (elemstat_t *)(void *) cp;
4086 	s_end = (elemstat_t *)(void *) (cp + datalen);
4087 
4088 	/* Loop through the element status pages */
4089 	for (i = 0; s < s_end; i++) {
4090 		char	*typestr;
4091 
4092 		desclen = (int) util_bswap16((word16_t) s->desclen);
4093 		pagelen = (int) util_bswap32((word32_t) s->pagelen);
4094 
4095 		if (app_data.debug & DBG_DEVIO) {
4096 			(void) fprintf(errfp, "ELEMENT STATUS PAGE %d:\n", i);
4097 
4098 			switch ((int) s->type) {
4099 			case ELEMTYP_MT:
4100 				typestr = "MT";
4101 				break;
4102 			case ELEMTYP_ST:
4103 				typestr = "ST";
4104 				break;
4105 			case ELEMTYP_IE:
4106 				typestr = "IE";
4107 				break;
4108 			case ELEMTYP_DT:
4109 				typestr = "DT";
4110 				break;
4111 			default:
4112 				typestr = "invalid";
4113 				break;
4114 			}
4115 			(void) fprintf(errfp, "  Type: %d (%s)\n",
4116 				       s->type, typestr);
4117 
4118 			(void) fprintf(errfp, "  Pri voltag: %d\n",s->pvoltag);
4119 			(void) fprintf(errfp, "  Alt voltag: %d\n",s->avoltag);
4120 			(void) fprintf(errfp, "  Desc len: %d\n",desclen);
4121 			(void) fprintf(errfp, "  Page len: %d\n",pagelen);
4122 		}
4123 
4124 		cp += SZ_ELEMSTAT;
4125 		d = (elemdesc_t *)(void *) cp;
4126 		d_end = (elemdesc_t *)(void *) (cp + pagelen);
4127 
4128 		/* Loop through the element status descriptors */
4129 		for (j = 0; d < d_end; j++) {
4130 			word16_t	elemaddr;
4131 			word16_t	srcaddr;
4132 
4133 			elemaddr = util_bswap16((word16_t) d->mt.elemaddr);
4134 			srcaddr = util_bswap16((word16_t) d->mt.srcaddr);
4135 
4136 			if (app_data.debug & DBG_DEVIO) {
4137 				(void) fprintf(errfp,
4138 					       "  ELEMENT DESCRIPTOR %d:\n",
4139 					       j);
4140 				(void) fprintf(errfp,
4141 					       "    Element addr: 0x%x\n",
4142 					       (int) elemaddr);
4143 
4144 				(void) fprintf(errfp, "    Flags1: 0x%02x",
4145 					       (int) cp[2]);
4146 				if (d->ie.full)
4147 					(void) fprintf(errfp, " Full");
4148 				if (d->ie.impexp)
4149 					(void) fprintf(errfp, " ImpExp");
4150 				if (d->ie.excpt)
4151 					(void) fprintf(errfp, " Except");
4152 				if (d->ie.access)
4153 					(void) fprintf(errfp, " Access");
4154 				if (d->ie.exenab)
4155 					(void) fprintf(errfp, " ExEnab");
4156 				if (d->ie.inenab)
4157 					(void) fprintf(errfp, " InEnab");
4158 
4159 				(void) fprintf(errfp, "\n    ASC: 0x%02x\n",
4160 					       (int) d->dt.asc);
4161 
4162 				(void) fprintf(errfp, "    ASCQ: 0x%02x\n",
4163 					       (int) d->dt.ascq);
4164 
4165 				(void) fprintf(errfp, "    Flags2: 0x%02x",
4166 					       (int) cp[6]);
4167 				if (d->dt.luvalid)
4168 					(void) fprintf(errfp, " LUValid");
4169 				if (d->dt.idvalid)
4170 					(void) fprintf(errfp, " IDValid");
4171 				if (d->dt.notbus)
4172 					(void) fprintf(errfp, " NotBus");
4173 				if (d->dt.luvalid)
4174 					(void) fprintf(errfp, " LUN=%d",
4175 						       (int) d->dt.lun);
4176 				if (d->dt.idvalid)
4177 					(void) fprintf(errfp, " ID=%d",
4178 						       (int) d->dt.busaddr);
4179 
4180 				(void) fprintf(errfp, "\n    Flags3: 0x%02x",
4181 					       (int) cp[9]);
4182 				if (d->dt.svalid)
4183 					(void) fprintf(errfp, " SValid");
4184 				if (d->dt.invert)
4185 					(void) fprintf(errfp, " Invert");
4186 				if (d->dt.svalid)
4187 					(void) fprintf(errfp, " Src_addr=0x%x",
4188 						       srcaddr);
4189 				(void) fprintf(errfp, "\n");
4190 			}
4191 
4192 			if (s->type == ELEMTYP_ST && (d->st.full != 0)) {
4193 				scsipt_medmap[j] = TRUE;
4194 				scsipt_medmap_valid = TRUE;
4195 			}
4196 
4197 			cp += desclen;
4198 			d = (elemdesc_t *)(void *) cp;
4199 		}
4200 
4201 		s = (elemstat_t *)(void *) d_end;
4202 	}
4203 
4204 	if (app_data.debug & DBG_DEVIO) {
4205 		(void) fprintf(errfp, "\nMedium map:\n");
4206 		for (i = 0; i < app_data.numdiscs; i++) {
4207 			(void) fprintf(errfp, "  Slot[%d]: %s\n",
4208 				       i+1,
4209 				       scsipt_medmap[i] ? "full" : "empty");
4210 		}
4211 	}
4212 
4213 	MEM_FREE(buf);
4214 	return TRUE;
4215 }
4216 
4217 
4218 /*
4219  * scsipt_chg_start
4220  *	Multi-disc changer startup initialization
4221  *
4222  * Args:
4223  *	s - Pointer to the curstat_t structure
4224  *
4225  * Return:
4226  *	TRUE - success
4227  *	FALSE - failure
4228  */
4229 STATIC bool_t
scsipt_chg_start(curstat_t * s)4230 scsipt_chg_start(curstat_t *s)
4231 {
4232 	inquiry_data_t		*inq;
4233 	mode_sense_6_data_t	*ms_data6 = NULL;
4234 	mode_sense_10_data_t	*ms_data10 = NULL;
4235 	blk_desc_t		*bdesc;
4236 	dev_capab_t		*dcapab;
4237 	elem_addr_t		*eaddr;
4238 	int			bdesclen;
4239 	byte_t			buf[SZ_MSENSE];
4240 
4241 	inq = (inquiry_data_t *)(void *) buf;
4242 	if (app_data.msen_10) {
4243 		ms_data10 = (mode_sense_10_data_t *)(void *) buf;
4244 		bdesc = (blk_desc_t *)(void *) ms_data10->data;
4245 	}
4246 	else  {
4247 		ms_data6 = (mode_sense_6_data_t *)(void *) buf;
4248 		bdesc = (blk_desc_t *)(void *) ms_data6->data;
4249 	}
4250 
4251 	switch (app_data.chg_method) {
4252 	case CHG_SCSI_MEDCHG:
4253 		break;
4254 
4255 	case CHG_OS_IOCTL:
4256 		DBGPRN(DBG_DEVIO)(errfp,
4257 		"%s: OS-ioctl changer method not supported in this mode.\n",
4258 		"SCSI pass-through");
4259 		return FALSE;
4260 
4261 	default:
4262 		/* Nothing to do here */
4263 		return TRUE;
4264 	}
4265 
4266 	(void) memset(buf, 0, sizeof(buf));
4267 
4268 	/* Send SCSI Inquiry */
4269 	if (!scsipt_inquiry(chgp, DI_ROLE_MAIN, buf, sizeof(inquiry_data_t))) {
4270 		DBGPRN(DBG_DEVIO)(errfp,
4271 			"%s: SCSI Inquiry failed\n", di_devlist[1]);
4272 		return FALSE;
4273 	}
4274 
4275 	DBGPRN(DBG_DEVIO)(errfp,
4276 		"\nChanger: vendor=\"%.8s\" prod=\"%.16s\" rev=\"%.4s\"\n",
4277 		inq->vendor, inq->prod, inq->revnum);
4278 
4279 	if (inq->type != DEV_CHANGER) {
4280 		DBGPRN(DBG_DEVIO)(errfp,
4281 			"%s (type=%d) is not a medium changer device\n",
4282 			di_devlist[1], inq->type);
4283 		return FALSE;
4284 	}
4285 
4286 	/* Rezero Unit */
4287 	if (!scsipt_rezero_unit(chgp, DI_ROLE_MAIN)) {
4288 		DBGPRN(DBG_DEVIO)(errfp, "%s: Rezero Unit command error\n",
4289 			di_devlist[1]);
4290 		/* Move on anyway, since Rezero Unit is an optional cmd */
4291 	}
4292 
4293 	/* Clear any unit attention condition */
4294 	(void) scsipt_chg_ready(s);
4295 
4296 	(void) memset(buf, 0, sizeof(buf));
4297 
4298 	/* Check device capabilities */
4299 	if (!scsipt_modesense(chgp, DI_ROLE_MAIN, buf, 0,
4300 			      PG_DEVCAPAB, SZ_DEVCAPAB)) {
4301 		DBGPRN(DBG_DEVIO)(errfp,
4302 			"%s: Mode sense command error\n", di_devlist[1]);
4303 		return FALSE;
4304 	}
4305 
4306 	if (app_data.msen_10)
4307 		bdesclen = (int)
4308 			util_bswap16((word16_t) ms_data10->bdescr_len);
4309 	else
4310 		bdesclen = (int) ms_data6->bdescr_len;
4311 
4312 	dcapab = (dev_capab_t *)(void *) ((byte_t *) bdesc + bdesclen);
4313 
4314 	if (dcapab->pg_code != PG_DEVCAPAB) {
4315 		DBGPRN(DBG_DEVIO)(errfp,
4316 			"%s: Mode sense data error\n", di_devlist[1]);
4317 		return FALSE;
4318 	}
4319 
4320 	if (dcapab->stor_dt == 0 || dcapab->stor_st == 0 ||
4321 	    dcapab->move_st_dt == 0 || dcapab->move_dt_st == 0) {
4322 		DBGPRN(DBG_DEVIO)(errfp,
4323 			"%s: Missing required changer capabilities\n",
4324 			di_devlist[1]);
4325 		return FALSE;
4326 	}
4327 
4328 	(void) memset(buf, 0, sizeof(buf));
4329 
4330 	/* Get element addresses */
4331 	if (!scsipt_modesense(chgp, DI_ROLE_MAIN, buf, 0,
4332 			      PG_ELEMADDR, SZ_ELEMADDR)) {
4333 		DBGPRN(DBG_DEVIO)(errfp,
4334 			"%s: Mode sense command error\n", di_devlist[1]);
4335 		return FALSE;
4336 	}
4337 
4338 	if (app_data.msen_10)
4339 		bdesclen = (int)
4340 			util_bswap16((word16_t) ms_data10->bdescr_len);
4341 	else
4342 		bdesclen = (int) ms_data6->bdescr_len;
4343 
4344 	eaddr = (elem_addr_t *)(void *) ((byte_t *) bdesc + bdesclen);
4345 
4346 	if (eaddr->pg_code != PG_ELEMADDR) {
4347 		DBGPRN(DBG_DEVIO)(errfp,
4348 			"%s: Mode sense data error\n", di_devlist[1]);
4349 		return FALSE;
4350 	}
4351 
4352 	scsipt_mcparm.mtbase = util_bswap16((word16_t) eaddr->mt_addr);
4353 	scsipt_mcparm.stbase = util_bswap16((word16_t) eaddr->st_addr);
4354 	scsipt_mcparm.iebase = util_bswap16((word16_t) eaddr->ie_addr);
4355 	scsipt_mcparm.dtbase = util_bswap16((word16_t) eaddr->dt_addr);
4356 
4357 	DBGPRN(DBG_DEVIO)(errfp,
4358 		"\nMedium changer: MT=0x%x ST=0x%x IE=0x%x DT=0x%x\n",
4359 		(int) scsipt_mcparm.mtbase,
4360 		(int) scsipt_mcparm.stbase,
4361 		(int) scsipt_mcparm.iebase,
4362 		(int) scsipt_mcparm.dtbase);
4363 
4364 	if ((int) util_bswap16((word16_t) eaddr->st_num) != app_data.numdiscs){
4365 		DBGPRN(DBG_DEVIO)(errfp,
4366 			"Number of discs configuration mismatch\n");
4367 		return FALSE;
4368 	}
4369 	if ((int) util_bswap16((word16_t) eaddr->mt_num) > 1) {
4370 		DBGPRN(DBG_DEVIO)(errfp,
4371 			"Multi-transport changer not supported\n");
4372 		return FALSE;
4373 	}
4374 	if ((int) util_bswap16((word16_t) eaddr->dt_num) > 1) {
4375 		DBGPRN(DBG_DEVIO)(errfp,
4376 			"Multi-spindle changer not supported\n");
4377 		return FALSE;
4378 	}
4379 
4380 	/* Allocate medium map array */
4381 	if (scsipt_medmap == NULL) {
4382 		scsipt_medmap = (bool_t *) MEM_ALLOC(
4383 			"scsipt_medmap", app_data.numdiscs * sizeof(bool_t)
4384 		);
4385 		if (scsipt_medmap == NULL) {
4386 			DI_FATAL(app_data.str_nomemory);
4387 			return FALSE;
4388 		}
4389 
4390 		(void) memset(scsipt_medmap, 0,
4391 			      app_data.numdiscs * sizeof(bool_t));
4392 	}
4393 
4394 	/* Check changer status */
4395 	(void) scsipt_chg_rdstatus();	/* Update medium map */
4396 
4397 	return TRUE;
4398 }
4399 
4400 
4401 /*
4402  * scsipt_chg_halt
4403  *	Multi-disc changer shutdown
4404  *
4405  * Args:
4406  *	s - Pointer to the curstat_t structure
4407  *
4408  * Return:
4409  *	Nothing.
4410  */
4411 /*ARGSUSED*/
4412 STATIC void
scsipt_chg_halt(curstat_t * s)4413 scsipt_chg_halt(curstat_t *s)
4414 {
4415 	/* Close medium changer device */
4416 	if (chgp != NULL) {
4417 		scsipt_close(chgp);
4418 		chgp = NULL;
4419 	}
4420 
4421 	/* Free medium changer map if allocated */
4422 	if (scsipt_medmap != NULL) {
4423 		MEM_FREE(scsipt_medmap);
4424 		scsipt_medmap = NULL;
4425 	}
4426 }
4427 
4428 
4429 /***********************
4430  *   public routines   *
4431  ***********************/
4432 
4433 
4434 /*
4435  * scsipt_reqsense_keystr
4436  *	Given a request sense key, return an associated descriptive string.
4437  *
4438  * Args:
4439  *	key - The request sense key value
4440  *
4441  * Return:
4442  *	Descriptive text string.
4443  */
4444 char *
scsipt_reqsense_keystr(int key)4445 scsipt_reqsense_keystr(int key)
4446 {
4447 	int	i;
4448 
4449 	for (i = 0; rsense_keymap[i].text != NULL; i++) {
4450 		if (key == rsense_keymap[i].key)
4451 			return (rsense_keymap[i].text);
4452 	}
4453 	return ("UNKNOWN KEY");
4454 }
4455 
4456 
4457 /*
4458  * scsipt_enable
4459  *	Enable device for SCSI pass-through I/O.
4460  *
4461  * Args:
4462  *	dp - Device descriptor
4463  *	role - Role id for which I/O is to be enabled
4464  *
4465  * Return:
4466  *	Nothing.
4467  */
4468 void
scsipt_enable(di_dev_t * dp,int role)4469 scsipt_enable(di_dev_t *dp, int role)
4470 {
4471 	DBGPRN(DBG_DEVIO)(errfp, "\nEnable device: %s role: %d\n",
4472 			  dp->path, role);
4473 	pthru_enable(dp, role);
4474 }
4475 
4476 
4477 /*
4478  * scsipt_disable
4479  *	Disable device for SCSI pass-through I/O.
4480  *
4481  * Args:
4482  *	dp - Device descriptor
4483  *	role - Role id for which I/O is to be enabled
4484  *
4485  * Return:
4486  *	Nothing.
4487  */
4488 void
scsipt_disable(di_dev_t * dp,int role)4489 scsipt_disable(di_dev_t *dp, int role)
4490 {
4491 	if (dp->role != role) {
4492 		DBGPRN(DBG_DEVIO)(errfp,
4493 			"\nscsipt_disable: invalid role: %d (device %s)\n",
4494 			role, dp->path
4495 		);
4496 		return;
4497 	}
4498 
4499 	DBGPRN(DBG_DEVIO)(errfp, "\nDisable device: %s role: %d\n",
4500 			  dp->path, role);
4501 	pthru_disable(dp, role);
4502 }
4503 
4504 
4505 /*
4506  * scsipt_is_enabled
4507  *	Check whether device is enabled for SCSI pass-through I/O.
4508  *
4509  * Args:
4510  *	dp - Device descriptor
4511  *	role - Role id for which to check
4512  *
4513  * Return:
4514  *	TRUE  - Enabled.
4515  *	FALSE - Disabled.
4516  */
4517 bool_t
scsipt_is_enabled(di_dev_t * dp,int role)4518 scsipt_is_enabled(di_dev_t *dp, int role)
4519 {
4520 	return (pthru_is_enabled(dp, role));
4521 }
4522 
4523 
4524 /*
4525  * scsipt_init
4526  *	Top-level function to initialize the SCSI pass-through and
4527  *	vendor-unique modules.
4528  *
4529  * Args:
4530  *	s - Pointer to the curstat_t structure
4531  *
4532  * Return:
4533  *	Nothing.
4534  */
4535 void
scsipt_init(curstat_t * s,di_tbl_t * dt)4536 scsipt_init(curstat_t *s, di_tbl_t *dt)
4537 {
4538 	int	i;
4539 
4540 	if (app_data.di_method != DI_SCSIPT)
4541 		/* SCSI pass-through not configured */
4542 		return;
4543 
4544 	/* Initialize libdi calling table */
4545 	dt->load_cdtext = scsipt_load_cdtext;
4546 	dt->playmode = scsipt_playmode;
4547 	dt->check_disc = scsipt_check_disc;
4548 	dt->status_upd = scsipt_status_upd;
4549 	dt->lock = scsipt_lock;
4550 	dt->repeat = scsipt_repeat;
4551 	dt->shuffle = scsipt_shuffle;
4552 	dt->load_eject = scsipt_load_eject;
4553 	dt->ab = scsipt_ab;
4554 	dt->sample = scsipt_sample;
4555 	dt->level = scsipt_level;
4556 	dt->play_pause = scsipt_play_pause;
4557 	dt->stop = scsipt_stop;
4558 	dt->chgdisc = scsipt_chgdisc;
4559 	dt->prevtrk = scsipt_prevtrk;
4560 	dt->nexttrk = scsipt_nexttrk;
4561 	dt->previdx = scsipt_previdx;
4562 	dt->nextidx = scsipt_nextidx;
4563 	dt->rew = scsipt_rew;
4564 	dt->ff = scsipt_ff;
4565 	dt->warp = scsipt_warp;
4566 	dt->route = scsipt_route;
4567 	dt->mute_on = scsipt_mute_on;
4568 	dt->mute_off = scsipt_mute_off;
4569 	dt->cddajitter = scsipt_cddajitter;
4570 	dt->debug = scsipt_debug;
4571 	dt->start = scsipt_start;
4572 	dt->icon = scsipt_icon;
4573 	dt->halt = scsipt_halt;
4574 	dt->methodstr = scsipt_methodstr;
4575 
4576 	/* Initalize SCSI pass-through module */
4577 	scsipt_stat_polling = FALSE;
4578 	scsipt_stat_interval = app_data.stat_interval;
4579 	scsipt_insert_polling = FALSE;
4580 	scsipt_next_sam = FALSE;
4581 	scsipt_new_progshuf = FALSE;
4582 	scsipt_sav_end_addr = 0;
4583 	scsipt_sav_end_msf.min = scsipt_sav_end_msf.sec =
4584 		scsipt_sav_end_msf.frame = 0;
4585 	scsipt_sav_end_fmt = 0;
4586 
4587 #ifdef SETUID_ROOT
4588 #ifdef SOL2_VOLMGT
4589 	if (!app_data.sol2_volmgt)
4590 #endif	/* SOL2_VOLMGT */
4591 	{
4592 		DBGPRN(DBG_DEVIO)(errfp, "\nSetting uid to 0\n");
4593 
4594 #ifdef HAS_EUID
4595 		if (util_seteuid(0) < 0 || geteuid() != 0)
4596 #else
4597 		if (setuid(0) < 0 || getuid() != 0)
4598 #endif
4599 		{
4600 			DI_FATAL(app_data.str_moderr);
4601 			return;
4602 		}
4603 	}
4604 #endif	/* SETUID_ROOT */
4605 
4606 	/* Initialize curstat structure */
4607 	di_reset_curstat(s, TRUE, TRUE);
4608 
4609 	/* Initialize the SCSI-2 entry of the scsipt_vutbl jump table */
4610 	scsipt_vutbl[VENDOR_SCSI2].vendor = "SCSI-2";
4611 	scsipt_vutbl[VENDOR_SCSI2].playaudio = NULL;
4612 	scsipt_vutbl[VENDOR_SCSI2].pause_resume = NULL;
4613 	scsipt_vutbl[VENDOR_SCSI2].start_stop = NULL;
4614 	scsipt_vutbl[VENDOR_SCSI2].get_playstatus = NULL;
4615 	scsipt_vutbl[VENDOR_SCSI2].volume = NULL;
4616 	scsipt_vutbl[VENDOR_SCSI2].route = NULL;
4617 	scsipt_vutbl[VENDOR_SCSI2].mute = NULL;
4618 	scsipt_vutbl[VENDOR_SCSI2].get_toc = NULL;
4619 	scsipt_vutbl[VENDOR_SCSI2].eject = NULL;
4620 	scsipt_vutbl[VENDOR_SCSI2].start = NULL;
4621 	scsipt_vutbl[VENDOR_SCSI2].halt = NULL;
4622 
4623 	DBGPRN(DBG_DEVIO)(errfp, "%s\n\t%s\n",
4624 		"libdi: SCSI pass-through method", "SCSI-2");
4625 
4626 	/* Initialize all configured vendor-unique modules */
4627 	for (i = 0; i < MAX_VENDORS; i++) {
4628 		if (vuinit[i].init != NULL) {
4629 			vuinit[i].init();
4630 			DBGPRN(DBG_DEVIO)(errfp,
4631 				"\t%s\n", scsipt_vutbl[i].vendor);
4632 		}
4633 	}
4634 
4635 	if (app_data.vendor_code != VENDOR_SCSI2 &&
4636 	    vuinit[app_data.vendor_code].init == NULL) {
4637 		DI_FATAL(app_data.str_novu);
4638 	}
4639 }
4640 
4641 
4642 /*
4643  * scsipt_load_cdtext
4644  *	Parse CD-TEXT raw data and fill in the di_cdtext_t structure.
4645  *
4646  * Args:
4647  *	s - Pointer to the curstat_t structure
4648  *	t - Pointer to the di_cdtext_t structure
4649  *
4650  * Return:
4651  *	Nothing.
4652  */
4653 void
scsipt_load_cdtext(curstat_t * s,di_cdtext_t * t)4654 scsipt_load_cdtext(curstat_t *s, di_cdtext_t *t)
4655 {
4656 	size_t			len;
4657 	int			npacks,
4658 				i,
4659 				j,
4660 				k,
4661 				n,
4662 				prevtrk,
4663 				trk,
4664 				valid;
4665 	toc_hdr_t		*h;
4666 	toc_cdtext_pack_t	*p,
4667 				*prevp;
4668 	char			**obj = NULL,
4669 				*prevobj = NULL,
4670 				*info = NULL;
4671 	bool_t			two_byte,
4672 				trk_gap,
4673 				upd_obj;
4674 
4675 	/* Initialize */
4676 	(void) memset(t, 0, sizeof(di_cdtext_t));
4677 	t->cdtext_valid = FALSE;
4678 
4679 	h = (toc_hdr_t *)(void *) scsipt_cdtext_buf;
4680 	if ((len = util_bswap16(h->data_len)) == 0)
4681 		return;		/* No CD-TEXT data */
4682 
4683 	npacks = (len - 2) / sizeof(toc_cdtext_pack_t);
4684 	if (npacks == 0)
4685 		return;		/* No CD-TEXT data */
4686 
4687 	/* Allocate scratch buffer */
4688 	info = (char *) MEM_ALLOC("cdtext_info", SZ_CDTEXTINFO);
4689 	if (info == NULL) {
4690 		DI_FATAL(app_data.str_nomemory);
4691 		return;
4692 	}
4693 	(void) memset(info, 0, SZ_CDTEXTINFO);
4694 
4695 	/*
4696 	 * Parse cached data and fill di_cdtext_t structure
4697 	 * This code is fugly because the raw CD-TEXT data
4698 	 * format is so convoluted.
4699 	 */
4700 
4701 	prevp = NULL;
4702 	prevtrk = 0;
4703 	upd_obj = FALSE;
4704 	p = (toc_cdtext_pack_t *)(void *) (scsipt_cdtext_buf + SZ_TOCHDR);
4705 	j = 0;
4706 
4707 	for (i = 0; i < npacks; i++, p++) {
4708 		if (p->pack_type == PACK_SIZEINFO ||
4709 		    p->pack_type == PACK_GENRE ||
4710 		    p->pack_type == PACK_TOC ||
4711 		    p->pack_type == PACK_TOC2) {
4712 			n = 0;
4713 			trk = -1;
4714 			two_byte = FALSE;
4715 			trk_gap = FALSE;
4716 		}
4717 		else {
4718 			trk = (int) p->trk_no - (int) s->first_trk;
4719 			two_byte = (bool_t) ((p->blk_char & 0x80) != 0);
4720 			trk_gap = FALSE;
4721 
4722 			n = (int) (p->blk_char & 0x0f);
4723 			if (n > SZ_CDTEXTPKD)
4724 				n = SZ_CDTEXTPKD;
4725 
4726 			if (trk >= (int) s->tot_trks) {
4727 				/* Invalid track number */
4728 				DBGPRN(DBG_DEVIO|DBG_CDI)(errfp,
4729 					"Invalid track number %02u in "
4730 					"CD-TEXT data: skipped.\n",
4731 					(unsigned int) p->trk_no);
4732 				prevp = NULL;
4733 				continue;
4734 			}
4735 			else if (trk == 0) {
4736 				/* First track */
4737 				prevobj = NULL;
4738 			}
4739 			else if (trk > 0 && trk > (prevtrk+1) && j > 0 &&
4740 				 j < SZ_CDTEXTPKD) {
4741 				/* Skipped a track: Because the
4742 				 * residual data in the previous pack
4743 				 * has all of the missing track's data.
4744 				 * Fake it.
4745 				 */
4746 				trk_gap = TRUE;
4747 				trk--;
4748 				p--;
4749 				i--;
4750 			}
4751 			prevtrk = trk;
4752 		}
4753 
4754 		switch ((int) p->pack_type) {
4755 		case PACK_TITLE:
4756 			if (trk < 0)
4757 				obj = &t->disc.title;
4758 			else
4759 				obj = &t->track[trk].title;
4760 			break;
4761 
4762 		case PACK_PERFORMER:
4763 			if (trk < 0)
4764 				obj = &t->disc.performer;
4765 			else
4766 				obj = &t->track[trk].performer;
4767 			break;
4768 
4769 		case PACK_SONGWRITER:
4770 			if (trk < 0)
4771 				obj = &t->disc.songwriter;
4772 			else
4773 				obj = &t->track[trk].songwriter;
4774 			break;
4775 
4776 		case PACK_COMPOSER:
4777 			if (trk < 0)
4778 				obj = &t->disc.composer;
4779 			else
4780 				obj = &t->track[trk].composer;
4781 			break;
4782 
4783 		case PACK_ARRANGER:
4784 			if (trk < 0)
4785 				obj = &t->disc.arranger;
4786 			else
4787 				obj = &t->track[trk].arranger;
4788 			break;
4789 
4790 		case PACK_MESSAGE:
4791 			if (trk < 0)
4792 				obj = &t->disc.message;
4793 			else
4794 				obj = &t->track[trk].message;
4795 			break;
4796 
4797 		case PACK_IDENT:
4798 			if (trk < 0)
4799 				obj = &t->ident;
4800 			else
4801 				obj = NULL;
4802 			break;
4803 
4804 		case PACK_UPCEAN:
4805 			if (trk < 0)
4806 				obj = &t->disc.catno;
4807 			else
4808 				obj = &t->track[trk].catno;
4809 			break;
4810 
4811 		case PACK_GENRE:
4812 		case PACK_TOC:
4813 		case PACK_TOC2:
4814 			/* These pack types are not supported for now:
4815 			 * I can't find any documentation on its data format
4816 			 * (supposed to be binary)
4817 			 */
4818 			obj = NULL;
4819 			break;
4820 
4821 		case PACK_SIZEINFO:
4822 			/* This is just informational only */
4823 			if ((app_data.debug & (DBG_DEVIO|DBG_CDI)) != 0) {
4824 				switch ((int) p->trk_no) {
4825 				case 0:
4826 				    (void) fprintf(errfp,
4827 						"\nCD-TEXT cooked sizeinfo\n");
4828 				    (void) fprintf(errfp,
4829 						"  First track: %d\n"
4830 						"  last track: %d\n",
4831 						(int) p->data[1],
4832 						(int) p->data[2]);
4833 				    if (p->data[3] & 0x80) {
4834 					(void) fprintf(errfp,
4835 						"  Program area CD-TEXT "
4836 						"available\n");
4837 					if (p->data[3] & 0x40) {
4838 					    (void) fprintf(errfp,
4839 						    "Program area copy-"
4840 						    "protection available\n");
4841 					}
4842 				    }
4843 				    if (p->data[3] & 0x07) {
4844 					(void) fprintf(errfp,
4845 						"  Album/Track names "
4846 						"%scopyrighted\n",
4847 						(p->data[3] & 0x01) ?
4848 						"" : "not ");
4849 					(void) fprintf(errfp,
4850 						"  Performer/Songwriter/"
4851 						"Composer/Arranger names "
4852 						"%scopyrighted\n",
4853 						(p->data[3] & 0x02) ?
4854 						"" : "not ");
4855 					(void) fprintf(errfp,
4856 						"  Message info "
4857 						"%scopyrighted\n",
4858 						(p->data[3] & 0x04) ?
4859 						"" : "not ");
4860 				    }
4861 				    (void) fprintf(errfp,
4862 					    "  Album/track names: %d packs\n",
4863 					    (int) p->data[4]);
4864 				    (void) fprintf(errfp,
4865 					    "  Performer names: %d packs\n",
4866 					    (int) p->data[5]);
4867 				    (void) fprintf(errfp,
4868 					    "  Songwriter names: %d packs\n",
4869 					    (int) p->data[6]);
4870 				    (void) fprintf(errfp,
4871 					    "  Composer names: %d packs\n",
4872 					    (int) p->data[7]);
4873 				    (void) fprintf(errfp,
4874 					    "  Arranger names: %d packs\n",
4875 					    (int) p->data[8]);
4876 				    (void) fprintf(errfp,
4877 					    "  Messages: %d packs\n",
4878 					    (int) p->data[9]);
4879 				    (void) fprintf(errfp,
4880 					    "  Ident info: %d packs\n",
4881 					    (int) p->data[10]);
4882 				    (void) fprintf(errfp,
4883 					    "  Genre info: %d packs\n",
4884 					    (int) p->data[11]);
4885 				    break;
4886 
4887 				case 1:
4888 				    (void) fprintf(errfp,
4889 					    "  TOC info: %d packs\n",
4890 					    (int) p->data[0]);
4891 				    (void) fprintf(errfp,
4892 					    "  TOC2 info: %d packs\n",
4893 					    (int) p->data[1]);
4894 				    (void) fprintf(errfp,
4895 					    "  UPC/EAN ISRC: %d packs\n",
4896 					    (int) p->data[6]);
4897 				    (void) fprintf(errfp,
4898 					    "  Size info: %d packs\n",
4899 					    (int) p->data[7]);
4900 				    (void) fprintf(errfp,
4901 					    "  Last seq num blks 1-4: "
4902 					    "0x%02x 0x%02x 0x%02x 0x%02x\n",
4903 					    (int) p->data[8],
4904 					    (int) p->data[9],
4905 					    (int) p->data[10],
4906 					    (int) p->data[11]);
4907 				    break;
4908 
4909 				case 2:
4910 				    (void) fprintf(errfp,
4911 					    "  Last seq num blks 5-8: "
4912 					    "0x%02x 0x%02x 0x%02x 0x%02x\n",
4913 					    (int) p->data[0],
4914 					    (int) p->data[1],
4915 					    (int) p->data[2],
4916 					    (int) p->data[3]);
4917 				    (void) fprintf(errfp,
4918 					    "  Language codes blks 1-4: "
4919 					    "0x%02x 0x%02x 0x%02x 0x%02x\n",
4920 					    (int) p->data[4],
4921 					    (int) p->data[5],
4922 					    (int) p->data[6],
4923 					    (int) p->data[7]);
4924 				    (void) fprintf(errfp,
4925 					    "  Language codes blks 5-8: "
4926 					    "0x%02x 0x%02x 0x%02x 0x%02x\n",
4927 					    (int) p->data[8],
4928 					    (int) p->data[9],
4929 					    (int) p->data[10],
4930 					    (int) p->data[11]);
4931 				    break;
4932 
4933 				default:
4934 				    /* Invalid */
4935 				    break;
4936 				}
4937 			}
4938 
4939 			obj = NULL;
4940 			break;
4941 
4942 		default:
4943 			DBGPRN(DBG_DEVIO)(errfp,
4944 				"scsipt_load_cdtext: unknown pack type 0x%x\n",
4945 				p->pack_type);
4946 			obj = NULL;
4947 			break;
4948 		}
4949 
4950 		if (obj == NULL) {
4951 			prevp = NULL;
4952 			continue;
4953 		}
4954 
4955 		if (trk_gap) {
4956 			while (p->data[++j] == '\0' && j < (SZ_CDTEXTPKD-1))
4957 				;
4958 			if (j == (SZ_CDTEXTPKD-1))
4959 				continue;
4960 
4961 			for (k = 0; j < SZ_CDTEXTPKD; j++, k++) {
4962 				info[k] = (char) p->data[j];
4963 				if (info[k] == '\0') {
4964 					upd_obj = TRUE;
4965 					break;
4966 				}
4967 			}
4968 			if (j == SZ_CDTEXTPKD)
4969 				(void) memset(info, 0, SZ_CDTEXTINFO);
4970 		}
4971 		else {
4972 			if (prevp != NULL && n > 0 && n < SZ_CDTEXTPKD) {
4973 				k = strlen(info);
4974 				(void) strncpy(
4975 				    &info[k],
4976 				    (char *) &prevp->data[SZ_CDTEXTPKD] - n,
4977 				    n
4978 				);
4979 				info[k+n] = '\0';
4980 				k = strlen(info);
4981 			}
4982 
4983 			for (j = 0, k = strlen(info);
4984 			     j < SZ_CDTEXTPKD;
4985 			     j++, k++) {
4986 				info[k] = (char) p->data[j];
4987 				if (info[k] == '\0') {
4988 					upd_obj = TRUE;
4989 					break;
4990 				}
4991 			}
4992 		}
4993 
4994 		if (info[0] != '\0' && upd_obj) {
4995 			if (!two_byte && trk > 0 && prevobj != NULL &&
4996 			    info[0] == '\t') {
4997 				/* One Tab means same as previous track for
4998 				 * single-byte languages.
4999 				 */
5000 				if (!util_newstr(obj, prevobj)) {
5001 					DI_FATAL(app_data.str_nomemory);
5002 					MEM_FREE(info);
5003 					return;
5004 				}
5005 			}
5006 			else if (two_byte && trk > 0 && prevobj != NULL &&
5007 				 info[0] == '\t' && info[1] == '\t') {
5008 				/* Two tabs means same as previous track for
5009 				 * double-byte languages.
5010 				 */
5011 				if (!util_newstr(obj, prevobj)) {
5012 					DI_FATAL(app_data.str_nomemory);
5013 					MEM_FREE(info);
5014 					return;
5015 				}
5016 			}
5017 			else {
5018 				if (*obj == NULL) {
5019 					*obj = (char *) MEM_ALLOC(
5020 						"cdtext_obj", strlen(info) + 1
5021 					);
5022 					if (*obj != NULL)
5023 						**obj = '\0';
5024 				}
5025 				else {
5026 					*obj = (char *) MEM_REALLOC(
5027 						"cdtext_obj", *obj,
5028 						strlen(*obj) + strlen(info) + 1
5029 					);
5030 				}
5031 				if (*obj == NULL) {
5032 					DI_FATAL(app_data.str_nomemory);
5033 					MEM_FREE(info);
5034 					return;
5035 				}
5036 				(void) strcat(*obj, info);
5037 			}
5038 
5039 			(void) memset(info, 0, SZ_CDTEXTINFO);
5040 			upd_obj = FALSE;
5041 		}
5042 
5043 		prevobj = *obj;
5044 		prevp = p;
5045 	}
5046 
5047 	MEM_FREE(info);
5048 
5049 	/* Check data validity and display "cooked" CD-TEXT data in
5050 	 * debug mode
5051 	 */
5052 	valid = 0;
5053 	DBGPRN(DBG_DEVIO|DBG_CDI)(errfp, "\nCD-TEXT cooked data:\n");
5054 	if (t->ident != NULL) {
5055 		valid++;
5056 		DBGPRN(DBG_DEVIO|DBG_CDI)(errfp, "  Ident: %s\n", t->ident);
5057 	}
5058 	if (t->disc.title != NULL) {
5059 		valid++;
5060 		DBGPRN(DBG_DEVIO|DBG_CDI)(errfp,
5061 			"  Album title: %s\n", t->disc.title);
5062 	}
5063 	if (t->disc.performer != NULL) {
5064 		valid++;
5065 		DBGPRN(DBG_DEVIO|DBG_CDI)(errfp,
5066 			"  Album performer: %s\n", t->disc.performer);
5067 	}
5068 	if (t->disc.songwriter != NULL) {
5069 		valid++;
5070 		DBGPRN(DBG_DEVIO|DBG_CDI)(errfp,
5071 			"  Album songwriter: %s\n", t->disc.songwriter);
5072 	}
5073 	if (t->disc.composer != NULL) {
5074 		valid++;
5075 		DBGPRN(DBG_DEVIO|DBG_CDI)(errfp,
5076 			"  Album composer: %s\n", t->disc.composer);
5077 	}
5078 	if (t->disc.arranger != NULL) {
5079 		valid++;
5080 		DBGPRN(DBG_DEVIO|DBG_CDI)(errfp,
5081 			"  Album arranger: %s\n", t->disc.arranger);
5082 	}
5083 	if (t->disc.message != NULL) {
5084 		valid++;
5085 		DBGPRN(DBG_DEVIO|DBG_CDI)(errfp,
5086 			"  Album message: %s\n", t->disc.message);
5087 	}
5088 	if (t->disc.catno != NULL) {
5089 		valid++;
5090 		DBGPRN(DBG_DEVIO|DBG_CDI)(errfp,
5091 			"  Album UPC/EAN: %s\n", t->disc.catno);
5092 	}
5093 
5094 	for (i = 0; i < (int) s->tot_trks; i++) {
5095 		if (t->track[i].title != NULL) {
5096 			valid++;
5097 			DBGPRN(DBG_DEVIO|DBG_CDI)(errfp,
5098 				"  Track %02d title: %s\n",
5099 				s->trkinfo[i].trkno, t->track[i].title);
5100 		}
5101 		if (t->track[i].performer != NULL) {
5102 			valid++;
5103 			DBGPRN(DBG_DEVIO|DBG_CDI)(errfp,
5104 				"  Track %02d performer: %s\n",
5105 				s->trkinfo[i].trkno, t->track[i].performer);
5106 		}
5107 		if (t->track[i].songwriter != NULL) {
5108 			valid++;
5109 			DBGPRN(DBG_DEVIO|DBG_CDI)(errfp,
5110 				"  Track %02d songwriter: %s\n",
5111 				s->trkinfo[i].trkno, t->track[i].songwriter);
5112 		}
5113 		if (t->track[i].composer != NULL) {
5114 			valid++;
5115 			DBGPRN(DBG_DEVIO|DBG_CDI)(errfp,
5116 				"  Track %02d composer: %s\n",
5117 				s->trkinfo[i].trkno, t->track[i].composer);
5118 		}
5119 		if (t->track[i].arranger != NULL) {
5120 			valid++;
5121 			DBGPRN(DBG_DEVIO|DBG_CDI)(errfp,
5122 				"  Track %02d arranger: %s\n",
5123 				s->trkinfo[i].trkno, t->track[i].arranger);
5124 		}
5125 		if (t->track[i].message != NULL) {
5126 			valid++;
5127 			DBGPRN(DBG_DEVIO|DBG_CDI)(errfp,
5128 				"  Track %02d message: %s\n",
5129 				s->trkinfo[i].trkno, t->track[i].message);
5130 		}
5131 		if (t->track[i].catno != NULL) {
5132 			valid++;
5133 			DBGPRN(DBG_DEVIO|DBG_CDI)(errfp,
5134 				"  Track %02d ISRC: %s\n",
5135 				s->trkinfo[i].trkno, t->track[i].catno);
5136 		}
5137 	}
5138 
5139 	if (valid > 0)
5140 		t->cdtext_valid = TRUE;
5141 	else {
5142 		(void) memset(t, 0, sizeof(di_cdtext_t));
5143 		DBGPRN(DBG_DEVIO|DBG_CDI)(errfp,
5144 			"No valid CD-TEXT information found.\n");
5145 	}
5146 }
5147 
5148 
5149 /*
5150  * scsipt_playmode
5151  *	Init/halt CDDA mode
5152  *
5153  * Args:
5154  *	s - Pointer to the curstat_t structure
5155  *
5156  * Return:
5157  *	TRUE - success
5158  *	FALSE - failure
5159  */
5160 bool_t
scsipt_playmode(curstat_t * s)5161 scsipt_playmode(curstat_t *s)
5162 {
5163 	bool_t		cdda,
5164 			ret;
5165 	static bool_t	prev_cdda = FALSE;
5166 
5167 	cdda = (bool_t) PLAYMODE_IS_CDDA(app_data.play_mode);
5168 
5169 	if (cdda == prev_cdda)
5170 		return TRUE;	/* No change */
5171 
5172 	if (cdda) {
5173 		scsipt_cdda_client.curstat_addr = di_clinfo->curstat_addr;
5174 		scsipt_cdda_client.fatal_msg = di_clinfo->fatal_msg;
5175 		scsipt_cdda_client.warning_msg = di_clinfo->warning_msg;
5176 		scsipt_cdda_client.info_msg = di_clinfo->info_msg;
5177 		scsipt_cdda_client.info2_msg = di_clinfo->info2_msg;
5178 
5179 		ret = cdda_init(s, &scsipt_cdda_client);
5180 	}
5181 	else {
5182 		cdda_halt(devp, s);
5183 		ret = TRUE;
5184 
5185 		/* Initialize volume/balance/routing controls */
5186 		scsipt_init_vol(s, FALSE);
5187 	}
5188 
5189 	if (ret)
5190 		prev_cdda = cdda;
5191 
5192 	return (ret);
5193 }
5194 
5195 
5196 /*
5197  * scsipt_check_disc
5198  *	Check if disc is ready for use
5199  *
5200  * Args:
5201  *	s - Pointer to the curstat_t structure
5202  *
5203  * Return:
5204  *	TRUE - success
5205  *	FALSE - failure
5206  */
5207 bool_t
scsipt_check_disc(curstat_t * s)5208 scsipt_check_disc(curstat_t *s)
5209 {
5210 	return (scsipt_disc_ready(s));
5211 }
5212 
5213 
5214 /*
5215  * scsipt_status_upd
5216  *	Force update of playback status
5217  *
5218  * Args:
5219  *	s - Pointer to the curstat_t structure
5220  *
5221  * Return:
5222  *	Nothing.
5223  */
5224 void
scsipt_status_upd(curstat_t * s)5225 scsipt_status_upd(curstat_t *s)
5226 {
5227 	(void) scsipt_get_playstatus(s);
5228 }
5229 
5230 
5231 /*
5232  * scsipt_lock
5233  *	Caddy lock function
5234  *
5235  * Args:
5236  *	s - Pointer to the curstat_t structure
5237  *	enable - whether to enable/disable caddy lock
5238  *
5239  * Return:
5240  *	Nothing.
5241  */
5242 void
scsipt_lock(curstat_t * s,bool_t enable)5243 scsipt_lock(curstat_t *s, bool_t enable)
5244 {
5245 	if (s->mode == MOD_BUSY || s->mode == MOD_NODISC) {
5246 		SET_LOCK_BTN(FALSE);
5247 		return;
5248 	}
5249 	else if (s->mode != MOD_STOP) {
5250 		/* Only allow changing lock status when stopped */
5251 		DO_BEEP();
5252 		SET_LOCK_BTN((bool_t) !enable);
5253 		return;
5254 	}
5255 
5256 	if (!scsipt_prev_allow(devp, DI_ROLE_MAIN, enable)) {
5257 		/* Cannot lock/unlock caddy */
5258 		DO_BEEP();
5259 		SET_LOCK_BTN((bool_t) !enable);
5260 		return;
5261 	}
5262 
5263 	s->caddy_lock = enable;
5264 	SET_LOCK_BTN(enable);
5265 }
5266 
5267 
5268 /*
5269  * scsipt_repeat
5270  *	Repeat mode function
5271  *
5272  * Args:
5273  *	s - Pointer to the curstat_t structure
5274  *	enable - whether to enable/disable repeat mode
5275  *
5276  * Return:
5277  *	Nothing.
5278  */
5279 void
scsipt_repeat(curstat_t * s,bool_t enable)5280 scsipt_repeat(curstat_t *s, bool_t enable)
5281 {
5282 	s->repeat = enable;
5283 
5284 	if (!enable && scsipt_new_progshuf) {
5285 		scsipt_new_progshuf = FALSE;
5286 		if (s->rptcnt > 0)
5287 			s->rptcnt--;
5288 	}
5289 	DPY_RPTCNT(s);
5290 }
5291 
5292 
5293 /*
5294  * scsipt_shuffle
5295  *	Shuffle mode function
5296  *
5297  * Args:
5298  *	s - Pointer to the curstat_t structure
5299  *	enable - whether to enable/disable shuffle mode
5300  *
5301  * Return:
5302  *	Nothing.
5303  */
5304 void
scsipt_shuffle(curstat_t * s,bool_t enable)5305 scsipt_shuffle(curstat_t *s, bool_t enable)
5306 {
5307 	if (s->segplay == SEGP_A) {
5308 		/* Can't set shuffle during a->? mode */
5309 		DO_BEEP();
5310 		SET_SHUFFLE_BTN((bool_t) !enable);
5311 		return;
5312 	}
5313 
5314 	switch (s->mode) {
5315 	case MOD_STOP:
5316 	case MOD_BUSY:
5317 	case MOD_NODISC:
5318 		if (s->program) {
5319 			/* Currently in program mode: can't enable shuffle */
5320 			DO_BEEP();
5321 			SET_SHUFFLE_BTN((bool_t) !enable);
5322 			return;
5323 		}
5324 		break;
5325 	default:
5326 		if (enable) {
5327 			/* Can't enable shuffle unless when stopped */
5328 			DO_BEEP();
5329 			SET_SHUFFLE_BTN((bool_t) !enable);
5330 			return;
5331 		}
5332 		break;
5333 	}
5334 
5335 	s->segplay = SEGP_NONE;	/* Cancel a->b mode */
5336 	DPY_PROGMODE(s, FALSE);
5337 
5338 	s->shuffle = enable;
5339 	if (!s->shuffle)
5340 		s->prog_tot = 0;
5341 }
5342 
5343 
5344 /*
5345  * scsipt_load_eject
5346  *	CD caddy load and eject function.  If disc caddy is not
5347  *	loaded, it will attempt to load it.  Otherwise, it will be
5348  *	ejected.
5349  *
5350  * Args:
5351  *	s - Pointer to the curstat_t structure
5352  *
5353  * Return:
5354  *	Nothing.
5355  */
5356 void
scsipt_load_eject(curstat_t * s)5357 scsipt_load_eject(curstat_t *s)
5358 {
5359 	req_sense_data_t	sense;
5360 	bool_t			dbg;
5361 
5362 	if (devp == NULL)
5363 		return;
5364 
5365 	dbg = (bool_t) ((app_data.debug & DBG_DEVIO) != 0);
5366 
5367 	(void) memset(&sense, 0, sizeof(sense));
5368 
5369 	if (scsipt_is_enabled(devp, DI_ROLE_MAIN) &&
5370 	    !scsipt_disc_present(devp, DI_ROLE_MAIN, s, &sense)) {
5371 		/* No disc */
5372 		switch ((int) sense.key) {
5373 		case 0x02:	/* Not ready */
5374 			switch ((int) sense.code) {
5375 			case 0x3a:
5376 				switch ((int) sense.qual) {
5377 		    		case 0x02:
5378 					/* Tray open */
5379 					if (app_data.load_supp) {
5380 						/* Close the tray */
5381 						(void) scsipt_do_start_stop(
5382 							devp, TRUE, TRUE, TRUE
5383 						);
5384 					}
5385 					break;
5386 
5387 				case 0x01:
5388 					/* Closed but Empty tray */
5389 					if (!app_data.eject_supp)
5390 						break;
5391 
5392 					/* Unlock caddy if supported */
5393 					if (app_data.caddylock_supp)
5394 						scsipt_lock(s, FALSE);
5395 
5396 					/* Open the tray */
5397 					(void) scsipt_do_start_stop(
5398 						devp, FALSE, TRUE, TRUE
5399 					);
5400 					break;
5401 
5402 				case 0x00:
5403 				default:
5404 					/* Can't tell if tray is open or
5405 					 * closed with no disc.  Yuck.
5406 					 */
5407 
5408 					if (app_data.load_supp) {
5409 						/* Close the tray */
5410 						(void) scsipt_do_start_stop(
5411 							devp, TRUE, TRUE, dbg
5412 						);
5413 					}
5414 
5415 					/* Wait for disc */
5416 					if (scsipt_disc_present(devp,
5417 								DI_ROLE_MAIN,
5418 								s, NULL))
5419 						break;
5420 
5421 					if (app_data.eject_supp) {
5422 						/* Opening the tray */
5423 						(void) scsipt_do_start_stop(
5424 							devp, FALSE, TRUE, dbg
5425 						);
5426 					}
5427 					break;
5428 				}
5429 				break;
5430 
5431 			default:
5432 				break;
5433 			}
5434 			break;
5435 
5436 		default:
5437 			break;
5438 		}
5439 
5440 		scsipt_stop_stat_poll();
5441 		di_reset_curstat(s, TRUE, TRUE);
5442 		s->mode = MOD_NODISC;
5443 
5444 		di_clear_cdinfo(s, FALSE);
5445 		DPY_ALL(s);
5446 
5447 		if (devp != NULL && app_data.eject_close) {
5448 			scsipt_close(devp);
5449 			devp = NULL;
5450 			scsipt_not_open = TRUE;
5451 		}
5452 
5453 		scsipt_start_insert_poll(s);
5454 		return;
5455 	}
5456 
5457 	/* Eject the disc */
5458 
5459 	/* Spin down the CD */
5460 	(void) scsipt_do_start_stop(devp, FALSE, FALSE, TRUE);
5461 
5462 	if (!app_data.eject_supp) {
5463 		DO_BEEP();
5464 
5465 		scsipt_stop_stat_poll();
5466 		di_reset_curstat(s, TRUE, TRUE);
5467 		s->mode = MOD_NODISC;
5468 
5469 		di_clear_cdinfo(s, FALSE);
5470 		DPY_ALL(s);
5471 
5472 		if (devp != NULL && app_data.eject_close) {
5473 			scsipt_close(devp);
5474 			devp = NULL;
5475 			scsipt_not_open = TRUE;
5476 		}
5477 
5478 		scsipt_start_insert_poll(s);
5479 		return;
5480 	}
5481 
5482 	/* Unlock caddy if supported */
5483 	if (app_data.caddylock_supp)
5484 		scsipt_lock(s, FALSE);
5485 
5486 	scsipt_stop_stat_poll();
5487 	di_reset_curstat(s, TRUE, TRUE);
5488 	s->mode = MOD_NODISC;
5489 
5490 	di_clear_cdinfo(s, FALSE);
5491 	DPY_ALL(s);
5492 
5493 	/* Eject the CD */
5494 	(void) scsipt_do_start_stop(devp, FALSE, TRUE, TRUE);
5495 
5496 	if (app_data.eject_exit)
5497 		di_clinfo->quit(s);
5498 	else {
5499 		if (devp != NULL && app_data.eject_close) {
5500 			scsipt_close(devp);
5501 			devp = NULL;
5502 			scsipt_not_open = TRUE;
5503 		}
5504 
5505 		scsipt_start_insert_poll(s);
5506 	}
5507 }
5508 
5509 
5510 /*
5511  * scsipt_ab
5512  *	A->B segment play mode function
5513  *
5514  * Args:
5515  *	s - Pointer to the curstat_t structure
5516  *
5517  * Return:
5518  *	Nothing.
5519  */
5520 void
scsipt_ab(curstat_t * s)5521 scsipt_ab(curstat_t *s)
5522 {
5523 	if (!scsipt_run_ab(s))
5524 		DO_BEEP();
5525 }
5526 
5527 
5528 /*
5529  * scsipt_sample
5530  *	Sample play mode function
5531  *
5532  * Args:
5533  *	s - Pointer to the curstat_t structure
5534  *
5535  * Return:
5536  *	Nothing.
5537  */
5538 void
scsipt_sample(curstat_t * s)5539 scsipt_sample(curstat_t *s)
5540 {
5541 	int	i;
5542 
5543 	if (!scsipt_disc_ready(s)) {
5544 		DO_BEEP();
5545 		return;
5546 	}
5547 
5548 	if (s->shuffle || s->program || s->segplay != SEGP_NONE) {
5549 		/* Sample is not supported in program/shuffle or a->b modes */
5550 		DO_BEEP();
5551 		return;
5552 	}
5553 
5554 	switch (s->mode) {
5555 	case MOD_STOP:
5556 		scsipt_start_stat_poll(s);
5557 		/*FALLTHROUGH*/
5558 	case MOD_PLAY:
5559 		/* If already playing a track, start sampling the track after
5560 		 * the current one.  Otherwise, sample from the beginning.
5561 		 */
5562 		if (s->cur_trk > 0 && s->cur_trk != s->last_trk) {
5563 			i = di_curtrk_pos(s) + 1;
5564 			s->cur_trk = s->trkinfo[i].trkno;
5565 			scsipt_next_sam = (byte_t) i;
5566 		}
5567 		else {
5568 			s->cur_trk = s->first_trk;
5569 			scsipt_next_sam = 0;
5570 		}
5571 
5572 		s->cur_idx = 1;
5573 
5574 		s->mode = MOD_SAMPLE;
5575 		DPY_ALL(s);
5576 
5577 		if (!scsipt_run_sample(s))
5578 			return;
5579 
5580 		break;
5581 
5582 	case MOD_SAMPLE:
5583 		/* Currently doing Sample playback, just call scsipt_play_pause
5584 		 * to resume normal playback.
5585 		 */
5586 		scsipt_play_pause(s);
5587 		break;
5588 
5589 	default:
5590 		DO_BEEP();
5591 		break;
5592 	}
5593 }
5594 
5595 
5596 /*
5597  * scsipt_level
5598  *	Audio volume control function
5599  *
5600  * Args:
5601  *	s - Pointer to the curstat_t structure
5602  *	level - The volume level to set to
5603  *	drag - Whether this is an update due to the user dragging the
5604  *		volume control slider thumb.  If this is FALSE, then
5605  *		a final volume setting has been found.
5606  *
5607  * Return:
5608  *	Nothing.
5609  */
5610 void
scsipt_level(curstat_t * s,byte_t level,bool_t drag)5611 scsipt_level(curstat_t *s, byte_t level, bool_t drag)
5612 {
5613 	int	actual;
5614 
5615 	if (drag && app_data.vendor_code != VENDOR_SCSI2 &&
5616 	    scsipt_vutbl[app_data.vendor_code].volume == NULL)
5617 		return;
5618 
5619 	/* Set volume level */
5620 	if ((actual = scsipt_cfg_vol((int) level, s, FALSE, TRUE)) >= 0)
5621 		s->level = (byte_t) actual;
5622 }
5623 
5624 
5625 /*
5626  * scsipt_play_pause
5627  *	Audio playback and pause function
5628  *
5629  * Args:
5630  *	s - Pointer to the curstat_t structure
5631  *
5632  * Return:
5633  *	Nothing.
5634  */
5635 void
scsipt_play_pause(curstat_t * s)5636 scsipt_play_pause(curstat_t *s)
5637 {
5638 	sword32_t	i,
5639 			start_addr;
5640 	msf_t		start_msf,
5641 			end_msf;
5642 
5643 	scsipt_override_ap = TRUE;
5644 
5645 	if (!scsipt_disc_ready(s)) {
5646 		scsipt_override_ap = FALSE;
5647 		DO_BEEP();
5648 		return;
5649 	}
5650 
5651 	scsipt_override_ap = FALSE;
5652 
5653 	if (s->mode == MOD_NODISC)
5654 		s->mode = MOD_STOP;
5655 
5656 	switch (s->mode) {
5657 	case MOD_PLAY:
5658 		/* Currently playing: go to pause mode */
5659 
5660 		if (!scsipt_do_pause_resume(devp, FALSE)) {
5661 			DO_BEEP();
5662 			return;
5663 		}
5664 		scsipt_stop_stat_poll();
5665 		s->mode = MOD_PAUSE;
5666 		DPY_PLAYMODE(s, FALSE);
5667 		break;
5668 
5669 	case MOD_PAUSE:
5670 		/* Currently paused: resume play */
5671 
5672 		if (!scsipt_do_pause_resume(devp, TRUE)) {
5673 			DO_BEEP();
5674 			return;
5675 		}
5676 		s->mode = MOD_PLAY;
5677 		DPY_PLAYMODE(s, FALSE);
5678 		scsipt_start_stat_poll(s);
5679 		break;
5680 
5681 	case MOD_STOP:
5682 		/* Currently stopped: start play */
5683 
5684 		if (!di_prepare_cdda(s))
5685 			return;
5686 
5687 		if (s->shuffle || s->program) {
5688 			scsipt_new_progshuf = TRUE;
5689 
5690 			/* Start shuffle/program play */
5691 			if (!scsipt_run_prog(s))
5692 				return;
5693 		}
5694 		else if (s->segplay == SEGP_AB) {
5695 			/* Play defined segment */
5696 			if (!scsipt_run_ab(s))
5697 				return;
5698 		}
5699 		else {
5700 			s->segplay = SEGP_NONE;	/* Cancel a->b mode */
5701 
5702 			/* Start normal play */
5703 			if ((i = di_curtrk_pos(s)) < 0 || s->cur_trk <= 0) {
5704 				/* Start play from the beginning */
5705 				i = 0;
5706 				s->cur_trk = s->first_trk;
5707 				start_addr = s->trkinfo[0].addr +
5708 					     s->curpos_trk.addr;
5709 				util_blktomsf(
5710 					start_addr,
5711 					&start_msf.min,
5712 					&start_msf.sec,
5713 					&start_msf.frame,
5714 					MSF_OFFSET
5715 				);
5716 			}
5717 			else {
5718 				/* User has specified a starting track */
5719 				start_addr = s->trkinfo[i].addr +
5720 					     s->curpos_trk.addr;
5721 			}
5722 
5723 			util_blktomsf(
5724 				start_addr,
5725 				&start_msf.min,
5726 				&start_msf.sec,
5727 				&start_msf.frame,
5728 				MSF_OFFSET
5729 			);
5730 
5731 			end_msf.min = s->discpos_tot.min;
5732 			end_msf.sec = s->discpos_tot.sec;
5733 			end_msf.frame = s->discpos_tot.frame;
5734 
5735 			if (s->trkinfo[i].type == TYP_DATA) {
5736 				DPY_TRACK(s);
5737 				DPY_TIME(s, FALSE);
5738 				DO_BEEP();
5739 				return;
5740 			}
5741 
5742 			s->cur_idx = 1;
5743 			s->mode = MOD_PLAY;
5744 
5745 			if (!scsipt_do_playaudio(devp, ADDR_BLK | ADDR_MSF,
5746 					  start_addr, s->discpos_tot.addr,
5747 					  &start_msf, &end_msf, 0, 0)) {
5748 				DO_BEEP();
5749 				s->mode = MOD_STOP;
5750 				return;
5751 			}
5752 		}
5753 
5754 		DPY_ALL(s);
5755 		scsipt_start_stat_poll(s);
5756 		break;
5757 
5758 	case MOD_SAMPLE:
5759 		/* Force update of curstat */
5760 		if (!scsipt_get_playstatus(s)) {
5761 			DO_BEEP();
5762 			return;
5763 		}
5764 
5765 		/* Currently doing a->b or sample playback: just resume play */
5766 		if (s->shuffle || s->program) {
5767 			if ((i = di_curtrk_pos(s)) < 0 ||
5768 			    s->trkinfo[i].trkno == LEAD_OUT_TRACK)
5769 				return;
5770 
5771 			start_msf.min = s->curpos_tot.min;
5772 			start_msf.sec = s->curpos_tot.sec;
5773 			start_msf.frame = s->curpos_tot.frame;
5774 			end_msf.min = s->trkinfo[i+1].min;
5775 			end_msf.sec = s->trkinfo[i+1].sec;
5776 			end_msf.frame = s->trkinfo[i+1].frame;
5777 
5778 			if (!scsipt_do_playaudio(devp, ADDR_BLK | ADDR_MSF,
5779 					  s->curpos_tot.addr,
5780 					  s->trkinfo[i+1].addr,
5781 					  &start_msf, &end_msf, 0, 0)) {
5782 				DO_BEEP();
5783 				return;
5784 			}
5785 		}
5786 		else {
5787 			start_msf.min = s->curpos_tot.min;
5788 			start_msf.sec = s->curpos_tot.sec;
5789 			start_msf.frame = s->curpos_tot.frame;
5790 			end_msf.min = s->discpos_tot.min;
5791 			end_msf.sec = s->discpos_tot.sec;
5792 			end_msf.frame = s->discpos_tot.frame;
5793 
5794 			if (!scsipt_do_playaudio(devp, ADDR_BLK | ADDR_MSF,
5795 					  s->curpos_tot.addr,
5796 					  s->discpos_tot.addr,
5797 					  &start_msf, &end_msf, 0, 0)) {
5798 				DO_BEEP();
5799 				return;
5800 			}
5801 		}
5802 		s->mode = MOD_PLAY;
5803 		DPY_PLAYMODE(s, FALSE);
5804 		break;
5805 
5806 	default:
5807 		DO_BEEP();
5808 		break;
5809 	}
5810 }
5811 
5812 
5813 /*
5814  * scsipt_stop
5815  *	Stop function
5816  *
5817  * Args:
5818  *	s - Pointer to the curstat_t structure
5819  *	stop_disc - Whether to actually spin down the disc or just
5820  *		update status.
5821  *
5822  * Return:
5823  *	Nothing.
5824  */
5825 void
scsipt_stop(curstat_t * s,bool_t stop_disc)5826 scsipt_stop(curstat_t *s, bool_t stop_disc)
5827 {
5828 	/* The stop_disc parameter will cause the disc to spin down.
5829 	 * This is usually set to TRUE, but can be FALSE if the caller
5830 	 * just wants to set the current state to stop but will
5831 	 * immediately go into play state again.  Not spinning down
5832 	 * the drive makes things a little faster...
5833 	 */
5834 	if (!scsipt_disc_ready(s))
5835 		return;
5836 
5837 	switch (s->mode) {
5838 	case MOD_PLAY:
5839 	case MOD_PAUSE:
5840 	case MOD_SAMPLE:
5841 	case MOD_STOP:
5842 		/* Currently playing or paused: stop */
5843 
5844 		if (stop_disc &&
5845 		    !scsipt_do_start_stop(devp, FALSE, FALSE, TRUE)) {
5846 			DO_BEEP();
5847 			return;
5848 		}
5849 		scsipt_stop_stat_poll();
5850 
5851 		di_reset_curstat(s, FALSE, FALSE);
5852 		s->mode = MOD_STOP;
5853 		s->rptcnt = 0;
5854 
5855 		DPY_ALL(s);
5856 		break;
5857 
5858 	default:
5859 		break;
5860 	}
5861 }
5862 
5863 
5864 /*
5865  * scsipt_chgdisc
5866  *	Change disc function
5867  *
5868  * Args:
5869  *	s - Pointer to the curstat_t structure
5870  *
5871  * Return:
5872  *	Nothing.
5873  */
5874 void
scsipt_chgdisc(curstat_t * s)5875 scsipt_chgdisc(curstat_t *s)
5876 {
5877 	int	i,
5878 		sav_rptcnt;
5879 	bool_t	nochg,
5880 		ret;
5881 
5882 	if (s->first_disc == s->last_disc) {
5883 		/* Single-CD drive: cannot change discs */
5884 		DO_BEEP();
5885 		return;
5886 	}
5887 
5888 	if (s->cur_disc < s->first_disc || s->cur_disc > s->last_disc) {
5889 		/* Bogus disc number */
5890 		s->cur_disc = s->first_disc;
5891 		return;
5892 	}
5893 
5894 	if (s->segplay != SEGP_NONE) {
5895 		s->segplay = SEGP_NONE;	/* Cancel a->b mode */
5896 		DPY_PROGMODE(s, FALSE);
5897 	}
5898 
5899 	/* Check target slot against medium map if applicable */
5900 	if (scsipt_medmap_valid && !scsipt_medmap[s->cur_disc-1]) {
5901 		nochg = FALSE;
5902 
5903 		if (app_data.multi_play) {
5904 			/* This requested disc slot is empty:
5905 			 * Go to the next loaded slot.
5906 			 */
5907 			nochg = TRUE;
5908 			if (app_data.reverse) {
5909 				while (s->cur_disc > s->first_disc) {
5910 					/* Try the previous loaded slot */
5911 					s->cur_disc--;
5912 					if (scsipt_medmap[s->cur_disc-1]) {
5913 						nochg = FALSE;
5914 						break;
5915 					}
5916 				}
5917 			}
5918 			else {
5919 				while (s->cur_disc < s->last_disc) {
5920 					/* Go to the next loaded slot */
5921 					s->cur_disc++;
5922 					if (scsipt_medmap[s->cur_disc-1]) {
5923 						nochg = FALSE;
5924 						break;
5925 					}
5926 				}
5927 			}
5928 		}
5929 		else
5930 			nochg = TRUE;
5931 
5932 		if (nochg)
5933 			/* Can't load from an empty slot */
5934 			return;
5935 
5936 		DPY_DISC(s);
5937 	}
5938 
5939 	/* If we're currently in normal playback mode, after we change
5940 	 * disc we want to automatically start playback.
5941 	 */
5942 	if ((s->mode == MOD_PLAY || s->mode == MOD_PAUSE) && !s->program)
5943 		scsipt_mult_autoplay = TRUE;
5944 
5945 	/* If we're currently paused, go to pause mode after disc change */
5946 	scsipt_mult_pause = (s->mode == MOD_PAUSE);
5947 
5948 	sav_rptcnt = s->rptcnt;
5949 
5950 	/* Stop the CD first */
5951 	scsipt_stop(s, TRUE);
5952 
5953 	/* Unlock caddy if supported */
5954 	if (app_data.caddylock_supp)
5955 		scsipt_lock(s, FALSE);
5956 
5957 	di_reset_curstat(s, TRUE, FALSE);
5958 	s->mode = MOD_NODISC;
5959 	di_clear_cdinfo(s, FALSE);
5960 
5961 	s->rptcnt = sav_rptcnt;
5962 
5963 	if (devp != NULL && app_data.eject_close) {
5964 		scsipt_close(devp);
5965 		devp = NULL;
5966 		scsipt_not_open = TRUE;
5967 	}
5968 
5969 	switch (app_data.chg_method) {
5970 	case CHG_SCSI_LUN:
5971 		/* SCSI LUN addressing method */
5972 
5973 		/* Set new device */
5974 		s->curdev = di_devlist[s->cur_disc - 1];
5975 
5976 		/* Load desired disc */
5977 		(void) scsipt_disc_ready(s);
5978 
5979 		break;
5980 
5981 	case CHG_SCSI_MEDCHG:
5982 		/* SCSI medium changer method */
5983 
5984 		/* Unload old disc */
5985 		if (s->prev_disc > 0) {
5986 			for (i = 0; i < 2; i++) {
5987 				ret = scsipt_move_medium(
5988 					chgp, DI_ROLE_MAIN,
5989 					scsipt_mcparm.mtbase,
5990 					scsipt_mcparm.dtbase,
5991 					(word16_t) (scsipt_mcparm.stbase +
5992 						    s->prev_disc - 1)
5993 				);
5994 
5995 				if (ret)
5996 					break;
5997 
5998 				if (scsipt_chg_ready(s))
5999 					(void) scsipt_chg_rdstatus();
6000 			}
6001 
6002 			s->prev_disc = -1;
6003 		}
6004 
6005 		/* Load desired disc */
6006 		(void) scsipt_disc_ready(s);
6007 
6008 		break;
6009 
6010 	default:
6011 		/* Do nothing */
6012 		break;
6013 	}
6014 }
6015 
6016 
6017 /*
6018  * scsipt_prevtrk
6019  *	Previous track function
6020  *
6021  * Args:
6022  *	s - Pointer to the curstat_t structure
6023  *
6024  * Return:
6025  *	Nothing.
6026  */
6027 void
scsipt_prevtrk(curstat_t * s)6028 scsipt_prevtrk(curstat_t *s)
6029 {
6030 	sword32_t	i,
6031 			start_addr;
6032 	msf_t		start_msf,
6033 			end_msf;
6034 	bool_t		go_prev;
6035 
6036 	if (!scsipt_disc_ready(s)) {
6037 		DO_BEEP();
6038 		return;
6039 	}
6040 
6041 	switch (s->mode) {
6042 	case MOD_SAMPLE:
6043 		s->mode = MOD_PLAY;
6044 		DPY_PLAYMODE(s, FALSE);
6045 		/*FALLTHROUGH*/
6046 	case MOD_PLAY:
6047 	case MOD_PAUSE:
6048 		/* Find appropriate track to start */
6049 		if (s->shuffle || s->program) {
6050 			if (s->prog_cnt > 0) {
6051 				s->prog_cnt--;
6052 				scsipt_new_progshuf = FALSE;
6053 			}
6054 			i = di_curprog_pos(s);
6055 		}
6056 		else
6057 			i = di_curtrk_pos(s);
6058 
6059 		if (s->segplay == SEGP_AB) {
6060 			s->segplay = SEGP_NONE;	/* Cancel a->b mode */
6061 			DPY_PROGMODE(s, FALSE);
6062 		}
6063 
6064 		go_prev = FALSE;
6065 
6066 		if (i == 0 && s->cur_idx == 0) {
6067 			i = 0;
6068 			start_addr = di_clip_frames;
6069 			util_blktomsf(
6070 				start_addr,
6071 				&start_msf.min,
6072 				&start_msf.sec,
6073 				&start_msf.frame,
6074 				MSF_OFFSET
6075 			);
6076 			s->cur_trk = s->trkinfo[i].trkno;
6077 			s->cur_idx = 0;
6078 		}
6079 		else {
6080 			start_addr = s->trkinfo[i].addr;
6081 			start_msf.min = s->trkinfo[i].min;
6082 			start_msf.sec = s->trkinfo[i].sec;
6083 			start_msf.frame = s->trkinfo[i].frame;
6084 			s->cur_trk = s->trkinfo[i].trkno;
6085 			s->cur_idx = 1;
6086 
6087 			/* If the current track has been playing for less
6088 			 * than app_data.prev_threshold blocks, then go
6089 			 * to the beginning of the previous track (if we
6090 			 * are not already on the first track).
6091 			 */
6092 			if ((s->curpos_tot.addr - start_addr) <=
6093 			    app_data.prev_threshold)
6094 				go_prev = TRUE;
6095 		}
6096 
6097 		if (go_prev) {
6098 			if (s->shuffle || s->program) {
6099 				if (s->prog_cnt > 0) {
6100 					s->prog_cnt--;
6101 					scsipt_new_progshuf = FALSE;
6102 				}
6103 				if ((i = di_curprog_pos(s)) < 0)
6104 					return;
6105 
6106 				start_addr = s->trkinfo[i].addr;
6107 				start_msf.min = s->trkinfo[i].min;
6108 				start_msf.sec = s->trkinfo[i].sec;
6109 				start_msf.frame = s->trkinfo[i].frame;
6110 				s->cur_trk = s->trkinfo[i].trkno;
6111 			}
6112 			else if (i == 0) {
6113 				/* Go to the very beginning: this may be
6114 				 * a lead-in area before the start of track 1.
6115 				 */
6116 				start_addr = di_clip_frames;
6117 				util_blktomsf(
6118 					start_addr,
6119 					&start_msf.min,
6120 					&start_msf.sec,
6121 					&start_msf.frame,
6122 					MSF_OFFSET
6123 				);
6124 				s->cur_trk = s->trkinfo[i].trkno;
6125 			}
6126 			else if (i > 0) {
6127 				i--;
6128 
6129 				/* Skip over data tracks */
6130 				while (s->trkinfo[i].type == TYP_DATA) {
6131 					if (i <= 0)
6132 						break;
6133 					i--;
6134 				}
6135 
6136 				if (s->trkinfo[i].type != TYP_DATA) {
6137 					start_addr = s->trkinfo[i].addr;
6138 					start_msf.min = s->trkinfo[i].min;
6139 					start_msf.sec = s->trkinfo[i].sec;
6140 					start_msf.frame = s->trkinfo[i].frame;
6141 					s->cur_trk = s->trkinfo[i].trkno;
6142 				}
6143 			}
6144 		}
6145 
6146 		if (s->mode == MOD_PAUSE)
6147 			/* Mute: so we don't get a transient */
6148 			scsipt_mute_on(s);
6149 
6150 		if (s->shuffle || s->program) {
6151 			/* Program/Shuffle mode: just stop the playback
6152 			 * and let scsipt_run_prog go to the previous track
6153 			 */
6154 			scsipt_fake_stop = TRUE;
6155 
6156 			/* Force status update */
6157 			(void) scsipt_get_playstatus(s);
6158 		}
6159 		else {
6160 			end_msf.min = s->discpos_tot.min;
6161 			end_msf.sec = s->discpos_tot.sec;
6162 			end_msf.frame = s->discpos_tot.frame;
6163 
6164 			s->curpos_tot.addr = start_addr;
6165 			s->curpos_tot.min = start_msf.min;
6166 			s->curpos_tot.sec = start_msf.sec;
6167 			s->curpos_tot.frame = start_msf.frame;
6168 			s->curpos_trk.addr = 0;
6169 			s->curpos_trk.min = 0;
6170 			s->curpos_trk.sec = 0;
6171 			s->curpos_trk.frame = 0;
6172 
6173 			DPY_TRACK(s);
6174 			DPY_INDEX(s);
6175 			DPY_TIME(s, FALSE);
6176 
6177 			if (!scsipt_do_playaudio(devp, ADDR_BLK | ADDR_MSF,
6178 					  start_addr, s->discpos_tot.addr,
6179 					  &start_msf, &end_msf, 0, 0)) {
6180 				DO_BEEP();
6181 
6182 				/* Restore volume */
6183 				scsipt_mute_off(s);
6184 				return;
6185 			}
6186 
6187 			if (s->mode == MOD_PAUSE) {
6188 				(void) scsipt_do_pause_resume(devp, FALSE);
6189 
6190 				/* Restore volume */
6191 				scsipt_mute_off(s);
6192 			}
6193 		}
6194 
6195 		break;
6196 
6197 	case MOD_STOP:
6198 		if (s->shuffle || s->program) {
6199 			/* Pre-selecting tracks not supported in shuffle
6200 			 * or program mode.
6201 			 */
6202 			DO_BEEP();
6203 			return;
6204 		}
6205 
6206 		/* Find previous track */
6207 		if (s->cur_trk <= 0) {
6208 			s->cur_trk = s->trkinfo[0].trkno;
6209 			DPY_TRACK(s);
6210 		}
6211 		else {
6212 			i = di_curtrk_pos(s);
6213 
6214 			if (i > 0) {
6215 				s->cur_trk = s->trkinfo[i-1].trkno;
6216 				DPY_TRACK(s);
6217 			}
6218 		}
6219 		break;
6220 
6221 	default:
6222 		DO_BEEP();
6223 		break;
6224 	}
6225 }
6226 
6227 
6228 /*
6229  * scsipt_nexttrk
6230  *	Next track function
6231  *
6232  * Args:
6233  *	s - Pointer to the curstat_t structure
6234  *
6235  * Return:
6236  *	Nothing.
6237  */
6238 void
scsipt_nexttrk(curstat_t * s)6239 scsipt_nexttrk(curstat_t *s)
6240 {
6241 	sword32_t	i,
6242 			start_addr;
6243 	msf_t		start_msf,
6244 			end_msf;
6245 
6246 	if (!scsipt_disc_ready(s)) {
6247 		DO_BEEP();
6248 		return;
6249 	}
6250 
6251 	switch (s->mode) {
6252 	case MOD_SAMPLE:
6253 		s->mode = MOD_PLAY;
6254 		DPY_PLAYMODE(s, FALSE);
6255 		/*FALLTHROUGH*/
6256 	case MOD_PLAY:
6257 	case MOD_PAUSE:
6258 		if (s->shuffle || s->program) {
6259 			if (s->prog_cnt >= s->prog_tot) {
6260 				/* Disallow advancing beyond current
6261 				 * shuffle/program sequence if
6262 				 * repeat mode is not on.
6263 				 */
6264 				if (s->repeat && !app_data.multi_play)
6265 					scsipt_new_progshuf = TRUE;
6266 				else
6267 					return;
6268 			}
6269 
6270 			if (s->mode == MOD_PAUSE)
6271 				/* Mute: so we don't get a transient */
6272 				scsipt_mute_on(s);
6273 
6274 			/* Program/Shuffle mode: just stop the playback
6275 			 * and let scsipt_run_prog go to the next track.
6276 			 */
6277 			scsipt_fake_stop = TRUE;
6278 
6279 			/* Force status update */
6280 			(void) scsipt_get_playstatus(s);
6281 
6282 			return;
6283 		}
6284 		else if (s->segplay == SEGP_AB) {
6285 			s->segplay = SEGP_NONE;	/* Cancel a->b mode */
6286 			DPY_PROGMODE(s, FALSE);
6287 		}
6288 
6289 		/* Find next track */
6290 		if ((i = di_curtrk_pos(s)) < 0)
6291 			return;
6292 
6293 		if (i > 0 || s->cur_idx > 0)
6294 			i++;
6295 
6296 		/* Skip over data tracks */
6297 		while (i < MAXTRACK && s->trkinfo[i].type == TYP_DATA)
6298 			i++;
6299 
6300 		if (i < MAXTRACK &&
6301 		    s->trkinfo[i].trkno >= 0 &&
6302 		    s->trkinfo[i].trkno != LEAD_OUT_TRACK) {
6303 
6304 			start_addr = s->trkinfo[i].addr;
6305 			start_msf.min = s->trkinfo[i].min;
6306 			start_msf.sec = s->trkinfo[i].sec;
6307 			start_msf.frame = s->trkinfo[i].frame;
6308 			s->cur_trk = s->trkinfo[i].trkno;
6309 			s->cur_idx = 1;
6310 
6311 			if (s->mode == MOD_PAUSE)
6312 				/* Mute: so we don't get a transient */
6313 				scsipt_mute_on(s);
6314 
6315 			end_msf.min = s->discpos_tot.min;
6316 			end_msf.sec = s->discpos_tot.sec;
6317 			end_msf.frame = s->discpos_tot.frame;
6318 
6319 			s->curpos_tot.addr = start_addr;
6320 			s->curpos_tot.min = start_msf.min;
6321 			s->curpos_tot.sec = start_msf.sec;
6322 			s->curpos_tot.frame = start_msf.frame;
6323 			s->curpos_trk.addr = 0;
6324 			s->curpos_trk.min = 0;
6325 			s->curpos_trk.sec = 0;
6326 			s->curpos_trk.frame = 0;
6327 
6328 			DPY_TRACK(s);
6329 			DPY_INDEX(s);
6330 			DPY_TIME(s, FALSE);
6331 
6332 			if (!scsipt_do_playaudio(devp, ADDR_BLK | ADDR_MSF,
6333 					  start_addr, s->discpos_tot.addr,
6334 					  &start_msf, &end_msf, 0, 0)) {
6335 				DO_BEEP();
6336 				return;
6337 			}
6338 
6339 			if (s->mode == MOD_PAUSE) {
6340 				(void) scsipt_do_pause_resume(devp, FALSE);
6341 
6342 				/* Restore volume */
6343 				scsipt_mute_off(s);
6344 			}
6345 		}
6346 
6347 		break;
6348 
6349 	case MOD_STOP:
6350 		if (s->shuffle || s->program) {
6351 			/* Pre-selecting tracks not supported in shuffle
6352 			 * or program mode.
6353 			 */
6354 			DO_BEEP();
6355 			return;
6356 		}
6357 
6358 		/* Find next track */
6359 		if (s->cur_trk <= 0) {
6360 			s->cur_trk = s->trkinfo[0].trkno;
6361 			DPY_TRACK(s);
6362 		}
6363 		else {
6364 			i = di_curtrk_pos(s) + 1;
6365 
6366 			if (i > 0 && s->trkinfo[i].trkno != LEAD_OUT_TRACK) {
6367 				s->cur_trk = s->trkinfo[i].trkno;
6368 				DPY_TRACK(s);
6369 			}
6370 		}
6371 		break;
6372 
6373 	default:
6374 		DO_BEEP();
6375 		break;
6376 	}
6377 }
6378 
6379 
6380 /*
6381  * scsipt_previdx
6382  *	Previous index function
6383  *
6384  * Args:
6385  *	s - Pointer to the curstat_t structure
6386  *
6387  * Return:
6388  *	Nothing.
6389  */
6390 void
scsipt_previdx(curstat_t * s)6391 scsipt_previdx(curstat_t *s)
6392 {
6393 	msf_t		start_msf,
6394 			end_msf;
6395 	byte_t		idx;
6396 
6397 	if (s->shuffle || s->program) {
6398 		/* Index search is not supported in program/shuffle mode */
6399 		DO_BEEP();
6400 		return;
6401 	}
6402 
6403 	switch (s->mode) {
6404 	case MOD_SAMPLE:
6405 		s->mode = MOD_PLAY;
6406 		DPY_PLAYMODE(s, FALSE);
6407 		/*FALLTHROUGH*/
6408 	case MOD_PLAY:
6409 	case MOD_PAUSE:
6410 		if (s->segplay == SEGP_AB) {
6411 			s->segplay = SEGP_NONE;	/* Cancel a->b mode */
6412 			DPY_PROGMODE(s, FALSE);
6413 		}
6414 
6415 		/* Find appropriate index to start */
6416 		if (s->cur_idx > 1 &&
6417 		    (s->curpos_tot.addr - s->sav_iaddr) <=
6418 			    app_data.prev_threshold)
6419 			idx = s->cur_idx - 1;
6420 		else
6421 			idx = s->cur_idx;
6422 
6423 		/* This is a Hack...
6424 		 * Since there is no standard SCSI-2 command to start
6425 		 * playback on an index boundary and then go on playing
6426 		 * until the end of the disc, we will use the PLAY AUDIO
6427 		 * TRACK/INDEX command to go to where we want to start,
6428 		 * immediately followed by a PAUSE.  We then find the
6429 		 * current block position and issue a PLAY AUDIO MSF
6430 		 * or PLAY AUDIO(12) command to start play there.
6431 		 * We mute the audio in between these operations to
6432 		 * prevent unpleasant transients.
6433 		 */
6434 
6435 		/* Mute */
6436 		scsipt_mute_on(s);
6437 
6438 		if (!scsipt_do_playaudio(devp, ADDR_TRKIDX, 0, 0, NULL, NULL,
6439 				  (byte_t) s->cur_trk, idx)) {
6440 			/* Restore volume */
6441 			scsipt_mute_off(s);
6442 			DO_BEEP();
6443 			return;
6444 		}
6445 
6446 		/* A small delay to make sure the command took effect */
6447 		util_delayms(10);
6448 
6449 		scsipt_idx_pause = TRUE;
6450 
6451 		if (!scsipt_do_pause_resume(devp, FALSE)) {
6452 			/* Restore volume */
6453 			scsipt_mute_off(s);
6454 			scsipt_idx_pause = FALSE;
6455 			return;
6456 		}
6457 
6458 		/* Use scsipt_get_playstatus to update the current status */
6459 		if (!scsipt_get_playstatus(s)) {
6460 			/* Restore volume */
6461 			scsipt_mute_off(s);
6462 			scsipt_idx_pause = FALSE;
6463 			return;
6464 		}
6465 
6466 		/* Save starting block addr of this index */
6467 		s->sav_iaddr = s->curpos_tot.addr;
6468 
6469 		if (s->mode != MOD_PAUSE)
6470 			/* Restore volume */
6471 			scsipt_mute_off(s);
6472 
6473 		start_msf.min = s->curpos_tot.min;
6474 		start_msf.sec = s->curpos_tot.sec;
6475 		start_msf.frame = s->curpos_tot.frame;
6476 		end_msf.min = s->discpos_tot.min;
6477 		end_msf.sec = s->discpos_tot.sec;
6478 		end_msf.frame = s->discpos_tot.frame;
6479 
6480 		if (!scsipt_do_playaudio(devp, ADDR_BLK | ADDR_MSF,
6481 				  s->curpos_tot.addr, s->discpos_tot.addr,
6482 				  &start_msf, &end_msf, 0, 0)) {
6483 			DO_BEEP();
6484 			scsipt_idx_pause = FALSE;
6485 			return;
6486 		}
6487 
6488 		scsipt_idx_pause = FALSE;
6489 
6490 		if (s->mode == MOD_PAUSE) {
6491 			(void) scsipt_do_pause_resume(devp, FALSE);
6492 
6493 			/* Restore volume */
6494 			scsipt_mute_off(s);
6495 
6496 			/* Force update of curstat */
6497 			(void) scsipt_get_playstatus(s);
6498 		}
6499 
6500 		break;
6501 
6502 	default:
6503 		DO_BEEP();
6504 		break;
6505 	}
6506 }
6507 
6508 
6509 /*
6510  * scsipt_nextidx
6511  *	Next index function
6512  *
6513  * Args:
6514  *	s - Pointer to the curstat_t structure
6515  *
6516  * Return:
6517  *	Nothing.
6518  */
6519 void
scsipt_nextidx(curstat_t * s)6520 scsipt_nextidx(curstat_t *s)
6521 {
6522 	msf_t		start_msf,
6523 			end_msf;
6524 
6525 	if (s->shuffle || s->program) {
6526 		/* Index search is not supported in program/shuffle mode */
6527 		DO_BEEP();
6528 		return;
6529 	}
6530 
6531 	switch (s->mode) {
6532 	case MOD_SAMPLE:
6533 		s->mode = MOD_PLAY;
6534 		DPY_PLAYMODE(s, FALSE);
6535 		/*FALLTHROUGH*/
6536 	case MOD_PLAY:
6537 	case MOD_PAUSE:
6538 		if (s->segplay == SEGP_AB) {
6539 			s->segplay = SEGP_NONE;	/* Cancel a->b mode */
6540 			DPY_PROGMODE(s, FALSE);
6541 		}
6542 
6543 		/* Find appropriate index to start */
6544 
6545 		/* This is a Hack...
6546 		 * Since there is no standard SCSI-2 command to start
6547 		 * playback on an index boundary and then go on playing
6548 		 * until the end of the disc, we will use the PLAY AUDIO
6549 		 * TRACK/INDEX command to go to where we want to start,
6550 		 * immediately followed by a PAUSE.  We then find the
6551 		 * current block position and issue a PLAY AUDIO MSF
6552 		 * or PLAY AUDIO(12) command to start play there.
6553 		 * We mute the audio in between these operations to
6554 		 * prevent unpleasant transients.
6555 		 */
6556 
6557 		/* Mute */
6558 		scsipt_mute_on(s);
6559 
6560 		if (!scsipt_do_playaudio(devp, ADDR_TRKIDX, 0, 0, NULL, NULL,
6561 				  (byte_t) s->cur_trk,
6562 				  (byte_t) (s->cur_idx + 1))) {
6563 			/* Restore volume */
6564 			scsipt_mute_off(s);
6565 			DO_BEEP();
6566 			return;
6567 		}
6568 
6569 		/* A small delay to make sure the command took effect */
6570 		util_delayms(10);
6571 
6572 		scsipt_idx_pause = TRUE;
6573 
6574 		if (!scsipt_do_pause_resume(devp, FALSE)) {
6575 			/* Restore volume */
6576 			scsipt_mute_off(s);
6577 			scsipt_idx_pause = FALSE;
6578 			return;
6579 		}
6580 
6581 		/* Use scsipt_get_playstatus to update the current status */
6582 		if (!scsipt_get_playstatus(s)) {
6583 			/* Restore volume */
6584 			scsipt_mute_off(s);
6585 			scsipt_idx_pause = FALSE;
6586 			return;
6587 		}
6588 
6589 		/* Save starting block addr of this index */
6590 		s->sav_iaddr = s->curpos_tot.addr;
6591 
6592 		if (s->mode != MOD_PAUSE)
6593 			/* Restore volume */
6594 			scsipt_mute_off(s);
6595 
6596 		start_msf.min = s->curpos_tot.min;
6597 		start_msf.sec = s->curpos_tot.sec;
6598 		start_msf.frame = s->curpos_tot.frame;
6599 		end_msf.min = s->discpos_tot.min;
6600 		end_msf.sec = s->discpos_tot.sec;
6601 		end_msf.frame = s->discpos_tot.frame;
6602 
6603 		if (!scsipt_do_playaudio(devp, ADDR_BLK | ADDR_MSF,
6604 				  s->curpos_tot.addr, s->discpos_tot.addr,
6605 				  &start_msf, &end_msf, 0, 0)) {
6606 			DO_BEEP();
6607 			scsipt_idx_pause = FALSE;
6608 			return;
6609 		}
6610 
6611 		scsipt_idx_pause = FALSE;
6612 
6613 		if (s->mode == MOD_PAUSE) {
6614 			(void) scsipt_do_pause_resume(devp, FALSE);
6615 
6616 			/* Restore volume */
6617 			scsipt_mute_off(s);
6618 
6619 			/* Force update of curstat */
6620 			(void) scsipt_get_playstatus(s);
6621 		}
6622 
6623 		break;
6624 
6625 	default:
6626 		DO_BEEP();
6627 		break;
6628 	}
6629 }
6630 
6631 
6632 /*
6633  * scsipt_rew
6634  *	Search-rewind function
6635  *
6636  * Args:
6637  *	s - Pointer to the curstat_t structure
6638  *
6639  * Return:
6640  *	Nothing.
6641  */
6642 void
scsipt_rew(curstat_t * s,bool_t start)6643 scsipt_rew(curstat_t *s, bool_t start)
6644 {
6645 	sword32_t	i;
6646 	msf_t		start_msf,
6647 			end_msf;
6648 	byte_t		vol;
6649 
6650 	switch (s->mode) {
6651 	case MOD_SAMPLE:
6652 		/* Go to normal play mode first */
6653 		scsipt_play_pause(s);
6654 
6655 		/*FALLTHROUGH*/
6656 	case MOD_PLAY:
6657 	case MOD_PAUSE:
6658 		if (start) {
6659 			/* Button press */
6660 
6661 			if (s->mode == MOD_PLAY)
6662 				scsipt_stop_stat_poll();
6663 
6664 			if (PLAYMODE_IS_STD(app_data.play_mode)) {
6665 				/* Reduce volume */
6666 				vol = (byte_t) ((int) s->level *
6667 					app_data.skip_vol / 100);
6668 
6669 				(void) scsipt_cfg_vol((int)
6670 					((vol < (byte_t)app_data.skip_minvol) ?
6671 					 (byte_t) app_data.skip_minvol : vol),
6672 					s,
6673 					FALSE,
6674 					FALSE
6675 				);
6676 			}
6677 
6678 			/* Start search rewind */
6679 			scsipt_start_search = TRUE;
6680 			scsipt_run_rew(s);
6681 		}
6682 		else {
6683 			/* Button release */
6684 
6685 			scsipt_stop_rew(s);
6686 
6687 			/* Update display */
6688 			(void) scsipt_get_playstatus(s);
6689 
6690 			if (s->mode == MOD_PAUSE)
6691 				/* Mute: so we don't get a transient */
6692 				scsipt_mute_on(s);
6693 			else
6694 				/* Restore volume */
6695 				scsipt_mute_off(s);
6696 
6697 			if (s->shuffle || s->program) {
6698 				if ((i = di_curtrk_pos(s)) < 0 ||
6699 				    s->trkinfo[i].trkno == LEAD_OUT_TRACK) {
6700 					/* Restore volume */
6701 					scsipt_mute_off(s);
6702 					return;
6703 				}
6704 
6705 				start_msf.min = s->curpos_tot.min;
6706 				start_msf.sec = s->curpos_tot.sec;
6707 				start_msf.frame = s->curpos_tot.frame;
6708 				end_msf.min = s->trkinfo[i+1].min;
6709 				end_msf.sec = s->trkinfo[i+1].sec;
6710 				end_msf.frame = s->trkinfo[i+1].frame;
6711 
6712 				if (!scsipt_do_playaudio(devp,
6713 						ADDR_BLK | ADDR_MSF,
6714 						s->curpos_tot.addr,
6715 						s->trkinfo[i+1].addr,
6716 						&start_msf, &end_msf,
6717 						0, 0)) {
6718 					DO_BEEP();
6719 
6720 					/* Restore volume */
6721 					scsipt_mute_off(s);
6722 					return;
6723 				}
6724 			}
6725 			else {
6726 				start_msf.min = s->curpos_tot.min;
6727 				start_msf.sec = s->curpos_tot.sec;
6728 				start_msf.frame = s->curpos_tot.frame;
6729 				end_msf.min = s->discpos_tot.min;
6730 				end_msf.sec = s->discpos_tot.sec;
6731 				end_msf.frame = s->discpos_tot.frame;
6732 
6733 				if (!scsipt_do_playaudio(devp,
6734 						ADDR_BLK | ADDR_MSF,
6735 						s->curpos_tot.addr,
6736 						s->discpos_tot.addr,
6737 						&start_msf, &end_msf,
6738 						0, 0)) {
6739 					DO_BEEP();
6740 
6741 					/* Restore volume */
6742 					scsipt_mute_off(s);
6743 					return;
6744 				}
6745 			}
6746 
6747 			if (s->mode == MOD_PAUSE) {
6748 				(void) scsipt_do_pause_resume(devp, FALSE);
6749 
6750 				/* Restore volume */
6751 				scsipt_mute_off(s);
6752 			}
6753 			else
6754 				scsipt_start_stat_poll(s);
6755 		}
6756 		break;
6757 
6758 	default:
6759 		if (start)
6760 			DO_BEEP();
6761 		break;
6762 	}
6763 }
6764 
6765 
6766 /*
6767  * scsipt_ff
6768  *	Search-fast-forward function
6769  *
6770  * Args:
6771  *	s - Pointer to the curstat_t structure
6772  *
6773  * Return:
6774  *	Nothing.
6775  */
6776 void
scsipt_ff(curstat_t * s,bool_t start)6777 scsipt_ff(curstat_t *s, bool_t start)
6778 {
6779 	sword32_t	i,
6780 			start_addr,
6781 			end_addr;
6782 	msf_t		start_msf,
6783 			end_msf;
6784 	byte_t		vol;
6785 
6786 	switch (s->mode) {
6787 	case MOD_SAMPLE:
6788 		/* Go to normal play mode first */
6789 		scsipt_play_pause(s);
6790 
6791 		/*FALLTHROUGH*/
6792 	case MOD_PLAY:
6793 	case MOD_PAUSE:
6794 		if (start) {
6795 			/* Button press */
6796 
6797 			if (s->mode == MOD_PLAY)
6798 				scsipt_stop_stat_poll();
6799 
6800 			if (PLAYMODE_IS_STD(app_data.play_mode)) {
6801 				/* Reduce volume */
6802 				vol = (byte_t) ((int) s->level *
6803 					app_data.skip_vol / 100);
6804 
6805 				(void) scsipt_cfg_vol((int)
6806 					((vol < (byte_t)app_data.skip_minvol) ?
6807 					 (byte_t) app_data.skip_minvol : vol),
6808 					s,
6809 					FALSE,
6810 					FALSE
6811 				);
6812 			}
6813 
6814 			/* Start search forward */
6815 			scsipt_start_search = TRUE;
6816 			scsipt_run_ff(s);
6817 		}
6818 		else {
6819 			/* Button release */
6820 
6821 			scsipt_stop_ff(s);
6822 
6823 			/* Update display */
6824 			(void) scsipt_get_playstatus(s);
6825 
6826 			if (s->mode == MOD_PAUSE)
6827 				/* Mute: so we don't get a transient */
6828 				scsipt_mute_on(s);
6829 			else
6830 				/* Restore volume */
6831 				scsipt_mute_off(s);
6832 
6833 			if (s->shuffle || s->program) {
6834 				if ((i = di_curtrk_pos(s)) < 0 ||
6835 				    s->trkinfo[i].trkno == LEAD_OUT_TRACK) {
6836 					/* Restore volume */
6837 					scsipt_mute_off(s);
6838 					return;
6839 				}
6840 
6841 				start_addr = s->curpos_tot.addr;
6842 				start_msf.min = s->curpos_tot.min;
6843 				start_msf.sec = s->curpos_tot.sec;
6844 				start_msf.frame = s->curpos_tot.frame;
6845 				end_addr = s->trkinfo[i+1].addr;
6846 				end_msf.min = s->trkinfo[i+1].min;
6847 				end_msf.sec = s->trkinfo[i+1].sec;
6848 				end_msf.frame = s->trkinfo[i+1].frame;
6849 
6850 				if (!scsipt_do_playaudio(devp,
6851 						ADDR_BLK | ADDR_MSF,
6852 						start_addr, end_addr,
6853 						&start_msf, &end_msf,
6854 						0, 0)) {
6855 					DO_BEEP();
6856 
6857 					/* Restore volume */
6858 					scsipt_mute_off(s);
6859 					return;
6860 				}
6861 			}
6862 			else if (s->segplay == SEGP_AB &&
6863 				 (s->curpos_tot.addr + app_data.min_playblks) >
6864 					s->bp_endpos_tot.addr) {
6865 				/* No more left to play */
6866 				/* Restore volume */
6867 				scsipt_mute_off(s);
6868 				return;
6869 			}
6870 			else {
6871 				start_addr = s->curpos_tot.addr;
6872 				start_msf.min = s->curpos_tot.min;
6873 				start_msf.sec = s->curpos_tot.sec;
6874 				start_msf.frame = s->curpos_tot.frame;
6875 
6876 				if (s->segplay == SEGP_AB) {
6877 					end_addr = s->bp_endpos_tot.addr;
6878 					end_msf.min = s->bp_endpos_tot.min;
6879 					end_msf.sec = s->bp_endpos_tot.sec;
6880 					end_msf.frame = s->bp_endpos_tot.frame;
6881 				}
6882 				else {
6883 					end_addr = s->discpos_tot.addr;
6884 					end_msf.min = s->discpos_tot.min;
6885 					end_msf.sec = s->discpos_tot.sec;
6886 					end_msf.frame = s->discpos_tot.frame;
6887 				}
6888 
6889 				if (!scsipt_do_playaudio(devp,
6890 						ADDR_BLK | ADDR_MSF,
6891 						start_addr, end_addr,
6892 						&start_msf, &end_msf,
6893 						0, 0)) {
6894 					DO_BEEP();
6895 
6896 					/* Restore volume */
6897 					scsipt_mute_off(s);
6898 					return;
6899 				}
6900 			}
6901 			if (s->mode == MOD_PAUSE) {
6902 				(void) scsipt_do_pause_resume(devp, FALSE);
6903 
6904 				/* Restore volume */
6905 				scsipt_mute_off(s);
6906 			}
6907 			else
6908 				scsipt_start_stat_poll(s);
6909 		}
6910 		break;
6911 
6912 	default:
6913 		if (start)
6914 			DO_BEEP();
6915 		break;
6916 	}
6917 }
6918 
6919 
6920 /*
6921  * scsipt_warp
6922  *	Track warp function
6923  *
6924  * Args:
6925  *	s - Pointer to the curstat_t structure
6926  *
6927  * Return:
6928  *	Nothing.
6929  */
6930 void
scsipt_warp(curstat_t * s)6931 scsipt_warp(curstat_t *s)
6932 {
6933 	sword32_t	start_addr,
6934 			end_addr;
6935 	msf_t		start_msf,
6936 			end_msf;
6937 	int		i;
6938 
6939 	start_addr = s->curpos_tot.addr;
6940 	start_msf.min = s->curpos_tot.min;
6941 	start_msf.sec = s->curpos_tot.sec;
6942 	start_msf.frame = s->curpos_tot.frame;
6943 
6944 	switch (s->mode) {
6945 	case MOD_SAMPLE:
6946 		/* Go to normal play mode first */
6947 		scsipt_play_pause(s);
6948 
6949 		/*FALLTHROUGH*/
6950 	case MOD_PLAY:
6951 	case MOD_PAUSE:
6952 		if (s->shuffle || s->program) {
6953 			if ((i = di_curtrk_pos(s)) < 0) {
6954 				DO_BEEP();
6955 				return;
6956 			}
6957 
6958 			end_addr = s->trkinfo[i+1].addr;
6959 			end_msf.min = s->trkinfo[i+1].min;
6960 			end_msf.sec = s->trkinfo[i+1].sec;
6961 			end_msf.frame = s->trkinfo[i+1].frame;
6962 		}
6963 		else {
6964 			end_addr = s->discpos_tot.addr;
6965 			end_msf.min = s->discpos_tot.min;
6966 			end_msf.sec = s->discpos_tot.sec;
6967 			end_msf.frame = s->discpos_tot.frame;
6968 		}
6969 
6970 		if (s->segplay == SEGP_AB) {
6971 			if (start_addr < s->bp_startpos_tot.addr) {
6972 				start_addr = s->bp_startpos_tot.addr;
6973 				start_msf.min = s->bp_startpos_tot.min;
6974 				start_msf.sec = s->bp_startpos_tot.sec;
6975 				start_msf.frame = s->bp_startpos_tot.frame;
6976 			}
6977 
6978 			if (end_addr > s->bp_endpos_tot.addr) {
6979 				end_addr = s->bp_endpos_tot.addr;
6980 				end_msf.min = s->bp_endpos_tot.min;
6981 				end_msf.sec = s->bp_endpos_tot.sec;
6982 				end_msf.frame = s->bp_endpos_tot.frame;
6983 			}
6984 		}
6985 
6986 		if ((end_addr - app_data.min_playblks) < start_addr) {
6987 			/* No more left to play: just stop */
6988 			if (!scsipt_do_start_stop(devp, FALSE, FALSE, TRUE))
6989 				DO_BEEP();
6990 		}
6991 		else {
6992 			if (s->mode == MOD_PAUSE)
6993 				/* Mute: so we don't get a transient */
6994 				scsipt_mute_on(s);
6995 
6996 			if (!scsipt_do_playaudio(devp,
6997 						 ADDR_BLK | ADDR_MSF,
6998 						 start_addr, end_addr,
6999 						 &start_msf, &end_msf,
7000 						 0, 0)) {
7001 				DO_BEEP();
7002 
7003 				/* Restore volume */
7004 				scsipt_mute_off(s);
7005 				return;
7006 			}
7007 
7008 			if (s->mode == MOD_PAUSE) {
7009 				(void) scsipt_do_pause_resume(devp, FALSE);
7010 
7011 				/* Restore volume */
7012 				scsipt_mute_off(s);
7013 			}
7014 		}
7015 		break;
7016 
7017 	default:
7018 		break;
7019 	}
7020 }
7021 
7022 
7023 /*
7024  * scsipt_route
7025  *	Channel routing function
7026  *
7027  * Args:
7028  *	s - Pointer to the curstat_t structure
7029  *
7030  * Return:
7031  *	Nothing.
7032  */
7033 void
scsipt_route(curstat_t * s)7034 scsipt_route(curstat_t *s)
7035 {
7036 	byte_t	val0,
7037 		val1;
7038 
7039 	if (!app_data.chroute_supp)
7040 		return;
7041 
7042 	if (PLAYMODE_IS_CDDA(app_data.play_mode)) {
7043 		(void) cdda_chroute(devp, s);
7044 		return;
7045 	}
7046 
7047 	if (scsipt_vutbl[app_data.vendor_code].route != NULL) {
7048 		(void) scsipt_vutbl[app_data.vendor_code].route(s);
7049 		return;
7050 	}
7051 
7052 	val0 = scsipt_route_val(app_data.ch_route, 0);
7053 	val1 = scsipt_route_val(app_data.ch_route, 1);
7054 
7055 	if (val0 == scsipt_route_left && val1 == scsipt_route_right)
7056 		/* No change: just return */
7057 		return;
7058 
7059 	scsipt_route_left = val0;
7060 	scsipt_route_right = val1;
7061 
7062 	/* With SCSI-2, channel routing is done with the volume control */
7063 	(void) scsipt_cfg_vol(s->level, s, FALSE, TRUE);
7064 }
7065 
7066 
7067 /*
7068  * scsipt_mute_on
7069  *	Mute audio function
7070  *
7071  * Args:
7072  *	s - Pointer to the curstat_t structure
7073  *
7074  * Return:
7075  *	Nothing.
7076  */
7077 void
scsipt_mute_on(curstat_t * s)7078 scsipt_mute_on(curstat_t *s)
7079 {
7080 	(void) scsipt_cfg_vol(0, s, FALSE, FALSE);
7081 }
7082 
7083 
7084 /*
7085  * scsipt_mute_off
7086  *	Un-mute audio function
7087  *
7088  * Args:
7089  *	s - Pointer to the curstat_t structure
7090  *
7091  * Return:
7092  *	Nothing.
7093  */
7094 void
scsipt_mute_off(curstat_t * s)7095 scsipt_mute_off(curstat_t *s)
7096 {
7097 	(void) scsipt_cfg_vol((int) s->level, s, FALSE, FALSE);
7098 }
7099 
7100 
7101 /*
7102  * scsipt_cddajitter
7103  *	CDDA jitter correction setting change notification function
7104  *
7105  * Args:
7106  *	s - Pointer to the curstat_t structure
7107  *
7108  * Return:
7109  *	Nothing.
7110  */
7111 void
scsipt_cddajitter(curstat_t * s)7112 scsipt_cddajitter(curstat_t *s)
7113 {
7114 	sword32_t	curblk = 0;
7115 	byte_t		omode;
7116 
7117 	if (PLAYMODE_IS_CDDA(app_data.play_mode)) {
7118 		omode = s->mode;
7119 		if (omode == MOD_PAUSE)
7120 			omode = MOD_PLAY;
7121 
7122 		/* Save state */
7123 		switch (omode) {
7124 		case MOD_PLAY:
7125 		case MOD_SAMPLE:
7126 			curblk = s->curpos_tot.addr;
7127 			scsipt_stop_stat_poll();
7128 			break;
7129 
7130 		default:
7131 			break;
7132 		}
7133 
7134 		/* Restart CDDA */
7135 		cdda_halt(devp, s);
7136 		util_delayms(1000);
7137 
7138 		scsipt_cdda_client.curstat_addr = di_clinfo->curstat_addr;
7139 		scsipt_cdda_client.fatal_msg = di_clinfo->fatal_msg;
7140 		scsipt_cdda_client.warning_msg = di_clinfo->warning_msg;
7141 		scsipt_cdda_client.info_msg = di_clinfo->info_msg;
7142 		scsipt_cdda_client.info2_msg = di_clinfo->info2_msg;
7143 
7144 		(void) cdda_init(s, &scsipt_cdda_client);
7145 
7146 		/* Restore old state */
7147 		switch (omode) {
7148 		case MOD_PLAY:
7149 		case MOD_SAMPLE:
7150 			if (scsipt_play_recov(curblk, FALSE))
7151 				scsipt_start_stat_poll(s);
7152 			break;
7153 
7154 		default:
7155 			break;
7156 		}
7157 
7158 		s->mode = omode;
7159 	}
7160 }
7161 
7162 
7163 /*
7164  * scsipt_debug
7165  *	Debug level change notification function
7166  *
7167  * Args:
7168  *	None.
7169  *
7170  * Return:
7171  *	Nothing.
7172  */
7173 void
scsipt_debug(void)7174 scsipt_debug(void)
7175 {
7176 	if (PLAYMODE_IS_CDDA(app_data.play_mode))
7177 		cdda_debug(app_data.debug);
7178 }
7179 
7180 
7181 /*
7182  * scsipt_start
7183  *	Start the SCSI pass-through module.
7184  *
7185  * Args:
7186  *	s - Pointer to the curstat_t structure
7187  *
7188  * Return:
7189  *	Nothing.
7190  */
7191 void
scsipt_start(curstat_t * s)7192 scsipt_start(curstat_t *s)
7193 {
7194 	/* Check to see if disc is ready */
7195 	if (di_clinfo->timeout != NULL)
7196 		scsipt_start_insert_poll(s);
7197 	else
7198 		(void) scsipt_disc_ready(s);
7199 
7200 	/* Update display */
7201 	DPY_ALL(s);
7202 }
7203 
7204 
7205 /*
7206  * scsipt_icon
7207  *	Handler for main window iconification/de-iconification
7208  *
7209  * Args:
7210  *	s - Pointer to the curstat_t structure
7211  *	iconified - Whether the main window is iconified
7212  *
7213  * Return:
7214  *	Nothing.
7215  */
7216 void
scsipt_icon(curstat_t * s,bool_t iconified)7217 scsipt_icon(curstat_t *s, bool_t iconified)
7218 {
7219 	/* This function attempts to reduce the status polling frequency
7220 	 * when possible to cut down on CPU and SCSI bus usage.  This is
7221 	 * done when the CD player is iconified.
7222 	 */
7223 
7224 	/* Increase status polling interval by 4 seconds when iconified */
7225 	if (iconified)
7226 		scsipt_stat_interval = app_data.stat_interval + 4000;
7227 	else
7228 		scsipt_stat_interval = app_data.stat_interval;
7229 
7230 	switch (s->mode) {
7231 	case MOD_BUSY:
7232 	case MOD_NODISC:
7233 	case MOD_STOP:
7234 	case MOD_PAUSE:
7235 		break;
7236 
7237 	case MOD_SAMPLE:
7238 		/* No optimization in these modes */
7239 		scsipt_stat_interval = app_data.stat_interval;
7240 		break;
7241 
7242 	case MOD_PLAY:
7243 		if (!iconified) {
7244 			/* Force an immediate update */
7245 			scsipt_stop_stat_poll();
7246 			scsipt_start_stat_poll(s);
7247 		}
7248 		break;
7249 
7250 	default:
7251 		break;
7252 	}
7253 }
7254 
7255 
7256 /*
7257  * scsipt_halt
7258  *	Shut down the SCSI pass-through and vendor-unique modules.
7259  *
7260  * Args:
7261  *	s - Pointer to the curstat_t structure
7262  *
7263  * Return:
7264  *	Nothing.
7265  */
7266 void
scsipt_halt(curstat_t * s)7267 scsipt_halt(curstat_t *s)
7268 {
7269 	int	i;
7270 
7271 	/* If playing CDDA, stop it */
7272 	if (PLAYMODE_IS_CDDA(app_data.play_mode)) {
7273 		switch (s->mode) {
7274 		case MOD_PLAY:
7275 		case MOD_PAUSE:
7276 		case MOD_SAMPLE:
7277 			(void) scsipt_do_start_stop(devp, FALSE, FALSE, TRUE);
7278 			s->mode = MOD_STOP;
7279 			scsipt_stop_stat_poll();
7280 			break;
7281 		default:
7282 			break;
7283 		}
7284 	}
7285 
7286 	/* Shut down CDDA */
7287 	cdda_halt(devp, s);
7288 	app_data.play_mode = PLAYMODE_STD;
7289 
7290 	/* Re-enable front-panel eject button */
7291 	if (app_data.caddylock_supp)
7292 		scsipt_lock(s, FALSE);
7293 
7294 	if (s->mode != MOD_BUSY && s->mode != MOD_NODISC) {
7295 		if (app_data.exit_eject && app_data.eject_supp) {
7296 			/* User closing application: Eject disc */
7297 			(void) scsipt_do_start_stop(devp, FALSE, TRUE, TRUE);
7298 		}
7299 		else {
7300 			if (app_data.exit_stop)
7301 				/* User closing application: Stop disc */
7302 				(void) scsipt_do_start_stop(devp, FALSE,
7303 							    FALSE, TRUE);
7304 
7305 			switch (s->mode) {
7306 			case MOD_PLAY:
7307 			case MOD_PAUSE:
7308 			case MOD_SAMPLE:
7309 				scsipt_stop_stat_poll();
7310 				break;
7311 			default:
7312 				break;
7313 			}
7314 		}
7315 	}
7316 
7317 	/* Shut down the vendor unique modules */
7318 	for (i = 0; i < MAX_VENDORS; i++) {
7319 		if (scsipt_vutbl[i].halt != NULL)
7320 			scsipt_vutbl[i].halt();
7321 	}
7322 
7323 	/* Close CD device */
7324 	if (devp != NULL) {
7325 		scsipt_close(devp);
7326 		devp = NULL;
7327 		scsipt_not_open = TRUE;
7328 	}
7329 
7330 	/* Shut down multi-disc changer */
7331 	if (app_data.numdiscs > 1)
7332 		scsipt_chg_halt(s);
7333 }
7334 
7335 
7336 /*
7337  * scsipt_methodstr
7338  *	Return a text string indicating the SCSI pass-through module's
7339  *	version number and which SCSI-1 vendor-unique modes are
7340  *	supported in this binary.
7341  *
7342  * Args:
7343  *	Nothing.
7344  *
7345  * Return:
7346  *	Version text string.
7347  */
7348 char *
scsipt_methodstr(void)7349 scsipt_methodstr(void)
7350 {
7351 	static char	str[STR_BUF_SZ * 4];
7352 
7353 	(void) sprintf(str,
7354 		   "SCSI pass-through\n    %s\n    %s%s interface\n",
7355 		   pthru_vers(),
7356 		   scsipt_vutbl[app_data.vendor_code].vendor == NULL ?
7357 		       "Unknown" :
7358 		       scsipt_vutbl[app_data.vendor_code].vendor,
7359 		   app_data.vendor_code == VENDOR_SCSI2 ?
7360 		       "" : " vendor unique");
7361 
7362 	return (str);
7363 }
7364 
7365 #endif	/* DI_SCSIPT */
7366 
7367