diff options
author | Krzysztof Helt <krzysztof.h1@wp.pl> | 2009-09-27 17:08:40 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-09-28 05:31:36 -0400 |
commit | f0968e3f7a8ea30728d2580d3043a30ea9994ec6 (patch) | |
tree | 4e9adca4a7b7b33e8497eeb5c21935f0538f7624 /sound/isa/sscape.c | |
parent | 4f272341c7a42a71586523f196b242bccde3be8c (diff) |
ALSA: sscape: add supoort for SPEA Media FX/Reveal SC-600
Move code from the OSS sscape driver in order to support old Soundscape OEM models.
Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/isa/sscape.c')
-rw-r--r-- | sound/isa/sscape.c | 116 |
1 files changed, 82 insertions, 34 deletions
diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index 66187122377c..b11c35f6aefe 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c | |||
@@ -127,7 +127,8 @@ enum GA_REG { | |||
127 | 127 | ||
128 | 128 | ||
129 | enum card_type { | 129 | enum card_type { |
130 | SSCAPE, | 130 | MEDIA_FX, /* Sequoia S-1000 */ |
131 | SSCAPE, /* Sequoia S-2000 */ | ||
131 | SSCAPE_PNP, | 132 | SSCAPE_PNP, |
132 | SSCAPE_VIVO, | 133 | SSCAPE_VIVO, |
133 | }; | 134 | }; |
@@ -784,20 +785,25 @@ static struct snd_kcontrol_new midi_mixer_ctl = { | |||
784 | * These IRQs are encoded as bit patterns so that they can be | 785 | * These IRQs are encoded as bit patterns so that they can be |
785 | * written to the control registers. | 786 | * written to the control registers. |
786 | */ | 787 | */ |
787 | static unsigned __devinit get_irq_config(int irq) | 788 | static unsigned __devinit get_irq_config(int sscape_type, int irq) |
788 | { | 789 | { |
789 | static const int valid_irq[] = { 9, 5, 7, 10 }; | 790 | static const int valid_irq[] = { 9, 5, 7, 10 }; |
791 | static const int old_irq[] = { 9, 7, 5, 15 }; | ||
790 | unsigned cfg; | 792 | unsigned cfg; |
791 | 793 | ||
792 | for (cfg = 0; cfg < ARRAY_SIZE(valid_irq); ++cfg) { | 794 | if (sscape_type == MEDIA_FX) { |
793 | if (irq == valid_irq[cfg]) | 795 | for (cfg = 0; cfg < ARRAY_SIZE(old_irq); ++cfg) |
794 | return cfg; | 796 | if (irq == old_irq[cfg]) |
795 | } /* for */ | 797 | return cfg; |
798 | } else { | ||
799 | for (cfg = 0; cfg < ARRAY_SIZE(valid_irq); ++cfg) | ||
800 | if (irq == valid_irq[cfg]) | ||
801 | return cfg; | ||
802 | } | ||
796 | 803 | ||
797 | return INVALID_IRQ; | 804 | return INVALID_IRQ; |
798 | } | 805 | } |
799 | 806 | ||
800 | |||
801 | /* | 807 | /* |
802 | * Perform certain arcane port-checks to see whether there | 808 | * Perform certain arcane port-checks to see whether there |
803 | * is a SoundScape board lurking behind the given ports. | 809 | * is a SoundScape board lurking behind the given ports. |
@@ -842,11 +848,39 @@ static int __devinit detect_sscape(struct soundscape *s, long wss_io) | |||
842 | if (s->type != SSCAPE_VIVO && (d & 0x9f) != 0x0e) | 848 | if (s->type != SSCAPE_VIVO && (d & 0x9f) != 0x0e) |
843 | goto _done; | 849 | goto _done; |
844 | 850 | ||
845 | d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f; | 851 | if (s->ic_type == IC_OPUS) |
846 | sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0); | 852 | activate_ad1845_unsafe(s->io_base); |
847 | 853 | ||
848 | if (s->type == SSCAPE_VIVO) | 854 | if (s->type == SSCAPE_VIVO) |
849 | wss_io += 4; | 855 | wss_io += 4; |
856 | |||
857 | d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f; | ||
858 | sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0); | ||
859 | |||
860 | /* wait for WSS codec */ | ||
861 | for (d = 0; d < 500; d++) { | ||
862 | if ((inb(wss_io) & 0x80) == 0) | ||
863 | break; | ||
864 | spin_unlock_irqrestore(&s->lock, flags); | ||
865 | msleep(1); | ||
866 | spin_lock_irqsave(&s->lock, flags); | ||
867 | } | ||
868 | snd_printd(KERN_INFO "init delay = %d ms\n", d); | ||
869 | |||
870 | if ((inb(wss_io) & 0x80) != 0) | ||
871 | goto _done; | ||
872 | |||
873 | if (inb(wss_io + 2) == 0xff) | ||
874 | goto _done; | ||
875 | |||
876 | d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f; | ||
877 | sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d); | ||
878 | |||
879 | if ((inb(wss_io) & 0x80) != 0) | ||
880 | s->type = MEDIA_FX; | ||
881 | |||
882 | d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f; | ||
883 | sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0); | ||
850 | /* wait for WSS codec */ | 884 | /* wait for WSS codec */ |
851 | for (d = 0; d < 500; d++) { | 885 | for (d = 0; d < 500; d++) { |
852 | if ((inb(wss_io) & 0x80) == 0) | 886 | if ((inb(wss_io) & 0x80) == 0) |
@@ -954,9 +988,6 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port, | |||
954 | if (sscape->type == SSCAPE_VIVO) | 988 | if (sscape->type == SSCAPE_VIVO) |
955 | port += 4; | 989 | port += 4; |
956 | 990 | ||
957 | if (dma1 == dma2) | ||
958 | dma2 = -1; | ||
959 | |||
960 | err = snd_wss_create(card, port, -1, irq, dma1, dma2, | 991 | err = snd_wss_create(card, port, -1, irq, dma1, dma2, |
961 | WSS_HW_DETECT, WSS_HWSHARE_DMA1, &chip); | 992 | WSS_HW_DETECT, WSS_HWSHARE_DMA1, &chip); |
962 | if (!err) { | 993 | if (!err) { |
@@ -1051,21 +1082,7 @@ static int __devinit create_sscape(int dev, struct snd_card *card) | |||
1051 | struct resource *wss_res; | 1082 | struct resource *wss_res; |
1052 | unsigned long flags; | 1083 | unsigned long flags; |
1053 | int err; | 1084 | int err; |
1054 | 1085 | const char *name; | |
1055 | /* | ||
1056 | * Check that the user didn't pass us garbage data ... | ||
1057 | */ | ||
1058 | irq_cfg = get_irq_config(irq[dev]); | ||
1059 | if (irq_cfg == INVALID_IRQ) { | ||
1060 | snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", irq[dev]); | ||
1061 | return -ENXIO; | ||
1062 | } | ||
1063 | |||
1064 | mpu_irq_cfg = get_irq_config(mpu_irq[dev]); | ||
1065 | if (mpu_irq_cfg == INVALID_IRQ) { | ||
1066 | printk(KERN_ERR "sscape: Invalid IRQ %d\n", mpu_irq[dev]); | ||
1067 | return -ENXIO; | ||
1068 | } | ||
1069 | 1086 | ||
1070 | /* | 1087 | /* |
1071 | * Grab IO ports that we will need to probe so that we | 1088 | * Grab IO ports that we will need to probe so that we |
@@ -1109,8 +1126,41 @@ static int __devinit create_sscape(int dev, struct snd_card *card) | |||
1109 | goto _release_dma; | 1126 | goto _release_dma; |
1110 | } | 1127 | } |
1111 | 1128 | ||
1112 | printk(KERN_INFO "sscape: hardware detected at 0x%x, using IRQ %d, DMA %d\n", | 1129 | switch (sscape->type) { |
1113 | sscape->io_base, irq[dev], dma[dev]); | 1130 | case MEDIA_FX: |
1131 | name = "MediaFX/SoundFX"; | ||
1132 | break; | ||
1133 | case SSCAPE: | ||
1134 | name = "Soundscape"; | ||
1135 | break; | ||
1136 | case SSCAPE_PNP: | ||
1137 | name = "Soundscape PnP"; | ||
1138 | break; | ||
1139 | case SSCAPE_VIVO: | ||
1140 | name = "Soundscape VIVO"; | ||
1141 | break; | ||
1142 | default: | ||
1143 | name = "unknown Soundscape"; | ||
1144 | break; | ||
1145 | } | ||
1146 | |||
1147 | printk(KERN_INFO "sscape: %s card detected at 0x%x, using IRQ %d, DMA %d\n", | ||
1148 | name, sscape->io_base, irq[dev], dma[dev]); | ||
1149 | |||
1150 | /* | ||
1151 | * Check that the user didn't pass us garbage data ... | ||
1152 | */ | ||
1153 | irq_cfg = get_irq_config(sscape->type, irq[dev]); | ||
1154 | if (irq_cfg == INVALID_IRQ) { | ||
1155 | snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", irq[dev]); | ||
1156 | return -ENXIO; | ||
1157 | } | ||
1158 | |||
1159 | mpu_irq_cfg = get_irq_config(sscape->type, mpu_irq[dev]); | ||
1160 | if (mpu_irq_cfg == INVALID_IRQ) { | ||
1161 | printk(KERN_ERR "sscape: Invalid IRQ %d\n", mpu_irq[dev]); | ||
1162 | return -ENXIO; | ||
1163 | } | ||
1114 | 1164 | ||
1115 | if (sscape->type != SSCAPE_VIVO) { | 1165 | if (sscape->type != SSCAPE_VIVO) { |
1116 | /* | 1166 | /* |
@@ -1141,8 +1191,6 @@ static int __devinit create_sscape(int dev, struct snd_card *card) | |||
1141 | */ | 1191 | */ |
1142 | spin_lock_irqsave(&sscape->lock, flags); | 1192 | spin_lock_irqsave(&sscape->lock, flags); |
1143 | 1193 | ||
1144 | activate_ad1845_unsafe(sscape->io_base); | ||
1145 | |||
1146 | sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x00); /* disable */ | 1194 | sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x00); /* disable */ |
1147 | sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2e); | 1195 | sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2e); |
1148 | sscape_write_unsafe(sscape->io_base, GA_SMCFGB_REG, 0x00); | 1196 | sscape_write_unsafe(sscape->io_base, GA_SMCFGB_REG, 0x00); |
@@ -1151,12 +1199,12 @@ static int __devinit create_sscape(int dev, struct snd_card *card) | |||
1151 | * Enable and configure the DMA channels ... | 1199 | * Enable and configure the DMA channels ... |
1152 | */ | 1200 | */ |
1153 | sscape_write_unsafe(sscape->io_base, GA_DMACFG_REG, 0x50); | 1201 | sscape_write_unsafe(sscape->io_base, GA_DMACFG_REG, 0x50); |
1154 | dma_cfg = (sscape->ic_type == IC_ODIE ? 0x70 : 0x40); | 1202 | dma_cfg = (sscape->ic_type == IC_OPUS ? 0x40 : 0x70); |
1155 | sscape_write_unsafe(sscape->io_base, GA_DMAA_REG, dma_cfg); | 1203 | sscape_write_unsafe(sscape->io_base, GA_DMAA_REG, dma_cfg); |
1156 | sscape_write_unsafe(sscape->io_base, GA_DMAB_REG, 0x20); | 1204 | sscape_write_unsafe(sscape->io_base, GA_DMAB_REG, 0x20); |
1157 | 1205 | ||
1158 | sscape_write_unsafe(sscape->io_base, | 1206 | mpu_irq_cfg |= mpu_irq_cfg << 2; |
1159 | GA_INTCFG_REG, 0xf0 | (mpu_irq_cfg << 2) | mpu_irq_cfg); | 1207 | sscape_write_unsafe(sscape->io_base, GA_INTCFG_REG, 0xf0 | mpu_irq_cfg); |
1160 | sscape_write_unsafe(sscape->io_base, | 1208 | sscape_write_unsafe(sscape->io_base, |
1161 | GA_CDCFG_REG, 0x09 | DMA_8BIT | 1209 | GA_CDCFG_REG, 0x09 | DMA_8BIT |
1162 | | (dma[dev] << 4) | (irq_cfg << 1)); | 1210 | | (dma[dev] << 4) | (irq_cfg << 1)); |