/* * RTEMS for Nintendo DS sound driver. * * Copyright (c) 2008 by Matthieu Bucchianeri * * 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 #include #include #include #include #include #include #include #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; }