]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge branch 'topic/sscape-fix' into for-linus
authorTakashi Iwai <tiwai@suse.de>
Mon, 23 Mar 2009 23:36:21 +0000 (00:36 +0100)
committerTakashi Iwai <tiwai@suse.de>
Mon, 23 Mar 2009 23:36:21 +0000 (00:36 +0100)
1  2 
sound/isa/Kconfig
sound/isa/sscape.c
sound/isa/wss/wss_lib.c

diff --combined sound/isa/Kconfig
index 2df20e403f247098e3d8bb3867b220099638eaa1,542c1ead14bd08898ac82c71b5c12a07ca2e0b7f..c5c9a9218ff6ef3c209c7554c2c788eb3b516de2
@@@ -56,8 -56,8 +56,8 @@@ config SND_AD184
          Say Y here to include support for AD1848 (Analog Devices) or
          CS4248 (Cirrus Logic - Crystal Semiconductors) chips.
          
 -        For newer chips from Cirrus Logic, use the CS4231, CS4232 or
 -        CS4236+ drivers.
 +        For newer chips from Cirrus Logic, use the CS4231 or CS4232+
 +        drivers.
  
          To compile this driver as a module, choose M here: the module
          will be called snd-ad1848.
@@@ -94,8 -94,6 +94,8 @@@ config SND_CMI833
        tristate "C-Media CMI8330"
        select SND_WSS_LIB
        select SND_SB16_DSP
 +      select SND_OPL3_LIB
 +      select SND_MPU401_UART
        help
          Say Y here to include support for soundcards based on the
          C-Media CMI8330 chip.
@@@ -114,15 -112,26 +114,15 @@@ config SND_CS423
          To compile this driver as a module, choose M here: the module
          will be called snd-cs4231.
  
 -config SND_CS4232
 -      tristate "Generic Cirrus Logic CS4232 driver"
 -      select SND_OPL3_LIB
 -      select SND_MPU401_UART
 -      select SND_WSS_LIB
 -      help
 -        Say Y here to include support for CS4232 chips from Cirrus
 -        Logic - Crystal Semiconductors.
 -
 -        To compile this driver as a module, choose M here: the module
 -        will be called snd-cs4232.
 -
  config SND_CS4236
 -      tristate "Generic Cirrus Logic CS4236+ driver"
 +      tristate "Generic Cirrus Logic CS4232/CS4236+ driver"
        select SND_OPL3_LIB
        select SND_MPU401_UART
        select SND_WSS_LIB
        help
 -        Say Y to include support for CS4235,CS4236,CS4237B,CS4238B,
 -        CS4239 chips from Cirrus Logic - Crystal Semiconductors.
 +        Say Y to include support for CS4232,CS4235,CS4236,CS4237B,
 +        CS4238B,CS4239 chips from Cirrus Logic - Crystal
 +        Semiconductors.
  
          To compile this driver as a module, choose M here: the module
          will be called snd-cs4236.
@@@ -368,14 -377,17 +368,17 @@@ config SND_SGALAX
          will be called snd-sgalaxy.
  
  config SND_SSCAPE
-       tristate "Ensoniq SoundScape PnP driver"
+       tristate "Ensoniq SoundScape driver"
        select SND_HWDEP
        select SND_MPU401_UART
        select SND_WSS_LIB
        help
-         Say Y here to include support for Ensoniq SoundScape PnP
+         Say Y here to include support for Ensoniq SoundScape 
          soundcards.
  
+         The PCM audio is supported on SoundScape Classic, Elite, PnP
+         and VIVO cards. The MIDI support is very experimental.
          To compile this driver as a module, choose M here: the module
          will be called snd-sscape.
  
@@@ -402,36 -414,5 +405,36 @@@ config SND_WAVEFRONT_FIRMWARE_IN_KERNE
          you need to install the firmware files from the
          alsa-firmware package.
  
 +config SND_MSND_PINNACLE
 +      tristate "Turtle Beach MultiSound Pinnacle/Fiji driver"
 +      depends on X86 && EXPERIMENTAL
 +      select FW_LOADER
 +      select SND_MPU401_UART
 +      select SND_PCM
 +      help
 +        Say Y to include support for Turtle Beach MultiSound Pinnacle/
 +        Fiji soundcards.
 +
 +        To compile this driver as a module, choose M here: the module
 +        will be called snd-msnd-pinnacle.
 +
 +config SND_MSND_CLASSIC
 +      tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey"
 +      depends on X86 && EXPERIMENTAL
 +      select FW_LOADER
 +      select SND_MPU401_UART
 +      select SND_PCM
 +      help
 +        Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or
 +        Monterey (not for the Pinnacle or Fiji).
 +
 +        See <file:Documentation/sound/oss/MultiSound> for important information
 +        about this driver.  Note that it has been discontinued, but the
 +        Voyetra Turtle Beach knowledge base entry for it is still available
 +        at <http://www.turtlebeach.com/site/kb_ftp/790.asp>.
 +
 +        To compile this driver as a module, choose M here: the module
 +        will be called snd-msnd-classic.
 +
  endif # SND_ISA
  
diff --combined sound/isa/sscape.c
index 4025fb558c5005d1b5143d8b3f41f679e6f54184,33c1258029f95152278f3e438be38bbacf4ed857..66187122377c544cbc2059a9e8c0ecd9fa5a594a
@@@ -89,9 -89,6 +89,6 @@@ MODULE_DEVICE_TABLE(pnp_card, sscape_pn
  #endif
  
  
- #define MPU401_IO(i)     ((i) + 0)
- #define MIDI_DATA_IO(i)  ((i) + 0)
- #define MIDI_CTRL_IO(i)  ((i) + 1)
  #define HOST_CTRL_IO(i)  ((i) + 2)
  #define HOST_DATA_IO(i)  ((i) + 3)
  #define ODIE_ADDR_IO(i)  ((i) + 4)
@@@ -129,9 -126,6 +126,6 @@@ enum GA_REG 
  #define DMA_8BIT  0x80
  
  
- #define AD1845_FREQ_SEL_MSB    0x16
- #define AD1845_FREQ_SEL_LSB    0x17
  enum card_type {
        SSCAPE,
        SSCAPE_PNP,
  struct soundscape {
        spinlock_t lock;
        unsigned io_base;
-       unsigned wss_base;
-       int codec_type;
        int ic_type;
        enum card_type type;
        struct resource *io_res;
@@@ -330,7 -322,7 +322,7 @@@ static int host_write_ctrl_unsafe(unsig
   */
  static inline int verify_mpu401(const struct snd_mpu401 * mpu)
  {
-       return ((inb(MIDI_CTRL_IO(mpu->port)) & 0xc0) == 0x80);
+       return ((inb(MPU401C(mpu)) & 0xc0) == 0x80);
  }
  
  /*
   */
  static inline void initialise_mpu401(const struct snd_mpu401 * mpu)
  {
-       outb(0, MIDI_DATA_IO(mpu->port));
+       outb(0, MPU401D(mpu));
  }
  
  /*
@@@ -396,20 -388,20 +388,20 @@@ static int sscape_wait_dma_unsafe(unsig
   */
  static int obp_startup_ack(struct soundscape *s, unsigned timeout)
  {
-       while (timeout != 0) {
+       unsigned long end_time = jiffies + msecs_to_jiffies(timeout);
+       do {
                unsigned long flags;
                unsigned char x;
  
-               schedule_timeout_uninterruptible(1);
                spin_lock_irqsave(&s->lock, flags);
                x = inb(HOST_DATA_IO(s->io_base));
                spin_unlock_irqrestore(&s->lock, flags);
                if ((x & 0xfe) == 0xfe)
                        return 1;
  
-               --timeout;
-       } /* while */
+               msleep(10);
+       } while (time_before(jiffies, end_time));
  
        return 0;
  }
   */
  static int host_startup_ack(struct soundscape *s, unsigned timeout)
  {
-       while (timeout != 0) {
+       unsigned long end_time = jiffies + msecs_to_jiffies(timeout);
+       do {
                unsigned long flags;
                unsigned char x;
  
-               schedule_timeout_uninterruptible(1);
                spin_lock_irqsave(&s->lock, flags);
                x = inb(HOST_DATA_IO(s->io_base));
                spin_unlock_irqrestore(&s->lock, flags);
                if (x == 0xfe)
                        return 1;
  
-               --timeout;
-       } /* while */
+               msleep(10);
+       } while (time_before(jiffies, end_time));
  
        return 0;
  }
@@@ -532,10 -524,10 +524,10 @@@ static int upload_dma_data(struct sound
         * give it 5 seconds (max) ...
         */
        ret = 0;
-       if (!obp_startup_ack(s, 5)) {
+       if (!obp_startup_ack(s, 5000)) {
                snd_printk(KERN_ERR "sscape: No response from on-board processor after upload\n");
                ret = -EAGAIN;
-       } else if (!host_startup_ack(s, 5)) {
+       } else if (!host_startup_ack(s, 5000)) {
                snd_printk(KERN_ERR "sscape: SoundScape failed to initialise\n");
                ret = -EAGAIN;
        }
@@@ -732,13 -724,7 +724,7 @@@ static int sscape_midi_get(struct snd_k
        unsigned long flags;
  
        spin_lock_irqsave(&s->lock, flags);
-       set_host_mode_unsafe(s->io_base);
-       if (host_write_ctrl_unsafe(s->io_base, CMD_GET_MIDI_VOL, 100)) {
-               uctl->value.integer.value[0] = host_read_ctrl_unsafe(s->io_base, 100);
-       }
-       set_midi_mode_unsafe(s->io_base);
+       uctl->value.integer.value[0] = s->midi_vol;
        spin_unlock_irqrestore(&s->lock, flags);
        return 0;
  }
@@@ -773,6 -759,7 +759,7 @@@ static int sscape_midi_put(struct snd_k
        change = (host_write_ctrl_unsafe(s->io_base, CMD_SET_MIDI_VOL, 100)
                  && host_write_ctrl_unsafe(s->io_base, ((unsigned char) uctl->value.integer. value[0]) & 127, 100)
                  && host_write_ctrl_unsafe(s->io_base, CMD_XXX_MIDI_VOL, 100));
+       s->midi_vol = (unsigned char) uctl->value.integer.value[0] & 127;
        __skip_change:
  
        /*
@@@ -815,12 -802,11 +802,11 @@@ static unsigned __devinit get_irq_confi
   * Perform certain arcane port-checks to see whether there
   * is a SoundScape board lurking behind the given ports.
   */
- static int __devinit detect_sscape(struct soundscape *s)
+ static int __devinit detect_sscape(struct soundscape *s, long wss_io)
  {
        unsigned long flags;
        unsigned d;
        int retval = 0;
-       int codec = s->wss_base;
  
        spin_lock_irqsave(&s->lock, flags);
  
        if ((d & 0x80) != 0)
                goto _done;
  
-       if (d == 0) {
-               s->codec_type = 1;
+       if (d == 0)
                s->ic_type = IC_ODIE;
-       } else if ((d & 0x60) != 0) {
-               s->codec_type = 2;
+       else if ((d & 0x60) != 0)
                s->ic_type = IC_OPUS;
-       else
+       else
                goto _done;
  
        outb(0xfa, ODIE_ADDR_IO(s->io_base));
        sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0);
  
        if (s->type == SSCAPE_VIVO)
-               codec += 4;
+               wss_io += 4;
        /* wait for WSS codec */
        for (d = 0; d < 500; d++) {
-               if ((inb(codec) & 0x80) == 0)
+               if ((inb(wss_io) & 0x80) == 0)
                        break;
                spin_unlock_irqrestore(&s->lock, flags);
                msleep(1);
@@@ -954,82 -938,6 +938,6 @@@ static int __devinit create_mpu401(stru
  }
  
  
- /*
-  * Override for the CS4231 playback format function.
-  * The AD1845 has much simpler format and rate selection.
-  */
- static void ad1845_playback_format(struct snd_wss *chip,
-                                  struct snd_pcm_hw_params *params,
-                                  unsigned char format)
- {
-       unsigned long flags;
-       unsigned rate = params_rate(params);
-       /*
-        * The AD1845 can't handle sample frequencies
-        * outside of 4 kHZ to 50 kHZ
-        */
-       if (rate > 50000)
-               rate = 50000;
-       else if (rate < 4000)
-               rate = 4000;
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       /*
-        * Program the AD1845 correctly for the playback stream.
-        * Note that we do NOT need to toggle the MCE bit because
-        * the PLAYBACK_ENABLE bit of the Interface Configuration
-        * register is set.
-        * 
-        * NOTE: We seem to need to write to the MSB before the LSB
-        *       to get the correct sample frequency.
-        */
-       snd_wss_out(chip, CS4231_PLAYBK_FORMAT, (format & 0xf0));
-       snd_wss_out(chip, AD1845_FREQ_SEL_MSB, (unsigned char) (rate >> 8));
-       snd_wss_out(chip, AD1845_FREQ_SEL_LSB, (unsigned char) rate);
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
- }
- /*
-  * Override for the CS4231 capture format function. 
-  * The AD1845 has much simpler format and rate selection.
-  */
- static void ad1845_capture_format(struct snd_wss *chip,
-                                 struct snd_pcm_hw_params *params,
-                                 unsigned char format)
- {
-       unsigned long flags;
-       unsigned rate = params_rate(params);
-       /*
-        * The AD1845 can't handle sample frequencies 
-        * outside of 4 kHZ to 50 kHZ
-        */
-       if (rate > 50000)
-               rate = 50000;
-       else if (rate < 4000)
-               rate = 4000;
-       spin_lock_irqsave(&chip->reg_lock, flags);
-       /*
-        * Program the AD1845 correctly for the playback stream.
-        * Note that we do NOT need to toggle the MCE bit because
-        * the CAPTURE_ENABLE bit of the Interface Configuration
-        * register is set.
-        *
-        * NOTE: We seem to need to write to the MSB before the LSB
-        *       to get the correct sample frequency.
-        */
-       snd_wss_out(chip, CS4231_REC_FORMAT, (format & 0xf0));
-       snd_wss_out(chip, AD1845_FREQ_SEL_MSB, (unsigned char) (rate >> 8));
-       snd_wss_out(chip, AD1845_FREQ_SEL_LSB, (unsigned char) rate);
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
- }
  /*
   * Create an AD1845 PCM subdevice on the SoundScape. The AD1845
   * is very much like a CS4231, with a few extra bits. We will
@@@ -1055,11 -963,6 +963,6 @@@ static int __devinit create_ad1845(stru
                unsigned long flags;
                struct snd_pcm *pcm;
  
- #define AD1845_FREQ_SEL_ENABLE  0x08
- #define AD1845_PWR_DOWN_CTRL   0x1b
- #define AD1845_CRYS_CLOCK_SEL  0x1d
  /*
   * It turns out that the PLAYBACK_ENABLE bit is set
   * by the lowlevel driver ...
   */
  
                if (sscape->type != SSCAPE_VIVO) {
-                       int val;
                        /*
                         * The input clock frequency on the SoundScape must
                         * be 14.31818 MHz, because we must set this register
                         */
                        snd_wss_mce_up(chip);
                        spin_lock_irqsave(&chip->reg_lock, flags);
-                       snd_wss_out(chip, AD1845_CRYS_CLOCK_SEL, 0x20);
+                       snd_wss_out(chip, AD1845_CLOCK, 0x20);
                        spin_unlock_irqrestore(&chip->reg_lock, flags);
                        snd_wss_mce_down(chip);
  
-                       /*
-                        * More custom configuration:
-                        * a) select "mode 2" and provide a current drive of 8mA
-                        * b) enable frequency selection (for capture/playback)
-                        */
-                       spin_lock_irqsave(&chip->reg_lock, flags);
-                       snd_wss_out(chip, CS4231_MISC_INFO,
-                                   CS4231_MODE2 | 0x10);
-                       val = snd_wss_in(chip, AD1845_PWR_DOWN_CTRL);
-                       snd_wss_out(chip, AD1845_PWR_DOWN_CTRL,
-                                   val | AD1845_FREQ_SEL_ENABLE);
-                       spin_unlock_irqrestore(&chip->reg_lock, flags);
                }
  
                err = snd_wss_pcm(chip, 0, &pcm);
                                            "for AD1845 chip\n");
                        goto _error;
                }
-               err = snd_wss_timer(chip, 0, NULL);
-               if (err < 0) {
-                       snd_printk(KERN_ERR "sscape: No timer device "
-                                           "for AD1845 chip\n");
-                       goto _error;
+               if (chip->hardware != WSS_HW_AD1848) {
+                       err = snd_wss_timer(chip, 0, NULL);
+                       if (err < 0) {
+                               snd_printk(KERN_ERR "sscape: No timer device "
+                                                   "for AD1845 chip\n");
+                               goto _error;
+                       }
                }
  
                if (sscape->type != SSCAPE_VIVO) {
                                                    "MIDI mixer control\n");
                                goto _error;
                        }
-                       chip->set_playback_format = ad1845_playback_format;
-                       chip->set_capture_format = ad1845_capture_format;
                }
  
                strcpy(card->driver, "SoundScape");
@@@ -1157,7 -1047,6 +1047,6 @@@ static int __devinit create_sscape(int 
        unsigned dma_cfg;
        unsigned irq_cfg;
        unsigned mpu_irq_cfg;
-       unsigned xport;
        struct resource *io_res;
        struct resource *wss_res;
        unsigned long flags;
                printk(KERN_ERR "sscape: Invalid IRQ %d\n", mpu_irq[dev]);
                return -ENXIO;
        }
-       xport = port[dev];
  
        /*
         * Grab IO ports that we will need to probe so that we
         * can detect and control this hardware ...
         */
-       io_res = request_region(xport, 8, "SoundScape");
+       io_res = request_region(port[dev], 8, "SoundScape");
        if (!io_res) {
-               snd_printk(KERN_ERR "sscape: can't grab port 0x%x\n", xport);
+               snd_printk(KERN_ERR
+                          "sscape: can't grab port 0x%lx\n", port[dev]);
                return -EBUSY;
        }
        wss_res = NULL;
        spin_lock_init(&sscape->fwlock);
        sscape->io_res = io_res;
        sscape->wss_res = wss_res;
-       sscape->io_base = xport;
-       sscape->wss_base = wss_port[dev];
+       sscape->io_base = port[dev];
  
-       if (!detect_sscape(sscape)) {
+       if (!detect_sscape(sscape, wss_port[dev])) {
                printk(KERN_ERR "sscape: hardware not detected at 0x%x\n", sscape->io_base);
                err = -ENODEV;
                goto _release_dma;
        }
  #define MIDI_DEVNUM  0
        if (sscape->type != SSCAPE_VIVO) {
-               err = create_mpu401(card, MIDI_DEVNUM,
-                                   MPU401_IO(xport), mpu_irq[dev]);
+               err = create_mpu401(card, MIDI_DEVNUM, port[dev], mpu_irq[dev]);
                if (err < 0) {
                        printk(KERN_ERR "sscape: Failed to create "
-                                       "MPU-401 device at 0x%x\n",
-                                       MPU401_IO(xport));
+                                       "MPU-401 device at 0x%lx\n",
+                                       port[dev]);
                        goto _release_dma;
                }
  
@@@ -1357,10 -1244,10 +1244,10 @@@ static int __devinit snd_sscape_probe(s
        struct soundscape *sscape;
        int ret;
  
 -      card = snd_card_new(index[dev], id[dev], THIS_MODULE,
 -                          sizeof(struct soundscape));
 -      if (!card)
 -              return -ENOMEM;
 +      ret = snd_card_create(index[dev], id[dev], THIS_MODULE,
 +                            sizeof(struct soundscape), &card);
 +      if (ret < 0)
 +              return ret;
  
        sscape = get_card_soundscape(card);
        sscape->type = SSCAPE;
@@@ -1462,10 -1349,10 +1349,10 @@@ static int __devinit sscape_pnp_detect(
         * Create a new ALSA sound card entry, in anticipation
         * of detecting our hardware ...
         */
 -      card = snd_card_new(index[idx], id[idx], THIS_MODULE,
 -                          sizeof(struct soundscape));
 -      if (!card)
 -              return -ENOMEM;
 +      ret = snd_card_create(index[idx], id[idx], THIS_MODULE,
 +                            sizeof(struct soundscape), &card);
 +      if (ret < 0)
 +              return ret;
  
        sscape = get_card_soundscape(card);
  
diff --combined sound/isa/wss/wss_lib.c
index ac27832b2c6f8e9714f05d5fa801ebced963586c,f0c0be5bb684d0f15a2c192854cbc14d1ef745c1..5d2ba1b749abef59839210b177944cd3c9a8a24c
@@@ -181,25 -181,6 +181,6 @@@ static void snd_wss_wait(struct snd_ws
                udelay(100);
  }
  
- static void snd_wss_outm(struct snd_wss *chip, unsigned char reg,
-                           unsigned char mask, unsigned char value)
- {
-       unsigned char tmp = (chip->image[reg] & mask) | value;
-       snd_wss_wait(chip);
- #ifdef CONFIG_SND_DEBUG
-       if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
-               snd_printk("outm: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
- #endif
-       chip->image[reg] = tmp;
-       if (!chip->calibrate_mute) {
-               wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
-               wmb();
-               wss_outb(chip, CS4231P(REG), tmp);
-               mb();
-       }
- }
  static void snd_wss_dout(struct snd_wss *chip, unsigned char reg,
                         unsigned char value)
  {
@@@ -219,8 -200,7 +200,8 @@@ void snd_wss_out(struct snd_wss *chip, 
        snd_wss_wait(chip);
  #ifdef CONFIG_SND_DEBUG
        if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
 -              snd_printk("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
 +              snd_printk(KERN_DEBUG "out: auto calibration time out "
 +                         "- reg = 0x%x, value = 0x%x\n", reg, value);
  #endif
        wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
        wss_outb(chip, CS4231P(REG), value);
@@@ -236,8 -216,7 +217,8 @@@ unsigned char snd_wss_in(struct snd_ws
        snd_wss_wait(chip);
  #ifdef CONFIG_SND_DEBUG
        if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
 -              snd_printk("in: auto calibration time out - reg = 0x%x\n", reg);
 +              snd_printk(KERN_DEBUG "in: auto calibration time out "
 +                         "- reg = 0x%x\n", reg);
  #endif
        wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
        mb();
@@@ -254,7 -233,7 +235,7 @@@ void snd_cs4236_ext_out(struct snd_wss 
        wss_outb(chip, CS4231P(REG), val);
        chip->eimage[CS4236_REG(reg)] = val;
  #if 0
 -      printk("ext out : reg = 0x%x, val = 0x%x\n", reg, val);
 +      printk(KERN_DEBUG "ext out : reg = 0x%x, val = 0x%x\n", reg, val);
  #endif
  }
  EXPORT_SYMBOL(snd_cs4236_ext_out);
@@@ -270,8 -249,7 +251,8 @@@ unsigned char snd_cs4236_ext_in(struct 
        {
                unsigned char res;
                res = wss_inb(chip, CS4231P(REG));
 -              printk("ext in : reg = 0x%x, val = 0x%x\n", reg, res);
 +              printk(KERN_DEBUG "ext in : reg = 0x%x, val = 0x%x\n",
 +                     reg, res);
                return res;
        }
  #endif
@@@ -397,16 -375,13 +378,16 @@@ void snd_wss_mce_up(struct snd_wss *chi
        snd_wss_wait(chip);
  #ifdef CONFIG_SND_DEBUG
        if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
 -              snd_printk("mce_up - auto calibration time out (0)\n");
 +              snd_printk(KERN_DEBUG
 +                         "mce_up - auto calibration time out (0)\n");
  #endif
        spin_lock_irqsave(&chip->reg_lock, flags);
        chip->mce_bit |= CS4231_MCE;
        timeout = wss_inb(chip, CS4231P(REGSEL));
        if (timeout == 0x80)
 -              snd_printk("mce_up [0x%lx]: serious init problem - codec still busy\n", chip->port);
 +              snd_printk(KERN_DEBUG "mce_up [0x%lx]: "
 +                         "serious init problem - codec still busy\n",
 +                         chip->port);
        if (!(timeout & CS4231_MCE))
                wss_outb(chip, CS4231P(REGSEL),
                         chip->mce_bit | (timeout & 0x1f));
@@@ -425,9 -400,7 +406,9 @@@ void snd_wss_mce_down(struct snd_wss *c
  
  #ifdef CONFIG_SND_DEBUG
        if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
 -              snd_printk("mce_down [0x%lx] - auto calibration time out (0)\n", (long)CS4231P(REGSEL));
 +              snd_printk(KERN_DEBUG "mce_down [0x%lx] - "
 +                         "auto calibration time out (0)\n",
 +                         (long)CS4231P(REGSEL));
  #endif
        spin_lock_irqsave(&chip->reg_lock, flags);
        chip->mce_bit &= ~CS4231_MCE;
        wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
        spin_unlock_irqrestore(&chip->reg_lock, flags);
        if (timeout == 0x80)
 -              snd_printk("mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port);
 +              snd_printk(KERN_DEBUG "mce_down [0x%lx]: "
 +                         "serious init problem - codec still busy\n",
 +                         chip->port);
        if ((timeout & CS4231_MCE) == 0 || !(chip->hardware & hw_mask))
                return;
  
@@@ -575,7 -546,7 +556,7 @@@ static unsigned char snd_wss_get_format
        if (channels > 1)
                rformat |= CS4231_STEREO;
  #if 0
 -      snd_printk("get_format: 0x%x (mode=0x%x)\n", format, mode);
 +      snd_printk(KERN_DEBUG "get_format: 0x%x (mode=0x%x)\n", format, mode);
  #endif
        return rformat;
  }
@@@ -597,7 -568,15 +578,15 @@@ static void snd_wss_calibrate_mute(stru
                             chip->image[CS4231_RIGHT_INPUT]);
                snd_wss_dout(chip, CS4231_LOOPBACK,
                             chip->image[CS4231_LOOPBACK]);
+       } else {
+               snd_wss_dout(chip, CS4231_LEFT_INPUT,
+                            0);
+               snd_wss_dout(chip, CS4231_RIGHT_INPUT,
+                            0);
+               snd_wss_dout(chip, CS4231_LOOPBACK,
+                            0xfd);
        }
        snd_wss_dout(chip, CS4231_AUX1_LEFT_INPUT,
                     mute | chip->image[CS4231_AUX1_LEFT_INPUT]);
        snd_wss_dout(chip, CS4231_AUX1_RIGHT_INPUT,
@@@ -640,7 -619,6 +629,6 @@@ static void snd_wss_playback_format(str
        int full_calib = 1;
  
        mutex_lock(&chip->mce_mutex);
-       snd_wss_calibrate_mute(chip, 1);
        if (chip->hardware == WSS_HW_CS4231A ||
            (chip->hardware & WSS_HW_CS4232_MASK)) {
                spin_lock_irqsave(&chip->reg_lock, flags);
                        full_calib = 0;
                }
                spin_unlock_irqrestore(&chip->reg_lock, flags);
+       } else if (chip->hardware == WSS_HW_AD1845) {
+               unsigned rate = params_rate(params);
+               /*
+                * Program the AD1845 correctly for the playback stream.
+                * Note that we do NOT need to toggle the MCE bit because
+                * the PLAYBACK_ENABLE bit of the Interface Configuration
+                * register is set.
+                *
+                * NOTE: We seem to need to write to the MSB before the LSB
+                *       to get the correct sample frequency.
+                */
+               spin_lock_irqsave(&chip->reg_lock, flags);
+               snd_wss_out(chip, CS4231_PLAYBK_FORMAT, (pdfr & 0xf0));
+               snd_wss_out(chip, AD1845_UPR_FREQ_SEL, (rate >> 8) & 0xff);
+               snd_wss_out(chip, AD1845_LWR_FREQ_SEL, rate & 0xff);
+               full_calib = 0;
+               spin_unlock_irqrestore(&chip->reg_lock, flags);
        }
        if (full_calib) {
                snd_wss_mce_up(chip);
                        udelay(100);    /* this seems to help */
                snd_wss_mce_down(chip);
        }
-       snd_wss_calibrate_mute(chip, 0);
        mutex_unlock(&chip->mce_mutex);
  }
  
@@@ -685,7 -680,6 +690,6 @@@ static void snd_wss_capture_format(stru
        int full_calib = 1;
  
        mutex_lock(&chip->mce_mutex);
-       snd_wss_calibrate_mute(chip, 1);
        if (chip->hardware == WSS_HW_CS4231A ||
            (chip->hardware & WSS_HW_CS4232_MASK)) {
                spin_lock_irqsave(&chip->reg_lock, flags);
                        full_calib = 0;
                }
                spin_unlock_irqrestore(&chip->reg_lock, flags);
+       } else if (chip->hardware == WSS_HW_AD1845) {
+               unsigned rate = params_rate(params);
+               /*
+                * Program the AD1845 correctly for the capture stream.
+                * Note that we do NOT need to toggle the MCE bit because
+                * the PLAYBACK_ENABLE bit of the Interface Configuration
+                * register is set.
+                *
+                * NOTE: We seem to need to write to the MSB before the LSB
+                *       to get the correct sample frequency.
+                */
+               spin_lock_irqsave(&chip->reg_lock, flags);
+               snd_wss_out(chip, CS4231_REC_FORMAT, (cdfr & 0xf0));
+               snd_wss_out(chip, AD1845_UPR_FREQ_SEL, (rate >> 8) & 0xff);
+               snd_wss_out(chip, AD1845_LWR_FREQ_SEL, rate & 0xff);
+               full_calib = 0;
+               spin_unlock_irqrestore(&chip->reg_lock, flags);
        }
        if (full_calib) {
                snd_wss_mce_up(chip);
                spin_unlock_irqrestore(&chip->reg_lock, flags);
                snd_wss_mce_down(chip);
        }
-       snd_wss_calibrate_mute(chip, 0);
        mutex_unlock(&chip->mce_mutex);
  }
  
@@@ -781,10 -792,11 +802,11 @@@ static void snd_wss_init(struct snd_ws
  {
        unsigned long flags;
  
+       snd_wss_calibrate_mute(chip, 1);
        snd_wss_mce_down(chip);
  
  #ifdef SNDRV_DEBUG_MCE
 -      snd_printk("init: (1)\n");
 +      snd_printk(KERN_DEBUG "init: (1)\n");
  #endif
        snd_wss_mce_up(chip);
        spin_lock_irqsave(&chip->reg_lock, flags);
        snd_wss_mce_down(chip);
  
  #ifdef SNDRV_DEBUG_MCE
 -      snd_printk("init: (2)\n");
 +      snd_printk(KERN_DEBUG "init: (2)\n");
  #endif
  
        snd_wss_mce_up(chip);
        spin_lock_irqsave(&chip->reg_lock, flags);
+       chip->image[CS4231_IFACE_CTRL] &= ~CS4231_AUTOCALIB;
+       snd_wss_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
        snd_wss_out(chip,
                    CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1]);
        spin_unlock_irqrestore(&chip->reg_lock, flags);
        snd_wss_mce_down(chip);
  
  #ifdef SNDRV_DEBUG_MCE
 -      snd_printk("init: (3) - afei = 0x%x\n",
 +      snd_printk(KERN_DEBUG "init: (3) - afei = 0x%x\n",
                   chip->image[CS4231_ALT_FEATURE_1]);
  #endif
  
        snd_wss_mce_down(chip);
  
  #ifdef SNDRV_DEBUG_MCE
 -      snd_printk("init: (4)\n");
 +      snd_printk(KERN_DEBUG "init: (4)\n");
  #endif
  
        snd_wss_mce_up(chip);
                            chip->image[CS4231_REC_FORMAT]);
        spin_unlock_irqrestore(&chip->reg_lock, flags);
        snd_wss_mce_down(chip);
+       snd_wss_calibrate_mute(chip, 0);
  
  #ifdef SNDRV_DEBUG_MCE
 -      snd_printk("init: (5)\n");
 +      snd_printk(KERN_DEBUG "init: (5)\n");
  #endif
  }
  
@@@ -895,8 -910,6 +920,6 @@@ static void snd_wss_close(struct snd_ws
                mutex_unlock(&chip->open_mutex);
                return;
        }
-       snd_wss_calibrate_mute(chip, 1);
        /* disable IRQ */
        spin_lock_irqsave(&chip->reg_lock, flags);
        if (!(chip->hardware & WSS_HW_AD1848_MASK))
        wss_outb(chip, CS4231P(STATUS), 0);     /* clear IRQ */
        spin_unlock_irqrestore(&chip->reg_lock, flags);
  
-       snd_wss_calibrate_mute(chip, 0);
        chip->mode = 0;
        mutex_unlock(&chip->open_mutex);
  }
@@@ -1123,7 -1134,7 +1144,7 @@@ irqreturn_t snd_wss_interrupt(int irq, 
        if (chip->hardware & WSS_HW_AD1848_MASK)
                wss_outb(chip, CS4231P(STATUS), 0);
        else
-               snd_wss_outm(chip, CS4231_IRQ_STATUS, status, 0);
+               snd_wss_out(chip, CS4231_IRQ_STATUS, status);
        spin_unlock(&chip->reg_lock);
        return IRQ_HANDLED;
  }
@@@ -1288,8 -1299,7 +1309,8 @@@ static int snd_wss_probe(struct snd_ws
                } else if (rev == 0x03) {
                        chip->hardware = WSS_HW_CS4236B;
                } else {
 -                      snd_printk("unknown CS chip with version 0x%x\n", rev);
 +                      snd_printk(KERN_ERR
 +                                 "unknown CS chip with version 0x%x\n", rev);
                        return -ENODEV;         /* unknown CS4231 chip? */
                }
        }
                chip->image[CS4231_ALT_FEATURE_2] =
                        chip->hardware == WSS_HW_INTERWAVE ? 0xc2 : 0x01;
        }
+       /* enable fine grained frequency selection */
+       if (chip->hardware == WSS_HW_AD1845)
+               chip->image[AD1845_PWR_DOWN] = 8;
        ptr = (unsigned char *) &chip->image;
        regnum = (chip->hardware & WSS_HW_AD1848_MASK) ? 16 : 32;
        snd_wss_mce_down(chip);
                                case 6:
                                        break;
                                default:
 -                                      snd_printk("unknown CS4235 chip (enhanced version = 0x%x)\n", id);
 +                                      snd_printk(KERN_WARNING
 +                                              "unknown CS4235 chip "
 +                                              "(enhanced version = 0x%x)\n",
 +                                              id);
                                }
                        } else if ((id & 0x1f) == 0x0b) {       /* CS4236/B */
                                switch (id >> 5) {
                                        chip->hardware = WSS_HW_CS4236B;
                                        break;
                                default:
 -                                      snd_printk("unknown CS4236 chip (enhanced version = 0x%x)\n", id);
 +                                      snd_printk(KERN_WARNING
 +                                              "unknown CS4236 chip "
 +                                              "(enhanced version = 0x%x)\n",
 +                                              id);
                                }
                        } else if ((id & 0x1f) == 0x08) {       /* CS4237B */
                                chip->hardware = WSS_HW_CS4237B;
                                case 7:
                                        break;
                                default:
 -                                      snd_printk("unknown CS4237B chip (enhanced version = 0x%x)\n", id);
 +                                      snd_printk(KERN_WARNING
 +                                              "unknown CS4237B chip "
 +                                              "(enhanced version = 0x%x)\n",
 +                                              id);
                                }
                        } else if ((id & 0x1f) == 0x09) {       /* CS4238B */
                                chip->hardware = WSS_HW_CS4238B;
                                case 7:
                                        break;
                                default:
 -                                      snd_printk("unknown CS4238B chip (enhanced version = 0x%x)\n", id);
 +                                      snd_printk(KERN_WARNING
 +                                              "unknown CS4238B chip "
 +                                              "(enhanced version = 0x%x)\n",
 +                                              id);
                                }
                        } else if ((id & 0x1f) == 0x1e) {       /* CS4239 */
                                chip->hardware = WSS_HW_CS4239;
                                case 6:
                                        break;
                                default:
 -                                      snd_printk("unknown CS4239 chip (enhanced version = 0x%x)\n", id);
 +                                      snd_printk(KERN_WARNING
 +                                              "unknown CS4239 chip "
 +                                              "(enhanced version = 0x%x)\n",
 +                                              id);
                                }
                        } else {
 -                              snd_printk("unknown CS4236/CS423xB chip (enhanced version = 0x%x)\n", id);
 +                              snd_printk(KERN_WARNING
 +                                         "unknown CS4236/CS423xB chip "
 +                                         "(enhanced version = 0x%x)\n", id);
                        }
                }
        }
@@@ -1646,8 -1643,7 +1671,8 @@@ static void snd_wss_resume(struct snd_w
        wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
        spin_unlock_irqrestore(&chip->reg_lock, flags);
        if (timeout == 0x80)
 -              snd_printk("down [0x%lx]: serious init problem - codec still busy\n", chip->port);
 +              snd_printk(KERN_ERR "down [0x%lx]: serious init problem "
 +                         "- codec still busy\n", chip->port);
        if ((timeout & CS4231_MCE) == 0 ||
            !(chip->hardware & (WSS_HW_CS4231_MASK | WSS_HW_CS4232_MASK))) {
                return;
  }
  #endif /* CONFIG_PM */
  
 -static int snd_wss_free(struct snd_wss *chip)
 +int snd_wss_free(struct snd_wss *chip)
  {
        release_and_free_resource(chip->res_port);
        release_and_free_resource(chip->res_cport);
        kfree(chip);
        return 0;
  }
 +EXPORT_SYMBOL(snd_wss_free);
  
  static int snd_wss_dev_free(struct snd_device *device)
  {
@@@ -1850,8 -1845,7 +1875,8 @@@ int snd_wss_create(struct snd_card *car
  #if 0
        if (chip->hardware & WSS_HW_CS4232_MASK) {
                if (chip->res_cport == NULL)
 -                      snd_printk("CS4232 control port features are not accessible\n");
 +                      snd_printk(KERN_ERR "CS4232 control port features are "
 +                                 "not accessible\n");
        }
  #endif