ALSA: pcxhr - add support for pcxhr stereo sound cards (core change)
authorMarkus Bollinger <bollinger@digigram.com>
Tue, 25 Nov 2008 11:24:54 +0000 (12:24 +0100)
committerTakashi Iwai <tiwai@suse.de>
Tue, 25 Nov 2008 11:27:03 +0000 (12:27 +0100)
- Add support for pcxhr stereo cards
- minor bugfixes : period and buffer size consraints
- fix PLL register values
- do some clean up

Signed-off-by: Markus Bollinger <bollinger@digigram.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/pcxhr/pcxhr.c
sound/pci/pcxhr/pcxhr.h

index 73de6e9..0327925 100644 (file)
 #include "pcxhr_mixer.h"
 #include "pcxhr_hwdep.h"
 #include "pcxhr_core.h"
+#include "pcxhr_mix22.h"
 
 #define DRIVER_NAME "pcxhr"
 
-MODULE_AUTHOR("Markus Bollinger <bollinger@digigram.com>");
+MODULE_AUTHOR("Markus Bollinger <bollinger@digigram.com>, "
+             "Marc Titinger <titinger@digigram.com>");
 MODULE_DESCRIPTION("Digigram " DRIVER_NAME " " PCXHR_DRIVER_VERSION_STRING);
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Digigram," DRIVER_NAME "}}");
 
-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] = SNDRV_DEFAULT_ENABLE_PNP;     /* Enable this card */
-static int mono[SNDRV_CARDS];                                  /* capture in mono only */
+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] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */
+static int mono[SNDRV_CARDS];                          /* capture  mono only */
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for Digigram " DRIVER_NAME " soundcard");
@@ -67,18 +69,58 @@ enum {
        PCI_ID_PCX882HR,
        PCI_ID_VX881HR,
        PCI_ID_PCX881HR,
+       PCI_ID_VX882E,
+       PCI_ID_PCX882E,
+       PCI_ID_VX881E,
+       PCI_ID_PCX881E,
+       PCI_ID_VX1222HR,
        PCI_ID_PCX1222HR,
+       PCI_ID_VX1221HR,
        PCI_ID_PCX1221HR,
+       PCI_ID_VX1222E,
+       PCI_ID_PCX1222E,
+       PCI_ID_VX1221E,
+       PCI_ID_PCX1221E,
+       PCI_ID_VX222HR,
+       PCI_ID_VX222E,
+       PCI_ID_PCX22HR,
+       PCI_ID_PCX22E,
+       PCI_ID_VX222HRMIC,
+       PCI_ID_VX222E_MIC,
+       PCI_ID_PCX924HR,
+       PCI_ID_PCX924E,
+       PCI_ID_PCX924HRMIC,
+       PCI_ID_PCX924E_MIC,
        PCI_ID_LAST
 };
 
 static struct pci_device_id pcxhr_ids[] = {
-       { 0x10b5, 0x9656, 0x1369, 0xb001, 0, 0, PCI_ID_VX882HR, },   /* VX882HR */
-       { 0x10b5, 0x9656, 0x1369, 0xb101, 0, 0, PCI_ID_PCX882HR, },  /* PCX882HR */
-       { 0x10b5, 0x9656, 0x1369, 0xb201, 0, 0, PCI_ID_VX881HR, },   /* VX881HR */
-       { 0x10b5, 0x9656, 0x1369, 0xb301, 0, 0, PCI_ID_PCX881HR, },  /* PCX881HR */
-       { 0x10b5, 0x9656, 0x1369, 0xb501, 0, 0, PCI_ID_PCX1222HR, }, /* PCX1222HR */
-       { 0x10b5, 0x9656, 0x1369, 0xb701, 0, 0, PCI_ID_PCX1221HR, }, /* PCX1221HR */
+       { 0x10b5, 0x9656, 0x1369, 0xb001, 0, 0, PCI_ID_VX882HR, },
+       { 0x10b5, 0x9656, 0x1369, 0xb101, 0, 0, PCI_ID_PCX882HR, },
+       { 0x10b5, 0x9656, 0x1369, 0xb201, 0, 0, PCI_ID_VX881HR, },
+       { 0x10b5, 0x9656, 0x1369, 0xb301, 0, 0, PCI_ID_PCX881HR, },
+       { 0x10b5, 0x9056, 0x1369, 0xb021, 0, 0, PCI_ID_VX882E, },
+       { 0x10b5, 0x9056, 0x1369, 0xb121, 0, 0, PCI_ID_PCX882E, },
+       { 0x10b5, 0x9056, 0x1369, 0xb221, 0, 0, PCI_ID_VX881E, },
+       { 0x10b5, 0x9056, 0x1369, 0xb321, 0, 0, PCI_ID_PCX881E, },
+       { 0x10b5, 0x9656, 0x1369, 0xb401, 0, 0, PCI_ID_VX1222HR, },
+       { 0x10b5, 0x9656, 0x1369, 0xb501, 0, 0, PCI_ID_PCX1222HR, },
+       { 0x10b5, 0x9656, 0x1369, 0xb601, 0, 0, PCI_ID_VX1221HR, },
+       { 0x10b5, 0x9656, 0x1369, 0xb701, 0, 0, PCI_ID_PCX1221HR, },
+       { 0x10b5, 0x9056, 0x1369, 0xb421, 0, 0, PCI_ID_VX1222E, },
+       { 0x10b5, 0x9056, 0x1369, 0xb521, 0, 0, PCI_ID_PCX1222E, },
+       { 0x10b5, 0x9056, 0x1369, 0xb621, 0, 0, PCI_ID_VX1221E, },
+       { 0x10b5, 0x9056, 0x1369, 0xb721, 0, 0, PCI_ID_PCX1221E, },
+       { 0x10b5, 0x9056, 0x1369, 0xba01, 0, 0, PCI_ID_VX222HR, },
+       { 0x10b5, 0x9056, 0x1369, 0xba21, 0, 0, PCI_ID_VX222E, },
+       { 0x10b5, 0x9056, 0x1369, 0xbd01, 0, 0, PCI_ID_PCX22HR, },
+       { 0x10b5, 0x9056, 0x1369, 0xbd21, 0, 0, PCI_ID_PCX22E, },
+       { 0x10b5, 0x9056, 0x1369, 0xbc01, 0, 0, PCI_ID_VX222HRMIC, },
+       { 0x10b5, 0x9056, 0x1369, 0xbc21, 0, 0, PCI_ID_VX222E_MIC, },
+       { 0x10b5, 0x9056, 0x1369, 0xbb01, 0, 0, PCI_ID_PCX924HR, },
+       { 0x10b5, 0x9056, 0x1369, 0xbb21, 0, 0, PCI_ID_PCX924E, },
+       { 0x10b5, 0x9056, 0x1369, 0xbf01, 0, 0, PCI_ID_PCX924HRMIC, },
+       { 0x10b5, 0x9056, 0x1369, 0xbf21, 0, 0, PCI_ID_PCX924E_MIC, },
        { 0, }
 };
 
@@ -88,27 +130,55 @@ struct board_parameters {
        char* board_name;
        short playback_chips;
        short capture_chips;
+       short fw_file_set;
        short firmware_num;
 };
 static struct board_parameters pcxhr_board_params[] = {
-[PCI_ID_VX882HR] =     { "VX882HR",   4, 4, 41, },
-[PCI_ID_PCX882HR] =    { "PCX882HR",  4, 4, 41, },
-[PCI_ID_VX881HR] =     { "VX881HR",   4, 4, 41, },
-[PCI_ID_PCX881HR] =    { "PCX881HR",  4, 4, 41, },
-[PCI_ID_PCX1222HR] =   { "PCX1222HR", 6, 1, 42, },
-[PCI_ID_PCX1221HR] =   { "PCX1221HR", 6, 1, 42, },
+[PCI_ID_VX882HR] =      { "VX882HR",      4, 4, 0, 41 },
+[PCI_ID_PCX882HR] =     { "PCX882HR",     4, 4, 0, 41 },
+[PCI_ID_VX881HR] =      { "VX881HR",      4, 4, 0, 41 },
+[PCI_ID_PCX881HR] =     { "PCX881HR",     4, 4, 0, 41 },
+[PCI_ID_VX882E] =       { "VX882e",       4, 4, 1, 41 },
+[PCI_ID_PCX882E] =      { "PCX882e",      4, 4, 1, 41 },
+[PCI_ID_VX881E] =       { "VX881e",       4, 4, 1, 41 },
+[PCI_ID_PCX881E] =      { "PCX881e",      4, 4, 1, 41 },
+[PCI_ID_VX1222HR] =     { "VX1222HR",     6, 1, 2, 42 },
+[PCI_ID_PCX1222HR] =    { "PCX1222HR",    6, 1, 2, 42 },
+[PCI_ID_VX1221HR] =     { "VX1221HR",     6, 1, 2, 42 },
+[PCI_ID_PCX1221HR] =    { "PCX1221HR",    6, 1, 2, 42 },
+[PCI_ID_VX1222E] =      { "VX1222e",      6, 1, 3, 42 },
+[PCI_ID_PCX1222E] =     { "PCX1222e",     6, 1, 3, 42 },
+[PCI_ID_VX1221E] =      { "VX1221e",      6, 1, 3, 42 },
+[PCI_ID_PCX1221E] =     { "PCX1221e",     6, 1, 3, 42 },
+[PCI_ID_VX222HR] =      { "VX222HR",      1, 1, 4, 44 },
+[PCI_ID_VX222E] =       { "VX222e",       1, 1, 4, 44 },
+[PCI_ID_PCX22HR] =      { "PCX22HR",      1, 0, 4, 44 },
+[PCI_ID_PCX22E] =       { "PCX22e",       1, 0, 4, 44 },
+[PCI_ID_VX222HRMIC] =   { "VX222HR-Mic",  1, 1, 5, 44 },
+[PCI_ID_VX222E_MIC] =   { "VX222e-Mic",   1, 1, 5, 44 },
+[PCI_ID_PCX924HR] =     { "PCX924HR",     1, 1, 5, 44 },
+[PCI_ID_PCX924E] =      { "PCX924e",      1, 1, 5, 44 },
+[PCI_ID_PCX924HRMIC] =  { "PCX924HR-Mic", 1, 1, 5, 44 },
+[PCI_ID_PCX924E_MIC] =  { "PCX924e-Mic",  1, 1, 5, 44 },
 };
 
+/* boards without hw AES1 and SRC onboard are all using fw_file_set==4 */
+/* VX222HR, VX222e, PCX22HR and PCX22e */
+#define PCXHR_BOARD_HAS_AES1(x) (x->fw_file_set != 4)
+/* some boards do not support 192kHz on digital AES input plugs */
+#define PCXHR_BOARD_AESIN_NO_192K(x) ((x->capture_chips == 0) || \
+                                     (x->fw_file_set == 0)   || \
+                                     (x->fw_file_set == 2))
 
 static int pcxhr_pll_freq_register(unsigned int freq, unsigned int* pllreg,
                                   unsigned int* realfreq)
 {
        unsigned int reg;
 
-       if (freq < 6900 || freq > 110250)
+       if (freq < 6900 || freq > 110000)
                return -EINVAL;
-       reg = (28224000 * 10) / freq;
-       reg = (reg + 5) / 10;
+       reg = (28224000 * 2) / freq;
+       reg = (reg - 1) / 2;
        if (reg < 0x200)
                *pllreg = reg + 0x800;
        else if (reg < 0x400)
@@ -121,7 +191,7 @@ static int pcxhr_pll_freq_register(unsigned int freq, unsigned int* pllreg,
                reg &= ~3;
        }
        if (realfreq)
-               *realfreq = ((28224000 * 10) / reg + 5) / 10;
+               *realfreq = (28224000 / (reg + 1));
        return 0;
 }
 
@@ -151,11 +221,6 @@ static int pcxhr_pll_freq_register(unsigned int freq, unsigned int* pllreg,
 #define PCXHR_FREQ_AES_3               0x03
 #define PCXHR_FREQ_AES_4               0x0d
 
-#define PCXHR_MODIFY_CLOCK_S_BIT       0x04
-
-#define PCXHR_IRQ_TIMER_FREQ           92000
-#define PCXHR_IRQ_TIMER_PERIOD         48
-
 static int pcxhr_get_clock_reg(struct pcxhr_mgr *mgr, unsigned int rate,
                               unsigned int *reg, unsigned int *freq)
 {
@@ -196,19 +261,32 @@ static int pcxhr_get_clock_reg(struct pcxhr_mgr *mgr, unsigned int rate,
                        err = pcxhr_send_msg(mgr, &rmh);
                        if (err < 0) {
                                snd_printk(KERN_ERR
-                                          "error CMD_ACCESS_IO_WRITE for PLL register : %x!\n",
-                                          err );
+                                          "error CMD_ACCESS_IO_WRITE "
+                                          "for PLL register : %x!\n", err);
                                return err;
                        }
                }
                break;
-       case PCXHR_CLOCK_TYPE_WORD_CLOCK :      val = PCXHR_FREQ_WORD_CLOCK;    break;
-       case PCXHR_CLOCK_TYPE_AES_SYNC :        val = PCXHR_FREQ_SYNC_AES;      break;
-       case PCXHR_CLOCK_TYPE_AES_1 :           val = PCXHR_FREQ_AES_1;         break;
-       case PCXHR_CLOCK_TYPE_AES_2 :           val = PCXHR_FREQ_AES_2;         break;
-       case PCXHR_CLOCK_TYPE_AES_3 :           val = PCXHR_FREQ_AES_3;         break;
-       case PCXHR_CLOCK_TYPE_AES_4 :           val = PCXHR_FREQ_AES_4;         break;
-       default : return -EINVAL;
+       case PCXHR_CLOCK_TYPE_WORD_CLOCK:
+               val = PCXHR_FREQ_WORD_CLOCK;
+               break;
+       case PCXHR_CLOCK_TYPE_AES_SYNC:
+               val = PCXHR_FREQ_SYNC_AES;
+               break;
+       case PCXHR_CLOCK_TYPE_AES_1:
+               val = PCXHR_FREQ_AES_1;
+               break;
+       case PCXHR_CLOCK_TYPE_AES_2:
+               val = PCXHR_FREQ_AES_2;
+               break;
+       case PCXHR_CLOCK_TYPE_AES_3:
+               val = PCXHR_FREQ_AES_3;
+               break;
+       case PCXHR_CLOCK_TYPE_AES_4:
+               val = PCXHR_FREQ_AES_4;
+               break;
+       default:
+               return -EINVAL;
        }
        *reg = val;
        *freq = realfreq;
@@ -216,14 +294,13 @@ static int pcxhr_get_clock_reg(struct pcxhr_mgr *mgr, unsigned int rate,
 }
 
 
-int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate)
+static int pcxhr_sub_set_clock(struct pcxhr_mgr *mgr,
+                              unsigned int rate,
+                              int *changed)
 {
        unsigned int val, realfreq, speed;
        struct pcxhr_rmh rmh;
-       int err, changed;
-
-       if (rate == 0)
-               return 0; /* nothing to do */
+       int err;
 
        err = pcxhr_get_clock_reg(mgr, rate, &val, &realfreq);
        if (err)
@@ -237,13 +314,17 @@ int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate)
        else
                speed = 2;      /* quad speed */
        if (mgr->codec_speed != speed) {
-               pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);      /* mute outputs */
+               pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); /* mute outputs */
                rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT;
+               if (DSP_EXT_CMD_SET(mgr)) {
+                       rmh.cmd[1]  = 1;
+                       rmh.cmd_len = 2;
+               }
                err = pcxhr_send_msg(mgr, &rmh);
                if (err)
                        return err;
 
-               pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);      /* set speed ratio */
+               pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); /* set speed ratio */
                rmh.cmd[0] |= IO_NUM_SPEED_RATIO;
                rmh.cmd[1] = speed;
                rmh.cmd_len = 2;
@@ -253,25 +334,57 @@ int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate)
        }
        /* set the new frequency */
        snd_printdd("clock register : set %x\n", val);
-       err = pcxhr_write_io_num_reg_cont(mgr, PCXHR_FREQ_REG_MASK, val, &changed);
+       err = pcxhr_write_io_num_reg_cont(mgr, PCXHR_FREQ_REG_MASK,
+                                         val, changed);
        if (err)
                return err;
+
        mgr->sample_rate_real = realfreq;
        mgr->cur_clock_type = mgr->use_clock_type;
 
        /* unmute after codec speed modes */
        if (mgr->codec_speed != speed) {
-               pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ);       /* unmute outputs */
+               pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); /* unmute outputs */
                rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT;
+               if (DSP_EXT_CMD_SET(mgr)) {
+                       rmh.cmd[1]  = 1;
+                       rmh.cmd_len = 2;
+               }
                err = pcxhr_send_msg(mgr, &rmh);
                if (err)
                        return err;
-               mgr->codec_speed = speed;                       /* save new codec speed */
+               mgr->codec_speed = speed;       /* save new codec speed */
        }
 
+       snd_printdd("pcxhr_sub_set_clock to %dHz (realfreq=%d)\n",
+                   rate, realfreq);
+       return 0;
+}
+
+#define PCXHR_MODIFY_CLOCK_S_BIT       0x04
+
+#define PCXHR_IRQ_TIMER_FREQ           92000
+#define PCXHR_IRQ_TIMER_PERIOD         48
+
+int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate)
+{
+       struct pcxhr_rmh rmh;
+       int err, changed;
+
+       if (rate == 0)
+               return 0; /* nothing to do */
+
+       if (mgr->is_hr_stereo)
+               err = hr222_sub_set_clock(mgr, rate, &changed);
+       else
+               err = pcxhr_sub_set_clock(mgr, rate, &changed);
+
+       if (err)
+               return err;
+
        if (changed) {
                pcxhr_init_rmh(&rmh, CMD_MODIFY_CLOCK);
-               rmh.cmd[0] |= PCXHR_MODIFY_CLOCK_S_BIT;         /* resync fifos  */
+               rmh.cmd[0] |= PCXHR_MODIFY_CLOCK_S_BIT; /* resync fifos  */
                if (rate < PCXHR_IRQ_TIMER_FREQ)
                        rmh.cmd[1] = PCXHR_IRQ_TIMER_PERIOD;
                else
@@ -282,26 +395,39 @@ int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate)
                if (err)
                        return err;
        }
-       snd_printdd("pcxhr_set_clock to %dHz (realfreq=%d)\n", rate, realfreq);
        return 0;
 }
 
 
-int pcxhr_get_external_clock(struct pcxhr_mgr *mgr, enum pcxhr_clock_type clock_type,
-                            int *sample_rate)
+static int pcxhr_sub_get_external_clock(struct pcxhr_mgr *mgr,
+                                       enum pcxhr_clock_type clock_type,
+                                       int *sample_rate)
 {
        struct pcxhr_rmh rmh;
        unsigned char reg;
        int err, rate;
 
        switch (clock_type) {
-       case PCXHR_CLOCK_TYPE_WORD_CLOCK :      reg = REG_STATUS_WORD_CLOCK;    break;
-       case PCXHR_CLOCK_TYPE_AES_SYNC :        reg = REG_STATUS_AES_SYNC;      break;
-       case PCXHR_CLOCK_TYPE_AES_1 :           reg = REG_STATUS_AES_1;         break;
-       case PCXHR_CLOCK_TYPE_AES_2 :           reg = REG_STATUS_AES_2;         break;
-       case PCXHR_CLOCK_TYPE_AES_3 :           reg = REG_STATUS_AES_3;         break;
-       case PCXHR_CLOCK_TYPE_AES_4 :           reg = REG_STATUS_AES_4;         break;
-       default : return -EINVAL;
+       case PCXHR_CLOCK_TYPE_WORD_CLOCK:
+               reg = REG_STATUS_WORD_CLOCK;
+               break;
+       case PCXHR_CLOCK_TYPE_AES_SYNC:
+               reg = REG_STATUS_AES_SYNC;
+               break;
+       case PCXHR_CLOCK_TYPE_AES_1:
+               reg = REG_STATUS_AES_1;
+               break;
+       case PCXHR_CLOCK_TYPE_AES_2:
+               reg = REG_STATUS_AES_2;
+               break;
+       case PCXHR_CLOCK_TYPE_AES_3:
+               reg = REG_STATUS_AES_3;
+               break;
+       case PCXHR_CLOCK_TYPE_AES_4:
+               reg = REG_STATUS_AES_4;
+               break;
+       default:
+               return -EINVAL;
        }
        pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ);
        rmh.cmd_len = 2;
@@ -311,7 +437,7 @@ int pcxhr_get_external_clock(struct pcxhr_mgr *mgr, enum pcxhr_clock_type clock_
                err = pcxhr_send_msg(mgr, &rmh);
                if (err)
                        return err;
-               udelay(100);            /* wait minimum 2 sample_frames at 32kHz ! */
+               udelay(100);    /* wait minimum 2 sample_frames at 32kHz ! */
                mgr->last_reg_stat = reg;
        }
        rmh.cmd[1]  = REG_STATUS_CURRENT;
@@ -336,6 +462,18 @@ int pcxhr_get_external_clock(struct pcxhr_mgr *mgr, enum pcxhr_clock_type clock_
 }
 
 
+int pcxhr_get_external_clock(struct pcxhr_mgr *mgr,
+                            enum pcxhr_clock_type clock_type,
+                            int *sample_rate)
+{
+       if (mgr->is_hr_stereo)
+               return hr222_get_external_clock(mgr, clock_type,
+                                               sample_rate);
+       else
+               return pcxhr_sub_get_external_clock(mgr, clock_type,
+                                                   sample_rate);
+}
+
 /*
  *  start or stop playback/capture substream
  */
@@ -350,7 +488,8 @@ static int pcxhr_set_stream_state(struct pcxhr_stream *stream)
                start = 1;
        else {
                if (stream->status != PCXHR_STREAM_STATUS_SCHEDULE_STOP) {
-                       snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state CANNOT be stopped\n");
+                       snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state "
+                                  "CANNOT be stopped\n");
                        return -EINVAL;
                }
                start = 0;
@@ -359,11 +498,12 @@ static int pcxhr_set_stream_state(struct pcxhr_stream *stream)
                return -EINVAL;
 
        stream->timer_abs_periods = 0;
-       stream->timer_period_frag = 0;            /* reset theoretical stream pos */
+       stream->timer_period_frag = 0;  /* reset theoretical stream pos */
        stream->timer_buf_periods = 0;
        stream->timer_is_synced = 0;
 
-       stream_mask = stream->pipe->is_capture ? 1 : 1<<stream->substream->number;
+       stream_mask =
+         stream->pipe->is_capture ? 1 : 1<<stream->substream->number;
 
        pcxhr_init_rmh(&rmh, start ? CMD_START_STREAM : CMD_STOP_STREAM);
        pcxhr_set_pipe_cmd_params(&rmh, stream->pipe->is_capture,
@@ -373,8 +513,10 @@ static int pcxhr_set_stream_state(struct pcxhr_stream *stream)
 
        err = pcxhr_send_msg(chip->mgr, &rmh);
        if (err)
-               snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state err=%x;\n", err);
-       stream->status = start ? PCXHR_STREAM_STATUS_STARTED : PCXHR_STREAM_STATUS_STOPPED;
+               snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state err=%x;\n",
+                          err);
+       stream->status =
+         start ? PCXHR_STREAM_STATUS_STARTED : PCXHR_STREAM_STATUS_STOPPED;
        return err;
 }
 
@@ -399,13 +541,15 @@ static int pcxhr_set_format(struct pcxhr_stream *stream)
                header = HEADER_FMT_BASE_LIN;
                break;
        case SNDRV_PCM_FORMAT_S16_LE:
-               header = HEADER_FMT_BASE_LIN | HEADER_FMT_16BITS | HEADER_FMT_INTEL;
+               header = HEADER_FMT_BASE_LIN |
+                        HEADER_FMT_16BITS | HEADER_FMT_INTEL;
                break;
        case SNDRV_PCM_FORMAT_S16_BE:
                header = HEADER_FMT_BASE_LIN | HEADER_FMT_16BITS;
                break;
        case SNDRV_PCM_FORMAT_S24_3LE:
-               header = HEADER_FMT_BASE_LIN | HEADER_FMT_24BITS | HEADER_FMT_INTEL;
+               header = HEADER_FMT_BASE_LIN |
+                        HEADER_FMT_24BITS | HEADER_FMT_INTEL;
                break;
        case SNDRV_PCM_FORMAT_S24_3BE:
                header = HEADER_FMT_BASE_LIN | HEADER_FMT_24BITS;
@@ -414,7 +558,8 @@ static int pcxhr_set_format(struct pcxhr_stream *stream)
                header = HEADER_FMT_BASE_FLOAT | HEADER_FMT_INTEL;
                break;
        default:
-               snd_printk(KERN_ERR "error pcxhr_set_format() : unknown format\n");
+               snd_printk(KERN_ERR
+                          "error pcxhr_set_format() : unknown format\n");
                return -EINVAL;
        }
        chip = snd_pcm_substream_chip(stream->substream);
@@ -432,14 +577,31 @@ static int pcxhr_set_format(struct pcxhr_stream *stream)
        is_capture = stream->pipe->is_capture;
        stream_num = is_capture ? 0 : stream->substream->number;
 
-       pcxhr_init_rmh(&rmh, is_capture ? CMD_FORMAT_STREAM_IN : CMD_FORMAT_STREAM_OUT);
-       pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio, stream_num, 0);
-       if (is_capture)
-               rmh.cmd[0] |= 1<<12;
+       pcxhr_init_rmh(&rmh, is_capture ?
+                      CMD_FORMAT_STREAM_IN : CMD_FORMAT_STREAM_OUT);
+       pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio,
+                                 stream_num, 0);
+       if (is_capture) {
+               /* bug with old dsp versions: */
+               /* bit 12 also sets the format of the playback stream */
+               if (DSP_EXT_CMD_SET(chip->mgr))
+                       rmh.cmd[0] |= 1<<10;
+               else
+                       rmh.cmd[0] |= 1<<12;
+       }
        rmh.cmd[1] = 0;
-       rmh.cmd[2] = header >> 8;
-       rmh.cmd[3] = (header & 0xff) << 16;
-       rmh.cmd_len = 4;
+       rmh.cmd_len = 2;
+       if (DSP_EXT_CMD_SET(chip->mgr)) {
+               /* add channels and set bit 19 if channels>2 */
+               rmh.cmd[1] = stream->channels;
+               if (!is_capture) {
+                       /* playback : add channel mask to command */
+                       rmh.cmd[2] = (stream->channels == 1) ? 0x01 : 0x03;
+                       rmh.cmd_len = 3;
+               }
+       }
+       rmh.cmd[rmh.cmd_len++] = header >> 8;
+       rmh.cmd[rmh.cmd_len++] = (header & 0xff) << 16;
        err = pcxhr_send_msg(chip->mgr, &rmh);
        if (err)
                snd_printk(KERN_ERR "ERROR pcxhr_set_format err=%x;\n", err);
@@ -456,30 +618,38 @@ static int pcxhr_update_r_buffer(struct pcxhr_stream *stream)
        is_capture = (subs->stream == SNDRV_PCM_STREAM_CAPTURE);
        stream_num = is_capture ? 0 : subs->number;
 
-       snd_printdd("pcxhr_update_r_buffer(pcm%c%d) : addr(%p) bytes(%zx) subs(%d)\n",
+       snd_printdd("pcxhr_update_r_buffer(pcm%c%d) : "
+                   "addr(%p) bytes(%zx) subs(%d)\n",
                    is_capture ? 'c' : 'p',
                    chip->chip_idx, (void *)(long)subs->runtime->dma_addr,
                    subs->runtime->dma_bytes, subs->number);
 
        pcxhr_init_rmh(&rmh, CMD_UPDATE_R_BUFFERS);
-       pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio, stream_num, 0);
+       pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio,
+                                 stream_num, 0);
 
        /* max buffer size is 2 MByte */
        snd_BUG_ON(subs->runtime->dma_bytes >= 0x200000);
-       rmh.cmd[1] = subs->runtime->dma_bytes * 8;              /* size in bits */
-       rmh.cmd[2] = subs->runtime->dma_addr >> 24;             /* most significant byte */
-       rmh.cmd[2] |= 1<<19;                                    /* this is a circular buffer */
-       rmh.cmd[3] = subs->runtime->dma_addr & MASK_DSP_WORD;   /* least 3 significant bytes */
+       /* size in bits */
+       rmh.cmd[1] = subs->runtime->dma_bytes * 8;
+       /* most significant byte */
+       rmh.cmd[2] = subs->runtime->dma_addr >> 24;
+       /* this is a circular buffer */
+       rmh.cmd[2] |= 1<<19;
+       /* least 3 significant bytes */
+       rmh.cmd[3] = subs->runtime->dma_addr & MASK_DSP_WORD;
        rmh.cmd_len = 4;
        err = pcxhr_send_msg(chip->mgr, &rmh);
        if (err)
-               snd_printk(KERN_ERR "ERROR CMD_UPDATE_R_BUFFERS err=%x;\n", err);
+               snd_printk(KERN_ERR
+                          "ERROR CMD_UPDATE_R_BUFFERS err=%x;\n", err);
        return err;
 }
 
 
 #if 0
-static int pcxhr_pipe_sample_count(struct pcxhr_stream *stream, snd_pcm_uframes_t *sample_count)
+static int pcxhr_pipe_sample_count(struct pcxhr_stream *stream,
+                                  snd_pcm_uframes_t *sample_count)
 {
        struct pcxhr_rmh rmh;
        int err;
@@ -533,8 +703,8 @@ static void pcxhr_trigger_tasklet(unsigned long arg)
                for (j = 0; j < chip->nb_streams_play; j++) {
                        if (pcxhr_stream_scheduled_get_pipe(&chip->playback_stream[j], &pipe)) {
                                playback_mask |= (1 << pipe->first_audio);
-                               break;  /* add only once, as all playback streams of
-                                        * one chip use the same pipe
+                               break;  /* add only once, as all playback
+                                        * streams of one chip use the same pipe
                                         */
                        }
                }
@@ -545,19 +715,21 @@ static void pcxhr_trigger_tasklet(unsigned long arg)
                return;
        }
 
-       snd_printdd("pcxhr_trigger_tasklet : playback_mask=%x capture_mask=%x\n",
+       snd_printdd("pcxhr_trigger_tasklet : "
+                   "playback_mask=%x capture_mask=%x\n",
                    playback_mask, capture_mask);
 
        /* synchronous stop of all the pipes concerned */
        err = pcxhr_set_pipe_state(mgr,  playback_mask, capture_mask, 0);
        if (err) {
                mutex_unlock(&mgr->setup_mutex);
-               snd_printk(KERN_ERR "pcxhr_trigger_tasklet : error stop pipes (P%x C%x)\n",
+               snd_printk(KERN_ERR "pcxhr_trigger_tasklet : "
+                          "error stop pipes (P%x C%x)\n",
                           playback_mask, capture_mask);
                return;
        }
 
-       /* unfortunately the dsp lost format and buffer info with the stop pipe */
+       /* the dsp lost format and buffer info with the stop pipe */
        for (i = 0; i < mgr->num_cards; i++) {
                struct pcxhr_stream *stream;
                chip = mgr->chip[i];
@@ -596,12 +768,15 @@ static void pcxhr_trigger_tasklet(unsigned long arg)
        err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1);
        if (err) {
                mutex_unlock(&mgr->setup_mutex);
-               snd_printk(KERN_ERR "pcxhr_trigger_tasklet : error start pipes (P%x C%x)\n",
+               snd_printk(KERN_ERR "pcxhr_trigger_tasklet : "
+                          "error start pipes (P%x C%x)\n",
                           playback_mask, capture_mask);
                return;
        }
 
-       /* put the streams into the running state now (increment pointer by interrupt) */
+       /* put the streams into the running state now
+        * (increment pointer by interrupt)
+        */
        spin_lock_irqsave(&mgr->lock, flags);
        for ( i =0; i < mgr->num_cards; i++) {
                struct pcxhr_stream *stream;
@@ -615,7 +790,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg)
                        stream = &chip->playback_stream[j];
                        if (stream->status == PCXHR_STREAM_STATUS_STARTED) {
                                /* playback will already have advanced ! */
-                               stream->timer_period_frag += PCXHR_GRANULARITY;
+                               stream->timer_period_frag += mgr->granularity;
                                stream->status = PCXHR_STREAM_STATUS_RUNNING;
                        }
                }
@@ -697,12 +872,14 @@ static int pcxhr_hardware_timer(struct pcxhr_mgr *mgr, int start)
 
        pcxhr_init_rmh(&rmh, CMD_SET_TIMER_INTERRUPT);
        if (start) {
-               mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID;    /* last dsp time invalid */
-               rmh.cmd[0] |= PCXHR_GRANULARITY;
+               /* last dsp time invalid */
+               mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID;
+               rmh.cmd[0] |= mgr->granularity;
        }
        err = pcxhr_send_msg(mgr, &rmh);
        if (err < 0)
-               snd_printk(KERN_ERR "error pcxhr_hardware_timer err(%x)\n", err);
+               snd_printk(KERN_ERR "error pcxhr_hardware_timer err(%x)\n",
+                          err);
        return err;
 }
 
@@ -713,38 +890,16 @@ static int pcxhr_prepare(struct snd_pcm_substream *subs)
 {
        struct snd_pcxhr *chip = snd_pcm_substream_chip(subs);
        struct pcxhr_mgr *mgr = chip->mgr;
-       /*
-       struct pcxhr_stream *stream = (pcxhr_stream_t*)subs->runtime->private_data;
-       */
        int err = 0;
 
        snd_printdd("pcxhr_prepare : period_size(%lx) periods(%x) buffer_size(%lx)\n",
                    subs->runtime->period_size, subs->runtime->periods,
                    subs->runtime->buffer_size);
 
-       /*
-       if(subs->runtime->period_size <= PCXHR_GRANULARITY) {
-               snd_printk(KERN_ERR "pcxhr_prepare : error period_size too small (%x)\n",
-                          (unsigned int)subs->runtime->period_size);
-               return -EINVAL;
-       }
-       */
-
        mutex_lock(&mgr->setup_mutex);
 
        do {
-               /* if the stream was stopped before, format and buffer were reset */
-               /*
-               if(stream->status == PCXHR_STREAM_STATUS_STOPPED) {
-                       err = pcxhr_set_format(stream);
-                       if(err) break;
-                       err = pcxhr_update_r_buffer(stream);
-                       if(err) break;
-               }
-               */
-
                /* only the first stream can choose the sample rate */
-               /* the further opened streams will be limited to its frequency (see open) */
                /* set the clock only once (first stream) */
                if (mgr->sample_rate != subs->runtime->rate) {
                        err = pcxhr_set_clock(mgr, subs->runtime->rate);
@@ -787,22 +942,9 @@ static int pcxhr_hw_params(struct snd_pcm_substream *subs,
        stream->channels = channels;
        stream->format = format;
 
-       /* set the format to the board */
-       /*
-       err = pcxhr_set_format(stream);
-       if(err) {
-               mutex_unlock(&mgr->setup_mutex);
-               return err;
-       }
-       */
        /* allocate buffer */
        err = snd_pcm_lib_malloc_pages(subs, params_buffer_bytes(hw));
 
-       /*
-       if (err > 0) {
-               err = pcxhr_update_r_buffer(stream);
-       }
-       */
        mutex_unlock(&mgr->setup_mutex);
 
        return err;
@@ -820,14 +962,18 @@ static int pcxhr_hw_free(struct snd_pcm_substream *subs)
  */
 static struct snd_pcm_hardware pcxhr_caps =
 {
-       .info             = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
-                             SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
-                             0 /*SNDRV_PCM_INFO_PAUSE*/),
-       .formats          = ( SNDRV_PCM_FMTBIT_U8 |
-                             SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
-                             SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |
-                             SNDRV_PCM_FMTBIT_FLOAT_LE ),
-       .rates            = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000,
+       .info             = (SNDRV_PCM_INFO_MMAP |
+                            SNDRV_PCM_INFO_INTERLEAVED |
+                            SNDRV_PCM_INFO_MMAP_VALID |
+                            SNDRV_PCM_INFO_SYNC_START),
+       .formats          = (SNDRV_PCM_FMTBIT_U8 |
+                            SNDRV_PCM_FMTBIT_S16_LE |
+                            SNDRV_PCM_FMTBIT_S16_BE |
+                            SNDRV_PCM_FMTBIT_S24_3LE |
+                            SNDRV_PCM_FMTBIT_S24_3BE |
+                            SNDRV_PCM_FMTBIT_FLOAT_LE),
+       .rates            = (SNDRV_PCM_RATE_CONTINUOUS |
+                            SNDRV_PCM_RATE_8000_192000),
        .rate_min         = 8000,
        .rate_max         = 192000,
        .channels_min     = 1,
@@ -847,6 +993,7 @@ static int pcxhr_open(struct snd_pcm_substream *subs)
        struct pcxhr_mgr       *mgr = chip->mgr;
        struct snd_pcm_runtime *runtime = subs->runtime;
        struct pcxhr_stream    *stream;
+       int err;
 
        mutex_lock(&mgr->setup_mutex);
 
@@ -874,6 +1021,18 @@ static int pcxhr_open(struct snd_pcm_substream *subs)
                return -EBUSY;
        }
 
+       /* float format support is in some cases buggy on stereo cards */
+       if (mgr->is_hr_stereo)
+               runtime->hw.formats &= ~SNDRV_PCM_FMTBIT_FLOAT_LE;
+
+       /* buffer-size should better be multiple of period-size */
+       err = snd_pcm_hw_constraint_integer(runtime,
+                                           SNDRV_PCM_HW_PARAM_PERIODS);
+       if (err < 0) {
+               mutex_unlock(&mgr->setup_mutex);
+               return err;
+       }
+
        /* if a sample rate is already used or fixed by external clock,
         * the stream cannot change
         */
@@ -889,7 +1048,8 @@ static int pcxhr_open(struct snd_pcm_substream *subs)
                                mutex_unlock(&mgr->setup_mutex);
                                return -EBUSY;
                        }
-                       runtime->hw.rate_min = runtime->hw.rate_max = external_rate;
+                       runtime->hw.rate_min = external_rate;
+                       runtime->hw.rate_max = external_rate;
                }
        }
 
@@ -899,9 +1059,11 @@ static int pcxhr_open(struct snd_pcm_substream *subs)
 
        runtime->private_data = stream;
 
-       snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 4);
-       snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4);
-
+       /* better get a divisor of granularity values (96 or 192) */
+       snd_pcm_hw_constraint_step(runtime, 0,
+                                  SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32);
+       snd_pcm_hw_constraint_step(runtime, 0,
+                                  SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 32);
        snd_pcm_set_sync(subs);
 
        mgr->ref_count_rate++;
@@ -919,11 +1081,12 @@ static int pcxhr_close(struct snd_pcm_substream *subs)
 
        mutex_lock(&mgr->setup_mutex);
 
-       snd_printdd("pcxhr_close chip%d subs%d\n", chip->chip_idx, subs->number);
+       snd_printdd("pcxhr_close chip%d subs%d\n",
+                   chip->chip_idx, subs->number);
 
        /* sample rate released */
        if (--mgr->ref_count_rate == 0) {
-               mgr->sample_rate = 0;           /* the sample rate is no more locked */
+               mgr->sample_rate = 0;   /* the sample rate is no more locked */
                pcxhr_hardware_timer(mgr, 0);   /* stop the DSP-timer */
        }
 
@@ -1016,7 +1179,8 @@ static int pcxhr_chip_dev_free(struct snd_device *device)
 
 /*
  */
-static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, struct snd_card *card, int idx)
+static int __devinit pcxhr_create(struct pcxhr_mgr *mgr,
+                                 struct snd_card *card, int idx)
 {
        int err;
        struct snd_pcxhr *chip;
@@ -1040,7 +1204,7 @@ static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, struct snd_card *card,
 
        if (idx < mgr->capture_chips) {
                if (mgr->mono_capture)
-                       chip->nb_streams_capt = 2;      /* 2 mono streams (left+right) */
+                       chip->nb_streams_capt = 2;      /* 2 mono streams */
                else
                        chip->nb_streams_capt = 1;      /* or 1 stereo stream */
        }
@@ -1056,7 +1220,8 @@ static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, struct snd_card *card,
 }
 
 /* proc interface */
-static void pcxhr_proc_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
+static void pcxhr_proc_info(struct snd_info_entry *entry,
+                           struct snd_info_buffer *buffer)
 {
        struct snd_pcxhr *chip = entry->private_data;
        struct pcxhr_mgr *mgr = chip->mgr;
@@ -1069,8 +1234,10 @@ static void pcxhr_proc_info(struct snd_info_entry *entry, struct snd_info_buffer
                short ver_maj = (mgr->dsp_version >> 16) & 0xff;
                short ver_min = (mgr->dsp_version >> 8) & 0xff;
                short ver_build = mgr->dsp_version & 0xff;
-               snd_iprintf(buffer, "module version %s\n", PCXHR_DRIVER_VERSION_STRING);
-               snd_iprintf(buffer, "dsp version %d.%d.%d\n", ver_maj, ver_min, ver_build);
+               snd_iprintf(buffer, "module version %s\n",
+                           PCXHR_DRIVER_VERSION_STRING);
+               snd_iprintf(buffer, "dsp version %d.%d.%d\n",
+                           ver_maj, ver_min, ver_build);
                if (mgr->board_has_analog)
                        snd_iprintf(buffer, "analog io available\n");
                else
@@ -1084,18 +1251,22 @@ static void pcxhr_proc_info(struct snd_info_entry *entry, struct snd_info_buffer
                        if (ref > 0) {
                                if (mgr->sample_rate_real != 0 &&
                                    mgr->sample_rate_real != 48000) {
-                                       ref = (ref * 48000) / mgr->sample_rate_real;
-                                       if (mgr->sample_rate_real >= PCXHR_IRQ_TIMER_FREQ)
+                                       ref = (ref * 48000) /
+                                         mgr->sample_rate_real;
+                                       if (mgr->sample_rate_real >=
+                                           PCXHR_IRQ_TIMER_FREQ)
                                                ref *= 2;
                                }
                                cur = 100 - (100 * cur) / ref;
                                snd_iprintf(buffer, "cpu load    %d%%\n", cur);
-                               snd_iprintf(buffer, "buffer pool %d/%d kWords\n",
+                               snd_iprintf(buffer, "buffer pool %d/%d\n",
                                            rmh.stat[2], rmh.stat[3]);
                        }
                }
-               snd_iprintf(buffer, "dma granularity : %d\n", PCXHR_GRANULARITY);
-               snd_iprintf(buffer, "dsp time errors : %d\n", mgr->dsp_time_err);
+               snd_iprintf(buffer, "dma granularity : %d\n",
+                           mgr->granularity);
+               snd_iprintf(buffer, "dsp time errors : %d\n",
+                           mgr->dsp_time_err);
                snd_iprintf(buffer, "dsp async pipe xrun errors : %d\n",
                            mgr->async_err_pipe_xrun);
                snd_iprintf(buffer, "dsp async stream xrun errors : %d\n",
@@ -1110,33 +1281,52 @@ static void pcxhr_proc_info(struct snd_info_entry *entry, struct snd_info_buffer
                rmh.cmd_idx = CMD_LAST_INDEX;
                if( ! pcxhr_send_msg(mgr, &rmh) ) {
                        int i;
+                       if (rmh.stat_len > 8)
+                               rmh.stat_len = 8;
                        for (i = 0; i < rmh.stat_len; i++)
-                               snd_iprintf(buffer, "debug[%02d] = %06x\n", i,  rmh.stat[i]);
+                               snd_iprintf(buffer, "debug[%02d] = %06x\n",
+                                           i,  rmh.stat[i]);
                }
        } else
                snd_iprintf(buffer, "no firmware loaded\n");
        snd_iprintf(buffer, "\n");
 }
-static void pcxhr_proc_sync(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
+static void pcxhr_proc_sync(struct snd_info_entry *entry,
+                           struct snd_info_buffer *buffer)
 {
        struct snd_pcxhr *chip = entry->private_data;
        struct pcxhr_mgr *mgr = chip->mgr;
-       static char *texts[7] = {
-               "Internal", "Word", "AES Sync", "AES 1", "AES 2", "AES 3", "AES 4"
+       static const char *textsHR22[3] = {
+               "Internal", "AES Sync", "AES 1"
+       };
+       static const char *textsPCXHR[7] = {
+               "Internal", "Word", "AES Sync",
+               "AES 1", "AES 2", "AES 3", "AES 4"
        };
+       const char **texts;
+       int max_clock;
+       if (mgr->is_hr_stereo) {
+               texts = textsHR22;
+               max_clock = HR22_CLOCK_TYPE_MAX;
+       } else {
+               texts = textsPCXHR;
+               max_clock = PCXHR_CLOCK_TYPE_MAX;
+       }
 
        snd_iprintf(buffer, "\n%s\n", mgr->longname);
-       snd_iprintf(buffer, "Current Sample Clock\t: %s\n", texts[mgr->cur_clock_type]);
-       snd_iprintf(buffer, "Current Sample Rate\t= %d\n", mgr->sample_rate_real);
-
+       snd_iprintf(buffer, "Current Sample Clock\t: %s\n",
+                   texts[mgr->cur_clock_type]);
+       snd_iprintf(buffer, "Current Sample Rate\t= %d\n",
+                   mgr->sample_rate_real);
        /* commands available when embedded DSP is running */
        if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) {
                int i, err, sample_rate;
-               for (i = PCXHR_CLOCK_TYPE_WORD_CLOCK; i< (3 + mgr->capture_chips); i++) {
+               for (i = 1; i <= max_clock; i++) {
                        err = pcxhr_get_external_clock(mgr, i, &sample_rate);
                        if (err)
                                break;
-                       snd_iprintf(buffer, "%s Clock\t\t= %d\n", texts[i], sample_rate);
+                       snd_iprintf(buffer, "%s Clock\t\t= %d\n",
+                                   texts[i], sample_rate);
                }
        } else
                snd_iprintf(buffer, "no firmware loaded\n");
@@ -1194,7 +1384,8 @@ static int pcxhr_free(struct pcxhr_mgr *mgr)
 /*
  *    probe function - creates the card manager
  */
-static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
+static int __devinit pcxhr_probe(struct pci_dev *pci,
+                                const struct pci_device_id *pci_id)
 {
        static int dev;
        struct pcxhr_mgr *mgr;
@@ -1217,7 +1408,8 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id
 
        /* check if we can restrict PCI DMA transfers to 32 bits */
        if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0) {
-               snd_printk(KERN_ERR "architecture does not support 32bit PCI busmaster DMA\n");
+               snd_printk(KERN_ERR "architecture does not support "
+                          "32bit PCI busmaster DMA\n");
                pci_disable_device(pci);
                return -ENXIO;
        }
@@ -1234,11 +1426,25 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id
                pci_disable_device(pci);
                return -ENODEV;
        }
-       card_name = pcxhr_board_params[pci_id->driver_data].board_name;
-       mgr->playback_chips = pcxhr_board_params[pci_id->driver_data].playback_chips;
-       mgr->capture_chips  = pcxhr_board_params[pci_id->driver_data].capture_chips;
-       mgr->firmware_num  = pcxhr_board_params[pci_id->driver_data].firmware_num;
+       card_name =
+               pcxhr_board_params[pci_id->driver_data].board_name;
+       mgr->playback_chips =
+               pcxhr_board_params[pci_id->driver_data].playback_chips;
+       mgr->capture_chips  =
+               pcxhr_board_params[pci_id->driver_data].capture_chips;
+       mgr->fw_file_set =
+               pcxhr_board_params[pci_id->driver_data].fw_file_set;
+       mgr->firmware_num  =
+               pcxhr_board_params[pci_id->driver_data].firmware_num;
        mgr->mono_capture = mono[dev];
+       mgr->is_hr_stereo = (mgr->playback_chips == 1);
+       mgr->board_has_aes1 = PCXHR_BOARD_HAS_AES1(mgr);
+       mgr->board_aes_in_192k = !PCXHR_BOARD_AESIN_NO_192K(mgr);
+
+       if (mgr->is_hr_stereo)
+               mgr->granularity = PCXHR_GRANULARITY_HR22;
+       else
+               mgr->granularity = PCXHR_GRANULARITY;
 
        /* resource assignment */
        if ((err = pci_request_regions(pci, card_name)) < 0) {
@@ -1261,7 +1467,8 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id
        mgr->irq = pci->irq;
 
        sprintf(mgr->shortname, "Digigram %s", card_name);
-       sprintf(mgr->longname, "%s at 0x%lx & 0x%lx, 0x%lx irq %i", mgr->shortname,
+       sprintf(mgr->longname, "%s at 0x%lx & 0x%lx, 0x%lx irq %i",
+               mgr->shortname,
                mgr->port[0], mgr->port[1], mgr->port[2], mgr->irq);
 
        /* ISR spinlock  */
@@ -1272,10 +1479,14 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id
        mutex_init(&mgr->setup_mutex);
 
        /* init taslket */
-       tasklet_init(&mgr->msg_taskq, pcxhr_msg_tasklet, (unsigned long) mgr);
-       tasklet_init(&mgr->trigger_taskq, pcxhr_trigger_tasklet, (unsigned long) mgr);
+       tasklet_init(&mgr->msg_taskq, pcxhr_msg_tasklet,
+                    (unsigned long) mgr);
+       tasklet_init(&mgr->trigger_taskq, pcxhr_trigger_tasklet,
+                    (unsigned long) mgr);
+
        mgr->prmh = kmalloc(sizeof(*mgr->prmh) + 
-                           sizeof(u32) * (PCXHR_SIZE_MAX_LONG_STATUS - PCXHR_SIZE_MAX_STATUS),
+                           sizeof(u32) * (PCXHR_SIZE_MAX_LONG_STATUS -
+                                          PCXHR_SIZE_MAX_STATUS),
                            GFP_KERNEL);
        if (! mgr->prmh) {
                pcxhr_free(mgr);
@@ -1296,7 +1507,8 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id
                else
                        idx = index[dev] + i;
 
-               snprintf(tmpid, sizeof(tmpid), "%s-%d", id[dev] ? id[dev] : card_name, i);
+               snprintf(tmpid, sizeof(tmpid), "%s-%d",
+                        id[dev] ? id[dev] : card_name, i);
                card = snd_card_new(idx, tmpid, THIS_MODULE, 0);
 
                if (! card) {
index 6520647..84131a9 100644 (file)
 #include <linux/mutex.h>
 #include <sound/pcm.h>
 
-#define PCXHR_DRIVER_VERSION           0x000804        /* 0.8.4 */
-#define PCXHR_DRIVER_VERSION_STRING    "0.8.4"         /* 0.8.4 */
+#define PCXHR_DRIVER_VERSION           0x000905        /* 0.9.5 */
+#define PCXHR_DRIVER_VERSION_STRING    "0.9.5"         /* 0.9.5 */
 
 
-#define PCXHR_MAX_CARDS                        6
-#define PCXHR_PLAYBACK_STREAMS         4
+#define PCXHR_MAX_CARDS                6
+#define PCXHR_PLAYBACK_STREAMS 4
 
-#define PCXHR_GRANULARITY              96      /* transfer granularity (should be min 96 and multiple of 48) */
-#define PCXHR_GRANULARITY_MIN          96      /* transfer granularity of pipes and the dsp time (MBOX4) */
+#define PCXHR_GRANULARITY      96      /* min 96 and multiple of 48 */
+/* transfer granularity of pipes and the dsp time (MBOX4) */
+#define PCXHR_GRANULARITY_MIN  96
+/* TODO : granularity could be 64 or 128 */
+#define PCXHR_GRANULARITY_HR22 192     /* granularity for stereo cards */
 
 struct snd_pcxhr;
 struct pcxhr_mgr;
@@ -51,6 +54,11 @@ enum pcxhr_clock_type {
        PCXHR_CLOCK_TYPE_AES_2,
        PCXHR_CLOCK_TYPE_AES_3,
        PCXHR_CLOCK_TYPE_AES_4,
+       PCXHR_CLOCK_TYPE_MAX = PCXHR_CLOCK_TYPE_AES_4,
+       HR22_CLOCK_TYPE_INTERNAL = PCXHR_CLOCK_TYPE_INTERNAL,
+       HR22_CLOCK_TYPE_AES_SYNC,
+       HR22_CLOCK_TYPE_AES_1,
+       HR22_CLOCK_TYPE_MAX = HR22_CLOCK_TYPE_AES_1,
 };
 
 struct pcxhr_mgr {
@@ -61,6 +69,8 @@ struct pcxhr_mgr {
 
        int irq;
 
+       int granularity;
+
        /* card access with 1 mem bar and 2 io bar's */
        unsigned long port[3];
 
@@ -83,11 +93,16 @@ struct pcxhr_mgr {
        /* hardware interface */
        unsigned int dsp_loaded;        /* bit flags of loaded dsp indices */
        unsigned int dsp_version;       /* read from embedded once firmware is loaded */
-       int board_has_analog;           /* if 0 the board is digital only */
-       int mono_capture;               /* if 1 the board does mono capture */
-       int playback_chips;             /* 4 or 6 */
-       int capture_chips;              /* 4 or 1 */
-       int firmware_num;               /* 41 or 42 */
+       int playback_chips;
+       int capture_chips;
+       int fw_file_set;
+       int firmware_num;
+       int is_hr_stereo:1;
+       int board_has_aes1:1;   /* if 1 board has AES1 plug and SRC */
+       int board_has_analog:1; /* if 0 the board is digital only */
+       int board_has_mic:1;    /* if 1 the board has microphone input */
+       int board_aes_in_192k:1;/* if 1 the aes input plugs do support 192kHz */
+       int mono_capture:1;     /* if 1 the board does mono capture */
 
        struct snd_dma_buffer hostport;
 
@@ -106,6 +121,9 @@ struct pcxhr_mgr {
        int async_err_stream_xrun;
        int async_err_pipe_xrun;
        int async_err_other_last;
+
+       unsigned char xlx_cfg;          /* copy of PCXHR_XLX_CFG register */
+       unsigned char xlx_selmic;       /* copy of PCXHR_XLX_SELMIC register */
 };
 
 
@@ -155,24 +173,30 @@ struct snd_pcxhr {
 
        struct snd_pcm *pcm;            /* PCM */
 
-       struct pcxhr_pipe playback_pipe;                /* 1 stereo pipe only */
-       struct pcxhr_pipe capture_pipe[2];              /* 1 stereo pipe or 2 mono pipes */
+       struct pcxhr_pipe playback_pipe;        /* 1 stereo pipe only */
+       struct pcxhr_pipe capture_pipe[2];      /* 1 stereo or 2 mono pipes */
 
        struct pcxhr_stream playback_stream[PCXHR_PLAYBACK_STREAMS];
-       struct pcxhr_stream capture_stream[2];  /* 1 stereo stream or 2 mono streams */
+       struct pcxhr_stream capture_stream[2];  /* 1 stereo or 2 mono streams */
        int nb_streams_play;
        int nb_streams_capt;
 
-       int analog_playback_active[2];          /* Mixer : Master Playback active (!mute) */
-       int analog_playback_volume[2];          /* Mixer : Master Playback Volume */
-       int analog_capture_volume[2];           /* Mixer : Master Capture Volume */
-       int digital_playback_active[PCXHR_PLAYBACK_STREAMS][2]; /* Mixer : Digital Playback Active [streams][stereo]*/
-       int digital_playback_volume[PCXHR_PLAYBACK_STREAMS][2]; /* Mixer : Digital Playback Volume [streams][stereo]*/
-       int digital_capture_volume[2];          /* Mixer : Digital Capture Volume [stereo] */
-       int monitoring_active[2];               /* Mixer : Monitoring Active */
-       int monitoring_volume[2];               /* Mixer : Monitoring Volume */
-       int audio_capture_source;               /* Mixer : Audio Capture Source */
-       unsigned char aes_bits[5];              /* Mixer : IEC958_AES bits */
+       int analog_playback_active[2];  /* Mixer : Master Playback !mute */
+       int analog_playback_volume[2];  /* Mixer : Master Playback Volume */
+       int analog_capture_volume[2];   /* Mixer : Master Capture Volume */
+       int digital_playback_active[PCXHR_PLAYBACK_STREAMS][2];
+       int digital_playback_volume[PCXHR_PLAYBACK_STREAMS][2];
+       int digital_capture_volume[2];  /* Mixer : Digital Capture Volume */
+       int monitoring_active[2];       /* Mixer : Monitoring Active */
+       int monitoring_volume[2];       /* Mixer : Monitoring Volume */
+       int audio_capture_source;       /* Mixer : Audio Capture Source */
+       int mic_volume;                 /* used by cards with MIC only */
+       int mic_boost;                  /* used by cards with MIC only */
+       int mic_active;                 /* used by cards with MIC only */
+       int analog_capture_active;      /* used by cards with MIC only */
+       int phantom_power;              /* used by cards with MIC only */
+
+       unsigned char aes_bits[5];      /* Mixer : IEC958_AES bits */
 };
 
 struct pcxhr_hostport
@@ -184,6 +208,8 @@ struct pcxhr_hostport
 /* exported */
 int pcxhr_create_pcm(struct snd_pcxhr *chip);
 int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate);
-int pcxhr_get_external_clock(struct pcxhr_mgr *mgr, enum pcxhr_clock_type clock_type, int *sample_rate);
+int pcxhr_get_external_clock(struct pcxhr_mgr *mgr,
+                            enum pcxhr_clock_type clock_type,
+                            int *sample_rate);
 
 #endif /* __SOUND_PCXHR_H */