Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
[safe/jmp/linux-2.6] / sound / ppc / pmac.c
index adbc868..7bc492e 100644 (file)
@@ -20,7 +20,6 @@
  */
 
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <linux/init.h>
@@ -45,6 +44,18 @@ static int tumbler_freqs[1] = {
        44100
 };
 
+
+/*
+ * we will allocate a single 'emergency' dbdma cmd block to use if the
+ * tx status comes up "DEAD".  This happens on some PowerComputing Pmac
+ * clones, either owing to a bug in dbdma or some interaction between
+ * IDE and sound.  However, this measure would deal with DEAD status if
+ * it appeared elsewhere.
+ */
+static struct pmac_dbdma emergency_dbdma;
+static int emergency_in_use;
+
+
 /*
  * allocate DBDMA command arrays
  */
@@ -203,7 +214,7 @@ static int snd_pmac_pcm_prepare(struct snd_pmac *chip, struct pmac_stream *rec,
        int rate_index;
        long offset;
        struct pmac_stream *astr;
-       
+
        rec->dma_size = snd_pcm_lib_buffer_bytes(subs);
        rec->period_size = snd_pcm_lib_period_bytes(subs);
        rec->nperiods = rec->dma_size / rec->period_size;
@@ -288,7 +299,7 @@ static int snd_pmac_pcm_trigger(struct snd_pmac *chip, struct pmac_stream *rec,
        case SNDRV_PCM_TRIGGER_SUSPEND:
                spin_lock(&chip->reg_lock);
                rec->running = 0;
-               /*printk("stopped!!\n");*/
+               /*printk(KERN_DEBUG "stopped!!\n");*/
                snd_pmac_dma_stop(rec);
                for (i = 0, cp = rec->cmd.cmds; i < rec->nperiods; i++, cp++)
                        out_le16(&cp->command, DBDMA_STOP);
@@ -323,7 +334,7 @@ static snd_pcm_uframes_t snd_pmac_pcm_pointer(struct snd_pmac *chip,
        }
 #endif
        count += rec->cur_period * rec->period_size;
-       /*printk("pointer=%d\n", count);*/
+       /*printk(KERN_DEBUG "pointer=%d\n", count);*/
        return bytes_to_frames(subs->runtime, count);
 }
 
@@ -376,6 +387,75 @@ static snd_pcm_uframes_t snd_pmac_capture_pointer(struct snd_pcm_substream *subs
 
 
 /*
+ * Handle DEAD DMA transfers:
+ * if the TX status comes up "DEAD" - reported on some Power Computing machines
+ * we need to re-start the dbdma - but from a different physical start address
+ * and with a different transfer length.  It would get very messy to do this
+ * with the normal dbdma_cmd blocks - we would have to re-write the buffer start
+ * addresses each time.  So, we will keep a single dbdma_cmd block which can be
+ * fiddled with.
+ * When DEAD status is first reported the content of the faulted dbdma block is
+ * copied into the emergency buffer and we note that the buffer is in use.
+ * we then bump the start physical address by the amount that was successfully
+ * output before it died.
+ * On any subsequent DEAD result we just do the bump-ups (we know that we are
+ * already using the emergency dbdma_cmd).
+ * CHECK: this just tries to "do it".  It is possible that we should abandon
+ * xfers when the number of residual bytes gets below a certain value - I can
+ * see that this might cause a loop-forever if a too small transfer causes
+ * DEAD status.  However this is a TODO for now - we'll see what gets reported.
+ * When we get a successful transfer result with the emergency buffer we just
+ * pretend that it completed using the original dmdma_cmd and carry on.  The
+ * 'next_cmd' field will already point back to the original loop of blocks.
+ */
+static inline void snd_pmac_pcm_dead_xfer(struct pmac_stream *rec,
+                                         volatile struct dbdma_cmd __iomem *cp)
+{
+       unsigned short req, res ;
+       unsigned int phy ;
+
+       /* printk(KERN_WARNING "snd-powermac: DMA died - patching it up!\n"); */
+
+       /* to clear DEAD status we must first clear RUN
+          set it to quiescent to be on the safe side */
+       (void)in_le32(&rec->dma->status);
+       out_le32(&rec->dma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+
+       if (!emergency_in_use) { /* new problem */
+               memcpy((void *)emergency_dbdma.cmds, (void *)cp,
+                      sizeof(struct dbdma_cmd));
+               emergency_in_use = 1;
+               st_le16(&cp->xfer_status, 0);
+               st_le16(&cp->req_count, rec->period_size);
+               cp = emergency_dbdma.cmds;
+       }
+
+       /* now bump the values to reflect the amount
+          we haven't yet shifted */
+       req = ld_le16(&cp->req_count);
+       res = ld_le16(&cp->res_count);
+       phy = ld_le32(&cp->phy_addr);
+       phy += (req - res);
+       st_le16(&cp->req_count, res);
+       st_le16(&cp->res_count, 0);
+       st_le16(&cp->xfer_status, 0);
+       st_le32(&cp->phy_addr, phy);
+
+       st_le32(&cp->cmd_dep, rec->cmd.addr
+               + sizeof(struct dbdma_cmd)*((rec->cur_period+1)%rec->nperiods));
+
+       st_le16(&cp->command, OUTPUT_MORE | BR_ALWAYS | INTR_ALWAYS);
+
+       /* point at our patched up command block */
+       out_le32(&rec->dma->cmdptr, emergency_dbdma.addr);
+
+       /* we must re-start the controller */
+       (void)in_le32(&rec->dma->status);
+       /* should complete clearing the DEAD status */
+       out_le32(&rec->dma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
+}
+
+/*
  * update playback/capture pointer from interrupts
  */
 static void snd_pmac_pcm_update(struct snd_pmac *chip, struct pmac_stream *rec)
@@ -386,21 +466,35 @@ static void snd_pmac_pcm_update(struct snd_pmac *chip, struct pmac_stream *rec)
 
        spin_lock(&chip->reg_lock);
        if (rec->running) {
-               cp = &rec->cmd.cmds[rec->cur_period];
                for (c = 0; c < rec->nperiods; c++) { /* at most all fragments */
+
+                       if (emergency_in_use)   /* already using DEAD xfer? */
+                               cp = emergency_dbdma.cmds;
+                       else
+                               cp = &rec->cmd.cmds[rec->cur_period];
+
                        stat = ld_le16(&cp->xfer_status);
+
+                       if (stat & DEAD) {
+                               snd_pmac_pcm_dead_xfer(rec, cp);
+                               break; /* this block is still going */
+                       }
+
+                       if (emergency_in_use)
+                               emergency_in_use = 0 ; /* done that */
+
                        if (! (stat & ACTIVE))
                                break;
-                       /*printk("update frag %d\n", rec->cur_period);*/
+
+                       /*printk(KERN_DEBUG "update frag %d\n", rec->cur_period);*/
                        st_le16(&cp->xfer_status, 0);
                        st_le16(&cp->req_count, rec->period_size);
                        /*st_le16(&cp->res_count, 0);*/
                        rec->cur_period++;
                        if (rec->cur_period >= rec->nperiods) {
                                rec->cur_period = 0;
-                               cp = rec->cmd.cmds;
-                       } else
-                               cp++;
+                       }
+
                        spin_unlock(&chip->reg_lock);
                        snd_pcm_period_elapsed(rec->substream);
                        spin_lock(&chip->reg_lock);
@@ -490,35 +584,14 @@ static int snd_pmac_pcm_open(struct snd_pmac *chip, struct pmac_stream *rec,
                             struct snd_pcm_substream *subs)
 {
        struct snd_pcm_runtime *runtime = subs->runtime;
-       int i, j, fflags;
-       static int typical_freqs[] = {
-               44100,
-               22050,
-               11025,
-               0,
-       };
-       static int typical_freq_flags[] = {
-               SNDRV_PCM_RATE_44100,
-               SNDRV_PCM_RATE_22050,
-               SNDRV_PCM_RATE_11025,
-               0,
-       };
+       int i;
 
        /* look up frequency table and fill bit mask */
        runtime->hw.rates = 0;
-       fflags = chip->freqs_ok;
-       for (i = 0; typical_freqs[i]; i++) {
-               for (j = 0; j < chip->num_freqs; j++) {
-                       if ((chip->freqs_ok & (1 << j)) &&
-                           chip->freq_table[j] == typical_freqs[i]) {
-                               runtime->hw.rates |= typical_freq_flags[i];
-                               fflags &= ~(1 << j);
-                               break;
-                       }
-               }
-       }
-       if (fflags) /* rest */
-               runtime->hw.rates |= SNDRV_PCM_RATE_KNOT;
+       for (i = 0; i < chip->num_freqs; i++)
+               if (chip->freqs_ok & (1 << i))
+                       runtime->hw.rates |=
+                               snd_pcm_rate_to_rate_bit(chip->freq_table[i]);
 
        /* check for minimum and maximum rates */
        for (i = 0; i < chip->num_freqs; i++) {
@@ -551,9 +624,6 @@ static int snd_pmac_pcm_open(struct snd_pmac *chip, struct pmac_stream *rec,
 
        runtime->hw.periods_max = rec->cmd.size - 1;
 
-       if (chip->can_duplex)
-               snd_pcm_set_sync(subs);
-
        /* constraints to fix choppy sound */
        snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
        return 0;
@@ -573,7 +643,7 @@ static int snd_pmac_pcm_close(struct snd_pmac *chip, struct pmac_stream *rec,
        /* reset constraints */
        astr->cur_freqs = chip->freqs_ok;
        astr->cur_formats = chip->formats_ok;
-       
+
        return 0;
 }
 
@@ -632,7 +702,7 @@ static struct snd_pcm_ops snd_pmac_capture_ops = {
        .pointer =      snd_pmac_capture_pointer,
 };
 
-int __init snd_pmac_pcm_new(struct snd_pmac *chip)
+int __devinit snd_pmac_pcm_new(struct snd_pmac *chip)
 {
        struct snd_pcm *pcm;
        int err;
@@ -736,7 +806,7 @@ snd_pmac_ctrl_intr(int irq, void *devid)
        struct snd_pmac *chip = devid;
        int ctrl = in_le32(&chip->awacs->control);
 
-       /*printk("pmac: control interrupt.. 0x%x\n", ctrl);*/
+       /*printk(KERN_DEBUG "pmac: control interrupt.. 0x%x\n", ctrl);*/
        if (ctrl & MASK_PORTCHG) {
                /* do something when headphone is plugged/unplugged? */
                if (chip->update_automute)
@@ -794,6 +864,7 @@ static int snd_pmac_free(struct snd_pmac *chip)
        snd_pmac_dbdma_free(chip, &chip->playback.cmd);
        snd_pmac_dbdma_free(chip, &chip->capture.cmd);
        snd_pmac_dbdma_free(chip, &chip->extra_dma);
+       snd_pmac_dbdma_free(chip, &emergency_dbdma);
        if (chip->macio_base)
                iounmap(chip->macio_base);
        if (chip->latch_base)
@@ -837,7 +908,7 @@ static int snd_pmac_dev_free(struct snd_device *device)
  * check the machine support byteswap (little-endian)
  */
 
-static void __init detect_byte_swap(struct snd_pmac *chip)
+static void __devinit detect_byte_swap(struct snd_pmac *chip)
 {
        struct device_node *mio;
 
@@ -863,7 +934,7 @@ static void __init detect_byte_swap(struct snd_pmac *chip)
 /*
  * detect a sound chip
  */
-static int __init snd_pmac_detect(struct snd_pmac *chip)
+static int __devinit snd_pmac_detect(struct snd_pmac *chip)
 {
        struct device_node *sound;
        struct device_node *dn;
@@ -962,7 +1033,8 @@ static int __init snd_pmac_detect(struct snd_pmac *chip)
        }
        if (of_device_is_compatible(sound, "tumbler")) {
                chip->model = PMAC_TUMBLER;
-               chip->can_capture = 0;  /* no capture */
+               chip->can_capture = machine_is_compatible("PowerMac4,2")
+                               || machine_is_compatible("PowerBook4,1");
                chip->can_duplex = 0;
                // chip->can_byte_swap = 0; /* FIXME: check this */
                chip->num_freqs = ARRAY_SIZE(tumbler_freqs);
@@ -1052,7 +1124,7 @@ static int pmac_auto_mute_put(struct snd_kcontrol *kcontrol,
 {
        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
        if (ucontrol->value.integer.value[0] != chip->auto_mute) {
-               chip->auto_mute = ucontrol->value.integer.value[0];
+               chip->auto_mute = !!ucontrol->value.integer.value[0];
                if (chip->update_automute)
                        chip->update_automute(chip, 1);
                return 1;
@@ -1071,7 +1143,7 @@ static int pmac_hp_detect_get(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-static struct snd_kcontrol_new auto_mute_controls[] __initdata = {
+static struct snd_kcontrol_new auto_mute_controls[] __devinitdata = {
        { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
          .name = "Auto Mute Switch",
          .info = snd_pmac_boolean_mono_info,
@@ -1086,7 +1158,7 @@ static struct snd_kcontrol_new auto_mute_controls[] __initdata = {
        },
 };
 
-int __init snd_pmac_add_automute(struct snd_pmac *chip)
+int __devinit snd_pmac_add_automute(struct snd_pmac *chip)
 {
        int err;
        chip->auto_mute = 1;
@@ -1103,7 +1175,7 @@ int __init snd_pmac_add_automute(struct snd_pmac *chip)
 /*
  * create and detect a pmac chip record
  */
-int __init snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
+int __devinit snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
 {
        struct snd_pmac *chip;
        struct device_node *np;
@@ -1132,7 +1204,8 @@ int __init snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
 
        if (snd_pmac_dbdma_alloc(chip, &chip->playback.cmd, PMAC_MAX_FRAGS + 1) < 0 ||
            snd_pmac_dbdma_alloc(chip, &chip->capture.cmd, PMAC_MAX_FRAGS + 1) < 0 ||
-           snd_pmac_dbdma_alloc(chip, &chip->extra_dma, 2) < 0) {
+           snd_pmac_dbdma_alloc(chip, &chip->extra_dma, 2) < 0 ||
+           snd_pmac_dbdma_alloc(chip, &emergency_dbdma, 2) < 0) {
                err = -ENOMEM;
                goto __error;
        }
@@ -1228,9 +1301,9 @@ int __init snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
 
        snd_pmac_sound_feature(chip, 1);
 
-       /* reset */
-       if (chip->model == PMAC_AWACS)
-               out_le32(&chip->awacs->control, 0x11);
+       /* reset & enable interrupts */
+       if (chip->model <= PMAC_BURGUNDY)
+               out_le32(&chip->awacs->control, chip->control_mask);
 
        /* Powerbooks have odd ways of enabling inputs such as
           an expansion-bay CD or sound from an internal modem