1 /* $NetBSD: pkgsrc/audio/xcdplayer/files/cdrom_freebsd.c,v 1.6 2005/12/11 20:48:46 joerg Exp $ */
2 /*
3  * Copyright (C) 1990 Regents of the University of California.
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and
6  * its documentation for any purpose is hereby granted without fee,
7  * provided that the above copyright notice appear in all copies and that
8  * both that copyright notice and this permission notice appear in
9  * supporting documentation, and that the name of the University of
10  * California not be used in advertising or publicity pertaining to
11  * distribution of the software without specific, written prior
12  * permission.  the University of California makes no representations
13  * about the suitability of this software for any purpose.  It is provided
14  * "as is" without express or implied warranty.
15  */
16 
17 static int c;
18 
19 # include <stdio.h>
20 # include <sys/file.h>
21 # include <sys/types.h>
22 # include <sys/param.h>
23 # include <sys/stat.h>
24 # include <string.h>
25 # include <sys/time.h>
26 
27 #include <sys/ioctl.h>
28 #include <sys/disklabel.h>
29 #include <sys/cdio.h>
30 
31 # include "debug.h"
32 # include "cdrom_freebsd.h"
33 # include "app.h"
34 
35 #ifdef __NetBSD__
36 static char     cdrom[] =       "/dev/rcd0d";
37 static char     cdrom1[] =      "/dev/rmcd0d";
38 #else
39 static char     cdrom[] =       "/dev/cd0c";
40 static char     cdrom1[] =      "/dev/mcd0c";
41 #endif
42 
43 cdrom_info	cdi;
44 char		info_filename[256];
45 FILE		*disc_info = NULL;
46 
47 static int	cdrom_fd = -1;
48 
49 extern AppData app_data;
50 
get_stored_info()51 get_stored_info()
52 {
53 	int i,n;
54 	char	line[100];
55 	char	*title;
56 
57 	if(disc_info) {
58 	  fclose(disc_info);
59 	  disc_info = NULL;
60 	}
61 
62         if ( cdi.maxtrack == 0) {
63                 return(0);
64         }
65 	for (i = 0, n = 0; i < cdi.maxtrack; i++)
66 	    n = n + ((i+1) * cdi.times[i]);
67 	n = n / cdi.maxtrack;
68 
69         disc_title = NULL;
70 	if (app_data.cdInfoDir != NULL)
71 	    sprintf(info_filename, "%s/cd.%d", app_data.cdInfoDir, n);
72 	else
73 	    sprintf(info_filename, "cd.%d", n);
74 
75 	if ((disc_info = fopen(info_filename, "r")) != NULL)
76 	{
77 	    fgets(line, 100, disc_info);
78 	    title = strchr(line, ':');
79 	    if (title != NULL)
80 	    {
81 	    	*(strchr(title, '\n')) = '\0';
82 	        disc_title = strdup(title + 1);
83 	    }
84 	    fgets(line, 100, disc_info);
85 	    sscanf(line, "Program: %s", program_str);
86 	}
87 	else {
88                 disc_title = strdup(NOTITLESTR);
89 		program_str[0] = 0;
90 	      }
91         if (disc_title == NULL) {
92                 disc_title = strdup(NOTITLESTR);
93         }
94 }
95 
96 int
cdrom_open()97 cdrom_open() {
98 	int	n;
99 	extern void update_title();
100 
101 	if (cdrom_fd != -1)
102 		return(cdi.curtrack);
103 
104 	if (app_data.device != NULL) {
105 		if ((cdrom_fd = open(app_data.device, O_RDONLY)) == -1) {
106 			perror(app_data.device);
107 			return(-1);
108 		}
109 	} else {
110 		if (   (cdrom_fd = open(cdrom, O_RDONLY)) == -1
111 		    && (cdrom_fd = open(cdrom1, O_RDONLY)) == -1
112 		   ) {
113 			perror("open: ");
114 			return(-1);
115 		}
116 	}
117 
118 	if (cdrom_get_times() == -1) {
119 		cdrom_close();
120 		return(-1);
121 	}
122 
123 	if ((n = cdrom_get_curtrack()) == -1)
124 		return(-1);
125 
126 	get_stored_info();
127 
128 	update_title();
129 
130 	if (cdi.state & CDROM_STATE_PLAY)
131 		cdi.curtrack = n;
132 
133 	if (cdi.state & CDROM_STATE_SHUFFLE)
134 		shuffle_setup();
135 
136 	return(cdi.curtrack);
137 }
138 
139 void
cdrom_close()140 cdrom_close() {
141 	if (cdrom_fd == -1)
142 		return;
143 
144 	if (cdi.times != NULL) {
145 		free((char *) cdi.times);
146 		free((char *) cdi.addrs);
147 		cdi.times = NULL;
148 		cdi.addrs = NULL;
149 	}
150 
151 	(void) close(cdrom_fd);
152 	cdrom_fd = -1;
153 }
154 
155 
156 int
cdrom_start()157 cdrom_start() {
158 	if (cdrom_fd == -1)
159 		return(-1);
160 
161 	if (ioctl(cdrom_fd, CDIOCSTART) == -1) {
162 		perror("ioctl(cdromstart)");
163 		return(-1);
164 	}
165 
166 	return(0);
167 }
168 
169 int
cdrom_stop()170 cdrom_stop() {
171 	if (cdrom_fd == -1)
172 		return(-1);
173 
174 	if (ioctl(cdrom_fd, CDIOCSTOP) == -1) {
175 		perror("ioctl(cdromstop)");
176 		return(-1);
177 	}
178 
179 	return(0);
180 }
181 
182 int
cdrom_eject()183 cdrom_eject() {
184 	if (cdrom_fd == -1)
185 		return(-1);
186 
187         if (ioctl(cdrom_fd, CDIOCALLOW) == -1) {
188 		perror("ioctl(cdromallow)");
189 		return(-1);
190 	}
191 
192 	if (ioctl(cdrom_fd, CDIOCEJECT) == -1) {
193 		perror("ioctl(cdromeject)");
194 		return(-1);
195 	}
196 
197 	return(0);
198 }
199 
200 int
cdrom_pause()201 cdrom_pause() {
202 	if (cdrom_fd == -1)
203 		return(-1);
204 
205 	if (ioctl(cdrom_fd, CDIOCPAUSE) == -1) {
206 		perror("ioctl(cdrompause)");
207 		return(-1);
208 	}
209 
210 	return(0);
211 }
212 
213 int
cdrom_resume()214 cdrom_resume() {
215 	if (cdrom_fd == -1)
216 		return(-1);
217 
218 	if (ioctl(cdrom_fd, CDIOCRESUME) == -1) {
219 		perror("ioctl(cdromresume)");
220 		return(-1);
221 	}
222 
223 	return(0);
224 }
225 
226 int
cdrom_volume(left_vol,right_vol)227 cdrom_volume(left_vol, right_vol)
228 	int			left_vol;
229 	int			right_vol;
230 {
231 	struct ioc_vol	vol;
232 
233 	if (cdrom_fd == -1)
234 		return(-1);
235 
236 	vol.vol[0] = left_vol;
237 	vol.vol[1] = right_vol;
238 	vol.vol[2] = 0;
239 	vol.vol[3] = 0;
240 
241 	if (ioctl(cdrom_fd, CDIOCSETVOL, &vol) == -1) {
242 		perror("ioctl(cdromvolctrl)");
243 		return(-1);
244 	}
245 
246 	return(0);
247 }
248 
249 int
cdrom_get_times()250 cdrom_get_times() {
251 	struct ioc_toc_header	tochdr;
252 	extern unsigned short	*ushort_malloc();
253 	extern struct msf	*msf_malloc();
254 	unsigned long		trk, trk_total, otime;
255 	struct msf		msf;
256 
257 	if (cdrom_read_tochdr(&tochdr) == -1)
258 		return(-1);
259 
260 	cdi.mintrack = tochdr.starting_track;
261 	cdi.maxtrack = tochdr.ending_track;
262 
263 	if (cdi.times != NULL)
264 	{
265 		free((char *) cdi.times);
266 		free((char *) cdi.addrs);
267 		cdi.times = NULL;
268 		cdi.addrs = NULL;
269 	}
270 
271 	cdi.times = ushort_malloc(cdi.maxtrack - cdi.mintrack + 1);
272 	cdi.addrs = msf_malloc(cdi.maxtrack - cdi.mintrack + 2);
273 
274 	otime = 0;
275 
276 	for (trk = cdi.mintrack; trk <= cdi.maxtrack; trk++) {
277 		if (cdrom_get_msf(trk, &msf, &trk_total) == -1)
278 			return(-1);
279 
280 		/* record start address for each track (track 1 starts at 0)*/
281 		cdi.addrs[trk - cdi.mintrack] = msf;
282 
283 		trk_total -= otime;
284 
285 		/* use start time of next track as length of previous */
286 		if (otime != 0)
287 		{
288 			cdi.times[trk - cdi.mintrack - 1] = trk_total;
289 		}
290 
291 		otime += trk_total;
292 
293 	}
294 
295         /* find start of  leadout to get length of last track */
296         if (cdrom_get_msf(CDROM_LEADOUT, &msf, &trk_total) == -1)
297                 return(-1);
298 
299         /* recode leadout start address */
300         cdi.addrs[trk - cdi.mintrack] = msf;
301         trk_total -= otime;
302         otime += trk_total;
303 
304         cdi.times[trk - cdi.mintrack - 1] = trk_total;
305 	return(0);
306 }
307 
308 int
cdrom_get_curtrack()309 cdrom_get_curtrack() {
310 	struct cd_sub_channel_info data;
311 
312 	if (cdrom_read_subchannel(&data) == -1)
313 	  return(-1);
314 
315 	switch (data.header.audio_status) {
316 		case CD_AS_AUDIO_INVALID:
317 		return(-1);
318 
319 		/* playing track subchnl.cdsc_trk */
320 	      case CD_AS_PLAY_IN_PROGRESS:
321 		return((int) data.what.position.track_number);
322 
323 		/* paused on track subchnl.cdsc_trk */
324 	      case CD_AS_PLAY_PAUSED:
325 		return((int) data.what.position.track_number);
326 
327 		/* punt */
328 	      case CD_AS_PLAY_COMPLETED:
329 		return(0);
330 
331 	      case CD_AS_PLAY_ERROR:
332 		return(-1);
333 
334 		/* punt */
335 	      case CD_AS_NO_STATUS:
336 		debug_printf(1, "cdrom_get_curtrack: no status\n");
337 		return(0);
338 	}
339 
340 	/* bad value in cdsc_audiostatus */
341 	return(-1);
342 }
343 
344 int
cdrom_get_msf(track,msf,length)345 cdrom_get_msf(track, msf, length)
346 	unsigned long		track;
347 	struct msf		*msf;
348 	unsigned long		*length;
349 {
350         struct cd_toc_entry     data;
351 
352 	if (cdrom_read_tocentry(track, &data, sizeof(data)) == -1)
353 	  return(-1);
354 
355 	msf->minute = data.addr.msf.minute;
356 	msf->second = data.addr.msf.second;
357 	msf->frame =  data.addr.msf.frame;
358 	*length = (((unsigned int) msf->minute) * 60) + (unsigned int) msf->second;
359 	return(0);
360 }
361 
362 int
cdrom_get_curmsf(msf)363 cdrom_get_curmsf(msf)
364 	struct msf *msf;
365 {
366 	struct cd_sub_channel_info data;
367 
368 	if (cdrom_read_subchannel(&data) == -1)
369 	  return(-1);
370 
371 	msf->minute = data.what.position.absaddr.msf.minute;
372 	msf->second = data.what.position.absaddr.msf.second;
373 	msf->frame =  data.what.position.absaddr.msf.frame;
374 	return (0);
375 }
376 
377 int
cdrom_play_track(start_track,end_track)378 cdrom_play_track(start_track, end_track)
379 	unsigned char		start_track;
380 	unsigned char		end_track;
381 {
382 	struct	ioc_play_track	ti;
383 	struct	ioc_play_msf	play_addr;
384 	char *addr;
385 
386 	if (cdrom_fd == -1)
387 		return(-1);
388 
389 	play_addr.start_m = cdi.addrs[start_track - cdi.mintrack].minute;
390 	play_addr.start_s = cdi.addrs[start_track - cdi.mintrack].second;
391 	play_addr.start_f = cdi.addrs[start_track - cdi.mintrack].frame;
392 	play_addr.end_m = cdi.addrs[end_track - cdi.mintrack + 1].minute;
393 	play_addr.end_s = cdi.addrs[end_track - cdi.mintrack + 1].second;
394 	play_addr.end_f = cdi.addrs[end_track - cdi.mintrack + 1].frame - 1;
395 
396 	if(play_addr.end_f >= 75) {
397 	  play_addr.end_f = 74;
398 	  play_addr.end_s--;
399 	}
400 	if(play_addr.end_s >= 60) {
401 	  play_addr.end_s = 59;
402 	  play_addr.end_m--;
403 	}
404 	addr = (char *)&play_addr;
405 	if (ioctl(cdrom_fd, CDIOCPLAYMSF, &play_addr) == -1) {
406 		perror("ioctl(cdromplaymsftrk)");
407 		return(-1);
408 	}
409 
410 	return(0);
411 }
412 
413 int
cdrom_play_msf(start_msf,end_msf)414 cdrom_play_msf(start_msf, end_msf)
415 	struct msf	*start_msf;
416 	struct msf	*end_msf;
417 {
418 	struct	ioc_play_msf	play_addr;
419 
420 	if (cdrom_fd == -1)
421 		return(-1);
422 
423 	play_addr.start_m = start_msf->minute;
424 	play_addr.start_s = start_msf->second;
425 	play_addr.start_f = start_msf->frame;
426 	play_addr.end_m = end_msf->minute;
427 	play_addr.end_s = end_msf->second;
428 	play_addr.end_f = end_msf->frame;
429 
430 	if (ioctl(cdrom_fd, CDIOCPLAYMSF, &play_addr) == -1) {
431 		perror("ioctl(cdromplaymsf)");
432 		return(-1);
433 	}
434 
435 	return(0);
436 }
437 
438 
439 int
cdrom_read_subchannel(data)440 cdrom_read_subchannel(data)
441 	struct cd_sub_channel_info *data;
442 {
443 	struct ioc_read_subchannel	subchnl;
444 
445 	if (cdrom_fd == -1)
446 		return(-1);
447 
448         subchnl.address_format = CD_MSF_FORMAT;
449 	subchnl.data_format = CD_CURRENT_POSITION;
450 	subchnl.data_len = /* sizeof(struct cd_sub_channel_info)*/ 16;
451 	subchnl.track = 0;
452 	subchnl.data = data;
453 
454 	if (ioctl(cdrom_fd, CDIOCREADSUBCHANNEL, (char *) &subchnl) == -1) {
455 		fprintf(stderr, "ioctl(cdromsubchnl): ");
456 		perror(cdrom);
457 		return(-1);
458 	}
459 
460 	return(0);
461 }
462 
463 int
cdrom_read_track(track,data)464 cdrom_read_track(track, data)
465 	unsigned int		track;
466 	struct cd_sub_channel_info *data;
467 {
468 	struct ioc_read_subchannel	subchnl;
469 
470 	if (cdrom_fd == -1)
471 		return(-1);
472 
473 	subchnl.address_format = CD_MSF_FORMAT;
474 	subchnl.data_format = CD_TRACK_INFO;
475 	subchnl.data_len = /* sizeof(struct cd_sub_channel_info)*/ 24;
476 	subchnl.track = track;
477 	subchnl.data = data;
478 
479 	if (ioctl(cdrom_fd, CDIOCREADSUBCHANNEL, (char *) &subchnl) == -1) {
480 		fprintf(stderr, "ioctl(cdromsubchnltrk): ");
481 		perror(cdrom);
482 		return(-1);
483 	}
484 
485 	return(0);
486 }
487 
488 int
cdrom_read_tocentry(track,data,size)489 cdrom_read_tocentry(track, data, size)
490 	unsigned int		track;
491         struct cd_toc_entry *data;
492      int size;
493 {
494 	struct ioc_read_toc_entry tocentry;
495 
496 	if (cdrom_fd == -1)
497 		return(-1);
498 
499 	tocentry.starting_track = (unsigned char)track;
500 	tocentry.address_format = CD_MSF_FORMAT;
501 	tocentry.data_len = /* sizeof(struct cd_toc_entry)*/ size;
502 	tocentry.data = data;
503 
504 	if (ioctl(cdrom_fd, CDIOREADTOCENTRYS, (char *) &tocentry) == -1) {
505 		perror("ioctl(cdromreadtocentry)");
506 		return(-1);
507 	}
508 
509 	return(0);
510 }
511 
512 int
cdrom_read_tochdr(tochdr)513 cdrom_read_tochdr(tochdr)
514 	struct ioc_toc_header	*tochdr;
515 {
516 	if (cdrom_fd == -1)
517 		return(-1);
518 
519 	if (ioctl(cdrom_fd, CDIOREADTOCHEADER, (char *) tochdr) == -1) {
520 		perror("ioctl(cdromreadtochdr): ");
521 		return(-1);
522 	}
523 
524 	return(0);
525 }
526 
527 int
cdrom_status()528 cdrom_status() {
529 	struct cd_sub_channel_info data;
530 
531 	if (cdrom_read_subchannel(&data) == -1)
532 	  return(-1);
533 
534 	switch (data.header.audio_status) {
535 		case CD_AS_AUDIO_INVALID:
536 		return(CDROM_INVALID);
537 
538 		case CD_AS_PLAY_IN_PROGRESS:
539 		return(CDROM_PLAYING);
540 
541 		case CD_AS_PLAY_PAUSED:
542 		return(CDROM_PAUSED);
543 
544 		case CD_AS_PLAY_COMPLETED:
545 		return(CDROM_COMPLETED);
546 
547 		case CD_AS_PLAY_ERROR:
548 		return(CDROM_ERROR);
549 
550 		case CD_AS_NO_STATUS:
551 		return(CDROM_NO_STATUS);
552 	}
553 
554 	return(-1);
555 }
556 
557 unsigned short *
ushort_malloc(n)558 ushort_malloc(n)
559 	int		n;
560 {
561 	extern char	*calloc();
562 	unsigned short	*ptr;
563 
564 	ptr = (unsigned short *) calloc(n, sizeof(unsigned short));
565 	if (ptr == NULL) {
566 		perror("calloc");
567 		exit(1);
568 	}
569 
570 	return(ptr);
571 }
572 
573 struct msf *
msf_malloc(n)574 msf_malloc(n)
575 	int		n;
576 {
577 	extern char	*calloc();
578 	struct msf	*ptr;
579 
580 	ptr = (struct msf *) calloc(n, sizeof(struct msf));
581 	if (ptr == NULL) {
582 		perror("calloc");
583 		exit(1);
584 	}
585 
586 	return(ptr);
587 }
588 
589 int
cdrom_disp_cdi()590 cdrom_disp_cdi() {
591 	int trk;
592 
593 	fprintf(stderr,"CDI structure:\n");
594 	fprintf(stderr,"\tcurtrack: %d\n",cdi.curtrack);
595 	fprintf(stderr,"\tmin: %d  max: %d  total: %d\n",
596 		cdi.mintrack, cdi.maxtrack, cdi.ntracks);
597 	fprintf(stderr,"\tdur: %d  state: %2x\n",cdi.duration, cdi.state);
598 	fprintf(stderr,"\tcurrand: %d  lastprog: %d\n",
599 		cdi.currand, cdi.lastprog);
600 	fprintf(stderr,"\n\tTracklist:\n");
601 	if (cdi.maxtrack != cdi.mintrack) {
602 		for (trk=0; trk<=cdi.maxtrack-cdi.mintrack+1; trk++) {
603 			fprintf(stderr,"\t%3d: %d %02d:%02d %d\n",trk,cdi.times[trk],
604 				cdi.addrs[trk].minute,cdi.addrs[trk].second,
605 				cdi.addrs[trk].frame);
606 		}
607 	}
608 }
609