From: <ljs...@us...> - 2008-08-30 19:52:42
|
Revision: 603 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=603&view=rev Author: ljsebald Date: 2008-08-30 19:52:37 +0000 (Sat, 30 Aug 2008) Log Message: ----------- Adding in rewritten microphone driver that now supports more than just the 16-bit signed @ 11025Hz encoding for samples. Modified Paths: -------------- kos/doc/CHANGELOG kos/kernel/arch/dreamcast/hardware/maple/sip.c kos/kernel/arch/dreamcast/include/dc/maple/sip.h Modified: kos/doc/CHANGELOG =================================================================== --- kos/doc/CHANGELOG 2008-08-18 00:08:44 UTC (rev 602) +++ kos/doc/CHANGELOG 2008-08-30 19:52:37 UTC (rev 603) @@ -162,6 +162,8 @@ - DC If a packet is < 60 bytes, pad it with null bytes for clarity, rather than just transmitting whatever random junk was in the transmit buffer from previous sends [LS] +- DC Rewrote microphone driver to make it support the different encodings + available to the hardware [LS] KallistiOS version 1.2.0 ----------------------------------------------- - DC Fix to use DCARM7_CFLAGS when compiling ARM driver [Christian Groessler == CG] Modified: kos/kernel/arch/dreamcast/hardware/maple/sip.c =================================================================== --- kos/kernel/arch/dreamcast/hardware/maple/sip.c 2008-08-18 00:08:44 UTC (rev 602) +++ kos/kernel/arch/dreamcast/hardware/maple/sip.c 2008-08-30 19:52:37 UTC (rev 603) @@ -1,279 +1,402 @@ /* KallistiOS ##version## sip.c - Copyright (C) 2005 Lawrence Sebald + Copyright (C) 2005, 2008 Lawrence Sebald */ #include <assert.h> #include <stdio.h> #include <string.h> #include <stdlib.h> +#include <arch/irq.h> #include <kos/genwait.h> #include <dc/maple.h> #include <dc/maple/sip.h> -static void sip_generic_cb(maple_frame_t *frame) { - /* Unlock the frame */ - maple_frame_unlock(frame); - - /* Wake up! */ - genwait_wake_all(frame); +#define SIP_START_SAMPLING 0x80 + +static void sip_start_sampling_cb(maple_frame_t *frame) { + sip_state_t *sip; + maple_response_t *resp; + + /* Unlock the frame */ + maple_frame_unlock(frame); + + /* Make sure we got a valid response */ + resp = (maple_response_t *)frame->recv_buf; + + if(resp->response != MAPLE_RESPONSE_OK) + return; + + /* Set the is_sampling flag. */ + sip = (sip_state_t *)frame->dev->status; + sip->is_sampling = 1; + + /* Wake up! */ + genwait_wake_all(frame); } -int sip_set_gain(maple_device_t *dev, uint8 g) { - sip_state_t *sip; +static void sip_stop_sampling_cb(maple_frame_t *frame) { + sip_state_t *sip; + maple_response_t *resp; - assert( dev != NULL ); - - sip = (sip_state_t *)dev->status; + /* Unlock the frame */ + maple_frame_unlock(frame); - /* Check the gain value for validity */ - if(g > 0x1F) - return MAPLE_EINVALID; + /* Make sure we got a valid response */ + resp = (maple_response_t *)frame->recv_buf; - sip->amp_gain = g; + if(resp->response != MAPLE_RESPONSE_OK) + return; - return MAPLE_EOK; + /* Clear the is_sampling flag. */ + sip = (sip_state_t *)frame->dev->status; + sip->is_sampling = 0; + + /* Wake up! */ + genwait_wake_all(frame); } -int sip_start_sampling(maple_device_t *dev) { - sip_state_t *sip; - uint32 *send_buf; - - assert( dev != NULL ); - - sip = (sip_state_t *)dev->status; - - /* Make sure we aren't yet sampling */ - if(sip->is_sampling) - return MAPLE_EFAIL; - - /* Lock the frame */ - if(maple_frame_lock(&dev->frame) < 0) - return MAPLE_EAGAIN; - - /* Reset the frame */ - maple_frame_init(&dev->frame); - send_buf = (uint32 *)dev->frame.recv_buf; - send_buf[0] = MAPLE_FUNC_MICROPHONE; - send_buf[1] = 0x02 | (0x80 << 8); /* Start sampling */ - dev->frame.cmd = MAPLE_COMMAND_MICCONTROL; - dev->frame.dst_port = dev->port; - dev->frame.dst_unit = dev->unit; - dev->frame.length = 2; - dev->frame.callback = sip_generic_cb; - dev->frame.send_buf = send_buf; - maple_queue_frame(&dev->frame); - - /* Wait for the SIP to accept it */ - if(genwait_wait(&dev->frame, "sip_start_sampling", 500, NULL) < 0) { - if(dev->frame.state != MAPLE_FRAME_VACANT) { - /* Something went wrong.... */ - dev->frame.state = MAPLE_FRAME_VACANT; - dbglog(DBG_ERROR, "sip_start_sampling: timeout to unit %c%c\n", - dev->port + 'A', dev->unit + '0'); - return MAPLE_ETIMEOUT; - } - } - - sip->is_sampling = 1; - - return MAPLE_EOK; +int sip_set_gain(maple_device_t *dev, unsigned int g) { + sip_state_t *sip; + + assert( dev != NULL ); + + /* Check the gain value for validity */ + if(g > SIP_MAX_GAIN) + return MAPLE_EINVALID; + + sip = (sip_state_t *)dev->status; + sip->amp_gain = g; + + return MAPLE_EOK; } -int sip_stop_sampling(maple_device_t *dev) { - sip_state_t *sip; - uint32 *send_buf; +int sip_set_sample_type(maple_device_t *dev, unsigned int type) { + sip_state_t *sip; - assert( dev != NULL ); + assert( dev != NULL ); - sip = (sip_state_t *)dev->status; + /* Check the sample type value for validity. */ + if(type > SIP_SAMPLE_8BIT_ULAW) + return MAPLE_EINVALID; - /* Make sure we actually are sampling */ - if(!sip->is_sampling) - return MAPLE_EFAIL; + sip = (sip_state_t *)dev->status; - /* Lock the frame */ - if(maple_frame_lock(&dev->frame) < 0) - return MAPLE_EAGAIN; + /* Make sure we aren't sampling already. */ + if(sip->is_sampling) + return MAPLE_EFAIL; - /* Reset the frame */ - maple_frame_init(&dev->frame); - send_buf = (uint32 *)dev->frame.recv_buf; - send_buf[0] = MAPLE_FUNC_MICROPHONE; - send_buf[1] = 0x02; /* Stop sampling */ - dev->frame.cmd = MAPLE_COMMAND_MICCONTROL; - dev->frame.dst_port = dev->port; - dev->frame.dst_unit = dev->unit; - dev->frame.length = 2; - dev->frame.callback = sip_generic_cb; - dev->frame.send_buf = send_buf; - maple_queue_frame(&dev->frame); + sip->sample_type = type; - /* Wait for the SIP to accept it */ - if(genwait_wait(&dev->frame, "sip_stop_sampling", 500, NULL) < 0) { - if(dev->frame.state != MAPLE_FRAME_VACANT) { - /* Something went wrong.... */ - dev->frame.state = MAPLE_FRAME_VACANT; - dbglog(DBG_ERROR, "sip_stop_sampling: timeout to unit %c%c\n", - dev->port + 'A', dev->unit + '0'); - return MAPLE_ETIMEOUT; - } - } + return MAPLE_EOK; +} - sip->is_sampling = 0; +int sip_set_frequency(maple_device_t *dev, unsigned int freq) { + sip_state_t *sip; - return MAPLE_EOK; + assert( dev != NULL ); + + /* Check the frequency value for validity. */ + if(freq > SIP_SAMPLE_8KHZ) + return MAPLE_EINVALID; + + sip = (sip_state_t *)dev->status; + + /* Make sure we aren't sampling already. */ + if(sip->is_sampling) + return MAPLE_EFAIL; + + sip->frequency = freq; + + return MAPLE_EOK; } -int sip_get_samples(maple_device_t *dev, uint8 *buf, size_t len) { - sip_state_t *sip; - size_t sz; +int sip_start_sampling(maple_device_t *dev, int block) { + sip_state_t *sip; + uint32 *send_buf; - sip = (sip_state_t *)dev->status; + assert( dev != NULL ); - if(sip->is_sampling) - return MAPLE_EFAIL; + sip = (sip_state_t *)dev->status; - sz = sip->buf_pos > len ? len : sip->buf_pos; + /* Make sure we aren't yet sampling */ + if(sip->is_sampling) + return MAPLE_EFAIL; - memcpy(buf, sip->samples_buf, sz); + /* Lock the frame */ + if(maple_frame_lock(&dev->frame) < 0) + return MAPLE_EAGAIN; - if(sz == sip->buf_pos) { - sip->buf_pos = 0; - } - else { - memcpy(sip->samples_buf + sz, sip->samples_buf, sip->buf_pos - sz); - sip->buf_pos -= sz; - } + /* Reset the frame */ + maple_frame_init(&dev->frame); + send_buf = (uint32 *)dev->frame.recv_buf; + send_buf[0] = MAPLE_FUNC_MICROPHONE; + send_buf[1] = SIP_SUBCOMMAND_BASIC_CTRL | + (((sip->sample_type) | (sip->frequency << 2) | + SIP_START_SAMPLING) << 8); + dev->frame.cmd = MAPLE_COMMAND_MICCONTROL; + dev->frame.dst_port = dev->port; + dev->frame.dst_unit = dev->unit; + dev->frame.length = 2; + dev->frame.callback = sip_start_sampling_cb; + dev->frame.send_buf = send_buf; + maple_queue_frame(&dev->frame); - return sz; + if(block) { + /* Wait for the SIP to accept it */ + if(genwait_wait(&dev->frame, "sip_start_sampling", 500, NULL) < 0) { + if(dev->frame.state != MAPLE_FRAME_VACANT) { + /* Something went wrong.... */ + dev->frame.state = MAPLE_FRAME_VACANT; + dbglog(DBG_ERROR, "sip_start_sampling: timeout to unit %c%c\n", + dev->port + 'A', dev->unit + '0'); + return MAPLE_ETIMEOUT; + } + } + } + + return MAPLE_EOK; } -int sip_clear_samples(maple_device_t *dev) { - sip_state_t *sip; +int sip_stop_sampling(maple_device_t *dev, int block) { + sip_state_t *sip; + uint32 *send_buf; - sip = (sip_state_t *)dev->status; + assert( dev != NULL ); - if(sip->is_sampling) - return MAPLE_EFAIL; + sip = (sip_state_t *)dev->status; - sip->buf_pos = 0; + /* Make sure we actually are sampling */ + if(!sip->is_sampling) + return MAPLE_EFAIL; - return MAPLE_EOK; + /* Lock the frame */ + if(maple_frame_lock(&dev->frame) < 0) + return MAPLE_EAGAIN; + + /* Reset the frame */ + maple_frame_init(&dev->frame); + send_buf = (uint32 *)dev->frame.recv_buf; + send_buf[0] = MAPLE_FUNC_MICROPHONE; + send_buf[1] = SIP_SUBCOMMAND_BASIC_CTRL; + dev->frame.cmd = MAPLE_COMMAND_MICCONTROL; + dev->frame.dst_port = dev->port; + dev->frame.dst_unit = dev->unit; + dev->frame.length = 2; + dev->frame.callback = sip_stop_sampling_cb; + dev->frame.send_buf = send_buf; + maple_queue_frame(&dev->frame); + + if(block) { + /* Wait for the SIP to accept it */ + if(genwait_wait(&dev->frame, "sip_stop_sampling", 500, NULL) < 0) { + if(dev->frame.state != MAPLE_FRAME_VACANT) { + /* Something went wrong.... */ + dev->frame.state = MAPLE_FRAME_VACANT; + dbglog(DBG_ERROR, "sip_stop_sampling: timeout to unit %c%c\n", + dev->port + 'A', dev->unit + '0'); + return MAPLE_ETIMEOUT; + } + } + } + + return MAPLE_EOK; } -static void sip_reply(maple_frame_t *frm) { - maple_response_t *resp; - uint32 *respbuf; - size_t sz, i; - sip_state_t *sip; - - /* Unlock the frame now (it's ok, we're in an IRQ) */ - maple_frame_unlock(frm); - - /* Make sure we got a valid response */ - resp = (maple_response_t *)frm->recv_buf; - - if (resp->response != MAPLE_RESPONSE_DATATRF) - return; - respbuf = (uint32 *)resp->data; - if (respbuf[0] != MAPLE_FUNC_MICROPHONE) - return; - - if(frm->dev) { - sip = (sip_state_t *)frm->dev->status; - frm->dev->status_valid = 1; +uint8 *sip_get_samples(maple_device_t *dev, size_t *sz) { + sip_state_t *sip; + uint8 *rv; + uint32 old; - if(sip->is_sampling) { - sz = resp->data_len * 4 - 8; + assert( dev != NULL ); + assert( sz != NULL ); - /* Make sure we don't overflow the buffer */ - if(sz + sip->buf_pos <= sip->buf_len) { - for(i = 0; i < sz; i++) { - sip->samples_buf[i + sip->buf_pos] = resp->data[i + 8]; - } - sip->buf_pos += sz; - } - } - } + /* Disable interrupts so that nothing changes underneath us. */ + old = irq_disable(); + + sip = (sip_state_t *)dev->status; + + /* Make sure that we're not currently sampling. */ + if(sip->is_sampling) { + irq_restore(old); + *sz = (size_t)-1; + return NULL; + } + + /* Grab the values to return. */ + *sz = sip->buf_pos; + rv = sip->samples_buf; + + /* Allocate us a new buffer. */ + sip->buf_pos = 0; + sip->samples_buf = (uint8 *)malloc(11025 * 2 * 10); + + if(sip->samples_buf == NULL) { + sip->buf_len = 0; + dev->status_valid = 0; + } + else { + sip->buf_len = 11025 * 2 * 10; + dev->status_valid = 1; + } + + irq_restore(old); + return rv; } +int sip_clear_samples(maple_device_t *dev) { + sip_state_t *sip; + uint32 old; -static int sip_poll(maple_device_t *dev) { - sip_state_t *sip; - uint32 *send_buf; + assert( dev != NULL ); - /* Test to make sure that the particular mic is enabled */ - sip = (sip_state_t *)dev->status; + /* Disable IRQs so that nothing changes under us */ + old = irq_disable(); - /* Lock the frame, or die trying */ - if(maple_frame_lock(&dev->frame) < 0) - return 0; + sip = (sip_state_t *)dev->status; - maple_frame_init(&dev->frame); - send_buf = (uint32 *)dev->frame.recv_buf; - send_buf[0] = MAPLE_FUNC_MICROPHONE; - send_buf[1] = 0x01 | (sip->amp_gain << 8); /* Get samples/status */ - dev->frame.cmd = MAPLE_COMMAND_MICCONTROL; - dev->frame.dst_port = dev->port; - dev->frame.dst_unit = dev->unit; - dev->frame.length = 2; - dev->frame.callback = sip_reply; - dev->frame.send_buf = send_buf; - maple_queue_frame(&dev->frame); + if(sip->is_sampling) { + irq_restore(old); + return MAPLE_EFAIL; + } - return 0; + sip->buf_pos = 0; + + irq_restore(old); + + return MAPLE_EOK; } +static void sip_reply(maple_frame_t *frm) { + maple_response_t *resp; + uint32 *respbuf; + size_t sz; + sip_state_t *sip; + void *tmp; + + /* Unlock the frame now (it's ok, we're in an IRQ) */ + maple_frame_unlock(frm); + + /* Make sure we got a valid response */ + resp = (maple_response_t *)frm->recv_buf; + + if(resp->response != MAPLE_RESPONSE_DATATRF) + return; + + respbuf = (uint32 *)resp->data; + + if(respbuf[0] != MAPLE_FUNC_MICROPHONE) + return; + + if(frm->dev) { + sip = (sip_state_t *)frm->dev->status; + frm->dev->status_valid = 1; + + if(sip->is_sampling) { + sz = resp->data_len * 4 - 8; + + /* Resize the buffer, if it is needed. */ + if(sz + sip->buf_pos > sip->buf_len) { + /* Attempt to double the buffer size. */ + tmp = realloc(sip->samples_buf, sip->buf_len << 1); + + if(!tmp) { + return; + } + + sip->samples_buf = tmp; + sip->buf_len <<= 1; + } + + memcpy(sip->samples_buf + sip->buf_pos, resp->data + 8, sz); + sip->buf_pos += sz; + } + } +} + +static int sip_poll(maple_device_t *dev) { + sip_state_t *sip; + uint32 *send_buf; + + sip = (sip_state_t *)dev->status; + + /* Test to make sure that the particular mic is enabled */ + if(!sip->is_sampling) { + return 0; + } + + /* Lock the frame, or die trying */ + if(maple_frame_lock(&dev->frame) < 0) + return 0; + + maple_frame_init(&dev->frame); + send_buf = (uint32 *)dev->frame.recv_buf; + send_buf[0] = MAPLE_FUNC_MICROPHONE; + send_buf[1] = SIP_SUBCOMMAND_GET_SAMPLES | + (sip->amp_gain << 8); + dev->frame.cmd = MAPLE_COMMAND_MICCONTROL; + dev->frame.dst_port = dev->port; + dev->frame.dst_unit = dev->unit; + dev->frame.length = 2; + dev->frame.callback = sip_reply; + dev->frame.send_buf = send_buf; + maple_queue_frame(&dev->frame); + + return 0; +} + static void sip_periodic(maple_driver_t *drv) { - maple_driver_foreach(drv, sip_poll); + maple_driver_foreach(drv, sip_poll); } static int sip_attach(maple_driver_t *drv, maple_device_t *dev) { - sip_state_t *sip; + sip_state_t *sip; - /* Allocate the sample buffer for 10 seconds worth of samples */ - sip = (sip_state_t *)dev->status; - sip->is_sampling = 0; - sip->amp_gain = 0; - sip->buf_pos = 0; - sip->samples_buf = (uint8 *)malloc(11025 * 2 * 10); + /* Allocate the sample buffer for 10 seconds worth of samples (11.025kHz, + 16-bit signed samples). */ + sip = (sip_state_t *)dev->status; + sip->is_sampling = 0; + sip->amp_gain = SIP_DEFAULT_GAIN; + sip->buf_pos = 0; + sip->samples_buf = (uint8 *)malloc(11025 * 2 * 10); - if(sip->samples_buf == NULL) { - dev->status_valid = 0; - sip->buf_len = 0; - return -1; - } - else { - dev->status_valid = 1; - sip->buf_len = 11025 * 2 * 10; - return 0; - } + if(sip->samples_buf == NULL) { + dev->status_valid = 0; + sip->buf_len = 0; + return -1; + } + else { + dev->status_valid = 1; + sip->buf_len = 11025 * 2 * 10; + return 0; + } } static void sip_detach(maple_driver_t *drv, maple_device_t *dev) { - sip_state_t *sip; + sip_state_t *sip; - sip = (sip_state_t *)dev->status; - free(sip->samples_buf); + sip = (sip_state_t *)dev->status; + + if(sip->samples_buf) { + free(sip->samples_buf); + } } /* Device Driver Struct */ static maple_driver_t sip_drv = { - functions: MAPLE_FUNC_MICROPHONE, - name: "Sound Input Peripheral", - periodic: sip_periodic, - attach: sip_attach, - detach: sip_detach + functions: MAPLE_FUNC_MICROPHONE, + name: "Sound Input Peripheral", + periodic: sip_periodic, + attach: sip_attach, + detach: sip_detach }; /* Add the SIP to the driver chain */ int sip_init() { - return maple_driver_reg(&sip_drv); + return maple_driver_reg(&sip_drv); } void sip_shutdown() { - maple_driver_unreg(&sip_drv); + maple_driver_unreg(&sip_drv); } - Modified: kos/kernel/arch/dreamcast/include/dc/maple/sip.h =================================================================== --- kos/kernel/arch/dreamcast/include/dc/maple/sip.h 2008-08-18 00:08:44 UTC (rev 602) +++ kos/kernel/arch/dreamcast/include/dc/maple/sip.h 2008-08-30 19:52:37 UTC (rev 603) @@ -1,7 +1,7 @@ /* KallistiOS ##version## dc/maple/sip.h - Copyright (C) 2005 Lawrence Sebald + Copyright (C) 2005, 2008 Lawrence Sebald */ @@ -13,40 +13,75 @@ #include <sys/types.h> -/* This driver controls the Sound Input Peripheral for the maple - bus (the microphone). Many thanks go out to ZeZu for pointing - me towards what some commands actually do. +/* This driver controls the Sound Input Peripheral for the maple bus (aka, the + microphone that came with Seaman and the Dreameye). Many thanks go out to + ZeZu for pointing me towards what some commands actually do in the original + version of this driver. */ -/* SIP Status structure */ +/* SIP Status structure. Everything in here should be considered to be read-only + from user programs. */ typedef struct sip_state { - uint8 amp_gain; - uint8 is_sampling; - size_t buf_len; - off_t buf_pos; - uint8 *samples_buf; + int amp_gain; + int sample_type; + int frequency; + int is_sampling; + size_t buf_len; + off_t buf_pos; + uint8 *samples_buf; } sip_state_t; -/* The maximum gain value to be passed to the function - below. */ -#define SIP_MAX_GAIN 0x1F +/* Subcommands of the Microphone command. */ +#define SIP_SUBCOMMAND_GET_SAMPLES 0x01 +#define SIP_SUBCOMMAND_BASIC_CTRL 0x02 -/* Set the amplifier's gain. This should only be called prior - to sampling, to ensure that the sound returned is of the - same volume. */ -int sip_set_gain(maple_device_t *dev, uint8 g); +/* The minimum, maximum, and default gain values that can be passed to the + sip_set_gain function. */ +#define SIP_MIN_GAIN 0x00 +#define SIP_DEFAULT_GAIN 0x0F +#define SIP_MAX_GAIN 0x1F -/* Start sampling. */ -int sip_start_sampling(maple_device_t *dev); +/* Set the amplifier's gain. This should only be called prior to sampling, to + ensure that the sound returned is of the same volume (unlike the other + functions below, this is not strictly a requirement, as this gets sent + with all of the get samples packets). */ +int sip_set_gain(maple_device_t *dev, unsigned int g); -/* Stop sampling. */ -int sip_stop_sampling(maple_device_t *dev); +/* Sample types. These two values are the only defined types of samples that + the SIP can output. 16-bit signed is your standard 16-bit signed samples, + where 8-bit ulaw is obvously encoded as ulaw. */ +#define SIP_SAMPLE_16BIT_SIGNED 0x00 +#define SIP_SAMPLE_8BIT_ULAW 0x01 -/* Get samples out of the buffer. This can ONLY be called after - sampling has been stopped. Returns the size in bytes of the - filled buffer. */ -int sip_get_samples(maple_device_t *dev, uint8 *buf, size_t len); +/* Set the sample type to be returned by the microphone. This must be called + prior to a sip_start_sampling if you want to change it from the default + (16-bit signed is the default). */ +int sip_set_sample_type(maple_device_t *dev, unsigned int type); +/* Sampling frequencies. The SIP supports sampling at either 8kHz or 11.025 kHz. + One of these values should be passed to the sip_set_frequency function. */ +#define SIP_SAMPLE_11KHZ 0x00 +#define SIP_SAMPLE_8KHZ 0x01 + +/* Set the sampling frequency to be returned by the microphone. This must be + called prior to a sip_start_sampling if you want to change it from the + default (11kHz is the default). */ +int sip_set_frequency(maple_device_t *dev, unsigned int freq); + +/* Start sampling. If you want the function to block until sampling has started, + set the block argument to something other than zero. Otherwise, check the + is_sampling member of the device status to know when sampling has started. */ +int sip_start_sampling(maple_device_t *dev, int block); + +/* Stop sampling. Same comment about blocking above applies here too. */ +int sip_stop_sampling(maple_device_t *dev, int block); + +/* Grab the samples buffer from the device. This function can only be called + when the microphone is not sampling. Once you call this function, you are + responsible for the buffer, so you must free it when you're done. The sz + pointer is used to return how long the sample data is. */ +uint8 *sip_get_samples(maple_device_t *dev, size_t *sz); + /* Clear the internal sample buffer. */ int sip_clear_samples(maple_device_t *dev); @@ -57,4 +92,3 @@ __END_DECLS #endif /* __DC_MAPLE_SIP_H */ - This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |