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
22 /*
23 * FreeBSD/NetBSD/OpenBSD ioctl method module
24 *
25 * Contributing author: Gennady B. Sorokopud
26 * E-mail: gena@NetVision.net.il
27 *
28 * Older NetBSD systems may need -DNETBSD_OLDIOC to compile.
29 */
30
31 #ifndef lint
32 static char *_fbioc_c_ident_ = "@(#)fbioc.c 6.199 04/04/08";
33 #endif
34
35 #include "common_d/appenv.h"
36 #include "common_d/util.h"
37 #include "libdi_d/libdi.h"
38 #include "libdi_d/fbioc.h"
39 #include "cdda_d/cdda.h"
40
41 #if defined(DI_FBIOC) && !defined(DEMO_ONLY)
42
43 extern appdata_t app_data;
44 extern FILE *errfp;
45 extern di_client_t *di_clinfo;
46 extern sword32_t di_clip_frames;
47
48
49 STATIC bool_t fbioc_pause_resume(bool_t),
50 fbioc_run_ab(curstat_t *),
51 fbioc_run_sample(curstat_t *),
52 fbioc_run_prog(curstat_t *),
53 fbioc_run_repeat(curstat_t *),
54 fbioc_disc_ready(curstat_t *),
55 fbioc_disc_present(bool_t);
56 STATIC int fbioc_cfg_vol(int, curstat_t *, bool_t);
57 STATIC void fbioc_stat_poll(curstat_t *),
58 fbioc_insert_poll(curstat_t *);
59
60
61 STATIC di_dev_t *fbioc_devp = NULL; /* CD device descriptor */
62 STATIC int fbioc_stat_interval, /* Status poll interval */
63 fbioc_ins_interval; /* Insert poll interval */
64 STATIC long fbioc_stat_id, /* Play status poll timer id */
65 fbioc_insert_id, /* Disc insert poll timer id */
66 fbioc_search_id; /* FF/REW timer id */
67 STATIC byte_t fbioc_tst_status = MOD_NODISC; /* Playback status on load */
68 STATIC bool_t fbioc_not_open = TRUE, /* Device not opened yet */
69 fbioc_stat_polling, /* Polling play status */
70 fbioc_insert_polling, /* Polling disc insert */
71 fbioc_new_progshuf, /* New program/shuffle seq */
72 fbioc_start_search, /* Start FF/REW play segment */
73 fbioc_idx_pause, /* Prev/next index pausing */
74 fbioc_fake_stop, /* Force a completion status */
75 fbioc_playing, /* Currently playing */
76 fbioc_paused, /* Currently paused */
77 fbioc_bcd_hack, /* Track numbers in BCD hack */
78 fbioc_override_ap, /* Override auto-play */
79 fbioc_use_pread; /* Use pread(2) to read CDDA */
80 STATIC sword32_t fbioc_sav_end_addr; /* Err recov saved end addr */
81 STATIC word32_t fbioc_next_sam; /* Next SAMPLE track */
82 STATIC msf_t fbioc_sav_end_msf; /* Err recov saved end MSF */
83 STATIC byte_t fbioc_sav_end_fmt; /* Err recov saved end fmt */
84 STATIC cdda_client_t fbioc_cdda_client; /* CDDA client struct */
85
86
87 /* FreeBSD/NetBSD/OpenBSD CDROM ioctl names */
88 STATIC iocname_t iname[] = {
89 { CDIOCREADSUBCHANNEL, "CDIOCREADSUBCHANNEL" },
90 { CDIOREADTOCHEADER, "CDIOREADTOCHEADER" },
91 { CDIOREADTOCENTRYS, "CDIOREADTOCENTRYS" },
92 { CDIOCEJECT, "CDIOCEJECT" },
93 { CDIOCSTART, "CDIOCSTART" },
94 { CDIOCSTOP, "CDIOCSTOP" },
95 { CDIOCPAUSE, "CDIOCPAUSE" },
96 { CDIOCRESUME, "CDIOCRESUME" },
97 { CDIOCGETVOL, "CDIOCGETVOL" },
98 { CDIOCSETVOL, "CDIOCSETVOL" },
99 { CDIOCPLAYTRACKS, "CDIOCPLAYTRACKS" },
100 { CDIOCPLAYMSF, "CDIOCPLAYMSF" },
101 { CDIOCALLOW, "CDIOCALLOW" },
102 { CDIOCPREVENT, "CDIOCPREVENT" },
103 { CDIOCREADAUDIO, "CDIOCREADAUDIO" },
104 { 0, NULL },
105 };
106
107
108 /***********************
109 * internal routines *
110 ***********************/
111
112
113 /*
114 * fbioc_close
115 * Close CD device
116 *
117 * Args:
118 * Nothing.
119 *
120 * Return:
121 * Nothing.
122 */
123 STATIC void
fbioc_close(void)124 fbioc_close(void)
125 {
126 if (fbioc_devp != NULL) {
127 DBGPRN(DBG_DEVIO)(errfp, "\nClose device: %s\n",
128 fbioc_devp->path);
129
130 if (fbioc_devp->fd > 0)
131 (void) close(fbioc_devp->fd);
132 di_devfree(fbioc_devp);
133 fbioc_devp = NULL;
134 }
135 }
136
137
138 /*
139 * fbioc_open
140 * Open CD device
141 *
142 * Args:
143 * path - device path name string
144 *
145 * Return:
146 * TRUE - open successful
147 * FALSE - open failed
148 */
149 STATIC bool_t
fbioc_open(char * path)150 fbioc_open(char *path)
151 {
152 struct stat stbuf;
153 char errstr[ERR_BUF_SZ];
154
155 DBGPRN(DBG_DEVIO)(errfp, "\nOpen device: %s\n", path);
156
157 /* Check for validity of device node */
158 if (stat(path, &stbuf) < 0) {
159 (void) sprintf(errstr, app_data.str_staterr, path);
160 DI_FATAL(errstr);
161 return FALSE;
162 }
163
164 if (!S_ISCHR(stbuf.st_mode)) {
165 (void) sprintf(errstr, app_data.str_noderr, path);
166 DI_FATAL(errstr);
167 return FALSE;
168 }
169
170 if ((fbioc_devp = di_devalloc(path)) == NULL) {
171 DI_FATAL(app_data.str_nomemory);
172 return FALSE;
173 }
174
175 if ((fbioc_devp->fd = open(path, O_RDONLY | O_EXCL)) < 0) {
176 DBGPRN(DBG_DEVIO)(errfp,
177 "Cannot open %s: errno=%d\n", path, errno);
178 di_devfree(fbioc_devp);
179 fbioc_devp = NULL;
180 return FALSE;
181 }
182
183 return TRUE;
184 }
185
186
187 /*
188 * fbioc_init_vol
189 * Initialize volume, balance and channel routing controls
190 * to match the settings in the hardware, or to the preset
191 * value, if specified.
192 *
193 * Args:
194 * s - Pointer to the curstat_t structure.
195 * preset - If a preset value is configured, whether to force to
196 * the preset.
197 *
198 * Return:
199 * Nothing.
200 */
201 STATIC void
fbioc_init_vol(curstat_t * s,bool_t preset)202 fbioc_init_vol(curstat_t *s, bool_t preset)
203 {
204 int vol;
205
206 /* Query current volume/balance settings */
207 if ((vol = fbioc_cfg_vol(0, s, TRUE)) >= 0)
208 s->level = (byte_t) vol;
209 else
210 s->level = 0;
211
212 /* Set volume to preset value, if so configured */
213 if (app_data.startup_vol > 0 && preset) {
214 s->level_left = s->level_right = 100;
215
216 if ((vol = fbioc_cfg_vol(app_data.startup_vol, s, FALSE)) >= 0)
217 s->level = (byte_t) vol;
218 }
219
220 /* Initialize sliders */
221 SET_VOL_SLIDER(s->level);
222 SET_BAL_SLIDER((int) (s->level_right - s->level_left) / 2);
223
224 /* Set up channel routing */
225 fbioc_route(s);
226 }
227
228
229 /*
230 * fbioc_rdsubq
231 * Send Read Subchannel command to the device
232 *
233 * Args:
234 * sp - Pointer to the caller-supplied cdstat_t return structure
235 *
236 * Return:
237 * TRUE - success
238 * FALSE - failure
239 */
240 STATIC bool_t
fbioc_rdsubq(cdstat_t * sp)241 fbioc_rdsubq(cdstat_t *sp)
242 {
243 struct ioc_read_subchannel subchnl;
244 struct cd_sub_channel_info sub;
245 bool_t ret;
246
247 memset((byte_t *) &sub, 0, sizeof(struct cd_sub_channel_info));
248
249 subchnl.address_format = app_data.subq_lba ?
250 CD_LBA_FORMAT : CD_MSF_FORMAT;
251 subchnl.data_format = CD_CURRENT_POSITION;
252 subchnl.track = 0;
253 subchnl.data_len = sizeof(struct cd_sub_channel_info);
254 subchnl.data = ⊂
255
256 DBGDUMP(DBG_DEVIO)("ioc_read_subchannel data bytes",
257 (byte_t *) &subchnl, sizeof(struct ioc_read_subchannel));
258
259 ret = fbioc_send(DI_ROLE_MAIN, CDIOCREADSUBCHANNEL, &subchnl, TRUE);
260
261 if (!ret)
262 return FALSE;
263
264 DBGDUMP(DBG_DEVIO)("cd_sub_channel_info data bytes", (byte_t *) &sub,
265 sizeof(struct cd_sub_channel_info));
266
267 /* Hack: to work around firmware anomalies in some CD drives. */
268 if (sub.what.position.track_number >= MAXTRACK &&
269 sub.what.position.track_number != LEAD_OUT_TRACK) {
270 sp->status = CDSTAT_NOSTATUS;
271 return TRUE;
272 }
273
274 /* Map the subchannel data into cdstat_t form */
275
276 switch (sub.header.audio_status) {
277 case CD_AS_PLAY_IN_PROGRESS:
278 sp->status = CDSTAT_PLAYING;
279 break;
280 case CD_AS_PLAY_PAUSED:
281 sp->status = CDSTAT_PAUSED;
282 break;
283 case CD_AS_PLAY_COMPLETED:
284 sp->status = CDSTAT_COMPLETED;
285 break;
286 case CD_AS_PLAY_ERROR:
287 sp->status = CDSTAT_FAILED;
288 break;
289 case CD_AS_AUDIO_INVALID:
290 case CD_AS_NO_STATUS:
291 default:
292 sp->status = CDSTAT_NOSTATUS;
293 break;
294 }
295
296 if (fbioc_bcd_hack) {
297 /* Hack: BUGLY CD drive firmware */
298 sp->track = (int) util_bcdtol(sub.what.position.track_number);
299 sp->index = (int) util_bcdtol(sub.what.position.index_number);
300 }
301 else {
302 sp->track = (int) sub.what.position.track_number;
303 sp->index = (int) sub.what.position.index_number;
304 }
305
306 if (app_data.subq_lba) {
307 /* LBA mode */
308 #ifdef NETBSD_OLDIOC
309 sp->abs_addr.addr = util_xlate_blk((sword32_t)
310 (sub.what.position.absaddr[3] << 24) |
311 (sub.what.position.absaddr[2] << 16) |
312 (sub.what.position.absaddr[1] << 8) |
313 sub.what.position.absaddr[0]
314 );
315 sp->rel_addr.addr = util_xlate_blk((sword32_t)
316 (sub.what.position.reladdr[3] << 24) |
317 (sub.what.position.reladdr[2] << 16) |
318 (sub.what.position.reladdr[1] << 8) |
319 sub.what.position.reladdr[0]
320 );
321 #else
322 sp->abs_addr.addr = util_xlate_blk((sword32_t)
323 util_bswap32(sub.what.position.absaddr.lba)
324 );
325 sp->rel_addr.addr = util_xlate_blk((sword32_t)
326 util_bswap32(sub.what.position.reladdr.lba)
327 );
328 #endif
329 util_blktomsf(
330 sp->abs_addr.addr,
331 &sp->abs_addr.min,
332 &sp->abs_addr.sec,
333 &sp->abs_addr.frame,
334 MSF_OFFSET
335 );
336 util_blktomsf(
337 sp->rel_addr.addr,
338 &sp->rel_addr.min,
339 &sp->rel_addr.sec,
340 &sp->rel_addr.frame,
341 0
342 );
343 }
344 else {
345 /* MSF mode */
346 #ifdef NETBSD_OLDIOC
347 sp->abs_addr.min = sub.what.position.absaddr[1];
348 sp->abs_addr.sec = sub.what.position.absaddr[2];
349 sp->abs_addr.frame = sub.what.position.absaddr[3];
350
351 sp->rel_addr.min = sub.what.position.reladdr[1];
352 sp->rel_addr.sec = sub.what.position.reladdr[2];
353 sp->rel_addr.frame = sub.what.position.reladdr[3];
354 #else
355 sp->abs_addr.min = sub.what.position.absaddr.msf.minute;
356 sp->abs_addr.sec = sub.what.position.absaddr.msf.second;
357 sp->abs_addr.frame = sub.what.position.absaddr.msf.frame;
358
359 sp->rel_addr.min = sub.what.position.reladdr.msf.minute;
360 sp->rel_addr.sec = sub.what.position.reladdr.msf.second;
361 sp->rel_addr.frame = sub.what.position.reladdr.msf.frame;
362 #endif
363 util_msftoblk(
364 sp->abs_addr.min,
365 sp->abs_addr.sec,
366 sp->abs_addr.frame,
367 &sp->abs_addr.addr,
368 MSF_OFFSET
369 );
370 util_msftoblk(
371 sp->rel_addr.min,
372 sp->rel_addr.sec,
373 sp->rel_addr.frame,
374 &sp->rel_addr.addr,
375 0
376 );
377 }
378
379 return (ret);
380 }
381
382
383 /*
384 * fbioc_rdtoc
385 * Send Read TOC command to the device
386 *
387 * Args:
388 * buf - Pointer to the return data toc header
389 * h - address of pointer to array of toc entrys will be allocated
390 * by this routine
391 * start - Starting track number for which the TOC data is returned
392 * msf - Whether to use MSF or logical block address data format
393 *
394 * Return:
395 * TRUE - success
396 * FALSE - failure
397 */
398 STATIC bool_t
fbioc_rdtoc(struct ioc_toc_header * h,struct cd_toc_entry ** e,int start,bool_t msf)399 fbioc_rdtoc(struct ioc_toc_header *h, struct cd_toc_entry **e,
400 int start, bool_t msf)
401 {
402 int i,
403 j,
404 k,
405 allocsz;
406 struct cd_toc_entry *t;
407 struct ioc_read_toc_entry tocentry;
408
409 /* Read the TOC header first */
410 if (!fbioc_send(DI_ROLE_MAIN, CDIOREADTOCHEADER, h, TRUE))
411 return FALSE;
412
413 DBGDUMP(DBG_DEVIO)("ioc_toc_header data bytes", (byte_t *) h,
414 sizeof(struct ioc_toc_header));
415
416 if (start == 0)
417 start = h->starting_track;
418
419 if (start > (int) h->ending_track)
420 return FALSE;
421
422 allocsz = (h->ending_track - start + 2) * sizeof(struct cd_toc_entry);
423
424 *e = (struct cd_toc_entry *)(void *) MEM_ALLOC(
425 "cd_toc_entry",
426 allocsz
427 );
428 t = (struct cd_toc_entry *)(void *) MEM_ALLOC(
429 "cd_toc_entry",
430 allocsz
431 );
432
433 if (*e == NULL || t == NULL) {
434 DI_FATAL(app_data.str_nomemory);
435 return FALSE;
436 }
437
438 (void) memset((byte_t *) *e, 0, allocsz);
439 (void) memset((byte_t *) t, 0, allocsz);
440 tocentry.starting_track = start;
441 tocentry.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT;
442 tocentry.data_len = allocsz;
443 tocentry.data = t;
444
445 DBGDUMP(DBG_DEVIO)("ioc_read_toc_entry data bytes",
446 (byte_t *) &tocentry, sizeof( struct ioc_read_toc_entry));
447
448 if (!fbioc_send(DI_ROLE_MAIN, CDIOREADTOCENTRYS, &tocentry, TRUE)) {
449 MEM_FREE(*e);
450 MEM_FREE(t);
451 return FALSE;
452 }
453
454 DBGDUMP(DBG_DEVIO)("cd_toc_entry data bytes", (byte_t *) t, allocsz);
455
456 for (i = start; i <= (int) (h->ending_track + 1); i++) {
457 j = i - start;
458
459 /* Hack: workaround CD drive firmware bug
460 * Some CD drives return track numbers in BCD
461 * rather than binary.
462 */
463 #ifdef NETBSD_OLDIOC
464 if ((int) (t[j].track & 0xf) > 0x9 &&
465 (int) (t[j].track & 0xf) < 0x10 &&
466 t[j].addr[0] == 0 && t[j].addr[1] == 0 &&
467 t[j].addr[2] == 0 && t[j].addr[3] == 0)
468 #else
469 if ((int) (t[j].track & 0xf) > 0x9 &&
470 (int) (t[j].track & 0xf) < 0x10 &&
471 t[j].addr.lba == 0)
472 #endif
473 {
474 /* BUGLY CD drive firmware detected! */
475 fbioc_bcd_hack = TRUE;
476 }
477
478 /* Sanity check */
479 #ifdef NETBSD_OLDIOC
480 if (t[j].track == LEAD_OUT_TRACK &&
481 t[j].addr[0] == t[0].addr[0] &&
482 t[j].addr[1] == t[1].addr[1] &&
483 t[j].addr[2] == t[2].addr[2] &&
484 t[j].addr[3] == t[3].addr[3])
485 #else
486 if (t[j].track == LEAD_OUT_TRACK &&
487 t[j].addr.lba == t[0].addr.lba)
488 #endif
489 {
490 MEM_FREE(*e);
491 MEM_FREE(t);
492 return FALSE;
493 }
494 }
495
496 /* Fix up TOC data */
497 for (i = start; i <= (int) (h->ending_track + 1); i++) {
498 if (fbioc_bcd_hack && (i & 0xf) > 0x9 && (i & 0xf) < 0x10)
499 continue;
500
501 j = i - start;
502 k = (fbioc_bcd_hack ? util_bcdtol(i) : i) - start;
503
504 if (i == (h->ending_track + 1)) {
505 /* FreeBSD HACK: Fix up lead-out track number */
506 t[j].track = LEAD_OUT_TRACK;
507 }
508
509 (*e)[k].control = t[j].control;
510 (*e)[k].addr_type = t[j].addr_type;
511 #ifdef NETBSD_OLDIOC
512 (*e)[k].addr[0] = t[j].addr[0];
513 (*e)[k].addr[1] = t[j].addr[1];
514 (*e)[k].addr[2] = t[j].addr[2];
515 (*e)[k].addr[3] = t[j].addr[3];
516 #else
517 (*e)[k].addr.lba = t[j].addr.lba;
518 #endif
519 if (t[j].track == LEAD_OUT_TRACK) {
520 (*e)[k].track = t[j].track;
521 break;
522 }
523 else {
524 if (fbioc_bcd_hack)
525 (*e)[k].track = (byte_t)
526 util_bcdtol(t[j].track);
527 else
528 (*e)[k].track = t[j].track;
529 }
530 }
531
532 if (fbioc_bcd_hack)
533 h->ending_track = (byte_t) util_bcdtol(h->ending_track);
534
535 MEM_FREE(t);
536
537 return TRUE;
538 }
539
540
541 /*
542 * fbioc_disc_present
543 * Check if a CD is loaded.
544 *
545 * Args:
546 * savstat - Whether to save start-up status in fbioc_tst_status.
547 *
548 * Return:
549 * TRUE - success
550 * FALSE - failure (drive not ready)
551 */
552 STATIC bool_t
fbioc_disc_present(bool_t savstat)553 fbioc_disc_present(bool_t savstat)
554 {
555 int allocsz;
556 sword32_t a1,
557 a2;
558 struct cd_toc_entry *e;
559 struct cd_sub_channel_info sub;
560 struct ioc_read_subchannel subchnl;
561 struct ioc_toc_header h;
562 struct ioc_read_toc_entry tocentry;
563 static int tot_trks = 0;
564 static sword32_t sav_a1 = 0,
565 sav_a2 = 0;
566
567 if (savstat)
568 fbioc_tst_status = MOD_NODISC;
569
570 /* Fake it with CDIOCREADSUBCHANNEL */
571 (void) memset((byte_t *) &sub, 0, sizeof(struct cd_sub_channel_info));
572 subchnl.address_format = CD_MSF_FORMAT;
573 subchnl.data_format = CD_CURRENT_POSITION;
574 subchnl.track = 0;
575 subchnl.data_len = sizeof(struct cd_sub_channel_info);
576 subchnl.data = ⊂
577
578 if (!fbioc_send(DI_ROLE_MAIN, CDIOCREADSUBCHANNEL, &subchnl,
579 (bool_t) ((app_data.debug & DBG_DEVIO) != 0)))
580 return FALSE;
581
582 switch (sub.header.audio_status) {
583 case CD_AS_PLAY_IN_PROGRESS:
584 if (savstat) {
585 DBGPRN(DBG_DEVIO)(errfp,
586 "\nstatus=CD_AS_PLAY_IN_PROGRESS\n");
587 fbioc_tst_status = MOD_PLAY;
588 return TRUE;
589 }
590 break;
591 case CD_AS_PLAY_PAUSED:
592 if (savstat) {
593 DBGPRN(DBG_DEVIO)(errfp,
594 "\nstatus=CD_AS_PLAY_PAUSED\n");
595 fbioc_tst_status = MOD_PAUSE;
596 return TRUE;
597 }
598 break;
599 case CD_AS_PLAY_ERROR:
600 DBGPRN(DBG_DEVIO)(errfp, "\nstatus=CD_AS_PLAY_ERROR\n");
601 break;
602 case CD_AS_PLAY_COMPLETED:
603 DBGPRN(DBG_DEVIO)(errfp, "\nstatus=CD_AS_PLAY_COMPLETED\n");
604 break;
605 case CD_AS_NO_STATUS:
606 DBGPRN(DBG_DEVIO)(errfp, "\nstatus=CD_AS_NO_STATUS\n");
607 break;
608 case CD_AS_AUDIO_INVALID:
609 DBGPRN(DBG_DEVIO)(errfp, "\nstatus=CD_AS_AUDIO_INVALID\n");
610 break;
611 default:
612 DBGPRN(DBG_DEVIO)(errfp, "\nstatus=unknown (%d)\n",
613 sub.header.audio_status);
614 return FALSE;
615 }
616
617 if (savstat)
618 fbioc_tst_status = MOD_STOP;
619
620 /* CDIOCREADSUBCHANNEL didn't give useful info.
621 * Try CDIOREADTOCHEADER and CDIOREADTOCENTRYS.
622 */
623 (void) memset((byte_t *) &h, 0, sizeof(struct ioc_toc_header));
624
625 if (!fbioc_send(DI_ROLE_MAIN, CDIOREADTOCHEADER, &h,
626 (bool_t) ((app_data.debug & DBG_DEVIO) != 0)))
627 return FALSE;
628
629 if (h.starting_track == 0 && h.ending_track == 0)
630 return FALSE;
631
632 if ((h.ending_track - h.starting_track + 1) != tot_trks) {
633 /* Disc changed */
634 tot_trks = h.ending_track - h.starting_track + 1;
635 return FALSE;
636 }
637
638 allocsz = (tot_trks + 1) * sizeof(struct cd_toc_entry);
639 e = (struct cd_toc_entry *)(void *) MEM_ALLOC("cd_toc_entry", allocsz);
640 if (e == NULL) {
641 DI_FATAL(app_data.str_nomemory);
642 return FALSE;
643 }
644
645 (void) memset((byte_t *) e, 0, allocsz);
646 tocentry.starting_track = (unsigned char) h.starting_track;
647 tocentry.address_format = CD_MSF_FORMAT;
648 tocentry.data_len = allocsz;
649 tocentry.data = e;
650
651 if (!fbioc_send(DI_ROLE_MAIN, CDIOREADTOCENTRYS, &tocentry,
652 (bool_t) ((app_data.debug & DBG_DEVIO) != 0))) {
653 MEM_FREE(e);
654 return FALSE;
655 }
656
657 #ifdef NETBSD_OLDIOC
658 a1 = (sword32_t) (
659 (e[h.starting_track - 1].addr[3] << 24) |
660 (e[h.starting_track - 1].addr[2] << 16) |
661 (e[h.starting_track - 1].addr[1] << 8) |
662 (e[h.starting_track - 1].addr[0])
663 );
664 a2 = (sword32_t) (
665 (e[h.ending_track - 1].addr[3] << 24) |
666 (e[h.ending_track - 1].addr[2] << 16) |
667 (e[h.ending_track - 1].addr[1] << 8) |
668 (e[h.ending_track - 1].addr[0])
669 );
670 #else
671 a1 = (sword32_t) e[h.starting_track - 1].addr.lba;
672 a2 = (sword32_t) e[h.ending_track - 1].addr.lba;
673 #endif
674
675 DBGPRN(DBG_DEVIO)(errfp, "\na1=0x%x a2=0x%x\n", a1, a2);
676 MEM_FREE(e);
677
678 if (a1 != sav_a1 || a2 != sav_a2) {
679 /* Disc changed */
680 sav_a1 = a1;
681 sav_a2 = a2;
682 return FALSE;
683 }
684
685 if (tot_trks > 1 && a1 == a2)
686 return FALSE;
687
688 return TRUE;
689 }
690
691
692 /*
693 * fbioc_playmsf
694 * Send Play Audio MSF command to the device
695 *
696 * Args:
697 * start - Pointer to the starting position MSF data
698 * end - Pointer to the ending position MSF data
699 *
700 * Return:
701 * TRUE - success
702 * FALSE - failure
703 */
704 STATIC bool_t
fbioc_playmsf(msf_t * start,msf_t * end)705 fbioc_playmsf(msf_t *start, msf_t *end)
706 {
707 struct ioc_play_msf m;
708
709 /* If the start or end positions are less than the minimum
710 * position, patch them to the minimum positions.
711 */
712 if (start->min == 0 && start->sec < 2) {
713 m.start_m = 0;
714 m.start_s = 2;
715 m.start_f = 0;
716 }
717 else {
718 m.start_m = start->min;
719 m.start_s = start->sec;
720 m.start_f = start->frame;
721 }
722
723 if (end->min == 0 && end->sec < 2) {
724 m.end_m = 0;
725 m.end_s = 2;
726 m.end_f = 0;
727 }
728 else {
729 m.end_m = end->min;
730 m.end_s = end->sec;
731 m.end_f = end->frame;
732 }
733
734 /* If start == end, just return success */
735 if (m.start_m == m.end_m &&
736 m.start_s == m.end_s &&
737 m.start_f == m.end_f)
738 return TRUE;
739
740 DBGDUMP(DBG_DEVIO)("ioc_play_msf data bytes", (byte_t *) &m,
741 sizeof(struct ioc_play_msf));
742
743 return (fbioc_send(DI_ROLE_MAIN, CDIOCPLAYMSF, &m, TRUE));
744 }
745
746
747 /*
748 * fbioc_play_trkidx
749 * Send Play Audio Track/Index command to the device
750 *
751 * Args:
752 * start_trk - Starting track number
753 * start_idx - Starting index number
754 * end_trk - Ending track number
755 * end_idx - Ending index number
756 *
757 * Return:
758 * TRUE - success
759 * FALSE - failure
760 */
761 bool_t
fbioc_play_trkidx(int start_trk,int start_idx,int end_trk,int end_idx)762 fbioc_play_trkidx(int start_trk, int start_idx, int end_trk, int end_idx)
763 {
764 struct ioc_play_track t;
765
766 if (fbioc_bcd_hack) {
767 /* Hack: BUGLY CD drive firmware */
768 t.start_track = util_ltobcd(start_trk);
769 t.start_index = util_ltobcd(start_idx);
770 t.end_track = util_ltobcd(end_trk);
771 t.end_index = util_ltobcd(end_idx);
772 }
773 else {
774 t.start_track = start_trk;
775 t.start_index = start_idx;
776 t.end_track = end_trk;
777 t.end_index = end_idx;
778 }
779
780 DBGDUMP(DBG_DEVIO)("ioc_play_track data bytes", (byte_t *) &t,
781 sizeof(struct ioc_play_track));
782
783 return (fbioc_send(DI_ROLE_MAIN, CDIOCPLAYTRACKS, &t, TRUE));
784 }
785
786
787 /*
788 * fbioc_start_stop
789 * Send Start/Stop Unit command to the device
790 *
791 * Args:
792 * start - Whether to start unit or stop unit
793 * loej - Whether caddy load/eject operation should be performed
794 *
795 * Return:
796 * TRUE - success
797 * FALSE - failure
798 */
799 STATIC bool_t
fbioc_start_stop(bool_t start,bool_t loej)800 fbioc_start_stop(bool_t start, bool_t loej)
801 {
802 bool_t ret;
803 curstat_t *s = di_clinfo->curstat_addr();
804
805 if (app_data.strict_pause_resume && fbioc_paused)
806 (void) fbioc_pause_resume(TRUE);
807
808 if (start) {
809 if (loej)
810 ret = FALSE;
811 else
812 ret = fbioc_send(DI_ROLE_MAIN, CDIOCSTART, NULL, TRUE);
813 }
814 else {
815 fbioc_playing = FALSE;
816
817 if (PLAYMODE_IS_CDDA(app_data.play_mode)) {
818 (void) cdda_stop(fbioc_devp, s);
819
820 if (!fbioc_is_enabled(DI_ROLE_MAIN)) {
821 /* Enable I/O from current process */
822 fbioc_enable(DI_ROLE_MAIN);
823 }
824 }
825
826 if (loej)
827 ret = fbioc_send(DI_ROLE_MAIN, CDIOCEJECT, NULL, TRUE);
828 else
829 ret = fbioc_send(DI_ROLE_MAIN, CDIOCSTOP, NULL, TRUE);
830 }
831
832 /* Delay a bit to let the CD load or eject. This is a hack to
833 * work around firmware bugs in some CD drives. These drives
834 * don't handle new commands well when the CD is loading/ejecting
835 * with the IMMED bit set in the Start/Stop Unit command.
836 */
837 if (ret) {
838 if (loej) {
839 int n;
840
841 n = (app_data.ins_interval + 1000 - 1) / 1000;
842 if (start)
843 n *= 2;
844
845 util_delayms(n * 1000);
846 }
847 else if (start && app_data.spinup_interval > 0)
848 util_delayms(app_data.spinup_interval * 1000);
849 }
850
851 return (ret);
852
853 }
854
855
856 /*
857 * fbioc_pause_resume
858 * Send Pause/Resume command to the device
859 *
860 * Args:
861 * resume - Whether to resume or pause
862 *
863 * Return:
864 * TRUE - success
865 * FALSE - failure
866 */
867 STATIC bool_t
fbioc_pause_resume(bool_t resume)868 fbioc_pause_resume(bool_t resume)
869 {
870 bool_t ret;
871 curstat_t *s = di_clinfo->curstat_addr();
872
873 if (!app_data.pause_supp)
874 return FALSE;
875
876 if (PLAYMODE_IS_CDDA(app_data.play_mode)) {
877 ret = cdda_pause_resume(fbioc_devp, s, resume);
878 }
879 else {
880 ret = fbioc_send(
881 DI_ROLE_MAIN, resume ? CDIOCRESUME : CDIOCPAUSE,
882 NULL, TRUE
883 );
884 }
885 if (ret)
886 fbioc_paused = !resume;
887
888 return (ret);
889 }
890
891
892 /*
893 * fbioc_do_playaudio
894 * General top-level play audio function
895 *
896 * Args:
897 * addr_fmt - The address formats specified:
898 * ADDR_BLK: logical block address (not supported)
899 * ADDR_MSF: MSF address
900 * ADDR_TRKIDX: Track/index numbers
901 * ADDR_OPTEND: Ending address can be ignored
902 * start_addr - Starting logical block address (not supported)
903 * end_addr - Ending logical block address (not supported)
904 * start_msf - Pointer to start address MSF data
905 * end_msf - Pointer to end address MSF data
906 * trk - Starting track number
907 * idx - Starting index number
908 *
909 * Return:
910 * TRUE - success
911 * FALSE - failure
912 */
913 STATIC bool_t
fbioc_do_playaudio(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)914 fbioc_do_playaudio(
915 byte_t addr_fmt,
916 sword32_t start_addr,
917 sword32_t end_addr,
918 msf_t *start_msf,
919 msf_t *end_msf,
920 byte_t trk,
921 byte_t idx
922 )
923 {
924 msf_t emsf,
925 *emsfp = NULL;
926 sword32_t tmp_saddr,
927 tmp_eaddr;
928 bool_t ret = FALSE,
929 do_playmsf,
930 do_play10,
931 do_play12,
932 do_playti;
933 curstat_t *s = di_clinfo->curstat_addr();
934
935 /* Fix addresses: Some CD drives will only allow playing to
936 * the last frame minus a few frames.
937 */
938 if ((addr_fmt & ADDR_MSF) && end_msf != NULL) {
939 emsf = *end_msf; /* Structure copy */
940 emsfp = &emsf;
941
942 util_msftoblk(
943 start_msf->min,
944 start_msf->sec,
945 start_msf->frame,
946 &tmp_saddr,
947 MSF_OFFSET
948 );
949
950 util_msftoblk(
951 emsfp->min,
952 emsfp->sec,
953 emsfp->frame,
954 &tmp_eaddr,
955 MSF_OFFSET
956 );
957
958 if (tmp_eaddr > s->discpos_tot.addr)
959 tmp_eaddr = s->discpos_tot.addr;
960
961 if (tmp_eaddr >= di_clip_frames)
962 tmp_eaddr -= di_clip_frames;
963 else
964 tmp_eaddr = 0;
965
966 util_blktomsf(
967 tmp_eaddr,
968 &emsfp->min,
969 &emsfp->sec,
970 &emsfp->frame,
971 MSF_OFFSET
972 );
973
974 if (tmp_saddr >= tmp_eaddr)
975 return FALSE;
976
977 emsfp->res = start_msf->res = 0;
978
979 /* Save end address for error recovery */
980 fbioc_sav_end_msf = *end_msf;
981 }
982 if (addr_fmt & ADDR_BLK) {
983 if (end_addr > s->discpos_tot.addr)
984 end_addr = s->discpos_tot.addr;
985
986 if (end_addr >= di_clip_frames)
987 end_addr -= di_clip_frames;
988 else
989 end_addr = 0;
990
991 if (start_addr >= end_addr)
992 return FALSE;
993
994 /* Save end address for error recovery */
995 fbioc_sav_end_addr = end_addr;
996 }
997
998 /* Save end address format for error recovery */
999 fbioc_sav_end_fmt = addr_fmt;
1000
1001 do_playmsf = (addr_fmt & ADDR_MSF) && app_data.playmsf_supp;
1002 do_play10 = (addr_fmt & ADDR_BLK) && app_data.play10_supp;
1003 do_play12 = (addr_fmt & ADDR_BLK) && app_data.play12_supp;
1004 do_playti = (addr_fmt & ADDR_TRKIDX) && app_data.playti_supp;
1005
1006 if (do_playmsf || do_playti) {
1007 if (fbioc_paused) {
1008 if (app_data.strict_pause_resume) {
1009 /* Resume first */
1010 (void) fbioc_pause_resume(TRUE);
1011 }
1012 }
1013 else if (fbioc_playing) {
1014 if (app_data.play_pause_play) {
1015 /* Pause first */
1016 (void) fbioc_pause_resume(FALSE);
1017 }
1018 }
1019 else {
1020 /* Spin up CD */
1021 (void) fbioc_start_stop(TRUE, FALSE);
1022 }
1023 }
1024
1025 if (PLAYMODE_IS_CDDA(app_data.play_mode)) {
1026 if (do_play12 || do_play10) {
1027 if (fbioc_is_enabled(DI_ROLE_MAIN)) {
1028 /* Disable I/O from current process */
1029 fbioc_disable(DI_ROLE_MAIN);
1030 }
1031
1032 ret = cdda_play(fbioc_devp, s, start_addr, end_addr);
1033 }
1034 else if (do_playmsf) {
1035 util_msftoblk(
1036 start_msf->min,
1037 start_msf->sec,
1038 start_msf->frame,
1039 &start_addr,
1040 MSF_OFFSET
1041 );
1042 util_msftoblk(
1043 emsfp->min,
1044 emsfp->sec,
1045 emsfp->frame,
1046 &end_addr,
1047 MSF_OFFSET
1048 );
1049
1050 ret = cdda_play(fbioc_devp, s, start_addr, end_addr);
1051 }
1052 }
1053 else {
1054 if (do_playmsf)
1055 ret = fbioc_playmsf(start_msf, emsfp);
1056
1057 if (!ret && do_playti)
1058 ret = fbioc_play_trkidx(trk, idx, trk, idx);
1059 }
1060
1061 if (ret) {
1062 fbioc_playing = TRUE;
1063 fbioc_paused = FALSE;
1064 }
1065
1066 return (ret);
1067 }
1068
1069
1070 /*
1071 * fbioc_play_recov
1072 * Playback interruption recovery handler: Restart playback after
1073 * skipping some frames.
1074 *
1075 * Args:
1076 * blk - Interruption frame address
1077 * iserr - Whether interruption is due to an error
1078 *
1079 * Return:
1080 * TRUE - success
1081 * FALSE - failure
1082 */
1083 STATIC bool_t
fbioc_play_recov(sword32_t blk,bool_t iserr)1084 fbioc_play_recov(sword32_t blk, bool_t iserr)
1085 {
1086 msf_t recov_start_msf;
1087 sword32_t recov_start_addr;
1088 bool_t ret;
1089
1090 ret = TRUE;
1091
1092 recov_start_addr = blk + ERR_SKIPBLKS;
1093 util_blktomsf(
1094 recov_start_addr,
1095 &recov_start_msf.min,
1096 &recov_start_msf.sec,
1097 &recov_start_msf.frame,
1098 MSF_OFFSET
1099 );
1100
1101 /* Check to see if we have skipped past
1102 * the end.
1103 */
1104 if (recov_start_msf.min > fbioc_sav_end_msf.min)
1105 ret = FALSE;
1106 else if (recov_start_msf.min == fbioc_sav_end_msf.min) {
1107 if (recov_start_msf.sec > fbioc_sav_end_msf.sec)
1108 ret = FALSE;
1109 else if ((recov_start_msf.sec ==
1110 fbioc_sav_end_msf.sec) &&
1111 (recov_start_msf.frame >
1112 fbioc_sav_end_msf.frame)) {
1113 ret = FALSE;
1114 }
1115 }
1116 if (recov_start_addr >= fbioc_sav_end_addr)
1117 ret = FALSE;
1118
1119 if (ret) {
1120 /* Restart playback */
1121 if (iserr) {
1122 (void) fprintf(errfp,
1123 "CD audio: %s (%02u:%02u.%02u)\n",
1124 app_data.str_recoverr,
1125 recov_start_msf.min,
1126 recov_start_msf.sec,
1127 recov_start_msf.frame
1128 );
1129 }
1130
1131 ret = fbioc_do_playaudio(
1132 fbioc_sav_end_fmt,
1133 recov_start_addr, fbioc_sav_end_addr,
1134 &recov_start_msf, &fbioc_sav_end_msf,
1135 0, 0
1136 );
1137 }
1138
1139 return (ret);
1140 }
1141
1142
1143 /*
1144 * fbioc_get_playstatus
1145 * Obtain and update current playback status information
1146 *
1147 * Args:
1148 * s - Pointer to the curstat_t structure
1149 *
1150 * Return:
1151 * TRUE - Audio playback is in progress
1152 * FALSE - Audio playback stopped or command failure
1153 */
1154 STATIC bool_t
fbioc_get_playstatus(curstat_t * s)1155 fbioc_get_playstatus(curstat_t *s)
1156 {
1157 cdstat_t cdstat;
1158 word32_t curtrk,
1159 curidx;
1160 bool_t ret,
1161 done;
1162 static int errcnt = 0,
1163 nostatcnt = 0;
1164 static sword32_t errblk = 0;
1165 static bool_t in_fbioc_get_playstatus = FALSE;
1166
1167 /* Lock this routine from multiple entry */
1168 if (in_fbioc_get_playstatus)
1169 return TRUE;
1170
1171 in_fbioc_get_playstatus = TRUE;
1172
1173 if (PLAYMODE_IS_CDDA(app_data.play_mode)) {
1174 ret = cdda_getstatus(fbioc_devp, s, &cdstat);
1175 if (ret &&
1176 (cdstat.level != s->level ||
1177 cdstat.level_left != s->level_left ||
1178 cdstat.level_right != s->level_right)) {
1179 int vol;
1180
1181 /* Update volume & balance level */
1182 s->level_left = cdstat.level_left;
1183 s->level_right = cdstat.level_right;
1184 vol = fbioc_cfg_vol((int) cdstat.level, s, FALSE);
1185 if (vol >= 0) {
1186 s->level = vol;
1187 SET_VOL_SLIDER(s->level);
1188 SET_BAL_SLIDER((int)
1189 (s->level_right - s->level_left) / 2
1190 );
1191 }
1192 }
1193 }
1194 else
1195 ret = fbioc_rdsubq(&cdstat);
1196
1197 if (!ret) {
1198 /* Check to see if the disc had been manually ejected */
1199 if (!fbioc_disc_ready(s)) {
1200 fbioc_sav_end_addr = 0;
1201 fbioc_sav_end_msf.min = 0;
1202 fbioc_sav_end_msf.sec = 0;
1203 fbioc_sav_end_msf.frame = 0;
1204 fbioc_sav_end_fmt = 0;
1205 errcnt = 0;
1206 errblk = 0;
1207
1208 in_fbioc_get_playstatus = FALSE;
1209 return FALSE;
1210 }
1211
1212 /* The read subchannel command failed for some
1213 * unknown reason. Just return success and
1214 * hope the next poll succeeds. We don't want
1215 * to return FALSE here because that would stop
1216 * the poll.
1217 */
1218 in_fbioc_get_playstatus = FALSE;
1219 return TRUE;
1220 }
1221
1222 curtrk = cdstat.track;
1223 curidx = cdstat.index;
1224 s->curpos_tot = cdstat.abs_addr; /* structure copy */
1225 s->curpos_trk = cdstat.rel_addr; /* structure copy */
1226
1227 s->tot_frm = cdstat.tot_frm;
1228 s->frm_played = cdstat.frm_played;
1229 s->frm_per_sec = cdstat.frm_per_sec;
1230
1231 /* Update time display */
1232 DPY_TIME(s, FALSE);
1233
1234 if (curtrk != s->cur_trk) {
1235 s->cur_trk = curtrk;
1236 /* Update track number display */
1237 DPY_TRACK(s);
1238 }
1239
1240 if (curidx != s->cur_idx) {
1241 s->cur_idx = curidx;
1242 s->sav_iaddr = s->curpos_tot.addr;
1243 /* Update index number display */
1244 DPY_INDEX(s);
1245 }
1246
1247 /* Update play mode display */
1248 DPY_PLAYMODE(s, FALSE);
1249
1250 /* Hack: to work around the fact that some CD drives return
1251 * CD_AS_PLAY_PAUSED status after issuing a Stop Unit command.
1252 * Just treat the status as completed if we get a paused status
1253 * and we don't expect the drive to be paused.
1254 */
1255 if (cdstat.status == CDSTAT_PAUSED && s->mode != MOD_PAUSE &&
1256 !fbioc_idx_pause)
1257 cdstat.status = CDSTAT_COMPLETED;
1258
1259 /* Force completion status */
1260 if (fbioc_fake_stop)
1261 cdstat.status = CDSTAT_COMPLETED;
1262
1263 /* Deal with playback status */
1264 switch (cdstat.status) {
1265 case CDSTAT_PLAYING:
1266 case CDSTAT_PAUSED:
1267 nostatcnt = 0;
1268 done = FALSE;
1269
1270 /* If we haven't encountered an error for a while, then
1271 * clear the error count.
1272 */
1273 if (errcnt > 0 &&
1274 (s->curpos_tot.addr - errblk) > ERR_CLRTHRESH)
1275 errcnt = 0;
1276 break;
1277
1278 case CDSTAT_FAILED:
1279 nostatcnt = 0;
1280 /* Check to see if the disc had been manually ejected */
1281 if (!fbioc_disc_ready(s)) {
1282 fbioc_sav_end_addr = 0;
1283 fbioc_sav_end_msf.min = 0;
1284 fbioc_sav_end_msf.sec = 0;
1285 fbioc_sav_end_msf.frame = 0;
1286 fbioc_sav_end_fmt = 0;
1287 errcnt = 0;
1288 errblk = 0;
1289
1290 in_fbioc_get_playstatus = FALSE;
1291 return FALSE;
1292 }
1293
1294 /* Audio playback stopped due to a disc error. We will
1295 * try to restart the playback by skipping a few frames
1296 * and continuing. This will cause a glitch in the sound
1297 * but is better than just stopping.
1298 */
1299 done = FALSE;
1300
1301 /* Check for max errors limit */
1302 if (++errcnt > MAX_RECOVERR) {
1303 done = TRUE;
1304 (void) fprintf(errfp, "CD audio: %s\n",
1305 app_data.str_maxerr);
1306 }
1307
1308 errblk = s->curpos_tot.addr;
1309
1310 if (!done && fbioc_play_recov(errblk, TRUE)) {
1311 in_fbioc_get_playstatus = FALSE;
1312 return TRUE;
1313 }
1314
1315 /*FALLTHROUGH*/
1316
1317 case CDSTAT_COMPLETED:
1318 case CDSTAT_NOSTATUS:
1319 default:
1320 if (cdstat.status == CDSTAT_NOSTATUS && nostatcnt++ < 20) {
1321 /* Allow 20 occurrences of nostatus, then stop */
1322 done = FALSE;
1323 break;
1324 }
1325 nostatcnt = 0;
1326 done = TRUE;
1327
1328 if (!fbioc_fake_stop)
1329 fbioc_playing = FALSE;
1330
1331 fbioc_fake_stop = FALSE;
1332
1333 switch (s->mode) {
1334 case MOD_SAMPLE:
1335 done = !fbioc_run_sample(s);
1336 break;
1337
1338 case MOD_PLAY:
1339 case MOD_PAUSE:
1340 s->curpos_trk.addr = 0;
1341 s->curpos_trk.min = 0;
1342 s->curpos_trk.sec = 0;
1343 s->curpos_trk.frame = 0;
1344
1345 if (s->shuffle || s->program)
1346 done = !fbioc_run_prog(s);
1347
1348 if (s->repeat)
1349 done = !fbioc_run_repeat(s);
1350
1351 if (s->repeat && s->segplay == SEGP_AB)
1352 done = !fbioc_run_ab(s);
1353
1354 break;
1355 }
1356
1357 break;
1358 }
1359
1360 if (done) {
1361 /* Reset states */
1362 di_reset_curstat(s, FALSE, FALSE);
1363 s->mode = MOD_STOP;
1364
1365 /* Cancel a->? if the user didn't select an end point */
1366 if (s->segplay == SEGP_A) {
1367 s->segplay = SEGP_NONE;
1368 DPY_PROGMODE(s, FALSE);
1369 }
1370
1371 fbioc_sav_end_addr = 0;
1372 fbioc_sav_end_msf.min = fbioc_sav_end_msf.sec =
1373 fbioc_sav_end_msf.frame = 0;
1374 fbioc_sav_end_fmt = 0;
1375 errcnt = 0;
1376 errblk = 0;
1377 s->rptcnt = 0;
1378 DPY_ALL(s);
1379
1380 if (app_data.done_eject) {
1381 /* Eject the disc */
1382 fbioc_load_eject(s);
1383 }
1384 else {
1385 /* Spin down the disc */
1386 (void) fbioc_start_stop(FALSE, FALSE);
1387 }
1388 if (app_data.done_exit) {
1389 /* Exit */
1390 di_clinfo->quit(s);
1391 }
1392
1393 in_fbioc_get_playstatus = FALSE;
1394 return FALSE;
1395 }
1396
1397 in_fbioc_get_playstatus = FALSE;
1398 return TRUE;
1399 }
1400
1401
1402 /*
1403 * fbioc_cfg_vol
1404 * Audio volume control function
1405 *
1406 * Args:
1407 * vol - Logical volume value to set to
1408 * s - Pointer to the curstat_t structure
1409 * query - If TRUE, query current volume only
1410 *
1411 * Return:
1412 * The current logical volume value, or -1 on failure.
1413 */
1414 STATIC int
fbioc_cfg_vol(int vol,curstat_t * s,bool_t query)1415 fbioc_cfg_vol(int vol, curstat_t *s, bool_t query)
1416 {
1417 int vol1,
1418 vol2;
1419 struct ioc_vol volctrl;
1420 static bool_t first = TRUE;
1421
1422 if (!app_data.mselvol_supp)
1423 return 0;
1424
1425 if (s->mode == MOD_BUSY)
1426 return -1;
1427
1428 if (PLAYMODE_IS_CDDA(app_data.play_mode))
1429 return (cdda_vol(fbioc_devp, s, vol, query));
1430
1431 (void) memset((byte_t *) &volctrl, 0, sizeof(struct ioc_vol));
1432
1433 if (query) {
1434 if (first) {
1435 first = FALSE;
1436
1437 /* Try using the CDIOCGETVOL ioctl */
1438 if (fbioc_send(DI_ROLE_MAIN, CDIOCGETVOL,
1439 &volctrl, FALSE)) {
1440 DBGDUMP(DBG_DEVIO)("cdrom_volctrl data bytes",
1441 (byte_t *) &volctrl,
1442 sizeof(struct ioc_vol));
1443 vol1 = util_untaper_vol(
1444 util_unscale_vol((int) volctrl.vol[0])
1445 );
1446 vol2 = util_untaper_vol(
1447 util_unscale_vol((int) volctrl.vol[1])
1448 );
1449
1450 if (vol1 == vol2) {
1451 s->level_left = s->level_right = 100;
1452 vol = vol1;
1453 }
1454 else if (vol1 > vol2) {
1455 s->level_left = 100;
1456 s->level_right =
1457 (byte_t)((vol2 * 100) / vol1);
1458 vol = vol1;
1459 }
1460 else {
1461 s->level_left =
1462 (byte_t) ((vol1 * 100) / vol2);
1463 s->level_right = 100;
1464 vol = vol2;
1465 }
1466
1467 return (vol);
1468 }
1469
1470 /* There is no way to read volume setting via
1471 * CDROM ioctl. Force the setting to maximum.
1472 */
1473 vol = 100;
1474 s->level_left = s->level_right = 100;
1475
1476 (void) fbioc_cfg_vol(vol, s, FALSE);
1477 }
1478 return (vol);
1479 }
1480 else {
1481 volctrl.vol[0] = util_scale_vol(
1482 util_taper_vol(vol * (int) s->level_left / 100)
1483 );
1484 volctrl.vol[1] = util_scale_vol(
1485 util_taper_vol(vol * (int) s->level_right / 100)
1486 );
1487
1488 DBGDUMP(DBG_DEVIO)("ioc_vol data bytes", (byte_t *) &volctrl,
1489 sizeof(struct ioc_vol));
1490
1491 if (fbioc_send(DI_ROLE_MAIN, CDIOCSETVOL, &volctrl, TRUE))
1492 return (vol);
1493 else if (volctrl.vol[0] != volctrl.vol[1]) {
1494 /* Set the balance to the center
1495 * and retry.
1496 */
1497 volctrl.vol[0] = volctrl.vol[1] =
1498 util_scale_vol(util_taper_vol(vol));
1499
1500 DBGDUMP(DBG_DEVIO)("ioc_vol data bytes",
1501 (byte_t *) &volctrl, sizeof(struct ioc_vol));
1502
1503 if (fbioc_send(DI_ROLE_MAIN, CDIOCSETVOL,
1504 &volctrl, TRUE)) {
1505 /* Success: Warp balance control */
1506 s->level_left = s->level_right = 100;
1507 SET_BAL_SLIDER(0);
1508
1509 return (vol);
1510 }
1511
1512 /* Still failed: just drop through */
1513 }
1514 }
1515
1516 return -1;
1517 }
1518
1519
1520 /*
1521 * fbioc_vendor_model
1522 * Query and update CD drive vendor/model/revision information
1523 *
1524 * Args:
1525 * s - Pointer to the curstat_t structure
1526 *
1527 * Return:
1528 * Nothing.
1529 */
1530 STATIC void
fbioc_vendor_model(curstat_t * s)1531 fbioc_vendor_model(curstat_t *s)
1532 {
1533 /*
1534 * There is currently no way to get this info,
1535 * so just fill in some default info.
1536 */
1537 (void) strcpy(s->vendor, "standard");
1538 (void) strcpy(s->prod, "CD-ROM drive");
1539 s->revnum[0] = '\0';
1540 }
1541
1542
1543 /*
1544 * fbioc_fix_toc
1545 * CD Table Of Contents post-processing function. This is to patch
1546 * the end-of-audio position to handle "enhanced CD" or "CD Extra"
1547 * multisession CDs.
1548 *
1549 * Args:
1550 * s - Pointer to the curstat_t structure
1551 *
1552 * Return:
1553 * Nothing.
1554 */
1555 STATIC void
fbioc_fix_toc(curstat_t * s)1556 fbioc_fix_toc(curstat_t *s)
1557 {
1558 int i;
1559
1560 /*
1561 * Set the end-of-audio to the first data track after the first
1562 * track, minus 02:32:00, if applicable. The 02:32:00 is the
1563 * inter-session lead-out and lead-in time plus the 2-second
1564 * pre-gap for the last session.
1565 */
1566 for (i = 1; i < (int) s->tot_trks; i++) {
1567 if (s->trkinfo[i].type == TYP_DATA) {
1568 s->discpos_tot.addr = s->trkinfo[i].addr;
1569 s->discpos_tot.addr -= 11400;
1570 util_blktomsf(
1571 s->discpos_tot.addr,
1572 &s->discpos_tot.min,
1573 &s->discpos_tot.sec,
1574 &s->discpos_tot.frame,
1575 MSF_OFFSET
1576 );
1577 break;
1578 }
1579 }
1580 }
1581
1582
1583 /*
1584 * fbioc_get_toc
1585 * Query and update the CD Table Of Contents
1586 *
1587 * Args:
1588 * s - Pointer to the curstat_t structure
1589 *
1590 * Return:
1591 * TRUE - success
1592 * FALSE - failure
1593 */
1594 STATIC bool_t
fbioc_get_toc(curstat_t * s)1595 fbioc_get_toc(curstat_t *s)
1596 {
1597 struct ioc_toc_header h;
1598 struct cd_toc_entry *e,
1599 *p;
1600 int i,
1601 ntrks;
1602
1603 (void) memset((byte_t *) &h, 0, sizeof(struct ioc_toc_header));
1604 if (!fbioc_rdtoc(&h, &e, 0, !app_data.toc_lba))
1605 return FALSE;
1606
1607 /* Fill curstat structure with TOC data */
1608 s->first_trk = h.starting_track;
1609 ntrks = (int) (h.ending_track - h.starting_track) + 1;
1610
1611 p = e;
1612
1613 for (i = 0; i <= ntrks; i++) {
1614 s->trkinfo[i].trkno = p->track;
1615 s->trkinfo[i].type =
1616 (p->control & 0x04) ? TYP_DATA : TYP_AUDIO;
1617
1618 if (app_data.toc_lba) {
1619 /* LBA mode */
1620 #ifdef NETBSD_OLDIOC
1621 s->trkinfo[i].addr = util_xlate_blk((sword32_t)
1622 (p->addr[3] << 24) | (p->addr[2] << 16) |
1623 (p->addr[2] << 8) | p->addr[0]
1624 );
1625 #else
1626 s->trkinfo[i].addr = util_xlate_blk((sword32_t)
1627 util_bswap32(p->addr.lba)
1628 );
1629 #endif
1630 util_blktomsf(
1631 s->trkinfo[i].addr,
1632 &s->trkinfo[i].min,
1633 &s->trkinfo[i].sec,
1634 &s->trkinfo[i].frame,
1635 MSF_OFFSET
1636 );
1637 }
1638 else {
1639 /* MSF mode */
1640 #ifdef NETBSD_OLDIOC
1641 s->trkinfo[i].min = p->addr[1];
1642 s->trkinfo[i].sec = p->addr[2];
1643 s->trkinfo[i].frame = p->addr[3];
1644 #else
1645 s->trkinfo[i].min = p->addr.msf.minute;
1646 s->trkinfo[i].sec = p->addr.msf.second;
1647 s->trkinfo[i].frame = p->addr.msf.frame;
1648 #endif
1649 util_msftoblk(
1650 s->trkinfo[i].min,
1651 s->trkinfo[i].sec,
1652 s->trkinfo[i].frame,
1653 &s->trkinfo[i].addr,
1654 MSF_OFFSET
1655 );
1656 }
1657
1658 if (p->track == LEAD_OUT_TRACK || i == (MAXTRACK - 1)) {
1659 s->discpos_tot.min = s->trkinfo[i].min;
1660 s->discpos_tot.sec = s->trkinfo[i].sec;
1661 s->discpos_tot.frame = s->trkinfo[i].frame;
1662 s->tot_trks = (byte_t) i;
1663 s->discpos_tot.addr = s->trkinfo[i].addr;
1664 s->last_trk = s->trkinfo[i-1].trkno;
1665
1666 break;
1667 }
1668
1669 p++;
1670 }
1671
1672 MEM_FREE(e);
1673
1674 fbioc_fix_toc(s);
1675 return TRUE;
1676 }
1677
1678
1679 /*
1680 * fbioc_start_stat_poll
1681 * Start polling the drive for current playback status
1682 *
1683 * Args:
1684 * s - Pointer to the curstat_t structure
1685 *
1686 * Return:
1687 * Nothing.
1688 */
1689 STATIC void
fbioc_start_stat_poll(curstat_t * s)1690 fbioc_start_stat_poll(curstat_t *s)
1691 {
1692 /* Start poll timer */
1693 if (di_clinfo->timeout != NULL) {
1694 fbioc_stat_id = di_clinfo->timeout(
1695 fbioc_stat_interval,
1696 fbioc_stat_poll,
1697 (byte_t *) s
1698 );
1699
1700 if (fbioc_stat_id != 0)
1701 fbioc_stat_polling = TRUE;
1702 }
1703 }
1704
1705
1706 /*
1707 * fbioc_stop_stat_poll
1708 * Stop polling the drive for current playback status
1709 *
1710 * Args:
1711 * Nothing.
1712 *
1713 * Return:
1714 * Nothing.
1715 */
1716 STATIC void
fbioc_stop_stat_poll(void)1717 fbioc_stop_stat_poll(void)
1718 {
1719 if (fbioc_stat_polling) {
1720 /* Stop poll timer */
1721 if (di_clinfo->untimeout != NULL)
1722 di_clinfo->untimeout(fbioc_stat_id);
1723
1724 fbioc_stat_polling = FALSE;
1725 }
1726 }
1727
1728
1729 /*
1730 * fbioc_start_insert_poll
1731 * Start polling the drive for disc insertion
1732 *
1733 * Args:
1734 * s - Pointer to the curstat_t structure
1735 *
1736 * Return:
1737 * Nothing.
1738 */
1739 STATIC void
fbioc_start_insert_poll(curstat_t * s)1740 fbioc_start_insert_poll(curstat_t *s)
1741 {
1742 int delay;
1743 bool_t first = TRUE;
1744
1745 if (fbioc_insert_polling || app_data.ins_disable ||
1746 (s->mode != MOD_BUSY && s->mode != MOD_NODISC))
1747 return;
1748
1749 if (app_data.numdiscs > 1 && app_data.multi_play)
1750 fbioc_ins_interval =
1751 app_data.ins_interval / app_data.numdiscs;
1752 else
1753 fbioc_ins_interval = app_data.ins_interval;
1754
1755 if (fbioc_ins_interval < 500)
1756 fbioc_ins_interval = 500;
1757
1758 if (first) {
1759 first = FALSE;
1760 delay = 50;
1761 }
1762 else
1763 delay = fbioc_ins_interval;
1764
1765 /* Start poll timer */
1766 if (di_clinfo->timeout != NULL) {
1767 fbioc_insert_id = di_clinfo->timeout(
1768 delay,
1769 fbioc_insert_poll,
1770 (byte_t *) s
1771 );
1772
1773 if (fbioc_insert_id != 0)
1774 fbioc_insert_polling = TRUE;
1775 }
1776 }
1777
1778
1779 /*
1780 * fbioc_stat_poll
1781 * The playback status polling function
1782 *
1783 * Args:
1784 * s - Pointer to the curstat_t structure
1785 *
1786 * Return:
1787 * Nothing.
1788 */
1789 STATIC void
fbioc_stat_poll(curstat_t * s)1790 fbioc_stat_poll(curstat_t *s)
1791 {
1792 if (!fbioc_stat_polling)
1793 return;
1794
1795 /* Get current audio playback status */
1796 if (fbioc_get_playstatus(s)) {
1797 /* Register next poll interval */
1798 if (di_clinfo->timeout != NULL) {
1799 fbioc_stat_id = di_clinfo->timeout(
1800 fbioc_stat_interval,
1801 fbioc_stat_poll,
1802 (byte_t *) s
1803 );
1804 }
1805 }
1806 else
1807 fbioc_stat_polling = FALSE;
1808 }
1809
1810
1811 /*
1812 * fbioc_insert_poll
1813 * The disc insertion polling function
1814 *
1815 * Args:
1816 * s - Pointer to the curstat_t structure
1817 *
1818 * Return:
1819 * Nothing.
1820 */
1821 STATIC void
fbioc_insert_poll(curstat_t * s)1822 fbioc_insert_poll(curstat_t *s)
1823 {
1824 /* Check to see if a disc is inserted */
1825 if (!fbioc_disc_ready(s)) {
1826 /* Register next poll interval */
1827 if (di_clinfo->timeout != NULL) {
1828 fbioc_insert_id = di_clinfo->timeout(
1829 fbioc_ins_interval,
1830 fbioc_insert_poll,
1831 (byte_t *) s
1832 );
1833 }
1834 }
1835 else
1836 fbioc_insert_polling = FALSE;
1837 }
1838
1839
1840 /*
1841 * fbioc_disc_ready
1842 * Check if the disc is loaded and ready for use, and update
1843 * curstat table.
1844 *
1845 * Args:
1846 * s - Pointer to the curstat_t structure
1847 *
1848 * Return:
1849 * TRUE - Disc is ready
1850 * FALSE - Disc is not ready
1851 */
1852 STATIC bool_t
fbioc_disc_ready(curstat_t * s)1853 fbioc_disc_ready(curstat_t *s)
1854 {
1855 bool_t no_disc;
1856 static bool_t first_open = TRUE,
1857 in_fbioc_disc_ready = FALSE;
1858
1859 /* Lock this routine from multiple entry */
1860 if (in_fbioc_disc_ready)
1861 return TRUE;
1862
1863 in_fbioc_disc_ready = TRUE;
1864
1865 /* If device has not been opened, attempt to open it */
1866 if (fbioc_not_open) {
1867 /* Check for another copy of the CD player running on
1868 * the specified device.
1869 */
1870 if (!s->devlocked && !di_devlock(s, app_data.device)) {
1871 s->mode = MOD_BUSY;
1872 DPY_TIME(s, FALSE);
1873 fbioc_start_insert_poll(s);
1874 in_fbioc_disc_ready = FALSE;
1875 return FALSE;
1876 }
1877
1878 s->devlocked = TRUE;
1879 s->mode = MOD_NODISC;
1880
1881 if (fbioc_open(s->curdev)) {
1882 fbioc_not_open = FALSE;
1883
1884 if (!fbioc_is_enabled(DI_ROLE_MAIN)) {
1885 /* Enable device for I/O */
1886 fbioc_enable(DI_ROLE_MAIN);
1887 }
1888
1889 /* Check if a disc is loaded and ready */
1890 no_disc = !fbioc_disc_present(first_open);
1891 }
1892 else {
1893 DBGPRN(DBG_DEVIO)(errfp,
1894 "Open of %s failed\n", s->curdev);
1895 no_disc = TRUE;
1896 }
1897 }
1898 else {
1899 /* Just return success if we're playing CDDA */
1900 if (!fbioc_is_enabled(DI_ROLE_MAIN)) {
1901 no_disc = FALSE;
1902 }
1903 else if ((no_disc = !fbioc_disc_present(FALSE)) == TRUE) {
1904 /* The disc was manually ejected */
1905 s->mode = MOD_NODISC;
1906 di_clear_cdinfo(s, FALSE);
1907 }
1908 }
1909
1910 if (!no_disc) {
1911 if (first_open) {
1912 first_open = FALSE;
1913
1914 /* Fill in inquiry data */
1915 fbioc_vendor_model(s);
1916
1917 /* Initialize volume/balance/routing controls */
1918 fbioc_init_vol(s, TRUE);
1919 }
1920 else {
1921 /* Force to current settings */
1922 (void) fbioc_cfg_vol(s->level, s, FALSE);
1923
1924 /* Set up channel routing */
1925 fbioc_route(s);
1926 }
1927 }
1928
1929 /* Read disc table of contents if a new disc was detected */
1930 if (fbioc_not_open || no_disc ||
1931 (s->mode == MOD_NODISC && !fbioc_get_toc(s))) {
1932 if (fbioc_devp != NULL && app_data.eject_close) {
1933 fbioc_close();
1934 fbioc_not_open = TRUE;
1935 }
1936
1937 di_reset_curstat(s, TRUE, TRUE);
1938 DPY_ALL(s);
1939
1940 fbioc_start_insert_poll(s);
1941 in_fbioc_disc_ready = FALSE;
1942 return FALSE;
1943 }
1944
1945 if (s->mode != MOD_NODISC) {
1946 in_fbioc_disc_ready = FALSE;
1947 return TRUE;
1948 }
1949
1950 /* Load saved track program, if any */
1951 PROGGET(s);
1952
1953 s->mode = MOD_STOP;
1954 DPY_ALL(s);
1955
1956 /* Set caddy lock configuration */
1957 if (app_data.caddylock_supp)
1958 fbioc_lock(s, app_data.caddy_lock);
1959
1960 if (app_data.load_play) {
1961 /* Start auto-play */
1962 if (!fbioc_override_ap)
1963 fbioc_play_pause(s);
1964 }
1965 else if (app_data.load_spindown) {
1966 /* Spin down disc in case the user isn't going to
1967 * play anything for a while. This reduces wear and
1968 * tear on the drive.
1969 */
1970 (void) fbioc_start_stop(FALSE, FALSE);
1971 }
1972 else {
1973 switch (fbioc_tst_status) {
1974 case MOD_PLAY:
1975 case MOD_PAUSE:
1976 /* Drive is current playing audio or paused:
1977 * act appropriately.
1978 */
1979 s->mode = fbioc_tst_status;
1980 (void) fbioc_get_playstatus(s);
1981 DPY_ALL(s);
1982 if (s->mode == MOD_PLAY)
1983 fbioc_start_stat_poll(s);
1984 break;
1985 default:
1986 /* Drive is stopped: do nothing */
1987 break;
1988 }
1989 }
1990
1991 in_fbioc_disc_ready = FALSE;
1992
1993 /* Load CD information for this disc.
1994 * This operation has to be done outside the scope of
1995 * in_fbioc_disc_ready because it may recurse
1996 * back into this function.
1997 */
1998 (void) di_get_cdinfo(s);
1999
2000 return TRUE;
2001 }
2002
2003
2004 /*
2005 * fbioc_run_rew
2006 * Run search-rewind operation
2007 *
2008 * Args:
2009 * s - Pointer to the curstat_t structure
2010 *
2011 * Return:
2012 * Nothing.
2013 */
2014 STATIC void
fbioc_run_rew(curstat_t * s)2015 fbioc_run_rew(curstat_t *s)
2016 {
2017 int i,
2018 skip_blks;
2019 sword32_t addr,
2020 end_addr;
2021 msf_t smsf,
2022 emsf;
2023 static sword32_t start_addr,
2024 seq;
2025
2026 /* Find out where we are */
2027 if (!fbioc_get_playstatus(s)) {
2028 DO_BEEP();
2029 return;
2030 }
2031
2032 skip_blks = app_data.skip_blks;
2033 addr = s->curpos_tot.addr;
2034
2035 if (fbioc_start_search) {
2036 fbioc_start_search = FALSE;
2037 seq = 0;
2038 i = (int) (addr - skip_blks);
2039 }
2040 else {
2041 if (app_data.skip_spdup > 0 && seq > app_data.skip_spdup)
2042 /* Speed up search */
2043 skip_blks *= 3;
2044
2045 i = (int) (start_addr - skip_blks);
2046 }
2047
2048 start_addr = (sword32_t) ((i > di_clip_frames) ? i : di_clip_frames);
2049
2050 seq++;
2051
2052 if (s->shuffle || s->program) {
2053 if ((i = di_curtrk_pos(s)) < 0)
2054 i = 0;
2055
2056 if (start_addr < s->trkinfo[i].addr)
2057 start_addr = s->trkinfo[i].addr;
2058 }
2059 else if (s->segplay == SEGP_AB && start_addr < s->bp_startpos_tot.addr)
2060 start_addr = s->bp_startpos_tot.addr;
2061
2062 end_addr = start_addr + MAX_SRCH_BLKS;
2063
2064 util_blktomsf(
2065 start_addr,
2066 &smsf.min,
2067 &smsf.sec,
2068 &smsf.frame,
2069 MSF_OFFSET
2070 );
2071 util_blktomsf(
2072 end_addr,
2073 &emsf.min,
2074 &emsf.sec,
2075 &emsf.frame,
2076 MSF_OFFSET
2077 );
2078
2079 /* Play next search interval */
2080 (void) fbioc_do_playaudio(
2081 ADDR_BLK | ADDR_MSF | ADDR_OPTEND,
2082 start_addr, end_addr,
2083 &smsf, &emsf,
2084 0, 0
2085 );
2086
2087 if (di_clinfo->timeout != NULL) {
2088 fbioc_search_id = di_clinfo->timeout(
2089 app_data.skip_pause,
2090 fbioc_run_rew,
2091 (byte_t *) s
2092 );
2093 }
2094 }
2095
2096
2097 /*
2098 * fbioc_stop_rew
2099 * Stop search-rewind operation
2100 *
2101 * Args:
2102 * s - Pointer to the curstat_t structure
2103 *
2104 * Return:
2105 * Nothing.
2106 */
2107 /*ARGSUSED*/
2108 STATIC void
fbioc_stop_rew(curstat_t * s)2109 fbioc_stop_rew(curstat_t *s)
2110 {
2111 if (di_clinfo->untimeout != NULL)
2112 di_clinfo->untimeout(fbioc_search_id);
2113 }
2114
2115
2116 /*
2117 * fbioc_run_ff
2118 * Run search-fast-forward operation
2119 *
2120 * Args:
2121 * s - Pointer to the curstat_t structure
2122 *
2123 * Return:
2124 * Nothing.
2125 */
2126 STATIC void
fbioc_run_ff(curstat_t * s)2127 fbioc_run_ff(curstat_t *s)
2128 {
2129 int i,
2130 skip_blks;
2131 sword32_t addr,
2132 end_addr;
2133 msf_t smsf,
2134 emsf;
2135 static sword32_t start_addr,
2136 seq;
2137
2138 /* Find out where we are */
2139 if (!fbioc_get_playstatus(s)) {
2140 DO_BEEP();
2141 return;
2142 }
2143
2144 skip_blks = app_data.skip_blks;
2145 addr = s->curpos_tot.addr;
2146
2147 if (fbioc_start_search) {
2148 fbioc_start_search = FALSE;
2149 seq = 0;
2150 start_addr = addr + skip_blks;
2151 }
2152 else {
2153 if (app_data.skip_spdup > 0 && seq > app_data.skip_spdup)
2154 /* Speed up search */
2155 skip_blks *= 3;
2156
2157 start_addr += skip_blks;
2158 }
2159
2160 seq++;
2161
2162 if (s->shuffle || s->program) {
2163 if ((i = di_curtrk_pos(s)) < 0)
2164 i = s->tot_trks - 1;
2165 else if (s->cur_idx == 0)
2166 /* We're in the lead-in: consider this to be
2167 * within the previous track.
2168 */
2169 i--;
2170 }
2171 else
2172 i = s->tot_trks - 1;
2173
2174 end_addr = start_addr + MAX_SRCH_BLKS;
2175
2176 if (end_addr >= s->trkinfo[i+1].addr) {
2177 end_addr = s->trkinfo[i+1].addr;
2178 start_addr = end_addr - skip_blks;
2179 }
2180
2181 if (s->segplay == SEGP_AB && end_addr > s->bp_endpos_tot.addr) {
2182 end_addr = s->bp_endpos_tot.addr;
2183 start_addr = end_addr - skip_blks;
2184 }
2185
2186 util_blktomsf(
2187 start_addr,
2188 &smsf.min,
2189 &smsf.sec,
2190 &smsf.frame,
2191 MSF_OFFSET
2192 );
2193 util_blktomsf(
2194 end_addr,
2195 &emsf.min,
2196 &emsf.sec,
2197 &emsf.frame,
2198 MSF_OFFSET
2199 );
2200
2201 /* Play next search interval */
2202 (void) fbioc_do_playaudio(
2203 ADDR_BLK | ADDR_MSF | ADDR_OPTEND,
2204 start_addr, end_addr,
2205 &smsf, &emsf,
2206 0, 0
2207 );
2208
2209 if (di_clinfo->timeout != NULL) {
2210 fbioc_search_id = di_clinfo->timeout(
2211 app_data.skip_pause,
2212 fbioc_run_ff,
2213 (byte_t *) s
2214 );
2215 }
2216 }
2217
2218
2219 /*
2220 * fbioc_stop_ff
2221 * Stop search-fast-forward operation
2222 *
2223 * Args:
2224 * s - Pointer to the curstat_t structure
2225 *
2226 * Return:
2227 * Nothing.
2228 */
2229 /*ARGSUSED*/
2230 STATIC void
fbioc_stop_ff(curstat_t * s)2231 fbioc_stop_ff(curstat_t *s)
2232 {
2233 if (di_clinfo->untimeout != NULL)
2234 di_clinfo->untimeout(fbioc_search_id);
2235 }
2236
2237
2238 /*
2239 * fbioc_run_ab
2240 * Run a->b segment play operation
2241 *
2242 * Args:
2243 * s - Pointer to the curstat_t structure
2244 *
2245 * Return:
2246 * TRUE - success
2247 * FALSE - failure
2248 */
2249 /*ARGSUSED*/
2250 STATIC bool_t
fbioc_run_ab(curstat_t * s)2251 fbioc_run_ab(curstat_t *s)
2252 {
2253 msf_t start_msf,
2254 end_msf;
2255
2256 if ((s->bp_startpos_tot.addr + app_data.min_playblks) >=
2257 s->bp_endpos_tot.addr) {
2258 DO_BEEP();
2259 return FALSE;
2260 }
2261
2262 start_msf.min = s->bp_startpos_tot.min;
2263 start_msf.sec = s->bp_startpos_tot.sec;
2264 start_msf.frame = s->bp_startpos_tot.frame;
2265 end_msf.min = s->bp_endpos_tot.min;
2266 end_msf.sec = s->bp_endpos_tot.sec;
2267 end_msf.frame = s->bp_endpos_tot.frame;
2268 s->mode = MOD_PLAY;
2269 DPY_ALL(s);
2270 fbioc_start_stat_poll(s);
2271
2272 return (
2273 fbioc_do_playaudio(
2274 ADDR_BLK | ADDR_MSF,
2275 s->bp_startpos_tot.addr, s->bp_endpos_tot.addr,
2276 &start_msf, &end_msf,
2277 0, 0
2278 )
2279 );
2280 }
2281
2282
2283 /*
2284 * fbioc_run_sample
2285 * Run sample play operation
2286 *
2287 * Args:
2288 * s - Pointer to the curstat_t structure
2289 *
2290 * Return:
2291 * TRUE - success
2292 * FALSE - failure
2293 */
2294 STATIC bool_t
fbioc_run_sample(curstat_t * s)2295 fbioc_run_sample(curstat_t *s)
2296 {
2297 sword32_t saddr,
2298 eaddr;
2299 msf_t smsf,
2300 emsf;
2301
2302 if (fbioc_next_sam < s->tot_trks) {
2303 saddr = s->trkinfo[fbioc_next_sam].addr;
2304 eaddr = saddr + app_data.sample_blks,
2305
2306 util_blktomsf(
2307 saddr,
2308 &smsf.min,
2309 &smsf.sec,
2310 &smsf.frame,
2311 MSF_OFFSET
2312 );
2313 util_blktomsf(
2314 eaddr,
2315 &emsf.min,
2316 &emsf.sec,
2317 &emsf.frame,
2318 MSF_OFFSET
2319 );
2320
2321 if (s->trkinfo[fbioc_next_sam].type != TYP_AUDIO ||
2322 fbioc_do_playaudio(ADDR_BLK | ADDR_MSF,
2323 saddr, eaddr, &smsf, &emsf, 0, 0)) {
2324 fbioc_next_sam++;
2325 return TRUE;
2326 }
2327 }
2328
2329 fbioc_next_sam = 0;
2330 return FALSE;
2331 }
2332
2333
2334 /*
2335 * fbioc_run_prog
2336 * Run program/shuffle play operation
2337 *
2338 * Args:
2339 * s - Pointer to the curstat_t structure
2340 *
2341 * Return:
2342 * TRUE - success
2343 * FALSE - failure
2344 */
2345 STATIC bool_t
fbioc_run_prog(curstat_t * s)2346 fbioc_run_prog(curstat_t *s)
2347 {
2348 sword32_t i,
2349 start_addr,
2350 end_addr;
2351 msf_t start_msf,
2352 end_msf;
2353 bool_t hasaudio,
2354 ret;
2355
2356 if (!s->shuffle && !s->program)
2357 return FALSE;
2358
2359 if (fbioc_new_progshuf) {
2360 fbioc_new_progshuf = FALSE;
2361
2362 if (s->shuffle)
2363 /* New shuffle sequence needed */
2364 di_reset_shuffle(s);
2365 else
2366 /* Program play: simply reset the count */
2367 s->prog_cnt = 0;
2368
2369 /* Do not allow a program that contains only data tracks */
2370 hasaudio = FALSE;
2371 for (i = 0; i < (int) s->prog_tot; i++) {
2372 if (s->trkinfo[s->trkinfo[i].playorder].type ==
2373 TYP_AUDIO) {
2374 hasaudio = TRUE;
2375 break;
2376 }
2377 }
2378
2379 if (!hasaudio) {
2380 DO_BEEP();
2381 return FALSE;
2382 }
2383 }
2384
2385 if (s->prog_cnt >= s->prog_tot)
2386 /* Done with program/shuffle play cycle */
2387 return FALSE;
2388
2389 if ((i = di_curprog_pos(s)) < 0)
2390 return FALSE;
2391
2392 if (s->trkinfo[i].trkno == LEAD_OUT_TRACK)
2393 return FALSE;
2394
2395 s->prog_cnt++;
2396 s->cur_trk = s->trkinfo[i].trkno;
2397 s->cur_idx = 1;
2398
2399 start_addr = s->trkinfo[i].addr + s->curpos_trk.addr;
2400 util_blktomsf(
2401 start_addr,
2402 &s->curpos_tot.min,
2403 &s->curpos_tot.sec,
2404 &s->curpos_tot.frame,
2405 MSF_OFFSET
2406 );
2407 start_msf.min = s->curpos_tot.min;
2408 start_msf.sec = s->curpos_tot.sec;
2409 start_msf.frame = s->curpos_tot.frame;
2410
2411 end_addr = s->trkinfo[i+1].addr;
2412 end_msf.min = s->trkinfo[i+1].min;
2413 end_msf.sec = s->trkinfo[i+1].sec;
2414 end_msf.frame = s->trkinfo[i+1].frame;
2415
2416 s->curpos_tot.addr = start_addr;
2417
2418 if (s->mode != MOD_PAUSE)
2419 s->mode = MOD_PLAY;
2420
2421 DPY_ALL(s);
2422
2423 if (s->trkinfo[i].type == TYP_DATA)
2424 /* Data track: just fake it */
2425 return TRUE;
2426
2427 ret = fbioc_do_playaudio(
2428 ADDR_BLK | ADDR_MSF,
2429 start_addr, end_addr,
2430 &start_msf, &end_msf,
2431 0, 0
2432 );
2433
2434 if (s->mode == MOD_PAUSE) {
2435 (void) fbioc_pause_resume(FALSE);
2436
2437 /* Restore volume */
2438 fbioc_mute_off(s);
2439 }
2440
2441 return (ret);
2442 }
2443
2444
2445 /*
2446 * fbioc_run_repeat
2447 * Run repeat play operation
2448 *
2449 * Args:
2450 * s - Pointer to the curstat_t structure
2451 *
2452 * Return:
2453 * TRUE - success
2454 * FALSE - failure
2455 */
2456 STATIC bool_t
fbioc_run_repeat(curstat_t * s)2457 fbioc_run_repeat(curstat_t *s)
2458 {
2459 msf_t start_msf,
2460 end_msf;
2461 bool_t ret;
2462
2463 if (!s->repeat)
2464 return FALSE;
2465
2466 if (s->shuffle || s->program) {
2467 ret = TRUE;
2468
2469 if (s->prog_cnt < s->prog_tot)
2470 /* Not done with program/shuffle sequence yet */
2471 return (ret);
2472
2473 fbioc_new_progshuf = TRUE;
2474 s->rptcnt++;
2475 }
2476 else {
2477 s->cur_trk = s->first_trk;
2478 s->cur_idx = 1;
2479
2480 s->curpos_tot.addr = 0;
2481 s->curpos_tot.min = 0;
2482 s->curpos_tot.sec = 0;
2483 s->curpos_tot.frame = 0;
2484 s->rptcnt++;
2485 DPY_ALL(s);
2486
2487 start_msf.min = s->trkinfo[0].min;
2488 start_msf.sec = s->trkinfo[0].sec;
2489 start_msf.frame = s->trkinfo[0].frame;
2490 end_msf.min = s->discpos_tot.min;
2491 end_msf.sec = s->discpos_tot.sec;
2492 end_msf.frame = s->discpos_tot.frame;
2493
2494 ret = fbioc_do_playaudio(
2495 ADDR_BLK | ADDR_MSF,
2496 s->trkinfo[0].addr, s->discpos_tot.addr,
2497 &start_msf, &end_msf, 0, 0
2498 );
2499
2500 if (s->mode == MOD_PAUSE) {
2501 (void) fbioc_pause_resume(FALSE);
2502
2503 /* Restore volume */
2504 fbioc_mute_off(s);
2505 }
2506
2507 }
2508
2509 return (ret);
2510 }
2511
2512
2513 /***********************
2514 * public routines *
2515 ***********************/
2516
2517
2518 /*
2519 * fbioc_enable
2520 * Enable device in this process for I/O
2521 *
2522 * Args:
2523 * role - Role id for which I/O is to be enabled
2524 *
2525 * Return:
2526 * Nothing.
2527 */
2528 void
fbioc_enable(int role)2529 fbioc_enable(int role)
2530 {
2531 DBGPRN(DBG_DEVIO)(errfp, "Enable device: %s role: %d\n",
2532 fbioc_devp->path, role);
2533 fbioc_devp->role = role;
2534 }
2535
2536
2537 /*
2538 * fbioc_disable
2539 * Disable device in this process for I/O
2540 *
2541 * Args:
2542 * role - Role id for which I/O is to be disabled
2543 *
2544 * Return:
2545 * Nothing.
2546 */
2547 void
fbioc_disable(int role)2548 fbioc_disable(int role)
2549 {
2550 if (fbioc_devp->role != role) {
2551 DBGPRN(DBG_DEVIO)(errfp, "fbioc_disable: invalid role: %d\n",
2552 role);
2553 return;
2554 }
2555
2556 DBGPRN(DBG_DEVIO)(errfp, "Disable device: %s role: %d\n",
2557 fbioc_devp->path, role);
2558 fbioc_devp->role = 0;
2559 }
2560
2561
2562 /*
2563 * fbioc_is_enabled
2564 * Check whether device is enabled for I/O in this process
2565 *
2566 * Args:
2567 * role - Role id for which to check
2568 *
2569 * Return:
2570 * TRUE - enabled
2571 * FALSE - disabled
2572 */
2573 bool_t
fbioc_is_enabled(int role)2574 fbioc_is_enabled(int role)
2575 {
2576 return ((bool_t) (fbioc_devp->role == role));
2577 }
2578
2579
2580 /*
2581 * fbioc_send
2582 * Issue ioctl command.
2583 *
2584 * Args:
2585 * role - role id for which command is to be sent
2586 * cmd - ioctl command
2587 * arg - ioctl argument
2588 * prnerr - whether an error message is to be displayed if the ioctl fails
2589 *
2590 * Return:
2591 * TRUE - ioctl successful
2592 * FALSE - ioctl failed
2593 */
2594 bool_t
fbioc_send(int role,unsigned int cmd,void * arg,bool_t prnerr)2595 fbioc_send(int role, unsigned int cmd, void *arg, bool_t prnerr)
2596 {
2597 int i,
2598 ret;
2599 curstat_t *s = di_clinfo->curstat_addr();
2600
2601 if (fbioc_devp == NULL || fbioc_devp->fd <= 0)
2602 return FALSE;
2603
2604 if (fbioc_devp->role != role) {
2605 DBGPRN(DBG_DEVIO)(errfp,
2606 "NOTICE: fbioc_send: disabled role! (%d)\n",
2607 role);
2608 return FALSE;
2609 }
2610
2611 if (cmd == CDIOCREADAUDIO && fbioc_use_pread) {
2612 struct ioc_read_audio *p = (struct ioc_read_audio *) arg;
2613 int offset,
2614 nbytes;
2615
2616 offset = p->address.lba * CDDA_BLKSZ;
2617 nbytes = p->nframes * CDDA_BLKSZ;
2618
2619 DBGPRN(DBG_DEVIO)(errfp, "\nPREAD: offset=%d nbytes=%d\n",
2620 offset, nbytes);
2621
2622 ret = pread(fbioc_devp->fd, p->buffer, nbytes, offset);
2623 if (ret == nbytes)
2624 return TRUE;
2625
2626 if (prnerr) {
2627 (void) fprintf(errfp,
2628 "PREAD error on %s: ret=%d, errno=%d\n",
2629 s->curdev, ret, errno
2630 );
2631 }
2632 return FALSE;
2633 }
2634
2635 if (app_data.debug & DBG_DEVIO) {
2636 for (i = 0; iname[i].name != NULL; i++) {
2637 if (iname[i].cmd == cmd) {
2638 (void) fprintf(errfp, "\nIOCTL: %s arg=0x%lx ",
2639 iname[i].name, (long) arg);
2640 break;
2641 }
2642 }
2643 if (iname[i].name == NULL)
2644 (void) fprintf(errfp, "\nIOCTL: 0x%x arg=0x%lx ",
2645 cmd, (long) arg);
2646 }
2647
2648 ret = ioctl(fbioc_devp->fd, cmd, arg);
2649
2650 DBGPRN(DBG_DEVIO)(errfp, "ret=%d\n", ret);
2651
2652 if (ret < 0) {
2653 if (prnerr) {
2654 (void) fprintf(errfp, "CD audio: ioctl error on %s: ",
2655 s->curdev);
2656
2657 for (i = 0; iname[i].name != NULL; i++) {
2658 if (iname[i].cmd == cmd) {
2659 (void) fprintf(errfp,
2660 "cmd=%s errno=%d\n",
2661 iname[i].name, errno);
2662 break;
2663 }
2664 }
2665 if (iname[i].name == NULL)
2666 (void) fprintf(errfp, "cmd=0x%x errno=%d\n",
2667 cmd, errno);
2668 }
2669 return FALSE;
2670 }
2671
2672 return TRUE;
2673 }
2674
2675
2676 /*
2677 * fbioc_init
2678 * Top-level function to initialize the FreeBSD/NetBSD/OpenBSD
2679 * ioctl method.
2680 *
2681 * Args:
2682 * s - Pointer to the curstat_t structure
2683 *
2684 * Return:
2685 * Nothing.
2686 */
2687 void
fbioc_init(curstat_t * s,di_tbl_t * dt)2688 fbioc_init(curstat_t *s, di_tbl_t *dt)
2689 {
2690 char *cp;
2691 int kver,
2692 len;
2693
2694 if (app_data.di_method != DI_FBIOC)
2695 /* FreeBSD/NetBSD/OpenBSD ioctl method not configured */
2696 return;
2697
2698 /* Set the default CDDA read method based on running kernel version */
2699 len = sizeof(kver);
2700 if (sysctlbyname("kern.osreldate", &kver, &len, NULL, 0) < 0 ||
2701 kver < 501106)
2702 fbioc_use_pread = FALSE;
2703 else
2704 fbioc_use_pread = TRUE;
2705
2706 /* Allow the user to override the default CDDA read method via the
2707 * CDDA_USE_PREAD environment variable
2708 */
2709 if ((cp = getenv("CDDA_USE_PREAD")) != NULL)
2710 fbioc_use_pread = (bool_t) (atoi(cp) > 0);
2711
2712 /* Initialize libdi calling table */
2713 dt->load_cdtext = NULL;
2714 dt->playmode = fbioc_playmode;
2715 dt->check_disc = fbioc_check_disc;
2716 dt->status_upd = fbioc_status_upd;
2717 dt->lock = fbioc_lock;
2718 dt->repeat = fbioc_repeat;
2719 dt->shuffle = fbioc_shuffle;
2720 dt->load_eject = fbioc_load_eject;
2721 dt->ab = fbioc_ab;
2722 dt->sample = fbioc_sample;
2723 dt->level = fbioc_level;
2724 dt->play_pause = fbioc_play_pause;
2725 dt->stop = fbioc_stop;
2726 dt->chgdisc = fbioc_chgdisc;
2727 dt->prevtrk = fbioc_prevtrk;
2728 dt->nexttrk = fbioc_nexttrk;
2729 dt->previdx = fbioc_previdx;
2730 dt->nextidx = fbioc_nextidx;
2731 dt->rew = fbioc_rew;
2732 dt->ff = fbioc_ff;
2733 dt->warp = fbioc_warp;
2734 dt->route = fbioc_route;
2735 dt->mute_on = fbioc_mute_on;
2736 dt->mute_off = fbioc_mute_off;
2737 dt->cddajitter = fbioc_cddajitter;
2738 dt->debug = fbioc_debug;
2739 dt->start = fbioc_start;
2740 dt->icon = fbioc_icon;
2741 dt->halt = fbioc_halt;
2742 dt->methodstr = fbioc_methodstr;
2743
2744 /* Hardwire some unsupported features */
2745 app_data.chroute_supp = FALSE;
2746
2747 /* Initalize FreeBSD/NetBSD/OpenBSD ioctl method */
2748 fbioc_stat_polling = FALSE;
2749 fbioc_stat_interval = app_data.stat_interval;
2750 fbioc_insert_polling = FALSE;
2751 fbioc_next_sam = FALSE;
2752 fbioc_new_progshuf = FALSE;
2753 fbioc_sav_end_addr = 0;
2754 fbioc_sav_end_msf.min = fbioc_sav_end_msf.sec =
2755 fbioc_sav_end_msf.frame = 0;
2756 fbioc_sav_end_fmt = 0;
2757
2758 /* Initialize curstat structure */
2759 di_reset_curstat(s, TRUE, TRUE);
2760
2761 if (app_data.numdiscs > 1) {
2762 /* There is currently no changer support */
2763 DBGPRN(DBG_DEVIO)(errfp, "CD changer not supported:\n%s\n",
2764 "Setting to single disc mode.");
2765
2766 app_data.numdiscs = 1;
2767 app_data.chg_method = CHG_NONE;
2768 app_data.multi_play = FALSE;
2769 app_data.reverse = FALSE;
2770 s->first_disc = s->last_disc = s->cur_disc = 1;
2771 }
2772
2773 #ifdef __FreeBSD__
2774 DBGPRN(DBG_DEVIO)(errfp, "libdi: FreeBSD ioctl method\n");
2775 #endif
2776 #ifdef __NetBSD__
2777 DBGPRN(DBG_DEVIO)(errfp, "libdi: NetBSD ioctl method\n");
2778 #endif
2779 #ifdef __OpenBSD__
2780 DBGPRN(DBG_DEVIO)(errfp, "libdi: OpenBSD ioctl method\n");
2781 #endif
2782 }
2783
2784
2785 /*
2786 * fbioc_playmode
2787 * Init/halt CDDA mode
2788 *
2789 * Args:
2790 * s - Pointer to the curstat_t structure
2791 *
2792 * Return:
2793 * TRUE - success
2794 * FALSE - failure
2795 */
2796 bool_t
fbioc_playmode(curstat_t * s)2797 fbioc_playmode(curstat_t *s)
2798 {
2799 bool_t ret,
2800 cdda;
2801 static bool_t prev_cdda = FALSE;
2802
2803 cdda = (bool_t) PLAYMODE_IS_CDDA(app_data.play_mode);
2804
2805 if (cdda == prev_cdda)
2806 return TRUE; /* No change */
2807
2808 if (cdda) {
2809 fbioc_cdda_client.curstat_addr = di_clinfo->curstat_addr;
2810 fbioc_cdda_client.fatal_msg = di_clinfo->fatal_msg;
2811 fbioc_cdda_client.warning_msg = di_clinfo->warning_msg;
2812 fbioc_cdda_client.info_msg = di_clinfo->info_msg;
2813 fbioc_cdda_client.info2_msg = di_clinfo->info2_msg;
2814
2815 ret = cdda_init(s, &fbioc_cdda_client);
2816 }
2817 else {
2818 cdda_halt(fbioc_devp, s);
2819 ret = TRUE;
2820
2821 /* Initialize volume/balance/routing controls */
2822 fbioc_init_vol(s, FALSE);
2823 }
2824
2825 if (ret)
2826 prev_cdda = cdda;
2827
2828 return (ret);
2829 }
2830
2831
2832 /*
2833 * fbioc_check_disc
2834 * Check if disc is ready for use
2835 *
2836 * Args:
2837 * s - Pointer to the curstat_t structure
2838 *
2839 * Return:
2840 * TRUE - success
2841 * FALSE - failure
2842 */
2843 bool_t
fbioc_check_disc(curstat_t * s)2844 fbioc_check_disc(curstat_t *s)
2845 {
2846 return (fbioc_disc_ready(s));
2847 }
2848
2849
2850 /*
2851 * fbioc_status_upd
2852 * Force update of playback status
2853 *
2854 * Args:
2855 * s - Pointer to the curstat_t structure
2856 *
2857 * Return:
2858 * Nothing.
2859 */
2860 void
fbioc_status_upd(curstat_t * s)2861 fbioc_status_upd(curstat_t *s)
2862 {
2863 (void) fbioc_get_playstatus(s);
2864 }
2865
2866
2867 /*
2868 * fbioc_lock
2869 * Caddy lock function
2870 *
2871 * Args:
2872 * s - Pointer to the curstat_t structure
2873 * enable - whether to enable/disable caddy lock
2874 *
2875 * Return:
2876 * Nothing.
2877 */
2878 void
fbioc_lock(curstat_t * s,bool_t enable)2879 fbioc_lock(curstat_t *s, bool_t enable)
2880 {
2881 if (s->mode == MOD_BUSY || s->mode == MOD_NODISC) {
2882 SET_LOCK_BTN(FALSE);
2883 return;
2884 }
2885 else if (s->mode != MOD_STOP) {
2886 /* Only allow changing lock status when stopped */
2887 DO_BEEP();
2888 SET_LOCK_BTN((bool_t) !enable);
2889 return;
2890 }
2891
2892 if (!fbioc_send(DI_ROLE_MAIN, enable ? CDIOCPREVENT : CDIOCALLOW,
2893 NULL, TRUE)) {
2894 /* Cannot lock/unlock caddy */
2895 DO_BEEP();
2896 SET_LOCK_BTN((bool_t) !enable);
2897 return;
2898 }
2899
2900 s->caddy_lock = enable;
2901 SET_LOCK_BTN(enable);
2902 }
2903
2904
2905 /*
2906 * fbioc_repeat
2907 * Repeat mode function
2908 *
2909 * Args:
2910 * s - Pointer to the curstat_t structure
2911 * enable - whether to enable/disable repeat mode
2912 *
2913 * Return:
2914 * Nothing.
2915 */
2916 void
fbioc_repeat(curstat_t * s,bool_t enable)2917 fbioc_repeat(curstat_t *s, bool_t enable)
2918 {
2919 s->repeat = enable;
2920
2921 if (!enable && fbioc_new_progshuf) {
2922 fbioc_new_progshuf = FALSE;
2923 if (s->rptcnt > 0)
2924 s->rptcnt--;
2925 }
2926 DPY_RPTCNT(s);
2927 }
2928
2929
2930 /*
2931 * fbioc_shuffle
2932 * Shuffle mode function
2933 *
2934 * Args:
2935 * s - Pointer to the curstat_t structure
2936 * enable - whether to enable/disable shuffle mode
2937 *
2938 * Return:
2939 * Nothing.
2940 */
2941 void
fbioc_shuffle(curstat_t * s,bool_t enable)2942 fbioc_shuffle(curstat_t *s, bool_t enable)
2943 {
2944 if (s->segplay == SEGP_A) {
2945 /* Can't set shuffle during a->? mode */
2946 DO_BEEP();
2947 SET_SHUFFLE_BTN((bool_t) !enable);
2948 return;
2949 }
2950
2951 switch (s->mode) {
2952 case MOD_STOP:
2953 case MOD_BUSY:
2954 case MOD_NODISC:
2955 if (s->program) {
2956 /* Currently in program mode: can't enable shuffle */
2957 DO_BEEP();
2958 SET_SHUFFLE_BTN((bool_t) !enable);
2959 return;
2960 }
2961 break;
2962 default:
2963 if (enable) {
2964 /* Can't enable shuffle unless when stopped */
2965 DO_BEEP();
2966 SET_SHUFFLE_BTN((bool_t) !enable);
2967 return;
2968 }
2969 break;
2970 }
2971
2972 s->segplay = SEGP_NONE; /* Cancel a->b mode */
2973 DPY_PROGMODE(s, FALSE);
2974
2975 s->shuffle = enable;
2976 if (!s->shuffle)
2977 s->prog_tot = 0;
2978 }
2979
2980
2981 /*
2982 * fbioc_load_eject
2983 * CD caddy load and eject function. If disc caddy is not
2984 * loaded, it will attempt to load it. Otherwise, it will be
2985 * ejected.
2986 *
2987 * Args:
2988 * s - Pointer to the curstat_t structure
2989 *
2990 * Return:
2991 * Nothing.
2992 */
2993 void
fbioc_load_eject(curstat_t * s)2994 fbioc_load_eject(curstat_t *s)
2995 {
2996 bool_t ret = FALSE;
2997
2998 if (fbioc_devp == NULL)
2999 return;
3000
3001 if (fbioc_is_enabled(DI_ROLE_MAIN) && !fbioc_disc_present(FALSE)) {
3002 /* No disc */
3003 if (app_data.load_supp) {
3004 /* Try loading the disc */
3005 ret = fbioc_start_stop(TRUE, TRUE);
3006 }
3007
3008 if (!ret && app_data.eject_supp) {
3009 /* Cannot load, maybe the tray is already closed
3010 * but empty.
3011 */
3012
3013 /* Unlock caddy if supported */
3014 if (app_data.caddylock_supp)
3015 fbioc_lock(s, FALSE);
3016
3017 /* Try opening the tray */
3018 if (fbioc_start_stop(FALSE, TRUE))
3019 DO_BEEP();
3020 }
3021
3022 fbioc_stop_stat_poll();
3023 di_reset_curstat(s, TRUE, TRUE);
3024 s->mode = MOD_NODISC;
3025
3026 di_clear_cdinfo(s, FALSE);
3027 DPY_ALL(s);
3028
3029 if (fbioc_devp != NULL && app_data.eject_close) {
3030 fbioc_close();
3031 fbioc_not_open = TRUE;
3032 }
3033
3034 fbioc_start_insert_poll(s);
3035 return;
3036 }
3037
3038 /* Eject the disc */
3039
3040 /* Spin down the CD */
3041 (void) fbioc_start_stop(FALSE, FALSE);
3042
3043 if (!app_data.eject_supp) {
3044 DO_BEEP();
3045
3046 fbioc_stop_stat_poll();
3047 di_reset_curstat(s, TRUE, TRUE);
3048 s->mode = MOD_NODISC;
3049
3050 di_clear_cdinfo(s, FALSE);
3051 DPY_ALL(s);
3052
3053 if (fbioc_devp != NULL && app_data.eject_close) {
3054 fbioc_close();
3055 fbioc_not_open = TRUE;
3056 }
3057
3058 fbioc_start_insert_poll(s);
3059 return;
3060 }
3061
3062 /* Unlock caddy if supported */
3063 if (app_data.caddylock_supp)
3064 fbioc_lock(s, FALSE);
3065
3066 fbioc_stop_stat_poll();
3067 di_reset_curstat(s, TRUE, TRUE);
3068 s->mode = MOD_NODISC;
3069
3070 di_clear_cdinfo(s, FALSE);
3071 DPY_ALL(s);
3072
3073 /* Eject the CD */
3074 (void) fbioc_start_stop(FALSE, TRUE);
3075
3076 if (app_data.eject_exit)
3077 di_clinfo->quit(s);
3078 else {
3079 if (fbioc_devp != NULL && app_data.eject_close) {
3080 fbioc_close();
3081 fbioc_not_open = TRUE;
3082 }
3083
3084 fbioc_start_insert_poll(s);
3085 }
3086 }
3087
3088
3089 /*
3090 * fbioc_ab
3091 * A->B segment play mode function
3092 *
3093 * Args:
3094 * s - Pointer to the curstat_t structure
3095 *
3096 * Return:
3097 * Nothing.
3098 */
3099 void
fbioc_ab(curstat_t * s)3100 fbioc_ab(curstat_t *s)
3101 {
3102 if (!fbioc_run_ab(s))
3103 DO_BEEP();
3104 }
3105
3106
3107 /*
3108 * fbioc_sample
3109 * Sample play mode function
3110 *
3111 * Args:
3112 * s - Pointer to the curstat_t structure
3113 *
3114 * Return:
3115 * Nothing.
3116 */
3117 void
fbioc_sample(curstat_t * s)3118 fbioc_sample(curstat_t *s)
3119 {
3120 int i;
3121
3122 if (!fbioc_disc_ready(s)) {
3123 DO_BEEP();
3124 return;
3125 }
3126
3127 if (s->shuffle || s->program || s->segplay != SEGP_NONE) {
3128 /* Sample is not supported in program/shuffle or a->b modes */
3129 DO_BEEP();
3130 return;
3131 }
3132
3133 switch (s->mode) {
3134 case MOD_STOP:
3135 fbioc_start_stat_poll(s);
3136 /*FALLTHROUGH*/
3137 case MOD_PLAY:
3138 /* If already playing a track, start sampling the track after
3139 * the current one. Otherwise, sample from the beginning.
3140 */
3141 if (s->cur_trk > 0 && s->cur_trk != s->last_trk) {
3142 i = di_curtrk_pos(s) + 1;
3143 s->cur_trk = s->trkinfo[i].trkno;
3144 fbioc_next_sam = (byte_t) i;
3145 }
3146 else {
3147 s->cur_trk = s->first_trk;
3148 fbioc_next_sam = 0;
3149 }
3150
3151 s->cur_idx = 1;
3152
3153 s->mode = MOD_SAMPLE;
3154 DPY_ALL(s);
3155
3156 if (!fbioc_run_sample(s))
3157 return;
3158
3159 break;
3160
3161 case MOD_SAMPLE:
3162 /* Currently doing Sample playback, just call fbioc_play_pause
3163 * to resume normal playback.
3164 */
3165 fbioc_play_pause(s);
3166 break;
3167
3168 default:
3169 DO_BEEP();
3170 break;
3171 }
3172 }
3173
3174
3175 /*
3176 * fbioc_level
3177 * Audio volume control function
3178 *
3179 * Args:
3180 * s - Pointer to the curstat_t structure
3181 * level - The volume level to set to
3182 * drag - Whether this is an update due to the user dragging the
3183 * volume control slider thumb. If this is FALSE, then
3184 * a final volume setting has been found.
3185 *
3186 * Return:
3187 * Nothing.
3188 */
3189 /*ARGSUSED*/
3190 void
fbioc_level(curstat_t * s,byte_t level,bool_t drag)3191 fbioc_level(curstat_t *s, byte_t level, bool_t drag)
3192 {
3193 int actual;
3194
3195 /* Set volume level */
3196 if ((actual = fbioc_cfg_vol((int) level, s, FALSE)) >= 0)
3197 s->level = (byte_t) actual;
3198 }
3199
3200
3201 /*
3202 * fbioc_play_pause
3203 * Audio playback and pause function
3204 *
3205 * Args:
3206 * s - Pointer to the curstat_t structure
3207 *
3208 * Return:
3209 * Nothing.
3210 */
3211 void
fbioc_play_pause(curstat_t * s)3212 fbioc_play_pause(curstat_t *s)
3213 {
3214 sword32_t i,
3215 start_addr;
3216 msf_t start_msf,
3217 end_msf;
3218
3219 fbioc_override_ap = TRUE;
3220
3221 if (!fbioc_disc_ready(s)) {
3222 fbioc_override_ap = FALSE;
3223 DO_BEEP();
3224 return;
3225 }
3226
3227 fbioc_override_ap = FALSE;
3228
3229 if (s->mode == MOD_NODISC)
3230 s->mode = MOD_STOP;
3231
3232 switch (s->mode) {
3233 case MOD_PLAY:
3234 /* Currently playing: go to pause mode */
3235
3236 if (!fbioc_pause_resume(FALSE)) {
3237 DO_BEEP();
3238 return;
3239 }
3240 fbioc_stop_stat_poll();
3241 s->mode = MOD_PAUSE;
3242 DPY_PLAYMODE(s, FALSE);
3243 break;
3244
3245 case MOD_PAUSE:
3246 /* Currently paused: resume play */
3247
3248 if (!fbioc_pause_resume(TRUE)) {
3249 DO_BEEP();
3250 return;
3251 }
3252 s->mode = MOD_PLAY;
3253 DPY_PLAYMODE(s, FALSE);
3254 fbioc_start_stat_poll(s);
3255 break;
3256
3257 case MOD_STOP:
3258 /* Currently stopped: start play */
3259
3260 if (!di_prepare_cdda(s))
3261 return;
3262
3263 if (s->shuffle || s->program) {
3264 fbioc_new_progshuf = TRUE;
3265
3266 /* Start shuffle/program play */
3267 if (!fbioc_run_prog(s))
3268 return;
3269 }
3270 else if (s->segplay == SEGP_AB) {
3271 /* Play defined segment */
3272 if (!fbioc_run_ab(s))
3273 return;
3274 }
3275 else {
3276 s->segplay = SEGP_NONE; /* Cancel a->b mode */
3277
3278 /* Start normal play */
3279 if ((i = di_curtrk_pos(s)) < 0 || s->cur_trk <= 0) {
3280 /* Start play from the beginning */
3281 i = 0;
3282 s->cur_trk = s->first_trk;
3283 start_addr = s->trkinfo[0].addr +
3284 s->curpos_trk.addr;
3285 util_blktomsf(
3286 start_addr,
3287 &start_msf.min,
3288 &start_msf.sec,
3289 &start_msf.frame,
3290 MSF_OFFSET
3291 );
3292 }
3293 else {
3294 /* User has specified a starting track */
3295 start_addr = s->trkinfo[i].addr +
3296 s->curpos_trk.addr;
3297 }
3298
3299 util_blktomsf(
3300 start_addr,
3301 &start_msf.min,
3302 &start_msf.sec,
3303 &start_msf.frame,
3304 MSF_OFFSET
3305 );
3306
3307 end_msf.min = s->discpos_tot.min;
3308 end_msf.sec = s->discpos_tot.sec;
3309 end_msf.frame = s->discpos_tot.frame;
3310
3311 if (s->trkinfo[i].type == TYP_DATA) {
3312 DPY_TRACK(s);
3313 DPY_TIME(s, FALSE);
3314 DO_BEEP();
3315 return;
3316 }
3317
3318 s->cur_idx = 1;
3319 s->mode = MOD_PLAY;
3320
3321 if (!fbioc_do_playaudio(ADDR_BLK | ADDR_MSF,
3322 start_addr, s->discpos_tot.addr,
3323 &start_msf, &end_msf, 0, 0)) {
3324 DO_BEEP();
3325 s->mode = MOD_STOP;
3326 return;
3327 }
3328 }
3329
3330 DPY_ALL(s);
3331 fbioc_start_stat_poll(s);
3332 break;
3333
3334 case MOD_SAMPLE:
3335 /* Force update of curstat */
3336 if (!fbioc_get_playstatus(s)) {
3337 DO_BEEP();
3338 return;
3339 }
3340
3341 /* Currently doing a->b or sample playback: just resume play */
3342 if (s->shuffle || s->program) {
3343 if ((i = di_curtrk_pos(s)) < 0 ||
3344 s->trkinfo[i].trkno == LEAD_OUT_TRACK)
3345 return;
3346
3347 start_msf.min = s->curpos_tot.min;
3348 start_msf.sec = s->curpos_tot.sec;
3349 start_msf.frame = s->curpos_tot.frame;
3350 end_msf.min = s->trkinfo[i+1].min;
3351 end_msf.sec = s->trkinfo[i+1].sec;
3352 end_msf.frame = s->trkinfo[i+1].frame;
3353
3354 if (!fbioc_do_playaudio(ADDR_BLK | ADDR_MSF,
3355 s->curpos_tot.addr,
3356 s->trkinfo[i+1].addr,
3357 &start_msf, &end_msf, 0, 0)) {
3358 DO_BEEP();
3359 return;
3360 }
3361 }
3362 else {
3363 start_msf.min = s->curpos_tot.min;
3364 start_msf.sec = s->curpos_tot.sec;
3365 start_msf.frame = s->curpos_tot.frame;
3366 end_msf.min = s->discpos_tot.min;
3367 end_msf.sec = s->discpos_tot.sec;
3368 end_msf.frame = s->discpos_tot.frame;
3369
3370 if (!fbioc_do_playaudio(ADDR_BLK | ADDR_MSF,
3371 s->curpos_tot.addr,
3372 s->discpos_tot.addr,
3373 &start_msf, &end_msf, 0, 0)) {
3374 DO_BEEP();
3375 return;
3376 }
3377 }
3378 s->mode = MOD_PLAY;
3379 DPY_PLAYMODE(s, FALSE);
3380 break;
3381
3382 default:
3383 DO_BEEP();
3384 break;
3385 }
3386 }
3387
3388
3389 /*
3390 * fbioc_stop
3391 * Stop function
3392 *
3393 * Args:
3394 * s - Pointer to the curstat_t structure
3395 * stop_disc - Whether to actually spin down the disc or just
3396 * update status.
3397 *
3398 * Return:
3399 * Nothing.
3400 */
3401 void
fbioc_stop(curstat_t * s,bool_t stop_disc)3402 fbioc_stop(curstat_t *s, bool_t stop_disc)
3403 {
3404 /* The stop_disc parameter will cause the disc to spin down.
3405 * This is usually set to TRUE, but can be FALSE if the caller
3406 * just wants to set the current state to stop but will
3407 * immediately go into play state again. Not spinning down
3408 * the drive makes things a little faster...
3409 */
3410 if (!fbioc_disc_ready(s))
3411 return;
3412
3413 switch (s->mode) {
3414 case MOD_PLAY:
3415 case MOD_PAUSE:
3416 case MOD_SAMPLE:
3417 case MOD_STOP:
3418 /* Currently playing or paused: stop */
3419
3420 if (stop_disc && !fbioc_start_stop(FALSE, FALSE)) {
3421 DO_BEEP();
3422 return;
3423 }
3424 fbioc_stop_stat_poll();
3425
3426 di_reset_curstat(s, FALSE, FALSE);
3427 s->mode = MOD_STOP;
3428 s->rptcnt = 0;
3429
3430 DPY_ALL(s);
3431 break;
3432
3433 default:
3434 break;
3435 }
3436 }
3437
3438
3439 /*
3440 * fbioc_chgdisc
3441 * Change disc function
3442 *
3443 * Args:
3444 * s - Pointer to the curstat_t structure
3445 *
3446 * Return:
3447 * Nothing.
3448 */
3449 /*ARGSUSED*/
3450 void
fbioc_chgdisc(curstat_t * s)3451 fbioc_chgdisc(curstat_t *s)
3452 {
3453 /* Disc change is not implemented in this module */
3454 DO_BEEP();
3455 }
3456
3457
3458 /*
3459 * fbioc_prevtrk
3460 * Previous track function
3461 *
3462 * Args:
3463 * s - Pointer to the curstat_t structure
3464 *
3465 * Return:
3466 * Nothing.
3467 */
3468 void
fbioc_prevtrk(curstat_t * s)3469 fbioc_prevtrk(curstat_t *s)
3470 {
3471 sword32_t i,
3472 start_addr;
3473 msf_t start_msf,
3474 end_msf;
3475 bool_t go_prev;
3476
3477 if (!fbioc_disc_ready(s)) {
3478 DO_BEEP();
3479 return;
3480 }
3481
3482 switch (s->mode) {
3483 case MOD_SAMPLE:
3484 s->mode = MOD_PLAY;
3485 DPY_PLAYMODE(s, FALSE);
3486 /*FALLTHROUGH*/
3487 case MOD_PLAY:
3488 case MOD_PAUSE:
3489 /* Find appropriate track to start */
3490 if (s->shuffle || s->program) {
3491 if (s->prog_cnt > 0) {
3492 s->prog_cnt--;
3493 fbioc_new_progshuf = FALSE;
3494 }
3495 i = di_curprog_pos(s);
3496 }
3497 else
3498 i = di_curtrk_pos(s);
3499
3500 if (s->segplay == SEGP_AB) {
3501 s->segplay = SEGP_NONE; /* Cancel a->b mode */
3502 DPY_PROGMODE(s, FALSE);
3503 }
3504
3505 go_prev = FALSE;
3506
3507 if (i == 0 && s->cur_idx == 0) {
3508 i = 0;
3509 start_addr = di_clip_frames;
3510 util_blktomsf(
3511 start_addr,
3512 &start_msf.min,
3513 &start_msf.sec,
3514 &start_msf.frame,
3515 MSF_OFFSET
3516 );
3517 s->cur_trk = s->trkinfo[i].trkno;
3518 s->cur_idx = 0;
3519 }
3520 else {
3521 start_addr = s->trkinfo[i].addr;
3522 start_msf.min = s->trkinfo[i].min;
3523 start_msf.sec = s->trkinfo[i].sec;
3524 start_msf.frame = s->trkinfo[i].frame;
3525 s->cur_trk = s->trkinfo[i].trkno;
3526 s->cur_idx = 1;
3527
3528 /* If the current track has been playing for less
3529 * than app_data.prev_threshold blocks, then go
3530 * to the beginning of the previous track (if we
3531 * are not already on the first track).
3532 */
3533 if ((s->curpos_tot.addr - start_addr) <=
3534 app_data.prev_threshold)
3535 go_prev = TRUE;
3536 }
3537
3538 if (go_prev) {
3539 if (s->shuffle || s->program) {
3540 if (s->prog_cnt > 0) {
3541 s->prog_cnt--;
3542 fbioc_new_progshuf = FALSE;
3543 }
3544 if ((i = di_curprog_pos(s)) < 0)
3545 return;
3546
3547 start_addr = s->trkinfo[i].addr;
3548 start_msf.min = s->trkinfo[i].min;
3549 start_msf.sec = s->trkinfo[i].sec;
3550 start_msf.frame = s->trkinfo[i].frame;
3551 s->cur_trk = s->trkinfo[i].trkno;
3552 }
3553 else if (i == 0) {
3554 /* Go to the very beginning: this may be
3555 * a lead-in area before the start of track 1.
3556 */
3557 start_addr = di_clip_frames;
3558 util_blktomsf(
3559 start_addr,
3560 &start_msf.min,
3561 &start_msf.sec,
3562 &start_msf.frame,
3563 MSF_OFFSET
3564 );
3565 s->cur_trk = s->trkinfo[i].trkno;
3566 }
3567 else if (i > 0) {
3568 i--;
3569
3570 /* Skip over data tracks */
3571 while (s->trkinfo[i].type == TYP_DATA) {
3572 if (i <= 0)
3573 break;
3574 i--;
3575 }
3576
3577 if (s->trkinfo[i].type != TYP_DATA) {
3578 start_addr = s->trkinfo[i].addr;
3579 start_msf.min = s->trkinfo[i].min;
3580 start_msf.sec = s->trkinfo[i].sec;
3581 start_msf.frame = s->trkinfo[i].frame;
3582 s->cur_trk = s->trkinfo[i].trkno;
3583 }
3584 }
3585 }
3586
3587 if (s->mode == MOD_PAUSE)
3588 /* Mute: so we don't get a transient */
3589 fbioc_mute_on(s);
3590
3591 if (s->shuffle || s->program) {
3592 /* Program/Shuffle mode: just stop the playback
3593 * and let fbioc_run_prog go to the previous track
3594 */
3595 fbioc_fake_stop = TRUE;
3596
3597 /* Force status update */
3598 (void) fbioc_get_playstatus(s);
3599 }
3600 else {
3601 end_msf.min = s->discpos_tot.min;
3602 end_msf.sec = s->discpos_tot.sec;
3603 end_msf.frame = s->discpos_tot.frame;
3604
3605 s->curpos_tot.addr = start_addr;
3606 s->curpos_tot.min = start_msf.min;
3607 s->curpos_tot.sec = start_msf.sec;
3608 s->curpos_tot.frame = start_msf.frame;
3609 s->curpos_trk.addr = 0;
3610 s->curpos_trk.min = 0;
3611 s->curpos_trk.sec = 0;
3612 s->curpos_trk.frame = 0;
3613
3614 DPY_TRACK(s);
3615 DPY_INDEX(s);
3616 DPY_TIME(s, FALSE);
3617
3618 if (!fbioc_do_playaudio(ADDR_BLK | ADDR_MSF,
3619 start_addr, s->discpos_tot.addr,
3620 &start_msf, &end_msf, 0, 0)) {
3621 DO_BEEP();
3622
3623 /* Restore volume */
3624 fbioc_mute_off(s);
3625 return;
3626 }
3627
3628 if (s->mode == MOD_PAUSE) {
3629 (void) fbioc_pause_resume(FALSE);
3630
3631 /* Restore volume */
3632 fbioc_mute_off(s);
3633 }
3634 }
3635
3636 break;
3637
3638 case MOD_STOP:
3639 if (s->shuffle || s->program) {
3640 /* Pre-selecting tracks not supported in shuffle
3641 * or program mode.
3642 */
3643 DO_BEEP();
3644 return;
3645 }
3646
3647 /* Find previous track */
3648 if (s->cur_trk <= 0) {
3649 s->cur_trk = s->trkinfo[0].trkno;
3650 DPY_TRACK(s);
3651 }
3652 else {
3653 i = di_curtrk_pos(s);
3654
3655 if (i > 0) {
3656 s->cur_trk = s->trkinfo[i-1].trkno;
3657 DPY_TRACK(s);
3658 }
3659 }
3660 break;
3661
3662 default:
3663 DO_BEEP();
3664 break;
3665 }
3666 }
3667
3668
3669 /*
3670 * fbioc_nexttrk
3671 * Next track function
3672 *
3673 * Args:
3674 * s - Pointer to the curstat_t structure
3675 *
3676 * Return:
3677 * Nothing.
3678 */
3679 void
fbioc_nexttrk(curstat_t * s)3680 fbioc_nexttrk(curstat_t *s)
3681 {
3682 sword32_t i,
3683 start_addr;
3684 msf_t start_msf,
3685 end_msf;
3686
3687 if (!fbioc_disc_ready(s)) {
3688 DO_BEEP();
3689 return;
3690 }
3691
3692 switch (s->mode) {
3693 case MOD_SAMPLE:
3694 s->mode = MOD_PLAY;
3695 DPY_PLAYMODE(s, FALSE);
3696 /*FALLTHROUGH*/
3697 case MOD_PLAY:
3698 case MOD_PAUSE:
3699 if (s->shuffle || s->program) {
3700 if (s->prog_cnt >= s->prog_tot) {
3701 /* Disallow advancing beyond current
3702 * shuffle/program sequence if
3703 * repeat mode is not on.
3704 */
3705 if (s->repeat)
3706 fbioc_new_progshuf = TRUE;
3707 else
3708 return;
3709 }
3710
3711 if (s->mode == MOD_PAUSE)
3712 /* Mute: so we don't get a transient */
3713 fbioc_mute_on(s);
3714
3715 /* Program/Shuffle mode: just stop the playback
3716 * and let fbioc_run_prog go to the next track.
3717 */
3718 fbioc_fake_stop = TRUE;
3719
3720 /* Force status update */
3721 (void) fbioc_get_playstatus(s);
3722
3723 return;
3724 }
3725 else if (s->segplay == SEGP_AB) {
3726 s->segplay = SEGP_NONE; /* Cancel a->b mode */
3727 DPY_PROGMODE(s, FALSE);
3728 }
3729
3730 /* Find next track */
3731 if ((i = di_curtrk_pos(s)) < 0)
3732 return;
3733
3734 if (i > 0 || s->cur_idx > 0)
3735 i++;
3736
3737 /* Skip over data tracks */
3738 while (i < MAXTRACK && s->trkinfo[i].type == TYP_DATA)
3739 i++;
3740
3741 if (i < MAXTRACK &&
3742 s->trkinfo[i].trkno >= 0 &&
3743 s->trkinfo[i].trkno != LEAD_OUT_TRACK) {
3744
3745 start_addr = s->trkinfo[i].addr;
3746 start_msf.min = s->trkinfo[i].min;
3747 start_msf.sec = s->trkinfo[i].sec;
3748 start_msf.frame = s->trkinfo[i].frame;
3749 s->cur_trk = s->trkinfo[i].trkno;
3750 s->cur_idx = 1;
3751
3752 if (s->mode == MOD_PAUSE)
3753 /* Mute: so we don't get a transient */
3754 fbioc_mute_on(s);
3755
3756 end_msf.min = s->discpos_tot.min;
3757 end_msf.sec = s->discpos_tot.sec;
3758 end_msf.frame = s->discpos_tot.frame;
3759
3760 s->curpos_tot.addr = start_addr;
3761 s->curpos_tot.min = start_msf.min;
3762 s->curpos_tot.sec = start_msf.sec;
3763 s->curpos_tot.frame = start_msf.frame;
3764 s->curpos_trk.addr = 0;
3765 s->curpos_trk.min = 0;
3766 s->curpos_trk.sec = 0;
3767 s->curpos_trk.frame = 0;
3768
3769 DPY_TRACK(s);
3770 DPY_INDEX(s);
3771 DPY_TIME(s, FALSE);
3772
3773 if (!fbioc_do_playaudio(ADDR_BLK | ADDR_MSF,
3774 start_addr, s->discpos_tot.addr,
3775 &start_msf, &end_msf, 0, 0)) {
3776 DO_BEEP();
3777 return;
3778 }
3779
3780 if (s->mode == MOD_PAUSE) {
3781 (void) fbioc_pause_resume(FALSE);
3782
3783 /* Restore volume */
3784 fbioc_mute_off(s);
3785 }
3786 }
3787
3788 break;
3789
3790 case MOD_STOP:
3791 if (s->shuffle || s->program) {
3792 /* Pre-selecting tracks not supported in shuffle
3793 * or program mode.
3794 */
3795 DO_BEEP();
3796 return;
3797 }
3798
3799 /* Find next track */
3800 if (s->cur_trk <= 0) {
3801 s->cur_trk = s->trkinfo[0].trkno;
3802 DPY_TRACK(s);
3803 }
3804 else {
3805 i = di_curtrk_pos(s) + 1;
3806
3807 if (i > 0 && s->trkinfo[i].trkno != LEAD_OUT_TRACK) {
3808 s->cur_trk = s->trkinfo[i].trkno;
3809 DPY_TRACK(s);
3810 }
3811 }
3812 break;
3813
3814 default:
3815 DO_BEEP();
3816 break;
3817 }
3818 }
3819
3820
3821 /*
3822 * fbioc_previdx
3823 * Previous index function
3824 *
3825 * Args:
3826 * s - Pointer to the curstat_t structure
3827 *
3828 * Return:
3829 * Nothing.
3830 */
3831 void
fbioc_previdx(curstat_t * s)3832 fbioc_previdx(curstat_t *s)
3833 {
3834 msf_t start_msf,
3835 end_msf;
3836 byte_t idx;
3837
3838 if (s->shuffle || s->program) {
3839 /* Index search is not supported in program/shuffle mode */
3840 DO_BEEP();
3841 return;
3842 }
3843
3844 switch (s->mode) {
3845 case MOD_SAMPLE:
3846 s->mode = MOD_PLAY;
3847 DPY_PLAYMODE(s, FALSE);
3848 /*FALLTHROUGH*/
3849 case MOD_PLAY:
3850 case MOD_PAUSE:
3851 if (s->segplay == SEGP_AB) {
3852 s->segplay = SEGP_NONE; /* Cancel a->b mode */
3853 DPY_PROGMODE(s, FALSE);
3854 }
3855
3856 /* Find appropriate index to start */
3857 if (s->cur_idx > 1 &&
3858 (s->curpos_tot.addr - s->sav_iaddr) <=
3859 app_data.prev_threshold)
3860 idx = s->cur_idx - 1;
3861 else
3862 idx = s->cur_idx;
3863
3864 /* This is a Hack...
3865 * Since there is no standard command to start
3866 * playback on an index boundary and then go on playing
3867 * until the end of the disc, we will use the PLAY AUDIO
3868 * TRACK/INDEX command to go to where we want to start,
3869 * immediately followed by a PAUSE. We then find the
3870 * current block position and issue a PLAY AUDIO MSF
3871 * or PLAY AUDIO(12) command to start play there.
3872 * We mute the audio in between these operations to
3873 * prevent unpleasant transients.
3874 */
3875
3876 /* Mute */
3877 fbioc_mute_on(s);
3878
3879 if (!fbioc_do_playaudio(ADDR_TRKIDX, 0, 0, NULL, NULL,
3880 (byte_t) s->cur_trk, idx)) {
3881 /* Restore volume */
3882 fbioc_mute_off(s);
3883 DO_BEEP();
3884 return;
3885 }
3886
3887 /* A small delay to make sure the command took effect */
3888 util_delayms(10);
3889
3890 fbioc_idx_pause = TRUE;
3891
3892 if (!fbioc_pause_resume(FALSE)) {
3893 /* Restore volume */
3894 fbioc_mute_off(s);
3895 fbioc_idx_pause = FALSE;
3896 return;
3897 }
3898
3899 /* Use fbioc_get_playstatus to update the current status */
3900 if (!fbioc_get_playstatus(s)) {
3901 /* Restore volume */
3902 fbioc_mute_off(s);
3903 fbioc_idx_pause = FALSE;
3904 return;
3905 }
3906
3907 /* Save starting block addr of this index */
3908 s->sav_iaddr = s->curpos_tot.addr;
3909
3910 if (s->mode != MOD_PAUSE)
3911 /* Restore volume */
3912 fbioc_mute_off(s);
3913
3914 start_msf.min = s->curpos_tot.min;
3915 start_msf.sec = s->curpos_tot.sec;
3916 start_msf.frame = s->curpos_tot.frame;
3917 end_msf.min = s->discpos_tot.min;
3918 end_msf.sec = s->discpos_tot.sec;
3919 end_msf.frame = s->discpos_tot.frame;
3920
3921 if (!fbioc_do_playaudio(ADDR_BLK | ADDR_MSF,
3922 s->curpos_tot.addr, s->discpos_tot.addr,
3923 &start_msf, &end_msf, 0, 0)) {
3924 DO_BEEP();
3925 fbioc_idx_pause = FALSE;
3926 return;
3927 }
3928
3929 fbioc_idx_pause = FALSE;
3930
3931 if (s->mode == MOD_PAUSE) {
3932 (void) fbioc_pause_resume(FALSE);
3933
3934 /* Restore volume */
3935 fbioc_mute_off(s);
3936
3937 /* Force update of curstat */
3938 (void) fbioc_get_playstatus(s);
3939 }
3940
3941 break;
3942
3943 default:
3944 DO_BEEP();
3945 break;
3946 }
3947 }
3948
3949
3950 /*
3951 * fbioc_nextidx
3952 * Next index function
3953 *
3954 * Args:
3955 * s - Pointer to the curstat_t structure
3956 *
3957 * Return:
3958 * Nothing.
3959 */
3960 void
fbioc_nextidx(curstat_t * s)3961 fbioc_nextidx(curstat_t *s)
3962 {
3963 msf_t start_msf,
3964 end_msf;
3965
3966 if (s->shuffle || s->program) {
3967 /* Index search is not supported in program/shuffle mode */
3968 DO_BEEP();
3969 return;
3970 }
3971
3972 switch (s->mode) {
3973 case MOD_SAMPLE:
3974 s->mode = MOD_PLAY;
3975 DPY_PLAYMODE(s, FALSE);
3976 /*FALLTHROUGH*/
3977 case MOD_PLAY:
3978 case MOD_PAUSE:
3979 if (s->segplay == SEGP_AB) {
3980 s->segplay = SEGP_NONE; /* Cancel a->b mode */
3981 DPY_PROGMODE(s, FALSE);
3982 }
3983
3984 /* Find appropriate index to start */
3985
3986 /* This is a Hack...
3987 * Since there is no standard command to start
3988 * playback on an index boundary and then go on playing
3989 * until the end of the disc, we will use the PLAY AUDIO
3990 * TRACK/INDEX command to go to where we want to start,
3991 * immediately followed by a PAUSE. We then find the
3992 * current block position and issue a PLAY AUDIO MSF
3993 * or PLAY AUDIO(12) command to start play there.
3994 * We mute the audio in between these operations to
3995 * prevent unpleasant transients.
3996 */
3997
3998 /* Mute */
3999 fbioc_mute_on(s);
4000
4001 if (!fbioc_do_playaudio(ADDR_TRKIDX, 0, 0, NULL, NULL,
4002 (byte_t) s->cur_trk,
4003 (byte_t) (s->cur_idx + 1))) {
4004 /* Restore volume */
4005 fbioc_mute_off(s);
4006 DO_BEEP();
4007 return;
4008 }
4009
4010 /* A small delay to make sure the command took effect */
4011 util_delayms(10);
4012
4013 fbioc_idx_pause = TRUE;
4014
4015 if (!fbioc_pause_resume(FALSE)) {
4016 /* Restore volume */
4017 fbioc_mute_off(s);
4018 fbioc_idx_pause = FALSE;
4019 return;
4020 }
4021
4022 /* Use fbioc_get_playstatus to update the current status */
4023 if (!fbioc_get_playstatus(s)) {
4024 /* Restore volume */
4025 fbioc_mute_off(s);
4026 fbioc_idx_pause = FALSE;
4027 return;
4028 }
4029
4030 /* Save starting block addr of this index */
4031 s->sav_iaddr = s->curpos_tot.addr;
4032
4033 if (s->mode != MOD_PAUSE)
4034 /* Restore volume */
4035 fbioc_mute_off(s);
4036
4037 start_msf.min = s->curpos_tot.min;
4038 start_msf.sec = s->curpos_tot.sec;
4039 start_msf.frame = s->curpos_tot.frame;
4040 end_msf.min = s->discpos_tot.min;
4041 end_msf.sec = s->discpos_tot.sec;
4042 end_msf.frame = s->discpos_tot.frame;
4043
4044 if (!fbioc_do_playaudio(ADDR_BLK | ADDR_MSF,
4045 s->curpos_tot.addr, s->discpos_tot.addr,
4046 &start_msf, &end_msf, 0, 0)) {
4047 DO_BEEP();
4048 fbioc_idx_pause = FALSE;
4049 return;
4050 }
4051
4052 fbioc_idx_pause = FALSE;
4053
4054 if (s->mode == MOD_PAUSE) {
4055 (void) fbioc_pause_resume(FALSE);
4056
4057 /* Restore volume */
4058 fbioc_mute_off(s);
4059
4060 /* Force update of curstat */
4061 (void) fbioc_get_playstatus(s);
4062 }
4063
4064 break;
4065
4066 default:
4067 DO_BEEP();
4068 break;
4069 }
4070 }
4071
4072
4073 /*
4074 * fbioc_rew
4075 * Search-rewind function
4076 *
4077 * Args:
4078 * s - Pointer to the curstat_t structure
4079 *
4080 * Return:
4081 * Nothing.
4082 */
4083 void
fbioc_rew(curstat_t * s,bool_t start)4084 fbioc_rew(curstat_t *s, bool_t start)
4085 {
4086 sword32_t i;
4087 msf_t start_msf,
4088 end_msf;
4089 byte_t vol;
4090
4091 switch (s->mode) {
4092 case MOD_SAMPLE:
4093 /* Go to normal play mode first */
4094 fbioc_play_pause(s);
4095
4096 /*FALLTHROUGH*/
4097 case MOD_PLAY:
4098 case MOD_PAUSE:
4099 if (start) {
4100 /* Button press */
4101
4102 if (s->mode == MOD_PLAY)
4103 fbioc_stop_stat_poll();
4104
4105 if (PLAYMODE_IS_STD(app_data.play_mode)) {
4106 /* Reduce volume */
4107 vol = (byte_t) ((int) s->level *
4108 app_data.skip_vol / 100);
4109
4110 (void) fbioc_cfg_vol((int)
4111 ((vol < (byte_t)app_data.skip_minvol) ?
4112 (byte_t) app_data.skip_minvol : vol),
4113 s,
4114 FALSE
4115 );
4116 }
4117
4118 /* Start search rewind */
4119 fbioc_start_search = TRUE;
4120 fbioc_run_rew(s);
4121 }
4122 else {
4123 /* Button release */
4124
4125 fbioc_stop_rew(s);
4126
4127 /* Update display */
4128 (void) fbioc_get_playstatus(s);
4129
4130 if (s->mode == MOD_PAUSE)
4131 /* Mute: so we don't get a transient */
4132 fbioc_mute_on(s);
4133 else
4134 /* Restore volume */
4135 fbioc_mute_off(s);
4136
4137 if (s->shuffle || s->program) {
4138 if ((i = di_curtrk_pos(s)) < 0 ||
4139 s->trkinfo[i].trkno == LEAD_OUT_TRACK) {
4140 /* Restore volume */
4141 fbioc_mute_off(s);
4142 return;
4143 }
4144
4145 start_msf.min = s->curpos_tot.min;
4146 start_msf.sec = s->curpos_tot.sec;
4147 start_msf.frame = s->curpos_tot.frame;
4148 end_msf.min = s->trkinfo[i+1].min;
4149 end_msf.sec = s->trkinfo[i+1].sec;
4150 end_msf.frame = s->trkinfo[i+1].frame;
4151
4152 if (!fbioc_do_playaudio(ADDR_BLK | ADDR_MSF,
4153 s->curpos_tot.addr,
4154 s->trkinfo[i+1].addr,
4155 &start_msf, &end_msf,
4156 0, 0)) {
4157 DO_BEEP();
4158
4159 /* Restore volume */
4160 fbioc_mute_off(s);
4161 return;
4162 }
4163 }
4164 else {
4165 start_msf.min = s->curpos_tot.min;
4166 start_msf.sec = s->curpos_tot.sec;
4167 start_msf.frame = s->curpos_tot.frame;
4168 end_msf.min = s->discpos_tot.min;
4169 end_msf.sec = s->discpos_tot.sec;
4170 end_msf.frame = s->discpos_tot.frame;
4171
4172 if (!fbioc_do_playaudio(ADDR_BLK | ADDR_MSF,
4173 s->curpos_tot.addr,
4174 s->discpos_tot.addr,
4175 &start_msf, &end_msf,
4176 0, 0)) {
4177 DO_BEEP();
4178
4179 /* Restore volume */
4180 fbioc_mute_off(s);
4181 return;
4182 }
4183 }
4184
4185 if (s->mode == MOD_PAUSE) {
4186 (void) fbioc_pause_resume(FALSE);
4187
4188 /* Restore volume */
4189 fbioc_mute_off(s);
4190 }
4191 else
4192 fbioc_start_stat_poll(s);
4193 }
4194 break;
4195
4196 default:
4197 if (start)
4198 DO_BEEP();
4199 break;
4200 }
4201 }
4202
4203
4204 /*
4205 * fbioc_ff
4206 * Search-fast-forward function
4207 *
4208 * Args:
4209 * s - Pointer to the curstat_t structure
4210 *
4211 * Return:
4212 * Nothing.
4213 */
4214 void
fbioc_ff(curstat_t * s,bool_t start)4215 fbioc_ff(curstat_t *s, bool_t start)
4216 {
4217 sword32_t i,
4218 start_addr,
4219 end_addr;
4220 msf_t start_msf,
4221 end_msf;
4222 byte_t vol;
4223
4224 switch (s->mode) {
4225 case MOD_SAMPLE:
4226 /* Go to normal play mode first */
4227 fbioc_play_pause(s);
4228
4229 /*FALLTHROUGH*/
4230 case MOD_PLAY:
4231 case MOD_PAUSE:
4232 if (start) {
4233 /* Button press */
4234
4235 if (s->mode == MOD_PLAY)
4236 fbioc_stop_stat_poll();
4237
4238 if (PLAYMODE_IS_STD(app_data.play_mode)) {
4239 /* Reduce volume */
4240 vol = (byte_t) ((int) s->level *
4241 app_data.skip_vol / 100);
4242
4243 (void) fbioc_cfg_vol((int)
4244 ((vol < (byte_t)app_data.skip_minvol) ?
4245 (byte_t) app_data.skip_minvol : vol),
4246 s,
4247 FALSE
4248 );
4249 }
4250
4251 /* Start search forward */
4252 fbioc_start_search = TRUE;
4253 fbioc_run_ff(s);
4254 }
4255 else {
4256 /* Button release */
4257
4258 fbioc_stop_ff(s);
4259
4260 /* Update display */
4261 (void) fbioc_get_playstatus(s);
4262
4263 if (s->mode == MOD_PAUSE)
4264 /* Mute: so we don't get a transient */
4265 fbioc_mute_on(s);
4266 else
4267 /* Restore volume */
4268 fbioc_mute_off(s);
4269
4270 if (s->shuffle || s->program) {
4271 if ((i = di_curtrk_pos(s)) < 0 ||
4272 s->trkinfo[i].trkno == LEAD_OUT_TRACK) {
4273 /* Restore volume */
4274 fbioc_mute_off(s);
4275 return;
4276 }
4277
4278 start_addr = s->curpos_tot.addr;
4279 start_msf.min = s->curpos_tot.min;
4280 start_msf.sec = s->curpos_tot.sec;
4281 start_msf.frame = s->curpos_tot.frame;
4282 end_addr = s->trkinfo[i+1].addr;
4283 end_msf.min = s->trkinfo[i+1].min;
4284 end_msf.sec = s->trkinfo[i+1].sec;
4285 end_msf.frame = s->trkinfo[i+1].frame;
4286
4287 if (!fbioc_do_playaudio(ADDR_BLK | ADDR_MSF,
4288 start_addr, end_addr,
4289 &start_msf, &end_msf,
4290 0, 0)) {
4291 DO_BEEP();
4292
4293 /* Restore volume */
4294 fbioc_mute_off(s);
4295 return;
4296 }
4297 }
4298 else if (s->segplay == SEGP_AB &&
4299 (s->curpos_tot.addr + app_data.min_playblks) >
4300 s->bp_endpos_tot.addr) {
4301 /* No more left to play */
4302 /* Restore volume */
4303 fbioc_mute_off(s);
4304 return;
4305 }
4306 else {
4307 start_addr = s->curpos_tot.addr;
4308 start_msf.min = s->curpos_tot.min;
4309 start_msf.sec = s->curpos_tot.sec;
4310 start_msf.frame = s->curpos_tot.frame;
4311
4312 if (s->segplay == SEGP_AB) {
4313 end_addr = s->bp_endpos_tot.addr;
4314 end_msf.min = s->bp_endpos_tot.min;
4315 end_msf.sec = s->bp_endpos_tot.sec;
4316 end_msf.frame = s->bp_endpos_tot.frame;
4317 }
4318 else {
4319 end_addr = s->discpos_tot.addr;
4320 end_msf.min = s->discpos_tot.min;
4321 end_msf.sec = s->discpos_tot.sec;
4322 end_msf.frame = s->discpos_tot.frame;
4323 }
4324
4325 if (!fbioc_do_playaudio(ADDR_BLK | ADDR_MSF,
4326 start_addr, end_addr,
4327 &start_msf, &end_msf,
4328 0, 0)) {
4329 DO_BEEP();
4330
4331 /* Restore volume */
4332 fbioc_mute_off(s);
4333 return;
4334 }
4335 }
4336 if (s->mode == MOD_PAUSE) {
4337 (void) fbioc_pause_resume(FALSE);
4338
4339 /* Restore volume */
4340 fbioc_mute_off(s);
4341 }
4342 else
4343 fbioc_start_stat_poll(s);
4344 }
4345 break;
4346
4347 default:
4348 if (start)
4349 DO_BEEP();
4350 break;
4351 }
4352 }
4353
4354
4355 /*
4356 * fbioc_warp
4357 * Track warp function
4358 *
4359 * Args:
4360 * s - Pointer to the curstat_t structure
4361 *
4362 * Return:
4363 * Nothing.
4364 */
4365 void
fbioc_warp(curstat_t * s)4366 fbioc_warp(curstat_t *s)
4367 {
4368 sword32_t start_addr,
4369 end_addr;
4370 msf_t start_msf,
4371 end_msf;
4372 int i;
4373
4374 start_addr = s->curpos_tot.addr;
4375 start_msf.min = s->curpos_tot.min;
4376 start_msf.sec = s->curpos_tot.sec;
4377 start_msf.frame = s->curpos_tot.frame;
4378
4379 switch (s->mode) {
4380 case MOD_SAMPLE:
4381 /* Go to normal play mode first */
4382 fbioc_play_pause(s);
4383
4384 /*FALLTHROUGH*/
4385 case MOD_PLAY:
4386 case MOD_PAUSE:
4387 if (s->shuffle || s->program) {
4388 if ((i = di_curtrk_pos(s)) < 0) {
4389 DO_BEEP();
4390 return;
4391 }
4392
4393 end_addr = s->trkinfo[i+1].addr;
4394 end_msf.min = s->trkinfo[i+1].min;
4395 end_msf.sec = s->trkinfo[i+1].sec;
4396 end_msf.frame = s->trkinfo[i+1].frame;
4397 }
4398 else {
4399 end_addr = s->discpos_tot.addr;
4400 end_msf.min = s->discpos_tot.min;
4401 end_msf.sec = s->discpos_tot.sec;
4402 end_msf.frame = s->discpos_tot.frame;
4403 }
4404
4405 if (s->segplay == SEGP_AB) {
4406 if (start_addr < s->bp_startpos_tot.addr) {
4407 start_addr = s->bp_startpos_tot.addr;
4408 start_msf.min = s->bp_startpos_tot.min;
4409 start_msf.sec = s->bp_startpos_tot.sec;
4410 start_msf.frame = s->bp_startpos_tot.frame;
4411 }
4412
4413 if (end_addr > s->bp_endpos_tot.addr) {
4414 end_addr = s->bp_endpos_tot.addr;
4415 end_msf.min = s->bp_endpos_tot.min;
4416 end_msf.sec = s->bp_endpos_tot.sec;
4417 end_msf.frame = s->bp_endpos_tot.frame;
4418 }
4419 }
4420
4421 if ((end_addr - app_data.min_playblks) < start_addr) {
4422 /* No more left to play: just stop */
4423 if (!fbioc_start_stop(FALSE, FALSE))
4424 DO_BEEP();
4425 }
4426 else {
4427 if (s->mode == MOD_PAUSE)
4428 /* Mute: so we don't get a transient */
4429 fbioc_mute_on(s);
4430
4431 if (!fbioc_do_playaudio(ADDR_BLK | ADDR_MSF,
4432 start_addr, end_addr,
4433 &start_msf, &end_msf,
4434 0, 0)) {
4435 DO_BEEP();
4436
4437 /* Restore volume */
4438 fbioc_mute_off(s);
4439 return;
4440 }
4441
4442 if (s->mode == MOD_PAUSE) {
4443 (void) fbioc_pause_resume(FALSE);
4444
4445 /* Restore volume */
4446 fbioc_mute_off(s);
4447 }
4448 }
4449 break;
4450
4451 default:
4452 break;
4453 }
4454 }
4455
4456
4457 /*
4458 * fbioc_route
4459 * Channel routing function
4460 *
4461 * Args:
4462 * s - Pointer to the curstat_t structure
4463 *
4464 * Return:
4465 * Nothing.
4466 */
4467 void
fbioc_route(curstat_t * s)4468 fbioc_route(curstat_t *s)
4469 {
4470 if (!app_data.chroute_supp)
4471 return;
4472
4473 /* Only CDDA mode supports channel routing on FreeBSD/OpenBSD/NetBSD */
4474 if (PLAYMODE_IS_CDDA(app_data.play_mode))
4475 (void) cdda_chroute(fbioc_devp, s);
4476 }
4477
4478
4479 /*
4480 * fbioc_mute_on
4481 * Mute audio function
4482 *
4483 * Args:
4484 * s - Pointer to the curstat_t structure
4485 *
4486 * Return:
4487 * Nothing.
4488 */
4489 void
fbioc_mute_on(curstat_t * s)4490 fbioc_mute_on(curstat_t *s)
4491 {
4492 (void) fbioc_cfg_vol(0, s, FALSE);
4493 }
4494
4495
4496 /*
4497 * fbioc_mute_off
4498 * Un-mute audio function
4499 *
4500 * Args:
4501 * s - Pointer to the curstat_t structure
4502 *
4503 * Return:
4504 * Nothing.
4505 */
4506 void
fbioc_mute_off(curstat_t * s)4507 fbioc_mute_off(curstat_t *s)
4508 {
4509 (void) fbioc_cfg_vol((int) s->level, s, FALSE);
4510 }
4511
4512
4513 /*
4514 * fbioc_cddajitter
4515 * CDDA jitter correction setting change notification
4516 *
4517 * Args:
4518 * s - Pointer to the curstat_t structure
4519 *
4520 * Return:
4521 * Nothing.
4522 */
4523 void
fbioc_cddajitter(curstat_t * s)4524 fbioc_cddajitter(curstat_t *s)
4525 {
4526 sword32_t curblk = 0;
4527 byte_t omode;
4528
4529 if (PLAYMODE_IS_CDDA(app_data.play_mode)) {
4530 omode = s->mode;
4531 if (omode == MOD_PAUSE)
4532 omode = MOD_PLAY;
4533
4534 /* Save state */
4535 switch (omode) {
4536 case MOD_PLAY:
4537 case MOD_SAMPLE:
4538 curblk = s->curpos_tot.addr;
4539 fbioc_stop_stat_poll();
4540 break;
4541
4542 default:
4543 break;
4544 }
4545
4546 /* Restart CDDA */
4547 cdda_halt(fbioc_devp, s);
4548 util_delayms(1000);
4549
4550 fbioc_cdda_client.curstat_addr = di_clinfo->curstat_addr;
4551 fbioc_cdda_client.fatal_msg = di_clinfo->fatal_msg;
4552 fbioc_cdda_client.warning_msg = di_clinfo->warning_msg;
4553 fbioc_cdda_client.info_msg = di_clinfo->info_msg;
4554 fbioc_cdda_client.info2_msg = di_clinfo->info2_msg;
4555
4556 (void) cdda_init(s, &fbioc_cdda_client);
4557
4558 /* Restore old state */
4559 switch (omode) {
4560 case MOD_PLAY:
4561 case MOD_SAMPLE:
4562 if (fbioc_play_recov(curblk, FALSE)) {
4563 fbioc_start_stat_poll(s);
4564
4565 if (omode == MOD_PAUSE)
4566 (void) fbioc_pause_resume(FALSE);
4567 }
4568 break;
4569
4570 default:
4571 break;
4572 }
4573
4574 s->mode = omode;
4575 }
4576 }
4577
4578
4579 /*
4580 * fbioc_debug
4581 * Debug level change notification
4582 *
4583 * Args:
4584 * None.
4585 *
4586 * Return:
4587 * Nothing.
4588 */
4589 void
fbioc_debug(void)4590 fbioc_debug(void)
4591 {
4592 if (PLAYMODE_IS_CDDA(app_data.play_mode))
4593 cdda_debug(app_data.debug);
4594 }
4595
4596
4597 /*
4598 * fbioc_start
4599 * Start the FreeBSD/NetBSD/OpenBSD ioctl method.
4600 *
4601 * Args:
4602 * s - Pointer to the curstat_t structure
4603 *
4604 * Return:
4605 * Nothing.
4606 */
4607 void
fbioc_start(curstat_t * s)4608 fbioc_start(curstat_t *s)
4609 {
4610 /* Check to see if disc is ready */
4611 if (di_clinfo->timeout != NULL)
4612 fbioc_start_insert_poll(s);
4613 else
4614 (void) fbioc_disc_ready(s);
4615
4616 /* Update display */
4617 DPY_ALL(s);
4618 }
4619
4620
4621 /*
4622 * fbioc_icon
4623 * Handler for main window iconification/de-iconification
4624 *
4625 * Args:
4626 * s - Pointer to the curstat_t structure
4627 * iconified - Whether the main window is iconified
4628 *
4629 * Return:
4630 * Nothing.
4631 */
4632 void
fbioc_icon(curstat_t * s,bool_t iconified)4633 fbioc_icon(curstat_t *s, bool_t iconified)
4634 {
4635 /* This function attempts to reduce the status polling frequency
4636 * when possible to cut down on CPU and bus usage. This is
4637 * done when the CD player is iconified.
4638 */
4639
4640 /* Increase status polling interval by 4 seconds when iconified */
4641 if (iconified)
4642 fbioc_stat_interval = app_data.stat_interval + 4000;
4643 else
4644 fbioc_stat_interval = app_data.stat_interval;
4645
4646 switch (s->mode) {
4647 case MOD_BUSY:
4648 case MOD_NODISC:
4649 case MOD_STOP:
4650 case MOD_PAUSE:
4651 break;
4652
4653 case MOD_SAMPLE:
4654 /* No optimization in these modes */
4655 fbioc_stat_interval = app_data.stat_interval;
4656 break;
4657
4658 case MOD_PLAY:
4659 if (!iconified) {
4660 /* Force an immediate update */
4661 fbioc_stop_stat_poll();
4662 fbioc_start_stat_poll(s);
4663 }
4664 break;
4665 }
4666 }
4667
4668
4669 /*
4670 * fbioc_halt
4671 * Shut down the FreeBSD/NetBSD/OpenBSD ioctl method.
4672 *
4673 * Args:
4674 * s - Pointer to the curstat_t structure
4675 *
4676 * Return:
4677 * Nothing.
4678 */
4679 void
fbioc_halt(curstat_t * s)4680 fbioc_halt(curstat_t *s)
4681 {
4682 /* If playing CDDA, stop it */
4683 if (PLAYMODE_IS_CDDA(app_data.play_mode)) {
4684 switch (s->mode) {
4685 case MOD_PLAY:
4686 case MOD_PAUSE:
4687 case MOD_SAMPLE:
4688 (void) fbioc_start_stop(FALSE, FALSE);
4689 s->mode = MOD_STOP;
4690 fbioc_stop_stat_poll();
4691 break;
4692 default:
4693 break;
4694 }
4695 }
4696
4697 /* Shut down CDDA */
4698 cdda_halt(fbioc_devp, s);
4699 app_data.play_mode = PLAYMODE_STD;
4700
4701 /* Re-enable front-panel eject button */
4702 if (app_data.caddylock_supp)
4703 fbioc_lock(s, FALSE);
4704
4705 if (s->mode != MOD_BUSY && s->mode != MOD_NODISC) {
4706 if (app_data.exit_eject && app_data.eject_supp) {
4707 /* User closing application: Eject disc */
4708 (void) fbioc_start_stop(FALSE, TRUE);
4709 }
4710 else {
4711 if (app_data.exit_stop)
4712 /* User closing application: Stop disc */
4713 fbioc_start_stop(FALSE, FALSE);
4714
4715 switch (s->mode) {
4716 case MOD_PLAY:
4717 case MOD_PAUSE:
4718 case MOD_SAMPLE:
4719 fbioc_stop_stat_poll();
4720 break;
4721 default:
4722 break;
4723 }
4724 }
4725 }
4726
4727 if (fbioc_devp != NULL) {
4728 fbioc_close();
4729 fbioc_not_open = TRUE;
4730 }
4731 }
4732
4733
4734 /*
4735 * fbioc_methodstr
4736 * Return a text string indicating the current method.
4737 *
4738 * Args:
4739 * Nothing.
4740 *
4741 * Return:
4742 * Method text string.
4743 */
4744 char *
fbioc_methodstr(void)4745 fbioc_methodstr(void)
4746 {
4747 #ifdef __FreeBSD__
4748 return ("FreeBSD ioctl\n");
4749 #endif
4750 #ifdef __NetBSD__
4751 return ("NetBSD ioctl\n");
4752 #endif
4753 #ifdef __OpenBSD__
4754 return ("OpenBSD ioctl\n");
4755 #endif
4756 }
4757
4758
4759 #endif /* DI_FBIOC DEMO_ONLY */
4760
4761