*** linux_adio.c.ORIG	Fri Nov 20 10:03:27 1998
--- linux_adio.c	Tue Dec 29 12:02:50 1998
***************
*** 19,27 ****
--- 19,33 ----
  
  #include <stdio.h>
  #include <stdlib.h>
+ #ifndef __FreeBSD__
  #include <malloc.h>
+ #endif
  #include <sys/ioctl.h>
+ #ifdef __FreeBSD__
+ #include <machine/soundcard.h>
+ #else
  #include <linux/soundcard.h>
+ #endif
  #include <errno.h>
  #include <unistd.h>
  #include <math.h>
***************
*** 52,59 ****
--- 58,69 ----
  
  static void dsp_reset(int fd)
  {
+   printf("skipping reset\n");
+ /* reset is suppressed, because it is being called at an inappropriate time:
+    it resets some earlier ioctl calls to the driver.
    if(ioctl(fd, SNDCTL_DSP_RESET, NULL) < 0)
      sls_warn("dsp_sync(): Unable to sync the DSP device!");
+ */
  }
  
  static void dsp_sync(int fd)
***************
*** 70,115 ****
  
  static void dsp_settrigger(int fd, int trigger)
  {
!   if(ioctl(fd, SNDCTL_DSP_SETTRIGGER, &trigger) < 0)
      sls_warn("dsp_settrigger(): Unable to settrigger the DSP device!");
  }
  
  static int dsp_gettrigger(int fd)
  {
    int trigger;
!   if(ioctl(fd, SNDCTL_DSP_GETTRIGGER, &trigger) < 0) {
      sls_warn("dsp_gettrigger(): Unable to gettrigger the DSP device!");
      return 0;
    }
    return trigger;
  }
  
! static void dsp_start_recording(int fd)
  {
!   int trigger = dsp_gettrigger(fd);
    char buf[65536]; /* size is arbitrary */
  
    /* turn off recording */
!   dsp_settrigger(fd, trigger & ~PCM_ENABLE_INPUT);
  
    /* drain recording buffer by reading all samples -- this doesn't block */
    while (read(fd, buf, sizeof(buf)) > 0)
      ;
  
    /* turn on recording */
!   dsp_settrigger(fd, trigger |  PCM_ENABLE_INPUT);
  }
  
! static void dsp_stop_recording(int fd)
  {
!   dsp_settrigger(fd, dsp_gettrigger(fd) & ~PCM_ENABLE_INPUT);
  }
  
  static int dsp_set_sample_rate(int fd, int sample_rate)
  {
    dsp_sync(fd);
  
!   if(ioctl(fd, SNDCTL_DSP_SPEED, &sample_rate) < 0) {
      sls_warn("dsp_set_sample_rate(): Unable to set sample_rate to %d!",
  	     sample_rate);
      return(-1);
--- 80,132 ----
  
  static void dsp_settrigger(int fd, int trigger)
  {
!   if(ioctl(fd, SNDCTL_DSP_SETTRIGGER, (char *)&trigger) < 0)
      sls_warn("dsp_settrigger(): Unable to settrigger the DSP device!");
  }
  
  static int dsp_gettrigger(int fd)
  {
    int trigger;
!   if(ioctl(fd, SNDCTL_DSP_GETTRIGGER, (char *)&trigger) < 0) {
      sls_warn("dsp_gettrigger(): Unable to gettrigger the DSP device!");
      return 0;
    }
    return trigger;
  }
  
! static void dsp_start_recording(int fd, int has_trigger, int is_hdx)
  {
!   int trigger = 0;
    char buf[65536]; /* size is arbitrary */
  
    /* turn off recording */
!   if (has_trigger) {
!   	trigger = dsp_gettrigger(fd);
!   	dsp_settrigger(fd, trigger & ~PCM_ENABLE_INPUT);
! 	}
  
    /* drain recording buffer by reading all samples -- this doesn't block */
    while (read(fd, buf, sizeof(buf)) > 0)
      ;
  
    /* turn on recording */
!   if (has_trigger) {
! 	if (is_hdx) trigger &= ~PCM_ENABLE_OUTPUT;
!   	dsp_settrigger(fd, trigger |  PCM_ENABLE_INPUT);
!   }
  }
  
! static void dsp_stop_recording(int fd, int has_trigger)
  {
!   if (has_trigger) dsp_settrigger(fd, 
! 	(dsp_gettrigger(fd) & ~PCM_ENABLE_INPUT) | PCM_ENABLE_OUTPUT);
  }
  
  static int dsp_set_sample_rate(int fd, int sample_rate)
  {
    dsp_sync(fd);
  
!   if(ioctl(fd, SNDCTL_DSP_SPEED, (char *)&sample_rate) < 0) {
      sls_warn("dsp_set_sample_rate(): Unable to set sample_rate to %d!",
  	     sample_rate);
      return(-1);
***************
*** 135,141 ****
      return(-1);
    }
      
!   if(ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0) {
      sls_warn("dsp_set_sample_type(): Unable to set sample_size to %d bits and type to %s!",
  	     sample_size, linear ? "linear" : "u-law");
      return(-1);
--- 152,158 ----
      return(-1);
    }
      
!   if(ioctl(fd, SNDCTL_DSP_SETFMT, (char *)&format) < 0) {
      sls_warn("dsp_set_sample_type(): Unable to set sample_size to %d bits and type to %s!",
  	     sample_size, linear ? "linear" : "u-law");
      return(-1);
***************
*** 147,153 ****
  {
    dsp_sync(fd);
  
!   if(ioctl(fd, SNDCTL_DSP_STEREO, &stereo) < 0) {
      if(stereo)
        sls_warn("dsp_set_stereo(): Unable to set to stereo!");
      else
--- 164,170 ----
  {
    dsp_sync(fd);
  
!   if(ioctl(fd, SNDCTL_DSP_STEREO, (char *)&stereo) < 0) {
      if(stereo)
        sls_warn("dsp_set_stereo(): Unable to set to stereo!");
      else
***************
*** 162,168 ****
    int recsrc;
  
    recsrc = (1 << port);
!   if(ioctl(fd, SOUND_MIXER_WRITE_RECSRC, &port) < 0) {
      sls_warn("mixer_set_record_port(): Unable to set record port to %s!",
  	     linux_device_names[port]);
      return(-1);
--- 179,185 ----
    int recsrc;
  
    recsrc = (1 << port);
!   if(ioctl(fd, SOUND_MIXER_WRITE_RECSRC, (char *)&port) < 0) {
      sls_warn("mixer_set_record_port(): Unable to set record port to %s!",
  	     linux_device_names[port]);
      return(-1);
***************
*** 174,180 ****
  
  static int mixer_get_record_port(int fd, int *port)
  {
!   if(ioctl(fd, SOUND_MIXER_READ_RECSRC, port) < 0) {
      sls_warn("mixer_get_record_port(): Unable to get record port to %s!");
      return(-1);
    }
--- 191,197 ----
  
  static int mixer_get_record_port(int fd, int *port)
  {
!   if(ioctl(fd, SOUND_MIXER_READ_RECSRC, (char *)port) < 0) {
      sls_warn("mixer_get_record_port(): Unable to get record port to %s!");
      return(-1);
    }
***************
*** 183,189 ****
  
  static int mixer_get_play_gain(int fd, int *gain)
  {
!   if(ioctl(fd, SOUND_MIXER_READ_VOLUME, gain) < 0) {
      sls_warn("mixer_get_play_gain(): Unable to get play_gain");
      return(-1);
    }
--- 200,206 ----
  
  static int mixer_get_play_gain(int fd, int *gain)
  {
!   if(ioctl(fd, SOUND_MIXER_READ_VOLUME, (char *)gain) < 0) {
      sls_warn("mixer_get_play_gain(): Unable to get play_gain");
      return(-1);
    }
***************
*** 201,207 ****
      recsrc /= 2;
    recsrc = bit;
  
!   if(ioctl(fd, MIXER_READ(recsrc), gain) < 0) {
      sls_warn("mixer_get_record_gain(): Unable to get record_gain for %s!",
  	     linux_device_names[recsrc]);
      return(-1);
--- 218,224 ----
      recsrc /= 2;
    recsrc = bit;
  
!   if(ioctl(fd, MIXER_READ(recsrc), (char *)gain) < 0) {
      sls_warn("mixer_get_record_gain(): Unable to get record_gain for %s!",
  	     linux_device_names[recsrc]);
      return(-1);
***************
*** 215,221 ****
    int stereogain;
  
    stereogain = ((*gain & 0x7F) << 8) | (*gain & 0x7F);
!   if(ioctl(fd, SOUND_MIXER_WRITE_VOLUME, &stereogain) < 0) {
      sls_warn("mixer_set_play_gain(): Unable to set play_gain to %d!", *gain);
      return(-1);
    }
--- 232,238 ----
    int stereogain;
  
    stereogain = ((*gain & 0x7F) << 8) | (*gain & 0x7F);
!   if(ioctl(fd, SOUND_MIXER_WRITE_VOLUME, (char *)&stereogain) < 0) {
      sls_warn("mixer_set_play_gain(): Unable to set play_gain to %d!", *gain);
      return(-1);
    }
***************
*** 233,239 ****
    recsrc = bit;
  
    stereogain = ((*gain & 0x7F) << 8) | (*gain & 0x7F);
!   if(ioctl(fd, MIXER_WRITE(recsrc), &stereogain) < 0) {
      sls_warn("mixer_set_record_gain(): Unable to set record_gain for %d to %s!",
  	     linux_device_names[recsrc], *gain);
      return(-1);
--- 250,256 ----
    recsrc = bit;
  
    stereogain = ((*gain & 0x7F) << 8) | (*gain & 0x7F);
!   if(ioctl(fd, MIXER_WRITE(recsrc), (char *)&stereogain) < 0) {
      sls_warn("mixer_set_record_gain(): Unable to set record_gain for %d to %s!",
  	     linux_device_names[recsrc], *gain);
      return(-1);
***************
*** 247,253 ****
  linux_adio_open(bnum_UNUSED)
    int bnum_UNUSED;
  {
!   int fd, mixer_fd, status, adio_fd;
    int abuf_size, flags;
    extern int sys_nerr;
    LINUX_ADIO *linux_adio = NULL;
--- 264,270 ----
  linux_adio_open(bnum_UNUSED)
    int bnum_UNUSED;
  {
!   int fd, mixer_fd, status, adio_fd, trigger, hdx;
    int abuf_size, flags;
    extern int sys_nerr;
    LINUX_ADIO *linux_adio = NULL;
***************
*** 286,300 ****
    }
  
    if (fd != -1) {
-     /* Turn NDELAY/NONBLOCK mode off -- it doesn't work with OSS anyways */
-     if((status = fcntl(fd, F_GETFL, 0)) == -1) {
-       sls_warn("fcntl F_GETFL on /dev/dsp failed");
-     } else {
-       status &= ~O_NDELAY;
-       if(fcntl(fd, F_SETFL, status) == -1) {
- 	sls_warn("fcntl F_SETFL on /dev/dsp failed");
-       }
-     }
  
  #if 0
      /* Set fragment size - 16K fragments */
--- 303,308 ----
***************
*** 308,315 ****
  #endif
  
      /* Set DUPLEX */
!     if(ioctl(fd, SNDCTL_DSP_GETCAPS, &flags) != -1) {
        if(flags & DSP_CAP_DUPLEX) {
  	if(ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0) == -1) {
  	  sls_warn("linux_adio_open(): can't set to duplex mode");
  	  close(mixer_fd);
--- 316,325 ----
  #endif
  
      /* Set DUPLEX */
!     if(ioctl(fd, SNDCTL_DSP_GETCAPS, (char *)&flags) != -1) {
        if(flags & DSP_CAP_DUPLEX) {
+ /* disabled because freebsd lacks SNDCTL_DSP_SETDUPLEX defn */
+ #ifndef __FreeBSD__
  	if(ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0) == -1) {
  	  sls_warn("linux_adio_open(): can't set to duplex mode");
  	  close(mixer_fd);
***************
*** 318,334 ****
  	} else {
  	  sls_debug1("linux_adio_open(): succesfully set to duplex mode\n");
  	}
        } else {
  	sls_debug1("linux_adio_open(): no duplex abilities\n");
        }
!       if (!(flags & DSP_CAP_TRIGGER))
! 	sls_warn("linux_adio_open(): no trigger capability\n");
        
      } else sls_warn("linux_adio_open(): Couldn't determine capabilities!");
  
      /* Skipping hardware check for now...  Write it later */
      /* Make sure AD/DA is 16-bit and has stereo */
!     if(ioctl(fd, SNDCTL_DSP_GETFMTS, &flags) != -1) {
        if(flags & AFMT_S16_LE || flags & AFMT_S16_BE ||
  	 flags & AFMT_U16_LE || flags & AFMT_U16_BE)
  	flags = 1;
--- 328,353 ----
  	} else {
  	  sls_debug1("linux_adio_open(): succesfully set to duplex mode\n");
  	}
+ #endif
        } else {
  	sls_debug1("linux_adio_open(): no duplex abilities\n");
        }
!       if (!(flags & DSP_CAP_TRIGGER)) {
! 	trigger = 0;
! 	/* sls_warn("linux_adio_open(): no trigger capability\n"); */
! 	}
!       else trigger = 1;
!       if (!(flags & DSP_CAP_DUPLEX)) {
! 	hdx = 1;
! 	/* sls_warn("linux_adio_open(): no trigger capability\n"); */
! 	}
!       else hdx = 0;
        
      } else sls_warn("linux_adio_open(): Couldn't determine capabilities!");
  
      /* Skipping hardware check for now...  Write it later */
      /* Make sure AD/DA is 16-bit and has stereo */
!     if(ioctl(fd, SNDCTL_DSP_GETFMTS, (char *)&flags) != -1) {
        if(flags & AFMT_S16_LE || flags & AFMT_S16_BE ||
  	 flags & AFMT_U16_LE || flags & AFMT_U16_BE)
  	flags = 1;
***************
*** 338,343 ****
--- 357,374 ----
        sls_warn("linux_adio_open(): Couldn't determine formats!");
      }
  
+     /* Turn NDELAY/NONBLOCK mode off -- it doesn't work with OSS anyways */
+     if (hdx) {  /* not sure this is the right test... */
+       if((status = fcntl(fd, F_GETFL, 0)) == -1) {
+         sls_warn("fcntl F_GETFL on /dev/dsp failed");
+       } else {
+         status &= ~O_NDELAY;
+         if(fcntl(fd, F_SETFL, status) == -1) {
+ 	  sls_warn("fcntl F_SETFL on /dev/dsp failed");
+         }
+       }
+     }
+ 
      /* Fill in the LINUXAD structure. */
      linux_adio = (LINUX_ADIO *) calloc(1, sizeof(LINUX_ADIO));
      linux_adio->fd = fd;
***************
*** 352,357 ****
--- 383,390 ----
      linux_adio->play_gain = 100;
      linux_adio->rec_gain = 100;
      linux_adio->mixer_fd = mixer_fd;
+     linux_adio->trigger = trigger;
+     linux_adio->hdx = hdx;
  
      /* 4front-tech.com website suggests decoupling mixer things from
         audio things.  however, we do need to set the port to record from */
***************
*** 375,381 ****
  
      /* Linux does need to get a buffer - OSSFree Pguide suggests doing this
         after setting sample parameters */
!     if(ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &abuf_size) == -1) {
        sls_warn("linux_adio_open(): ioctl failed for SNDCTL_DSP_GETBLKSIZE with error# %d", errno);
        close(mixer_fd);
        close(fd);
--- 408,414 ----
  
      /* Linux does need to get a buffer - OSSFree Pguide suggests doing this
         after setting sample parameters */
!     if(ioctl(fd, SNDCTL_DSP_GETBLKSIZE, (char *)&abuf_size) == -1) {
        sls_warn("linux_adio_open(): ioctl failed for SNDCTL_DSP_GETBLKSIZE with error# %d", errno);
        close(mixer_fd);
        close(fd);
***************
*** 541,547 ****
    linux_adio->new_max_set = 0;
  
    /* Using the ioctl suggested by OSSFree */
!   ioctl(linux_adio->fd, SNDCTL_DSP_GETIPTR, &info);
  #if 0
    /* NO!  This reads the hardware sample counter.  We need to use our software
       counter because ep_adio needs to be able to reset. */
--- 574,580 ----
    linux_adio->new_max_set = 0;
  
    /* Using the ioctl suggested by OSSFree */
!   ioctl(linux_adio->fd, SNDCTL_DSP_GETIPTR, (char *)&info);
  #if 0
    /* NO!  This reads the hardware sample counter.  We need to use our software
       counter because ep_adio needs to be able to reset. */
***************
*** 550,556 ****
    else linux_adio->n_samp_recorded = info.bytes/(2*sizeof(char));
  #endif
    params->n_samp_recorded = linux_adio->n_samp_recorded;
!   ioctl(linux_adio->fd, SNDCTL_DSP_GETOPTR, &info);
    if(linux_adio->wide)
      linux_adio->n_samp_played = info.bytes/(2*sizeof(short));
    else linux_adio->n_samp_played = info.bytes/(2*sizeof(char));
--- 583,589 ----
    else linux_adio->n_samp_recorded = info.bytes/(2*sizeof(char));
  #endif
    params->n_samp_recorded = linux_adio->n_samp_recorded;
!   ioctl(linux_adio->fd, SNDCTL_DSP_GETOPTR, (char *)&info);
    if(linux_adio->wide)
      linux_adio->n_samp_played = info.bytes/(2*sizeof(short));
    else linux_adio->n_samp_played = info.bytes/(2*sizeof(char));
***************
*** 561,567 ****
    else params->is_recording = 0;
  
    /* Using the ioctl suggested by OSSFree */
!   ioctl(linux_adio->fd, SNDCTL_DSP_GETOSPACE, &buf_info);
    if(buf_info.bytes < buf_info.fragstotal*buf_info.fragsize)
      params->is_playing = 1;
    else
--- 594,600 ----
    else params->is_recording = 0;
  
    /* Using the ioctl suggested by OSSFree */
!   ioctl(linux_adio->fd, SNDCTL_DSP_GETOSPACE, (char *)&buf_info);
    if(buf_info.bytes < buf_info.fragstotal*buf_info.fragsize)
      params->is_playing = 1;
    else
***************
*** 586,592 ****
    if (!(linux_adio = linux_adio_i_lookup_fd(fd_adio, "adio_start_record")))
      return(-1);
  
!   dsp_start_recording(linux_adio->fd);
  
    linux_adio->n_samp_recorded = 0;
    linux_adio->state |= ADIO_RECORD;
--- 619,625 ----
    if (!(linux_adio = linux_adio_i_lookup_fd(fd_adio, "adio_start_record")))
      return(-1);
  
!   dsp_start_recording(linux_adio->fd, linux_adio->trigger, linux_adio->hdx);
  
    linux_adio->n_samp_recorded = 0;
    linux_adio->state |= ADIO_RECORD;
***************
*** 605,611 ****
  
    linux_adio->state &= ~ADIO_RECORD;
  
!   dsp_stop_recording(linux_adio->fd);
  
    return(0);
  }
--- 638,644 ----
  
    linux_adio->state &= ~ADIO_RECORD;
  
!   dsp_stop_recording(linux_adio->fd, linux_adio->trigger);
  
    return(0);
  }
***************
*** 654,660 ****
      return(-1);
  
    /* get number of samples available - only use full fragments */
!   if(ioctl(linux_adio->fd, SNDCTL_DSP_GETISPACE, &buf_info) == -1)
      sls_warn("linux_adio: ioctl error on SNDCTL_DSP_GETISPACE!");
    if(linux_adio->wide)
      samp_avail = (buf_info.bytes)/(2*sizeof(short));
--- 687,693 ----
      return(-1);
  
    /* get number of samples available - only use full fragments */
!   if(ioctl(linux_adio->fd, SNDCTL_DSP_GETISPACE, (char *)&buf_info) == -1)
      sls_warn("linux_adio: ioctl error on SNDCTL_DSP_GETISPACE!");
    if(linux_adio->wide)
      samp_avail = (buf_info.bytes)/(2*sizeof(short));
