libdockapp: fix multiple definitions of global variable.
[dockapps.git] / ascd / libworkman / plat_sun.c
blob14005dea57207ceb1490ce88181595dabe994852
1 /*
2 * $Id: plat_sun.c,v 1.9 1999/05/28 03:35:54 dirk Exp $
4 * This file is part of WorkMan, the civilized CD player library
5 * (c) 1991-1997 by Steven Grimm (original author)
6 * (c) by Dirk Försterling (current 'author' = maintainer)
7 * The maintainer can be contacted by his e-mail address:
8 * milliByte@DeathsDoor.com
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public
21 * License along with this library; if not, write to the Free
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 * Sun-specific drive control routines.
28 #ifdef sun
29 static char plat_sun_id[] = "$Id: plat_sun.c,v 1.9 1999/05/28 03:35:54 dirk Exp $";
31 #include <errno.h>
32 #include <stdio.h>
33 #include <sys/types.h>
34 #include <fcntl.h>
35 #include <string.h>
36 #include <sys/param.h>
37 #include <sys/stat.h>
38 #include <sys/time.h>
39 #include <sys/ioctl.h>
41 #include "include/wm_config.h"
42 #include "include/wm_helpers.h"
43 #include "include/wm_cdrom.h"
46 #include <ustat.h>
47 #include <unistd.h>
48 #include <signal.h>
49 #ifdef solbourne
50 # include <mfg/dklabel.h>
51 # include <mfg/dkio.h>
52 # include <sys/unistd.h>
53 # include <dev/srvar.h>
54 #else /* A real Sun */
55 # ifdef SYSV
56 # include <poll.h>
57 # include <stdlib.h>
58 # include <sys/cdio.h>
59 # include <sys/socket.h>
60 # include <sys/scsi/impl/uscsi.h>
61 # include "include/wm_cdda.h"
62 # else
63 # include <sys/buf.h>
64 # include <sun/dkio.h>
65 # include <scsi/targets/srdef.h>
66 # include <scsi/impl/uscsi.h>
67 # include <scsi/generic/commands.h>
68 # endif
69 #endif
71 #include "include/wm_struct.h"
73 #define WM_MSG_CLASS WM_MSG_CLASS_PLATFORM
75 int min_volume = 0;
76 int max_volume = 255;
78 extern char *cd_device, *cddaslave_path;
79 extern int intermittent_dev;
81 int cdda_slave = -1;
83 int current_end;
85 #if defined(SYSV) && defined(SIGTHAW)
86 #ifdef __GNUC__
87 void sigthawinit(void) __attribute__ ((constructor));
88 #else
89 #pragma init(sigthawinit)
90 #endif /* GNUC */
92 static int last_left, last_right;
93 static struct wm_drive *thecd;
95 static void thawme(int sig)
97 change_mode(NULL, WM_CDM_STOPPED, NULL);
98 codec_init();
99 if( thecd )
100 gen_set_volume(thecd, last_left, last_right);
101 } /* thawme */
103 void sigthawinit( void )
105 struct sigaction sa;
107 sa.sa_handler = thawme;
108 sigemptyset(&sa.sa_mask);
109 sa.sa_flags = 0;
111 sigaction(SIGTHAW, &sa, NULL);
114 #endif /* SYSV && SIGTHAW */
117 * find_cdrom
119 * Determine the name of the CD-ROM device.
121 * Use the first of /vol/dev/aliases/cdrom0, /dev/rdsk/c0t6d0s2, and /dev/rsr0
122 * that exists. (Check for /vol/dev/aliases, not cdrom0, since it won't be
123 * there if there's no CD in the drive.) This is done so a single SunOS 4.x
124 * binary can be used on any 4.x or higher Sun system.
126 void
127 find_cdrom( void )
129 if (access("/vol/dev/aliases", X_OK) == 0)
131 /* Volume manager. Device might not be there. */
132 intermittent_dev = 1;
134 /* If vold is running us, it'll tell us the device name. */
135 cd_device = getenv("VOLUME_DEVICE");
136 if (cd_device == NULL)
137 cd_device = "/vol/dev/aliases/cdrom0";
139 else if (access("/dev/rdsk/c0t6d0s2", F_OK) == 0)
141 /* Solaris 2.x w/o volume manager. */
142 cd_device = "/dev/rdsk/c0t6d0s2";
144 else if (access("/dev/rcd0", F_OK) == 0)
146 cd_device = "/dev/rcd0";
148 else if (access("/dev/rsr0", F_OK) == 0)
149 cd_device = "/dev/rsr0";
150 else
152 fprintf(stderr, "Couldn't find a CD device!\n");
153 exit(1);
158 * Wait for an acknowledgement from the CDDA slave.
160 static int
161 get_ack(int fd)
163 #if defined(BUILD_CDDA) && defined(WMCDDA_DONE) /* { */
164 struct cdda_block blk;
167 if (read(fd, &blk, sizeof(blk)) <= 0)
168 return (0);
169 while (blk.status != WMCDDA_ACK);
170 #endif /* } */
172 return (1);
176 * Initialize the drive. A no-op for the generic driver.
179 gen_init( struct wm_drive *d )
181 codec_init();
182 return (0);
186 * Try to initialize the CDDA slave. Returns 0 on error.
189 cdda_init( struct wm_drive *d )
191 #if defined(BUILD_CDDA) && defined(WMCDDA_DONE) /* { */
192 int slavefds[2];
194 if (cdda_slave > -1)
195 return (1);
197 if (socketpair(AF_UNIX, SOCK_STREAM, 0, slavefds))
199 perror("socketpair");
200 return (0);
203 switch (fork()) {
204 case 0:
205 close(slavefds[0]);
206 dup2(slavefds[1], 1);
207 dup2(slavefds[1], 0);
208 close(slavefds[1]);
209 close(d->fd);
210 /* Try the default path first. */
211 execl(cddaslave_path, cddaslave_path, cd_device, NULL);
212 /* Search $PATH if that didn't work. */
213 execlp("cddaslave", "cddaslave", cd_device, NULL);
214 perror(cddaslave_path);
215 exit(1);
217 case -1:
218 close(slavefds[0]);
219 close(slavefds[1]);
220 perror("fork");
221 return (0);
224 close(slavefds[1]);
225 cdda_slave = slavefds[0];
227 if (!get_ack(cdda_slave))
229 cdda_slave = -1;
230 codec_start();
231 return (0);
234 return (1);
236 #else /* BUILD_CDDA } { */
238 * If we're not building CDDA support, don't even bother trying.
240 return (0);
241 #endif
245 * Turn off the CDDA slave.
247 void
248 cdda_kill( struct wm_drive *d )
250 if (cdda_slave > -1)
252 write(cdda_slave, "Q", 1);
253 get_ack(cdda_slave);
254 wait(NULL);
255 cdda_slave = -1;
256 codec_start();
261 * Get the number of tracks on the CD.
264 gen_get_trackcount( struct wm_drive *d, int *tracks )
266 struct cdrom_tochdr hdr;
268 if (ioctl(d->fd, CDROMREADTOCHDR, &hdr))
269 return (-1);
271 *tracks = hdr.cdth_trk1;
272 return (0);
276 * Get the start time and mode (data or audio) of a track.
279 gen_get_trackinfo( struct wm_drive *d, int track, int *data, int *startframe)
281 struct cdrom_tocentry entry;
283 entry.cdte_track = track;
284 entry.cdte_format = CDROM_MSF;
286 if (ioctl(d->fd, CDROMREADTOCENTRY, &entry))
287 return (-1);
289 *startframe = entry.cdte_addr.msf.minute * 60 * 75 +
290 entry.cdte_addr.msf.second * 75 +
291 entry.cdte_addr.msf.frame;
292 *data = entry.cdte_ctrl & CDROM_DATA_TRACK ? 1 : 0;
294 return (0);
298 * Get the number of frames on the CD.
301 gen_get_cdlen(struct wm_drive *d, int *frames )
303 int tmp;
305 return (gen_get_trackinfo(d, CDROM_LEADOUT, &tmp, frames));
309 /* Alarm signal handler. */
310 static void do_nothing( int x ) { x++; }
313 * Get the current status of the drive: the current play mode, the absolute
314 * position from start of disc (in frames), and the current track and index
315 * numbers if the CD is playing or paused.
318 gen_get_drive_status( struct wm_drive *d,
319 enum wm_cd_modes oldmode,
320 enum wm_cd_modes *mode,
321 int *pos, int *track, int *index )
323 struct cdrom_subchnl sc;
324 struct itimerval old_timer, new_timer;
325 struct sigaction old_sig, new_sig;
327 /* If we can't get status, the CD is ejected, so default to that. */
328 *mode = WM_CDM_EJECTED;
330 /* Is the device open? */
331 if (d->fd < 0)
333 switch (wmcd_open(d)) {
334 case -1: /* error */
335 return (-1);
337 case 1: /* retry */
338 return (0);
342 #if defined(BUILD_CDDA) && defined(WMCDDA_DONE) /* { */
343 if ((oldmode == WM_CDM_PAUSED || oldmode == WM_CDM_PLAYING || oldmode == WM_CDM_STOPPED) &&
344 cdda_slave > -1)
346 struct cdda_block blk;
347 struct pollfd fds;
348 int gotone = 0;
350 fds.fd = cdda_slave;
351 fds.events = POLLRDNORM;
353 *mode = oldmode;
355 while (poll(&fds, 1, 0) > 0)
357 read(cdda_slave, &blk, sizeof(blk));
358 gotone = 1;
361 /* We only want to use the latest status report. */
362 if (gotone)
364 if (blk.status == WMCDDA_PLAYED)
366 *track = blk.track;
367 *index = blk.index;
368 *pos = blk.minute * 60 * 75 +
369 blk.second * 75 +
370 blk.frame;
372 *mode = WM_CDM_PLAYING;
374 else if (blk.status == WMCDDA_DONE)
375 *mode = WM_CDM_TRACK_DONE;
376 else if (blk.status == WMCDDA_STOPPED)
378 if (oldmode == WM_CDM_PLAYING || oldmode == WM_CDM_PAUSED)
379 *mode = WM_CDM_PAUSED;
380 else
381 *mode = WM_CDM_STOPPED;
383 else if (blk.status == WMCDDA_ERROR)
386 * An error near the end of the CD probably
387 * just means we hit the end.
389 *mode = WM_CDM_TRACK_DONE;
391 else if (blk.status == WMCDDA_EJECTED)
393 *mode = WM_CDM_EJECTED;
397 return (0);
399 #endif /* } */
402 * Solaris 2.2 hangs on this ioctl if someone else ejects the CD.
403 * So we schedule a signal to break out of the hang if the call
404 * takes an unreasonable amount of time. The signal handler and
405 * timer are restored immediately to avoid interfering with XView.
407 if (intermittent_dev)
410 * First clear out the timer so XView's signal doesn't happen
411 * while we're diddling with the signal handler.
413 timerclear(&new_timer.it_interval);
414 timerclear(&new_timer.it_value);
415 setitimer(ITIMER_REAL, &new_timer, &old_timer);
418 * Now install the no-op signal handler.
420 new_sig.sa_handler = do_nothing;
421 memset(&new_sig.sa_mask, 0, sizeof(new_sig.sa_mask));
422 new_sig.sa_flags = 0;
423 if (sigaction(SIGALRM, &new_sig, &old_sig))
424 perror("sigaction");
427 * And finally, set the timer.
429 new_timer.it_value.tv_sec = 2;
430 setitimer(ITIMER_REAL, &new_timer, NULL);
433 sc.cdsc_format = CDROM_MSF;
435 if (ioctl(d->fd, CDROMSUBCHNL, &sc))
437 if (intermittent_dev)
439 sigaction(SIGALRM, &old_sig, NULL);
440 setitimer(ITIMER_REAL, &old_timer, NULL);
442 /* If the device can disappear, let it do so. */
443 close(d->fd);
444 d->fd = -1;
447 return (0);
450 if (intermittent_dev)
452 sigaction(SIGALRM, &old_sig, NULL);
453 setitimer(ITIMER_REAL, &old_timer, NULL);
456 switch (sc.cdsc_audiostatus) {
457 case CDROM_AUDIO_PLAY:
458 *mode = WM_CDM_PLAYING;
459 *track = sc.cdsc_trk;
460 *index = sc.cdsc_ind;
461 *pos = sc.cdsc_absaddr.msf.minute * 60 * 75 +
462 sc.cdsc_absaddr.msf.second * 75 +
463 sc.cdsc_absaddr.msf.frame;
464 break;
466 case CDROM_AUDIO_PAUSED:
467 case CDROM_AUDIO_INVALID:
468 case CDROM_AUDIO_NO_STATUS:
469 if (oldmode == WM_CDM_PLAYING || oldmode == WM_CDM_PAUSED)
471 *mode = WM_CDM_PAUSED;
472 *track = sc.cdsc_trk;
473 *index = sc.cdsc_ind;
474 *pos = sc.cdsc_absaddr.msf.minute * 60 * 75 +
475 sc.cdsc_absaddr.msf.second * 75 +
476 sc.cdsc_absaddr.msf.frame;
478 else
479 *mode = WM_CDM_STOPPED;
480 break;
482 /* CD ejected manually during play. */
483 case CDROM_AUDIO_ERROR:
484 break;
486 case CDROM_AUDIO_COMPLETED:
487 *mode = WM_CDM_TRACK_DONE; /* waiting for next track. */
488 break;
490 default:
491 *mode = WM_CDM_UNKNOWN;
492 break;
495 return (0);
499 * Set the volume level for the left and right channels. Their values
500 * range from 0 to 100.
503 gen_set_volume( struct wm_drive *d, int left, int right )
505 struct cdrom_volctrl v;
507 #if defined(SIGTHAW) && defined(SYSV)
508 last_left = left;
509 last_right = right;
510 thecd = d;
511 #endif
513 if (cdda_slave > -1)
515 int bal, vol;
516 unsigned char cmd[2];
518 bal = (right - left) + 100;
519 bal *= 255;
520 bal /= 200;
521 if (right > left)
522 vol = right;
523 else
524 vol = left;
525 vol *= 255;
526 vol /= 100;
528 cmd[0] = 'B';
529 cmd[1] = bal;
530 write(cdda_slave, cmd, 2);
531 cmd[0] = 'V';
532 cmd[1] = vol;
533 write(cdda_slave, cmd, 2);
535 * Don't wait for the ack, or the user won't be able to drag
536 * the volume slider smoothly.
539 return (0);
542 left = (left * (max_volume - min_volume)) / 100 + min_volume;
543 right = (right * (max_volume - min_volume)) / 100 + min_volume;
545 v.channel0 = left < 0 ? 0 : left > 255 ? 255 : left;
546 v.channel1 = right < 0 ? 0 : right > 255 ? 255 : right;
548 return (ioctl(d->fd, CDROMVOLCTRL, &v));
552 * Pause the CD.
555 gen_pause( struct wm_drive *d )
557 if (cdda_slave > -1)
559 int dummy, mode = WM_CDM_PLAYING;
561 write(cdda_slave, "S", 1);
562 get_ack(cdda_slave);
563 /* while (mode != WM_CDM_PAUSED)
564 gen_get_drive_status(d, WM_CDM_PAUSED, &mode, &dummy, &dummy,
565 &dummy);
567 return (0);
570 codec_stop();
571 return (ioctl(d->fd, CDROMPAUSE));
575 * Resume playing the CD (assuming it was paused.)
578 gen_resume( struct wm_drive *d )
580 if (cdda_slave > -1)
581 return (1);
583 codec_start();
584 return (ioctl(d->fd, CDROMRESUME));
588 * Stop the CD.
591 gen_stop( struct wm_drive *d )
593 if (cdda_slave > -1)
595 write(cdda_slave, "S", 1);
596 get_ack(cdda_slave);
599 * The WMCDDA_STOPPED status message will be caught by
600 * gen_get_drive_status.
603 return (0);
605 codec_stop();
606 return (ioctl(d->fd, CDROMSTOP));
610 * Play the CD from one position to another.
612 * d Drive structure.
613 * start Frame to start playing at.
614 * end End of this chunk.
615 * realstart Beginning of this chunk (<= start)
618 gen_play( struct wm_drive *d, int start, int end, int realstart)
620 struct cdrom_msf msf;
621 unsigned char cmdbuf[10];
623 current_end = end;
625 if (cdda_slave > -1)
627 cmdbuf[0] = 'P';
628 cmdbuf[1] = start / (60 * 75);
629 cmdbuf[2] = (start % (60*75)) / 75;
630 cmdbuf[3] = start % 75;
631 cmdbuf[4] = end / (60*75);
632 cmdbuf[5] = (end % (60*75)) / 75;
633 cmdbuf[6] = end % 75;
634 cmdbuf[7] = realstart / (60 * 75);
635 cmdbuf[8] = (realstart % (60*75)) / 75;
636 cmdbuf[9] = realstart % 75;
638 /* Write the play command and make sure the slave has it. */
639 write(cdda_slave, cmdbuf, 10);
640 get_ack(cdda_slave);
642 return (0);
645 msf.cdmsf_min0 = start / (60*75);
646 msf.cdmsf_sec0 = (start % (60*75)) / 75;
647 msf.cdmsf_frame0 = start % 75;
648 msf.cdmsf_min1 = end / (60*75);
649 msf.cdmsf_sec1 = (end % (60*75)) / 75;
650 msf.cdmsf_frame1 = end % 75;
652 codec_start();
653 if (ioctl(d->fd, CDROMSTART))
654 return (-1);
655 if (ioctl(d->fd, CDROMPLAYMSF, &msf))
656 return (-2);
658 return (0);
662 * Eject the current CD, if there is one.
665 gen_eject( struct wm_drive *d )
667 struct stat stbuf;
668 struct ustat ust;
670 if (fstat(d->fd, &stbuf) != 0)
671 return (-2);
673 /* Is this a mounted filesystem? */
674 if (ustat(stbuf.st_rdev, &ust) == 0)
675 return (-3);
677 if (cdda_slave > -1)
679 write(cdda_slave, "S", 1);
680 get_ack(cdda_slave);
683 if (ioctl(d->fd, CDROMEJECT))
684 return (-1);
686 /* Close the device if it needs to vanish. */
687 if (intermittent_dev)
689 close(d->fd);
690 d->fd = -1;
691 /* Also remember to tell the cddaslave since volume
692 manager switches links around on us */
693 if (cdda_slave > -1)
695 write(cdda_slave, "E", 1);
696 get_ack(cdda_slave);
700 return (0);
701 } /* gen_eject() */
703 /*----------------------------------------*
704 * Close the CD tray
706 * Please edit and send changes to
707 * milliByte@DeathsDoor.com
708 *----------------------------------------*/
710 int gen_closetray(struct wm_drive *d)
712 #ifdef CAN_CLOSE
713 if(!close(d->fd))
715 d->fd=-1;
716 return(wmcd_reopen(d));
717 } else {
718 return(-1);
720 #else
721 /* Always succeed if the drive can't close */
722 return(0);
723 #endif /* CAN_CLOSE */
724 } /* gen_closetray() */
728 * Read the initial volume from the drive, if available. Each channel
729 * ranges from 0 to 100, with -1 indicating data not available.
732 gen_get_volume( struct wm_drive *d, int *left, int *right )
734 #if defined(BUILD_CDDA) && defined(WMCDDA_DONE) /* { */
735 struct cdda_block blk;
737 if (cdda_slave > -1)
739 write(cdda_slave, "G", 1);
740 get_ack(cdda_slave);
741 read(cdda_slave, &blk, sizeof(blk));
743 *left = *right = (blk.volume * 100 + 254) / 255;
745 if (blk.balance < 110)
746 *right = (((blk.volume * blk.balance + 127) / 128) *
747 100 + 254) / 255;
748 else if (blk.balance > 146)
749 *left = (((blk.volume * (255 - blk.balance) +
750 127) / 128) * 100 + 254) / 255;
752 return (0);
754 #endif /* } */
756 *left = *right = -1;
758 return (wm_scsi2_get_volume(d, left, right));
761 #ifdef BUILD_CDDA /* { */
764 * Tell the CDDA slave to set the play direction.
766 void
767 gen_set_direction( int newdir )
769 unsigned char buf[2];
771 if (cdda_slave > -1)
773 buf[0] = 'd';
774 buf[1] = newdir;
775 write(cdda_slave, buf, 2);
776 get_ack(cdda_slave);
781 * Tell the CDDA slave to set the play speed.
783 void
784 gen_set_speed( int speed )
786 unsigned char buf[2];
788 if (cdda_slave > -1)
790 buf[0] = 's';
791 buf[1] = speed;
792 write(cdda_slave, buf, 2);
793 get_ack(cdda_slave);
798 * Tell the CDDA slave to set the loudness level.
800 void
801 gen_set_loudness( int loud )
803 unsigned char buf[2];
805 if (cdda_slave > -1)
807 buf[0] = 'L';
808 buf[1] = loud;
809 write(cdda_slave, buf, 2);
810 get_ack(cdda_slave);
815 * Tell the CDDA slave to start (or stop) saving to a file.
817 void
818 gen_save( char *filename )
820 int len;
822 if (filename == NULL || filename[0] == '\0')
823 len = 0;
824 else
825 len = strlen(filename);
826 write(cdda_slave, "F", 1);
827 write(cdda_slave, &len, sizeof(len));
828 if (len)
829 write(cdda_slave, filename, len);
830 get_ack(cdda_slave);
833 #endif /* BUILD_CDDA } */
835 #ifndef solbourne
837 * Send an arbitrary SCSI command out the bus and optionally wait for
838 * a reply if "retbuf" isn't NULL.
841 wm_scsi( struct wm_drive *d,
842 unsigned char *cdb,
843 int cdblen, void *retbuf,
844 int retbuflen, int getreply )
846 char x;
847 struct uscsi_cmd cmd;
849 memset(&cmd, 0, sizeof(cmd));
850 cmd.uscsi_cdb = (void *) cdb;
851 cmd.uscsi_cdblen = cdblen;
852 cmd.uscsi_bufaddr = retbuf ? retbuf : (void *)&x;
853 cmd.uscsi_buflen = retbuf ? retbuflen : 0;
854 cmd.uscsi_flags = USCSI_ISOLATE | USCSI_SILENT;
855 if (getreply)
856 cmd.uscsi_flags |= USCSI_READ;
858 if (ioctl(d->fd, USCSICMD, &cmd))
859 return (-1);
861 if (cmd.uscsi_status)
862 return (-1);
864 return (0);
866 #else
868 int wm_scsi() { return (-1); }
870 #endif
873 * Open the CD device and figure out what kind of drive is attached.
876 wmcd_open( struct wm_drive *d )
878 int fd;
879 static int warned = 0;
880 char vendor[32] = WM_STR_GENVENDOR;
881 char model[32] = WM_STR_GENMODEL;
882 char rev[32] = WM_STR_GENREV;
884 if (cd_device == NULL)
885 find_cdrom();
887 if (d->fd >= 0) /* Device already open? */
888 return (0);
890 d->fd = open(cd_device, 0);
891 if (d->fd < 0)
893 /* Solaris 2.2 volume manager moves links around */
894 if (errno == ENOENT && intermittent_dev)
895 return (1);
897 if (errno == EACCES)
899 if (!warned)
901 char realname[MAXPATHLEN];
903 if (realpath(cd_device, realname) == NULL)
905 perror("realpath");
906 return (-1);
909 fprintf(stderr,
910 "As root, please run\n\nchmod 666 %s\n\n%s\n", realname,
911 "to give yourself permission to access the CD-ROM device.");
912 warned++;
915 else if (errno != ENXIO)
917 perror(cd_device);
918 exit(1);
921 /* No CD in drive. */
922 return (1);
925 if (warned)
927 warned = 0;
928 fprintf(stderr, "Thank you.\n");
931 /* Now fill in the relevant parts of the wm_drive structure. */
932 fd = d->fd;
935 * See if we can do digital audio.
937 if (cdda_init(d))
938 enable_cdda_controls(1);
940 /* Can we figure out the drive type? */
941 if (wm_scsi_get_drive_type(d, vendor, model, rev)) {
942 if (errno == EPERM) {
944 * Solaris 2.4 seems to refuse to do USCSICMD ioctls
945 * when not running as root. SunOS 4.x allows it
946 * as an unprivileged user, though.
948 fprintf(stderr, "Warning: WorkMan can't adapt itself to your drive unless it runs as root.\n");
949 } else {
950 fprintf(stderr, "Warning: WorkMan couldn't determine drive type\n");
952 *d = *(find_drive_struct("Generic", "drive type", ""));
953 } else {
954 *d = *(find_drive_struct(vendor, model, rev));
957 wm_drive_settype(vendor, model, rev);
958 d->fd = fd;
960 (d->init)(d);
962 return (0);
963 } /* wmcd_open() */
966 * Re-Open the device if it is open.
969 wmcd_reopen( struct wm_drive *d )
971 int status;
973 do {
974 wm_lib_message(WM_MSG_LEVEL_DEBUG|WM_MSG_CLASS, "wmcd_reopen ");
975 if (d->fd >= 0) /* Device really open? */
977 wm_lib_message(WM_MSG_LEVEL_DEBUG|WM_MSG_CLASS, "closes the device and ");
978 status = close( d->fd ); /* close it! */
979 /* we know, that the file is closed, do we? */
980 d->fd = -1;
982 wm_susleep( 1000 );
983 wm_lib_message(WM_MSG_LEVEL_DEBUG|WM_MSG_CLASS, "calls wmcd_open()\n");
984 status = wmcd_open( d ); /* open it as usual */
985 wm_susleep( 1000 );
986 } while ( status != 0 );
987 return status;
988 } /* wmcd_reopen() */
992 * The following code activates the internal CD audio passthrough on
993 * SPARCstation 5 systems (and possibly others.)
995 * Thanks to <stevep@ctc.ih.att.com>, Roger Oscarsson <roger@cs.umu.se>
996 * and Steve McKinty <>
998 * Most CD drives have a headphone socket on the front, but it
999 * is often more convenient to route the audio though the
1000 * built-in audio device. That way the user can leave their
1001 * headphones plugged-in to the base system, for use with
1002 * other audio stuff like ShowMeTV
1005 #ifdef CODEC /* { */
1006 #ifdef SYSV /* { */
1008 # include <sys/ioctl.h>
1009 # include <sys/audioio.h>
1010 # include <stdlib.h>
1012 #else /* } { */
1014 # include <sun/audioio.h>
1015 # define AUDIO_DEV_SS5STYLE 5
1016 typedef int audio_device_t;
1018 #endif /* } */
1019 #endif /* } */
1022 * Don't do anything with /dev/audio if we can't set it to high quality.
1023 * Also, don't do anything real if it's not Solaris.
1025 #if !defined(AUDIO_ENCODING_LINEAR) || !defined(CODEC) || !defined(SYSV) /* { */
1026 codec_init() { return 0; }
1027 codec_start() { return 0; }
1028 codec_stop() { return 0; }
1029 #else
1031 #ifndef AUDIO_INTERNAL_CD_IN
1032 #define AUDIO_INTERNAL_CD_IN 0x4
1033 #endif
1035 static char* devname = 0;
1036 static char* ctlname = 0;
1037 static int ctl_fd = -1;
1038 static int port = AUDIO_LINE_IN;
1039 int internal_audio = 1;
1041 codec_init( void )
1043 register int i;
1044 char* ctlname;
1045 audio_info_t foo;
1046 audio_device_t aud_dev;
1048 if (internal_audio == 0)
1050 ctl_fd = -1;
1051 return(0);
1054 if (!(devname = getenv("AUDIODEV"))) devname = "/dev/audio";
1055 ctlname = strcat(strcpy(malloc(strlen(devname) + 4), devname), "ctl");
1056 if ((ctl_fd = open(ctlname, O_WRONLY, 0)) < 0) {
1057 perror(ctlname);
1058 return -1;
1060 if (ioctl(ctl_fd, AUDIO_GETDEV, &aud_dev) < 0) {
1061 close(ctl_fd);
1062 ctl_fd = -1;
1063 return -1;
1066 * Instead of filtering the "OLD_SUN_AUDIO", try to find the new ones.
1067 * Not sure if this is all correct.
1069 #ifdef SYSV
1070 if (strcmp(aud_dev.name, "SUNW,CS4231") &&
1071 strcmp(aud_dev.name, "SUNW,sb16") &&
1072 strcmp(aud_dev.name, "SUNW,sbpro"))
1073 #else
1074 if (aud_dev != AUDIO_DEV_SS5STYLE)
1075 #endif
1077 close(ctl_fd);
1078 ctl_fd = -1;
1079 return 0; /* but it's okay */
1083 * Does the chosen device have an internal CD port?
1084 * If so, use it. If not then try and use the
1085 * Line In port.
1087 if (ioctl(ctl_fd, AUDIO_GETINFO, &foo) < 0)
1089 perror("AUDIO_GETINFO");
1090 close(ctl_fd);
1091 ctl_fd = -1;
1092 return(-1);
1094 if (foo.record.avail_ports & AUDIO_INTERNAL_CD_IN)
1095 port = AUDIO_INTERNAL_CD_IN;
1096 else
1097 port = AUDIO_LINE_IN;
1100 * now set it up to use it. See audio(7I)
1103 AUDIO_INITINFO(&foo);
1104 foo.record.port = port;
1105 foo.record.balance = foo.play.balance = AUDIO_MID_BALANCE;
1106 #ifdef BUILD_CDDA
1107 if (cdda_slave > -1)
1108 foo.monitor_gain = 0;
1109 else
1110 #endif
1111 foo.monitor_gain = AUDIO_MAX_GAIN;
1113 * These next ones are tricky. The voulme will depend on the CD drive
1114 * volume (set by the knob on the drive and/or by workman's volume
1115 * control), the audio device record gain and the audio device
1116 * play gain. For simplicity we set the latter two to something
1117 * reasonable, but we don't force them to be reset if the user
1118 * wants to change them.
1120 foo.record.gain = (AUDIO_MAX_GAIN * 80) / 100;
1121 foo.play.gain = (AUDIO_MAX_GAIN * 40) / 100;
1123 ioctl(ctl_fd, AUDIO_SETINFO, &foo);
1124 return 0;
1127 static kick_codec( void ) {
1128 audio_info_t foo;
1129 int dev_fd;
1130 int retval = 0;
1133 * Open the audio device, not the control device. This
1134 * will fail if someone else has taken it.
1137 if ((dev_fd = open(devname, O_WRONLY|O_NDELAY, 0)) < 0) {
1138 perror(devname);
1139 return -1;
1142 AUDIO_INITINFO(&foo);
1143 foo.record.port = port;
1144 foo.monitor_gain = AUDIO_MAX_GAIN;
1146 /* These can only be set on the real device */
1147 foo.play.sample_rate = 44100;
1148 foo.play.channels = 2;
1149 foo.play.precision = 16;
1150 foo.play.encoding = AUDIO_ENCODING_LINEAR;
1152 if ((retval = ioctl(dev_fd, AUDIO_SETINFO, &foo)) < 0)
1153 perror(devname);
1155 close(dev_fd);
1156 return retval;
1159 codec_start( void )
1161 audio_info_t foo;
1163 if (ctl_fd < 0)
1164 return 0;
1166 if (ioctl(ctl_fd, AUDIO_GETINFO, &foo) < 0)
1167 return -1;
1169 if (foo.play.channels != 2) return kick_codec();
1170 if (foo.play.encoding != AUDIO_ENCODING_LINEAR) return kick_codec();
1171 if (foo.play.precision != 16) return kick_codec();
1172 if (foo.play.sample_rate != 44100) return kick_codec();
1174 if (foo.record.channels != 2) return kick_codec();
1175 if (foo.record.encoding != AUDIO_ENCODING_LINEAR) return kick_codec();
1176 if (foo.record.precision != 16) return kick_codec();
1177 if (foo.record.sample_rate != 44100) return kick_codec();
1179 if (foo.monitor_gain != AUDIO_MAX_GAIN) return kick_codec();
1180 if (foo.record.port != port) return kick_codec();
1182 return 0;
1185 codec_stop( void ) { return 0; }
1187 #endif /* CODEC } */
1188 #endif /* sun } */