ALSA: ctxfi - Set periods_min to 2
[safe/jmp/linux-2.6] / sound / pci / ctxfi / ctpcm.c
index a64cb0e..a0bd31c 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #include "ctpcm.h"
+#include "cttimer.h"
 #include <sound/pcm.h>
 
 /* Hardware descriptions for playback */
@@ -26,12 +27,10 @@ static struct snd_pcm_hardware ct_pcm_playback_hw = {
                                   SNDRV_PCM_INFO_MMAP_VALID |
                                   SNDRV_PCM_INFO_PAUSE),
        .formats                = (SNDRV_PCM_FMTBIT_U8 |
-                                  SNDRV_PCM_FMTBIT_S8 |
                                   SNDRV_PCM_FMTBIT_S16_LE |
-                                  SNDRV_PCM_FMTBIT_U16_LE |
                                   SNDRV_PCM_FMTBIT_S24_3LE |
-                                  SNDRV_PCM_FMTBIT_S24_LE |
-                                  SNDRV_PCM_FMTBIT_S32_LE),
+                                  SNDRV_PCM_FMTBIT_S32_LE |
+                                  SNDRV_PCM_FMTBIT_FLOAT_LE),
        .rates                  = (SNDRV_PCM_RATE_CONTINUOUS |
                                   SNDRV_PCM_RATE_8000_192000),
        .rate_min               = 8000,
@@ -41,7 +40,7 @@ static struct snd_pcm_hardware ct_pcm_playback_hw = {
        .buffer_bytes_max       = (128*1024),
        .period_bytes_min       = (64),
        .period_bytes_max       = (128*1024),
-       .periods_min            = 1,
+       .periods_min            = 2,
        .periods_max            = 1024,
        .fifo_size              = 0,
 };
@@ -52,8 +51,7 @@ static struct snd_pcm_hardware ct_spdif_passthru_playback_hw = {
                                   SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                   SNDRV_PCM_INFO_MMAP_VALID |
                                   SNDRV_PCM_INFO_PAUSE),
-       .formats                = (SNDRV_PCM_FMTBIT_S16_LE |
-                                  SNDRV_PCM_FMTBIT_U16_LE),
+       .formats                = SNDRV_PCM_FMTBIT_S16_LE,
        .rates                  = (SNDRV_PCM_RATE_48000 |
                                   SNDRV_PCM_RATE_44100 |
                                   SNDRV_PCM_RATE_32000),
@@ -64,7 +62,7 @@ static struct snd_pcm_hardware ct_spdif_passthru_playback_hw = {
        .buffer_bytes_max       = (128*1024),
        .period_bytes_min       = (64),
        .period_bytes_max       = (128*1024),
-       .periods_min            = 1,
+       .periods_min            = 2,
        .periods_max            = 1024,
        .fifo_size              = 0,
 };
@@ -77,12 +75,10 @@ static struct snd_pcm_hardware ct_pcm_capture_hw = {
                                   SNDRV_PCM_INFO_PAUSE |
                                   SNDRV_PCM_INFO_MMAP_VALID),
        .formats                = (SNDRV_PCM_FMTBIT_U8 |
-                                  SNDRV_PCM_FMTBIT_S8 |
                                   SNDRV_PCM_FMTBIT_S16_LE |
-                                  SNDRV_PCM_FMTBIT_U16_LE |
                                   SNDRV_PCM_FMTBIT_S24_3LE |
-                                  SNDRV_PCM_FMTBIT_S24_LE |
-                                  SNDRV_PCM_FMTBIT_S32_LE),
+                                  SNDRV_PCM_FMTBIT_S32_LE |
+                                  SNDRV_PCM_FMTBIT_FLOAT_LE),
        .rates                  = (SNDRV_PCM_RATE_CONTINUOUS |
                                   SNDRV_PCM_RATE_8000_96000),
        .rate_min               = 8000,
@@ -113,6 +109,7 @@ static void ct_atc_pcm_free_substream(struct snd_pcm_runtime *runtime)
        struct ct_atc *atc = snd_pcm_substream_chip(apcm->substream);
 
        atc->pcm_release_resources(atc, apcm);
+       ct_timer_instance_free(apcm->timer);
        kfree(apcm);
        runtime->private_data = NULL;
 }
@@ -129,8 +126,6 @@ static int ct_pcm_playback_open(struct snd_pcm_substream *substream)
        if (NULL == apcm)
                return -ENOMEM;
 
-       spin_lock_init(&apcm->timer_lock);
-       apcm->stop_timer = 0;
        apcm->substream = substream;
        apcm->interrupt = ct_atc_pcm_interrupt;
        runtime->private_data = apcm;
@@ -158,6 +153,10 @@ static int ct_pcm_playback_open(struct snd_pcm_substream *substream)
                return err;
        }
 
+       apcm->timer = ct_timer_instance_new(atc->timer, apcm);
+       if (!apcm->timer)
+               return -ENOMEM;
+
        return 0;
 }
 
@@ -187,89 +186,6 @@ static int ct_pcm_hw_free(struct snd_pcm_substream *substream)
        return snd_pcm_lib_free_pages(substream);
 }
 
-static void ct_pcm_timer_callback(unsigned long data)
-{
-       struct ct_atc_pcm *apcm = (struct ct_atc_pcm *)data;
-       struct snd_pcm_substream *substream = apcm->substream;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       unsigned int period_size = runtime->period_size;
-       unsigned int buffer_size = runtime->buffer_size;
-       unsigned long flags;
-       unsigned int position = 0, dist = 0, interval = 0;
-
-       position = substream->ops->pointer(substream);
-       dist = (position + buffer_size - apcm->position) % buffer_size;
-       if ((dist >= period_size) ||
-               (position/period_size != apcm->position/period_size)) {
-               apcm->interrupt(apcm);
-               apcm->position = position;
-       }
-       /* Add extra HZ*5/1000 to avoid overrun issue when recording
-        * at 8kHz in 8-bit format or at 88kHz in 24-bit format. */
-       interval = ((period_size - (position % period_size))
-                  * HZ + (runtime->rate - 1)) / runtime->rate + HZ * 5 / 1000;
-       spin_lock_irqsave(&apcm->timer_lock, flags);
-       apcm->timer.expires = jiffies + interval;
-       if (!apcm->stop_timer)
-               add_timer(&apcm->timer);
-
-       spin_unlock_irqrestore(&apcm->timer_lock, flags);
-}
-
-static int ct_pcm_timer_prepare(struct ct_atc_pcm *apcm)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&apcm->timer_lock, flags);
-       if (timer_pending(&apcm->timer)) {
-               /* The timer has already been started. */
-               spin_unlock_irqrestore(&apcm->timer_lock, flags);
-               return 0;
-       }
-
-       init_timer(&apcm->timer);
-       apcm->timer.data = (unsigned long)apcm;
-       apcm->timer.function = ct_pcm_timer_callback;
-       spin_unlock_irqrestore(&apcm->timer_lock, flags);
-       apcm->position = 0;
-
-       return 0;
-}
-
-static int ct_pcm_timer_start(struct ct_atc_pcm *apcm)
-{
-       struct snd_pcm_runtime *runtime = apcm->substream->runtime;
-       unsigned long flags;
-
-       spin_lock_irqsave(&apcm->timer_lock, flags);
-       if (timer_pending(&apcm->timer)) {
-               /* The timer has already been started. */
-               spin_unlock_irqrestore(&apcm->timer_lock, flags);
-               return 0;
-       }
-
-       apcm->timer.expires = jiffies + (runtime->period_size * HZ +
-                               (runtime->rate - 1)) / runtime->rate;
-       apcm->stop_timer = 0;
-       add_timer(&apcm->timer);
-       spin_unlock_irqrestore(&apcm->timer_lock, flags);
-
-       return 0;
-}
-
-static int ct_pcm_timer_stop(struct ct_atc_pcm *apcm)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&apcm->timer_lock, flags);
-       apcm->stop_timer = 1;
-       del_timer(&apcm->timer);
-       spin_unlock_irqrestore(&apcm->timer_lock, flags);
-
-       try_to_del_timer_sync(&apcm->timer);
-
-       return 0;
-}
 
 static int ct_pcm_playback_prepare(struct snd_pcm_substream *substream)
 {
@@ -288,8 +204,6 @@ static int ct_pcm_playback_prepare(struct snd_pcm_substream *substream)
                return err;
        }
 
-       ct_pcm_timer_prepare(apcm);
-
        return 0;
 }
 
@@ -305,12 +219,10 @@ ct_pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                atc->pcm_playback_start(atc, apcm);
-               ct_pcm_timer_start(apcm);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               ct_pcm_timer_stop(apcm);
                atc->pcm_playback_stop(atc, apcm);
                break;
        default:
@@ -346,9 +258,7 @@ static int ct_pcm_capture_open(struct snd_pcm_substream *substream)
        if (NULL == apcm)
                return -ENOMEM;
 
-       spin_lock_init(&apcm->timer_lock);
        apcm->started = 0;
-       apcm->stop_timer = 0;
        apcm->substream = substream;
        apcm->interrupt = ct_atc_pcm_interrupt;
        runtime->private_data = apcm;
@@ -370,6 +280,10 @@ static int ct_pcm_capture_open(struct snd_pcm_substream *substream)
                return err;
        }
 
+       apcm->timer = ct_timer_instance_new(atc->timer, apcm);
+       if (!apcm->timer)
+               return -ENOMEM;
+
        return 0;
 }
 
@@ -393,8 +307,6 @@ static int ct_pcm_capture_prepare(struct snd_pcm_substream *substream)
                return err;
        }
 
-       ct_pcm_timer_prepare(apcm);
-
        return 0;
 }
 
@@ -408,14 +320,11 @@ ct_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
                atc->pcm_capture_start(atc, apcm);
-               ct_pcm_timer_start(apcm);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
-               ct_pcm_timer_stop(apcm);
                atc->pcm_capture_stop(atc, apcm);
                break;
        default:
-               ct_pcm_timer_stop(apcm);
                atc->pcm_capture_stop(atc, apcm);
                break;
        }
@@ -447,6 +356,7 @@ static struct snd_pcm_ops ct_pcm_playback_ops = {
        .prepare        = ct_pcm_playback_prepare,
        .trigger        = ct_pcm_playback_trigger,
        .pointer        = ct_pcm_playback_pointer,
+       .page           = snd_pcm_sgbuf_ops_page,
 };
 
 /* PCM operators for capture */
@@ -459,6 +369,7 @@ static struct snd_pcm_ops ct_pcm_capture_ops = {
        .prepare        = ct_pcm_capture_prepare,
        .trigger        = ct_pcm_capture_trigger,
        .pointer        = ct_pcm_capture_pointer,
+       .page           = snd_pcm_sgbuf_ops_page,
 };
 
 /* Create ALSA pcm device */
@@ -469,12 +380,10 @@ int ct_alsa_pcm_create(struct ct_atc *atc,
        struct snd_pcm *pcm;
        int err;
        int playback_count, capture_count;
-       char name[128];
 
-       strncpy(name, device_name, sizeof(name));
        playback_count = (IEC958 == device) ? 1 : 8;
        capture_count = (FRONT == device) ? 1 : 0;
-       err = snd_pcm_new(atc->card, name, device,
+       err = snd_pcm_new(atc->card, "ctxfi", device,
                          playback_count, capture_count, &pcm);
        if (err < 0) {
                printk(KERN_ERR "ctxfi: snd_pcm_new failed!! Err=%d\n", err);
@@ -484,7 +393,7 @@ int ct_alsa_pcm_create(struct ct_atc *atc,
        pcm->private_data = atc;
        pcm->info_flags = 0;
        pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
-       strcpy(pcm->name, device_name);
+       strlcpy(pcm->name, device_name, sizeof(pcm->name));
 
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ct_pcm_playback_ops);
 
@@ -492,7 +401,7 @@ int ct_alsa_pcm_create(struct ct_atc *atc,
                snd_pcm_set_ops(pcm,
                                SNDRV_PCM_STREAM_CAPTURE, &ct_pcm_capture_ops);
 
-       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
                        snd_dma_pci_data(atc->pci), 128*1024, 128*1024);
 
        return 0;