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