/*
ZAURUS SL5500 mixer

The zaurus has 2 mixer devices, one for record and one for playback,
/dev/mixer and /dev/dsp1 respectively.



*/

#include <unistd.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/soundcard.h>

#define VERSION "0.1"

#define PLAY_MIXER_DEV 0
#define PLAY_MIXER "/dev/dsp"

void show_level (int device, int devmask, int fd);
void show_mixer_details (int device, char* mixer, int devmask, int fd);
void set_level (int device, int devmask, int level);
int is_stereo_device (int fd);
char * y_or_n (int option);
void usage (void);

int main (int argc, char *argv[]){

  int play_fd, rec_fd, devmask_play, devmask_rec, i, status;
  int optn, query = 0, set = 0, play = 0;
  int num_options = 0;
  char * level = 0;
  

  while (1) {
    optn = getopt(argc, argv, "aqsiol:r:");
    if (optn == -1)
      break;
    
    switch (optn) {
    case 'q':
      query = 1; num_options++;
      break;
    case 's':
      set = 1; num_options++;
      break;
    case 'o':
      play = 1; num_options++;
      break;
    case 'l':
      level = optarg; num_options++;
      break;
      //case 'v':
      //verbose = 1; num_options++;
    }
  }

  if (!num_options){
    usage();
    exit(1);
  }
  
  if ((play_fd = open(PLAY_MIXER, O_RDONLY)) == -1)
    perror("PLAY_MIXER failed to open");

  ioctl(play_fd, SOUND_MIXER_READ_DEVMASK, &devmask_play);

  if (level){
    if (play)
      set_level(PLAY_MIXER_DEV, play_fd, atoi(level));
  }

 if (query){
    if (play)
    show_mixer_details(PLAY_MIXER_DEV, PLAY_MIXER, devmask_play, play_fd);
  }

  close(play_fd);

}

void show_mixer_details (int device, char* mixer, int devmask, int fd){

  printf("\n%s\n----------\n", mixer);
  show_level(device, devmask, fd);
  printf("Stereo: %s\n", y_or_n(is_stereo_device(fd)));
}

void show_level (int device, int devmask, int fd){
  int status = 0, level = 0;
  int left_level, right_level;

  if ((1 << device) & devmask){
    status = ioctl(fd, MIXER_READ(device), &level);

    if ((1 << device) & is_stereo_device(fd)){
       printf(
             "level:\t(left=%d%%, right=%d%%)\n", 
             level & 0xff, 
             (level & 0xff00) >> 8
             );
    } else {
        printf("Level:\t%d%%\n", level/257);
    }
  }
}

void set_level (int device, int fd, int level){
  int mix_level, status;

 
   mix_level = level + (level << 8);
 
   status = ioctl(fd, MIXER_WRITE(device), &mix_level);
   if (status == -1)
     perror("MIXER_WRITE ioctl failed");
}

int is_stereo_device (int fd){
  int status = 0, stereodevs;
  // the record device is /only/ mono, but we check anyway
  status = ioctl(fd, SOUND_MIXER_READ_STEREODEVS, &stereodevs);
  if (status == -1)
    perror("SOUND_MIXER_READ_STEREODEVS ioctl failed");

  return stereodevs;
}

char * y_or_n (int option){
  return option ? "y" : "n";
}

void usage (void){

  printf("zmix %s usage: zmix [-q] [-o] [-l n] [-v]\n", VERSION);
  printf("\
  -q:\tquery\n\
  -o:\toutput mixer\n\
  -l:\tlevel (%)\n\n");
  //-v:\tverbose\n\n");
  
}

