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.
29 static char plat_sun_id
[] = "$Id: plat_sun.c,v 1.9 1999/05/28 03:35:54 dirk Exp $";
33 #include <sys/types.h>
36 #include <sys/param.h>
39 #include <sys/ioctl.h>
41 #include "include/wm_config.h"
42 #include "include/wm_helpers.h"
43 #include "include/wm_cdrom.h"
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 */
58 # include <sys/cdio.h>
59 # include <sys/socket.h>
60 # include <sys/scsi/impl/uscsi.h>
61 # include "include/wm_cdda.h"
64 # include <sun/dkio.h>
65 # include <scsi/targets/srdef.h>
66 # include <scsi/impl/uscsi.h>
67 # include <scsi/generic/commands.h>
71 #include "include/wm_struct.h"
73 #define WM_MSG_CLASS WM_MSG_CLASS_PLATFORM
78 extern char *cd_device
, *cddaslave_path
;
79 extern int intermittent_dev
;
85 #if defined(SYSV) && defined(SIGTHAW)
87 void sigthawinit(void) __attribute__ ((constructor
));
89 #pragma init(sigthawinit)
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
);
100 gen_set_volume(thecd
, last_left
, last_right
);
103 void sigthawinit( void )
107 sa
.sa_handler
= thawme
;
108 sigemptyset(&sa
.sa_mask
);
111 sigaction(SIGTHAW
, &sa
, NULL
);
114 #endif /* SYSV && SIGTHAW */
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.
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";
152 fprintf(stderr
, "Couldn't find a CD device!\n");
158 * Wait for an acknowledgement from the CDDA slave.
163 #if defined(BUILD_CDDA) && defined(WMCDDA_DONE) /* { */
164 struct cdda_block blk
;
167 if (read(fd
, &blk
, sizeof(blk
)) <= 0)
169 while (blk
.status
!= WMCDDA_ACK
);
176 * Initialize the drive. A no-op for the generic driver.
179 gen_init( struct wm_drive
*d
)
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) /* { */
197 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, slavefds
))
199 perror("socketpair");
206 dup2(slavefds
[1], 1);
207 dup2(slavefds
[1], 0);
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
);
225 cdda_slave
= slavefds
[0];
227 if (!get_ack(cdda_slave
))
236 #else /* BUILD_CDDA } { */
238 * If we're not building CDDA support, don't even bother trying.
245 * Turn off the CDDA slave.
248 cdda_kill( struct wm_drive
*d
)
252 write(cdda_slave
, "Q", 1);
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
))
271 *tracks
= hdr
.cdth_trk1
;
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
))
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;
298 * Get the number of frames on the CD.
301 gen_get_cdlen(struct wm_drive
*d
, int *frames
)
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? */
333 switch (wmcd_open(d
)) {
342 #if defined(BUILD_CDDA) && defined(WMCDDA_DONE) /* { */
343 if ((oldmode
== WM_CDM_PAUSED
|| oldmode
== WM_CDM_PLAYING
|| oldmode
== WM_CDM_STOPPED
) &&
346 struct cdda_block blk
;
351 fds
.events
= POLLRDNORM
;
355 while (poll(&fds
, 1, 0) > 0)
357 read(cdda_slave
, &blk
, sizeof(blk
));
361 /* We only want to use the latest status report. */
364 if (blk
.status
== WMCDDA_PLAYED
)
368 *pos
= blk
.minute
* 60 * 75 +
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
;
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
;
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
))
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. */
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
;
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
;
479 *mode
= WM_CDM_STOPPED
;
482 /* CD ejected manually during play. */
483 case CDROM_AUDIO_ERROR
:
486 case CDROM_AUDIO_COMPLETED
:
487 *mode
= WM_CDM_TRACK_DONE
; /* waiting for next track. */
491 *mode
= WM_CDM_UNKNOWN
;
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)
516 unsigned char cmd
[2];
518 bal
= (right
- left
) + 100;
530 write(cdda_slave
, cmd
, 2);
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.
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
));
555 gen_pause( struct wm_drive
*d
)
559 int dummy
, mode
= WM_CDM_PLAYING
;
561 write(cdda_slave
, "S", 1);
563 /* while (mode != WM_CDM_PAUSED)
564 gen_get_drive_status(d, WM_CDM_PAUSED, &mode, &dummy, &dummy,
571 return (ioctl(d
->fd
, CDROMPAUSE
));
575 * Resume playing the CD (assuming it was paused.)
578 gen_resume( struct wm_drive
*d
)
584 return (ioctl(d
->fd
, CDROMRESUME
));
591 gen_stop( struct wm_drive
*d
)
595 write(cdda_slave
, "S", 1);
599 * The WMCDDA_STOPPED status message will be caught by
600 * gen_get_drive_status.
606 return (ioctl(d
->fd
, CDROMSTOP
));
610 * Play the CD from one position to another.
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];
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);
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;
653 if (ioctl(d
->fd
, CDROMSTART
))
655 if (ioctl(d
->fd
, CDROMPLAYMSF
, &msf
))
662 * Eject the current CD, if there is one.
665 gen_eject( struct wm_drive
*d
)
670 if (fstat(d
->fd
, &stbuf
) != 0)
673 /* Is this a mounted filesystem? */
674 if (ustat(stbuf
.st_rdev
, &ust
) == 0)
679 write(cdda_slave
, "S", 1);
683 if (ioctl(d
->fd
, CDROMEJECT
))
686 /* Close the device if it needs to vanish. */
687 if (intermittent_dev
)
691 /* Also remember to tell the cddaslave since volume
692 manager switches links around on us */
695 write(cdda_slave
, "E", 1);
703 /*----------------------------------------*
706 * Please edit and send changes to
707 * milliByte@DeathsDoor.com
708 *----------------------------------------*/
710 int gen_closetray(struct wm_drive
*d
)
716 return(wmcd_reopen(d
));
721 /* Always succeed if the drive can't close */
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
;
739 write(cdda_slave
, "G", 1);
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) *
748 else if (blk
.balance
> 146)
749 *left
= (((blk
.volume
* (255 - blk
.balance
) +
750 127) / 128) * 100 + 254) / 255;
758 return (wm_scsi2_get_volume(d
, left
, right
));
761 #ifdef BUILD_CDDA /* { */
764 * Tell the CDDA slave to set the play direction.
767 gen_set_direction( int newdir
)
769 unsigned char buf
[2];
775 write(cdda_slave
, buf
, 2);
781 * Tell the CDDA slave to set the play speed.
784 gen_set_speed( int speed
)
786 unsigned char buf
[2];
792 write(cdda_slave
, buf
, 2);
798 * Tell the CDDA slave to set the loudness level.
801 gen_set_loudness( int loud
)
803 unsigned char buf
[2];
809 write(cdda_slave
, buf
, 2);
815 * Tell the CDDA slave to start (or stop) saving to a file.
818 gen_save( char *filename
)
822 if (filename
== NULL
|| filename
[0] == '\0')
825 len
= strlen(filename
);
826 write(cdda_slave
, "F", 1);
827 write(cdda_slave
, &len
, sizeof(len
));
829 write(cdda_slave
, filename
, len
);
833 #endif /* BUILD_CDDA } */
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
,
843 int cdblen
, void *retbuf
,
844 int retbuflen
, int getreply
)
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
;
856 cmd
.uscsi_flags
|= USCSI_READ
;
858 if (ioctl(d
->fd
, USCSICMD
, &cmd
))
861 if (cmd
.uscsi_status
)
868 int wm_scsi() { return (-1); }
873 * Open the CD device and figure out what kind of drive is attached.
876 wmcd_open( struct wm_drive
*d
)
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
)
887 if (d
->fd
>= 0) /* Device already open? */
890 d
->fd
= open(cd_device
, 0);
893 /* Solaris 2.2 volume manager moves links around */
894 if (errno
== ENOENT
&& intermittent_dev
)
901 char realname
[MAXPATHLEN
];
903 if (realpath(cd_device
, realname
) == NULL
)
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.");
915 else if (errno
!= ENXIO
)
921 /* No CD in drive. */
928 fprintf(stderr
, "Thank you.\n");
931 /* Now fill in the relevant parts of the wm_drive structure. */
935 * See if we can do digital audio.
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");
950 fprintf(stderr
, "Warning: WorkMan couldn't determine drive type\n");
952 *d
= *(find_drive_struct("Generic", "drive type", ""));
954 *d
= *(find_drive_struct(vendor
, model
, rev
));
957 wm_drive_settype(vendor
, model
, rev
);
966 * Re-Open the device if it is open.
969 wmcd_reopen( struct wm_drive
*d
)
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? */
983 wm_lib_message(WM_MSG_LEVEL_DEBUG
|WM_MSG_CLASS
, "calls wmcd_open()\n");
984 status
= wmcd_open( d
); /* open it as usual */
986 } while ( status
!= 0 );
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 /* { */
1008 # include <sys/ioctl.h>
1009 # include <sys/audioio.h>
1010 # include <stdlib.h>
1014 # include <sun/audioio.h>
1015 # define AUDIO_DEV_SS5STYLE 5
1016 typedef int audio_device_t
;
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; }
1031 #ifndef AUDIO_INTERNAL_CD_IN
1032 #define AUDIO_INTERNAL_CD_IN 0x4
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;
1046 audio_device_t aud_dev
;
1048 if (internal_audio
== 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) {
1060 if (ioctl(ctl_fd
, AUDIO_GETDEV
, &aud_dev
) < 0) {
1066 * Instead of filtering the "OLD_SUN_AUDIO", try to find the new ones.
1067 * Not sure if this is all correct.
1070 if (strcmp(aud_dev
.name
, "SUNW,CS4231") &&
1071 strcmp(aud_dev
.name
, "SUNW,sb16") &&
1072 strcmp(aud_dev
.name
, "SUNW,sbpro"))
1074 if (aud_dev
!= AUDIO_DEV_SS5STYLE
)
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
1087 if (ioctl(ctl_fd
, AUDIO_GETINFO
, &foo
) < 0)
1089 perror("AUDIO_GETINFO");
1094 if (foo
.record
.avail_ports
& AUDIO_INTERNAL_CD_IN
)
1095 port
= AUDIO_INTERNAL_CD_IN
;
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
;
1107 if (cdda_slave
> -1)
1108 foo
.monitor_gain
= 0;
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
);
1127 static kick_codec( void ) {
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) {
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)
1166 if (ioctl(ctl_fd
, AUDIO_GETINFO
, &foo
) < 0)
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();
1185 codec_stop( void ) { return 0; }
1187 #endif /* CODEC } */