]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/staging/tm6000/tm6000-alsa.c
Merge branch 'devel' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/edac
[mv-sheeva.git] / drivers / staging / tm6000 / tm6000-alsa.c
index 273e26ede650415f44f019c250cf8f003daab63c..087137d9164deb1dbf17ba110a0686e7669c6926 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/usb.h>
 #include <linux/slab.h>
+#include <linux/vmalloc.h>
 
 #include <asm/delay.h>
 #include <sound/core.h>
                printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg); \
        } while (0)
 
-/****************************************************************************
-       Data type declarations - Can be moded to a header file later
- ****************************************************************************/
-
-struct snd_tm6000_card {
-       struct snd_card            *card;
-
-       spinlock_t                 reg_lock;
-
-       atomic_t                   count;
-
-       unsigned int               period_size;
-       unsigned int               num_periods;
-
-       struct tm6000_core         *core;
-       struct tm6000_buffer       *buf;
-
-       int                        bufsize;
-
-       struct snd_pcm_substream *substream;
-};
-
-
 /****************************************************************************
                        Module global static vars
  ****************************************************************************/
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
-static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;       /* ID for this card */
+
 static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
 
 module_param_array(enable, bool, NULL, 0444);
@@ -100,11 +78,15 @@ static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip)
        struct tm6000_core *core = chip->core;
        int val;
 
+       dprintk(1, "Starting audio DMA\n");
+
        /* Enables audio */
        val = tm6000_get_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x0);
        val |= 0x20;
        tm6000_set_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val);
 
+       tm6000_set_audio_bitrate(core, 48000);
+
        tm6000_set_reg(core, TM6010_REQ08_R01_A_INIT, 0x80);
 
        return 0;
@@ -129,19 +111,39 @@ static int _tm6000_stop_audio_dma(struct snd_tm6000_card *chip)
        return 0;
 }
 
-static int dsp_buffer_free(struct snd_tm6000_card *chip)
+static void dsp_buffer_free(struct snd_pcm_substream *substream)
 {
-       BUG_ON(!chip->bufsize);
+       struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
 
        dprintk(2, "Freeing buffer\n");
 
-       /* FIXME: Frees buffer */
+       vfree(substream->runtime->dma_area);
+       substream->runtime->dma_area = NULL;
+       substream->runtime->dma_bytes = 0;
+}
 
-       chip->bufsize = 0;
+static int dsp_buffer_alloc(struct snd_pcm_substream *substream, int size)
+{
+       struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+
+       dprintk(2, "Allocating buffer\n");
+
+       if (substream->runtime->dma_area) {
+               if (substream->runtime->dma_bytes > size)
+                       return 0;
+               dsp_buffer_free(substream);
+       }
 
-       return 0;
+       substream->runtime->dma_area = vmalloc(size);
+       if (!substream->runtime->dma_area)
+               return -ENOMEM;
+
+       substream->runtime->dma_bytes = size;
+
+       return 0;
 }
 
+
 /****************************************************************************
                                ALSA PCM Interface
  ****************************************************************************/
@@ -158,16 +160,16 @@ static struct snd_pcm_hardware snd_tm6000_digital_hw = {
                SNDRV_PCM_INFO_MMAP_VALID,
        .formats = SNDRV_PCM_FMTBIT_S16_LE,
 
-       .rates =                SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
-       .rate_min =             44100,
+       .rates =                SNDRV_PCM_RATE_48000,
+       .rate_min =             48000,
        .rate_max =             48000,
        .channels_min = 2,
        .channels_max = 2,
-       .period_bytes_min = DEFAULT_FIFO_SIZE/4,
-       .period_bytes_max = DEFAULT_FIFO_SIZE/4,
+       .period_bytes_min = 62720,
+       .period_bytes_max = 62720,
        .periods_min = 1,
        .periods_max = 1024,
-       .buffer_bytes_max = (1024*1024),
+       .buffer_bytes_max = 62720 * 8,
 };
 
 /*
@@ -202,29 +204,64 @@ static int snd_tm6000_close(struct snd_pcm_substream *substream)
        return 0;
 }
 
+static int tm6000_fillbuf(struct tm6000_core *core, char *buf, int size)
+{
+       struct snd_tm6000_card *chip = core->adev;
+       struct snd_pcm_substream *substream = chip->substream;
+       struct snd_pcm_runtime *runtime;
+       int period_elapsed = 0;
+       unsigned int stride, buf_pos;
+
+       if (!size || !substream)
+               return -EINVAL;
+
+       runtime = substream->runtime;
+       if (!runtime || !runtime->dma_area)
+               return -EINVAL;
+
+       buf_pos = chip->buf_pos;
+       stride = runtime->frame_bits >> 3;
+
+       dprintk(1, "Copying %d bytes at %p[%d] - buf size=%d x %d\n", size,
+               runtime->dma_area, buf_pos,
+               (unsigned int)runtime->buffer_size, stride);
+
+       if (buf_pos + size >= runtime->buffer_size * stride) {
+               unsigned int cnt = runtime->buffer_size * stride - buf_pos;
+               memcpy(runtime->dma_area + buf_pos, buf, cnt);
+               memcpy(runtime->dma_area, buf + cnt, size - cnt);
+       } else
+               memcpy(runtime->dma_area + buf_pos, buf, size);
+
+       chip->buf_pos += size;
+       if (chip->buf_pos >= runtime->buffer_size * stride)
+               chip->buf_pos -= runtime->buffer_size * stride;
+
+       chip->period_pos += size;
+       if (chip->period_pos >= runtime->period_size) {
+               chip->period_pos -= runtime->period_size;
+               period_elapsed = 1;
+       }
+
+       if (period_elapsed)
+               snd_pcm_period_elapsed(substream);
+
+       return 0;
+}
+
 /*
  * hw_params callback
  */
 static int snd_tm6000_hw_params(struct snd_pcm_substream *substream,
                              struct snd_pcm_hw_params *hw_params)
 {
-       struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
-
-       if (substream->runtime->dma_area) {
-               dsp_buffer_free(chip);
-               substream->runtime->dma_area = NULL;
-       }
-
-       chip->period_size = params_period_bytes(hw_params);
-       chip->num_periods = params_periods(hw_params);
-       chip->bufsize = chip->period_size * params_periods(hw_params);
-
-       BUG_ON(!chip->bufsize);
+       int size, rc;
 
-       dprintk(1, "Setting buffer\n");
-
-       /* FIXME: Allocate buffer for audio */
+       size = params_period_bytes(hw_params) * params_periods(hw_params);
 
+       rc = dsp_buffer_alloc(substream, size);
+       if (rc < 0)
+               return rc;
 
        return 0;
 }
@@ -234,13 +271,9 @@ static int snd_tm6000_hw_params(struct snd_pcm_substream *substream,
  */
 static int snd_tm6000_hw_free(struct snd_pcm_substream *substream)
 {
-
        struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
 
-       if (substream->runtime->dma_area) {
-               dsp_buffer_free(chip);
-               substream->runtime->dma_area = NULL;
-       }
+       _tm6000_stop_audio_dma(chip);
 
        return 0;
 }
@@ -250,6 +283,11 @@ static int snd_tm6000_hw_free(struct snd_pcm_substream *substream)
  */
 static int snd_tm6000_prepare(struct snd_pcm_substream *substream)
 {
+       struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+
+       chip->buf_pos = 0;
+       chip->period_pos = 0;
+
        return 0;
 }
 
@@ -287,12 +325,8 @@ static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd)
 static snd_pcm_uframes_t snd_tm6000_pointer(struct snd_pcm_substream *substream)
 {
        struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       u16 count;
-
-       count = atomic_read(&chip->count);
 
-       return runtime->period_size * (count & (runtime->periods-1));
+       return chip->buf_pos;
 }
 
 /*
@@ -312,21 +346,6 @@ static struct snd_pcm_ops snd_tm6000_pcm_ops = {
 /*
  * create a PCM device
  */
-static int __devinit snd_tm6000_pcm(struct snd_tm6000_card *chip,
-                                   int device, char *name)
-{
-       int err;
-       struct snd_pcm *pcm;
-
-       err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm);
-       if (err < 0)
-               return err;
-       pcm->private_data = chip;
-       strcpy(pcm->name, name);
-       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops);
-
-       return 0;
-}
 
 /* FIXME: Control interface - How to control volume/mute? */
 
@@ -337,27 +356,41 @@ static int __devinit snd_tm6000_pcm(struct snd_tm6000_card *chip,
 /*
  * Alsa Constructor - Component probe
  */
-
-int tm6000_audio_init(struct tm6000_core *dev, int idx)
+int tm6000_audio_init(struct tm6000_core *dev)
 {
-       struct snd_card         *card;
-       struct snd_tm6000_card  *chip;
-       int                     rc, len;
-       char                    component[14];
+       struct snd_card         *card;
+       struct snd_tm6000_card  *chip;
+       int                     rc;
+       static int              devnr;
+       char                    component[14];
+       struct snd_pcm          *pcm;
+
+       if (!dev)
+               return 0;
 
-       if (idx >= SNDRV_CARDS)
+       if (devnr >= SNDRV_CARDS)
                return -ENODEV;
 
-       if (!enable[idx])
+       if (!enable[devnr])
                return -ENOENT;
 
-       rc = snd_card_create(index[idx], id[idx], THIS_MODULE, 0, &card);
+       rc = snd_card_create(index[devnr], "tm6000", THIS_MODULE, 0, &card);
        if (rc < 0) {
-               snd_printk(KERN_ERR "cannot create card instance %d\n", idx);
+               snd_printk(KERN_ERR "cannot create card instance %d\n", devnr);
                return rc;
        }
+       strcpy(card->driver, "tm6000-alsa");
+       strcpy(card->shortname, "TM5600/60x0");
+       sprintf(card->longname, "TM5600/60x0 Audio at bus %d device %d",
+               dev->udev->bus->busnum, dev->udev->devnum);
+
+       sprintf(component, "USB%04x:%04x",
+               le16_to_cpu(dev->udev->descriptor.idVendor),
+               le16_to_cpu(dev->udev->descriptor.idProduct));
+       snd_component_add(card, component);
+       snd_card_set_dev(card, &dev->udev->dev);
 
-       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       chip = kzalloc(sizeof(struct snd_tm6000_card), GFP_KERNEL);
        if (!chip) {
                rc = -ENOMEM;
                goto error;
@@ -365,45 +398,24 @@ int tm6000_audio_init(struct tm6000_core *dev, int idx)
 
        chip->core = dev;
        chip->card = card;
+       dev->adev = chip;
+       spin_lock_init(&chip->reg_lock);
 
-       strcpy(card->driver, "tm6000-alsa");
-       sprintf(component, "USB%04x:%04x",
-               le16_to_cpu(dev->udev->descriptor.idVendor),
-               le16_to_cpu(dev->udev->descriptor.idProduct));
-       snd_component_add(card, component);
-
-       if (dev->udev->descriptor.iManufacturer)
-               len = usb_string(dev->udev,
-                                dev->udev->descriptor.iManufacturer,
-                                card->longname, sizeof(card->longname));
-       else
-               len = 0;
-
-       if (len > 0)
-               strlcat(card->longname, " ", sizeof(card->longname));
-
-       strlcat(card->longname, card->shortname, sizeof(card->longname));
-
-       len = strlcat(card->longname, " at ", sizeof(card->longname));
-
-       if (len < sizeof(card->longname))
-               usb_make_path(dev->udev, card->longname + len,
-                             sizeof(card->longname) - len);
-
-       strlcat(card->longname,
-               dev->udev->speed == USB_SPEED_LOW ? ", low speed" :
-               dev->udev->speed == USB_SPEED_FULL ? ", full speed" :
-                                                          ", high speed",
-               sizeof(card->longname));
-
-       rc = snd_tm6000_pcm(chip, 0, "tm6000 Digital");
+       rc = snd_pcm_new(card, "TM6000 Audio", 0, 0, 1, &pcm);
        if (rc < 0)
                goto error;
 
+       pcm->info_flags = 0;
+       pcm->private_data = chip;
+       strcpy(pcm->name, "Trident TM5600/60x0");
+
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops);
+
        rc = snd_card_register(card);
        if (rc < 0)
                goto error;
 
+       dprintk(1,"Registered audio driver for %s\n", card->longname);
 
        return 0;
 
@@ -414,14 +426,31 @@ error:
 
 static int tm6000_audio_fini(struct tm6000_core *dev)
 {
+       struct snd_tm6000_card  *chip = dev->adev;
+
+       if (!dev)
+               return 0;
+
+       if (!chip)
+               return 0;
+
+       if (!chip->card)
+               return 0;
+
+       snd_card_free(chip->card);
+       chip->card = NULL;
+       kfree(chip);
+       dev->adev = NULL;
+
        return 0;
 }
 
 struct tm6000_ops audio_ops = {
-       .id     = TM6000_AUDIO,
+       .type   = TM6000_AUDIO,
        .name   = "TM6000 Audio Extension",
        .init   = tm6000_audio_init,
        .fini   = tm6000_audio_fini,
+       .fillbuf = tm6000_fillbuf,
 };
 
 static int __init tm6000_alsa_register(void)