forked from Imagelibrary/rtems
226 lines
4.9 KiB
C
226 lines
4.9 KiB
C
/*
|
|
* 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
|
|
*
|
|
* $Id$
|
|
*/
|
|
|
|
#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;
|
|
}
|