diff -r 304cfde05b3f linux/drivers/staging/tm6000/tm6000-alsa.c --- a/linux/drivers/staging/tm6000/tm6000-alsa.c Tue May 25 23:50:51 2010 -0400 +++ b/linux/drivers/staging/tm6000/tm6000-alsa.c Fri Jun 04 16:14:09 2010 -0300 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -182,6 +183,69 @@ .buffer_bytes_max = (1024*1024), }; +static void tm6000_audio_isocirq(struct tm6000_audio *adev, u8 *cp, int actual_length) { + + unsigned int oldptr; + unsigned int stride; + struct snd_pcm_substream *substream; + struct snd_pcm_runtime *runtime; + + cp += 4; + + int period_elapsed = 0; + + //actual_length = 4; + + if (adev->capture_pcm_substream) { + substream = adev->capture_pcm_substream; + runtime = substream->runtime; + stride = runtime->frame_bits >> 3; // 4 + + int length = actual_length / stride; + + if (!length) + return; + + oldptr = adev->hwptr_done_capture; + if (oldptr + length >= runtime->buffer_size) { + unsigned int cnt = + runtime->buffer_size - oldptr; + memcpy(runtime->dma_area + oldptr * stride, cp, + cnt * stride); + memcpy(runtime->dma_area, cp + cnt * stride, + length * stride - cnt * stride); + } else { + memcpy(runtime->dma_area + oldptr * stride, cp, + length * stride); + } + + snd_pcm_stream_lock(substream); + + adev->hwptr_done_capture += length; + if (adev->hwptr_done_capture >= + runtime->buffer_size) + adev->hwptr_done_capture -= + runtime->buffer_size; + + adev->capture_transfer_done += length; + if (adev->capture_transfer_done >= + runtime->period_size) { + adev->capture_transfer_done -= + runtime->period_size; + period_elapsed = 1; + } + + snd_pcm_stream_unlock(substream); + + if (period_elapsed) { + snd_pcm_period_elapsed(substream); + } + + } + + return; +} + /* * audio pcm capture open callback */ @@ -190,6 +254,10 @@ struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int err; + + chip->core->adev.capture_pcm_substream = substream; + chip->core->adev.initialized = 1; + chip->core->audio_isoc_callback = tm6000_audio_isocirq; err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS); @@ -211,6 +281,25 @@ */ static int snd_tm6000_close(struct snd_pcm_substream *substream) { + struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); + chip->core->adev.initialized = 0; + return 0; +} + +/* allocate virtual buffer; may be called more than once */ +static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t size) +{ + struct snd_pcm_runtime *runtime = subs->runtime; + if (runtime->dma_area) { + if (runtime->dma_bytes >= size) + return 0; /* already large enough */ + vfree(runtime->dma_area); + } + printk("alloc %d\n", size); + runtime->dma_area = vmalloc_user(size); + if (!runtime->dma_area) + return -ENOMEM; + runtime->dma_bytes = size; return 0; } @@ -220,6 +309,7 @@ static int snd_tm6000_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { + int ret; struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); if (substream->runtime->dma_area) { @@ -236,6 +326,9 @@ dprintk(1, "Setting buffer\n"); /* FIXME: Allocate buffer for audio */ + + ret = snd_pcm_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); #if 0 substream->runtime->dma_area = chip->dma_risc->vmalloc; @@ -260,11 +353,18 @@ return 0; } + + /* * prepare callback */ static int snd_tm6000_prepare(struct snd_pcm_substream *substream) { + struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); + + chip->core->adev.capture_transfer_done = 0; + chip->core->adev.hwptr_done_capture = 0; + return 0; } diff -r 304cfde05b3f linux/drivers/staging/tm6000/tm6000-video.c --- a/linux/drivers/staging/tm6000/tm6000-video.c Tue May 25 23:50:51 2010 -0400 +++ b/linux/drivers/staging/tm6000/tm6000-video.c Fri Jun 04 16:14:09 2010 -0300 @@ -320,9 +320,13 @@ case TM6000_URB_MSG_PTS: break; case TM6000_URB_MSG_AUDIO: -/* Need some code to process audio */ -printk ("%ld: cmd=%s, size=%d\n", jiffies, - tm6000_msg_type[cmd],size); + if (dev->adev.initialized) { + dev->audio_isoc_callback(&dev->adev, *ptr, cpysize); + } + + break; + + case TM6000_URB_MSG_VBI: break; default: dprintk (dev, V4L2_DEBUG_ISOC, "cmd=%s, size=%d\n", diff -r 304cfde05b3f linux/drivers/staging/tm6000/tm6000.h --- a/linux/drivers/staging/tm6000/tm6000.h Tue May 25 23:50:51 2010 -0400 +++ b/linux/drivers/staging/tm6000/tm6000.h Fri Jun 04 16:14:09 2010 -0300 @@ -148,6 +148,15 @@ unsigned maxsize; }; +struct tm6000_audio { + struct snd_pcm_substream *capture_pcm_substream; + unsigned int capture_transfer_done; + unsigned int hwptr_done_capture; + int initialized; +}; + +typedef void (*tm6000_audio_complete_t)(struct tm6000_audio *adev, u8 *ptr, int len); + struct tm6000_core { /* generic device properties */ char name[30]; /* name (including minor) of the device */ @@ -168,6 +177,11 @@ int tuner_addr; /* tuner address */ struct tm6000_gpio gpio; + + /* Audio device */ + struct tm6000_audio adev; + tm6000_audio_complete_t audio_isoc_callback; + /* Demodulator configuration */ int demod_addr; /* demodulator address */