]> err.no Git - linux-2.6/blobdiff - sound/pci/cmipci.c
[PATCH] e100: support ETHTOOL_GPERMADDR
[linux-2.6] / sound / pci / cmipci.c
index 113208fbde1bc3487063f2106cc55db578f40b47..1eb3315d136dd2e50bbc0aab0168b32ee7cbf4b3 100644 (file)
@@ -79,13 +79,6 @@ module_param_array(joystick_port, int, NULL, 0444);
 MODULE_PARM_DESC(joystick_port, "Joystick port address.");
 #endif
 
-#ifndef PCI_DEVICE_ID_CMEDIA_CM8738
-#define PCI_DEVICE_ID_CMEDIA_CM8738    0x0111
-#endif
-#ifndef PCI_DEVICE_ID_CMEDIA_CM8738B
-#define PCI_DEVICE_ID_CMEDIA_CM8738B   0x0112
-#endif
-
 /*
  * CM8x38 registers definition
  */
@@ -306,7 +299,7 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address.");
 #define CM_REG_FM_PCI          0x50
 
 /*
- * for CMI-8338 .. this is not valid for CMI-8738.
+ * access from SB-mixer port
  */
 #define CM_REG_EXTENT_IND      0xf0
 #define CM_VPHONE_MASK         0xe0    /* Phone volume control (0-3) << 5 */
@@ -315,6 +308,7 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address.");
 #define CM_VSPKM               0x08    /* Speaker mute control, default high */
 #define CM_RLOOPREN            0x04    /* Rec. R-channel enable */
 #define CM_RLOOPLEN            0x02    /* Rec. L-channel enable */
+#define CM_VADMIC3             0x01    /* Mic record boost */
 
 /*
  * CMI-8338 spec ver 0.5 (this is not valid for CMI-8738):
@@ -346,25 +340,6 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address.");
 #define CM_EXTENT_SYNTH          0x4
 
 
-/*
- * pci ids
- */
-#ifndef PCI_VENDOR_ID_CMEDIA
-#define PCI_VENDOR_ID_CMEDIA         0x13F6
-#endif
-#ifndef PCI_DEVICE_ID_CMEDIA_CM8338A
-#define PCI_DEVICE_ID_CMEDIA_CM8338A 0x0100
-#endif
-#ifndef PCI_DEVICE_ID_CMEDIA_CM8338B
-#define PCI_DEVICE_ID_CMEDIA_CM8338B 0x0101
-#endif
-#ifndef PCI_DEVICE_ID_CMEDIA_CM8738
-#define PCI_DEVICE_ID_CMEDIA_CM8738  0x0111
-#endif
-#ifndef PCI_DEVICE_ID_CMEDIA_CM8738B
-#define PCI_DEVICE_ID_CMEDIA_CM8738B 0x0112
-#endif
-
 /*
  * channels for playback / capture
  */
@@ -488,71 +463,83 @@ struct snd_stru_cmipci {
 
 
 /* read/write operations for dword register */
-inline static void snd_cmipci_write(cmipci_t *cm, unsigned int cmd, unsigned int data)
+static inline void snd_cmipci_write(cmipci_t *cm, unsigned int cmd, unsigned int data)
 {
        outl(data, cm->iobase + cmd);
 }
-inline static unsigned int snd_cmipci_read(cmipci_t *cm, unsigned int cmd)
+
+static inline unsigned int snd_cmipci_read(cmipci_t *cm, unsigned int cmd)
 {
        return inl(cm->iobase + cmd);
 }
 
 /* read/write operations for word register */
-inline static void snd_cmipci_write_w(cmipci_t *cm, unsigned int cmd, unsigned short data)
+static inline void snd_cmipci_write_w(cmipci_t *cm, unsigned int cmd, unsigned short data)
 {
        outw(data, cm->iobase + cmd);
 }
-inline static unsigned short snd_cmipci_read_w(cmipci_t *cm, unsigned int cmd)
+
+static inline unsigned short snd_cmipci_read_w(cmipci_t *cm, unsigned int cmd)
 {
        return inw(cm->iobase + cmd);
 }
 
 /* read/write operations for byte register */
-inline static void snd_cmipci_write_b(cmipci_t *cm, unsigned int cmd, unsigned char data)
+static inline void snd_cmipci_write_b(cmipci_t *cm, unsigned int cmd, unsigned char data)
 {
        outb(data, cm->iobase + cmd);
 }
 
-inline static unsigned char snd_cmipci_read_b(cmipci_t *cm, unsigned int cmd)
+static inline unsigned char snd_cmipci_read_b(cmipci_t *cm, unsigned int cmd)
 {
        return inb(cm->iobase + cmd);
 }
 
 /* bit operations for dword register */
-static void snd_cmipci_set_bit(cmipci_t *cm, unsigned int cmd, unsigned int flag)
+static int snd_cmipci_set_bit(cmipci_t *cm, unsigned int cmd, unsigned int flag)
 {
-       unsigned int val;
-       val = inl(cm->iobase + cmd);
+       unsigned int val, oval;
+       val = oval = inl(cm->iobase + cmd);
        val |= flag;
+       if (val == oval)
+               return 0;
        outl(val, cm->iobase + cmd);
+       return 1;
 }
 
-static void snd_cmipci_clear_bit(cmipci_t *cm, unsigned int cmd, unsigned int flag)
+static int snd_cmipci_clear_bit(cmipci_t *cm, unsigned int cmd, unsigned int flag)
 {
-       unsigned int val;
-       val = inl(cm->iobase + cmd);
+       unsigned int val, oval;
+       val = oval = inl(cm->iobase + cmd);
        val &= ~flag;
+       if (val == oval)
+               return 0;
        outl(val, cm->iobase + cmd);
+       return 1;
 }
 
-#if 0 // not used
 /* bit operations for byte register */
-static void snd_cmipci_set_bit_b(cmipci_t *cm, unsigned int cmd, unsigned char flag)
+static int snd_cmipci_set_bit_b(cmipci_t *cm, unsigned int cmd, unsigned char flag)
 {
-       unsigned char val;
-       val = inb(cm->iobase + cmd);
+       unsigned char val, oval;
+       val = oval = inb(cm->iobase + cmd);
        val |= flag;
+       if (val == oval)
+               return 0;
        outb(val, cm->iobase + cmd);
+       return 1;
 }
 
-static void snd_cmipci_clear_bit_b(cmipci_t *cm, unsigned int cmd, unsigned char flag)
+static int snd_cmipci_clear_bit_b(cmipci_t *cm, unsigned int cmd, unsigned char flag)
 {
-       unsigned char val;
-       val = inb(cm->iobase + cmd);
+       unsigned char val, oval;
+       val = oval = inb(cm->iobase + cmd);
        val &= ~flag;
+       if (val == oval)
+               return 0;
        outb(val, cm->iobase + cmd);
+       return 1;
 }
-#endif
 
 
 /*
@@ -1016,7 +1003,7 @@ static int snd_cmipci_spdif_mask_get(snd_kcontrol_t * kcontrol,
 static snd_kcontrol_new_t snd_cmipci_spdif_mask __devinitdata =
 {
        .access =       SNDRV_CTL_ELEM_ACCESS_READ,
-       .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
        .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
        .info =         snd_cmipci_spdif_mask_info,
        .get =          snd_cmipci_spdif_mask_get,
@@ -2123,8 +2110,12 @@ static snd_kcontrol_new_t snd_cmipci_mixers[] __devinitdata = {
        CMIPCI_MIXER_VOL_STEREO("Aux Playback Volume", CM_REG_AUX_VOL, 4, 0, 15),
        CMIPCI_MIXER_SW_STEREO("Aux Playback Switch", CM_REG_MIXER2, CM_VAUXLM_SHIFT, CM_VAUXRM_SHIFT, 0),
        CMIPCI_MIXER_SW_STEREO("Aux Capture Switch", CM_REG_MIXER2, CM_RAUXLEN_SHIFT, CM_RAUXREN_SHIFT, 0),
-       CMIPCI_MIXER_SW_MONO("Mic Boost", CM_REG_MIXER2, CM_MICGAINZ_SHIFT, 1),
+       CMIPCI_MIXER_SW_MONO("Mic Boost Playback Switch", CM_REG_MIXER2, CM_MICGAINZ_SHIFT, 1),
        CMIPCI_MIXER_VOL_MONO("Mic Capture Volume", CM_REG_MIXER2, CM_VADMIC_SHIFT, 7),
+       CMIPCI_SB_VOL_MONO("Phone Playback Volume", CM_REG_EXTENT_IND, 5, 7),
+       CMIPCI_DOUBLE("Phone Playback Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 4, 4, 1, 0, 0),
+       CMIPCI_DOUBLE("PC Speaker Playnack Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 3, 3, 1, 0, 0),
+       CMIPCI_DOUBLE("Mic Boost Capture Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 0, 0, 1, 0, 0),
 };
 
 /*
@@ -2250,8 +2241,8 @@ DEFINE_SWITCH_ARG(exchange_dac, CM_REG_MISC_CTRL, CM_XCHGDAC, 0, 0, 0); /* rever
 DEFINE_SWITCH_ARG(exchange_dac, CM_REG_MISC_CTRL, CM_XCHGDAC, CM_XCHGDAC, 0, 0);
 #endif
 DEFINE_BIT_SWITCH_ARG(fourch, CM_REG_MISC_CTRL, CM_N4SPK3D, 0, 0);
-DEFINE_BIT_SWITCH_ARG(line_rear, CM_REG_MIXER1, CM_SPK4, 1, 0);
-DEFINE_BIT_SWITCH_ARG(line_bass, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS, 0, 0);
+// DEFINE_BIT_SWITCH_ARG(line_rear, CM_REG_MIXER1, CM_SPK4, 1, 0);
+// DEFINE_BIT_SWITCH_ARG(line_bass, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS, 0, 0);
 // DEFINE_BIT_SWITCH_ARG(joystick, CM_REG_FUNCTRL1, CM_JYSTK_EN, 0, 0); /* now module option */
 DEFINE_SWITCH_ARG(modem, CM_REG_MISC_CTRL, CM_FLINKON|CM_FLINKOFF, CM_FLINKON, 0, 0);
 
@@ -2300,10 +2291,114 @@ static int snd_cmipci_spdout_enable_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_v
 }
 
 
+static int snd_cmipci_line_in_mode_info(snd_kcontrol_t *kcontrol,
+                                       snd_ctl_elem_info_t *uinfo)
+{
+       cmipci_t *cm = snd_kcontrol_chip(kcontrol);
+       static char *texts[3] = { "Line-In", "Rear Output", "Bass Output" };
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = cm->chip_version >= 39 ? 3 : 2;
+       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+               uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+       return 0;
+}
+
+static inline unsigned int get_line_in_mode(cmipci_t *cm)
+{
+       unsigned int val;
+       if (cm->chip_version >= 39) {
+               val = snd_cmipci_read(cm, CM_REG_LEGACY_CTRL);
+               if (val & CM_LINE_AS_BASS)
+                       return 2;
+       }
+       val = snd_cmipci_read_b(cm, CM_REG_MIXER1);
+       if (val & CM_SPK4)
+               return 1;
+       return 0;
+}
+
+static int snd_cmipci_line_in_mode_get(snd_kcontrol_t *kcontrol,
+                                      snd_ctl_elem_value_t *ucontrol)
+{
+       cmipci_t *cm = snd_kcontrol_chip(kcontrol);
+
+       spin_lock_irq(&cm->reg_lock);
+       ucontrol->value.enumerated.item[0] = get_line_in_mode(cm);
+       spin_unlock_irq(&cm->reg_lock);
+       return 0;
+}
+
+static int snd_cmipci_line_in_mode_put(snd_kcontrol_t *kcontrol,
+                                      snd_ctl_elem_value_t *ucontrol)
+{
+       cmipci_t *cm = snd_kcontrol_chip(kcontrol);
+       int change;
+
+       spin_lock_irq(&cm->reg_lock);
+       if (ucontrol->value.enumerated.item[0] == 2)
+               change = snd_cmipci_set_bit(cm, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS);
+       else
+               change = snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS);
+       if (ucontrol->value.enumerated.item[0] == 1)
+               change |= snd_cmipci_set_bit_b(cm, CM_REG_MIXER1, CM_SPK4);
+       else
+               change |= snd_cmipci_clear_bit_b(cm, CM_REG_MIXER1, CM_SPK4);
+       spin_unlock_irq(&cm->reg_lock);
+       return change;
+}
+
+static int snd_cmipci_mic_in_mode_info(snd_kcontrol_t *kcontrol,
+                                      snd_ctl_elem_info_t *uinfo)
+{
+       static char *texts[2] = { "Mic-In", "Center/LFE Output" };
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = 2;
+       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+               uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+       return 0;
+}
+
+static int snd_cmipci_mic_in_mode_get(snd_kcontrol_t *kcontrol,
+                                     snd_ctl_elem_value_t *ucontrol)
+{
+       cmipci_t *cm = snd_kcontrol_chip(kcontrol);
+       /* same bit as spdi_phase */
+       spin_lock_irq(&cm->reg_lock);
+       ucontrol->value.enumerated.item[0] = 
+               (snd_cmipci_read_b(cm, CM_REG_MISC) & CM_SPDIF_INVERSE) ? 1 : 0;
+       spin_unlock_irq(&cm->reg_lock);
+       return 0;
+}
+
+static int snd_cmipci_mic_in_mode_put(snd_kcontrol_t *kcontrol,
+                                     snd_ctl_elem_value_t *ucontrol)
+{
+       cmipci_t *cm = snd_kcontrol_chip(kcontrol);
+       int change;
+
+       spin_lock_irq(&cm->reg_lock);
+       if (ucontrol->value.enumerated.item[0])
+               change = snd_cmipci_set_bit_b(cm, CM_REG_MISC, CM_SPDIF_INVERSE);
+       else
+               change = snd_cmipci_clear_bit_b(cm, CM_REG_MISC, CM_SPDIF_INVERSE);
+       spin_unlock_irq(&cm->reg_lock);
+       return change;
+}
+
 /* both for CM8338/8738 */
 static snd_kcontrol_new_t snd_cmipci_mixer_switches[] __devinitdata = {
        DEFINE_MIXER_SWITCH("Four Channel Mode", fourch),
-       DEFINE_MIXER_SWITCH("Line-In As Rear", line_rear),
+       {
+               .name = "Line-In Mode",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .info = snd_cmipci_line_in_mode_info,
+               .get = snd_cmipci_line_in_mode_get,
+               .put = snd_cmipci_line_in_mode_put,
+       },
 };
 
 /* for non-multichannel chips */
@@ -2341,10 +2436,15 @@ static snd_kcontrol_new_t snd_cmipci_old_mixer_switches[] __devinitdata = {
 
 /* only for model 039 or later */
 static snd_kcontrol_new_t snd_cmipci_extra_mixer_switches[] __devinitdata = {
-       DEFINE_MIXER_SWITCH("Line-In As Bass", line_bass),
        DEFINE_MIXER_SWITCH("IEC958 In Select", spdif_in_sel2),
        DEFINE_MIXER_SWITCH("IEC958 In Phase Inverse", spdi_phase2),
-       DEFINE_MIXER_SWITCH("Mic As Center/LFE", spdi_phase), /* same bit as spdi_phase */
+       {
+               .name = "Mic-In Mode",
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .info = snd_cmipci_mic_in_mode_info,
+               .get = snd_cmipci_mic_in_mode_get,
+               .put = snd_cmipci_mic_in_mode_put,
+       }
 };
 
 /* card control switches */
@@ -2675,7 +2775,7 @@ static int __devinit snd_cmipci_create(snd_card_t *card, struct pci_dev *pci,
        if ((err = pci_enable_device(pci)) < 0)
                return err;
 
-       cm = kcalloc(1, sizeof(*cm), GFP_KERNEL);
+       cm = kzalloc(sizeof(*cm), GFP_KERNEL);
        if (cm == NULL) {
                pci_disable_device(pci);
                return -ENOMEM;
@@ -2937,6 +3037,7 @@ static void __devexit snd_cmipci_remove(struct pci_dev *pci)
 
 static struct pci_driver driver = {
        .name = "C-Media PCI",
+       .owner = THIS_MODULE,
        .id_table = snd_cmipci_ids,
        .probe = snd_cmipci_probe,
        .remove = __devexit_p(snd_cmipci_remove),
@@ -2944,7 +3045,7 @@ static struct pci_driver driver = {
        
 static int __init alsa_card_cmipci_init(void)
 {
-       return pci_module_init(&driver);
+       return pci_register_driver(&driver);
 }
 
 static void __exit alsa_card_cmipci_exit(void)