📄 vxsound.cpp
字号:
/****************************************************************** MODULE: VxSound.cpp** DESCRIPTION: A framework for porting ALSA library sound card drivers* to VxWorks.* * ORIGINAL AUTHOR: Dan Walkes - with lots of influence from GNU ALSA* library files and linux sound driver code.* * UPDATED BY: * * CREATED: Oct, 2005* MODIFIED: * * NOTES:** In most cases, functions without a vx_ prefix were taken from the ALSA library* files and modified little (if any) to work with VxWorks. Functions starting with a* vx_ were changed significantly to support VxWorks instead of linux.** CODE USAGE:* See references** REVISION HISTORY AND NOTES:** Date Update* ---------------------------------------------------------------------* Oct 1, 2005 Created.** REFERENCES:** 1) "vxWALSA Sound Driver" document included with this release.*****************************************************************/#include "vxworks.h"#include "stdlib.h"#include <stdio.h>#include <string.h>/* Vxworks -linux includes */#include "VxTypes.h"#include "VxPCI.h"#include "VxSound.h"#include "es1938.h" /*-------------------------------------------------------------- Global Variables----------------------------------------------------------------*/static int maximum_substreams = 4;uint32 snd_interrupt=0;snd_card_t *psndCard;static int preallocate_dma = 1;/* variables for debugging/reference */pci_dev *pGlobPCIDev;snd_pcm_substream_t *gplayback;/* include application .h files here */#include "vx_tone_ap.h"/* a structure with sound applications.. replace with your application. See vx_tone_ap for more information */vx_snd_application sndAp ={ { TONE_PLAYBACK_PRIORITY, toneApPlaybackTaskInit }, // playback params { 0 } // capture params};/*-------------------------------------------------------------- Function Prototypes----------------------------------------------------------------*/static int snd_pcm_free(snd_pcm_t *pcm);static int snd_pcm_lib_preallocate_pages1(snd_pcm_substream_t *substream, size_t size, size_t max);static int vx_snd_pcm_substream_proc_done( snd_pcm_substream_t *substream );static int vx_snd_pcm_substream_proc_init( snd_pcm_substream_t *substream );/*-------------------------------------------------------------- Function Description: Allocates a new snd_card_t structure based on the passed parameters This function was taken directly from the ALSA library and includes lots of stuff specific to Linux in the VXWORKS_UNUSED compile-switched section. Basically all this function does now is allocate the snd_card_t structure and initialize members. Call snd_card_free to free this structure. Arguments: int idx - not used const char *xid - not used void *module - not used int extra size - extra size allocated within the sound card structure Returns: snd_card_t * the new card or NULL if failure ---------------------------------------------------------------*/snd_card_t *snd_card_new( int idx, const char *xid, void *module, int extra_size){ snd_card_t *card; int err; if (extra_size < 0) extra_size = 0; card = (snd_card_t *) kcalloc(1, sizeof(*card) + extra_size, GFP_KERNEL); if (card == NULL) return NULL; card->private_free = NULL; return card; /* note.. eventually may need to do some of the stuff below */ #if VXWORKS_UNUSED if (xid) { if (!snd_info_check_reserved_words(xid)) goto __error; strlcpy(card->id, xid, sizeof(card->id)); } err = 0; write_lock(&snd_card_rwlock); if (idx < 0) { int idx2; for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) if (~snd_cards_lock & idx & 1<<idx2) { idx = idx2; if (idx >= snd_ecards_limit) snd_ecards_limit = idx + 1; break; } } else if (idx < snd_ecards_limit) { if (snd_cards_lock & (1 << idx)) err = -ENODEV; /* invalid */ } else if (idx < SNDRV_CARDS) snd_ecards_limit = idx + 1; /* increase the limit */ else err = -ENODEV; if (idx < 0 || err < 0) { write_unlock(&snd_card_rwlock); snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i)\n", idx, snd_ecards_limit - 1); goto __error; } snd_cards_lock |= 1 << idx; /* lock it */ write_unlock(&snd_card_rwlock); card->number = idx; card->module = module; INIT_LIST_HEAD(&card->devices); init_rwsem(&card->controls_rwsem); rwlock_init(&card->ctl_files_rwlock); INIT_LIST_HEAD(&card->controls); INIT_LIST_HEAD(&card->ctl_files); spin_lock_init(&card->files_lock); init_waitqueue_head(&card->shutdown_sleep); INIT_WORK(&card->free_workq, snd_card_free_thread, card);#ifdef CONFIG_PM init_MUTEX(&card->power_lock); init_waitqueue_head(&card->power_sleep);#endif /* the control interface cannot be accessed from the user space until */ /* snd_cards_bitmask and snd_cards are set with snd_card_register */ if ((err = snd_ctl_create(card)) < 0) { snd_printd("unable to register control minors\n"); goto __error; } if ((err = snd_info_card_create(card)) < 0) { snd_printd("unable to create card info\n"); goto __error_ctl; } if (extra_size > 0) card->private_data = (char *)card + sizeof(snd_card_t); return card; __error_ctl: snd_device_free_all(card, SNDRV_DEV_CMD_PRE); __error: kfree(card); return NULL;#endif}/*-------------------------------------------------------------- Function Description: Frees a snd_card_t structure. This function has been modified to call a private free function and assumes a pci structure (frees the pci structure as well.) Arguments: snd_card_t *pcard - a pointer to the snd_card_t structure to free Returns:---------------------------------------------------------------*/void snd_card_free( snd_card_t *pcard ){ if( pcard->pcm ) { snd_pcm_free( pcard->pcm ); } if( pcard->private_free ) { ( *pcard->private_free )(pcard); } kfree( pcard );}/*-------------------------------------------------------------- Function Description: Frees the DMA area in the substream.. if one was allocated. Arguments: snd_pcm_substream_t *substream - a pointer to the substream for which to free the DMA area Returns:---------------------------------------------------------------*/static void snd_pcm_lib_preallocate_dma_free(snd_pcm_substream_t *substream){ if (substream->dma_buffer.area == NULL) return;#if VX_BUILD_UNUSED /* add later.. actually do the mem free */ if (substream->dma_buf_id) snd_dma_reserve_buf(&substream->dma_buffer, substream->dma_buf_id); else snd_dma_free_pages(&substream->dma_buffer);#else free( substream->dma_buffer.area );#endif substream->dma_buffer.area = NULL;}/** * snd_pcm_lib_preallocate_free - release the preallocated buffer of the specified substream. * @substream: the pcm substream instance * * Releases the pre-allocated buffer of the given substream. * * Returns zero if successful, or a negative error code on failure. */int snd_pcm_lib_preallocate_free(snd_pcm_substream_t *substream){ snd_pcm_lib_preallocate_dma_free(substream);#if VX_BUILD_NO_INCLUDE if (substream->proc_prealloc_entry) { snd_info_unregister(substream->proc_prealloc_entry); substream->proc_prealloc_entry = NULL; }#endif return 0;}/** * snd_pcm_lib_preallocate_free_for_all - release all pre-allocated buffers on the pcm * @pcm: the pcm instance * * Releases all the pre-allocated buffers on the given pcm. * * Returns zero if successful, or a negative error code on failure. */int snd_pcm_lib_preallocate_free_for_all(snd_pcm_t *pcm){ snd_pcm_substream_t *substream; int stream; for (stream = 0; stream < 2; stream++) for (substream = pcm->streams[stream].substream; substream; substream = substream->next) snd_pcm_lib_preallocate_free(substream); return 0;}/** * snd_pcm_set_ops - set the PCM operators * @pcm: the pcm instance * @direction: stream direction, SNDRV_PCM_STREAM_XXX * @ops: the operator table * * Sets the given PCM operators to the pcm instance. */void snd_pcm_set_ops(snd_pcm_t *pcm, int direction, snd_pcm_ops_t *ops){ snd_pcm_str_t *stream = &pcm->streams[direction]; snd_pcm_substream_t *substream; for (substream = stream->substream; substream != NULL; substream = substream->next) substream->ops = ops;}/** * snd_pcm_new_stream - create a new PCM stream * @pcm: the pcm instance * @stream: the stream direction, SNDRV_PCM_STREAM_XXX * @substream_count: the number of substreams * * Creates a new stream for the pcm. * The corresponding stream on the pcm must have been empty before * calling this, i.e. zero must be given to the argument of * snd_pcm_new(). * * Returns zero if successful, or a negative error code on failure. */int snd_pcm_new_stream(snd_pcm_t *pcm, int stream, int substream_count){ int idx, err; snd_pcm_str_t *pstr = &pcm->streams[stream]; snd_pcm_substream_t *substream, *prev;#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) init_MUTEX(&pstr->oss.setup_mutex);#endif pstr->stream = stream; pstr->pcm = pcm; pstr->substream_count = substream_count;#if VX_BUILD_NO_INCLUDE if (substream_count > 0) { err = snd_pcm_stream_proc_init(pstr); if (err < 0) return err; } pstr->reg = &snd_pcm_reg[stream];#endif prev = NULL; for (idx = 0, prev = NULL; idx < substream_count; idx++) { substream = (snd_pcm_substream_t *) kcalloc(1, sizeof(*substream), GFP_KERNEL); if (substream == NULL) return -ENOMEM; substream->pcm = pcm; substream->pstr = pstr; substream->number = idx; substream->stream = stream; sprintf(substream->name, "subdevice #%i", idx); substream->buffer_bytes_max = UINT_MAX; /* note: not sure where this is done in linux.. but it seems like it should work to allocate here */ substream->runtime = (snd_pcm_runtime_t *)kcalloc( 1, sizeof(snd_pcm_runtime_t), 0 ); if( substream->runtime == NULL ) { kfree( substream ); return -ENOMEM; } if (prev == NULL) pstr->substream = substream; else prev->next = substream; /* create an empty semaphore to show when the dma period has elapsed */ err = snd_pcm_substream_proc_init(substream); if (err < 0) { kfree(substream->runtime); kfree(substream); return err; }#if VX_BUILD_NO_INCLUDE substream->group = &substream->self_group; spin_lock_init(&substream->self_group.lock); INIT_LIST_HEAD(&substream->self_group.substreams); list_add_tail(&substream->link_list, &substream->self_group.substreams); spin_lock_init(&substream->timer_lock);#endif prev = substream; } return 0;}/*-------------------------------------------------------------- Function Description: Allocates memory space of the passed size for DMA access for the specified substream and fills in parameters in the structure with DMA address/sizes Arguments: snd_pcm_substream_t *substream - a pointer to the substream for which to free the DMA area Returns: 0 on success negative on failure---------------------------------------------------------------*/static int vx_preallocate_pcm_pages(snd_pcm_substream_t *substream,size_t size ){ struct snd_dma_buffer *dmab = &substream->dma_buffer; int err; snd_assert(size > 0, return -EINVAL); dmab->bytes = size; dmab->addr = (uint32) vx_pci_get_next_dma_mem_space_align( size );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -