vserver 2.0 rc7
[linux-2.6.git] / sound / pci / cmipci.c
index 17fbed0..113208f 100644 (file)
@@ -156,6 +156,8 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address.");
 #define CM_CHIP_MASK2          0xff000000
 #define CM_CHIP_039            0x04000000
 #define CM_CHIP_039_6CH                0x01000000
+#define CM_CHIP_055            0x08000000
+#define CM_CHIP_8768           0x20000000
 #define CM_TDMA_INT_EN         0x00040000
 #define CM_CH1_INT_EN          0x00020000
 #define CM_CH0_INT_EN          0x00010000
@@ -328,6 +330,13 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address.");
 #define CM_REG_CH0_FRAME2      0x84
 #define CM_REG_CH1_FRAME1      0x88    /* 0-15: count of samples at bus master; buffer size */
 #define CM_REG_CH1_FRAME2      0x8C    /* 16-31: count of samples at codec; fragment size */
+#define CM_REG_MISC_CTRL_8768  0x92    /* reg. name the same as 0x18 */
+#define CM_CHB3D8C             0x20    /* 7.1 channels support */
+#define CM_SPD32FMT            0x10    /* SPDIF/IN 32k */
+#define CM_ADC2SPDIF           0x08    /* ADC output to SPDIF/OUT */
+#define CM_SHAREADC            0x04    /* DAC in ADC as Center/LFE */
+#define CM_REALTCMP            0x02    /* monitor the CMPL/CMPR of ADC */
+#define CM_INVLRCK             0x01    /* invert ZVPORT's LRCK */
 
 /*
  * size of i/o region
@@ -458,7 +467,7 @@ struct snd_stru_cmipci {
        int opened[2];  /* open mode */
        struct semaphore open_mutex;
 
-       int mixer_insensitive: 1;
+       unsigned int mixer_insensitive: 1;
        snd_kcontrol_t *mixer_res_ctl[CM_SAVED_MIXERS];
        int mixer_res_status[CM_SAVED_MIXERS];
 
@@ -471,8 +480,7 @@ struct snd_stru_cmipci {
        snd_rawmidi_t *rmidi;
 
 #ifdef SUPPORT_JOYSTICK
-       struct gameport gameport;
-       struct resource *res_joystick;
+       struct gameport *gameport;
 #endif
 
        spinlock_t reg_lock;
@@ -674,7 +682,7 @@ static int snd_cmipci_hw_free(snd_pcm_substream_t * substream)
 /*
  */
 
-static unsigned int hw_channels[] = {1, 2, 4, 5, 6};
+static unsigned int hw_channels[] = {1, 2, 4, 5, 6, 8};
 static snd_pcm_hw_constraint_list_t hw_constraints_channels_4 = {
        .count = 3,
        .list = hw_channels,
@@ -685,6 +693,11 @@ static snd_pcm_hw_constraint_list_t hw_constraints_channels_6 = {
        .list = hw_channels,
        .mask = 0,
 };
+static snd_pcm_hw_constraint_list_t hw_constraints_channels_8 = {
+       .count = 6,
+       .list = hw_channels,
+       .mask = 0,
+};
 
 static int set_dac_channels(cmipci_t *cm, cmipci_pcm_t *rec, int channels)
 {
@@ -704,13 +717,20 @@ static int set_dac_channels(cmipci_t *cm, cmipci_pcm_t *rec, int channels)
                        snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_CHB3D5C);
                        snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_CHB3D);
                }
-               if (channels == 6) {
+               if (channels >= 6) {
                        snd_cmipci_set_bit(cm, CM_REG_LEGACY_CTRL, CM_CHB3D6C);
                        snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_ENCENTER);
                } else {
                        snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_CHB3D6C);
                        snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_ENCENTER);
                }
+               if (cm->chip_version == 68) {
+                       if (channels == 8) {
+                               snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL_8768, CM_CHB3D8C);
+                       } else {
+                               snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL_8768, CM_CHB3D8C);
+                       }
+               }
                spin_unlock_irq(&cm->reg_lock);
 
        } else {
@@ -1504,6 +1524,7 @@ static int snd_cmipci_playback_open(snd_pcm_substream_t *substream)
        if ((err = open_device_check(cm, CM_OPEN_PLAYBACK, substream)) < 0)
                return err;
        runtime->hw = snd_cmipci_playback;
+       runtime->hw.channels_max = cm->max_channels;
        snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000);
        cm->dig_pcm_status = cm->dig_status;
        return 0;
@@ -1518,6 +1539,10 @@ static int snd_cmipci_capture_open(snd_pcm_substream_t *substream)
        if ((err = open_device_check(cm, CM_OPEN_CAPTURE, substream)) < 0)
                return err;
        runtime->hw = snd_cmipci_capture;
+       if (cm->chip_version == 68) {   // 8768 only supports 44k/48k recording
+               runtime->hw.rate_min = 41000;
+               runtime->hw.rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000;
+       }
        snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000);
        return 0;
 }
@@ -1537,8 +1562,10 @@ static int snd_cmipci_playback2_open(snd_pcm_substream_t *substream)
                        runtime->hw.channels_max = cm->max_channels;
                        if (cm->max_channels == 4)
                                snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels_4);
-                       else
+                       else if (cm->max_channels == 6)
                                snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels_6);
+                       else if (cm->max_channels == 8)
+                               snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels_8);
                }
                snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000);
        }
@@ -2108,8 +2135,8 @@ typedef struct snd_cmipci_switch_args {
        int reg;                /* register index */
        unsigned int mask;      /* mask bits */
        unsigned int mask_on;   /* mask bits to turn on */
-       int is_byte: 1;         /* byte access? */
-       int ac3_sensitive: 1;   /* access forbidden during non-audio operation? */
+       unsigned int is_byte: 1;                /* byte access? */
+       unsigned int ac3_sensitive: 1;  /* access forbidden during non-audio operation? */
 } snd_cmipci_switch_args_t;
 
 static int snd_cmipci_uswitch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
@@ -2346,6 +2373,11 @@ static int __devinit snd_cmipci_mixer_new(cmipci_t *cm, int pcm_spdif_device)
        spin_unlock_irq(&cm->reg_lock);
 
        for (idx = 0; idx < ARRAY_SIZE(snd_cmipci_mixers); idx++) {
+               if (cm->chip_version == 68) {   // 8768 has no PCM volume
+                       if (!strcmp(snd_cmipci_mixers[idx].name,
+                               "PCM Playback Volume"))
+                               continue;
+               }
                if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cmipci_mixers[idx], cm))) < 0)
                        return err;
        }
@@ -2496,32 +2528,98 @@ static void __devinit query_chip(cmipci_t *cm)
                }
        } else {
                /* check reg 0Ch, bit 26 */
-               if (detect & CM_CHIP_039) {
+               if (detect & CM_CHIP_8768) {
+                       cm->chip_version = 68;
+                       cm->max_channels = 8;
+                       cm->can_ac3_hw = 1;
+                       cm->has_dual_dac = 1;
+                       cm->can_multi_ch = 1;
+               } else if (detect & CM_CHIP_055) {
+                       cm->chip_version = 55;
+                       cm->max_channels = 6;
+                       cm->can_ac3_hw = 1;
+                       cm->has_dual_dac = 1;
+                       cm->can_multi_ch = 1;
+               } else if (detect & CM_CHIP_039) {
                        cm->chip_version = 39;
-                       if (detect & CM_CHIP_039_6CH)
-                               cm->max_channels  = 6;
+                       if (detect & CM_CHIP_039_6CH) /* 4 or 6 channels */
+                               cm->max_channels = 6;
                        else
                                cm->max_channels = 4;
                        cm->can_ac3_hw = 1;
                        cm->has_dual_dac = 1;
                        cm->can_multi_ch = 1;
                } else {
-                       cm->chip_version = 55; /* 4 or 6 channels */
-                       cm->max_channels  = 6;
-                       cm->can_ac3_hw = 1;
-                       cm->has_dual_dac = 1;
-                       cm->can_multi_ch = 1;
+                       printk(KERN_ERR "chip %x version not supported\n", detect);
                }
        }
+}
 
-       /* added -MCx suffix for chip supporting multi-channels */
-       if (cm->can_multi_ch)
-               sprintf(cm->card->driver + strlen(cm->card->driver),
-                       "-MC%d", cm->max_channels);
-       else if (cm->can_ac3_sw)
-               strcpy(cm->card->driver + strlen(cm->card->driver), "-SWIEC");
+#ifdef SUPPORT_JOYSTICK
+static int __devinit snd_cmipci_create_gameport(cmipci_t *cm, int dev)
+{
+       static int ports[] = { 0x201, 0x200, 0 }; /* FIXME: majority is 0x201? */
+       struct gameport *gp;
+       struct resource *r = NULL;
+       int i, io_port = 0;
+
+       if (joystick_port[dev] == 0)
+               return -ENODEV;
+
+       if (joystick_port[dev] == 1) { /* auto-detect */
+               for (i = 0; ports[i]; i++) {
+                       io_port = ports[i];
+                       r = request_region(io_port, 1, "CMIPCI gameport");
+                       if (r)
+                               break;
+               }
+       } else {
+               io_port = joystick_port[dev];
+               r = request_region(io_port, 1, "CMIPCI gameport");
+       }
+
+       if (!r) {
+               printk(KERN_WARNING "cmipci: cannot reserve joystick ports\n");
+               return -EBUSY;
+       }
+
+       cm->gameport = gp = gameport_allocate_port();
+       if (!gp) {
+               printk(KERN_ERR "cmipci: cannot allocate memory for gameport\n");
+               release_resource(r);
+               kfree_nocheck(r);
+               return -ENOMEM;
+       }
+       gameport_set_name(gp, "C-Media Gameport");
+       gameport_set_phys(gp, "pci%s/gameport0", pci_name(cm->pci));
+       gameport_set_dev_parent(gp, &cm->pci->dev);
+       gp->io = io_port;
+       gameport_set_port_data(gp, r);
+
+       snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_JYSTK_EN);
+
+       gameport_register_port(cm->gameport);
+
+       return 0;
 }
 
+static void snd_cmipci_free_gameport(cmipci_t *cm)
+{
+       if (cm->gameport) {
+               struct resource *r = gameport_get_port_data(cm->gameport);
+
+               gameport_unregister_port(cm->gameport);
+               cm->gameport = NULL;
+
+               snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_JYSTK_EN);
+               release_resource(r);
+               kfree_nocheck(r);
+       }
+}
+#else
+static inline int snd_cmipci_create_gameport(cmipci_t *cm, int dev) { return -ENOSYS; }
+static inline void snd_cmipci_free_gameport(cmipci_t *cm) { }
+#endif
 
 static int snd_cmipci_free(cmipci_t *cm)
 {
@@ -2541,14 +2639,8 @@ static int snd_cmipci_free(cmipci_t *cm)
 
                free_irq(cm->irq, (void *)cm);
        }
-#ifdef SUPPORT_JOYSTICK
-       if (cm->res_joystick) {
-               gameport_unregister_port(&cm->gameport);
-               snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_JYSTK_EN);
-               release_resource(cm->res_joystick);
-               kfree_nocheck(cm->res_joystick);
-       }
-#endif
+
+       snd_cmipci_free_gameport(cm);
        pci_release_regions(cm->pci);
        pci_disable_device(cm->pci);
        kfree(cm);
@@ -2623,7 +2715,15 @@ static int __devinit snd_cmipci_create(snd_card_t *card, struct pci_dev *pci,
        cm->max_channels = 2;
        cm->do_soft_ac3 = soft_ac3[dev];
 
-       query_chip(cm);
+       if (pci->device != PCI_DEVICE_ID_CMEDIA_CM8338A &&
+           pci->device != PCI_DEVICE_ID_CMEDIA_CM8338B)
+               query_chip(cm);
+       /* added -MCx suffix for chip supporting multi-channels */
+       if (cm->can_multi_ch)
+               sprintf(cm->card->driver + strlen(cm->card->driver),
+                       "-MC%d", cm->max_channels);
+       else if (cm->can_ac3_sw)
+               strcpy(cm->card->driver + strlen(cm->card->driver), "-SWIEC");
 
        cm->dig_status = SNDRV_PCM_DEFAULT_CON_SPDIF;
        cm->dig_pcm_status = SNDRV_PCM_DEFAULT_CON_SPDIF;
@@ -2757,31 +2857,9 @@ static int __devinit snd_cmipci_create(snd_card_t *card, struct pci_dev *pci,
        snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_SPDIF48K|CM_SPDF_AC97);
 #endif /* USE_VAR48KRATE */
 
-#ifdef SUPPORT_JOYSTICK
-       if (joystick_port[dev] > 0) {
-               if (joystick_port[dev] == 1) { /* auto-detect */
-                       static int ports[] = { 0x201, 0x200, 0 }; /* FIXME: majority is 0x201? */
-                       int i;
-                       for (i = 0; ports[i]; i++) {
-                               joystick_port[dev] = ports[i];
-                               cm->res_joystick = request_region(ports[i], 1, "CMIPCI gameport");
-                               if (cm->res_joystick)
-                                       break;
-                       }
-               } else {
-                       cm->res_joystick = request_region(joystick_port[dev], 1, "CMIPCI gameport");
-               }
-       }
-       if (cm->res_joystick) {
-               cm->gameport.io = joystick_port[dev];
-               snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_JYSTK_EN);
-               gameport_register_port(&cm->gameport);
-       } else {
-               if (joystick_port[dev] > 0)
-                       printk(KERN_WARNING "cmipci: cannot reserve joystick ports\n");
+       if (snd_cmipci_create_gameport(cm, dev) < 0)
                snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_JYSTK_EN);
-       }
-#endif
+
        snd_card_set_dev(card, &pci->dev);
 
        *rcmipci = cm;