summaryrefslogblamecommitdiffstats
path: root/c/src/lib/libbsp/arm/nds/sound/sound.c
blob: 9e133be45a15b228765c73ad54557a6c3e75093f (plain) (tree)
1
2
3
4
5
6
7
8
9








                                                                  







                      
                      




































                                                               
                                               













































                                                                         
                                                                                           























































































































                                                                    
/*
 * RTEMS for Nintendo DS sound driver.
 *
 * Copyright (c) 2008 by Matthieu Bucchianeri <mbucchia@gmail.com>
 *
 * The license and distribution terms for this file may be
 * found in the file LICENSE in this distribution or at
 *
 * http://www.rtems.com/license/LICENSE
 */

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>

#include <bsp.h>
#include <rtems/irq.h>
#include <rtems/libio.h>
#include <nds.h>

#include "sound.h"
#include "../include/my_ipc.h"

/*
 * default values.
 */

static int volume = 64;
static int pan = 64;
static int freq = 11025;
static int format = 0;          // 0 is 8 bits and 1 is 16 bits
static int offset = 0;

/*
 * sound device driver initialize entry point.
 */

rtems_device_driver
sound_initialize (rtems_device_major_number major,
                  rtems_device_minor_number minor, void *arg)
{
  rtems_status_code status;

  printk ("[+] sound started\n");

  /* register the devices */
  status = rtems_io_register_name ("/dev/pcm", major, 0);
  if (status != RTEMS_SUCCESSFUL) {
    printk ("[!] error registering sound\n");
    rtems_fatal_error_occurred (status);
  }

  /* reset IPCs structs */
  IPC->soundData = NULL;
  memset ((void *)my_IPC, 0, sizeof (*my_IPC));
  DC_FlushAll ();

  return RTEMS_SUCCESSFUL;
}

/*
 * sound device driver open operation.
 */

rtems_device_driver
sound_open (rtems_device_major_number major,
            rtems_device_minor_number minor, void *arg)
{
  return RTEMS_SUCCESSFUL;
}

/*
 * sound device driver close operation.
 */

rtems_device_driver
sound_close (rtems_device_major_number major,
             rtems_device_minor_number minor, void *arg)
{
  return RTEMS_SUCCESSFUL;
}

/*
 * sound device driver read operation. read data from recorded microphone
 * samples.
 */

rtems_device_driver
sound_read (rtems_device_major_number major,
            rtems_device_minor_number minor, void *arg)
{
  rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *) arg;

  /* check end of file */
  if (offset >= my_IPC->recorded_length) {
    rw_args->bytes_moved = 0;

    return RTEMS_SUCCESSFUL;
  }

  /* read buffer */
  memcpy ((void *)rw_args->buffer, (void *)my_IPC->record_buffer + offset, rw_args->count);
  offset += rw_args->count;
  rw_args->bytes_moved = rw_args->count;
  return RTEMS_SUCCESSFUL;
}

/*
 * sound device driver write operation. read a pcm sound.
 */

rtems_device_driver
sound_write (rtems_device_major_number major,
             rtems_device_minor_number minor, void *arg)
{
  rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *) arg;
  static TransferSound snd;

  /* XXX not exclusive */
  while (IPC->soundData != NULL);

  snd.count = 1;
  snd.data[0].data = rw_args->buffer;
  snd.data[0].len = rw_args->count;
  snd.data[0].rate = freq;
  snd.data[0].vol = volume;
  snd.data[0].pan = pan;
  snd.data[0].format = format;

  IPC->soundData = &snd;
  DC_FlushAll ();

  rw_args->bytes_moved = rw_args->count;
  return RTEMS_SUCCESSFUL;
}

/*
 * ioctl entry point.
 */

rtems_device_driver
sound_control (rtems_device_major_number major,
               rtems_device_minor_number minor, void *arg)
{
  rtems_libio_ioctl_args_t *args = arg;
  uint32_t *val = (uint32_t *) args->buffer;

  switch (args->command) {
    /* sound volume management */
  case SOUND_SVOL:
    volume = *val;
    break;
  case SOUND_GVOL:
    *val = volume;
    break;
    /* sound format settings */
  case SOUND_SFMT:
    switch (*val & SOUND_FREQ_MASK) {
    case SOUND_FREQ_11025:
      freq = 11025;
      break;
    case SOUND_FREQ_22050:
      freq = 22050;
      break;
    case SOUND_FREQ_44100:
      freq = 44100;
      break;
    case SOUND_FREQ_RECORD:
      freq = 16384;
      break;
    }
    format = (*val & SOUND_FORMAT_16) ? 1 : 0;
    printk ("[+] pcm %d bits @ %d hz\n", format ? 16 : 8, freq);
    break;
  case SOUND_GFMT:
    if (freq == 11025) {
      *val = SOUND_FREQ_11025;
    } else if (freq == 22050) {
      *val = SOUND_FREQ_22050;
    } else if (freq == 44100) {
      *val = SOUND_FREQ_44100;
    } else if (freq == 16384) {
      *val = SOUND_FREQ_RECORD;
    }
    *val |= format ? SOUND_FORMAT_16 : SOUND_FORMAT_8;
    break;
    /* sound pan settings */
  case SOUND_SPAN:
    pan = *val;
    break;
  case SOUND_GPAN:
    *val = pan;
    break;
    /* set recording buffer length */
  case SOUND_SRECLEN:
    my_IPC->record_buffer = malloc (*val);
    my_IPC->record_length_max = *val;
    printk ("[+] mic buffer %u B @ %p\n", my_IPC->record_length_max,
            my_IPC->record_buffer);
    break;
    /* start recording */
  case SOUND_STARTREC:
    my_IPC->recorded_length = 0;
    my_IPC->record = 1;
    break;
    /* stop recording */
  case SOUND_STOPREC:
    if (!my_IPC->record) {
      printk ("[!] STOPREC while not recording\n");
    }
    my_IPC->record = 0;
    while (my_IPC->recorded_length == 0);
    offset = 0;
    if (val != NULL) {
      *val = my_IPC->recorded_length;
    }
    break;
  default:
    break;
  }
  return RTEMS_SUCCESSFUL;
}