diff options
Diffstat (limited to 'sound')
417 files changed, 23255 insertions, 7771 deletions
diff --git a/sound/aoa/aoa.h b/sound/aoa/aoa.h index 541b908f3cdf..e08789484e30 100644 --- a/sound/aoa/aoa.h +++ b/sound/aoa/aoa.h | |||
@@ -10,8 +10,6 @@ | |||
10 | #define __AOA_H | 10 | #define __AOA_H |
11 | #include <asm/prom.h> | 11 | #include <asm/prom.h> |
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | /* So apparently there's a reason for requiring driver.h to be included first! */ | ||
14 | #include <sound/driver.h> | ||
15 | #include <sound/core.h> | 13 | #include <sound/core.h> |
16 | #include <sound/asound.h> | 14 | #include <sound/asound.h> |
17 | #include <sound/control.h> | 15 | #include <sound/control.h> |
diff --git a/sound/aoa/codecs/snd-aoa-codec-onyx.c b/sound/aoa/codecs/snd-aoa-codec-onyx.c index 71e3f9360658..6a3837d480e5 100644 --- a/sound/aoa/codecs/snd-aoa-codec-onyx.c +++ b/sound/aoa/codecs/snd-aoa-codec-onyx.c | |||
@@ -138,6 +138,13 @@ static int onyx_snd_vol_put(struct snd_kcontrol *kcontrol, | |||
138 | struct onyx *onyx = snd_kcontrol_chip(kcontrol); | 138 | struct onyx *onyx = snd_kcontrol_chip(kcontrol); |
139 | s8 l, r; | 139 | s8 l, r; |
140 | 140 | ||
141 | if (ucontrol->value.integer.value[0] < -128 + VOLUME_RANGE_SHIFT || | ||
142 | ucontrol->value.integer.value[0] > -1 + VOLUME_RANGE_SHIFT) | ||
143 | return -EINVAL; | ||
144 | if (ucontrol->value.integer.value[1] < -128 + VOLUME_RANGE_SHIFT || | ||
145 | ucontrol->value.integer.value[1] > -1 + VOLUME_RANGE_SHIFT) | ||
146 | return -EINVAL; | ||
147 | |||
141 | mutex_lock(&onyx->mutex); | 148 | mutex_lock(&onyx->mutex); |
142 | onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, &l); | 149 | onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, &l); |
143 | onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, &r); | 150 | onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, &r); |
@@ -206,6 +213,9 @@ static int onyx_snd_inputgain_put(struct snd_kcontrol *kcontrol, | |||
206 | struct onyx *onyx = snd_kcontrol_chip(kcontrol); | 213 | struct onyx *onyx = snd_kcontrol_chip(kcontrol); |
207 | u8 v, n; | 214 | u8 v, n; |
208 | 215 | ||
216 | if (ucontrol->value.integer.value[0] < 3 + INPUTGAIN_RANGE_SHIFT || | ||
217 | ucontrol->value.integer.value[0] > 28 + INPUTGAIN_RANGE_SHIFT) | ||
218 | return -EINVAL; | ||
209 | mutex_lock(&onyx->mutex); | 219 | mutex_lock(&onyx->mutex); |
210 | onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v); | 220 | onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v); |
211 | n = v; | 221 | n = v; |
@@ -272,6 +282,8 @@ static void onyx_set_capture_source(struct onyx *onyx, int mic) | |||
272 | static int onyx_snd_capture_source_put(struct snd_kcontrol *kcontrol, | 282 | static int onyx_snd_capture_source_put(struct snd_kcontrol *kcontrol, |
273 | struct snd_ctl_elem_value *ucontrol) | 283 | struct snd_ctl_elem_value *ucontrol) |
274 | { | 284 | { |
285 | if (ucontrol->value.enumerated.item[0] > 1) | ||
286 | return -EINVAL; | ||
275 | onyx_set_capture_source(snd_kcontrol_chip(kcontrol), | 287 | onyx_set_capture_source(snd_kcontrol_chip(kcontrol), |
276 | ucontrol->value.enumerated.item[0]); | 288 | ucontrol->value.enumerated.item[0]); |
277 | return 1; | 289 | return 1; |
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.c b/sound/aoa/codecs/snd-aoa-codec-tas.c index 70c341684794..7a16a3331f7e 100644 --- a/sound/aoa/codecs/snd-aoa-codec-tas.c +++ b/sound/aoa/codecs/snd-aoa-codec-tas.c | |||
@@ -248,6 +248,13 @@ static int tas_snd_vol_put(struct snd_kcontrol *kcontrol, | |||
248 | { | 248 | { |
249 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 249 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
250 | 250 | ||
251 | if (ucontrol->value.integer.value[0] < 0 || | ||
252 | ucontrol->value.integer.value[0] > 177) | ||
253 | return -EINVAL; | ||
254 | if (ucontrol->value.integer.value[1] < 0 || | ||
255 | ucontrol->value.integer.value[1] > 177) | ||
256 | return -EINVAL; | ||
257 | |||
251 | mutex_lock(&tas->mtx); | 258 | mutex_lock(&tas->mtx); |
252 | if (tas->cached_volume_l == ucontrol->value.integer.value[0] | 259 | if (tas->cached_volume_l == ucontrol->value.integer.value[0] |
253 | && tas->cached_volume_r == ucontrol->value.integer.value[1]) { | 260 | && tas->cached_volume_r == ucontrol->value.integer.value[1]) { |
@@ -401,6 +408,10 @@ static int tas_snd_drc_range_put(struct snd_kcontrol *kcontrol, | |||
401 | { | 408 | { |
402 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 409 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
403 | 410 | ||
411 | if (ucontrol->value.integer.value[0] < 0 || | ||
412 | ucontrol->value.integer.value[0] > TAS3004_DRC_MAX) | ||
413 | return -EINVAL; | ||
414 | |||
404 | mutex_lock(&tas->mtx); | 415 | mutex_lock(&tas->mtx); |
405 | if (tas->drc_range == ucontrol->value.integer.value[0]) { | 416 | if (tas->drc_range == ucontrol->value.integer.value[0]) { |
406 | mutex_unlock(&tas->mtx); | 417 | mutex_unlock(&tas->mtx); |
@@ -447,7 +458,7 @@ static int tas_snd_drc_switch_put(struct snd_kcontrol *kcontrol, | |||
447 | return 0; | 458 | return 0; |
448 | } | 459 | } |
449 | 460 | ||
450 | tas->drc_enabled = ucontrol->value.integer.value[0]; | 461 | tas->drc_enabled = !!ucontrol->value.integer.value[0]; |
451 | if (tas->hw_enabled) | 462 | if (tas->hw_enabled) |
452 | tas3004_set_drc(tas); | 463 | tas3004_set_drc(tas); |
453 | mutex_unlock(&tas->mtx); | 464 | mutex_unlock(&tas->mtx); |
@@ -494,6 +505,8 @@ static int tas_snd_capture_source_put(struct snd_kcontrol *kcontrol, | |||
494 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 505 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
495 | int oldacr; | 506 | int oldacr; |
496 | 507 | ||
508 | if (ucontrol->value.enumerated.item[0] > 1) | ||
509 | return -EINVAL; | ||
497 | mutex_lock(&tas->mtx); | 510 | mutex_lock(&tas->mtx); |
498 | oldacr = tas->acr; | 511 | oldacr = tas->acr; |
499 | 512 | ||
@@ -562,6 +575,9 @@ static int tas_snd_treble_put(struct snd_kcontrol *kcontrol, | |||
562 | { | 575 | { |
563 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 576 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
564 | 577 | ||
578 | if (ucontrol->value.integer.value[0] < TAS3004_TREBLE_MIN || | ||
579 | ucontrol->value.integer.value[0] > TAS3004_TREBLE_MAX) | ||
580 | return -EINVAL; | ||
565 | mutex_lock(&tas->mtx); | 581 | mutex_lock(&tas->mtx); |
566 | if (tas->treble == ucontrol->value.integer.value[0]) { | 582 | if (tas->treble == ucontrol->value.integer.value[0]) { |
567 | mutex_unlock(&tas->mtx); | 583 | mutex_unlock(&tas->mtx); |
@@ -610,6 +626,9 @@ static int tas_snd_bass_put(struct snd_kcontrol *kcontrol, | |||
610 | { | 626 | { |
611 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 627 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
612 | 628 | ||
629 | if (ucontrol->value.integer.value[0] < TAS3004_BASS_MIN || | ||
630 | ucontrol->value.integer.value[0] > TAS3004_BASS_MAX) | ||
631 | return -EINVAL; | ||
613 | mutex_lock(&tas->mtx); | 632 | mutex_lock(&tas->mtx); |
614 | if (tas->bass == ucontrol->value.integer.value[0]) { | 633 | if (tas->bass == ucontrol->value.integer.value[0]) { |
615 | mutex_unlock(&tas->mtx); | 634 | mutex_unlock(&tas->mtx); |
diff --git a/sound/aoa/fabrics/snd-aoa-fabric-layout.c b/sound/aoa/fabrics/snd-aoa-fabric-layout.c index 8b2ba99d7f8a..dea7abb082cd 100644 --- a/sound/aoa/fabrics/snd-aoa-fabric-layout.c +++ b/sound/aoa/fabrics/snd-aoa-fabric-layout.c | |||
@@ -600,7 +600,7 @@ static int n##_control_put(struct snd_kcontrol *kcontrol, \ | |||
600 | struct gpio_runtime *gpio = snd_kcontrol_chip(kcontrol); \ | 600 | struct gpio_runtime *gpio = snd_kcontrol_chip(kcontrol); \ |
601 | if (gpio->methods && gpio->methods->get_##n) \ | 601 | if (gpio->methods && gpio->methods->get_##n) \ |
602 | gpio->methods->set_##n(gpio, \ | 602 | gpio->methods->set_##n(gpio, \ |
603 | ucontrol->value.integer.value[0]); \ | 603 | !!ucontrol->value.integer.value[0]); \ |
604 | return 1; \ | 604 | return 1; \ |
605 | } \ | 605 | } \ |
606 | static struct snd_kcontrol_new n##_ctl = { \ | 606 | static struct snd_kcontrol_new n##_ctl = { \ |
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-core.c b/sound/aoa/soundbus/i2sbus/i2sbus-core.c index efb9441b3acf..e6beb92c6933 100644 --- a/sound/aoa/soundbus/i2sbus/i2sbus-core.c +++ b/sound/aoa/soundbus/i2sbus/i2sbus-core.c | |||
@@ -11,7 +11,6 @@ | |||
11 | #include <linux/interrupt.h> | 11 | #include <linux/interrupt.h> |
12 | #include <linux/dma-mapping.h> | 12 | #include <linux/dma-mapping.h> |
13 | 13 | ||
14 | #include <sound/driver.h> | ||
15 | #include <sound/core.h> | 14 | #include <sound/core.h> |
16 | 15 | ||
17 | #include <asm/macio.h> | 16 | #include <asm/macio.h> |
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c index c6b42f9bdbc9..59bacd365733 100644 --- a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c +++ b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c | |||
@@ -8,9 +8,6 @@ | |||
8 | 8 | ||
9 | #include <asm/io.h> | 9 | #include <asm/io.h> |
10 | #include <linux/delay.h> | 10 | #include <linux/delay.h> |
11 | /* So apparently there's a reason for requiring driver.h | ||
12 | * to be included first, even if I don't know it... */ | ||
13 | #include <sound/driver.h> | ||
14 | #include <sound/core.h> | 11 | #include <sound/core.h> |
15 | #include <asm/macio.h> | 12 | #include <asm/macio.h> |
16 | #include <linux/pci.h> | 13 | #include <linux/pci.h> |
@@ -194,6 +191,12 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in) | |||
194 | hw->period_bytes_max = 16384; | 191 | hw->period_bytes_max = 16384; |
195 | hw->periods_min = 3; | 192 | hw->periods_min = 3; |
196 | hw->periods_max = MAX_DBDMA_COMMANDS; | 193 | hw->periods_max = MAX_DBDMA_COMMANDS; |
194 | err = snd_pcm_hw_constraint_integer(pi->substream->runtime, | ||
195 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
196 | if (err < 0) { | ||
197 | result = err; | ||
198 | goto out_unlock; | ||
199 | } | ||
197 | list_for_each_entry(cii, &sdev->codec_list, list) { | 200 | list_for_each_entry(cii, &sdev->codec_list, list) { |
198 | if (cii->codec->open) { | 201 | if (cii->codec->open) { |
199 | err = cii->codec->open(cii, pi->substream); | 202 | err = cii->codec->open(cii, pi->substream); |
@@ -990,6 +993,7 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, | |||
990 | if (dev->pcm->card != card) { | 993 | if (dev->pcm->card != card) { |
991 | printk(KERN_ERR | 994 | printk(KERN_ERR |
992 | "Can't attach same bus to different cards!\n"); | 995 | "Can't attach same bus to different cards!\n"); |
996 | err = -EINVAL; | ||
993 | goto out_put_ci_module; | 997 | goto out_put_ci_module; |
994 | } | 998 | } |
995 | err = snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 1); | 999 | err = snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 1); |
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 3b73ba7d03e8..b0a474494966 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <asm/irq.h> | 23 | #include <asm/irq.h> |
24 | #include <asm/sizes.h> | 24 | #include <asm/sizes.h> |
25 | 25 | ||
26 | #include <sound/driver.h> | ||
27 | #include <sound/core.h> | 26 | #include <sound/core.h> |
28 | #include <sound/initval.h> | 27 | #include <sound/initval.h> |
29 | #include <sound/ac97_codec.h> | 28 | #include <sound/ac97_codec.h> |
diff --git a/sound/arm/devdma.c b/sound/arm/devdma.c index ca3bf4ee05a3..9d1e6665b546 100644 --- a/sound/arm/devdma.c +++ b/sound/arm/devdma.c | |||
@@ -12,7 +12,6 @@ | |||
12 | #include <linux/device.h> | 12 | #include <linux/device.h> |
13 | #include <linux/dma-mapping.h> | 13 | #include <linux/dma-mapping.h> |
14 | 14 | ||
15 | #include <sound/driver.h> | ||
16 | #include <sound/core.h> | 15 | #include <sound/core.h> |
17 | #include <sound/pcm.h> | 16 | #include <sound/pcm.h> |
18 | 17 | ||
diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c index 55c6c822bec1..5d86e6809752 100644 --- a/sound/arm/pxa2xx-ac97.c +++ b/sound/arm/pxa2xx-ac97.c | |||
@@ -18,7 +18,6 @@ | |||
18 | #include <linux/wait.h> | 18 | #include <linux/wait.h> |
19 | #include <linux/delay.h> | 19 | #include <linux/delay.h> |
20 | 20 | ||
21 | #include <sound/driver.h> | ||
22 | #include <sound/core.h> | 21 | #include <sound/core.h> |
23 | #include <sound/pcm.h> | 22 | #include <sound/pcm.h> |
24 | #include <sound/ac97_codec.h> | 23 | #include <sound/ac97_codec.h> |
@@ -352,6 +351,7 @@ static int __devinit pxa2xx_ac97_probe(struct platform_device *dev) | |||
352 | snprintf(card->longname, sizeof(card->longname), | 351 | snprintf(card->longname, sizeof(card->longname), |
353 | "%s (%s)", dev->dev.driver->name, card->mixername); | 352 | "%s (%s)", dev->dev.driver->name, card->mixername); |
354 | 353 | ||
354 | snd_card_set_dev(card, &dev->dev); | ||
355 | ret = snd_card_register(card); | 355 | ret = snd_card_register(card); |
356 | if (ret == 0) { | 356 | if (ret == 0) { |
357 | platform_set_drvdata(dev, card); | 357 | platform_set_drvdata(dev, card); |
diff --git a/sound/arm/pxa2xx-pcm.c b/sound/arm/pxa2xx-pcm.c index e8cf904b8358..0ede9e4656a8 100644 --- a/sound/arm/pxa2xx-pcm.c +++ b/sound/arm/pxa2xx-pcm.c | |||
@@ -16,7 +16,6 @@ | |||
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/dma-mapping.h> | 17 | #include <linux/dma-mapping.h> |
18 | 18 | ||
19 | #include <sound/driver.h> | ||
20 | #include <sound/core.h> | 19 | #include <sound/core.h> |
21 | #include <sound/pcm.h> | 20 | #include <sound/pcm.h> |
22 | #include <sound/pcm_params.h> | 21 | #include <sound/pcm_params.h> |
diff --git a/sound/arm/sa11xx-uda1341.c b/sound/arm/sa11xx-uda1341.c index 81c64b09d359..0eff33ca0f79 100644 --- a/sound/arm/sa11xx-uda1341.c +++ b/sound/arm/sa11xx-uda1341.c | |||
@@ -59,7 +59,6 @@ | |||
59 | * | 59 | * |
60 | ***************************************************************************************************/ | 60 | ***************************************************************************************************/ |
61 | 61 | ||
62 | #include <sound/driver.h> | ||
63 | #include <linux/module.h> | 62 | #include <linux/module.h> |
64 | #include <linux/moduleparam.h> | 63 | #include <linux/moduleparam.h> |
65 | #include <linux/init.h> | 64 | #include <linux/init.h> |
diff --git a/sound/core/control.c b/sound/core/control.c index df0774c76f6f..01a1a5af47bb 100644 --- a/sound/core/control.c +++ b/sound/core/control.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/threads.h> | 22 | #include <linux/threads.h> |
24 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
@@ -232,8 +231,6 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol, | |||
232 | access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : | 231 | access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : |
233 | (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE| | 232 | (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE| |
234 | SNDRV_CTL_ELEM_ACCESS_INACTIVE| | 233 | SNDRV_CTL_ELEM_ACCESS_INACTIVE| |
235 | SNDRV_CTL_ELEM_ACCESS_DINDIRECT| | ||
236 | SNDRV_CTL_ELEM_ACCESS_INDIRECT| | ||
237 | SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE| | 234 | SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE| |
238 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)); | 235 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)); |
239 | kctl.info = ncontrol->info; | 236 | kctl.info = ncontrol->info; |
@@ -692,7 +689,7 @@ int snd_ctl_elem_read(struct snd_card *card, struct snd_ctl_elem_value *control) | |||
692 | struct snd_kcontrol *kctl; | 689 | struct snd_kcontrol *kctl; |
693 | struct snd_kcontrol_volatile *vd; | 690 | struct snd_kcontrol_volatile *vd; |
694 | unsigned int index_offset; | 691 | unsigned int index_offset; |
695 | int result, indirect; | 692 | int result; |
696 | 693 | ||
697 | down_read(&card->controls_rwsem); | 694 | down_read(&card->controls_rwsem); |
698 | kctl = snd_ctl_find_id(card, &control->id); | 695 | kctl = snd_ctl_find_id(card, &control->id); |
@@ -701,17 +698,12 @@ int snd_ctl_elem_read(struct snd_card *card, struct snd_ctl_elem_value *control) | |||
701 | } else { | 698 | } else { |
702 | index_offset = snd_ctl_get_ioff(kctl, &control->id); | 699 | index_offset = snd_ctl_get_ioff(kctl, &control->id); |
703 | vd = &kctl->vd[index_offset]; | 700 | vd = &kctl->vd[index_offset]; |
704 | indirect = vd->access & SNDRV_CTL_ELEM_ACCESS_INDIRECT ? 1 : 0; | 701 | if ((vd->access & SNDRV_CTL_ELEM_ACCESS_READ) && |
705 | if (control->indirect != indirect) { | 702 | kctl->get != NULL) { |
706 | result = -EACCES; | 703 | snd_ctl_build_ioff(&control->id, kctl, index_offset); |
707 | } else { | 704 | result = kctl->get(kctl, control); |
708 | if ((vd->access & SNDRV_CTL_ELEM_ACCESS_READ) && kctl->get != NULL) { | 705 | } else |
709 | snd_ctl_build_ioff(&control->id, kctl, index_offset); | 706 | result = -EPERM; |
710 | result = kctl->get(kctl, control); | ||
711 | } else { | ||
712 | result = -EPERM; | ||
713 | } | ||
714 | } | ||
715 | } | 707 | } |
716 | up_read(&card->controls_rwsem); | 708 | up_read(&card->controls_rwsem); |
717 | return result; | 709 | return result; |
@@ -748,7 +740,7 @@ int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, | |||
748 | struct snd_kcontrol *kctl; | 740 | struct snd_kcontrol *kctl; |
749 | struct snd_kcontrol_volatile *vd; | 741 | struct snd_kcontrol_volatile *vd; |
750 | unsigned int index_offset; | 742 | unsigned int index_offset; |
751 | int result, indirect; | 743 | int result; |
752 | 744 | ||
753 | down_read(&card->controls_rwsem); | 745 | down_read(&card->controls_rwsem); |
754 | kctl = snd_ctl_find_id(card, &control->id); | 746 | kctl = snd_ctl_find_id(card, &control->id); |
@@ -757,23 +749,19 @@ int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, | |||
757 | } else { | 749 | } else { |
758 | index_offset = snd_ctl_get_ioff(kctl, &control->id); | 750 | index_offset = snd_ctl_get_ioff(kctl, &control->id); |
759 | vd = &kctl->vd[index_offset]; | 751 | vd = &kctl->vd[index_offset]; |
760 | indirect = vd->access & SNDRV_CTL_ELEM_ACCESS_INDIRECT ? 1 : 0; | 752 | if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_WRITE) || |
761 | if (control->indirect != indirect) { | 753 | kctl->put == NULL || |
762 | result = -EACCES; | 754 | (file && vd->owner && vd->owner != file)) { |
755 | result = -EPERM; | ||
763 | } else { | 756 | } else { |
764 | if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_WRITE) || | 757 | snd_ctl_build_ioff(&control->id, kctl, index_offset); |
765 | kctl->put == NULL || | 758 | result = kctl->put(kctl, control); |
766 | (file && vd->owner != NULL && vd->owner != file)) { | 759 | } |
767 | result = -EPERM; | 760 | if (result > 0) { |
768 | } else { | 761 | up_read(&card->controls_rwsem); |
769 | snd_ctl_build_ioff(&control->id, kctl, index_offset); | 762 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, |
770 | result = kctl->put(kctl, control); | 763 | &control->id); |
771 | } | 764 | return 0; |
772 | if (result > 0) { | ||
773 | up_read(&card->controls_rwsem); | ||
774 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &control->id); | ||
775 | return 0; | ||
776 | } | ||
777 | } | 765 | } |
778 | } | 766 | } |
779 | up_read(&card->controls_rwsem); | 767 | up_read(&card->controls_rwsem); |
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c index 9311ca397bbc..6101259ad860 100644 --- a/sound/core/control_compat.c +++ b/sound/core/control_compat.c | |||
@@ -219,7 +219,8 @@ static int copy_ctl_value_from_user(struct snd_card *card, | |||
219 | struct snd_ctl_elem_value32 __user *data32, | 219 | struct snd_ctl_elem_value32 __user *data32, |
220 | int *typep, int *countp) | 220 | int *typep, int *countp) |
221 | { | 221 | { |
222 | int i, type, count, size; | 222 | int i, type, size; |
223 | int uninitialized_var(count); | ||
223 | unsigned int indirect; | 224 | unsigned int indirect; |
224 | 225 | ||
225 | if (copy_from_user(&data->id, &data32->id, sizeof(data->id))) | 226 | if (copy_from_user(&data->id, &data32->id, sizeof(data->id))) |
diff --git a/sound/core/device.c b/sound/core/device.c index ea1a0621eefb..202dac0e4d89 100644 --- a/sound/core/device.c +++ b/sound/core/device.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
24 | #include <linux/time.h> | 23 | #include <linux/time.h> |
25 | #include <linux/errno.h> | 24 | #include <linux/errno.h> |
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index bfd9d182b8a3..6d6589f93899 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/major.h> | 22 | #include <linux/major.h> |
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
diff --git a/sound/core/info.c b/sound/core/info.c index 1ffd29bb4cd0..9977ec2eace3 100644 --- a/sound/core/info.c +++ b/sound/core/info.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/time.h> | 23 | #include <linux/time.h> |
25 | #include <linux/smp_lock.h> | 24 | #include <linux/smp_lock.h> |
diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c index 435c9399f7a9..e35789a92752 100644 --- a/sound/core/info_oss.c +++ b/sound/core/info_oss.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
24 | #include <linux/time.h> | 23 | #include <linux/time.h> |
25 | #include <linux/string.h> | 24 | #include <linux/string.h> |
@@ -66,8 +65,6 @@ int snd_oss_info_register(int dev, int num, char *string) | |||
66 | 65 | ||
67 | EXPORT_SYMBOL(snd_oss_info_register); | 66 | EXPORT_SYMBOL(snd_oss_info_register); |
68 | 67 | ||
69 | extern void snd_card_info_read_oss(struct snd_info_buffer *buffer); | ||
70 | |||
71 | static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int dev) | 68 | static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int dev) |
72 | { | 69 | { |
73 | int idx, ok = -1; | 70 | int idx, ok = -1; |
diff --git a/sound/core/init.c b/sound/core/init.c index 2cb7099eb1e1..e3338d6071ef 100644 --- a/sound/core/init.c +++ b/sound/core/init.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/sched.h> | 23 | #include <linux/sched.h> |
25 | #include <linux/file.h> | 24 | #include <linux/file.h> |
@@ -43,6 +42,40 @@ EXPORT_SYMBOL(snd_cards); | |||
43 | 42 | ||
44 | static DEFINE_MUTEX(snd_card_mutex); | 43 | static DEFINE_MUTEX(snd_card_mutex); |
45 | 44 | ||
45 | static char *slots[SNDRV_CARDS]; | ||
46 | module_param_array(slots, charp, NULL, 0444); | ||
47 | MODULE_PARM_DESC(slots, "Module names assigned to the slots."); | ||
48 | |||
49 | /* return non-zero if the given index is already reserved for another | ||
50 | * module via slots option | ||
51 | */ | ||
52 | static int module_slot_mismatch(struct module *module, int idx) | ||
53 | { | ||
54 | #ifdef MODULE | ||
55 | char *s1, *s2; | ||
56 | if (!module || !module->name || !slots[idx]) | ||
57 | return 0; | ||
58 | s1 = slots[idx]; | ||
59 | s2 = module->name; | ||
60 | /* compare module name strings | ||
61 | * hyphens are handled as equivalent with underscore | ||
62 | */ | ||
63 | for (;;) { | ||
64 | char c1 = *s1++; | ||
65 | char c2 = *s2++; | ||
66 | if (c1 == '-') | ||
67 | c1 = '_'; | ||
68 | if (c2 == '-') | ||
69 | c2 = '_'; | ||
70 | if (c1 != c2) | ||
71 | return 1; | ||
72 | if (!c1) | ||
73 | break; | ||
74 | } | ||
75 | #endif | ||
76 | return 0; | ||
77 | } | ||
78 | |||
46 | #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) | 79 | #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) |
47 | int (*snd_mixer_oss_notify_callback)(struct snd_card *card, int free_flag); | 80 | int (*snd_mixer_oss_notify_callback)(struct snd_card *card, int free_flag); |
48 | EXPORT_SYMBOL(snd_mixer_oss_notify_callback); | 81 | EXPORT_SYMBOL(snd_mixer_oss_notify_callback); |
@@ -115,6 +148,8 @@ struct snd_card *snd_card_new(int idx, const char *xid, | |||
115 | for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) | 148 | for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) |
116 | /* idx == -1 == 0xffff means: take any free slot */ | 149 | /* idx == -1 == 0xffff means: take any free slot */ |
117 | if (~snd_cards_lock & idx & 1<<idx2) { | 150 | if (~snd_cards_lock & idx & 1<<idx2) { |
151 | if (module_slot_mismatch(module, idx2)) | ||
152 | continue; | ||
118 | idx = idx2; | 153 | idx = idx2; |
119 | if (idx >= snd_ecards_limit) | 154 | if (idx >= snd_ecards_limit) |
120 | snd_ecards_limit = idx + 1; | 155 | snd_ecards_limit = idx + 1; |
@@ -304,8 +339,8 @@ int snd_card_disconnect(struct snd_card *card) | |||
304 | list_add(&mfile->shutdown_list, &shutdown_files); | 339 | list_add(&mfile->shutdown_list, &shutdown_files); |
305 | spin_unlock(&shutdown_lock); | 340 | spin_unlock(&shutdown_lock); |
306 | 341 | ||
307 | fops_get(&snd_shutdown_f_ops); | ||
308 | mfile->file->f_op = &snd_shutdown_f_ops; | 342 | mfile->file->f_op = &snd_shutdown_f_ops; |
343 | fops_get(mfile->file->f_op); | ||
309 | 344 | ||
310 | mfile = mfile->next; | 345 | mfile = mfile->next; |
311 | } | 346 | } |
diff --git a/sound/core/isadma.c b/sound/core/isadma.c index eb173cef4f05..79f0f16af339 100644 --- a/sound/core/isadma.c +++ b/sound/core/isadma.c | |||
@@ -26,7 +26,6 @@ | |||
26 | 26 | ||
27 | #undef HAVE_REALLY_SLOW_DMA_CONTROLLER | 27 | #undef HAVE_REALLY_SLOW_DMA_CONTROLLER |
28 | 28 | ||
29 | #include <sound/driver.h> | ||
30 | #include <sound/core.h> | 29 | #include <sound/core.h> |
31 | #include <asm/dma.h> | 30 | #include <asm/dma.h> |
32 | 31 | ||
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index 9b4992eab479..920e5780c228 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c | |||
@@ -568,6 +568,7 @@ static ssize_t snd_mem_proc_write(struct file *file, const char __user * buffer, | |||
568 | if (pci_set_dma_mask(pci, mask) < 0 || | 568 | if (pci_set_dma_mask(pci, mask) < 0 || |
569 | pci_set_consistent_dma_mask(pci, mask) < 0) { | 569 | pci_set_consistent_dma_mask(pci, mask) < 0) { |
570 | printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", mask, vendor, device); | 570 | printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", mask, vendor, device); |
571 | pci_dev_put(pci); | ||
571 | return count; | 572 | return count; |
572 | } | 573 | } |
573 | } | 574 | } |
diff --git a/sound/core/memory.c b/sound/core/memory.c index 25b0f056563e..1161158582a6 100644 --- a/sound/core/memory.c +++ b/sound/core/memory.c | |||
@@ -20,9 +20,9 @@ | |||
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <linux/module.h> | ||
24 | #include <asm/io.h> | 23 | #include <asm/io.h> |
25 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
25 | #include <sound/core.h> | ||
26 | 26 | ||
27 | /** | 27 | /** |
28 | * copy_to_user_fromio - copy data from mmio-space to user-space | 28 | * copy_to_user_fromio - copy data from mmio-space to user-space |
diff --git a/sound/core/misc.c b/sound/core/misc.c index 6cabab8cc537..102d1c36cf26 100644 --- a/sound/core/misc.c +++ b/sound/core/misc.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/time.h> | 23 | #include <linux/time.h> |
25 | #include <linux/ioport.h> | 24 | #include <linux/ioport.h> |
diff --git a/sound/core/oss/copy.c b/sound/core/oss/copy.c index d6a04c2d5a75..9ded30d0e97d 100644 --- a/sound/core/oss/copy.c +++ b/sound/core/oss/copy.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/time.h> | 22 | #include <linux/time.h> |
24 | #include <sound/core.h> | 23 | #include <sound/core.h> |
25 | #include <sound/pcm.h> | 24 | #include <sound/pcm.h> |
diff --git a/sound/core/oss/io.c b/sound/core/oss/io.c index 3ece39fc48db..f874f6ca3657 100644 --- a/sound/core/oss/io.c +++ b/sound/core/oss/io.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/time.h> | 22 | #include <linux/time.h> |
24 | #include <sound/core.h> | 23 | #include <sound/core.h> |
25 | #include <sound/pcm.h> | 24 | #include <sound/pcm.h> |
diff --git a/sound/core/oss/linear.c b/sound/core/oss/linear.c index 06f96a3e86f6..da3dbd41669e 100644 --- a/sound/core/oss/linear.c +++ b/sound/core/oss/linear.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/time.h> | 23 | #include <linux/time.h> |
25 | #include <sound/core.h> | 24 | #include <sound/core.h> |
26 | #include <sound/pcm.h> | 25 | #include <sound/pcm.h> |
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index c5a5ab9cae8c..75daed298a15 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
25 | #include <linux/time.h> | 24 | #include <linux/time.h> |
diff --git a/sound/core/oss/mulaw.c b/sound/core/oss/mulaw.c index 848db82529ed..77f96194a0ed 100644 --- a/sound/core/oss/mulaw.c +++ b/sound/core/oss/mulaw.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/time.h> | 24 | #include <linux/time.h> |
26 | #include <sound/core.h> | 25 | #include <sound/core.h> |
27 | #include <sound/pcm.h> | 26 | #include <sound/pcm.h> |
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index d0c4ceb9f0b4..4c601b192ddf 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #define OSS_DEBUG | 26 | #define OSS_DEBUG |
27 | #endif | 27 | #endif |
28 | 28 | ||
29 | #include <sound/driver.h> | ||
30 | #include <linux/init.h> | 29 | #include <linux/init.h> |
31 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
32 | #include <linux/time.h> | 31 | #include <linux/time.h> |
@@ -985,10 +984,8 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) | |||
985 | sw_params->stop_threshold = runtime->buffer_size; | 984 | sw_params->stop_threshold = runtime->buffer_size; |
986 | sw_params->tstamp_mode = SNDRV_PCM_TSTAMP_NONE; | 985 | sw_params->tstamp_mode = SNDRV_PCM_TSTAMP_NONE; |
987 | sw_params->period_step = 1; | 986 | sw_params->period_step = 1; |
988 | sw_params->sleep_min = 0; | ||
989 | sw_params->avail_min = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? | 987 | sw_params->avail_min = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? |
990 | 1 : runtime->period_size; | 988 | 1 : runtime->period_size; |
991 | sw_params->xfer_align = 1; | ||
992 | if (atomic_read(&substream->mmap_count) || | 989 | if (atomic_read(&substream->mmap_count) || |
993 | substream->oss.setup.nosilence) { | 990 | substream->oss.setup.nosilence) { |
994 | sw_params->silence_threshold = 0; | 991 | sw_params->silence_threshold = 0; |
@@ -1624,6 +1621,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) | |||
1624 | snd_pcm_format_set_silence(runtime->format, | 1621 | snd_pcm_format_set_silence(runtime->format, |
1625 | runtime->oss.buffer, | 1622 | runtime->oss.buffer, |
1626 | size1); | 1623 | size1); |
1624 | size1 /= runtime->channels; /* frames */ | ||
1627 | fs = snd_enter_user(); | 1625 | fs = snd_enter_user(); |
1628 | snd_pcm_lib_write(substream, (void __user *)runtime->oss.buffer, size1); | 1626 | snd_pcm_lib_write(substream, (void __user *)runtime->oss.buffer, size1); |
1629 | snd_leave_user(fs); | 1627 | snd_leave_user(fs); |
diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c index 14095a927a1b..bec94138205e 100644 --- a/sound/core/oss/pcm_plugin.c +++ b/sound/core/oss/pcm_plugin.c | |||
@@ -24,7 +24,6 @@ | |||
24 | #define PLUGIN_DEBUG | 24 | #define PLUGIN_DEBUG |
25 | #endif | 25 | #endif |
26 | 26 | ||
27 | #include <sound/driver.h> | ||
28 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
29 | #include <linux/time.h> | 28 | #include <linux/time.h> |
30 | #include <linux/vmalloc.h> | 29 | #include <linux/vmalloc.h> |
diff --git a/sound/core/oss/rate.c b/sound/core/oss/rate.c index 9eb267913c38..14dfb3175d84 100644 --- a/sound/core/oss/rate.c +++ b/sound/core/oss/rate.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/time.h> | 22 | #include <linux/time.h> |
24 | #include <sound/core.h> | 23 | #include <sound/core.h> |
25 | #include <sound/pcm.h> | 24 | #include <sound/pcm.h> |
diff --git a/sound/core/oss/route.c b/sound/core/oss/route.c index de3ffdeaf7e3..da7ab7a3e82c 100644 --- a/sound/core/oss/route.c +++ b/sound/core/oss/route.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
24 | #include <linux/time.h> | 23 | #include <linux/time.h> |
25 | #include <sound/core.h> | 24 | #include <sound/core.h> |
diff --git a/sound/core/pcm.c b/sound/core/pcm.c index cf9b9493d41d..9dd9bc73fe1d 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
25 | #include <linux/time.h> | 24 | #include <linux/time.h> |
@@ -228,7 +227,7 @@ static char *snd_pcm_subformat_names[] = { | |||
228 | 227 | ||
229 | static char *snd_pcm_tstamp_mode_names[] = { | 228 | static char *snd_pcm_tstamp_mode_names[] = { |
230 | TSTAMP(NONE), | 229 | TSTAMP(NONE), |
231 | TSTAMP(MMAP), | 230 | TSTAMP(ENABLE), |
232 | }; | 231 | }; |
233 | 232 | ||
234 | static const char *snd_pcm_stream_name(int stream) | 233 | static const char *snd_pcm_stream_name(int stream) |
@@ -359,7 +358,6 @@ static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry, | |||
359 | snd_iprintf(buffer, "rate: %u (%u/%u)\n", runtime->rate, runtime->rate_num, runtime->rate_den); | 358 | snd_iprintf(buffer, "rate: %u (%u/%u)\n", runtime->rate, runtime->rate_num, runtime->rate_den); |
360 | snd_iprintf(buffer, "period_size: %lu\n", runtime->period_size); | 359 | snd_iprintf(buffer, "period_size: %lu\n", runtime->period_size); |
361 | snd_iprintf(buffer, "buffer_size: %lu\n", runtime->buffer_size); | 360 | snd_iprintf(buffer, "buffer_size: %lu\n", runtime->buffer_size); |
362 | snd_iprintf(buffer, "tick_time: %u\n", runtime->tick_time); | ||
363 | #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) | 361 | #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) |
364 | if (substream->oss.oss) { | 362 | if (substream->oss.oss) { |
365 | snd_iprintf(buffer, "OSS format: %s\n", snd_pcm_oss_format_name(runtime->oss.format)); | 363 | snd_iprintf(buffer, "OSS format: %s\n", snd_pcm_oss_format_name(runtime->oss.format)); |
@@ -387,9 +385,7 @@ static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry, | |||
387 | } | 385 | } |
388 | snd_iprintf(buffer, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(runtime->tstamp_mode)); | 386 | snd_iprintf(buffer, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(runtime->tstamp_mode)); |
389 | snd_iprintf(buffer, "period_step: %u\n", runtime->period_step); | 387 | snd_iprintf(buffer, "period_step: %u\n", runtime->period_step); |
390 | snd_iprintf(buffer, "sleep_min: %u\n", runtime->sleep_min); | ||
391 | snd_iprintf(buffer, "avail_min: %lu\n", runtime->control->avail_min); | 388 | snd_iprintf(buffer, "avail_min: %lu\n", runtime->control->avail_min); |
392 | snd_iprintf(buffer, "xfer_align: %lu\n", runtime->xfer_align); | ||
393 | snd_iprintf(buffer, "start_threshold: %lu\n", runtime->start_threshold); | 389 | snd_iprintf(buffer, "start_threshold: %lu\n", runtime->start_threshold); |
394 | snd_iprintf(buffer, "stop_threshold: %lu\n", runtime->stop_threshold); | 390 | snd_iprintf(buffer, "stop_threshold: %lu\n", runtime->stop_threshold); |
395 | snd_iprintf(buffer, "silence_threshold: %lu\n", runtime->silence_threshold); | 391 | snd_iprintf(buffer, "silence_threshold: %lu\n", runtime->silence_threshold); |
@@ -765,12 +761,6 @@ static int snd_pcm_dev_free(struct snd_device *device) | |||
765 | return snd_pcm_free(pcm); | 761 | return snd_pcm_free(pcm); |
766 | } | 762 | } |
767 | 763 | ||
768 | static void snd_pcm_tick_timer_func(unsigned long data) | ||
769 | { | ||
770 | struct snd_pcm_substream *substream = (struct snd_pcm_substream *) data; | ||
771 | snd_pcm_tick_elapsed(substream); | ||
772 | } | ||
773 | |||
774 | int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, | 764 | int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, |
775 | struct file *file, | 765 | struct file *file, |
776 | struct snd_pcm_substream **rsubstream) | 766 | struct snd_pcm_substream **rsubstream) |
@@ -877,9 +867,6 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, | |||
877 | memset((void*)runtime->control, 0, size); | 867 | memset((void*)runtime->control, 0, size); |
878 | 868 | ||
879 | init_waitqueue_head(&runtime->sleep); | 869 | init_waitqueue_head(&runtime->sleep); |
880 | init_timer(&runtime->tick_timer); | ||
881 | runtime->tick_timer.function = snd_pcm_tick_timer_func; | ||
882 | runtime->tick_timer.data = (unsigned long) substream; | ||
883 | 870 | ||
884 | runtime->status->state = SNDRV_PCM_STATE_OPEN; | 871 | runtime->status->state = SNDRV_PCM_STATE_OPEN; |
885 | 872 | ||
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index 2b539799d23b..49aa693fba8a 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c | |||
@@ -484,6 +484,7 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l | |||
484 | case SNDRV_PCM_IOCTL_PVERSION: | 484 | case SNDRV_PCM_IOCTL_PVERSION: |
485 | case SNDRV_PCM_IOCTL_INFO: | 485 | case SNDRV_PCM_IOCTL_INFO: |
486 | case SNDRV_PCM_IOCTL_TSTAMP: | 486 | case SNDRV_PCM_IOCTL_TSTAMP: |
487 | case SNDRV_PCM_IOCTL_TTSTAMP: | ||
487 | case SNDRV_PCM_IOCTL_HWSYNC: | 488 | case SNDRV_PCM_IOCTL_HWSYNC: |
488 | case SNDRV_PCM_IOCTL_PREPARE: | 489 | case SNDRV_PCM_IOCTL_PREPARE: |
489 | case SNDRV_PCM_IOCTL_RESET: | 490 | case SNDRV_PCM_IOCTL_RESET: |
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 806f1fba5446..1533f0379e9d 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
25 | #include <linux/time.h> | 24 | #include <linux/time.h> |
26 | #include <sound/core.h> | 25 | #include <sound/core.h> |
@@ -145,11 +144,11 @@ static inline snd_pcm_uframes_t snd_pcm_update_hw_ptr_pos(struct snd_pcm_substre | |||
145 | { | 144 | { |
146 | snd_pcm_uframes_t pos; | 145 | snd_pcm_uframes_t pos; |
147 | 146 | ||
147 | if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) | ||
148 | snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); | ||
148 | pos = substream->ops->pointer(substream); | 149 | pos = substream->ops->pointer(substream); |
149 | if (pos == SNDRV_PCM_POS_XRUN) | 150 | if (pos == SNDRV_PCM_POS_XRUN) |
150 | return pos; /* XRUN */ | 151 | return pos; /* XRUN */ |
151 | if (runtime->tstamp_mode & SNDRV_PCM_TSTAMP_MMAP) | ||
152 | getnstimeofday((struct timespec *)&runtime->status->tstamp); | ||
153 | #ifdef CONFIG_SND_DEBUG | 152 | #ifdef CONFIG_SND_DEBUG |
154 | if (pos >= runtime->buffer_size) { | 153 | if (pos >= runtime->buffer_size) { |
155 | snd_printk(KERN_ERR "BUG: stream = %i, pos = 0x%lx, buffer size = 0x%lx, period size = 0x%lx\n", substream->stream, pos, runtime->buffer_size, runtime->period_size); | 154 | snd_printk(KERN_ERR "BUG: stream = %i, pos = 0x%lx, buffer size = 0x%lx, period size = 0x%lx\n", substream->stream, pos, runtime->buffer_size, runtime->period_size); |
@@ -1139,7 +1138,7 @@ EXPORT_SYMBOL(snd_pcm_hw_constraint_step); | |||
1139 | 1138 | ||
1140 | static int snd_pcm_hw_rule_pow2(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) | 1139 | static int snd_pcm_hw_rule_pow2(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) |
1141 | { | 1140 | { |
1142 | static int pow2_sizes[] = { | 1141 | static unsigned int pow2_sizes[] = { |
1143 | 1<<0, 1<<1, 1<<2, 1<<3, 1<<4, 1<<5, 1<<6, 1<<7, | 1142 | 1<<0, 1<<1, 1<<2, 1<<3, 1<<4, 1<<5, 1<<6, 1<<7, |
1144 | 1<<8, 1<<9, 1<<10, 1<<11, 1<<12, 1<<13, 1<<14, 1<<15, | 1143 | 1<<8, 1<<9, 1<<10, 1<<11, 1<<12, 1<<13, 1<<14, 1<<15, |
1145 | 1<<16, 1<<17, 1<<18, 1<<19, 1<<20, 1<<21, 1<<22, 1<<23, | 1144 | 1<<16, 1<<17, 1<<18, 1<<19, 1<<20, 1<<21, 1<<22, 1<<23, |
@@ -1451,108 +1450,13 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, | |||
1451 | 1450 | ||
1452 | EXPORT_SYMBOL(snd_pcm_lib_ioctl); | 1451 | EXPORT_SYMBOL(snd_pcm_lib_ioctl); |
1453 | 1452 | ||
1454 | /* | ||
1455 | * Conditions | ||
1456 | */ | ||
1457 | |||
1458 | static void snd_pcm_system_tick_set(struct snd_pcm_substream *substream, | ||
1459 | unsigned long ticks) | ||
1460 | { | ||
1461 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
1462 | if (ticks == 0) | ||
1463 | del_timer(&runtime->tick_timer); | ||
1464 | else { | ||
1465 | ticks += (1000000 / HZ) - 1; | ||
1466 | ticks /= (1000000 / HZ); | ||
1467 | mod_timer(&runtime->tick_timer, jiffies + ticks); | ||
1468 | } | ||
1469 | } | ||
1470 | |||
1471 | /* Temporary alias */ | ||
1472 | void snd_pcm_tick_set(struct snd_pcm_substream *substream, unsigned long ticks) | ||
1473 | { | ||
1474 | snd_pcm_system_tick_set(substream, ticks); | ||
1475 | } | ||
1476 | |||
1477 | void snd_pcm_tick_prepare(struct snd_pcm_substream *substream) | ||
1478 | { | ||
1479 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
1480 | snd_pcm_uframes_t frames = ULONG_MAX; | ||
1481 | snd_pcm_uframes_t avail, dist; | ||
1482 | unsigned int ticks; | ||
1483 | u_int64_t n; | ||
1484 | u_int32_t r; | ||
1485 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
1486 | if (runtime->silence_size >= runtime->boundary) { | ||
1487 | frames = 1; | ||
1488 | } else if (runtime->silence_size > 0 && | ||
1489 | runtime->silence_filled < runtime->buffer_size) { | ||
1490 | snd_pcm_sframes_t noise_dist; | ||
1491 | noise_dist = snd_pcm_playback_hw_avail(runtime) + runtime->silence_filled; | ||
1492 | if (noise_dist > (snd_pcm_sframes_t)runtime->silence_threshold) | ||
1493 | frames = noise_dist - runtime->silence_threshold; | ||
1494 | } | ||
1495 | avail = snd_pcm_playback_avail(runtime); | ||
1496 | } else { | ||
1497 | avail = snd_pcm_capture_avail(runtime); | ||
1498 | } | ||
1499 | if (avail < runtime->control->avail_min) { | ||
1500 | snd_pcm_sframes_t n = runtime->control->avail_min - avail; | ||
1501 | if (n > 0 && frames > (snd_pcm_uframes_t)n) | ||
1502 | frames = n; | ||
1503 | } | ||
1504 | if (avail < runtime->buffer_size) { | ||
1505 | snd_pcm_sframes_t n = runtime->buffer_size - avail; | ||
1506 | if (n > 0 && frames > (snd_pcm_uframes_t)n) | ||
1507 | frames = n; | ||
1508 | } | ||
1509 | if (frames == ULONG_MAX) { | ||
1510 | snd_pcm_tick_set(substream, 0); | ||
1511 | return; | ||
1512 | } | ||
1513 | dist = runtime->status->hw_ptr - runtime->hw_ptr_base; | ||
1514 | /* Distance to next interrupt */ | ||
1515 | dist = runtime->period_size - dist % runtime->period_size; | ||
1516 | if (dist <= frames) { | ||
1517 | snd_pcm_tick_set(substream, 0); | ||
1518 | return; | ||
1519 | } | ||
1520 | /* the base time is us */ | ||
1521 | n = frames; | ||
1522 | n *= 1000000; | ||
1523 | div64_32(&n, runtime->tick_time * runtime->rate, &r); | ||
1524 | ticks = n + (r > 0 ? 1 : 0); | ||
1525 | if (ticks < runtime->sleep_min) | ||
1526 | ticks = runtime->sleep_min; | ||
1527 | snd_pcm_tick_set(substream, (unsigned long) ticks); | ||
1528 | } | ||
1529 | |||
1530 | void snd_pcm_tick_elapsed(struct snd_pcm_substream *substream) | ||
1531 | { | ||
1532 | struct snd_pcm_runtime *runtime; | ||
1533 | unsigned long flags; | ||
1534 | |||
1535 | snd_assert(substream != NULL, return); | ||
1536 | runtime = substream->runtime; | ||
1537 | snd_assert(runtime != NULL, return); | ||
1538 | |||
1539 | snd_pcm_stream_lock_irqsave(substream, flags); | ||
1540 | if (!snd_pcm_running(substream) || | ||
1541 | snd_pcm_update_hw_ptr(substream) < 0) | ||
1542 | goto _end; | ||
1543 | if (runtime->sleep_min) | ||
1544 | snd_pcm_tick_prepare(substream); | ||
1545 | _end: | ||
1546 | snd_pcm_stream_unlock_irqrestore(substream, flags); | ||
1547 | } | ||
1548 | |||
1549 | /** | 1453 | /** |
1550 | * snd_pcm_period_elapsed - update the pcm status for the next period | 1454 | * snd_pcm_period_elapsed - update the pcm status for the next period |
1551 | * @substream: the pcm substream instance | 1455 | * @substream: the pcm substream instance |
1552 | * | 1456 | * |
1553 | * This function is called from the interrupt handler when the | 1457 | * This function is called from the interrupt handler when the |
1554 | * PCM has processed the period size. It will update the current | 1458 | * PCM has processed the period size. It will update the current |
1555 | * pointer, set up the tick, wake up sleepers, etc. | 1459 | * pointer, wake up sleepers, etc. |
1556 | * | 1460 | * |
1557 | * Even if more than one periods have elapsed since the last call, you | 1461 | * Even if more than one periods have elapsed since the last call, you |
1558 | * have to call this only once. | 1462 | * have to call this only once. |
@@ -1576,8 +1480,6 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream) | |||
1576 | 1480 | ||
1577 | if (substream->timer_running) | 1481 | if (substream->timer_running) |
1578 | snd_timer_interrupt(substream->timer, 1); | 1482 | snd_timer_interrupt(substream->timer, 1); |
1579 | if (runtime->sleep_min) | ||
1580 | snd_pcm_tick_prepare(substream); | ||
1581 | _end: | 1483 | _end: |
1582 | snd_pcm_stream_unlock_irqrestore(substream, flags); | 1484 | snd_pcm_stream_unlock_irqrestore(substream, flags); |
1583 | if (runtime->transfer_ack_end) | 1485 | if (runtime->transfer_ack_end) |
@@ -1587,6 +1489,71 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream) | |||
1587 | 1489 | ||
1588 | EXPORT_SYMBOL(snd_pcm_period_elapsed); | 1490 | EXPORT_SYMBOL(snd_pcm_period_elapsed); |
1589 | 1491 | ||
1492 | /* | ||
1493 | * Wait until avail_min data becomes available | ||
1494 | * Returns a negative error code if any error occurs during operation. | ||
1495 | * The available space is stored on availp. When err = 0 and avail = 0 | ||
1496 | * on the capture stream, it indicates the stream is in DRAINING state. | ||
1497 | */ | ||
1498 | static int wait_for_avail_min(struct snd_pcm_substream *substream, | ||
1499 | snd_pcm_uframes_t *availp) | ||
1500 | { | ||
1501 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
1502 | int is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | ||
1503 | wait_queue_t wait; | ||
1504 | int err = 0; | ||
1505 | snd_pcm_uframes_t avail = 0; | ||
1506 | long tout; | ||
1507 | |||
1508 | init_waitqueue_entry(&wait, current); | ||
1509 | add_wait_queue(&runtime->sleep, &wait); | ||
1510 | for (;;) { | ||
1511 | if (signal_pending(current)) { | ||
1512 | err = -ERESTARTSYS; | ||
1513 | break; | ||
1514 | } | ||
1515 | set_current_state(TASK_INTERRUPTIBLE); | ||
1516 | snd_pcm_stream_unlock_irq(substream); | ||
1517 | tout = schedule_timeout(msecs_to_jiffies(10000)); | ||
1518 | snd_pcm_stream_lock_irq(substream); | ||
1519 | switch (runtime->status->state) { | ||
1520 | case SNDRV_PCM_STATE_SUSPENDED: | ||
1521 | err = -ESTRPIPE; | ||
1522 | goto _endloop; | ||
1523 | case SNDRV_PCM_STATE_XRUN: | ||
1524 | err = -EPIPE; | ||
1525 | goto _endloop; | ||
1526 | case SNDRV_PCM_STATE_DRAINING: | ||
1527 | if (is_playback) | ||
1528 | err = -EPIPE; | ||
1529 | else | ||
1530 | avail = 0; /* indicate draining */ | ||
1531 | goto _endloop; | ||
1532 | case SNDRV_PCM_STATE_OPEN: | ||
1533 | case SNDRV_PCM_STATE_SETUP: | ||
1534 | case SNDRV_PCM_STATE_DISCONNECTED: | ||
1535 | err = -EBADFD; | ||
1536 | goto _endloop; | ||
1537 | } | ||
1538 | if (!tout) { | ||
1539 | snd_printd("%s write error (DMA or IRQ trouble?)\n", | ||
1540 | is_playback ? "playback" : "capture"); | ||
1541 | err = -EIO; | ||
1542 | break; | ||
1543 | } | ||
1544 | if (is_playback) | ||
1545 | avail = snd_pcm_playback_avail(runtime); | ||
1546 | else | ||
1547 | avail = snd_pcm_capture_avail(runtime); | ||
1548 | if (avail >= runtime->control->avail_min) | ||
1549 | break; | ||
1550 | } | ||
1551 | _endloop: | ||
1552 | remove_wait_queue(&runtime->sleep, &wait); | ||
1553 | *availp = avail; | ||
1554 | return err; | ||
1555 | } | ||
1556 | |||
1590 | static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream, | 1557 | static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream, |
1591 | unsigned int hwoff, | 1558 | unsigned int hwoff, |
1592 | unsigned long data, unsigned int off, | 1559 | unsigned long data, unsigned int off, |
@@ -1624,8 +1591,6 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, | |||
1624 | 1591 | ||
1625 | if (size == 0) | 1592 | if (size == 0) |
1626 | return 0; | 1593 | return 0; |
1627 | if (size > runtime->xfer_align) | ||
1628 | size -= size % runtime->xfer_align; | ||
1629 | 1594 | ||
1630 | snd_pcm_stream_lock_irq(substream); | 1595 | snd_pcm_stream_lock_irq(substream); |
1631 | switch (runtime->status->state) { | 1596 | switch (runtime->status->state) { |
@@ -1648,84 +1613,18 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, | |||
1648 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; | 1613 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; |
1649 | snd_pcm_uframes_t avail; | 1614 | snd_pcm_uframes_t avail; |
1650 | snd_pcm_uframes_t cont; | 1615 | snd_pcm_uframes_t cont; |
1651 | if (runtime->sleep_min == 0 && runtime->status->state == SNDRV_PCM_STATE_RUNNING) | 1616 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) |
1652 | snd_pcm_update_hw_ptr(substream); | 1617 | snd_pcm_update_hw_ptr(substream); |
1653 | avail = snd_pcm_playback_avail(runtime); | 1618 | avail = snd_pcm_playback_avail(runtime); |
1654 | if (((avail < runtime->control->avail_min && size > avail) || | 1619 | if (!avail) { |
1655 | (size >= runtime->xfer_align && avail < runtime->xfer_align))) { | ||
1656 | wait_queue_t wait; | ||
1657 | enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED, DROPPED } state; | ||
1658 | long tout; | ||
1659 | |||
1660 | if (nonblock) { | 1620 | if (nonblock) { |
1661 | err = -EAGAIN; | 1621 | err = -EAGAIN; |
1662 | goto _end_unlock; | 1622 | goto _end_unlock; |
1663 | } | 1623 | } |
1664 | 1624 | err = wait_for_avail_min(substream, &avail); | |
1665 | init_waitqueue_entry(&wait, current); | 1625 | if (err < 0) |
1666 | add_wait_queue(&runtime->sleep, &wait); | ||
1667 | while (1) { | ||
1668 | if (signal_pending(current)) { | ||
1669 | state = SIGNALED; | ||
1670 | break; | ||
1671 | } | ||
1672 | set_current_state(TASK_INTERRUPTIBLE); | ||
1673 | snd_pcm_stream_unlock_irq(substream); | ||
1674 | tout = schedule_timeout(10 * HZ); | ||
1675 | snd_pcm_stream_lock_irq(substream); | ||
1676 | if (tout == 0) { | ||
1677 | if (runtime->status->state != SNDRV_PCM_STATE_PREPARED && | ||
1678 | runtime->status->state != SNDRV_PCM_STATE_PAUSED) { | ||
1679 | state = runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ? SUSPENDED : EXPIRED; | ||
1680 | break; | ||
1681 | } | ||
1682 | } | ||
1683 | switch (runtime->status->state) { | ||
1684 | case SNDRV_PCM_STATE_XRUN: | ||
1685 | case SNDRV_PCM_STATE_DRAINING: | ||
1686 | state = ERROR; | ||
1687 | goto _end_loop; | ||
1688 | case SNDRV_PCM_STATE_SUSPENDED: | ||
1689 | state = SUSPENDED; | ||
1690 | goto _end_loop; | ||
1691 | case SNDRV_PCM_STATE_SETUP: | ||
1692 | state = DROPPED; | ||
1693 | goto _end_loop; | ||
1694 | default: | ||
1695 | break; | ||
1696 | } | ||
1697 | avail = snd_pcm_playback_avail(runtime); | ||
1698 | if (avail >= runtime->control->avail_min) { | ||
1699 | state = READY; | ||
1700 | break; | ||
1701 | } | ||
1702 | } | ||
1703 | _end_loop: | ||
1704 | remove_wait_queue(&runtime->sleep, &wait); | ||
1705 | |||
1706 | switch (state) { | ||
1707 | case ERROR: | ||
1708 | err = -EPIPE; | ||
1709 | goto _end_unlock; | ||
1710 | case SUSPENDED: | ||
1711 | err = -ESTRPIPE; | ||
1712 | goto _end_unlock; | ||
1713 | case SIGNALED: | ||
1714 | err = -ERESTARTSYS; | ||
1715 | goto _end_unlock; | ||
1716 | case EXPIRED: | ||
1717 | snd_printd("playback write error (DMA or IRQ trouble?)\n"); | ||
1718 | err = -EIO; | ||
1719 | goto _end_unlock; | ||
1720 | case DROPPED: | ||
1721 | err = -EBADFD; | ||
1722 | goto _end_unlock; | 1626 | goto _end_unlock; |
1723 | default: | ||
1724 | break; | ||
1725 | } | ||
1726 | } | 1627 | } |
1727 | if (avail > runtime->xfer_align) | ||
1728 | avail -= avail % runtime->xfer_align; | ||
1729 | frames = size > avail ? avail : size; | 1628 | frames = size > avail ? avail : size; |
1730 | cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size; | 1629 | cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size; |
1731 | if (frames > cont) | 1630 | if (frames > cont) |
@@ -1763,9 +1662,6 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, | |||
1763 | if (err < 0) | 1662 | if (err < 0) |
1764 | goto _end_unlock; | 1663 | goto _end_unlock; |
1765 | } | 1664 | } |
1766 | if (runtime->sleep_min && | ||
1767 | runtime->status->state == SNDRV_PCM_STATE_RUNNING) | ||
1768 | snd_pcm_tick_prepare(substream); | ||
1769 | } | 1665 | } |
1770 | _end_unlock: | 1666 | _end_unlock: |
1771 | snd_pcm_stream_unlock_irq(substream); | 1667 | snd_pcm_stream_unlock_irq(substream); |
@@ -1893,8 +1789,6 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, | |||
1893 | 1789 | ||
1894 | if (size == 0) | 1790 | if (size == 0) |
1895 | return 0; | 1791 | return 0; |
1896 | if (size > runtime->xfer_align) | ||
1897 | size -= size % runtime->xfer_align; | ||
1898 | 1792 | ||
1899 | snd_pcm_stream_lock_irq(substream); | 1793 | snd_pcm_stream_lock_irq(substream); |
1900 | switch (runtime->status->state) { | 1794 | switch (runtime->status->state) { |
@@ -1924,91 +1818,25 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, | |||
1924 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; | 1818 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; |
1925 | snd_pcm_uframes_t avail; | 1819 | snd_pcm_uframes_t avail; |
1926 | snd_pcm_uframes_t cont; | 1820 | snd_pcm_uframes_t cont; |
1927 | if (runtime->sleep_min == 0 && runtime->status->state == SNDRV_PCM_STATE_RUNNING) | 1821 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) |
1928 | snd_pcm_update_hw_ptr(substream); | 1822 | snd_pcm_update_hw_ptr(substream); |
1929 | __draining: | ||
1930 | avail = snd_pcm_capture_avail(runtime); | 1823 | avail = snd_pcm_capture_avail(runtime); |
1931 | if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) { | 1824 | if (!avail) { |
1932 | if (avail < runtime->xfer_align) { | 1825 | if (runtime->status->state == |
1933 | err = -EPIPE; | 1826 | SNDRV_PCM_STATE_DRAINING) { |
1827 | snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); | ||
1934 | goto _end_unlock; | 1828 | goto _end_unlock; |
1935 | } | 1829 | } |
1936 | } else if ((avail < runtime->control->avail_min && size > avail) || | ||
1937 | (size >= runtime->xfer_align && avail < runtime->xfer_align)) { | ||
1938 | wait_queue_t wait; | ||
1939 | enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED, DROPPED } state; | ||
1940 | long tout; | ||
1941 | |||
1942 | if (nonblock) { | 1830 | if (nonblock) { |
1943 | err = -EAGAIN; | 1831 | err = -EAGAIN; |
1944 | goto _end_unlock; | 1832 | goto _end_unlock; |
1945 | } | 1833 | } |
1946 | 1834 | err = wait_for_avail_min(substream, &avail); | |
1947 | init_waitqueue_entry(&wait, current); | 1835 | if (err < 0) |
1948 | add_wait_queue(&runtime->sleep, &wait); | ||
1949 | while (1) { | ||
1950 | if (signal_pending(current)) { | ||
1951 | state = SIGNALED; | ||
1952 | break; | ||
1953 | } | ||
1954 | set_current_state(TASK_INTERRUPTIBLE); | ||
1955 | snd_pcm_stream_unlock_irq(substream); | ||
1956 | tout = schedule_timeout(10 * HZ); | ||
1957 | snd_pcm_stream_lock_irq(substream); | ||
1958 | if (tout == 0) { | ||
1959 | if (runtime->status->state != SNDRV_PCM_STATE_PREPARED && | ||
1960 | runtime->status->state != SNDRV_PCM_STATE_PAUSED) { | ||
1961 | state = runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ? SUSPENDED : EXPIRED; | ||
1962 | break; | ||
1963 | } | ||
1964 | } | ||
1965 | switch (runtime->status->state) { | ||
1966 | case SNDRV_PCM_STATE_XRUN: | ||
1967 | state = ERROR; | ||
1968 | goto _end_loop; | ||
1969 | case SNDRV_PCM_STATE_SUSPENDED: | ||
1970 | state = SUSPENDED; | ||
1971 | goto _end_loop; | ||
1972 | case SNDRV_PCM_STATE_DRAINING: | ||
1973 | goto __draining; | ||
1974 | case SNDRV_PCM_STATE_SETUP: | ||
1975 | state = DROPPED; | ||
1976 | goto _end_loop; | ||
1977 | default: | ||
1978 | break; | ||
1979 | } | ||
1980 | avail = snd_pcm_capture_avail(runtime); | ||
1981 | if (avail >= runtime->control->avail_min) { | ||
1982 | state = READY; | ||
1983 | break; | ||
1984 | } | ||
1985 | } | ||
1986 | _end_loop: | ||
1987 | remove_wait_queue(&runtime->sleep, &wait); | ||
1988 | |||
1989 | switch (state) { | ||
1990 | case ERROR: | ||
1991 | err = -EPIPE; | ||
1992 | goto _end_unlock; | ||
1993 | case SUSPENDED: | ||
1994 | err = -ESTRPIPE; | ||
1995 | goto _end_unlock; | ||
1996 | case SIGNALED: | ||
1997 | err = -ERESTARTSYS; | ||
1998 | goto _end_unlock; | ||
1999 | case EXPIRED: | ||
2000 | snd_printd("capture read error (DMA or IRQ trouble?)\n"); | ||
2001 | err = -EIO; | ||
2002 | goto _end_unlock; | ||
2003 | case DROPPED: | ||
2004 | err = -EBADFD; | ||
2005 | goto _end_unlock; | 1836 | goto _end_unlock; |
2006 | default: | 1837 | if (!avail) |
2007 | break; | 1838 | continue; /* draining */ |
2008 | } | ||
2009 | } | 1839 | } |
2010 | if (avail > runtime->xfer_align) | ||
2011 | avail -= avail % runtime->xfer_align; | ||
2012 | frames = size > avail ? avail : size; | 1840 | frames = size > avail ? avail : size; |
2013 | cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size; | 1841 | cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size; |
2014 | if (frames > cont) | 1842 | if (frames > cont) |
@@ -2040,9 +1868,6 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, | |||
2040 | offset += frames; | 1868 | offset += frames; |
2041 | size -= frames; | 1869 | size -= frames; |
2042 | xfer += frames; | 1870 | xfer += frames; |
2043 | if (runtime->sleep_min && | ||
2044 | runtime->status->state == SNDRV_PCM_STATE_RUNNING) | ||
2045 | snd_pcm_tick_prepare(substream); | ||
2046 | } | 1871 | } |
2047 | _end_unlock: | 1872 | _end_unlock: |
2048 | snd_pcm_stream_unlock_irq(substream); | 1873 | snd_pcm_stream_unlock_irq(substream); |
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index a13e38cfd2c6..ff07b4a9992e 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <asm/io.h> | 22 | #include <asm/io.h> |
24 | #include <linux/time.h> | 23 | #include <linux/time.h> |
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c index dd9aa51d8c82..89b7f549bebd 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/time.h> | 22 | #include <linux/time.h> |
24 | #include <sound/core.h> | 23 | #include <sound/core.h> |
25 | #include <sound/pcm.h> | 24 | #include <sound/pcm.h> |
@@ -75,7 +74,7 @@ static struct pcm_format_data pcm_formats[SNDRV_PCM_FORMAT_LAST+1] = { | |||
75 | }, | 74 | }, |
76 | [SNDRV_PCM_FORMAT_U24_BE] = { | 75 | [SNDRV_PCM_FORMAT_U24_BE] = { |
77 | .width = 24, .phys = 32, .le = 0, .signd = 0, | 76 | .width = 24, .phys = 32, .le = 0, .signd = 0, |
78 | .silence = { 0x80, 0x00, 0x00 }, | 77 | .silence = { 0x00, 0x80, 0x00, 0x00 }, |
79 | }, | 78 | }, |
80 | [SNDRV_PCM_FORMAT_S32_LE] = { | 79 | [SNDRV_PCM_FORMAT_S32_LE] = { |
81 | .width = 32, .phys = 32, .le = 1, .signd = 1, | 80 | .width = 32, .phys = 32, .le = 1, .signd = 1, |
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index fb3dde4db045..62449117ee14 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/mm.h> | 22 | #include <linux/mm.h> |
24 | #include <linux/file.h> | 23 | #include <linux/file.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
@@ -413,7 +412,6 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, | |||
413 | runtime->period_size = params_period_size(params); | 412 | runtime->period_size = params_period_size(params); |
414 | runtime->periods = params_periods(params); | 413 | runtime->periods = params_periods(params); |
415 | runtime->buffer_size = params_buffer_size(params); | 414 | runtime->buffer_size = params_buffer_size(params); |
416 | runtime->tick_time = params_tick_time(params); | ||
417 | runtime->info = params->info; | 415 | runtime->info = params->info; |
418 | runtime->rate_num = params->rate_num; | 416 | runtime->rate_num = params->rate_num; |
419 | runtime->rate_den = params->rate_den; | 417 | runtime->rate_den = params->rate_den; |
@@ -433,9 +431,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, | |||
433 | /* Default sw params */ | 431 | /* Default sw params */ |
434 | runtime->tstamp_mode = SNDRV_PCM_TSTAMP_NONE; | 432 | runtime->tstamp_mode = SNDRV_PCM_TSTAMP_NONE; |
435 | runtime->period_step = 1; | 433 | runtime->period_step = 1; |
436 | runtime->sleep_min = 0; | ||
437 | runtime->control->avail_min = runtime->period_size; | 434 | runtime->control->avail_min = runtime->period_size; |
438 | runtime->xfer_align = runtime->period_size; | ||
439 | runtime->start_threshold = 1; | 435 | runtime->start_threshold = 1; |
440 | runtime->stop_threshold = runtime->buffer_size; | 436 | runtime->stop_threshold = runtime->buffer_size; |
441 | runtime->silence_threshold = 0; | 437 | runtime->silence_threshold = 0; |
@@ -532,9 +528,6 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, | |||
532 | return -EINVAL; | 528 | return -EINVAL; |
533 | if (params->avail_min == 0) | 529 | if (params->avail_min == 0) |
534 | return -EINVAL; | 530 | return -EINVAL; |
535 | if (params->xfer_align == 0 || | ||
536 | params->xfer_align % runtime->min_align != 0) | ||
537 | return -EINVAL; | ||
538 | if (params->silence_size >= runtime->boundary) { | 531 | if (params->silence_size >= runtime->boundary) { |
539 | if (params->silence_threshold != 0) | 532 | if (params->silence_threshold != 0) |
540 | return -EINVAL; | 533 | return -EINVAL; |
@@ -546,20 +539,14 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, | |||
546 | } | 539 | } |
547 | snd_pcm_stream_lock_irq(substream); | 540 | snd_pcm_stream_lock_irq(substream); |
548 | runtime->tstamp_mode = params->tstamp_mode; | 541 | runtime->tstamp_mode = params->tstamp_mode; |
549 | runtime->sleep_min = params->sleep_min; | ||
550 | runtime->period_step = params->period_step; | 542 | runtime->period_step = params->period_step; |
551 | runtime->control->avail_min = params->avail_min; | 543 | runtime->control->avail_min = params->avail_min; |
552 | runtime->start_threshold = params->start_threshold; | 544 | runtime->start_threshold = params->start_threshold; |
553 | runtime->stop_threshold = params->stop_threshold; | 545 | runtime->stop_threshold = params->stop_threshold; |
554 | runtime->silence_threshold = params->silence_threshold; | 546 | runtime->silence_threshold = params->silence_threshold; |
555 | runtime->silence_size = params->silence_size; | 547 | runtime->silence_size = params->silence_size; |
556 | runtime->xfer_align = params->xfer_align; | ||
557 | params->boundary = runtime->boundary; | 548 | params->boundary = runtime->boundary; |
558 | if (snd_pcm_running(substream)) { | 549 | if (snd_pcm_running(substream)) { |
559 | if (runtime->sleep_min) | ||
560 | snd_pcm_tick_prepare(substream); | ||
561 | else | ||
562 | snd_pcm_tick_set(substream, 0); | ||
563 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && | 550 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && |
564 | runtime->silence_size > 0) | 551 | runtime->silence_size > 0) |
565 | snd_pcm_playback_silence(substream, ULONG_MAX); | 552 | snd_pcm_playback_silence(substream, ULONG_MAX); |
@@ -595,12 +582,13 @@ int snd_pcm_status(struct snd_pcm_substream *substream, | |||
595 | status->trigger_tstamp = runtime->trigger_tstamp; | 582 | status->trigger_tstamp = runtime->trigger_tstamp; |
596 | if (snd_pcm_running(substream)) { | 583 | if (snd_pcm_running(substream)) { |
597 | snd_pcm_update_hw_ptr(substream); | 584 | snd_pcm_update_hw_ptr(substream); |
598 | if (runtime->tstamp_mode & SNDRV_PCM_TSTAMP_MMAP) | 585 | if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) { |
599 | status->tstamp = runtime->status->tstamp; | 586 | status->tstamp = runtime->status->tstamp; |
600 | else | 587 | goto _tstamp_end; |
601 | getnstimeofday(&status->tstamp); | 588 | } |
602 | } else | 589 | } |
603 | getnstimeofday(&status->tstamp); | 590 | snd_pcm_gettime(runtime, &status->tstamp); |
591 | _tstamp_end: | ||
604 | status->appl_ptr = runtime->control->appl_ptr; | 592 | status->appl_ptr = runtime->control->appl_ptr; |
605 | status->hw_ptr = runtime->status->hw_ptr; | 593 | status->hw_ptr = runtime->status->hw_ptr; |
606 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 594 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
@@ -688,7 +676,7 @@ static void snd_pcm_trigger_tstamp(struct snd_pcm_substream *substream) | |||
688 | if (runtime->trigger_master == NULL) | 676 | if (runtime->trigger_master == NULL) |
689 | return; | 677 | return; |
690 | if (runtime->trigger_master == substream) { | 678 | if (runtime->trigger_master == substream) { |
691 | getnstimeofday(&runtime->trigger_tstamp); | 679 | snd_pcm_gettime(runtime, &runtime->trigger_tstamp); |
692 | } else { | 680 | } else { |
693 | snd_pcm_trigger_tstamp(runtime->trigger_master); | 681 | snd_pcm_trigger_tstamp(runtime->trigger_master); |
694 | runtime->trigger_tstamp = runtime->trigger_master->runtime->trigger_tstamp; | 682 | runtime->trigger_tstamp = runtime->trigger_master->runtime->trigger_tstamp; |
@@ -875,8 +863,6 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state) | |||
875 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && | 863 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && |
876 | runtime->silence_size > 0) | 864 | runtime->silence_size > 0) |
877 | snd_pcm_playback_silence(substream, ULONG_MAX); | 865 | snd_pcm_playback_silence(substream, ULONG_MAX); |
878 | if (runtime->sleep_min) | ||
879 | snd_pcm_tick_prepare(substream); | ||
880 | if (substream->timer) | 866 | if (substream->timer) |
881 | snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTART, | 867 | snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTART, |
882 | &runtime->trigger_tstamp); | 868 | &runtime->trigger_tstamp); |
@@ -930,7 +916,6 @@ static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state) | |||
930 | snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTOP, | 916 | snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTOP, |
931 | &runtime->trigger_tstamp); | 917 | &runtime->trigger_tstamp); |
932 | runtime->status->state = state; | 918 | runtime->status->state = state; |
933 | snd_pcm_tick_set(substream, 0); | ||
934 | } | 919 | } |
935 | wake_up(&runtime->sleep); | 920 | wake_up(&runtime->sleep); |
936 | } | 921 | } |
@@ -1014,12 +999,9 @@ static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push) | |||
1014 | snd_timer_notify(substream->timer, | 999 | snd_timer_notify(substream->timer, |
1015 | SNDRV_TIMER_EVENT_MPAUSE, | 1000 | SNDRV_TIMER_EVENT_MPAUSE, |
1016 | &runtime->trigger_tstamp); | 1001 | &runtime->trigger_tstamp); |
1017 | snd_pcm_tick_set(substream, 0); | ||
1018 | wake_up(&runtime->sleep); | 1002 | wake_up(&runtime->sleep); |
1019 | } else { | 1003 | } else { |
1020 | runtime->status->state = SNDRV_PCM_STATE_RUNNING; | 1004 | runtime->status->state = SNDRV_PCM_STATE_RUNNING; |
1021 | if (runtime->sleep_min) | ||
1022 | snd_pcm_tick_prepare(substream); | ||
1023 | if (substream->timer) | 1005 | if (substream->timer) |
1024 | snd_timer_notify(substream->timer, | 1006 | snd_timer_notify(substream->timer, |
1025 | SNDRV_TIMER_EVENT_MCONTINUE, | 1007 | SNDRV_TIMER_EVENT_MCONTINUE, |
@@ -1074,7 +1056,6 @@ static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state) | |||
1074 | &runtime->trigger_tstamp); | 1056 | &runtime->trigger_tstamp); |
1075 | runtime->status->suspended_state = runtime->status->state; | 1057 | runtime->status->suspended_state = runtime->status->state; |
1076 | runtime->status->state = SNDRV_PCM_STATE_SUSPENDED; | 1058 | runtime->status->state = SNDRV_PCM_STATE_SUSPENDED; |
1077 | snd_pcm_tick_set(substream, 0); | ||
1078 | wake_up(&runtime->sleep); | 1059 | wake_up(&runtime->sleep); |
1079 | } | 1060 | } |
1080 | 1061 | ||
@@ -1177,8 +1158,6 @@ static void snd_pcm_post_resume(struct snd_pcm_substream *substream, int state) | |||
1177 | snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MRESUME, | 1158 | snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MRESUME, |
1178 | &runtime->trigger_tstamp); | 1159 | &runtime->trigger_tstamp); |
1179 | runtime->status->state = runtime->status->suspended_state; | 1160 | runtime->status->state = runtime->status->suspended_state; |
1180 | if (runtime->sleep_min) | ||
1181 | snd_pcm_tick_prepare(substream); | ||
1182 | } | 1161 | } |
1183 | 1162 | ||
1184 | static struct action_ops snd_pcm_action_resume = { | 1163 | static struct action_ops snd_pcm_action_resume = { |
@@ -1395,10 +1374,10 @@ static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, int state) | |||
1395 | } else { | 1374 | } else { |
1396 | /* stop running stream */ | 1375 | /* stop running stream */ |
1397 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) { | 1376 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) { |
1398 | int state = snd_pcm_capture_avail(runtime) > 0 ? | 1377 | int new_state = snd_pcm_capture_avail(runtime) > 0 ? |
1399 | SNDRV_PCM_STATE_DRAINING : SNDRV_PCM_STATE_SETUP; | 1378 | SNDRV_PCM_STATE_DRAINING : SNDRV_PCM_STATE_SETUP; |
1400 | snd_pcm_do_stop(substream, state); | 1379 | snd_pcm_do_stop(substream, new_state); |
1401 | snd_pcm_post_stop(substream, state); | 1380 | snd_pcm_post_stop(substream, new_state); |
1402 | } | 1381 | } |
1403 | } | 1382 | } |
1404 | return 0; | 1383 | return 0; |
@@ -2007,8 +1986,6 @@ int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream) | |||
2007 | } | 1986 | } |
2008 | 1987 | ||
2009 | /* FIXME: this belong to lowlevel */ | 1988 | /* FIXME: this belong to lowlevel */ |
2010 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_TICK_TIME, | ||
2011 | 1000000 / HZ, 1000000 / HZ); | ||
2012 | snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); | 1989 | snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); |
2013 | 1990 | ||
2014 | return 0; | 1991 | return 0; |
@@ -2244,15 +2221,10 @@ static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *subst | |||
2244 | } | 2221 | } |
2245 | if (frames > (snd_pcm_uframes_t)hw_avail) | 2222 | if (frames > (snd_pcm_uframes_t)hw_avail) |
2246 | frames = hw_avail; | 2223 | frames = hw_avail; |
2247 | else | ||
2248 | frames -= frames % runtime->xfer_align; | ||
2249 | appl_ptr = runtime->control->appl_ptr - frames; | 2224 | appl_ptr = runtime->control->appl_ptr - frames; |
2250 | if (appl_ptr < 0) | 2225 | if (appl_ptr < 0) |
2251 | appl_ptr += runtime->boundary; | 2226 | appl_ptr += runtime->boundary; |
2252 | runtime->control->appl_ptr = appl_ptr; | 2227 | runtime->control->appl_ptr = appl_ptr; |
2253 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING && | ||
2254 | runtime->sleep_min) | ||
2255 | snd_pcm_tick_prepare(substream); | ||
2256 | ret = frames; | 2228 | ret = frames; |
2257 | __end: | 2229 | __end: |
2258 | snd_pcm_stream_unlock_irq(substream); | 2230 | snd_pcm_stream_unlock_irq(substream); |
@@ -2294,15 +2266,10 @@ static snd_pcm_sframes_t snd_pcm_capture_rewind(struct snd_pcm_substream *substr | |||
2294 | } | 2266 | } |
2295 | if (frames > (snd_pcm_uframes_t)hw_avail) | 2267 | if (frames > (snd_pcm_uframes_t)hw_avail) |
2296 | frames = hw_avail; | 2268 | frames = hw_avail; |
2297 | else | ||
2298 | frames -= frames % runtime->xfer_align; | ||
2299 | appl_ptr = runtime->control->appl_ptr - frames; | 2269 | appl_ptr = runtime->control->appl_ptr - frames; |
2300 | if (appl_ptr < 0) | 2270 | if (appl_ptr < 0) |
2301 | appl_ptr += runtime->boundary; | 2271 | appl_ptr += runtime->boundary; |
2302 | runtime->control->appl_ptr = appl_ptr; | 2272 | runtime->control->appl_ptr = appl_ptr; |
2303 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING && | ||
2304 | runtime->sleep_min) | ||
2305 | snd_pcm_tick_prepare(substream); | ||
2306 | ret = frames; | 2273 | ret = frames; |
2307 | __end: | 2274 | __end: |
2308 | snd_pcm_stream_unlock_irq(substream); | 2275 | snd_pcm_stream_unlock_irq(substream); |
@@ -2345,15 +2312,10 @@ static snd_pcm_sframes_t snd_pcm_playback_forward(struct snd_pcm_substream *subs | |||
2345 | } | 2312 | } |
2346 | if (frames > (snd_pcm_uframes_t)avail) | 2313 | if (frames > (snd_pcm_uframes_t)avail) |
2347 | frames = avail; | 2314 | frames = avail; |
2348 | else | ||
2349 | frames -= frames % runtime->xfer_align; | ||
2350 | appl_ptr = runtime->control->appl_ptr + frames; | 2315 | appl_ptr = runtime->control->appl_ptr + frames; |
2351 | if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) | 2316 | if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) |
2352 | appl_ptr -= runtime->boundary; | 2317 | appl_ptr -= runtime->boundary; |
2353 | runtime->control->appl_ptr = appl_ptr; | 2318 | runtime->control->appl_ptr = appl_ptr; |
2354 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING && | ||
2355 | runtime->sleep_min) | ||
2356 | snd_pcm_tick_prepare(substream); | ||
2357 | ret = frames; | 2319 | ret = frames; |
2358 | __end: | 2320 | __end: |
2359 | snd_pcm_stream_unlock_irq(substream); | 2321 | snd_pcm_stream_unlock_irq(substream); |
@@ -2396,15 +2358,10 @@ static snd_pcm_sframes_t snd_pcm_capture_forward(struct snd_pcm_substream *subst | |||
2396 | } | 2358 | } |
2397 | if (frames > (snd_pcm_uframes_t)avail) | 2359 | if (frames > (snd_pcm_uframes_t)avail) |
2398 | frames = avail; | 2360 | frames = avail; |
2399 | else | ||
2400 | frames -= frames % runtime->xfer_align; | ||
2401 | appl_ptr = runtime->control->appl_ptr + frames; | 2361 | appl_ptr = runtime->control->appl_ptr + frames; |
2402 | if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) | 2362 | if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) |
2403 | appl_ptr -= runtime->boundary; | 2363 | appl_ptr -= runtime->boundary; |
2404 | runtime->control->appl_ptr = appl_ptr; | 2364 | runtime->control->appl_ptr = appl_ptr; |
2405 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING && | ||
2406 | runtime->sleep_min) | ||
2407 | snd_pcm_tick_prepare(substream); | ||
2408 | ret = frames; | 2365 | ret = frames; |
2409 | __end: | 2366 | __end: |
2410 | snd_pcm_stream_unlock_irq(substream); | 2367 | snd_pcm_stream_unlock_irq(substream); |
@@ -2519,6 +2476,21 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, | |||
2519 | return -EFAULT; | 2476 | return -EFAULT; |
2520 | return 0; | 2477 | return 0; |
2521 | } | 2478 | } |
2479 | |||
2480 | static int snd_pcm_tstamp(struct snd_pcm_substream *substream, int __user *_arg) | ||
2481 | { | ||
2482 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
2483 | int arg; | ||
2484 | |||
2485 | if (get_user(arg, _arg)) | ||
2486 | return -EFAULT; | ||
2487 | if (arg < 0 || arg > SNDRV_PCM_TSTAMP_TYPE_LAST) | ||
2488 | return -EINVAL; | ||
2489 | runtime->tstamp_type = SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY; | ||
2490 | if (arg == SNDRV_PCM_TSTAMP_TYPE_MONOTONIC) | ||
2491 | runtime->tstamp_type = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC; | ||
2492 | return 0; | ||
2493 | } | ||
2522 | 2494 | ||
2523 | static int snd_pcm_common_ioctl1(struct file *file, | 2495 | static int snd_pcm_common_ioctl1(struct file *file, |
2524 | struct snd_pcm_substream *substream, | 2496 | struct snd_pcm_substream *substream, |
@@ -2531,8 +2503,10 @@ static int snd_pcm_common_ioctl1(struct file *file, | |||
2531 | return put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0; | 2503 | return put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0; |
2532 | case SNDRV_PCM_IOCTL_INFO: | 2504 | case SNDRV_PCM_IOCTL_INFO: |
2533 | return snd_pcm_info_user(substream, arg); | 2505 | return snd_pcm_info_user(substream, arg); |
2534 | case SNDRV_PCM_IOCTL_TSTAMP: /* just for compatibility */ | 2506 | case SNDRV_PCM_IOCTL_TSTAMP: /* just for compatibility */ |
2535 | return 0; | 2507 | return 0; |
2508 | case SNDRV_PCM_IOCTL_TTSTAMP: | ||
2509 | return snd_pcm_tstamp(substream, arg); | ||
2536 | case SNDRV_PCM_IOCTL_HW_REFINE: | 2510 | case SNDRV_PCM_IOCTL_HW_REFINE: |
2537 | return snd_pcm_hw_refine_user(substream, arg); | 2511 | return snd_pcm_hw_refine_user(substream, arg); |
2538 | case SNDRV_PCM_IOCTL_HW_PARAMS: | 2512 | case SNDRV_PCM_IOCTL_HW_PARAMS: |
@@ -3018,26 +2992,23 @@ static unsigned int snd_pcm_capture_poll(struct file *file, poll_table * wait) | |||
3018 | /* | 2992 | /* |
3019 | * mmap status record | 2993 | * mmap status record |
3020 | */ | 2994 | */ |
3021 | static struct page * snd_pcm_mmap_status_nopage(struct vm_area_struct *area, | 2995 | static int snd_pcm_mmap_status_fault(struct vm_area_struct *area, |
3022 | unsigned long address, int *type) | 2996 | struct vm_fault *vmf) |
3023 | { | 2997 | { |
3024 | struct snd_pcm_substream *substream = area->vm_private_data; | 2998 | struct snd_pcm_substream *substream = area->vm_private_data; |
3025 | struct snd_pcm_runtime *runtime; | 2999 | struct snd_pcm_runtime *runtime; |
3026 | struct page * page; | ||
3027 | 3000 | ||
3028 | if (substream == NULL) | 3001 | if (substream == NULL) |
3029 | return NOPAGE_SIGBUS; | 3002 | return VM_FAULT_SIGBUS; |
3030 | runtime = substream->runtime; | 3003 | runtime = substream->runtime; |
3031 | page = virt_to_page(runtime->status); | 3004 | vmf->page = virt_to_page(runtime->status); |
3032 | get_page(page); | 3005 | get_page(vmf->page); |
3033 | if (type) | 3006 | return 0; |
3034 | *type = VM_FAULT_MINOR; | ||
3035 | return page; | ||
3036 | } | 3007 | } |
3037 | 3008 | ||
3038 | static struct vm_operations_struct snd_pcm_vm_ops_status = | 3009 | static struct vm_operations_struct snd_pcm_vm_ops_status = |
3039 | { | 3010 | { |
3040 | .nopage = snd_pcm_mmap_status_nopage, | 3011 | .fault = snd_pcm_mmap_status_fault, |
3041 | }; | 3012 | }; |
3042 | 3013 | ||
3043 | static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file, | 3014 | static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file, |
@@ -3061,26 +3032,23 @@ static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file | |||
3061 | /* | 3032 | /* |
3062 | * mmap control record | 3033 | * mmap control record |
3063 | */ | 3034 | */ |
3064 | static struct page * snd_pcm_mmap_control_nopage(struct vm_area_struct *area, | 3035 | static int snd_pcm_mmap_control_fault(struct vm_area_struct *area, |
3065 | unsigned long address, int *type) | 3036 | struct vm_fault *vmf) |
3066 | { | 3037 | { |
3067 | struct snd_pcm_substream *substream = area->vm_private_data; | 3038 | struct snd_pcm_substream *substream = area->vm_private_data; |
3068 | struct snd_pcm_runtime *runtime; | 3039 | struct snd_pcm_runtime *runtime; |
3069 | struct page * page; | ||
3070 | 3040 | ||
3071 | if (substream == NULL) | 3041 | if (substream == NULL) |
3072 | return NOPAGE_SIGBUS; | 3042 | return VM_FAULT_SIGBUS; |
3073 | runtime = substream->runtime; | 3043 | runtime = substream->runtime; |
3074 | page = virt_to_page(runtime->control); | 3044 | vmf->page = virt_to_page(runtime->control); |
3075 | get_page(page); | 3045 | get_page(vmf->page); |
3076 | if (type) | 3046 | return 0; |
3077 | *type = VM_FAULT_MINOR; | ||
3078 | return page; | ||
3079 | } | 3047 | } |
3080 | 3048 | ||
3081 | static struct vm_operations_struct snd_pcm_vm_ops_control = | 3049 | static struct vm_operations_struct snd_pcm_vm_ops_control = |
3082 | { | 3050 | { |
3083 | .nopage = snd_pcm_mmap_control_nopage, | 3051 | .fault = snd_pcm_mmap_control_fault, |
3084 | }; | 3052 | }; |
3085 | 3053 | ||
3086 | static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file *file, | 3054 | static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file *file, |
@@ -3117,10 +3085,10 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file | |||
3117 | #endif /* coherent mmap */ | 3085 | #endif /* coherent mmap */ |
3118 | 3086 | ||
3119 | /* | 3087 | /* |
3120 | * nopage callback for mmapping a RAM page | 3088 | * fault callback for mmapping a RAM page |
3121 | */ | 3089 | */ |
3122 | static struct page *snd_pcm_mmap_data_nopage(struct vm_area_struct *area, | 3090 | static int snd_pcm_mmap_data_fault(struct vm_area_struct *area, |
3123 | unsigned long address, int *type) | 3091 | struct vm_fault *vmf) |
3124 | { | 3092 | { |
3125 | struct snd_pcm_substream *substream = area->vm_private_data; | 3093 | struct snd_pcm_substream *substream = area->vm_private_data; |
3126 | struct snd_pcm_runtime *runtime; | 3094 | struct snd_pcm_runtime *runtime; |
@@ -3130,33 +3098,30 @@ static struct page *snd_pcm_mmap_data_nopage(struct vm_area_struct *area, | |||
3130 | size_t dma_bytes; | 3098 | size_t dma_bytes; |
3131 | 3099 | ||
3132 | if (substream == NULL) | 3100 | if (substream == NULL) |
3133 | return NOPAGE_SIGBUS; | 3101 | return VM_FAULT_SIGBUS; |
3134 | runtime = substream->runtime; | 3102 | runtime = substream->runtime; |
3135 | offset = area->vm_pgoff << PAGE_SHIFT; | 3103 | offset = vmf->pgoff << PAGE_SHIFT; |
3136 | offset += address - area->vm_start; | ||
3137 | snd_assert((offset % PAGE_SIZE) == 0, return NOPAGE_SIGBUS); | ||
3138 | dma_bytes = PAGE_ALIGN(runtime->dma_bytes); | 3104 | dma_bytes = PAGE_ALIGN(runtime->dma_bytes); |
3139 | if (offset > dma_bytes - PAGE_SIZE) | 3105 | if (offset > dma_bytes - PAGE_SIZE) |
3140 | return NOPAGE_SIGBUS; | 3106 | return VM_FAULT_SIGBUS; |
3141 | if (substream->ops->page) { | 3107 | if (substream->ops->page) { |
3142 | page = substream->ops->page(substream, offset); | 3108 | page = substream->ops->page(substream, offset); |
3143 | if (! page) | 3109 | if (!page) |
3144 | return NOPAGE_OOM; /* XXX: is this really due to OOM? */ | 3110 | return VM_FAULT_SIGBUS; |
3145 | } else { | 3111 | } else { |
3146 | vaddr = runtime->dma_area + offset; | 3112 | vaddr = runtime->dma_area + offset; |
3147 | page = virt_to_page(vaddr); | 3113 | page = virt_to_page(vaddr); |
3148 | } | 3114 | } |
3149 | get_page(page); | 3115 | get_page(page); |
3150 | if (type) | 3116 | vmf->page = page; |
3151 | *type = VM_FAULT_MINOR; | 3117 | return 0; |
3152 | return page; | ||
3153 | } | 3118 | } |
3154 | 3119 | ||
3155 | static struct vm_operations_struct snd_pcm_vm_ops_data = | 3120 | static struct vm_operations_struct snd_pcm_vm_ops_data = |
3156 | { | 3121 | { |
3157 | .open = snd_pcm_mmap_data_open, | 3122 | .open = snd_pcm_mmap_data_open, |
3158 | .close = snd_pcm_mmap_data_close, | 3123 | .close = snd_pcm_mmap_data_close, |
3159 | .nopage = snd_pcm_mmap_data_nopage, | 3124 | .fault = snd_pcm_mmap_data_fault, |
3160 | }; | 3125 | }; |
3161 | 3126 | ||
3162 | /* | 3127 | /* |
diff --git a/sound/core/pcm_timer.c b/sound/core/pcm_timer.c index 23aa9a27e215..033a024d153a 100644 --- a/sound/core/pcm_timer.c +++ b/sound/core/pcm_timer.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/time.h> | 22 | #include <linux/time.h> |
24 | #include <sound/core.h> | 23 | #include <sound/core.h> |
25 | #include <sound/pcm.h> | 24 | #include <sound/pcm.h> |
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index b8e700b94e59..f7ea7287c59c 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <sound/core.h> | 22 | #include <sound/core.h> |
24 | #include <linux/major.h> | 23 | #include <linux/major.h> |
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
@@ -912,7 +911,8 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, | |||
912 | } | 911 | } |
913 | 912 | ||
914 | static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, | 913 | static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, |
915 | unsigned char *buf, long count, int kernel) | 914 | unsigned char __user *userbuf, |
915 | unsigned char *kernelbuf, long count) | ||
916 | { | 916 | { |
917 | unsigned long flags; | 917 | unsigned long flags; |
918 | long result = 0, count1; | 918 | long result = 0, count1; |
@@ -925,11 +925,11 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, | |||
925 | spin_lock_irqsave(&runtime->lock, flags); | 925 | spin_lock_irqsave(&runtime->lock, flags); |
926 | if (count1 > (int)runtime->avail) | 926 | if (count1 > (int)runtime->avail) |
927 | count1 = runtime->avail; | 927 | count1 = runtime->avail; |
928 | if (kernel) { | 928 | if (kernelbuf) |
929 | memcpy(buf + result, runtime->buffer + runtime->appl_ptr, count1); | 929 | memcpy(kernelbuf + result, runtime->buffer + runtime->appl_ptr, count1); |
930 | } else { | 930 | if (userbuf) { |
931 | spin_unlock_irqrestore(&runtime->lock, flags); | 931 | spin_unlock_irqrestore(&runtime->lock, flags); |
932 | if (copy_to_user((char __user *)buf + result, | 932 | if (copy_to_user(userbuf + result, |
933 | runtime->buffer + runtime->appl_ptr, count1)) { | 933 | runtime->buffer + runtime->appl_ptr, count1)) { |
934 | return result > 0 ? result : -EFAULT; | 934 | return result > 0 ? result : -EFAULT; |
935 | } | 935 | } |
@@ -949,7 +949,7 @@ long snd_rawmidi_kernel_read(struct snd_rawmidi_substream *substream, | |||
949 | unsigned char *buf, long count) | 949 | unsigned char *buf, long count) |
950 | { | 950 | { |
951 | snd_rawmidi_input_trigger(substream, 1); | 951 | snd_rawmidi_input_trigger(substream, 1); |
952 | return snd_rawmidi_kernel_read1(substream, buf, count, 1); | 952 | return snd_rawmidi_kernel_read1(substream, NULL/*userbuf*/, buf, count); |
953 | } | 953 | } |
954 | 954 | ||
955 | static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t count, | 955 | static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t count, |
@@ -990,8 +990,9 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun | |||
990 | } | 990 | } |
991 | spin_unlock_irq(&runtime->lock); | 991 | spin_unlock_irq(&runtime->lock); |
992 | count1 = snd_rawmidi_kernel_read1(substream, | 992 | count1 = snd_rawmidi_kernel_read1(substream, |
993 | (unsigned char __force *)buf, | 993 | (unsigned char __user *)buf, |
994 | count, 0); | 994 | NULL/*kernelbuf*/, |
995 | count); | ||
995 | if (count1 < 0) | 996 | if (count1 < 0) |
996 | return result > 0 ? result : count1; | 997 | return result > 0 ? result : count1; |
997 | result += count1; | 998 | result += count1; |
@@ -1132,13 +1133,15 @@ int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream, | |||
1132 | } | 1133 | } |
1133 | 1134 | ||
1134 | static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, | 1135 | static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, |
1135 | const unsigned char *buf, long count, int kernel) | 1136 | const unsigned char __user *userbuf, |
1137 | const unsigned char *kernelbuf, | ||
1138 | long count) | ||
1136 | { | 1139 | { |
1137 | unsigned long flags; | 1140 | unsigned long flags; |
1138 | long count1, result; | 1141 | long count1, result; |
1139 | struct snd_rawmidi_runtime *runtime = substream->runtime; | 1142 | struct snd_rawmidi_runtime *runtime = substream->runtime; |
1140 | 1143 | ||
1141 | snd_assert(buf != NULL, return -EINVAL); | 1144 | snd_assert(kernelbuf != NULL || userbuf != NULL, return -EINVAL); |
1142 | snd_assert(runtime->buffer != NULL, return -EINVAL); | 1145 | snd_assert(runtime->buffer != NULL, return -EINVAL); |
1143 | 1146 | ||
1144 | result = 0; | 1147 | result = 0; |
@@ -1155,12 +1158,13 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, | |||
1155 | count1 = count; | 1158 | count1 = count; |
1156 | if (count1 > (long)runtime->avail) | 1159 | if (count1 > (long)runtime->avail) |
1157 | count1 = runtime->avail; | 1160 | count1 = runtime->avail; |
1158 | if (kernel) { | 1161 | if (kernelbuf) |
1159 | memcpy(runtime->buffer + runtime->appl_ptr, buf, count1); | 1162 | memcpy(runtime->buffer + runtime->appl_ptr, |
1160 | } else { | 1163 | kernelbuf + result, count1); |
1164 | else if (userbuf) { | ||
1161 | spin_unlock_irqrestore(&runtime->lock, flags); | 1165 | spin_unlock_irqrestore(&runtime->lock, flags); |
1162 | if (copy_from_user(runtime->buffer + runtime->appl_ptr, | 1166 | if (copy_from_user(runtime->buffer + runtime->appl_ptr, |
1163 | (char __user *)buf, count1)) { | 1167 | userbuf + result, count1)) { |
1164 | spin_lock_irqsave(&runtime->lock, flags); | 1168 | spin_lock_irqsave(&runtime->lock, flags); |
1165 | result = result > 0 ? result : -EFAULT; | 1169 | result = result > 0 ? result : -EFAULT; |
1166 | goto __end; | 1170 | goto __end; |
@@ -1171,7 +1175,6 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, | |||
1171 | runtime->appl_ptr %= runtime->buffer_size; | 1175 | runtime->appl_ptr %= runtime->buffer_size; |
1172 | runtime->avail -= count1; | 1176 | runtime->avail -= count1; |
1173 | result += count1; | 1177 | result += count1; |
1174 | buf += count1; | ||
1175 | count -= count1; | 1178 | count -= count1; |
1176 | } | 1179 | } |
1177 | __end: | 1180 | __end: |
@@ -1185,7 +1188,7 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, | |||
1185 | long snd_rawmidi_kernel_write(struct snd_rawmidi_substream *substream, | 1188 | long snd_rawmidi_kernel_write(struct snd_rawmidi_substream *substream, |
1186 | const unsigned char *buf, long count) | 1189 | const unsigned char *buf, long count) |
1187 | { | 1190 | { |
1188 | return snd_rawmidi_kernel_write1(substream, buf, count, 1); | 1191 | return snd_rawmidi_kernel_write1(substream, NULL, buf, count); |
1189 | } | 1192 | } |
1190 | 1193 | ||
1191 | static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, | 1194 | static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, |
@@ -1225,9 +1228,7 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, | |||
1225 | spin_lock_irq(&runtime->lock); | 1228 | spin_lock_irq(&runtime->lock); |
1226 | } | 1229 | } |
1227 | spin_unlock_irq(&runtime->lock); | 1230 | spin_unlock_irq(&runtime->lock); |
1228 | count1 = snd_rawmidi_kernel_write1(substream, | 1231 | count1 = snd_rawmidi_kernel_write1(substream, buf, NULL, count); |
1229 | (unsigned char __force *)buf, | ||
1230 | count, 0); | ||
1231 | if (count1 < 0) | 1232 | if (count1 < 0) |
1232 | return result > 0 ? result : count1; | 1233 | return result > 0 ? result : count1; |
1233 | result += count1; | 1234 | result += count1; |
diff --git a/sound/core/rtctimer.c b/sound/core/rtctimer.c index 7cd5e8f5d4ce..97b30fb4c361 100644 --- a/sound/core/rtctimer.c +++ b/sound/core/rtctimer.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
26 | #include <linux/moduleparam.h> | 25 | #include <linux/moduleparam.h> |
diff --git a/sound/core/seq/Makefile b/sound/core/seq/Makefile index ceef14afee30..069593717fba 100644 --- a/sound/core/seq/Makefile +++ b/sound/core/seq/Makefile | |||
@@ -3,7 +3,6 @@ | |||
3 | # Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> | 3 | # Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> |
4 | # | 4 | # |
5 | 5 | ||
6 | obj-$(CONFIG_SND) += instr/ | ||
7 | ifeq ($(CONFIG_SND_SEQUENCER_OSS),y) | 6 | ifeq ($(CONFIG_SND_SEQUENCER_OSS),y) |
8 | obj-$(CONFIG_SND_SEQUENCER) += oss/ | 7 | obj-$(CONFIG_SND_SEQUENCER) += oss/ |
9 | endif | 8 | endif |
@@ -15,7 +14,6 @@ snd-seq-objs := seq.o seq_lock.o seq_clientmgr.o seq_memory.o seq_queue.o \ | |||
15 | snd-seq-midi-objs := seq_midi.o | 14 | snd-seq-midi-objs := seq_midi.o |
16 | snd-seq-midi-emul-objs := seq_midi_emul.o | 15 | snd-seq-midi-emul-objs := seq_midi_emul.o |
17 | snd-seq-midi-event-objs := seq_midi_event.o | 16 | snd-seq-midi-event-objs := seq_midi_event.o |
18 | snd-seq-instr-objs := seq_instr.o | ||
19 | snd-seq-dummy-objs := seq_dummy.o | 17 | snd-seq-dummy-objs := seq_dummy.o |
20 | snd-seq-virmidi-objs := seq_virmidi.o | 18 | snd-seq-virmidi-objs := seq_virmidi.o |
21 | 19 | ||
@@ -36,9 +34,7 @@ obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-dummy.o | |||
36 | # Toplevel Module Dependency | 34 | # Toplevel Module Dependency |
37 | obj-$(CONFIG_SND_VIRMIDI) += snd-seq-virmidi.o snd-seq-midi-event.o | 35 | obj-$(CONFIG_SND_VIRMIDI) += snd-seq-virmidi.o snd-seq-midi-event.o |
38 | obj-$(call sequencer,$(CONFIG_SND_RAWMIDI)) += snd-seq-midi.o snd-seq-midi-event.o | 36 | obj-$(call sequencer,$(CONFIG_SND_RAWMIDI)) += snd-seq-midi.o snd-seq-midi-event.o |
39 | obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o | 37 | obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o |
40 | obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o | 38 | obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o |
41 | obj-$(call sequencer,$(CONFIG_SND_GUS_SYNTH)) += snd-seq-midi-emul.o snd-seq-instr.o | ||
42 | obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-seq-midi-emul.o snd-seq-virmidi.o | 39 | obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-seq-midi-emul.o snd-seq-virmidi.o |
43 | obj-$(call sequencer,$(CONFIG_SND_EMU10K1)) += snd-seq-midi-emul.o snd-seq-virmidi.o | 40 | obj-$(call sequencer,$(CONFIG_SND_EMU10K1)) += snd-seq-midi-emul.o snd-seq-virmidi.o |
44 | obj-$(call sequencer,$(CONFIG_SND_TRIDENT)) += snd-seq-midi-emul.o snd-seq-instr.o | ||
diff --git a/sound/core/seq/instr/Makefile b/sound/core/seq/instr/Makefile deleted file mode 100644 index 608960364813..000000000000 --- a/sound/core/seq/instr/Makefile +++ /dev/null | |||
@@ -1,23 +0,0 @@ | |||
1 | # | ||
2 | # Makefile for ALSA | ||
3 | # Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> | ||
4 | # | ||
5 | |||
6 | snd-ainstr-fm-objs := ainstr_fm.o | ||
7 | snd-ainstr-simple-objs := ainstr_simple.o | ||
8 | snd-ainstr-gf1-objs := ainstr_gf1.o | ||
9 | snd-ainstr-iw-objs := ainstr_iw.o | ||
10 | |||
11 | # | ||
12 | # this function returns: | ||
13 | # "m" - CONFIG_SND_SEQUENCER is m | ||
14 | # <empty string> - CONFIG_SND_SEQUENCER is undefined | ||
15 | # otherwise parameter #1 value | ||
16 | # | ||
17 | sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) | ||
18 | |||
19 | # Toplevel Module Dependency | ||
20 | obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-ainstr-fm.o | ||
21 | obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-ainstr-fm.o | ||
22 | obj-$(call sequencer,$(CONFIG_SND_GUS_SYNTH)) += snd-ainstr-gf1.o snd-ainstr-simple.o snd-ainstr-iw.o | ||
23 | obj-$(call sequencer,$(CONFIG_SND_TRIDENT)) += snd-ainstr-simple.o | ||
diff --git a/sound/core/seq/instr/ainstr_fm.c b/sound/core/seq/instr/ainstr_fm.c deleted file mode 100644 index f80fab8f2ed1..000000000000 --- a/sound/core/seq/instr/ainstr_fm.c +++ /dev/null | |||
@@ -1,155 +0,0 @@ | |||
1 | /* | ||
2 | * FM (OPL2/3) Instrument routines | ||
3 | * Copyright (c) 2000 Uros Bizjak <uros@kss-loka.si> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include <sound/driver.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <sound/core.h> | ||
24 | #include <sound/ainstr_fm.h> | ||
25 | #include <sound/initval.h> | ||
26 | #include <asm/uaccess.h> | ||
27 | |||
28 | MODULE_AUTHOR("Uros Bizjak <uros@kss-loka.si>"); | ||
29 | MODULE_DESCRIPTION("Advanced Linux Sound Architecture FM Instrument support."); | ||
30 | MODULE_LICENSE("GPL"); | ||
31 | |||
32 | static int snd_seq_fm_put(void *private_data, struct snd_seq_kinstr *instr, | ||
33 | char __user *instr_data, long len, int atomic, int cmd) | ||
34 | { | ||
35 | struct fm_instrument *ip; | ||
36 | struct fm_xinstrument ix; | ||
37 | int idx; | ||
38 | |||
39 | if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE) | ||
40 | return -EINVAL; | ||
41 | /* copy instrument data */ | ||
42 | if (len < (long)sizeof(ix)) | ||
43 | return -EINVAL; | ||
44 | if (copy_from_user(&ix, instr_data, sizeof(ix))) | ||
45 | return -EFAULT; | ||
46 | if (ix.stype != FM_STRU_INSTR) | ||
47 | return -EINVAL; | ||
48 | ip = (struct fm_instrument *)KINSTR_DATA(instr); | ||
49 | ip->share_id[0] = le32_to_cpu(ix.share_id[0]); | ||
50 | ip->share_id[1] = le32_to_cpu(ix.share_id[1]); | ||
51 | ip->share_id[2] = le32_to_cpu(ix.share_id[2]); | ||
52 | ip->share_id[3] = le32_to_cpu(ix.share_id[3]); | ||
53 | ip->type = ix.type; | ||
54 | for (idx = 0; idx < 4; idx++) { | ||
55 | ip->op[idx].am_vib = ix.op[idx].am_vib; | ||
56 | ip->op[idx].ksl_level = ix.op[idx].ksl_level; | ||
57 | ip->op[idx].attack_decay = ix.op[idx].attack_decay; | ||
58 | ip->op[idx].sustain_release = ix.op[idx].sustain_release; | ||
59 | ip->op[idx].wave_select = ix.op[idx].wave_select; | ||
60 | } | ||
61 | for (idx = 0; idx < 2; idx++) { | ||
62 | ip->feedback_connection[idx] = ix.feedback_connection[idx]; | ||
63 | } | ||
64 | ip->echo_delay = ix.echo_delay; | ||
65 | ip->echo_atten = ix.echo_atten; | ||
66 | ip->chorus_spread = ix.chorus_spread; | ||
67 | ip->trnsps = ix.trnsps; | ||
68 | ip->fix_dur = ix.fix_dur; | ||
69 | ip->modes = ix.modes; | ||
70 | ip->fix_key = ix.fix_key; | ||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | static int snd_seq_fm_get(void *private_data, struct snd_seq_kinstr *instr, | ||
75 | char __user *instr_data, long len, int atomic, | ||
76 | int cmd) | ||
77 | { | ||
78 | struct fm_instrument *ip; | ||
79 | struct fm_xinstrument ix; | ||
80 | int idx; | ||
81 | |||
82 | if (cmd != SNDRV_SEQ_INSTR_GET_CMD_FULL) | ||
83 | return -EINVAL; | ||
84 | if (len < (long)sizeof(ix)) | ||
85 | return -ENOMEM; | ||
86 | memset(&ix, 0, sizeof(ix)); | ||
87 | ip = (struct fm_instrument *)KINSTR_DATA(instr); | ||
88 | ix.stype = FM_STRU_INSTR; | ||
89 | ix.share_id[0] = cpu_to_le32(ip->share_id[0]); | ||
90 | ix.share_id[1] = cpu_to_le32(ip->share_id[1]); | ||
91 | ix.share_id[2] = cpu_to_le32(ip->share_id[2]); | ||
92 | ix.share_id[3] = cpu_to_le32(ip->share_id[3]); | ||
93 | ix.type = ip->type; | ||
94 | for (idx = 0; idx < 4; idx++) { | ||
95 | ix.op[idx].am_vib = ip->op[idx].am_vib; | ||
96 | ix.op[idx].ksl_level = ip->op[idx].ksl_level; | ||
97 | ix.op[idx].attack_decay = ip->op[idx].attack_decay; | ||
98 | ix.op[idx].sustain_release = ip->op[idx].sustain_release; | ||
99 | ix.op[idx].wave_select = ip->op[idx].wave_select; | ||
100 | } | ||
101 | for (idx = 0; idx < 2; idx++) { | ||
102 | ix.feedback_connection[idx] = ip->feedback_connection[idx]; | ||
103 | } | ||
104 | if (copy_to_user(instr_data, &ix, sizeof(ix))) | ||
105 | return -EFAULT; | ||
106 | ix.echo_delay = ip->echo_delay; | ||
107 | ix.echo_atten = ip->echo_atten; | ||
108 | ix.chorus_spread = ip->chorus_spread; | ||
109 | ix.trnsps = ip->trnsps; | ||
110 | ix.fix_dur = ip->fix_dur; | ||
111 | ix.modes = ip->modes; | ||
112 | ix.fix_key = ip->fix_key; | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static int snd_seq_fm_get_size(void *private_data, struct snd_seq_kinstr *instr, | ||
117 | long *size) | ||
118 | { | ||
119 | *size = sizeof(struct fm_xinstrument); | ||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | int snd_seq_fm_init(struct snd_seq_kinstr_ops *ops, | ||
124 | struct snd_seq_kinstr_ops *next) | ||
125 | { | ||
126 | memset(ops, 0, sizeof(*ops)); | ||
127 | // ops->private_data = private_data; | ||
128 | ops->add_len = sizeof(struct fm_instrument); | ||
129 | ops->instr_type = SNDRV_SEQ_INSTR_ID_OPL2_3; | ||
130 | ops->put = snd_seq_fm_put; | ||
131 | ops->get = snd_seq_fm_get; | ||
132 | ops->get_size = snd_seq_fm_get_size; | ||
133 | // ops->remove = snd_seq_fm_remove; | ||
134 | // ops->notify = snd_seq_fm_notify; | ||
135 | ops->next = next; | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | /* | ||
140 | * Init part | ||
141 | */ | ||
142 | |||
143 | static int __init alsa_ainstr_fm_init(void) | ||
144 | { | ||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | static void __exit alsa_ainstr_fm_exit(void) | ||
149 | { | ||
150 | } | ||
151 | |||
152 | module_init(alsa_ainstr_fm_init) | ||
153 | module_exit(alsa_ainstr_fm_exit) | ||
154 | |||
155 | EXPORT_SYMBOL(snd_seq_fm_init); | ||
diff --git a/sound/core/seq/instr/ainstr_gf1.c b/sound/core/seq/instr/ainstr_gf1.c deleted file mode 100644 index 49400262b1eb..000000000000 --- a/sound/core/seq/instr/ainstr_gf1.c +++ /dev/null | |||
@@ -1,359 +0,0 @@ | |||
1 | /* | ||
2 | * GF1 (GUS) Patch - Instrument routines | ||
3 | * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include <sound/driver.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <sound/core.h> | ||
25 | #include <sound/ainstr_gf1.h> | ||
26 | #include <sound/initval.h> | ||
27 | #include <asm/uaccess.h> | ||
28 | |||
29 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); | ||
30 | MODULE_DESCRIPTION("Advanced Linux Sound Architecture GF1 (GUS) Patch support."); | ||
31 | MODULE_LICENSE("GPL"); | ||
32 | |||
33 | static unsigned int snd_seq_gf1_size(unsigned int size, unsigned int format) | ||
34 | { | ||
35 | unsigned int result = size; | ||
36 | |||
37 | if (format & GF1_WAVE_16BIT) | ||
38 | result <<= 1; | ||
39 | if (format & GF1_WAVE_STEREO) | ||
40 | result <<= 1; | ||
41 | return format; | ||
42 | } | ||
43 | |||
44 | static int snd_seq_gf1_copy_wave_from_stream(struct snd_gf1_ops *ops, | ||
45 | struct gf1_instrument *ip, | ||
46 | char __user **data, | ||
47 | long *len, | ||
48 | int atomic) | ||
49 | { | ||
50 | struct gf1_wave *wp, *prev; | ||
51 | struct gf1_xwave xp; | ||
52 | int err; | ||
53 | gfp_t gfp_mask; | ||
54 | unsigned int real_size; | ||
55 | |||
56 | gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL; | ||
57 | if (*len < (long)sizeof(xp)) | ||
58 | return -EINVAL; | ||
59 | if (copy_from_user(&xp, *data, sizeof(xp))) | ||
60 | return -EFAULT; | ||
61 | *data += sizeof(xp); | ||
62 | *len -= sizeof(xp); | ||
63 | wp = kzalloc(sizeof(*wp), gfp_mask); | ||
64 | if (wp == NULL) | ||
65 | return -ENOMEM; | ||
66 | wp->share_id[0] = le32_to_cpu(xp.share_id[0]); | ||
67 | wp->share_id[1] = le32_to_cpu(xp.share_id[1]); | ||
68 | wp->share_id[2] = le32_to_cpu(xp.share_id[2]); | ||
69 | wp->share_id[3] = le32_to_cpu(xp.share_id[3]); | ||
70 | wp->format = le32_to_cpu(xp.format); | ||
71 | wp->size = le32_to_cpu(xp.size); | ||
72 | wp->start = le32_to_cpu(xp.start); | ||
73 | wp->loop_start = le32_to_cpu(xp.loop_start); | ||
74 | wp->loop_end = le32_to_cpu(xp.loop_end); | ||
75 | wp->loop_repeat = le16_to_cpu(xp.loop_repeat); | ||
76 | wp->flags = xp.flags; | ||
77 | wp->sample_rate = le32_to_cpu(xp.sample_rate); | ||
78 | wp->low_frequency = le32_to_cpu(xp.low_frequency); | ||
79 | wp->high_frequency = le32_to_cpu(xp.high_frequency); | ||
80 | wp->root_frequency = le32_to_cpu(xp.root_frequency); | ||
81 | wp->tune = le16_to_cpu(xp.tune); | ||
82 | wp->balance = xp.balance; | ||
83 | memcpy(wp->envelope_rate, xp.envelope_rate, 6); | ||
84 | memcpy(wp->envelope_offset, xp.envelope_offset, 6); | ||
85 | wp->tremolo_sweep = xp.tremolo_sweep; | ||
86 | wp->tremolo_rate = xp.tremolo_rate; | ||
87 | wp->tremolo_depth = xp.tremolo_depth; | ||
88 | wp->vibrato_sweep = xp.vibrato_sweep; | ||
89 | wp->vibrato_rate = xp.vibrato_rate; | ||
90 | wp->vibrato_depth = xp.vibrato_depth; | ||
91 | wp->scale_frequency = le16_to_cpu(xp.scale_frequency); | ||
92 | wp->scale_factor = le16_to_cpu(xp.scale_factor); | ||
93 | real_size = snd_seq_gf1_size(wp->size, wp->format); | ||
94 | if ((long)real_size > *len) { | ||
95 | kfree(wp); | ||
96 | return -ENOMEM; | ||
97 | } | ||
98 | if (ops->put_sample) { | ||
99 | err = ops->put_sample(ops->private_data, wp, | ||
100 | *data, real_size, atomic); | ||
101 | if (err < 0) { | ||
102 | kfree(wp); | ||
103 | return err; | ||
104 | } | ||
105 | } | ||
106 | *data += real_size; | ||
107 | *len -= real_size; | ||
108 | prev = ip->wave; | ||
109 | if (prev) { | ||
110 | while (prev->next) prev = prev->next; | ||
111 | prev->next = wp; | ||
112 | } else { | ||
113 | ip->wave = wp; | ||
114 | } | ||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | static void snd_seq_gf1_wave_free(struct snd_gf1_ops *ops, | ||
119 | struct gf1_wave *wave, | ||
120 | int atomic) | ||
121 | { | ||
122 | if (ops->remove_sample) | ||
123 | ops->remove_sample(ops->private_data, wave, atomic); | ||
124 | kfree(wave); | ||
125 | } | ||
126 | |||
127 | static void snd_seq_gf1_instr_free(struct snd_gf1_ops *ops, | ||
128 | struct gf1_instrument *ip, | ||
129 | int atomic) | ||
130 | { | ||
131 | struct gf1_wave *wave; | ||
132 | |||
133 | while ((wave = ip->wave) != NULL) { | ||
134 | ip->wave = wave->next; | ||
135 | snd_seq_gf1_wave_free(ops, wave, atomic); | ||
136 | } | ||
137 | } | ||
138 | |||
139 | static int snd_seq_gf1_put(void *private_data, struct snd_seq_kinstr *instr, | ||
140 | char __user *instr_data, long len, int atomic, | ||
141 | int cmd) | ||
142 | { | ||
143 | struct snd_gf1_ops *ops = private_data; | ||
144 | struct gf1_instrument *ip; | ||
145 | struct gf1_xinstrument ix; | ||
146 | int err; | ||
147 | gfp_t gfp_mask; | ||
148 | |||
149 | if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE) | ||
150 | return -EINVAL; | ||
151 | gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL; | ||
152 | /* copy instrument data */ | ||
153 | if (len < (long)sizeof(ix)) | ||
154 | return -EINVAL; | ||
155 | if (copy_from_user(&ix, instr_data, sizeof(ix))) | ||
156 | return -EFAULT; | ||
157 | if (ix.stype != GF1_STRU_INSTR) | ||
158 | return -EINVAL; | ||
159 | instr_data += sizeof(ix); | ||
160 | len -= sizeof(ix); | ||
161 | ip = (struct gf1_instrument *)KINSTR_DATA(instr); | ||
162 | ip->exclusion = le16_to_cpu(ix.exclusion); | ||
163 | ip->exclusion_group = le16_to_cpu(ix.exclusion_group); | ||
164 | ip->effect1 = ix.effect1; | ||
165 | ip->effect1_depth = ix.effect1_depth; | ||
166 | ip->effect2 = ix.effect2; | ||
167 | ip->effect2_depth = ix.effect2_depth; | ||
168 | /* copy layers */ | ||
169 | while (len > (long)sizeof(__u32)) { | ||
170 | __u32 stype; | ||
171 | |||
172 | if (copy_from_user(&stype, instr_data, sizeof(stype))) | ||
173 | return -EFAULT; | ||
174 | if (stype != GF1_STRU_WAVE) { | ||
175 | snd_seq_gf1_instr_free(ops, ip, atomic); | ||
176 | return -EINVAL; | ||
177 | } | ||
178 | err = snd_seq_gf1_copy_wave_from_stream(ops, | ||
179 | ip, | ||
180 | &instr_data, | ||
181 | &len, | ||
182 | atomic); | ||
183 | if (err < 0) { | ||
184 | snd_seq_gf1_instr_free(ops, ip, atomic); | ||
185 | return err; | ||
186 | } | ||
187 | } | ||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | static int snd_seq_gf1_copy_wave_to_stream(struct snd_gf1_ops *ops, | ||
192 | struct gf1_instrument *ip, | ||
193 | char __user **data, | ||
194 | long *len, | ||
195 | int atomic) | ||
196 | { | ||
197 | struct gf1_wave *wp; | ||
198 | struct gf1_xwave xp; | ||
199 | int err; | ||
200 | unsigned int real_size; | ||
201 | |||
202 | for (wp = ip->wave; wp; wp = wp->next) { | ||
203 | if (*len < (long)sizeof(xp)) | ||
204 | return -ENOMEM; | ||
205 | memset(&xp, 0, sizeof(xp)); | ||
206 | xp.stype = GF1_STRU_WAVE; | ||
207 | xp.share_id[0] = cpu_to_le32(wp->share_id[0]); | ||
208 | xp.share_id[1] = cpu_to_le32(wp->share_id[1]); | ||
209 | xp.share_id[2] = cpu_to_le32(wp->share_id[2]); | ||
210 | xp.share_id[3] = cpu_to_le32(wp->share_id[3]); | ||
211 | xp.format = cpu_to_le32(wp->format); | ||
212 | xp.size = cpu_to_le32(wp->size); | ||
213 | xp.start = cpu_to_le32(wp->start); | ||
214 | xp.loop_start = cpu_to_le32(wp->loop_start); | ||
215 | xp.loop_end = cpu_to_le32(wp->loop_end); | ||
216 | xp.loop_repeat = cpu_to_le32(wp->loop_repeat); | ||
217 | xp.flags = wp->flags; | ||
218 | xp.sample_rate = cpu_to_le32(wp->sample_rate); | ||
219 | xp.low_frequency = cpu_to_le32(wp->low_frequency); | ||
220 | xp.high_frequency = cpu_to_le32(wp->high_frequency); | ||
221 | xp.root_frequency = cpu_to_le32(wp->root_frequency); | ||
222 | xp.tune = cpu_to_le16(wp->tune); | ||
223 | xp.balance = wp->balance; | ||
224 | memcpy(xp.envelope_rate, wp->envelope_rate, 6); | ||
225 | memcpy(xp.envelope_offset, wp->envelope_offset, 6); | ||
226 | xp.tremolo_sweep = wp->tremolo_sweep; | ||
227 | xp.tremolo_rate = wp->tremolo_rate; | ||
228 | xp.tremolo_depth = wp->tremolo_depth; | ||
229 | xp.vibrato_sweep = wp->vibrato_sweep; | ||
230 | xp.vibrato_rate = wp->vibrato_rate; | ||
231 | xp.vibrato_depth = wp->vibrato_depth; | ||
232 | xp.scale_frequency = cpu_to_le16(wp->scale_frequency); | ||
233 | xp.scale_factor = cpu_to_le16(wp->scale_factor); | ||
234 | if (copy_to_user(*data, &xp, sizeof(xp))) | ||
235 | return -EFAULT; | ||
236 | *data += sizeof(xp); | ||
237 | *len -= sizeof(xp); | ||
238 | real_size = snd_seq_gf1_size(wp->size, wp->format); | ||
239 | if (*len < (long)real_size) | ||
240 | return -ENOMEM; | ||
241 | if (ops->get_sample) { | ||
242 | err = ops->get_sample(ops->private_data, wp, | ||
243 | *data, real_size, atomic); | ||
244 | if (err < 0) | ||
245 | return err; | ||
246 | } | ||
247 | *data += wp->size; | ||
248 | *len -= wp->size; | ||
249 | } | ||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | static int snd_seq_gf1_get(void *private_data, struct snd_seq_kinstr *instr, | ||
254 | char __user *instr_data, long len, int atomic, | ||
255 | int cmd) | ||
256 | { | ||
257 | struct snd_gf1_ops *ops = private_data; | ||
258 | struct gf1_instrument *ip; | ||
259 | struct gf1_xinstrument ix; | ||
260 | |||
261 | if (cmd != SNDRV_SEQ_INSTR_GET_CMD_FULL) | ||
262 | return -EINVAL; | ||
263 | if (len < (long)sizeof(ix)) | ||
264 | return -ENOMEM; | ||
265 | memset(&ix, 0, sizeof(ix)); | ||
266 | ip = (struct gf1_instrument *)KINSTR_DATA(instr); | ||
267 | ix.stype = GF1_STRU_INSTR; | ||
268 | ix.exclusion = cpu_to_le16(ip->exclusion); | ||
269 | ix.exclusion_group = cpu_to_le16(ip->exclusion_group); | ||
270 | ix.effect1 = cpu_to_le16(ip->effect1); | ||
271 | ix.effect1_depth = cpu_to_le16(ip->effect1_depth); | ||
272 | ix.effect2 = ip->effect2; | ||
273 | ix.effect2_depth = ip->effect2_depth; | ||
274 | if (copy_to_user(instr_data, &ix, sizeof(ix))) | ||
275 | return -EFAULT; | ||
276 | instr_data += sizeof(ix); | ||
277 | len -= sizeof(ix); | ||
278 | return snd_seq_gf1_copy_wave_to_stream(ops, | ||
279 | ip, | ||
280 | &instr_data, | ||
281 | &len, | ||
282 | atomic); | ||
283 | } | ||
284 | |||
285 | static int snd_seq_gf1_get_size(void *private_data, struct snd_seq_kinstr *instr, | ||
286 | long *size) | ||
287 | { | ||
288 | long result; | ||
289 | struct gf1_instrument *ip; | ||
290 | struct gf1_wave *wp; | ||
291 | |||
292 | *size = 0; | ||
293 | ip = (struct gf1_instrument *)KINSTR_DATA(instr); | ||
294 | result = sizeof(struct gf1_xinstrument); | ||
295 | for (wp = ip->wave; wp; wp = wp->next) { | ||
296 | result += sizeof(struct gf1_xwave); | ||
297 | result += wp->size; | ||
298 | } | ||
299 | *size = result; | ||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static int snd_seq_gf1_remove(void *private_data, | ||
304 | struct snd_seq_kinstr *instr, | ||
305 | int atomic) | ||
306 | { | ||
307 | struct snd_gf1_ops *ops = private_data; | ||
308 | struct gf1_instrument *ip; | ||
309 | |||
310 | ip = (struct gf1_instrument *)KINSTR_DATA(instr); | ||
311 | snd_seq_gf1_instr_free(ops, ip, atomic); | ||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | static void snd_seq_gf1_notify(void *private_data, | ||
316 | struct snd_seq_kinstr *instr, | ||
317 | int what) | ||
318 | { | ||
319 | struct snd_gf1_ops *ops = private_data; | ||
320 | |||
321 | if (ops->notify) | ||
322 | ops->notify(ops->private_data, instr, what); | ||
323 | } | ||
324 | |||
325 | int snd_seq_gf1_init(struct snd_gf1_ops *ops, | ||
326 | void *private_data, | ||
327 | struct snd_seq_kinstr_ops *next) | ||
328 | { | ||
329 | memset(ops, 0, sizeof(*ops)); | ||
330 | ops->private_data = private_data; | ||
331 | ops->kops.private_data = ops; | ||
332 | ops->kops.add_len = sizeof(struct gf1_instrument); | ||
333 | ops->kops.instr_type = SNDRV_SEQ_INSTR_ID_GUS_PATCH; | ||
334 | ops->kops.put = snd_seq_gf1_put; | ||
335 | ops->kops.get = snd_seq_gf1_get; | ||
336 | ops->kops.get_size = snd_seq_gf1_get_size; | ||
337 | ops->kops.remove = snd_seq_gf1_remove; | ||
338 | ops->kops.notify = snd_seq_gf1_notify; | ||
339 | ops->kops.next = next; | ||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | /* | ||
344 | * Init part | ||
345 | */ | ||
346 | |||
347 | static int __init alsa_ainstr_gf1_init(void) | ||
348 | { | ||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | static void __exit alsa_ainstr_gf1_exit(void) | ||
353 | { | ||
354 | } | ||
355 | |||
356 | module_init(alsa_ainstr_gf1_init) | ||
357 | module_exit(alsa_ainstr_gf1_exit) | ||
358 | |||
359 | EXPORT_SYMBOL(snd_seq_gf1_init); | ||
diff --git a/sound/core/seq/instr/ainstr_iw.c b/sound/core/seq/instr/ainstr_iw.c deleted file mode 100644 index 6c40eb73fa9f..000000000000 --- a/sound/core/seq/instr/ainstr_iw.c +++ /dev/null | |||
@@ -1,623 +0,0 @@ | |||
1 | /* | ||
2 | * IWFFFF - AMD InterWave (tm) - Instrument routines | ||
3 | * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include <sound/driver.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <sound/core.h> | ||
25 | #include <sound/ainstr_iw.h> | ||
26 | #include <sound/initval.h> | ||
27 | #include <asm/uaccess.h> | ||
28 | |||
29 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); | ||
30 | MODULE_DESCRIPTION("Advanced Linux Sound Architecture IWFFFF support."); | ||
31 | MODULE_LICENSE("GPL"); | ||
32 | |||
33 | static unsigned int snd_seq_iwffff_size(unsigned int size, unsigned int format) | ||
34 | { | ||
35 | unsigned int result = size; | ||
36 | |||
37 | if (format & IWFFFF_WAVE_16BIT) | ||
38 | result <<= 1; | ||
39 | if (format & IWFFFF_WAVE_STEREO) | ||
40 | result <<= 1; | ||
41 | return result; | ||
42 | } | ||
43 | |||
44 | static void snd_seq_iwffff_copy_lfo_from_stream(struct iwffff_lfo *fp, | ||
45 | struct iwffff_xlfo *fx) | ||
46 | { | ||
47 | fp->freq = le16_to_cpu(fx->freq); | ||
48 | fp->depth = le16_to_cpu(fx->depth); | ||
49 | fp->sweep = le16_to_cpu(fx->sweep); | ||
50 | fp->shape = fx->shape; | ||
51 | fp->delay = fx->delay; | ||
52 | } | ||
53 | |||
54 | static int snd_seq_iwffff_copy_env_from_stream(__u32 req_stype, | ||
55 | struct iwffff_layer *lp, | ||
56 | struct iwffff_env *ep, | ||
57 | struct iwffff_xenv *ex, | ||
58 | char __user **data, | ||
59 | long *len, | ||
60 | gfp_t gfp_mask) | ||
61 | { | ||
62 | __u32 stype; | ||
63 | struct iwffff_env_record *rp, *rp_last; | ||
64 | struct iwffff_xenv_record rx; | ||
65 | struct iwffff_env_point *pp; | ||
66 | struct iwffff_xenv_point px; | ||
67 | int points_size, idx; | ||
68 | |||
69 | ep->flags = ex->flags; | ||
70 | ep->mode = ex->mode; | ||
71 | ep->index = ex->index; | ||
72 | rp_last = NULL; | ||
73 | while (1) { | ||
74 | if (*len < (long)sizeof(__u32)) | ||
75 | return -EINVAL; | ||
76 | if (copy_from_user(&stype, *data, sizeof(stype))) | ||
77 | return -EFAULT; | ||
78 | if (stype == IWFFFF_STRU_WAVE) | ||
79 | return 0; | ||
80 | if (req_stype != stype) { | ||
81 | if (stype == IWFFFF_STRU_ENV_RECP || | ||
82 | stype == IWFFFF_STRU_ENV_RECV) | ||
83 | return 0; | ||
84 | } | ||
85 | if (*len < (long)sizeof(rx)) | ||
86 | return -EINVAL; | ||
87 | if (copy_from_user(&rx, *data, sizeof(rx))) | ||
88 | return -EFAULT; | ||
89 | *data += sizeof(rx); | ||
90 | *len -= sizeof(rx); | ||
91 | points_size = (le16_to_cpu(rx.nattack) + le16_to_cpu(rx.nrelease)) * 2 * sizeof(__u16); | ||
92 | if (points_size > *len) | ||
93 | return -EINVAL; | ||
94 | rp = kzalloc(sizeof(*rp) + points_size, gfp_mask); | ||
95 | if (rp == NULL) | ||
96 | return -ENOMEM; | ||
97 | rp->nattack = le16_to_cpu(rx.nattack); | ||
98 | rp->nrelease = le16_to_cpu(rx.nrelease); | ||
99 | rp->sustain_offset = le16_to_cpu(rx.sustain_offset); | ||
100 | rp->sustain_rate = le16_to_cpu(rx.sustain_rate); | ||
101 | rp->release_rate = le16_to_cpu(rx.release_rate); | ||
102 | rp->hirange = rx.hirange; | ||
103 | pp = (struct iwffff_env_point *)(rp + 1); | ||
104 | for (idx = 0; idx < rp->nattack + rp->nrelease; idx++) { | ||
105 | if (copy_from_user(&px, *data, sizeof(px))) | ||
106 | return -EFAULT; | ||
107 | *data += sizeof(px); | ||
108 | *len -= sizeof(px); | ||
109 | pp->offset = le16_to_cpu(px.offset); | ||
110 | pp->rate = le16_to_cpu(px.rate); | ||
111 | } | ||
112 | if (ep->record == NULL) { | ||
113 | ep->record = rp; | ||
114 | } else { | ||
115 | rp_last = rp; | ||
116 | } | ||
117 | rp_last = rp; | ||
118 | } | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | static int snd_seq_iwffff_copy_wave_from_stream(struct snd_iwffff_ops *ops, | ||
123 | struct iwffff_layer *lp, | ||
124 | char __user **data, | ||
125 | long *len, | ||
126 | int atomic) | ||
127 | { | ||
128 | struct iwffff_wave *wp, *prev; | ||
129 | struct iwffff_xwave xp; | ||
130 | int err; | ||
131 | gfp_t gfp_mask; | ||
132 | unsigned int real_size; | ||
133 | |||
134 | gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL; | ||
135 | if (*len < (long)sizeof(xp)) | ||
136 | return -EINVAL; | ||
137 | if (copy_from_user(&xp, *data, sizeof(xp))) | ||
138 | return -EFAULT; | ||
139 | *data += sizeof(xp); | ||
140 | *len -= sizeof(xp); | ||
141 | wp = kzalloc(sizeof(*wp), gfp_mask); | ||
142 | if (wp == NULL) | ||
143 | return -ENOMEM; | ||
144 | wp->share_id[0] = le32_to_cpu(xp.share_id[0]); | ||
145 | wp->share_id[1] = le32_to_cpu(xp.share_id[1]); | ||
146 | wp->share_id[2] = le32_to_cpu(xp.share_id[2]); | ||
147 | wp->share_id[3] = le32_to_cpu(xp.share_id[3]); | ||
148 | wp->format = le32_to_cpu(xp.format); | ||
149 | wp->address.memory = le32_to_cpu(xp.offset); | ||
150 | wp->size = le32_to_cpu(xp.size); | ||
151 | wp->start = le32_to_cpu(xp.start); | ||
152 | wp->loop_start = le32_to_cpu(xp.loop_start); | ||
153 | wp->loop_end = le32_to_cpu(xp.loop_end); | ||
154 | wp->loop_repeat = le16_to_cpu(xp.loop_repeat); | ||
155 | wp->sample_ratio = le32_to_cpu(xp.sample_ratio); | ||
156 | wp->attenuation = xp.attenuation; | ||
157 | wp->low_note = xp.low_note; | ||
158 | wp->high_note = xp.high_note; | ||
159 | real_size = snd_seq_iwffff_size(wp->size, wp->format); | ||
160 | if (!(wp->format & IWFFFF_WAVE_ROM)) { | ||
161 | if ((long)real_size > *len) { | ||
162 | kfree(wp); | ||
163 | return -ENOMEM; | ||
164 | } | ||
165 | } | ||
166 | if (ops->put_sample) { | ||
167 | err = ops->put_sample(ops->private_data, wp, | ||
168 | *data, real_size, atomic); | ||
169 | if (err < 0) { | ||
170 | kfree(wp); | ||
171 | return err; | ||
172 | } | ||
173 | } | ||
174 | if (!(wp->format & IWFFFF_WAVE_ROM)) { | ||
175 | *data += real_size; | ||
176 | *len -= real_size; | ||
177 | } | ||
178 | prev = lp->wave; | ||
179 | if (prev) { | ||
180 | while (prev->next) prev = prev->next; | ||
181 | prev->next = wp; | ||
182 | } else { | ||
183 | lp->wave = wp; | ||
184 | } | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static void snd_seq_iwffff_env_free(struct snd_iwffff_ops *ops, | ||
189 | struct iwffff_env *env, | ||
190 | int atomic) | ||
191 | { | ||
192 | struct iwffff_env_record *rec; | ||
193 | |||
194 | while ((rec = env->record) != NULL) { | ||
195 | env->record = rec->next; | ||
196 | kfree(rec); | ||
197 | } | ||
198 | } | ||
199 | |||
200 | static void snd_seq_iwffff_wave_free(struct snd_iwffff_ops *ops, | ||
201 | struct iwffff_wave *wave, | ||
202 | int atomic) | ||
203 | { | ||
204 | if (ops->remove_sample) | ||
205 | ops->remove_sample(ops->private_data, wave, atomic); | ||
206 | kfree(wave); | ||
207 | } | ||
208 | |||
209 | static void snd_seq_iwffff_instr_free(struct snd_iwffff_ops *ops, | ||
210 | struct iwffff_instrument *ip, | ||
211 | int atomic) | ||
212 | { | ||
213 | struct iwffff_layer *layer; | ||
214 | struct iwffff_wave *wave; | ||
215 | |||
216 | while ((layer = ip->layer) != NULL) { | ||
217 | ip->layer = layer->next; | ||
218 | snd_seq_iwffff_env_free(ops, &layer->penv, atomic); | ||
219 | snd_seq_iwffff_env_free(ops, &layer->venv, atomic); | ||
220 | while ((wave = layer->wave) != NULL) { | ||
221 | layer->wave = wave->next; | ||
222 | snd_seq_iwffff_wave_free(ops, wave, atomic); | ||
223 | } | ||
224 | kfree(layer); | ||
225 | } | ||
226 | } | ||
227 | |||
228 | static int snd_seq_iwffff_put(void *private_data, struct snd_seq_kinstr *instr, | ||
229 | char __user *instr_data, long len, int atomic, | ||
230 | int cmd) | ||
231 | { | ||
232 | struct snd_iwffff_ops *ops = private_data; | ||
233 | struct iwffff_instrument *ip; | ||
234 | struct iwffff_xinstrument ix; | ||
235 | struct iwffff_layer *lp, *prev_lp; | ||
236 | struct iwffff_xlayer lx; | ||
237 | int err; | ||
238 | gfp_t gfp_mask; | ||
239 | |||
240 | if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE) | ||
241 | return -EINVAL; | ||
242 | gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL; | ||
243 | /* copy instrument data */ | ||
244 | if (len < (long)sizeof(ix)) | ||
245 | return -EINVAL; | ||
246 | if (copy_from_user(&ix, instr_data, sizeof(ix))) | ||
247 | return -EFAULT; | ||
248 | if (ix.stype != IWFFFF_STRU_INSTR) | ||
249 | return -EINVAL; | ||
250 | instr_data += sizeof(ix); | ||
251 | len -= sizeof(ix); | ||
252 | ip = (struct iwffff_instrument *)KINSTR_DATA(instr); | ||
253 | ip->exclusion = le16_to_cpu(ix.exclusion); | ||
254 | ip->layer_type = le16_to_cpu(ix.layer_type); | ||
255 | ip->exclusion_group = le16_to_cpu(ix.exclusion_group); | ||
256 | ip->effect1 = ix.effect1; | ||
257 | ip->effect1_depth = ix.effect1_depth; | ||
258 | ip->effect2 = ix.effect2; | ||
259 | ip->effect2_depth = ix.effect2_depth; | ||
260 | /* copy layers */ | ||
261 | prev_lp = NULL; | ||
262 | while (len > 0) { | ||
263 | if (len < (long)sizeof(struct iwffff_xlayer)) { | ||
264 | snd_seq_iwffff_instr_free(ops, ip, atomic); | ||
265 | return -EINVAL; | ||
266 | } | ||
267 | if (copy_from_user(&lx, instr_data, sizeof(lx))) | ||
268 | return -EFAULT; | ||
269 | instr_data += sizeof(lx); | ||
270 | len -= sizeof(lx); | ||
271 | if (lx.stype != IWFFFF_STRU_LAYER) { | ||
272 | snd_seq_iwffff_instr_free(ops, ip, atomic); | ||
273 | return -EINVAL; | ||
274 | } | ||
275 | lp = kzalloc(sizeof(*lp), gfp_mask); | ||
276 | if (lp == NULL) { | ||
277 | snd_seq_iwffff_instr_free(ops, ip, atomic); | ||
278 | return -ENOMEM; | ||
279 | } | ||
280 | if (prev_lp) { | ||
281 | prev_lp->next = lp; | ||
282 | } else { | ||
283 | ip->layer = lp; | ||
284 | } | ||
285 | prev_lp = lp; | ||
286 | lp->flags = lx.flags; | ||
287 | lp->velocity_mode = lx.velocity_mode; | ||
288 | lp->layer_event = lx.layer_event; | ||
289 | lp->low_range = lx.low_range; | ||
290 | lp->high_range = lx.high_range; | ||
291 | lp->pan = lx.pan; | ||
292 | lp->pan_freq_scale = lx.pan_freq_scale; | ||
293 | lp->attenuation = lx.attenuation; | ||
294 | snd_seq_iwffff_copy_lfo_from_stream(&lp->tremolo, &lx.tremolo); | ||
295 | snd_seq_iwffff_copy_lfo_from_stream(&lp->vibrato, &lx.vibrato); | ||
296 | lp->freq_scale = le16_to_cpu(lx.freq_scale); | ||
297 | lp->freq_center = lx.freq_center; | ||
298 | err = snd_seq_iwffff_copy_env_from_stream(IWFFFF_STRU_ENV_RECP, | ||
299 | lp, | ||
300 | &lp->penv, &lx.penv, | ||
301 | &instr_data, &len, | ||
302 | gfp_mask); | ||
303 | if (err < 0) { | ||
304 | snd_seq_iwffff_instr_free(ops, ip, atomic); | ||
305 | return err; | ||
306 | } | ||
307 | err = snd_seq_iwffff_copy_env_from_stream(IWFFFF_STRU_ENV_RECV, | ||
308 | lp, | ||
309 | &lp->venv, &lx.venv, | ||
310 | &instr_data, &len, | ||
311 | gfp_mask); | ||
312 | if (err < 0) { | ||
313 | snd_seq_iwffff_instr_free(ops, ip, atomic); | ||
314 | return err; | ||
315 | } | ||
316 | while (len > (long)sizeof(__u32)) { | ||
317 | __u32 stype; | ||
318 | |||
319 | if (copy_from_user(&stype, instr_data, sizeof(stype))) | ||
320 | return -EFAULT; | ||
321 | if (stype != IWFFFF_STRU_WAVE) | ||
322 | break; | ||
323 | err = snd_seq_iwffff_copy_wave_from_stream(ops, | ||
324 | lp, | ||
325 | &instr_data, | ||
326 | &len, | ||
327 | atomic); | ||
328 | if (err < 0) { | ||
329 | snd_seq_iwffff_instr_free(ops, ip, atomic); | ||
330 | return err; | ||
331 | } | ||
332 | } | ||
333 | } | ||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | static void snd_seq_iwffff_copy_lfo_to_stream(struct iwffff_xlfo *fx, | ||
338 | struct iwffff_lfo *fp) | ||
339 | { | ||
340 | fx->freq = cpu_to_le16(fp->freq); | ||
341 | fx->depth = cpu_to_le16(fp->depth); | ||
342 | fx->sweep = cpu_to_le16(fp->sweep); | ||
343 | fp->shape = fx->shape; | ||
344 | fp->delay = fx->delay; | ||
345 | } | ||
346 | |||
347 | static int snd_seq_iwffff_copy_env_to_stream(__u32 req_stype, | ||
348 | struct iwffff_layer *lp, | ||
349 | struct iwffff_xenv *ex, | ||
350 | struct iwffff_env *ep, | ||
351 | char __user **data, | ||
352 | long *len) | ||
353 | { | ||
354 | struct iwffff_env_record *rp; | ||
355 | struct iwffff_xenv_record rx; | ||
356 | struct iwffff_env_point *pp; | ||
357 | struct iwffff_xenv_point px; | ||
358 | int points_size, idx; | ||
359 | |||
360 | ex->flags = ep->flags; | ||
361 | ex->mode = ep->mode; | ||
362 | ex->index = ep->index; | ||
363 | for (rp = ep->record; rp; rp = rp->next) { | ||
364 | if (*len < (long)sizeof(rx)) | ||
365 | return -ENOMEM; | ||
366 | memset(&rx, 0, sizeof(rx)); | ||
367 | rx.stype = req_stype; | ||
368 | rx.nattack = cpu_to_le16(rp->nattack); | ||
369 | rx.nrelease = cpu_to_le16(rp->nrelease); | ||
370 | rx.sustain_offset = cpu_to_le16(rp->sustain_offset); | ||
371 | rx.sustain_rate = cpu_to_le16(rp->sustain_rate); | ||
372 | rx.release_rate = cpu_to_le16(rp->release_rate); | ||
373 | rx.hirange = cpu_to_le16(rp->hirange); | ||
374 | if (copy_to_user(*data, &rx, sizeof(rx))) | ||
375 | return -EFAULT; | ||
376 | *data += sizeof(rx); | ||
377 | *len -= sizeof(rx); | ||
378 | points_size = (rp->nattack + rp->nrelease) * 2 * sizeof(__u16); | ||
379 | if (*len < points_size) | ||
380 | return -ENOMEM; | ||
381 | pp = (struct iwffff_env_point *)(rp + 1); | ||
382 | for (idx = 0; idx < rp->nattack + rp->nrelease; idx++) { | ||
383 | px.offset = cpu_to_le16(pp->offset); | ||
384 | px.rate = cpu_to_le16(pp->rate); | ||
385 | if (copy_to_user(*data, &px, sizeof(px))) | ||
386 | return -EFAULT; | ||
387 | *data += sizeof(px); | ||
388 | *len -= sizeof(px); | ||
389 | } | ||
390 | } | ||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static int snd_seq_iwffff_copy_wave_to_stream(struct snd_iwffff_ops *ops, | ||
395 | struct iwffff_layer *lp, | ||
396 | char __user **data, | ||
397 | long *len, | ||
398 | int atomic) | ||
399 | { | ||
400 | struct iwffff_wave *wp; | ||
401 | struct iwffff_xwave xp; | ||
402 | int err; | ||
403 | unsigned int real_size; | ||
404 | |||
405 | for (wp = lp->wave; wp; wp = wp->next) { | ||
406 | if (*len < (long)sizeof(xp)) | ||
407 | return -ENOMEM; | ||
408 | memset(&xp, 0, sizeof(xp)); | ||
409 | xp.stype = IWFFFF_STRU_WAVE; | ||
410 | xp.share_id[0] = cpu_to_le32(wp->share_id[0]); | ||
411 | xp.share_id[1] = cpu_to_le32(wp->share_id[1]); | ||
412 | xp.share_id[2] = cpu_to_le32(wp->share_id[2]); | ||
413 | xp.share_id[3] = cpu_to_le32(wp->share_id[3]); | ||
414 | xp.format = cpu_to_le32(wp->format); | ||
415 | if (wp->format & IWFFFF_WAVE_ROM) | ||
416 | xp.offset = cpu_to_le32(wp->address.memory); | ||
417 | xp.size = cpu_to_le32(wp->size); | ||
418 | xp.start = cpu_to_le32(wp->start); | ||
419 | xp.loop_start = cpu_to_le32(wp->loop_start); | ||
420 | xp.loop_end = cpu_to_le32(wp->loop_end); | ||
421 | xp.loop_repeat = cpu_to_le32(wp->loop_repeat); | ||
422 | xp.sample_ratio = cpu_to_le32(wp->sample_ratio); | ||
423 | xp.attenuation = wp->attenuation; | ||
424 | xp.low_note = wp->low_note; | ||
425 | xp.high_note = wp->high_note; | ||
426 | if (copy_to_user(*data, &xp, sizeof(xp))) | ||
427 | return -EFAULT; | ||
428 | *data += sizeof(xp); | ||
429 | *len -= sizeof(xp); | ||
430 | real_size = snd_seq_iwffff_size(wp->size, wp->format); | ||
431 | if (!(wp->format & IWFFFF_WAVE_ROM)) { | ||
432 | if (*len < (long)real_size) | ||
433 | return -ENOMEM; | ||
434 | } | ||
435 | if (ops->get_sample) { | ||
436 | err = ops->get_sample(ops->private_data, wp, | ||
437 | *data, real_size, atomic); | ||
438 | if (err < 0) | ||
439 | return err; | ||
440 | } | ||
441 | if (!(wp->format & IWFFFF_WAVE_ROM)) { | ||
442 | *data += real_size; | ||
443 | *len -= real_size; | ||
444 | } | ||
445 | } | ||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | static int snd_seq_iwffff_get(void *private_data, struct snd_seq_kinstr *instr, | ||
450 | char __user *instr_data, long len, int atomic, int cmd) | ||
451 | { | ||
452 | struct snd_iwffff_ops *ops = private_data; | ||
453 | struct iwffff_instrument *ip; | ||
454 | struct iwffff_xinstrument ix; | ||
455 | struct iwffff_layer *lp; | ||
456 | struct iwffff_xlayer lx; | ||
457 | char __user *layer_instr_data; | ||
458 | int err; | ||
459 | |||
460 | if (cmd != SNDRV_SEQ_INSTR_GET_CMD_FULL) | ||
461 | return -EINVAL; | ||
462 | if (len < (long)sizeof(ix)) | ||
463 | return -ENOMEM; | ||
464 | memset(&ix, 0, sizeof(ix)); | ||
465 | ip = (struct iwffff_instrument *)KINSTR_DATA(instr); | ||
466 | ix.stype = IWFFFF_STRU_INSTR; | ||
467 | ix.exclusion = cpu_to_le16(ip->exclusion); | ||
468 | ix.layer_type = cpu_to_le16(ip->layer_type); | ||
469 | ix.exclusion_group = cpu_to_le16(ip->exclusion_group); | ||
470 | ix.effect1 = cpu_to_le16(ip->effect1); | ||
471 | ix.effect1_depth = cpu_to_le16(ip->effect1_depth); | ||
472 | ix.effect2 = ip->effect2; | ||
473 | ix.effect2_depth = ip->effect2_depth; | ||
474 | if (copy_to_user(instr_data, &ix, sizeof(ix))) | ||
475 | return -EFAULT; | ||
476 | instr_data += sizeof(ix); | ||
477 | len -= sizeof(ix); | ||
478 | for (lp = ip->layer; lp; lp = lp->next) { | ||
479 | if (len < (long)sizeof(lx)) | ||
480 | return -ENOMEM; | ||
481 | memset(&lx, 0, sizeof(lx)); | ||
482 | lx.stype = IWFFFF_STRU_LAYER; | ||
483 | lx.flags = lp->flags; | ||
484 | lx.velocity_mode = lp->velocity_mode; | ||
485 | lx.layer_event = lp->layer_event; | ||
486 | lx.low_range = lp->low_range; | ||
487 | lx.high_range = lp->high_range; | ||
488 | lx.pan = lp->pan; | ||
489 | lx.pan_freq_scale = lp->pan_freq_scale; | ||
490 | lx.attenuation = lp->attenuation; | ||
491 | snd_seq_iwffff_copy_lfo_to_stream(&lx.tremolo, &lp->tremolo); | ||
492 | snd_seq_iwffff_copy_lfo_to_stream(&lx.vibrato, &lp->vibrato); | ||
493 | layer_instr_data = instr_data; | ||
494 | instr_data += sizeof(lx); | ||
495 | len -= sizeof(lx); | ||
496 | err = snd_seq_iwffff_copy_env_to_stream(IWFFFF_STRU_ENV_RECP, | ||
497 | lp, | ||
498 | &lx.penv, &lp->penv, | ||
499 | &instr_data, &len); | ||
500 | if (err < 0) | ||
501 | return err; | ||
502 | err = snd_seq_iwffff_copy_env_to_stream(IWFFFF_STRU_ENV_RECV, | ||
503 | lp, | ||
504 | &lx.venv, &lp->venv, | ||
505 | &instr_data, &len); | ||
506 | if (err < 0) | ||
507 | return err; | ||
508 | /* layer structure updating is now finished */ | ||
509 | if (copy_to_user(layer_instr_data, &lx, sizeof(lx))) | ||
510 | return -EFAULT; | ||
511 | err = snd_seq_iwffff_copy_wave_to_stream(ops, | ||
512 | lp, | ||
513 | &instr_data, | ||
514 | &len, | ||
515 | atomic); | ||
516 | if (err < 0) | ||
517 | return err; | ||
518 | } | ||
519 | return 0; | ||
520 | } | ||
521 | |||
522 | static long snd_seq_iwffff_env_size_in_stream(struct iwffff_env *ep) | ||
523 | { | ||
524 | long result = 0; | ||
525 | struct iwffff_env_record *rp; | ||
526 | |||
527 | for (rp = ep->record; rp; rp = rp->next) { | ||
528 | result += sizeof(struct iwffff_xenv_record); | ||
529 | result += (rp->nattack + rp->nrelease) * 2 * sizeof(__u16); | ||
530 | } | ||
531 | return 0; | ||
532 | } | ||
533 | |||
534 | static long snd_seq_iwffff_wave_size_in_stream(struct iwffff_layer *lp) | ||
535 | { | ||
536 | long result = 0; | ||
537 | struct iwffff_wave *wp; | ||
538 | |||
539 | for (wp = lp->wave; wp; wp = wp->next) { | ||
540 | result += sizeof(struct iwffff_xwave); | ||
541 | if (!(wp->format & IWFFFF_WAVE_ROM)) | ||
542 | result += wp->size; | ||
543 | } | ||
544 | return result; | ||
545 | } | ||
546 | |||
547 | static int snd_seq_iwffff_get_size(void *private_data, struct snd_seq_kinstr *instr, | ||
548 | long *size) | ||
549 | { | ||
550 | long result; | ||
551 | struct iwffff_instrument *ip; | ||
552 | struct iwffff_layer *lp; | ||
553 | |||
554 | *size = 0; | ||
555 | ip = (struct iwffff_instrument *)KINSTR_DATA(instr); | ||
556 | result = sizeof(struct iwffff_xinstrument); | ||
557 | for (lp = ip->layer; lp; lp = lp->next) { | ||
558 | result += sizeof(struct iwffff_xlayer); | ||
559 | result += snd_seq_iwffff_env_size_in_stream(&lp->penv); | ||
560 | result += snd_seq_iwffff_env_size_in_stream(&lp->venv); | ||
561 | result += snd_seq_iwffff_wave_size_in_stream(lp); | ||
562 | } | ||
563 | *size = result; | ||
564 | return 0; | ||
565 | } | ||
566 | |||
567 | static int snd_seq_iwffff_remove(void *private_data, | ||
568 | struct snd_seq_kinstr *instr, | ||
569 | int atomic) | ||
570 | { | ||
571 | struct snd_iwffff_ops *ops = private_data; | ||
572 | struct iwffff_instrument *ip; | ||
573 | |||
574 | ip = (struct iwffff_instrument *)KINSTR_DATA(instr); | ||
575 | snd_seq_iwffff_instr_free(ops, ip, atomic); | ||
576 | return 0; | ||
577 | } | ||
578 | |||
579 | static void snd_seq_iwffff_notify(void *private_data, | ||
580 | struct snd_seq_kinstr *instr, | ||
581 | int what) | ||
582 | { | ||
583 | struct snd_iwffff_ops *ops = private_data; | ||
584 | |||
585 | if (ops->notify) | ||
586 | ops->notify(ops->private_data, instr, what); | ||
587 | } | ||
588 | |||
589 | int snd_seq_iwffff_init(struct snd_iwffff_ops *ops, | ||
590 | void *private_data, | ||
591 | struct snd_seq_kinstr_ops *next) | ||
592 | { | ||
593 | memset(ops, 0, sizeof(*ops)); | ||
594 | ops->private_data = private_data; | ||
595 | ops->kops.private_data = ops; | ||
596 | ops->kops.add_len = sizeof(struct iwffff_instrument); | ||
597 | ops->kops.instr_type = SNDRV_SEQ_INSTR_ID_INTERWAVE; | ||
598 | ops->kops.put = snd_seq_iwffff_put; | ||
599 | ops->kops.get = snd_seq_iwffff_get; | ||
600 | ops->kops.get_size = snd_seq_iwffff_get_size; | ||
601 | ops->kops.remove = snd_seq_iwffff_remove; | ||
602 | ops->kops.notify = snd_seq_iwffff_notify; | ||
603 | ops->kops.next = next; | ||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | /* | ||
608 | * Init part | ||
609 | */ | ||
610 | |||
611 | static int __init alsa_ainstr_iw_init(void) | ||
612 | { | ||
613 | return 0; | ||
614 | } | ||
615 | |||
616 | static void __exit alsa_ainstr_iw_exit(void) | ||
617 | { | ||
618 | } | ||
619 | |||
620 | module_init(alsa_ainstr_iw_init) | ||
621 | module_exit(alsa_ainstr_iw_exit) | ||
622 | |||
623 | EXPORT_SYMBOL(snd_seq_iwffff_init); | ||
diff --git a/sound/core/seq/instr/ainstr_simple.c b/sound/core/seq/instr/ainstr_simple.c deleted file mode 100644 index 78f68bee24fe..000000000000 --- a/sound/core/seq/instr/ainstr_simple.c +++ /dev/null | |||
@@ -1,215 +0,0 @@ | |||
1 | /* | ||
2 | * Simple (MOD player) - Instrument routines | ||
3 | * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include <sound/driver.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <sound/core.h> | ||
25 | #include <sound/ainstr_simple.h> | ||
26 | #include <sound/initval.h> | ||
27 | #include <asm/uaccess.h> | ||
28 | |||
29 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); | ||
30 | MODULE_DESCRIPTION("Advanced Linux Sound Architecture Simple Instrument support."); | ||
31 | MODULE_LICENSE("GPL"); | ||
32 | |||
33 | static unsigned int snd_seq_simple_size(unsigned int size, unsigned int format) | ||
34 | { | ||
35 | unsigned int result = size; | ||
36 | |||
37 | if (format & SIMPLE_WAVE_16BIT) | ||
38 | result <<= 1; | ||
39 | if (format & SIMPLE_WAVE_STEREO) | ||
40 | result <<= 1; | ||
41 | return result; | ||
42 | } | ||
43 | |||
44 | static void snd_seq_simple_instr_free(struct snd_simple_ops *ops, | ||
45 | struct simple_instrument *ip, | ||
46 | int atomic) | ||
47 | { | ||
48 | if (ops->remove_sample) | ||
49 | ops->remove_sample(ops->private_data, ip, atomic); | ||
50 | } | ||
51 | |||
52 | static int snd_seq_simple_put(void *private_data, struct snd_seq_kinstr *instr, | ||
53 | char __user *instr_data, long len, | ||
54 | int atomic, int cmd) | ||
55 | { | ||
56 | struct snd_simple_ops *ops = private_data; | ||
57 | struct simple_instrument *ip; | ||
58 | struct simple_xinstrument ix; | ||
59 | int err; | ||
60 | gfp_t gfp_mask; | ||
61 | unsigned int real_size; | ||
62 | |||
63 | if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE) | ||
64 | return -EINVAL; | ||
65 | gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL; | ||
66 | /* copy instrument data */ | ||
67 | if (len < (long)sizeof(ix)) | ||
68 | return -EINVAL; | ||
69 | if (copy_from_user(&ix, instr_data, sizeof(ix))) | ||
70 | return -EFAULT; | ||
71 | if (ix.stype != SIMPLE_STRU_INSTR) | ||
72 | return -EINVAL; | ||
73 | instr_data += sizeof(ix); | ||
74 | len -= sizeof(ix); | ||
75 | ip = (struct simple_instrument *)KINSTR_DATA(instr); | ||
76 | ip->share_id[0] = le32_to_cpu(ix.share_id[0]); | ||
77 | ip->share_id[1] = le32_to_cpu(ix.share_id[1]); | ||
78 | ip->share_id[2] = le32_to_cpu(ix.share_id[2]); | ||
79 | ip->share_id[3] = le32_to_cpu(ix.share_id[3]); | ||
80 | ip->format = le32_to_cpu(ix.format); | ||
81 | ip->size = le32_to_cpu(ix.size); | ||
82 | ip->start = le32_to_cpu(ix.start); | ||
83 | ip->loop_start = le32_to_cpu(ix.loop_start); | ||
84 | ip->loop_end = le32_to_cpu(ix.loop_end); | ||
85 | ip->loop_repeat = le16_to_cpu(ix.loop_repeat); | ||
86 | ip->effect1 = ix.effect1; | ||
87 | ip->effect1_depth = ix.effect1_depth; | ||
88 | ip->effect2 = ix.effect2; | ||
89 | ip->effect2_depth = ix.effect2_depth; | ||
90 | real_size = snd_seq_simple_size(ip->size, ip->format); | ||
91 | if (len < (long)real_size) | ||
92 | return -EINVAL; | ||
93 | if (ops->put_sample) { | ||
94 | err = ops->put_sample(ops->private_data, ip, | ||
95 | instr_data, real_size, atomic); | ||
96 | if (err < 0) | ||
97 | return err; | ||
98 | } | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static int snd_seq_simple_get(void *private_data, struct snd_seq_kinstr *instr, | ||
103 | char __user *instr_data, long len, | ||
104 | int atomic, int cmd) | ||
105 | { | ||
106 | struct snd_simple_ops *ops = private_data; | ||
107 | struct simple_instrument *ip; | ||
108 | struct simple_xinstrument ix; | ||
109 | int err; | ||
110 | unsigned int real_size; | ||
111 | |||
112 | if (cmd != SNDRV_SEQ_INSTR_GET_CMD_FULL) | ||
113 | return -EINVAL; | ||
114 | if (len < (long)sizeof(ix)) | ||
115 | return -ENOMEM; | ||
116 | memset(&ix, 0, sizeof(ix)); | ||
117 | ip = (struct simple_instrument *)KINSTR_DATA(instr); | ||
118 | ix.stype = SIMPLE_STRU_INSTR; | ||
119 | ix.share_id[0] = cpu_to_le32(ip->share_id[0]); | ||
120 | ix.share_id[1] = cpu_to_le32(ip->share_id[1]); | ||
121 | ix.share_id[2] = cpu_to_le32(ip->share_id[2]); | ||
122 | ix.share_id[3] = cpu_to_le32(ip->share_id[3]); | ||
123 | ix.format = cpu_to_le32(ip->format); | ||
124 | ix.size = cpu_to_le32(ip->size); | ||
125 | ix.start = cpu_to_le32(ip->start); | ||
126 | ix.loop_start = cpu_to_le32(ip->loop_start); | ||
127 | ix.loop_end = cpu_to_le32(ip->loop_end); | ||
128 | ix.loop_repeat = cpu_to_le32(ip->loop_repeat); | ||
129 | ix.effect1 = cpu_to_le16(ip->effect1); | ||
130 | ix.effect1_depth = cpu_to_le16(ip->effect1_depth); | ||
131 | ix.effect2 = ip->effect2; | ||
132 | ix.effect2_depth = ip->effect2_depth; | ||
133 | if (copy_to_user(instr_data, &ix, sizeof(ix))) | ||
134 | return -EFAULT; | ||
135 | instr_data += sizeof(ix); | ||
136 | len -= sizeof(ix); | ||
137 | real_size = snd_seq_simple_size(ip->size, ip->format); | ||
138 | if (len < (long)real_size) | ||
139 | return -ENOMEM; | ||
140 | if (ops->get_sample) { | ||
141 | err = ops->get_sample(ops->private_data, ip, | ||
142 | instr_data, real_size, atomic); | ||
143 | if (err < 0) | ||
144 | return err; | ||
145 | } | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static int snd_seq_simple_get_size(void *private_data, struct snd_seq_kinstr *instr, | ||
150 | long *size) | ||
151 | { | ||
152 | struct simple_instrument *ip; | ||
153 | |||
154 | ip = (struct simple_instrument *)KINSTR_DATA(instr); | ||
155 | *size = sizeof(struct simple_xinstrument) + snd_seq_simple_size(ip->size, ip->format); | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static int snd_seq_simple_remove(void *private_data, | ||
160 | struct snd_seq_kinstr *instr, | ||
161 | int atomic) | ||
162 | { | ||
163 | struct snd_simple_ops *ops = private_data; | ||
164 | struct simple_instrument *ip; | ||
165 | |||
166 | ip = (struct simple_instrument *)KINSTR_DATA(instr); | ||
167 | snd_seq_simple_instr_free(ops, ip, atomic); | ||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | static void snd_seq_simple_notify(void *private_data, | ||
172 | struct snd_seq_kinstr *instr, | ||
173 | int what) | ||
174 | { | ||
175 | struct snd_simple_ops *ops = private_data; | ||
176 | |||
177 | if (ops->notify) | ||
178 | ops->notify(ops->private_data, instr, what); | ||
179 | } | ||
180 | |||
181 | int snd_seq_simple_init(struct snd_simple_ops *ops, | ||
182 | void *private_data, | ||
183 | struct snd_seq_kinstr_ops *next) | ||
184 | { | ||
185 | memset(ops, 0, sizeof(*ops)); | ||
186 | ops->private_data = private_data; | ||
187 | ops->kops.private_data = ops; | ||
188 | ops->kops.add_len = sizeof(struct simple_instrument); | ||
189 | ops->kops.instr_type = SNDRV_SEQ_INSTR_ID_SIMPLE; | ||
190 | ops->kops.put = snd_seq_simple_put; | ||
191 | ops->kops.get = snd_seq_simple_get; | ||
192 | ops->kops.get_size = snd_seq_simple_get_size; | ||
193 | ops->kops.remove = snd_seq_simple_remove; | ||
194 | ops->kops.notify = snd_seq_simple_notify; | ||
195 | ops->kops.next = next; | ||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | /* | ||
200 | * Init part | ||
201 | */ | ||
202 | |||
203 | static int __init alsa_ainstr_simple_init(void) | ||
204 | { | ||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | static void __exit alsa_ainstr_simple_exit(void) | ||
209 | { | ||
210 | } | ||
211 | |||
212 | module_init(alsa_ainstr_simple_init) | ||
213 | module_exit(alsa_ainstr_simple_exit) | ||
214 | |||
215 | EXPORT_SYMBOL(snd_seq_simple_init); | ||
diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c index bc0992398461..777796e94490 100644 --- a/sound/core/seq/oss/seq_oss.c +++ b/sound/core/seq/oss/seq_oss.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <linux/moduleparam.h> | 24 | #include <linux/moduleparam.h> |
26 | #include <linux/mutex.h> | 25 | #include <linux/mutex.h> |
diff --git a/sound/core/seq/oss/seq_oss_device.h b/sound/core/seq/oss/seq_oss_device.h index 9a8567c928ec..bf8d2b4cb15e 100644 --- a/sound/core/seq/oss/seq_oss_device.h +++ b/sound/core/seq/oss/seq_oss_device.h | |||
@@ -21,7 +21,6 @@ | |||
21 | #ifndef __SEQ_OSS_DEVICE_H | 21 | #ifndef __SEQ_OSS_DEVICE_H |
22 | #define __SEQ_OSS_DEVICE_H | 22 | #define __SEQ_OSS_DEVICE_H |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/time.h> | 24 | #include <linux/time.h> |
26 | #include <linux/wait.h> | 25 | #include <linux/wait.h> |
27 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
diff --git a/sound/core/seq/seq.c b/sound/core/seq/seq.c index 1878208a8026..ee0f8405ab35 100644 --- a/sound/core/seq/seq.c +++ b/sound/core/seq/seq.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/moduleparam.h> | 23 | #include <linux/moduleparam.h> |
25 | #include <sound/core.h> | 24 | #include <sound/core.h> |
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 2e3fa25ab19f..f97c1ba43a28 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
27 | #include <sound/core.h> | 26 | #include <sound/core.h> |
@@ -130,8 +129,6 @@ static struct snd_seq_client *clientptr(int clientid) | |||
130 | return clienttab[clientid]; | 129 | return clienttab[clientid]; |
131 | } | 130 | } |
132 | 131 | ||
133 | extern int seq_client_load[]; | ||
134 | |||
135 | struct snd_seq_client *snd_seq_client_use_ptr(int clientid) | 132 | struct snd_seq_client *snd_seq_client_use_ptr(int clientid) |
136 | { | 133 | { |
137 | unsigned long flags; | 134 | unsigned long flags; |
@@ -966,8 +963,7 @@ static int check_event_type_and_length(struct snd_seq_event *ev) | |||
966 | return -EINVAL; | 963 | return -EINVAL; |
967 | break; | 964 | break; |
968 | case SNDRV_SEQ_EVENT_LENGTH_VARUSR: | 965 | case SNDRV_SEQ_EVENT_LENGTH_VARUSR: |
969 | if (! snd_seq_ev_is_instr_type(ev) || | 966 | if (! snd_seq_ev_is_direct(ev)) |
970 | ! snd_seq_ev_is_direct(ev)) | ||
971 | return -EINVAL; | 967 | return -EINVAL; |
972 | break; | 968 | break; |
973 | } | 969 | } |
diff --git a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h index 5e04e20e239f..20f0a725ec7d 100644 --- a/sound/core/seq/seq_clientmgr.h +++ b/sound/core/seq/seq_clientmgr.h | |||
@@ -98,4 +98,6 @@ int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table | |||
98 | int snd_seq_client_notify_subscription(int client, int port, | 98 | int snd_seq_client_notify_subscription(int client, int port, |
99 | struct snd_seq_port_subscribe *info, int evtype); | 99 | struct snd_seq_port_subscribe *info, int evtype); |
100 | 100 | ||
101 | extern int seq_client_load[15]; | ||
102 | |||
101 | #endif | 103 | #endif |
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index 37852cdace76..155dc7da4722 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c | |||
@@ -36,7 +36,6 @@ | |||
36 | * | 36 | * |
37 | */ | 37 | */ |
38 | 38 | ||
39 | #include <sound/driver.h> | ||
40 | #include <linux/init.h> | 39 | #include <linux/init.h> |
41 | #include <sound/core.h> | 40 | #include <sound/core.h> |
42 | #include <sound/info.h> | 41 | #include <sound/info.h> |
diff --git a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c index e55488d1237c..f3bdc54b429a 100644 --- a/sound/core/seq/seq_dummy.c +++ b/sound/core/seq/seq_dummy.c | |||
@@ -18,7 +18,6 @@ | |||
18 | * | 18 | * |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <sound/driver.h> | ||
22 | #include <linux/init.h> | 21 | #include <linux/init.h> |
23 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
24 | #include <linux/moduleparam.h> | 23 | #include <linux/moduleparam.h> |
diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c index 6b055aed7a4b..3a94ed021bd9 100644 --- a/sound/core/seq/seq_fifo.c +++ b/sound/core/seq/seq_fifo.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <sound/core.h> | 22 | #include <sound/core.h> |
24 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
25 | #include "seq_fifo.h" | 24 | #include "seq_fifo.h" |
diff --git a/sound/core/seq/seq_info.c b/sound/core/seq/seq_info.c index 8a7fe5cca1c9..201f8106ffdd 100644 --- a/sound/core/seq/seq_info.c +++ b/sound/core/seq/seq_info.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <sound/core.h> | 23 | #include <sound/core.h> |
25 | 24 | ||
diff --git a/sound/core/seq/seq_instr.c b/sound/core/seq/seq_instr.c deleted file mode 100644 index 9a6fd56c9109..000000000000 --- a/sound/core/seq/seq_instr.c +++ /dev/null | |||
@@ -1,655 +0,0 @@ | |||
1 | /* | ||
2 | * Generic Instrument routines for ALSA sequencer | ||
3 | * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include <sound/driver.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <sound/core.h> | ||
25 | #include "seq_clientmgr.h" | ||
26 | #include <sound/seq_instr.h> | ||
27 | #include <sound/initval.h> | ||
28 | |||
29 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); | ||
30 | MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer instrument library."); | ||
31 | MODULE_LICENSE("GPL"); | ||
32 | |||
33 | |||
34 | static void snd_instr_lock_ops(struct snd_seq_kinstr_list *list) | ||
35 | { | ||
36 | if (!(list->flags & SNDRV_SEQ_INSTR_FLG_DIRECT)) { | ||
37 | spin_lock_irqsave(&list->ops_lock, list->ops_flags); | ||
38 | } else { | ||
39 | mutex_lock(&list->ops_mutex); | ||
40 | } | ||
41 | } | ||
42 | |||
43 | static void snd_instr_unlock_ops(struct snd_seq_kinstr_list *list) | ||
44 | { | ||
45 | if (!(list->flags & SNDRV_SEQ_INSTR_FLG_DIRECT)) { | ||
46 | spin_unlock_irqrestore(&list->ops_lock, list->ops_flags); | ||
47 | } else { | ||
48 | mutex_unlock(&list->ops_mutex); | ||
49 | } | ||
50 | } | ||
51 | |||
52 | static struct snd_seq_kinstr *snd_seq_instr_new(int add_len, int atomic) | ||
53 | { | ||
54 | struct snd_seq_kinstr *instr; | ||
55 | |||
56 | instr = kzalloc(sizeof(struct snd_seq_kinstr) + add_len, atomic ? GFP_ATOMIC : GFP_KERNEL); | ||
57 | if (instr == NULL) | ||
58 | return NULL; | ||
59 | instr->add_len = add_len; | ||
60 | return instr; | ||
61 | } | ||
62 | |||
63 | static int snd_seq_instr_free(struct snd_seq_kinstr *instr, int atomic) | ||
64 | { | ||
65 | int result = 0; | ||
66 | |||
67 | if (instr == NULL) | ||
68 | return -EINVAL; | ||
69 | if (instr->ops && instr->ops->remove) | ||
70 | result = instr->ops->remove(instr->ops->private_data, instr, 1); | ||
71 | if (!result) | ||
72 | kfree(instr); | ||
73 | return result; | ||
74 | } | ||
75 | |||
76 | struct snd_seq_kinstr_list *snd_seq_instr_list_new(void) | ||
77 | { | ||
78 | struct snd_seq_kinstr_list *list; | ||
79 | |||
80 | list = kzalloc(sizeof(struct snd_seq_kinstr_list), GFP_KERNEL); | ||
81 | if (list == NULL) | ||
82 | return NULL; | ||
83 | spin_lock_init(&list->lock); | ||
84 | spin_lock_init(&list->ops_lock); | ||
85 | mutex_init(&list->ops_mutex); | ||
86 | list->owner = -1; | ||
87 | return list; | ||
88 | } | ||
89 | |||
90 | void snd_seq_instr_list_free(struct snd_seq_kinstr_list **list_ptr) | ||
91 | { | ||
92 | struct snd_seq_kinstr_list *list; | ||
93 | struct snd_seq_kinstr *instr; | ||
94 | struct snd_seq_kcluster *cluster; | ||
95 | int idx; | ||
96 | unsigned long flags; | ||
97 | |||
98 | if (list_ptr == NULL) | ||
99 | return; | ||
100 | list = *list_ptr; | ||
101 | *list_ptr = NULL; | ||
102 | if (list == NULL) | ||
103 | return; | ||
104 | |||
105 | for (idx = 0; idx < SNDRV_SEQ_INSTR_HASH_SIZE; idx++) { | ||
106 | while ((instr = list->hash[idx]) != NULL) { | ||
107 | list->hash[idx] = instr->next; | ||
108 | list->count--; | ||
109 | spin_lock_irqsave(&list->lock, flags); | ||
110 | while (instr->use) { | ||
111 | spin_unlock_irqrestore(&list->lock, flags); | ||
112 | schedule_timeout_uninterruptible(1); | ||
113 | spin_lock_irqsave(&list->lock, flags); | ||
114 | } | ||
115 | spin_unlock_irqrestore(&list->lock, flags); | ||
116 | if (snd_seq_instr_free(instr, 0)<0) | ||
117 | snd_printk(KERN_WARNING "instrument free problem\n"); | ||
118 | } | ||
119 | while ((cluster = list->chash[idx]) != NULL) { | ||
120 | list->chash[idx] = cluster->next; | ||
121 | list->ccount--; | ||
122 | kfree(cluster); | ||
123 | } | ||
124 | } | ||
125 | kfree(list); | ||
126 | } | ||
127 | |||
128 | static int instr_free_compare(struct snd_seq_kinstr *instr, | ||
129 | struct snd_seq_instr_header *ifree, | ||
130 | unsigned int client) | ||
131 | { | ||
132 | switch (ifree->cmd) { | ||
133 | case SNDRV_SEQ_INSTR_FREE_CMD_ALL: | ||
134 | /* all, except private for other clients */ | ||
135 | if ((instr->instr.std & 0xff000000) == 0) | ||
136 | return 0; | ||
137 | if (((instr->instr.std >> 24) & 0xff) == client) | ||
138 | return 0; | ||
139 | return 1; | ||
140 | case SNDRV_SEQ_INSTR_FREE_CMD_PRIVATE: | ||
141 | /* all my private instruments */ | ||
142 | if ((instr->instr.std & 0xff000000) == 0) | ||
143 | return 1; | ||
144 | if (((instr->instr.std >> 24) & 0xff) == client) | ||
145 | return 0; | ||
146 | return 1; | ||
147 | case SNDRV_SEQ_INSTR_FREE_CMD_CLUSTER: | ||
148 | /* all my private instruments */ | ||
149 | if ((instr->instr.std & 0xff000000) == 0) { | ||
150 | if (instr->instr.cluster == ifree->id.cluster) | ||
151 | return 0; | ||
152 | return 1; | ||
153 | } | ||
154 | if (((instr->instr.std >> 24) & 0xff) == client) { | ||
155 | if (instr->instr.cluster == ifree->id.cluster) | ||
156 | return 0; | ||
157 | } | ||
158 | return 1; | ||
159 | } | ||
160 | return 1; | ||
161 | } | ||
162 | |||
163 | int snd_seq_instr_list_free_cond(struct snd_seq_kinstr_list *list, | ||
164 | struct snd_seq_instr_header *ifree, | ||
165 | int client, | ||
166 | int atomic) | ||
167 | { | ||
168 | struct snd_seq_kinstr *instr, *prev, *next, *flist; | ||
169 | int idx; | ||
170 | unsigned long flags; | ||
171 | |||
172 | snd_instr_lock_ops(list); | ||
173 | for (idx = 0; idx < SNDRV_SEQ_INSTR_HASH_SIZE; idx++) { | ||
174 | spin_lock_irqsave(&list->lock, flags); | ||
175 | instr = list->hash[idx]; | ||
176 | prev = flist = NULL; | ||
177 | while (instr) { | ||
178 | while (instr && instr_free_compare(instr, ifree, (unsigned int)client)) { | ||
179 | prev = instr; | ||
180 | instr = instr->next; | ||
181 | } | ||
182 | if (instr == NULL) | ||
183 | continue; | ||
184 | if (instr->ops && instr->ops->notify) | ||
185 | instr->ops->notify(instr->ops->private_data, instr, SNDRV_SEQ_INSTR_NOTIFY_REMOVE); | ||
186 | next = instr->next; | ||
187 | if (prev == NULL) { | ||
188 | list->hash[idx] = next; | ||
189 | } else { | ||
190 | prev->next = next; | ||
191 | } | ||
192 | list->count--; | ||
193 | instr->next = flist; | ||
194 | flist = instr; | ||
195 | instr = next; | ||
196 | } | ||
197 | spin_unlock_irqrestore(&list->lock, flags); | ||
198 | while (flist) { | ||
199 | instr = flist; | ||
200 | flist = instr->next; | ||
201 | while (instr->use) { | ||
202 | schedule_timeout_uninterruptible(1); | ||
203 | barrier(); | ||
204 | } | ||
205 | if (snd_seq_instr_free(instr, atomic)<0) | ||
206 | snd_printk(KERN_WARNING "instrument free problem\n"); | ||
207 | instr = next; | ||
208 | } | ||
209 | } | ||
210 | snd_instr_unlock_ops(list); | ||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | static int compute_hash_instr_key(struct snd_seq_instr *instr) | ||
215 | { | ||
216 | int result; | ||
217 | |||
218 | result = instr->bank | (instr->prg << 16); | ||
219 | result += result >> 24; | ||
220 | result += result >> 16; | ||
221 | result += result >> 8; | ||
222 | return result & (SNDRV_SEQ_INSTR_HASH_SIZE-1); | ||
223 | } | ||
224 | |||
225 | #if 0 | ||
226 | static int compute_hash_cluster_key(snd_seq_instr_cluster_t cluster) | ||
227 | { | ||
228 | int result; | ||
229 | |||
230 | result = cluster; | ||
231 | result += result >> 24; | ||
232 | result += result >> 16; | ||
233 | result += result >> 8; | ||
234 | return result & (SNDRV_SEQ_INSTR_HASH_SIZE-1); | ||
235 | } | ||
236 | #endif | ||
237 | |||
238 | static int compare_instr(struct snd_seq_instr *i1, struct snd_seq_instr *i2, int exact) | ||
239 | { | ||
240 | if (exact) { | ||
241 | if (i1->cluster != i2->cluster || | ||
242 | i1->bank != i2->bank || | ||
243 | i1->prg != i2->prg) | ||
244 | return 1; | ||
245 | if ((i1->std & 0xff000000) != (i2->std & 0xff000000)) | ||
246 | return 1; | ||
247 | if (!(i1->std & i2->std)) | ||
248 | return 1; | ||
249 | return 0; | ||
250 | } else { | ||
251 | unsigned int client_check; | ||
252 | |||
253 | if (i2->cluster && i1->cluster != i2->cluster) | ||
254 | return 1; | ||
255 | client_check = i2->std & 0xff000000; | ||
256 | if (client_check) { | ||
257 | if ((i1->std & 0xff000000) != client_check) | ||
258 | return 1; | ||
259 | } else { | ||
260 | if ((i1->std & i2->std) != i2->std) | ||
261 | return 1; | ||
262 | } | ||
263 | return i1->bank != i2->bank || i1->prg != i2->prg; | ||
264 | } | ||
265 | } | ||
266 | |||
267 | struct snd_seq_kinstr *snd_seq_instr_find(struct snd_seq_kinstr_list *list, | ||
268 | struct snd_seq_instr *instr, | ||
269 | int exact, | ||
270 | int follow_alias) | ||
271 | { | ||
272 | unsigned long flags; | ||
273 | int depth = 0; | ||
274 | struct snd_seq_kinstr *result; | ||
275 | |||
276 | if (list == NULL || instr == NULL) | ||
277 | return NULL; | ||
278 | spin_lock_irqsave(&list->lock, flags); | ||
279 | __again: | ||
280 | result = list->hash[compute_hash_instr_key(instr)]; | ||
281 | while (result) { | ||
282 | if (!compare_instr(&result->instr, instr, exact)) { | ||
283 | if (follow_alias && (result->type == SNDRV_SEQ_INSTR_ATYPE_ALIAS)) { | ||
284 | instr = (struct snd_seq_instr *)KINSTR_DATA(result); | ||
285 | if (++depth > 10) | ||
286 | goto __not_found; | ||
287 | goto __again; | ||
288 | } | ||
289 | result->use++; | ||
290 | spin_unlock_irqrestore(&list->lock, flags); | ||
291 | return result; | ||
292 | } | ||
293 | result = result->next; | ||
294 | } | ||
295 | __not_found: | ||
296 | spin_unlock_irqrestore(&list->lock, flags); | ||
297 | return NULL; | ||
298 | } | ||
299 | |||
300 | void snd_seq_instr_free_use(struct snd_seq_kinstr_list *list, | ||
301 | struct snd_seq_kinstr *instr) | ||
302 | { | ||
303 | unsigned long flags; | ||
304 | |||
305 | if (list == NULL || instr == NULL) | ||
306 | return; | ||
307 | spin_lock_irqsave(&list->lock, flags); | ||
308 | if (instr->use <= 0) { | ||
309 | snd_printk(KERN_ERR "free_use: fatal!!! use = %i, name = '%s'\n", instr->use, instr->name); | ||
310 | } else { | ||
311 | instr->use--; | ||
312 | } | ||
313 | spin_unlock_irqrestore(&list->lock, flags); | ||
314 | } | ||
315 | |||
316 | static struct snd_seq_kinstr_ops *instr_ops(struct snd_seq_kinstr_ops *ops, | ||
317 | char *instr_type) | ||
318 | { | ||
319 | while (ops) { | ||
320 | if (!strcmp(ops->instr_type, instr_type)) | ||
321 | return ops; | ||
322 | ops = ops->next; | ||
323 | } | ||
324 | return NULL; | ||
325 | } | ||
326 | |||
327 | static int instr_result(struct snd_seq_event *ev, | ||
328 | int type, int result, | ||
329 | int atomic) | ||
330 | { | ||
331 | struct snd_seq_event sev; | ||
332 | |||
333 | memset(&sev, 0, sizeof(sev)); | ||
334 | sev.type = SNDRV_SEQ_EVENT_RESULT; | ||
335 | sev.flags = SNDRV_SEQ_TIME_STAMP_REAL | SNDRV_SEQ_EVENT_LENGTH_FIXED | | ||
336 | SNDRV_SEQ_PRIORITY_NORMAL; | ||
337 | sev.source = ev->dest; | ||
338 | sev.dest = ev->source; | ||
339 | sev.data.result.event = type; | ||
340 | sev.data.result.result = result; | ||
341 | #if 0 | ||
342 | printk("instr result - type = %i, result = %i, queue = %i, source.client:port = %i:%i, dest.client:port = %i:%i\n", | ||
343 | type, result, | ||
344 | sev.queue, | ||
345 | sev.source.client, sev.source.port, | ||
346 | sev.dest.client, sev.dest.port); | ||
347 | #endif | ||
348 | return snd_seq_kernel_client_dispatch(sev.source.client, &sev, atomic, 0); | ||
349 | } | ||
350 | |||
351 | static int instr_begin(struct snd_seq_kinstr_ops *ops, | ||
352 | struct snd_seq_kinstr_list *list, | ||
353 | struct snd_seq_event *ev, | ||
354 | int atomic, int hop) | ||
355 | { | ||
356 | unsigned long flags; | ||
357 | |||
358 | spin_lock_irqsave(&list->lock, flags); | ||
359 | if (list->owner >= 0 && list->owner != ev->source.client) { | ||
360 | spin_unlock_irqrestore(&list->lock, flags); | ||
361 | return instr_result(ev, SNDRV_SEQ_EVENT_INSTR_BEGIN, -EBUSY, atomic); | ||
362 | } | ||
363 | list->owner = ev->source.client; | ||
364 | spin_unlock_irqrestore(&list->lock, flags); | ||
365 | return instr_result(ev, SNDRV_SEQ_EVENT_INSTR_BEGIN, 0, atomic); | ||
366 | } | ||
367 | |||
368 | static int instr_end(struct snd_seq_kinstr_ops *ops, | ||
369 | struct snd_seq_kinstr_list *list, | ||
370 | struct snd_seq_event *ev, | ||
371 | int atomic, int hop) | ||
372 | { | ||
373 | unsigned long flags; | ||
374 | |||
375 | /* TODO: timeout handling */ | ||
376 | spin_lock_irqsave(&list->lock, flags); | ||
377 | if (list->owner == ev->source.client) { | ||
378 | list->owner = -1; | ||
379 | spin_unlock_irqrestore(&list->lock, flags); | ||
380 | return instr_result(ev, SNDRV_SEQ_EVENT_INSTR_END, 0, atomic); | ||
381 | } | ||
382 | spin_unlock_irqrestore(&list->lock, flags); | ||
383 | return instr_result(ev, SNDRV_SEQ_EVENT_INSTR_END, -EINVAL, atomic); | ||
384 | } | ||
385 | |||
386 | static int instr_info(struct snd_seq_kinstr_ops *ops, | ||
387 | struct snd_seq_kinstr_list *list, | ||
388 | struct snd_seq_event *ev, | ||
389 | int atomic, int hop) | ||
390 | { | ||
391 | return -ENXIO; | ||
392 | } | ||
393 | |||
394 | static int instr_format_info(struct snd_seq_kinstr_ops *ops, | ||
395 | struct snd_seq_kinstr_list *list, | ||
396 | struct snd_seq_event *ev, | ||
397 | int atomic, int hop) | ||
398 | { | ||
399 | return -ENXIO; | ||
400 | } | ||
401 | |||
402 | static int instr_reset(struct snd_seq_kinstr_ops *ops, | ||
403 | struct snd_seq_kinstr_list *list, | ||
404 | struct snd_seq_event *ev, | ||
405 | int atomic, int hop) | ||
406 | { | ||
407 | return -ENXIO; | ||
408 | } | ||
409 | |||
410 | static int instr_status(struct snd_seq_kinstr_ops *ops, | ||
411 | struct snd_seq_kinstr_list *list, | ||
412 | struct snd_seq_event *ev, | ||
413 | int atomic, int hop) | ||
414 | { | ||
415 | return -ENXIO; | ||
416 | } | ||
417 | |||
418 | static int instr_put(struct snd_seq_kinstr_ops *ops, | ||
419 | struct snd_seq_kinstr_list *list, | ||
420 | struct snd_seq_event *ev, | ||
421 | int atomic, int hop) | ||
422 | { | ||
423 | unsigned long flags; | ||
424 | struct snd_seq_instr_header put; | ||
425 | struct snd_seq_kinstr *instr; | ||
426 | int result = -EINVAL, len, key; | ||
427 | |||
428 | if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARUSR) | ||
429 | goto __return; | ||
430 | |||
431 | if (ev->data.ext.len < sizeof(struct snd_seq_instr_header)) | ||
432 | goto __return; | ||
433 | if (copy_from_user(&put, (void __user *)ev->data.ext.ptr, | ||
434 | sizeof(struct snd_seq_instr_header))) { | ||
435 | result = -EFAULT; | ||
436 | goto __return; | ||
437 | } | ||
438 | snd_instr_lock_ops(list); | ||
439 | if (put.id.instr.std & 0xff000000) { /* private instrument */ | ||
440 | put.id.instr.std &= 0x00ffffff; | ||
441 | put.id.instr.std |= (unsigned int)ev->source.client << 24; | ||
442 | } | ||
443 | if ((instr = snd_seq_instr_find(list, &put.id.instr, 1, 0))) { | ||
444 | snd_seq_instr_free_use(list, instr); | ||
445 | snd_instr_unlock_ops(list); | ||
446 | result = -EBUSY; | ||
447 | goto __return; | ||
448 | } | ||
449 | ops = instr_ops(ops, put.data.data.format); | ||
450 | if (ops == NULL) { | ||
451 | snd_instr_unlock_ops(list); | ||
452 | goto __return; | ||
453 | } | ||
454 | len = ops->add_len; | ||
455 | if (put.data.type == SNDRV_SEQ_INSTR_ATYPE_ALIAS) | ||
456 | len = sizeof(struct snd_seq_instr); | ||
457 | instr = snd_seq_instr_new(len, atomic); | ||
458 | if (instr == NULL) { | ||
459 | snd_instr_unlock_ops(list); | ||
460 | result = -ENOMEM; | ||
461 | goto __return; | ||
462 | } | ||
463 | instr->ops = ops; | ||
464 | instr->instr = put.id.instr; | ||
465 | strlcpy(instr->name, put.data.name, sizeof(instr->name)); | ||
466 | instr->type = put.data.type; | ||
467 | if (instr->type == SNDRV_SEQ_INSTR_ATYPE_DATA) { | ||
468 | result = ops->put(ops->private_data, | ||
469 | instr, | ||
470 | (void __user *)ev->data.ext.ptr + sizeof(struct snd_seq_instr_header), | ||
471 | ev->data.ext.len - sizeof(struct snd_seq_instr_header), | ||
472 | atomic, | ||
473 | put.cmd); | ||
474 | if (result < 0) { | ||
475 | snd_seq_instr_free(instr, atomic); | ||
476 | snd_instr_unlock_ops(list); | ||
477 | goto __return; | ||
478 | } | ||
479 | } | ||
480 | key = compute_hash_instr_key(&instr->instr); | ||
481 | spin_lock_irqsave(&list->lock, flags); | ||
482 | instr->next = list->hash[key]; | ||
483 | list->hash[key] = instr; | ||
484 | list->count++; | ||
485 | spin_unlock_irqrestore(&list->lock, flags); | ||
486 | snd_instr_unlock_ops(list); | ||
487 | result = 0; | ||
488 | __return: | ||
489 | instr_result(ev, SNDRV_SEQ_EVENT_INSTR_PUT, result, atomic); | ||
490 | return result; | ||
491 | } | ||
492 | |||
493 | static int instr_get(struct snd_seq_kinstr_ops *ops, | ||
494 | struct snd_seq_kinstr_list *list, | ||
495 | struct snd_seq_event *ev, | ||
496 | int atomic, int hop) | ||
497 | { | ||
498 | return -ENXIO; | ||
499 | } | ||
500 | |||
501 | static int instr_free(struct snd_seq_kinstr_ops *ops, | ||
502 | struct snd_seq_kinstr_list *list, | ||
503 | struct snd_seq_event *ev, | ||
504 | int atomic, int hop) | ||
505 | { | ||
506 | struct snd_seq_instr_header ifree; | ||
507 | struct snd_seq_kinstr *instr, *prev; | ||
508 | int result = -EINVAL; | ||
509 | unsigned long flags; | ||
510 | unsigned int hash; | ||
511 | |||
512 | if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARUSR) | ||
513 | goto __return; | ||
514 | |||
515 | if (ev->data.ext.len < sizeof(struct snd_seq_instr_header)) | ||
516 | goto __return; | ||
517 | if (copy_from_user(&ifree, (void __user *)ev->data.ext.ptr, | ||
518 | sizeof(struct snd_seq_instr_header))) { | ||
519 | result = -EFAULT; | ||
520 | goto __return; | ||
521 | } | ||
522 | if (ifree.cmd == SNDRV_SEQ_INSTR_FREE_CMD_ALL || | ||
523 | ifree.cmd == SNDRV_SEQ_INSTR_FREE_CMD_PRIVATE || | ||
524 | ifree.cmd == SNDRV_SEQ_INSTR_FREE_CMD_CLUSTER) { | ||
525 | result = snd_seq_instr_list_free_cond(list, &ifree, ev->dest.client, atomic); | ||
526 | goto __return; | ||
527 | } | ||
528 | if (ifree.cmd == SNDRV_SEQ_INSTR_FREE_CMD_SINGLE) { | ||
529 | if (ifree.id.instr.std & 0xff000000) { | ||
530 | ifree.id.instr.std &= 0x00ffffff; | ||
531 | ifree.id.instr.std |= (unsigned int)ev->source.client << 24; | ||
532 | } | ||
533 | hash = compute_hash_instr_key(&ifree.id.instr); | ||
534 | snd_instr_lock_ops(list); | ||
535 | spin_lock_irqsave(&list->lock, flags); | ||
536 | instr = list->hash[hash]; | ||
537 | prev = NULL; | ||
538 | while (instr) { | ||
539 | if (!compare_instr(&instr->instr, &ifree.id.instr, 1)) | ||
540 | goto __free_single; | ||
541 | prev = instr; | ||
542 | instr = instr->next; | ||
543 | } | ||
544 | result = -ENOENT; | ||
545 | spin_unlock_irqrestore(&list->lock, flags); | ||
546 | snd_instr_unlock_ops(list); | ||
547 | goto __return; | ||
548 | |||
549 | __free_single: | ||
550 | if (prev) { | ||
551 | prev->next = instr->next; | ||
552 | } else { | ||
553 | list->hash[hash] = instr->next; | ||
554 | } | ||
555 | if (instr->ops && instr->ops->notify) | ||
556 | instr->ops->notify(instr->ops->private_data, instr, | ||
557 | SNDRV_SEQ_INSTR_NOTIFY_REMOVE); | ||
558 | while (instr->use) { | ||
559 | spin_unlock_irqrestore(&list->lock, flags); | ||
560 | schedule_timeout_uninterruptible(1); | ||
561 | spin_lock_irqsave(&list->lock, flags); | ||
562 | } | ||
563 | spin_unlock_irqrestore(&list->lock, flags); | ||
564 | result = snd_seq_instr_free(instr, atomic); | ||
565 | snd_instr_unlock_ops(list); | ||
566 | goto __return; | ||
567 | } | ||
568 | |||
569 | __return: | ||
570 | instr_result(ev, SNDRV_SEQ_EVENT_INSTR_FREE, result, atomic); | ||
571 | return result; | ||
572 | } | ||
573 | |||
574 | static int instr_list(struct snd_seq_kinstr_ops *ops, | ||
575 | struct snd_seq_kinstr_list *list, | ||
576 | struct snd_seq_event *ev, | ||
577 | int atomic, int hop) | ||
578 | { | ||
579 | return -ENXIO; | ||
580 | } | ||
581 | |||
582 | static int instr_cluster(struct snd_seq_kinstr_ops *ops, | ||
583 | struct snd_seq_kinstr_list *list, | ||
584 | struct snd_seq_event *ev, | ||
585 | int atomic, int hop) | ||
586 | { | ||
587 | return -ENXIO; | ||
588 | } | ||
589 | |||
590 | int snd_seq_instr_event(struct snd_seq_kinstr_ops *ops, | ||
591 | struct snd_seq_kinstr_list *list, | ||
592 | struct snd_seq_event *ev, | ||
593 | int client, | ||
594 | int atomic, | ||
595 | int hop) | ||
596 | { | ||
597 | int direct = 0; | ||
598 | |||
599 | snd_assert(ops != NULL && list != NULL && ev != NULL, return -EINVAL); | ||
600 | if (snd_seq_ev_is_direct(ev)) { | ||
601 | direct = 1; | ||
602 | switch (ev->type) { | ||
603 | case SNDRV_SEQ_EVENT_INSTR_BEGIN: | ||
604 | return instr_begin(ops, list, ev, atomic, hop); | ||
605 | case SNDRV_SEQ_EVENT_INSTR_END: | ||
606 | return instr_end(ops, list, ev, atomic, hop); | ||
607 | } | ||
608 | } | ||
609 | if ((list->flags & SNDRV_SEQ_INSTR_FLG_DIRECT) && !direct) | ||
610 | return -EINVAL; | ||
611 | switch (ev->type) { | ||
612 | case SNDRV_SEQ_EVENT_INSTR_INFO: | ||
613 | return instr_info(ops, list, ev, atomic, hop); | ||
614 | case SNDRV_SEQ_EVENT_INSTR_FINFO: | ||
615 | return instr_format_info(ops, list, ev, atomic, hop); | ||
616 | case SNDRV_SEQ_EVENT_INSTR_RESET: | ||
617 | return instr_reset(ops, list, ev, atomic, hop); | ||
618 | case SNDRV_SEQ_EVENT_INSTR_STATUS: | ||
619 | return instr_status(ops, list, ev, atomic, hop); | ||
620 | case SNDRV_SEQ_EVENT_INSTR_PUT: | ||
621 | return instr_put(ops, list, ev, atomic, hop); | ||
622 | case SNDRV_SEQ_EVENT_INSTR_GET: | ||
623 | return instr_get(ops, list, ev, atomic, hop); | ||
624 | case SNDRV_SEQ_EVENT_INSTR_FREE: | ||
625 | return instr_free(ops, list, ev, atomic, hop); | ||
626 | case SNDRV_SEQ_EVENT_INSTR_LIST: | ||
627 | return instr_list(ops, list, ev, atomic, hop); | ||
628 | case SNDRV_SEQ_EVENT_INSTR_CLUSTER: | ||
629 | return instr_cluster(ops, list, ev, atomic, hop); | ||
630 | } | ||
631 | return -EINVAL; | ||
632 | } | ||
633 | |||
634 | /* | ||
635 | * Init part | ||
636 | */ | ||
637 | |||
638 | static int __init alsa_seq_instr_init(void) | ||
639 | { | ||
640 | return 0; | ||
641 | } | ||
642 | |||
643 | static void __exit alsa_seq_instr_exit(void) | ||
644 | { | ||
645 | } | ||
646 | |||
647 | module_init(alsa_seq_instr_init) | ||
648 | module_exit(alsa_seq_instr_exit) | ||
649 | |||
650 | EXPORT_SYMBOL(snd_seq_instr_list_new); | ||
651 | EXPORT_SYMBOL(snd_seq_instr_list_free); | ||
652 | EXPORT_SYMBOL(snd_seq_instr_list_free_cond); | ||
653 | EXPORT_SYMBOL(snd_seq_instr_find); | ||
654 | EXPORT_SYMBOL(snd_seq_instr_free_use); | ||
655 | EXPORT_SYMBOL(snd_seq_instr_event); | ||
diff --git a/sound/core/seq/seq_lock.c b/sound/core/seq/seq_lock.c index 1a34941d4217..54f921edda79 100644 --- a/sound/core/seq/seq_lock.c +++ b/sound/core/seq/seq_lock.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <sound/core.h> | 22 | #include <sound/core.h> |
24 | #include "seq_lock.h" | 23 | #include "seq_lock.h" |
25 | 24 | ||
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c index a72a1945bf8a..0cf6ac477318 100644 --- a/sound/core/seq/seq_memory.c +++ b/sound/core/seq/seq_memory.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
26 | #include <linux/vmalloc.h> | 25 | #include <linux/vmalloc.h> |
diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index 5929aaf1df9d..99b35360c506 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c | |||
@@ -26,7 +26,6 @@ Possible options for midisynth module: | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | 28 | ||
29 | #include <sound/driver.h> | ||
30 | #include <linux/init.h> | 29 | #include <linux/init.h> |
31 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
32 | #include <linux/errno.h> | 31 | #include <linux/errno.h> |
diff --git a/sound/core/seq/seq_midi_emul.c b/sound/core/seq/seq_midi_emul.c index 17b3e6f13ca3..07c663135c62 100644 --- a/sound/core/seq/seq_midi_emul.c +++ b/sound/core/seq/seq_midi_emul.c | |||
@@ -29,7 +29,6 @@ | |||
29 | * code in here. If there is it should be reported as a bug. | 29 | * code in here. If there is it should be reported as a bug. |
30 | */ | 30 | */ |
31 | 31 | ||
32 | #include <sound/driver.h> | ||
33 | #include <linux/init.h> | 32 | #include <linux/init.h> |
34 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
35 | #include <linux/string.h> | 34 | #include <linux/string.h> |
@@ -229,13 +228,6 @@ snd_midi_process_event(struct snd_midi_op *ops, | |||
229 | case SNDRV_SEQ_EVENT_PORT_START: | 228 | case SNDRV_SEQ_EVENT_PORT_START: |
230 | case SNDRV_SEQ_EVENT_PORT_EXIT: | 229 | case SNDRV_SEQ_EVENT_PORT_EXIT: |
231 | case SNDRV_SEQ_EVENT_PORT_CHANGE: | 230 | case SNDRV_SEQ_EVENT_PORT_CHANGE: |
232 | case SNDRV_SEQ_EVENT_SAMPLE: | ||
233 | case SNDRV_SEQ_EVENT_SAMPLE_START: | ||
234 | case SNDRV_SEQ_EVENT_SAMPLE_STOP: | ||
235 | case SNDRV_SEQ_EVENT_SAMPLE_FREQ: | ||
236 | case SNDRV_SEQ_EVENT_SAMPLE_VOLUME: | ||
237 | case SNDRV_SEQ_EVENT_SAMPLE_LOOP: | ||
238 | case SNDRV_SEQ_EVENT_SAMPLE_POSITION: | ||
239 | case SNDRV_SEQ_EVENT_ECHO: | 231 | case SNDRV_SEQ_EVENT_ECHO: |
240 | not_yet: | 232 | not_yet: |
241 | default: | 233 | default: |
diff --git a/sound/core/seq/seq_midi_event.c b/sound/core/seq/seq_midi_event.c index b6820a5a73fc..8284f176a342 100644 --- a/sound/core/seq/seq_midi_event.c +++ b/sound/core/seq/seq_midi_event.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
24 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
25 | #include <linux/string.h> | 24 | #include <linux/string.h> |
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index b6e23ad12ab9..1c32a53d6bd8 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <sound/core.h> | 23 | #include <sound/core.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
26 | #include "seq_system.h" | 25 | #include "seq_system.h" |
diff --git a/sound/core/seq/seq_prioq.c b/sound/core/seq/seq_prioq.c index 074418617ee9..85969db576c9 100644 --- a/sound/core/seq/seq_prioq.c +++ b/sound/core/seq/seq_prioq.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/time.h> | 22 | #include <linux/time.h> |
24 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
25 | #include <sound/core.h> | 24 | #include <sound/core.h> |
diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c index 9b87bb0c7f33..4a48c6ee8ee8 100644 --- a/sound/core/seq/seq_queue.c +++ b/sound/core/seq/seq_queue.c | |||
@@ -35,7 +35,6 @@ | |||
35 | * - Addition of experimental sync support. | 35 | * - Addition of experimental sync support. |
36 | */ | 36 | */ |
37 | 37 | ||
38 | #include <sound/driver.h> | ||
39 | #include <linux/init.h> | 38 | #include <linux/init.h> |
40 | #include <linux/slab.h> | 39 | #include <linux/slab.h> |
41 | #include <sound/core.h> | 40 | #include <sound/core.h> |
diff --git a/sound/core/seq/seq_system.c b/sound/core/seq/seq_system.c index b201b76e9412..77884e62b648 100644 --- a/sound/core/seq/seq_system.c +++ b/sound/core/seq/seq_system.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <sound/core.h> | 23 | #include <sound/core.h> |
25 | #include "seq_system.h" | 24 | #include "seq_system.h" |
diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index 8716352afc81..d8fcd62e400f 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c | |||
@@ -20,20 +20,12 @@ | |||
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <sound/core.h> | 23 | #include <sound/core.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
26 | #include "seq_timer.h" | 25 | #include "seq_timer.h" |
27 | #include "seq_queue.h" | 26 | #include "seq_queue.h" |
28 | #include "seq_info.h" | 27 | #include "seq_info.h" |
29 | 28 | ||
30 | extern int seq_default_timer_class; | ||
31 | extern int seq_default_timer_sclass; | ||
32 | extern int seq_default_timer_card; | ||
33 | extern int seq_default_timer_device; | ||
34 | extern int seq_default_timer_subdevice; | ||
35 | extern int seq_default_timer_resolution; | ||
36 | |||
37 | /* allowed sequencer timer frequencies, in Hz */ | 29 | /* allowed sequencer timer frequencies, in Hz */ |
38 | #define MIN_FREQUENCY 10 | 30 | #define MIN_FREQUENCY 10 |
39 | #define MAX_FREQUENCY 6250 | 31 | #define MAX_FREQUENCY 6250 |
diff --git a/sound/core/seq/seq_timer.h b/sound/core/seq/seq_timer.h index e9ee1543c924..88dfb71805ae 100644 --- a/sound/core/seq/seq_timer.h +++ b/sound/core/seq/seq_timer.h | |||
@@ -138,4 +138,11 @@ int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew, unsigne | |||
138 | snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr); | 138 | snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr); |
139 | snd_seq_tick_time_t snd_seq_timer_get_cur_tick(struct snd_seq_timer *tmr); | 139 | snd_seq_tick_time_t snd_seq_timer_get_cur_tick(struct snd_seq_timer *tmr); |
140 | 140 | ||
141 | extern int seq_default_timer_class; | ||
142 | extern int seq_default_timer_sclass; | ||
143 | extern int seq_default_timer_card; | ||
144 | extern int seq_default_timer_device; | ||
145 | extern int seq_default_timer_subdevice; | ||
146 | extern int seq_default_timer_resolution; | ||
147 | |||
141 | #endif | 148 | #endif |
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index e11790f6debe..86e7739269ca 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c | |||
@@ -35,7 +35,6 @@ | |||
35 | * | 35 | * |
36 | */ | 36 | */ |
37 | 37 | ||
38 | #include <sound/driver.h> | ||
39 | #include <linux/init.h> | 38 | #include <linux/init.h> |
40 | #include <linux/wait.h> | 39 | #include <linux/wait.h> |
41 | #include <linux/slab.h> | 40 | #include <linux/slab.h> |
diff --git a/sound/core/sound.c b/sound/core/sound.c index 7b486c4d70db..00cca4d6e562 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
25 | #include <linux/time.h> | 24 | #include <linux/time.h> |
diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c index dc73313b733a..7be51546eb9e 100644 --- a/sound/core/sound_oss.c +++ b/sound/core/sound_oss.c | |||
@@ -19,8 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | |||
24 | #ifdef CONFIG_SND_OSSEMUL | 22 | #ifdef CONFIG_SND_OSSEMUL |
25 | 23 | ||
26 | #if !defined(CONFIG_SOUND) && !(defined(MODULE) && defined(CONFIG_SOUND_MODULE)) | 24 | #if !defined(CONFIG_SOUND) && !(defined(MODULE) && defined(CONFIG_SOUND_MODULE)) |
diff --git a/sound/core/timer.c b/sound/core/timer.c index e7dc56ca4b97..aece465934b8 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
@@ -44,11 +43,14 @@ | |||
44 | #endif | 43 | #endif |
45 | 44 | ||
46 | static int timer_limit = DEFAULT_TIMER_LIMIT; | 45 | static int timer_limit = DEFAULT_TIMER_LIMIT; |
46 | static int timer_tstamp_monotonic = 1; | ||
47 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.de>"); | 47 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.de>"); |
48 | MODULE_DESCRIPTION("ALSA timer interface"); | 48 | MODULE_DESCRIPTION("ALSA timer interface"); |
49 | MODULE_LICENSE("GPL"); | 49 | MODULE_LICENSE("GPL"); |
50 | module_param(timer_limit, int, 0444); | 50 | module_param(timer_limit, int, 0444); |
51 | MODULE_PARM_DESC(timer_limit, "Maximum global timers in system."); | 51 | MODULE_PARM_DESC(timer_limit, "Maximum global timers in system."); |
52 | module_param(timer_tstamp_monotonic, int, 0444); | ||
53 | MODULE_PARM_DESC(timer_tstamp_monotonic, "Use posix monotonic clock source for timestamps (default)."); | ||
52 | 54 | ||
53 | struct snd_timer_user { | 55 | struct snd_timer_user { |
54 | struct snd_timer_instance *timeri; | 56 | struct snd_timer_instance *timeri; |
@@ -381,7 +383,10 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event) | |||
381 | struct snd_timer_instance *ts; | 383 | struct snd_timer_instance *ts; |
382 | struct timespec tstamp; | 384 | struct timespec tstamp; |
383 | 385 | ||
384 | getnstimeofday(&tstamp); | 386 | if (timer_tstamp_monotonic) |
387 | do_posix_clock_monotonic_gettime(&tstamp); | ||
388 | else | ||
389 | getnstimeofday(&tstamp); | ||
385 | snd_assert(event >= SNDRV_TIMER_EVENT_START && | 390 | snd_assert(event >= SNDRV_TIMER_EVENT_START && |
386 | event <= SNDRV_TIMER_EVENT_PAUSE, return); | 391 | event <= SNDRV_TIMER_EVENT_PAUSE, return); |
387 | if (event == SNDRV_TIMER_EVENT_START || | 392 | if (event == SNDRV_TIMER_EVENT_START || |
@@ -1182,8 +1187,12 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri, | |||
1182 | spin_unlock(&tu->qlock); | 1187 | spin_unlock(&tu->qlock); |
1183 | return; | 1188 | return; |
1184 | } | 1189 | } |
1185 | if (tu->last_resolution != resolution || ticks > 0) | 1190 | if (tu->last_resolution != resolution || ticks > 0) { |
1186 | getnstimeofday(&tstamp); | 1191 | if (timer_tstamp_monotonic) |
1192 | do_posix_clock_monotonic_gettime(&tstamp); | ||
1193 | else | ||
1194 | getnstimeofday(&tstamp); | ||
1195 | } | ||
1187 | if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) && | 1196 | if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) && |
1188 | tu->last_resolution != resolution) { | 1197 | tu->last_resolution != resolution) { |
1189 | r1.event = SNDRV_TIMER_EVENT_RESOLUTION; | 1198 | r1.event = SNDRV_TIMER_EVENT_RESOLUTION; |
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index 83529b08d019..75d4fe09fdf3 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig | |||
@@ -120,4 +120,16 @@ config SND_PORTMAN2X4 | |||
120 | To compile this driver as a module, choose M here: the module | 120 | To compile this driver as a module, choose M here: the module |
121 | will be called snd-portman2x4. | 121 | will be called snd-portman2x4. |
122 | 122 | ||
123 | config SND_ML403_AC97CR | ||
124 | tristate "Xilinx ML403 AC97 Controller Reference" | ||
125 | depends on SND && XILINX_VIRTEX | ||
126 | select SND_AC97_CODEC | ||
127 | help | ||
128 | Say Y here to include support for the | ||
129 | opb_ac97_controller_ref_v1_00_a ip core found in Xilinx' ML403 | ||
130 | reference design. | ||
131 | |||
132 | To compile this driver as a module, choose M here: the module | ||
133 | will be called snd-ml403_ac97cr. | ||
134 | |||
123 | endmenu | 135 | endmenu |
diff --git a/sound/drivers/Makefile b/sound/drivers/Makefile index 80aeff5ccdea..8e5530006e1f 100644 --- a/sound/drivers/Makefile +++ b/sound/drivers/Makefile | |||
@@ -9,6 +9,7 @@ snd-mts64-objs := mts64.o | |||
9 | snd-portman2x4-objs := portman2x4.o | 9 | snd-portman2x4-objs := portman2x4.o |
10 | snd-serial-u16550-objs := serial-u16550.o | 10 | snd-serial-u16550-objs := serial-u16550.o |
11 | snd-virmidi-objs := virmidi.o | 11 | snd-virmidi-objs := virmidi.o |
12 | snd-ml403-ac97cr-objs := ml403-ac97cr.o pcm-indirect2.o | ||
12 | 13 | ||
13 | # Toplevel Module Dependency | 14 | # Toplevel Module Dependency |
14 | obj-$(CONFIG_SND_DUMMY) += snd-dummy.o | 15 | obj-$(CONFIG_SND_DUMMY) += snd-dummy.o |
@@ -17,5 +18,6 @@ obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o | |||
17 | obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o | 18 | obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o |
18 | obj-$(CONFIG_SND_MTS64) += snd-mts64.o | 19 | obj-$(CONFIG_SND_MTS64) += snd-mts64.o |
19 | obj-$(CONFIG_SND_PORTMAN2X4) += snd-portman2x4.o | 20 | obj-$(CONFIG_SND_PORTMAN2X4) += snd-portman2x4.o |
21 | obj-$(CONFIG_SND_ML403_AC97CR) += snd-ml403-ac97cr.o | ||
20 | 22 | ||
21 | obj-$(CONFIG_SND) += opl3/ opl4/ mpu401/ vx/ | 23 | obj-$(CONFIG_SND) += opl3/ opl4/ mpu401/ vx/ |
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index e008f3c58eac..a240eaeb5c62 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c | |||
@@ -18,7 +18,6 @@ | |||
18 | * | 18 | * |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <sound/driver.h> | ||
22 | #include <linux/init.h> | 21 | #include <linux/init.h> |
23 | #include <linux/err.h> | 22 | #include <linux/err.h> |
24 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
diff --git a/sound/drivers/ml403-ac97cr.c b/sound/drivers/ml403-ac97cr.c new file mode 100644 index 000000000000..05a871aa7b81 --- /dev/null +++ b/sound/drivers/ml403-ac97cr.c | |||
@@ -0,0 +1,1352 @@ | |||
1 | /* | ||
2 | * ALSA driver for Xilinx ML403 AC97 Controller Reference | ||
3 | * IP: opb_ac97_controller_ref_v1_00_a (EDK 8.1i) | ||
4 | * IP: opb_ac97_controller_ref_v1_00_a (EDK 9.1i) | ||
5 | * | ||
6 | * Copyright (c) by 2007 Joachim Foerster <JOFT@gmx.de> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | /* Some notes / status of this driver: | ||
25 | * | ||
26 | * - Don't wonder about some strange implementations of things - especially the | ||
27 | * (heavy) shadowing of codec registers, with which I tried to reduce read | ||
28 | * accesses to a minimum, because after a variable amount of accesses, the AC97 | ||
29 | * controller doesn't raise the register access finished bit anymore ... | ||
30 | * | ||
31 | * - Playback support seems to be pretty stable - no issues here. | ||
32 | * - Capture support "works" now, too. Overruns don't happen any longer so often. | ||
33 | * But there might still be some ... | ||
34 | */ | ||
35 | |||
36 | #include <linux/init.h> | ||
37 | #include <linux/moduleparam.h> | ||
38 | |||
39 | #include <linux/platform_device.h> | ||
40 | |||
41 | #include <linux/ioport.h> | ||
42 | #include <linux/io.h> | ||
43 | #include <linux/interrupt.h> | ||
44 | |||
45 | /* HZ */ | ||
46 | #include <linux/param.h> | ||
47 | /* jiffies, time_*() */ | ||
48 | #include <linux/jiffies.h> | ||
49 | /* schedule_timeout*() */ | ||
50 | #include <linux/sched.h> | ||
51 | /* spin_lock*() */ | ||
52 | #include <linux/spinlock.h> | ||
53 | /* struct mutex, mutex_init(), mutex_*lock() */ | ||
54 | #include <linux/mutex.h> | ||
55 | |||
56 | /* snd_printk(), snd_printd() */ | ||
57 | #include <sound/core.h> | ||
58 | #include <sound/pcm.h> | ||
59 | #include <sound/pcm_params.h> | ||
60 | #include <sound/initval.h> | ||
61 | #include <sound/ac97_codec.h> | ||
62 | |||
63 | #include "pcm-indirect2.h" | ||
64 | |||
65 | |||
66 | #define SND_ML403_AC97CR_DRIVER "ml403-ac97cr" | ||
67 | |||
68 | MODULE_AUTHOR("Joachim Foerster <JOFT@gmx.de>"); | ||
69 | MODULE_DESCRIPTION("Xilinx ML403 AC97 Controller Reference"); | ||
70 | MODULE_LICENSE("GPL"); | ||
71 | MODULE_SUPPORTED_DEVICE("{{Xilinx,ML403 AC97 Controller Reference}}"); | ||
72 | |||
73 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | ||
74 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | ||
75 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; | ||
76 | |||
77 | module_param_array(index, int, NULL, 0444); | ||
78 | MODULE_PARM_DESC(index, "Index value for ML403 AC97 Controller Reference."); | ||
79 | module_param_array(id, charp, NULL, 0444); | ||
80 | MODULE_PARM_DESC(id, "ID string for ML403 AC97 Controller Reference."); | ||
81 | module_param_array(enable, bool, NULL, 0444); | ||
82 | MODULE_PARM_DESC(enable, "Enable this ML403 AC97 Controller Reference."); | ||
83 | |||
84 | /* Special feature options */ | ||
85 | /*#define CODEC_WRITE_CHECK_RAF*/ /* don't return after a write to a codec | ||
86 | * register, while RAF bit is not set | ||
87 | */ | ||
88 | /* Debug options for code which may be removed completely in a final version */ | ||
89 | #ifdef CONFIG_SND_DEBUG | ||
90 | /*#define CODEC_STAT*/ /* turn on some minimal "statistics" | ||
91 | * about codec register usage | ||
92 | */ | ||
93 | #define SND_PCM_INDIRECT2_STAT /* turn on some "statistics" about the | ||
94 | * process of copying bytes from the | ||
95 | * intermediate buffer to the hardware | ||
96 | * fifo and the other way round | ||
97 | */ | ||
98 | #endif | ||
99 | |||
100 | /* Definition of a "level/facility dependent" printk(); may be removed | ||
101 | * completely in a final version | ||
102 | */ | ||
103 | #undef PDEBUG | ||
104 | #ifdef CONFIG_SND_DEBUG | ||
105 | /* "facilities" for PDEBUG */ | ||
106 | #define UNKNOWN (1<<0) | ||
107 | #define CODEC_SUCCESS (1<<1) | ||
108 | #define CODEC_FAKE (1<<2) | ||
109 | #define INIT_INFO (1<<3) | ||
110 | #define INIT_FAILURE (1<<4) | ||
111 | #define WORK_INFO (1<<5) | ||
112 | #define WORK_FAILURE (1<<6) | ||
113 | |||
114 | #define PDEBUG_FACILITIES (UNKNOWN | INIT_FAILURE | WORK_FAILURE) | ||
115 | |||
116 | #define PDEBUG(fac, fmt, args...) do { \ | ||
117 | if (fac & PDEBUG_FACILITIES) \ | ||
118 | snd_printd(KERN_DEBUG SND_ML403_AC97CR_DRIVER ": " \ | ||
119 | fmt, ##args); \ | ||
120 | } while (0) | ||
121 | #else | ||
122 | #define PDEBUG(fac, fmt, args...) /* nothing */ | ||
123 | #endif | ||
124 | |||
125 | |||
126 | |||
127 | /* Defines for "waits"/timeouts (portions of HZ=250 on arch/ppc by default) */ | ||
128 | #define CODEC_TIMEOUT_ON_INIT 5 /* timeout for checking for codec | ||
129 | * readiness (after insmod) | ||
130 | */ | ||
131 | #ifndef CODEC_WRITE_CHECK_RAF | ||
132 | #define CODEC_WAIT_AFTER_WRITE 100 /* general, static wait after a write | ||
133 | * access to a codec register, may be | ||
134 | * 0 to completely remove wait | ||
135 | */ | ||
136 | #else | ||
137 | #define CODEC_TIMEOUT_AFTER_WRITE 5 /* timeout after a write access to a | ||
138 | * codec register, if RAF bit is used | ||
139 | */ | ||
140 | #endif | ||
141 | #define CODEC_TIMEOUT_AFTER_READ 5 /* timeout after a read access to a | ||
142 | * codec register (checking RAF bit) | ||
143 | */ | ||
144 | |||
145 | /* Infrastructure for codec register shadowing */ | ||
146 | #define LM4550_REG_OK (1<<0) /* register exists */ | ||
147 | #define LM4550_REG_DONEREAD (1<<1) /* read register once, value should be | ||
148 | * the same currently in the register | ||
149 | */ | ||
150 | #define LM4550_REG_NOSAVE (1<<2) /* values written to this register will | ||
151 | * not be saved in the register | ||
152 | */ | ||
153 | #define LM4550_REG_NOSHADOW (1<<3) /* don't do register shadowing, use plain | ||
154 | * hardware access | ||
155 | */ | ||
156 | #define LM4550_REG_READONLY (1<<4) /* register is read only */ | ||
157 | #define LM4550_REG_FAKEPROBE (1<<5) /* fake write _and_ read actions during | ||
158 | * probe() correctly | ||
159 | */ | ||
160 | #define LM4550_REG_FAKEREAD (1<<6) /* fake read access, always return | ||
161 | * default value | ||
162 | */ | ||
163 | #define LM4550_REG_ALLFAKE (LM4550_REG_FAKEREAD | LM4550_REG_FAKEPROBE) | ||
164 | |||
165 | struct lm4550_reg { | ||
166 | u16 value; | ||
167 | u16 flag; | ||
168 | u16 wmask; | ||
169 | u16 def; | ||
170 | }; | ||
171 | |||
172 | struct lm4550_reg lm4550_regfile[64] = { | ||
173 | [AC97_RESET / 2] = {.flag = LM4550_REG_OK \ | ||
174 | | LM4550_REG_NOSAVE \ | ||
175 | | LM4550_REG_FAKEREAD, | ||
176 | .def = 0x0D50}, | ||
177 | [AC97_MASTER / 2] = {.flag = LM4550_REG_OK | ||
178 | | LM4550_REG_FAKEPROBE, | ||
179 | .wmask = 0x9F1F, | ||
180 | .def = 0x8000}, | ||
181 | [AC97_HEADPHONE / 2] = {.flag = LM4550_REG_OK \ | ||
182 | | LM4550_REG_FAKEPROBE, | ||
183 | .wmask = 0x9F1F, | ||
184 | .def = 0x8000}, | ||
185 | [AC97_MASTER_MONO / 2] = {.flag = LM4550_REG_OK \ | ||
186 | | LM4550_REG_FAKEPROBE, | ||
187 | .wmask = 0x801F, | ||
188 | .def = 0x8000}, | ||
189 | [AC97_PC_BEEP / 2] = {.flag = LM4550_REG_OK \ | ||
190 | | LM4550_REG_FAKEPROBE, | ||
191 | .wmask = 0x801E, | ||
192 | .def = 0x0}, | ||
193 | [AC97_PHONE / 2] = {.flag = LM4550_REG_OK \ | ||
194 | | LM4550_REG_FAKEPROBE, | ||
195 | .wmask = 0x801F, | ||
196 | .def = 0x8008}, | ||
197 | [AC97_MIC / 2] = {.flag = LM4550_REG_OK \ | ||
198 | | LM4550_REG_FAKEPROBE, | ||
199 | .wmask = 0x805F, | ||
200 | .def = 0x8008}, | ||
201 | [AC97_LINE / 2] = {.flag = LM4550_REG_OK \ | ||
202 | | LM4550_REG_FAKEPROBE, | ||
203 | .wmask = 0x9F1F, | ||
204 | .def = 0x8808}, | ||
205 | [AC97_CD / 2] = {.flag = LM4550_REG_OK \ | ||
206 | | LM4550_REG_FAKEPROBE, | ||
207 | .wmask = 0x9F1F, | ||
208 | .def = 0x8808}, | ||
209 | [AC97_VIDEO / 2] = {.flag = LM4550_REG_OK \ | ||
210 | | LM4550_REG_FAKEPROBE, | ||
211 | .wmask = 0x9F1F, | ||
212 | .def = 0x8808}, | ||
213 | [AC97_AUX / 2] = {.flag = LM4550_REG_OK \ | ||
214 | | LM4550_REG_FAKEPROBE, | ||
215 | .wmask = 0x9F1F, | ||
216 | .def = 0x8808}, | ||
217 | [AC97_PCM / 2] = {.flag = LM4550_REG_OK \ | ||
218 | | LM4550_REG_FAKEPROBE, | ||
219 | .wmask = 0x9F1F, | ||
220 | .def = 0x8008}, | ||
221 | [AC97_REC_SEL / 2] = {.flag = LM4550_REG_OK \ | ||
222 | | LM4550_REG_FAKEPROBE, | ||
223 | .wmask = 0x707, | ||
224 | .def = 0x0}, | ||
225 | [AC97_REC_GAIN / 2] = {.flag = LM4550_REG_OK \ | ||
226 | | LM4550_REG_FAKEPROBE, | ||
227 | .wmask = 0x8F0F, | ||
228 | .def = 0x8000}, | ||
229 | [AC97_GENERAL_PURPOSE / 2] = {.flag = LM4550_REG_OK \ | ||
230 | | LM4550_REG_FAKEPROBE, | ||
231 | .def = 0x0, | ||
232 | .wmask = 0xA380}, | ||
233 | [AC97_3D_CONTROL / 2] = {.flag = LM4550_REG_OK \ | ||
234 | | LM4550_REG_FAKEREAD \ | ||
235 | | LM4550_REG_READONLY, | ||
236 | .def = 0x0101}, | ||
237 | [AC97_POWERDOWN / 2] = {.flag = LM4550_REG_OK \ | ||
238 | | LM4550_REG_NOSHADOW \ | ||
239 | | LM4550_REG_NOSAVE, | ||
240 | .wmask = 0xFF00}, | ||
241 | /* may not write ones to | ||
242 | * REF/ANL/DAC/ADC bits | ||
243 | * FIXME: Is this ok? | ||
244 | */ | ||
245 | [AC97_EXTENDED_ID / 2] = {.flag = LM4550_REG_OK \ | ||
246 | | LM4550_REG_FAKEREAD \ | ||
247 | | LM4550_REG_READONLY, | ||
248 | .def = 0x0201}, /* primary codec */ | ||
249 | [AC97_EXTENDED_STATUS / 2] = {.flag = LM4550_REG_OK \ | ||
250 | | LM4550_REG_NOSHADOW \ | ||
251 | | LM4550_REG_NOSAVE, | ||
252 | .wmask = 0x1}, | ||
253 | [AC97_PCM_FRONT_DAC_RATE / 2] = {.flag = LM4550_REG_OK \ | ||
254 | | LM4550_REG_FAKEPROBE, | ||
255 | .def = 0xBB80, | ||
256 | .wmask = 0xFFFF}, | ||
257 | [AC97_PCM_LR_ADC_RATE / 2] = {.flag = LM4550_REG_OK \ | ||
258 | | LM4550_REG_FAKEPROBE, | ||
259 | .def = 0xBB80, | ||
260 | .wmask = 0xFFFF}, | ||
261 | [AC97_VENDOR_ID1 / 2] = {.flag = LM4550_REG_OK \ | ||
262 | | LM4550_REG_READONLY \ | ||
263 | | LM4550_REG_FAKEREAD, | ||
264 | .def = 0x4E53}, | ||
265 | [AC97_VENDOR_ID2 / 2] = {.flag = LM4550_REG_OK \ | ||
266 | | LM4550_REG_READONLY \ | ||
267 | | LM4550_REG_FAKEREAD, | ||
268 | .def = 0x4350} | ||
269 | }; | ||
270 | |||
271 | #define LM4550_RF_OK(reg) (lm4550_regfile[reg / 2].flag & LM4550_REG_OK) | ||
272 | |||
273 | static void lm4550_regfile_init(void) | ||
274 | { | ||
275 | int i; | ||
276 | for (i = 0; i < 64; i++) | ||
277 | if (lm4550_regfile[i].flag & LM4550_REG_FAKEPROBE) | ||
278 | lm4550_regfile[i].value = lm4550_regfile[i].def; | ||
279 | } | ||
280 | |||
281 | static void lm4550_regfile_write_values_after_init(struct snd_ac97 *ac97) | ||
282 | { | ||
283 | int i; | ||
284 | for (i = 0; i < 64; i++) | ||
285 | if ((lm4550_regfile[i].flag & LM4550_REG_FAKEPROBE) && | ||
286 | (lm4550_regfile[i].value != lm4550_regfile[i].def)) { | ||
287 | PDEBUG(CODEC_FAKE, "lm4550_regfile_write_values_after_" | ||
288 | "init(): reg=0x%x value=0x%x / %d is different " | ||
289 | "from def=0x%x / %d\n", | ||
290 | i, lm4550_regfile[i].value, | ||
291 | lm4550_regfile[i].value, lm4550_regfile[i].def, | ||
292 | lm4550_regfile[i].def); | ||
293 | snd_ac97_write(ac97, i * 2, lm4550_regfile[i].value); | ||
294 | lm4550_regfile[i].flag |= LM4550_REG_DONEREAD; | ||
295 | } | ||
296 | } | ||
297 | |||
298 | |||
299 | /* direct registers */ | ||
300 | #define CR_REG(ml403_ac97cr, x) ((ml403_ac97cr)->port + CR_REG_##x) | ||
301 | |||
302 | #define CR_REG_PLAYFIFO 0x00 | ||
303 | #define CR_PLAYDATA(a) ((a) & 0xFFFF) | ||
304 | |||
305 | #define CR_REG_RECFIFO 0x04 | ||
306 | #define CR_RECDATA(a) ((a) & 0xFFFF) | ||
307 | |||
308 | #define CR_REG_STATUS 0x08 | ||
309 | #define CR_RECOVER (1<<7) | ||
310 | #define CR_PLAYUNDER (1<<6) | ||
311 | #define CR_CODECREADY (1<<5) | ||
312 | #define CR_RAF (1<<4) | ||
313 | #define CR_RECEMPTY (1<<3) | ||
314 | #define CR_RECFULL (1<<2) | ||
315 | #define CR_PLAYHALF (1<<1) | ||
316 | #define CR_PLAYFULL (1<<0) | ||
317 | |||
318 | #define CR_REG_RESETFIFO 0x0C | ||
319 | #define CR_RECRESET (1<<1) | ||
320 | #define CR_PLAYRESET (1<<0) | ||
321 | |||
322 | #define CR_REG_CODEC_ADDR 0x10 | ||
323 | /* UG082 says: | ||
324 | * #define CR_CODEC_ADDR(a) ((a) << 1) | ||
325 | * #define CR_CODEC_READ (1<<0) | ||
326 | * #define CR_CODEC_WRITE (0<<0) | ||
327 | */ | ||
328 | /* RefDesign example says: */ | ||
329 | #define CR_CODEC_ADDR(a) ((a) << 0) | ||
330 | #define CR_CODEC_READ (1<<7) | ||
331 | #define CR_CODEC_WRITE (0<<7) | ||
332 | |||
333 | #define CR_REG_CODEC_DATAREAD 0x14 | ||
334 | #define CR_CODEC_DATAREAD(v) ((v) & 0xFFFF) | ||
335 | |||
336 | #define CR_REG_CODEC_DATAWRITE 0x18 | ||
337 | #define CR_CODEC_DATAWRITE(v) ((v) & 0xFFFF) | ||
338 | |||
339 | #define CR_FIFO_SIZE 32 | ||
340 | |||
341 | struct snd_ml403_ac97cr { | ||
342 | /* lock for access to (controller) registers */ | ||
343 | spinlock_t reg_lock; | ||
344 | /* mutex for the whole sequence of accesses to (controller) registers | ||
345 | * which affect codec registers | ||
346 | */ | ||
347 | struct mutex cdc_mutex; | ||
348 | |||
349 | int irq; /* for playback */ | ||
350 | int enable_irq; /* for playback */ | ||
351 | |||
352 | int capture_irq; | ||
353 | int enable_capture_irq; | ||
354 | |||
355 | struct resource *res_port; | ||
356 | void *port; | ||
357 | |||
358 | struct snd_ac97 *ac97; | ||
359 | int ac97_fake; | ||
360 | #ifdef CODEC_STAT | ||
361 | int ac97_read; | ||
362 | int ac97_write; | ||
363 | #endif | ||
364 | |||
365 | struct platform_device *pfdev; | ||
366 | struct snd_card *card; | ||
367 | struct snd_pcm *pcm; | ||
368 | struct snd_pcm_substream *playback_substream; | ||
369 | struct snd_pcm_substream *capture_substream; | ||
370 | |||
371 | struct snd_pcm_indirect2 ind_rec; /* for playback */ | ||
372 | struct snd_pcm_indirect2 capture_ind2_rec; | ||
373 | }; | ||
374 | |||
375 | static struct snd_pcm_hardware snd_ml403_ac97cr_playback = { | ||
376 | .info = (SNDRV_PCM_INFO_MMAP | | ||
377 | SNDRV_PCM_INFO_INTERLEAVED | | ||
378 | SNDRV_PCM_INFO_MMAP_VALID), | ||
379 | .formats = SNDRV_PCM_FMTBIT_S16_BE, | ||
380 | .rates = (SNDRV_PCM_RATE_CONTINUOUS | | ||
381 | SNDRV_PCM_RATE_8000_48000), | ||
382 | .rate_min = 4000, | ||
383 | .rate_max = 48000, | ||
384 | .channels_min = 2, | ||
385 | .channels_max = 2, | ||
386 | .buffer_bytes_max = (128*1024), | ||
387 | .period_bytes_min = CR_FIFO_SIZE/2, | ||
388 | .period_bytes_max = (64*1024), | ||
389 | .periods_min = 2, | ||
390 | .periods_max = (128*1024)/(CR_FIFO_SIZE/2), | ||
391 | .fifo_size = 0, | ||
392 | }; | ||
393 | |||
394 | static struct snd_pcm_hardware snd_ml403_ac97cr_capture = { | ||
395 | .info = (SNDRV_PCM_INFO_MMAP | | ||
396 | SNDRV_PCM_INFO_INTERLEAVED | | ||
397 | SNDRV_PCM_INFO_MMAP_VALID), | ||
398 | .formats = SNDRV_PCM_FMTBIT_S16_BE, | ||
399 | .rates = (SNDRV_PCM_RATE_CONTINUOUS | | ||
400 | SNDRV_PCM_RATE_8000_48000), | ||
401 | .rate_min = 4000, | ||
402 | .rate_max = 48000, | ||
403 | .channels_min = 2, | ||
404 | .channels_max = 2, | ||
405 | .buffer_bytes_max = (128*1024), | ||
406 | .period_bytes_min = CR_FIFO_SIZE/2, | ||
407 | .period_bytes_max = (64*1024), | ||
408 | .periods_min = 2, | ||
409 | .periods_max = (128*1024)/(CR_FIFO_SIZE/2), | ||
410 | .fifo_size = 0, | ||
411 | }; | ||
412 | |||
413 | static size_t | ||
414 | snd_ml403_ac97cr_playback_ind2_zero(struct snd_pcm_substream *substream, | ||
415 | struct snd_pcm_indirect2 *rec) | ||
416 | { | ||
417 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
418 | int copied_words = 0; | ||
419 | u32 full = 0; | ||
420 | |||
421 | ml403_ac97cr = snd_pcm_substream_chip(substream); | ||
422 | |||
423 | spin_lock(&ml403_ac97cr->reg_lock); | ||
424 | while ((full = (in_be32(CR_REG(ml403_ac97cr, STATUS)) & | ||
425 | CR_PLAYFULL)) != CR_PLAYFULL) { | ||
426 | out_be32(CR_REG(ml403_ac97cr, PLAYFIFO), 0); | ||
427 | copied_words++; | ||
428 | } | ||
429 | rec->hw_ready = 0; | ||
430 | spin_unlock(&ml403_ac97cr->reg_lock); | ||
431 | |||
432 | return (size_t) (copied_words * 2); | ||
433 | } | ||
434 | |||
435 | static size_t | ||
436 | snd_ml403_ac97cr_playback_ind2_copy(struct snd_pcm_substream *substream, | ||
437 | struct snd_pcm_indirect2 *rec, | ||
438 | size_t bytes) | ||
439 | { | ||
440 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
441 | u16 *src; | ||
442 | int copied_words = 0; | ||
443 | u32 full = 0; | ||
444 | |||
445 | ml403_ac97cr = snd_pcm_substream_chip(substream); | ||
446 | src = (u16 *)(substream->runtime->dma_area + rec->sw_data); | ||
447 | |||
448 | spin_lock(&ml403_ac97cr->reg_lock); | ||
449 | while (((full = (in_be32(CR_REG(ml403_ac97cr, STATUS)) & | ||
450 | CR_PLAYFULL)) != CR_PLAYFULL) && (bytes > 1)) { | ||
451 | out_be32(CR_REG(ml403_ac97cr, PLAYFIFO), | ||
452 | CR_PLAYDATA(src[copied_words])); | ||
453 | copied_words++; | ||
454 | bytes = bytes - 2; | ||
455 | } | ||
456 | if (full != CR_PLAYFULL) | ||
457 | rec->hw_ready = 1; | ||
458 | else | ||
459 | rec->hw_ready = 0; | ||
460 | spin_unlock(&ml403_ac97cr->reg_lock); | ||
461 | |||
462 | return (size_t) (copied_words * 2); | ||
463 | } | ||
464 | |||
465 | static size_t | ||
466 | snd_ml403_ac97cr_capture_ind2_null(struct snd_pcm_substream *substream, | ||
467 | struct snd_pcm_indirect2 *rec) | ||
468 | { | ||
469 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
470 | int copied_words = 0; | ||
471 | u32 empty = 0; | ||
472 | |||
473 | ml403_ac97cr = snd_pcm_substream_chip(substream); | ||
474 | |||
475 | spin_lock(&ml403_ac97cr->reg_lock); | ||
476 | while ((empty = (in_be32(CR_REG(ml403_ac97cr, STATUS)) & | ||
477 | CR_RECEMPTY)) != CR_RECEMPTY) { | ||
478 | volatile u32 trash; | ||
479 | |||
480 | trash = CR_RECDATA(in_be32(CR_REG(ml403_ac97cr, RECFIFO))); | ||
481 | /* Hmmmm, really necessary? Don't want call to in_be32() | ||
482 | * to be optimised away! | ||
483 | */ | ||
484 | trash++; | ||
485 | copied_words++; | ||
486 | } | ||
487 | rec->hw_ready = 0; | ||
488 | spin_unlock(&ml403_ac97cr->reg_lock); | ||
489 | |||
490 | return (size_t) (copied_words * 2); | ||
491 | } | ||
492 | |||
493 | static size_t | ||
494 | snd_ml403_ac97cr_capture_ind2_copy(struct snd_pcm_substream *substream, | ||
495 | struct snd_pcm_indirect2 *rec, size_t bytes) | ||
496 | { | ||
497 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
498 | u16 *dst; | ||
499 | int copied_words = 0; | ||
500 | u32 empty = 0; | ||
501 | |||
502 | ml403_ac97cr = snd_pcm_substream_chip(substream); | ||
503 | dst = (u16 *)(substream->runtime->dma_area + rec->sw_data); | ||
504 | |||
505 | spin_lock(&ml403_ac97cr->reg_lock); | ||
506 | while (((empty = (in_be32(CR_REG(ml403_ac97cr, STATUS)) & | ||
507 | CR_RECEMPTY)) != CR_RECEMPTY) && (bytes > 1)) { | ||
508 | dst[copied_words] = CR_RECDATA(in_be32(CR_REG(ml403_ac97cr, | ||
509 | RECFIFO))); | ||
510 | copied_words++; | ||
511 | bytes = bytes - 2; | ||
512 | } | ||
513 | if (empty != CR_RECEMPTY) | ||
514 | rec->hw_ready = 1; | ||
515 | else | ||
516 | rec->hw_ready = 0; | ||
517 | spin_unlock(&ml403_ac97cr->reg_lock); | ||
518 | |||
519 | return (size_t) (copied_words * 2); | ||
520 | } | ||
521 | |||
522 | static snd_pcm_uframes_t | ||
523 | snd_ml403_ac97cr_pcm_pointer(struct snd_pcm_substream *substream) | ||
524 | { | ||
525 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
526 | struct snd_pcm_indirect2 *ind2_rec = NULL; | ||
527 | |||
528 | ml403_ac97cr = snd_pcm_substream_chip(substream); | ||
529 | |||
530 | if (substream == ml403_ac97cr->playback_substream) | ||
531 | ind2_rec = &ml403_ac97cr->ind_rec; | ||
532 | if (substream == ml403_ac97cr->capture_substream) | ||
533 | ind2_rec = &ml403_ac97cr->capture_ind2_rec; | ||
534 | |||
535 | if (ind2_rec != NULL) | ||
536 | return snd_pcm_indirect2_pointer(substream, ind2_rec); | ||
537 | return (snd_pcm_uframes_t) 0; | ||
538 | } | ||
539 | |||
540 | static int | ||
541 | snd_ml403_ac97cr_pcm_playback_trigger(struct snd_pcm_substream *substream, | ||
542 | int cmd) | ||
543 | { | ||
544 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
545 | int err = 0; | ||
546 | |||
547 | ml403_ac97cr = snd_pcm_substream_chip(substream); | ||
548 | |||
549 | switch (cmd) { | ||
550 | case SNDRV_PCM_TRIGGER_START: | ||
551 | PDEBUG(WORK_INFO, "trigger(playback): START\n"); | ||
552 | ml403_ac97cr->ind_rec.hw_ready = 1; | ||
553 | |||
554 | /* clear play FIFO */ | ||
555 | out_be32(CR_REG(ml403_ac97cr, RESETFIFO), CR_PLAYRESET); | ||
556 | |||
557 | /* enable play irq */ | ||
558 | ml403_ac97cr->enable_irq = 1; | ||
559 | enable_irq(ml403_ac97cr->irq); | ||
560 | break; | ||
561 | case SNDRV_PCM_TRIGGER_STOP: | ||
562 | PDEBUG(WORK_INFO, "trigger(playback): STOP\n"); | ||
563 | ml403_ac97cr->ind_rec.hw_ready = 0; | ||
564 | #ifdef SND_PCM_INDIRECT2_STAT | ||
565 | snd_pcm_indirect2_stat(substream, &ml403_ac97cr->ind_rec); | ||
566 | #endif | ||
567 | /* disable play irq */ | ||
568 | disable_irq_nosync(ml403_ac97cr->irq); | ||
569 | ml403_ac97cr->enable_irq = 0; | ||
570 | break; | ||
571 | default: | ||
572 | err = -EINVAL; | ||
573 | break; | ||
574 | } | ||
575 | PDEBUG(WORK_INFO, "trigger(playback): (done)\n"); | ||
576 | return err; | ||
577 | } | ||
578 | |||
579 | static int | ||
580 | snd_ml403_ac97cr_pcm_capture_trigger(struct snd_pcm_substream *substream, | ||
581 | int cmd) | ||
582 | { | ||
583 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
584 | int err = 0; | ||
585 | |||
586 | ml403_ac97cr = snd_pcm_substream_chip(substream); | ||
587 | |||
588 | switch (cmd) { | ||
589 | case SNDRV_PCM_TRIGGER_START: | ||
590 | PDEBUG(WORK_INFO, "trigger(capture): START\n"); | ||
591 | ml403_ac97cr->capture_ind2_rec.hw_ready = 0; | ||
592 | |||
593 | /* clear record FIFO */ | ||
594 | out_be32(CR_REG(ml403_ac97cr, RESETFIFO), CR_RECRESET); | ||
595 | |||
596 | /* enable record irq */ | ||
597 | ml403_ac97cr->enable_capture_irq = 1; | ||
598 | enable_irq(ml403_ac97cr->capture_irq); | ||
599 | break; | ||
600 | case SNDRV_PCM_TRIGGER_STOP: | ||
601 | PDEBUG(WORK_INFO, "trigger(capture): STOP\n"); | ||
602 | ml403_ac97cr->capture_ind2_rec.hw_ready = 0; | ||
603 | #ifdef SND_PCM_INDIRECT2_STAT | ||
604 | snd_pcm_indirect2_stat(substream, | ||
605 | &ml403_ac97cr->capture_ind2_rec); | ||
606 | #endif | ||
607 | /* disable capture irq */ | ||
608 | disable_irq_nosync(ml403_ac97cr->capture_irq); | ||
609 | ml403_ac97cr->enable_capture_irq = 0; | ||
610 | break; | ||
611 | default: | ||
612 | err = -EINVAL; | ||
613 | break; | ||
614 | } | ||
615 | PDEBUG(WORK_INFO, "trigger(capture): (done)\n"); | ||
616 | return err; | ||
617 | } | ||
618 | |||
619 | static int | ||
620 | snd_ml403_ac97cr_pcm_playback_prepare(struct snd_pcm_substream *substream) | ||
621 | { | ||
622 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
623 | struct snd_pcm_runtime *runtime; | ||
624 | |||
625 | ml403_ac97cr = snd_pcm_substream_chip(substream); | ||
626 | runtime = substream->runtime; | ||
627 | |||
628 | PDEBUG(WORK_INFO, | ||
629 | "prepare(): period_bytes=%d, minperiod_bytes=%d\n", | ||
630 | snd_pcm_lib_period_bytes(substream), CR_FIFO_SIZE / 2); | ||
631 | |||
632 | /* set sampling rate */ | ||
633 | snd_ac97_set_rate(ml403_ac97cr->ac97, AC97_PCM_FRONT_DAC_RATE, | ||
634 | runtime->rate); | ||
635 | PDEBUG(WORK_INFO, "prepare(): rate=%d\n", runtime->rate); | ||
636 | |||
637 | /* init struct for intermediate buffer */ | ||
638 | memset(&ml403_ac97cr->ind_rec, 0, | ||
639 | sizeof(struct snd_pcm_indirect2)); | ||
640 | ml403_ac97cr->ind_rec.hw_buffer_size = CR_FIFO_SIZE; | ||
641 | ml403_ac97cr->ind_rec.sw_buffer_size = | ||
642 | snd_pcm_lib_buffer_bytes(substream); | ||
643 | ml403_ac97cr->ind_rec.min_periods = -1; | ||
644 | ml403_ac97cr->ind_rec.min_multiple = | ||
645 | snd_pcm_lib_period_bytes(substream) / (CR_FIFO_SIZE / 2); | ||
646 | PDEBUG(WORK_INFO, "prepare(): hw_buffer_size=%d, " | ||
647 | "sw_buffer_size=%d, min_multiple=%d\n", | ||
648 | CR_FIFO_SIZE, ml403_ac97cr->ind_rec.sw_buffer_size, | ||
649 | ml403_ac97cr->ind_rec.min_multiple); | ||
650 | return 0; | ||
651 | } | ||
652 | |||
653 | static int | ||
654 | snd_ml403_ac97cr_pcm_capture_prepare(struct snd_pcm_substream *substream) | ||
655 | { | ||
656 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
657 | struct snd_pcm_runtime *runtime; | ||
658 | |||
659 | ml403_ac97cr = snd_pcm_substream_chip(substream); | ||
660 | runtime = substream->runtime; | ||
661 | |||
662 | PDEBUG(WORK_INFO, | ||
663 | "prepare(capture): period_bytes=%d, minperiod_bytes=%d\n", | ||
664 | snd_pcm_lib_period_bytes(substream), CR_FIFO_SIZE / 2); | ||
665 | |||
666 | /* set sampling rate */ | ||
667 | snd_ac97_set_rate(ml403_ac97cr->ac97, AC97_PCM_LR_ADC_RATE, | ||
668 | runtime->rate); | ||
669 | PDEBUG(WORK_INFO, "prepare(capture): rate=%d\n", runtime->rate); | ||
670 | |||
671 | /* init struct for intermediate buffer */ | ||
672 | memset(&ml403_ac97cr->capture_ind2_rec, 0, | ||
673 | sizeof(struct snd_pcm_indirect2)); | ||
674 | ml403_ac97cr->capture_ind2_rec.hw_buffer_size = CR_FIFO_SIZE; | ||
675 | ml403_ac97cr->capture_ind2_rec.sw_buffer_size = | ||
676 | snd_pcm_lib_buffer_bytes(substream); | ||
677 | ml403_ac97cr->capture_ind2_rec.min_multiple = | ||
678 | snd_pcm_lib_period_bytes(substream) / (CR_FIFO_SIZE / 2); | ||
679 | PDEBUG(WORK_INFO, "prepare(capture): hw_buffer_size=%d, " | ||
680 | "sw_buffer_size=%d, min_multiple=%d\n", CR_FIFO_SIZE, | ||
681 | ml403_ac97cr->capture_ind2_rec.sw_buffer_size, | ||
682 | ml403_ac97cr->capture_ind2_rec.min_multiple); | ||
683 | return 0; | ||
684 | } | ||
685 | |||
686 | static int snd_ml403_ac97cr_hw_free(struct snd_pcm_substream *substream) | ||
687 | { | ||
688 | PDEBUG(WORK_INFO, "hw_free()\n"); | ||
689 | return snd_pcm_lib_free_pages(substream); | ||
690 | } | ||
691 | |||
692 | static int | ||
693 | snd_ml403_ac97cr_hw_params(struct snd_pcm_substream *substream, | ||
694 | struct snd_pcm_hw_params *hw_params) | ||
695 | { | ||
696 | PDEBUG(WORK_INFO, "hw_params(): desired buffer bytes=%d, desired " | ||
697 | "period bytes=%d\n", | ||
698 | params_buffer_bytes(hw_params), params_period_bytes(hw_params)); | ||
699 | return snd_pcm_lib_malloc_pages(substream, | ||
700 | params_buffer_bytes(hw_params)); | ||
701 | } | ||
702 | |||
703 | static int snd_ml403_ac97cr_playback_open(struct snd_pcm_substream *substream) | ||
704 | { | ||
705 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
706 | struct snd_pcm_runtime *runtime; | ||
707 | |||
708 | ml403_ac97cr = snd_pcm_substream_chip(substream); | ||
709 | runtime = substream->runtime; | ||
710 | |||
711 | PDEBUG(WORK_INFO, "open(playback)\n"); | ||
712 | ml403_ac97cr->playback_substream = substream; | ||
713 | runtime->hw = snd_ml403_ac97cr_playback; | ||
714 | |||
715 | snd_pcm_hw_constraint_step(runtime, 0, | ||
716 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, | ||
717 | CR_FIFO_SIZE / 2); | ||
718 | return 0; | ||
719 | } | ||
720 | |||
721 | static int snd_ml403_ac97cr_capture_open(struct snd_pcm_substream *substream) | ||
722 | { | ||
723 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
724 | struct snd_pcm_runtime *runtime; | ||
725 | |||
726 | ml403_ac97cr = snd_pcm_substream_chip(substream); | ||
727 | runtime = substream->runtime; | ||
728 | |||
729 | PDEBUG(WORK_INFO, "open(capture)\n"); | ||
730 | ml403_ac97cr->capture_substream = substream; | ||
731 | runtime->hw = snd_ml403_ac97cr_capture; | ||
732 | |||
733 | snd_pcm_hw_constraint_step(runtime, 0, | ||
734 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, | ||
735 | CR_FIFO_SIZE / 2); | ||
736 | return 0; | ||
737 | } | ||
738 | |||
739 | static int snd_ml403_ac97cr_playback_close(struct snd_pcm_substream *substream) | ||
740 | { | ||
741 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
742 | |||
743 | ml403_ac97cr = snd_pcm_substream_chip(substream); | ||
744 | |||
745 | PDEBUG(WORK_INFO, "close(playback)\n"); | ||
746 | ml403_ac97cr->playback_substream = NULL; | ||
747 | return 0; | ||
748 | } | ||
749 | |||
750 | static int snd_ml403_ac97cr_capture_close(struct snd_pcm_substream *substream) | ||
751 | { | ||
752 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
753 | |||
754 | ml403_ac97cr = snd_pcm_substream_chip(substream); | ||
755 | |||
756 | PDEBUG(WORK_INFO, "close(capture)\n"); | ||
757 | ml403_ac97cr->capture_substream = NULL; | ||
758 | return 0; | ||
759 | } | ||
760 | |||
761 | static struct snd_pcm_ops snd_ml403_ac97cr_playback_ops = { | ||
762 | .open = snd_ml403_ac97cr_playback_open, | ||
763 | .close = snd_ml403_ac97cr_playback_close, | ||
764 | .ioctl = snd_pcm_lib_ioctl, | ||
765 | .hw_params = snd_ml403_ac97cr_hw_params, | ||
766 | .hw_free = snd_ml403_ac97cr_hw_free, | ||
767 | .prepare = snd_ml403_ac97cr_pcm_playback_prepare, | ||
768 | .trigger = snd_ml403_ac97cr_pcm_playback_trigger, | ||
769 | .pointer = snd_ml403_ac97cr_pcm_pointer, | ||
770 | }; | ||
771 | |||
772 | static struct snd_pcm_ops snd_ml403_ac97cr_capture_ops = { | ||
773 | .open = snd_ml403_ac97cr_capture_open, | ||
774 | .close = snd_ml403_ac97cr_capture_close, | ||
775 | .ioctl = snd_pcm_lib_ioctl, | ||
776 | .hw_params = snd_ml403_ac97cr_hw_params, | ||
777 | .hw_free = snd_ml403_ac97cr_hw_free, | ||
778 | .prepare = snd_ml403_ac97cr_pcm_capture_prepare, | ||
779 | .trigger = snd_ml403_ac97cr_pcm_capture_trigger, | ||
780 | .pointer = snd_ml403_ac97cr_pcm_pointer, | ||
781 | }; | ||
782 | |||
783 | static irqreturn_t snd_ml403_ac97cr_irq(int irq, void *dev_id) | ||
784 | { | ||
785 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
786 | struct platform_device *pfdev; | ||
787 | int cmp_irq; | ||
788 | |||
789 | ml403_ac97cr = (struct snd_ml403_ac97cr *)dev_id; | ||
790 | if (ml403_ac97cr == NULL) | ||
791 | return IRQ_NONE; | ||
792 | |||
793 | pfdev = ml403_ac97cr->pfdev; | ||
794 | |||
795 | /* playback interrupt */ | ||
796 | cmp_irq = platform_get_irq(pfdev, 0); | ||
797 | if (irq == cmp_irq) { | ||
798 | if (ml403_ac97cr->enable_irq) | ||
799 | snd_pcm_indirect2_playback_interrupt( | ||
800 | ml403_ac97cr->playback_substream, | ||
801 | &ml403_ac97cr->ind_rec, | ||
802 | snd_ml403_ac97cr_playback_ind2_copy, | ||
803 | snd_ml403_ac97cr_playback_ind2_zero); | ||
804 | else | ||
805 | goto __disable_irq; | ||
806 | } else { | ||
807 | /* record interrupt */ | ||
808 | cmp_irq = platform_get_irq(pfdev, 1); | ||
809 | if (irq == cmp_irq) { | ||
810 | if (ml403_ac97cr->enable_capture_irq) | ||
811 | snd_pcm_indirect2_capture_interrupt( | ||
812 | ml403_ac97cr->capture_substream, | ||
813 | &ml403_ac97cr->capture_ind2_rec, | ||
814 | snd_ml403_ac97cr_capture_ind2_copy, | ||
815 | snd_ml403_ac97cr_capture_ind2_null); | ||
816 | else | ||
817 | goto __disable_irq; | ||
818 | } else | ||
819 | return IRQ_NONE; | ||
820 | } | ||
821 | return IRQ_HANDLED; | ||
822 | |||
823 | __disable_irq: | ||
824 | PDEBUG(INIT_INFO, "irq(): irq %d is meant to be disabled! So, now try " | ||
825 | "to disable it _really_!\n", irq); | ||
826 | disable_irq_nosync(irq); | ||
827 | return IRQ_HANDLED; | ||
828 | } | ||
829 | |||
830 | static unsigned short | ||
831 | snd_ml403_ac97cr_codec_read(struct snd_ac97 *ac97, unsigned short reg) | ||
832 | { | ||
833 | struct snd_ml403_ac97cr *ml403_ac97cr = ac97->private_data; | ||
834 | #ifdef CODEC_STAT | ||
835 | u32 stat; | ||
836 | u32 rafaccess = 0; | ||
837 | #endif | ||
838 | unsigned long end_time; | ||
839 | u16 value = 0; | ||
840 | |||
841 | if (!LM4550_RF_OK(reg)) { | ||
842 | snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " | ||
843 | "access to unknown/unused codec register 0x%x " | ||
844 | "ignored!\n", reg); | ||
845 | return 0; | ||
846 | } | ||
847 | /* check if we can fake/answer this access from our shadow register */ | ||
848 | if ((lm4550_regfile[reg / 2].flag & | ||
849 | (LM4550_REG_DONEREAD | LM4550_REG_ALLFAKE)) && | ||
850 | !(lm4550_regfile[reg / 2].flag & LM4550_REG_NOSHADOW)) { | ||
851 | if (lm4550_regfile[reg / 2].flag & LM4550_REG_FAKEREAD) { | ||
852 | PDEBUG(CODEC_FAKE, "codec_read(): faking read from " | ||
853 | "reg=0x%x, val=0x%x / %d\n", | ||
854 | reg, lm4550_regfile[reg / 2].def, | ||
855 | lm4550_regfile[reg / 2].def); | ||
856 | return lm4550_regfile[reg / 2].def; | ||
857 | } else if ((lm4550_regfile[reg / 2].flag & | ||
858 | LM4550_REG_FAKEPROBE) && | ||
859 | ml403_ac97cr->ac97_fake) { | ||
860 | PDEBUG(CODEC_FAKE, "codec_read(): faking read from " | ||
861 | "reg=0x%x, val=0x%x / %d (probe)\n", | ||
862 | reg, lm4550_regfile[reg / 2].value, | ||
863 | lm4550_regfile[reg / 2].value); | ||
864 | return lm4550_regfile[reg / 2].value; | ||
865 | } else { | ||
866 | #ifdef CODEC_STAT | ||
867 | PDEBUG(CODEC_FAKE, "codec_read(): read access " | ||
868 | "answered by shadow register 0x%x (value=0x%x " | ||
869 | "/ %d) (cw=%d cr=%d)\n", | ||
870 | reg, lm4550_regfile[reg / 2].value, | ||
871 | lm4550_regfile[reg / 2].value, | ||
872 | ml403_ac97cr->ac97_write, | ||
873 | ml403_ac97cr->ac97_read); | ||
874 | #else | ||
875 | PDEBUG(CODEC_FAKE, "codec_read(): read access " | ||
876 | "answered by shadow register 0x%x (value=0x%x " | ||
877 | "/ %d)\n", | ||
878 | reg, lm4550_regfile[reg / 2].value, | ||
879 | lm4550_regfile[reg / 2].value); | ||
880 | #endif | ||
881 | return lm4550_regfile[reg / 2].value; | ||
882 | } | ||
883 | } | ||
884 | /* if we are here, we _have_ to access the codec really, no faking */ | ||
885 | if (mutex_lock_interruptible(&ml403_ac97cr->cdc_mutex) != 0) | ||
886 | return 0; | ||
887 | #ifdef CODEC_STAT | ||
888 | ml403_ac97cr->ac97_read++; | ||
889 | #endif | ||
890 | spin_lock(&ml403_ac97cr->reg_lock); | ||
891 | out_be32(CR_REG(ml403_ac97cr, CODEC_ADDR), | ||
892 | CR_CODEC_ADDR(reg) | CR_CODEC_READ); | ||
893 | spin_unlock(&ml403_ac97cr->reg_lock); | ||
894 | end_time = jiffies + (HZ / CODEC_TIMEOUT_AFTER_READ); | ||
895 | do { | ||
896 | spin_lock(&ml403_ac97cr->reg_lock); | ||
897 | #ifdef CODEC_STAT | ||
898 | rafaccess++; | ||
899 | stat = in_be32(CR_REG(ml403_ac97cr, STATUS)); | ||
900 | if ((stat & CR_RAF) == CR_RAF) { | ||
901 | value = CR_CODEC_DATAREAD( | ||
902 | in_be32(CR_REG(ml403_ac97cr, CODEC_DATAREAD))); | ||
903 | PDEBUG(CODEC_SUCCESS, "codec_read(): (done) reg=0x%x, " | ||
904 | "value=0x%x / %d (STATUS=0x%x)\n", | ||
905 | reg, value, value, stat); | ||
906 | #else | ||
907 | if ((in_be32(CR_REG(ml403_ac97cr, STATUS)) & | ||
908 | CR_RAF) == CR_RAF) { | ||
909 | value = CR_CODEC_DATAREAD( | ||
910 | in_be32(CR_REG(ml403_ac97cr, CODEC_DATAREAD))); | ||
911 | PDEBUG(CODEC_SUCCESS, "codec_read(): (done) " | ||
912 | "reg=0x%x, value=0x%x / %d\n", | ||
913 | reg, value, value); | ||
914 | #endif | ||
915 | lm4550_regfile[reg / 2].value = value; | ||
916 | lm4550_regfile[reg / 2].flag |= LM4550_REG_DONEREAD; | ||
917 | spin_unlock(&ml403_ac97cr->reg_lock); | ||
918 | mutex_unlock(&ml403_ac97cr->cdc_mutex); | ||
919 | return value; | ||
920 | } | ||
921 | spin_unlock(&ml403_ac97cr->reg_lock); | ||
922 | schedule_timeout_uninterruptible(1); | ||
923 | } while (time_after(end_time, jiffies)); | ||
924 | /* read the DATAREAD register anyway, see comment below */ | ||
925 | spin_lock(&ml403_ac97cr->reg_lock); | ||
926 | value = | ||
927 | CR_CODEC_DATAREAD(in_be32(CR_REG(ml403_ac97cr, CODEC_DATAREAD))); | ||
928 | spin_unlock(&ml403_ac97cr->reg_lock); | ||
929 | #ifdef CODEC_STAT | ||
930 | snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " | ||
931 | "timeout while codec read! " | ||
932 | "(reg=0x%x, last STATUS=0x%x, DATAREAD=0x%x / %d, %d) " | ||
933 | "(cw=%d, cr=%d)\n", | ||
934 | reg, stat, value, value, rafaccess, | ||
935 | ml403_ac97cr->ac97_write, ml403_ac97cr->ac97_read); | ||
936 | #else | ||
937 | snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " | ||
938 | "timeout while codec read! " | ||
939 | "(reg=0x%x, DATAREAD=0x%x / %d)\n", | ||
940 | reg, value, value); | ||
941 | #endif | ||
942 | /* BUG: This is PURE speculation! But after _most_ read timeouts the | ||
943 | * value in the register is ok! | ||
944 | */ | ||
945 | lm4550_regfile[reg / 2].value = value; | ||
946 | lm4550_regfile[reg / 2].flag |= LM4550_REG_DONEREAD; | ||
947 | mutex_unlock(&ml403_ac97cr->cdc_mutex); | ||
948 | return value; | ||
949 | } | ||
950 | |||
951 | static void | ||
952 | snd_ml403_ac97cr_codec_write(struct snd_ac97 *ac97, unsigned short reg, | ||
953 | unsigned short val) | ||
954 | { | ||
955 | struct snd_ml403_ac97cr *ml403_ac97cr = ac97->private_data; | ||
956 | |||
957 | #ifdef CODEC_STAT | ||
958 | u32 stat; | ||
959 | u32 rafaccess = 0; | ||
960 | #endif | ||
961 | #ifdef CODEC_WRITE_CHECK_RAF | ||
962 | unsigned long end_time; | ||
963 | #endif | ||
964 | |||
965 | if (!LM4550_RF_OK(reg)) { | ||
966 | snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " | ||
967 | "access to unknown/unused codec register 0x%x " | ||
968 | "ignored!\n", reg); | ||
969 | return; | ||
970 | } | ||
971 | if (lm4550_regfile[reg / 2].flag & LM4550_REG_READONLY) { | ||
972 | snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " | ||
973 | "write access to read only codec register 0x%x " | ||
974 | "ignored!\n", reg); | ||
975 | return; | ||
976 | } | ||
977 | if ((val & lm4550_regfile[reg / 2].wmask) != val) { | ||
978 | snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " | ||
979 | "write access to codec register 0x%x " | ||
980 | "with bad value 0x%x / %d!\n", | ||
981 | reg, val, val); | ||
982 | val = val & lm4550_regfile[reg / 2].wmask; | ||
983 | } | ||
984 | if (((lm4550_regfile[reg / 2].flag & LM4550_REG_FAKEPROBE) && | ||
985 | ml403_ac97cr->ac97_fake) && | ||
986 | !(lm4550_regfile[reg / 2].flag & LM4550_REG_NOSHADOW)) { | ||
987 | PDEBUG(CODEC_FAKE, "codec_write(): faking write to reg=0x%x, " | ||
988 | "val=0x%x / %d\n", reg, val, val); | ||
989 | lm4550_regfile[reg / 2].value = (val & | ||
990 | lm4550_regfile[reg / 2].wmask); | ||
991 | return; | ||
992 | } | ||
993 | if (mutex_lock_interruptible(&ml403_ac97cr->cdc_mutex) != 0) | ||
994 | return; | ||
995 | #ifdef CODEC_STAT | ||
996 | ml403_ac97cr->ac97_write++; | ||
997 | #endif | ||
998 | spin_lock(&ml403_ac97cr->reg_lock); | ||
999 | out_be32(CR_REG(ml403_ac97cr, CODEC_DATAWRITE), | ||
1000 | CR_CODEC_DATAWRITE(val)); | ||
1001 | out_be32(CR_REG(ml403_ac97cr, CODEC_ADDR), | ||
1002 | CR_CODEC_ADDR(reg) | CR_CODEC_WRITE); | ||
1003 | spin_unlock(&ml403_ac97cr->reg_lock); | ||
1004 | #ifdef CODEC_WRITE_CHECK_RAF | ||
1005 | /* check CR_CODEC_RAF bit to see if write access to register is done; | ||
1006 | * loop until bit is set or timeout happens | ||
1007 | */ | ||
1008 | end_time = jiffies + HZ / CODEC_TIMEOUT_AFTER_WRITE; | ||
1009 | do { | ||
1010 | spin_lock(&ml403_ac97cr->reg_lock); | ||
1011 | #ifdef CODEC_STAT | ||
1012 | rafaccess++; | ||
1013 | stat = in_be32(CR_REG(ml403_ac97cr, STATUS)) | ||
1014 | if ((stat & CR_RAF) == CR_RAF) { | ||
1015 | #else | ||
1016 | if ((in_be32(CR_REG(ml403_ac97cr, STATUS)) & | ||
1017 | CR_RAF) == CR_RAF) { | ||
1018 | #endif | ||
1019 | PDEBUG(CODEC_SUCCESS, "codec_write(): (done) " | ||
1020 | "reg=0x%x, value=%d / 0x%x\n", | ||
1021 | reg, val, val); | ||
1022 | if (!(lm4550_regfile[reg / 2].flag & | ||
1023 | LM4550_REG_NOSHADOW) && | ||
1024 | !(lm4550_regfile[reg / 2].flag & | ||
1025 | LM4550_REG_NOSAVE)) | ||
1026 | lm4550_regfile[reg / 2].value = val; | ||
1027 | lm4550_regfile[reg / 2].flag |= LM4550_REG_DONEREAD; | ||
1028 | spin_unlock(&ml403_ac97cr->reg_lock); | ||
1029 | mutex_unlock(&ml403_ac97cr->cdc_mutex); | ||
1030 | return; | ||
1031 | } | ||
1032 | spin_unlock(&ml403_ac97cr->reg_lock); | ||
1033 | schedule_timeout_uninterruptible(1); | ||
1034 | } while (time_after(end_time, jiffies)); | ||
1035 | #ifdef CODEC_STAT | ||
1036 | snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " | ||
1037 | "timeout while codec write " | ||
1038 | "(reg=0x%x, val=0x%x / %d, last STATUS=0x%x, %d) " | ||
1039 | "(cw=%d, cr=%d)\n", | ||
1040 | reg, val, val, stat, rafaccess, ml403_ac97cr->ac97_write, | ||
1041 | ml403_ac97cr->ac97_read); | ||
1042 | #else | ||
1043 | snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": " | ||
1044 | "timeout while codec write (reg=0x%x, val=0x%x / %d)\n", | ||
1045 | reg, val, val); | ||
1046 | #endif | ||
1047 | #else /* CODEC_WRITE_CHECK_RAF */ | ||
1048 | #if CODEC_WAIT_AFTER_WRITE > 0 | ||
1049 | /* officially, in AC97 spec there is no possibility for a AC97 | ||
1050 | * controller to determine, if write access is done or not - so: How | ||
1051 | * is Xilinx able to provide a RAF bit for write access? | ||
1052 | * => very strange, thus just don't check RAF bit (compare with | ||
1053 | * Xilinx's example app in EDK 8.1i) and wait | ||
1054 | */ | ||
1055 | schedule_timeout_uninterruptible(HZ / CODEC_WAIT_AFTER_WRITE); | ||
1056 | #endif | ||
1057 | PDEBUG(CODEC_SUCCESS, "codec_write(): (done) " | ||
1058 | "reg=0x%x, value=%d / 0x%x (no RAF check)\n", | ||
1059 | reg, val, val); | ||
1060 | #endif | ||
1061 | mutex_unlock(&ml403_ac97cr->cdc_mutex); | ||
1062 | return; | ||
1063 | } | ||
1064 | |||
1065 | static int __devinit | ||
1066 | snd_ml403_ac97cr_chip_init(struct snd_ml403_ac97cr *ml403_ac97cr) | ||
1067 | { | ||
1068 | unsigned long end_time; | ||
1069 | PDEBUG(INIT_INFO, "chip_init():\n"); | ||
1070 | end_time = jiffies + HZ / CODEC_TIMEOUT_ON_INIT; | ||
1071 | do { | ||
1072 | if (in_be32(CR_REG(ml403_ac97cr, STATUS)) & CR_CODECREADY) { | ||
1073 | /* clear both hardware FIFOs */ | ||
1074 | out_be32(CR_REG(ml403_ac97cr, RESETFIFO), | ||
1075 | CR_RECRESET | CR_PLAYRESET); | ||
1076 | PDEBUG(INIT_INFO, "chip_init(): (done)\n"); | ||
1077 | return 0; | ||
1078 | } | ||
1079 | schedule_timeout_uninterruptible(1); | ||
1080 | } while (time_after(end_time, jiffies)); | ||
1081 | snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": " | ||
1082 | "timeout while waiting for codec, " | ||
1083 | "not ready!\n"); | ||
1084 | return -EBUSY; | ||
1085 | } | ||
1086 | |||
1087 | static int snd_ml403_ac97cr_free(struct snd_ml403_ac97cr *ml403_ac97cr) | ||
1088 | { | ||
1089 | PDEBUG(INIT_INFO, "free():\n"); | ||
1090 | /* irq release */ | ||
1091 | if (ml403_ac97cr->irq >= 0) | ||
1092 | free_irq(ml403_ac97cr->irq, ml403_ac97cr); | ||
1093 | if (ml403_ac97cr->capture_irq >= 0) | ||
1094 | free_irq(ml403_ac97cr->capture_irq, ml403_ac97cr); | ||
1095 | /* give back "port" */ | ||
1096 | if (ml403_ac97cr->port != NULL) | ||
1097 | iounmap(ml403_ac97cr->port); | ||
1098 | kfree(ml403_ac97cr); | ||
1099 | PDEBUG(INIT_INFO, "free(): (done)\n"); | ||
1100 | return 0; | ||
1101 | } | ||
1102 | |||
1103 | static int snd_ml403_ac97cr_dev_free(struct snd_device *snddev) | ||
1104 | { | ||
1105 | struct snd_ml403_ac97cr *ml403_ac97cr = snddev->device_data; | ||
1106 | PDEBUG(INIT_INFO, "dev_free():\n"); | ||
1107 | return snd_ml403_ac97cr_free(ml403_ac97cr); | ||
1108 | } | ||
1109 | |||
1110 | static int __devinit | ||
1111 | snd_ml403_ac97cr_create(struct snd_card *card, struct platform_device *pfdev, | ||
1112 | struct snd_ml403_ac97cr **rml403_ac97cr) | ||
1113 | { | ||
1114 | struct snd_ml403_ac97cr *ml403_ac97cr; | ||
1115 | int err; | ||
1116 | static struct snd_device_ops ops = { | ||
1117 | .dev_free = snd_ml403_ac97cr_dev_free, | ||
1118 | }; | ||
1119 | struct resource *resource; | ||
1120 | int irq; | ||
1121 | |||
1122 | *rml403_ac97cr = NULL; | ||
1123 | ml403_ac97cr = kzalloc(sizeof(*ml403_ac97cr), GFP_KERNEL); | ||
1124 | if (ml403_ac97cr == NULL) | ||
1125 | return -ENOMEM; | ||
1126 | spin_lock_init(&ml403_ac97cr->reg_lock); | ||
1127 | mutex_init(&ml403_ac97cr->cdc_mutex); | ||
1128 | ml403_ac97cr->card = card; | ||
1129 | ml403_ac97cr->pfdev = pfdev; | ||
1130 | ml403_ac97cr->irq = -1; | ||
1131 | ml403_ac97cr->enable_irq = 0; | ||
1132 | ml403_ac97cr->capture_irq = -1; | ||
1133 | ml403_ac97cr->enable_capture_irq = 0; | ||
1134 | ml403_ac97cr->port = NULL; | ||
1135 | ml403_ac97cr->res_port = NULL; | ||
1136 | |||
1137 | PDEBUG(INIT_INFO, "Trying to reserve resources now ...\n"); | ||
1138 | resource = platform_get_resource(pfdev, IORESOURCE_MEM, 0); | ||
1139 | /* get "port" */ | ||
1140 | ml403_ac97cr->port = ioremap_nocache(resource->start, | ||
1141 | (resource->end) - | ||
1142 | (resource->start) + 1); | ||
1143 | if (ml403_ac97cr->port == NULL) { | ||
1144 | snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": " | ||
1145 | "unable to remap memory region (%x to %x)\n", | ||
1146 | resource->start, resource->end); | ||
1147 | snd_ml403_ac97cr_free(ml403_ac97cr); | ||
1148 | return -EBUSY; | ||
1149 | } | ||
1150 | snd_printk(KERN_INFO SND_ML403_AC97CR_DRIVER ": " | ||
1151 | "remap controller memory region to " | ||
1152 | "0x%x done\n", (unsigned int)ml403_ac97cr->port); | ||
1153 | /* get irq */ | ||
1154 | irq = platform_get_irq(pfdev, 0); | ||
1155 | if (request_irq(irq, snd_ml403_ac97cr_irq, IRQF_DISABLED, | ||
1156 | pfdev->dev.bus_id, (void *)ml403_ac97cr)) { | ||
1157 | snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": " | ||
1158 | "unable to grab IRQ %d\n", | ||
1159 | irq); | ||
1160 | snd_ml403_ac97cr_free(ml403_ac97cr); | ||
1161 | return -EBUSY; | ||
1162 | } | ||
1163 | ml403_ac97cr->irq = irq; | ||
1164 | snd_printk(KERN_INFO SND_ML403_AC97CR_DRIVER ": " | ||
1165 | "request (playback) irq %d done\n", | ||
1166 | ml403_ac97cr->irq); | ||
1167 | irq = platform_get_irq(pfdev, 1); | ||
1168 | if (request_irq(irq, snd_ml403_ac97cr_irq, IRQF_DISABLED, | ||
1169 | pfdev->dev.bus_id, (void *)ml403_ac97cr)) { | ||
1170 | snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": " | ||
1171 | "unable to grab IRQ %d\n", | ||
1172 | irq); | ||
1173 | snd_ml403_ac97cr_free(ml403_ac97cr); | ||
1174 | return -EBUSY; | ||
1175 | } | ||
1176 | ml403_ac97cr->capture_irq = irq; | ||
1177 | snd_printk(KERN_INFO SND_ML403_AC97CR_DRIVER ": " | ||
1178 | "request (capture) irq %d done\n", | ||
1179 | ml403_ac97cr->capture_irq); | ||
1180 | |||
1181 | err = snd_ml403_ac97cr_chip_init(ml403_ac97cr); | ||
1182 | if (err < 0) { | ||
1183 | snd_ml403_ac97cr_free(ml403_ac97cr); | ||
1184 | return err; | ||
1185 | } | ||
1186 | |||
1187 | err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ml403_ac97cr, &ops); | ||
1188 | if (err < 0) { | ||
1189 | PDEBUG(INIT_FAILURE, "probe(): snd_device_new() failed!\n"); | ||
1190 | snd_ml403_ac97cr_free(ml403_ac97cr); | ||
1191 | return err; | ||
1192 | } | ||
1193 | |||
1194 | snd_card_set_dev(card, &pfdev->dev); | ||
1195 | |||
1196 | *rml403_ac97cr = ml403_ac97cr; | ||
1197 | return 0; | ||
1198 | } | ||
1199 | |||
1200 | static void snd_ml403_ac97cr_mixer_free(struct snd_ac97 *ac97) | ||
1201 | { | ||
1202 | struct snd_ml403_ac97cr *ml403_ac97cr = ac97->private_data; | ||
1203 | PDEBUG(INIT_INFO, "mixer_free():\n"); | ||
1204 | ml403_ac97cr->ac97 = NULL; | ||
1205 | PDEBUG(INIT_INFO, "mixer_free(): (done)\n"); | ||
1206 | } | ||
1207 | |||
1208 | static int __devinit | ||
1209 | snd_ml403_ac97cr_mixer(struct snd_ml403_ac97cr *ml403_ac97cr) | ||
1210 | { | ||
1211 | struct snd_ac97_bus *bus; | ||
1212 | struct snd_ac97_template ac97; | ||
1213 | int err; | ||
1214 | static struct snd_ac97_bus_ops ops = { | ||
1215 | .write = snd_ml403_ac97cr_codec_write, | ||
1216 | .read = snd_ml403_ac97cr_codec_read, | ||
1217 | }; | ||
1218 | PDEBUG(INIT_INFO, "mixer():\n"); | ||
1219 | err = snd_ac97_bus(ml403_ac97cr->card, 0, &ops, NULL, &bus); | ||
1220 | if (err < 0) | ||
1221 | return err; | ||
1222 | |||
1223 | memset(&ac97, 0, sizeof(ac97)); | ||
1224 | ml403_ac97cr->ac97_fake = 1; | ||
1225 | lm4550_regfile_init(); | ||
1226 | #ifdef CODEC_STAT | ||
1227 | ml403_ac97cr->ac97_read = 0; | ||
1228 | ml403_ac97cr->ac97_write = 0; | ||
1229 | #endif | ||
1230 | ac97.private_data = ml403_ac97cr; | ||
1231 | ac97.private_free = snd_ml403_ac97cr_mixer_free; | ||
1232 | ac97.scaps = AC97_SCAP_AUDIO | AC97_SCAP_SKIP_MODEM | | ||
1233 | AC97_SCAP_NO_SPDIF; | ||
1234 | err = snd_ac97_mixer(bus, &ac97, &ml403_ac97cr->ac97); | ||
1235 | ml403_ac97cr->ac97_fake = 0; | ||
1236 | lm4550_regfile_write_values_after_init(ml403_ac97cr->ac97); | ||
1237 | PDEBUG(INIT_INFO, "mixer(): (done) snd_ac97_mixer()=%d\n", err); | ||
1238 | return err; | ||
1239 | } | ||
1240 | |||
1241 | static int __devinit | ||
1242 | snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device, | ||
1243 | struct snd_pcm **rpcm) | ||
1244 | { | ||
1245 | struct snd_pcm *pcm; | ||
1246 | int err; | ||
1247 | |||
1248 | if (rpcm) | ||
1249 | *rpcm = NULL; | ||
1250 | err = snd_pcm_new(ml403_ac97cr->card, "ML403AC97CR/1", device, 1, 1, | ||
1251 | &pcm); | ||
1252 | if (err < 0) | ||
1253 | return err; | ||
1254 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, | ||
1255 | &snd_ml403_ac97cr_playback_ops); | ||
1256 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, | ||
1257 | &snd_ml403_ac97cr_capture_ops); | ||
1258 | pcm->private_data = ml403_ac97cr; | ||
1259 | pcm->info_flags = 0; | ||
1260 | strcpy(pcm->name, "ML403AC97CR DAC/ADC"); | ||
1261 | ml403_ac97cr->pcm = pcm; | ||
1262 | |||
1263 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, | ||
1264 | snd_dma_continuous_data(GFP_KERNEL), | ||
1265 | 64 * 1024, | ||
1266 | 128 * 1024); | ||
1267 | if (rpcm) | ||
1268 | *rpcm = pcm; | ||
1269 | return 0; | ||
1270 | } | ||
1271 | |||
1272 | static int __devinit snd_ml403_ac97cr_probe(struct platform_device *pfdev) | ||
1273 | { | ||
1274 | struct snd_card *card; | ||
1275 | struct snd_ml403_ac97cr *ml403_ac97cr = NULL; | ||
1276 | int err; | ||
1277 | int dev = pfdev->id; | ||
1278 | |||
1279 | if (dev >= SNDRV_CARDS) | ||
1280 | return -ENODEV; | ||
1281 | if (!enable[dev]) | ||
1282 | return -ENOENT; | ||
1283 | |||
1284 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); | ||
1285 | if (card == NULL) | ||
1286 | return -ENOMEM; | ||
1287 | err = snd_ml403_ac97cr_create(card, pfdev, &ml403_ac97cr); | ||
1288 | if (err < 0) { | ||
1289 | PDEBUG(INIT_FAILURE, "probe(): create failed!\n"); | ||
1290 | snd_card_free(card); | ||
1291 | return err; | ||
1292 | } | ||
1293 | PDEBUG(INIT_INFO, "probe(): create done\n"); | ||
1294 | card->private_data = ml403_ac97cr; | ||
1295 | err = snd_ml403_ac97cr_mixer(ml403_ac97cr); | ||
1296 | if (err < 0) { | ||
1297 | snd_card_free(card); | ||
1298 | return err; | ||
1299 | } | ||
1300 | PDEBUG(INIT_INFO, "probe(): mixer done\n"); | ||
1301 | err = snd_ml403_ac97cr_pcm(ml403_ac97cr, 0, NULL); | ||
1302 | if (err < 0) { | ||
1303 | snd_card_free(card); | ||
1304 | return err; | ||
1305 | } | ||
1306 | PDEBUG(INIT_INFO, "probe(): PCM done\n"); | ||
1307 | strcpy(card->driver, SND_ML403_AC97CR_DRIVER); | ||
1308 | strcpy(card->shortname, "ML403 AC97 Controller Reference"); | ||
1309 | sprintf(card->longname, "%s %s at 0x%lx, irq %i & %i, device %i", | ||
1310 | card->shortname, card->driver, | ||
1311 | (unsigned long)ml403_ac97cr->port, ml403_ac97cr->irq, | ||
1312 | ml403_ac97cr->capture_irq, dev + 1); | ||
1313 | |||
1314 | snd_card_set_dev(card, &pfdev->dev); | ||
1315 | |||
1316 | err = snd_card_register(card); | ||
1317 | if (err < 0) { | ||
1318 | snd_card_free(card); | ||
1319 | return err; | ||
1320 | } | ||
1321 | platform_set_drvdata(pfdev, card); | ||
1322 | PDEBUG(INIT_INFO, "probe(): (done)\n"); | ||
1323 | return 0; | ||
1324 | } | ||
1325 | |||
1326 | static int snd_ml403_ac97cr_remove(struct platform_device *pfdev) | ||
1327 | { | ||
1328 | snd_card_free(platform_get_drvdata(pfdev)); | ||
1329 | platform_set_drvdata(pfdev, NULL); | ||
1330 | return 0; | ||
1331 | } | ||
1332 | |||
1333 | static struct platform_driver snd_ml403_ac97cr_driver = { | ||
1334 | .probe = snd_ml403_ac97cr_probe, | ||
1335 | .remove = snd_ml403_ac97cr_remove, | ||
1336 | .driver = { | ||
1337 | .name = SND_ML403_AC97CR_DRIVER, | ||
1338 | }, | ||
1339 | }; | ||
1340 | |||
1341 | static int __init alsa_card_ml403_ac97cr_init(void) | ||
1342 | { | ||
1343 | return platform_driver_register(&snd_ml403_ac97cr_driver); | ||
1344 | } | ||
1345 | |||
1346 | static void __exit alsa_card_ml403_ac97cr_exit(void) | ||
1347 | { | ||
1348 | platform_driver_unregister(&snd_ml403_ac97cr_driver); | ||
1349 | } | ||
1350 | |||
1351 | module_init(alsa_card_ml403_ac97cr_init) | ||
1352 | module_exit(alsa_card_ml403_ac97cr_exit) | ||
diff --git a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c index 1fc95dadde1d..5b996f3faba5 100644 --- a/sound/drivers/mpu401/mpu401.c +++ b/sound/drivers/mpu401/mpu401.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <linux/pnp.h> | 24 | #include <linux/pnp.h> |
26 | #include <linux/err.h> | 25 | #include <linux/err.h> |
diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c index b57f2d5a1c9d..5993864acbd3 100644 --- a/sound/drivers/mpu401/mpu401_uart.c +++ b/sound/drivers/mpu401/mpu401_uart.c | |||
@@ -28,7 +28,6 @@ | |||
28 | * | 28 | * |
29 | */ | 29 | */ |
30 | 30 | ||
31 | #include <sound/driver.h> | ||
32 | #include <asm/io.h> | 31 | #include <asm/io.h> |
33 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
34 | #include <linux/init.h> | 33 | #include <linux/init.h> |
diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c index 40eb026c86ed..b5e1a71bb64b 100644 --- a/sound/drivers/mtpav.c +++ b/sound/drivers/mtpav.c | |||
@@ -50,7 +50,6 @@ | |||
50 | * | 50 | * |
51 | */ | 51 | */ |
52 | 52 | ||
53 | #include <sound/driver.h> | ||
54 | #include <linux/init.h> | 53 | #include <linux/init.h> |
55 | #include <linux/interrupt.h> | 54 | #include <linux/interrupt.h> |
56 | #include <linux/err.h> | 55 | #include <linux/err.h> |
diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c index dcc90f995294..87ba1ddc0115 100644 --- a/sound/drivers/mts64.c +++ b/sound/drivers/mts64.c | |||
@@ -18,7 +18,6 @@ | |||
18 | * | 18 | * |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <sound/driver.h> | ||
22 | #include <linux/init.h> | 21 | #include <linux/init.h> |
23 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
24 | #include <linux/parport.h> | 23 | #include <linux/parport.h> |
@@ -461,13 +460,14 @@ static int snd_mts64_ctl_smpte_switch_put(struct snd_kcontrol* kctl, | |||
461 | { | 460 | { |
462 | struct mts64 *mts = snd_kcontrol_chip(kctl); | 461 | struct mts64 *mts = snd_kcontrol_chip(kctl); |
463 | int changed = 0; | 462 | int changed = 0; |
463 | int val = !!uctl->value.integer.value[0]; | ||
464 | 464 | ||
465 | spin_lock_irq(&mts->lock); | 465 | spin_lock_irq(&mts->lock); |
466 | if (mts->smpte_switch == uctl->value.integer.value[0]) | 466 | if (mts->smpte_switch == val) |
467 | goto __out; | 467 | goto __out; |
468 | 468 | ||
469 | changed = 1; | 469 | changed = 1; |
470 | mts->smpte_switch = uctl->value.integer.value[0]; | 470 | mts->smpte_switch = val; |
471 | if (mts->smpte_switch) { | 471 | if (mts->smpte_switch) { |
472 | mts64_smpte_start(mts->pardev->port, | 472 | mts64_smpte_start(mts->pardev->port, |
473 | mts->time[0], mts->time[1], | 473 | mts->time[0], mts->time[1], |
@@ -541,12 +541,13 @@ static int snd_mts64_ctl_smpte_time_put(struct snd_kcontrol *kctl, | |||
541 | { | 541 | { |
542 | struct mts64 *mts = snd_kcontrol_chip(kctl); | 542 | struct mts64 *mts = snd_kcontrol_chip(kctl); |
543 | int idx = kctl->private_value; | 543 | int idx = kctl->private_value; |
544 | unsigned int time = uctl->value.integer.value[0] % 60; | ||
544 | int changed = 0; | 545 | int changed = 0; |
545 | 546 | ||
546 | spin_lock_irq(&mts->lock); | 547 | spin_lock_irq(&mts->lock); |
547 | if (mts->time[idx] != uctl->value.integer.value[0]) { | 548 | if (mts->time[idx] != time) { |
548 | changed = 1; | 549 | changed = 1; |
549 | mts->time[idx] = uctl->value.integer.value[0]; | 550 | mts->time[idx] = time; |
550 | } | 551 | } |
551 | spin_unlock_irq(&mts->lock); | 552 | spin_unlock_irq(&mts->lock); |
552 | 553 | ||
@@ -636,6 +637,8 @@ static int snd_mts64_ctl_smpte_fps_put(struct snd_kcontrol *kctl, | |||
636 | struct mts64 *mts = snd_kcontrol_chip(kctl); | 637 | struct mts64 *mts = snd_kcontrol_chip(kctl); |
637 | int changed = 0; | 638 | int changed = 0; |
638 | 639 | ||
640 | if (uctl->value.enumerated.item[0] >= 5) | ||
641 | return -EINVAL; | ||
639 | spin_lock_irq(&mts->lock); | 642 | spin_lock_irq(&mts->lock); |
640 | if (mts->fps != uctl->value.enumerated.item[0]) { | 643 | if (mts->fps != uctl->value.enumerated.item[0]) { |
641 | changed = 1; | 644 | changed = 1; |
@@ -662,7 +665,7 @@ static int __devinit snd_mts64_ctl_create(struct snd_card *card, | |||
662 | struct mts64 *mts) | 665 | struct mts64 *mts) |
663 | { | 666 | { |
664 | int err, i; | 667 | int err, i; |
665 | static struct snd_kcontrol_new *control[] = { | 668 | static struct snd_kcontrol_new *control[] __devinitdata = { |
666 | &mts64_ctl_smpte_switch, | 669 | &mts64_ctl_smpte_switch, |
667 | &mts64_ctl_smpte_time_hours, | 670 | &mts64_ctl_smpte_time_hours, |
668 | &mts64_ctl_smpte_time_minutes, | 671 | &mts64_ctl_smpte_time_minutes, |
@@ -1004,6 +1007,8 @@ static int __devinit snd_mts64_probe(struct platform_device *pdev) | |||
1004 | 1007 | ||
1005 | platform_set_drvdata(pdev, card); | 1008 | platform_set_drvdata(pdev, card); |
1006 | 1009 | ||
1010 | snd_card_set_dev(card, &pdev->dev); | ||
1011 | |||
1007 | /* At this point card will be usable */ | 1012 | /* At this point card will be usable */ |
1008 | if ((err = snd_card_register(card)) < 0) { | 1013 | if ((err = snd_card_register(card)) < 0) { |
1009 | snd_printd("Cannot register card\n"); | 1014 | snd_printd("Cannot register card\n"); |
diff --git a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c index a2b9ce060295..ebe4359047cb 100644 --- a/sound/drivers/opl3/opl3_lib.c +++ b/sound/drivers/opl3/opl3_lib.c | |||
@@ -327,6 +327,7 @@ static int snd_opl3_free(struct snd_opl3 *opl3) | |||
327 | snd_assert(opl3 != NULL, return -ENXIO); | 327 | snd_assert(opl3 != NULL, return -ENXIO); |
328 | if (opl3->private_free) | 328 | if (opl3->private_free) |
329 | opl3->private_free(opl3); | 329 | opl3->private_free(opl3); |
330 | snd_opl3_clear_patches(opl3); | ||
330 | release_and_free_resource(opl3->res_l_port); | 331 | release_and_free_resource(opl3->res_l_port); |
331 | release_and_free_resource(opl3->res_r_port); | 332 | release_and_free_resource(opl3->res_r_port); |
332 | kfree(opl3); | 333 | kfree(opl3); |
@@ -360,7 +361,6 @@ int snd_opl3_new(struct snd_card *card, | |||
360 | opl3->hardware = hardware; | 361 | opl3->hardware = hardware; |
361 | spin_lock_init(&opl3->reg_lock); | 362 | spin_lock_init(&opl3->reg_lock); |
362 | spin_lock_init(&opl3->timer_lock); | 363 | spin_lock_init(&opl3->timer_lock); |
363 | mutex_init(&opl3->access_mutex); | ||
364 | 364 | ||
365 | if ((err = snd_device_new(card, SNDRV_DEV_CODEC, opl3, &ops)) < 0) { | 365 | if ((err = snd_device_new(card, SNDRV_DEV_CODEC, opl3, &ops)) < 0) { |
366 | snd_opl3_free(opl3); | 366 | snd_opl3_free(opl3); |
@@ -496,6 +496,7 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3, | |||
496 | return err; | 496 | return err; |
497 | } | 497 | } |
498 | hw->private_data = opl3; | 498 | hw->private_data = opl3; |
499 | hw->exclusive = 1; | ||
499 | #ifdef CONFIG_SND_OSSEMUL | 500 | #ifdef CONFIG_SND_OSSEMUL |
500 | if (device == 0) { | 501 | if (device == 0) { |
501 | hw->oss_type = SNDRV_OSS_DEVICE_TYPE_DMFM; | 502 | hw->oss_type = SNDRV_OSS_DEVICE_TYPE_DMFM; |
@@ -521,8 +522,10 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3, | |||
521 | /* operators - only ioctl */ | 522 | /* operators - only ioctl */ |
522 | hw->ops.open = snd_opl3_open; | 523 | hw->ops.open = snd_opl3_open; |
523 | hw->ops.ioctl = snd_opl3_ioctl; | 524 | hw->ops.ioctl = snd_opl3_ioctl; |
525 | hw->ops.write = snd_opl3_write; | ||
524 | hw->ops.release = snd_opl3_release; | 526 | hw->ops.release = snd_opl3_release; |
525 | 527 | ||
528 | opl3->hwdep = hw; | ||
526 | opl3->seq_dev_num = seq_device; | 529 | opl3->seq_dev_num = seq_device; |
527 | #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) | 530 | #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) |
528 | if (snd_seq_device_new(card, seq_device, SNDRV_SEQ_DEV_ID_OPL3, | 531 | if (snd_seq_device_new(card, seq_device, SNDRV_SEQ_DEV_ID_OPL3, |
diff --git a/sound/drivers/opl3/opl3_midi.c b/sound/drivers/opl3/opl3_midi.c index 3557b6e20eb5..cebcb8b78acb 100644 --- a/sound/drivers/opl3/opl3_midi.c +++ b/sound/drivers/opl3/opl3_midi.c | |||
@@ -289,8 +289,6 @@ static int snd_opl3_oss_map[MAX_OPL3_VOICES] = { | |||
289 | void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) | 289 | void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) |
290 | { | 290 | { |
291 | struct snd_opl3 *opl3; | 291 | struct snd_opl3 *opl3; |
292 | struct snd_seq_instr wanted; | ||
293 | struct snd_seq_kinstr *kinstr; | ||
294 | int instr_4op; | 292 | int instr_4op; |
295 | 293 | ||
296 | int voice; | 294 | int voice; |
@@ -306,11 +304,13 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) | |||
306 | unsigned char voice_offset; | 304 | unsigned char voice_offset; |
307 | unsigned short opl3_reg; | 305 | unsigned short opl3_reg; |
308 | unsigned char reg_val; | 306 | unsigned char reg_val; |
307 | unsigned char prg, bank; | ||
309 | 308 | ||
310 | int key = note; | 309 | int key = note; |
311 | unsigned char fnum, blocknum; | 310 | unsigned char fnum, blocknum; |
312 | int i; | 311 | int i; |
313 | 312 | ||
313 | struct fm_patch *patch; | ||
314 | struct fm_instrument *fm; | 314 | struct fm_instrument *fm; |
315 | unsigned long flags; | 315 | unsigned long flags; |
316 | 316 | ||
@@ -320,19 +320,17 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) | |||
320 | snd_printk("Note on, ch %i, inst %i, note %i, vel %i\n", | 320 | snd_printk("Note on, ch %i, inst %i, note %i, vel %i\n", |
321 | chan->number, chan->midi_program, note, vel); | 321 | chan->number, chan->midi_program, note, vel); |
322 | #endif | 322 | #endif |
323 | wanted.cluster = 0; | ||
324 | wanted.std = SNDRV_SEQ_INSTR_TYPE2_OPL2_3; | ||
325 | 323 | ||
326 | /* in SYNTH mode, application takes care of voices */ | 324 | /* in SYNTH mode, application takes care of voices */ |
327 | /* in SEQ mode, drum voice numbers are notes on drum channel */ | 325 | /* in SEQ mode, drum voice numbers are notes on drum channel */ |
328 | if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) { | 326 | if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) { |
329 | if (chan->drum_channel) { | 327 | if (chan->drum_channel) { |
330 | /* percussion instruments are located in bank 128 */ | 328 | /* percussion instruments are located in bank 128 */ |
331 | wanted.bank = 128; | 329 | bank = 128; |
332 | wanted.prg = note; | 330 | prg = note; |
333 | } else { | 331 | } else { |
334 | wanted.bank = chan->gm_bank_select; | 332 | bank = chan->gm_bank_select; |
335 | wanted.prg = chan->midi_program; | 333 | prg = chan->midi_program; |
336 | } | 334 | } |
337 | } else { | 335 | } else { |
338 | /* Prepare for OSS mode */ | 336 | /* Prepare for OSS mode */ |
@@ -340,8 +338,8 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) | |||
340 | return; | 338 | return; |
341 | 339 | ||
342 | /* OSS instruments are located in bank 127 */ | 340 | /* OSS instruments are located in bank 127 */ |
343 | wanted.bank = 127; | 341 | bank = 127; |
344 | wanted.prg = chan->midi_program; | 342 | prg = chan->midi_program; |
345 | } | 343 | } |
346 | 344 | ||
347 | spin_lock_irqsave(&opl3->voice_lock, flags); | 345 | spin_lock_irqsave(&opl3->voice_lock, flags); |
@@ -353,15 +351,14 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) | |||
353 | } | 351 | } |
354 | 352 | ||
355 | __extra_prg: | 353 | __extra_prg: |
356 | kinstr = snd_seq_instr_find(opl3->ilist, &wanted, 1, 0); | 354 | patch = snd_opl3_find_patch(opl3, prg, bank, 0); |
357 | if (kinstr == NULL) { | 355 | if (!patch) { |
358 | spin_unlock_irqrestore(&opl3->voice_lock, flags); | 356 | spin_unlock_irqrestore(&opl3->voice_lock, flags); |
359 | return; | 357 | return; |
360 | } | 358 | } |
361 | 359 | ||
362 | fm = KINSTR_DATA(kinstr); | 360 | fm = &patch->inst; |
363 | 361 | switch (patch->type) { | |
364 | switch (fm->type) { | ||
365 | case FM_PATCH_OPL2: | 362 | case FM_PATCH_OPL2: |
366 | instr_4op = 0; | 363 | instr_4op = 0; |
367 | break; | 364 | break; |
@@ -371,14 +368,12 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) | |||
371 | break; | 368 | break; |
372 | } | 369 | } |
373 | default: | 370 | default: |
374 | snd_seq_instr_free_use(opl3->ilist, kinstr); | ||
375 | spin_unlock_irqrestore(&opl3->voice_lock, flags); | 371 | spin_unlock_irqrestore(&opl3->voice_lock, flags); |
376 | return; | 372 | return; |
377 | } | 373 | } |
378 | |||
379 | #ifdef DEBUG_MIDI | 374 | #ifdef DEBUG_MIDI |
380 | snd_printk(" --> OPL%i instrument: %s\n", | 375 | snd_printk(" --> OPL%i instrument: %s\n", |
381 | instr_4op ? 3 : 2, kinstr->name); | 376 | instr_4op ? 3 : 2, patch->name); |
382 | #endif | 377 | #endif |
383 | /* in SYNTH mode, application takes care of voices */ | 378 | /* in SYNTH mode, application takes care of voices */ |
384 | /* in SEQ mode, allocate voice on free OPL3 channel */ | 379 | /* in SEQ mode, allocate voice on free OPL3 channel */ |
@@ -569,8 +564,6 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) | |||
569 | /* get extra pgm, but avoid possible loops */ | 564 | /* get extra pgm, but avoid possible loops */ |
570 | extra_prg = (extra_prg) ? 0 : fm->modes; | 565 | extra_prg = (extra_prg) ? 0 : fm->modes; |
571 | 566 | ||
572 | snd_seq_instr_free_use(opl3->ilist, kinstr); | ||
573 | |||
574 | /* do the bookkeeping */ | 567 | /* do the bookkeeping */ |
575 | vp->time = opl3->use_time++; | 568 | vp->time = opl3->use_time++; |
576 | vp->note = key; | 569 | vp->note = key; |
@@ -601,12 +594,12 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) | |||
601 | /* allocate extra program if specified in patch library */ | 594 | /* allocate extra program if specified in patch library */ |
602 | if (extra_prg) { | 595 | if (extra_prg) { |
603 | if (extra_prg > 128) { | 596 | if (extra_prg > 128) { |
604 | wanted.bank = 128; | 597 | bank = 128; |
605 | /* percussions start at 35 */ | 598 | /* percussions start at 35 */ |
606 | wanted.prg = extra_prg - 128 + 35 - 1; | 599 | prg = extra_prg - 128 + 35 - 1; |
607 | } else { | 600 | } else { |
608 | wanted.bank = 0; | 601 | bank = 0; |
609 | wanted.prg = extra_prg - 1; | 602 | prg = extra_prg - 1; |
610 | } | 603 | } |
611 | #ifdef DEBUG_MIDI | 604 | #ifdef DEBUG_MIDI |
612 | snd_printk(" *** allocating extra program\n"); | 605 | snd_printk(" *** allocating extra program\n"); |
diff --git a/sound/drivers/opl3/opl3_oss.c b/sound/drivers/opl3/opl3_oss.c index 5fd3a4c95626..239347f26154 100644 --- a/sound/drivers/opl3/opl3_oss.c +++ b/sound/drivers/opl3/opl3_oss.c | |||
@@ -195,17 +195,6 @@ static int snd_opl3_close_seq_oss(struct snd_seq_oss_arg *arg) | |||
195 | 195 | ||
196 | /* load patch */ | 196 | /* load patch */ |
197 | 197 | ||
198 | /* offsets for SBI params */ | ||
199 | #define AM_VIB 0 | ||
200 | #define KSL_LEVEL 2 | ||
201 | #define ATTACK_DECAY 4 | ||
202 | #define SUSTAIN_RELEASE 6 | ||
203 | #define WAVE_SELECT 8 | ||
204 | |||
205 | /* offset for SBI instrument */ | ||
206 | #define CONNECTION 10 | ||
207 | #define OFFSET_4OP 11 | ||
208 | |||
209 | /* from sound_config.h */ | 198 | /* from sound_config.h */ |
210 | #define SBFM_MAXINSTR 256 | 199 | #define SBFM_MAXINSTR 256 |
211 | 200 | ||
@@ -213,112 +202,42 @@ static int snd_opl3_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format, | |||
213 | const char __user *buf, int offs, int count) | 202 | const char __user *buf, int offs, int count) |
214 | { | 203 | { |
215 | struct snd_opl3 *opl3; | 204 | struct snd_opl3 *opl3; |
216 | int err = -EINVAL; | 205 | struct sbi_instrument sbi; |
206 | char name[32]; | ||
207 | int err, type; | ||
217 | 208 | ||
218 | snd_assert(arg != NULL, return -ENXIO); | 209 | snd_assert(arg != NULL, return -ENXIO); |
219 | opl3 = arg->private_data; | 210 | opl3 = arg->private_data; |
220 | 211 | ||
221 | if ((format == FM_PATCH) || (format == OPL3_PATCH)) { | 212 | if (format == FM_PATCH) |
222 | struct sbi_instrument sbi; | 213 | type = FM_PATCH_OPL2; |
214 | else if (format == OPL3_PATCH) | ||
215 | type = FM_PATCH_OPL3; | ||
216 | else | ||
217 | return -EINVAL; | ||
223 | 218 | ||
224 | size_t size; | 219 | if (count < (int)sizeof(sbi)) { |
225 | struct snd_seq_instr_header *put; | 220 | snd_printk("FM Error: Patch record too short\n"); |
226 | struct snd_seq_instr_data *data; | 221 | return -EINVAL; |
227 | struct fm_xinstrument *xinstr; | 222 | } |
223 | if (copy_from_user(&sbi, buf, sizeof(sbi))) | ||
224 | return -EFAULT; | ||
228 | 225 | ||
229 | struct snd_seq_event ev; | 226 | if (sbi.channel < 0 || sbi.channel >= SBFM_MAXINSTR) { |
230 | int i; | 227 | snd_printk("FM Error: Invalid instrument number %d\n", |
228 | sbi.channel); | ||
229 | return -EINVAL; | ||
230 | } | ||
231 | 231 | ||
232 | mm_segment_t fs; | 232 | memset(name, 0, sizeof(name)); |
233 | sprintf(name, "Chan%d", sbi.channel); | ||
233 | 234 | ||
234 | if (count < (int)sizeof(sbi)) { | 235 | err = snd_opl3_load_patch(opl3, sbi.channel, 127, type, name, NULL, |
235 | snd_printk("FM Error: Patch record too short\n"); | 236 | sbi.operators); |
236 | return -EINVAL; | 237 | if (err < 0) |
237 | } | 238 | return err; |
238 | if (copy_from_user(&sbi, buf, sizeof(sbi))) | ||
239 | return -EFAULT; | ||
240 | 239 | ||
241 | if (sbi.channel < 0 || sbi.channel >= SBFM_MAXINSTR) { | 240 | return sizeof(sbi); |
242 | snd_printk("FM Error: Invalid instrument number %d\n", sbi.channel); | ||
243 | return -EINVAL; | ||
244 | } | ||
245 | |||
246 | size = sizeof(*put) + sizeof(struct fm_xinstrument); | ||
247 | put = kzalloc(size, GFP_KERNEL); | ||
248 | if (put == NULL) | ||
249 | return -ENOMEM; | ||
250 | /* build header */ | ||
251 | data = &put->data; | ||
252 | data->type = SNDRV_SEQ_INSTR_ATYPE_DATA; | ||
253 | strcpy(data->data.format, SNDRV_SEQ_INSTR_ID_OPL2_3); | ||
254 | /* build data section */ | ||
255 | xinstr = (struct fm_xinstrument *)(data + 1); | ||
256 | xinstr->stype = FM_STRU_INSTR; | ||
257 | |||
258 | for (i = 0; i < 2; i++) { | ||
259 | xinstr->op[i].am_vib = sbi.operators[AM_VIB + i]; | ||
260 | xinstr->op[i].ksl_level = sbi.operators[KSL_LEVEL + i]; | ||
261 | xinstr->op[i].attack_decay = sbi.operators[ATTACK_DECAY + i]; | ||
262 | xinstr->op[i].sustain_release = sbi.operators[SUSTAIN_RELEASE + i]; | ||
263 | xinstr->op[i].wave_select = sbi.operators[WAVE_SELECT + i]; | ||
264 | } | ||
265 | xinstr->feedback_connection[0] = sbi.operators[CONNECTION]; | ||
266 | |||
267 | if (format == OPL3_PATCH) { | ||
268 | xinstr->type = FM_PATCH_OPL3; | ||
269 | for (i = 0; i < 2; i++) { | ||
270 | xinstr->op[i+2].am_vib = sbi.operators[OFFSET_4OP + AM_VIB + i]; | ||
271 | xinstr->op[i+2].ksl_level = sbi.operators[OFFSET_4OP + KSL_LEVEL + i]; | ||
272 | xinstr->op[i+2].attack_decay = sbi.operators[OFFSET_4OP + ATTACK_DECAY + i]; | ||
273 | xinstr->op[i+2].sustain_release = sbi.operators[OFFSET_4OP + SUSTAIN_RELEASE + i]; | ||
274 | xinstr->op[i+2].wave_select = sbi.operators[OFFSET_4OP + WAVE_SELECT + i]; | ||
275 | } | ||
276 | xinstr->feedback_connection[1] = sbi.operators[OFFSET_4OP + CONNECTION]; | ||
277 | } else { | ||
278 | xinstr->type = FM_PATCH_OPL2; | ||
279 | } | ||
280 | |||
281 | put->id.instr.std = SNDRV_SEQ_INSTR_TYPE2_OPL2_3; | ||
282 | put->id.instr.bank = 127; | ||
283 | put->id.instr.prg = sbi.channel; | ||
284 | put->cmd = SNDRV_SEQ_INSTR_PUT_CMD_CREATE; | ||
285 | |||
286 | memset (&ev, 0, sizeof(ev)); | ||
287 | ev.source.client = SNDRV_SEQ_CLIENT_OSS; | ||
288 | ev.dest = arg->addr; | ||
289 | |||
290 | ev.flags = SNDRV_SEQ_EVENT_LENGTH_VARUSR; | ||
291 | ev.queue = SNDRV_SEQ_QUEUE_DIRECT; | ||
292 | |||
293 | fs = snd_enter_user(); | ||
294 | __again: | ||
295 | ev.type = SNDRV_SEQ_EVENT_INSTR_PUT; | ||
296 | ev.data.ext.len = size; | ||
297 | ev.data.ext.ptr = put; | ||
298 | |||
299 | err = snd_seq_instr_event(&opl3->fm_ops, opl3->ilist, &ev, | ||
300 | opl3->seq_client, 0, 0); | ||
301 | if (err == -EBUSY) { | ||
302 | struct snd_seq_instr_header remove; | ||
303 | |||
304 | memset (&remove, 0, sizeof(remove)); | ||
305 | remove.cmd = SNDRV_SEQ_INSTR_FREE_CMD_SINGLE; | ||
306 | remove.id.instr = put->id.instr; | ||
307 | |||
308 | /* remove instrument */ | ||
309 | ev.type = SNDRV_SEQ_EVENT_INSTR_FREE; | ||
310 | ev.data.ext.len = sizeof(remove); | ||
311 | ev.data.ext.ptr = &remove; | ||
312 | |||
313 | snd_seq_instr_event(&opl3->fm_ops, opl3->ilist, &ev, | ||
314 | opl3->seq_client, 0, 0); | ||
315 | goto __again; | ||
316 | } | ||
317 | snd_leave_user(fs); | ||
318 | |||
319 | kfree(put); | ||
320 | } | ||
321 | return err; | ||
322 | } | 241 | } |
323 | 242 | ||
324 | /* ioctl */ | 243 | /* ioctl */ |
diff --git a/sound/drivers/opl3/opl3_seq.c b/sound/drivers/opl3/opl3_seq.c index 96762c9d4855..2d33f53d36b8 100644 --- a/sound/drivers/opl3/opl3_seq.c +++ b/sound/drivers/opl3/opl3_seq.c | |||
@@ -51,14 +51,15 @@ void snd_opl3_synth_use_dec(struct snd_opl3 * opl3) | |||
51 | int snd_opl3_synth_setup(struct snd_opl3 * opl3) | 51 | int snd_opl3_synth_setup(struct snd_opl3 * opl3) |
52 | { | 52 | { |
53 | int idx; | 53 | int idx; |
54 | struct snd_hwdep *hwdep = opl3->hwdep; | ||
54 | 55 | ||
55 | mutex_lock(&opl3->access_mutex); | 56 | mutex_lock(&hwdep->open_mutex); |
56 | if (opl3->used) { | 57 | if (hwdep->used) { |
57 | mutex_unlock(&opl3->access_mutex); | 58 | mutex_unlock(&hwdep->open_mutex); |
58 | return -EBUSY; | 59 | return -EBUSY; |
59 | } | 60 | } |
60 | opl3->used++; | 61 | hwdep->used++; |
61 | mutex_unlock(&opl3->access_mutex); | 62 | mutex_unlock(&hwdep->open_mutex); |
62 | 63 | ||
63 | snd_opl3_reset(opl3); | 64 | snd_opl3_reset(opl3); |
64 | 65 | ||
@@ -81,6 +82,7 @@ int snd_opl3_synth_setup(struct snd_opl3 * opl3) | |||
81 | void snd_opl3_synth_cleanup(struct snd_opl3 * opl3) | 82 | void snd_opl3_synth_cleanup(struct snd_opl3 * opl3) |
82 | { | 83 | { |
83 | unsigned long flags; | 84 | unsigned long flags; |
85 | struct snd_hwdep *hwdep; | ||
84 | 86 | ||
85 | /* Stop system timer */ | 87 | /* Stop system timer */ |
86 | spin_lock_irqsave(&opl3->sys_timer_lock, flags); | 88 | spin_lock_irqsave(&opl3->sys_timer_lock, flags); |
@@ -91,9 +93,11 @@ void snd_opl3_synth_cleanup(struct snd_opl3 * opl3) | |||
91 | spin_unlock_irqrestore(&opl3->sys_timer_lock, flags); | 93 | spin_unlock_irqrestore(&opl3->sys_timer_lock, flags); |
92 | 94 | ||
93 | snd_opl3_reset(opl3); | 95 | snd_opl3_reset(opl3); |
94 | mutex_lock(&opl3->access_mutex); | 96 | hwdep = opl3->hwdep; |
95 | opl3->used--; | 97 | mutex_lock(&hwdep->open_mutex); |
96 | mutex_unlock(&opl3->access_mutex); | 98 | hwdep->used--; |
99 | mutex_unlock(&hwdep->open_mutex); | ||
100 | wake_up(&hwdep->open_wait); | ||
97 | } | 101 | } |
98 | 102 | ||
99 | static int snd_opl3_synth_use(void *private_data, struct snd_seq_port_subscribe * info) | 103 | static int snd_opl3_synth_use(void *private_data, struct snd_seq_port_subscribe * info) |
@@ -152,15 +156,7 @@ static int snd_opl3_synth_event_input(struct snd_seq_event * ev, int direct, | |||
152 | { | 156 | { |
153 | struct snd_opl3 *opl3 = private_data; | 157 | struct snd_opl3 *opl3 = private_data; |
154 | 158 | ||
155 | if (ev->type >= SNDRV_SEQ_EVENT_INSTR_BEGIN && | 159 | snd_midi_process_event(&opl3_ops, ev, opl3->chset); |
156 | ev->type <= SNDRV_SEQ_EVENT_INSTR_CHANGE) { | ||
157 | if (direct) { | ||
158 | snd_seq_instr_event(&opl3->fm_ops, opl3->ilist, ev, | ||
159 | opl3->seq_client, atomic, hop); | ||
160 | } | ||
161 | } else { | ||
162 | snd_midi_process_event(&opl3_ops, ev, opl3->chset); | ||
163 | } | ||
164 | return 0; | 160 | return 0; |
165 | } | 161 | } |
166 | 162 | ||
@@ -249,16 +245,6 @@ static int snd_opl3_seq_new_device(struct snd_seq_device *dev) | |||
249 | return err; | 245 | return err; |
250 | } | 246 | } |
251 | 247 | ||
252 | /* initialize instrument list */ | ||
253 | opl3->ilist = snd_seq_instr_list_new(); | ||
254 | if (opl3->ilist == NULL) { | ||
255 | snd_seq_delete_kernel_client(client); | ||
256 | opl3->seq_client = -1; | ||
257 | return -ENOMEM; | ||
258 | } | ||
259 | opl3->ilist->flags = SNDRV_SEQ_INSTR_FLG_DIRECT; | ||
260 | snd_seq_fm_init(&opl3->fm_ops, NULL); | ||
261 | |||
262 | /* setup system timer */ | 248 | /* setup system timer */ |
263 | init_timer(&opl3->tlist); | 249 | init_timer(&opl3->tlist); |
264 | opl3->tlist.function = snd_opl3_timer_func; | 250 | opl3->tlist.function = snd_opl3_timer_func; |
@@ -287,8 +273,6 @@ static int snd_opl3_seq_delete_device(struct snd_seq_device *dev) | |||
287 | snd_seq_delete_kernel_client(opl3->seq_client); | 273 | snd_seq_delete_kernel_client(opl3->seq_client); |
288 | opl3->seq_client = -1; | 274 | opl3->seq_client = -1; |
289 | } | 275 | } |
290 | if (opl3->ilist) | ||
291 | snd_seq_instr_list_free(&opl3->ilist); | ||
292 | return 0; | 276 | return 0; |
293 | } | 277 | } |
294 | 278 | ||
diff --git a/sound/drivers/opl3/opl3_synth.c b/sound/drivers/opl3/opl3_synth.c index a4b3543a7118..a7bf7a4b1f85 100644 --- a/sound/drivers/opl3/opl3_synth.c +++ b/sound/drivers/opl3/opl3_synth.c | |||
@@ -76,16 +76,6 @@ static int snd_opl3_set_connection(struct snd_opl3 * opl3, int connection); | |||
76 | */ | 76 | */ |
77 | int snd_opl3_open(struct snd_hwdep * hw, struct file *file) | 77 | int snd_opl3_open(struct snd_hwdep * hw, struct file *file) |
78 | { | 78 | { |
79 | struct snd_opl3 *opl3 = hw->private_data; | ||
80 | |||
81 | mutex_lock(&opl3->access_mutex); | ||
82 | if (opl3->used) { | ||
83 | mutex_unlock(&opl3->access_mutex); | ||
84 | return -EAGAIN; | ||
85 | } | ||
86 | opl3->used++; | ||
87 | mutex_unlock(&opl3->access_mutex); | ||
88 | |||
89 | return 0; | 79 | return 0; |
90 | } | 80 | } |
91 | 81 | ||
@@ -165,6 +155,10 @@ int snd_opl3_ioctl(struct snd_hwdep * hw, struct file *file, | |||
165 | #endif | 155 | #endif |
166 | return snd_opl3_set_connection(opl3, (int) arg); | 156 | return snd_opl3_set_connection(opl3, (int) arg); |
167 | 157 | ||
158 | case SNDRV_DM_FM_IOCTL_CLEAR_PATCHES: | ||
159 | snd_opl3_clear_patches(opl3); | ||
160 | return 0; | ||
161 | |||
168 | #ifdef CONFIG_SND_DEBUG | 162 | #ifdef CONFIG_SND_DEBUG |
169 | default: | 163 | default: |
170 | snd_printk("unknown IOCTL: 0x%x\n", cmd); | 164 | snd_printk("unknown IOCTL: 0x%x\n", cmd); |
@@ -181,12 +175,172 @@ int snd_opl3_release(struct snd_hwdep * hw, struct file *file) | |||
181 | struct snd_opl3 *opl3 = hw->private_data; | 175 | struct snd_opl3 *opl3 = hw->private_data; |
182 | 176 | ||
183 | snd_opl3_reset(opl3); | 177 | snd_opl3_reset(opl3); |
184 | mutex_lock(&opl3->access_mutex); | 178 | return 0; |
185 | opl3->used--; | 179 | } |
186 | mutex_unlock(&opl3->access_mutex); | 180 | |
181 | /* | ||
182 | * write the device - load patches | ||
183 | */ | ||
184 | long snd_opl3_write(struct snd_hwdep *hw, const char __user *buf, long count, | ||
185 | loff_t *offset) | ||
186 | { | ||
187 | struct snd_opl3 *opl3 = hw->private_data; | ||
188 | long result = 0; | ||
189 | int err = 0; | ||
190 | struct sbi_patch inst; | ||
191 | |||
192 | while (count >= sizeof(inst)) { | ||
193 | unsigned char type; | ||
194 | if (copy_from_user(&inst, buf, sizeof(inst))) | ||
195 | return -EFAULT; | ||
196 | if (!memcmp(inst.key, FM_KEY_SBI, 4) || | ||
197 | !memcmp(inst.key, FM_KEY_2OP, 4)) | ||
198 | type = FM_PATCH_OPL2; | ||
199 | else if (!memcmp(inst.key, FM_KEY_4OP, 4)) | ||
200 | type = FM_PATCH_OPL3; | ||
201 | else /* invalid type */ | ||
202 | break; | ||
203 | err = snd_opl3_load_patch(opl3, inst.prog, inst.bank, type, | ||
204 | inst.name, inst.extension, | ||
205 | inst.data); | ||
206 | if (err < 0) | ||
207 | break; | ||
208 | result += sizeof(inst); | ||
209 | count -= sizeof(inst); | ||
210 | } | ||
211 | return result > 0 ? result : err; | ||
212 | } | ||
213 | |||
214 | |||
215 | /* | ||
216 | * Patch management | ||
217 | */ | ||
218 | |||
219 | /* offsets for SBI params */ | ||
220 | #define AM_VIB 0 | ||
221 | #define KSL_LEVEL 2 | ||
222 | #define ATTACK_DECAY 4 | ||
223 | #define SUSTAIN_RELEASE 6 | ||
224 | #define WAVE_SELECT 8 | ||
225 | |||
226 | /* offset for SBI instrument */ | ||
227 | #define CONNECTION 10 | ||
228 | #define OFFSET_4OP 11 | ||
229 | |||
230 | /* | ||
231 | * load a patch, obviously. | ||
232 | * | ||
233 | * loaded on the given program and bank numbers with the given type | ||
234 | * (FM_PATCH_OPLx). | ||
235 | * data is the pointer of SBI record _without_ header (key and name). | ||
236 | * name is the name string of the patch. | ||
237 | * ext is the extension data of 7 bytes long (stored in name of SBI | ||
238 | * data up to offset 25), or NULL to skip. | ||
239 | * return 0 if successful or a negative error code. | ||
240 | */ | ||
241 | int snd_opl3_load_patch(struct snd_opl3 *opl3, | ||
242 | int prog, int bank, int type, | ||
243 | const char *name, | ||
244 | const unsigned char *ext, | ||
245 | const unsigned char *data) | ||
246 | { | ||
247 | struct fm_patch *patch; | ||
248 | int i; | ||
249 | |||
250 | patch = snd_opl3_find_patch(opl3, prog, bank, 1); | ||
251 | if (!patch) | ||
252 | return -ENOMEM; | ||
253 | |||
254 | patch->type = type; | ||
255 | |||
256 | for (i = 0; i < 2; i++) { | ||
257 | patch->inst.op[i].am_vib = data[AM_VIB + i]; | ||
258 | patch->inst.op[i].ksl_level = data[KSL_LEVEL + i]; | ||
259 | patch->inst.op[i].attack_decay = data[ATTACK_DECAY + i]; | ||
260 | patch->inst.op[i].sustain_release = data[SUSTAIN_RELEASE + i]; | ||
261 | patch->inst.op[i].wave_select = data[WAVE_SELECT + i]; | ||
262 | } | ||
263 | patch->inst.feedback_connection[0] = data[CONNECTION]; | ||
264 | |||
265 | if (type == FM_PATCH_OPL3) { | ||
266 | for (i = 0; i < 2; i++) { | ||
267 | patch->inst.op[i+2].am_vib = | ||
268 | data[OFFSET_4OP + AM_VIB + i]; | ||
269 | patch->inst.op[i+2].ksl_level = | ||
270 | data[OFFSET_4OP + KSL_LEVEL + i]; | ||
271 | patch->inst.op[i+2].attack_decay = | ||
272 | data[OFFSET_4OP + ATTACK_DECAY + i]; | ||
273 | patch->inst.op[i+2].sustain_release = | ||
274 | data[OFFSET_4OP + SUSTAIN_RELEASE + i]; | ||
275 | patch->inst.op[i+2].wave_select = | ||
276 | data[OFFSET_4OP + WAVE_SELECT + i]; | ||
277 | } | ||
278 | patch->inst.feedback_connection[1] = | ||
279 | data[OFFSET_4OP + CONNECTION]; | ||
280 | } | ||
281 | |||
282 | if (ext) { | ||
283 | patch->inst.echo_delay = ext[0]; | ||
284 | patch->inst.echo_atten = ext[1]; | ||
285 | patch->inst.chorus_spread = ext[2]; | ||
286 | patch->inst.trnsps = ext[3]; | ||
287 | patch->inst.fix_dur = ext[4]; | ||
288 | patch->inst.modes = ext[5]; | ||
289 | patch->inst.fix_key = ext[6]; | ||
290 | } | ||
291 | |||
292 | if (name) | ||
293 | strlcpy(patch->name, name, sizeof(patch->name)); | ||
187 | 294 | ||
188 | return 0; | 295 | return 0; |
189 | } | 296 | } |
297 | EXPORT_SYMBOL(snd_opl3_load_patch); | ||
298 | |||
299 | /* | ||
300 | * find a patch with the given program and bank numbers, returns its pointer | ||
301 | * if no matching patch is found and create_patch is set, it creates a | ||
302 | * new patch object. | ||
303 | */ | ||
304 | struct fm_patch *snd_opl3_find_patch(struct snd_opl3 *opl3, int prog, int bank, | ||
305 | int create_patch) | ||
306 | { | ||
307 | /* pretty dumb hash key */ | ||
308 | unsigned int key = (prog + bank) % OPL3_PATCH_HASH_SIZE; | ||
309 | struct fm_patch *patch; | ||
310 | |||
311 | for (patch = opl3->patch_table[key]; patch; patch = patch->next) { | ||
312 | if (patch->prog == prog && patch->bank == bank) | ||
313 | return patch; | ||
314 | } | ||
315 | if (!create_patch) | ||
316 | return NULL; | ||
317 | |||
318 | patch = kzalloc(sizeof(*patch), GFP_KERNEL); | ||
319 | if (!patch) | ||
320 | return NULL; | ||
321 | patch->prog = prog; | ||
322 | patch->bank = bank; | ||
323 | patch->next = opl3->patch_table[key]; | ||
324 | opl3->patch_table[key] = patch; | ||
325 | return patch; | ||
326 | } | ||
327 | EXPORT_SYMBOL(snd_opl3_find_patch); | ||
328 | |||
329 | /* | ||
330 | * Clear all patches of the given OPL3 instance | ||
331 | */ | ||
332 | void snd_opl3_clear_patches(struct snd_opl3 *opl3) | ||
333 | { | ||
334 | int i; | ||
335 | for (i = 0; i < OPL3_PATCH_HASH_SIZE; i++) { | ||
336 | struct fm_patch *patch, *next; | ||
337 | for (patch = opl3->patch_table[i]; patch; patch = next) { | ||
338 | next = patch->next; | ||
339 | kfree(patch); | ||
340 | } | ||
341 | } | ||
342 | memset(opl3->patch_table, 0, sizeof(opl3->patch_table)); | ||
343 | } | ||
190 | 344 | ||
191 | /* ------------------------------ */ | 345 | /* ------------------------------ */ |
192 | 346 | ||
diff --git a/sound/drivers/pcm-indirect2.c b/sound/drivers/pcm-indirect2.c new file mode 100644 index 000000000000..3c93c23e4883 --- /dev/null +++ b/sound/drivers/pcm-indirect2.c | |||
@@ -0,0 +1,573 @@ | |||
1 | /* | ||
2 | * Helper functions for indirect PCM data transfer to a simple FIFO in | ||
3 | * hardware (small, no possibility to read "hardware io position", | ||
4 | * updating position done by interrupt, ...) | ||
5 | * | ||
6 | * Copyright (c) by 2007 Joachim Foerster <JOFT@gmx.de> | ||
7 | * | ||
8 | * Based on "pcm-indirect.h" (alsa-driver-1.0.13) by | ||
9 | * | ||
10 | * Copyright (c) by Takashi Iwai <tiwai@suse.de> | ||
11 | * Jaroslav Kysela <perex@suse.cz> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
26 | */ | ||
27 | |||
28 | /* snd_printk/d() */ | ||
29 | #include <sound/core.h> | ||
30 | /* struct snd_pcm_substream, struct snd_pcm_runtime, snd_pcm_uframes_t | ||
31 | * snd_pcm_period_elapsed() */ | ||
32 | #include <sound/pcm.h> | ||
33 | |||
34 | #include "pcm-indirect2.h" | ||
35 | |||
36 | #ifdef SND_PCM_INDIRECT2_STAT | ||
37 | /* jiffies */ | ||
38 | #include <linux/jiffies.h> | ||
39 | |||
40 | void snd_pcm_indirect2_stat(struct snd_pcm_substream *substream, | ||
41 | struct snd_pcm_indirect2 *rec) | ||
42 | { | ||
43 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
44 | int i; | ||
45 | int j; | ||
46 | int k; | ||
47 | int seconds = (rec->lastbytetime - rec->firstbytetime) / HZ; | ||
48 | |||
49 | snd_printk(KERN_DEBUG "STAT: mul_elapsed: %u, mul_elapsed_real: %d, " | ||
50 | "irq_occured: %d\n", | ||
51 | rec->mul_elapsed, rec->mul_elapsed_real, rec->irq_occured); | ||
52 | snd_printk(KERN_DEBUG "STAT: min_multiple: %d (irqs/period)\n", | ||
53 | rec->min_multiple); | ||
54 | snd_printk(KERN_DEBUG "STAT: firstbytetime: %lu, lastbytetime: %lu, " | ||
55 | "firstzerotime: %lu\n", | ||
56 | rec->firstbytetime, rec->lastbytetime, rec->firstzerotime); | ||
57 | snd_printk(KERN_DEBUG "STAT: bytes2hw: %u Bytes => (by runtime->rate) " | ||
58 | "length: %d s\n", | ||
59 | rec->bytes2hw, rec->bytes2hw / 2 / 2 / runtime->rate); | ||
60 | snd_printk(KERN_DEBUG "STAT: (by measurement) length: %d => " | ||
61 | "rate: %d Bytes/s = %d Frames/s|Hz\n", | ||
62 | seconds, rec->bytes2hw / seconds, | ||
63 | rec->bytes2hw / 2 / 2 / seconds); | ||
64 | snd_printk(KERN_DEBUG | ||
65 | "STAT: zeros2hw: %u = %d ms ~ %d * %d zero copies\n", | ||
66 | rec->zeros2hw, ((rec->zeros2hw / 2 / 2) * 1000) / | ||
67 | runtime->rate, | ||
68 | rec->zeros2hw / (rec->hw_buffer_size / 2), | ||
69 | (rec->hw_buffer_size / 2)); | ||
70 | snd_printk(KERN_DEBUG "STAT: pointer_calls: %u, lastdifftime: %u\n", | ||
71 | rec->pointer_calls, rec->lastdifftime); | ||
72 | snd_printk(KERN_DEBUG "STAT: sw_io: %d, sw_data: %d\n", rec->sw_io, | ||
73 | rec->sw_data); | ||
74 | snd_printk(KERN_DEBUG "STAT: byte_sizes[]:\n"); | ||
75 | k = 0; | ||
76 | for (j = 0; j < 8; j++) { | ||
77 | for (i = j * 8; i < (j + 1) * 8; i++) | ||
78 | if (rec->byte_sizes[i] != 0) { | ||
79 | snd_printk(KERN_DEBUG "%u: %u", | ||
80 | i, rec->byte_sizes[i]); | ||
81 | k++; | ||
82 | } | ||
83 | if (((k % 8) == 0) && (k != 0)) { | ||
84 | snd_printk(KERN_DEBUG "\n"); | ||
85 | k = 0; | ||
86 | } | ||
87 | } | ||
88 | snd_printk(KERN_DEBUG "\n"); | ||
89 | snd_printk(KERN_DEBUG "STAT: zero_sizes[]:\n"); | ||
90 | for (j = 0; j < 8; j++) { | ||
91 | k = 0; | ||
92 | for (i = j * 8; i < (j + 1) * 8; i++) | ||
93 | if (rec->zero_sizes[i] != 0) | ||
94 | snd_printk(KERN_DEBUG "%u: %u", | ||
95 | i, rec->zero_sizes[i]); | ||
96 | else | ||
97 | k++; | ||
98 | if (!k) | ||
99 | snd_printk(KERN_DEBUG "\n"); | ||
100 | } | ||
101 | snd_printk(KERN_DEBUG "\n"); | ||
102 | snd_printk(KERN_DEBUG "STAT: min_adds[]:\n"); | ||
103 | for (j = 0; j < 8; j++) { | ||
104 | if (rec->min_adds[j] != 0) | ||
105 | snd_printk(KERN_DEBUG "%u: %u", j, rec->min_adds[j]); | ||
106 | } | ||
107 | snd_printk(KERN_DEBUG "\n"); | ||
108 | snd_printk(KERN_DEBUG "STAT: mul_adds[]:\n"); | ||
109 | for (j = 0; j < 8; j++) { | ||
110 | if (rec->mul_adds[j] != 0) | ||
111 | snd_printk(KERN_DEBUG "%u: %u", j, rec->mul_adds[j]); | ||
112 | } | ||
113 | snd_printk(KERN_DEBUG "\n"); | ||
114 | snd_printk(KERN_DEBUG | ||
115 | "STAT: zero_times_saved: %d, zero_times_notsaved: %d\n", | ||
116 | rec->zero_times_saved, rec->zero_times_notsaved); | ||
117 | /* snd_printk(KERN_DEBUG "STAT: zero_times[]\n"); | ||
118 | i = 0; | ||
119 | for (j = 0; j < 3750; j++) { | ||
120 | if (rec->zero_times[j] != 0) { | ||
121 | snd_printk(KERN_DEBUG "%u: %u", j, rec->zero_times[j]); | ||
122 | i++; | ||
123 | } | ||
124 | if (((i % 8) == 0) && (i != 0)) | ||
125 | snd_printk(KERN_DEBUG "\n"); | ||
126 | } | ||
127 | snd_printk(KERN_DEBUG "\n"); */ | ||
128 | return; | ||
129 | } | ||
130 | #endif | ||
131 | |||
132 | /* | ||
133 | * _internal_ helper function for playback/capture transfer function | ||
134 | */ | ||
135 | static void | ||
136 | snd_pcm_indirect2_increase_min_periods(struct snd_pcm_substream *substream, | ||
137 | struct snd_pcm_indirect2 *rec, | ||
138 | int isplay, int iscopy, | ||
139 | unsigned int bytes) | ||
140 | { | ||
141 | if (rec->min_periods >= 0) { | ||
142 | if (iscopy) { | ||
143 | rec->sw_io += bytes; | ||
144 | if (rec->sw_io >= rec->sw_buffer_size) | ||
145 | rec->sw_io -= rec->sw_buffer_size; | ||
146 | } else if (isplay) { | ||
147 | /* If application does not write data in multiples of | ||
148 | * a period, move sw_data to the next correctly aligned | ||
149 | * position, so that sw_io can converge to it (in the | ||
150 | * next step). | ||
151 | */ | ||
152 | if (!rec->check_alignment) { | ||
153 | if (rec->bytes2hw % | ||
154 | snd_pcm_lib_period_bytes(substream)) { | ||
155 | unsigned bytes2hw_aligned = | ||
156 | (1 + | ||
157 | (rec->bytes2hw / | ||
158 | snd_pcm_lib_period_bytes | ||
159 | (substream))) * | ||
160 | snd_pcm_lib_period_bytes | ||
161 | (substream); | ||
162 | rec->sw_data = | ||
163 | bytes2hw_aligned % | ||
164 | rec->sw_buffer_size; | ||
165 | #ifdef SND_PCM_INDIRECT2_STAT | ||
166 | snd_printk(KERN_DEBUG | ||
167 | "STAT: @re-align: aligned " | ||
168 | "bytes2hw to next period " | ||
169 | "size boundary: %d " | ||
170 | "(instead of %d)\n", | ||
171 | bytes2hw_aligned, | ||
172 | rec->bytes2hw); | ||
173 | snd_printk(KERN_DEBUG | ||
174 | "STAT: @re-align: sw_data " | ||
175 | "moves to: %d\n", | ||
176 | rec->sw_data); | ||
177 | #endif | ||
178 | } | ||
179 | rec->check_alignment = 1; | ||
180 | } | ||
181 | /* We are at the end and are copying zeros into the | ||
182 | * fifo. | ||
183 | * Now, we have to make sure that sw_io is increased | ||
184 | * until the position of sw_data: Filling the fifo with | ||
185 | * the first zeros means, the last bytes were played. | ||
186 | */ | ||
187 | if (rec->sw_io != rec->sw_data) { | ||
188 | unsigned int diff; | ||
189 | if (rec->sw_data > rec->sw_io) | ||
190 | diff = rec->sw_data - rec->sw_io; | ||
191 | else | ||
192 | diff = (rec->sw_buffer_size - | ||
193 | rec->sw_io) + | ||
194 | rec->sw_data; | ||
195 | if (bytes >= diff) | ||
196 | rec->sw_io = rec->sw_data; | ||
197 | else { | ||
198 | rec->sw_io += bytes; | ||
199 | if (rec->sw_io >= rec->sw_buffer_size) | ||
200 | rec->sw_io -= | ||
201 | rec->sw_buffer_size; | ||
202 | } | ||
203 | } | ||
204 | } | ||
205 | rec->min_period_count += bytes; | ||
206 | if (rec->min_period_count >= (rec->hw_buffer_size / 2)) { | ||
207 | rec->min_periods += (rec->min_period_count / | ||
208 | (rec->hw_buffer_size / 2)); | ||
209 | #ifdef SND_PCM_INDIRECT2_STAT | ||
210 | if ((rec->min_period_count / | ||
211 | (rec->hw_buffer_size / 2)) > 7) | ||
212 | snd_printk(KERN_DEBUG | ||
213 | "STAT: more than 7 (%d) min_adds " | ||
214 | "at once - too big to save!\n", | ||
215 | (rec->min_period_count / | ||
216 | (rec->hw_buffer_size / 2))); | ||
217 | else | ||
218 | rec->min_adds[(rec->min_period_count / | ||
219 | (rec->hw_buffer_size / 2))]++; | ||
220 | #endif | ||
221 | rec->min_period_count = (rec->min_period_count % | ||
222 | (rec->hw_buffer_size / 2)); | ||
223 | } | ||
224 | } else if (isplay && iscopy) | ||
225 | rec->min_periods = 0; | ||
226 | } | ||
227 | |||
228 | /* | ||
229 | * helper function for playback/capture pointer callback | ||
230 | */ | ||
231 | snd_pcm_uframes_t | ||
232 | snd_pcm_indirect2_pointer(struct snd_pcm_substream *substream, | ||
233 | struct snd_pcm_indirect2 *rec) | ||
234 | { | ||
235 | #ifdef SND_PCM_INDIRECT2_STAT | ||
236 | rec->pointer_calls++; | ||
237 | #endif | ||
238 | return bytes_to_frames(substream->runtime, rec->sw_io); | ||
239 | } | ||
240 | |||
241 | /* | ||
242 | * _internal_ helper function for playback interrupt callback | ||
243 | */ | ||
244 | static void | ||
245 | snd_pcm_indirect2_playback_transfer(struct snd_pcm_substream *substream, | ||
246 | struct snd_pcm_indirect2 *rec, | ||
247 | snd_pcm_indirect2_copy_t copy, | ||
248 | snd_pcm_indirect2_zero_t zero) | ||
249 | { | ||
250 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
251 | snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr; | ||
252 | |||
253 | /* runtime->control->appl_ptr: position where ALSA will write next time | ||
254 | * rec->appl_ptr: position where ALSA was last time | ||
255 | * diff: obviously ALSA wrote that much bytes into the intermediate | ||
256 | * buffer since we checked last time | ||
257 | */ | ||
258 | snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr; | ||
259 | |||
260 | if (diff) { | ||
261 | #ifdef SND_PCM_INDIRECT2_STAT | ||
262 | rec->lastdifftime = jiffies; | ||
263 | #endif | ||
264 | if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2)) | ||
265 | diff += runtime->boundary; | ||
266 | /* number of bytes "added" by ALSA increases the number of | ||
267 | * bytes which are ready to "be transfered to HW"/"played" | ||
268 | * Then, set rec->appl_ptr to not count bytes twice next time. | ||
269 | */ | ||
270 | rec->sw_ready += (int)frames_to_bytes(runtime, diff); | ||
271 | rec->appl_ptr = appl_ptr; | ||
272 | } | ||
273 | if (rec->hw_ready && (rec->sw_ready <= 0)) { | ||
274 | unsigned int bytes; | ||
275 | |||
276 | #ifdef SND_PCM_INDIRECT2_STAT | ||
277 | if (rec->firstzerotime == 0) { | ||
278 | rec->firstzerotime = jiffies; | ||
279 | snd_printk(KERN_DEBUG | ||
280 | "STAT: @firstzerotime: mul_elapsed: %d, " | ||
281 | "min_period_count: %d\n", | ||
282 | rec->mul_elapsed, rec->min_period_count); | ||
283 | snd_printk(KERN_DEBUG | ||
284 | "STAT: @firstzerotime: sw_io: %d, " | ||
285 | "sw_data: %d, appl_ptr: %u\n", | ||
286 | rec->sw_io, rec->sw_data, | ||
287 | (unsigned int)appl_ptr); | ||
288 | } | ||
289 | if ((jiffies - rec->firstzerotime) < 3750) { | ||
290 | rec->zero_times[(jiffies - rec->firstzerotime)]++; | ||
291 | rec->zero_times_saved++; | ||
292 | } else | ||
293 | rec->zero_times_notsaved++; | ||
294 | #endif | ||
295 | bytes = zero(substream, rec); | ||
296 | |||
297 | #ifdef SND_PCM_INDIRECT2_STAT | ||
298 | rec->zeros2hw += bytes; | ||
299 | if (bytes < 64) | ||
300 | rec->zero_sizes[bytes]++; | ||
301 | else | ||
302 | snd_printk(KERN_DEBUG | ||
303 | "STAT: %d zero Bytes copied to hardware at " | ||
304 | "once - too big to save!\n", | ||
305 | bytes); | ||
306 | #endif | ||
307 | snd_pcm_indirect2_increase_min_periods(substream, rec, 1, 0, | ||
308 | bytes); | ||
309 | return; | ||
310 | } | ||
311 | while (rec->hw_ready && (rec->sw_ready > 0)) { | ||
312 | /* sw_to_end: max. number of bytes that can be read/take from | ||
313 | * the current position (sw_data) in _one_ step | ||
314 | */ | ||
315 | unsigned int sw_to_end = rec->sw_buffer_size - rec->sw_data; | ||
316 | |||
317 | /* bytes: number of bytes we have available (for reading) */ | ||
318 | unsigned int bytes = rec->sw_ready; | ||
319 | |||
320 | if (sw_to_end < bytes) | ||
321 | bytes = sw_to_end; | ||
322 | if (!bytes) | ||
323 | break; | ||
324 | |||
325 | #ifdef SND_PCM_INDIRECT2_STAT | ||
326 | if (rec->firstbytetime == 0) | ||
327 | rec->firstbytetime = jiffies; | ||
328 | rec->lastbytetime = jiffies; | ||
329 | #endif | ||
330 | /* copy bytes from intermediate buffer position sw_data to the | ||
331 | * HW and return number of bytes actually written | ||
332 | * Furthermore, set hw_ready to 0, if the fifo isn't empty | ||
333 | * now => more could be transfered to fifo | ||
334 | */ | ||
335 | bytes = copy(substream, rec, bytes); | ||
336 | rec->bytes2hw += bytes; | ||
337 | |||
338 | #ifdef SND_PCM_INDIRECT2_STAT | ||
339 | if (bytes < 64) | ||
340 | rec->byte_sizes[bytes]++; | ||
341 | else | ||
342 | snd_printk(KERN_DEBUG | ||
343 | "STAT: %d Bytes copied to hardware at once " | ||
344 | "- too big to save!\n", | ||
345 | bytes); | ||
346 | #endif | ||
347 | /* increase sw_data by the number of actually written bytes | ||
348 | * (= number of taken bytes from intermediate buffer) | ||
349 | */ | ||
350 | rec->sw_data += bytes; | ||
351 | if (rec->sw_data == rec->sw_buffer_size) | ||
352 | rec->sw_data = 0; | ||
353 | /* now sw_data is the position where ALSA is going to write | ||
354 | * in the intermediate buffer next time = position we are going | ||
355 | * to read from next time | ||
356 | */ | ||
357 | |||
358 | snd_pcm_indirect2_increase_min_periods(substream, rec, 1, 1, | ||
359 | bytes); | ||
360 | |||
361 | /* we read bytes from intermediate buffer, so we need to say | ||
362 | * that the number of bytes ready for transfer are decreased | ||
363 | * now | ||
364 | */ | ||
365 | rec->sw_ready -= bytes; | ||
366 | } | ||
367 | return; | ||
368 | } | ||
369 | |||
370 | /* | ||
371 | * helper function for playback interrupt routine | ||
372 | */ | ||
373 | void | ||
374 | snd_pcm_indirect2_playback_interrupt(struct snd_pcm_substream *substream, | ||
375 | struct snd_pcm_indirect2 *rec, | ||
376 | snd_pcm_indirect2_copy_t copy, | ||
377 | snd_pcm_indirect2_zero_t zero) | ||
378 | { | ||
379 | #ifdef SND_PCM_INDIRECT2_STAT | ||
380 | rec->irq_occured++; | ||
381 | #endif | ||
382 | /* hardware played some bytes, so there is room again (in fifo) */ | ||
383 | rec->hw_ready = 1; | ||
384 | |||
385 | /* don't call ack() now, instead call transfer() function directly | ||
386 | * (normally called by ack() ) | ||
387 | */ | ||
388 | snd_pcm_indirect2_playback_transfer(substream, rec, copy, zero); | ||
389 | |||
390 | if (rec->min_periods >= rec->min_multiple) { | ||
391 | #ifdef SND_PCM_INDIRECT2_STAT | ||
392 | if ((rec->min_periods / rec->min_multiple) > 7) | ||
393 | snd_printk(KERN_DEBUG | ||
394 | "STAT: more than 7 (%d) mul_adds - too big " | ||
395 | "to save!\n", | ||
396 | (rec->min_periods / rec->min_multiple)); | ||
397 | else | ||
398 | rec->mul_adds[(rec->min_periods / | ||
399 | rec->min_multiple)]++; | ||
400 | rec->mul_elapsed_real += (rec->min_periods / | ||
401 | rec->min_multiple); | ||
402 | rec->mul_elapsed++; | ||
403 | #endif | ||
404 | rec->min_periods = (rec->min_periods % rec->min_multiple); | ||
405 | snd_pcm_period_elapsed(substream); | ||
406 | } | ||
407 | } | ||
408 | |||
409 | /* | ||
410 | * _internal_ helper function for capture interrupt callback | ||
411 | */ | ||
412 | static void | ||
413 | snd_pcm_indirect2_capture_transfer(struct snd_pcm_substream *substream, | ||
414 | struct snd_pcm_indirect2 *rec, | ||
415 | snd_pcm_indirect2_copy_t copy, | ||
416 | snd_pcm_indirect2_zero_t null) | ||
417 | { | ||
418 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
419 | snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr; | ||
420 | snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr; | ||
421 | |||
422 | if (diff) { | ||
423 | #ifdef SND_PCM_INDIRECT2_STAT | ||
424 | rec->lastdifftime = jiffies; | ||
425 | #endif | ||
426 | if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2)) | ||
427 | diff += runtime->boundary; | ||
428 | rec->sw_ready -= frames_to_bytes(runtime, diff); | ||
429 | rec->appl_ptr = appl_ptr; | ||
430 | } | ||
431 | /* if hardware has something, but the intermediate buffer is full | ||
432 | * => skip contents of buffer | ||
433 | */ | ||
434 | if (rec->hw_ready && (rec->sw_ready >= (int)rec->sw_buffer_size)) { | ||
435 | unsigned int bytes; | ||
436 | |||
437 | #ifdef SND_PCM_INDIRECT2_STAT | ||
438 | if (rec->firstzerotime == 0) { | ||
439 | rec->firstzerotime = jiffies; | ||
440 | snd_printk(KERN_DEBUG "STAT: (capture) " | ||
441 | "@firstzerotime: mul_elapsed: %d, " | ||
442 | "min_period_count: %d\n", | ||
443 | rec->mul_elapsed, rec->min_period_count); | ||
444 | snd_printk(KERN_DEBUG "STAT: (capture) " | ||
445 | "@firstzerotime: sw_io: %d, sw_data: %d, " | ||
446 | "appl_ptr: %u\n", | ||
447 | rec->sw_io, rec->sw_data, | ||
448 | (unsigned int)appl_ptr); | ||
449 | } | ||
450 | if ((jiffies - rec->firstzerotime) < 3750) { | ||
451 | rec->zero_times[(jiffies - rec->firstzerotime)]++; | ||
452 | rec->zero_times_saved++; | ||
453 | } else | ||
454 | rec->zero_times_notsaved++; | ||
455 | #endif | ||
456 | bytes = null(substream, rec); | ||
457 | |||
458 | #ifdef SND_PCM_INDIRECT2_STAT | ||
459 | rec->zeros2hw += bytes; | ||
460 | if (bytes < 64) | ||
461 | rec->zero_sizes[bytes]++; | ||
462 | else | ||
463 | snd_printk(KERN_DEBUG | ||
464 | "STAT: (capture) %d zero Bytes copied to " | ||
465 | "hardware at once - too big to save!\n", | ||
466 | bytes); | ||
467 | #endif | ||
468 | snd_pcm_indirect2_increase_min_periods(substream, rec, 0, 0, | ||
469 | bytes); | ||
470 | /* report an overrun */ | ||
471 | rec->sw_io = SNDRV_PCM_POS_XRUN; | ||
472 | return; | ||
473 | } | ||
474 | while (rec->hw_ready && (rec->sw_ready < (int)rec->sw_buffer_size)) { | ||
475 | /* sw_to_end: max. number of bytes that we can write to the | ||
476 | * intermediate buffer (until it's end) | ||
477 | */ | ||
478 | size_t sw_to_end = rec->sw_buffer_size - rec->sw_data; | ||
479 | |||
480 | /* bytes: max. number of bytes, which may be copied to the | ||
481 | * intermediate buffer without overflow (in _one_ step) | ||
482 | */ | ||
483 | size_t bytes = rec->sw_buffer_size - rec->sw_ready; | ||
484 | |||
485 | /* limit number of bytes (for transfer) by available room in | ||
486 | * the intermediate buffer | ||
487 | */ | ||
488 | if (sw_to_end < bytes) | ||
489 | bytes = sw_to_end; | ||
490 | if (!bytes) | ||
491 | break; | ||
492 | |||
493 | #ifdef SND_PCM_INDIRECT2_STAT | ||
494 | if (rec->firstbytetime == 0) | ||
495 | rec->firstbytetime = jiffies; | ||
496 | rec->lastbytetime = jiffies; | ||
497 | #endif | ||
498 | /* copy bytes from the intermediate buffer (position sw_data) | ||
499 | * to the HW at most and return number of bytes actually copied | ||
500 | * from HW | ||
501 | * Furthermore, set hw_ready to 0, if the fifo is empty now. | ||
502 | */ | ||
503 | bytes = copy(substream, rec, bytes); | ||
504 | rec->bytes2hw += bytes; | ||
505 | |||
506 | #ifdef SND_PCM_INDIRECT2_STAT | ||
507 | if (bytes < 64) | ||
508 | rec->byte_sizes[bytes]++; | ||
509 | else | ||
510 | snd_printk(KERN_DEBUG | ||
511 | "STAT: (capture) %d Bytes copied to " | ||
512 | "hardware at once - too big to save!\n", | ||
513 | bytes); | ||
514 | #endif | ||
515 | /* increase sw_data by the number of actually copied bytes from | ||
516 | * HW | ||
517 | */ | ||
518 | rec->sw_data += bytes; | ||
519 | if (rec->sw_data == rec->sw_buffer_size) | ||
520 | rec->sw_data = 0; | ||
521 | |||
522 | snd_pcm_indirect2_increase_min_periods(substream, rec, 0, 1, | ||
523 | bytes); | ||
524 | |||
525 | /* number of bytes in the intermediate buffer, which haven't | ||
526 | * been fetched by ALSA yet. | ||
527 | */ | ||
528 | rec->sw_ready += bytes; | ||
529 | } | ||
530 | return; | ||
531 | } | ||
532 | |||
533 | /* | ||
534 | * helper function for capture interrupt routine | ||
535 | */ | ||
536 | void | ||
537 | snd_pcm_indirect2_capture_interrupt(struct snd_pcm_substream *substream, | ||
538 | struct snd_pcm_indirect2 *rec, | ||
539 | snd_pcm_indirect2_copy_t copy, | ||
540 | snd_pcm_indirect2_zero_t null) | ||
541 | { | ||
542 | #ifdef SND_PCM_INDIRECT2_STAT | ||
543 | rec->irq_occured++; | ||
544 | #endif | ||
545 | /* hardware recorded some bytes, so there is something to read from the | ||
546 | * record fifo: | ||
547 | */ | ||
548 | rec->hw_ready = 1; | ||
549 | |||
550 | /* don't call ack() now, instead call transfer() function directly | ||
551 | * (normally called by ack() ) | ||
552 | */ | ||
553 | snd_pcm_indirect2_capture_transfer(substream, rec, copy, null); | ||
554 | |||
555 | if (rec->min_periods >= rec->min_multiple) { | ||
556 | |||
557 | #ifdef SND_PCM_INDIRECT2_STAT | ||
558 | if ((rec->min_periods / rec->min_multiple) > 7) | ||
559 | snd_printk(KERN_DEBUG | ||
560 | "STAT: more than 7 (%d) mul_adds - " | ||
561 | "too big to save!\n", | ||
562 | (rec->min_periods / rec->min_multiple)); | ||
563 | else | ||
564 | rec->mul_adds[(rec->min_periods / | ||
565 | rec->min_multiple)]++; | ||
566 | rec->mul_elapsed_real += (rec->min_periods / | ||
567 | rec->min_multiple); | ||
568 | rec->mul_elapsed++; | ||
569 | #endif | ||
570 | rec->min_periods = (rec->min_periods % rec->min_multiple); | ||
571 | snd_pcm_period_elapsed(substream); | ||
572 | } | ||
573 | } | ||
diff --git a/sound/drivers/pcm-indirect2.h b/sound/drivers/pcm-indirect2.h new file mode 100644 index 000000000000..2ea6e460f348 --- /dev/null +++ b/sound/drivers/pcm-indirect2.h | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * Helper functions for indirect PCM data transfer to a simple FIFO in | ||
3 | * hardware (small, no possibility to read "hardware io position", | ||
4 | * updating position done by interrupt, ...) | ||
5 | * | ||
6 | * Copyright (c) by 2007 Joachim Foerster <JOFT@gmx.de> | ||
7 | * | ||
8 | * Based on "pcm-indirect.h" (alsa-driver-1.0.13) by | ||
9 | * | ||
10 | * Copyright (c) by Takashi Iwai <tiwai@suse.de> | ||
11 | * Jaroslav Kysela <perex@suse.cz> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
26 | */ | ||
27 | |||
28 | #ifndef __SOUND_PCM_INDIRECT2_H | ||
29 | #define __SOUND_PCM_INDIRECT2_H | ||
30 | |||
31 | /* struct snd_pcm_substream, struct snd_pcm_runtime, snd_pcm_uframes_t */ | ||
32 | #include <sound/pcm.h> | ||
33 | |||
34 | /* Debug options for code which may be removed completely in a final version */ | ||
35 | #ifdef CONFIG_SND_DEBUG | ||
36 | #define SND_PCM_INDIRECT2_STAT /* turn on some "statistics" about the | ||
37 | * process of copying bytes from the | ||
38 | * intermediate buffer to the hardware | ||
39 | * fifo and the other way round | ||
40 | */ | ||
41 | #endif | ||
42 | |||
43 | struct snd_pcm_indirect2 { | ||
44 | unsigned int hw_buffer_size; /* Byte size of hardware buffer */ | ||
45 | int hw_ready; /* playback: 1 = hw fifo has room left, | ||
46 | * 0 = hw fifo is full | ||
47 | */ | ||
48 | unsigned int min_multiple; | ||
49 | int min_periods; /* counts number of min. periods until | ||
50 | * min_multiple is reached | ||
51 | */ | ||
52 | int min_period_count; /* counts bytes to count number of | ||
53 | * min. periods | ||
54 | */ | ||
55 | |||
56 | unsigned int sw_buffer_size; /* Byte size of software buffer */ | ||
57 | |||
58 | /* sw_data: position in intermediate buffer, where we will read (or | ||
59 | * write) from/to next time (to transfer data to/from HW) | ||
60 | */ | ||
61 | unsigned int sw_data; /* Offset to next dst (or src) in sw | ||
62 | * ring buffer | ||
63 | */ | ||
64 | /* easiest case (playback): | ||
65 | * sw_data is nearly the same as ~ runtime->control->appl_ptr, with the | ||
66 | * exception that sw_data is "behind" by the number if bytes ALSA wrote | ||
67 | * to the intermediate buffer last time. | ||
68 | * A call to ack() callback synchronizes both indirectly. | ||
69 | */ | ||
70 | |||
71 | /* We have no real sw_io pointer here. Usually sw_io is pointing to the | ||
72 | * current playback/capture position _inside_ the hardware. Devices | ||
73 | * with plain FIFOs often have no possibility to publish this position. | ||
74 | * So we say: if sw_data is updated, that means bytes were copied to | ||
75 | * the hardware, we increase sw_io by that amount, because there have | ||
76 | * to be as much bytes which were played. So sw_io will stay behind | ||
77 | * sw_data all the time and has to converge to sw_data at the end of | ||
78 | * playback. | ||
79 | */ | ||
80 | unsigned int sw_io; /* Current software pointer in bytes */ | ||
81 | |||
82 | /* sw_ready: number of bytes ALSA copied to the intermediate buffer, so | ||
83 | * it represents the number of bytes which wait for transfer to the HW | ||
84 | */ | ||
85 | int sw_ready; /* Bytes ready to be transferred to/from hw */ | ||
86 | |||
87 | /* appl_ptr: last known position of ALSA (where ALSA is going to write | ||
88 | * next time into the intermediate buffer | ||
89 | */ | ||
90 | snd_pcm_uframes_t appl_ptr; /* Last seen appl_ptr */ | ||
91 | |||
92 | unsigned int bytes2hw; | ||
93 | int check_alignment; | ||
94 | |||
95 | #ifdef SND_PCM_INDIRECT2_STAT | ||
96 | unsigned int zeros2hw; | ||
97 | unsigned int mul_elapsed; | ||
98 | unsigned int mul_elapsed_real; | ||
99 | unsigned long firstbytetime; | ||
100 | unsigned long lastbytetime; | ||
101 | unsigned long firstzerotime; | ||
102 | unsigned int byte_sizes[64]; | ||
103 | unsigned int zero_sizes[64]; | ||
104 | unsigned int min_adds[8]; | ||
105 | unsigned int mul_adds[8]; | ||
106 | unsigned int zero_times[3750]; /* = 15s */ | ||
107 | unsigned int zero_times_saved; | ||
108 | unsigned int zero_times_notsaved; | ||
109 | unsigned int irq_occured; | ||
110 | unsigned int pointer_calls; | ||
111 | unsigned int lastdifftime; | ||
112 | #endif | ||
113 | }; | ||
114 | |||
115 | typedef size_t (*snd_pcm_indirect2_copy_t) (struct snd_pcm_substream *substream, | ||
116 | struct snd_pcm_indirect2 *rec, | ||
117 | size_t bytes); | ||
118 | typedef size_t (*snd_pcm_indirect2_zero_t) (struct snd_pcm_substream *substream, | ||
119 | struct snd_pcm_indirect2 *rec); | ||
120 | |||
121 | #ifdef SND_PCM_INDIRECT2_STAT | ||
122 | void snd_pcm_indirect2_stat(struct snd_pcm_substream *substream, | ||
123 | struct snd_pcm_indirect2 *rec); | ||
124 | #endif | ||
125 | |||
126 | snd_pcm_uframes_t | ||
127 | snd_pcm_indirect2_pointer(struct snd_pcm_substream *substream, | ||
128 | struct snd_pcm_indirect2 *rec); | ||
129 | void | ||
130 | snd_pcm_indirect2_playback_interrupt(struct snd_pcm_substream *substream, | ||
131 | struct snd_pcm_indirect2 *rec, | ||
132 | snd_pcm_indirect2_copy_t copy, | ||
133 | snd_pcm_indirect2_zero_t zero); | ||
134 | void | ||
135 | snd_pcm_indirect2_capture_interrupt(struct snd_pcm_substream *substream, | ||
136 | struct snd_pcm_indirect2 *rec, | ||
137 | snd_pcm_indirect2_copy_t copy, | ||
138 | snd_pcm_indirect2_zero_t null); | ||
139 | |||
140 | #endif /* __SOUND_PCM_INDIRECT2_H */ | ||
diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c index 1b832870cc84..b1c047ec19af 100644 --- a/sound/drivers/portman2x4.c +++ b/sound/drivers/portman2x4.c | |||
@@ -37,7 +37,6 @@ | |||
37 | * - ported from alsa 0.5 to 1.0 | 37 | * - ported from alsa 0.5 to 1.0 |
38 | */ | 38 | */ |
39 | 39 | ||
40 | #include <sound/driver.h> | ||
41 | #include <linux/init.h> | 40 | #include <linux/init.h> |
42 | #include <linux/platform_device.h> | 41 | #include <linux/platform_device.h> |
43 | #include <linux/parport.h> | 42 | #include <linux/parport.h> |
@@ -797,6 +796,8 @@ static int __devinit snd_portman_probe(struct platform_device *pdev) | |||
797 | 796 | ||
798 | platform_set_drvdata(pdev, card); | 797 | platform_set_drvdata(pdev, card); |
799 | 798 | ||
799 | snd_card_set_dev(card, &pdev->dev); | ||
800 | |||
800 | /* At this point card will be usable */ | 801 | /* At this point card will be usable */ |
801 | if ((err = snd_card_register(card)) < 0) { | 802 | if ((err = snd_card_register(card)) < 0) { |
802 | snd_printd("Cannot register card\n"); | 803 | snd_printd("Cannot register card\n"); |
diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c index 65de3a755ddb..d8aab9da97c2 100644 --- a/sound/drivers/serial-u16550.c +++ b/sound/drivers/serial-u16550.c | |||
@@ -30,7 +30,6 @@ | |||
30 | * More documentation can be found in serial-u16550.txt. | 30 | * More documentation can be found in serial-u16550.txt. |
31 | */ | 31 | */ |
32 | 32 | ||
33 | #include <sound/driver.h> | ||
34 | #include <linux/init.h> | 33 | #include <linux/init.h> |
35 | #include <linux/interrupt.h> | 34 | #include <linux/interrupt.h> |
36 | #include <linux/err.h> | 35 | #include <linux/err.h> |
@@ -43,6 +42,7 @@ | |||
43 | #include <sound/initval.h> | 42 | #include <sound/initval.h> |
44 | 43 | ||
45 | #include <linux/serial_reg.h> | 44 | #include <linux/serial_reg.h> |
45 | #include <linux/jiffies.h> | ||
46 | 46 | ||
47 | #include <asm/io.h> | 47 | #include <asm/io.h> |
48 | 48 | ||
@@ -455,7 +455,7 @@ static void snd_uart16550_do_open(struct snd_uart16550 * uart) | |||
455 | | UART_IER_THRI /* Enable Transmitter holding register empty interrupt */ | 455 | | UART_IER_THRI /* Enable Transmitter holding register empty interrupt */ |
456 | ; | 456 | ; |
457 | } | 457 | } |
458 | outb(byte, uart->base + UART_IER); /* Interupt enable Register */ | 458 | outb(byte, uart->base + UART_IER); /* Interrupt enable Register */ |
459 | 459 | ||
460 | inb(uart->base + UART_LSR); /* Clear any pre-existing overrun indication */ | 460 | inb(uart->base + UART_LSR); /* Clear any pre-existing overrun indication */ |
461 | inb(uart->base + UART_IIR); /* Clear any pre-existing transmit interrupt */ | 461 | inb(uart->base + UART_IIR); /* Clear any pre-existing transmit interrupt */ |
@@ -473,7 +473,7 @@ static void snd_uart16550_do_close(struct snd_uart16550 * uart) | |||
473 | 473 | ||
474 | outb((0 & UART_IER_RDI) /* Disable Receiver data interrupt */ | 474 | outb((0 & UART_IER_RDI) /* Disable Receiver data interrupt */ |
475 | |(0 & UART_IER_THRI) /* Disable Transmitter holding register empty interrupt */ | 475 | |(0 & UART_IER_THRI) /* Disable Transmitter holding register empty interrupt */ |
476 | ,uart->base + UART_IER); /* Interupt enable Register */ | 476 | ,uart->base + UART_IER); /* Interrupt enable Register */ |
477 | 477 | ||
478 | switch (uart->adaptor) { | 478 | switch (uart->adaptor) { |
479 | default: | 479 | default: |
@@ -653,7 +653,7 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream) | |||
653 | char first; | 653 | char first; |
654 | static unsigned long lasttime = 0; | 654 | static unsigned long lasttime = 0; |
655 | 655 | ||
656 | /* Interupts are disabled during the updating of the tx_buff, | 656 | /* Interrupts are disabled during the updating of the tx_buff, |
657 | * since it is 'bad' to have two processes updating the same | 657 | * since it is 'bad' to have two processes updating the same |
658 | * variables (ie buff_in & buff_out) | 658 | * variables (ie buff_in & buff_out) |
659 | */ | 659 | */ |
@@ -694,7 +694,7 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream) | |||
694 | (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS || | 694 | (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS || |
695 | uart->adaptor == SNDRV_SERIAL_GENERIC) && | 695 | uart->adaptor == SNDRV_SERIAL_GENERIC) && |
696 | (uart->prev_out != substream->number || | 696 | (uart->prev_out != substream->number || |
697 | jiffies-lasttime > 3*HZ)) { | 697 | time_after(jiffies, lasttime + 3*HZ))) { |
698 | 698 | ||
699 | if (snd_uart16550_buffer_can_write(uart, 3)) { | 699 | if (snd_uart16550_buffer_can_write(uart, 3)) { |
700 | /* Roland Soundcanvas part selection */ | 700 | /* Roland Soundcanvas part selection */ |
diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c index 915c86773c21..f79e3614079d 100644 --- a/sound/drivers/virmidi.c +++ b/sound/drivers/virmidi.c | |||
@@ -41,7 +41,6 @@ | |||
41 | * - Run application using a midi device (eg. /dev/snd/midiC1D0) | 41 | * - Run application using a midi device (eg. /dev/snd/midiC1D0) |
42 | */ | 42 | */ |
43 | 43 | ||
44 | #include <sound/driver.h> | ||
45 | #include <linux/init.h> | 44 | #include <linux/init.h> |
46 | #include <linux/wait.h> | 45 | #include <linux/wait.h> |
47 | #include <linux/err.h> | 46 | #include <linux/err.h> |
diff --git a/sound/drivers/vx/vx_cmd.c b/sound/drivers/vx/vx_cmd.c index 7a221349f285..9529e3bf2866 100644 --- a/sound/drivers/vx/vx_cmd.c +++ b/sound/drivers/vx/vx_cmd.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <sound/core.h> | 23 | #include <sound/core.h> |
25 | #include <sound/pcm.h> | 24 | #include <sound/pcm.h> |
26 | #include <sound/vx_core.h> | 25 | #include <sound/vx_core.h> |
diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c index ed19bc17400b..99538862e342 100644 --- a/sound/drivers/vx/vx_core.c +++ b/sound/drivers/vx/vx_core.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
26 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
diff --git a/sound/drivers/vx/vx_hwdep.c b/sound/drivers/vx/vx_hwdep.c index 9a8154c9416e..1dfe6948e6ff 100644 --- a/sound/drivers/vx/vx_hwdep.c +++ b/sound/drivers/vx/vx_hwdep.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/device.h> | 23 | #include <linux/device.h> |
25 | #include <linux/firmware.h> | 24 | #include <linux/firmware.h> |
26 | #include <linux/vmalloc.h> | 25 | #include <linux/vmalloc.h> |
diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c index b8fcd79a7e11..5a347321f8c0 100644 --- a/sound/drivers/vx/vx_mixer.c +++ b/sound/drivers/vx/vx_mixer.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <sound/core.h> | 23 | #include <sound/core.h> |
25 | #include <sound/control.h> | 24 | #include <sound/control.h> |
26 | #include <sound/tlv.h> | 25 | #include <sound/tlv.h> |
@@ -439,14 +438,19 @@ static int vx_output_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele | |||
439 | { | 438 | { |
440 | struct vx_core *chip = snd_kcontrol_chip(kcontrol); | 439 | struct vx_core *chip = snd_kcontrol_chip(kcontrol); |
441 | int codec = kcontrol->id.index; | 440 | int codec = kcontrol->id.index; |
441 | unsigned int val[2], vmax; | ||
442 | |||
443 | vmax = chip->hw->output_level_max; | ||
444 | val[0] = ucontrol->value.integer.value[0]; | ||
445 | val[1] = ucontrol->value.integer.value[1]; | ||
446 | if (val[0] > vmax || val[1] > vmax) | ||
447 | return -EINVAL; | ||
442 | mutex_lock(&chip->mixer_mutex); | 448 | mutex_lock(&chip->mixer_mutex); |
443 | if (ucontrol->value.integer.value[0] != chip->output_level[codec][0] || | 449 | if (val[0] != chip->output_level[codec][0] || |
444 | ucontrol->value.integer.value[1] != chip->output_level[codec][1]) { | 450 | val[1] != chip->output_level[codec][1]) { |
445 | vx_set_analog_output_level(chip, codec, | 451 | vx_set_analog_output_level(chip, codec, val[0], val[1]); |
446 | ucontrol->value.integer.value[0], | 452 | chip->output_level[codec][0] = val[0]; |
447 | ucontrol->value.integer.value[1]); | 453 | chip->output_level[codec][1] = val[1]; |
448 | chip->output_level[codec][0] = ucontrol->value.integer.value[0]; | ||
449 | chip->output_level[codec][1] = ucontrol->value.integer.value[1]; | ||
450 | mutex_unlock(&chip->mixer_mutex); | 454 | mutex_unlock(&chip->mixer_mutex); |
451 | return 1; | 455 | return 1; |
452 | } | 456 | } |
@@ -506,6 +510,14 @@ static int vx_audio_src_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v | |||
506 | static int vx_audio_src_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 510 | static int vx_audio_src_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
507 | { | 511 | { |
508 | struct vx_core *chip = snd_kcontrol_chip(kcontrol); | 512 | struct vx_core *chip = snd_kcontrol_chip(kcontrol); |
513 | |||
514 | if (chip->type >= VX_TYPE_VXPOCKET) { | ||
515 | if (ucontrol->value.enumerated.item[0] > 2) | ||
516 | return -EINVAL; | ||
517 | } else { | ||
518 | if (ucontrol->value.enumerated.item[0] > 1) | ||
519 | return -EINVAL; | ||
520 | } | ||
509 | mutex_lock(&chip->mixer_mutex); | 521 | mutex_lock(&chip->mixer_mutex); |
510 | if (chip->audio_source_target != ucontrol->value.enumerated.item[0]) { | 522 | if (chip->audio_source_target != ucontrol->value.enumerated.item[0]) { |
511 | chip->audio_source_target = ucontrol->value.enumerated.item[0]; | 523 | chip->audio_source_target = ucontrol->value.enumerated.item[0]; |
@@ -554,6 +566,9 @@ static int vx_clock_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ | |||
554 | static int vx_clock_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 566 | static int vx_clock_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
555 | { | 567 | { |
556 | struct vx_core *chip = snd_kcontrol_chip(kcontrol); | 568 | struct vx_core *chip = snd_kcontrol_chip(kcontrol); |
569 | |||
570 | if (ucontrol->value.enumerated.item[0] > 2) | ||
571 | return -EINVAL; | ||
557 | mutex_lock(&chip->mixer_mutex); | 572 | mutex_lock(&chip->mixer_mutex); |
558 | if (chip->clock_mode != ucontrol->value.enumerated.item[0]) { | 573 | if (chip->clock_mode != ucontrol->value.enumerated.item[0]) { |
559 | chip->clock_mode = ucontrol->value.enumerated.item[0]; | 574 | chip->clock_mode = ucontrol->value.enumerated.item[0]; |
@@ -603,12 +618,17 @@ static int vx_audio_gain_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ | |||
603 | struct vx_core *chip = snd_kcontrol_chip(kcontrol); | 618 | struct vx_core *chip = snd_kcontrol_chip(kcontrol); |
604 | int audio = kcontrol->private_value & 0xff; | 619 | int audio = kcontrol->private_value & 0xff; |
605 | int capture = (kcontrol->private_value >> 8) & 1; | 620 | int capture = (kcontrol->private_value >> 8) & 1; |
621 | unsigned int val[2]; | ||
606 | 622 | ||
623 | val[0] = ucontrol->value.integer.value[0]; | ||
624 | val[1] = ucontrol->value.integer.value[1]; | ||
625 | if (val[0] > CVAL_MAX || val[1] > CVAL_MAX) | ||
626 | return -EINVAL; | ||
607 | mutex_lock(&chip->mixer_mutex); | 627 | mutex_lock(&chip->mixer_mutex); |
608 | if (ucontrol->value.integer.value[0] != chip->audio_gain[capture][audio] || | 628 | if (val[0] != chip->audio_gain[capture][audio] || |
609 | ucontrol->value.integer.value[1] != chip->audio_gain[capture][audio+1]) { | 629 | val[1] != chip->audio_gain[capture][audio+1]) { |
610 | vx_set_audio_gain(chip, audio, capture, ucontrol->value.integer.value[0]); | 630 | vx_set_audio_gain(chip, audio, capture, val[0]); |
611 | vx_set_audio_gain(chip, audio+1, capture, ucontrol->value.integer.value[1]); | 631 | vx_set_audio_gain(chip, audio+1, capture, val[1]); |
612 | mutex_unlock(&chip->mixer_mutex); | 632 | mutex_unlock(&chip->mixer_mutex); |
613 | return 1; | 633 | return 1; |
614 | } | 634 | } |
@@ -632,13 +652,19 @@ static int vx_audio_monitor_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el | |||
632 | { | 652 | { |
633 | struct vx_core *chip = snd_kcontrol_chip(kcontrol); | 653 | struct vx_core *chip = snd_kcontrol_chip(kcontrol); |
634 | int audio = kcontrol->private_value & 0xff; | 654 | int audio = kcontrol->private_value & 0xff; |
655 | unsigned int val[2]; | ||
656 | |||
657 | val[0] = ucontrol->value.integer.value[0]; | ||
658 | val[1] = ucontrol->value.integer.value[1]; | ||
659 | if (val[0] > CVAL_MAX || val[1] > CVAL_MAX) | ||
660 | return -EINVAL; | ||
635 | 661 | ||
636 | mutex_lock(&chip->mixer_mutex); | 662 | mutex_lock(&chip->mixer_mutex); |
637 | if (ucontrol->value.integer.value[0] != chip->audio_monitor[audio] || | 663 | if (val[0] != chip->audio_monitor[audio] || |
638 | ucontrol->value.integer.value[1] != chip->audio_monitor[audio+1]) { | 664 | val[1] != chip->audio_monitor[audio+1]) { |
639 | vx_set_monitor_level(chip, audio, ucontrol->value.integer.value[0], | 665 | vx_set_monitor_level(chip, audio, val[0], |
640 | chip->audio_monitor_active[audio]); | 666 | chip->audio_monitor_active[audio]); |
641 | vx_set_monitor_level(chip, audio+1, ucontrol->value.integer.value[1], | 667 | vx_set_monitor_level(chip, audio+1, val[1], |
642 | chip->audio_monitor_active[audio+1]); | 668 | chip->audio_monitor_active[audio+1]); |
643 | mutex_unlock(&chip->mixer_mutex); | 669 | mutex_unlock(&chip->mixer_mutex); |
644 | return 1; | 670 | return 1; |
@@ -669,8 +695,10 @@ static int vx_audio_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_va | |||
669 | mutex_lock(&chip->mixer_mutex); | 695 | mutex_lock(&chip->mixer_mutex); |
670 | if (ucontrol->value.integer.value[0] != chip->audio_active[audio] || | 696 | if (ucontrol->value.integer.value[0] != chip->audio_active[audio] || |
671 | ucontrol->value.integer.value[1] != chip->audio_active[audio+1]) { | 697 | ucontrol->value.integer.value[1] != chip->audio_active[audio+1]) { |
672 | vx_set_audio_switch(chip, audio, ucontrol->value.integer.value[0]); | 698 | vx_set_audio_switch(chip, audio, |
673 | vx_set_audio_switch(chip, audio+1, ucontrol->value.integer.value[1]); | 699 | !!ucontrol->value.integer.value[0]); |
700 | vx_set_audio_switch(chip, audio+1, | ||
701 | !!ucontrol->value.integer.value[1]); | ||
674 | mutex_unlock(&chip->mixer_mutex); | 702 | mutex_unlock(&chip->mixer_mutex); |
675 | return 1; | 703 | return 1; |
676 | } | 704 | } |
@@ -699,9 +727,9 @@ static int vx_monitor_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ | |||
699 | if (ucontrol->value.integer.value[0] != chip->audio_monitor_active[audio] || | 727 | if (ucontrol->value.integer.value[0] != chip->audio_monitor_active[audio] || |
700 | ucontrol->value.integer.value[1] != chip->audio_monitor_active[audio+1]) { | 728 | ucontrol->value.integer.value[1] != chip->audio_monitor_active[audio+1]) { |
701 | vx_set_monitor_level(chip, audio, chip->audio_monitor[audio], | 729 | vx_set_monitor_level(chip, audio, chip->audio_monitor[audio], |
702 | ucontrol->value.integer.value[0]); | 730 | !!ucontrol->value.integer.value[0]); |
703 | vx_set_monitor_level(chip, audio+1, chip->audio_monitor[audio+1], | 731 | vx_set_monitor_level(chip, audio+1, chip->audio_monitor[audio+1], |
704 | ucontrol->value.integer.value[1]); | 732 | !!ucontrol->value.integer.value[1]); |
705 | mutex_unlock(&chip->mixer_mutex); | 733 | mutex_unlock(&chip->mixer_mutex); |
706 | return 1; | 734 | return 1; |
707 | } | 735 | } |
diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index 7e65a103fbb2..fdbf86571b1f 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c | |||
@@ -45,7 +45,6 @@ | |||
45 | * - scheduled action on the stream. | 45 | * - scheduled action on the stream. |
46 | */ | 46 | */ |
47 | 47 | ||
48 | #include <sound/driver.h> | ||
49 | #include <linux/slab.h> | 48 | #include <linux/slab.h> |
50 | #include <linux/vmalloc.h> | 49 | #include <linux/vmalloc.h> |
51 | #include <linux/delay.h> | 50 | #include <linux/delay.h> |
diff --git a/sound/drivers/vx/vx_uer.c b/sound/drivers/vx/vx_uer.c index 7400306b7f28..fb8932af888d 100644 --- a/sound/drivers/vx/vx_uer.c +++ b/sound/drivers/vx/vx_uer.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <sound/core.h> | 24 | #include <sound/core.h> |
26 | #include <sound/vx_core.h> | 25 | #include <sound/vx_core.h> |
diff --git a/sound/i2c/cs8427.c b/sound/i2c/cs8427.c index 744366b72345..e57e9cbe6a0f 100644 --- a/sound/i2c/cs8427.c +++ b/sound/i2c/cs8427.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
25 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
26 | #include <linux/init.h> | 25 | #include <linux/init.h> |
diff --git a/sound/i2c/i2c.c b/sound/i2c/i2c.c index 1e58a963b2a7..b1e74e40cba0 100644 --- a/sound/i2c/i2c.c +++ b/sound/i2c/i2c.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
26 | #include <linux/string.h> | 25 | #include <linux/string.h> |
diff --git a/sound/i2c/l3/uda1341.c b/sound/i2c/l3/uda1341.c index b074fdddea55..bfa5d2c3608b 100644 --- a/sound/i2c/l3/uda1341.c +++ b/sound/i2c/l3/uda1341.c | |||
@@ -19,7 +19,6 @@ | |||
19 | 19 | ||
20 | /* $Id: uda1341.c,v 1.18 2005/11/17 14:17:21 tiwai Exp $ */ | 20 | /* $Id: uda1341.c,v 1.18 2005/11/17 14:17:21 tiwai Exp $ */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/module.h> | 22 | #include <linux/module.h> |
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <linux/types.h> | 24 | #include <linux/types.h> |
diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c index facde46f957a..15061bd72776 100644 --- a/sound/i2c/other/ak4114.c +++ b/sound/i2c/other/ak4114.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
25 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
26 | #include <sound/core.h> | 25 | #include <sound/core.h> |
diff --git a/sound/i2c/other/ak4117.c b/sound/i2c/other/ak4117.c index ee1585aec99b..f350835ade96 100644 --- a/sound/i2c/other/ak4117.c +++ b/sound/i2c/other/ak4117.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
25 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
26 | #include <sound/core.h> | 25 | #include <sound/core.h> |
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c index de03f689fa2e..35fbbf2cb9fa 100644 --- a/sound/i2c/other/ak4xxx-adda.c +++ b/sound/i2c/other/ak4xxx-adda.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <asm/io.h> | 24 | #include <asm/io.h> |
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
27 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
@@ -293,6 +292,11 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) | |||
293 | case SND_AK5365: | 292 | case SND_AK5365: |
294 | /* FIXME: any init sequence? */ | 293 | /* FIXME: any init sequence? */ |
295 | return; | 294 | return; |
295 | case NON_AKM: | ||
296 | /* fake value for non-akm codecs using akm infrastructure | ||
297 | * (e.g. of ice1724) - certainly FIXME | ||
298 | */ | ||
299 | return; | ||
296 | default: | 300 | default: |
297 | snd_BUG(); | 301 | snd_BUG(); |
298 | return; | 302 | return; |
@@ -377,8 +381,11 @@ static int put_ak_reg(struct snd_kcontrol *kcontrol, int addr, | |||
377 | static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol, | 381 | static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol, |
378 | struct snd_ctl_elem_value *ucontrol) | 382 | struct snd_ctl_elem_value *ucontrol) |
379 | { | 383 | { |
380 | return put_ak_reg(kcontrol, AK_GET_ADDR(kcontrol->private_value), | 384 | unsigned int mask = AK_GET_MASK(kcontrol->private_value); |
381 | ucontrol->value.integer.value[0]); | 385 | unsigned int val = ucontrol->value.integer.value[0]; |
386 | if (val > mask) | ||
387 | return -EINVAL; | ||
388 | return put_ak_reg(kcontrol, AK_GET_ADDR(kcontrol->private_value), val); | ||
382 | } | 389 | } |
383 | 390 | ||
384 | static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol, | 391 | static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol, |
@@ -409,11 +416,16 @@ static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol, | |||
409 | struct snd_ctl_elem_value *ucontrol) | 416 | struct snd_ctl_elem_value *ucontrol) |
410 | { | 417 | { |
411 | int addr = AK_GET_ADDR(kcontrol->private_value); | 418 | int addr = AK_GET_ADDR(kcontrol->private_value); |
419 | unsigned int mask = AK_GET_MASK(kcontrol->private_value); | ||
420 | unsigned int val[2]; | ||
412 | int change; | 421 | int change; |
413 | 422 | ||
414 | change = put_ak_reg(kcontrol, addr, ucontrol->value.integer.value[0]); | 423 | val[0] = ucontrol->value.integer.value[0]; |
415 | change |= put_ak_reg(kcontrol, addr + 1, | 424 | val[1] = ucontrol->value.integer.value[1]; |
416 | ucontrol->value.integer.value[1]); | 425 | if (val[0] > mask || val[1] > mask) |
426 | return -EINVAL; | ||
427 | change = put_ak_reg(kcontrol, addr, val[0]); | ||
428 | change |= put_ak_reg(kcontrol, addr + 1, val[1]); | ||
417 | return change; | 429 | return change; |
418 | } | 430 | } |
419 | 431 | ||
@@ -508,6 +520,18 @@ static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol, | |||
508 | 520 | ||
509 | #define AK5365_NUM_INPUTS 5 | 521 | #define AK5365_NUM_INPUTS 5 |
510 | 522 | ||
523 | static int ak4xxx_capture_num_inputs(struct snd_akm4xxx *ak, int mixer_ch) | ||
524 | { | ||
525 | int num_names; | ||
526 | const char **input_names; | ||
527 | |||
528 | input_names = ak->adc_info[mixer_ch].input_names; | ||
529 | num_names = 0; | ||
530 | while (num_names < AK5365_NUM_INPUTS && input_names[num_names]) | ||
531 | ++num_names; | ||
532 | return num_names; | ||
533 | } | ||
534 | |||
511 | static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol, | 535 | static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol, |
512 | struct snd_ctl_elem_info *uinfo) | 536 | struct snd_ctl_elem_info *uinfo) |
513 | { | 537 | { |
@@ -516,18 +540,16 @@ static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol, | |||
516 | const char **input_names; | 540 | const char **input_names; |
517 | int num_names, idx; | 541 | int num_names, idx; |
518 | 542 | ||
519 | input_names = ak->adc_info[mixer_ch].input_names; | 543 | num_names = ak4xxx_capture_num_inputs(ak, mixer_ch); |
520 | 544 | if (!num_names) | |
521 | num_names = 0; | 545 | return -EINVAL; |
522 | while (num_names < AK5365_NUM_INPUTS && input_names[num_names]) | ||
523 | ++num_names; | ||
524 | |||
525 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 546 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
526 | uinfo->count = 1; | 547 | uinfo->count = 1; |
527 | uinfo->value.enumerated.items = num_names; | 548 | uinfo->value.enumerated.items = num_names; |
528 | idx = uinfo->value.enumerated.item; | 549 | idx = uinfo->value.enumerated.item; |
529 | if (idx >= num_names) | 550 | if (idx >= num_names) |
530 | return -EINVAL; | 551 | return -EINVAL; |
552 | input_names = ak->adc_info[mixer_ch].input_names; | ||
531 | strncpy(uinfo->value.enumerated.name, input_names[idx], | 553 | strncpy(uinfo->value.enumerated.name, input_names[idx], |
532 | sizeof(uinfo->value.enumerated.name)); | 554 | sizeof(uinfo->value.enumerated.name)); |
533 | return 0; | 555 | return 0; |
@@ -551,10 +573,15 @@ static int ak4xxx_capture_source_put(struct snd_kcontrol *kcontrol, | |||
551 | struct snd_ctl_elem_value *ucontrol) | 573 | struct snd_ctl_elem_value *ucontrol) |
552 | { | 574 | { |
553 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | 575 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); |
576 | int mixer_ch = AK_GET_SHIFT(kcontrol->private_value); | ||
554 | int chip = AK_GET_CHIP(kcontrol->private_value); | 577 | int chip = AK_GET_CHIP(kcontrol->private_value); |
555 | int addr = AK_GET_ADDR(kcontrol->private_value); | 578 | int addr = AK_GET_ADDR(kcontrol->private_value); |
556 | int mask = AK_GET_MASK(kcontrol->private_value); | 579 | int mask = AK_GET_MASK(kcontrol->private_value); |
557 | unsigned char oval, val; | 580 | unsigned char oval, val; |
581 | int num_names = ak4xxx_capture_num_inputs(ak, mixer_ch); | ||
582 | |||
583 | if (ucontrol->value.enumerated.item[0] >= num_names) | ||
584 | return -EINVAL; | ||
558 | 585 | ||
559 | oval = snd_akm4xxx_get(ak, chip, addr); | 586 | oval = snd_akm4xxx_get(ak, chip, addr); |
560 | val = oval & ~mask; | 587 | val = oval & ~mask; |
diff --git a/sound/i2c/other/pt2258.c b/sound/i2c/other/pt2258.c index 00c83d8b32b1..797d3a6687eb 100644 --- a/sound/i2c/other/pt2258.c +++ b/sound/i2c/other/pt2258.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <sound/core.h> | 22 | #include <sound/core.h> |
24 | #include <sound/control.h> | 23 | #include <sound/control.h> |
25 | #include <sound/tlv.h> | 24 | #include <sound/tlv.h> |
@@ -113,6 +112,8 @@ static int pt2258_stereo_volume_put(struct snd_kcontrol *kcontrol, | |||
113 | 112 | ||
114 | val0 = 79 - ucontrol->value.integer.value[0]; | 113 | val0 = 79 - ucontrol->value.integer.value[0]; |
115 | val1 = 79 - ucontrol->value.integer.value[1]; | 114 | val1 = 79 - ucontrol->value.integer.value[1]; |
115 | if (val0 < 0 || val0 > 79 || val1 < 0 || val1 > 79) | ||
116 | return -EINVAL; | ||
116 | if (val0 == pt->volume[base] && val1 == pt->volume[base + 1]) | 117 | if (val0 == pt->volume[base] && val1 == pt->volume[base + 1]) |
117 | return 0; | 118 | return 0; |
118 | 119 | ||
diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c index 37c47fb95aca..87e3aefeddc3 100644 --- a/sound/i2c/other/tea575x-tuner.c +++ b/sound/i2c/other/tea575x-tuner.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <asm/io.h> | 23 | #include <asm/io.h> |
25 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
26 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
@@ -159,6 +158,10 @@ static int snd_tea575x_ioctl(struct inode *inode, struct file *file, | |||
159 | struct video_audio v; | 158 | struct video_audio v; |
160 | if(copy_from_user(&v, arg, sizeof(v))) | 159 | if(copy_from_user(&v, arg, sizeof(v))) |
161 | return -EFAULT; | 160 | return -EFAULT; |
161 | if (tea->ops->mute) | ||
162 | tea->ops->mute(tea, | ||
163 | (v.flags & | ||
164 | VIDEO_AUDIO_MUTE) ? 1 : 0); | ||
162 | if(v.audio) | 165 | if(v.audio) |
163 | return -EINVAL; | 166 | return -EINVAL; |
164 | return 0; | 167 | return 0; |
@@ -206,6 +209,10 @@ void snd_tea575x_init(struct snd_tea575x *tea) | |||
206 | tea->freq = 90500 * 16; /* 90.5Mhz default */ | 209 | tea->freq = 90500 * 16; /* 90.5Mhz default */ |
207 | 210 | ||
208 | snd_tea575x_set_freq(tea); | 211 | snd_tea575x_set_freq(tea); |
212 | |||
213 | /* mute on init */ | ||
214 | if (tea->ops->mute) | ||
215 | tea->ops->mute(tea, 1); | ||
209 | } | 216 | } |
210 | 217 | ||
211 | void snd_tea575x_exit(struct snd_tea575x *tea) | 218 | void snd_tea575x_exit(struct snd_tea575x *tea) |
diff --git a/sound/i2c/tea6330t.c b/sound/i2c/tea6330t.c index 9bab744af0ef..0e3a9f2c5297 100644 --- a/sound/i2c/tea6330t.c +++ b/sound/i2c/tea6330t.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
26 | #include <sound/core.h> | 25 | #include <sound/core.h> |
diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c index fc88a31da6f5..68f1260b5602 100644 --- a/sound/isa/ad1816a/ad1816a.c +++ b/sound/isa/ad1816a/ad1816a.c | |||
@@ -18,7 +18,6 @@ | |||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <sound/driver.h> | ||
22 | #include <linux/init.h> | 21 | #include <linux/init.h> |
23 | #include <linux/time.h> | 22 | #include <linux/time.h> |
24 | #include <linux/wait.h> | 23 | #include <linux/wait.h> |
@@ -61,20 +60,6 @@ module_param_array(id, charp, NULL, 0444); | |||
61 | MODULE_PARM_DESC(id, "ID string for ad1816a based soundcard."); | 60 | MODULE_PARM_DESC(id, "ID string for ad1816a based soundcard."); |
62 | module_param_array(enable, bool, NULL, 0444); | 61 | module_param_array(enable, bool, NULL, 0444); |
63 | MODULE_PARM_DESC(enable, "Enable ad1816a based soundcard."); | 62 | MODULE_PARM_DESC(enable, "Enable ad1816a based soundcard."); |
64 | module_param_array(port, long, NULL, 0444); | ||
65 | MODULE_PARM_DESC(port, "Port # for ad1816a driver."); | ||
66 | module_param_array(mpu_port, long, NULL, 0444); | ||
67 | MODULE_PARM_DESC(mpu_port, "MPU-401 port # for ad1816a driver."); | ||
68 | module_param_array(fm_port, long, NULL, 0444); | ||
69 | MODULE_PARM_DESC(fm_port, "FM port # for ad1816a driver."); | ||
70 | module_param_array(irq, int, NULL, 0444); | ||
71 | MODULE_PARM_DESC(irq, "IRQ # for ad1816a driver."); | ||
72 | module_param_array(mpu_irq, int, NULL, 0444); | ||
73 | MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for ad1816a driver."); | ||
74 | module_param_array(dma1, int, NULL, 0444); | ||
75 | MODULE_PARM_DESC(dma1, "1st DMA # for ad1816a driver."); | ||
76 | module_param_array(dma2, int, NULL, 0444); | ||
77 | MODULE_PARM_DESC(dma2, "2nd DMA # for ad1816a driver."); | ||
78 | module_param_array(clockfreq, int, NULL, 0444); | 63 | module_param_array(clockfreq, int, NULL, 0444); |
79 | MODULE_PARM_DESC(clockfreq, "Clock frequency for ad1816a driver (default = 0)."); | 64 | MODULE_PARM_DESC(clockfreq, "Clock frequency for ad1816a driver (default = 0)."); |
80 | 65 | ||
@@ -117,16 +102,12 @@ static int __devinit snd_card_ad1816a_pnp(int dev, struct snd_card_ad1816a *acar | |||
117 | const struct pnp_card_device_id *id) | 102 | const struct pnp_card_device_id *id) |
118 | { | 103 | { |
119 | struct pnp_dev *pdev; | 104 | struct pnp_dev *pdev; |
120 | struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL); | ||
121 | int err; | 105 | int err; |
122 | 106 | ||
123 | if (!cfg) | ||
124 | return -ENOMEM; | ||
125 | acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL); | 107 | acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL); |
126 | if (acard->dev == NULL) { | 108 | if (acard->dev == NULL) |
127 | kfree(cfg); | ||
128 | return -EBUSY; | 109 | return -EBUSY; |
129 | } | 110 | |
130 | acard->devmpu = pnp_request_card_device(card, id->devs[1].id, NULL); | 111 | acard->devmpu = pnp_request_card_device(card, id->devs[1].id, NULL); |
131 | if (acard->devmpu == NULL) { | 112 | if (acard->devmpu == NULL) { |
132 | mpu_port[dev] = -1; | 113 | mpu_port[dev] = -1; |
@@ -134,25 +115,10 @@ static int __devinit snd_card_ad1816a_pnp(int dev, struct snd_card_ad1816a *acar | |||
134 | } | 115 | } |
135 | 116 | ||
136 | pdev = acard->dev; | 117 | pdev = acard->dev; |
137 | pnp_init_resource_table(cfg); | 118 | |
138 | |||
139 | if (port[dev] != SNDRV_AUTO_PORT) | ||
140 | pnp_resource_change(&cfg->port_resource[2], port[dev], 16); | ||
141 | if (fm_port[dev] != SNDRV_AUTO_PORT) | ||
142 | pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4); | ||
143 | if (dma1[dev] != SNDRV_AUTO_DMA) | ||
144 | pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1); | ||
145 | if (dma2[dev] != SNDRV_AUTO_DMA) | ||
146 | pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1); | ||
147 | if (irq[dev] != SNDRV_AUTO_IRQ) | ||
148 | pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1); | ||
149 | |||
150 | if (pnp_manual_config_dev(pdev, cfg, 0) < 0) | ||
151 | snd_printk(KERN_ERR PFX "AUDIO the requested resources are invalid, using auto config\n"); | ||
152 | err = pnp_activate_dev(pdev); | 119 | err = pnp_activate_dev(pdev); |
153 | if (err < 0) { | 120 | if (err < 0) { |
154 | printk(KERN_ERR PFX "AUDIO PnP configure failure\n"); | 121 | printk(KERN_ERR PFX "AUDIO PnP configure failure\n"); |
155 | kfree(cfg); | ||
156 | return -EBUSY; | 122 | return -EBUSY; |
157 | } | 123 | } |
158 | 124 | ||
@@ -162,20 +128,11 @@ static int __devinit snd_card_ad1816a_pnp(int dev, struct snd_card_ad1816a *acar | |||
162 | dma2[dev] = pnp_dma(pdev, 1); | 128 | dma2[dev] = pnp_dma(pdev, 1); |
163 | irq[dev] = pnp_irq(pdev, 0); | 129 | irq[dev] = pnp_irq(pdev, 0); |
164 | 130 | ||
165 | if (acard->devmpu == NULL) { | 131 | if (acard->devmpu == NULL) |
166 | kfree(cfg); | ||
167 | return 0; | 132 | return 0; |
168 | } | ||
169 | pdev = acard->devmpu; | ||
170 | pnp_init_resource_table(cfg); | ||
171 | 133 | ||
172 | if (mpu_port[dev] != SNDRV_AUTO_PORT) | 134 | pdev = acard->devmpu; |
173 | pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2); | ||
174 | if (mpu_irq[dev] != SNDRV_AUTO_IRQ) | ||
175 | pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1); | ||
176 | 135 | ||
177 | if (pnp_manual_config_dev(pdev, cfg, 0) < 0) | ||
178 | snd_printk(KERN_ERR PFX "AUDIO the requested resources are invalid, using auto config\n"); | ||
179 | err = pnp_activate_dev(pdev); | 136 | err = pnp_activate_dev(pdev); |
180 | if (err < 0) { | 137 | if (err < 0) { |
181 | printk(KERN_ERR PFX "MPU401 PnP configure failure\n"); | 138 | printk(KERN_ERR PFX "MPU401 PnP configure failure\n"); |
@@ -186,7 +143,6 @@ static int __devinit snd_card_ad1816a_pnp(int dev, struct snd_card_ad1816a *acar | |||
186 | mpu_irq[dev] = pnp_irq(pdev, 0); | 143 | mpu_irq[dev] = pnp_irq(pdev, 0); |
187 | } | 144 | } |
188 | 145 | ||
189 | kfree(cfg); | ||
190 | return 0; | 146 | return 0; |
191 | } | 147 | } |
192 | 148 | ||
diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c index cf18fe4617a1..4b8dfe2e3dcb 100644 --- a/sound/isa/ad1816a/ad1816a_lib.c +++ b/sound/isa/ad1816a/ad1816a_lib.c | |||
@@ -17,7 +17,6 @@ | |||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <sound/driver.h> | ||
21 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
22 | #include <linux/init.h> | 21 | #include <linux/init.h> |
23 | #include <linux/interrupt.h> | 22 | #include <linux/interrupt.h> |
diff --git a/sound/isa/ad1848/ad1848.c b/sound/isa/ad1848/ad1848.c index a4710b5e214c..5f5271efdc59 100644 --- a/sound/isa/ad1848/ad1848.c +++ b/sound/isa/ad1848/ad1848.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <linux/err.h> | 25 | #include <linux/err.h> |
27 | #include <linux/isa.h> | 26 | #include <linux/isa.h> |
diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c index a901cd1ee692..630c90f9ee50 100644 --- a/sound/isa/ad1848/ad1848_lib.c +++ b/sound/isa/ad1848/ad1848_lib.c | |||
@@ -20,7 +20,6 @@ | |||
20 | */ | 20 | */ |
21 | 21 | ||
22 | #define SNDRV_MAIN_OBJECT_FILE | 22 | #define SNDRV_MAIN_OBJECT_FILE |
23 | #include <sound/driver.h> | ||
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
@@ -213,7 +212,7 @@ static void snd_ad1848_mce_down(struct snd_ad1848 *chip) | |||
213 | for (timeout = 12000; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD1848_INIT); timeout--) | 212 | for (timeout = 12000; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD1848_INIT); timeout--) |
214 | udelay(100); | 213 | udelay(100); |
215 | 214 | ||
216 | snd_printdd("(1) timeout = %d\n", timeout); | 215 | snd_printdd("(1) timeout = %ld\n", timeout); |
217 | 216 | ||
218 | #ifdef CONFIG_SND_DEBUG | 217 | #ifdef CONFIG_SND_DEBUG |
219 | if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT) | 218 | if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT) |
diff --git a/sound/isa/adlib.c b/sound/isa/adlib.c index d68720724c91..efa8c80d05b6 100644 --- a/sound/isa/adlib.c +++ b/sound/isa/adlib.c | |||
@@ -2,7 +2,6 @@ | |||
2 | * AdLib FM card driver. | 2 | * AdLib FM card driver. |
3 | */ | 3 | */ |
4 | 4 | ||
5 | #include <sound/driver.h> | ||
6 | #include <linux/kernel.h> | 5 | #include <linux/kernel.h> |
7 | #include <linux/module.h> | 6 | #include <linux/module.h> |
8 | #include <linux/isa.h> | 7 | #include <linux/isa.h> |
diff --git a/sound/isa/als100.c b/sound/isa/als100.c index f2bcfb2cf5f5..f1ce30f379c9 100644 --- a/sound/isa/als100.c +++ b/sound/isa/als100.c | |||
@@ -20,7 +20,6 @@ | |||
20 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <linux/wait.h> | 24 | #include <linux/wait.h> |
26 | #include <linux/time.h> | 25 | #include <linux/time.h> |
@@ -63,20 +62,6 @@ module_param_array(id, charp, NULL, 0444); | |||
63 | MODULE_PARM_DESC(id, "ID string for als100 based soundcard."); | 62 | MODULE_PARM_DESC(id, "ID string for als100 based soundcard."); |
64 | module_param_array(enable, bool, NULL, 0444); | 63 | module_param_array(enable, bool, NULL, 0444); |
65 | MODULE_PARM_DESC(enable, "Enable als100 based soundcard."); | 64 | MODULE_PARM_DESC(enable, "Enable als100 based soundcard."); |
66 | module_param_array(port, long, NULL, 0444); | ||
67 | MODULE_PARM_DESC(port, "Port # for als100 driver."); | ||
68 | module_param_array(mpu_port, long, NULL, 0444); | ||
69 | MODULE_PARM_DESC(mpu_port, "MPU-401 port # for als100 driver."); | ||
70 | module_param_array(fm_port, long, NULL, 0444); | ||
71 | MODULE_PARM_DESC(fm_port, "FM port # for als100 driver."); | ||
72 | module_param_array(irq, int, NULL, 0444); | ||
73 | MODULE_PARM_DESC(irq, "IRQ # for als100 driver."); | ||
74 | module_param_array(mpu_irq, int, NULL, 0444); | ||
75 | MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for als100 driver."); | ||
76 | module_param_array(dma8, int, NULL, 0444); | ||
77 | MODULE_PARM_DESC(dma8, "8-bit DMA # for als100 driver."); | ||
78 | module_param_array(dma16, int, NULL, 0444); | ||
79 | MODULE_PARM_DESC(dma16, "16-bit DMA # for als100 driver."); | ||
80 | 65 | ||
81 | struct snd_card_als100 { | 66 | struct snd_card_als100 { |
82 | int dev_no; | 67 | int dev_no; |
@@ -111,38 +96,20 @@ static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard, | |||
111 | const struct pnp_card_device_id *id) | 96 | const struct pnp_card_device_id *id) |
112 | { | 97 | { |
113 | struct pnp_dev *pdev; | 98 | struct pnp_dev *pdev; |
114 | struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL); | ||
115 | int err; | 99 | int err; |
116 | 100 | ||
117 | if (!cfg) | ||
118 | return -ENOMEM; | ||
119 | acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL); | 101 | acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL); |
120 | if (acard->dev == NULL) { | 102 | if (acard->dev == NULL) |
121 | kfree(cfg); | ||
122 | return -ENODEV; | 103 | return -ENODEV; |
123 | } | 104 | |
124 | acard->devmpu = pnp_request_card_device(card, id->devs[1].id, acard->dev); | 105 | acard->devmpu = pnp_request_card_device(card, id->devs[1].id, acard->dev); |
125 | acard->devopl = pnp_request_card_device(card, id->devs[2].id, acard->dev); | 106 | acard->devopl = pnp_request_card_device(card, id->devs[2].id, acard->dev); |
126 | 107 | ||
127 | pdev = acard->dev; | 108 | pdev = acard->dev; |
128 | 109 | ||
129 | pnp_init_resource_table(cfg); | ||
130 | |||
131 | /* override resources */ | ||
132 | if (port[dev] != SNDRV_AUTO_PORT) | ||
133 | pnp_resource_change(&cfg->port_resource[0], port[dev], 16); | ||
134 | if (dma8[dev] != SNDRV_AUTO_DMA) | ||
135 | pnp_resource_change(&cfg->dma_resource[0], dma8[dev], 1); | ||
136 | if (dma16[dev] != SNDRV_AUTO_DMA) | ||
137 | pnp_resource_change(&cfg->dma_resource[1], dma16[dev], 1); | ||
138 | if (irq[dev] != SNDRV_AUTO_IRQ) | ||
139 | pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1); | ||
140 | if (pnp_manual_config_dev(pdev, cfg, 0) < 0) | ||
141 | snd_printk(KERN_ERR PFX "AUDIO the requested resources are invalid, using auto config\n"); | ||
142 | err = pnp_activate_dev(pdev); | 110 | err = pnp_activate_dev(pdev); |
143 | if (err < 0) { | 111 | if (err < 0) { |
144 | snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n"); | 112 | snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n"); |
145 | kfree(cfg); | ||
146 | return err; | 113 | return err; |
147 | } | 114 | } |
148 | port[dev] = pnp_port_start(pdev, 0); | 115 | port[dev] = pnp_port_start(pdev, 0); |
@@ -152,13 +119,6 @@ static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard, | |||
152 | 119 | ||
153 | pdev = acard->devmpu; | 120 | pdev = acard->devmpu; |
154 | if (pdev != NULL) { | 121 | if (pdev != NULL) { |
155 | pnp_init_resource_table(cfg); | ||
156 | if (mpu_port[dev] != SNDRV_AUTO_PORT) | ||
157 | pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2); | ||
158 | if (mpu_irq[dev] != SNDRV_AUTO_IRQ) | ||
159 | pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1); | ||
160 | if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0) | ||
161 | snd_printk(KERN_ERR PFX "MPU401 the requested resources are invalid, using auto config\n"); | ||
162 | err = pnp_activate_dev(pdev); | 122 | err = pnp_activate_dev(pdev); |
163 | if (err < 0) | 123 | if (err < 0) |
164 | goto __mpu_error; | 124 | goto __mpu_error; |
@@ -176,11 +136,6 @@ static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard, | |||
176 | 136 | ||
177 | pdev = acard->devopl; | 137 | pdev = acard->devopl; |
178 | if (pdev != NULL) { | 138 | if (pdev != NULL) { |
179 | pnp_init_resource_table(cfg); | ||
180 | if (fm_port[dev] != SNDRV_AUTO_PORT) | ||
181 | pnp_resource_change(&cfg->port_resource[0], fm_port[dev], 4); | ||
182 | if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0) | ||
183 | snd_printk(KERN_ERR PFX "OPL3 the requested resources are invalid, using auto config\n"); | ||
184 | err = pnp_activate_dev(pdev); | 139 | err = pnp_activate_dev(pdev); |
185 | if (err < 0) | 140 | if (err < 0) |
186 | goto __fm_error; | 141 | goto __fm_error; |
@@ -195,7 +150,6 @@ static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard, | |||
195 | fm_port[dev] = -1; | 150 | fm_port[dev] = -1; |
196 | } | 151 | } |
197 | 152 | ||
198 | kfree(cfg); | ||
199 | return 0; | 153 | return 0; |
200 | } | 154 | } |
201 | 155 | ||
diff --git a/sound/isa/azt2320.c b/sound/isa/azt2320.c index b615538a928d..154e728f592d 100644 --- a/sound/isa/azt2320.c +++ b/sound/isa/azt2320.c | |||
@@ -29,7 +29,6 @@ | |||
29 | activation method (full-duplex audio!). | 29 | activation method (full-duplex audio!). |
30 | */ | 30 | */ |
31 | 31 | ||
32 | #include <sound/driver.h> | ||
33 | #include <asm/io.h> | 32 | #include <asm/io.h> |
34 | #include <linux/delay.h> | 33 | #include <linux/delay.h> |
35 | #include <linux/init.h> | 34 | #include <linux/init.h> |
@@ -72,22 +71,6 @@ module_param_array(id, charp, NULL, 0444); | |||
72 | MODULE_PARM_DESC(id, "ID string for azt2320 based soundcard."); | 71 | MODULE_PARM_DESC(id, "ID string for azt2320 based soundcard."); |
73 | module_param_array(enable, bool, NULL, 0444); | 72 | module_param_array(enable, bool, NULL, 0444); |
74 | MODULE_PARM_DESC(enable, "Enable azt2320 based soundcard."); | 73 | MODULE_PARM_DESC(enable, "Enable azt2320 based soundcard."); |
75 | module_param_array(port, long, NULL, 0444); | ||
76 | MODULE_PARM_DESC(port, "Port # for azt2320 driver."); | ||
77 | module_param_array(wss_port, long, NULL, 0444); | ||
78 | MODULE_PARM_DESC(wss_port, "WSS Port # for azt2320 driver."); | ||
79 | module_param_array(mpu_port, long, NULL, 0444); | ||
80 | MODULE_PARM_DESC(mpu_port, "MPU-401 port # for azt2320 driver."); | ||
81 | module_param_array(fm_port, long, NULL, 0444); | ||
82 | MODULE_PARM_DESC(fm_port, "FM port # for azt2320 driver."); | ||
83 | module_param_array(irq, int, NULL, 0444); | ||
84 | MODULE_PARM_DESC(irq, "IRQ # for azt2320 driver."); | ||
85 | module_param_array(mpu_irq, int, NULL, 0444); | ||
86 | MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for azt2320 driver."); | ||
87 | module_param_array(dma1, int, NULL, 0444); | ||
88 | MODULE_PARM_DESC(dma1, "1st DMA # for azt2320 driver."); | ||
89 | module_param_array(dma2, int, NULL, 0444); | ||
90 | MODULE_PARM_DESC(dma2, "2nd DMA # for azt2320 driver."); | ||
91 | 74 | ||
92 | struct snd_card_azt2320 { | 75 | struct snd_card_azt2320 { |
93 | int dev_no; | 76 | int dev_no; |
@@ -121,43 +104,19 @@ static int __devinit snd_card_azt2320_pnp(int dev, struct snd_card_azt2320 *acar | |||
121 | const struct pnp_card_device_id *id) | 104 | const struct pnp_card_device_id *id) |
122 | { | 105 | { |
123 | struct pnp_dev *pdev; | 106 | struct pnp_dev *pdev; |
124 | struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL); | ||
125 | int err; | 107 | int err; |
126 | 108 | ||
127 | if (!cfg) | ||
128 | return -ENOMEM; | ||
129 | |||
130 | acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL); | 109 | acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL); |
131 | if (acard->dev == NULL) { | 110 | if (acard->dev == NULL) |
132 | kfree(cfg); | ||
133 | return -ENODEV; | 111 | return -ENODEV; |
134 | } | ||
135 | 112 | ||
136 | acard->devmpu = pnp_request_card_device(card, id->devs[1].id, NULL); | 113 | acard->devmpu = pnp_request_card_device(card, id->devs[1].id, NULL); |
137 | 114 | ||
138 | pdev = acard->dev; | 115 | pdev = acard->dev; |
139 | pnp_init_resource_table(cfg); | ||
140 | |||
141 | /* override resources */ | ||
142 | if (port[dev] != SNDRV_AUTO_PORT) | ||
143 | pnp_resource_change(&cfg->port_resource[0], port[dev], 16); | ||
144 | if (fm_port[dev] != SNDRV_AUTO_PORT) | ||
145 | pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4); | ||
146 | if (wss_port[dev] != SNDRV_AUTO_PORT) | ||
147 | pnp_resource_change(&cfg->port_resource[2], wss_port[dev], 4); | ||
148 | if (dma1[dev] != SNDRV_AUTO_DMA) | ||
149 | pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1); | ||
150 | if (dma2[dev] != SNDRV_AUTO_DMA) | ||
151 | pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1); | ||
152 | if (irq[dev] != SNDRV_AUTO_IRQ) | ||
153 | pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1); | ||
154 | if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0) | ||
155 | snd_printk(KERN_ERR PFX "AUDIO the requested resources are invalid, using auto config\n"); | ||
156 | 116 | ||
157 | err = pnp_activate_dev(pdev); | 117 | err = pnp_activate_dev(pdev); |
158 | if (err < 0) { | 118 | if (err < 0) { |
159 | snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n"); | 119 | snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n"); |
160 | kfree(cfg); | ||
161 | return err; | 120 | return err; |
162 | } | 121 | } |
163 | port[dev] = pnp_port_start(pdev, 0); | 122 | port[dev] = pnp_port_start(pdev, 0); |
@@ -169,13 +128,6 @@ static int __devinit snd_card_azt2320_pnp(int dev, struct snd_card_azt2320 *acar | |||
169 | 128 | ||
170 | pdev = acard->devmpu; | 129 | pdev = acard->devmpu; |
171 | if (pdev != NULL) { | 130 | if (pdev != NULL) { |
172 | pnp_init_resource_table(cfg); | ||
173 | if (mpu_port[dev] != SNDRV_AUTO_PORT) | ||
174 | pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2); | ||
175 | if (mpu_irq[dev] != SNDRV_AUTO_IRQ) | ||
176 | pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1); | ||
177 | if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0) | ||
178 | snd_printk(KERN_ERR PFX "MPU401 the requested resources are invalid, using auto config\n"); | ||
179 | err = pnp_activate_dev(pdev); | 131 | err = pnp_activate_dev(pdev); |
180 | if (err < 0) | 132 | if (err < 0) |
181 | goto __mpu_error; | 133 | goto __mpu_error; |
@@ -191,7 +143,6 @@ static int __devinit snd_card_azt2320_pnp(int dev, struct snd_card_azt2320 *acar | |||
191 | mpu_port[dev] = -1; | 143 | mpu_port[dev] = -1; |
192 | } | 144 | } |
193 | 145 | ||
194 | kfree (cfg); | ||
195 | return 0; | 146 | return 0; |
196 | } | 147 | } |
197 | 148 | ||
diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c index f471f8ad6885..4d198ec71e9b 100644 --- a/sound/isa/cmi8330.c +++ b/sound/isa/cmi8330.c | |||
@@ -43,7 +43,6 @@ | |||
43 | * full control over both mixers. | 43 | * full control over both mixers. |
44 | */ | 44 | */ |
45 | 45 | ||
46 | #include <sound/driver.h> | ||
47 | #include <linux/init.h> | 46 | #include <linux/init.h> |
48 | #include <linux/err.h> | 47 | #include <linux/err.h> |
49 | #include <linux/isa.h> | 48 | #include <linux/isa.h> |
@@ -286,39 +285,21 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard, | |||
286 | const struct pnp_card_device_id *id) | 285 | const struct pnp_card_device_id *id) |
287 | { | 286 | { |
288 | struct pnp_dev *pdev; | 287 | struct pnp_dev *pdev; |
289 | struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL); | ||
290 | int err; | 288 | int err; |
291 | 289 | ||
292 | if (!cfg) | ||
293 | return -ENOMEM; | ||
294 | acard->cap = pnp_request_card_device(card, id->devs[0].id, NULL); | 290 | acard->cap = pnp_request_card_device(card, id->devs[0].id, NULL); |
295 | if (acard->cap == NULL) { | 291 | if (acard->cap == NULL) |
296 | kfree(cfg); | ||
297 | return -EBUSY; | 292 | return -EBUSY; |
298 | } | 293 | |
299 | acard->play = pnp_request_card_device(card, id->devs[1].id, NULL); | 294 | acard->play = pnp_request_card_device(card, id->devs[1].id, NULL); |
300 | if (acard->play == NULL) { | 295 | if (acard->play == NULL) |
301 | kfree(cfg); | ||
302 | return -EBUSY; | 296 | return -EBUSY; |
303 | } | ||
304 | 297 | ||
305 | pdev = acard->cap; | 298 | pdev = acard->cap; |
306 | pnp_init_resource_table(cfg); | 299 | |
307 | /* allocate AD1848 resources */ | ||
308 | if (wssport[dev] != SNDRV_AUTO_PORT) | ||
309 | pnp_resource_change(&cfg->port_resource[0], wssport[dev], 8); | ||
310 | if (wssdma[dev] != SNDRV_AUTO_DMA) | ||
311 | pnp_resource_change(&cfg->dma_resource[0], wssdma[dev], 1); | ||
312 | if (wssirq[dev] != SNDRV_AUTO_IRQ) | ||
313 | pnp_resource_change(&cfg->irq_resource[0], wssirq[dev], 1); | ||
314 | |||
315 | err = pnp_manual_config_dev(pdev, cfg, 0); | ||
316 | if (err < 0) | ||
317 | snd_printk(KERN_ERR "CMI8330/C3D (AD1848) PnP manual resources are invalid, using auto config\n"); | ||
318 | err = pnp_activate_dev(pdev); | 300 | err = pnp_activate_dev(pdev); |
319 | if (err < 0) { | 301 | if (err < 0) { |
320 | snd_printk(KERN_ERR "CMI8330/C3D (AD1848) PnP configure failure\n"); | 302 | snd_printk(KERN_ERR "CMI8330/C3D (AD1848) PnP configure failure\n"); |
321 | kfree(cfg); | ||
322 | return -EBUSY; | 303 | return -EBUSY; |
323 | } | 304 | } |
324 | wssport[dev] = pnp_port_start(pdev, 0); | 305 | wssport[dev] = pnp_port_start(pdev, 0); |
@@ -327,23 +308,10 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard, | |||
327 | 308 | ||
328 | /* allocate SB16 resources */ | 309 | /* allocate SB16 resources */ |
329 | pdev = acard->play; | 310 | pdev = acard->play; |
330 | pnp_init_resource_table(cfg); | 311 | |
331 | if (sbport[dev] != SNDRV_AUTO_PORT) | ||
332 | pnp_resource_change(&cfg->port_resource[0], sbport[dev], 16); | ||
333 | if (sbdma8[dev] != SNDRV_AUTO_DMA) | ||
334 | pnp_resource_change(&cfg->dma_resource[0], sbdma8[dev], 1); | ||
335 | if (sbdma16[dev] != SNDRV_AUTO_DMA) | ||
336 | pnp_resource_change(&cfg->dma_resource[1], sbdma16[dev], 1); | ||
337 | if (sbirq[dev] != SNDRV_AUTO_IRQ) | ||
338 | pnp_resource_change(&cfg->irq_resource[0], sbirq[dev], 1); | ||
339 | |||
340 | err = pnp_manual_config_dev(pdev, cfg, 0); | ||
341 | if (err < 0) | ||
342 | snd_printk(KERN_ERR "CMI8330/C3D (SB16) PnP manual resources are invalid, using auto config\n"); | ||
343 | err = pnp_activate_dev(pdev); | 312 | err = pnp_activate_dev(pdev); |
344 | if (err < 0) { | 313 | if (err < 0) { |
345 | snd_printk(KERN_ERR "CMI8330/C3D (SB16) PnP configure failure\n"); | 314 | snd_printk(KERN_ERR "CMI8330/C3D (SB16) PnP configure failure\n"); |
346 | kfree(cfg); | ||
347 | return -EBUSY; | 315 | return -EBUSY; |
348 | } | 316 | } |
349 | sbport[dev] = pnp_port_start(pdev, 0); | 317 | sbport[dev] = pnp_port_start(pdev, 0); |
@@ -351,7 +319,6 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard, | |||
351 | sbdma16[dev] = pnp_dma(pdev, 1); | 319 | sbdma16[dev] = pnp_dma(pdev, 1); |
352 | sbirq[dev] = pnp_irq(pdev, 0); | 320 | sbirq[dev] = pnp_irq(pdev, 0); |
353 | 321 | ||
354 | kfree(cfg); | ||
355 | return 0; | 322 | return 0; |
356 | } | 323 | } |
357 | #endif | 324 | #endif |
diff --git a/sound/isa/cs423x/cs4231.c b/sound/isa/cs423x/cs4231.c index 13db6842eaaa..e9462b9944be 100644 --- a/sound/isa/cs423x/cs4231.c +++ b/sound/isa/cs423x/cs4231.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <linux/err.h> | 24 | #include <linux/err.h> |
26 | #include <linux/isa.h> | 25 | #include <linux/isa.h> |
diff --git a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c index a5eb9659b519..0aa8649e5c7f 100644 --- a/sound/isa/cs423x/cs4231_lib.c +++ b/sound/isa/cs423x/cs4231_lib.c | |||
@@ -24,7 +24,6 @@ | |||
24 | * | 24 | * |
25 | */ | 25 | */ |
26 | 26 | ||
27 | #include <sound/driver.h> | ||
28 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
29 | #include <linux/pm.h> | 28 | #include <linux/pm.h> |
30 | #include <linux/init.h> | 29 | #include <linux/init.h> |
@@ -333,7 +332,6 @@ void snd_cs4231_mce_down(struct snd_cs4231 *chip) | |||
333 | !(chip->hardware & (CS4231_HW_CS4231_MASK | CS4231_HW_CS4232_MASK))) { | 332 | !(chip->hardware & (CS4231_HW_CS4231_MASK | CS4231_HW_CS4232_MASK))) { |
334 | return; | 333 | return; |
335 | } | 334 | } |
336 | snd_cs4231_busy_wait(chip); | ||
337 | 335 | ||
338 | /* | 336 | /* |
339 | * Wait for (possible -- during init auto-calibration may not be set) | 337 | * Wait for (possible -- during init auto-calibration may not be set) |
diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c index 5784b43f4123..dbe63db4bfd6 100644 --- a/sound/isa/cs423x/cs4236.c +++ b/sound/isa/cs423x/cs4236.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/err.h> | 23 | #include <linux/err.h> |
25 | #include <linux/isa.h> | 24 | #include <linux/isa.h> |
@@ -270,29 +269,9 @@ static struct pnp_card_device_id snd_cs423x_pnpids[] = { | |||
270 | MODULE_DEVICE_TABLE(pnp_card, snd_cs423x_pnpids); | 269 | MODULE_DEVICE_TABLE(pnp_card, snd_cs423x_pnpids); |
271 | 270 | ||
272 | /* WSS initialization */ | 271 | /* WSS initialization */ |
273 | static int __devinit snd_cs423x_pnp_init_wss(int dev, struct pnp_dev *pdev, | 272 | static int __devinit snd_cs423x_pnp_init_wss(int dev, struct pnp_dev *pdev) |
274 | struct pnp_resource_table *cfg) | ||
275 | { | 273 | { |
276 | int err; | 274 | if (pnp_activate_dev(pdev) < 0) { |
277 | |||
278 | pnp_init_resource_table(cfg); | ||
279 | if (port[dev] != SNDRV_AUTO_PORT) | ||
280 | pnp_resource_change(&cfg->port_resource[0], port[dev], 4); | ||
281 | if (fm_port[dev] != SNDRV_AUTO_PORT && fm_port[dev] > 0) | ||
282 | pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4); | ||
283 | if (sb_port[dev] != SNDRV_AUTO_PORT) | ||
284 | pnp_resource_change(&cfg->port_resource[2], sb_port[dev], 16); | ||
285 | if (irq[dev] != SNDRV_AUTO_IRQ) | ||
286 | pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1); | ||
287 | if (dma1[dev] != SNDRV_AUTO_DMA) | ||
288 | pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1); | ||
289 | if (dma2[dev] != SNDRV_AUTO_DMA) | ||
290 | pnp_resource_change(&cfg->dma_resource[1], dma2[dev] < 0 ? 4 : dma2[dev], 1); | ||
291 | err = pnp_manual_config_dev(pdev, cfg, 0); | ||
292 | if (err < 0) | ||
293 | snd_printk(KERN_ERR IDENT " WSS PnP manual resources are invalid, using auto config\n"); | ||
294 | err = pnp_activate_dev(pdev); | ||
295 | if (err < 0) { | ||
296 | printk(KERN_ERR IDENT " WSS PnP configure failed for WSS (out of resources?)\n"); | 275 | printk(KERN_ERR IDENT " WSS PnP configure failed for WSS (out of resources?)\n"); |
297 | return -EBUSY; | 276 | return -EBUSY; |
298 | } | 277 | } |
@@ -311,19 +290,9 @@ static int __devinit snd_cs423x_pnp_init_wss(int dev, struct pnp_dev *pdev, | |||
311 | } | 290 | } |
312 | 291 | ||
313 | /* CTRL initialization */ | 292 | /* CTRL initialization */ |
314 | static int __devinit snd_cs423x_pnp_init_ctrl(int dev, struct pnp_dev *pdev, | 293 | static int __devinit snd_cs423x_pnp_init_ctrl(int dev, struct pnp_dev *pdev) |
315 | struct pnp_resource_table *cfg) | ||
316 | { | 294 | { |
317 | int err; | 295 | if (pnp_activate_dev(pdev) < 0) { |
318 | |||
319 | pnp_init_resource_table(cfg); | ||
320 | if (cport[dev] != SNDRV_AUTO_PORT) | ||
321 | pnp_resource_change(&cfg->port_resource[0], cport[dev], 8); | ||
322 | err = pnp_manual_config_dev(pdev, cfg, 0); | ||
323 | if (err < 0) | ||
324 | snd_printk(KERN_ERR IDENT " CTRL PnP manual resources are invalid, using auto config\n"); | ||
325 | err = pnp_activate_dev(pdev); | ||
326 | if (err < 0) { | ||
327 | printk(KERN_ERR IDENT " CTRL PnP configure failed for WSS (out of resources?)\n"); | 296 | printk(KERN_ERR IDENT " CTRL PnP configure failed for WSS (out of resources?)\n"); |
328 | return -EBUSY; | 297 | return -EBUSY; |
329 | } | 298 | } |
@@ -333,21 +302,9 @@ static int __devinit snd_cs423x_pnp_init_ctrl(int dev, struct pnp_dev *pdev, | |||
333 | } | 302 | } |
334 | 303 | ||
335 | /* MPU initialization */ | 304 | /* MPU initialization */ |
336 | static int __devinit snd_cs423x_pnp_init_mpu(int dev, struct pnp_dev *pdev, | 305 | static int __devinit snd_cs423x_pnp_init_mpu(int dev, struct pnp_dev *pdev) |
337 | struct pnp_resource_table *cfg) | ||
338 | { | 306 | { |
339 | int err; | 307 | if (pnp_activate_dev(pdev) < 0) { |
340 | |||
341 | pnp_init_resource_table(cfg); | ||
342 | if (mpu_port[dev] != SNDRV_AUTO_PORT) | ||
343 | pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2); | ||
344 | if (mpu_irq[dev] != SNDRV_AUTO_IRQ && mpu_irq[dev] >= 0) | ||
345 | pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1); | ||
346 | err = pnp_manual_config_dev(pdev, cfg, 0); | ||
347 | if (err < 0) | ||
348 | snd_printk(KERN_ERR IDENT " MPU401 PnP manual resources are invalid, using auto config\n"); | ||
349 | err = pnp_activate_dev(pdev); | ||
350 | if (err < 0) { | ||
351 | printk(KERN_ERR IDENT " MPU401 PnP configure failed for WSS (out of resources?)\n"); | 308 | printk(KERN_ERR IDENT " MPU401 PnP configure failed for WSS (out of resources?)\n"); |
352 | mpu_port[dev] = SNDRV_AUTO_PORT; | 309 | mpu_port[dev] = SNDRV_AUTO_PORT; |
353 | mpu_irq[dev] = SNDRV_AUTO_IRQ; | 310 | mpu_irq[dev] = SNDRV_AUTO_IRQ; |
@@ -368,15 +325,8 @@ static int __devinit snd_cs423x_pnp_init_mpu(int dev, struct pnp_dev *pdev, | |||
368 | static int __devinit snd_card_cs4232_pnp(int dev, struct snd_card_cs4236 *acard, | 325 | static int __devinit snd_card_cs4232_pnp(int dev, struct snd_card_cs4236 *acard, |
369 | struct pnp_dev *pdev) | 326 | struct pnp_dev *pdev) |
370 | { | 327 | { |
371 | struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL); | 328 | if (snd_cs423x_pnp_init_wss(dev, acard->wss) < 0) |
372 | |||
373 | if (!cfg) | ||
374 | return -ENOMEM; | ||
375 | if (snd_cs423x_pnp_init_wss(dev, acard->wss, cfg) < 0) { | ||
376 | kfree(cfg); | ||
377 | return -EBUSY; | 329 | return -EBUSY; |
378 | } | ||
379 | kfree(cfg); | ||
380 | cport[dev] = -1; | 330 | cport[dev] = -1; |
381 | return 0; | 331 | return 0; |
382 | } | 332 | } |
@@ -386,43 +336,33 @@ static int __devinit snd_card_cs423x_pnpc(int dev, struct snd_card_cs4236 *acard | |||
386 | struct pnp_card_link *card, | 336 | struct pnp_card_link *card, |
387 | const struct pnp_card_device_id *id) | 337 | const struct pnp_card_device_id *id) |
388 | { | 338 | { |
389 | struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL); | ||
390 | |||
391 | if (!cfg) | ||
392 | return -ENOMEM; | ||
393 | |||
394 | acard->wss = pnp_request_card_device(card, id->devs[0].id, NULL); | 339 | acard->wss = pnp_request_card_device(card, id->devs[0].id, NULL); |
395 | if (acard->wss == NULL) | 340 | if (acard->wss == NULL) |
396 | goto error; | 341 | return -EBUSY; |
397 | acard->ctrl = pnp_request_card_device(card, id->devs[1].id, NULL); | 342 | acard->ctrl = pnp_request_card_device(card, id->devs[1].id, NULL); |
398 | if (acard->ctrl == NULL) | 343 | if (acard->ctrl == NULL) |
399 | goto error; | 344 | return -EBUSY; |
400 | if (id->devs[2].id[0]) { | 345 | if (id->devs[2].id[0]) { |
401 | acard->mpu = pnp_request_card_device(card, id->devs[2].id, NULL); | 346 | acard->mpu = pnp_request_card_device(card, id->devs[2].id, NULL); |
402 | if (acard->mpu == NULL) | 347 | if (acard->mpu == NULL) |
403 | goto error; | 348 | return -EBUSY; |
404 | } | 349 | } |
405 | 350 | ||
406 | /* WSS initialization */ | 351 | /* WSS initialization */ |
407 | if (snd_cs423x_pnp_init_wss(dev, acard->wss, cfg) < 0) | 352 | if (snd_cs423x_pnp_init_wss(dev, acard->wss) < 0) |
408 | goto error; | 353 | return -EBUSY; |
409 | 354 | ||
410 | /* CTRL initialization */ | 355 | /* CTRL initialization */ |
411 | if (acard->ctrl && cport[dev] > 0) { | 356 | if (acard->ctrl && cport[dev] > 0) { |
412 | if (snd_cs423x_pnp_init_ctrl(dev, acard->ctrl, cfg) < 0) | 357 | if (snd_cs423x_pnp_init_ctrl(dev, acard->ctrl) < 0) |
413 | goto error; | 358 | return -EBUSY; |
414 | } | 359 | } |
415 | /* MPU initialization */ | 360 | /* MPU initialization */ |
416 | if (acard->mpu && mpu_port[dev] > 0) { | 361 | if (acard->mpu && mpu_port[dev] > 0) { |
417 | if (snd_cs423x_pnp_init_mpu(dev, acard->mpu, cfg) < 0) | 362 | if (snd_cs423x_pnp_init_mpu(dev, acard->mpu) < 0) |
418 | goto error; | 363 | return -EBUSY; |
419 | } | 364 | } |
420 | kfree(cfg); | ||
421 | return 0; | 365 | return 0; |
422 | |||
423 | error: | ||
424 | kfree(cfg); | ||
425 | return -EBUSY; | ||
426 | } | 366 | } |
427 | #endif /* CONFIG_PNP */ | 367 | #endif /* CONFIG_PNP */ |
428 | 368 | ||
diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c index 6bd064470d4c..de71910401ea 100644 --- a/sound/isa/cs423x/cs4236_lib.c +++ b/sound/isa/cs423x/cs4236_lib.c | |||
@@ -79,7 +79,6 @@ | |||
79 | * | 79 | * |
80 | */ | 80 | */ |
81 | 81 | ||
82 | #include <sound/driver.h> | ||
83 | #include <asm/io.h> | 82 | #include <asm/io.h> |
84 | #include <linux/delay.h> | 83 | #include <linux/delay.h> |
85 | #include <linux/init.h> | 84 | #include <linux/init.h> |
diff --git a/sound/isa/dt019x.c b/sound/isa/dt019x.c index ce57d526f7bc..a0242c3b613e 100644 --- a/sound/isa/dt019x.c +++ b/sound/isa/dt019x.c | |||
@@ -21,7 +21,6 @@ | |||
21 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <linux/wait.h> | 25 | #include <linux/wait.h> |
27 | #include <linux/pnp.h> | 26 | #include <linux/pnp.h> |
@@ -56,18 +55,6 @@ module_param_array(id, charp, NULL, 0444); | |||
56 | MODULE_PARM_DESC(id, "ID string for DT-019X based soundcard."); | 55 | MODULE_PARM_DESC(id, "ID string for DT-019X based soundcard."); |
57 | module_param_array(enable, bool, NULL, 0444); | 56 | module_param_array(enable, bool, NULL, 0444); |
58 | MODULE_PARM_DESC(enable, "Enable DT-019X based soundcard."); | 57 | MODULE_PARM_DESC(enable, "Enable DT-019X based soundcard."); |
59 | module_param_array(port, long, NULL, 0444); | ||
60 | MODULE_PARM_DESC(port, "Port # for dt019x driver."); | ||
61 | module_param_array(mpu_port, long, NULL, 0444); | ||
62 | MODULE_PARM_DESC(mpu_port, "MPU-401 port # for dt019x driver."); | ||
63 | module_param_array(fm_port, long, NULL, 0444); | ||
64 | MODULE_PARM_DESC(fm_port, "FM port # for dt019x driver."); | ||
65 | module_param_array(irq, int, NULL, 0444); | ||
66 | MODULE_PARM_DESC(irq, "IRQ # for dt019x driver."); | ||
67 | module_param_array(mpu_irq, int, NULL, 0444); | ||
68 | MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for dt019x driver."); | ||
69 | module_param_array(dma8, int, NULL, 0444); | ||
70 | MODULE_PARM_DESC(dma8, "8-bit DMA # for dt019x driver."); | ||
71 | 58 | ||
72 | struct snd_card_dt019x { | 59 | struct snd_card_dt019x { |
73 | struct pnp_dev *dev; | 60 | struct pnp_dev *dev; |
@@ -95,36 +82,20 @@ static int __devinit snd_card_dt019x_pnp(int dev, struct snd_card_dt019x *acard, | |||
95 | const struct pnp_card_device_id *pid) | 82 | const struct pnp_card_device_id *pid) |
96 | { | 83 | { |
97 | struct pnp_dev *pdev; | 84 | struct pnp_dev *pdev; |
98 | struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL); | ||
99 | int err; | 85 | int err; |
100 | 86 | ||
101 | if (!cfg) | ||
102 | return -ENOMEM; | ||
103 | |||
104 | acard->dev = pnp_request_card_device(card, pid->devs[0].id, NULL); | 87 | acard->dev = pnp_request_card_device(card, pid->devs[0].id, NULL); |
105 | if (acard->dev == NULL) { | 88 | if (acard->dev == NULL) |
106 | kfree (cfg); | ||
107 | return -ENODEV; | 89 | return -ENODEV; |
108 | } | 90 | |
109 | acard->devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL); | 91 | acard->devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL); |
110 | acard->devopl = pnp_request_card_device(card, pid->devs[2].id, NULL); | 92 | acard->devopl = pnp_request_card_device(card, pid->devs[2].id, NULL); |
111 | 93 | ||
112 | pdev = acard->dev; | 94 | pdev = acard->dev; |
113 | pnp_init_resource_table(cfg); | ||
114 | |||
115 | if (port[dev] != SNDRV_AUTO_PORT) | ||
116 | pnp_resource_change(&cfg->port_resource[0], port[dev], 16); | ||
117 | if (dma8[dev] != SNDRV_AUTO_DMA) | ||
118 | pnp_resource_change(&cfg->dma_resource[0], dma8[dev], 1); | ||
119 | if (irq[dev] != SNDRV_AUTO_IRQ) | ||
120 | pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1); | ||
121 | 95 | ||
122 | if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0) | ||
123 | snd_printk(KERN_ERR PFX "DT-019X AUDIO the requested resources are invalid, using auto config\n"); | ||
124 | err = pnp_activate_dev(pdev); | 96 | err = pnp_activate_dev(pdev); |
125 | if (err < 0) { | 97 | if (err < 0) { |
126 | snd_printk(KERN_ERR PFX "DT-019X AUDIO pnp configure failure\n"); | 98 | snd_printk(KERN_ERR PFX "DT-019X AUDIO pnp configure failure\n"); |
127 | kfree(cfg); | ||
128 | return err; | 99 | return err; |
129 | } | 100 | } |
130 | 101 | ||
@@ -135,15 +106,7 @@ static int __devinit snd_card_dt019x_pnp(int dev, struct snd_card_dt019x *acard, | |||
135 | port[dev],irq[dev],dma8[dev]); | 106 | port[dev],irq[dev],dma8[dev]); |
136 | 107 | ||
137 | pdev = acard->devmpu; | 108 | pdev = acard->devmpu; |
138 | |||
139 | if (pdev != NULL) { | 109 | if (pdev != NULL) { |
140 | pnp_init_resource_table(cfg); | ||
141 | if (mpu_port[dev] != SNDRV_AUTO_PORT) | ||
142 | pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2); | ||
143 | if (mpu_irq[dev] != SNDRV_AUTO_IRQ) | ||
144 | pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1); | ||
145 | if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0) | ||
146 | snd_printk(KERN_ERR PFX "DT-019X MPU401 the requested resources are invalid, using auto config\n"); | ||
147 | err = pnp_activate_dev(pdev); | 110 | err = pnp_activate_dev(pdev); |
148 | if (err < 0) { | 111 | if (err < 0) { |
149 | pnp_release_card_device(pdev); | 112 | pnp_release_card_device(pdev); |
@@ -162,11 +125,6 @@ static int __devinit snd_card_dt019x_pnp(int dev, struct snd_card_dt019x *acard, | |||
162 | 125 | ||
163 | pdev = acard->devopl; | 126 | pdev = acard->devopl; |
164 | if (pdev != NULL) { | 127 | if (pdev != NULL) { |
165 | pnp_init_resource_table(cfg); | ||
166 | if (fm_port[dev] != SNDRV_AUTO_PORT) | ||
167 | pnp_resource_change(&cfg->port_resource[0], fm_port[dev], 4); | ||
168 | if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0) | ||
169 | snd_printk(KERN_ERR PFX "DT-019X OPL3 the requested resources are invalid, using auto config\n"); | ||
170 | err = pnp_activate_dev(pdev); | 128 | err = pnp_activate_dev(pdev); |
171 | if (err < 0) { | 129 | if (err < 0) { |
172 | pnp_release_card_device(pdev); | 130 | pnp_release_card_device(pdev); |
@@ -181,7 +139,6 @@ static int __devinit snd_card_dt019x_pnp(int dev, struct snd_card_dt019x *acard, | |||
181 | fm_port[dev] = -1; | 139 | fm_port[dev] = -1; |
182 | } | 140 | } |
183 | 141 | ||
184 | kfree(cfg); | ||
185 | return 0; | 142 | return 0; |
186 | } | 143 | } |
187 | 144 | ||
diff --git a/sound/isa/es1688/es1688.c b/sound/isa/es1688/es1688.c index 74bbc92f2e7c..f88639ea64b2 100644 --- a/sound/isa/es1688/es1688.c +++ b/sound/isa/es1688/es1688.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/err.h> | 23 | #include <linux/err.h> |
25 | #include <linux/isa.h> | 24 | #include <linux/isa.h> |
diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c index 5c26d495daa8..1e1e575b1db3 100644 --- a/sound/isa/es1688/es1688_lib.c +++ b/sound/isa/es1688/es1688_lib.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
25 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index c1af28fd4a1f..90498e4ca260 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c | |||
@@ -77,7 +77,6 @@ | |||
77 | * needed for ZV, so maybe the datasheet is entirely wrong here. | 77 | * needed for ZV, so maybe the datasheet is entirely wrong here. |
78 | */ | 78 | */ |
79 | 79 | ||
80 | #include <sound/driver.h> | ||
81 | #include <linux/init.h> | 80 | #include <linux/init.h> |
82 | #include <linux/err.h> | 81 | #include <linux/err.h> |
83 | #include <linux/isa.h> | 82 | #include <linux/isa.h> |
@@ -163,7 +162,7 @@ struct snd_audiodrive { | |||
163 | #define ES18XX_DUPLEX_SAME 0x0010 /* Playback and record must share the same rate */ | 162 | #define ES18XX_DUPLEX_SAME 0x0010 /* Playback and record must share the same rate */ |
164 | #define ES18XX_NEW_RATE 0x0020 /* More precise rate setting */ | 163 | #define ES18XX_NEW_RATE 0x0020 /* More precise rate setting */ |
165 | #define ES18XX_AUXB 0x0040 /* AuxB mixer control */ | 164 | #define ES18XX_AUXB 0x0040 /* AuxB mixer control */ |
166 | #define ES18XX_HWV 0x0080 /* Has seperate hardware volume mixer controls*/ | 165 | #define ES18XX_HWV 0x0080 /* Has separate hardware volume mixer controls*/ |
167 | #define ES18XX_MONO 0x0100 /* Mono_in mixer control */ | 166 | #define ES18XX_MONO 0x0100 /* Mono_in mixer control */ |
168 | #define ES18XX_I2S 0x0200 /* I2S mixer control */ | 167 | #define ES18XX_I2S 0x0200 /* I2S mixer control */ |
169 | #define ES18XX_MUTEREC 0x0400 /* Record source can be muted */ | 168 | #define ES18XX_MUTEREC 0x0400 /* Record source can be muted */ |
@@ -1442,6 +1441,8 @@ static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip) | |||
1442 | snd_es18xx_write(chip, 0xB2, 0x50); | 1441 | snd_es18xx_write(chip, 0xB2, 0x50); |
1443 | /* Enable MPU and hardware volume interrupt */ | 1442 | /* Enable MPU and hardware volume interrupt */ |
1444 | snd_es18xx_mixer_write(chip, 0x64, 0x42); | 1443 | snd_es18xx_mixer_write(chip, 0x64, 0x42); |
1444 | /* Enable ESS wavetable input */ | ||
1445 | snd_es18xx_mixer_bits(chip, 0x48, 0x10, 0x10); | ||
1445 | } | 1446 | } |
1446 | else { | 1447 | else { |
1447 | int irqmask, dma1mask, dma2mask; | 1448 | int irqmask, dma1mask, dma2mask; |
@@ -2035,31 +2036,9 @@ static struct pnp_device_id snd_audiodrive_pnpbiosids[] = { | |||
2035 | MODULE_DEVICE_TABLE(pnp, snd_audiodrive_pnpbiosids); | 2036 | MODULE_DEVICE_TABLE(pnp, snd_audiodrive_pnpbiosids); |
2036 | 2037 | ||
2037 | /* PnP main device initialization */ | 2038 | /* PnP main device initialization */ |
2038 | static int __devinit snd_audiodrive_pnp_init_main(int dev, struct pnp_dev *pdev, | 2039 | static int __devinit snd_audiodrive_pnp_init_main(int dev, struct pnp_dev *pdev) |
2039 | struct pnp_resource_table *cfg) | ||
2040 | { | 2040 | { |
2041 | int err; | 2041 | if (pnp_activate_dev(pdev) < 0) { |
2042 | |||
2043 | pnp_init_resource_table(cfg); | ||
2044 | if (port[dev] != SNDRV_AUTO_PORT) | ||
2045 | pnp_resource_change(&cfg->port_resource[0], port[dev], 16); | ||
2046 | if (fm_port[dev] != SNDRV_AUTO_PORT) | ||
2047 | pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4); | ||
2048 | if (mpu_port[dev] != SNDRV_AUTO_PORT) | ||
2049 | pnp_resource_change(&cfg->port_resource[2], mpu_port[dev], 2); | ||
2050 | if (dma1[dev] != SNDRV_AUTO_DMA) | ||
2051 | pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1); | ||
2052 | if (dma2[dev] != SNDRV_AUTO_DMA) | ||
2053 | pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1); | ||
2054 | if (irq[dev] != SNDRV_AUTO_IRQ) | ||
2055 | pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1); | ||
2056 | if (pnp_device_is_isapnp(pdev)) { | ||
2057 | err = pnp_manual_config_dev(pdev, cfg, 0); | ||
2058 | if (err < 0) | ||
2059 | snd_printk(KERN_ERR PFX "PnP manual resources are invalid, using auto config\n"); | ||
2060 | } | ||
2061 | err = pnp_activate_dev(pdev); | ||
2062 | if (err < 0) { | ||
2063 | snd_printk(KERN_ERR PFX "PnP configure failure (out of resources?)\n"); | 2042 | snd_printk(KERN_ERR PFX "PnP configure failure (out of resources?)\n"); |
2064 | return -EBUSY; | 2043 | return -EBUSY; |
2065 | } | 2044 | } |
@@ -2087,16 +2066,9 @@ static int __devinit snd_audiodrive_pnp_init_main(int dev, struct pnp_dev *pdev, | |||
2087 | static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard, | 2066 | static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard, |
2088 | struct pnp_dev *pdev) | 2067 | struct pnp_dev *pdev) |
2089 | { | 2068 | { |
2090 | struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL); | ||
2091 | |||
2092 | if (!cfg) | ||
2093 | return -ENOMEM; | ||
2094 | acard->dev = pdev; | 2069 | acard->dev = pdev; |
2095 | if (snd_audiodrive_pnp_init_main(dev, acard->dev, cfg) < 0) { | 2070 | if (snd_audiodrive_pnp_init_main(dev, acard->dev) < 0) |
2096 | kfree(cfg); | ||
2097 | return -EBUSY; | 2071 | return -EBUSY; |
2098 | } | ||
2099 | kfree(cfg); | ||
2100 | return 0; | 2072 | return 0; |
2101 | } | 2073 | } |
2102 | 2074 | ||
@@ -2125,33 +2097,24 @@ static int __devinit snd_audiodrive_pnpc(int dev, struct snd_audiodrive *acard, | |||
2125 | struct pnp_card_link *card, | 2097 | struct pnp_card_link *card, |
2126 | const struct pnp_card_device_id *id) | 2098 | const struct pnp_card_device_id *id) |
2127 | { | 2099 | { |
2128 | struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL); | ||
2129 | |||
2130 | if (!cfg) | ||
2131 | return -ENOMEM; | ||
2132 | acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL); | 2100 | acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL); |
2133 | if (acard->dev == NULL) { | 2101 | if (acard->dev == NULL) |
2134 | kfree(cfg); | ||
2135 | return -EBUSY; | 2102 | return -EBUSY; |
2136 | } | 2103 | |
2137 | acard->devc = pnp_request_card_device(card, id->devs[1].id, NULL); | 2104 | acard->devc = pnp_request_card_device(card, id->devs[1].id, NULL); |
2138 | if (acard->devc == NULL) { | 2105 | if (acard->devc == NULL) |
2139 | kfree(cfg); | ||
2140 | return -EBUSY; | 2106 | return -EBUSY; |
2141 | } | 2107 | |
2142 | /* Control port initialization */ | 2108 | /* Control port initialization */ |
2143 | if (pnp_activate_dev(acard->devc) < 0) { | 2109 | if (pnp_activate_dev(acard->devc) < 0) { |
2144 | kfree(cfg); | ||
2145 | snd_printk(KERN_ERR PFX "PnP control configure failure (out of resources?)\n"); | 2110 | snd_printk(KERN_ERR PFX "PnP control configure failure (out of resources?)\n"); |
2146 | return -EAGAIN; | 2111 | return -EAGAIN; |
2147 | } | 2112 | } |
2148 | snd_printdd("pnp: port=0x%llx\n", | 2113 | snd_printdd("pnp: port=0x%llx\n", |
2149 | (unsigned long long)pnp_port_start(acard->devc, 0)); | 2114 | (unsigned long long)pnp_port_start(acard->devc, 0)); |
2150 | if (snd_audiodrive_pnp_init_main(dev, acard->dev, cfg) < 0) { | 2115 | if (snd_audiodrive_pnp_init_main(dev, acard->dev) < 0) |
2151 | kfree(cfg); | ||
2152 | return -EBUSY; | 2116 | return -EBUSY; |
2153 | } | 2117 | |
2154 | kfree(cfg); | ||
2155 | return 0; | 2118 | return 0; |
2156 | } | 2119 | } |
2157 | #endif /* CONFIG_PNP */ | 2120 | #endif /* CONFIG_PNP */ |
diff --git a/sound/isa/gus/Makefile b/sound/isa/gus/Makefile index df3d59f25f5e..6cd4ee03754a 100644 --- a/sound/isa/gus/Makefile +++ b/sound/isa/gus/Makefile | |||
@@ -9,7 +9,6 @@ snd-gus-lib-objs := gus_main.o \ | |||
9 | gus_pcm.o gus_mixer.o \ | 9 | gus_pcm.o gus_mixer.o \ |
10 | gus_uart.o \ | 10 | gus_uart.o \ |
11 | gus_reset.o | 11 | gus_reset.o |
12 | snd-gus-synth-objs := gus_synth.o gus_sample.o gus_simple.o gus_instr.o | ||
13 | 12 | ||
14 | snd-gusclassic-objs := gusclassic.o | 13 | snd-gusclassic-objs := gusclassic.o |
15 | snd-gusextreme-objs := gusextreme.o | 14 | snd-gusextreme-objs := gusextreme.o |
@@ -17,20 +16,9 @@ snd-gusmax-objs := gusmax.o | |||
17 | snd-interwave-objs := interwave.o | 16 | snd-interwave-objs := interwave.o |
18 | snd-interwave-stb-objs := interwave-stb.o | 17 | snd-interwave-stb-objs := interwave-stb.o |
19 | 18 | ||
20 | # | ||
21 | # this function returns: | ||
22 | # "m" - CONFIG_SND_SEQUENCER is m | ||
23 | # <empty string> - CONFIG_SND_SEQUENCER is undefined | ||
24 | # otherwise parameter #1 value | ||
25 | # | ||
26 | sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) | ||
27 | |||
28 | # Toplevel Module Dependency | 19 | # Toplevel Module Dependency |
29 | obj-$(CONFIG_SND_GUSCLASSIC) += snd-gusclassic.o snd-gus-lib.o | 20 | obj-$(CONFIG_SND_GUSCLASSIC) += snd-gusclassic.o snd-gus-lib.o |
30 | obj-$(CONFIG_SND_GUSMAX) += snd-gusmax.o snd-gus-lib.o | 21 | obj-$(CONFIG_SND_GUSMAX) += snd-gusmax.o snd-gus-lib.o |
31 | obj-$(CONFIG_SND_GUSEXTREME) += snd-gusextreme.o snd-gus-lib.o | 22 | obj-$(CONFIG_SND_GUSEXTREME) += snd-gusextreme.o snd-gus-lib.o |
32 | obj-$(CONFIG_SND_INTERWAVE) += snd-interwave.o snd-gus-lib.o | 23 | obj-$(CONFIG_SND_INTERWAVE) += snd-interwave.o snd-gus-lib.o |
33 | obj-$(CONFIG_SND_INTERWAVE_STB) += snd-interwave-stb.o snd-gus-lib.o | 24 | obj-$(CONFIG_SND_INTERWAVE_STB) += snd-interwave-stb.o snd-gus-lib.o |
34 | obj-$(call sequencer,$(CONFIG_SND_GUS_SYNTH)) += snd-gus-synth.o | ||
35 | |||
36 | obj-m := $(sort $(obj-m)) | ||
diff --git a/sound/isa/gus/gus_dma.c b/sound/isa/gus/gus_dma.c index fc905141e8a5..f45f6116c77a 100644 --- a/sound/isa/gus/gus_dma.c +++ b/sound/isa/gus/gus_dma.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <asm/dma.h> | 22 | #include <asm/dma.h> |
24 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
25 | #include <sound/core.h> | 24 | #include <sound/core.h> |
diff --git a/sound/isa/gus/gus_dram.c b/sound/isa/gus/gus_dram.c index 9eaa932f6efe..fd2e2e2ed4e7 100644 --- a/sound/isa/gus/gus_dram.c +++ b/sound/isa/gus/gus_dram.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/time.h> | 22 | #include <linux/time.h> |
24 | #include <sound/core.h> | 23 | #include <sound/core.h> |
25 | #include <sound/gus.h> | 24 | #include <sound/gus.h> |
diff --git a/sound/isa/gus/gus_instr.c b/sound/isa/gus/gus_instr.c index bf137ea72329..4dc9caf8ddcf 100644 --- a/sound/isa/gus/gus_instr.c +++ b/sound/isa/gus/gus_instr.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/time.h> | 22 | #include <linux/time.h> |
24 | #include <sound/core.h> | 23 | #include <sound/core.h> |
25 | #include <sound/gus.h> | 24 | #include <sound/gus.h> |
diff --git a/sound/isa/gus/gus_io.c b/sound/isa/gus/gus_io.c index 3d4f899285ef..ca79878d8d8c 100644 --- a/sound/isa/gus/gus_io.c +++ b/sound/isa/gus/gus_io.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
24 | #include <linux/time.h> | 23 | #include <linux/time.h> |
25 | #include <sound/core.h> | 24 | #include <sound/core.h> |
diff --git a/sound/isa/gus/gus_irq.c b/sound/isa/gus/gus_irq.c index cd9a6f1c99e6..041894ddd014 100644 --- a/sound/isa/gus/gus_irq.c +++ b/sound/isa/gus/gus_irq.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <sound/core.h> | 22 | #include <sound/core.h> |
24 | #include <sound/info.h> | 23 | #include <sound/info.h> |
25 | #include <sound/gus.h> | 24 | #include <sound/gus.h> |
diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c index b14d5d6d9a32..cccc16c8113f 100644 --- a/sound/isa/gus/gus_main.c +++ b/sound/isa/gus/gus_main.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
25 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
@@ -104,12 +103,6 @@ static int snd_gus_free(struct snd_gus_card *gus) | |||
104 | { | 103 | { |
105 | if (gus->gf1.res_port2 == NULL) | 104 | if (gus->gf1.res_port2 == NULL) |
106 | goto __hw_end; | 105 | goto __hw_end; |
107 | #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) | ||
108 | if (gus->seq_dev) { | ||
109 | snd_device_free(gus->card, gus->seq_dev); | ||
110 | gus->seq_dev = NULL; | ||
111 | } | ||
112 | #endif | ||
113 | snd_gf1_stop(gus); | 106 | snd_gf1_stop(gus); |
114 | snd_gus_init_dma_irq(gus, 0); | 107 | snd_gus_init_dma_irq(gus, 0); |
115 | __hw_end: | 108 | __hw_end: |
@@ -408,14 +401,6 @@ static int snd_gus_check_version(struct snd_gus_card * gus) | |||
408 | return 0; | 401 | return 0; |
409 | } | 402 | } |
410 | 403 | ||
411 | #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) | ||
412 | static void snd_gus_seq_dev_free(struct snd_seq_device *seq_dev) | ||
413 | { | ||
414 | struct snd_gus_card *gus = seq_dev->private_data; | ||
415 | gus->seq_dev = NULL; | ||
416 | } | ||
417 | #endif | ||
418 | |||
419 | int snd_gus_initialize(struct snd_gus_card *gus) | 404 | int snd_gus_initialize(struct snd_gus_card *gus) |
420 | { | 405 | { |
421 | int err; | 406 | int err; |
@@ -430,15 +415,6 @@ int snd_gus_initialize(struct snd_gus_card *gus) | |||
430 | } | 415 | } |
431 | if ((err = snd_gus_init_dma_irq(gus, 1)) < 0) | 416 | if ((err = snd_gus_init_dma_irq(gus, 1)) < 0) |
432 | return err; | 417 | return err; |
433 | #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) | ||
434 | if (snd_seq_device_new(gus->card, 1, SNDRV_SEQ_DEV_ID_GUS, | ||
435 | sizeof(struct snd_gus_card *), &gus->seq_dev) >= 0) { | ||
436 | strcpy(gus->seq_dev->name, "GUS"); | ||
437 | *(struct snd_gus_card **)SNDRV_SEQ_DEVICE_ARGPTR(gus->seq_dev) = gus; | ||
438 | gus->seq_dev->private_data = gus; | ||
439 | gus->seq_dev->private_free = snd_gus_seq_dev_free; | ||
440 | } | ||
441 | #endif | ||
442 | snd_gf1_start(gus); | 418 | snd_gf1_start(gus); |
443 | gus->initialized = 1; | 419 | gus->initialized = 1; |
444 | return 0; | 420 | return 0; |
diff --git a/sound/isa/gus/gus_mem.c b/sound/isa/gus/gus_mem.c index bcf4656853c4..661205c4dcea 100644 --- a/sound/isa/gus/gus_mem.c +++ b/sound/isa/gus/gus_mem.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
24 | #include <linux/string.h> | 23 | #include <linux/string.h> |
25 | #include <sound/core.h> | 24 | #include <sound/core.h> |
diff --git a/sound/isa/gus/gus_mem_proc.c b/sound/isa/gus/gus_mem_proc.c index f69a44728ebf..2803e227aec9 100644 --- a/sound/isa/gus/gus_mem_proc.c +++ b/sound/isa/gus/gus_mem_proc.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
24 | #include <sound/core.h> | 23 | #include <sound/core.h> |
25 | #include <sound/gus.h> | 24 | #include <sound/gus.h> |
diff --git a/sound/isa/gus/gus_mixer.c b/sound/isa/gus/gus_mixer.c index a96253e16654..ebdb33469306 100644 --- a/sound/isa/gus/gus_mixer.c +++ b/sound/isa/gus/gus_mixer.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/time.h> | 22 | #include <linux/time.h> |
24 | #include <linux/wait.h> | 23 | #include <linux/wait.h> |
25 | #include <sound/core.h> | 24 | #include <sound/core.h> |
diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c index a7971f5ffe63..99731dc97325 100644 --- a/sound/isa/gus/gus_pcm.c +++ b/sound/isa/gus/gus_pcm.c | |||
@@ -25,7 +25,6 @@ | |||
25 | * | 25 | * |
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include <sound/driver.h> | ||
29 | #include <asm/dma.h> | 28 | #include <asm/dma.h> |
30 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
31 | #include <sound/core.h> | 30 | #include <sound/core.h> |
diff --git a/sound/isa/gus/gus_reset.c b/sound/isa/gus/gus_reset.c index 20cfdb87f84a..3d1fed0c2620 100644 --- a/sound/isa/gus/gus_reset.c +++ b/sound/isa/gus/gus_reset.c | |||
@@ -18,7 +18,6 @@ | |||
18 | * | 18 | * |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <sound/driver.h> | ||
22 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
23 | #include <linux/interrupt.h> | 22 | #include <linux/interrupt.h> |
24 | #include <linux/time.h> | 23 | #include <linux/time.h> |
diff --git a/sound/isa/gus/gus_sample.c b/sound/isa/gus/gus_sample.c deleted file mode 100644 index cba0829a7106..000000000000 --- a/sound/isa/gus/gus_sample.c +++ /dev/null | |||
@@ -1,165 +0,0 @@ | |||
1 | /* | ||
2 | * Routines for Gravis UltraSound soundcards - Sample support | ||
3 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> | ||
4 | * | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <sound/driver.h> | ||
23 | #include <linux/time.h> | ||
24 | #include <sound/core.h> | ||
25 | #include <sound/gus.h> | ||
26 | |||
27 | /* | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | static void select_instrument(struct snd_gus_card * gus, struct snd_gus_voice * v) | ||
32 | { | ||
33 | struct snd_seq_kinstr *instr; | ||
34 | |||
35 | #if 0 | ||
36 | printk("select instrument: cluster = %li, std = 0x%x, bank = %i, prg = %i\n", | ||
37 | v->instr.cluster, | ||
38 | v->instr.std, | ||
39 | v->instr.bank, | ||
40 | v->instr.prg); | ||
41 | #endif | ||
42 | instr = snd_seq_instr_find(gus->gf1.ilist, &v->instr, 0, 1); | ||
43 | if (instr != NULL) { | ||
44 | if (instr->ops) { | ||
45 | if (!strcmp(instr->ops->instr_type, SNDRV_SEQ_INSTR_ID_SIMPLE)) | ||
46 | snd_gf1_simple_init(v); | ||
47 | } | ||
48 | snd_seq_instr_free_use(gus->gf1.ilist, instr); | ||
49 | } | ||
50 | } | ||
51 | |||
52 | /* | ||
53 | * | ||
54 | */ | ||
55 | |||
56 | static void event_sample(struct snd_seq_event *ev, struct snd_gus_port *p, | ||
57 | struct snd_gus_voice *v) | ||
58 | { | ||
59 | if (v->sample_ops && v->sample_ops->sample_stop) | ||
60 | v->sample_ops->sample_stop(p->gus, v, SAMPLE_STOP_IMMEDIATELY); | ||
61 | v->instr.std = ev->data.sample.param.sample.std; | ||
62 | if (v->instr.std & 0xff000000) { /* private instrument */ | ||
63 | v->instr.std &= 0x00ffffff; | ||
64 | v->instr.std |= (unsigned int)ev->source.client << 24; | ||
65 | } | ||
66 | v->instr.bank = ev->data.sample.param.sample.bank; | ||
67 | v->instr.prg = ev->data.sample.param.sample.prg; | ||
68 | select_instrument(p->gus, v); | ||
69 | } | ||
70 | |||
71 | static void event_cluster(struct snd_seq_event *ev, struct snd_gus_port *p, | ||
72 | struct snd_gus_voice *v) | ||
73 | { | ||
74 | if (v->sample_ops && v->sample_ops->sample_stop) | ||
75 | v->sample_ops->sample_stop(p->gus, v, SAMPLE_STOP_IMMEDIATELY); | ||
76 | v->instr.cluster = ev->data.sample.param.cluster.cluster; | ||
77 | select_instrument(p->gus, v); | ||
78 | } | ||
79 | |||
80 | static void event_start(struct snd_seq_event *ev, struct snd_gus_port *p, | ||
81 | struct snd_gus_voice *v) | ||
82 | { | ||
83 | if (v->sample_ops && v->sample_ops->sample_start) | ||
84 | v->sample_ops->sample_start(p->gus, v, ev->data.sample.param.position); | ||
85 | } | ||
86 | |||
87 | static void event_stop(struct snd_seq_event *ev, struct snd_gus_port *p, | ||
88 | struct snd_gus_voice *v) | ||
89 | { | ||
90 | if (v->sample_ops && v->sample_ops->sample_stop) | ||
91 | v->sample_ops->sample_stop(p->gus, v, ev->data.sample.param.stop_mode); | ||
92 | } | ||
93 | |||
94 | static void event_freq(struct snd_seq_event *ev, struct snd_gus_port *p, | ||
95 | struct snd_gus_voice *v) | ||
96 | { | ||
97 | if (v->sample_ops && v->sample_ops->sample_freq) | ||
98 | v->sample_ops->sample_freq(p->gus, v, ev->data.sample.param.frequency); | ||
99 | } | ||
100 | |||
101 | static void event_volume(struct snd_seq_event *ev, struct snd_gus_port *p, | ||
102 | struct snd_gus_voice *v) | ||
103 | { | ||
104 | if (v->sample_ops && v->sample_ops->sample_volume) | ||
105 | v->sample_ops->sample_volume(p->gus, v, &ev->data.sample.param.volume); | ||
106 | } | ||
107 | |||
108 | static void event_loop(struct snd_seq_event *ev, struct snd_gus_port *p, | ||
109 | struct snd_gus_voice *v) | ||
110 | { | ||
111 | if (v->sample_ops && v->sample_ops->sample_loop) | ||
112 | v->sample_ops->sample_loop(p->gus, v, &ev->data.sample.param.loop); | ||
113 | } | ||
114 | |||
115 | static void event_position(struct snd_seq_event *ev, struct snd_gus_port *p, | ||
116 | struct snd_gus_voice *v) | ||
117 | { | ||
118 | if (v->sample_ops && v->sample_ops->sample_pos) | ||
119 | v->sample_ops->sample_pos(p->gus, v, ev->data.sample.param.position); | ||
120 | } | ||
121 | |||
122 | static void event_private1(struct snd_seq_event *ev, struct snd_gus_port *p, | ||
123 | struct snd_gus_voice *v) | ||
124 | { | ||
125 | if (v->sample_ops && v->sample_ops->sample_private1) | ||
126 | v->sample_ops->sample_private1(p->gus, v, (unsigned char *)&ev->data.sample.param.raw8); | ||
127 | } | ||
128 | |||
129 | typedef void (gus_sample_event_handler_t)(struct snd_seq_event *ev, | ||
130 | struct snd_gus_port *p, | ||
131 | struct snd_gus_voice *v); | ||
132 | static gus_sample_event_handler_t *gus_sample_event_handlers[9] = { | ||
133 | event_sample, | ||
134 | event_cluster, | ||
135 | event_start, | ||
136 | event_stop, | ||
137 | event_freq, | ||
138 | event_volume, | ||
139 | event_loop, | ||
140 | event_position, | ||
141 | event_private1 | ||
142 | }; | ||
143 | |||
144 | void snd_gus_sample_event(struct snd_seq_event *ev, struct snd_gus_port *p) | ||
145 | { | ||
146 | int idx, voice; | ||
147 | struct snd_gus_card *gus = p->gus; | ||
148 | struct snd_gus_voice *v; | ||
149 | unsigned long flags; | ||
150 | |||
151 | idx = ev->type - SNDRV_SEQ_EVENT_SAMPLE; | ||
152 | if (idx < 0 || idx > 8) | ||
153 | return; | ||
154 | for (voice = 0; voice < 32; voice++) { | ||
155 | v = &gus->gf1.voices[voice]; | ||
156 | if (v->use && v->client == ev->source.client && | ||
157 | v->port == ev->source.port && | ||
158 | v->index == ev->data.sample.channel) { | ||
159 | spin_lock_irqsave(&gus->event_lock, flags); | ||
160 | gus_sample_event_handlers[idx](ev, p, v); | ||
161 | spin_unlock_irqrestore(&gus->event_lock, flags); | ||
162 | return; | ||
163 | } | ||
164 | } | ||
165 | } | ||
diff --git a/sound/isa/gus/gus_simple.c b/sound/isa/gus/gus_simple.c deleted file mode 100644 index 39d121e2c8c4..000000000000 --- a/sound/isa/gus/gus_simple.c +++ /dev/null | |||
@@ -1,634 +0,0 @@ | |||
1 | /* | ||
2 | * Routines for Gravis UltraSound soundcards - Simple instrument handlers | ||
3 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> | ||
4 | * | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <sound/driver.h> | ||
23 | #include <linux/time.h> | ||
24 | #include <sound/core.h> | ||
25 | #include <sound/gus.h> | ||
26 | #include "gus_tables.h" | ||
27 | |||
28 | /* | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | static void interrupt_wave(struct snd_gus_card *gus, struct snd_gus_voice *voice); | ||
33 | static void interrupt_volume(struct snd_gus_card *gus, struct snd_gus_voice *voice); | ||
34 | static void interrupt_effect(struct snd_gus_card *gus, struct snd_gus_voice *voice); | ||
35 | |||
36 | static void sample_start(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_position_t position); | ||
37 | static void sample_stop(struct snd_gus_card *gus, struct snd_gus_voice *voice, int mode); | ||
38 | static void sample_freq(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_frequency_t freq); | ||
39 | static void sample_volume(struct snd_gus_card *card, struct snd_gus_voice *voice, struct snd_seq_ev_volume *volume); | ||
40 | static void sample_loop(struct snd_gus_card *card, struct snd_gus_voice *voice, struct snd_seq_ev_loop *loop); | ||
41 | static void sample_pos(struct snd_gus_card *card, struct snd_gus_voice *voice, snd_seq_position_t position); | ||
42 | static void sample_private1(struct snd_gus_card *card, struct snd_gus_voice *voice, unsigned char *data); | ||
43 | |||
44 | static struct snd_gus_sample_ops sample_ops = { | ||
45 | sample_start, | ||
46 | sample_stop, | ||
47 | sample_freq, | ||
48 | sample_volume, | ||
49 | sample_loop, | ||
50 | sample_pos, | ||
51 | sample_private1 | ||
52 | }; | ||
53 | |||
54 | #if 0 | ||
55 | |||
56 | static void note_stop(struct snd_gus_card *gus, struct snd_gus_voice *voice, int wait); | ||
57 | static void note_wait(struct snd_gus_card *gus, struct snd_gus_voice *voice); | ||
58 | static void note_off(struct snd_gus_card *gus, struct snd_gus_voice *voice); | ||
59 | static void note_volume(struct snd_gus_card *card, struct snd_gus_voice *voice); | ||
60 | static void note_pitchbend(struct snd_gus_card *card, struct snd_gus_voice *voice); | ||
61 | static void note_vibrato(struct snd_gus_card *card, struct snd_gus_voice *voice); | ||
62 | static void note_tremolo(struct snd_gus_card *card, struct snd_gus_voice *voice); | ||
63 | |||
64 | static struct snd_gus_note_handlers note_commands = { | ||
65 | note_stop, | ||
66 | note_wait, | ||
67 | note_off, | ||
68 | note_volume, | ||
69 | note_pitchbend, | ||
70 | note_vibrato, | ||
71 | note_tremolo | ||
72 | }; | ||
73 | |||
74 | static void chn_trigger_down(struct snd_gus_card *card, ultra_channel_t *channel, ultra_instrument_t *instrument, unsigned char note, unsigned char velocity, unsigned char priority ); | ||
75 | static void chn_trigger_up( ultra_card_t *card, ultra_note_t *note ); | ||
76 | static void chn_control( ultra_card_t *card, ultra_channel_t *channel, unsigned short p1, unsigned short p2 ); | ||
77 | |||
78 | static struct ULTRA_STRU_INSTRUMENT_CHANNEL_COMMANDS channel_commands = { | ||
79 | chn_trigger_down, | ||
80 | chn_trigger_up, | ||
81 | chn_control | ||
82 | }; | ||
83 | |||
84 | #endif | ||
85 | |||
86 | static void do_volume_envelope(struct snd_gus_card *card, struct snd_gus_voice *voice); | ||
87 | static void do_pan_envelope(struct snd_gus_card *card, struct snd_gus_voice *voice); | ||
88 | |||
89 | /* | ||
90 | * | ||
91 | */ | ||
92 | |||
93 | static void interrupt_wave(struct snd_gus_card *gus, struct snd_gus_voice *voice) | ||
94 | { | ||
95 | spin_lock(&gus->event_lock); | ||
96 | snd_gf1_stop_voice(gus, voice->number); | ||
97 | spin_lock(&gus->reg_lock); | ||
98 | snd_gf1_select_voice(gus, voice->number); | ||
99 | snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, 0); | ||
100 | spin_unlock(&gus->reg_lock); | ||
101 | voice->flags &= ~SNDRV_GF1_VFLG_RUNNING; | ||
102 | spin_unlock(&gus->event_lock); | ||
103 | } | ||
104 | |||
105 | static void interrupt_volume(struct snd_gus_card *gus, struct snd_gus_voice *voice) | ||
106 | { | ||
107 | spin_lock(&gus->event_lock); | ||
108 | if (voice->flags & SNDRV_GF1_VFLG_RUNNING) | ||
109 | do_volume_envelope(gus, voice); | ||
110 | else | ||
111 | snd_gf1_stop_voice(gus, voice->number); | ||
112 | spin_unlock(&gus->event_lock); | ||
113 | } | ||
114 | |||
115 | static void interrupt_effect(struct snd_gus_card *gus, struct snd_gus_voice *voice) | ||
116 | { | ||
117 | spin_lock(&gus->event_lock); | ||
118 | if ((voice->flags & (SNDRV_GF1_VFLG_RUNNING|SNDRV_GF1_VFLG_EFFECT_TIMER1)) == | ||
119 | (SNDRV_GF1_VFLG_RUNNING|SNDRV_GF1_VFLG_EFFECT_TIMER1)) | ||
120 | do_pan_envelope(gus, voice); | ||
121 | spin_unlock(&gus->event_lock); | ||
122 | } | ||
123 | |||
124 | /* | ||
125 | * | ||
126 | */ | ||
127 | |||
128 | static void do_volume_envelope(struct snd_gus_card *gus, struct snd_gus_voice *voice) | ||
129 | { | ||
130 | unsigned short next, rate, old_volume; | ||
131 | int program_next_ramp; | ||
132 | unsigned long flags; | ||
133 | |||
134 | if (!gus->gf1.volume_ramp) { | ||
135 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
136 | snd_gf1_select_voice(gus, voice->number); | ||
137 | snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL); | ||
138 | snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, voice->gf1_volume); | ||
139 | /* printk("gf1_volume = 0x%x\n", voice->gf1_volume); */ | ||
140 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
141 | return; | ||
142 | } | ||
143 | program_next_ramp = 0; | ||
144 | rate = next = 0; | ||
145 | while (1) { | ||
146 | program_next_ramp = 0; | ||
147 | rate = next = 0; | ||
148 | switch (voice->venv_state) { | ||
149 | case VENV_BEFORE: | ||
150 | voice->venv_state = VENV_ATTACK; | ||
151 | voice->venv_value_next = 0; | ||
152 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
153 | snd_gf1_select_voice(gus, voice->number); | ||
154 | snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL); | ||
155 | snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, SNDRV_GF1_MIN_VOLUME); | ||
156 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
157 | break; | ||
158 | case VENV_ATTACK: | ||
159 | voice->venv_state = VENV_SUSTAIN; | ||
160 | program_next_ramp++; | ||
161 | next = 255; | ||
162 | rate = gus->gf1.volume_ramp; | ||
163 | break; | ||
164 | case VENV_SUSTAIN: | ||
165 | voice->venv_state = VENV_RELEASE; | ||
166 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
167 | snd_gf1_select_voice(gus, voice->number); | ||
168 | snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL); | ||
169 | snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, ((int)voice->gf1_volume * (int)voice->venv_value_next) / 255); | ||
170 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
171 | return; | ||
172 | case VENV_RELEASE: | ||
173 | voice->venv_state = VENV_DONE; | ||
174 | program_next_ramp++; | ||
175 | next = 0; | ||
176 | rate = gus->gf1.volume_ramp; | ||
177 | break; | ||
178 | case VENV_DONE: | ||
179 | snd_gf1_stop_voice(gus, voice->number); | ||
180 | voice->flags &= ~SNDRV_GF1_VFLG_RUNNING; | ||
181 | return; | ||
182 | case VENV_VOLUME: | ||
183 | program_next_ramp++; | ||
184 | next = voice->venv_value_next; | ||
185 | rate = gus->gf1.volume_ramp; | ||
186 | voice->venv_state = voice->venv_state_prev; | ||
187 | break; | ||
188 | } | ||
189 | voice->venv_value_next = next; | ||
190 | if (!program_next_ramp) | ||
191 | continue; | ||
192 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
193 | snd_gf1_select_voice(gus, voice->number); | ||
194 | snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL); | ||
195 | old_volume = snd_gf1_read16(gus, SNDRV_GF1_VW_VOLUME) >> 8; | ||
196 | if (!rate) { | ||
197 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
198 | continue; | ||
199 | } | ||
200 | next = (((int)voice->gf1_volume * (int)next) / 255) >> 8; | ||
201 | if (old_volume < SNDRV_GF1_MIN_OFFSET) | ||
202 | old_volume = SNDRV_GF1_MIN_OFFSET; | ||
203 | if (next < SNDRV_GF1_MIN_OFFSET) | ||
204 | next = SNDRV_GF1_MIN_OFFSET; | ||
205 | if (next > SNDRV_GF1_MAX_OFFSET) | ||
206 | next = SNDRV_GF1_MAX_OFFSET; | ||
207 | if (old_volume == next) { | ||
208 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
209 | continue; | ||
210 | } | ||
211 | voice->volume_control &= ~0xc3; | ||
212 | voice->volume_control |= 0x20; | ||
213 | if (old_volume > next) { | ||
214 | snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_START, next); | ||
215 | snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_END, old_volume); | ||
216 | voice->volume_control |= 0x40; | ||
217 | } else { | ||
218 | snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_START, old_volume); | ||
219 | snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_END, next); | ||
220 | } | ||
221 | snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_RATE, rate); | ||
222 | snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, voice->volume_control); | ||
223 | if (!gus->gf1.enh_mode) { | ||
224 | snd_gf1_delay(gus); | ||
225 | snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, voice->volume_control); | ||
226 | } | ||
227 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
228 | return; | ||
229 | } | ||
230 | } | ||
231 | |||
232 | static void do_pan_envelope(struct snd_gus_card *gus, struct snd_gus_voice *voice) | ||
233 | { | ||
234 | unsigned long flags; | ||
235 | unsigned char old_pan; | ||
236 | |||
237 | #if 0 | ||
238 | snd_gf1_select_voice(gus, voice->number); | ||
239 | printk(" -%i- do_pan_envelope - flags = 0x%x (0x%x -> 0x%x)\n", | ||
240 | voice->number, | ||
241 | voice->flags, | ||
242 | voice->gf1_pan, | ||
243 | snd_gf1_i_read8(gus, SNDRV_GF1_VB_PAN) & 0x0f); | ||
244 | #endif | ||
245 | if (gus->gf1.enh_mode) { | ||
246 | voice->flags &= ~(SNDRV_GF1_VFLG_EFFECT_TIMER1|SNDRV_GF1_VFLG_PAN); | ||
247 | return; | ||
248 | } | ||
249 | if (!gus->gf1.smooth_pan) { | ||
250 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
251 | snd_gf1_select_voice(gus, voice->number); | ||
252 | snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, voice->gf1_pan); | ||
253 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
254 | return; | ||
255 | } | ||
256 | if (!(voice->flags & SNDRV_GF1_VFLG_PAN)) /* before */ | ||
257 | voice->flags |= SNDRV_GF1_VFLG_EFFECT_TIMER1|SNDRV_GF1_VFLG_PAN; | ||
258 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
259 | snd_gf1_select_voice(gus, voice->number); | ||
260 | old_pan = snd_gf1_read8(gus, SNDRV_GF1_VB_PAN) & 0x0f; | ||
261 | if (old_pan > voice->gf1_pan ) | ||
262 | old_pan--; | ||
263 | if (old_pan < voice->gf1_pan) | ||
264 | old_pan++; | ||
265 | snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, old_pan); | ||
266 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
267 | if (old_pan == voice->gf1_pan) /* the goal was reached */ | ||
268 | voice->flags &= ~(SNDRV_GF1_VFLG_EFFECT_TIMER1|SNDRV_GF1_VFLG_PAN); | ||
269 | #if 0 | ||
270 | snd_gf1_select_voice(gus, voice->number); | ||
271 | printk(" -%i- (1) do_pan_envelope - flags = 0x%x (0x%x -> 0x%x)\n", | ||
272 | voice->number, | ||
273 | voice->flags, | ||
274 | voice->gf1_pan, | ||
275 | snd_gf1_i_read8(gus, GF1_VB_PAN) & 0x0f); | ||
276 | #endif | ||
277 | } | ||
278 | |||
279 | static void set_enhanced_pan(struct snd_gus_card *gus, struct snd_gus_voice *voice, unsigned short pan) | ||
280 | { | ||
281 | unsigned long flags; | ||
282 | unsigned short vlo, vro; | ||
283 | |||
284 | vlo = SNDRV_GF1_ATTEN((SNDRV_GF1_ATTEN_TABLE_SIZE-1) - pan); | ||
285 | vro = SNDRV_GF1_ATTEN(pan); | ||
286 | if (pan != SNDRV_GF1_ATTEN_TABLE_SIZE - 1 && pan != 0) { | ||
287 | vlo >>= 1; | ||
288 | vro >>= 1; | ||
289 | } | ||
290 | vlo <<= 4; | ||
291 | vro <<= 4; | ||
292 | #if 0 | ||
293 | printk("vlo = 0x%x (0x%x), vro = 0x%x (0x%x)\n", | ||
294 | vlo, snd_gf1_i_read16(gus, GF1_VW_OFFSET_LEFT), | ||
295 | vro, snd_gf1_i_read16(gus, GF1_VW_OFFSET_RIGHT)); | ||
296 | #endif | ||
297 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
298 | snd_gf1_select_voice(gus, voice->number); | ||
299 | snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_LEFT_FINAL, vlo); | ||
300 | snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_RIGHT_FINAL, vro); | ||
301 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
302 | voice->vlo = vlo; | ||
303 | voice->vro = vro; | ||
304 | } | ||
305 | |||
306 | /* | ||
307 | * | ||
308 | */ | ||
309 | |||
310 | static void sample_start(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_position_t position) | ||
311 | { | ||
312 | unsigned long flags; | ||
313 | unsigned int begin, addr, addr_end, addr_start; | ||
314 | int w_16; | ||
315 | struct simple_instrument *simple; | ||
316 | struct snd_seq_kinstr *instr; | ||
317 | |||
318 | instr = snd_seq_instr_find(gus->gf1.ilist, &voice->instr, 0, 1); | ||
319 | if (instr == NULL) | ||
320 | return; | ||
321 | voice->instr = instr->instr; /* copy ID to speedup aliases */ | ||
322 | simple = KINSTR_DATA(instr); | ||
323 | begin = simple->address.memory << 4; | ||
324 | w_16 = simple->format & SIMPLE_WAVE_16BIT ? 0x04 : 0; | ||
325 | addr_start = simple->loop_start; | ||
326 | if (simple->format & SIMPLE_WAVE_LOOP) { | ||
327 | addr_end = simple->loop_end; | ||
328 | } else { | ||
329 | addr_end = (simple->size << 4) - (w_16 ? 40 : 24); | ||
330 | } | ||
331 | if (simple->format & SIMPLE_WAVE_BACKWARD) { | ||
332 | addr = simple->loop_end; | ||
333 | if (position < simple->loop_end) | ||
334 | addr -= position; | ||
335 | } else { | ||
336 | addr = position; | ||
337 | } | ||
338 | voice->control = 0x00; | ||
339 | voice->mode = 0x20; /* enable offset registers */ | ||
340 | if (simple->format & SIMPLE_WAVE_16BIT) | ||
341 | voice->control |= 0x04; | ||
342 | if (simple->format & SIMPLE_WAVE_BACKWARD) | ||
343 | voice->control |= 0x40; | ||
344 | if (simple->format & SIMPLE_WAVE_LOOP) { | ||
345 | voice->control |= 0x08; | ||
346 | } else { | ||
347 | voice->control |= 0x20; | ||
348 | } | ||
349 | if (simple->format & SIMPLE_WAVE_BIDIR) | ||
350 | voice->control |= 0x10; | ||
351 | if (simple->format & SIMPLE_WAVE_ULAW) | ||
352 | voice->mode |= 0x40; | ||
353 | if (w_16) { | ||
354 | addr = ((addr << 1) & ~0x1f) | (addr & 0x0f); | ||
355 | addr_start = ((addr_start << 1) & ~0x1f) | (addr_start & 0x0f); | ||
356 | addr_end = ((addr_end << 1) & ~0x1f) | (addr_end & 0x0f); | ||
357 | } | ||
358 | addr += begin; | ||
359 | addr_start += begin; | ||
360 | addr_end += begin; | ||
361 | snd_gf1_stop_voice(gus, voice->number); | ||
362 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
363 | snd_gf1_select_voice(gus, voice->number); | ||
364 | snd_gf1_write16(gus, SNDRV_GF1_VW_FREQUENCY, voice->fc_register + voice->fc_lfo); | ||
365 | voice->venv_state = VENV_BEFORE; | ||
366 | voice->volume_control = 0x03; | ||
367 | snd_gf1_write_addr(gus, SNDRV_GF1_VA_START, addr_start, w_16); | ||
368 | snd_gf1_write_addr(gus, SNDRV_GF1_VA_END, addr_end, w_16); | ||
369 | snd_gf1_write_addr(gus, SNDRV_GF1_VA_CURRENT, addr, w_16); | ||
370 | if (!gus->gf1.enh_mode) { | ||
371 | snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, voice->gf1_pan); | ||
372 | } else { | ||
373 | snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_LEFT, voice->vlo); | ||
374 | snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_LEFT_FINAL, voice->vlo); | ||
375 | snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_RIGHT, voice->vro); | ||
376 | snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_RIGHT_FINAL, voice->vro); | ||
377 | snd_gf1_write8(gus, SNDRV_GF1_VB_ACCUMULATOR, voice->effect_accumulator); | ||
378 | snd_gf1_write16(gus, SNDRV_GF1_VW_EFFECT_VOLUME, voice->gf1_effect_volume); | ||
379 | snd_gf1_write16(gus, SNDRV_GF1_VW_EFFECT_VOLUME_FINAL, voice->gf1_effect_volume); | ||
380 | } | ||
381 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
382 | do_volume_envelope(gus, voice); | ||
383 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
384 | snd_gf1_select_voice(gus, voice->number); | ||
385 | if (gus->gf1.enh_mode) | ||
386 | snd_gf1_write8(gus, SNDRV_GF1_VB_MODE, voice->mode); | ||
387 | snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice->control); | ||
388 | if (!gus->gf1.enh_mode) { | ||
389 | snd_gf1_delay(gus); | ||
390 | snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice->control ); | ||
391 | } | ||
392 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
393 | #if 0 | ||
394 | snd_gf1_print_voice_registers(gus); | ||
395 | #endif | ||
396 | voice->flags |= SNDRV_GF1_VFLG_RUNNING; | ||
397 | snd_seq_instr_free_use(gus->gf1.ilist, instr); | ||
398 | } | ||
399 | |||
400 | static void sample_stop(struct snd_gus_card *gus, struct snd_gus_voice *voice, int mode) | ||
401 | { | ||
402 | unsigned char control; | ||
403 | unsigned long flags; | ||
404 | |||
405 | if (!(voice->flags & SNDRV_GF1_VFLG_RUNNING)) | ||
406 | return; | ||
407 | switch (mode) { | ||
408 | default: | ||
409 | if (gus->gf1.volume_ramp > 0) { | ||
410 | if (voice->venv_state < VENV_RELEASE) { | ||
411 | voice->venv_state = VENV_RELEASE; | ||
412 | do_volume_envelope(gus, voice); | ||
413 | } | ||
414 | } | ||
415 | if (mode != SAMPLE_STOP_VENVELOPE) { | ||
416 | snd_gf1_stop_voice(gus, voice->number); | ||
417 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
418 | snd_gf1_select_voice(gus, voice->number); | ||
419 | snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, SNDRV_GF1_MIN_VOLUME); | ||
420 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
421 | voice->flags &= ~SNDRV_GF1_VFLG_RUNNING; | ||
422 | } | ||
423 | break; | ||
424 | case SAMPLE_STOP_LOOP: /* disable loop only */ | ||
425 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
426 | snd_gf1_select_voice(gus, voice->number); | ||
427 | control = snd_gf1_read8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL); | ||
428 | control &= ~(0x83 | 0x04); | ||
429 | control |= 0x20; | ||
430 | snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, control); | ||
431 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
432 | break; | ||
433 | } | ||
434 | } | ||
435 | |||
436 | static void sample_freq(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_frequency_t freq) | ||
437 | { | ||
438 | unsigned long flags; | ||
439 | |||
440 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
441 | voice->fc_register = snd_gf1_translate_freq(gus, freq); | ||
442 | snd_gf1_select_voice(gus, voice->number); | ||
443 | snd_gf1_write16(gus, SNDRV_GF1_VW_FREQUENCY, voice->fc_register + voice->fc_lfo); | ||
444 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
445 | } | ||
446 | |||
447 | static void sample_volume(struct snd_gus_card *gus, struct snd_gus_voice *voice, struct snd_seq_ev_volume *volume) | ||
448 | { | ||
449 | if (volume->volume >= 0) { | ||
450 | volume->volume &= 0x3fff; | ||
451 | voice->gf1_volume = snd_gf1_lvol_to_gvol_raw(volume->volume << 2) << 4; | ||
452 | voice->venv_state_prev = VENV_SUSTAIN; | ||
453 | voice->venv_state = VENV_VOLUME; | ||
454 | do_volume_envelope(gus, voice); | ||
455 | } | ||
456 | if (volume->lr >= 0) { | ||
457 | volume->lr &= 0x3fff; | ||
458 | if (!gus->gf1.enh_mode) { | ||
459 | voice->gf1_pan = (volume->lr >> 10) & 15; | ||
460 | if (!gus->gf1.full_range_pan) { | ||
461 | if (voice->gf1_pan == 0) | ||
462 | voice->gf1_pan++; | ||
463 | if (voice->gf1_pan == 15) | ||
464 | voice->gf1_pan--; | ||
465 | } | ||
466 | voice->flags &= ~SNDRV_GF1_VFLG_PAN; /* before */ | ||
467 | do_pan_envelope(gus, voice); | ||
468 | } else { | ||
469 | set_enhanced_pan(gus, voice, volume->lr >> 7); | ||
470 | } | ||
471 | } | ||
472 | } | ||
473 | |||
474 | static void sample_loop(struct snd_gus_card *gus, struct snd_gus_voice *voice, struct snd_seq_ev_loop *loop) | ||
475 | { | ||
476 | unsigned long flags; | ||
477 | int w_16 = voice->control & 0x04; | ||
478 | unsigned int begin, addr_start, addr_end; | ||
479 | struct simple_instrument *simple; | ||
480 | struct snd_seq_kinstr *instr; | ||
481 | |||
482 | #if 0 | ||
483 | printk("voice_loop: start = 0x%x, end = 0x%x\n", loop->start, loop->end); | ||
484 | #endif | ||
485 | instr = snd_seq_instr_find(gus->gf1.ilist, &voice->instr, 0, 1); | ||
486 | if (instr == NULL) | ||
487 | return; | ||
488 | voice->instr = instr->instr; /* copy ID to speedup aliases */ | ||
489 | simple = KINSTR_DATA(instr); | ||
490 | begin = simple->address.memory; | ||
491 | addr_start = loop->start; | ||
492 | addr_end = loop->end; | ||
493 | addr_start = (((addr_start << 1) & ~0x1f) | (addr_start & 0x0f)) + begin; | ||
494 | addr_end = (((addr_end << 1) & ~0x1f) | (addr_end & 0x0f)) + begin; | ||
495 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
496 | snd_gf1_select_voice(gus, voice->number); | ||
497 | snd_gf1_write_addr(gus, SNDRV_GF1_VA_START, addr_start, w_16); | ||
498 | snd_gf1_write_addr(gus, SNDRV_GF1_VA_END, addr_end, w_16); | ||
499 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
500 | snd_seq_instr_free_use(gus->gf1.ilist, instr); | ||
501 | } | ||
502 | |||
503 | static void sample_pos(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_position_t position) | ||
504 | { | ||
505 | unsigned long flags; | ||
506 | int w_16 = voice->control & 0x04; | ||
507 | unsigned int begin, addr; | ||
508 | struct simple_instrument *simple; | ||
509 | struct snd_seq_kinstr *instr; | ||
510 | |||
511 | #if 0 | ||
512 | printk("voice_loop: start = 0x%x, end = 0x%x\n", loop->start, loop->end); | ||
513 | #endif | ||
514 | instr = snd_seq_instr_find(gus->gf1.ilist, &voice->instr, 0, 1); | ||
515 | if (instr == NULL) | ||
516 | return; | ||
517 | voice->instr = instr->instr; /* copy ID to speedup aliases */ | ||
518 | simple = KINSTR_DATA(instr); | ||
519 | begin = simple->address.memory; | ||
520 | addr = (((position << 1) & ~0x1f) | (position & 0x0f)) + begin; | ||
521 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
522 | snd_gf1_select_voice(gus, voice->number); | ||
523 | snd_gf1_write_addr(gus, SNDRV_GF1_VA_CURRENT, addr, w_16); | ||
524 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
525 | snd_seq_instr_free_use(gus->gf1.ilist, instr); | ||
526 | } | ||
527 | |||
528 | #if 0 | ||
529 | |||
530 | static unsigned char get_effects_mask( ultra_card_t *card, int value ) | ||
531 | { | ||
532 | if ( value > 7 ) return 0; | ||
533 | if ( card -> gf1.effects && card -> gf1.effects -> chip_type == ULTRA_EFFECT_CHIP_INTERWAVE ) | ||
534 | return card -> gf1.effects -> chip.interwave.voice_output[ value ]; | ||
535 | return 0; | ||
536 | } | ||
537 | |||
538 | #endif | ||
539 | |||
540 | static void sample_private1(struct snd_gus_card *card, struct snd_gus_voice *voice, unsigned char *data) | ||
541 | { | ||
542 | #if 0 | ||
543 | unsigned long flags; | ||
544 | unsigned char uc; | ||
545 | |||
546 | switch ( *data ) { | ||
547 | case ULTRA_PRIV1_IW_EFFECT: | ||
548 | uc = get_effects_mask( card, ultra_get_byte( data, 4 ) ); | ||
549 | uc |= get_effects_mask( card, ultra_get_byte( data, 4 ) >> 4 ); | ||
550 | uc |= get_effects_mask( card, ultra_get_byte( data, 5 ) ); | ||
551 | uc |= get_effects_mask( card, ultra_get_byte( data, 5 ) >> 4 ); | ||
552 | voice -> data.simple.effect_accumulator = uc; | ||
553 | voice -> data.simple.effect_volume = ultra_translate_voice_volume( card, ultra_get_word( data, 2 ) ) << 4; | ||
554 | if ( !card -> gf1.enh_mode ) return; | ||
555 | if ( voice -> flags & VFLG_WAIT_FOR_START ) return; | ||
556 | if ( voice -> flags & VFLG_RUNNING ) | ||
557 | { | ||
558 | CLI( &flags ); | ||
559 | gf1_select_voice( card, voice -> number ); | ||
560 | ultra_write8( card, GF1_VB_ACCUMULATOR, voice -> data.simple.effect_accumulator ); | ||
561 | ultra_write16( card, GF1_VW_EFFECT_VOLUME_FINAL, voice -> data.simple.effect_volume ); | ||
562 | STI( &flags ); | ||
563 | } | ||
564 | break; | ||
565 | case ULTRA_PRIV1_IW_LFO: | ||
566 | ultra_lfo_command( card, voice -> number, data ); | ||
567 | } | ||
568 | #endif | ||
569 | } | ||
570 | |||
571 | #if 0 | ||
572 | |||
573 | /* | ||
574 | * | ||
575 | */ | ||
576 | |||
577 | static void note_stop( ultra_card_t *card, ultra_voice_t *voice, int wait ) | ||
578 | { | ||
579 | } | ||
580 | |||
581 | static void note_wait( ultra_card_t *card, ultra_voice_t *voice ) | ||
582 | { | ||
583 | } | ||
584 | |||
585 | static void note_off( ultra_card_t *card, ultra_voice_t *voice ) | ||
586 | { | ||
587 | } | ||
588 | |||
589 | static void note_volume( ultra_card_t *card, ultra_voice_t *voice ) | ||
590 | { | ||
591 | } | ||
592 | |||
593 | static void note_pitchbend( ultra_card_t *card, ultra_voice_t *voice ) | ||
594 | { | ||
595 | } | ||
596 | |||
597 | static void note_vibrato( ultra_card_t *card, ultra_voice_t *voice ) | ||
598 | { | ||
599 | } | ||
600 | |||
601 | static void note_tremolo( ultra_card_t *card, ultra_voice_t *voice ) | ||
602 | { | ||
603 | } | ||
604 | |||
605 | /* | ||
606 | * | ||
607 | */ | ||
608 | |||
609 | static void chn_trigger_down( ultra_card_t *card, ultra_channel_t *channel, ultra_instrument_t *instrument, unsigned char note, unsigned char velocity, unsigned char priority ) | ||
610 | { | ||
611 | } | ||
612 | |||
613 | static void chn_trigger_up( ultra_card_t *card, ultra_note_t *note ) | ||
614 | { | ||
615 | } | ||
616 | |||
617 | static void chn_control( ultra_card_t *card, ultra_channel_t *channel, unsigned short p1, unsigned short p2 ) | ||
618 | { | ||
619 | } | ||
620 | |||
621 | /* | ||
622 | * | ||
623 | */ | ||
624 | |||
625 | #endif | ||
626 | |||
627 | void snd_gf1_simple_init(struct snd_gus_voice *voice) | ||
628 | { | ||
629 | voice->handler_wave = interrupt_wave; | ||
630 | voice->handler_volume = interrupt_volume; | ||
631 | voice->handler_effect = interrupt_effect; | ||
632 | voice->volume_change = NULL; | ||
633 | voice->sample_ops = &sample_ops; | ||
634 | } | ||
diff --git a/sound/isa/gus/gus_synth.c b/sound/isa/gus/gus_synth.c deleted file mode 100644 index 2c2051782aa2..000000000000 --- a/sound/isa/gus/gus_synth.c +++ /dev/null | |||
@@ -1,314 +0,0 @@ | |||
1 | /* | ||
2 | * Routines for Gravis UltraSound soundcards - Synthesizer | ||
3 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> | ||
4 | * | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/time.h> | ||
25 | #include <sound/core.h> | ||
26 | #include <sound/gus.h> | ||
27 | #include <sound/seq_device.h> | ||
28 | |||
29 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); | ||
30 | MODULE_DESCRIPTION("Routines for Gravis UltraSound soundcards - Synthesizer"); | ||
31 | MODULE_LICENSE("GPL"); | ||
32 | |||
33 | /* | ||
34 | * | ||
35 | */ | ||
36 | |||
37 | static void snd_gus_synth_free_voices(struct snd_gus_card * gus, int client, int port) | ||
38 | { | ||
39 | int idx; | ||
40 | struct snd_gus_voice * voice; | ||
41 | |||
42 | for (idx = 0; idx < 32; idx++) { | ||
43 | voice = &gus->gf1.voices[idx]; | ||
44 | if (voice->use && voice->client == client && voice->port == port) | ||
45 | snd_gf1_free_voice(gus, voice); | ||
46 | } | ||
47 | } | ||
48 | |||
49 | static int snd_gus_synth_use(void *private_data, struct snd_seq_port_subscribe *info) | ||
50 | { | ||
51 | struct snd_gus_port * port = private_data; | ||
52 | struct snd_gus_card * gus = port->gus; | ||
53 | struct snd_gus_voice * voice; | ||
54 | unsigned int idx; | ||
55 | |||
56 | if (info->voices > 32) | ||
57 | return -EINVAL; | ||
58 | mutex_lock(&gus->register_mutex); | ||
59 | if (!snd_gus_use_inc(gus)) { | ||
60 | mutex_unlock(&gus->register_mutex); | ||
61 | return -EFAULT; | ||
62 | } | ||
63 | for (idx = 0; idx < info->voices; idx++) { | ||
64 | voice = snd_gf1_alloc_voice(gus, SNDRV_GF1_VOICE_TYPE_SYNTH, info->sender.client, info->sender.port); | ||
65 | if (voice == NULL) { | ||
66 | snd_gus_synth_free_voices(gus, info->sender.client, info->sender.port); | ||
67 | snd_gus_use_dec(gus); | ||
68 | mutex_unlock(&gus->register_mutex); | ||
69 | return -EBUSY; | ||
70 | } | ||
71 | voice->index = idx; | ||
72 | } | ||
73 | mutex_unlock(&gus->register_mutex); | ||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | static int snd_gus_synth_unuse(void *private_data, struct snd_seq_port_subscribe *info) | ||
78 | { | ||
79 | struct snd_gus_port * port = private_data; | ||
80 | struct snd_gus_card * gus = port->gus; | ||
81 | |||
82 | mutex_lock(&gus->register_mutex); | ||
83 | snd_gus_synth_free_voices(gus, info->sender.client, info->sender.port); | ||
84 | snd_gus_use_dec(gus); | ||
85 | mutex_unlock(&gus->register_mutex); | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * | ||
91 | */ | ||
92 | |||
93 | static void snd_gus_synth_free_private_instruments(struct snd_gus_port *p, int client) | ||
94 | { | ||
95 | struct snd_seq_instr_header ifree; | ||
96 | |||
97 | memset(&ifree, 0, sizeof(ifree)); | ||
98 | ifree.cmd = SNDRV_SEQ_INSTR_FREE_CMD_PRIVATE; | ||
99 | snd_seq_instr_list_free_cond(p->gus->gf1.ilist, &ifree, client, 0); | ||
100 | } | ||
101 | |||
102 | static int snd_gus_synth_event_input(struct snd_seq_event *ev, int direct, | ||
103 | void *private_data, int atomic, int hop) | ||
104 | { | ||
105 | struct snd_gus_port * p = private_data; | ||
106 | |||
107 | snd_assert(p != NULL, return -EINVAL); | ||
108 | if (ev->type >= SNDRV_SEQ_EVENT_SAMPLE && | ||
109 | ev->type <= SNDRV_SEQ_EVENT_SAMPLE_PRIVATE1) { | ||
110 | snd_gus_sample_event(ev, p); | ||
111 | return 0; | ||
112 | } | ||
113 | if (ev->source.client == SNDRV_SEQ_CLIENT_SYSTEM && | ||
114 | ev->source.port == SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE) { | ||
115 | if (ev->type == SNDRV_SEQ_EVENT_CLIENT_EXIT) { | ||
116 | snd_gus_synth_free_private_instruments(p, ev->data.addr.client); | ||
117 | return 0; | ||
118 | } | ||
119 | } | ||
120 | if (direct) { | ||
121 | if (ev->type >= SNDRV_SEQ_EVENT_INSTR_BEGIN) { | ||
122 | snd_seq_instr_event(&p->gus->gf1.iwffff_ops.kops, | ||
123 | p->gus->gf1.ilist, | ||
124 | ev, | ||
125 | p->gus->gf1.seq_client, | ||
126 | atomic, hop); | ||
127 | return 0; | ||
128 | } | ||
129 | } | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static void snd_gus_synth_instr_notify(void *private_data, | ||
134 | struct snd_seq_kinstr *instr, | ||
135 | int what) | ||
136 | { | ||
137 | unsigned int idx; | ||
138 | struct snd_gus_card *gus = private_data; | ||
139 | struct snd_gus_voice *pvoice; | ||
140 | unsigned long flags; | ||
141 | |||
142 | spin_lock_irqsave(&gus->event_lock, flags); | ||
143 | for (idx = 0; idx < 32; idx++) { | ||
144 | pvoice = &gus->gf1.voices[idx]; | ||
145 | if (pvoice->use && !memcmp(&pvoice->instr, &instr->instr, sizeof(pvoice->instr))) { | ||
146 | if (pvoice->sample_ops && pvoice->sample_ops->sample_stop) { | ||
147 | pvoice->sample_ops->sample_stop(gus, pvoice, SAMPLE_STOP_IMMEDIATELY); | ||
148 | } else { | ||
149 | snd_gf1_stop_voice(gus, pvoice->number); | ||
150 | pvoice->flags &= ~SNDRV_GF1_VFLG_RUNNING; | ||
151 | } | ||
152 | } | ||
153 | } | ||
154 | spin_unlock_irqrestore(&gus->event_lock, flags); | ||
155 | } | ||
156 | |||
157 | /* | ||
158 | * | ||
159 | */ | ||
160 | |||
161 | static void snd_gus_synth_free_port(void *private_data) | ||
162 | { | ||
163 | struct snd_gus_port * p = private_data; | ||
164 | |||
165 | if (p) | ||
166 | snd_midi_channel_free_set(p->chset); | ||
167 | } | ||
168 | |||
169 | static int snd_gus_synth_create_port(struct snd_gus_card * gus, int idx) | ||
170 | { | ||
171 | struct snd_gus_port * p; | ||
172 | struct snd_seq_port_callback callbacks; | ||
173 | char name[32]; | ||
174 | int result; | ||
175 | |||
176 | p = &gus->gf1.seq_ports[idx]; | ||
177 | p->chset = snd_midi_channel_alloc_set(16); | ||
178 | if (p->chset == NULL) | ||
179 | return -ENOMEM; | ||
180 | p->chset->private_data = p; | ||
181 | p->gus = gus; | ||
182 | p->client = gus->gf1.seq_client; | ||
183 | |||
184 | memset(&callbacks, 0, sizeof(callbacks)); | ||
185 | callbacks.owner = THIS_MODULE; | ||
186 | callbacks.use = snd_gus_synth_use; | ||
187 | callbacks.unuse = snd_gus_synth_unuse; | ||
188 | callbacks.event_input = snd_gus_synth_event_input; | ||
189 | callbacks.private_free = snd_gus_synth_free_port; | ||
190 | callbacks.private_data = p; | ||
191 | |||
192 | sprintf(name, "%s port %i", gus->interwave ? "AMD InterWave" : "GF1", idx); | ||
193 | p->chset->port = snd_seq_event_port_attach(gus->gf1.seq_client, | ||
194 | &callbacks, | ||
195 | SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE, | ||
196 | SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE | | ||
197 | SNDRV_SEQ_PORT_TYPE_SYNTH | | ||
198 | SNDRV_SEQ_PORT_TYPE_HARDWARE | | ||
199 | SNDRV_SEQ_PORT_TYPE_SYNTHESIZER, | ||
200 | 16, 0, | ||
201 | name); | ||
202 | if (p->chset->port < 0) { | ||
203 | result = p->chset->port; | ||
204 | snd_gus_synth_free_port(p); | ||
205 | return result; | ||
206 | } | ||
207 | p->port = p->chset->port; | ||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | /* | ||
212 | * | ||
213 | */ | ||
214 | |||
215 | static int snd_gus_synth_new_device(struct snd_seq_device *dev) | ||
216 | { | ||
217 | struct snd_gus_card *gus; | ||
218 | int client, i; | ||
219 | struct snd_seq_port_subscribe sub; | ||
220 | struct snd_iwffff_ops *iwops; | ||
221 | struct snd_gf1_ops *gf1ops; | ||
222 | struct snd_simple_ops *simpleops; | ||
223 | |||
224 | gus = *(struct snd_gus_card **)SNDRV_SEQ_DEVICE_ARGPTR(dev); | ||
225 | if (gus == NULL) | ||
226 | return -EINVAL; | ||
227 | |||
228 | mutex_init(&gus->register_mutex); | ||
229 | gus->gf1.seq_client = -1; | ||
230 | |||
231 | /* allocate new client */ | ||
232 | client = gus->gf1.seq_client = | ||
233 | snd_seq_create_kernel_client(gus->card, 1, gus->interwave ? | ||
234 | "AMD InterWave" : "GF1"); | ||
235 | if (client < 0) | ||
236 | return client; | ||
237 | |||
238 | for (i = 0; i < 4; i++) | ||
239 | snd_gus_synth_create_port(gus, i); | ||
240 | |||
241 | gus->gf1.ilist = snd_seq_instr_list_new(); | ||
242 | if (gus->gf1.ilist == NULL) { | ||
243 | snd_seq_delete_kernel_client(client); | ||
244 | gus->gf1.seq_client = -1; | ||
245 | return -ENOMEM; | ||
246 | } | ||
247 | gus->gf1.ilist->flags = SNDRV_SEQ_INSTR_FLG_DIRECT; | ||
248 | |||
249 | simpleops = &gus->gf1.simple_ops; | ||
250 | snd_seq_simple_init(simpleops, gus, NULL); | ||
251 | simpleops->put_sample = snd_gus_simple_put_sample; | ||
252 | simpleops->get_sample = snd_gus_simple_get_sample; | ||
253 | simpleops->remove_sample = snd_gus_simple_remove_sample; | ||
254 | simpleops->notify = snd_gus_synth_instr_notify; | ||
255 | |||
256 | gf1ops = &gus->gf1.gf1_ops; | ||
257 | snd_seq_gf1_init(gf1ops, gus, &simpleops->kops); | ||
258 | gf1ops->put_sample = snd_gus_gf1_put_sample; | ||
259 | gf1ops->get_sample = snd_gus_gf1_get_sample; | ||
260 | gf1ops->remove_sample = snd_gus_gf1_remove_sample; | ||
261 | gf1ops->notify = snd_gus_synth_instr_notify; | ||
262 | |||
263 | iwops = &gus->gf1.iwffff_ops; | ||
264 | snd_seq_iwffff_init(iwops, gus, &gf1ops->kops); | ||
265 | iwops->put_sample = snd_gus_iwffff_put_sample; | ||
266 | iwops->get_sample = snd_gus_iwffff_get_sample; | ||
267 | iwops->remove_sample = snd_gus_iwffff_remove_sample; | ||
268 | iwops->notify = snd_gus_synth_instr_notify; | ||
269 | |||
270 | memset(&sub, 0, sizeof(sub)); | ||
271 | sub.sender.client = SNDRV_SEQ_CLIENT_SYSTEM; | ||
272 | sub.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE; | ||
273 | sub.dest.client = client; | ||
274 | sub.dest.port = 0; | ||
275 | snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &sub); | ||
276 | |||
277 | return 0; | ||
278 | } | ||
279 | |||
280 | static int snd_gus_synth_delete_device(struct snd_seq_device *dev) | ||
281 | { | ||
282 | struct snd_gus_card *gus; | ||
283 | |||
284 | gus = *(struct snd_gus_card **)SNDRV_SEQ_DEVICE_ARGPTR(dev); | ||
285 | if (gus == NULL) | ||
286 | return -EINVAL; | ||
287 | |||
288 | if (gus->gf1.seq_client >= 0) { | ||
289 | snd_seq_delete_kernel_client(gus->gf1.seq_client); | ||
290 | gus->gf1.seq_client = -1; | ||
291 | } | ||
292 | if (gus->gf1.ilist) | ||
293 | snd_seq_instr_list_free(&gus->gf1.ilist); | ||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | static int __init alsa_gus_synth_init(void) | ||
298 | { | ||
299 | static struct snd_seq_dev_ops ops = { | ||
300 | snd_gus_synth_new_device, | ||
301 | snd_gus_synth_delete_device | ||
302 | }; | ||
303 | |||
304 | return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_GUS, &ops, | ||
305 | sizeof(struct snd_gus_card *)); | ||
306 | } | ||
307 | |||
308 | static void __exit alsa_gus_synth_exit(void) | ||
309 | { | ||
310 | snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_GUS); | ||
311 | } | ||
312 | |||
313 | module_init(alsa_gus_synth_init) | ||
314 | module_exit(alsa_gus_synth_exit) | ||
diff --git a/sound/isa/gus/gus_timer.c b/sound/isa/gus/gus_timer.c index 99eac573c414..c53727147a1a 100644 --- a/sound/isa/gus/gus_timer.c +++ b/sound/isa/gus/gus_timer.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/time.h> | 24 | #include <linux/time.h> |
26 | #include <sound/core.h> | 25 | #include <sound/core.h> |
27 | #include <sound/gus.h> | 26 | #include <sound/gus.h> |
diff --git a/sound/isa/gus/gus_uart.c b/sound/isa/gus/gus_uart.c index e6fd9b01c492..f0af3f79b08b 100644 --- a/sound/isa/gus/gus_uart.c +++ b/sound/isa/gus/gus_uart.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
24 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
25 | #include <linux/time.h> | 24 | #include <linux/time.h> |
diff --git a/sound/isa/gus/gus_volume.c b/sound/isa/gus/gus_volume.c index 71a67744a14b..c3c028a4a46b 100644 --- a/sound/isa/gus/gus_volume.c +++ b/sound/isa/gus/gus_volume.c | |||
@@ -18,7 +18,6 @@ | |||
18 | * | 18 | * |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <sound/driver.h> | ||
22 | #include <linux/time.h> | 21 | #include <linux/time.h> |
23 | #include <sound/core.h> | 22 | #include <sound/core.h> |
24 | #include <sound/gus.h> | 23 | #include <sound/gus.h> |
diff --git a/sound/isa/gus/gusclassic.c b/sound/isa/gus/gusclassic.c index 29e422b00b58..8f914b37bf89 100644 --- a/sound/isa/gus/gusclassic.c +++ b/sound/isa/gus/gusclassic.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/err.h> | 23 | #include <linux/err.h> |
25 | #include <linux/isa.h> | 24 | #include <linux/isa.h> |
diff --git a/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c index fc59536c918e..da13185eb0a0 100644 --- a/sound/isa/gus/gusextreme.c +++ b/sound/isa/gus/gusextreme.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/err.h> | 23 | #include <linux/err.h> |
25 | #include <linux/isa.h> | 24 | #include <linux/isa.h> |
diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c index 4922f5da08f9..f87c6236661c 100644 --- a/sound/isa/gus/gusmax.c +++ b/sound/isa/gus/gusmax.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/err.h> | 23 | #include <linux/err.h> |
25 | #include <linux/isa.h> | 24 | #include <linux/isa.h> |
diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c index 2091c50b2e3e..ca0d7ace0c75 100644 --- a/sound/isa/gus/interwave.c +++ b/sound/isa/gus/interwave.c | |||
@@ -22,7 +22,6 @@ | |||
22 | * | 22 | * |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <sound/driver.h> | ||
26 | #include <linux/init.h> | 25 | #include <linux/init.h> |
27 | #include <linux/err.h> | 26 | #include <linux/err.h> |
28 | #include <linux/isa.h> | 27 | #include <linux/isa.h> |
@@ -560,50 +559,27 @@ static int __devinit snd_interwave_pnp(int dev, struct snd_interwave *iwcard, | |||
560 | const struct pnp_card_device_id *id) | 559 | const struct pnp_card_device_id *id) |
561 | { | 560 | { |
562 | struct pnp_dev *pdev; | 561 | struct pnp_dev *pdev; |
563 | struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL); | ||
564 | int err; | 562 | int err; |
565 | 563 | ||
566 | if (!cfg) | ||
567 | return -ENOMEM; | ||
568 | iwcard->dev = pnp_request_card_device(card, id->devs[0].id, NULL); | 564 | iwcard->dev = pnp_request_card_device(card, id->devs[0].id, NULL); |
569 | if (iwcard->dev == NULL) { | 565 | if (iwcard->dev == NULL) |
570 | kfree(cfg); | ||
571 | return -EBUSY; | 566 | return -EBUSY; |
572 | } | 567 | |
573 | #ifdef SNDRV_STB | 568 | #ifdef SNDRV_STB |
574 | iwcard->devtc = pnp_request_card_device(card, id->devs[1].id, NULL); | 569 | iwcard->devtc = pnp_request_card_device(card, id->devs[1].id, NULL); |
575 | if (iwcard->devtc == NULL) { | 570 | if (iwcard->devtc == NULL) |
576 | kfree(cfg); | ||
577 | return -EBUSY; | 571 | return -EBUSY; |
578 | } | ||
579 | #endif | 572 | #endif |
580 | /* Synth & Codec initialization */ | 573 | /* Synth & Codec initialization */ |
581 | pdev = iwcard->dev; | 574 | pdev = iwcard->dev; |
582 | pnp_init_resource_table(cfg); | 575 | |
583 | if (port[dev] != SNDRV_AUTO_PORT) { | ||
584 | pnp_resource_change(&cfg->port_resource[0], port[dev], 16); | ||
585 | pnp_resource_change(&cfg->port_resource[1], port[dev] + 0x100, 12); | ||
586 | pnp_resource_change(&cfg->port_resource[2], port[dev] + 0x10c, 4); | ||
587 | } | ||
588 | if (dma1[dev] != SNDRV_AUTO_DMA) | ||
589 | pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1); | ||
590 | if (dma2[dev] != SNDRV_AUTO_DMA) | ||
591 | pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1); | ||
592 | if (dma2[dev] < 0) | ||
593 | pnp_resource_change(&cfg->dma_resource[1], 4, 1); | ||
594 | if (irq[dev] != SNDRV_AUTO_IRQ) | ||
595 | pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1); | ||
596 | if (pnp_manual_config_dev(pdev, cfg, 0) < 0) | ||
597 | snd_printk(KERN_ERR "InterWave - Synth - the requested resources are invalid, using auto config\n"); | ||
598 | err = pnp_activate_dev(pdev); | 576 | err = pnp_activate_dev(pdev); |
599 | if (err < 0) { | 577 | if (err < 0) { |
600 | kfree(cfg); | ||
601 | snd_printk(KERN_ERR "InterWave PnP configure failure (out of resources?)\n"); | 578 | snd_printk(KERN_ERR "InterWave PnP configure failure (out of resources?)\n"); |
602 | return err; | 579 | return err; |
603 | } | 580 | } |
604 | if (pnp_port_start(pdev, 0) + 0x100 != pnp_port_start(pdev, 1) || | 581 | if (pnp_port_start(pdev, 0) + 0x100 != pnp_port_start(pdev, 1) || |
605 | pnp_port_start(pdev, 0) + 0x10c != pnp_port_start(pdev, 2)) { | 582 | pnp_port_start(pdev, 0) + 0x10c != pnp_port_start(pdev, 2)) { |
606 | kfree(cfg); | ||
607 | snd_printk(KERN_ERR "PnP configure failure (wrong ports)\n"); | 583 | snd_printk(KERN_ERR "PnP configure failure (wrong ports)\n"); |
608 | return -ENOENT; | 584 | return -ENOENT; |
609 | } | 585 | } |
@@ -620,21 +596,15 @@ static int __devinit snd_interwave_pnp(int dev, struct snd_interwave *iwcard, | |||
620 | #ifdef SNDRV_STB | 596 | #ifdef SNDRV_STB |
621 | /* Tone Control initialization */ | 597 | /* Tone Control initialization */ |
622 | pdev = iwcard->devtc; | 598 | pdev = iwcard->devtc; |
623 | pnp_init_resource_table(cfg); | 599 | |
624 | if (port_tc[dev] != SNDRV_AUTO_PORT) | ||
625 | pnp_resource_change(&cfg->port_resource[0], port_tc[dev], 1); | ||
626 | if (pnp_manual_config_dev(pdev, cfg, 0) < 0) | ||
627 | snd_printk(KERN_ERR "InterWave - ToneControl - the requested resources are invalid, using auto config\n"); | ||
628 | err = pnp_activate_dev(pdev); | 600 | err = pnp_activate_dev(pdev); |
629 | if (err < 0) { | 601 | if (err < 0) { |
630 | kfree(cfg); | ||
631 | snd_printk(KERN_ERR "InterWave ToneControl PnP configure failure (out of resources?)\n"); | 602 | snd_printk(KERN_ERR "InterWave ToneControl PnP configure failure (out of resources?)\n"); |
632 | return err; | 603 | return err; |
633 | } | 604 | } |
634 | port_tc[dev] = pnp_port_start(pdev, 0); | 605 | port_tc[dev] = pnp_port_start(pdev, 0); |
635 | snd_printdd("isapnp IW: tone control port=0x%lx\n", port_tc[dev]); | 606 | snd_printdd("isapnp IW: tone control port=0x%lx\n", port_tc[dev]); |
636 | #endif | 607 | #endif |
637 | kfree(cfg); | ||
638 | return 0; | 608 | return 0; |
639 | } | 609 | } |
640 | #endif /* CONFIG_PNP */ | 610 | #endif /* CONFIG_PNP */ |
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c index 59af9ab7191f..854a9f74b466 100644 --- a/sound/isa/opl3sa2.c +++ b/sound/isa/opl3sa2.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/err.h> | 23 | #include <linux/err.h> |
25 | #include <linux/isa.h> | 24 | #include <linux/isa.h> |
@@ -610,39 +609,8 @@ static int snd_opl3sa2_resume(struct snd_card *card) | |||
610 | static int __devinit snd_opl3sa2_pnp(int dev, struct snd_opl3sa2 *chip, | 609 | static int __devinit snd_opl3sa2_pnp(int dev, struct snd_opl3sa2 *chip, |
611 | struct pnp_dev *pdev) | 610 | struct pnp_dev *pdev) |
612 | { | 611 | { |
613 | struct pnp_resource_table * cfg; | 612 | if (pnp_activate_dev(pdev) < 0) { |
614 | int err; | 613 | snd_printk(KERN_ERR "PnP configure failure (out of resources?)\n"); |
615 | |||
616 | cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL); | ||
617 | if (!cfg) { | ||
618 | snd_printk(KERN_ERR PFX "cannot allocate pnp cfg\n"); | ||
619 | return -ENOMEM; | ||
620 | } | ||
621 | /* PnP initialization */ | ||
622 | pnp_init_resource_table(cfg); | ||
623 | if (sb_port[dev] != SNDRV_AUTO_PORT) | ||
624 | pnp_resource_change(&cfg->port_resource[0], sb_port[dev], 16); | ||
625 | if (wss_port[dev] != SNDRV_AUTO_PORT) | ||
626 | pnp_resource_change(&cfg->port_resource[1], wss_port[dev], 8); | ||
627 | if (fm_port[dev] != SNDRV_AUTO_PORT) | ||
628 | pnp_resource_change(&cfg->port_resource[2], fm_port[dev], 4); | ||
629 | if (midi_port[dev] != SNDRV_AUTO_PORT) | ||
630 | pnp_resource_change(&cfg->port_resource[3], midi_port[dev], 2); | ||
631 | if (port[dev] != SNDRV_AUTO_PORT) | ||
632 | pnp_resource_change(&cfg->port_resource[4], port[dev], 2); | ||
633 | if (dma1[dev] != SNDRV_AUTO_DMA) | ||
634 | pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1); | ||
635 | if (dma2[dev] != SNDRV_AUTO_DMA) | ||
636 | pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1); | ||
637 | if (irq[dev] != SNDRV_AUTO_IRQ) | ||
638 | pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1); | ||
639 | err = pnp_manual_config_dev(pdev, cfg, 0); | ||
640 | if (err < 0) | ||
641 | snd_printk(KERN_WARNING "PnP manual resources are invalid, using auto config\n"); | ||
642 | err = pnp_activate_dev(pdev); | ||
643 | if (err < 0) { | ||
644 | kfree(cfg); | ||
645 | snd_printk(KERN_ERR "PnP configure failure (out of resources?) err = %d\n", err); | ||
646 | return -EBUSY; | 614 | return -EBUSY; |
647 | } | 615 | } |
648 | sb_port[dev] = pnp_port_start(pdev, 0); | 616 | sb_port[dev] = pnp_port_start(pdev, 0); |
@@ -657,7 +625,6 @@ static int __devinit snd_opl3sa2_pnp(int dev, struct snd_opl3sa2 *chip, | |||
657 | pnp_device_is_pnpbios(pdev) ? "BIOS" : "ISA", sb_port[dev], wss_port[dev], fm_port[dev], midi_port[dev]); | 625 | pnp_device_is_pnpbios(pdev) ? "BIOS" : "ISA", sb_port[dev], wss_port[dev], fm_port[dev], midi_port[dev]); |
658 | snd_printdd("%sPnP OPL3-SA: control port=0x%lx, dma1=%i, dma2=%i, irq=%i\n", | 626 | snd_printdd("%sPnP OPL3-SA: control port=0x%lx, dma1=%i, dma2=%i, irq=%i\n", |
659 | pnp_device_is_pnpbios(pdev) ? "BIOS" : "ISA", port[dev], dma1[dev], dma2[dev], irq[dev]); | 627 | pnp_device_is_pnpbios(pdev) ? "BIOS" : "ISA", port[dev], dma1[dev], dma2[dev], irq[dev]); |
660 | kfree(cfg); | ||
661 | return 0; | 628 | return 0; |
662 | } | 629 | } |
663 | #endif /* CONFIG_PNP */ | 630 | #endif /* CONFIG_PNP */ |
diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index d295936611f8..2a1e2f5d12c2 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c | |||
@@ -22,7 +22,6 @@ | |||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <sound/driver.h> | ||
26 | #include <linux/init.h> | 25 | #include <linux/init.h> |
27 | #include <linux/err.h> | 26 | #include <linux/err.h> |
28 | #include <linux/isa.h> | 27 | #include <linux/isa.h> |
@@ -483,6 +482,10 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol, | |||
483 | 482 | ||
484 | /* equalizer elements */ | 483 | /* equalizer elements */ |
485 | 484 | ||
485 | if (left < -0x7f || left > 0x7f || | ||
486 | right < -0x7f || right > 0x7f) | ||
487 | return -EINVAL; | ||
488 | |||
486 | if (left_old > 0x80) | 489 | if (left_old > 0x80) |
487 | left_old = 0x80 - left_old; | 490 | left_old = 0x80 - left_old; |
488 | if (right_old > 0x80) | 491 | if (right_old > 0x80) |
@@ -520,6 +523,10 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol, | |||
520 | 523 | ||
521 | /* non-equalizer elements */ | 524 | /* non-equalizer elements */ |
522 | 525 | ||
526 | if (left < 0 || left > 0x20 || | ||
527 | right < 0 || right > 0x20) | ||
528 | return -EINVAL; | ||
529 | |||
523 | left_old = 0x20 - left_old; | 530 | left_old = 0x20 - left_old; |
524 | right_old = 0x20 - right_old; | 531 | right_old = 0x20 - right_old; |
525 | 532 | ||
@@ -662,7 +669,7 @@ static int __devinit snd_set_aci_init_values(struct snd_miro *miro) | |||
662 | return 0; | 669 | return 0; |
663 | } | 670 | } |
664 | 671 | ||
665 | static int snd_miro_mixer(struct snd_miro *miro) | 672 | static int __devinit snd_miro_mixer(struct snd_miro *miro) |
666 | { | 673 | { |
667 | struct snd_card *card; | 674 | struct snd_card *card; |
668 | unsigned int idx; | 675 | unsigned int idx; |
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index ee1a824d8fc0..fe1afc13a01d 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c | |||
@@ -23,7 +23,6 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | 25 | ||
26 | #include <sound/driver.h> | ||
27 | #include <linux/init.h> | 26 | #include <linux/init.h> |
28 | #include <linux/err.h> | 27 | #include <linux/err.h> |
29 | #include <linux/isa.h> | 28 | #include <linux/isa.h> |
@@ -1595,7 +1594,7 @@ OPTi93X_DOUBLE("Capture Volume", 0, OPTi93X_MIXOUT_LEFT, OPTi93X_MIXOUT_RIGHT, 0 | |||
1595 | } | 1594 | } |
1596 | }; | 1595 | }; |
1597 | 1596 | ||
1598 | static int snd_opti93x_mixer(struct snd_opti93x *chip) | 1597 | static int __devinit snd_opti93x_mixer(struct snd_opti93x *chip) |
1599 | { | 1598 | { |
1600 | struct snd_card *card; | 1599 | struct snd_card *card; |
1601 | struct snd_kcontrol_new knew; | 1600 | struct snd_kcontrol_new knew; |
@@ -1690,53 +1689,19 @@ static int __devinit snd_card_opti9xx_pnp(struct snd_opti9xx *chip, | |||
1690 | const struct pnp_card_device_id *pid) | 1689 | const struct pnp_card_device_id *pid) |
1691 | { | 1690 | { |
1692 | struct pnp_dev *pdev; | 1691 | struct pnp_dev *pdev; |
1693 | struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL); | ||
1694 | int err; | 1692 | int err; |
1695 | 1693 | ||
1696 | if (!cfg) | ||
1697 | return -ENOMEM; | ||
1698 | chip->dev = pnp_request_card_device(card, pid->devs[0].id, NULL); | 1694 | chip->dev = pnp_request_card_device(card, pid->devs[0].id, NULL); |
1699 | if (chip->dev == NULL) { | 1695 | if (chip->dev == NULL) |
1700 | kfree(cfg); | ||
1701 | return -EBUSY; | 1696 | return -EBUSY; |
1702 | } | 1697 | |
1703 | chip->devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL); | 1698 | chip->devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL); |
1704 | 1699 | ||
1705 | pdev = chip->dev; | 1700 | pdev = chip->dev; |
1706 | pnp_init_resource_table(cfg); | ||
1707 | 1701 | ||
1708 | #ifdef OPTi93X | ||
1709 | if (port != SNDRV_AUTO_PORT) | ||
1710 | pnp_resource_change(&cfg->port_resource[0], port + 4, 4); | ||
1711 | #else | ||
1712 | if (pid->driver_data != 0x0924 && port != SNDRV_AUTO_PORT) | ||
1713 | pnp_resource_change(&cfg->port_resource[1], port, 4); | ||
1714 | #endif /* OPTi93X */ | ||
1715 | if (irq != SNDRV_AUTO_IRQ) | ||
1716 | pnp_resource_change(&cfg->irq_resource[0], irq, 1); | ||
1717 | if (dma1 != SNDRV_AUTO_DMA) | ||
1718 | pnp_resource_change(&cfg->dma_resource[0], dma1, 1); | ||
1719 | #if defined(CS4231) || defined(OPTi93X) | ||
1720 | if (dma2 != SNDRV_AUTO_DMA) | ||
1721 | pnp_resource_change(&cfg->dma_resource[1], dma2, 1); | ||
1722 | #else | ||
1723 | #ifdef snd_opti9xx_fixup_dma2 | ||
1724 | snd_opti9xx_fixup_dma2(pdev); | ||
1725 | #endif | ||
1726 | #endif /* CS4231 || OPTi93X */ | ||
1727 | #ifdef OPTi93X | ||
1728 | if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) | ||
1729 | pnp_resource_change(&cfg->port_resource[1], fm_port, 4); | ||
1730 | #else | ||
1731 | if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) | ||
1732 | pnp_resource_change(&cfg->port_resource[2], fm_port, 4); | ||
1733 | #endif | ||
1734 | if (pnp_manual_config_dev(pdev, cfg, 0) < 0) | ||
1735 | snd_printk(KERN_ERR "AUDIO the requested resources are invalid, using auto config\n"); | ||
1736 | err = pnp_activate_dev(pdev); | 1702 | err = pnp_activate_dev(pdev); |
1737 | if (err < 0) { | 1703 | if (err < 0) { |
1738 | snd_printk(KERN_ERR "AUDIO pnp configure failure: %d\n", err); | 1704 | snd_printk(KERN_ERR "AUDIO pnp configure failure: %d\n", err); |
1739 | kfree(cfg); | ||
1740 | return err; | 1705 | return err; |
1741 | } | 1706 | } |
1742 | 1707 | ||
@@ -1756,15 +1721,6 @@ static int __devinit snd_card_opti9xx_pnp(struct snd_opti9xx *chip, | |||
1756 | 1721 | ||
1757 | pdev = chip->devmpu; | 1722 | pdev = chip->devmpu; |
1758 | if (pdev && mpu_port > 0) { | 1723 | if (pdev && mpu_port > 0) { |
1759 | pnp_init_resource_table(cfg); | ||
1760 | |||
1761 | if (mpu_port != SNDRV_AUTO_PORT) | ||
1762 | pnp_resource_change(&cfg->port_resource[0], mpu_port, 2); | ||
1763 | if (mpu_irq != SNDRV_AUTO_IRQ) | ||
1764 | pnp_resource_change(&cfg->irq_resource[0], mpu_irq, 1); | ||
1765 | |||
1766 | if (pnp_manual_config_dev(pdev, cfg, 0) < 0) | ||
1767 | snd_printk(KERN_ERR "AUDIO the requested resources are invalid, using auto config\n"); | ||
1768 | err = pnp_activate_dev(pdev); | 1724 | err = pnp_activate_dev(pdev); |
1769 | if (err < 0) { | 1725 | if (err < 0) { |
1770 | snd_printk(KERN_ERR "AUDIO pnp configure failure\n"); | 1726 | snd_printk(KERN_ERR "AUDIO pnp configure failure\n"); |
@@ -1775,7 +1731,6 @@ static int __devinit snd_card_opti9xx_pnp(struct snd_opti9xx *chip, | |||
1775 | mpu_irq = pnp_irq(pdev, 0); | 1731 | mpu_irq = pnp_irq(pdev, 0); |
1776 | } | 1732 | } |
1777 | } | 1733 | } |
1778 | kfree(cfg); | ||
1779 | return pid->driver_data; | 1734 | return pid->driver_data; |
1780 | } | 1735 | } |
1781 | #endif /* CONFIG_PNP */ | 1736 | #endif /* CONFIG_PNP */ |
diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c index 4eea84cfd4f4..b35be7d9a9fa 100644 --- a/sound/isa/sb/emu8000.c +++ b/sound/isa/sb/emu8000.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/wait.h> | 23 | #include <linux/wait.h> |
25 | #include <linux/sched.h> | 24 | #include <linux/sched.h> |
26 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
diff --git a/sound/isa/sb/emu8000_local.h b/sound/isa/sb/emu8000_local.h index 2ac77f10bb4e..7e87c349272f 100644 --- a/sound/isa/sb/emu8000_local.h +++ b/sound/isa/sb/emu8000_local.h | |||
@@ -21,7 +21,6 @@ | |||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/wait.h> | 24 | #include <linux/wait.h> |
26 | #include <linux/sched.h> | 25 | #include <linux/sched.h> |
27 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
diff --git a/sound/isa/sb/es968.c b/sound/isa/sb/es968.c index d4b218726ce7..c8c8e214c843 100644 --- a/sound/isa/sb/es968.c +++ b/sound/isa/sb/es968.c | |||
@@ -20,7 +20,6 @@ | |||
20 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <linux/time.h> | 24 | #include <linux/time.h> |
26 | #include <linux/pnp.h> | 25 | #include <linux/pnp.h> |
@@ -49,12 +48,6 @@ module_param_array(id, charp, NULL, 0444); | |||
49 | MODULE_PARM_DESC(id, "ID string for es968 based soundcard."); | 48 | MODULE_PARM_DESC(id, "ID string for es968 based soundcard."); |
50 | module_param_array(enable, bool, NULL, 0444); | 49 | module_param_array(enable, bool, NULL, 0444); |
51 | MODULE_PARM_DESC(enable, "Enable es968 based soundcard."); | 50 | MODULE_PARM_DESC(enable, "Enable es968 based soundcard."); |
52 | module_param_array(port, long, NULL, 0444); | ||
53 | MODULE_PARM_DESC(port, "Port # for es968 driver."); | ||
54 | module_param_array(irq, int, NULL, 0444); | ||
55 | MODULE_PARM_DESC(irq, "IRQ # for es968 driver."); | ||
56 | module_param_array(dma8, int, NULL, 0444); | ||
57 | MODULE_PARM_DESC(dma8, "8-bit DMA # for es968 driver."); | ||
58 | 51 | ||
59 | struct snd_card_es968 { | 52 | struct snd_card_es968 { |
60 | struct pnp_dev *dev; | 53 | struct pnp_dev *dev; |
@@ -86,40 +79,23 @@ static int __devinit snd_card_es968_pnp(int dev, struct snd_card_es968 *acard, | |||
86 | const struct pnp_card_device_id *id) | 79 | const struct pnp_card_device_id *id) |
87 | { | 80 | { |
88 | struct pnp_dev *pdev; | 81 | struct pnp_dev *pdev; |
89 | struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL); | ||
90 | int err; | 82 | int err; |
91 | if (!cfg) | 83 | |
92 | return -ENOMEM; | ||
93 | acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL); | 84 | acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL); |
94 | if (acard->dev == NULL) { | 85 | if (acard->dev == NULL) |
95 | kfree(cfg); | ||
96 | return -ENODEV; | 86 | return -ENODEV; |
97 | } | ||
98 | 87 | ||
99 | pdev = acard->dev; | 88 | pdev = acard->dev; |
100 | 89 | ||
101 | pnp_init_resource_table(cfg); | ||
102 | |||
103 | /* override resources */ | ||
104 | if (port[dev] != SNDRV_AUTO_PORT) | ||
105 | pnp_resource_change(&cfg->port_resource[0], port[dev], 16); | ||
106 | if (dma8[dev] != SNDRV_AUTO_DMA) | ||
107 | pnp_resource_change(&cfg->dma_resource[0], dma8[dev], 1); | ||
108 | if (irq[dev] != SNDRV_AUTO_IRQ) | ||
109 | pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1); | ||
110 | if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0) | ||
111 | snd_printk(KERN_ERR PFX "AUDIO the requested resources are invalid, using auto config\n"); | ||
112 | err = pnp_activate_dev(pdev); | 90 | err = pnp_activate_dev(pdev); |
113 | if (err < 0) { | 91 | if (err < 0) { |
114 | snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n"); | 92 | snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n"); |
115 | kfree(cfg); | ||
116 | return err; | 93 | return err; |
117 | } | 94 | } |
118 | port[dev] = pnp_port_start(pdev, 0); | 95 | port[dev] = pnp_port_start(pdev, 0); |
119 | dma8[dev] = pnp_dma(pdev, 1); | 96 | dma8[dev] = pnp_dma(pdev, 1); |
120 | irq[dev] = pnp_irq(pdev, 0); | 97 | irq[dev] = pnp_irq(pdev, 0); |
121 | 98 | ||
122 | kfree(cfg); | ||
123 | return 0; | 99 | return 0; |
124 | } | 100 | } |
125 | 101 | ||
diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c index e7f9edd92626..2c201f78ce50 100644 --- a/sound/isa/sb/sb16.c +++ b/sound/isa/sb/sb16.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <asm/dma.h> | 22 | #include <asm/dma.h> |
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
@@ -257,44 +256,21 @@ static int __devinit snd_card_sb16_pnp(int dev, struct snd_card_sb16 *acard, | |||
257 | const struct pnp_card_device_id *id) | 256 | const struct pnp_card_device_id *id) |
258 | { | 257 | { |
259 | struct pnp_dev *pdev; | 258 | struct pnp_dev *pdev; |
260 | struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL); | ||
261 | int err; | 259 | int err; |
262 | 260 | ||
263 | if (!cfg) | ||
264 | return -ENOMEM; | ||
265 | acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL); | 261 | acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL); |
266 | if (acard->dev == NULL) { | 262 | if (acard->dev == NULL) |
267 | kfree(cfg); | ||
268 | return -ENODEV; | 263 | return -ENODEV; |
269 | } | 264 | |
270 | #ifdef SNDRV_SBAWE_EMU8000 | 265 | #ifdef SNDRV_SBAWE_EMU8000 |
271 | acard->devwt = pnp_request_card_device(card, id->devs[1].id, acard->dev); | 266 | acard->devwt = pnp_request_card_device(card, id->devs[1].id, acard->dev); |
272 | #endif | 267 | #endif |
273 | /* Audio initialization */ | 268 | /* Audio initialization */ |
274 | pdev = acard->dev; | 269 | pdev = acard->dev; |
275 | 270 | ||
276 | pnp_init_resource_table(cfg); | ||
277 | |||
278 | /* override resources */ | ||
279 | |||
280 | if (port[dev] != SNDRV_AUTO_PORT) | ||
281 | pnp_resource_change(&cfg->port_resource[0], port[dev], 16); | ||
282 | if (mpu_port[dev] != SNDRV_AUTO_PORT) | ||
283 | pnp_resource_change(&cfg->port_resource[1], mpu_port[dev], 2); | ||
284 | if (fm_port[dev] != SNDRV_AUTO_PORT) | ||
285 | pnp_resource_change(&cfg->port_resource[2], fm_port[dev], 4); | ||
286 | if (dma8[dev] != SNDRV_AUTO_DMA) | ||
287 | pnp_resource_change(&cfg->dma_resource[0], dma8[dev], 1); | ||
288 | if (dma16[dev] != SNDRV_AUTO_DMA) | ||
289 | pnp_resource_change(&cfg->dma_resource[1], dma16[dev], 1); | ||
290 | if (irq[dev] != SNDRV_AUTO_IRQ) | ||
291 | pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1); | ||
292 | if (pnp_manual_config_dev(pdev, cfg, 0) < 0) | ||
293 | snd_printk(KERN_ERR PFX "AUDIO the requested resources are invalid, using auto config\n"); | ||
294 | err = pnp_activate_dev(pdev); | 271 | err = pnp_activate_dev(pdev); |
295 | if (err < 0) { | 272 | if (err < 0) { |
296 | snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n"); | 273 | snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n"); |
297 | kfree(cfg); | ||
298 | return err; | 274 | return err; |
299 | } | 275 | } |
300 | port[dev] = pnp_port_start(pdev, 0); | 276 | port[dev] = pnp_port_start(pdev, 0); |
@@ -311,17 +287,6 @@ static int __devinit snd_card_sb16_pnp(int dev, struct snd_card_sb16 *acard, | |||
311 | /* WaveTable initialization */ | 287 | /* WaveTable initialization */ |
312 | pdev = acard->devwt; | 288 | pdev = acard->devwt; |
313 | if (pdev != NULL) { | 289 | if (pdev != NULL) { |
314 | pnp_init_resource_table(cfg); | ||
315 | |||
316 | /* override resources */ | ||
317 | |||
318 | if (awe_port[dev] != SNDRV_AUTO_PORT) { | ||
319 | pnp_resource_change(&cfg->port_resource[0], awe_port[dev], 4); | ||
320 | pnp_resource_change(&cfg->port_resource[1], awe_port[dev] + 0x400, 4); | ||
321 | pnp_resource_change(&cfg->port_resource[2], awe_port[dev] + 0x800, 4); | ||
322 | } | ||
323 | if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0) | ||
324 | snd_printk(KERN_ERR PFX "WaveTable the requested resources are invalid, using auto config\n"); | ||
325 | err = pnp_activate_dev(pdev); | 290 | err = pnp_activate_dev(pdev); |
326 | if (err < 0) { | 291 | if (err < 0) { |
327 | goto __wt_error; | 292 | goto __wt_error; |
@@ -339,7 +304,6 @@ __wt_error: | |||
339 | awe_port[dev] = -1; | 304 | awe_port[dev] = -1; |
340 | } | 305 | } |
341 | #endif | 306 | #endif |
342 | kfree(cfg); | ||
343 | return 0; | 307 | return 0; |
344 | } | 308 | } |
345 | 309 | ||
diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c index 3682059787ab..bed29ca22239 100644 --- a/sound/isa/sb/sb16_csp.c +++ b/sound/isa/sb/sb16_csp.c | |||
@@ -23,7 +23,6 @@ | |||
23 | * | 23 | * |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <sound/driver.h> | ||
27 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
28 | #include <linux/init.h> | 27 | #include <linux/init.h> |
29 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
@@ -118,7 +117,8 @@ static void info_read(struct snd_info_entry *entry, struct snd_info_buffer *buff | |||
118 | int snd_sb_csp_new(struct snd_sb *chip, int device, struct snd_hwdep ** rhwdep) | 117 | int snd_sb_csp_new(struct snd_sb *chip, int device, struct snd_hwdep ** rhwdep) |
119 | { | 118 | { |
120 | struct snd_sb_csp *p; | 119 | struct snd_sb_csp *p; |
121 | int version, err; | 120 | int uninitialized_var(version); |
121 | int err; | ||
122 | struct snd_hwdep *hw; | 122 | struct snd_hwdep *hw; |
123 | 123 | ||
124 | if (rhwdep) | 124 | if (rhwdep) |
diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c index c06754f7ee5d..f7e8192270ae 100644 --- a/sound/isa/sb/sb16_main.c +++ b/sound/isa/sb/sb16_main.c | |||
@@ -33,7 +33,6 @@ | |||
33 | * | 33 | * |
34 | */ | 34 | */ |
35 | 35 | ||
36 | #include <sound/driver.h> | ||
37 | #include <asm/io.h> | 36 | #include <asm/io.h> |
38 | #include <asm/dma.h> | 37 | #include <asm/dma.h> |
39 | #include <linux/init.h> | 38 | #include <linux/init.h> |
diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c index f933aef7d8a9..336a34277907 100644 --- a/sound/isa/sb/sb8.c +++ b/sound/isa/sb/sb8.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/err.h> | 23 | #include <linux/err.h> |
25 | #include <linux/isa.h> | 24 | #include <linux/isa.h> |
diff --git a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c index bee894b3f5c7..6304c3a89ba0 100644 --- a/sound/isa/sb/sb8_main.c +++ b/sound/isa/sb/sb8_main.c | |||
@@ -30,7 +30,6 @@ | |||
30 | * Cleaned up and rewrote lowlevel routines. | 30 | * Cleaned up and rewrote lowlevel routines. |
31 | */ | 31 | */ |
32 | 32 | ||
33 | #include <sound/driver.h> | ||
34 | #include <asm/io.h> | 33 | #include <asm/io.h> |
35 | #include <asm/dma.h> | 34 | #include <asm/dma.h> |
36 | #include <linux/init.h> | 35 | #include <linux/init.h> |
diff --git a/sound/isa/sb/sb8_midi.c b/sound/isa/sb/sb8_midi.c index e56e5633411c..988a8b73475f 100644 --- a/sound/isa/sb/sb8_midi.c +++ b/sound/isa/sb/sb8_midi.c | |||
@@ -26,7 +26,6 @@ | |||
26 | * Added full duplex UART mode for DSP version 2.0 and later. | 26 | * Added full duplex UART mode for DSP version 2.0 and later. |
27 | */ | 27 | */ |
28 | 28 | ||
29 | #include <sound/driver.h> | ||
30 | #include <asm/io.h> | 29 | #include <asm/io.h> |
31 | #include <linux/time.h> | 30 | #include <linux/time.h> |
32 | #include <sound/core.h> | 31 | #include <sound/core.h> |
diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c index 176193c05101..d63c1af550de 100644 --- a/sound/isa/sb/sb_common.c +++ b/sound/isa/sb/sb_common.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c index 03241cd5aaef..91d14224f6b3 100644 --- a/sound/isa/sb/sb_mixer.c +++ b/sound/isa/sb/sb_mixer.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <asm/io.h> | 22 | #include <asm/io.h> |
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <linux/time.h> | 24 | #include <linux/time.h> |
diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c index 94daf8399994..da3d152bcad4 100644 --- a/sound/isa/sc6000.c +++ b/sound/isa/sc6000.c | |||
@@ -23,7 +23,6 @@ | |||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <sound/driver.h> | ||
27 | #include <linux/module.h> | 26 | #include <linux/module.h> |
28 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
29 | #include <linux/isa.h> | 28 | #include <linux/isa.h> |
@@ -390,7 +389,7 @@ static int __devinit sc6000_init_board(char __iomem *vport, int irq, int dma, | |||
390 | 389 | ||
391 | err = sc6000_init_mss(vport, config, vmss_port, mss_config); | 390 | err = sc6000_init_mss(vport, config, vmss_port, mss_config); |
392 | if (err < 0) { | 391 | if (err < 0) { |
393 | snd_printk(KERN_ERR "Can not initialize" | 392 | snd_printk(KERN_ERR "Can not initialize " |
394 | "Microsoft Sound System mode.\n"); | 393 | "Microsoft Sound System mode.\n"); |
395 | return -ENODEV; | 394 | return -ENODEV; |
396 | } | 395 | } |
diff --git a/sound/isa/sgalaxy.c b/sound/isa/sgalaxy.c index 922519def099..a07274ecb149 100644 --- a/sound/isa/sgalaxy.c +++ b/sound/isa/sgalaxy.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <linux/err.h> | 25 | #include <linux/err.h> |
27 | #include <linux/isa.h> | 26 | #include <linux/isa.h> |
diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index 1cb921d6137e..06ad7863dff5 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <linux/err.h> | 25 | #include <linux/err.h> |
27 | #include <linux/isa.h> | 26 | #include <linux/isa.h> |
diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c index 83c2fc4cfc64..3a6c6fe1ec4d 100644 --- a/sound/isa/wavefront/wavefront.c +++ b/sound/isa/wavefront/wavefront.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
@@ -104,21 +103,15 @@ snd_wavefront_pnp (int dev, snd_wavefront_card_t *acard, struct pnp_card_link *c | |||
104 | const struct pnp_card_device_id *id) | 103 | const struct pnp_card_device_id *id) |
105 | { | 104 | { |
106 | struct pnp_dev *pdev; | 105 | struct pnp_dev *pdev; |
107 | struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL); | ||
108 | int err; | 106 | int err; |
109 | 107 | ||
110 | if (!cfg) | ||
111 | return -ENOMEM; | ||
112 | |||
113 | /* Check for each logical device. */ | 108 | /* Check for each logical device. */ |
114 | 109 | ||
115 | /* CS4232 chip (aka "windows sound system") is logical device 0 */ | 110 | /* CS4232 chip (aka "windows sound system") is logical device 0 */ |
116 | 111 | ||
117 | acard->wss = pnp_request_card_device(card, id->devs[0].id, NULL); | 112 | acard->wss = pnp_request_card_device(card, id->devs[0].id, NULL); |
118 | if (acard->wss == NULL) { | 113 | if (acard->wss == NULL) |
119 | kfree(cfg); | ||
120 | return -EBUSY; | 114 | return -EBUSY; |
121 | } | ||
122 | 115 | ||
123 | /* there is a game port at logical device 1, but we ignore it completely */ | 116 | /* there is a game port at logical device 1, but we ignore it completely */ |
124 | 117 | ||
@@ -133,26 +126,20 @@ snd_wavefront_pnp (int dev, snd_wavefront_card_t *acard, struct pnp_card_link *c | |||
133 | 126 | ||
134 | if (use_cs4232_midi[dev]) { | 127 | if (use_cs4232_midi[dev]) { |
135 | acard->mpu = pnp_request_card_device(card, id->devs[2].id, NULL); | 128 | acard->mpu = pnp_request_card_device(card, id->devs[2].id, NULL); |
136 | if (acard->mpu == NULL) { | 129 | if (acard->mpu == NULL) |
137 | kfree(cfg); | ||
138 | return -EBUSY; | 130 | return -EBUSY; |
139 | } | ||
140 | } | 131 | } |
141 | 132 | ||
142 | /* The ICS2115 synth is logical device 4 */ | 133 | /* The ICS2115 synth is logical device 4 */ |
143 | 134 | ||
144 | acard->synth = pnp_request_card_device(card, id->devs[3].id, NULL); | 135 | acard->synth = pnp_request_card_device(card, id->devs[3].id, NULL); |
145 | if (acard->synth == NULL) { | 136 | if (acard->synth == NULL) |
146 | kfree(cfg); | ||
147 | return -EBUSY; | 137 | return -EBUSY; |
148 | } | ||
149 | 138 | ||
150 | /* PCM/FM initialization */ | 139 | /* PCM/FM initialization */ |
151 | 140 | ||
152 | pdev = acard->wss; | 141 | pdev = acard->wss; |
153 | 142 | ||
154 | pnp_init_resource_table(cfg); | ||
155 | |||
156 | /* An interesting note from the Tropez+ FAQ: | 143 | /* An interesting note from the Tropez+ FAQ: |
157 | 144 | ||
158 | Q. [Ports] Why is the base address of the WSS I/O ports off by 4? | 145 | Q. [Ports] Why is the base address of the WSS I/O ports off by 4? |
@@ -165,23 +152,9 @@ snd_wavefront_pnp (int dev, snd_wavefront_card_t *acard, struct pnp_card_link *c | |||
165 | 152 | ||
166 | */ | 153 | */ |
167 | 154 | ||
168 | if (cs4232_pcm_port[dev] != SNDRV_AUTO_PORT) | ||
169 | pnp_resource_change(&cfg->port_resource[0], cs4232_pcm_port[dev], 4); | ||
170 | if (fm_port[dev] != SNDRV_AUTO_PORT) | ||
171 | pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4); | ||
172 | if (dma1[dev] != SNDRV_AUTO_DMA) | ||
173 | pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1); | ||
174 | if (dma2[dev] != SNDRV_AUTO_DMA) | ||
175 | pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1); | ||
176 | if (cs4232_pcm_irq[dev] != SNDRV_AUTO_IRQ) | ||
177 | pnp_resource_change(&cfg->irq_resource[0], cs4232_pcm_irq[dev], 1); | ||
178 | |||
179 | if (pnp_manual_config_dev(pdev, cfg, 0) < 0) | ||
180 | snd_printk(KERN_ERR "PnP WSS the requested resources are invalid, using auto config\n"); | ||
181 | err = pnp_activate_dev(pdev); | 155 | err = pnp_activate_dev(pdev); |
182 | if (err < 0) { | 156 | if (err < 0) { |
183 | snd_printk(KERN_ERR "PnP WSS pnp configure failure\n"); | 157 | snd_printk(KERN_ERR "PnP WSS pnp configure failure\n"); |
184 | kfree(cfg); | ||
185 | return err; | 158 | return err; |
186 | } | 159 | } |
187 | 160 | ||
@@ -195,22 +168,9 @@ snd_wavefront_pnp (int dev, snd_wavefront_card_t *acard, struct pnp_card_link *c | |||
195 | 168 | ||
196 | pdev = acard->synth; | 169 | pdev = acard->synth; |
197 | 170 | ||
198 | pnp_init_resource_table(cfg); | ||
199 | |||
200 | if (ics2115_port[dev] != SNDRV_AUTO_PORT) { | ||
201 | pnp_resource_change(&cfg->port_resource[0], ics2115_port[dev], 16); | ||
202 | } | ||
203 | |||
204 | if (ics2115_port[dev] != SNDRV_AUTO_IRQ) { | ||
205 | pnp_resource_change(&cfg->irq_resource[0], ics2115_irq[dev], 1); | ||
206 | } | ||
207 | |||
208 | if (pnp_manual_config_dev(pdev, cfg, 0) < 0) | ||
209 | snd_printk(KERN_ERR "PnP ICS2115 the requested resources are invalid, using auto config\n"); | ||
210 | err = pnp_activate_dev(pdev); | 171 | err = pnp_activate_dev(pdev); |
211 | if (err < 0) { | 172 | if (err < 0) { |
212 | snd_printk(KERN_ERR "PnP ICS2115 pnp configure failure\n"); | 173 | snd_printk(KERN_ERR "PnP ICS2115 pnp configure failure\n"); |
213 | kfree(cfg); | ||
214 | return err; | 174 | return err; |
215 | } | 175 | } |
216 | 176 | ||
@@ -226,15 +186,6 @@ snd_wavefront_pnp (int dev, snd_wavefront_card_t *acard, struct pnp_card_link *c | |||
226 | 186 | ||
227 | pdev = acard->mpu; | 187 | pdev = acard->mpu; |
228 | 188 | ||
229 | pnp_init_resource_table(cfg); | ||
230 | |||
231 | if (cs4232_mpu_port[dev] != SNDRV_AUTO_PORT) | ||
232 | pnp_resource_change(&cfg->port_resource[0], cs4232_mpu_port[dev], 2); | ||
233 | if (cs4232_mpu_irq[dev] != SNDRV_AUTO_IRQ) | ||
234 | pnp_resource_change(&cfg->port_resource[0], cs4232_mpu_irq[dev], 1); | ||
235 | |||
236 | if (pnp_manual_config_dev(pdev, cfg, 0) < 0) | ||
237 | snd_printk(KERN_ERR "PnP MPU401 the requested resources are invalid, using auto config\n"); | ||
238 | err = pnp_activate_dev(pdev); | 189 | err = pnp_activate_dev(pdev); |
239 | if (err < 0) { | 190 | if (err < 0) { |
240 | snd_printk(KERN_ERR "PnP MPU401 pnp configure failure\n"); | 191 | snd_printk(KERN_ERR "PnP MPU401 pnp configure failure\n"); |
@@ -258,7 +209,6 @@ snd_wavefront_pnp (int dev, snd_wavefront_card_t *acard, struct pnp_card_link *c | |||
258 | ics2115_port[dev], | 209 | ics2115_port[dev], |
259 | ics2115_irq[dev]); | 210 | ics2115_irq[dev]); |
260 | 211 | ||
261 | kfree(cfg); | ||
262 | return 0; | 212 | return 0; |
263 | } | 213 | } |
264 | 214 | ||
diff --git a/sound/isa/wavefront/wavefront_fx.c b/sound/isa/wavefront/wavefront_fx.c index fc95a870f690..2efaa7f205aa 100644 --- a/sound/isa/wavefront/wavefront_fx.c +++ b/sound/isa/wavefront/wavefront_fx.c | |||
@@ -16,7 +16,6 @@ | |||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <sound/driver.h> | ||
20 | #include <asm/io.h> | 19 | #include <asm/io.h> |
21 | #include <linux/init.h> | 20 | #include <linux/init.h> |
22 | #include <linux/time.h> | 21 | #include <linux/time.h> |
diff --git a/sound/isa/wavefront/wavefront_midi.c b/sound/isa/wavefront/wavefront_midi.c index cb3460094324..a33384a55b0f 100644 --- a/sound/isa/wavefront/wavefront_midi.c +++ b/sound/isa/wavefront/wavefront_midi.c | |||
@@ -47,7 +47,6 @@ | |||
47 | * | 47 | * |
48 | */ | 48 | */ |
49 | 49 | ||
50 | #include <sound/driver.h> | ||
51 | #include <asm/io.h> | 50 | #include <asm/io.h> |
52 | #include <linux/init.h> | 51 | #include <linux/init.h> |
53 | #include <linux/time.h> | 52 | #include <linux/time.h> |
diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c index a1ebb7c5c684..95eeca163354 100644 --- a/sound/isa/wavefront/wavefront_synth.c +++ b/sound/isa/wavefront/wavefront_synth.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <asm/io.h> | 23 | #include <asm/io.h> |
25 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
26 | #include <linux/init.h> | 25 | #include <linux/init.h> |
diff --git a/sound/last.c b/sound/last.c index 282b0cdb0589..bdd0857b8871 100644 --- a/sound/last.c +++ b/sound/last.c | |||
@@ -20,7 +20,6 @@ | |||
20 | */ | 20 | */ |
21 | 21 | ||
22 | #define SNDRV_MAIN_OBJECT_FILE | 22 | #define SNDRV_MAIN_OBJECT_FILE |
23 | #include <sound/driver.h> | ||
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <sound/core.h> | 24 | #include <sound/core.h> |
26 | 25 | ||
diff --git a/sound/mips/au1x00.c b/sound/mips/au1x00.c index 24460a558bf7..ee0741f9eb53 100644 --- a/sound/mips/au1x00.c +++ b/sound/mips/au1x00.c | |||
@@ -36,7 +36,6 @@ | |||
36 | 36 | ||
37 | #include <linux/ioport.h> | 37 | #include <linux/ioport.h> |
38 | #include <linux/interrupt.h> | 38 | #include <linux/interrupt.h> |
39 | #include <sound/driver.h> | ||
40 | #include <linux/init.h> | 39 | #include <linux/init.h> |
41 | #include <linux/slab.h> | 40 | #include <linux/slab.h> |
42 | #include <linux/version.h> | 41 | #include <linux/version.h> |
diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c index ff705c63a03a..99f5483abf2e 100644 --- a/sound/parisc/harmony.c +++ b/sound/parisc/harmony.c | |||
@@ -45,7 +45,6 @@ | |||
45 | #include <linux/spinlock.h> | 45 | #include <linux/spinlock.h> |
46 | #include <linux/dma-mapping.h> | 46 | #include <linux/dma-mapping.h> |
47 | 47 | ||
48 | #include <sound/driver.h> | ||
49 | #include <sound/core.h> | 48 | #include <sound/core.h> |
50 | #include <sound/pcm.h> | 49 | #include <sound/pcm.h> |
51 | #include <sound/control.h> | 50 | #include <sound/control.h> |
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 356bf21a1506..812085d521f1 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig | |||
@@ -183,6 +183,30 @@ config SND_CMIPCI | |||
183 | To compile this driver as a module, choose M here: the module | 183 | To compile this driver as a module, choose M here: the module |
184 | will be called snd-cmipci. | 184 | will be called snd-cmipci. |
185 | 185 | ||
186 | config SND_OXYGEN_LIB | ||
187 | tristate | ||
188 | depends on SND | ||
189 | select SND_PCM | ||
190 | select SND_MPU401_UART | ||
191 | |||
192 | config SND_OXYGEN | ||
193 | tristate "C-Media 8788 (Oxygen)" | ||
194 | depends on SND | ||
195 | select SND_OXYGEN_LIB | ||
196 | help | ||
197 | Say Y here to include support for sound cards based on the | ||
198 | C-Media CMI8788 (Oxygen HD Audio) chip: | ||
199 | * Asound A-8788 | ||
200 | * AuzenTech X-Meridian | ||
201 | * Bgears b-Enspirer | ||
202 | * Club3D Theatron DTS | ||
203 | * HT-Omega Claro | ||
204 | * Razer Barracuda AC-1 | ||
205 | * Sondigo Inferno | ||
206 | |||
207 | To compile this driver as a module, choose M here: the module | ||
208 | will be called snd-oxygen. | ||
209 | |||
186 | config SND_CS4281 | 210 | config SND_CS4281 |
187 | tristate "Cirrus Logic (Sound Fusion) CS4281" | 211 | tristate "Cirrus Logic (Sound Fusion) CS4281" |
188 | depends on SND | 212 | depends on SND |
@@ -623,6 +647,17 @@ config SND_HDSPM | |||
623 | To compile this driver as a module, choose M here: the module | 647 | To compile this driver as a module, choose M here: the module |
624 | will be called snd-hdspm. | 648 | will be called snd-hdspm. |
625 | 649 | ||
650 | config SND_HIFIER | ||
651 | tristate "TempoTec HiFier Fantasia" | ||
652 | depends on SND | ||
653 | select SND_OXYGEN_LIB | ||
654 | help | ||
655 | Say Y here to include support for the MediaTek/TempoTec HiFier | ||
656 | Fantasia sound card. | ||
657 | |||
658 | To compile this driver as a module, choose M here: the module | ||
659 | will be called snd-hifier. | ||
660 | |||
626 | config SND_ICE1712 | 661 | config SND_ICE1712 |
627 | tristate "ICEnsemble ICE1712 (Envy24)" | 662 | tristate "ICEnsemble ICE1712 (Envy24)" |
628 | depends on SND | 663 | depends on SND |
@@ -802,6 +837,16 @@ config SND_RME9652 | |||
802 | To compile this driver as a module, choose M here: the module | 837 | To compile this driver as a module, choose M here: the module |
803 | will be called snd-rme9652. | 838 | will be called snd-rme9652. |
804 | 839 | ||
840 | config SND_SIS7019 | ||
841 | tristate "SiS 7019 Audio Accelerator" | ||
842 | depends on SND && X86 && !X86_64 | ||
843 | select SND_AC97_CODEC | ||
844 | help | ||
845 | Say Y here to include support for the SiS 7019 Audio Accelerator. | ||
846 | |||
847 | To compile this driver as a module, choose M here: the module | ||
848 | will be called snd-sis7019. | ||
849 | |||
805 | config SND_SONICVIBES | 850 | config SND_SONICVIBES |
806 | tristate "S3 SonicVibes" | 851 | tristate "S3 SonicVibes" |
807 | depends on SND | 852 | depends on SND |
@@ -850,6 +895,17 @@ config SND_VIA82XX_MODEM | |||
850 | To compile this driver as a module, choose M here: the module | 895 | To compile this driver as a module, choose M here: the module |
851 | will be called snd-via82xx-modem. | 896 | will be called snd-via82xx-modem. |
852 | 897 | ||
898 | config SND_VIRTUOSO | ||
899 | tristate "Asus Virtuoso 200 (Xonar)" | ||
900 | depends on SND | ||
901 | select SND_OXYGEN_LIB | ||
902 | help | ||
903 | Say Y here to include support for sound cards based on the | ||
904 | Asus AV200 chip, i.e., Xonar D2 and Xonar D2X. | ||
905 | |||
906 | To compile this driver as a module, choose M here: the module | ||
907 | will be called snd-virtuoso. | ||
908 | |||
853 | config SND_VX222 | 909 | config SND_VX222 |
854 | tristate "Digigram VX222" | 910 | tristate "Digigram VX222" |
855 | depends on SND | 911 | depends on SND |
diff --git a/sound/pci/Makefile b/sound/pci/Makefile index 09ddc82eeca2..2d42fd28f4e7 100644 --- a/sound/pci/Makefile +++ b/sound/pci/Makefile | |||
@@ -23,6 +23,7 @@ snd-intel8x0m-objs := intel8x0m.o | |||
23 | snd-maestro3-objs := maestro3.o | 23 | snd-maestro3-objs := maestro3.o |
24 | snd-rme32-objs := rme32.o | 24 | snd-rme32-objs := rme32.o |
25 | snd-rme96-objs := rme96.o | 25 | snd-rme96-objs := rme96.o |
26 | snd-sis7019-objs := sis7019.o | ||
26 | snd-sonicvibes-objs := sonicvibes.o | 27 | snd-sonicvibes-objs := sonicvibes.o |
27 | snd-via82xx-objs := via82xx.o | 28 | snd-via82xx-objs := via82xx.o |
28 | snd-via82xx-modem-objs := via82xx_modem.o | 29 | snd-via82xx-modem-objs := via82xx_modem.o |
@@ -48,6 +49,7 @@ obj-$(CONFIG_SND_INTEL8X0M) += snd-intel8x0m.o | |||
48 | obj-$(CONFIG_SND_MAESTRO3) += snd-maestro3.o | 49 | obj-$(CONFIG_SND_MAESTRO3) += snd-maestro3.o |
49 | obj-$(CONFIG_SND_RME32) += snd-rme32.o | 50 | obj-$(CONFIG_SND_RME32) += snd-rme32.o |
50 | obj-$(CONFIG_SND_RME96) += snd-rme96.o | 51 | obj-$(CONFIG_SND_RME96) += snd-rme96.o |
52 | obj-$(CONFIG_SND_SIS7019) += snd-sis7019.o | ||
51 | obj-$(CONFIG_SND_SONICVIBES) += snd-sonicvibes.o | 53 | obj-$(CONFIG_SND_SONICVIBES) += snd-sonicvibes.o |
52 | obj-$(CONFIG_SND_VIA82XX) += snd-via82xx.o | 54 | obj-$(CONFIG_SND_VIA82XX) += snd-via82xx.o |
53 | obj-$(CONFIG_SND_VIA82XX_MODEM) += snd-via82xx-modem.o | 55 | obj-$(CONFIG_SND_VIA82XX_MODEM) += snd-via82xx-modem.o |
@@ -66,6 +68,7 @@ obj-$(CONFIG_SND) += \ | |||
66 | korg1212/ \ | 68 | korg1212/ \ |
67 | mixart/ \ | 69 | mixart/ \ |
68 | nm256/ \ | 70 | nm256/ \ |
71 | oxygen/ \ | ||
69 | pcxhr/ \ | 72 | pcxhr/ \ |
70 | riptide/ \ | 73 | riptide/ \ |
71 | rme9652/ \ | 74 | rme9652/ \ |
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 6a9966df0cc9..45fd29017ddd 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c | |||
@@ -22,7 +22,6 @@ | |||
22 | * | 22 | * |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <sound/driver.h> | ||
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
27 | #include <linux/init.h> | 26 | #include <linux/init.h> |
28 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 98c8b727b62b..50c637e55ffa 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c | |||
@@ -133,6 +133,14 @@ static int ac97_channel_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
133 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); | 133 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); |
134 | unsigned char mode = ucontrol->value.enumerated.item[0]; | 134 | unsigned char mode = ucontrol->value.enumerated.item[0]; |
135 | 135 | ||
136 | if (kcontrol->private_value) { | ||
137 | if (mode >= 2) | ||
138 | return -EINVAL; | ||
139 | } else { | ||
140 | if (mode >= 3) | ||
141 | return -EINVAL; | ||
142 | } | ||
143 | |||
136 | if (mode != ac97->channel_mode) { | 144 | if (mode != ac97->channel_mode) { |
137 | ac97->channel_mode = mode; | 145 | ac97->channel_mode = mode; |
138 | if (ac97->build_ops->update_jacks) | 146 | if (ac97->build_ops->update_jacks) |
@@ -2142,8 +2150,7 @@ static int snd_ac97_ad1985_vrefout_put(struct snd_kcontrol *kcontrol, | |||
2142 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); | 2150 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); |
2143 | unsigned short val; | 2151 | unsigned short val; |
2144 | 2152 | ||
2145 | if (ucontrol->value.enumerated.item[0] > 3 | 2153 | if (ucontrol->value.enumerated.item[0] > 3) |
2146 | || ucontrol->value.enumerated.item[0] < 0) | ||
2147 | return -EINVAL; | 2154 | return -EINVAL; |
2148 | val = ctrl2reg[ucontrol->value.enumerated.item[0]] | 2155 | val = ctrl2reg[ucontrol->value.enumerated.item[0]] |
2149 | << AC97_AD198X_VREF_SHIFT; | 2156 | << AC97_AD198X_VREF_SHIFT; |
diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h index 9cccc27ea1b5..47bf8dfe8276 100644 --- a/sound/pci/ac97/ac97_patch.h +++ b/sound/pci/ac97/ac97_patch.h | |||
@@ -83,8 +83,10 @@ static int snd_ac97_swap_ctl(struct snd_ac97 *ac97, const char *s1, | |||
83 | const char *s2, const char *suffix); | 83 | const char *s2, const char *suffix); |
84 | static void snd_ac97_rename_vol_ctl(struct snd_ac97 *ac97, const char *src, | 84 | static void snd_ac97_rename_vol_ctl(struct snd_ac97 *ac97, const char *src, |
85 | const char *dst); | 85 | const char *dst); |
86 | #ifdef CONFIG_PM | ||
86 | static void snd_ac97_restore_status(struct snd_ac97 *ac97); | 87 | static void snd_ac97_restore_status(struct snd_ac97 *ac97); |
87 | static void snd_ac97_restore_iec958(struct snd_ac97 *ac97); | 88 | static void snd_ac97_restore_iec958(struct snd_ac97 *ac97); |
89 | #endif | ||
88 | static int snd_ac97_info_enum_double(struct snd_kcontrol *kcontrol, | 90 | static int snd_ac97_info_enum_double(struct snd_kcontrol *kcontrol, |
89 | struct snd_ctl_elem_info *uinfo); | 91 | struct snd_ctl_elem_info *uinfo); |
90 | static int snd_ac97_get_enum_double(struct snd_kcontrol *kcontrol, | 92 | static int snd_ac97_get_enum_double(struct snd_kcontrol *kcontrol, |
diff --git a/sound/pci/ac97/ac97_pcm.c b/sound/pci/ac97/ac97_pcm.c index 8cbc03332b01..3674f35c4a79 100644 --- a/sound/pci/ac97/ac97_pcm.c +++ b/sound/pci/ac97/ac97_pcm.c | |||
@@ -23,7 +23,6 @@ | |||
23 | * | 23 | * |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <sound/driver.h> | ||
27 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
28 | #include <linux/init.h> | 27 | #include <linux/init.h> |
29 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
diff --git a/sound/pci/ac97/ac97_proc.c b/sound/pci/ac97/ac97_proc.c index fed4a2c3d8a1..060ea59d5f02 100644 --- a/sound/pci/ac97/ac97_proc.c +++ b/sound/pci/ac97/ac97_proc.c | |||
@@ -22,7 +22,6 @@ | |||
22 | * | 22 | * |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <sound/driver.h> | ||
26 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
27 | #include <linux/mutex.h> | 26 | #include <linux/mutex.h> |
28 | 27 | ||
diff --git a/sound/pci/ac97/ak4531_codec.c b/sound/pci/ac97/ak4531_codec.c index 722de451d15f..c0c1633999ea 100644 --- a/sound/pci/ac97/ak4531_codec.c +++ b/sound/pci/ac97/ak4531_codec.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index 98970d401be9..a66d5150bb7a 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c | |||
@@ -40,7 +40,6 @@ | |||
40 | #include <linux/compiler.h> | 40 | #include <linux/compiler.h> |
41 | #include <linux/delay.h> | 41 | #include <linux/delay.h> |
42 | 42 | ||
43 | #include <sound/driver.h> | ||
44 | #include <sound/core.h> | 43 | #include <sound/core.h> |
45 | #include <sound/pcm.h> | 44 | #include <sound/pcm.h> |
46 | #include <sound/initval.h> | 45 | #include <sound/initval.h> |
@@ -1055,7 +1054,7 @@ static struct pci_device_id snd_ad1889_ids[] = { | |||
1055 | }; | 1054 | }; |
1056 | MODULE_DEVICE_TABLE(pci, snd_ad1889_ids); | 1055 | MODULE_DEVICE_TABLE(pci, snd_ad1889_ids); |
1057 | 1056 | ||
1058 | static struct pci_driver ad1889_pci = { | 1057 | static struct pci_driver ad1889_pci_driver = { |
1059 | .name = "AD1889 Audio", | 1058 | .name = "AD1889 Audio", |
1060 | .id_table = snd_ad1889_ids, | 1059 | .id_table = snd_ad1889_ids, |
1061 | .probe = snd_ad1889_probe, | 1060 | .probe = snd_ad1889_probe, |
@@ -1065,13 +1064,13 @@ static struct pci_driver ad1889_pci = { | |||
1065 | static int __init | 1064 | static int __init |
1066 | alsa_ad1889_init(void) | 1065 | alsa_ad1889_init(void) |
1067 | { | 1066 | { |
1068 | return pci_register_driver(&ad1889_pci); | 1067 | return pci_register_driver(&ad1889_pci_driver); |
1069 | } | 1068 | } |
1070 | 1069 | ||
1071 | static void __exit | 1070 | static void __exit |
1072 | alsa_ad1889_fini(void) | 1071 | alsa_ad1889_fini(void) |
1073 | { | 1072 | { |
1074 | pci_unregister_driver(&ad1889_pci); | 1073 | pci_unregister_driver(&ad1889_pci_driver); |
1075 | } | 1074 | } |
1076 | 1075 | ||
1077 | module_init(alsa_ad1889_init); | 1076 | module_init(alsa_ad1889_init); |
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index 4c2bd7adf674..6a905ed9cbd6 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c | |||
@@ -25,7 +25,6 @@ | |||
25 | * | 25 | * |
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include <sound/driver.h> | ||
29 | #include <asm/io.h> | 28 | #include <asm/io.h> |
30 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
31 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
diff --git a/sound/pci/als300.c b/sound/pci/als300.c index 48cc39b771d9..0e990a735821 100644 --- a/sound/pci/als300.c +++ b/sound/pci/als300.c | |||
@@ -30,7 +30,6 @@ | |||
30 | * to keep track of what period we are in. | 30 | * to keep track of what period we are in. |
31 | */ | 31 | */ |
32 | 32 | ||
33 | #include <sound/driver.h> | ||
34 | #include <linux/delay.h> | 33 | #include <linux/delay.h> |
35 | #include <linux/init.h> | 34 | #include <linux/init.h> |
36 | #include <linux/moduleparam.h> | 35 | #include <linux/moduleparam.h> |
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index 1190ef366a41..27ce6136ab00 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c | |||
@@ -63,7 +63,6 @@ | |||
63 | * - power management? (card can do voice wakeup according to datasheet!!) | 63 | * - power management? (card can do voice wakeup according to datasheet!!) |
64 | */ | 64 | */ |
65 | 65 | ||
66 | #include <sound/driver.h> | ||
67 | #include <asm/io.h> | 66 | #include <asm/io.h> |
68 | #include <linux/init.h> | 67 | #include <linux/init.h> |
69 | #include <linux/pci.h> | 68 | #include <linux/pci.h> |
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 89184a424140..4594186b83ee 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <asm/io.h> | 22 | #include <asm/io.h> |
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
@@ -560,7 +559,7 @@ static int snd_atiixp_aclink_down(struct atiixp *chip) | |||
560 | ATI_REG_ISR_CODEC2_NOT_READY) | 559 | ATI_REG_ISR_CODEC2_NOT_READY) |
561 | #define CODEC_CHECK_BITS (ALL_CODEC_NOT_READY|ATI_REG_ISR_NEW_FRAME) | 560 | #define CODEC_CHECK_BITS (ALL_CODEC_NOT_READY|ATI_REG_ISR_NEW_FRAME) |
562 | 561 | ||
563 | static int ac97_probing_bugs(struct pci_dev *pci) | 562 | static int __devinit ac97_probing_bugs(struct pci_dev *pci) |
564 | { | 563 | { |
565 | const struct snd_pci_quirk *q; | 564 | const struct snd_pci_quirk *q; |
566 | 565 | ||
@@ -574,7 +573,7 @@ static int ac97_probing_bugs(struct pci_dev *pci) | |||
574 | return -1; | 573 | return -1; |
575 | } | 574 | } |
576 | 575 | ||
577 | static int snd_atiixp_codec_detect(struct atiixp *chip) | 576 | static int __devinit snd_atiixp_codec_detect(struct atiixp *chip) |
578 | { | 577 | { |
579 | int timeout; | 578 | int timeout; |
580 | 579 | ||
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index ce752f84457a..a67a869180d4 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <asm/io.h> | 22 | #include <asm/io.h> |
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h index 5ccf0b1ec670..4aad35bba11a 100644 --- a/sound/pci/au88x0/au88x0.h +++ b/sound/pci/au88x0/au88x0.h | |||
@@ -18,7 +18,6 @@ | |||
18 | #define __SOUND_AU88X0_H | 18 | #define __SOUND_AU88X0_H |
19 | 19 | ||
20 | #ifdef __KERNEL__ | 20 | #ifdef __KERNEL__ |
21 | #include <sound/driver.h> | ||
22 | #include <linux/pci.h> | 21 | #include <linux/pci.h> |
23 | #include <asm/io.h> | 22 | #include <asm/io.h> |
24 | #include <sound/core.h> | 23 | #include <sound/core.h> |
diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c index 4a336eaae9d2..333c62de8620 100644 --- a/sound/pci/au88x0/au88x0_core.c +++ b/sound/pci/au88x0/au88x0_core.c | |||
@@ -2395,7 +2395,7 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id) | |||
2395 | if (!(hwread(vortex->mmio, VORTEX_STAT) & 0x1)) | 2395 | if (!(hwread(vortex->mmio, VORTEX_STAT) & 0x1)) |
2396 | return IRQ_NONE; | 2396 | return IRQ_NONE; |
2397 | 2397 | ||
2398 | // This is the Interrrupt Enable flag we set before (consistency check). | 2398 | // This is the Interrupt Enable flag we set before (consistency check). |
2399 | if (!(hwread(vortex->mmio, VORTEX_CTRL) & CTRL_IRQ_ENABLE)) | 2399 | if (!(hwread(vortex->mmio, VORTEX_CTRL) & CTRL_IRQ_ENABLE)) |
2400 | return IRQ_NONE; | 2400 | return IRQ_NONE; |
2401 | 2401 | ||
diff --git a/sound/pci/au88x0/au88x0_game.c b/sound/pci/au88x0/au88x0_game.c index a07d1deba322..bc212f41a38a 100644 --- a/sound/pci/au88x0/au88x0_game.c +++ b/sound/pci/au88x0/au88x0_game.c | |||
@@ -30,7 +30,6 @@ | |||
30 | * driver. (email: mjander@embedded.cl). | 30 | * driver. (email: mjander@embedded.cl). |
31 | */ | 31 | */ |
32 | 32 | ||
33 | #include <sound/driver.h> | ||
34 | #include <linux/time.h> | 33 | #include <linux/time.h> |
35 | #include <linux/delay.h> | 34 | #include <linux/delay.h> |
36 | #include <linux/init.h> | 35 | #include <linux/init.h> |
diff --git a/sound/pci/au88x0/au88x0_mixer.c b/sound/pci/au88x0/au88x0_mixer.c index c96da1dab863..c92f493d341e 100644 --- a/sound/pci/au88x0/au88x0_mixer.c +++ b/sound/pci/au88x0/au88x0_mixer.c | |||
@@ -5,7 +5,6 @@ | |||
5 | * | 5 | * |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <sound/driver.h> | ||
9 | #include <linux/time.h> | 8 | #include <linux/time.h> |
10 | #include <linux/init.h> | 9 | #include <linux/init.h> |
11 | #include <sound/core.h> | 10 | #include <sound/core.h> |
diff --git a/sound/pci/au88x0/au88x0_mpu401.c b/sound/pci/au88x0/au88x0_mpu401.c index 8db3d3e6f7bb..0dc8d259d1ed 100644 --- a/sound/pci/au88x0/au88x0_mpu401.c +++ b/sound/pci/au88x0/au88x0_mpu401.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/time.h> | 24 | #include <linux/time.h> |
26 | #include <linux/init.h> | 25 | #include <linux/init.h> |
27 | #include <sound/core.h> | 26 | #include <sound/core.h> |
diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c index 7b5baa173859..526c6c5ecf7b 100644 --- a/sound/pci/au88x0/au88x0_pcm.c +++ b/sound/pci/au88x0/au88x0_pcm.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * It remains stuck,and DMA transfers do not happen. | 21 | * It remains stuck,and DMA transfers do not happen. |
22 | */ | 22 | */ |
23 | #include <sound/asoundef.h> | 23 | #include <sound/asoundef.h> |
24 | #include <sound/driver.h> | ||
25 | #include <linux/time.h> | 24 | #include <linux/time.h> |
26 | #include <sound/core.h> | 25 | #include <sound/core.h> |
27 | #include <sound/pcm.h> | 26 | #include <sound/pcm.h> |
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 36d3666a5b77..4e71a55120a0 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c | |||
@@ -115,7 +115,6 @@ | |||
115 | * code (but I'm not too optimistic that doing this is possible at all) | 115 | * code (but I'm not too optimistic that doing this is possible at all) |
116 | */ | 116 | */ |
117 | 117 | ||
118 | #include <sound/driver.h> | ||
119 | #include <asm/io.h> | 118 | #include <asm/io.h> |
120 | #include <linux/init.h> | 119 | #include <linux/init.h> |
121 | #include <linux/pci.h> | 120 | #include <linux/pci.h> |
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index 2dba752faf4e..c9a2421cf6f0 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
27 | #include <linux/pci.h> | 26 | #include <linux/pci.h> |
diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index 75da1746e758..74175fc80c7f 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h | |||
@@ -272,7 +272,6 @@ | |||
272 | #define SPCS_WORD_LENGTH_20A 0x0000000a /* Word Length 20 bit */ | 272 | #define SPCS_WORD_LENGTH_20A 0x0000000a /* Word Length 20 bit */ |
273 | #define SPCS_WORD_LENGTH_20 0x00000009 /* Word Length 20 bit (both 0xa and 0x9 are 20 bit) */ | 273 | #define SPCS_WORD_LENGTH_20 0x00000009 /* Word Length 20 bit (both 0xa and 0x9 are 20 bit) */ |
274 | #define SPCS_WORD_LENGTH_21 0x00000007 /* Word Length 21 bit */ | 274 | #define SPCS_WORD_LENGTH_21 0x00000007 /* Word Length 21 bit */ |
275 | #define SPCS_WORD_LENGTH_21 0x00000007 /* Word Length 21 bit */ | ||
276 | #define SPCS_WORD_LENGTH_22 0x00000005 /* Word Length 22 bit */ | 275 | #define SPCS_WORD_LENGTH_22 0x00000005 /* Word Length 22 bit */ |
277 | #define SPCS_WORD_LENGTH_23 0x00000003 /* Word Length 23 bit */ | 276 | #define SPCS_WORD_LENGTH_23 0x00000003 /* Word Length 23 bit */ |
278 | #define SPCS_WORD_LENGTH_24 0x0000000b /* Word Length 24 bit */ | 277 | #define SPCS_WORD_LENGTH_24 0x0000000b /* Word Length 24 bit */ |
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 31d8db9f7a4c..176e0f0e8058 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c | |||
@@ -135,7 +135,6 @@ | |||
135 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 135 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
136 | * | 136 | * |
137 | */ | 137 | */ |
138 | #include <sound/driver.h> | ||
139 | #include <linux/delay.h> | 138 | #include <linux/delay.h> |
140 | #include <linux/init.h> | 139 | #include <linux/init.h> |
141 | #include <linux/interrupt.h> | 140 | #include <linux/interrupt.h> |
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 3f9b5c560036..af736869d9b1 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c | |||
@@ -60,7 +60,6 @@ | |||
60 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 60 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
61 | * | 61 | * |
62 | */ | 62 | */ |
63 | #include <sound/driver.h> | ||
64 | #include <linux/delay.h> | 63 | #include <linux/delay.h> |
65 | #include <linux/init.h> | 64 | #include <linux/init.h> |
66 | #include <linux/interrupt.h> | 65 | #include <linux/interrupt.h> |
diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c index 61f2718ae359..c62b7d10ec61 100644 --- a/sound/pci/ca0106/ca0106_proc.c +++ b/sound/pci/ca0106/ca0106_proc.c | |||
@@ -60,7 +60,6 @@ | |||
60 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 60 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
61 | * | 61 | * |
62 | */ | 62 | */ |
63 | #include <sound/driver.h> | ||
64 | #include <linux/delay.h> | 63 | #include <linux/delay.h> |
65 | #include <linux/init.h> | 64 | #include <linux/init.h> |
66 | #include <linux/interrupt.h> | 65 | #include <linux/interrupt.h> |
diff --git a/sound/pci/ca0106/ca_midi.c b/sound/pci/ca0106/ca_midi.c index ad32eff2713f..893ee4f1ea77 100644 --- a/sound/pci/ca0106/ca_midi.c +++ b/sound/pci/ca0106/ca_midi.c | |||
@@ -27,7 +27,6 @@ | |||
27 | */ | 27 | */ |
28 | 28 | ||
29 | #include <linux/spinlock.h> | 29 | #include <linux/spinlock.h> |
30 | #include <sound/driver.h> | ||
31 | #include <sound/core.h> | 30 | #include <sound/core.h> |
32 | #include <sound/rawmidi.h> | 31 | #include <sound/rawmidi.h> |
33 | 32 | ||
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 1fa5f004e858..135f30860753 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c | |||
@@ -20,7 +20,6 @@ | |||
20 | /* Does not work. Warning may block system in capture mode */ | 20 | /* Does not work. Warning may block system in capture mode */ |
21 | /* #define USE_VAR48KRATE */ | 21 | /* #define USE_VAR48KRATE */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <asm/io.h> | 23 | #include <asm/io.h> |
25 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
26 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
@@ -150,6 +149,8 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address."); | |||
150 | #define CM_CH0_SRATE_176K 0x00000200 | 149 | #define CM_CH0_SRATE_176K 0x00000200 |
151 | #define CM_CH0_SRATE_96K 0x00000200 /* model 055? */ | 150 | #define CM_CH0_SRATE_96K 0x00000200 /* model 055? */ |
152 | #define CM_CH0_SRATE_88K 0x00000100 | 151 | #define CM_CH0_SRATE_88K 0x00000100 |
152 | #define CM_CH0_SRATE_128K 0x00000300 | ||
153 | #define CM_CH0_SRATE_MASK 0x00000300 | ||
153 | 154 | ||
154 | #define CM_SPDIF_INVERSE2 0x00000080 /* model 055? */ | 155 | #define CM_SPDIF_INVERSE2 0x00000080 /* model 055? */ |
155 | #define CM_DBLSPDS 0x00000040 /* double SPDIF sample rate 88.2/96 */ | 156 | #define CM_DBLSPDS 0x00000040 /* double SPDIF sample rate 88.2/96 */ |
@@ -473,6 +474,7 @@ struct cmipci { | |||
473 | unsigned int can_ac3_sw: 1; | 474 | unsigned int can_ac3_sw: 1; |
474 | unsigned int can_ac3_hw: 1; | 475 | unsigned int can_ac3_hw: 1; |
475 | unsigned int can_multi_ch: 1; | 476 | unsigned int can_multi_ch: 1; |
477 | unsigned int can_96k: 1; /* samplerate above 48k */ | ||
476 | unsigned int do_soft_ac3: 1; | 478 | unsigned int do_soft_ac3: 1; |
477 | 479 | ||
478 | unsigned int spdif_playback_avail: 1; /* spdif ready? */ | 480 | unsigned int spdif_playback_avail: 1; /* spdif ready? */ |
@@ -603,8 +605,6 @@ static unsigned int snd_cmipci_rate_freq(unsigned int rate) | |||
603 | { | 605 | { |
604 | unsigned int i; | 606 | unsigned int i; |
605 | 607 | ||
606 | if (rate > 48000) | ||
607 | rate /= 2; | ||
608 | for (i = 0; i < ARRAY_SIZE(rates); i++) { | 608 | for (i = 0; i < ARRAY_SIZE(rates); i++) { |
609 | if (rates[i] == rate) | 609 | if (rates[i] == rate) |
610 | return i; | 610 | return i; |
@@ -782,7 +782,7 @@ static int set_dac_channels(struct cmipci *cm, struct cmipci_pcm *rec, int chann | |||
782 | static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec, | 782 | static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec, |
783 | struct snd_pcm_substream *substream) | 783 | struct snd_pcm_substream *substream) |
784 | { | 784 | { |
785 | unsigned int reg, freq, val; | 785 | unsigned int reg, freq, freq_ext, val; |
786 | unsigned int period_size; | 786 | unsigned int period_size; |
787 | struct snd_pcm_runtime *runtime = substream->runtime; | 787 | struct snd_pcm_runtime *runtime = substream->runtime; |
788 | 788 | ||
@@ -830,7 +830,17 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec, | |||
830 | //snd_printd("cmipci: functrl0 = %08x\n", cm->ctrl); | 830 | //snd_printd("cmipci: functrl0 = %08x\n", cm->ctrl); |
831 | 831 | ||
832 | /* set sample rate */ | 832 | /* set sample rate */ |
833 | freq = snd_cmipci_rate_freq(runtime->rate); | 833 | freq = 0; |
834 | freq_ext = 0; | ||
835 | if (runtime->rate > 48000) | ||
836 | switch (runtime->rate) { | ||
837 | case 88200: freq_ext = CM_CH0_SRATE_88K; break; | ||
838 | case 96000: freq_ext = CM_CH0_SRATE_96K; break; | ||
839 | case 128000: freq_ext = CM_CH0_SRATE_128K; break; | ||
840 | default: snd_BUG(); break; | ||
841 | } | ||
842 | else | ||
843 | freq = snd_cmipci_rate_freq(runtime->rate); | ||
834 | val = snd_cmipci_read(cm, CM_REG_FUNCTRL1); | 844 | val = snd_cmipci_read(cm, CM_REG_FUNCTRL1); |
835 | if (rec->ch) { | 845 | if (rec->ch) { |
836 | val &= ~CM_DSFC_MASK; | 846 | val &= ~CM_DSFC_MASK; |
@@ -851,19 +861,20 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec, | |||
851 | val &= ~CM_CH0FMT_MASK; | 861 | val &= ~CM_CH0FMT_MASK; |
852 | val |= rec->fmt << CM_CH0FMT_SHIFT; | 862 | val |= rec->fmt << CM_CH0FMT_SHIFT; |
853 | } | 863 | } |
854 | if (cm->chip_version == 68) { | 864 | if (cm->can_96k) { |
855 | if (runtime->rate == 88200) | 865 | val &= ~(CM_CH0_SRATE_MASK << (rec->ch * 2)); |
856 | val |= CM_CH0_SRATE_88K << (rec->ch * 2); | 866 | val |= freq_ext << (rec->ch * 2); |
857 | else | ||
858 | val &= ~(CM_CH0_SRATE_88K << (rec->ch * 2)); | ||
859 | if (runtime->rate == 96000) | ||
860 | val |= CM_CH0_SRATE_96K << (rec->ch * 2); | ||
861 | else | ||
862 | val &= ~(CM_CH0_SRATE_96K << (rec->ch * 2)); | ||
863 | } | 867 | } |
864 | snd_cmipci_write(cm, CM_REG_CHFORMAT, val); | 868 | snd_cmipci_write(cm, CM_REG_CHFORMAT, val); |
865 | //snd_printd("cmipci: chformat = %08x\n", val); | 869 | //snd_printd("cmipci: chformat = %08x\n", val); |
866 | 870 | ||
871 | if (!rec->is_dac && cm->chip_version) { | ||
872 | if (runtime->rate > 44100) | ||
873 | snd_cmipci_set_bit(cm, CM_REG_EXT_MISC, CM_ADC48K44K); | ||
874 | else | ||
875 | snd_cmipci_clear_bit(cm, CM_REG_EXT_MISC, CM_ADC48K44K); | ||
876 | } | ||
877 | |||
867 | rec->running = 0; | 878 | rec->running = 0; |
868 | spin_unlock_irq(&cm->reg_lock); | 879 | spin_unlock_irq(&cm->reg_lock); |
869 | 880 | ||
@@ -1280,7 +1291,7 @@ static int snd_cmipci_playback_prepare(struct snd_pcm_substream *substream) | |||
1280 | int rate = substream->runtime->rate; | 1291 | int rate = substream->runtime->rate; |
1281 | int err, do_spdif, do_ac3 = 0; | 1292 | int err, do_spdif, do_ac3 = 0; |
1282 | 1293 | ||
1283 | do_spdif = (rate >= 44100 && | 1294 | do_spdif = (rate >= 44100 && rate <= 96000 && |
1284 | substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE && | 1295 | substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE && |
1285 | substream->runtime->channels == 2); | 1296 | substream->runtime->channels == 2); |
1286 | if (do_spdif && cm->can_ac3_hw) | 1297 | if (do_spdif && cm->can_ac3_hw) |
@@ -1336,10 +1347,8 @@ static void snd_cmipci_silence_hack(struct cmipci *cm, struct cmipci_pcm *rec) | |||
1336 | val = snd_cmipci_read(cm, CM_REG_CHFORMAT); | 1347 | val = snd_cmipci_read(cm, CM_REG_CHFORMAT); |
1337 | val &= ~(CM_CH0FMT_MASK << (rec->ch * 2)); | 1348 | val &= ~(CM_CH0FMT_MASK << (rec->ch * 2)); |
1338 | val |= (3 << CM_CH0FMT_SHIFT) << (rec->ch * 2); | 1349 | val |= (3 << CM_CH0FMT_SHIFT) << (rec->ch * 2); |
1339 | if (cm->chip_version == 68) { | 1350 | if (cm->can_96k) |
1340 | val &= ~(CM_CH0_SRATE_88K << (rec->ch * 2)); | 1351 | val &= ~(CM_CH0_SRATE_MASK << (rec->ch * 2)); |
1341 | val &= ~(CM_CH0_SRATE_96K << (rec->ch * 2)); | ||
1342 | } | ||
1343 | snd_cmipci_write(cm, CM_REG_CHFORMAT, val); | 1352 | snd_cmipci_write(cm, CM_REG_CHFORMAT, val); |
1344 | 1353 | ||
1345 | /* start stream (we don't need interrupts) */ | 1354 | /* start stream (we don't need interrupts) */ |
@@ -1391,6 +1400,17 @@ static int snd_cmipci_capture_spdif_prepare(struct snd_pcm_substream *substream) | |||
1391 | 1400 | ||
1392 | spin_lock_irq(&cm->reg_lock); | 1401 | spin_lock_irq(&cm->reg_lock); |
1393 | snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_CAPTURE_SPDF); | 1402 | snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_CAPTURE_SPDF); |
1403 | if (cm->can_96k) { | ||
1404 | if (substream->runtime->rate > 48000) | ||
1405 | snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_DBLSPDS); | ||
1406 | else | ||
1407 | snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_DBLSPDS); | ||
1408 | } | ||
1409 | if (snd_pcm_format_width(substream->runtime->format) > 16) | ||
1410 | snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL); | ||
1411 | else | ||
1412 | snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL); | ||
1413 | |||
1394 | spin_unlock_irq(&cm->reg_lock); | 1414 | spin_unlock_irq(&cm->reg_lock); |
1395 | 1415 | ||
1396 | return snd_cmipci_pcm_prepare(cm, &cm->channel[CM_CH_CAPT], substream); | 1416 | return snd_cmipci_pcm_prepare(cm, &cm->channel[CM_CH_CAPT], substream); |
@@ -1402,6 +1422,7 @@ static int snd_cmipci_capture_spdif_hw_free(struct snd_pcm_substream *subs) | |||
1402 | 1422 | ||
1403 | spin_lock_irq(&cm->reg_lock); | 1423 | spin_lock_irq(&cm->reg_lock); |
1404 | snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_CAPTURE_SPDF); | 1424 | snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_CAPTURE_SPDF); |
1425 | snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL); | ||
1405 | spin_unlock_irq(&cm->reg_lock); | 1426 | spin_unlock_irq(&cm->reg_lock); |
1406 | 1427 | ||
1407 | return snd_cmipci_hw_free(subs); | 1428 | return snd_cmipci_hw_free(subs); |
@@ -1553,7 +1574,8 @@ static struct snd_pcm_hardware snd_cmipci_capture_spdif = | |||
1553 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 1574 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
1554 | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | | 1575 | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | |
1555 | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), | 1576 | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), |
1556 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 1577 | .formats = SNDRV_PCM_FMTBIT_S16_LE | |
1578 | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE, | ||
1557 | .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, | 1579 | .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, |
1558 | .rate_min = 44100, | 1580 | .rate_min = 44100, |
1559 | .rate_max = 48000, | 1581 | .rate_max = 48000, |
@@ -1567,6 +1589,14 @@ static struct snd_pcm_hardware snd_cmipci_capture_spdif = | |||
1567 | .fifo_size = 0, | 1589 | .fifo_size = 0, |
1568 | }; | 1590 | }; |
1569 | 1591 | ||
1592 | static unsigned int rate_constraints[] = { 5512, 8000, 11025, 16000, 22050, | ||
1593 | 32000, 44100, 48000, 88200, 96000, 128000 }; | ||
1594 | static struct snd_pcm_hw_constraint_list hw_constraints_rates = { | ||
1595 | .count = ARRAY_SIZE(rate_constraints), | ||
1596 | .list = rate_constraints, | ||
1597 | .mask = 0, | ||
1598 | }; | ||
1599 | |||
1570 | /* | 1600 | /* |
1571 | * check device open/close | 1601 | * check device open/close |
1572 | */ | 1602 | */ |
@@ -1636,6 +1666,13 @@ static int snd_cmipci_playback_open(struct snd_pcm_substream *substream) | |||
1636 | runtime->hw.rates |= SNDRV_PCM_RATE_88200 | | 1666 | runtime->hw.rates |= SNDRV_PCM_RATE_88200 | |
1637 | SNDRV_PCM_RATE_96000; | 1667 | SNDRV_PCM_RATE_96000; |
1638 | runtime->hw.rate_max = 96000; | 1668 | runtime->hw.rate_max = 96000; |
1669 | } else if (cm->chip_version == 55) { | ||
1670 | err = snd_pcm_hw_constraint_list(runtime, 0, | ||
1671 | SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); | ||
1672 | if (err < 0) | ||
1673 | return err; | ||
1674 | runtime->hw.rates |= SNDRV_PCM_RATE_KNOT; | ||
1675 | runtime->hw.rate_max = 128000; | ||
1639 | } | 1676 | } |
1640 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000); | 1677 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000); |
1641 | cm->dig_pcm_status = cm->dig_status; | 1678 | cm->dig_pcm_status = cm->dig_status; |
@@ -1654,6 +1691,13 @@ static int snd_cmipci_capture_open(struct snd_pcm_substream *substream) | |||
1654 | if (cm->chip_version == 68) { // 8768 only supports 44k/48k recording | 1691 | if (cm->chip_version == 68) { // 8768 only supports 44k/48k recording |
1655 | runtime->hw.rate_min = 41000; | 1692 | runtime->hw.rate_min = 41000; |
1656 | runtime->hw.rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000; | 1693 | runtime->hw.rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000; |
1694 | } else if (cm->chip_version == 55) { | ||
1695 | err = snd_pcm_hw_constraint_list(runtime, 0, | ||
1696 | SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); | ||
1697 | if (err < 0) | ||
1698 | return err; | ||
1699 | runtime->hw.rates |= SNDRV_PCM_RATE_KNOT; | ||
1700 | runtime->hw.rate_max = 128000; | ||
1657 | } | 1701 | } |
1658 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000); | 1702 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000); |
1659 | return 0; | 1703 | return 0; |
@@ -1685,6 +1729,13 @@ static int snd_cmipci_playback2_open(struct snd_pcm_substream *substream) | |||
1685 | runtime->hw.rates |= SNDRV_PCM_RATE_88200 | | 1729 | runtime->hw.rates |= SNDRV_PCM_RATE_88200 | |
1686 | SNDRV_PCM_RATE_96000; | 1730 | SNDRV_PCM_RATE_96000; |
1687 | runtime->hw.rate_max = 96000; | 1731 | runtime->hw.rate_max = 96000; |
1732 | } else if (cm->chip_version == 55) { | ||
1733 | err = snd_pcm_hw_constraint_list(runtime, 0, | ||
1734 | SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); | ||
1735 | if (err < 0) | ||
1736 | return err; | ||
1737 | runtime->hw.rates |= SNDRV_PCM_RATE_KNOT; | ||
1738 | runtime->hw.rate_max = 128000; | ||
1688 | } | 1739 | } |
1689 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000); | 1740 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000); |
1690 | return 0; | 1741 | return 0; |
@@ -1704,7 +1755,7 @@ static int snd_cmipci_playback_spdif_open(struct snd_pcm_substream *substream) | |||
1704 | runtime->hw.formats |= SNDRV_PCM_FMTBIT_S32_LE; | 1755 | runtime->hw.formats |= SNDRV_PCM_FMTBIT_S32_LE; |
1705 | snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); | 1756 | snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); |
1706 | } | 1757 | } |
1707 | if (cm->chip_version == 68) { | 1758 | if (cm->can_96k) { |
1708 | runtime->hw.rates |= SNDRV_PCM_RATE_88200 | | 1759 | runtime->hw.rates |= SNDRV_PCM_RATE_88200 | |
1709 | SNDRV_PCM_RATE_96000; | 1760 | SNDRV_PCM_RATE_96000; |
1710 | runtime->hw.rate_max = 96000; | 1761 | runtime->hw.rate_max = 96000; |
@@ -1726,6 +1777,11 @@ static int snd_cmipci_capture_spdif_open(struct snd_pcm_substream *substream) | |||
1726 | if ((err = open_device_check(cm, CM_OPEN_SPDIF_CAPTURE, substream)) < 0) /* use channel B */ | 1777 | if ((err = open_device_check(cm, CM_OPEN_SPDIF_CAPTURE, substream)) < 0) /* use channel B */ |
1727 | return err; | 1778 | return err; |
1728 | runtime->hw = snd_cmipci_capture_spdif; | 1779 | runtime->hw = snd_cmipci_capture_spdif; |
1780 | if (cm->can_96k && !(cm->chip_version == 68)) { | ||
1781 | runtime->hw.rates |= SNDRV_PCM_RATE_88200 | | ||
1782 | SNDRV_PCM_RATE_96000; | ||
1783 | runtime->hw.rate_max = 96000; | ||
1784 | } | ||
1729 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x40000); | 1785 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x40000); |
1730 | return 0; | 1786 | return 0; |
1731 | } | 1787 | } |
@@ -2594,10 +2650,8 @@ static struct snd_kcontrol_new snd_cmipci_extra_mixer_switches[] __devinitdata = | |||
2594 | }; | 2650 | }; |
2595 | 2651 | ||
2596 | /* card control switches */ | 2652 | /* card control switches */ |
2597 | static struct snd_kcontrol_new snd_cmipci_control_switches[] __devinitdata = { | 2653 | static struct snd_kcontrol_new snd_cmipci_modem_switch __devinitdata = |
2598 | // DEFINE_CARD_SWITCH("Joystick", joystick), /* now module option */ | 2654 | DEFINE_CARD_SWITCH("Modem", modem); |
2599 | DEFINE_CARD_SWITCH("Modem", modem), | ||
2600 | }; | ||
2601 | 2655 | ||
2602 | 2656 | ||
2603 | static int __devinit snd_cmipci_mixer_new(struct cmipci *cm, int pcm_spdif_device) | 2657 | static int __devinit snd_cmipci_mixer_new(struct cmipci *cm, int pcm_spdif_device) |
@@ -2678,9 +2732,13 @@ static int __devinit snd_cmipci_mixer_new(struct cmipci *cm, int pcm_spdif_devic | |||
2678 | } | 2732 | } |
2679 | 2733 | ||
2680 | /* card switches */ | 2734 | /* card switches */ |
2681 | sw = snd_cmipci_control_switches; | 2735 | /* |
2682 | for (idx = 0; idx < ARRAY_SIZE(snd_cmipci_control_switches); idx++, sw++) { | 2736 | * newer chips don't have the register bits to force modem link |
2683 | err = snd_ctl_add(cm->card, snd_ctl_new1(sw, cm)); | 2737 | * detection; the bit that was FLINKON now mutes CH1 |
2738 | */ | ||
2739 | if (cm->chip_version < 39) { | ||
2740 | err = snd_ctl_add(cm->card, | ||
2741 | snd_ctl_new1(&snd_cmipci_modem_switch, cm)); | ||
2684 | if (err < 0) | 2742 | if (err < 0) |
2685 | return err; | 2743 | return err; |
2686 | } | 2744 | } |
@@ -2785,9 +2843,11 @@ static void __devinit query_chip(struct cmipci *cm) | |||
2785 | } else if (detect & CM_CHIP_8768) { | 2843 | } else if (detect & CM_CHIP_8768) { |
2786 | cm->chip_version = 68; | 2844 | cm->chip_version = 68; |
2787 | cm->max_channels = 8; | 2845 | cm->max_channels = 8; |
2846 | cm->can_96k = 1; | ||
2788 | } else { | 2847 | } else { |
2789 | cm->chip_version = 55; | 2848 | cm->chip_version = 55; |
2790 | cm->max_channels = 6; | 2849 | cm->max_channels = 6; |
2850 | cm->can_96k = 1; | ||
2791 | } | 2851 | } |
2792 | cm->can_ac3_hw = 1; | 2852 | cm->can_ac3_hw = 1; |
2793 | cm->can_multi_ch = 1; | 2853 | cm->can_multi_ch = 1; |
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 9a55f4a9739b..7556fd90d0eb 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <asm/io.h> | 22 | #include <asm/io.h> |
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c index 2699cb6c2cd6..e876b3263e46 100644 --- a/sound/pci/cs46xx/cs46xx.c +++ b/sound/pci/cs46xx/cs46xx.c | |||
@@ -25,7 +25,6 @@ | |||
25 | reloading the module may solve this. | 25 | reloading the module may solve this. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include <sound/driver.h> | ||
29 | #include <linux/pci.h> | 28 | #include <linux/pci.h> |
30 | #include <linux/time.h> | 29 | #include <linux/time.h> |
31 | #include <linux/init.h> | 30 | #include <linux/init.h> |
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 2c7bfc9fef61..87ddffcd9d89 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c | |||
@@ -8,7 +8,7 @@ | |||
8 | * - Sometimes the SPDIF input DSP tasks get's unsynchronized | 8 | * - Sometimes the SPDIF input DSP tasks get's unsynchronized |
9 | * and the SPDIF get somewhat "distorcionated", or/and left right channel | 9 | * and the SPDIF get somewhat "distorcionated", or/and left right channel |
10 | * are swapped. To get around this problem when it happens, mute and unmute | 10 | * are swapped. To get around this problem when it happens, mute and unmute |
11 | * the SPDIF input mixer controll. | 11 | * the SPDIF input mixer control. |
12 | * - On the Hercules Game Theater XP the amplifier are sometimes turned | 12 | * - On the Hercules Game Theater XP the amplifier are sometimes turned |
13 | * off on inadecuate moments which causes distorcions on sound. | 13 | * off on inadecuate moments which causes distorcions on sound. |
14 | * | 14 | * |
@@ -45,7 +45,6 @@ | |||
45 | * | 45 | * |
46 | */ | 46 | */ |
47 | 47 | ||
48 | #include <sound/driver.h> | ||
49 | #include <linux/delay.h> | 48 | #include <linux/delay.h> |
50 | #include <linux/pci.h> | 49 | #include <linux/pci.h> |
51 | #include <linux/pm.h> | 50 | #include <linux/pm.h> |
@@ -2084,71 +2083,6 @@ static int snd_cs46xx_spdif_stream_put(struct snd_kcontrol *kcontrol, | |||
2084 | #endif /* CONFIG_SND_CS46XX_NEW_DSP */ | 2083 | #endif /* CONFIG_SND_CS46XX_NEW_DSP */ |
2085 | 2084 | ||
2086 | 2085 | ||
2087 | #ifdef CONFIG_SND_CS46XX_DEBUG_GPIO | ||
2088 | static int snd_cs46xx_egpio_select_info(struct snd_kcontrol *kcontrol, | ||
2089 | struct snd_ctl_elem_info *uinfo) | ||
2090 | { | ||
2091 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
2092 | uinfo->count = 1; | ||
2093 | uinfo->value.integer.min = 0; | ||
2094 | uinfo->value.integer.max = 8; | ||
2095 | return 0; | ||
2096 | } | ||
2097 | |||
2098 | static int snd_cs46xx_egpio_select_get(struct snd_kcontrol *kcontrol, | ||
2099 | struct snd_ctl_elem_value *ucontrol) | ||
2100 | { | ||
2101 | struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol); | ||
2102 | ucontrol->value.integer.value[0] = chip->current_gpio; | ||
2103 | |||
2104 | return 0; | ||
2105 | } | ||
2106 | |||
2107 | static int snd_cs46xx_egpio_select_put(struct snd_kcontrol *kcontrol, | ||
2108 | struct snd_ctl_elem_value *ucontrol) | ||
2109 | { | ||
2110 | struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol); | ||
2111 | int change = (chip->current_gpio != ucontrol->value.integer.value[0]); | ||
2112 | chip->current_gpio = ucontrol->value.integer.value[0]; | ||
2113 | |||
2114 | return change; | ||
2115 | } | ||
2116 | |||
2117 | |||
2118 | static int snd_cs46xx_egpio_get(struct snd_kcontrol *kcontrol, | ||
2119 | struct snd_ctl_elem_value *ucontrol) | ||
2120 | { | ||
2121 | struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol); | ||
2122 | int reg = kcontrol->private_value; | ||
2123 | |||
2124 | snd_printdd ("put: reg = %04x, gpio %02x\n",reg,chip->current_gpio); | ||
2125 | ucontrol->value.integer.value[0] = | ||
2126 | (snd_cs46xx_peekBA0(chip, reg) & (1 << chip->current_gpio)) ? 1 : 0; | ||
2127 | |||
2128 | return 0; | ||
2129 | } | ||
2130 | |||
2131 | static int snd_cs46xx_egpio_put(struct snd_kcontrol *kcontrol, | ||
2132 | struct snd_ctl_elem_value *ucontrol) | ||
2133 | { | ||
2134 | struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol); | ||
2135 | int reg = kcontrol->private_value; | ||
2136 | int val = snd_cs46xx_peekBA0(chip, reg); | ||
2137 | int oldval = val; | ||
2138 | snd_printdd ("put: reg = %04x, gpio %02x\n",reg,chip->current_gpio); | ||
2139 | |||
2140 | if (ucontrol->value.integer.value[0]) | ||
2141 | val |= (1 << chip->current_gpio); | ||
2142 | else | ||
2143 | val &= ~(1 << chip->current_gpio); | ||
2144 | |||
2145 | snd_cs46xx_pokeBA0(chip, reg,val); | ||
2146 | snd_printdd ("put: val %08x oldval %08x\n",val,oldval); | ||
2147 | |||
2148 | return (oldval != val); | ||
2149 | } | ||
2150 | #endif /* CONFIG_SND_CS46XX_DEBUG_GPIO */ | ||
2151 | |||
2152 | static struct snd_kcontrol_new snd_cs46xx_controls[] __devinitdata = { | 2086 | static struct snd_kcontrol_new snd_cs46xx_controls[] __devinitdata = { |
2153 | { | 2087 | { |
2154 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2088 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -2241,40 +2175,6 @@ static struct snd_kcontrol_new snd_cs46xx_controls[] __devinitdata = { | |||
2241 | }, | 2175 | }, |
2242 | 2176 | ||
2243 | #endif | 2177 | #endif |
2244 | #ifdef CONFIG_SND_CS46XX_DEBUG_GPIO | ||
2245 | { | ||
2246 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2247 | .name = "EGPIO select", | ||
2248 | .info = snd_cs46xx_egpio_select_info, | ||
2249 | .get = snd_cs46xx_egpio_select_get, | ||
2250 | .put = snd_cs46xx_egpio_select_put, | ||
2251 | .private_value = 0, | ||
2252 | }, | ||
2253 | { | ||
2254 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2255 | .name = "EGPIO Input/Output", | ||
2256 | .info = snd_mixer_boolean_info, | ||
2257 | .get = snd_cs46xx_egpio_get, | ||
2258 | .put = snd_cs46xx_egpio_put, | ||
2259 | .private_value = BA0_EGPIODR, | ||
2260 | }, | ||
2261 | { | ||
2262 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2263 | .name = "EGPIO CMOS/Open drain", | ||
2264 | .info = snd_mixer_boolean_info, | ||
2265 | .get = snd_cs46xx_egpio_get, | ||
2266 | .put = snd_cs46xx_egpio_put, | ||
2267 | .private_value = BA0_EGPIOPTR, | ||
2268 | }, | ||
2269 | { | ||
2270 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2271 | .name = "EGPIO On/Off", | ||
2272 | .info = snd_mixer_boolean_info, | ||
2273 | .get = snd_cs46xx_egpio_get, | ||
2274 | .put = snd_cs46xx_egpio_put, | ||
2275 | .private_value = BA0_EGPIOSR, | ||
2276 | }, | ||
2277 | #endif | ||
2278 | }; | 2178 | }; |
2279 | 2179 | ||
2280 | #ifdef CONFIG_SND_CS46XX_NEW_DSP | 2180 | #ifdef CONFIG_SND_CS46XX_NEW_DSP |
diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c index 590b35d91df2..ccc8bedb5b1a 100644 --- a/sound/pci/cs46xx/dsp_spos.c +++ b/sound/pci/cs46xx/dsp_spos.c | |||
@@ -20,7 +20,6 @@ | |||
20 | */ | 20 | */ |
21 | 21 | ||
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <asm/io.h> | 23 | #include <asm/io.h> |
25 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
26 | #include <linux/pm.h> | 25 | #include <linux/pm.h> |
diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c index eded4dfeba12..2873cfe48c33 100644 --- a/sound/pci/cs46xx/dsp_spos_scb_lib.c +++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c | |||
@@ -21,7 +21,6 @@ | |||
21 | */ | 21 | */ |
22 | 22 | ||
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <asm/io.h> | 24 | #include <asm/io.h> |
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
27 | #include <linux/pm.h> | 26 | #include <linux/pm.h> |
diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c index 240a0a462209..7ff8b68e997e 100644 --- a/sound/pci/cs5530.c +++ b/sound/pci/cs5530.c | |||
@@ -36,7 +36,6 @@ | |||
36 | * same manner. | 36 | * same manner. |
37 | */ | 37 | */ |
38 | 38 | ||
39 | #include <sound/driver.h> | ||
40 | #include <linux/delay.h> | 39 | #include <linux/delay.h> |
41 | #include <linux/moduleparam.h> | 40 | #include <linux/moduleparam.h> |
42 | #include <linux/pci.h> | 41 | #include <linux/pci.h> |
diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 2b35889787be..1d8b16052535 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
26 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
27 | #include <linux/init.h> | 26 | #include <linux/init.h> |
@@ -145,7 +144,7 @@ static unsigned short snd_cs5535audio_ac97_codec_read(struct snd_ac97 *ac97, | |||
145 | return snd_cs5535audio_codec_read(cs5535au, reg); | 144 | return snd_cs5535audio_codec_read(cs5535au, reg); |
146 | } | 145 | } |
147 | 146 | ||
148 | static int snd_cs5535audio_mixer(struct cs5535audio *cs5535au) | 147 | static int __devinit snd_cs5535audio_mixer(struct cs5535audio *cs5535au) |
149 | { | 148 | { |
150 | struct snd_card *card = cs5535au->card; | 149 | struct snd_card *card = cs5535au->card; |
151 | struct snd_ac97_bus *pbus; | 150 | struct snd_ac97_bus *pbus; |
diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c index 21df0634af32..cdcda87116c3 100644 --- a/sound/pci/cs5535audio/cs5535audio_pcm.c +++ b/sound/pci/cs5535audio/cs5535audio_pcm.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/pci.h> | 27 | #include <linux/pci.h> |
28 | #include <sound/driver.h> | ||
29 | #include <sound/core.h> | 28 | #include <sound/core.h> |
30 | #include <sound/control.h> | 29 | #include <sound/control.h> |
31 | #include <sound/initval.h> | 30 | #include <sound/initval.h> |
@@ -98,6 +97,8 @@ static int snd_cs5535audio_playback_open(struct snd_pcm_substream *substream) | |||
98 | struct snd_pcm_runtime *runtime = substream->runtime; | 97 | struct snd_pcm_runtime *runtime = substream->runtime; |
99 | 98 | ||
100 | runtime->hw = snd_cs5535audio_playback; | 99 | runtime->hw = snd_cs5535audio_playback; |
100 | runtime->hw.rates = cs5535au->ac97->rates[AC97_RATES_FRONT_DAC]; | ||
101 | snd_pcm_limit_hw_rates(runtime); | ||
101 | cs5535au->playback_substream = substream; | 102 | cs5535au->playback_substream = substream; |
102 | runtime->private_data = &(cs5535au->dmas[CS5535AUDIO_DMA_PLAYBACK]); | 103 | runtime->private_data = &(cs5535au->dmas[CS5535AUDIO_DMA_PLAYBACK]); |
103 | if ((err = snd_pcm_hw_constraint_integer(runtime, | 104 | if ((err = snd_pcm_hw_constraint_integer(runtime, |
@@ -343,6 +344,8 @@ static int snd_cs5535audio_capture_open(struct snd_pcm_substream *substream) | |||
343 | struct snd_pcm_runtime *runtime = substream->runtime; | 344 | struct snd_pcm_runtime *runtime = substream->runtime; |
344 | 345 | ||
345 | runtime->hw = snd_cs5535audio_capture; | 346 | runtime->hw = snd_cs5535audio_capture; |
347 | runtime->hw.rates = cs5535au->ac97->rates[AC97_RATES_ADC]; | ||
348 | snd_pcm_limit_hw_rates(runtime); | ||
346 | cs5535au->capture_substream = substream; | 349 | cs5535au->capture_substream = substream; |
347 | runtime->private_data = &(cs5535au->dmas[CS5535AUDIO_DMA_CAPTURE]); | 350 | runtime->private_data = &(cs5535au->dmas[CS5535AUDIO_DMA_CAPTURE]); |
348 | if ((err = snd_pcm_hw_constraint_integer(runtime, | 351 | if ((err = snd_pcm_hw_constraint_integer(runtime, |
diff --git a/sound/pci/cs5535audio/cs5535audio_pm.c b/sound/pci/cs5535audio/cs5535audio_pm.c index 838708f6d45e..564c33b60953 100644 --- a/sound/pci/cs5535audio/cs5535audio_pm.c +++ b/sound/pci/cs5535audio/cs5535audio_pm.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
25 | #include <sound/driver.h> | ||
26 | #include <sound/core.h> | 25 | #include <sound/core.h> |
27 | #include <sound/control.h> | 26 | #include <sound/control.h> |
28 | #include <sound/initval.h> | 27 | #include <sound/initval.h> |
diff --git a/sound/pci/echoaudio/darla20.c b/sound/pci/echoaudio/darla20.c index 87078d3a6854..8c6db3aa3c1a 100644 --- a/sound/pci/echoaudio/darla20.c +++ b/sound/pci/echoaudio/darla20.c | |||
@@ -36,7 +36,6 @@ | |||
36 | #define BX_NUM 10 | 36 | #define BX_NUM 10 |
37 | 37 | ||
38 | 38 | ||
39 | #include <sound/driver.h> | ||
40 | #include <linux/delay.h> | 39 | #include <linux/delay.h> |
41 | #include <linux/init.h> | 40 | #include <linux/init.h> |
42 | #include <linux/interrupt.h> | 41 | #include <linux/interrupt.h> |
diff --git a/sound/pci/echoaudio/darla24.c b/sound/pci/echoaudio/darla24.c index 42b48f9d2128..04cbf3eaf05a 100644 --- a/sound/pci/echoaudio/darla24.c +++ b/sound/pci/echoaudio/darla24.c | |||
@@ -40,7 +40,6 @@ | |||
40 | #define BX_NUM 10 | 40 | #define BX_NUM 10 |
41 | 41 | ||
42 | 42 | ||
43 | #include <sound/driver.h> | ||
44 | #include <linux/delay.h> | 43 | #include <linux/delay.h> |
45 | #include <linux/init.h> | 44 | #include <linux/init.h> |
46 | #include <linux/interrupt.h> | 45 | #include <linux/interrupt.h> |
diff --git a/sound/pci/echoaudio/echo3g.c b/sound/pci/echoaudio/echo3g.c index 8dbb7ac865c1..4022e43a0053 100644 --- a/sound/pci/echoaudio/echo3g.c +++ b/sound/pci/echoaudio/echo3g.c | |||
@@ -47,7 +47,6 @@ | |||
47 | #define BX_NUM chip->bx_num | 47 | #define BX_NUM chip->bx_num |
48 | 48 | ||
49 | 49 | ||
50 | #include <sound/driver.h> | ||
51 | #include <linux/delay.h> | 50 | #include <linux/delay.h> |
52 | #include <linux/init.h> | 51 | #include <linux/init.h> |
53 | #include <linux/interrupt.h> | 52 | #include <linux/interrupt.h> |
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 499ee1a5319d..90ec090792ba 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c | |||
@@ -378,7 +378,7 @@ static int pcm_digital_in_open(struct snd_pcm_substream *substream) | |||
378 | 378 | ||
379 | DE_ACT(("pcm_digital_in_open\n")); | 379 | DE_ACT(("pcm_digital_in_open\n")); |
380 | max_channels = num_digital_busses_in(chip) - substream->number; | 380 | max_channels = num_digital_busses_in(chip) - substream->number; |
381 | down(&chip->mode_mutex); | 381 | mutex_lock(&chip->mode_mutex); |
382 | if (chip->digital_mode == DIGITAL_MODE_ADAT) | 382 | if (chip->digital_mode == DIGITAL_MODE_ADAT) |
383 | err = pcm_open(substream, max_channels); | 383 | err = pcm_open(substream, max_channels); |
384 | else /* If the card has ADAT, subtract the 6 channels | 384 | else /* If the card has ADAT, subtract the 6 channels |
@@ -405,7 +405,7 @@ static int pcm_digital_in_open(struct snd_pcm_substream *substream) | |||
405 | chip->can_set_rate=0; | 405 | chip->can_set_rate=0; |
406 | 406 | ||
407 | din_exit: | 407 | din_exit: |
408 | up(&chip->mode_mutex); | 408 | mutex_unlock(&chip->mode_mutex); |
409 | return err; | 409 | return err; |
410 | } | 410 | } |
411 | 411 | ||
@@ -420,7 +420,7 @@ static int pcm_digital_out_open(struct snd_pcm_substream *substream) | |||
420 | 420 | ||
421 | DE_ACT(("pcm_digital_out_open\n")); | 421 | DE_ACT(("pcm_digital_out_open\n")); |
422 | max_channels = num_digital_busses_out(chip) - substream->number; | 422 | max_channels = num_digital_busses_out(chip) - substream->number; |
423 | down(&chip->mode_mutex); | 423 | mutex_lock(&chip->mode_mutex); |
424 | if (chip->digital_mode == DIGITAL_MODE_ADAT) | 424 | if (chip->digital_mode == DIGITAL_MODE_ADAT) |
425 | err = pcm_open(substream, max_channels); | 425 | err = pcm_open(substream, max_channels); |
426 | else /* If the card has ADAT, subtract the 6 channels | 426 | else /* If the card has ADAT, subtract the 6 channels |
@@ -447,7 +447,7 @@ static int pcm_digital_out_open(struct snd_pcm_substream *substream) | |||
447 | if (atomic_read(&chip->opencount) > 1 && chip->rate_set) | 447 | if (atomic_read(&chip->opencount) > 1 && chip->rate_set) |
448 | chip->can_set_rate=0; | 448 | chip->can_set_rate=0; |
449 | dout_exit: | 449 | dout_exit: |
450 | up(&chip->mode_mutex); | 450 | mutex_unlock(&chip->mode_mutex); |
451 | return err; | 451 | return err; |
452 | } | 452 | } |
453 | 453 | ||
@@ -1420,7 +1420,7 @@ static int snd_echo_digital_mode_put(struct snd_kcontrol *kcontrol, | |||
1420 | if (dmode != chip->digital_mode) { | 1420 | if (dmode != chip->digital_mode) { |
1421 | /* mode_mutex is required to make this operation atomic wrt | 1421 | /* mode_mutex is required to make this operation atomic wrt |
1422 | pcm_digital_*_open() and set_input_clock() functions. */ | 1422 | pcm_digital_*_open() and set_input_clock() functions. */ |
1423 | down(&chip->mode_mutex); | 1423 | mutex_lock(&chip->mode_mutex); |
1424 | 1424 | ||
1425 | /* Do not allow the user to change the digital mode when a pcm | 1425 | /* Do not allow the user to change the digital mode when a pcm |
1426 | device is open because it also changes the number of channels | 1426 | device is open because it also changes the number of channels |
@@ -1439,7 +1439,7 @@ static int snd_echo_digital_mode_put(struct snd_kcontrol *kcontrol, | |||
1439 | if (changed >= 0) | 1439 | if (changed >= 0) |
1440 | changed = 1; /* No errors */ | 1440 | changed = 1; /* No errors */ |
1441 | } | 1441 | } |
1442 | up(&chip->mode_mutex); | 1442 | mutex_unlock(&chip->mode_mutex); |
1443 | } | 1443 | } |
1444 | return changed; | 1444 | return changed; |
1445 | } | 1445 | } |
@@ -1566,12 +1566,12 @@ static int snd_echo_clock_source_put(struct snd_kcontrol *kcontrol, | |||
1566 | return -EINVAL; | 1566 | return -EINVAL; |
1567 | dclock = chip->clock_source_list[eclock]; | 1567 | dclock = chip->clock_source_list[eclock]; |
1568 | if (chip->input_clock != dclock) { | 1568 | if (chip->input_clock != dclock) { |
1569 | down(&chip->mode_mutex); | 1569 | mutex_lock(&chip->mode_mutex); |
1570 | spin_lock_irq(&chip->lock); | 1570 | spin_lock_irq(&chip->lock); |
1571 | if ((changed = set_input_clock(chip, dclock)) == 0) | 1571 | if ((changed = set_input_clock(chip, dclock)) == 0) |
1572 | changed = 1; /* no errors */ | 1572 | changed = 1; /* no errors */ |
1573 | spin_unlock_irq(&chip->lock); | 1573 | spin_unlock_irq(&chip->lock); |
1574 | up(&chip->mode_mutex); | 1574 | mutex_unlock(&chip->mode_mutex); |
1575 | } | 1575 | } |
1576 | 1576 | ||
1577 | if (changed < 0) | 1577 | if (changed < 0) |
@@ -1972,7 +1972,7 @@ static __devinit int snd_echo_create(struct snd_card *card, | |||
1972 | return err; | 1972 | return err; |
1973 | } | 1973 | } |
1974 | atomic_set(&chip->opencount, 0); | 1974 | atomic_set(&chip->opencount, 0); |
1975 | init_MUTEX(&chip->mode_mutex); | 1975 | mutex_init(&chip->mode_mutex); |
1976 | chip->can_set_rate = 1; | 1976 | chip->can_set_rate = 1; |
1977 | *rchip = chip; | 1977 | *rchip = chip; |
1978 | /* Init done ! */ | 1978 | /* Init done ! */ |
diff --git a/sound/pci/echoaudio/echoaudio.h b/sound/pci/echoaudio/echoaudio.h index 7e88c968e22f..1c88e051abf2 100644 --- a/sound/pci/echoaudio/echoaudio.h +++ b/sound/pci/echoaudio/echoaudio.h | |||
@@ -361,7 +361,7 @@ struct echoaudio { | |||
361 | spinlock_t lock; | 361 | spinlock_t lock; |
362 | struct snd_pcm_substream *substream[DSP_MAXPIPES]; | 362 | struct snd_pcm_substream *substream[DSP_MAXPIPES]; |
363 | int last_period[DSP_MAXPIPES]; | 363 | int last_period[DSP_MAXPIPES]; |
364 | struct semaphore mode_mutex; | 364 | struct mutex mode_mutex; |
365 | u16 num_digital_modes, digital_mode_list[6]; | 365 | u16 num_digital_modes, digital_mode_list[6]; |
366 | u16 num_clock_sources, clock_source_list[10]; | 366 | u16 num_clock_sources, clock_source_list[10]; |
367 | atomic_t opencount; | 367 | atomic_t opencount; |
diff --git a/sound/pci/echoaudio/gina20.c b/sound/pci/echoaudio/gina20.c index fee2d4831732..c0e64b8f52a4 100644 --- a/sound/pci/echoaudio/gina20.c +++ b/sound/pci/echoaudio/gina20.c | |||
@@ -40,7 +40,6 @@ | |||
40 | #define BX_NUM 14 | 40 | #define BX_NUM 14 |
41 | 41 | ||
42 | 42 | ||
43 | #include <sound/driver.h> | ||
44 | #include <linux/delay.h> | 43 | #include <linux/delay.h> |
45 | #include <linux/init.h> | 44 | #include <linux/init.h> |
46 | #include <linux/interrupt.h> | 45 | #include <linux/interrupt.h> |
diff --git a/sound/pci/echoaudio/gina24.c b/sound/pci/echoaudio/gina24.c index d5eae470fe9a..c36a78dd0b5e 100644 --- a/sound/pci/echoaudio/gina24.c +++ b/sound/pci/echoaudio/gina24.c | |||
@@ -46,7 +46,6 @@ | |||
46 | #define BX_NUM 26 | 46 | #define BX_NUM 26 |
47 | 47 | ||
48 | 48 | ||
49 | #include <sound/driver.h> | ||
50 | #include <linux/delay.h> | 49 | #include <linux/delay.h> |
51 | #include <linux/init.h> | 50 | #include <linux/init.h> |
52 | #include <linux/interrupt.h> | 51 | #include <linux/interrupt.h> |
diff --git a/sound/pci/echoaudio/indigo.c b/sound/pci/echoaudio/indigo.c index 40f601cd016f..0a58a7c1fd7c 100644 --- a/sound/pci/echoaudio/indigo.c +++ b/sound/pci/echoaudio/indigo.c | |||
@@ -38,7 +38,6 @@ | |||
38 | #define BX_NUM 2 | 38 | #define BX_NUM 2 |
39 | 39 | ||
40 | 40 | ||
41 | #include <sound/driver.h> | ||
42 | #include <linux/delay.h> | 41 | #include <linux/delay.h> |
43 | #include <linux/init.h> | 42 | #include <linux/init.h> |
44 | #include <linux/interrupt.h> | 43 | #include <linux/interrupt.h> |
diff --git a/sound/pci/echoaudio/indigodj.c b/sound/pci/echoaudio/indigodj.c index 771c5383210d..2db24d29332b 100644 --- a/sound/pci/echoaudio/indigodj.c +++ b/sound/pci/echoaudio/indigodj.c | |||
@@ -38,7 +38,6 @@ | |||
38 | #define BX_NUM 4 | 38 | #define BX_NUM 4 |
39 | 39 | ||
40 | 40 | ||
41 | #include <sound/driver.h> | ||
42 | #include <linux/delay.h> | 41 | #include <linux/delay.h> |
43 | #include <linux/init.h> | 42 | #include <linux/init.h> |
44 | #include <linux/interrupt.h> | 43 | #include <linux/interrupt.h> |
diff --git a/sound/pci/echoaudio/indigoio.c b/sound/pci/echoaudio/indigoio.c index 49c550defcf9..a60c0a0a89b7 100644 --- a/sound/pci/echoaudio/indigoio.c +++ b/sound/pci/echoaudio/indigoio.c | |||
@@ -39,7 +39,6 @@ | |||
39 | #define BX_NUM 4 | 39 | #define BX_NUM 4 |
40 | 40 | ||
41 | 41 | ||
42 | #include <sound/driver.h> | ||
43 | #include <linux/delay.h> | 42 | #include <linux/delay.h> |
44 | #include <linux/init.h> | 43 | #include <linux/init.h> |
45 | #include <linux/interrupt.h> | 44 | #include <linux/interrupt.h> |
diff --git a/sound/pci/echoaudio/layla20.c b/sound/pci/echoaudio/layla20.c index 8f5483a405ae..506194688995 100644 --- a/sound/pci/echoaudio/layla20.c +++ b/sound/pci/echoaudio/layla20.c | |||
@@ -45,7 +45,6 @@ | |||
45 | #define BX_NUM 22 | 45 | #define BX_NUM 22 |
46 | 46 | ||
47 | 47 | ||
48 | #include <sound/driver.h> | ||
49 | #include <linux/delay.h> | 48 | #include <linux/delay.h> |
50 | #include <linux/init.h> | 49 | #include <linux/init.h> |
51 | #include <linux/interrupt.h> | 50 | #include <linux/interrupt.h> |
diff --git a/sound/pci/echoaudio/layla24.c b/sound/pci/echoaudio/layla24.c index 0524667c02f7..e09e3ea7781e 100644 --- a/sound/pci/echoaudio/layla24.c +++ b/sound/pci/echoaudio/layla24.c | |||
@@ -47,7 +47,6 @@ | |||
47 | #define BX_NUM 32 | 47 | #define BX_NUM 32 |
48 | 48 | ||
49 | 49 | ||
50 | #include <sound/driver.h> | ||
51 | #include <linux/delay.h> | 50 | #include <linux/delay.h> |
52 | #include <linux/init.h> | 51 | #include <linux/init.h> |
53 | #include <linux/interrupt.h> | 52 | #include <linux/interrupt.h> |
diff --git a/sound/pci/echoaudio/mia.c b/sound/pci/echoaudio/mia.c index 893c7c20dd70..f3b9b45c9c1b 100644 --- a/sound/pci/echoaudio/mia.c +++ b/sound/pci/echoaudio/mia.c | |||
@@ -45,7 +45,6 @@ | |||
45 | #define BX_NUM 8 | 45 | #define BX_NUM 8 |
46 | 46 | ||
47 | 47 | ||
48 | #include <sound/driver.h> | ||
49 | #include <linux/delay.h> | 48 | #include <linux/delay.h> |
50 | #include <linux/init.h> | 49 | #include <linux/init.h> |
51 | #include <linux/interrupt.h> | 50 | #include <linux/interrupt.h> |
diff --git a/sound/pci/echoaudio/mona.c b/sound/pci/echoaudio/mona.c index 3a5d5b0020df..b05bad944901 100644 --- a/sound/pci/echoaudio/mona.c +++ b/sound/pci/echoaudio/mona.c | |||
@@ -44,7 +44,6 @@ | |||
44 | #define BX_NUM 26 | 44 | #define BX_NUM 26 |
45 | 45 | ||
46 | 46 | ||
47 | #include <sound/driver.h> | ||
48 | #include <linux/delay.h> | 47 | #include <linux/delay.h> |
49 | #include <linux/init.h> | 48 | #include <linux/init.h> |
50 | #include <linux/interrupt.h> | 49 | #include <linux/interrupt.h> |
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 9680caff90c8..8354c1a83312 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c | |||
@@ -23,7 +23,6 @@ | |||
23 | * | 23 | * |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <sound/driver.h> | ||
27 | #include <linux/init.h> | 26 | #include <linux/init.h> |
28 | #include <linux/pci.h> | 27 | #include <linux/pci.h> |
29 | #include <linux/time.h> | 28 | #include <linux/time.h> |
diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c index 01965bd99966..45088ebcce50 100644 --- a/sound/pci/emu10k1/emu10k1_callback.c +++ b/sound/pci/emu10k1/emu10k1_callback.c | |||
@@ -35,9 +35,9 @@ struct best_voice { | |||
35 | /* | 35 | /* |
36 | * prototypes | 36 | * prototypes |
37 | */ | 37 | */ |
38 | static void lookup_voices(struct snd_emux *emu, struct snd_emu10k1 *hw, | 38 | static void lookup_voices(struct snd_emux *emux, struct snd_emu10k1 *hw, |
39 | struct best_voice *best, int active_only); | 39 | struct best_voice *best, int active_only); |
40 | static struct snd_emux_voice *get_voice(struct snd_emux *emu, | 40 | static struct snd_emux_voice *get_voice(struct snd_emux *emux, |
41 | struct snd_emux_port *port); | 41 | struct snd_emux_port *port); |
42 | static int start_voice(struct snd_emux_voice *vp); | 42 | static int start_voice(struct snd_emux_voice *vp); |
43 | static void trigger_voice(struct snd_emux_voice *vp); | 43 | static void trigger_voice(struct snd_emux_voice *vp); |
@@ -45,7 +45,6 @@ static void release_voice(struct snd_emux_voice *vp); | |||
45 | static void update_voice(struct snd_emux_voice *vp, int update); | 45 | static void update_voice(struct snd_emux_voice *vp, int update); |
46 | static void terminate_voice(struct snd_emux_voice *vp); | 46 | static void terminate_voice(struct snd_emux_voice *vp); |
47 | static void free_voice(struct snd_emux_voice *vp); | 47 | static void free_voice(struct snd_emux_voice *vp); |
48 | |||
49 | static void set_fmmod(struct snd_emu10k1 *hw, struct snd_emux_voice *vp); | 48 | static void set_fmmod(struct snd_emu10k1 *hw, struct snd_emux_voice *vp); |
50 | static void set_fm2frq2(struct snd_emu10k1 *hw, struct snd_emux_voice *vp); | 49 | static void set_fm2frq2(struct snd_emu10k1 *hw, struct snd_emux_voice *vp); |
51 | static void set_filterQ(struct snd_emu10k1 *hw, struct snd_emux_voice *vp); | 50 | static void set_filterQ(struct snd_emu10k1 *hw, struct snd_emux_voice *vp); |
@@ -75,9 +74,9 @@ static struct snd_emux_operators emu10k1_ops = { | |||
75 | }; | 74 | }; |
76 | 75 | ||
77 | void | 76 | void |
78 | snd_emu10k1_ops_setup(struct snd_emux *emu) | 77 | snd_emu10k1_ops_setup(struct snd_emux *emux) |
79 | { | 78 | { |
80 | emu->ops = emu10k1_ops; | 79 | emux->ops = emu10k1_ops; |
81 | } | 80 | } |
82 | 81 | ||
83 | 82 | ||
@@ -166,7 +165,11 @@ free_voice(struct snd_emux_voice *vp) | |||
166 | struct snd_emu10k1 *hw; | 165 | struct snd_emu10k1 *hw; |
167 | 166 | ||
168 | hw = vp->hw; | 167 | hw = vp->hw; |
169 | if (vp->ch >= 0) { | 168 | /* FIXME: emu10k1_synth is broken. */ |
169 | /* This can get called with hw == 0 */ | ||
170 | /* Problem apparent on plug, unplug then plug */ | ||
171 | /* on the Audigy 2 ZS Notebook. */ | ||
172 | if (hw && (vp->ch >= 0)) { | ||
170 | snd_emu10k1_ptr_write(hw, IFATN, vp->ch, 0xff00); | 173 | snd_emu10k1_ptr_write(hw, IFATN, vp->ch, 0xff00); |
171 | snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, 0x807f | DCYSUSV_CHANNELENABLE_MASK); | 174 | snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, 0x807f | DCYSUSV_CHANNELENABLE_MASK); |
172 | // snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, 0); | 175 | // snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, 0); |
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 97c41d72a255..9a9b977d3cf1 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c | |||
@@ -33,7 +33,6 @@ | |||
33 | 33 | ||
34 | #include <linux/sched.h> | 34 | #include <linux/sched.h> |
35 | #include <linux/kthread.h> | 35 | #include <linux/kthread.h> |
36 | #include <sound/driver.h> | ||
37 | #include <linux/delay.h> | 36 | #include <linux/delay.h> |
38 | #include <linux/init.h> | 37 | #include <linux/init.h> |
39 | #include <linux/interrupt.h> | 38 | #include <linux/interrupt.h> |
@@ -55,12 +54,14 @@ | |||
55 | #define DOCK_FILENAME "emu/audio_dock.fw" | 54 | #define DOCK_FILENAME "emu/audio_dock.fw" |
56 | #define EMU1010B_FILENAME "emu/emu1010b.fw" | 55 | #define EMU1010B_FILENAME "emu/emu1010b.fw" |
57 | #define MICRO_DOCK_FILENAME "emu/micro_dock.fw" | 56 | #define MICRO_DOCK_FILENAME "emu/micro_dock.fw" |
57 | #define EMU0404_FILENAME "emu/emu0404.fw" | ||
58 | #define EMU1010_NOTEBOOK_FILENAME "emu/emu1010_notebook.fw" | 58 | #define EMU1010_NOTEBOOK_FILENAME "emu/emu1010_notebook.fw" |
59 | 59 | ||
60 | MODULE_FIRMWARE(HANA_FILENAME); | 60 | MODULE_FIRMWARE(HANA_FILENAME); |
61 | MODULE_FIRMWARE(DOCK_FILENAME); | 61 | MODULE_FIRMWARE(DOCK_FILENAME); |
62 | MODULE_FIRMWARE(EMU1010B_FILENAME); | 62 | MODULE_FIRMWARE(EMU1010B_FILENAME); |
63 | MODULE_FIRMWARE(MICRO_DOCK_FILENAME); | 63 | MODULE_FIRMWARE(MICRO_DOCK_FILENAME); |
64 | MODULE_FIRMWARE(EMU0404_FILENAME); | ||
64 | MODULE_FIRMWARE(EMU1010_NOTEBOOK_FILENAME); | 65 | MODULE_FIRMWARE(EMU1010_NOTEBOOK_FILENAME); |
65 | 66 | ||
66 | 67 | ||
@@ -258,7 +259,6 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) | |||
258 | * GPIO7: Unknown | 259 | * GPIO7: Unknown |
259 | */ | 260 | */ |
260 | outl(0x76, emu->port + A_IOCFG); /* Windows uses 0x3f76 */ | 261 | outl(0x76, emu->port + A_IOCFG); /* Windows uses 0x3f76 */ |
261 | |||
262 | } | 262 | } |
263 | if (emu->card_capabilities->i2c_adc) { /* Audigy 2 ZS Notebook with ADC Wolfson WM8775 */ | 263 | if (emu->card_capabilities->i2c_adc) { /* Audigy 2 ZS Notebook with ADC Wolfson WM8775 */ |
264 | int size, n; | 264 | int size, n; |
@@ -274,7 +274,6 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) | |||
274 | emu->i2c_capture_volume[n][0]= 0xcf; | 274 | emu->i2c_capture_volume[n][0]= 0xcf; |
275 | emu->i2c_capture_volume[n][1]= 0xcf; | 275 | emu->i2c_capture_volume[n][1]= 0xcf; |
276 | } | 276 | } |
277 | |||
278 | } | 277 | } |
279 | 278 | ||
280 | 279 | ||
@@ -288,7 +287,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) | |||
288 | snd_emu10k1_ptr_write(emu, MAPB, ch, silent_page); | 287 | snd_emu10k1_ptr_write(emu, MAPB, ch, silent_page); |
289 | } | 288 | } |
290 | 289 | ||
291 | if (emu->card_capabilities->emu1010) { | 290 | if (emu->card_capabilities->emu_model) { |
292 | outl(HCFG_AUTOMUTE_ASYNC | | 291 | outl(HCFG_AUTOMUTE_ASYNC | |
293 | HCFG_EMU32_SLAVE | | 292 | HCFG_EMU32_SLAVE | |
294 | HCFG_AUDIOENABLE, emu->port + HCFG); | 293 | HCFG_AUDIOENABLE, emu->port + HCFG); |
@@ -318,7 +317,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) | |||
318 | outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG); | 317 | outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG); |
319 | 318 | ||
320 | if (enable_ir) { /* enable IR for SB Live */ | 319 | if (enable_ir) { /* enable IR for SB Live */ |
321 | if (emu->card_capabilities->emu1010) { | 320 | if (emu->card_capabilities->emu_model) { |
322 | ; /* Disable all access to A_IOCFG for the emu1010 */ | 321 | ; /* Disable all access to A_IOCFG for the emu1010 */ |
323 | } else if (emu->card_capabilities->i2c_adc) { | 322 | } else if (emu->card_capabilities->i2c_adc) { |
324 | ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ | 323 | ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ |
@@ -339,7 +338,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) | |||
339 | } | 338 | } |
340 | } | 339 | } |
341 | 340 | ||
342 | if (emu->card_capabilities->emu1010) { | 341 | if (emu->card_capabilities->emu_model) { |
343 | ; /* Disable all access to A_IOCFG for the emu1010 */ | 342 | ; /* Disable all access to A_IOCFG for the emu1010 */ |
344 | } else if (emu->card_capabilities->i2c_adc) { | 343 | } else if (emu->card_capabilities->i2c_adc) { |
345 | ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ | 344 | ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ |
@@ -359,7 +358,7 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu) | |||
359 | outl(inl(emu->port + HCFG) | HCFG_AUDIOENABLE, emu->port + HCFG); | 358 | outl(inl(emu->port + HCFG) | HCFG_AUDIOENABLE, emu->port + HCFG); |
360 | 359 | ||
361 | /* Enable analog/digital outs on audigy */ | 360 | /* Enable analog/digital outs on audigy */ |
362 | if (emu->card_capabilities->emu1010) { | 361 | if (emu->card_capabilities->emu_model) { |
363 | ; /* Disable all access to A_IOCFG for the emu1010 */ | 362 | ; /* Disable all access to A_IOCFG for the emu1010 */ |
364 | } else if (emu->card_capabilities->i2c_adc) { | 363 | } else if (emu->card_capabilities->i2c_adc) { |
365 | ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ | 364 | ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ |
@@ -652,6 +651,8 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 * emu) | |||
652 | value = inl(special_port); | 651 | value = inl(special_port); |
653 | 652 | ||
654 | snd_emu10k1_ptr20_write(emu, TINA2_VOLUME, 0, 0xfefefefe); /* Defaults to 0x30303030 */ | 653 | snd_emu10k1_ptr20_write(emu, TINA2_VOLUME, 0, 0xfefefefe); /* Defaults to 0x30303030 */ |
654 | /* Delay to give time for ADC chip to switch on. It needs 113ms */ | ||
655 | msleep(200); | ||
655 | return 0; | 656 | return 0; |
656 | } | 657 | } |
657 | 658 | ||
@@ -661,6 +662,8 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file | |||
661 | int n, i; | 662 | int n, i; |
662 | int reg; | 663 | int reg; |
663 | int value; | 664 | int value; |
665 | unsigned int write_post; | ||
666 | unsigned long flags; | ||
664 | const struct firmware *fw_entry; | 667 | const struct firmware *fw_entry; |
665 | 668 | ||
666 | if ((err = request_firmware(&fw_entry, filename, &emu->pci->dev)) != 0) { | 669 | if ((err = request_firmware(&fw_entry, filename, &emu->pci->dev)) != 0) { |
@@ -668,12 +671,6 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file | |||
668 | return err; | 671 | return err; |
669 | } | 672 | } |
670 | snd_printk(KERN_INFO "firmware size=0x%zx\n", fw_entry->size); | 673 | snd_printk(KERN_INFO "firmware size=0x%zx\n", fw_entry->size); |
671 | #if 0 | ||
672 | if (fw_entry->size != 0x133a4) { | ||
673 | snd_printk(KERN_ERR "firmware: %s wrong size.\n",filename); | ||
674 | return -EINVAL; | ||
675 | } | ||
676 | #endif | ||
677 | 674 | ||
678 | /* The FPGA is a Xilinx Spartan IIE XC2S50E */ | 675 | /* The FPGA is a Xilinx Spartan IIE XC2S50E */ |
679 | /* GPIO7 -> FPGA PGMN | 676 | /* GPIO7 -> FPGA PGMN |
@@ -681,9 +678,12 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file | |||
681 | * GPIO5 -> FPGA DIN | 678 | * GPIO5 -> FPGA DIN |
682 | * FPGA CONFIG OFF -> FPGA PGMN | 679 | * FPGA CONFIG OFF -> FPGA PGMN |
683 | */ | 680 | */ |
681 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
684 | outl(0x00, emu->port + A_IOCFG); /* Set PGMN low for 1uS. */ | 682 | outl(0x00, emu->port + A_IOCFG); /* Set PGMN low for 1uS. */ |
685 | udelay(1); | 683 | write_post = inl(emu->port + A_IOCFG); |
684 | udelay(100); | ||
686 | outl(0x80, emu->port + A_IOCFG); /* Leave bit 7 set during netlist setup. */ | 685 | outl(0x80, emu->port + A_IOCFG); /* Leave bit 7 set during netlist setup. */ |
686 | write_post = inl(emu->port + A_IOCFG); | ||
687 | udelay(100); /* Allow FPGA memory to clean */ | 687 | udelay(100); /* Allow FPGA memory to clean */ |
688 | for(n = 0; n < fw_entry->size; n++) { | 688 | for(n = 0; n < fw_entry->size; n++) { |
689 | value=fw_entry->data[n]; | 689 | value=fw_entry->data[n]; |
@@ -693,18 +693,22 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file | |||
693 | reg = reg | 0x20; | 693 | reg = reg | 0x20; |
694 | value = value >> 1; | 694 | value = value >> 1; |
695 | outl(reg, emu->port + A_IOCFG); | 695 | outl(reg, emu->port + A_IOCFG); |
696 | write_post = inl(emu->port + A_IOCFG); | ||
696 | outl(reg | 0x40, emu->port + A_IOCFG); | 697 | outl(reg | 0x40, emu->port + A_IOCFG); |
698 | write_post = inl(emu->port + A_IOCFG); | ||
697 | } | 699 | } |
698 | } | 700 | } |
699 | /* After programming, set GPIO bit 4 high again. */ | 701 | /* After programming, set GPIO bit 4 high again. */ |
700 | outl(0x10, emu->port + A_IOCFG); | 702 | outl(0x10, emu->port + A_IOCFG); |
701 | 703 | write_post = inl(emu->port + A_IOCFG); | |
704 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
702 | 705 | ||
703 | release_firmware(fw_entry); | 706 | release_firmware(fw_entry); |
704 | return 0; | 707 | return 0; |
705 | } | 708 | } |
706 | 709 | ||
707 | int emu1010_firmware_thread(void *data) { | 710 | static int emu1010_firmware_thread(void *data) |
711 | { | ||
708 | struct snd_emu10k1 * emu = data; | 712 | struct snd_emu10k1 * emu = data; |
709 | int tmp,tmp2; | 713 | int tmp,tmp2; |
710 | int reg; | 714 | int reg; |
@@ -712,7 +716,7 @@ int emu1010_firmware_thread(void *data) { | |||
712 | 716 | ||
713 | for (;;) { | 717 | for (;;) { |
714 | /* Delay to allow Audio Dock to settle */ | 718 | /* Delay to allow Audio Dock to settle */ |
715 | msleep(1000); | 719 | msleep_interruptible(1000); |
716 | if (kthread_should_stop()) | 720 | if (kthread_should_stop()) |
717 | break; | 721 | break; |
718 | snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp ); /* IRQ Status */ | 722 | snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp ); /* IRQ Status */ |
@@ -722,17 +726,20 @@ int emu1010_firmware_thread(void *data) { | |||
722 | /* Return to Audio Dock programming mode */ | 726 | /* Return to Audio Dock programming mode */ |
723 | snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n"); | 727 | snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n"); |
724 | snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK ); | 728 | snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK ); |
725 | if (emu->card_capabilities->emu1010 == 1) { | 729 | if (emu->card_capabilities->emu_model == |
730 | EMU_MODEL_EMU1010) { | ||
726 | if ((err = snd_emu1010_load_firmware(emu, DOCK_FILENAME)) != 0) { | 731 | if ((err = snd_emu1010_load_firmware(emu, DOCK_FILENAME)) != 0) { |
727 | return err; | 732 | continue; |
728 | } | 733 | } |
729 | } else if (emu->card_capabilities->emu1010 == 2) { | 734 | } else if (emu->card_capabilities->emu_model == |
735 | EMU_MODEL_EMU1010B) { | ||
730 | if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) { | 736 | if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) { |
731 | return err; | 737 | continue; |
732 | } | 738 | } |
733 | } else if (emu->card_capabilities->emu1010 == 3) { | 739 | } else if (emu->card_capabilities->emu_model == |
740 | EMU_MODEL_EMU1616) { | ||
734 | if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) { | 741 | if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) { |
735 | return err; | 742 | continue; |
736 | } | 743 | } |
737 | } | 744 | } |
738 | 745 | ||
@@ -745,8 +752,7 @@ int emu1010_firmware_thread(void *data) { | |||
745 | if ((reg & 0x1f) != 0x15) { | 752 | if ((reg & 0x1f) != 0x15) { |
746 | /* FPGA failed to be programmed */ | 753 | /* FPGA failed to be programmed */ |
747 | snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg=0x%x\n", reg); | 754 | snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg=0x%x\n", reg); |
748 | return 0; | 755 | continue; |
749 | return -ENODEV; | ||
750 | } | 756 | } |
751 | snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n"); | 757 | snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n"); |
752 | snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp ); | 758 | snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp ); |
@@ -757,9 +763,9 @@ int emu1010_firmware_thread(void *data) { | |||
757 | msleep(10); | 763 | msleep(10); |
758 | /* Unmute all. Default is muted after a firmware load */ | 764 | /* Unmute all. Default is muted after a firmware load */ |
759 | snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); | 765 | snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); |
760 | break; | ||
761 | } | 766 | } |
762 | } | 767 | } |
768 | snd_printk(KERN_INFO "emu1010: firmware thread stopping\n"); | ||
763 | return 0; | 769 | return 0; |
764 | } | 770 | } |
765 | 771 | ||
@@ -800,6 +806,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) | |||
800 | int tmp,tmp2; | 806 | int tmp,tmp2; |
801 | int reg; | 807 | int reg; |
802 | int err; | 808 | int err; |
809 | const char *filename = NULL; | ||
803 | 810 | ||
804 | snd_printk(KERN_INFO "emu1010: Special config.\n"); | 811 | snd_printk(KERN_INFO "emu1010: Special config.\n"); |
805 | /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, | 812 | /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, |
@@ -841,21 +848,31 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) | |||
841 | return -ENODEV; | 848 | return -ENODEV; |
842 | } | 849 | } |
843 | snd_printk(KERN_INFO "emu1010: EMU_HANA_ID=0x%x\n",reg); | 850 | snd_printk(KERN_INFO "emu1010: EMU_HANA_ID=0x%x\n",reg); |
844 | if (emu->card_capabilities->emu1010 == 1) { | 851 | switch (emu->card_capabilities->emu_model) { |
845 | if ((err = snd_emu1010_load_firmware(emu, HANA_FILENAME)) != 0) { | 852 | case EMU_MODEL_EMU1010: |
846 | snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file %s failed\n", HANA_FILENAME); | 853 | filename = HANA_FILENAME; |
847 | return err; | 854 | break; |
848 | } | 855 | case EMU_MODEL_EMU1010B: |
849 | } else if (emu->card_capabilities->emu1010 == 2) { | 856 | filename = EMU1010B_FILENAME; |
850 | if ((err = snd_emu1010_load_firmware(emu, EMU1010B_FILENAME)) != 0) { | 857 | break; |
851 | snd_printk(KERN_INFO "emu1010: Loading Firmware file %s failed\n", EMU1010B_FILENAME); | 858 | case EMU_MODEL_EMU1616: |
852 | return err; | 859 | filename = EMU1010_NOTEBOOK_FILENAME; |
853 | } | 860 | break; |
854 | } else if (emu->card_capabilities->emu1010 == 3) { | 861 | case EMU_MODEL_EMU0404: |
855 | if ((err = snd_emu1010_load_firmware(emu, EMU1010_NOTEBOOK_FILENAME)) != 0) { | 862 | filename = EMU0404_FILENAME; |
856 | snd_printk(KERN_INFO "emu1010: Loading Firmware file %s failed\n", EMU1010_NOTEBOOK_FILENAME); | 863 | break; |
857 | return err; | 864 | default: |
858 | } | 865 | filename = NULL; |
866 | return -ENODEV; | ||
867 | break; | ||
868 | } | ||
869 | snd_printk(KERN_INFO "emu1010: filename %s testing\n", filename); | ||
870 | err = snd_emu1010_load_firmware(emu, filename); | ||
871 | if (err != 0) { | ||
872 | snd_printk( | ||
873 | KERN_INFO "emu1010: Loading Firmware file %s failed\n", | ||
874 | filename); | ||
875 | return err; | ||
859 | } | 876 | } |
860 | 877 | ||
861 | /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ | 878 | /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ |
@@ -1074,10 +1091,12 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) | |||
1074 | snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); /* SPDIF Format spdif (or 0x11 for aes/ebu) */ | 1091 | snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); /* SPDIF Format spdif (or 0x11 for aes/ebu) */ |
1075 | 1092 | ||
1076 | /* Start Micro/Audio Dock firmware loader thread */ | 1093 | /* Start Micro/Audio Dock firmware loader thread */ |
1077 | emu->emu1010.firmware_thread = kthread_create(&emu1010_firmware_thread, | 1094 | if (!emu->emu1010.firmware_thread) { |
1078 | emu, | 1095 | emu->emu1010.firmware_thread = |
1079 | "emu1010_firmware"); | 1096 | kthread_create(emu1010_firmware_thread, emu, |
1080 | wake_up_process(emu->emu1010.firmware_thread); | 1097 | "emu1010_firmware"); |
1098 | wake_up_process(emu->emu1010.firmware_thread); | ||
1099 | } | ||
1081 | 1100 | ||
1082 | #if 0 | 1101 | #if 0 |
1083 | snd_emu1010_fpga_link_dst_src_write(emu, | 1102 | snd_emu1010_fpga_link_dst_src_write(emu, |
@@ -1090,79 +1109,114 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) | |||
1090 | EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 3); /* ALICE2 bus 0xb3 */ | 1109 | EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 3); /* ALICE2 bus 0xb3 */ |
1091 | #endif | 1110 | #endif |
1092 | /* Default outputs */ | 1111 | /* Default outputs */ |
1093 | snd_emu1010_fpga_link_dst_src_write(emu, | 1112 | if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) { |
1094 | EMU_DST_DOCK_DAC1_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ | 1113 | /* 1616(M) cardbus default outputs */ |
1095 | emu->emu1010.output_source[0] = 21; | 1114 | /* ALICE2 bus 0xa0 */ |
1096 | snd_emu1010_fpga_link_dst_src_write(emu, | 1115 | snd_emu1010_fpga_link_dst_src_write(emu, |
1097 | EMU_DST_DOCK_DAC1_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); | 1116 | EMU_DST_DOCK_DAC1_LEFT1, EMU_SRC_ALICE_EMU32A + 0); |
1098 | emu->emu1010.output_source[1] = 22; | 1117 | emu->emu1010.output_source[0] = 17; |
1099 | snd_emu1010_fpga_link_dst_src_write(emu, | 1118 | snd_emu1010_fpga_link_dst_src_write(emu, |
1100 | EMU_DST_DOCK_DAC2_LEFT1, EMU_SRC_ALICE_EMU32A + 2); | 1119 | EMU_DST_DOCK_DAC1_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); |
1101 | emu->emu1010.output_source[2] = 23; | 1120 | emu->emu1010.output_source[1] = 18; |
1102 | snd_emu1010_fpga_link_dst_src_write(emu, | 1121 | snd_emu1010_fpga_link_dst_src_write(emu, |
1103 | EMU_DST_DOCK_DAC2_RIGHT1, EMU_SRC_ALICE_EMU32A + 3); | 1122 | EMU_DST_DOCK_DAC2_LEFT1, EMU_SRC_ALICE_EMU32A + 2); |
1104 | emu->emu1010.output_source[3] = 24; | 1123 | emu->emu1010.output_source[2] = 19; |
1105 | snd_emu1010_fpga_link_dst_src_write(emu, | 1124 | snd_emu1010_fpga_link_dst_src_write(emu, |
1106 | EMU_DST_DOCK_DAC3_LEFT1, EMU_SRC_ALICE_EMU32A + 4); | 1125 | EMU_DST_DOCK_DAC2_RIGHT1, EMU_SRC_ALICE_EMU32A + 3); |
1107 | emu->emu1010.output_source[4] = 25; | 1126 | emu->emu1010.output_source[3] = 20; |
1108 | snd_emu1010_fpga_link_dst_src_write(emu, | 1127 | snd_emu1010_fpga_link_dst_src_write(emu, |
1109 | EMU_DST_DOCK_DAC3_RIGHT1, EMU_SRC_ALICE_EMU32A + 5); | 1128 | EMU_DST_DOCK_DAC3_LEFT1, EMU_SRC_ALICE_EMU32A + 4); |
1110 | emu->emu1010.output_source[5] = 26; | 1129 | emu->emu1010.output_source[4] = 21; |
1111 | snd_emu1010_fpga_link_dst_src_write(emu, | 1130 | snd_emu1010_fpga_link_dst_src_write(emu, |
1112 | EMU_DST_DOCK_DAC4_LEFT1, EMU_SRC_ALICE_EMU32A + 6); | 1131 | EMU_DST_DOCK_DAC3_RIGHT1, EMU_SRC_ALICE_EMU32A + 5); |
1113 | emu->emu1010.output_source[6] = 27; | 1132 | emu->emu1010.output_source[5] = 22; |
1114 | snd_emu1010_fpga_link_dst_src_write(emu, | 1133 | /* ALICE2 bus 0xa0 */ |
1115 | EMU_DST_DOCK_DAC4_RIGHT1, EMU_SRC_ALICE_EMU32A + 7); | 1134 | snd_emu1010_fpga_link_dst_src_write(emu, |
1116 | emu->emu1010.output_source[7] = 28; | 1135 | EMU_DST_MANA_DAC_LEFT, EMU_SRC_ALICE_EMU32A + 0); |
1117 | snd_emu1010_fpga_link_dst_src_write(emu, | 1136 | emu->emu1010.output_source[16] = 17; |
1118 | EMU_DST_DOCK_PHONES_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ | 1137 | snd_emu1010_fpga_link_dst_src_write(emu, |
1119 | emu->emu1010.output_source[8] = 21; | 1138 | EMU_DST_MANA_DAC_RIGHT, EMU_SRC_ALICE_EMU32A + 1); |
1120 | snd_emu1010_fpga_link_dst_src_write(emu, | 1139 | emu->emu1010.output_source[17] = 18; |
1121 | EMU_DST_DOCK_PHONES_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); | 1140 | } else { |
1122 | emu->emu1010.output_source[9] = 22; | 1141 | /* ALICE2 bus 0xa0 */ |
1123 | snd_emu1010_fpga_link_dst_src_write(emu, | 1142 | snd_emu1010_fpga_link_dst_src_write(emu, |
1124 | EMU_DST_DOCK_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ | 1143 | EMU_DST_DOCK_DAC1_LEFT1, EMU_SRC_ALICE_EMU32A + 0); |
1125 | emu->emu1010.output_source[10] = 21; | 1144 | emu->emu1010.output_source[0] = 21; |
1126 | snd_emu1010_fpga_link_dst_src_write(emu, | 1145 | snd_emu1010_fpga_link_dst_src_write(emu, |
1127 | EMU_DST_DOCK_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); | 1146 | EMU_DST_DOCK_DAC1_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); |
1128 | emu->emu1010.output_source[11] = 22; | 1147 | emu->emu1010.output_source[1] = 22; |
1129 | snd_emu1010_fpga_link_dst_src_write(emu, | 1148 | snd_emu1010_fpga_link_dst_src_write(emu, |
1130 | EMU_DST_HANA_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ | 1149 | EMU_DST_DOCK_DAC2_LEFT1, EMU_SRC_ALICE_EMU32A + 2); |
1131 | emu->emu1010.output_source[12] = 21; | 1150 | emu->emu1010.output_source[2] = 23; |
1132 | snd_emu1010_fpga_link_dst_src_write(emu, | 1151 | snd_emu1010_fpga_link_dst_src_write(emu, |
1133 | EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); | 1152 | EMU_DST_DOCK_DAC2_RIGHT1, EMU_SRC_ALICE_EMU32A + 3); |
1134 | emu->emu1010.output_source[13] = 22; | 1153 | emu->emu1010.output_source[3] = 24; |
1135 | snd_emu1010_fpga_link_dst_src_write(emu, | 1154 | snd_emu1010_fpga_link_dst_src_write(emu, |
1136 | EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ | 1155 | EMU_DST_DOCK_DAC3_LEFT1, EMU_SRC_ALICE_EMU32A + 4); |
1137 | emu->emu1010.output_source[14] = 21; | 1156 | emu->emu1010.output_source[4] = 25; |
1138 | snd_emu1010_fpga_link_dst_src_write(emu, | 1157 | snd_emu1010_fpga_link_dst_src_write(emu, |
1139 | EMU_DST_HAMOA_DAC_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); | 1158 | EMU_DST_DOCK_DAC3_RIGHT1, EMU_SRC_ALICE_EMU32A + 5); |
1140 | emu->emu1010.output_source[15] = 22; | 1159 | emu->emu1010.output_source[5] = 26; |
1141 | snd_emu1010_fpga_link_dst_src_write(emu, | 1160 | snd_emu1010_fpga_link_dst_src_write(emu, |
1142 | EMU_DST_HANA_ADAT, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ | 1161 | EMU_DST_DOCK_DAC4_LEFT1, EMU_SRC_ALICE_EMU32A + 6); |
1143 | emu->emu1010.output_source[16] = 21; | 1162 | emu->emu1010.output_source[6] = 27; |
1144 | snd_emu1010_fpga_link_dst_src_write(emu, | 1163 | snd_emu1010_fpga_link_dst_src_write(emu, |
1145 | EMU_DST_HANA_ADAT + 1, EMU_SRC_ALICE_EMU32A + 1); | 1164 | EMU_DST_DOCK_DAC4_RIGHT1, EMU_SRC_ALICE_EMU32A + 7); |
1146 | emu->emu1010.output_source[17] = 22; | 1165 | emu->emu1010.output_source[7] = 28; |
1147 | snd_emu1010_fpga_link_dst_src_write(emu, | 1166 | /* ALICE2 bus 0xa0 */ |
1148 | EMU_DST_HANA_ADAT + 2, EMU_SRC_ALICE_EMU32A + 2); | 1167 | snd_emu1010_fpga_link_dst_src_write(emu, |
1149 | emu->emu1010.output_source[18] = 23; | 1168 | EMU_DST_DOCK_PHONES_LEFT1, EMU_SRC_ALICE_EMU32A + 0); |
1150 | snd_emu1010_fpga_link_dst_src_write(emu, | 1169 | emu->emu1010.output_source[8] = 21; |
1151 | EMU_DST_HANA_ADAT + 3, EMU_SRC_ALICE_EMU32A + 3); | 1170 | snd_emu1010_fpga_link_dst_src_write(emu, |
1152 | emu->emu1010.output_source[19] = 24; | 1171 | EMU_DST_DOCK_PHONES_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); |
1153 | snd_emu1010_fpga_link_dst_src_write(emu, | 1172 | emu->emu1010.output_source[9] = 22; |
1154 | EMU_DST_HANA_ADAT + 4, EMU_SRC_ALICE_EMU32A + 4); | 1173 | /* ALICE2 bus 0xa0 */ |
1155 | emu->emu1010.output_source[20] = 25; | 1174 | snd_emu1010_fpga_link_dst_src_write(emu, |
1156 | snd_emu1010_fpga_link_dst_src_write(emu, | 1175 | EMU_DST_DOCK_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0); |
1157 | EMU_DST_HANA_ADAT + 5, EMU_SRC_ALICE_EMU32A + 5); | 1176 | emu->emu1010.output_source[10] = 21; |
1158 | emu->emu1010.output_source[21] = 26; | 1177 | snd_emu1010_fpga_link_dst_src_write(emu, |
1159 | snd_emu1010_fpga_link_dst_src_write(emu, | 1178 | EMU_DST_DOCK_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); |
1160 | EMU_DST_HANA_ADAT + 6, EMU_SRC_ALICE_EMU32A + 6); | 1179 | emu->emu1010.output_source[11] = 22; |
1161 | emu->emu1010.output_source[22] = 27; | 1180 | /* ALICE2 bus 0xa0 */ |
1162 | snd_emu1010_fpga_link_dst_src_write(emu, | 1181 | snd_emu1010_fpga_link_dst_src_write(emu, |
1163 | EMU_DST_HANA_ADAT + 7, EMU_SRC_ALICE_EMU32A + 7); | 1182 | EMU_DST_HANA_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0); |
1164 | emu->emu1010.output_source[23] = 28; | 1183 | emu->emu1010.output_source[12] = 21; |
1165 | 1184 | snd_emu1010_fpga_link_dst_src_write(emu, | |
1185 | EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); | ||
1186 | emu->emu1010.output_source[13] = 22; | ||
1187 | /* ALICE2 bus 0xa0 */ | ||
1188 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1189 | EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32A + 0); | ||
1190 | emu->emu1010.output_source[14] = 21; | ||
1191 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1192 | EMU_DST_HAMOA_DAC_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); | ||
1193 | emu->emu1010.output_source[15] = 22; | ||
1194 | /* ALICE2 bus 0xa0 */ | ||
1195 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1196 | EMU_DST_HANA_ADAT, EMU_SRC_ALICE_EMU32A + 0); | ||
1197 | emu->emu1010.output_source[16] = 21; | ||
1198 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1199 | EMU_DST_HANA_ADAT + 1, EMU_SRC_ALICE_EMU32A + 1); | ||
1200 | emu->emu1010.output_source[17] = 22; | ||
1201 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1202 | EMU_DST_HANA_ADAT + 2, EMU_SRC_ALICE_EMU32A + 2); | ||
1203 | emu->emu1010.output_source[18] = 23; | ||
1204 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1205 | EMU_DST_HANA_ADAT + 3, EMU_SRC_ALICE_EMU32A + 3); | ||
1206 | emu->emu1010.output_source[19] = 24; | ||
1207 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1208 | EMU_DST_HANA_ADAT + 4, EMU_SRC_ALICE_EMU32A + 4); | ||
1209 | emu->emu1010.output_source[20] = 25; | ||
1210 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1211 | EMU_DST_HANA_ADAT + 5, EMU_SRC_ALICE_EMU32A + 5); | ||
1212 | emu->emu1010.output_source[21] = 26; | ||
1213 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1214 | EMU_DST_HANA_ADAT + 6, EMU_SRC_ALICE_EMU32A + 6); | ||
1215 | emu->emu1010.output_source[22] = 27; | ||
1216 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1217 | EMU_DST_HANA_ADAT + 7, EMU_SRC_ALICE_EMU32A + 7); | ||
1218 | emu->emu1010.output_source[23] = 28; | ||
1219 | } | ||
1166 | /* TEMP: Select SPDIF in/out */ | 1220 | /* TEMP: Select SPDIF in/out */ |
1167 | //snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x0); /* Output spdif */ | 1221 | //snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x0); /* Output spdif */ |
1168 | 1222 | ||
@@ -1202,11 +1256,12 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu) | |||
1202 | } | 1256 | } |
1203 | snd_emu10k1_free_efx(emu); | 1257 | snd_emu10k1_free_efx(emu); |
1204 | } | 1258 | } |
1205 | if (emu->card_capabilities->emu1010) { | 1259 | if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1010) { |
1206 | /* Disable 48Volt power to Audio Dock */ | 1260 | /* Disable 48Volt power to Audio Dock */ |
1207 | snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0 ); | 1261 | snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0 ); |
1208 | kthread_stop(emu->emu1010.firmware_thread); | ||
1209 | } | 1262 | } |
1263 | if (emu->emu1010.firmware_thread) | ||
1264 | kthread_stop(emu->emu1010.firmware_thread); | ||
1210 | if (emu->memhdr) | 1265 | if (emu->memhdr) |
1211 | snd_util_memhdr_free(emu->memhdr); | 1266 | snd_util_memhdr_free(emu->memhdr); |
1212 | if (emu->silent_page.area) | 1267 | if (emu->silent_page.area) |
@@ -1338,6 +1393,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { | |||
1338 | .spi_dac = 1, | 1393 | .spi_dac = 1, |
1339 | .i2c_adc = 1, | 1394 | .i2c_adc = 1, |
1340 | .spk71 = 1} , | 1395 | .spk71 = 1} , |
1396 | /* Tested by James@superbug.co.uk 4th Nov 2007. */ | ||
1341 | {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x42011102, | 1397 | {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x42011102, |
1342 | .driver = "Audigy2", .name = "E-mu 1010 Notebook [MAEM8950]", | 1398 | .driver = "Audigy2", .name = "E-mu 1010 Notebook [MAEM8950]", |
1343 | .id = "EMU1010", | 1399 | .id = "EMU1010", |
@@ -1345,28 +1401,46 @@ static struct snd_emu_chip_details emu_chip_details[] = { | |||
1345 | .ca0108_chip = 1, | 1401 | .ca0108_chip = 1, |
1346 | .ca_cardbus_chip = 1, | 1402 | .ca_cardbus_chip = 1, |
1347 | .spk71 = 1 , | 1403 | .spk71 = 1 , |
1348 | .emu1010 = 3} , | 1404 | .emu_model = EMU_MODEL_EMU1616}, |
1405 | /* Tested by James@superbug.co.uk 4th Nov 2007. */ | ||
1349 | {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40041102, | 1406 | {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40041102, |
1350 | .driver = "Audigy2", .name = "E-mu 1010b PCI [MAEM????]", | 1407 | .driver = "Audigy2", .name = "E-mu 1010b PCI [MAEM????]", |
1351 | .id = "EMU1010", | 1408 | .id = "EMU1010", |
1352 | .emu10k2_chip = 1, | 1409 | .emu10k2_chip = 1, |
1353 | .ca0108_chip = 1, | 1410 | .ca0108_chip = 1, |
1354 | .spk71 = 1 , | 1411 | .spk71 = 1, |
1355 | .emu1010 = 2} , | 1412 | .emu_model = EMU_MODEL_EMU1010B}, |
1413 | /* Tested by James@superbug.co.uk 8th July 2005. */ | ||
1414 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102, | ||
1415 | .driver = "Audigy2", .name = "E-mu 1010 [4001]", | ||
1416 | .id = "EMU1010", | ||
1417 | .emu10k2_chip = 1, | ||
1418 | .ca0102_chip = 1, | ||
1419 | .spk71 = 1, | ||
1420 | .emu_model = EMU_MODEL_EMU1010}, /* Emu 1010 */ | ||
1421 | /* EMU0404b */ | ||
1422 | {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40021102, | ||
1423 | .driver = "Audigy2", .name = "E-mu 0404b [4002]", | ||
1424 | .id = "EMU0404", | ||
1425 | .emu10k2_chip = 1, | ||
1426 | .ca0108_chip = 1, | ||
1427 | .spk71 = 1, | ||
1428 | .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 */ | ||
1429 | /* Tested by James@superbug.co.uk 20-3-2007. */ | ||
1430 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40021102, | ||
1431 | .driver = "Audigy2", .name = "E-mu 0404 [4002]", | ||
1432 | .id = "EMU0404", | ||
1433 | .emu10k2_chip = 1, | ||
1434 | .ca0102_chip = 1, | ||
1435 | .spk71 = 1, | ||
1436 | .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 */ | ||
1437 | /* Audigy4 (Not PRO) SB0610 */ | ||
1356 | {.vendor = 0x1102, .device = 0x0008, | 1438 | {.vendor = 0x1102, .device = 0x0008, |
1357 | .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", | 1439 | .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", |
1358 | .id = "Audigy2", | 1440 | .id = "Audigy2", |
1359 | .emu10k2_chip = 1, | 1441 | .emu10k2_chip = 1, |
1360 | .ca0108_chip = 1, | 1442 | .ca0108_chip = 1, |
1361 | .ac97_chip = 1} , | 1443 | .ac97_chip = 1} , |
1362 | /* Tested by James@superbug.co.uk 8th July 2005. No sound available yet. */ | ||
1363 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102, | ||
1364 | .driver = "Audigy2", .name = "E-mu 1010 [4001]", | ||
1365 | .id = "EMU1010", | ||
1366 | .emu10k2_chip = 1, | ||
1367 | .ca0102_chip = 1, | ||
1368 | .spk71 = 1, | ||
1369 | .emu1010 = 1} , | ||
1370 | /* Tested by James@superbug.co.uk 3rd July 2005 */ | 1444 | /* Tested by James@superbug.co.uk 3rd July 2005 */ |
1371 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102, | 1445 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102, |
1372 | .driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]", | 1446 | .driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]", |
@@ -1654,6 +1728,8 @@ int __devinit snd_emu10k1_create(struct snd_card *card, | |||
1654 | emu->card = card; | 1728 | emu->card = card; |
1655 | spin_lock_init(&emu->reg_lock); | 1729 | spin_lock_init(&emu->reg_lock); |
1656 | spin_lock_init(&emu->emu_lock); | 1730 | spin_lock_init(&emu->emu_lock); |
1731 | spin_lock_init(&emu->spi_lock); | ||
1732 | spin_lock_init(&emu->i2c_lock); | ||
1657 | spin_lock_init(&emu->voice_lock); | 1733 | spin_lock_init(&emu->voice_lock); |
1658 | spin_lock_init(&emu->synth_lock); | 1734 | spin_lock_init(&emu->synth_lock); |
1659 | spin_lock_init(&emu->memblk_lock); | 1735 | spin_lock_init(&emu->memblk_lock); |
@@ -1794,7 +1870,7 @@ int __devinit snd_emu10k1_create(struct snd_card *card, | |||
1794 | if (emu->card_capabilities->ecard) { | 1870 | if (emu->card_capabilities->ecard) { |
1795 | if ((err = snd_emu10k1_ecard_init(emu)) < 0) | 1871 | if ((err = snd_emu10k1_ecard_init(emu)) < 0) |
1796 | goto error; | 1872 | goto error; |
1797 | } else if (emu->card_capabilities->emu1010) { | 1873 | } else if (emu->card_capabilities->emu_model) { |
1798 | if ((err = snd_emu10k1_emu1010_init(emu)) < 0) { | 1874 | if ((err = snd_emu10k1_emu1010_init(emu)) < 0) { |
1799 | snd_emu10k1_free(emu); | 1875 | snd_emu10k1_free(emu); |
1800 | return err; | 1876 | return err; |
@@ -1943,7 +2019,7 @@ void snd_emu10k1_resume_init(struct snd_emu10k1 *emu) | |||
1943 | snd_emu10k1_cardbus_init(emu); | 2019 | snd_emu10k1_cardbus_init(emu); |
1944 | if (emu->card_capabilities->ecard) | 2020 | if (emu->card_capabilities->ecard) |
1945 | snd_emu10k1_ecard_init(emu); | 2021 | snd_emu10k1_ecard_init(emu); |
1946 | else if (emu->card_capabilities->emu1010) | 2022 | else if (emu->card_capabilities->emu_model) |
1947 | snd_emu10k1_emu1010_init(emu); | 2023 | snd_emu10k1_emu1010_init(emu); |
1948 | else | 2024 | else |
1949 | snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE); | 2025 | snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE); |
diff --git a/sound/pci/emu10k1/emu10k1_synth.c b/sound/pci/emu10k1/emu10k1_synth.c index 204995a1dfbd..ad7b71491fc4 100644 --- a/sound/pci/emu10k1/emu10k1_synth.c +++ b/sound/pci/emu10k1/emu10k1_synth.c | |||
@@ -30,7 +30,7 @@ MODULE_LICENSE("GPL"); | |||
30 | */ | 30 | */ |
31 | static int snd_emu10k1_synth_new_device(struct snd_seq_device *dev) | 31 | static int snd_emu10k1_synth_new_device(struct snd_seq_device *dev) |
32 | { | 32 | { |
33 | struct snd_emux *emu; | 33 | struct snd_emux *emux; |
34 | struct snd_emu10k1 *hw; | 34 | struct snd_emu10k1 *hw; |
35 | struct snd_emu10k1_synth_arg *arg; | 35 | struct snd_emu10k1_synth_arg *arg; |
36 | unsigned long flags; | 36 | unsigned long flags; |
@@ -46,53 +46,56 @@ static int snd_emu10k1_synth_new_device(struct snd_seq_device *dev) | |||
46 | else if (arg->max_voices > 64) | 46 | else if (arg->max_voices > 64) |
47 | arg->max_voices = 64; | 47 | arg->max_voices = 64; |
48 | 48 | ||
49 | if (snd_emux_new(&emu) < 0) | 49 | if (snd_emux_new(&emux) < 0) |
50 | return -ENOMEM; | 50 | return -ENOMEM; |
51 | 51 | ||
52 | snd_emu10k1_ops_setup(emu); | 52 | snd_emu10k1_ops_setup(emux); |
53 | emu->hw = hw = arg->hwptr; | 53 | hw = arg->hwptr; |
54 | emu->max_voices = arg->max_voices; | 54 | emux->hw = hw; |
55 | emu->num_ports = arg->seq_ports; | 55 | emux->max_voices = arg->max_voices; |
56 | emu->pitch_shift = -501; | 56 | emux->num_ports = arg->seq_ports; |
57 | emu->memhdr = hw->memhdr; | 57 | emux->pitch_shift = -501; |
58 | emu->midi_ports = arg->seq_ports < 2 ? arg->seq_ports : 2; /* maximum two ports */ | 58 | emux->memhdr = hw->memhdr; |
59 | emu->midi_devidx = hw->audigy ? 2 : 1; /* audigy has two external midis */ | 59 | /* maximum two ports */ |
60 | emu->linear_panning = 0; | 60 | emux->midi_ports = arg->seq_ports < 2 ? arg->seq_ports : 2; |
61 | emu->hwdep_idx = 2; /* FIXED */ | 61 | /* audigy has two external midis */ |
62 | 62 | emux->midi_devidx = hw->audigy ? 2 : 1; | |
63 | if (snd_emux_register(emu, dev->card, arg->index, "Emu10k1") < 0) { | 63 | emux->linear_panning = 0; |
64 | snd_emux_free(emu); | 64 | emux->hwdep_idx = 2; /* FIXED */ |
65 | |||
66 | if (snd_emux_register(emux, dev->card, arg->index, "Emu10k1") < 0) { | ||
67 | snd_emux_free(emux); | ||
65 | return -ENOMEM; | 68 | return -ENOMEM; |
66 | } | 69 | } |
67 | 70 | ||
68 | spin_lock_irqsave(&hw->voice_lock, flags); | 71 | spin_lock_irqsave(&hw->voice_lock, flags); |
69 | hw->synth = emu; | 72 | hw->synth = emux; |
70 | hw->get_synth_voice = snd_emu10k1_synth_get_voice; | 73 | hw->get_synth_voice = snd_emu10k1_synth_get_voice; |
71 | spin_unlock_irqrestore(&hw->voice_lock, flags); | 74 | spin_unlock_irqrestore(&hw->voice_lock, flags); |
72 | 75 | ||
73 | dev->driver_data = emu; | 76 | dev->driver_data = emux; |
74 | 77 | ||
75 | return 0; | 78 | return 0; |
76 | } | 79 | } |
77 | 80 | ||
78 | static int snd_emu10k1_synth_delete_device(struct snd_seq_device *dev) | 81 | static int snd_emu10k1_synth_delete_device(struct snd_seq_device *dev) |
79 | { | 82 | { |
80 | struct snd_emux *emu; | 83 | struct snd_emux *emux; |
81 | struct snd_emu10k1 *hw; | 84 | struct snd_emu10k1 *hw; |
82 | unsigned long flags; | 85 | unsigned long flags; |
83 | 86 | ||
84 | if (dev->driver_data == NULL) | 87 | if (dev->driver_data == NULL) |
85 | return 0; /* not registered actually */ | 88 | return 0; /* not registered actually */ |
86 | 89 | ||
87 | emu = dev->driver_data; | 90 | emux = dev->driver_data; |
88 | 91 | ||
89 | hw = emu->hw; | 92 | hw = emux->hw; |
90 | spin_lock_irqsave(&hw->voice_lock, flags); | 93 | spin_lock_irqsave(&hw->voice_lock, flags); |
91 | hw->synth = NULL; | 94 | hw->synth = NULL; |
92 | hw->get_synth_voice = NULL; | 95 | hw->get_synth_voice = NULL; |
93 | spin_unlock_irqrestore(&hw->voice_lock, flags); | 96 | spin_unlock_irqrestore(&hw->voice_lock, flags); |
94 | 97 | ||
95 | snd_emux_free(emu); | 98 | snd_emux_free(emux); |
96 | return 0; | 99 | return 0; |
97 | } | 100 | } |
98 | 101 | ||
diff --git a/sound/pci/emu10k1/emu10k1_synth_local.h b/sound/pci/emu10k1/emu10k1_synth_local.h index 308ddc84bb4d..25f328ff639f 100644 --- a/sound/pci/emu10k1/emu10k1_synth_local.h +++ b/sound/pci/emu10k1/emu10k1_synth_local.h | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/time.h> | 23 | #include <linux/time.h> |
25 | #include <sound/core.h> | 24 | #include <sound/core.h> |
26 | #include <sound/emu10k1_synth.h> | 25 | #include <sound/emu10k1_synth.h> |
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 1ec7ebaff9e9..5512abd98bd9 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c | |||
@@ -29,7 +29,6 @@ | |||
29 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 29 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
30 | * | 30 | * |
31 | */ | 31 | */ |
32 | #include <sound/driver.h> | ||
33 | #include <linux/init.h> | 32 | #include <linux/init.h> |
34 | #include <linux/interrupt.h> | 33 | #include <linux/interrupt.h> |
35 | #include <linux/pci.h> | 34 | #include <linux/pci.h> |
@@ -1583,6 +1582,8 @@ static int __devinit snd_emu10k1x_probe(struct pci_dev *pci, | |||
1583 | sprintf(card->longname, "%s at 0x%lx irq %i", | 1582 | sprintf(card->longname, "%s at 0x%lx irq %i", |
1584 | card->shortname, chip->port, chip->irq); | 1583 | card->shortname, chip->port, chip->irq); |
1585 | 1584 | ||
1585 | snd_card_set_dev(card, &pci->dev); | ||
1586 | |||
1586 | if ((err = snd_card_register(card)) < 0) { | 1587 | if ((err = snd_card_register(card)) < 0) { |
1587 | snd_card_free(card); | 1588 | snd_card_free(card); |
1588 | return err; | 1589 | return err; |
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 9bf1cd592199..71dc4c8865b8 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c | |||
@@ -28,7 +28,6 @@ | |||
28 | * | 28 | * |
29 | */ | 29 | */ |
30 | 30 | ||
31 | #include <sound/driver.h> | ||
32 | #include <linux/pci.h> | 31 | #include <linux/pci.h> |
33 | #include <linux/capability.h> | 32 | #include <linux/capability.h> |
34 | #include <linux/delay.h> | 33 | #include <linux/delay.h> |
@@ -666,7 +665,7 @@ static unsigned int *copy_tlv(const unsigned int __user *_tlv) | |||
666 | return NULL; | 665 | return NULL; |
667 | if (data[1] >= MAX_TLV_SIZE) | 666 | if (data[1] >= MAX_TLV_SIZE) |
668 | return NULL; | 667 | return NULL; |
669 | tlv = kmalloc(data[1] * 4 + sizeof(data), GFP_KERNEL); | 668 | tlv = kmalloc(data[1] + sizeof(data), GFP_KERNEL); |
670 | if (!tlv) | 669 | if (!tlv) |
671 | return NULL; | 670 | return NULL; |
672 | memcpy(tlv, data, sizeof(data)); | 671 | memcpy(tlv, data, sizeof(data)); |
@@ -1262,7 +1261,7 @@ static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) | |||
1262 | A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) | 1261 | A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) |
1263 | 1262 | ||
1264 | /* emu1212 DSP 0 and DSP 1 Capture */ | 1263 | /* emu1212 DSP 0 and DSP 1 Capture */ |
1265 | if (emu->card_capabilities->emu1010) { | 1264 | if (emu->card_capabilities->emu_model) { |
1266 | if (emu->card_capabilities->ca0108_chip) { | 1265 | if (emu->card_capabilities->ca0108_chip) { |
1267 | /* Note:JCD:No longer bit shift lower 16bits to upper 16bits of 32bit value. */ | 1266 | /* Note:JCD:No longer bit shift lower 16bits to upper 16bits of 32bit value. */ |
1268 | A_OP(icode, &ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A3_EMU32IN(0x0), A_C_00000001); | 1267 | A_OP(icode, &ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A3_EMU32IN(0x0), A_C_00000001); |
@@ -1516,7 +1515,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) | |||
1516 | 1515 | ||
1517 | /* digital outputs */ | 1516 | /* digital outputs */ |
1518 | /* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */ | 1517 | /* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */ |
1519 | if (emu->card_capabilities->emu1010) { | 1518 | if (emu->card_capabilities->emu_model) { |
1520 | /* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */ | 1519 | /* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */ |
1521 | snd_printk("EMU outputs on\n"); | 1520 | snd_printk("EMU outputs on\n"); |
1522 | for (z = 0; z < 8; z++) { | 1521 | for (z = 0; z < 8; z++) { |
@@ -1564,7 +1563,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) | |||
1564 | A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1); | 1563 | A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1); |
1565 | #endif | 1564 | #endif |
1566 | 1565 | ||
1567 | if (emu->card_capabilities->emu1010) { | 1566 | if (emu->card_capabilities->emu_model) { |
1568 | if (emu->card_capabilities->ca0108_chip) { | 1567 | if (emu->card_capabilities->ca0108_chip) { |
1569 | snd_printk("EMU2 inputs on\n"); | 1568 | snd_printk("EMU2 inputs on\n"); |
1570 | for (z = 0; z < 0x10; z++) { | 1569 | for (z = 0; z < 0x10; z++) { |
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index ccacd7b890e8..fd221209abcb 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c | |||
@@ -30,7 +30,6 @@ | |||
30 | * | 30 | * |
31 | */ | 31 | */ |
32 | 32 | ||
33 | #include <sound/driver.h> | ||
34 | #include <linux/time.h> | 33 | #include <linux/time.h> |
35 | #include <linux/init.h> | 34 | #include <linux/init.h> |
36 | #include <sound/core.h> | 35 | #include <sound/core.h> |
@@ -140,6 +139,61 @@ static char *emu1010_src_texts[] = { | |||
140 | "DSP 31", | 139 | "DSP 31", |
141 | }; | 140 | }; |
142 | 141 | ||
142 | /* 1616(m) cardbus */ | ||
143 | |||
144 | static char *emu1616_src_texts[] = { | ||
145 | "Silence", | ||
146 | "Dock Mic A", | ||
147 | "Dock Mic B", | ||
148 | "Dock ADC1 Left", | ||
149 | "Dock ADC1 Right", | ||
150 | "Dock ADC2 Left", | ||
151 | "Dock ADC2 Right", | ||
152 | "Dock SPDIF Left", | ||
153 | "Dock SPDIF Right", | ||
154 | "ADAT 0", | ||
155 | "ADAT 1", | ||
156 | "ADAT 2", | ||
157 | "ADAT 3", | ||
158 | "ADAT 4", | ||
159 | "ADAT 5", | ||
160 | "ADAT 6", | ||
161 | "ADAT 7", | ||
162 | "DSP 0", | ||
163 | "DSP 1", | ||
164 | "DSP 2", | ||
165 | "DSP 3", | ||
166 | "DSP 4", | ||
167 | "DSP 5", | ||
168 | "DSP 6", | ||
169 | "DSP 7", | ||
170 | "DSP 8", | ||
171 | "DSP 9", | ||
172 | "DSP 10", | ||
173 | "DSP 11", | ||
174 | "DSP 12", | ||
175 | "DSP 13", | ||
176 | "DSP 14", | ||
177 | "DSP 15", | ||
178 | "DSP 16", | ||
179 | "DSP 17", | ||
180 | "DSP 18", | ||
181 | "DSP 19", | ||
182 | "DSP 20", | ||
183 | "DSP 21", | ||
184 | "DSP 22", | ||
185 | "DSP 23", | ||
186 | "DSP 24", | ||
187 | "DSP 25", | ||
188 | "DSP 26", | ||
189 | "DSP 27", | ||
190 | "DSP 28", | ||
191 | "DSP 29", | ||
192 | "DSP 30", | ||
193 | "DSP 31", | ||
194 | }; | ||
195 | |||
196 | |||
143 | /* | 197 | /* |
144 | * List of data sources available for each destination | 198 | * List of data sources available for each destination |
145 | */ | 199 | */ |
@@ -199,6 +253,59 @@ static unsigned int emu1010_src_regs[] = { | |||
199 | EMU_SRC_ALICE_EMU32B+0xf, /* 52 */ | 253 | EMU_SRC_ALICE_EMU32B+0xf, /* 52 */ |
200 | }; | 254 | }; |
201 | 255 | ||
256 | /* 1616(m) cardbus */ | ||
257 | static unsigned int emu1616_src_regs[] = { | ||
258 | EMU_SRC_SILENCE, | ||
259 | EMU_SRC_DOCK_MIC_A1, | ||
260 | EMU_SRC_DOCK_MIC_B1, | ||
261 | EMU_SRC_DOCK_ADC1_LEFT1, | ||
262 | EMU_SRC_DOCK_ADC1_RIGHT1, | ||
263 | EMU_SRC_DOCK_ADC2_LEFT1, | ||
264 | EMU_SRC_DOCK_ADC2_RIGHT1, | ||
265 | EMU_SRC_MDOCK_SPDIF_LEFT1, | ||
266 | EMU_SRC_MDOCK_SPDIF_RIGHT1, | ||
267 | EMU_SRC_MDOCK_ADAT, | ||
268 | EMU_SRC_MDOCK_ADAT+1, | ||
269 | EMU_SRC_MDOCK_ADAT+2, | ||
270 | EMU_SRC_MDOCK_ADAT+3, | ||
271 | EMU_SRC_MDOCK_ADAT+4, | ||
272 | EMU_SRC_MDOCK_ADAT+5, | ||
273 | EMU_SRC_MDOCK_ADAT+6, | ||
274 | EMU_SRC_MDOCK_ADAT+7, | ||
275 | EMU_SRC_ALICE_EMU32A, | ||
276 | EMU_SRC_ALICE_EMU32A+1, | ||
277 | EMU_SRC_ALICE_EMU32A+2, | ||
278 | EMU_SRC_ALICE_EMU32A+3, | ||
279 | EMU_SRC_ALICE_EMU32A+4, | ||
280 | EMU_SRC_ALICE_EMU32A+5, | ||
281 | EMU_SRC_ALICE_EMU32A+6, | ||
282 | EMU_SRC_ALICE_EMU32A+7, | ||
283 | EMU_SRC_ALICE_EMU32A+8, | ||
284 | EMU_SRC_ALICE_EMU32A+9, | ||
285 | EMU_SRC_ALICE_EMU32A+0xa, | ||
286 | EMU_SRC_ALICE_EMU32A+0xb, | ||
287 | EMU_SRC_ALICE_EMU32A+0xc, | ||
288 | EMU_SRC_ALICE_EMU32A+0xd, | ||
289 | EMU_SRC_ALICE_EMU32A+0xe, | ||
290 | EMU_SRC_ALICE_EMU32A+0xf, | ||
291 | EMU_SRC_ALICE_EMU32B, | ||
292 | EMU_SRC_ALICE_EMU32B+1, | ||
293 | EMU_SRC_ALICE_EMU32B+2, | ||
294 | EMU_SRC_ALICE_EMU32B+3, | ||
295 | EMU_SRC_ALICE_EMU32B+4, | ||
296 | EMU_SRC_ALICE_EMU32B+5, | ||
297 | EMU_SRC_ALICE_EMU32B+6, | ||
298 | EMU_SRC_ALICE_EMU32B+7, | ||
299 | EMU_SRC_ALICE_EMU32B+8, | ||
300 | EMU_SRC_ALICE_EMU32B+9, | ||
301 | EMU_SRC_ALICE_EMU32B+0xa, | ||
302 | EMU_SRC_ALICE_EMU32B+0xb, | ||
303 | EMU_SRC_ALICE_EMU32B+0xc, | ||
304 | EMU_SRC_ALICE_EMU32B+0xd, | ||
305 | EMU_SRC_ALICE_EMU32B+0xe, | ||
306 | EMU_SRC_ALICE_EMU32B+0xf, | ||
307 | }; | ||
308 | |||
202 | /* | 309 | /* |
203 | * Data destinations - physical EMU outputs. | 310 | * Data destinations - physical EMU outputs. |
204 | * Each destination has an enum mixer control to choose a data source | 311 | * Each destination has an enum mixer control to choose a data source |
@@ -230,6 +337,28 @@ static unsigned int emu1010_output_dst[] = { | |||
230 | EMU_DST_HANA_ADAT+7, /* 23 */ | 337 | EMU_DST_HANA_ADAT+7, /* 23 */ |
231 | }; | 338 | }; |
232 | 339 | ||
340 | /* 1616(m) cardbus */ | ||
341 | static unsigned int emu1616_output_dst[] = { | ||
342 | EMU_DST_DOCK_DAC1_LEFT1, | ||
343 | EMU_DST_DOCK_DAC1_RIGHT1, | ||
344 | EMU_DST_DOCK_DAC2_LEFT1, | ||
345 | EMU_DST_DOCK_DAC2_RIGHT1, | ||
346 | EMU_DST_DOCK_DAC3_LEFT1, | ||
347 | EMU_DST_DOCK_DAC3_RIGHT1, | ||
348 | EMU_DST_MDOCK_SPDIF_LEFT1, | ||
349 | EMU_DST_MDOCK_SPDIF_RIGHT1, | ||
350 | EMU_DST_MDOCK_ADAT, | ||
351 | EMU_DST_MDOCK_ADAT+1, | ||
352 | EMU_DST_MDOCK_ADAT+2, | ||
353 | EMU_DST_MDOCK_ADAT+3, | ||
354 | EMU_DST_MDOCK_ADAT+4, | ||
355 | EMU_DST_MDOCK_ADAT+5, | ||
356 | EMU_DST_MDOCK_ADAT+6, | ||
357 | EMU_DST_MDOCK_ADAT+7, | ||
358 | EMU_DST_MANA_DAC_LEFT, | ||
359 | EMU_DST_MANA_DAC_RIGHT, | ||
360 | }; | ||
361 | |||
233 | /* | 362 | /* |
234 | * Data destinations - HANA outputs going to Alice2 (audigy) for | 363 | * Data destinations - HANA outputs going to Alice2 (audigy) for |
235 | * capture (EMU32 + I2S links) | 364 | * capture (EMU32 + I2S links) |
@@ -260,14 +389,26 @@ static unsigned int emu1010_input_dst[] = { | |||
260 | EMU_DST_ALICE_I2S2_RIGHT, | 389 | EMU_DST_ALICE_I2S2_RIGHT, |
261 | }; | 390 | }; |
262 | 391 | ||
263 | static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 392 | static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, |
393 | struct snd_ctl_elem_info *uinfo) | ||
264 | { | 394 | { |
395 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | ||
396 | char **items; | ||
397 | |||
265 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 398 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
266 | uinfo->count = 1; | 399 | uinfo->count = 1; |
267 | uinfo->value.enumerated.items = 53; | 400 | if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) { |
401 | uinfo->value.enumerated.items = 49; | ||
402 | items = emu1616_src_texts; | ||
403 | } else { | ||
404 | uinfo->value.enumerated.items = 53; | ||
405 | items = emu1010_src_texts; | ||
406 | } | ||
268 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | 407 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) |
269 | uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; | 408 | uinfo->value.enumerated.item = |
270 | strcpy(uinfo->value.enumerated.name, emu1010_src_texts[uinfo->value.enumerated.item]); | 409 | uinfo->value.enumerated.items - 1; |
410 | strcpy(uinfo->value.enumerated.name, | ||
411 | items[uinfo->value.enumerated.item]); | ||
271 | return 0; | 412 | return 0; |
272 | } | 413 | } |
273 | 414 | ||
@@ -279,7 +420,9 @@ static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol, | |||
279 | 420 | ||
280 | channel = (kcontrol->private_value) & 0xff; | 421 | channel = (kcontrol->private_value) & 0xff; |
281 | /* Limit: emu1010_output_dst, emu->emu1010.output_source */ | 422 | /* Limit: emu1010_output_dst, emu->emu1010.output_source */ |
282 | if (channel >= 24) | 423 | if (channel >= 24 || |
424 | (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && | ||
425 | channel >= 18)) | ||
283 | return -EINVAL; | 426 | return -EINVAL; |
284 | ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel]; | 427 | ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel]; |
285 | return 0; | 428 | return 0; |
@@ -289,24 +432,30 @@ static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol, | |||
289 | struct snd_ctl_elem_value *ucontrol) | 432 | struct snd_ctl_elem_value *ucontrol) |
290 | { | 433 | { |
291 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | 434 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); |
292 | int change = 0; | ||
293 | unsigned int val; | 435 | unsigned int val; |
294 | unsigned int channel; | 436 | unsigned int channel; |
295 | 437 | ||
296 | val = ucontrol->value.enumerated.item[0]; | 438 | val = ucontrol->value.enumerated.item[0]; |
297 | if (val >= 53) | 439 | if (val >= 53 || |
440 | (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && | ||
441 | val >= 49)) | ||
298 | return -EINVAL; | 442 | return -EINVAL; |
299 | channel = (kcontrol->private_value) & 0xff; | 443 | channel = (kcontrol->private_value) & 0xff; |
300 | /* Limit: emu1010_output_dst, emu->emu1010.output_source */ | 444 | /* Limit: emu1010_output_dst, emu->emu1010.output_source */ |
301 | if (channel >= 24) | 445 | if (channel >= 24 || |
446 | (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && | ||
447 | channel >= 18)) | ||
302 | return -EINVAL; | 448 | return -EINVAL; |
303 | if (emu->emu1010.output_source[channel] != val) { | 449 | if (emu->emu1010.output_source[channel] == val) |
304 | emu->emu1010.output_source[channel] = val; | 450 | return 0; |
305 | change = 1; | 451 | emu->emu1010.output_source[channel] = val; |
452 | if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) | ||
453 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
454 | emu1616_output_dst[channel], emu1616_src_regs[val]); | ||
455 | else | ||
306 | snd_emu1010_fpga_link_dst_src_write(emu, | 456 | snd_emu1010_fpga_link_dst_src_write(emu, |
307 | emu1010_output_dst[channel], emu1010_src_regs[val]); | 457 | emu1010_output_dst[channel], emu1010_src_regs[val]); |
308 | } | 458 | return 1; |
309 | return change; | ||
310 | } | 459 | } |
311 | 460 | ||
312 | static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol, | 461 | static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol, |
@@ -327,24 +476,28 @@ static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol, | |||
327 | struct snd_ctl_elem_value *ucontrol) | 476 | struct snd_ctl_elem_value *ucontrol) |
328 | { | 477 | { |
329 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | 478 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); |
330 | int change = 0; | ||
331 | unsigned int val; | 479 | unsigned int val; |
332 | unsigned int channel; | 480 | unsigned int channel; |
333 | 481 | ||
334 | val = ucontrol->value.enumerated.item[0]; | 482 | val = ucontrol->value.enumerated.item[0]; |
335 | if (val >= 53) | 483 | if (val >= 53 || |
484 | (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && | ||
485 | val >= 49)) | ||
336 | return -EINVAL; | 486 | return -EINVAL; |
337 | channel = (kcontrol->private_value) & 0xff; | 487 | channel = (kcontrol->private_value) & 0xff; |
338 | /* Limit: emu1010_input_dst, emu->emu1010.input_source */ | 488 | /* Limit: emu1010_input_dst, emu->emu1010.input_source */ |
339 | if (channel >= 22) | 489 | if (channel >= 22) |
340 | return -EINVAL; | 490 | return -EINVAL; |
341 | if (emu->emu1010.input_source[channel] != val) { | 491 | if (emu->emu1010.input_source[channel] == val) |
342 | emu->emu1010.input_source[channel] = val; | 492 | return 0; |
343 | change = 1; | 493 | emu->emu1010.input_source[channel] = val; |
494 | if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) | ||
495 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
496 | emu1010_input_dst[channel], emu1616_src_regs[val]); | ||
497 | else | ||
344 | snd_emu1010_fpga_link_dst_src_write(emu, | 498 | snd_emu1010_fpga_link_dst_src_write(emu, |
345 | emu1010_input_dst[channel], emu1010_src_regs[val]); | 499 | emu1010_input_dst[channel], emu1010_src_regs[val]); |
346 | } | 500 | return 1; |
347 | return change; | ||
348 | } | 501 | } |
349 | 502 | ||
350 | #define EMU1010_SOURCE_OUTPUT(xname,chid) \ | 503 | #define EMU1010_SOURCE_OUTPUT(xname,chid) \ |
@@ -384,6 +537,30 @@ static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = { | |||
384 | EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17), | 537 | EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17), |
385 | }; | 538 | }; |
386 | 539 | ||
540 | |||
541 | /* 1616(m) cardbus */ | ||
542 | static struct snd_kcontrol_new snd_emu1616_output_enum_ctls[] __devinitdata = { | ||
543 | EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0), | ||
544 | EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1), | ||
545 | EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2), | ||
546 | EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3), | ||
547 | EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4), | ||
548 | EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5), | ||
549 | EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 6), | ||
550 | EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 7), | ||
551 | EMU1010_SOURCE_OUTPUT("Dock ADAT 0 Playback Enum", 8), | ||
552 | EMU1010_SOURCE_OUTPUT("Dock ADAT 1 Playback Enum", 9), | ||
553 | EMU1010_SOURCE_OUTPUT("Dock ADAT 2 Playback Enum", 0xa), | ||
554 | EMU1010_SOURCE_OUTPUT("Dock ADAT 3 Playback Enum", 0xb), | ||
555 | EMU1010_SOURCE_OUTPUT("Dock ADAT 4 Playback Enum", 0xc), | ||
556 | EMU1010_SOURCE_OUTPUT("Dock ADAT 5 Playback Enum", 0xd), | ||
557 | EMU1010_SOURCE_OUTPUT("Dock ADAT 6 Playback Enum", 0xe), | ||
558 | EMU1010_SOURCE_OUTPUT("Dock ADAT 7 Playback Enum", 0xf), | ||
559 | EMU1010_SOURCE_OUTPUT("Mana DAC Left Playback Enum", 0x10), | ||
560 | EMU1010_SOURCE_OUTPUT("Mana DAC Right Playback Enum", 0x11), | ||
561 | }; | ||
562 | |||
563 | |||
387 | #define EMU1010_SOURCE_INPUT(xname,chid) \ | 564 | #define EMU1010_SOURCE_INPUT(xname,chid) \ |
388 | { \ | 565 | { \ |
389 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 566 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
@@ -1793,7 +1970,7 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, | |||
1793 | return err; | 1970 | return err; |
1794 | } | 1971 | } |
1795 | 1972 | ||
1796 | if ( emu->card_capabilities->emu1010) { | 1973 | if (emu->card_capabilities->emu_model) { |
1797 | ; /* Disable the snd_audigy_spdif_shared_spdif */ | 1974 | ; /* Disable the snd_audigy_spdif_shared_spdif */ |
1798 | } else if (emu->audigy) { | 1975 | } else if (emu->audigy) { |
1799 | if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL) | 1976 | if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL) |
@@ -1818,30 +1995,73 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, | |||
1818 | return err; | 1995 | return err; |
1819 | } | 1996 | } |
1820 | 1997 | ||
1821 | if ( emu->card_capabilities->emu1010) { | 1998 | if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) { |
1999 | /* 1616(m) cardbus */ | ||
2000 | int i; | ||
2001 | |||
2002 | for (i = 0; i < ARRAY_SIZE(snd_emu1616_output_enum_ctls); i++) { | ||
2003 | err = snd_ctl_add(card, | ||
2004 | snd_ctl_new1(&snd_emu1616_output_enum_ctls[i], | ||
2005 | emu)); | ||
2006 | if (err < 0) | ||
2007 | return err; | ||
2008 | } | ||
2009 | for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) { | ||
2010 | err = snd_ctl_add(card, | ||
2011 | snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], | ||
2012 | emu)); | ||
2013 | if (err < 0) | ||
2014 | return err; | ||
2015 | } | ||
2016 | for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads) - 2; i++) { | ||
2017 | err = snd_ctl_add(card, | ||
2018 | snd_ctl_new1(&snd_emu1010_adc_pads[i], emu)); | ||
2019 | if (err < 0) | ||
2020 | return err; | ||
2021 | } | ||
2022 | for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads) - 2; i++) { | ||
2023 | err = snd_ctl_add(card, | ||
2024 | snd_ctl_new1(&snd_emu1010_dac_pads[i], emu)); | ||
2025 | if (err < 0) | ||
2026 | return err; | ||
2027 | } | ||
2028 | err = snd_ctl_add(card, | ||
2029 | snd_ctl_new1(&snd_emu1010_internal_clock, emu)); | ||
2030 | if (err < 0) | ||
2031 | return err; | ||
2032 | |||
2033 | } else if (emu->card_capabilities->emu_model) { | ||
2034 | /* all other e-mu cards for now */ | ||
1822 | int i; | 2035 | int i; |
1823 | 2036 | ||
1824 | for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) { | 2037 | for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) { |
1825 | err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_output_enum_ctls[i], emu)); | 2038 | err = snd_ctl_add(card, |
2039 | snd_ctl_new1(&snd_emu1010_output_enum_ctls[i], | ||
2040 | emu)); | ||
1826 | if (err < 0) | 2041 | if (err < 0) |
1827 | return err; | 2042 | return err; |
1828 | } | 2043 | } |
1829 | for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) { | 2044 | for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) { |
1830 | err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], emu)); | 2045 | err = snd_ctl_add(card, |
2046 | snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], | ||
2047 | emu)); | ||
1831 | if (err < 0) | 2048 | if (err < 0) |
1832 | return err; | 2049 | return err; |
1833 | } | 2050 | } |
1834 | for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) { | 2051 | for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) { |
1835 | err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_adc_pads[i], emu)); | 2052 | err = snd_ctl_add(card, |
2053 | snd_ctl_new1(&snd_emu1010_adc_pads[i], emu)); | ||
1836 | if (err < 0) | 2054 | if (err < 0) |
1837 | return err; | 2055 | return err; |
1838 | } | 2056 | } |
1839 | for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) { | 2057 | for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) { |
1840 | err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_dac_pads[i], emu)); | 2058 | err = snd_ctl_add(card, |
2059 | snd_ctl_new1(&snd_emu1010_dac_pads[i], emu)); | ||
1841 | if (err < 0) | 2060 | if (err < 0) |
1842 | return err; | 2061 | return err; |
1843 | } | 2062 | } |
1844 | err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_internal_clock, emu)); | 2063 | err = snd_ctl_add(card, |
2064 | snd_ctl_new1(&snd_emu1010_internal_clock, emu)); | ||
1845 | if (err < 0) | 2065 | if (err < 0) |
1846 | return err; | 2066 | return err; |
1847 | } | 2067 | } |
diff --git a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c index 04c7cf703531..c4d76d16661e 100644 --- a/sound/pci/emu10k1/emumpu401.c +++ b/sound/pci/emu10k1/emumpu401.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/time.h> | 22 | #include <linux/time.h> |
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <sound/core.h> | 24 | #include <sound/core.h> |
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 5ce5befc701b..cf9276ddad42 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c | |||
@@ -26,7 +26,6 @@ | |||
26 | * | 26 | * |
27 | */ | 27 | */ |
28 | 28 | ||
29 | #include <sound/driver.h> | ||
30 | #include <linux/pci.h> | 29 | #include <linux/pci.h> |
31 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
32 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
@@ -358,7 +357,7 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, | |||
358 | snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]); | 357 | snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]); |
359 | snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24)); | 358 | snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24)); |
360 | snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_amount[2] << 24)); | 359 | snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_amount[2] << 24)); |
361 | if (emu->card_capabilities->emu1010) | 360 | if (emu->card_capabilities->emu_model) |
362 | pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ | 361 | pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ |
363 | else | 362 | else |
364 | pitch_target = emu10k1_calc_pitch_target(runtime->rate); | 363 | pitch_target = emu10k1_calc_pitch_target(runtime->rate); |
@@ -701,7 +700,7 @@ static void snd_emu10k1_playback_trigger_voice(struct snd_emu10k1 *emu, struct s | |||
701 | voice = evoice->number; | 700 | voice = evoice->number; |
702 | 701 | ||
703 | pitch = snd_emu10k1_rate_to_pitch(runtime->rate) >> 8; | 702 | pitch = snd_emu10k1_rate_to_pitch(runtime->rate) >> 8; |
704 | if (emu->card_capabilities->emu1010) | 703 | if (emu->card_capabilities->emu_model) |
705 | pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ | 704 | pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ |
706 | else | 705 | else |
707 | pitch_target = emu10k1_calc_pitch_target(runtime->rate); | 706 | pitch_target = emu10k1_calc_pitch_target(runtime->rate); |
@@ -1232,7 +1231,7 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream) | |||
1232 | runtime->hw.rates = SNDRV_PCM_RATE_48000; | 1231 | runtime->hw.rates = SNDRV_PCM_RATE_48000; |
1233 | runtime->hw.rate_min = runtime->hw.rate_max = 48000; | 1232 | runtime->hw.rate_min = runtime->hw.rate_max = 48000; |
1234 | spin_lock_irq(&emu->reg_lock); | 1233 | spin_lock_irq(&emu->reg_lock); |
1235 | if (emu->card_capabilities->emu1010) { | 1234 | if (emu->card_capabilities->emu_model) { |
1236 | /* Nb. of channels has been increased to 16 */ | 1235 | /* Nb. of channels has been increased to 16 */ |
1237 | /* TODO | 1236 | /* TODO |
1238 | * SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | 1237 | * SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE |
@@ -1791,7 +1790,7 @@ int __devinit snd_emu10k1_pcm_efx(struct snd_emu10k1 * emu, int device, struct s | |||
1791 | /* emu->efx_voices_mask[0] = FXWC_DEFAULTROUTE_C | FXWC_DEFAULTROUTE_A; */ | 1790 | /* emu->efx_voices_mask[0] = FXWC_DEFAULTROUTE_C | FXWC_DEFAULTROUTE_A; */ |
1792 | if (emu->audigy) { | 1791 | if (emu->audigy) { |
1793 | emu->efx_voices_mask[0] = 0; | 1792 | emu->efx_voices_mask[0] = 0; |
1794 | if (emu->card_capabilities->emu1010) | 1793 | if (emu->card_capabilities->emu_model) |
1795 | /* Pavel Hofman - 32 voices will be used for | 1794 | /* Pavel Hofman - 32 voices will be used for |
1796 | * capture (write mode) - | 1795 | * capture (write mode) - |
1797 | * each bit = corresponding voice | 1796 | * each bit = corresponding voice |
diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index c3fb10e81c9e..f3caa3f890c6 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c | |||
@@ -28,7 +28,6 @@ | |||
28 | * | 28 | * |
29 | */ | 29 | */ |
30 | 30 | ||
31 | #include <sound/driver.h> | ||
32 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
33 | #include <linux/init.h> | 32 | #include <linux/init.h> |
34 | #include <sound/core.h> | 33 | #include <sound/core.h> |
@@ -245,7 +244,7 @@ static void snd_emu10k1_proc_spdif_read(struct snd_info_entry *entry, | |||
245 | unsigned long flags; | 244 | unsigned long flags; |
246 | u32 rate; | 245 | u32 rate; |
247 | 246 | ||
248 | if (emu->card_capabilities->emu1010) { | 247 | if (emu->card_capabilities->emu_model) { |
249 | spin_lock_irqsave(&emu->emu_lock, flags); | 248 | spin_lock_irqsave(&emu->emu_lock, flags); |
250 | snd_emu1010_fpga_read(emu, 0x38, &value); | 249 | snd_emu1010_fpga_read(emu, 0x38, &value); |
251 | spin_unlock_irqrestore(&emu->emu_lock, flags); | 250 | spin_unlock_irqrestore(&emu->emu_lock, flags); |
@@ -585,7 +584,7 @@ int __devinit snd_emu10k1_proc_init(struct snd_emu10k1 * emu) | |||
585 | { | 584 | { |
586 | struct snd_info_entry *entry; | 585 | struct snd_info_entry *entry; |
587 | #ifdef CONFIG_SND_DEBUG | 586 | #ifdef CONFIG_SND_DEBUG |
588 | if (emu->card_capabilities->emu1010) { | 587 | if (emu->card_capabilities->emu_model) { |
589 | if (! snd_card_proc_new(emu->card, "emu1010_regs", &entry)) | 588 | if (! snd_card_proc_new(emu->card, "emu1010_regs", &entry)) |
590 | snd_info_set_text_ops(entry, emu, snd_emu_proc_emu1010_reg_read); | 589 | snd_info_set_text_ops(entry, emu, snd_emu_proc_emu1010_reg_read); |
591 | } | 590 | } |
diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index 6702c15fefa3..b5a802bdeb7c 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c | |||
@@ -25,7 +25,6 @@ | |||
25 | * | 25 | * |
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include <sound/driver.h> | ||
29 | #include <linux/time.h> | 28 | #include <linux/time.h> |
30 | #include <sound/core.h> | 29 | #include <sound/core.h> |
31 | #include <sound/emu10k1.h> | 30 | #include <sound/emu10k1.h> |
@@ -71,6 +70,11 @@ void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned i | |||
71 | unsigned long flags; | 70 | unsigned long flags; |
72 | unsigned int mask; | 71 | unsigned int mask; |
73 | 72 | ||
73 | if (!emu) { | ||
74 | snd_printk(KERN_ERR "ptr_write: emu is null!\n"); | ||
75 | dump_stack(); | ||
76 | return; | ||
77 | } | ||
74 | mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK; | 78 | mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK; |
75 | regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK); | 79 | regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK); |
76 | 80 | ||
@@ -135,15 +139,23 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, | |||
135 | unsigned int reset, set; | 139 | unsigned int reset, set; |
136 | unsigned int reg, tmp; | 140 | unsigned int reg, tmp; |
137 | int n, result; | 141 | int n, result; |
142 | int err = 0; | ||
143 | |||
144 | /* This function is not re-entrant, so protect against it. */ | ||
145 | spin_lock(&emu->spi_lock); | ||
138 | if (emu->card_capabilities->ca0108_chip) | 146 | if (emu->card_capabilities->ca0108_chip) |
139 | reg = 0x3c; /* PTR20, reg 0x3c */ | 147 | reg = 0x3c; /* PTR20, reg 0x3c */ |
140 | else { | 148 | else { |
141 | /* For other chip types the SPI register | 149 | /* For other chip types the SPI register |
142 | * is currently unknown. */ | 150 | * is currently unknown. */ |
143 | return 1; | 151 | err = 1; |
152 | goto spi_write_exit; | ||
153 | } | ||
154 | if (data > 0xffff) { | ||
155 | /* Only 16bit values allowed */ | ||
156 | err = 1; | ||
157 | goto spi_write_exit; | ||
144 | } | 158 | } |
145 | if (data > 0xffff) /* Only 16bit values allowed */ | ||
146 | return 1; | ||
147 | 159 | ||
148 | tmp = snd_emu10k1_ptr20_read(emu, reg, 0); | 160 | tmp = snd_emu10k1_ptr20_read(emu, reg, 0); |
149 | reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */ | 161 | reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */ |
@@ -161,11 +173,17 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, | |||
161 | break; | 173 | break; |
162 | } | 174 | } |
163 | } | 175 | } |
164 | if (result) /* Timed out */ | 176 | if (result) { |
165 | return 1; | 177 | /* Timed out */ |
178 | err = 1; | ||
179 | goto spi_write_exit; | ||
180 | } | ||
166 | snd_emu10k1_ptr20_write(emu, reg, 0, reset | data); | 181 | snd_emu10k1_ptr20_write(emu, reg, 0, reset | data); |
167 | tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */ | 182 | tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */ |
168 | return 0; | 183 | err = 0; |
184 | spi_write_exit: | ||
185 | spin_unlock(&emu->spi_lock); | ||
186 | return err; | ||
169 | } | 187 | } |
170 | 188 | ||
171 | /* The ADC does not support i2c read, so only write is implemented */ | 189 | /* The ADC does not support i2c read, so only write is implemented */ |
@@ -177,15 +195,17 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, | |||
177 | int timeout = 0; | 195 | int timeout = 0; |
178 | int status; | 196 | int status; |
179 | int retry; | 197 | int retry; |
198 | int err = 0; | ||
199 | |||
180 | if ((reg > 0x7f) || (value > 0x1ff)) { | 200 | if ((reg > 0x7f) || (value > 0x1ff)) { |
181 | snd_printk(KERN_ERR "i2c_write: invalid values.\n"); | 201 | snd_printk(KERN_ERR "i2c_write: invalid values.\n"); |
182 | return -EINVAL; | 202 | return -EINVAL; |
183 | } | 203 | } |
184 | 204 | ||
205 | /* This function is not re-entrant, so protect against it. */ | ||
206 | spin_lock(&emu->i2c_lock); | ||
207 | |||
185 | tmp = reg << 25 | value << 16; | 208 | tmp = reg << 25 | value << 16; |
186 | // snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value); | ||
187 | /* Not sure what this I2C channel controls. */ | ||
188 | /* snd_emu10k1_ptr_write(emu, P17V_I2C_0, 0, tmp); */ | ||
189 | 209 | ||
190 | /* This controls the I2C connected to the WM8775 ADC Codec */ | 210 | /* This controls the I2C connected to the WM8775 ADC Codec */ |
191 | snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp); | 211 | snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp); |
@@ -193,17 +213,14 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, | |||
193 | 213 | ||
194 | for (retry = 0; retry < 10; retry++) { | 214 | for (retry = 0; retry < 10; retry++) { |
195 | /* Send the data to i2c */ | 215 | /* Send the data to i2c */ |
196 | //tmp = snd_emu10k1_ptr_read(emu, P17V_I2C_ADDR, 0); | ||
197 | //tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK); | ||
198 | tmp = 0; | 216 | tmp = 0; |
199 | tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD); | 217 | tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD); |
200 | snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp); | 218 | snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp); |
201 | 219 | ||
202 | /* Wait till the transaction ends */ | 220 | /* Wait till the transaction ends */ |
203 | while (1) { | 221 | while (1) { |
204 | udelay(10); | 222 | mdelay(1); |
205 | status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0); | 223 | status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0); |
206 | // snd_printk("I2C:status=0x%x\n", status); | ||
207 | timeout++; | 224 | timeout++; |
208 | if ((status & I2C_A_ADC_START) == 0) | 225 | if ((status & I2C_A_ADC_START) == 0) |
209 | break; | 226 | break; |
@@ -220,19 +237,26 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, | |||
220 | 237 | ||
221 | if (retry == 10) { | 238 | if (retry == 10) { |
222 | snd_printk(KERN_ERR "Writing to ADC failed!\n"); | 239 | snd_printk(KERN_ERR "Writing to ADC failed!\n"); |
223 | return -EINVAL; | 240 | snd_printk(KERN_ERR "status=0x%x, reg=%d, value=%d\n", |
241 | status, reg, value); | ||
242 | /* dump_stack(); */ | ||
243 | err = -EINVAL; | ||
224 | } | 244 | } |
225 | 245 | ||
226 | return 0; | 246 | spin_unlock(&emu->i2c_lock); |
247 | return err; | ||
227 | } | 248 | } |
228 | 249 | ||
229 | int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value) | 250 | int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value) |
230 | { | 251 | { |
252 | unsigned long flags; | ||
253 | |||
231 | if (reg > 0x3f) | 254 | if (reg > 0x3f) |
232 | return 1; | 255 | return 1; |
233 | reg += 0x40; /* 0x40 upwards are registers. */ | 256 | reg += 0x40; /* 0x40 upwards are registers. */ |
234 | if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */ | 257 | if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */ |
235 | return 1; | 258 | return 1; |
259 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
236 | outl(reg, emu->port + A_IOCFG); | 260 | outl(reg, emu->port + A_IOCFG); |
237 | udelay(10); | 261 | udelay(10); |
238 | outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ | 262 | outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ |
@@ -240,20 +264,24 @@ int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value) | |||
240 | outl(value, emu->port + A_IOCFG); | 264 | outl(value, emu->port + A_IOCFG); |
241 | udelay(10); | 265 | udelay(10); |
242 | outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ | 266 | outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ |
267 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
243 | 268 | ||
244 | return 0; | 269 | return 0; |
245 | } | 270 | } |
246 | 271 | ||
247 | int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value) | 272 | int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value) |
248 | { | 273 | { |
274 | unsigned long flags; | ||
249 | if (reg > 0x3f) | 275 | if (reg > 0x3f) |
250 | return 1; | 276 | return 1; |
251 | reg += 0x40; /* 0x40 upwards are registers. */ | 277 | reg += 0x40; /* 0x40 upwards are registers. */ |
278 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
252 | outl(reg, emu->port + A_IOCFG); | 279 | outl(reg, emu->port + A_IOCFG); |
253 | udelay(10); | 280 | udelay(10); |
254 | outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ | 281 | outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ |
255 | udelay(10); | 282 | udelay(10); |
256 | *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f); | 283 | *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f); |
284 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
257 | 285 | ||
258 | return 0; | 286 | return 0; |
259 | } | 287 | } |
diff --git a/sound/pci/emu10k1/irq.c b/sound/pci/emu10k1/irq.c index 3c114b45e0b2..30bfed6f8339 100644 --- a/sound/pci/emu10k1/irq.c +++ b/sound/pci/emu10k1/irq.c | |||
@@ -25,7 +25,6 @@ | |||
25 | * | 25 | * |
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include <sound/driver.h> | ||
29 | #include <linux/time.h> | 28 | #include <linux/time.h> |
30 | #include <sound/core.h> | 29 | #include <sound/core.h> |
31 | #include <sound/emu10k1.h> | 30 | #include <sound/emu10k1.h> |
@@ -35,9 +34,10 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id) | |||
35 | struct snd_emu10k1 *emu = dev_id; | 34 | struct snd_emu10k1 *emu = dev_id; |
36 | unsigned int status, status2, orig_status, orig_status2; | 35 | unsigned int status, status2, orig_status, orig_status2; |
37 | int handled = 0; | 36 | int handled = 0; |
37 | int timeout = 0; | ||
38 | 38 | ||
39 | while ((status = inl(emu->port + IPR)) != 0) { | 39 | while (((status = inl(emu->port + IPR)) != 0) && (timeout < 1000)) { |
40 | //snd_printk(KERN_INFO "emu10k1 irq - status = 0x%x\n", status); | 40 | timeout++; |
41 | orig_status = status; | 41 | orig_status = status; |
42 | handled = 1; | 42 | handled = 1; |
43 | if ((status & 0xffffffff) == 0xffffffff) { | 43 | if ((status & 0xffffffff) == 0xffffffff) { |
@@ -201,5 +201,8 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id) | |||
201 | } | 201 | } |
202 | outl(orig_status, emu->port + IPR); /* ack all */ | 202 | outl(orig_status, emu->port + IPR); /* ack all */ |
203 | } | 203 | } |
204 | if (timeout == 1000) | ||
205 | snd_printk(KERN_INFO "emu10k1 irq routine failure\n"); | ||
206 | |||
204 | return IRQ_RETVAL(handled); | 207 | return IRQ_RETVAL(handled); |
205 | } | 208 | } |
diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index 48097c6bb15c..916c1dbcd53c 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/pci.h> | 24 | #include <linux/pci.h> |
26 | #include <linux/time.h> | 25 | #include <linux/time.h> |
27 | #include <linux/mutex.h> | 26 | #include <linux/mutex.h> |
diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 9fd3135f3118..749a21b6bd06 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c | |||
@@ -87,7 +87,6 @@ | |||
87 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 87 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
88 | * | 88 | * |
89 | */ | 89 | */ |
90 | #include <sound/driver.h> | ||
91 | #include <linux/delay.h> | 90 | #include <linux/delay.h> |
92 | #include <linux/init.h> | 91 | #include <linux/init.h> |
93 | #include <linux/interrupt.h> | 92 | #include <linux/interrupt.h> |
diff --git a/sound/pci/emu10k1/timer.c b/sound/pci/emu10k1/timer.c index 6295b2dca785..72321e946ccc 100644 --- a/sound/pci/emu10k1/timer.c +++ b/sound/pci/emu10k1/timer.c | |||
@@ -25,7 +25,6 @@ | |||
25 | * | 25 | * |
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include <sound/driver.h> | ||
29 | #include <linux/time.h> | 28 | #include <linux/time.h> |
30 | #include <sound/core.h> | 29 | #include <sound/core.h> |
31 | #include <sound/emu10k1.h> | 30 | #include <sound/emu10k1.h> |
diff --git a/sound/pci/emu10k1/voice.c b/sound/pci/emu10k1/voice.c index 04fa8492abb0..958cb2a65a4e 100644 --- a/sound/pci/emu10k1/voice.c +++ b/sound/pci/emu10k1/voice.c | |||
@@ -28,7 +28,6 @@ | |||
28 | * | 28 | * |
29 | */ | 29 | */ |
30 | 30 | ||
31 | #include <sound/driver.h> | ||
32 | #include <linux/time.h> | 31 | #include <linux/time.h> |
33 | #include <sound/core.h> | 32 | #include <sound/core.h> |
34 | #include <sound/emu10k1.h> | 33 | #include <sound/emu10k1.h> |
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index b958f869cb13..72d85a5ae6a0 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c | |||
@@ -26,7 +26,6 @@ | |||
26 | * by Kurt J. Bosch | 26 | * by Kurt J. Bosch |
27 | */ | 27 | */ |
28 | 28 | ||
29 | #include <sound/driver.h> | ||
30 | #include <asm/io.h> | 29 | #include <asm/io.h> |
31 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
32 | #include <linux/interrupt.h> | 31 | #include <linux/interrupt.h> |
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index fb25abe68a02..1a314fa99c45 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c | |||
@@ -47,7 +47,6 @@ | |||
47 | */ | 47 | */ |
48 | 48 | ||
49 | 49 | ||
50 | #include <sound/driver.h> | ||
51 | #include <linux/init.h> | 50 | #include <linux/init.h> |
52 | #include <linux/interrupt.h> | 51 | #include <linux/interrupt.h> |
53 | #include <linux/pci.h> | 52 | #include <linux/pci.h> |
@@ -227,6 +226,7 @@ struct es1938 { | |||
227 | unsigned int dma2_start; | 226 | unsigned int dma2_start; |
228 | unsigned int dma1_shift; | 227 | unsigned int dma1_shift; |
229 | unsigned int dma2_shift; | 228 | unsigned int dma2_shift; |
229 | unsigned int last_capture_dmaaddr; | ||
230 | unsigned int active; | 230 | unsigned int active; |
231 | 231 | ||
232 | spinlock_t reg_lock; | 232 | spinlock_t reg_lock; |
@@ -529,6 +529,7 @@ static void snd_es1938_capture_setdma(struct es1938 *chip) | |||
529 | outb(1, SLDM_REG(chip, DMAMASK)); | 529 | outb(1, SLDM_REG(chip, DMAMASK)); |
530 | outb(0x14, SLDM_REG(chip, DMAMODE)); | 530 | outb(0x14, SLDM_REG(chip, DMAMODE)); |
531 | outl(chip->dma1_start, SLDM_REG(chip, DMAADDR)); | 531 | outl(chip->dma1_start, SLDM_REG(chip, DMAADDR)); |
532 | chip->last_capture_dmaaddr = chip->dma1_start; | ||
532 | outw(chip->dma1_size - 1, SLDM_REG(chip, DMACOUNT)); | 533 | outw(chip->dma1_size - 1, SLDM_REG(chip, DMACOUNT)); |
533 | /* 3. Unmask DMA */ | 534 | /* 3. Unmask DMA */ |
534 | outb(0, SLDM_REG(chip, DMAMASK)); | 535 | outb(0, SLDM_REG(chip, DMAMASK)); |
@@ -770,19 +771,40 @@ static int snd_es1938_playback_prepare(struct snd_pcm_substream *substream) | |||
770 | return -EINVAL; | 771 | return -EINVAL; |
771 | } | 772 | } |
772 | 773 | ||
774 | /* during the incrementing of dma counters the DMA register reads sometimes | ||
775 | returns garbage. To ensure a valid hw pointer, the following checks which | ||
776 | should be very unlikely to fail are used: | ||
777 | - is the current DMA address in the valid DMA range ? | ||
778 | - is the sum of DMA address and DMA counter pointing to the last DMA byte ? | ||
779 | One can argue this could differ by one byte depending on which register is | ||
780 | updated first, so the implementation below allows for that. | ||
781 | */ | ||
773 | static snd_pcm_uframes_t snd_es1938_capture_pointer(struct snd_pcm_substream *substream) | 782 | static snd_pcm_uframes_t snd_es1938_capture_pointer(struct snd_pcm_substream *substream) |
774 | { | 783 | { |
775 | struct es1938 *chip = snd_pcm_substream_chip(substream); | 784 | struct es1938 *chip = snd_pcm_substream_chip(substream); |
776 | size_t ptr; | 785 | size_t ptr; |
786 | #if 0 | ||
777 | size_t old, new; | 787 | size_t old, new; |
778 | #if 1 | ||
779 | /* This stuff is *needed*, don't ask why - AB */ | 788 | /* This stuff is *needed*, don't ask why - AB */ |
780 | old = inw(SLDM_REG(chip, DMACOUNT)); | 789 | old = inw(SLDM_REG(chip, DMACOUNT)); |
781 | while ((new = inw(SLDM_REG(chip, DMACOUNT))) != old) | 790 | while ((new = inw(SLDM_REG(chip, DMACOUNT))) != old) |
782 | old = new; | 791 | old = new; |
783 | ptr = chip->dma1_size - 1 - new; | 792 | ptr = chip->dma1_size - 1 - new; |
784 | #else | 793 | #else |
785 | ptr = inl(SLDM_REG(chip, DMAADDR)) - chip->dma1_start; | 794 | size_t count; |
795 | unsigned int diff; | ||
796 | |||
797 | ptr = inl(SLDM_REG(chip, DMAADDR)); | ||
798 | count = inw(SLDM_REG(chip, DMACOUNT)); | ||
799 | diff = chip->dma1_start + chip->dma1_size - ptr - count; | ||
800 | |||
801 | if (diff > 3 || ptr < chip->dma1_start | ||
802 | || ptr >= chip->dma1_start+chip->dma1_size) | ||
803 | ptr = chip->last_capture_dmaaddr; /* bad, use last saved */ | ||
804 | else | ||
805 | chip->last_capture_dmaaddr = ptr; /* good, remember it */ | ||
806 | |||
807 | ptr -= chip->dma1_start; | ||
786 | #endif | 808 | #endif |
787 | return ptr >> chip->dma1_shift; | 809 | return ptr >> chip->dma1_shift; |
788 | } | 810 | } |
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index d69b11d1f993..25ccfce45759 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c | |||
@@ -94,7 +94,6 @@ | |||
94 | * places. | 94 | * places. |
95 | */ | 95 | */ |
96 | 96 | ||
97 | #include <sound/driver.h> | ||
98 | #include <asm/io.h> | 97 | #include <asm/io.h> |
99 | #include <linux/delay.h> | 98 | #include <linux/delay.h> |
100 | #include <linux/interrupt.h> | 99 | #include <linux/interrupt.h> |
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 9939109f05a2..4c300e6149fc 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
@@ -979,6 +978,27 @@ static unsigned int snd_fm801_tea575x_64pcr_read(struct snd_tea575x *tea) | |||
979 | return val; | 978 | return val; |
980 | } | 979 | } |
981 | 980 | ||
981 | static void snd_fm801_tea575x_64pcr_mute(struct snd_tea575x *tea, | ||
982 | unsigned int mute) | ||
983 | { | ||
984 | struct fm801 *chip = tea->private_data; | ||
985 | unsigned short reg; | ||
986 | |||
987 | spin_lock_irq(&chip->reg_lock); | ||
988 | |||
989 | reg = inw(FM801_REG(chip, GPIO_CTRL)); | ||
990 | if (mute) | ||
991 | /* 0xf800 (mute) */ | ||
992 | reg &= ~FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE); | ||
993 | else | ||
994 | /* 0xf802 (unmute) */ | ||
995 | reg |= FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE); | ||
996 | outw(reg, FM801_REG(chip, GPIO_CTRL)); | ||
997 | udelay(1); | ||
998 | |||
999 | spin_unlock_irq(&chip->reg_lock); | ||
1000 | } | ||
1001 | |||
982 | static struct snd_tea575x_ops snd_fm801_tea_ops[3] = { | 1002 | static struct snd_tea575x_ops snd_fm801_tea_ops[3] = { |
983 | { | 1003 | { |
984 | /* 1 = MediaForte 256-PCS */ | 1004 | /* 1 = MediaForte 256-PCS */ |
@@ -994,6 +1014,7 @@ static struct snd_tea575x_ops snd_fm801_tea_ops[3] = { | |||
994 | /* 3 = MediaForte 64-PCR */ | 1014 | /* 3 = MediaForte 64-PCR */ |
995 | .write = snd_fm801_tea575x_64pcr_write, | 1015 | .write = snd_fm801_tea575x_64pcr_write, |
996 | .read = snd_fm801_tea575x_64pcr_read, | 1016 | .read = snd_fm801_tea575x_64pcr_read, |
1017 | .mute = snd_fm801_tea575x_64pcr_mute, | ||
997 | } | 1018 | } |
998 | }; | 1019 | }; |
999 | #endif | 1020 | #endif |
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index ab0c726d648e..9e0d8a1268aa 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile | |||
@@ -2,7 +2,7 @@ snd-hda-intel-y := hda_intel.o | |||
2 | # since snd-hda-intel is the only driver using hda-codec, | 2 | # since snd-hda-intel is the only driver using hda-codec, |
3 | # merge it into a single module although it was originally | 3 | # merge it into a single module although it was originally |
4 | # designed to be individual modules | 4 | # designed to be individual modules |
5 | snd-hda-intel-y += hda_codec.o | 5 | snd-hda-intel-y += hda_codec.o vmaster.o |
6 | snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o | 6 | snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o |
7 | snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o | 7 | snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o |
8 | snd-hda-intel-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o | 8 | snd-hda-intel-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o |
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 8cbe3bf1e317..26812dc2b7f2 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
@@ -55,6 +54,7 @@ static struct hda_vendor_id hda_vendor_ids[] = { | |||
55 | { 0x10ec, "Realtek" }, | 54 | { 0x10ec, "Realtek" }, |
56 | { 0x1057, "Motorola" }, | 55 | { 0x1057, "Motorola" }, |
57 | { 0x1106, "VIA" }, | 56 | { 0x1106, "VIA" }, |
57 | { 0x111d, "IDT" }, | ||
58 | { 0x11d4, "Analog Devices" }, | 58 | { 0x11d4, "Analog Devices" }, |
59 | { 0x13f6, "C-Media" }, | 59 | { 0x13f6, "C-Media" }, |
60 | { 0x14f1, "Conexant" }, | 60 | { 0x14f1, "Conexant" }, |
@@ -429,6 +429,10 @@ find_codec_preset(struct hda_codec *codec) | |||
429 | for (tbl = hda_preset_tables; *tbl; tbl++) { | 429 | for (tbl = hda_preset_tables; *tbl; tbl++) { |
430 | for (preset = *tbl; preset->id; preset++) { | 430 | for (preset = *tbl; preset->id; preset++) { |
431 | u32 mask = preset->mask; | 431 | u32 mask = preset->mask; |
432 | if (preset->afg && preset->afg != codec->afg) | ||
433 | continue; | ||
434 | if (preset->mfg && preset->mfg != codec->mfg) | ||
435 | continue; | ||
432 | if (!mask) | 436 | if (!mask) |
433 | mask = ~0; | 437 | mask = ~0; |
434 | if (preset->id == (codec->vendor_id & mask) && | 438 | if (preset->id == (codec->vendor_id & mask) && |
@@ -765,7 +769,7 @@ get_alloc_amp_hash(struct hda_codec *codec, u32 key) | |||
765 | /* | 769 | /* |
766 | * query AMP capabilities for the given widget and direction | 770 | * query AMP capabilities for the given widget and direction |
767 | */ | 771 | */ |
768 | static u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) | 772 | u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) |
769 | { | 773 | { |
770 | struct hda_amp_info *info; | 774 | struct hda_amp_info *info; |
771 | 775 | ||
@@ -933,7 +937,8 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, | |||
933 | caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; | 937 | caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; |
934 | if (!caps) { | 938 | if (!caps) { |
935 | printk(KERN_WARNING "hda_codec: " | 939 | printk(KERN_WARNING "hda_codec: " |
936 | "num_steps = 0 for NID=0x%x\n", nid); | 940 | "num_steps = 0 for NID=0x%x (ctl = %s)\n", nid, |
941 | kcontrol->id.name); | ||
937 | return -EINVAL; | 942 | return -EINVAL; |
938 | } | 943 | } |
939 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 944 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
@@ -1012,6 +1017,66 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, | |||
1012 | return 0; | 1017 | return 0; |
1013 | } | 1018 | } |
1014 | 1019 | ||
1020 | /* | ||
1021 | * set (static) TLV for virtual master volume; recalculated as max 0dB | ||
1022 | */ | ||
1023 | void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, | ||
1024 | unsigned int *tlv) | ||
1025 | { | ||
1026 | u32 caps; | ||
1027 | int nums, step; | ||
1028 | |||
1029 | caps = query_amp_caps(codec, nid, dir); | ||
1030 | nums = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; | ||
1031 | step = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT; | ||
1032 | step = (step + 1) * 25; | ||
1033 | tlv[0] = SNDRV_CTL_TLVT_DB_SCALE; | ||
1034 | tlv[1] = 2 * sizeof(unsigned int); | ||
1035 | tlv[2] = -nums * step; | ||
1036 | tlv[3] = step; | ||
1037 | } | ||
1038 | |||
1039 | /* find a mixer control element with the given name */ | ||
1040 | struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, | ||
1041 | const char *name) | ||
1042 | { | ||
1043 | struct snd_ctl_elem_id id; | ||
1044 | memset(&id, 0, sizeof(id)); | ||
1045 | id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
1046 | strcpy(id.name, name); | ||
1047 | return snd_ctl_find_id(codec->bus->card, &id); | ||
1048 | } | ||
1049 | |||
1050 | /* create a virtual master control and add slaves */ | ||
1051 | int snd_hda_add_vmaster(struct hda_codec *codec, char *name, | ||
1052 | unsigned int *tlv, const char **slaves) | ||
1053 | { | ||
1054 | struct snd_kcontrol *kctl; | ||
1055 | const char **s; | ||
1056 | int err; | ||
1057 | |||
1058 | kctl = snd_ctl_make_virtual_master(name, tlv); | ||
1059 | if (!kctl) | ||
1060 | return -ENOMEM; | ||
1061 | err = snd_ctl_add(codec->bus->card, kctl); | ||
1062 | if (err < 0) | ||
1063 | return err; | ||
1064 | |||
1065 | for (s = slaves; *s; s++) { | ||
1066 | struct snd_kcontrol *sctl; | ||
1067 | |||
1068 | sctl = snd_hda_find_mixer_ctl(codec, *s); | ||
1069 | if (!sctl) { | ||
1070 | snd_printdd("Cannot find slave %s, skipped\n", *s); | ||
1071 | continue; | ||
1072 | } | ||
1073 | err = snd_ctl_add_slave(kctl, sctl); | ||
1074 | if (err < 0) | ||
1075 | return err; | ||
1076 | } | ||
1077 | return 0; | ||
1078 | } | ||
1079 | |||
1015 | /* switch */ | 1080 | /* switch */ |
1016 | int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, | 1081 | int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, |
1017 | struct snd_ctl_elem_info *uinfo) | 1082 | struct snd_ctl_elem_info *uinfo) |
@@ -1434,7 +1499,8 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) | |||
1434 | return err; | 1499 | return err; |
1435 | } | 1500 | } |
1436 | codec->spdif_ctls = | 1501 | codec->spdif_ctls = |
1437 | snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT, 0); | 1502 | snd_hda_codec_read(codec, nid, 0, |
1503 | AC_VERB_GET_DIGI_CONVERT_1, 0); | ||
1438 | codec->spdif_status = convert_to_spdif_status(codec->spdif_ctls); | 1504 | codec->spdif_status = convert_to_spdif_status(codec->spdif_ctls); |
1439 | return 0; | 1505 | return 0; |
1440 | } | 1506 | } |
@@ -1481,7 +1547,7 @@ static int snd_hda_spdif_in_status_get(struct snd_kcontrol *kcontrol, | |||
1481 | unsigned short val; | 1547 | unsigned short val; |
1482 | unsigned int sbits; | 1548 | unsigned int sbits; |
1483 | 1549 | ||
1484 | val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT, 0); | 1550 | val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT_1, 0); |
1485 | sbits = convert_to_spdif_status(val); | 1551 | sbits = convert_to_spdif_status(val); |
1486 | ucontrol->value.iec958.status[0] = sbits; | 1552 | ucontrol->value.iec958.status[0] = sbits; |
1487 | ucontrol->value.iec958.status[1] = sbits >> 8; | 1553 | ucontrol->value.iec958.status[1] = sbits >> 8; |
@@ -1532,7 +1598,8 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) | |||
1532 | return err; | 1598 | return err; |
1533 | } | 1599 | } |
1534 | codec->spdif_in_enable = | 1600 | codec->spdif_in_enable = |
1535 | snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT, 0) & | 1601 | snd_hda_codec_read(codec, nid, 0, |
1602 | AC_VERB_GET_DIGI_CONVERT_1, 0) & | ||
1536 | AC_DIG1_ENABLE; | 1603 | AC_DIG1_ENABLE; |
1537 | return 0; | 1604 | return 0; |
1538 | } | 1605 | } |
@@ -1622,6 +1689,7 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, | |||
1622 | 1689 | ||
1623 | snd_hda_codec_write(codec, fg, 0, AC_VERB_SET_POWER_STATE, | 1690 | snd_hda_codec_write(codec, fg, 0, AC_VERB_SET_POWER_STATE, |
1624 | power_state); | 1691 | power_state); |
1692 | msleep(10); /* partial workaround for "azx_get_response timeout" */ | ||
1625 | 1693 | ||
1626 | nid = codec->start_nid; | 1694 | nid = codec->start_nid; |
1627 | for (i = 0; i < codec->num_nodes; i++, nid++) { | 1695 | for (i = 0; i < codec->num_nodes; i++, nid++) { |
@@ -2336,7 +2404,8 @@ int snd_hda_ch_mode_put(struct hda_codec *codec, | |||
2336 | unsigned int mode; | 2404 | unsigned int mode; |
2337 | 2405 | ||
2338 | mode = ucontrol->value.enumerated.item[0]; | 2406 | mode = ucontrol->value.enumerated.item[0]; |
2339 | snd_assert(mode < num_chmodes, return -EINVAL); | 2407 | if (mode >= num_chmodes) |
2408 | return -EINVAL; | ||
2340 | if (*max_channelsp == chmode[mode].channels) | 2409 | if (*max_channelsp == chmode[mode].channels) |
2341 | return 0; | 2410 | return 0; |
2342 | /* change the current channel setting */ | 2411 | /* change the current channel setting */ |
@@ -2602,20 +2671,21 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, | |||
2602 | struct auto_pin_cfg *cfg, | 2671 | struct auto_pin_cfg *cfg, |
2603 | hda_nid_t *ignore_nids) | 2672 | hda_nid_t *ignore_nids) |
2604 | { | 2673 | { |
2605 | hda_nid_t nid, nid_start; | 2674 | hda_nid_t nid, end_nid; |
2606 | int nodes; | ||
2607 | short seq, assoc_line_out, assoc_speaker; | 2675 | short seq, assoc_line_out, assoc_speaker; |
2608 | short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)]; | 2676 | short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)]; |
2609 | short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)]; | 2677 | short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)]; |
2678 | short sequences_hp[ARRAY_SIZE(cfg->hp_pins)]; | ||
2610 | 2679 | ||
2611 | memset(cfg, 0, sizeof(*cfg)); | 2680 | memset(cfg, 0, sizeof(*cfg)); |
2612 | 2681 | ||
2613 | memset(sequences_line_out, 0, sizeof(sequences_line_out)); | 2682 | memset(sequences_line_out, 0, sizeof(sequences_line_out)); |
2614 | memset(sequences_speaker, 0, sizeof(sequences_speaker)); | 2683 | memset(sequences_speaker, 0, sizeof(sequences_speaker)); |
2684 | memset(sequences_hp, 0, sizeof(sequences_hp)); | ||
2615 | assoc_line_out = assoc_speaker = 0; | 2685 | assoc_line_out = assoc_speaker = 0; |
2616 | 2686 | ||
2617 | nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start); | 2687 | end_nid = codec->start_nid + codec->num_nodes; |
2618 | for (nid = nid_start; nid < nodes + nid_start; nid++) { | 2688 | for (nid = codec->start_nid; nid < end_nid; nid++) { |
2619 | unsigned int wid_caps = get_wcaps(codec, nid); | 2689 | unsigned int wid_caps = get_wcaps(codec, nid); |
2620 | unsigned int wid_type = | 2690 | unsigned int wid_type = |
2621 | (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; | 2691 | (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; |
@@ -2638,6 +2708,10 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, | |||
2638 | case AC_JACK_LINE_OUT: | 2708 | case AC_JACK_LINE_OUT: |
2639 | seq = get_defcfg_sequence(def_conf); | 2709 | seq = get_defcfg_sequence(def_conf); |
2640 | assoc = get_defcfg_association(def_conf); | 2710 | assoc = get_defcfg_association(def_conf); |
2711 | |||
2712 | if (!(wid_caps & AC_WCAP_STEREO)) | ||
2713 | if (!cfg->mono_out_pin) | ||
2714 | cfg->mono_out_pin = nid; | ||
2641 | if (!assoc) | 2715 | if (!assoc) |
2642 | continue; | 2716 | continue; |
2643 | if (!assoc_line_out) | 2717 | if (!assoc_line_out) |
@@ -2666,9 +2740,12 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, | |||
2666 | cfg->speaker_outs++; | 2740 | cfg->speaker_outs++; |
2667 | break; | 2741 | break; |
2668 | case AC_JACK_HP_OUT: | 2742 | case AC_JACK_HP_OUT: |
2743 | seq = get_defcfg_sequence(def_conf); | ||
2744 | assoc = get_defcfg_association(def_conf); | ||
2669 | if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins)) | 2745 | if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins)) |
2670 | continue; | 2746 | continue; |
2671 | cfg->hp_pins[cfg->hp_outs] = nid; | 2747 | cfg->hp_pins[cfg->hp_outs] = nid; |
2748 | sequences_hp[cfg->hp_outs] = (assoc << 4) | seq; | ||
2672 | cfg->hp_outs++; | 2749 | cfg->hp_outs++; |
2673 | break; | 2750 | break; |
2674 | case AC_JACK_MIC_IN: { | 2751 | case AC_JACK_MIC_IN: { |
@@ -2712,7 +2789,24 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, | |||
2712 | cfg->line_outs); | 2789 | cfg->line_outs); |
2713 | sort_pins_by_sequence(cfg->speaker_pins, sequences_speaker, | 2790 | sort_pins_by_sequence(cfg->speaker_pins, sequences_speaker, |
2714 | cfg->speaker_outs); | 2791 | cfg->speaker_outs); |
2792 | sort_pins_by_sequence(cfg->hp_pins, sequences_hp, | ||
2793 | cfg->hp_outs); | ||
2715 | 2794 | ||
2795 | /* if we have only one mic, make it AUTO_PIN_MIC */ | ||
2796 | if (!cfg->input_pins[AUTO_PIN_MIC] && | ||
2797 | cfg->input_pins[AUTO_PIN_FRONT_MIC]) { | ||
2798 | cfg->input_pins[AUTO_PIN_MIC] = | ||
2799 | cfg->input_pins[AUTO_PIN_FRONT_MIC]; | ||
2800 | cfg->input_pins[AUTO_PIN_FRONT_MIC] = 0; | ||
2801 | } | ||
2802 | /* ditto for line-in */ | ||
2803 | if (!cfg->input_pins[AUTO_PIN_LINE] && | ||
2804 | cfg->input_pins[AUTO_PIN_FRONT_LINE]) { | ||
2805 | cfg->input_pins[AUTO_PIN_LINE] = | ||
2806 | cfg->input_pins[AUTO_PIN_FRONT_LINE]; | ||
2807 | cfg->input_pins[AUTO_PIN_FRONT_LINE] = 0; | ||
2808 | } | ||
2809 | |||
2716 | /* | 2810 | /* |
2717 | * FIX-UP: if no line-outs are detected, try to use speaker or HP pin | 2811 | * FIX-UP: if no line-outs are detected, try to use speaker or HP pin |
2718 | * as a primary output | 2812 | * as a primary output |
@@ -2766,6 +2860,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, | |||
2766 | cfg->hp_outs, cfg->hp_pins[0], | 2860 | cfg->hp_outs, cfg->hp_pins[0], |
2767 | cfg->hp_pins[1], cfg->hp_pins[2], | 2861 | cfg->hp_pins[1], cfg->hp_pins[2], |
2768 | cfg->hp_pins[3], cfg->hp_pins[4]); | 2862 | cfg->hp_pins[3], cfg->hp_pins[4]); |
2863 | snd_printd(" mono: mono_out=0x%x\n", cfg->mono_out_pin); | ||
2769 | snd_printd(" inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x," | 2864 | snd_printd(" inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x," |
2770 | " cd=0x%x, aux=0x%x\n", | 2865 | " cd=0x%x, aux=0x%x\n", |
2771 | cfg->input_pins[AUTO_PIN_MIC], | 2866 | cfg->input_pins[AUTO_PIN_MIC], |
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 2bce925d84ef..f14871151be9 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h | |||
@@ -77,12 +77,16 @@ enum { | |||
77 | #define AC_VERB_GET_PIN_SENSE 0x0f09 | 77 | #define AC_VERB_GET_PIN_SENSE 0x0f09 |
78 | #define AC_VERB_GET_BEEP_CONTROL 0x0f0a | 78 | #define AC_VERB_GET_BEEP_CONTROL 0x0f0a |
79 | #define AC_VERB_GET_EAPD_BTLENABLE 0x0f0c | 79 | #define AC_VERB_GET_EAPD_BTLENABLE 0x0f0c |
80 | #define AC_VERB_GET_DIGI_CONVERT 0x0f0d | 80 | #define AC_VERB_GET_DIGI_CONVERT_1 0x0f0d |
81 | #define AC_VERB_GET_DIGI_CONVERT_2 0x0f0e | ||
81 | #define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f | 82 | #define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f |
82 | /* f10-f1a: GPIO */ | 83 | /* f10-f1a: GPIO */ |
83 | #define AC_VERB_GET_GPIO_DATA 0x0f15 | 84 | #define AC_VERB_GET_GPIO_DATA 0x0f15 |
84 | #define AC_VERB_GET_GPIO_MASK 0x0f16 | 85 | #define AC_VERB_GET_GPIO_MASK 0x0f16 |
85 | #define AC_VERB_GET_GPIO_DIRECTION 0x0f17 | 86 | #define AC_VERB_GET_GPIO_DIRECTION 0x0f17 |
87 | #define AC_VERB_GET_GPIO_WAKE_MASK 0x0f18 | ||
88 | #define AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK 0x0f19 | ||
89 | #define AC_VERB_GET_GPIO_STICKY_MASK 0x0f1a | ||
86 | #define AC_VERB_GET_CONFIG_DEFAULT 0x0f1c | 90 | #define AC_VERB_GET_CONFIG_DEFAULT 0x0f1c |
87 | /* f20: AFG/MFG */ | 91 | /* f20: AFG/MFG */ |
88 | #define AC_VERB_GET_SUBSYSTEM_ID 0x0f20 | 92 | #define AC_VERB_GET_SUBSYSTEM_ID 0x0f20 |
@@ -110,6 +114,9 @@ enum { | |||
110 | #define AC_VERB_SET_GPIO_DATA 0x715 | 114 | #define AC_VERB_SET_GPIO_DATA 0x715 |
111 | #define AC_VERB_SET_GPIO_MASK 0x716 | 115 | #define AC_VERB_SET_GPIO_MASK 0x716 |
112 | #define AC_VERB_SET_GPIO_DIRECTION 0x717 | 116 | #define AC_VERB_SET_GPIO_DIRECTION 0x717 |
117 | #define AC_VERB_SET_GPIO_WAKE_MASK 0x718 | ||
118 | #define AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK 0x719 | ||
119 | #define AC_VERB_SET_GPIO_STICKY_MASK 0x71a | ||
113 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 0x71c | 120 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 0x71c |
114 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1 0x71d | 121 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1 0x71d |
115 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2 0x71e | 122 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2 0x71e |
@@ -135,6 +142,7 @@ enum { | |||
135 | #define AC_PAR_PROC_CAP 0x10 | 142 | #define AC_PAR_PROC_CAP 0x10 |
136 | #define AC_PAR_GPIO_CAP 0x11 | 143 | #define AC_PAR_GPIO_CAP 0x11 |
137 | #define AC_PAR_AMP_OUT_CAP 0x12 | 144 | #define AC_PAR_AMP_OUT_CAP 0x12 |
145 | #define AC_PAR_VOL_KNB_CAP 0x13 | ||
138 | 146 | ||
139 | /* | 147 | /* |
140 | * AC_VERB_PARAMETERS results (32bit) | 148 | * AC_VERB_PARAMETERS results (32bit) |
@@ -181,6 +189,27 @@ enum { | |||
181 | #define AC_SUPFMT_FLOAT32 (1<<1) | 189 | #define AC_SUPFMT_FLOAT32 (1<<1) |
182 | #define AC_SUPFMT_AC3 (1<<2) | 190 | #define AC_SUPFMT_AC3 (1<<2) |
183 | 191 | ||
192 | /* GP I/O count */ | ||
193 | #define AC_GPIO_IO_COUNT (0xff<<0) | ||
194 | #define AC_GPIO_O_COUNT (0xff<<8) | ||
195 | #define AC_GPIO_O_COUNT_SHIFT 8 | ||
196 | #define AC_GPIO_I_COUNT (0xff<<16) | ||
197 | #define AC_GPIO_I_COUNT_SHIFT 16 | ||
198 | #define AC_GPIO_UNSOLICITED (1<<30) | ||
199 | #define AC_GPIO_WAKE (1<<31) | ||
200 | |||
201 | /* Converter stream, channel */ | ||
202 | #define AC_CONV_CHANNEL (0xf<<0) | ||
203 | #define AC_CONV_STREAM (0xf<<4) | ||
204 | #define AC_CONV_STREAM_SHIFT 4 | ||
205 | |||
206 | /* Input converter SDI select */ | ||
207 | #define AC_SDI_SELECT (0xf<<0) | ||
208 | |||
209 | /* Unsolicited response */ | ||
210 | #define AC_UNSOL_TAG (0x3f<<0) | ||
211 | #define AC_UNSOL_ENABLED (1<<7) | ||
212 | |||
184 | /* Pin widget capabilies */ | 213 | /* Pin widget capabilies */ |
185 | #define AC_PINCAP_IMP_SENSE (1<<0) /* impedance sense capable */ | 214 | #define AC_PINCAP_IMP_SENSE (1<<0) /* impedance sense capable */ |
186 | #define AC_PINCAP_TRIG_REQ (1<<1) /* trigger required */ | 215 | #define AC_PINCAP_TRIG_REQ (1<<1) /* trigger required */ |
@@ -189,6 +218,10 @@ enum { | |||
189 | #define AC_PINCAP_OUT (1<<4) /* output capable */ | 218 | #define AC_PINCAP_OUT (1<<4) /* output capable */ |
190 | #define AC_PINCAP_IN (1<<5) /* input capable */ | 219 | #define AC_PINCAP_IN (1<<5) /* input capable */ |
191 | #define AC_PINCAP_BALANCE (1<<6) /* balanced I/O capable */ | 220 | #define AC_PINCAP_BALANCE (1<<6) /* balanced I/O capable */ |
221 | /* Note: This LR_SWAP pincap is defined in the Realtek ALC883 specification, | ||
222 | * but is marked reserved in the Intel HDA specification. | ||
223 | */ | ||
224 | #define AC_PINCAP_LR_SWAP (1<<7) /* L/R swap */ | ||
192 | #define AC_PINCAP_VREF (0x37<<8) | 225 | #define AC_PINCAP_VREF (0x37<<8) |
193 | #define AC_PINCAP_VREF_SHIFT 8 | 226 | #define AC_PINCAP_VREF_SHIFT 8 |
194 | #define AC_PINCAP_EAPD (1<<16) /* EAPD capable */ | 227 | #define AC_PINCAP_EAPD (1<<16) /* EAPD capable */ |
@@ -222,6 +255,9 @@ enum { | |||
222 | #define AC_PWRST_D3SUP (1<<3) | 255 | #define AC_PWRST_D3SUP (1<<3) |
223 | 256 | ||
224 | /* Power state values */ | 257 | /* Power state values */ |
258 | #define AC_PWRST_SETTING (0xf<<0) | ||
259 | #define AC_PWRST_ACTUAL (0xf<<4) | ||
260 | #define AC_PWRST_ACTUAL_SHIFT 4 | ||
225 | #define AC_PWRST_D0 0x00 | 261 | #define AC_PWRST_D0 0x00 |
226 | #define AC_PWRST_D1 0x01 | 262 | #define AC_PWRST_D1 0x01 |
227 | #define AC_PWRST_D2 0x02 | 263 | #define AC_PWRST_D2 0x02 |
@@ -230,10 +266,11 @@ enum { | |||
230 | /* Processing capabilies */ | 266 | /* Processing capabilies */ |
231 | #define AC_PCAP_BENIGN (1<<0) | 267 | #define AC_PCAP_BENIGN (1<<0) |
232 | #define AC_PCAP_NUM_COEF (0xff<<8) | 268 | #define AC_PCAP_NUM_COEF (0xff<<8) |
269 | #define AC_PCAP_NUM_COEF_SHIFT 8 | ||
233 | 270 | ||
234 | /* Volume knobs capabilities */ | 271 | /* Volume knobs capabilities */ |
235 | #define AC_KNBCAP_NUM_STEPS (0x7f<<0) | 272 | #define AC_KNBCAP_NUM_STEPS (0x7f<<0) |
236 | #define AC_KNBCAP_DELTA (1<<8) | 273 | #define AC_KNBCAP_DELTA (1<<7) |
237 | 274 | ||
238 | /* | 275 | /* |
239 | * Control Parameters | 276 | * Control Parameters |
@@ -266,6 +303,9 @@ enum { | |||
266 | #define AC_DIG1_PROFESSIONAL (1<<6) | 303 | #define AC_DIG1_PROFESSIONAL (1<<6) |
267 | #define AC_DIG1_LEVEL (1<<7) | 304 | #define AC_DIG1_LEVEL (1<<7) |
268 | 305 | ||
306 | /* DIGITAL2 bits */ | ||
307 | #define AC_DIG2_CC (0x7f<<0) | ||
308 | |||
269 | /* Pin widget control - 8bit */ | 309 | /* Pin widget control - 8bit */ |
270 | #define AC_PINCTL_VREFEN (0x7<<0) | 310 | #define AC_PINCTL_VREFEN (0x7<<0) |
271 | #define AC_PINCTL_VREF_HIZ 0 /* Hi-Z */ | 311 | #define AC_PINCTL_VREF_HIZ 0 /* Hi-Z */ |
@@ -280,12 +320,22 @@ enum { | |||
280 | /* Unsolicited response - 8bit */ | 320 | /* Unsolicited response - 8bit */ |
281 | #define AC_USRSP_EN (1<<7) | 321 | #define AC_USRSP_EN (1<<7) |
282 | 322 | ||
323 | /* Pin sense - 32bit */ | ||
324 | #define AC_PINSENSE_IMPEDANCE_MASK (0x7fffffff) | ||
325 | #define AC_PINSENSE_PRESENCE (1<<31) | ||
326 | |||
327 | /* EAPD/BTL enable - 32bit */ | ||
328 | #define AC_EAPDBTL_BALANCED (1<<0) | ||
329 | #define AC_EAPDBTL_EAPD (1<<1) | ||
330 | #define AC_EAPDBTL_LR_SWAP (1<<2) | ||
331 | |||
283 | /* configuration default - 32bit */ | 332 | /* configuration default - 32bit */ |
284 | #define AC_DEFCFG_SEQUENCE (0xf<<0) | 333 | #define AC_DEFCFG_SEQUENCE (0xf<<0) |
285 | #define AC_DEFCFG_DEF_ASSOC (0xf<<4) | 334 | #define AC_DEFCFG_DEF_ASSOC (0xf<<4) |
286 | #define AC_DEFCFG_ASSOC_SHIFT 4 | 335 | #define AC_DEFCFG_ASSOC_SHIFT 4 |
287 | #define AC_DEFCFG_MISC (0xf<<8) | 336 | #define AC_DEFCFG_MISC (0xf<<8) |
288 | #define AC_DEFCFG_MISC_SHIFT 8 | 337 | #define AC_DEFCFG_MISC_SHIFT 8 |
338 | #define AC_DEFCFG_MISC_NO_PRESENCE (1<<0) | ||
289 | #define AC_DEFCFG_COLOR (0xf<<12) | 339 | #define AC_DEFCFG_COLOR (0xf<<12) |
290 | #define AC_DEFCFG_COLOR_SHIFT 12 | 340 | #define AC_DEFCFG_COLOR_SHIFT 12 |
291 | #define AC_DEFCFG_CONN_TYPE (0xf<<16) | 341 | #define AC_DEFCFG_CONN_TYPE (0xf<<16) |
@@ -417,7 +467,7 @@ struct hda_bus_ops { | |||
417 | /* free the private data */ | 467 | /* free the private data */ |
418 | void (*private_free)(struct hda_bus *); | 468 | void (*private_free)(struct hda_bus *); |
419 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 469 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
420 | /* notify power-up/down from codec to contoller */ | 470 | /* notify power-up/down from codec to controller */ |
421 | void (*pm_notify)(struct hda_codec *codec); | 471 | void (*pm_notify)(struct hda_codec *codec); |
422 | #endif | 472 | #endif |
423 | }; | 473 | }; |
@@ -456,6 +506,9 @@ struct hda_bus { | |||
456 | struct hda_bus_unsolicited *unsol; | 506 | struct hda_bus_unsolicited *unsol; |
457 | 507 | ||
458 | struct snd_info_entry *proc; | 508 | struct snd_info_entry *proc; |
509 | |||
510 | /* misc op flags */ | ||
511 | unsigned int needs_damn_long_delay :1; | ||
459 | }; | 512 | }; |
460 | 513 | ||
461 | /* | 514 | /* |
@@ -470,6 +523,7 @@ struct hda_codec_preset { | |||
470 | unsigned int subs; | 523 | unsigned int subs; |
471 | unsigned int subs_mask; | 524 | unsigned int subs_mask; |
472 | unsigned int rev; | 525 | unsigned int rev; |
526 | hda_nid_t afg, mfg; | ||
473 | const char *name; | 527 | const char *name; |
474 | int (*patch)(struct hda_codec *codec); | 528 | int (*patch)(struct hda_codec *codec); |
475 | }; | 529 | }; |
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index c957eb58de5c..f9de7c467c25 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
26 | #include <sound/core.h> | 25 | #include <sound/core.h> |
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index bafb7b01f5a1..2177d9af5334 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c | |||
@@ -18,7 +18,6 @@ | |||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <sound/driver.h> | ||
22 | #include <linux/init.h> | 21 | #include <linux/init.h> |
23 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
24 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 3fa0f9704909..56f8a3050751 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -34,7 +34,6 @@ | |||
34 | * | 34 | * |
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include <sound/driver.h> | ||
38 | #include <asm/io.h> | 37 | #include <asm/io.h> |
39 | #include <linux/delay.h> | 38 | #include <linux/delay.h> |
40 | #include <linux/interrupt.h> | 39 | #include <linux/interrupt.h> |
@@ -50,29 +49,32 @@ | |||
50 | #include "hda_codec.h" | 49 | #include "hda_codec.h" |
51 | 50 | ||
52 | 51 | ||
53 | static int index = SNDRV_DEFAULT_IDX1; | 52 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; |
54 | static char *id = SNDRV_DEFAULT_STR1; | 53 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; |
55 | static char *model; | 54 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; |
56 | static int position_fix; | 55 | static char *model[SNDRV_CARDS]; |
57 | static int probe_mask = -1; | 56 | static int position_fix[SNDRV_CARDS]; |
57 | static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; | ||
58 | static int single_cmd; | 58 | static int single_cmd; |
59 | static int enable_msi; | 59 | static int enable_msi; |
60 | 60 | ||
61 | module_param(index, int, 0444); | 61 | module_param_array(index, int, NULL, 0444); |
62 | MODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); | 62 | MODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); |
63 | module_param(id, charp, 0444); | 63 | module_param_array(id, charp, NULL, 0444); |
64 | MODULE_PARM_DESC(id, "ID string for Intel HD audio interface."); | 64 | MODULE_PARM_DESC(id, "ID string for Intel HD audio interface."); |
65 | module_param(model, charp, 0444); | 65 | module_param_array(enable, bool, NULL, 0444); |
66 | MODULE_PARM_DESC(enable, "Enable Intel HD audio interface."); | ||
67 | module_param_array(model, charp, NULL, 0444); | ||
66 | MODULE_PARM_DESC(model, "Use the given board model."); | 68 | MODULE_PARM_DESC(model, "Use the given board model."); |
67 | module_param(position_fix, int, 0444); | 69 | module_param_array(position_fix, int, NULL, 0444); |
68 | MODULE_PARM_DESC(position_fix, "Fix DMA pointer " | 70 | MODULE_PARM_DESC(position_fix, "Fix DMA pointer " |
69 | "(0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)."); | 71 | "(0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)."); |
70 | module_param(probe_mask, int, 0444); | 72 | module_param_array(probe_mask, int, NULL, 0444); |
71 | MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); | 73 | MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); |
72 | module_param(single_cmd, bool, 0444); | 74 | module_param(single_cmd, bool, 0444); |
73 | MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs " | 75 | MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs " |
74 | "(for debugging only)."); | 76 | "(for debugging only)."); |
75 | module_param(enable_msi, int, 0); | 77 | module_param(enable_msi, int, 0444); |
76 | MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)"); | 78 | MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)"); |
77 | 79 | ||
78 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 80 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
@@ -87,10 +89,6 @@ module_param(power_save_controller, bool, 0644); | |||
87 | MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode."); | 89 | MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode."); |
88 | #endif | 90 | #endif |
89 | 91 | ||
90 | /* just for backward compatibility */ | ||
91 | static int enable; | ||
92 | module_param(enable, bool, 0444); | ||
93 | |||
94 | MODULE_LICENSE("GPL"); | 92 | MODULE_LICENSE("GPL"); |
95 | MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," | 93 | MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," |
96 | "{Intel, ICH6M}," | 94 | "{Intel, ICH6M}," |
@@ -98,12 +96,20 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," | |||
98 | "{Intel, ESB2}," | 96 | "{Intel, ESB2}," |
99 | "{Intel, ICH8}," | 97 | "{Intel, ICH8}," |
100 | "{Intel, ICH9}," | 98 | "{Intel, ICH9}," |
99 | "{Intel, ICH10}," | ||
100 | "{Intel, SCH}," | ||
101 | "{ATI, SB450}," | 101 | "{ATI, SB450}," |
102 | "{ATI, SB600}," | 102 | "{ATI, SB600}," |
103 | "{ATI, RS600}," | 103 | "{ATI, RS600}," |
104 | "{ATI, RS690}," | 104 | "{ATI, RS690}," |
105 | "{ATI, RS780}," | 105 | "{ATI, RS780}," |
106 | "{ATI, R600}," | 106 | "{ATI, R600}," |
107 | "{ATI, RV630}," | ||
108 | "{ATI, RV610}," | ||
109 | "{ATI, RV670}," | ||
110 | "{ATI, RV635}," | ||
111 | "{ATI, RV620}," | ||
112 | "{ATI, RV770}," | ||
107 | "{VIA, VT8251}," | 113 | "{VIA, VT8251}," |
108 | "{VIA, VT8237A}," | 114 | "{VIA, VT8237A}," |
109 | "{SiS, SIS966}," | 115 | "{SiS, SIS966}," |
@@ -370,6 +376,7 @@ struct azx { | |||
370 | /* driver types */ | 376 | /* driver types */ |
371 | enum { | 377 | enum { |
372 | AZX_DRIVER_ICH, | 378 | AZX_DRIVER_ICH, |
379 | AZX_DRIVER_SCH, | ||
373 | AZX_DRIVER_ATI, | 380 | AZX_DRIVER_ATI, |
374 | AZX_DRIVER_ATIHDMI, | 381 | AZX_DRIVER_ATIHDMI, |
375 | AZX_DRIVER_VIA, | 382 | AZX_DRIVER_VIA, |
@@ -380,6 +387,7 @@ enum { | |||
380 | 387 | ||
381 | static char *driver_short_names[] __devinitdata = { | 388 | static char *driver_short_names[] __devinitdata = { |
382 | [AZX_DRIVER_ICH] = "HDA Intel", | 389 | [AZX_DRIVER_ICH] = "HDA Intel", |
390 | [AZX_DRIVER_SCH] = "HDA Intel MID", | ||
383 | [AZX_DRIVER_ATI] = "HDA ATI SB", | 391 | [AZX_DRIVER_ATI] = "HDA ATI SB", |
384 | [AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI", | 392 | [AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI", |
385 | [AZX_DRIVER_VIA] = "HDA VIA VT82xx", | 393 | [AZX_DRIVER_VIA] = "HDA VIA VT82xx", |
@@ -547,7 +555,7 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec) | |||
547 | 555 | ||
548 | again: | 556 | again: |
549 | timeout = jiffies + msecs_to_jiffies(1000); | 557 | timeout = jiffies + msecs_to_jiffies(1000); |
550 | do { | 558 | for (;;) { |
551 | if (chip->polling_mode) { | 559 | if (chip->polling_mode) { |
552 | spin_lock_irq(&chip->reg_lock); | 560 | spin_lock_irq(&chip->reg_lock); |
553 | azx_update_rirb(chip); | 561 | azx_update_rirb(chip); |
@@ -555,8 +563,15 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec) | |||
555 | } | 563 | } |
556 | if (!chip->rirb.cmds) | 564 | if (!chip->rirb.cmds) |
557 | return chip->rirb.res; /* the last value */ | 565 | return chip->rirb.res; /* the last value */ |
558 | schedule_timeout_uninterruptible(1); | 566 | if (time_after(jiffies, timeout)) |
559 | } while (time_after_eq(timeout, jiffies)); | 567 | break; |
568 | if (codec->bus->needs_damn_long_delay) | ||
569 | msleep(2); /* temporary workaround */ | ||
570 | else { | ||
571 | udelay(10); | ||
572 | cond_resched(); | ||
573 | } | ||
574 | } | ||
560 | 575 | ||
561 | if (chip->msi) { | 576 | if (chip->msi) { |
562 | snd_printk(KERN_WARNING "hda_intel: No response from codec, " | 577 | snd_printk(KERN_WARNING "hda_intel: No response from codec, " |
@@ -618,8 +633,9 @@ static int azx_single_send_cmd(struct hda_codec *codec, u32 val) | |||
618 | } | 633 | } |
619 | udelay(1); | 634 | udelay(1); |
620 | } | 635 | } |
621 | snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n", | 636 | if (printk_ratelimit()) |
622 | azx_readw(chip, IRS), val); | 637 | snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n", |
638 | azx_readw(chip, IRS), val); | ||
623 | return -EIO; | 639 | return -EIO; |
624 | } | 640 | } |
625 | 641 | ||
@@ -635,8 +651,9 @@ static unsigned int azx_single_get_response(struct hda_codec *codec) | |||
635 | return azx_readl(chip, IR); | 651 | return azx_readl(chip, IR); |
636 | udelay(1); | 652 | udelay(1); |
637 | } | 653 | } |
638 | snd_printd(SFX "get_response timeout: IRS=0x%x\n", | 654 | if (printk_ratelimit()) |
639 | azx_readw(chip, IRS)); | 655 | snd_printd(SFX "get_response timeout: IRS=0x%x\n", |
656 | azx_readw(chip, IRS)); | ||
640 | return (unsigned int)-1; | 657 | return (unsigned int)-1; |
641 | } | 658 | } |
642 | 659 | ||
@@ -1031,7 +1048,8 @@ static unsigned int azx_max_codecs[] __devinitdata = { | |||
1031 | [AZX_DRIVER_NVIDIA] = 3, /* FIXME: correct? */ | 1048 | [AZX_DRIVER_NVIDIA] = 3, /* FIXME: correct? */ |
1032 | }; | 1049 | }; |
1033 | 1050 | ||
1034 | static int __devinit azx_codec_create(struct azx *chip, const char *model) | 1051 | static int __devinit azx_codec_create(struct azx *chip, const char *model, |
1052 | unsigned int codec_probe_mask) | ||
1035 | { | 1053 | { |
1036 | struct hda_bus_template bus_temp; | 1054 | struct hda_bus_template bus_temp; |
1037 | int c, codecs, audio_codecs, err; | 1055 | int c, codecs, audio_codecs, err; |
@@ -1052,7 +1070,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model) | |||
1052 | 1070 | ||
1053 | codecs = audio_codecs = 0; | 1071 | codecs = audio_codecs = 0; |
1054 | for (c = 0; c < AZX_MAX_CODECS; c++) { | 1072 | for (c = 0; c < AZX_MAX_CODECS; c++) { |
1055 | if ((chip->codec_mask & (1 << c)) & probe_mask) { | 1073 | if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { |
1056 | struct hda_codec *codec; | 1074 | struct hda_codec *codec; |
1057 | err = snd_hda_codec_new(chip->bus, c, &codec); | 1075 | err = snd_hda_codec_new(chip->bus, c, &codec); |
1058 | if (err < 0) | 1076 | if (err < 0) |
@@ -1065,7 +1083,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model) | |||
1065 | if (!audio_codecs) { | 1083 | if (!audio_codecs) { |
1066 | /* probe additional slots if no codec is found */ | 1084 | /* probe additional slots if no codec is found */ |
1067 | for (; c < azx_max_codecs[chip->driver_type]; c++) { | 1085 | for (; c < azx_max_codecs[chip->driver_type]; c++) { |
1068 | if ((chip->codec_mask & (1 << c)) & probe_mask) { | 1086 | if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { |
1069 | err = snd_hda_codec_new(chip->bus, c, NULL); | 1087 | err = snd_hda_codec_new(chip->bus, c, NULL); |
1070 | if (err < 0) | 1088 | if (err < 0) |
1071 | continue; | 1089 | continue; |
@@ -1676,18 +1694,18 @@ static struct snd_pci_quirk probe_mask_list[] __devinitdata = { | |||
1676 | {} | 1694 | {} |
1677 | }; | 1695 | }; |
1678 | 1696 | ||
1679 | static void __devinit check_probe_mask(struct azx *chip) | 1697 | static void __devinit check_probe_mask(struct azx *chip, int dev) |
1680 | { | 1698 | { |
1681 | const struct snd_pci_quirk *q; | 1699 | const struct snd_pci_quirk *q; |
1682 | 1700 | ||
1683 | if (probe_mask == -1) { | 1701 | if (probe_mask[dev] == -1) { |
1684 | q = snd_pci_quirk_lookup(chip->pci, probe_mask_list); | 1702 | q = snd_pci_quirk_lookup(chip->pci, probe_mask_list); |
1685 | if (q) { | 1703 | if (q) { |
1686 | printk(KERN_INFO | 1704 | printk(KERN_INFO |
1687 | "hda_intel: probe_mask set to 0x%x " | 1705 | "hda_intel: probe_mask set to 0x%x " |
1688 | "for device %04x:%04x\n", | 1706 | "for device %04x:%04x\n", |
1689 | q->value, q->subvendor, q->subdevice); | 1707 | q->value, q->subvendor, q->subdevice); |
1690 | probe_mask = q->value; | 1708 | probe_mask[dev] = q->value; |
1691 | } | 1709 | } |
1692 | } | 1710 | } |
1693 | } | 1711 | } |
@@ -1697,17 +1715,18 @@ static void __devinit check_probe_mask(struct azx *chip) | |||
1697 | * constructor | 1715 | * constructor |
1698 | */ | 1716 | */ |
1699 | static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | 1717 | static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, |
1700 | int driver_type, | 1718 | int dev, int driver_type, |
1701 | struct azx **rchip) | 1719 | struct azx **rchip) |
1702 | { | 1720 | { |
1703 | struct azx *chip; | 1721 | struct azx *chip; |
1704 | int err; | 1722 | int err; |
1723 | unsigned short gcap; | ||
1705 | static struct snd_device_ops ops = { | 1724 | static struct snd_device_ops ops = { |
1706 | .dev_free = azx_dev_free, | 1725 | .dev_free = azx_dev_free, |
1707 | }; | 1726 | }; |
1708 | 1727 | ||
1709 | *rchip = NULL; | 1728 | *rchip = NULL; |
1710 | 1729 | ||
1711 | err = pci_enable_device(pci); | 1730 | err = pci_enable_device(pci); |
1712 | if (err < 0) | 1731 | if (err < 0) |
1713 | return err; | 1732 | return err; |
@@ -1727,8 +1746,8 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
1727 | chip->driver_type = driver_type; | 1746 | chip->driver_type = driver_type; |
1728 | chip->msi = enable_msi; | 1747 | chip->msi = enable_msi; |
1729 | 1748 | ||
1730 | chip->position_fix = check_position_fix(chip, position_fix); | 1749 | chip->position_fix = check_position_fix(chip, position_fix[dev]); |
1731 | check_probe_mask(chip); | 1750 | check_probe_mask(chip, dev); |
1732 | 1751 | ||
1733 | chip->single_cmd = single_cmd; | 1752 | chip->single_cmd = single_cmd; |
1734 | 1753 | ||
@@ -1769,25 +1788,40 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
1769 | pci_set_master(pci); | 1788 | pci_set_master(pci); |
1770 | synchronize_irq(chip->irq); | 1789 | synchronize_irq(chip->irq); |
1771 | 1790 | ||
1772 | switch (chip->driver_type) { | 1791 | gcap = azx_readw(chip, GCAP); |
1773 | case AZX_DRIVER_ULI: | 1792 | snd_printdd("chipset global capabilities = 0x%x\n", gcap); |
1774 | chip->playback_streams = ULI_NUM_PLAYBACK; | 1793 | |
1775 | chip->capture_streams = ULI_NUM_CAPTURE; | 1794 | if (gcap) { |
1776 | chip->playback_index_offset = ULI_PLAYBACK_INDEX; | 1795 | /* read number of streams from GCAP register instead of using |
1777 | chip->capture_index_offset = ULI_CAPTURE_INDEX; | 1796 | * hardcoded value |
1778 | break; | 1797 | */ |
1779 | case AZX_DRIVER_ATIHDMI: | 1798 | chip->playback_streams = (gcap & (0xF << 12)) >> 12; |
1780 | chip->playback_streams = ATIHDMI_NUM_PLAYBACK; | 1799 | chip->capture_streams = (gcap & (0xF << 8)) >> 8; |
1781 | chip->capture_streams = ATIHDMI_NUM_CAPTURE; | 1800 | chip->playback_index_offset = (gcap & (0xF << 12)) >> 12; |
1782 | chip->playback_index_offset = ATIHDMI_PLAYBACK_INDEX; | 1801 | chip->capture_index_offset = 0; |
1783 | chip->capture_index_offset = ATIHDMI_CAPTURE_INDEX; | 1802 | } else { |
1784 | break; | 1803 | /* gcap didn't give any info, switching to old method */ |
1785 | default: | 1804 | |
1786 | chip->playback_streams = ICH6_NUM_PLAYBACK; | 1805 | switch (chip->driver_type) { |
1787 | chip->capture_streams = ICH6_NUM_CAPTURE; | 1806 | case AZX_DRIVER_ULI: |
1788 | chip->playback_index_offset = ICH6_PLAYBACK_INDEX; | 1807 | chip->playback_streams = ULI_NUM_PLAYBACK; |
1789 | chip->capture_index_offset = ICH6_CAPTURE_INDEX; | 1808 | chip->capture_streams = ULI_NUM_CAPTURE; |
1790 | break; | 1809 | chip->playback_index_offset = ULI_PLAYBACK_INDEX; |
1810 | chip->capture_index_offset = ULI_CAPTURE_INDEX; | ||
1811 | break; | ||
1812 | case AZX_DRIVER_ATIHDMI: | ||
1813 | chip->playback_streams = ATIHDMI_NUM_PLAYBACK; | ||
1814 | chip->capture_streams = ATIHDMI_NUM_CAPTURE; | ||
1815 | chip->playback_index_offset = ATIHDMI_PLAYBACK_INDEX; | ||
1816 | chip->capture_index_offset = ATIHDMI_CAPTURE_INDEX; | ||
1817 | break; | ||
1818 | default: | ||
1819 | chip->playback_streams = ICH6_NUM_PLAYBACK; | ||
1820 | chip->capture_streams = ICH6_NUM_CAPTURE; | ||
1821 | chip->playback_index_offset = ICH6_PLAYBACK_INDEX; | ||
1822 | chip->capture_index_offset = ICH6_CAPTURE_INDEX; | ||
1823 | break; | ||
1824 | } | ||
1791 | } | 1825 | } |
1792 | chip->num_streams = chip->playback_streams + chip->capture_streams; | 1826 | chip->num_streams = chip->playback_streams + chip->capture_streams; |
1793 | chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), | 1827 | chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), |
@@ -1869,17 +1903,25 @@ static void power_down_all_codecs(struct azx *chip) | |||
1869 | static int __devinit azx_probe(struct pci_dev *pci, | 1903 | static int __devinit azx_probe(struct pci_dev *pci, |
1870 | const struct pci_device_id *pci_id) | 1904 | const struct pci_device_id *pci_id) |
1871 | { | 1905 | { |
1906 | static int dev; | ||
1872 | struct snd_card *card; | 1907 | struct snd_card *card; |
1873 | struct azx *chip; | 1908 | struct azx *chip; |
1874 | int err; | 1909 | int err; |
1875 | 1910 | ||
1876 | card = snd_card_new(index, id, THIS_MODULE, 0); | 1911 | if (dev >= SNDRV_CARDS) |
1912 | return -ENODEV; | ||
1913 | if (!enable[dev]) { | ||
1914 | dev++; | ||
1915 | return -ENOENT; | ||
1916 | } | ||
1917 | |||
1918 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); | ||
1877 | if (!card) { | 1919 | if (!card) { |
1878 | snd_printk(KERN_ERR SFX "Error creating card!\n"); | 1920 | snd_printk(KERN_ERR SFX "Error creating card!\n"); |
1879 | return -ENOMEM; | 1921 | return -ENOMEM; |
1880 | } | 1922 | } |
1881 | 1923 | ||
1882 | err = azx_create(card, pci, pci_id->driver_data, &chip); | 1924 | err = azx_create(card, pci, dev, pci_id->driver_data, &chip); |
1883 | if (err < 0) { | 1925 | if (err < 0) { |
1884 | snd_card_free(card); | 1926 | snd_card_free(card); |
1885 | return err; | 1927 | return err; |
@@ -1887,7 +1929,7 @@ static int __devinit azx_probe(struct pci_dev *pci, | |||
1887 | card->private_data = chip; | 1929 | card->private_data = chip; |
1888 | 1930 | ||
1889 | /* create codec instances */ | 1931 | /* create codec instances */ |
1890 | err = azx_codec_create(chip, model); | 1932 | err = azx_codec_create(chip, model[dev], probe_mask[dev]); |
1891 | if (err < 0) { | 1933 | if (err < 0) { |
1892 | snd_card_free(card); | 1934 | snd_card_free(card); |
1893 | return err; | 1935 | return err; |
@@ -1919,6 +1961,7 @@ static int __devinit azx_probe(struct pci_dev *pci, | |||
1919 | chip->running = 1; | 1961 | chip->running = 1; |
1920 | power_down_all_codecs(chip); | 1962 | power_down_all_codecs(chip); |
1921 | 1963 | ||
1964 | dev++; | ||
1922 | return err; | 1965 | return err; |
1923 | } | 1966 | } |
1924 | 1967 | ||
@@ -1936,12 +1979,21 @@ static struct pci_device_id azx_ids[] = { | |||
1936 | { 0x8086, 0x284b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH8 */ | 1979 | { 0x8086, 0x284b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH8 */ |
1937 | { 0x8086, 0x293e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */ | 1980 | { 0x8086, 0x293e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */ |
1938 | { 0x8086, 0x293f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */ | 1981 | { 0x8086, 0x293f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */ |
1982 | { 0x8086, 0x3a3e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH10 */ | ||
1983 | { 0x8086, 0x3a6e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH10 */ | ||
1984 | { 0x8086, 0x811b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SCH }, /* SCH*/ | ||
1939 | { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */ | 1985 | { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */ |
1940 | { 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */ | 1986 | { 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */ |
1941 | { 0x1002, 0x793b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS600 HDMI */ | 1987 | { 0x1002, 0x793b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS600 HDMI */ |
1942 | { 0x1002, 0x7919, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS690 HDMI */ | 1988 | { 0x1002, 0x7919, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS690 HDMI */ |
1943 | { 0x1002, 0x960c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS780 HDMI */ | 1989 | { 0x1002, 0x960f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS780 HDMI */ |
1944 | { 0x1002, 0xaa00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI R600 HDMI */ | 1990 | { 0x1002, 0xaa00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI R600 HDMI */ |
1991 | { 0x1002, 0xaa08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV630 HDMI */ | ||
1992 | { 0x1002, 0xaa10, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV610 HDMI */ | ||
1993 | { 0x1002, 0xaa18, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV670 HDMI */ | ||
1994 | { 0x1002, 0xaa20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV635 HDMI */ | ||
1995 | { 0x1002, 0xaa28, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV620 HDMI */ | ||
1996 | { 0x1002, 0xaa30, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV770 HDMI */ | ||
1945 | { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */ | 1997 | { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */ |
1946 | { 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */ | 1998 | { 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */ |
1947 | { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */ | 1999 | { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */ |
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 8c56c9cb0d09..ad0014ab71f9 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h | |||
@@ -90,6 +90,13 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, | |||
90 | void snd_hda_codec_resume_amp(struct hda_codec *codec); | 90 | void snd_hda_codec_resume_amp(struct hda_codec *codec); |
91 | #endif | 91 | #endif |
92 | 92 | ||
93 | void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, | ||
94 | unsigned int *tlv); | ||
95 | struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, | ||
96 | const char *name); | ||
97 | int snd_hda_add_vmaster(struct hda_codec *codec, char *name, | ||
98 | unsigned int *tlv, const char **slaves); | ||
99 | |||
93 | /* amp value bits */ | 100 | /* amp value bits */ |
94 | #define HDA_AMP_MUTE 0x80 | 101 | #define HDA_AMP_MUTE 0x80 |
95 | #define HDA_AMP_UNMUTE 0x00 | 102 | #define HDA_AMP_UNMUTE 0x00 |
@@ -325,6 +332,7 @@ struct auto_pin_cfg { | |||
325 | hda_nid_t input_pins[AUTO_PIN_LAST]; | 332 | hda_nid_t input_pins[AUTO_PIN_LAST]; |
326 | hda_nid_t dig_out_pin; | 333 | hda_nid_t dig_out_pin; |
327 | hda_nid_t dig_in_pin; | 334 | hda_nid_t dig_in_pin; |
335 | hda_nid_t mono_out_pin; | ||
328 | }; | 336 | }; |
329 | 337 | ||
330 | #define get_defcfg_connect(cfg) \ | 338 | #define get_defcfg_connect(cfg) \ |
@@ -363,10 +371,11 @@ static inline u32 get_wcaps(struct hda_codec *codec, hda_nid_t nid) | |||
363 | { | 371 | { |
364 | if (nid < codec->start_nid || | 372 | if (nid < codec->start_nid || |
365 | nid >= codec->start_nid + codec->num_nodes) | 373 | nid >= codec->start_nid + codec->num_nodes) |
366 | return snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP); | 374 | return 0; |
367 | return codec->wcaps[nid - codec->start_nid]; | 375 | return codec->wcaps[nid - codec->start_nid]; |
368 | } | 376 | } |
369 | 377 | ||
378 | u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction); | ||
370 | int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, | 379 | int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, |
371 | unsigned int caps); | 380 | unsigned int caps); |
372 | 381 | ||
@@ -398,4 +407,11 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, | |||
398 | hda_nid_t nid); | 407 | hda_nid_t nid); |
399 | #endif /* CONFIG_SND_HDA_POWER_SAVE */ | 408 | #endif /* CONFIG_SND_HDA_POWER_SAVE */ |
400 | 409 | ||
410 | /* | ||
411 | * virtual master control | ||
412 | */ | ||
413 | struct snd_kcontrol *snd_ctl_make_virtual_master(char *name, | ||
414 | const unsigned int *tlv); | ||
415 | int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave); | ||
416 | |||
401 | #endif /* __SOUND_HDA_LOCAL_H */ | 417 | #endif /* __SOUND_HDA_LOCAL_H */ |
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index e94944f34ffd..35a630d1770f 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <sound/core.h> | 25 | #include <sound/core.h> |
27 | #include "hda_codec.h" | 26 | #include "hda_codec.h" |
@@ -203,7 +202,8 @@ static const char *get_jack_color(u32 cfg) | |||
203 | } | 202 | } |
204 | 203 | ||
205 | static void print_pin_caps(struct snd_info_buffer *buffer, | 204 | static void print_pin_caps(struct snd_info_buffer *buffer, |
206 | struct hda_codec *codec, hda_nid_t nid) | 205 | struct hda_codec *codec, hda_nid_t nid, |
206 | int *supports_vref) | ||
207 | { | 207 | { |
208 | static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" }; | 208 | static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" }; |
209 | static char *jack_types[16] = { | 209 | static char *jack_types[16] = { |
@@ -213,7 +213,7 @@ static void print_pin_caps(struct snd_info_buffer *buffer, | |||
213 | "SPDIF In", "Digitial In", "Reserved", "Other" | 213 | "SPDIF In", "Digitial In", "Reserved", "Other" |
214 | }; | 214 | }; |
215 | static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" }; | 215 | static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" }; |
216 | unsigned int caps; | 216 | unsigned int caps, val; |
217 | 217 | ||
218 | caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); | 218 | caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); |
219 | snd_iprintf(buffer, " Pincap 0x08%x:", caps); | 219 | snd_iprintf(buffer, " Pincap 0x08%x:", caps); |
@@ -227,7 +227,45 @@ static void print_pin_caps(struct snd_info_buffer *buffer, | |||
227 | snd_iprintf(buffer, " EAPD"); | 227 | snd_iprintf(buffer, " EAPD"); |
228 | if (caps & AC_PINCAP_PRES_DETECT) | 228 | if (caps & AC_PINCAP_PRES_DETECT) |
229 | snd_iprintf(buffer, " Detect"); | 229 | snd_iprintf(buffer, " Detect"); |
230 | if (caps & AC_PINCAP_BALANCE) | ||
231 | snd_iprintf(buffer, " Balanced"); | ||
232 | if (caps & AC_PINCAP_LR_SWAP) | ||
233 | snd_iprintf(buffer, " R/L"); | ||
234 | if (caps & AC_PINCAP_TRIG_REQ) | ||
235 | snd_iprintf(buffer, " Trigger"); | ||
236 | if (caps & AC_PINCAP_IMP_SENSE) | ||
237 | snd_iprintf(buffer, " ImpSense"); | ||
230 | snd_iprintf(buffer, "\n"); | 238 | snd_iprintf(buffer, "\n"); |
239 | if (caps & AC_PINCAP_VREF) { | ||
240 | unsigned int vref = | ||
241 | (caps & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; | ||
242 | snd_iprintf(buffer, " Vref caps:"); | ||
243 | if (vref & AC_PINCAP_VREF_HIZ) | ||
244 | snd_iprintf(buffer, " HIZ"); | ||
245 | if (vref & AC_PINCAP_VREF_50) | ||
246 | snd_iprintf(buffer, " 50"); | ||
247 | if (vref & AC_PINCAP_VREF_GRD) | ||
248 | snd_iprintf(buffer, " GRD"); | ||
249 | if (vref & AC_PINCAP_VREF_80) | ||
250 | snd_iprintf(buffer, " 80"); | ||
251 | if (vref & AC_PINCAP_VREF_100) | ||
252 | snd_iprintf(buffer, " 100"); | ||
253 | snd_iprintf(buffer, "\n"); | ||
254 | *supports_vref = 1; | ||
255 | } else | ||
256 | *supports_vref = 0; | ||
257 | if (caps & AC_PINCAP_EAPD) { | ||
258 | val = snd_hda_codec_read(codec, nid, 0, | ||
259 | AC_VERB_GET_EAPD_BTLENABLE, 0); | ||
260 | snd_iprintf(buffer, " EAPD 0x%x:", val); | ||
261 | if (val & AC_EAPDBTL_BALANCED) | ||
262 | snd_iprintf(buffer, " BALANCED"); | ||
263 | if (val & AC_EAPDBTL_EAPD) | ||
264 | snd_iprintf(buffer, " EAPD"); | ||
265 | if (val & AC_EAPDBTL_LR_SWAP) | ||
266 | snd_iprintf(buffer, " R/L"); | ||
267 | snd_iprintf(buffer, "\n"); | ||
268 | } | ||
231 | caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | 269 | caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); |
232 | snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps, | 270 | snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps, |
233 | jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT], | 271 | jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT], |
@@ -237,8 +275,233 @@ static void print_pin_caps(struct snd_info_buffer *buffer, | |||
237 | snd_iprintf(buffer, " Conn = %s, Color = %s\n", | 275 | snd_iprintf(buffer, " Conn = %s, Color = %s\n", |
238 | get_jack_connection(caps), | 276 | get_jack_connection(caps), |
239 | get_jack_color(caps)); | 277 | get_jack_color(caps)); |
278 | /* Default association and sequence values refer to default grouping | ||
279 | * of pin complexes and their sequence within the group. This is used | ||
280 | * for priority and resource allocation. | ||
281 | */ | ||
282 | snd_iprintf(buffer, " DefAssociation = 0x%x, Sequence = 0x%x\n", | ||
283 | (caps & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT, | ||
284 | caps & AC_DEFCFG_SEQUENCE); | ||
285 | if (((caps & AC_DEFCFG_MISC) >> AC_DEFCFG_MISC_SHIFT) & | ||
286 | AC_DEFCFG_MISC_NO_PRESENCE) { | ||
287 | /* Miscellaneous bit indicates external hardware does not | ||
288 | * support presence detection even if the pin complex | ||
289 | * indicates it is supported. | ||
290 | */ | ||
291 | snd_iprintf(buffer, " Misc = NO_PRESENCE\n"); | ||
292 | } | ||
293 | } | ||
294 | |||
295 | static void print_pin_ctls(struct snd_info_buffer *buffer, | ||
296 | struct hda_codec *codec, hda_nid_t nid, | ||
297 | int supports_vref) | ||
298 | { | ||
299 | unsigned int pinctls; | ||
300 | |||
301 | pinctls = snd_hda_codec_read(codec, nid, 0, | ||
302 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
303 | snd_iprintf(buffer, " Pin-ctls: 0x%02x:", pinctls); | ||
304 | if (pinctls & AC_PINCTL_IN_EN) | ||
305 | snd_iprintf(buffer, " IN"); | ||
306 | if (pinctls & AC_PINCTL_OUT_EN) | ||
307 | snd_iprintf(buffer, " OUT"); | ||
308 | if (pinctls & AC_PINCTL_HP_EN) | ||
309 | snd_iprintf(buffer, " HP"); | ||
310 | if (supports_vref) { | ||
311 | int vref = pinctls & AC_PINCTL_VREFEN; | ||
312 | switch (vref) { | ||
313 | case AC_PINCTL_VREF_HIZ: | ||
314 | snd_iprintf(buffer, " VREF_HIZ"); | ||
315 | break; | ||
316 | case AC_PINCTL_VREF_50: | ||
317 | snd_iprintf(buffer, " VREF_50"); | ||
318 | break; | ||
319 | case AC_PINCTL_VREF_GRD: | ||
320 | snd_iprintf(buffer, " VREF_GRD"); | ||
321 | break; | ||
322 | case AC_PINCTL_VREF_80: | ||
323 | snd_iprintf(buffer, " VREF_80"); | ||
324 | break; | ||
325 | case AC_PINCTL_VREF_100: | ||
326 | snd_iprintf(buffer, " VREF_100"); | ||
327 | break; | ||
328 | } | ||
329 | } | ||
330 | snd_iprintf(buffer, "\n"); | ||
331 | } | ||
332 | |||
333 | static void print_vol_knob(struct snd_info_buffer *buffer, | ||
334 | struct hda_codec *codec, hda_nid_t nid) | ||
335 | { | ||
336 | unsigned int cap = snd_hda_param_read(codec, nid, | ||
337 | AC_PAR_VOL_KNB_CAP); | ||
338 | snd_iprintf(buffer, " Volume-Knob: delta=%d, steps=%d, ", | ||
339 | (cap >> 7) & 1, cap & 0x7f); | ||
340 | cap = snd_hda_codec_read(codec, nid, 0, | ||
341 | AC_VERB_GET_VOLUME_KNOB_CONTROL, 0); | ||
342 | snd_iprintf(buffer, "direct=%d, val=%d\n", | ||
343 | (cap >> 7) & 1, cap & 0x7f); | ||
344 | } | ||
345 | |||
346 | static void print_audio_io(struct snd_info_buffer *buffer, | ||
347 | struct hda_codec *codec, hda_nid_t nid, | ||
348 | unsigned int wid_type) | ||
349 | { | ||
350 | int conv = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); | ||
351 | snd_iprintf(buffer, | ||
352 | " Converter: stream=%d, channel=%d\n", | ||
353 | (conv & AC_CONV_STREAM) >> AC_CONV_STREAM_SHIFT, | ||
354 | conv & AC_CONV_CHANNEL); | ||
355 | |||
356 | if (wid_type == AC_WID_AUD_IN && (conv & AC_CONV_CHANNEL) == 0) { | ||
357 | int sdi = snd_hda_codec_read(codec, nid, 0, | ||
358 | AC_VERB_GET_SDI_SELECT, 0); | ||
359 | snd_iprintf(buffer, " SDI-Select: %d\n", | ||
360 | sdi & AC_SDI_SELECT); | ||
361 | } | ||
362 | } | ||
363 | |||
364 | static void print_digital_conv(struct snd_info_buffer *buffer, | ||
365 | struct hda_codec *codec, hda_nid_t nid) | ||
366 | { | ||
367 | unsigned int digi1 = snd_hda_codec_read(codec, nid, 0, | ||
368 | AC_VERB_GET_DIGI_CONVERT_1, 0); | ||
369 | unsigned int digi2 = snd_hda_codec_read(codec, nid, 0, | ||
370 | AC_VERB_GET_DIGI_CONVERT_2, 0); | ||
371 | snd_iprintf(buffer, " Digital:"); | ||
372 | if (digi1 & AC_DIG1_ENABLE) | ||
373 | snd_iprintf(buffer, " Enabled"); | ||
374 | if (digi1 & AC_DIG1_V) | ||
375 | snd_iprintf(buffer, " Validity"); | ||
376 | if (digi1 & AC_DIG1_VCFG) | ||
377 | snd_iprintf(buffer, " ValidityCfg"); | ||
378 | if (digi1 & AC_DIG1_EMPHASIS) | ||
379 | snd_iprintf(buffer, " Preemphasis"); | ||
380 | if (digi1 & AC_DIG1_COPYRIGHT) | ||
381 | snd_iprintf(buffer, " Copyright"); | ||
382 | if (digi1 & AC_DIG1_NONAUDIO) | ||
383 | snd_iprintf(buffer, " Non-Audio"); | ||
384 | if (digi1 & AC_DIG1_PROFESSIONAL) | ||
385 | snd_iprintf(buffer, " Pro"); | ||
386 | if (digi1 & AC_DIG1_LEVEL) | ||
387 | snd_iprintf(buffer, " GenLevel"); | ||
388 | snd_iprintf(buffer, "\n"); | ||
389 | snd_iprintf(buffer, " Digital category: 0x%x\n", digi2 & AC_DIG2_CC); | ||
390 | } | ||
391 | |||
392 | static const char *get_pwr_state(u32 state) | ||
393 | { | ||
394 | static const char *buf[4] = { | ||
395 | "D0", "D1", "D2", "D3" | ||
396 | }; | ||
397 | if (state < 4) | ||
398 | return buf[state]; | ||
399 | return "UNKNOWN"; | ||
400 | } | ||
401 | |||
402 | static void print_power_state(struct snd_info_buffer *buffer, | ||
403 | struct hda_codec *codec, hda_nid_t nid) | ||
404 | { | ||
405 | int pwr = snd_hda_codec_read(codec, nid, 0, | ||
406 | AC_VERB_GET_POWER_STATE, 0); | ||
407 | snd_iprintf(buffer, " Power: setting=%s, actual=%s\n", | ||
408 | get_pwr_state(pwr & AC_PWRST_SETTING), | ||
409 | get_pwr_state((pwr & AC_PWRST_ACTUAL) >> | ||
410 | AC_PWRST_ACTUAL_SHIFT)); | ||
411 | } | ||
412 | |||
413 | static void print_unsol_cap(struct snd_info_buffer *buffer, | ||
414 | struct hda_codec *codec, hda_nid_t nid) | ||
415 | { | ||
416 | int unsol = snd_hda_codec_read(codec, nid, 0, | ||
417 | AC_VERB_GET_UNSOLICITED_RESPONSE, 0); | ||
418 | snd_iprintf(buffer, | ||
419 | " Unsolicited: tag=%02x, enabled=%d\n", | ||
420 | unsol & AC_UNSOL_TAG, | ||
421 | (unsol & AC_UNSOL_ENABLED) ? 1 : 0); | ||
422 | } | ||
423 | |||
424 | static void print_proc_caps(struct snd_info_buffer *buffer, | ||
425 | struct hda_codec *codec, hda_nid_t nid) | ||
426 | { | ||
427 | unsigned int proc_caps = snd_hda_param_read(codec, nid, | ||
428 | AC_PAR_PROC_CAP); | ||
429 | snd_iprintf(buffer, " Processing caps: benign=%d, ncoeff=%d\n", | ||
430 | proc_caps & AC_PCAP_BENIGN, | ||
431 | (proc_caps & AC_PCAP_NUM_COEF) >> AC_PCAP_NUM_COEF_SHIFT); | ||
240 | } | 432 | } |
241 | 433 | ||
434 | static void print_conn_list(struct snd_info_buffer *buffer, | ||
435 | struct hda_codec *codec, hda_nid_t nid, | ||
436 | unsigned int wid_type, hda_nid_t *conn, | ||
437 | int conn_len) | ||
438 | { | ||
439 | int c, curr = -1; | ||
440 | |||
441 | if (conn_len > 1 && wid_type != AC_WID_AUD_MIX) | ||
442 | curr = snd_hda_codec_read(codec, nid, 0, | ||
443 | AC_VERB_GET_CONNECT_SEL, 0); | ||
444 | snd_iprintf(buffer, " Connection: %d\n", conn_len); | ||
445 | if (conn_len > 0) { | ||
446 | snd_iprintf(buffer, " "); | ||
447 | for (c = 0; c < conn_len; c++) { | ||
448 | snd_iprintf(buffer, " 0x%02x", conn[c]); | ||
449 | if (c == curr) | ||
450 | snd_iprintf(buffer, "*"); | ||
451 | } | ||
452 | snd_iprintf(buffer, "\n"); | ||
453 | } | ||
454 | } | ||
455 | |||
456 | static void print_realtek_coef(struct snd_info_buffer *buffer, | ||
457 | struct hda_codec *codec, hda_nid_t nid) | ||
458 | { | ||
459 | int coeff = snd_hda_codec_read(codec, nid, 0, | ||
460 | AC_VERB_GET_PROC_COEF, 0); | ||
461 | snd_iprintf(buffer, " Processing Coefficient: 0x%02x\n", coeff); | ||
462 | coeff = snd_hda_codec_read(codec, nid, 0, | ||
463 | AC_VERB_GET_COEF_INDEX, 0); | ||
464 | snd_iprintf(buffer, " Coefficient Index: 0x%02x\n", coeff); | ||
465 | } | ||
466 | |||
467 | static void print_gpio(struct snd_info_buffer *buffer, | ||
468 | struct hda_codec *codec, hda_nid_t nid) | ||
469 | { | ||
470 | unsigned int gpio = | ||
471 | snd_hda_param_read(codec, codec->afg, AC_PAR_GPIO_CAP); | ||
472 | unsigned int enable, direction, wake, unsol, sticky, data; | ||
473 | int i, max; | ||
474 | snd_iprintf(buffer, "GPIO: io=%d, o=%d, i=%d, " | ||
475 | "unsolicited=%d, wake=%d\n", | ||
476 | gpio & AC_GPIO_IO_COUNT, | ||
477 | (gpio & AC_GPIO_O_COUNT) >> AC_GPIO_O_COUNT_SHIFT, | ||
478 | (gpio & AC_GPIO_I_COUNT) >> AC_GPIO_I_COUNT_SHIFT, | ||
479 | (gpio & AC_GPIO_UNSOLICITED) ? 1 : 0, | ||
480 | (gpio & AC_GPIO_WAKE) ? 1 : 0); | ||
481 | max = gpio & AC_GPIO_IO_COUNT; | ||
482 | enable = snd_hda_codec_read(codec, nid, 0, | ||
483 | AC_VERB_GET_GPIO_MASK, 0); | ||
484 | direction = snd_hda_codec_read(codec, nid, 0, | ||
485 | AC_VERB_GET_GPIO_DIRECTION, 0); | ||
486 | wake = snd_hda_codec_read(codec, nid, 0, | ||
487 | AC_VERB_GET_GPIO_WAKE_MASK, 0); | ||
488 | unsol = snd_hda_codec_read(codec, nid, 0, | ||
489 | AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK, 0); | ||
490 | sticky = snd_hda_codec_read(codec, nid, 0, | ||
491 | AC_VERB_GET_GPIO_STICKY_MASK, 0); | ||
492 | data = snd_hda_codec_read(codec, nid, 0, | ||
493 | AC_VERB_GET_GPIO_DATA, 0); | ||
494 | for (i = 0; i < max; ++i) | ||
495 | snd_iprintf(buffer, | ||
496 | " IO[%d]: enable=%d, dir=%d, wake=%d, " | ||
497 | "sticky=%d, data=%d\n", i, | ||
498 | (enable & (1<<i)) ? 1 : 0, | ||
499 | (direction & (1<<i)) ? 1 : 0, | ||
500 | (wake & (1<<i)) ? 1 : 0, | ||
501 | (sticky & (1<<i)) ? 1 : 0, | ||
502 | (data & (1<<i)) ? 1 : 0); | ||
503 | /* FIXME: add GPO and GPI pin information */ | ||
504 | } | ||
242 | 505 | ||
243 | static void print_codec_info(struct snd_info_entry *entry, | 506 | static void print_codec_info(struct snd_info_entry *entry, |
244 | struct snd_info_buffer *buffer) | 507 | struct snd_info_buffer *buffer) |
@@ -276,14 +539,17 @@ static void print_codec_info(struct snd_info_entry *entry, | |||
276 | snd_hda_power_down(codec); | 539 | snd_hda_power_down(codec); |
277 | return; | 540 | return; |
278 | } | 541 | } |
542 | |||
543 | print_gpio(buffer, codec, codec->afg); | ||
544 | |||
279 | for (i = 0; i < nodes; i++, nid++) { | 545 | for (i = 0; i < nodes; i++, nid++) { |
280 | unsigned int wid_caps = | 546 | unsigned int wid_caps = |
281 | snd_hda_param_read(codec, nid, | 547 | snd_hda_param_read(codec, nid, |
282 | AC_PAR_AUDIO_WIDGET_CAP); | 548 | AC_PAR_AUDIO_WIDGET_CAP); |
283 | unsigned int wid_type = | 549 | unsigned int wid_type = |
284 | (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; | 550 | (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; |
285 | int conn_len = 0; | ||
286 | hda_nid_t conn[HDA_MAX_CONNECTIONS]; | 551 | hda_nid_t conn[HDA_MAX_CONNECTIONS]; |
552 | int conn_len = 0; | ||
287 | 553 | ||
288 | snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid, | 554 | snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid, |
289 | get_wid_type_name(wid_type), wid_caps); | 555 | get_wid_type_name(wid_type), wid_caps); |
@@ -297,8 +563,18 @@ static void print_codec_info(struct snd_info_entry *entry, | |||
297 | snd_iprintf(buffer, " Amp-In"); | 563 | snd_iprintf(buffer, " Amp-In"); |
298 | if (wid_caps & AC_WCAP_OUT_AMP) | 564 | if (wid_caps & AC_WCAP_OUT_AMP) |
299 | snd_iprintf(buffer, " Amp-Out"); | 565 | snd_iprintf(buffer, " Amp-Out"); |
566 | if (wid_caps & AC_WCAP_STRIPE) | ||
567 | snd_iprintf(buffer, " Stripe"); | ||
568 | if (wid_caps & AC_WCAP_LR_SWAP) | ||
569 | snd_iprintf(buffer, " R/L"); | ||
300 | snd_iprintf(buffer, "\n"); | 570 | snd_iprintf(buffer, "\n"); |
301 | 571 | ||
572 | /* volume knob is a special widget that always have connection | ||
573 | * list | ||
574 | */ | ||
575 | if (wid_type == AC_WID_VOL_KNB) | ||
576 | wid_caps |= AC_WCAP_CONN_LIST; | ||
577 | |||
302 | if (wid_caps & AC_WCAP_CONN_LIST) | 578 | if (wid_caps & AC_WCAP_CONN_LIST) |
303 | conn_len = snd_hda_get_connections(codec, nid, conn, | 579 | conn_len = snd_hda_get_connections(codec, nid, conn, |
304 | HDA_MAX_CONNECTIONS); | 580 | HDA_MAX_CONNECTIONS); |
@@ -318,48 +594,49 @@ static void print_codec_info(struct snd_info_entry *entry, | |||
318 | wid_caps & AC_WCAP_STEREO, 1); | 594 | wid_caps & AC_WCAP_STEREO, 1); |
319 | } | 595 | } |
320 | 596 | ||
321 | if (wid_type == AC_WID_PIN) { | 597 | switch (wid_type) { |
322 | unsigned int pinctls; | 598 | case AC_WID_PIN: { |
323 | print_pin_caps(buffer, codec, nid); | 599 | int supports_vref; |
324 | pinctls = snd_hda_codec_read(codec, nid, 0, | 600 | print_pin_caps(buffer, codec, nid, &supports_vref); |
325 | AC_VERB_GET_PIN_WIDGET_CONTROL, | 601 | print_pin_ctls(buffer, codec, nid, supports_vref); |
326 | 0); | 602 | break; |
327 | snd_iprintf(buffer, " Pin-ctls: 0x%02x:", pinctls); | ||
328 | if (pinctls & AC_PINCTL_IN_EN) | ||
329 | snd_iprintf(buffer, " IN"); | ||
330 | if (pinctls & AC_PINCTL_OUT_EN) | ||
331 | snd_iprintf(buffer, " OUT"); | ||
332 | if (pinctls & AC_PINCTL_HP_EN) | ||
333 | snd_iprintf(buffer, " HP"); | ||
334 | snd_iprintf(buffer, "\n"); | ||
335 | } | 603 | } |
336 | 604 | case AC_WID_VOL_KNB: | |
337 | if ((wid_type == AC_WID_AUD_OUT || wid_type == AC_WID_AUD_IN) && | 605 | print_vol_knob(buffer, codec, nid); |
338 | (wid_caps & AC_WCAP_FORMAT_OVRD)) { | 606 | break; |
339 | snd_iprintf(buffer, " PCM:\n"); | 607 | case AC_WID_AUD_OUT: |
340 | print_pcm_caps(buffer, codec, nid); | 608 | case AC_WID_AUD_IN: |
609 | print_audio_io(buffer, codec, nid, wid_type); | ||
610 | if (wid_caps & AC_WCAP_DIGITAL) | ||
611 | print_digital_conv(buffer, codec, nid); | ||
612 | if (wid_caps & AC_WCAP_FORMAT_OVRD) { | ||
613 | snd_iprintf(buffer, " PCM:\n"); | ||
614 | print_pcm_caps(buffer, codec, nid); | ||
615 | } | ||
616 | break; | ||
341 | } | 617 | } |
342 | 618 | ||
619 | if (wid_caps & AC_WCAP_UNSOL_CAP) | ||
620 | print_unsol_cap(buffer, codec, nid); | ||
621 | |||
343 | if (wid_caps & AC_WCAP_POWER) | 622 | if (wid_caps & AC_WCAP_POWER) |
344 | snd_iprintf(buffer, " Power: 0x%x\n", | 623 | print_power_state(buffer, codec, nid); |
345 | snd_hda_codec_read(codec, nid, 0, | 624 | |
346 | AC_VERB_GET_POWER_STATE, | 625 | if (wid_caps & AC_WCAP_DELAY) |
347 | 0)); | 626 | snd_iprintf(buffer, " Delay: %d samples\n", |
348 | 627 | (wid_caps & AC_WCAP_DELAY) >> | |
349 | if (wid_caps & AC_WCAP_CONN_LIST) { | 628 | AC_WCAP_DELAY_SHIFT); |
350 | int c, curr = -1; | 629 | |
351 | if (conn_len > 1 && wid_type != AC_WID_AUD_MIX) | 630 | if (wid_caps & AC_WCAP_CONN_LIST) |
352 | curr = snd_hda_codec_read(codec, nid, 0, | 631 | print_conn_list(buffer, codec, nid, wid_type, |
353 | AC_VERB_GET_CONNECT_SEL, 0); | 632 | conn, conn_len); |
354 | snd_iprintf(buffer, " Connection: %d\n", conn_len); | 633 | |
355 | snd_iprintf(buffer, " "); | 634 | if (wid_caps & AC_WCAP_PROC_WID) |
356 | for (c = 0; c < conn_len; c++) { | 635 | print_proc_caps(buffer, codec, nid); |
357 | snd_iprintf(buffer, " 0x%02x", conn[c]); | 636 | |
358 | if (c == curr) | 637 | /* NID 0x20 == Realtek Define Registers */ |
359 | snd_iprintf(buffer, "*"); | 638 | if (codec->vendor_id == 0x10ec && nid == 0x20) |
360 | } | 639 | print_realtek_coef(buffer, codec, nid); |
361 | snd_iprintf(buffer, "\n"); | ||
362 | } | ||
363 | } | 640 | } |
364 | snd_hda_power_down(codec); | 641 | snd_hda_power_down(codec); |
365 | } | 642 | } |
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 196ad3c9405d..19f08846d6fc 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
@@ -79,6 +78,11 @@ struct ad198x_spec { | |||
79 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 78 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
80 | struct hda_loopback_check loopback; | 79 | struct hda_loopback_check loopback; |
81 | #endif | 80 | #endif |
81 | /* for virtual master */ | ||
82 | hda_nid_t vmaster_nid; | ||
83 | u32 vmaster_tlv[4]; | ||
84 | const char **slave_vols; | ||
85 | const char **slave_sws; | ||
82 | }; | 86 | }; |
83 | 87 | ||
84 | /* | 88 | /* |
@@ -126,6 +130,32 @@ static int ad198x_init(struct hda_codec *codec) | |||
126 | return 0; | 130 | return 0; |
127 | } | 131 | } |
128 | 132 | ||
133 | static const char *ad_slave_vols[] = { | ||
134 | "Front Playback Volume", | ||
135 | "Surround Playback Volume", | ||
136 | "Center Playback Volume", | ||
137 | "LFE Playback Volume", | ||
138 | "Side Playback Volume", | ||
139 | "Headphone Playback Volume", | ||
140 | "Mono Playback Volume", | ||
141 | "Speaker Playback Volume", | ||
142 | "IEC958 Playback Volume", | ||
143 | NULL | ||
144 | }; | ||
145 | |||
146 | static const char *ad_slave_sws[] = { | ||
147 | "Front Playback Switch", | ||
148 | "Surround Playback Switch", | ||
149 | "Center Playback Switch", | ||
150 | "LFE Playback Switch", | ||
151 | "Side Playback Switch", | ||
152 | "Headphone Playback Switch", | ||
153 | "Mono Playback Switch", | ||
154 | "Speaker Playback Switch", | ||
155 | "IEC958 Playback Switch", | ||
156 | NULL | ||
157 | }; | ||
158 | |||
129 | static int ad198x_build_controls(struct hda_codec *codec) | 159 | static int ad198x_build_controls(struct hda_codec *codec) |
130 | { | 160 | { |
131 | struct ad198x_spec *spec = codec->spec; | 161 | struct ad198x_spec *spec = codec->spec; |
@@ -147,6 +177,27 @@ static int ad198x_build_controls(struct hda_codec *codec) | |||
147 | if (err < 0) | 177 | if (err < 0) |
148 | return err; | 178 | return err; |
149 | } | 179 | } |
180 | |||
181 | /* if we have no master control, let's create it */ | ||
182 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { | ||
183 | snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, | ||
184 | HDA_OUTPUT, spec->vmaster_tlv); | ||
185 | err = snd_hda_add_vmaster(codec, "Master Playback Volume", | ||
186 | spec->vmaster_tlv, | ||
187 | (spec->slave_vols ? | ||
188 | spec->slave_vols : ad_slave_vols)); | ||
189 | if (err < 0) | ||
190 | return err; | ||
191 | } | ||
192 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { | ||
193 | err = snd_hda_add_vmaster(codec, "Master Playback Switch", | ||
194 | NULL, | ||
195 | (spec->slave_sws ? | ||
196 | spec->slave_sws : ad_slave_sws)); | ||
197 | if (err < 0) | ||
198 | return err; | ||
199 | } | ||
200 | |||
150 | return 0; | 201 | return 0; |
151 | } | 202 | } |
152 | 203 | ||
@@ -370,7 +421,7 @@ static int ad198x_eapd_put(struct snd_kcontrol *kcontrol, | |||
370 | int invert = (kcontrol->private_value >> 8) & 1; | 421 | int invert = (kcontrol->private_value >> 8) & 1; |
371 | hda_nid_t nid = kcontrol->private_value & 0xff; | 422 | hda_nid_t nid = kcontrol->private_value & 0xff; |
372 | unsigned int eapd; | 423 | unsigned int eapd; |
373 | eapd = ucontrol->value.integer.value[0]; | 424 | eapd = !!ucontrol->value.integer.value[0]; |
374 | if (invert) | 425 | if (invert) |
375 | eapd = !eapd; | 426 | eapd = !eapd; |
376 | if (eapd == spec->cur_eapd) | 427 | if (eapd == spec->cur_eapd) |
@@ -833,27 +884,29 @@ static const char *ad1986a_models[AD1986A_MODELS] = { | |||
833 | 884 | ||
834 | static struct snd_pci_quirk ad1986a_cfg_tbl[] = { | 885 | static struct snd_pci_quirk ad1986a_cfg_tbl[] = { |
835 | SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD), | 886 | SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD), |
836 | SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK), | ||
837 | SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD), | 887 | SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD), |
838 | SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD), | ||
839 | SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD), | 888 | SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD), |
889 | SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD), | ||
840 | SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD), | 890 | SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD), |
841 | SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD), | 891 | SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD), |
842 | SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD), | 892 | SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD), |
843 | SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD), | 893 | SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD), |
894 | SND_PCI_QUIRK(0x1043, 0x1443, "ASUS VX1", AD1986A_LAPTOP), | ||
844 | SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8J", AD1986A_3STACK), | 895 | SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8J", AD1986A_3STACK), |
845 | SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK), | 896 | SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK), |
846 | SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP), | 897 | SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP), |
847 | SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK), | 898 | SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK), |
848 | SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK), | 899 | SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK), |
849 | SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK), | 900 | SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK), |
901 | SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK), | ||
902 | SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD), | ||
850 | SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK), | 903 | SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK), |
851 | SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), | 904 | SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), |
852 | SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_LAPTOP_EAPD), | 905 | SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_LAPTOP_EAPD), |
853 | SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_LAPTOP_EAPD), | 906 | SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_LAPTOP_EAPD), |
854 | SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_LAPTOP_EAPD), | 907 | SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_LAPTOP_EAPD), |
855 | SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK), | ||
856 | SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA), | 908 | SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA), |
909 | SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK), | ||
857 | SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), | 910 | SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), |
858 | SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK), | 911 | SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK), |
859 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE), | 912 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE), |
@@ -872,6 +925,13 @@ static struct hda_amp_list ad1986a_loopbacks[] = { | |||
872 | }; | 925 | }; |
873 | #endif | 926 | #endif |
874 | 927 | ||
928 | static int is_jack_available(struct hda_codec *codec, hda_nid_t nid) | ||
929 | { | ||
930 | unsigned int conf = snd_hda_codec_read(codec, nid, 0, | ||
931 | AC_VERB_GET_CONFIG_DEFAULT, 0); | ||
932 | return get_defcfg_connect(conf) != AC_JACK_PORT_NONE; | ||
933 | } | ||
934 | |||
875 | static int patch_ad1986a(struct hda_codec *codec) | 935 | static int patch_ad1986a(struct hda_codec *codec) |
876 | { | 936 | { |
877 | struct ad198x_spec *spec; | 937 | struct ad198x_spec *spec; |
@@ -898,6 +958,7 @@ static int patch_ad1986a(struct hda_codec *codec) | |||
898 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 958 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
899 | spec->loopback.amplist = ad1986a_loopbacks; | 959 | spec->loopback.amplist = ad1986a_loopbacks; |
900 | #endif | 960 | #endif |
961 | spec->vmaster_nid = 0x1b; | ||
901 | 962 | ||
902 | codec->patch_ops = ad198x_patch_ops; | 963 | codec->patch_ops = ad198x_patch_ops; |
903 | 964 | ||
@@ -930,7 +991,8 @@ static int patch_ad1986a(struct hda_codec *codec) | |||
930 | spec->multiout.max_channels = 2; | 991 | spec->multiout.max_channels = 2; |
931 | spec->multiout.num_dacs = 1; | 992 | spec->multiout.num_dacs = 1; |
932 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | 993 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; |
933 | spec->multiout.dig_out_nid = 0; | 994 | if (!is_jack_available(codec, 0x25)) |
995 | spec->multiout.dig_out_nid = 0; | ||
934 | spec->input_mux = &ad1986a_laptop_eapd_capture_source; | 996 | spec->input_mux = &ad1986a_laptop_eapd_capture_source; |
935 | break; | 997 | break; |
936 | case AD1986A_LAPTOP_AUTOMUTE: | 998 | case AD1986A_LAPTOP_AUTOMUTE: |
@@ -941,7 +1003,8 @@ static int patch_ad1986a(struct hda_codec *codec) | |||
941 | spec->multiout.max_channels = 2; | 1003 | spec->multiout.max_channels = 2; |
942 | spec->multiout.num_dacs = 1; | 1004 | spec->multiout.num_dacs = 1; |
943 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | 1005 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; |
944 | spec->multiout.dig_out_nid = 0; | 1006 | if (!is_jack_available(codec, 0x25)) |
1007 | spec->multiout.dig_out_nid = 0; | ||
945 | spec->input_mux = &ad1986a_laptop_eapd_capture_source; | 1008 | spec->input_mux = &ad1986a_laptop_eapd_capture_source; |
946 | codec->patch_ops.unsol_event = ad1986a_hp_unsol_event; | 1009 | codec->patch_ops.unsol_event = ad1986a_hp_unsol_event; |
947 | codec->patch_ops.init = ad1986a_hp_init; | 1010 | codec->patch_ops.init = ad1986a_hp_init; |
@@ -1020,6 +1083,8 @@ static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
1020 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 1083 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
1021 | struct ad198x_spec *spec = codec->spec; | 1084 | struct ad198x_spec *spec = codec->spec; |
1022 | 1085 | ||
1086 | if (ucontrol->value.enumerated.item[0] > 1) | ||
1087 | return -EINVAL; | ||
1023 | if (spec->spdif_route != ucontrol->value.enumerated.item[0]) { | 1088 | if (spec->spdif_route != ucontrol->value.enumerated.item[0]) { |
1024 | spec->spdif_route = ucontrol->value.enumerated.item[0]; | 1089 | spec->spdif_route = ucontrol->value.enumerated.item[0]; |
1025 | snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0, | 1090 | snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0, |
@@ -1138,6 +1203,7 @@ static int patch_ad1983(struct hda_codec *codec) | |||
1138 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 1203 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
1139 | spec->loopback.amplist = ad1983_loopbacks; | 1204 | spec->loopback.amplist = ad1983_loopbacks; |
1140 | #endif | 1205 | #endif |
1206 | spec->vmaster_nid = 0x05; | ||
1141 | 1207 | ||
1142 | codec->patch_ops = ad198x_patch_ops; | 1208 | codec->patch_ops = ad198x_patch_ops; |
1143 | 1209 | ||
@@ -1496,14 +1562,14 @@ static const char *ad1981_models[AD1981_MODELS] = { | |||
1496 | }; | 1562 | }; |
1497 | 1563 | ||
1498 | static struct snd_pci_quirk ad1981_cfg_tbl[] = { | 1564 | static struct snd_pci_quirk ad1981_cfg_tbl[] = { |
1565 | SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD), | ||
1499 | /* All HP models */ | 1566 | /* All HP models */ |
1500 | SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP), | 1567 | SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP), |
1501 | /* HP nx6320 (reversed SSID, H/W bug) */ | 1568 | SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA), |
1502 | SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP), | ||
1503 | /* Lenovo Thinkpad T60/X60/Z6xx */ | 1569 | /* Lenovo Thinkpad T60/X60/Z6xx */ |
1504 | SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1981_THINKPAD), | 1570 | SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1981_THINKPAD), |
1505 | SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD), | 1571 | /* HP nx6320 (reversed SSID, H/W bug) */ |
1506 | SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA), | 1572 | SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP), |
1507 | {} | 1573 | {} |
1508 | }; | 1574 | }; |
1509 | 1575 | ||
@@ -1534,6 +1600,7 @@ static int patch_ad1981(struct hda_codec *codec) | |||
1534 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 1600 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
1535 | spec->loopback.amplist = ad1981_loopbacks; | 1601 | spec->loopback.amplist = ad1981_loopbacks; |
1536 | #endif | 1602 | #endif |
1603 | spec->vmaster_nid = 0x05; | ||
1537 | 1604 | ||
1538 | codec->patch_ops = ad198x_patch_ops; | 1605 | codec->patch_ops = ad198x_patch_ops; |
1539 | 1606 | ||
@@ -1908,7 +1975,6 @@ static struct snd_kcontrol_new ad1988_capture_mixers[] = { | |||
1908 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1975 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1909 | /* The multiple "Capture Source" controls confuse alsamixer | 1976 | /* The multiple "Capture Source" controls confuse alsamixer |
1910 | * So call somewhat different.. | 1977 | * So call somewhat different.. |
1911 | * FIXME: the controls appear in the "playback" view! | ||
1912 | */ | 1978 | */ |
1913 | /* .name = "Capture Source", */ | 1979 | /* .name = "Capture Source", */ |
1914 | .name = "Input Source", | 1980 | .name = "Input Source", |
@@ -1965,6 +2031,8 @@ static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol, | |||
1965 | int change; | 2031 | int change; |
1966 | 2032 | ||
1967 | val = ucontrol->value.enumerated.item[0]; | 2033 | val = ucontrol->value.enumerated.item[0]; |
2034 | if (val > 3) | ||
2035 | return -EINVAL; | ||
1968 | if (!val) { | 2036 | if (!val) { |
1969 | sel = snd_hda_codec_read(codec, 0x1d, 0, | 2037 | sel = snd_hda_codec_read(codec, 0x1d, 0, |
1970 | AC_VERB_GET_AMP_GAIN_MUTE, | 2038 | AC_VERB_GET_AMP_GAIN_MUTE, |
@@ -2079,6 +2147,8 @@ static struct hda_verb ad1988_6stack_init_verbs[] = { | |||
2079 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 2147 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
2080 | {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | 2148 | {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, |
2081 | {0x34, AC_VERB_SET_CONNECT_SEL, 0x0}, | 2149 | {0x34, AC_VERB_SET_CONNECT_SEL, 0x0}, |
2150 | /* Analog CD Input */ | ||
2151 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
2082 | 2152 | ||
2083 | { } | 2153 | { } |
2084 | }; | 2154 | }; |
@@ -2720,8 +2790,8 @@ static const char *ad1988_models[AD1988_MODEL_LAST] = { | |||
2720 | }; | 2790 | }; |
2721 | 2791 | ||
2722 | static struct snd_pci_quirk ad1988_cfg_tbl[] = { | 2792 | static struct snd_pci_quirk ad1988_cfg_tbl[] = { |
2723 | SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG), | ||
2724 | SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG), | 2793 | SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG), |
2794 | SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG), | ||
2725 | {} | 2795 | {} |
2726 | }; | 2796 | }; |
2727 | 2797 | ||
@@ -2843,6 +2913,7 @@ static int patch_ad1988(struct hda_codec *codec) | |||
2843 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 2913 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
2844 | spec->loopback.amplist = ad1988_loopbacks; | 2914 | spec->loopback.amplist = ad1988_loopbacks; |
2845 | #endif | 2915 | #endif |
2916 | spec->vmaster_nid = 0x04; | ||
2846 | 2917 | ||
2847 | return 0; | 2918 | return 0; |
2848 | } | 2919 | } |
@@ -2919,7 +2990,6 @@ static struct snd_kcontrol_new ad1884_base_mixers[] = { | |||
2919 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2990 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2920 | /* The multiple "Capture Source" controls confuse alsamixer | 2991 | /* The multiple "Capture Source" controls confuse alsamixer |
2921 | * So call somewhat different.. | 2992 | * So call somewhat different.. |
2922 | * FIXME: the controls appear in the "playback" view! | ||
2923 | */ | 2993 | */ |
2924 | /* .name = "Capture Source", */ | 2994 | /* .name = "Capture Source", */ |
2925 | .name = "Input Source", | 2995 | .name = "Input Source", |
@@ -3009,6 +3079,20 @@ static struct hda_amp_list ad1884_loopbacks[] = { | |||
3009 | }; | 3079 | }; |
3010 | #endif | 3080 | #endif |
3011 | 3081 | ||
3082 | static const char *ad1884_slave_vols[] = { | ||
3083 | "PCM Playback Volume", | ||
3084 | "Mic Playback Volume", | ||
3085 | "Mono Playback Volume", | ||
3086 | "Front Mic Playback Volume", | ||
3087 | "Mic Playback Volume", | ||
3088 | "CD Playback Volume", | ||
3089 | "Internal Mic Playback Volume", | ||
3090 | "Docking Mic Playback Volume" | ||
3091 | "Beep Playback Volume", | ||
3092 | "IEC958 Playback Volume", | ||
3093 | NULL | ||
3094 | }; | ||
3095 | |||
3012 | static int patch_ad1884(struct hda_codec *codec) | 3096 | static int patch_ad1884(struct hda_codec *codec) |
3013 | { | 3097 | { |
3014 | struct ad198x_spec *spec; | 3098 | struct ad198x_spec *spec; |
@@ -3036,6 +3120,9 @@ static int patch_ad1884(struct hda_codec *codec) | |||
3036 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 3120 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
3037 | spec->loopback.amplist = ad1884_loopbacks; | 3121 | spec->loopback.amplist = ad1884_loopbacks; |
3038 | #endif | 3122 | #endif |
3123 | spec->vmaster_nid = 0x04; | ||
3124 | /* we need to cover all playback volumes */ | ||
3125 | spec->slave_vols = ad1884_slave_vols; | ||
3039 | 3126 | ||
3040 | codec->patch_ops = ad198x_patch_ops; | 3127 | codec->patch_ops = ad198x_patch_ops; |
3041 | 3128 | ||
@@ -3054,6 +3141,20 @@ static struct hda_input_mux ad1984_thinkpad_capture_source = { | |||
3054 | }, | 3141 | }, |
3055 | }; | 3142 | }; |
3056 | 3143 | ||
3144 | |||
3145 | /* | ||
3146 | * Dell Precision T3400 | ||
3147 | */ | ||
3148 | static struct hda_input_mux ad1984_dell_desktop_capture_source = { | ||
3149 | .num_items = 3, | ||
3150 | .items = { | ||
3151 | { "Front Mic", 0x0 }, | ||
3152 | { "Line-In", 0x1 }, | ||
3153 | { "Mix", 0x3 }, | ||
3154 | }, | ||
3155 | }; | ||
3156 | |||
3157 | |||
3057 | static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = { | 3158 | static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = { |
3058 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), | 3159 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), |
3059 | /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */ | 3160 | /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */ |
@@ -3078,7 +3179,6 @@ static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = { | |||
3078 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 3179 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
3079 | /* The multiple "Capture Source" controls confuse alsamixer | 3180 | /* The multiple "Capture Source" controls confuse alsamixer |
3080 | * So call somewhat different.. | 3181 | * So call somewhat different.. |
3081 | * FIXME: the controls appear in the "playback" view! | ||
3082 | */ | 3182 | */ |
3083 | /* .name = "Capture Source", */ | 3183 | /* .name = "Capture Source", */ |
3084 | .name = "Input Source", | 3184 | .name = "Input Source", |
@@ -3087,6 +3187,16 @@ static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = { | |||
3087 | .get = ad198x_mux_enum_get, | 3187 | .get = ad198x_mux_enum_get, |
3088 | .put = ad198x_mux_enum_put, | 3188 | .put = ad198x_mux_enum_put, |
3089 | }, | 3189 | }, |
3190 | /* SPDIF controls */ | ||
3191 | HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
3192 | { | ||
3193 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3194 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
3195 | /* identical with ad1983 */ | ||
3196 | .info = ad1983_spdif_route_info, | ||
3197 | .get = ad1983_spdif_route_get, | ||
3198 | .put = ad1983_spdif_route_put, | ||
3199 | }, | ||
3090 | { } /* end */ | 3200 | { } /* end */ |
3091 | }; | 3201 | }; |
3092 | 3202 | ||
@@ -3104,6 +3214,44 @@ static struct hda_verb ad1984_thinkpad_init_verbs[] = { | |||
3104 | { } /* end */ | 3214 | { } /* end */ |
3105 | }; | 3215 | }; |
3106 | 3216 | ||
3217 | /* | ||
3218 | * Dell Precision T3400 | ||
3219 | */ | ||
3220 | static struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = { | ||
3221 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
3222 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
3223 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
3224 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), | ||
3225 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), | ||
3226 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
3227 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
3228 | HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
3229 | HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
3230 | /* | ||
3231 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x20, 0x03, HDA_INPUT), | ||
3232 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x20, 0x03, HDA_INPUT), | ||
3233 | */ | ||
3234 | HDA_CODEC_VOLUME("Line-In Boost", 0x15, 0x0, HDA_INPUT), | ||
3235 | HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT), | ||
3236 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
3237 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
3238 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3239 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3240 | { | ||
3241 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3242 | /* The multiple "Capture Source" controls confuse alsamixer | ||
3243 | * So call somewhat different.. | ||
3244 | */ | ||
3245 | /* .name = "Capture Source", */ | ||
3246 | .name = "Input Source", | ||
3247 | .count = 2, | ||
3248 | .info = ad198x_mux_enum_info, | ||
3249 | .get = ad198x_mux_enum_get, | ||
3250 | .put = ad198x_mux_enum_put, | ||
3251 | }, | ||
3252 | { } /* end */ | ||
3253 | }; | ||
3254 | |||
3107 | /* Digial MIC ADC NID 0x05 + 0x06 */ | 3255 | /* Digial MIC ADC NID 0x05 + 0x06 */ |
3108 | static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo, | 3256 | static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo, |
3109 | struct hda_codec *codec, | 3257 | struct hda_codec *codec, |
@@ -3157,17 +3305,20 @@ static int ad1984_build_pcms(struct hda_codec *codec) | |||
3157 | enum { | 3305 | enum { |
3158 | AD1984_BASIC, | 3306 | AD1984_BASIC, |
3159 | AD1984_THINKPAD, | 3307 | AD1984_THINKPAD, |
3308 | AD1984_DELL_DESKTOP, | ||
3160 | AD1984_MODELS | 3309 | AD1984_MODELS |
3161 | }; | 3310 | }; |
3162 | 3311 | ||
3163 | static const char *ad1984_models[AD1984_MODELS] = { | 3312 | static const char *ad1984_models[AD1984_MODELS] = { |
3164 | [AD1984_BASIC] = "basic", | 3313 | [AD1984_BASIC] = "basic", |
3165 | [AD1984_THINKPAD] = "thinkpad", | 3314 | [AD1984_THINKPAD] = "thinkpad", |
3315 | [AD1984_DELL_DESKTOP] = "dell_desktop", | ||
3166 | }; | 3316 | }; |
3167 | 3317 | ||
3168 | static struct snd_pci_quirk ad1984_cfg_tbl[] = { | 3318 | static struct snd_pci_quirk ad1984_cfg_tbl[] = { |
3169 | /* Lenovo Thinkpad T61/X61 */ | 3319 | /* Lenovo Thinkpad T61/X61 */ |
3170 | SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1984_THINKPAD), | 3320 | SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1984_THINKPAD), |
3321 | SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP), | ||
3171 | {} | 3322 | {} |
3172 | }; | 3323 | }; |
3173 | 3324 | ||
@@ -3189,11 +3340,16 @@ static int patch_ad1984(struct hda_codec *codec) | |||
3189 | codec->patch_ops.build_pcms = ad1984_build_pcms; | 3340 | codec->patch_ops.build_pcms = ad1984_build_pcms; |
3190 | break; | 3341 | break; |
3191 | case AD1984_THINKPAD: | 3342 | case AD1984_THINKPAD: |
3192 | spec->multiout.dig_out_nid = 0; | 3343 | spec->multiout.dig_out_nid = AD1884_SPDIF_OUT; |
3193 | spec->input_mux = &ad1984_thinkpad_capture_source; | 3344 | spec->input_mux = &ad1984_thinkpad_capture_source; |
3194 | spec->mixers[0] = ad1984_thinkpad_mixers; | 3345 | spec->mixers[0] = ad1984_thinkpad_mixers; |
3195 | spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs; | 3346 | spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs; |
3196 | break; | 3347 | break; |
3348 | case AD1984_DELL_DESKTOP: | ||
3349 | spec->multiout.dig_out_nid = 0; | ||
3350 | spec->input_mux = &ad1984_dell_desktop_capture_source; | ||
3351 | spec->mixers[0] = ad1984_dell_desktop_mixers; | ||
3352 | break; | ||
3197 | } | 3353 | } |
3198 | return 0; | 3354 | return 0; |
3199 | } | 3355 | } |
@@ -3267,7 +3423,6 @@ static struct snd_kcontrol_new ad1882_base_mixers[] = { | |||
3267 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 3423 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
3268 | /* The multiple "Capture Source" controls confuse alsamixer | 3424 | /* The multiple "Capture Source" controls confuse alsamixer |
3269 | * So call somewhat different.. | 3425 | * So call somewhat different.. |
3270 | * FIXME: the controls appear in the "playback" view! | ||
3271 | */ | 3426 | */ |
3272 | /* .name = "Capture Source", */ | 3427 | /* .name = "Capture Source", */ |
3273 | .name = "Input Source", | 3428 | .name = "Input Source", |
@@ -3468,6 +3623,7 @@ static int patch_ad1882(struct hda_codec *codec) | |||
3468 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 3623 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
3469 | spec->loopback.amplist = ad1882_loopbacks; | 3624 | spec->loopback.amplist = ad1882_loopbacks; |
3470 | #endif | 3625 | #endif |
3626 | spec->vmaster_nid = 0x04; | ||
3471 | 3627 | ||
3472 | codec->patch_ops = ad198x_patch_ops; | 3628 | codec->patch_ops = ad198x_patch_ops; |
3473 | 3629 | ||
diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c index fbb8969dc559..9a8bb4ce3f8d 100644 --- a/sound/pci/hda/patch_atihdmi.c +++ b/sound/pci/hda/patch_atihdmi.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
27 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
@@ -158,6 +157,6 @@ struct hda_codec_preset snd_hda_preset_atihdmi[] = { | |||
158 | { .id = 0x1002793c, .name = "ATI RS600 HDMI", .patch = patch_atihdmi }, | 157 | { .id = 0x1002793c, .name = "ATI RS600 HDMI", .patch = patch_atihdmi }, |
159 | { .id = 0x10027919, .name = "ATI RS600 HDMI", .patch = patch_atihdmi }, | 158 | { .id = 0x10027919, .name = "ATI RS600 HDMI", .patch = patch_atihdmi }, |
160 | { .id = 0x1002791a, .name = "ATI RS690/780 HDMI", .patch = patch_atihdmi }, | 159 | { .id = 0x1002791a, .name = "ATI RS690/780 HDMI", .patch = patch_atihdmi }, |
161 | { .id = 0x1002aa01, .name = "ATI R600 HDMI", .patch = patch_atihdmi }, | 160 | { .id = 0x1002aa01, .name = "ATI R6xx HDMI", .patch = patch_atihdmi }, |
162 | {} /* terminator */ | 161 | {} /* terminator */ |
163 | }; | 162 | }; |
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 6c54793bf424..3d6097ba1d68 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
27 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
@@ -186,7 +185,6 @@ static struct snd_kcontrol_new cmi9880_basic_mixer[] = { | |||
186 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 185 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
187 | /* The multiple "Capture Source" controls confuse alsamixer | 186 | /* The multiple "Capture Source" controls confuse alsamixer |
188 | * So call somewhat different.. | 187 | * So call somewhat different.. |
189 | * FIXME: the controls appear in the "playback" view! | ||
190 | */ | 188 | */ |
191 | /* .name = "Capture Source", */ | 189 | /* .name = "Capture Source", */ |
192 | .name = "Input Source", | 190 | .name = "Input Source", |
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 6aa073986747..f6dd51cda7b2 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
26 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
@@ -65,6 +64,11 @@ struct conexant_spec { | |||
65 | hda_nid_t *adc_nids; | 64 | hda_nid_t *adc_nids; |
66 | hda_nid_t dig_in_nid; /* digital-in NID; optional */ | 65 | hda_nid_t dig_in_nid; /* digital-in NID; optional */ |
67 | 66 | ||
67 | unsigned int cur_adc_idx; | ||
68 | hda_nid_t cur_adc; | ||
69 | unsigned int cur_adc_stream_tag; | ||
70 | unsigned int cur_adc_format; | ||
71 | |||
68 | /* capture source */ | 72 | /* capture source */ |
69 | const struct hda_input_mux *input_mux; | 73 | const struct hda_input_mux *input_mux; |
70 | hda_nid_t *capsrc_nids; | 74 | hda_nid_t *capsrc_nids; |
@@ -218,6 +222,41 @@ static struct hda_pcm_stream conexant_pcm_digital_capture = { | |||
218 | /* NID is set in alc_build_pcms */ | 222 | /* NID is set in alc_build_pcms */ |
219 | }; | 223 | }; |
220 | 224 | ||
225 | static int cx5051_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
226 | struct hda_codec *codec, | ||
227 | unsigned int stream_tag, | ||
228 | unsigned int format, | ||
229 | struct snd_pcm_substream *substream) | ||
230 | { | ||
231 | struct conexant_spec *spec = codec->spec; | ||
232 | spec->cur_adc = spec->adc_nids[spec->cur_adc_idx]; | ||
233 | spec->cur_adc_stream_tag = stream_tag; | ||
234 | spec->cur_adc_format = format; | ||
235 | snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); | ||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static int cx5051_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
240 | struct hda_codec *codec, | ||
241 | struct snd_pcm_substream *substream) | ||
242 | { | ||
243 | struct conexant_spec *spec = codec->spec; | ||
244 | snd_hda_codec_setup_stream(codec, spec->cur_adc, 0, 0, 0); | ||
245 | spec->cur_adc = 0; | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | static struct hda_pcm_stream cx5051_pcm_analog_capture = { | ||
250 | .substreams = 1, | ||
251 | .channels_min = 2, | ||
252 | .channels_max = 2, | ||
253 | .nid = 0, /* fill later */ | ||
254 | .ops = { | ||
255 | .prepare = cx5051_capture_pcm_prepare, | ||
256 | .cleanup = cx5051_capture_pcm_cleanup | ||
257 | }, | ||
258 | }; | ||
259 | |||
221 | static int conexant_build_pcms(struct hda_codec *codec) | 260 | static int conexant_build_pcms(struct hda_codec *codec) |
222 | { | 261 | { |
223 | struct conexant_spec *spec = codec->spec; | 262 | struct conexant_spec *spec = codec->spec; |
@@ -232,7 +271,12 @@ static int conexant_build_pcms(struct hda_codec *codec) | |||
232 | spec->multiout.max_channels; | 271 | spec->multiout.max_channels; |
233 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = | 272 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = |
234 | spec->multiout.dac_nids[0]; | 273 | spec->multiout.dac_nids[0]; |
235 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = conexant_pcm_analog_capture; | 274 | if (codec->vendor_id == 0x14f15051) |
275 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = | ||
276 | cx5051_pcm_analog_capture; | ||
277 | else | ||
278 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = | ||
279 | conexant_pcm_analog_capture; | ||
236 | info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids; | 280 | info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids; |
237 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; | 281 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; |
238 | 282 | ||
@@ -373,7 +417,7 @@ static int cxt_eapd_put(struct snd_kcontrol *kcontrol, | |||
373 | hda_nid_t nid = kcontrol->private_value & 0xff; | 417 | hda_nid_t nid = kcontrol->private_value & 0xff; |
374 | unsigned int eapd; | 418 | unsigned int eapd; |
375 | 419 | ||
376 | eapd = ucontrol->value.integer.value[0]; | 420 | eapd = !!ucontrol->value.integer.value[0]; |
377 | if (invert) | 421 | if (invert) |
378 | eapd = !eapd; | 422 | eapd = !eapd; |
379 | if (eapd == spec->cur_eapd) | 423 | if (eapd == spec->cur_eapd) |
@@ -454,7 +498,16 @@ static struct hda_input_mux cxt5045_capture_source = { | |||
454 | .num_items = 2, | 498 | .num_items = 2, |
455 | .items = { | 499 | .items = { |
456 | { "IntMic", 0x1 }, | 500 | { "IntMic", 0x1 }, |
457 | { "LineIn", 0x2 }, | 501 | { "ExtMic", 0x2 }, |
502 | } | ||
503 | }; | ||
504 | |||
505 | static struct hda_input_mux cxt5045_capture_source_benq = { | ||
506 | .num_items = 3, | ||
507 | .items = { | ||
508 | { "IntMic", 0x1 }, | ||
509 | { "ExtMic", 0x2 }, | ||
510 | { "LineIn", 0x3 }, | ||
458 | } | 511 | } |
459 | }; | 512 | }; |
460 | 513 | ||
@@ -577,6 +630,15 @@ static struct snd_kcontrol_new cxt5045_mixers[] = { | |||
577 | {} | 630 | {} |
578 | }; | 631 | }; |
579 | 632 | ||
633 | static struct snd_kcontrol_new cxt5045_benq_mixers[] = { | ||
634 | HDA_CODEC_VOLUME("Line In Capture Volume", 0x1a, 0x03, HDA_INPUT), | ||
635 | HDA_CODEC_MUTE("Line In Capture Switch", 0x1a, 0x03, HDA_INPUT), | ||
636 | HDA_CODEC_VOLUME("Line In Playback Volume", 0x17, 0x3, HDA_INPUT), | ||
637 | HDA_CODEC_MUTE("Line In Playback Switch", 0x17, 0x3, HDA_INPUT), | ||
638 | |||
639 | {} | ||
640 | }; | ||
641 | |||
580 | static struct hda_verb cxt5045_init_verbs[] = { | 642 | static struct hda_verb cxt5045_init_verbs[] = { |
581 | /* Line in, Mic */ | 643 | /* Line in, Mic */ |
582 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, | 644 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, |
@@ -602,6 +664,30 @@ static struct hda_verb cxt5045_init_verbs[] = { | |||
602 | { } /* end */ | 664 | { } /* end */ |
603 | }; | 665 | }; |
604 | 666 | ||
667 | static struct hda_verb cxt5045_benq_init_verbs[] = { | ||
668 | /* Int Mic, Mic */ | ||
669 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, | ||
670 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, | ||
671 | /* Line In,HP, Amp */ | ||
672 | {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
673 | {0x10, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
674 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
675 | {0x11, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
676 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
677 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
678 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
679 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
680 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
681 | /* Record selector: Int mic */ | ||
682 | {0x1a, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
683 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, | ||
684 | AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, | ||
685 | /* SPDIF route: PCM */ | ||
686 | {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
687 | /* EAPD */ | ||
688 | {0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | ||
689 | { } /* end */ | ||
690 | }; | ||
605 | 691 | ||
606 | static struct hda_verb cxt5045_hp_sense_init_verbs[] = { | 692 | static struct hda_verb cxt5045_hp_sense_init_verbs[] = { |
607 | /* pin sensing on HP jack */ | 693 | /* pin sensing on HP jack */ |
@@ -740,8 +826,10 @@ static int cxt5045_init(struct hda_codec *codec) | |||
740 | 826 | ||
741 | 827 | ||
742 | enum { | 828 | enum { |
743 | CXT5045_LAPTOP, /* Laptops w/ EAPD support */ | 829 | CXT5045_LAPTOP_HPSENSE, |
744 | CXT5045_FUJITSU, /* Laptops w/ EAPD support */ | 830 | CXT5045_LAPTOP_MICSENSE, |
831 | CXT5045_LAPTOP_HPMICSENSE, | ||
832 | CXT5045_BENQ, | ||
745 | #ifdef CONFIG_SND_DEBUG | 833 | #ifdef CONFIG_SND_DEBUG |
746 | CXT5045_TEST, | 834 | CXT5045_TEST, |
747 | #endif | 835 | #endif |
@@ -749,23 +837,35 @@ enum { | |||
749 | }; | 837 | }; |
750 | 838 | ||
751 | static const char *cxt5045_models[CXT5045_MODELS] = { | 839 | static const char *cxt5045_models[CXT5045_MODELS] = { |
752 | [CXT5045_LAPTOP] = "laptop", | 840 | [CXT5045_LAPTOP_HPSENSE] = "laptop-hpsense", |
753 | [CXT5045_FUJITSU] = "fujitsu", | 841 | [CXT5045_LAPTOP_MICSENSE] = "laptop-micsense", |
842 | [CXT5045_LAPTOP_HPMICSENSE] = "laptop-hpmicsense", | ||
843 | [CXT5045_BENQ] = "benq", | ||
754 | #ifdef CONFIG_SND_DEBUG | 844 | #ifdef CONFIG_SND_DEBUG |
755 | [CXT5045_TEST] = "test", | 845 | [CXT5045_TEST] = "test", |
756 | #endif | 846 | #endif |
757 | }; | 847 | }; |
758 | 848 | ||
759 | static struct snd_pci_quirk cxt5045_cfg_tbl[] = { | 849 | static struct snd_pci_quirk cxt5045_cfg_tbl[] = { |
760 | SND_PCI_QUIRK(0x103c, 0x30b7, "HP DV6000Z", CXT5045_LAPTOP), | 850 | SND_PCI_QUIRK(0x103c, 0x30a5, "HP", CXT5045_LAPTOP_HPSENSE), |
761 | SND_PCI_QUIRK(0x103c, 0x30bb, "HP DV8000", CXT5045_LAPTOP), | 851 | SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV Series", CXT5045_LAPTOP_HPSENSE), |
762 | SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV Series", CXT5045_LAPTOP), | 852 | SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2120", CXT5045_LAPTOP_HPSENSE), |
763 | SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2120", CXT5045_LAPTOP), | 853 | SND_PCI_QUIRK(0x103c, 0x30b7, "HP DV6000Z", CXT5045_LAPTOP_HPSENSE), |
764 | SND_PCI_QUIRK(0x103c, 0x30cd, "HP DV Series", CXT5045_LAPTOP), | 854 | SND_PCI_QUIRK(0x103c, 0x30bb, "HP DV8000", CXT5045_LAPTOP_HPSENSE), |
765 | SND_PCI_QUIRK(0x103c, 0x30d9, "HP Spartan", CXT5045_LAPTOP), | 855 | SND_PCI_QUIRK(0x103c, 0x30cd, "HP DV Series", CXT5045_LAPTOP_HPSENSE), |
766 | SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_FUJITSU), | 856 | SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV9533EG", CXT5045_LAPTOP_HPSENSE), |
767 | SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP), | 857 | SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HPSENSE), |
768 | SND_PCI_QUIRK(0x8086, 0x2111, "Conexant Reference board", CXT5045_LAPTOP), | 858 | SND_PCI_QUIRK(0x103c, 0x30d9, "HP Spartan", CXT5045_LAPTOP_HPSENSE), |
859 | SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ), | ||
860 | SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE), | ||
861 | SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP_HPMICSENSE), | ||
862 | SND_PCI_QUIRK(0x1734, 0x110e, "Fujitsu V5505", CXT5045_LAPTOP_HPSENSE), | ||
863 | SND_PCI_QUIRK(0x1509, 0x1e40, "FIC", CXT5045_LAPTOP_HPMICSENSE), | ||
864 | SND_PCI_QUIRK(0x1509, 0x2f05, "FIC", CXT5045_LAPTOP_HPMICSENSE), | ||
865 | SND_PCI_QUIRK(0x1509, 0x2f06, "FIC", CXT5045_LAPTOP_HPMICSENSE), | ||
866 | SND_PCI_QUIRK(0x1631, 0xc106, "Packard Bell", CXT5045_LAPTOP_HPMICSENSE), | ||
867 | SND_PCI_QUIRK(0x1631, 0xc107, "Packard Bell", CXT5045_LAPTOP_HPMICSENSE), | ||
868 | SND_PCI_QUIRK(0x8086, 0x2111, "Conexant Reference board", CXT5045_LAPTOP_HPSENSE), | ||
769 | {} | 869 | {} |
770 | }; | 870 | }; |
771 | 871 | ||
@@ -803,7 +903,7 @@ static int patch_cxt5045(struct hda_codec *codec) | |||
803 | cxt5045_models, | 903 | cxt5045_models, |
804 | cxt5045_cfg_tbl); | 904 | cxt5045_cfg_tbl); |
805 | switch (board_config) { | 905 | switch (board_config) { |
806 | case CXT5045_LAPTOP: | 906 | case CXT5045_LAPTOP_HPSENSE: |
807 | codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; | 907 | codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; |
808 | spec->input_mux = &cxt5045_capture_source; | 908 | spec->input_mux = &cxt5045_capture_source; |
809 | spec->num_init_verbs = 2; | 909 | spec->num_init_verbs = 2; |
@@ -811,20 +911,53 @@ static int patch_cxt5045(struct hda_codec *codec) | |||
811 | spec->mixers[0] = cxt5045_mixers; | 911 | spec->mixers[0] = cxt5045_mixers; |
812 | codec->patch_ops.init = cxt5045_init; | 912 | codec->patch_ops.init = cxt5045_init; |
813 | break; | 913 | break; |
814 | case CXT5045_FUJITSU: | 914 | case CXT5045_LAPTOP_MICSENSE: |
815 | spec->input_mux = &cxt5045_capture_source; | 915 | spec->input_mux = &cxt5045_capture_source; |
816 | spec->num_init_verbs = 2; | 916 | spec->num_init_verbs = 2; |
817 | spec->init_verbs[1] = cxt5045_mic_sense_init_verbs; | 917 | spec->init_verbs[1] = cxt5045_mic_sense_init_verbs; |
818 | spec->mixers[0] = cxt5045_mixers; | 918 | spec->mixers[0] = cxt5045_mixers; |
819 | codec->patch_ops.init = cxt5045_init; | 919 | codec->patch_ops.init = cxt5045_init; |
820 | break; | 920 | break; |
921 | default: | ||
922 | case CXT5045_LAPTOP_HPMICSENSE: | ||
923 | codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; | ||
924 | spec->input_mux = &cxt5045_capture_source; | ||
925 | spec->num_init_verbs = 3; | ||
926 | spec->init_verbs[1] = cxt5045_hp_sense_init_verbs; | ||
927 | spec->init_verbs[2] = cxt5045_mic_sense_init_verbs; | ||
928 | spec->mixers[0] = cxt5045_mixers; | ||
929 | codec->patch_ops.init = cxt5045_init; | ||
930 | break; | ||
931 | case CXT5045_BENQ: | ||
932 | codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; | ||
933 | spec->input_mux = &cxt5045_capture_source_benq; | ||
934 | spec->num_init_verbs = 1; | ||
935 | spec->init_verbs[0] = cxt5045_benq_init_verbs; | ||
936 | spec->mixers[0] = cxt5045_mixers; | ||
937 | spec->mixers[1] = cxt5045_benq_mixers; | ||
938 | spec->num_mixers = 2; | ||
939 | codec->patch_ops.init = cxt5045_init; | ||
940 | break; | ||
821 | #ifdef CONFIG_SND_DEBUG | 941 | #ifdef CONFIG_SND_DEBUG |
822 | case CXT5045_TEST: | 942 | case CXT5045_TEST: |
823 | spec->input_mux = &cxt5045_test_capture_source; | 943 | spec->input_mux = &cxt5045_test_capture_source; |
824 | spec->mixers[0] = cxt5045_test_mixer; | 944 | spec->mixers[0] = cxt5045_test_mixer; |
825 | spec->init_verbs[0] = cxt5045_test_init_verbs; | 945 | spec->init_verbs[0] = cxt5045_test_init_verbs; |
946 | break; | ||
947 | |||
826 | #endif | 948 | #endif |
827 | } | 949 | } |
950 | |||
951 | /* | ||
952 | * Fix max PCM level to 0 dB | ||
953 | * (originall it has 0x2b steps with 0dB offset 0x14) | ||
954 | */ | ||
955 | snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT, | ||
956 | (0x14 << AC_AMPCAP_OFFSET_SHIFT) | | ||
957 | (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||
958 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
959 | (1 << AC_AMPCAP_MUTE_SHIFT)); | ||
960 | |||
828 | return 0; | 961 | return 0; |
829 | } | 962 | } |
830 | 963 | ||
@@ -933,13 +1066,13 @@ static void cxt5047_hp2_automute(struct hda_codec *codec) | |||
933 | static void cxt5047_hp_automic(struct hda_codec *codec) | 1066 | static void cxt5047_hp_automic(struct hda_codec *codec) |
934 | { | 1067 | { |
935 | static struct hda_verb mic_jack_on[] = { | 1068 | static struct hda_verb mic_jack_on[] = { |
936 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | 1069 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, |
937 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | 1070 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
938 | {} | 1071 | {} |
939 | }; | 1072 | }; |
940 | static struct hda_verb mic_jack_off[] = { | 1073 | static struct hda_verb mic_jack_off[] = { |
941 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | 1074 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, |
942 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | 1075 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
943 | {} | 1076 | {} |
944 | }; | 1077 | }; |
945 | unsigned int present; | 1078 | unsigned int present; |
@@ -956,8 +1089,7 @@ static void cxt5047_hp_automic(struct hda_codec *codec) | |||
956 | static void cxt5047_hp_unsol_event(struct hda_codec *codec, | 1089 | static void cxt5047_hp_unsol_event(struct hda_codec *codec, |
957 | unsigned int res) | 1090 | unsigned int res) |
958 | { | 1091 | { |
959 | res >>= 26; | 1092 | switch (res >> 26) { |
960 | switch (res) { | ||
961 | case CONEXANT_HP_EVENT: | 1093 | case CONEXANT_HP_EVENT: |
962 | cxt5047_hp_automute(codec); | 1094 | cxt5047_hp_automute(codec); |
963 | break; | 1095 | break; |
@@ -1166,6 +1298,17 @@ static struct snd_kcontrol_new cxt5047_test_mixer[] = { | |||
1166 | .get = conexant_mux_enum_get, | 1298 | .get = conexant_mux_enum_get, |
1167 | .put = conexant_mux_enum_put, | 1299 | .put = conexant_mux_enum_put, |
1168 | }, | 1300 | }, |
1301 | HDA_CODEC_VOLUME("Input-1 Volume", 0x1a, 0x0, HDA_INPUT), | ||
1302 | HDA_CODEC_MUTE("Input-1 Switch", 0x1a, 0x0, HDA_INPUT), | ||
1303 | HDA_CODEC_VOLUME("Input-2 Volume", 0x1a, 0x1, HDA_INPUT), | ||
1304 | HDA_CODEC_MUTE("Input-2 Switch", 0x1a, 0x1, HDA_INPUT), | ||
1305 | HDA_CODEC_VOLUME("Input-3 Volume", 0x1a, 0x2, HDA_INPUT), | ||
1306 | HDA_CODEC_MUTE("Input-3 Switch", 0x1a, 0x2, HDA_INPUT), | ||
1307 | HDA_CODEC_VOLUME("Input-4 Volume", 0x1a, 0x3, HDA_INPUT), | ||
1308 | HDA_CODEC_MUTE("Input-4 Switch", 0x1a, 0x3, HDA_INPUT), | ||
1309 | HDA_CODEC_VOLUME("Input-5 Volume", 0x1a, 0x4, HDA_INPUT), | ||
1310 | HDA_CODEC_MUTE("Input-5 Switch", 0x1a, 0x4, HDA_INPUT), | ||
1311 | |||
1169 | { } /* end */ | 1312 | { } /* end */ |
1170 | }; | 1313 | }; |
1171 | 1314 | ||
@@ -1255,9 +1398,9 @@ static const char *cxt5047_models[CXT5047_MODELS] = { | |||
1255 | 1398 | ||
1256 | static struct snd_pci_quirk cxt5047_cfg_tbl[] = { | 1399 | static struct snd_pci_quirk cxt5047_cfg_tbl[] = { |
1257 | SND_PCI_QUIRK(0x103c, 0x30a0, "HP DV1000", CXT5047_LAPTOP), | 1400 | SND_PCI_QUIRK(0x103c, 0x30a0, "HP DV1000", CXT5047_LAPTOP), |
1401 | SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP), | ||
1258 | SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV2000T/DV3000T", CXT5047_LAPTOP), | 1402 | SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV2000T/DV3000T", CXT5047_LAPTOP), |
1259 | SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2000Z", CXT5047_LAPTOP), | 1403 | SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2000Z", CXT5047_LAPTOP), |
1260 | SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP), | ||
1261 | SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD), | 1404 | SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD), |
1262 | {} | 1405 | {} |
1263 | }; | 1406 | }; |
@@ -1324,10 +1467,260 @@ static int patch_cxt5047(struct hda_codec *codec) | |||
1324 | return 0; | 1467 | return 0; |
1325 | } | 1468 | } |
1326 | 1469 | ||
1470 | /* Conexant 5051 specific */ | ||
1471 | static hda_nid_t cxt5051_dac_nids[1] = { 0x10 }; | ||
1472 | static hda_nid_t cxt5051_adc_nids[2] = { 0x14, 0x15 }; | ||
1473 | #define CXT5051_SPDIF_OUT 0x1C | ||
1474 | #define CXT5051_PORTB_EVENT 0x38 | ||
1475 | #define CXT5051_PORTC_EVENT 0x39 | ||
1476 | |||
1477 | static struct hda_channel_mode cxt5051_modes[1] = { | ||
1478 | { 2, NULL }, | ||
1479 | }; | ||
1480 | |||
1481 | static void cxt5051_update_speaker(struct hda_codec *codec) | ||
1482 | { | ||
1483 | struct conexant_spec *spec = codec->spec; | ||
1484 | unsigned int pinctl; | ||
1485 | pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; | ||
1486 | snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
1487 | pinctl); | ||
1488 | } | ||
1489 | |||
1490 | /* turn on/off EAPD (+ mute HP) as a master switch */ | ||
1491 | static int cxt5051_hp_master_sw_put(struct snd_kcontrol *kcontrol, | ||
1492 | struct snd_ctl_elem_value *ucontrol) | ||
1493 | { | ||
1494 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1495 | |||
1496 | if (!cxt_eapd_put(kcontrol, ucontrol)) | ||
1497 | return 0; | ||
1498 | cxt5051_update_speaker(codec); | ||
1499 | return 1; | ||
1500 | } | ||
1501 | |||
1502 | /* toggle input of built-in and mic jack appropriately */ | ||
1503 | static void cxt5051_portb_automic(struct hda_codec *codec) | ||
1504 | { | ||
1505 | unsigned int present; | ||
1506 | |||
1507 | present = snd_hda_codec_read(codec, 0x17, 0, | ||
1508 | AC_VERB_GET_PIN_SENSE, 0) & | ||
1509 | AC_PINSENSE_PRESENCE; | ||
1510 | snd_hda_codec_write(codec, 0x14, 0, | ||
1511 | AC_VERB_SET_CONNECT_SEL, | ||
1512 | present ? 0x01 : 0x00); | ||
1513 | } | ||
1514 | |||
1515 | /* switch the current ADC according to the jack state */ | ||
1516 | static void cxt5051_portc_automic(struct hda_codec *codec) | ||
1517 | { | ||
1518 | struct conexant_spec *spec = codec->spec; | ||
1519 | unsigned int present; | ||
1520 | hda_nid_t new_adc; | ||
1521 | |||
1522 | present = snd_hda_codec_read(codec, 0x18, 0, | ||
1523 | AC_VERB_GET_PIN_SENSE, 0) & | ||
1524 | AC_PINSENSE_PRESENCE; | ||
1525 | if (present) | ||
1526 | spec->cur_adc_idx = 1; | ||
1527 | else | ||
1528 | spec->cur_adc_idx = 0; | ||
1529 | new_adc = spec->adc_nids[spec->cur_adc_idx]; | ||
1530 | if (spec->cur_adc && spec->cur_adc != new_adc) { | ||
1531 | /* stream is running, let's swap the current ADC */ | ||
1532 | snd_hda_codec_setup_stream(codec, spec->cur_adc, 0, 0, 0); | ||
1533 | spec->cur_adc = new_adc; | ||
1534 | snd_hda_codec_setup_stream(codec, new_adc, | ||
1535 | spec->cur_adc_stream_tag, 0, | ||
1536 | spec->cur_adc_format); | ||
1537 | } | ||
1538 | } | ||
1539 | |||
1540 | /* mute internal speaker if HP is plugged */ | ||
1541 | static void cxt5051_hp_automute(struct hda_codec *codec) | ||
1542 | { | ||
1543 | struct conexant_spec *spec = codec->spec; | ||
1544 | |||
1545 | spec->hp_present = snd_hda_codec_read(codec, 0x16, 0, | ||
1546 | AC_VERB_GET_PIN_SENSE, 0) & | ||
1547 | AC_PINSENSE_PRESENCE; | ||
1548 | cxt5051_update_speaker(codec); | ||
1549 | } | ||
1550 | |||
1551 | /* unsolicited event for HP jack sensing */ | ||
1552 | static void cxt5051_hp_unsol_event(struct hda_codec *codec, | ||
1553 | unsigned int res) | ||
1554 | { | ||
1555 | switch (res >> 26) { | ||
1556 | case CONEXANT_HP_EVENT: | ||
1557 | cxt5051_hp_automute(codec); | ||
1558 | break; | ||
1559 | case CXT5051_PORTB_EVENT: | ||
1560 | cxt5051_portb_automic(codec); | ||
1561 | break; | ||
1562 | case CXT5051_PORTC_EVENT: | ||
1563 | cxt5051_portc_automic(codec); | ||
1564 | break; | ||
1565 | } | ||
1566 | } | ||
1567 | |||
1568 | static struct snd_kcontrol_new cxt5051_mixers[] = { | ||
1569 | HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), | ||
1570 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), | ||
1571 | HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT), | ||
1572 | HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT), | ||
1573 | HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT), | ||
1574 | HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT), | ||
1575 | HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), | ||
1576 | { | ||
1577 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1578 | .name = "Master Playback Switch", | ||
1579 | .info = cxt_eapd_info, | ||
1580 | .get = cxt_eapd_get, | ||
1581 | .put = cxt5051_hp_master_sw_put, | ||
1582 | .private_value = 0x1a, | ||
1583 | }, | ||
1584 | |||
1585 | {} | ||
1586 | }; | ||
1587 | |||
1588 | static struct snd_kcontrol_new cxt5051_hp_mixers[] = { | ||
1589 | HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), | ||
1590 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), | ||
1591 | HDA_CODEC_VOLUME("External Mic Volume", 0x15, 0x00, HDA_INPUT), | ||
1592 | HDA_CODEC_MUTE("External Mic Switch", 0x15, 0x00, HDA_INPUT), | ||
1593 | HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), | ||
1594 | { | ||
1595 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1596 | .name = "Master Playback Switch", | ||
1597 | .info = cxt_eapd_info, | ||
1598 | .get = cxt_eapd_get, | ||
1599 | .put = cxt5051_hp_master_sw_put, | ||
1600 | .private_value = 0x1a, | ||
1601 | }, | ||
1602 | |||
1603 | {} | ||
1604 | }; | ||
1605 | |||
1606 | static struct hda_verb cxt5051_init_verbs[] = { | ||
1607 | /* Line in, Mic */ | ||
1608 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, | ||
1609 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1610 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, | ||
1611 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1612 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
1613 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, | ||
1614 | /* SPK */ | ||
1615 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1616 | {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
1617 | /* HP, Amp */ | ||
1618 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
1619 | {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
1620 | /* DAC1 */ | ||
1621 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1622 | /* Record selector: Int mic */ | ||
1623 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, | ||
1624 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, | ||
1625 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, | ||
1626 | /* SPDIF route: PCM */ | ||
1627 | {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1628 | /* EAPD */ | ||
1629 | {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | ||
1630 | {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, | ||
1631 | {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT}, | ||
1632 | {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTC_EVENT}, | ||
1633 | { } /* end */ | ||
1634 | }; | ||
1635 | |||
1636 | /* initialize jack-sensing, too */ | ||
1637 | static int cxt5051_init(struct hda_codec *codec) | ||
1638 | { | ||
1639 | conexant_init(codec); | ||
1640 | if (codec->patch_ops.unsol_event) { | ||
1641 | cxt5051_hp_automute(codec); | ||
1642 | cxt5051_portb_automic(codec); | ||
1643 | cxt5051_portc_automic(codec); | ||
1644 | } | ||
1645 | return 0; | ||
1646 | } | ||
1647 | |||
1648 | |||
1649 | enum { | ||
1650 | CXT5051_LAPTOP, /* Laptops w/ EAPD support */ | ||
1651 | CXT5051_HP, /* no docking */ | ||
1652 | CXT5051_MODELS | ||
1653 | }; | ||
1654 | |||
1655 | static const char *cxt5051_models[CXT5051_MODELS] = { | ||
1656 | [CXT5051_LAPTOP] = "laptop", | ||
1657 | [CXT5051_HP] = "hp", | ||
1658 | }; | ||
1659 | |||
1660 | static struct snd_pci_quirk cxt5051_cfg_tbl[] = { | ||
1661 | SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", | ||
1662 | CXT5051_LAPTOP), | ||
1663 | SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), | ||
1664 | {} | ||
1665 | }; | ||
1666 | |||
1667 | static int patch_cxt5051(struct hda_codec *codec) | ||
1668 | { | ||
1669 | struct conexant_spec *spec; | ||
1670 | int board_config; | ||
1671 | |||
1672 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
1673 | if (!spec) | ||
1674 | return -ENOMEM; | ||
1675 | mutex_init(&spec->amp_mutex); | ||
1676 | codec->spec = spec; | ||
1677 | |||
1678 | codec->patch_ops = conexant_patch_ops; | ||
1679 | codec->patch_ops.init = cxt5051_init; | ||
1680 | |||
1681 | spec->multiout.max_channels = 2; | ||
1682 | spec->multiout.num_dacs = ARRAY_SIZE(cxt5051_dac_nids); | ||
1683 | spec->multiout.dac_nids = cxt5051_dac_nids; | ||
1684 | spec->multiout.dig_out_nid = CXT5051_SPDIF_OUT; | ||
1685 | spec->num_adc_nids = 1; /* not 2; via auto-mic switch */ | ||
1686 | spec->adc_nids = cxt5051_adc_nids; | ||
1687 | spec->num_mixers = 1; | ||
1688 | spec->mixers[0] = cxt5051_mixers; | ||
1689 | spec->num_init_verbs = 1; | ||
1690 | spec->init_verbs[0] = cxt5051_init_verbs; | ||
1691 | spec->spdif_route = 0; | ||
1692 | spec->num_channel_mode = ARRAY_SIZE(cxt5051_modes); | ||
1693 | spec->channel_mode = cxt5051_modes; | ||
1694 | spec->cur_adc = 0; | ||
1695 | spec->cur_adc_idx = 0; | ||
1696 | |||
1697 | board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, | ||
1698 | cxt5051_models, | ||
1699 | cxt5051_cfg_tbl); | ||
1700 | switch (board_config) { | ||
1701 | case CXT5051_HP: | ||
1702 | codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; | ||
1703 | spec->mixers[0] = cxt5051_hp_mixers; | ||
1704 | break; | ||
1705 | default: | ||
1706 | case CXT5051_LAPTOP: | ||
1707 | codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; | ||
1708 | break; | ||
1709 | } | ||
1710 | |||
1711 | return 0; | ||
1712 | } | ||
1713 | |||
1714 | |||
1715 | /* | ||
1716 | */ | ||
1717 | |||
1327 | struct hda_codec_preset snd_hda_preset_conexant[] = { | 1718 | struct hda_codec_preset snd_hda_preset_conexant[] = { |
1328 | { .id = 0x14f15045, .name = "CX20549 (Venice)", | 1719 | { .id = 0x14f15045, .name = "CX20549 (Venice)", |
1329 | .patch = patch_cxt5045 }, | 1720 | .patch = patch_cxt5045 }, |
1330 | { .id = 0x14f15047, .name = "CX20551 (Waikiki)", | 1721 | { .id = 0x14f15047, .name = "CX20551 (Waikiki)", |
1331 | .patch = patch_cxt5047 }, | 1722 | .patch = patch_cxt5047 }, |
1723 | { .id = 0x14f15051, .name = "CX20561 (Hermosa)", | ||
1724 | .patch = patch_cxt5051 }, | ||
1332 | {} /* terminator */ | 1725 | {} /* terminator */ |
1333 | }; | 1726 | }; |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 1c502789cc1e..586d98f1b63d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -23,7 +23,6 @@ | |||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <sound/driver.h> | ||
27 | #include <linux/init.h> | 26 | #include <linux/init.h> |
28 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
29 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
@@ -92,9 +91,12 @@ enum { | |||
92 | ALC262_HP_BPC, | 91 | ALC262_HP_BPC, |
93 | ALC262_HP_BPC_D7000_WL, | 92 | ALC262_HP_BPC_D7000_WL, |
94 | ALC262_HP_BPC_D7000_WF, | 93 | ALC262_HP_BPC_D7000_WF, |
94 | ALC262_HP_TC_T5735, | ||
95 | ALC262_HP_RP5700, | ||
95 | ALC262_BENQ_ED8, | 96 | ALC262_BENQ_ED8, |
96 | ALC262_SONY_ASSAMD, | 97 | ALC262_SONY_ASSAMD, |
97 | ALC262_BENQ_T31, | 98 | ALC262_BENQ_T31, |
99 | ALC262_ULTRA, | ||
98 | ALC262_AUTO, | 100 | ALC262_AUTO, |
99 | ALC262_MODEL_LAST /* last tag */ | 101 | ALC262_MODEL_LAST /* last tag */ |
100 | }; | 102 | }; |
@@ -104,10 +106,21 @@ enum { | |||
104 | ALC268_3ST, | 106 | ALC268_3ST, |
105 | ALC268_TOSHIBA, | 107 | ALC268_TOSHIBA, |
106 | ALC268_ACER, | 108 | ALC268_ACER, |
109 | ALC268_DELL, | ||
110 | #ifdef CONFIG_SND_DEBUG | ||
111 | ALC268_TEST, | ||
112 | #endif | ||
107 | ALC268_AUTO, | 113 | ALC268_AUTO, |
108 | ALC268_MODEL_LAST /* last tag */ | 114 | ALC268_MODEL_LAST /* last tag */ |
109 | }; | 115 | }; |
110 | 116 | ||
117 | /* ALC269 models */ | ||
118 | enum { | ||
119 | ALC269_BASIC, | ||
120 | ALC269_AUTO, | ||
121 | ALC269_MODEL_LAST /* last tag */ | ||
122 | }; | ||
123 | |||
111 | /* ALC861 models */ | 124 | /* ALC861 models */ |
112 | enum { | 125 | enum { |
113 | ALC861_3ST, | 126 | ALC861_3ST, |
@@ -144,6 +157,7 @@ enum { | |||
144 | ALC662_5ST_DIG, | 157 | ALC662_5ST_DIG, |
145 | ALC662_LENOVO_101E, | 158 | ALC662_LENOVO_101E, |
146 | ALC662_ASUS_EEEPC_P701, | 159 | ALC662_ASUS_EEEPC_P701, |
160 | ALC662_ASUS_EEEPC_EP20, | ||
147 | ALC662_AUTO, | 161 | ALC662_AUTO, |
148 | ALC662_MODEL_LAST, | 162 | ALC662_MODEL_LAST, |
149 | }; | 163 | }; |
@@ -183,6 +197,8 @@ enum { | |||
183 | ALC883_HAIER_W66, | 197 | ALC883_HAIER_W66, |
184 | ALC888_6ST_HP, | 198 | ALC888_6ST_HP, |
185 | ALC888_3ST_HP, | 199 | ALC888_3ST_HP, |
200 | ALC888_6ST_DELL, | ||
201 | ALC883_MITAC, | ||
186 | ALC883_AUTO, | 202 | ALC883_AUTO, |
187 | ALC883_MODEL_LAST, | 203 | ALC883_MODEL_LAST, |
188 | }; | 204 | }; |
@@ -204,6 +220,8 @@ struct alc_spec { | |||
204 | char *stream_name_analog; /* analog PCM stream */ | 220 | char *stream_name_analog; /* analog PCM stream */ |
205 | struct hda_pcm_stream *stream_analog_playback; | 221 | struct hda_pcm_stream *stream_analog_playback; |
206 | struct hda_pcm_stream *stream_analog_capture; | 222 | struct hda_pcm_stream *stream_analog_capture; |
223 | struct hda_pcm_stream *stream_analog_alt_playback; | ||
224 | struct hda_pcm_stream *stream_analog_alt_capture; | ||
207 | 225 | ||
208 | char *stream_name_digital; /* digital PCM stream */ | 226 | char *stream_name_digital; /* digital PCM stream */ |
209 | struct hda_pcm_stream *stream_digital_playback; | 227 | struct hda_pcm_stream *stream_digital_playback; |
@@ -214,6 +232,7 @@ struct alc_spec { | |||
214 | * max_channels, dacs must be set | 232 | * max_channels, dacs must be set |
215 | * dig_out_nid and hp_nid are optional | 233 | * dig_out_nid and hp_nid are optional |
216 | */ | 234 | */ |
235 | hda_nid_t alt_dac_nid; | ||
217 | 236 | ||
218 | /* capture */ | 237 | /* capture */ |
219 | unsigned int num_adc_nids; | 238 | unsigned int num_adc_nids; |
@@ -247,7 +266,11 @@ struct alc_spec { | |||
247 | /* for pin sensing */ | 266 | /* for pin sensing */ |
248 | unsigned int sense_updated: 1; | 267 | unsigned int sense_updated: 1; |
249 | unsigned int jack_present: 1; | 268 | unsigned int jack_present: 1; |
269 | unsigned int master_sw: 1; | ||
250 | 270 | ||
271 | /* for virtual master */ | ||
272 | hda_nid_t vmaster_nid; | ||
273 | u32 vmaster_tlv[4]; | ||
251 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 274 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
252 | struct hda_loopback_check loopback; | 275 | struct hda_loopback_check loopback; |
253 | #endif | 276 | #endif |
@@ -562,7 +585,7 @@ static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol, | |||
562 | unsigned char mask = (kcontrol->private_value >> 16) & 0xff; | 585 | unsigned char mask = (kcontrol->private_value >> 16) & 0xff; |
563 | long *valp = ucontrol->value.integer.value; | 586 | long *valp = ucontrol->value.integer.value; |
564 | unsigned int val = snd_hda_codec_read(codec, nid, 0, | 587 | unsigned int val = snd_hda_codec_read(codec, nid, 0, |
565 | AC_VERB_GET_DIGI_CONVERT, 0x00); | 588 | AC_VERB_GET_DIGI_CONVERT_1, 0x00); |
566 | 589 | ||
567 | *valp = (val & mask) != 0; | 590 | *valp = (val & mask) != 0; |
568 | return 0; | 591 | return 0; |
@@ -576,7 +599,7 @@ static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol, | |||
576 | unsigned char mask = (kcontrol->private_value >> 16) & 0xff; | 599 | unsigned char mask = (kcontrol->private_value >> 16) & 0xff; |
577 | long val = *ucontrol->value.integer.value; | 600 | long val = *ucontrol->value.integer.value; |
578 | unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0, | 601 | unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0, |
579 | AC_VERB_GET_DIGI_CONVERT, | 602 | AC_VERB_GET_DIGI_CONVERT_1, |
580 | 0x00); | 603 | 0x00); |
581 | 604 | ||
582 | /* Set/unset the masked control bit(s) as needed */ | 605 | /* Set/unset the masked control bit(s) as needed */ |
@@ -598,6 +621,59 @@ static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol, | |||
598 | .private_value = nid | (mask<<16) } | 621 | .private_value = nid | (mask<<16) } |
599 | #endif /* CONFIG_SND_DEBUG */ | 622 | #endif /* CONFIG_SND_DEBUG */ |
600 | 623 | ||
624 | /* A switch control to allow the enabling EAPD digital outputs on the ALC26x. | ||
625 | * Again, this is only used in the ALC26x test models to help identify when | ||
626 | * the EAPD line must be asserted for features to work. | ||
627 | */ | ||
628 | #ifdef CONFIG_SND_DEBUG | ||
629 | #define alc_eapd_ctrl_info snd_ctl_boolean_mono_info | ||
630 | |||
631 | static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol, | ||
632 | struct snd_ctl_elem_value *ucontrol) | ||
633 | { | ||
634 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
635 | hda_nid_t nid = kcontrol->private_value & 0xffff; | ||
636 | unsigned char mask = (kcontrol->private_value >> 16) & 0xff; | ||
637 | long *valp = ucontrol->value.integer.value; | ||
638 | unsigned int val = snd_hda_codec_read(codec, nid, 0, | ||
639 | AC_VERB_GET_EAPD_BTLENABLE, 0x00); | ||
640 | |||
641 | *valp = (val & mask) != 0; | ||
642 | return 0; | ||
643 | } | ||
644 | |||
645 | static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol, | ||
646 | struct snd_ctl_elem_value *ucontrol) | ||
647 | { | ||
648 | int change; | ||
649 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
650 | hda_nid_t nid = kcontrol->private_value & 0xffff; | ||
651 | unsigned char mask = (kcontrol->private_value >> 16) & 0xff; | ||
652 | long val = *ucontrol->value.integer.value; | ||
653 | unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0, | ||
654 | AC_VERB_GET_EAPD_BTLENABLE, | ||
655 | 0x00); | ||
656 | |||
657 | /* Set/unset the masked control bit(s) as needed */ | ||
658 | change = (!val ? 0 : mask) != (ctrl_data & mask); | ||
659 | if (!val) | ||
660 | ctrl_data &= ~mask; | ||
661 | else | ||
662 | ctrl_data |= mask; | ||
663 | snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
664 | ctrl_data); | ||
665 | |||
666 | return change; | ||
667 | } | ||
668 | |||
669 | #define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \ | ||
670 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ | ||
671 | .info = alc_eapd_ctrl_info, \ | ||
672 | .get = alc_eapd_ctrl_get, \ | ||
673 | .put = alc_eapd_ctrl_put, \ | ||
674 | .private_value = nid | (mask<<16) } | ||
675 | #endif /* CONFIG_SND_DEBUG */ | ||
676 | |||
601 | /* | 677 | /* |
602 | * set up from the preset table | 678 | * set up from the preset table |
603 | */ | 679 | */ |
@@ -739,7 +815,7 @@ static void alc_subsystem_id(struct hda_codec *codec, | |||
739 | /* check sum */ | 815 | /* check sum */ |
740 | tmp = 0; | 816 | tmp = 0; |
741 | for (i = 1; i < 16; i++) { | 817 | for (i = 1; i < 16; i++) { |
742 | if ((ass >> i) && 1) | 818 | if ((ass >> i) & 1) |
743 | tmp++; | 819 | tmp++; |
744 | } | 820 | } |
745 | if (((ass >> 16) & 0xf) != tmp) | 821 | if (((ass >> 16) & 0xf) != tmp) |
@@ -828,10 +904,10 @@ do_sku: | |||
828 | break; | 904 | break; |
829 | } | 905 | } |
830 | 906 | ||
831 | /* is laptop and enable the function "Mute internal speaker | 907 | /* is laptop or Desktop and enable the function "Mute internal speaker |
832 | * when the external headphone out jack is plugged" | 908 | * when the external headphone out jack is plugged" |
833 | */ | 909 | */ |
834 | if (!(ass & 0x4) || !(ass & 0x8000)) | 910 | if (!(ass & 0x8000)) |
835 | return; | 911 | return; |
836 | /* | 912 | /* |
837 | * 10~8 : Jack location | 913 | * 10~8 : Jack location |
@@ -841,9 +917,9 @@ do_sku: | |||
841 | * when the external headphone out jack is plugged" | 917 | * when the external headphone out jack is plugged" |
842 | */ | 918 | */ |
843 | if (!spec->autocfg.speaker_pins[0]) { | 919 | if (!spec->autocfg.speaker_pins[0]) { |
844 | if (spec->multiout.dac_nids[0]) | 920 | if (spec->autocfg.line_out_pins[0]) |
845 | spec->autocfg.speaker_pins[0] = | 921 | spec->autocfg.speaker_pins[0] = |
846 | spec->multiout.dac_nids[0]; | 922 | spec->autocfg.line_out_pins[0]; |
847 | else | 923 | else |
848 | return; | 924 | return; |
849 | } | 925 | } |
@@ -1009,7 +1085,6 @@ static struct snd_kcontrol_new alc880_capture_mixer[] = { | |||
1009 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1085 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1010 | /* The multiple "Capture Source" controls confuse alsamixer | 1086 | /* The multiple "Capture Source" controls confuse alsamixer |
1011 | * So call somewhat different.. | 1087 | * So call somewhat different.. |
1012 | * FIXME: the controls appear in the "playback" view! | ||
1013 | */ | 1088 | */ |
1014 | /* .name = "Capture Source", */ | 1089 | /* .name = "Capture Source", */ |
1015 | .name = "Input Source", | 1090 | .name = "Input Source", |
@@ -1031,7 +1106,6 @@ static struct snd_kcontrol_new alc880_capture_alt_mixer[] = { | |||
1031 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1106 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1032 | /* The multiple "Capture Source" controls confuse alsamixer | 1107 | /* The multiple "Capture Source" controls confuse alsamixer |
1033 | * So call somewhat different.. | 1108 | * So call somewhat different.. |
1034 | * FIXME: the controls appear in the "playback" view! | ||
1035 | */ | 1109 | */ |
1036 | /* .name = "Capture Source", */ | 1110 | /* .name = "Capture Source", */ |
1037 | .name = "Input Source", | 1111 | .name = "Input Source", |
@@ -1226,7 +1300,6 @@ static struct snd_kcontrol_new alc880_z71v_mixer[] = { | |||
1226 | }; | 1300 | }; |
1227 | 1301 | ||
1228 | 1302 | ||
1229 | /* FIXME! */ | ||
1230 | /* | 1303 | /* |
1231 | * ALC880 F1734 model | 1304 | * ALC880 F1734 model |
1232 | * | 1305 | * |
@@ -1242,8 +1315,8 @@ static hda_nid_t alc880_f1734_dac_nids[1] = { | |||
1242 | static struct snd_kcontrol_new alc880_f1734_mixer[] = { | 1315 | static struct snd_kcontrol_new alc880_f1734_mixer[] = { |
1243 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 1316 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
1244 | HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), | 1317 | HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), |
1245 | HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | 1318 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), |
1246 | HDA_BIND_MUTE("Internal Speaker Playback Switch", 0x0d, 2, HDA_INPUT), | 1319 | HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), |
1247 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | 1320 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), |
1248 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | 1321 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), |
1249 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | 1322 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), |
@@ -1252,7 +1325,6 @@ static struct snd_kcontrol_new alc880_f1734_mixer[] = { | |||
1252 | }; | 1325 | }; |
1253 | 1326 | ||
1254 | 1327 | ||
1255 | /* FIXME! */ | ||
1256 | /* | 1328 | /* |
1257 | * ALC880 ASUS model | 1329 | * ALC880 ASUS model |
1258 | * | 1330 | * |
@@ -1289,7 +1361,6 @@ static struct snd_kcontrol_new alc880_asus_mixer[] = { | |||
1289 | { } /* end */ | 1361 | { } /* end */ |
1290 | }; | 1362 | }; |
1291 | 1363 | ||
1292 | /* FIXME! */ | ||
1293 | /* | 1364 | /* |
1294 | * ALC880 ASUS W1V model | 1365 | * ALC880 ASUS W1V model |
1295 | * | 1366 | * |
@@ -1327,7 +1398,6 @@ static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = { | |||
1327 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1398 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1328 | /* The multiple "Capture Source" controls confuse alsamixer | 1399 | /* The multiple "Capture Source" controls confuse alsamixer |
1329 | * So call somewhat different.. | 1400 | * So call somewhat different.. |
1330 | * FIXME: the controls appear in the "playback" view! | ||
1331 | */ | 1401 | */ |
1332 | /* .name = "Capture Source", */ | 1402 | /* .name = "Capture Source", */ |
1333 | .name = "Input Source", | 1403 | .name = "Input Source", |
@@ -1341,10 +1411,10 @@ static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = { | |||
1341 | 1411 | ||
1342 | /* Uniwill */ | 1412 | /* Uniwill */ |
1343 | static struct snd_kcontrol_new alc880_uniwill_mixer[] = { | 1413 | static struct snd_kcontrol_new alc880_uniwill_mixer[] = { |
1344 | HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 1414 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
1345 | HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT), | 1415 | HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), |
1346 | HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | 1416 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), |
1347 | HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT), | 1417 | HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), |
1348 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), | 1418 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), |
1349 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), | 1419 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), |
1350 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), | 1420 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), |
@@ -1384,16 +1454,49 @@ static struct snd_kcontrol_new alc880_fujitsu_mixer[] = { | |||
1384 | }; | 1454 | }; |
1385 | 1455 | ||
1386 | static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = { | 1456 | static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = { |
1387 | HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 1457 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
1388 | HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT), | 1458 | HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), |
1389 | HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | 1459 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), |
1390 | HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT), | 1460 | HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), |
1391 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | 1461 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), |
1392 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | 1462 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), |
1393 | { } /* end */ | 1463 | { } /* end */ |
1394 | }; | 1464 | }; |
1395 | 1465 | ||
1396 | /* | 1466 | /* |
1467 | * virtual master controls | ||
1468 | */ | ||
1469 | |||
1470 | /* | ||
1471 | * slave controls for virtual master | ||
1472 | */ | ||
1473 | static const char *alc_slave_vols[] = { | ||
1474 | "Front Playback Volume", | ||
1475 | "Surround Playback Volume", | ||
1476 | "Center Playback Volume", | ||
1477 | "LFE Playback Volume", | ||
1478 | "Side Playback Volume", | ||
1479 | "Headphone Playback Volume", | ||
1480 | "Speaker Playback Volume", | ||
1481 | "Mono Playback Volume", | ||
1482 | "Line-Out Playback Volume", | ||
1483 | NULL, | ||
1484 | }; | ||
1485 | |||
1486 | static const char *alc_slave_sws[] = { | ||
1487 | "Front Playback Switch", | ||
1488 | "Surround Playback Switch", | ||
1489 | "Center Playback Switch", | ||
1490 | "LFE Playback Switch", | ||
1491 | "Side Playback Switch", | ||
1492 | "Headphone Playback Switch", | ||
1493 | "Speaker Playback Switch", | ||
1494 | "Mono Playback Switch", | ||
1495 | "IEC958 Playback Switch", | ||
1496 | NULL, | ||
1497 | }; | ||
1498 | |||
1499 | /* | ||
1397 | * build control elements | 1500 | * build control elements |
1398 | */ | 1501 | */ |
1399 | static int alc_build_controls(struct hda_codec *codec) | 1502 | static int alc_build_controls(struct hda_codec *codec) |
@@ -1419,6 +1522,23 @@ static int alc_build_controls(struct hda_codec *codec) | |||
1419 | if (err < 0) | 1522 | if (err < 0) |
1420 | return err; | 1523 | return err; |
1421 | } | 1524 | } |
1525 | |||
1526 | /* if we have no master control, let's create it */ | ||
1527 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { | ||
1528 | snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, | ||
1529 | HDA_OUTPUT, spec->vmaster_tlv); | ||
1530 | err = snd_hda_add_vmaster(codec, "Master Playback Volume", | ||
1531 | spec->vmaster_tlv, alc_slave_vols); | ||
1532 | if (err < 0) | ||
1533 | return err; | ||
1534 | } | ||
1535 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { | ||
1536 | err = snd_hda_add_vmaster(codec, "Master Playback Switch", | ||
1537 | NULL, alc_slave_sws); | ||
1538 | if (err < 0) | ||
1539 | return err; | ||
1540 | } | ||
1541 | |||
1422 | return 0; | 1542 | return 0; |
1423 | } | 1543 | } |
1424 | 1544 | ||
@@ -1790,7 +1910,6 @@ static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec, | |||
1790 | alc880_uniwill_p53_dcvol_automute(codec); | 1910 | alc880_uniwill_p53_dcvol_automute(codec); |
1791 | } | 1911 | } |
1792 | 1912 | ||
1793 | /* FIXME! */ | ||
1794 | /* | 1913 | /* |
1795 | * F1734 pin configuration: | 1914 | * F1734 pin configuration: |
1796 | * HP = 0x14, speaker-out = 0x15, mic = 0x18 | 1915 | * HP = 0x14, speaker-out = 0x15, mic = 0x18 |
@@ -1819,7 +1938,6 @@ static struct hda_verb alc880_pin_f1734_init_verbs[] = { | |||
1819 | { } | 1938 | { } |
1820 | }; | 1939 | }; |
1821 | 1940 | ||
1822 | /* FIXME! */ | ||
1823 | /* | 1941 | /* |
1824 | * ASUS pin configuration: | 1942 | * ASUS pin configuration: |
1825 | * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a | 1943 | * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a |
@@ -1966,9 +2084,8 @@ static struct hda_channel_mode alc880_lg_ch_modes[3] = { | |||
1966 | }; | 2084 | }; |
1967 | 2085 | ||
1968 | static struct snd_kcontrol_new alc880_lg_mixer[] = { | 2086 | static struct snd_kcontrol_new alc880_lg_mixer[] = { |
1969 | /* FIXME: it's not really "master" but front channels */ | 2087 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT), |
1970 | HDA_CODEC_VOLUME("Master Playback Volume", 0x0f, 0x0, HDA_OUTPUT), | 2088 | HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT), |
1971 | HDA_BIND_MUTE("Master Playback Switch", 0x0f, 2, HDA_INPUT), | ||
1972 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 2089 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
1973 | HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT), | 2090 | HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT), |
1974 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT), | 2091 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT), |
@@ -2256,7 +2373,7 @@ static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, | |||
2256 | /* | 2373 | /* |
2257 | * Analog capture | 2374 | * Analog capture |
2258 | */ | 2375 | */ |
2259 | static int alc880_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | 2376 | static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo, |
2260 | struct hda_codec *codec, | 2377 | struct hda_codec *codec, |
2261 | unsigned int stream_tag, | 2378 | unsigned int stream_tag, |
2262 | unsigned int format, | 2379 | unsigned int format, |
@@ -2264,18 +2381,18 @@ static int alc880_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | |||
2264 | { | 2381 | { |
2265 | struct alc_spec *spec = codec->spec; | 2382 | struct alc_spec *spec = codec->spec; |
2266 | 2383 | ||
2267 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], | 2384 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1], |
2268 | stream_tag, 0, format); | 2385 | stream_tag, 0, format); |
2269 | return 0; | 2386 | return 0; |
2270 | } | 2387 | } |
2271 | 2388 | ||
2272 | static int alc880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | 2389 | static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, |
2273 | struct hda_codec *codec, | 2390 | struct hda_codec *codec, |
2274 | struct snd_pcm_substream *substream) | 2391 | struct snd_pcm_substream *substream) |
2275 | { | 2392 | { |
2276 | struct alc_spec *spec = codec->spec; | 2393 | struct alc_spec *spec = codec->spec; |
2277 | 2394 | ||
2278 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], | 2395 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1], |
2279 | 0, 0, 0); | 2396 | 0, 0, 0); |
2280 | return 0; | 2397 | return 0; |
2281 | } | 2398 | } |
@@ -2296,13 +2413,27 @@ static struct hda_pcm_stream alc880_pcm_analog_playback = { | |||
2296 | }; | 2413 | }; |
2297 | 2414 | ||
2298 | static struct hda_pcm_stream alc880_pcm_analog_capture = { | 2415 | static struct hda_pcm_stream alc880_pcm_analog_capture = { |
2299 | .substreams = 2, | 2416 | .substreams = 1, |
2417 | .channels_min = 2, | ||
2418 | .channels_max = 2, | ||
2419 | /* NID is set in alc_build_pcms */ | ||
2420 | }; | ||
2421 | |||
2422 | static struct hda_pcm_stream alc880_pcm_analog_alt_playback = { | ||
2423 | .substreams = 1, | ||
2424 | .channels_min = 2, | ||
2425 | .channels_max = 2, | ||
2426 | /* NID is set in alc_build_pcms */ | ||
2427 | }; | ||
2428 | |||
2429 | static struct hda_pcm_stream alc880_pcm_analog_alt_capture = { | ||
2430 | .substreams = 2, /* can be overridden */ | ||
2300 | .channels_min = 2, | 2431 | .channels_min = 2, |
2301 | .channels_max = 2, | 2432 | .channels_max = 2, |
2302 | /* NID is set in alc_build_pcms */ | 2433 | /* NID is set in alc_build_pcms */ |
2303 | .ops = { | 2434 | .ops = { |
2304 | .prepare = alc880_capture_pcm_prepare, | 2435 | .prepare = alc880_alt_capture_pcm_prepare, |
2305 | .cleanup = alc880_capture_pcm_cleanup | 2436 | .cleanup = alc880_alt_capture_pcm_cleanup |
2306 | }, | 2437 | }, |
2307 | }; | 2438 | }; |
2308 | 2439 | ||
@@ -2326,7 +2457,7 @@ static struct hda_pcm_stream alc880_pcm_digital_capture = { | |||
2326 | }; | 2457 | }; |
2327 | 2458 | ||
2328 | /* Used by alc_build_pcms to flag that a PCM has no playback stream */ | 2459 | /* Used by alc_build_pcms to flag that a PCM has no playback stream */ |
2329 | static struct hda_pcm_stream alc_pcm_null_playback = { | 2460 | static struct hda_pcm_stream alc_pcm_null_stream = { |
2330 | .substreams = 0, | 2461 | .substreams = 0, |
2331 | .channels_min = 0, | 2462 | .channels_min = 0, |
2332 | .channels_max = 0, | 2463 | .channels_max = 0, |
@@ -2383,17 +2514,32 @@ static int alc_build_pcms(struct hda_codec *codec) | |||
2383 | * model, configure a second analog capture-only PCM. | 2514 | * model, configure a second analog capture-only PCM. |
2384 | */ | 2515 | */ |
2385 | /* Additional Analaog capture for index #2 */ | 2516 | /* Additional Analaog capture for index #2 */ |
2386 | if (spec->num_adc_nids > 1 && spec->stream_analog_capture && | 2517 | if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) || |
2387 | spec->adc_nids) { | 2518 | (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) { |
2388 | codec->num_pcms = 3; | 2519 | codec->num_pcms = 3; |
2389 | info = spec->pcm_rec + 2; | 2520 | info = spec->pcm_rec + 2; |
2390 | info->name = spec->stream_name_analog; | 2521 | info->name = spec->stream_name_analog; |
2391 | /* No playback stream for second PCM */ | 2522 | if (spec->alt_dac_nid) { |
2392 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = alc_pcm_null_playback; | 2523 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = |
2393 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; | 2524 | *spec->stream_analog_alt_playback; |
2394 | if (spec->stream_analog_capture) { | 2525 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = |
2395 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); | 2526 | spec->alt_dac_nid; |
2396 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[1]; | 2527 | } else { |
2528 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = | ||
2529 | alc_pcm_null_stream; | ||
2530 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; | ||
2531 | } | ||
2532 | if (spec->num_adc_nids > 1) { | ||
2533 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = | ||
2534 | *spec->stream_analog_alt_capture; | ||
2535 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = | ||
2536 | spec->adc_nids[1]; | ||
2537 | info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = | ||
2538 | spec->num_adc_nids - 1; | ||
2539 | } else { | ||
2540 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = | ||
2541 | alc_pcm_null_stream; | ||
2542 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0; | ||
2397 | } | 2543 | } |
2398 | } | 2544 | } |
2399 | 2545 | ||
@@ -2723,23 +2869,17 @@ static const char *alc880_models[ALC880_MODEL_LAST] = { | |||
2723 | }; | 2869 | }; |
2724 | 2870 | ||
2725 | static struct snd_pci_quirk alc880_cfg_tbl[] = { | 2871 | static struct snd_pci_quirk alc880_cfg_tbl[] = { |
2726 | /* Broken BIOS configuration */ | 2872 | SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810), |
2727 | SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), | ||
2728 | SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG), | ||
2729 | |||
2730 | SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG), | 2873 | SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG), |
2731 | SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST), | 2874 | SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST), |
2732 | SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810), | ||
2733 | SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG), | 2875 | SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG), |
2734 | SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG), | 2876 | SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG), |
2735 | SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG), | 2877 | SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG), |
2736 | SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG), | 2878 | SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG), |
2737 | SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG), | 2879 | SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG), |
2738 | SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST), | 2880 | SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST), |
2739 | |||
2740 | SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG), | 2881 | SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG), |
2741 | SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST), | 2882 | SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST), |
2742 | |||
2743 | SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V), | 2883 | SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V), |
2744 | SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG), | 2884 | SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG), |
2745 | SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG), | 2885 | SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG), |
@@ -2754,54 +2894,50 @@ static struct snd_pci_quirk alc880_cfg_tbl[] = { | |||
2754 | SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG), | 2894 | SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG), |
2755 | SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST), | 2895 | SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST), |
2756 | SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST), | 2896 | SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST), |
2757 | SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS), | 2897 | SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS), /* default ASUS */ |
2758 | |||
2759 | SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST), | ||
2760 | SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST), | 2898 | SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST), |
2899 | SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST), | ||
2900 | SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST), | ||
2761 | SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST), | 2901 | SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST), |
2762 | SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST), | 2902 | SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST), |
2763 | SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST), | ||
2764 | SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO), | ||
2765 | SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO), | ||
2766 | SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG), | ||
2767 | SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810), | ||
2768 | SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG), | ||
2769 | SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700), | ||
2770 | SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG), | ||
2771 | SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG), | ||
2772 | SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG), | 2903 | SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG), |
2773 | SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG), | 2904 | SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG), |
2774 | SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG), | 2905 | SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG), |
2775 | SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG), | 2906 | SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG), |
2907 | SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO), | ||
2908 | SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO), | ||
2776 | SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2), | 2909 | SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2), |
2777 | 2910 | SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG), | |
2778 | SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG), | 2911 | SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG), |
2912 | SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734), | ||
2779 | SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL), | 2913 | SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL), |
2780 | SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53), | 2914 | SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53), |
2781 | SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734), | 2915 | SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810), |
2782 | 2916 | SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG), | |
2783 | SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG), | 2917 | SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG), |
2784 | SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL), | ||
2785 | SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734), | 2918 | SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734), |
2919 | SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL), | ||
2786 | SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU), | 2920 | SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU), |
2787 | 2921 | SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW), | |
2788 | SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG), | 2922 | SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG), |
2789 | SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG), | 2923 | SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG), |
2790 | SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW), | ||
2791 | SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW), | 2924 | SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW), |
2792 | 2925 | SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700), | |
2793 | SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG), | 2926 | SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */ |
2794 | SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG), | 2927 | SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG), |
2795 | SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG), | 2928 | SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG), |
2796 | SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG), | 2929 | SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG), |
2797 | SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG), | 2930 | SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG), |
2931 | SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG), | ||
2798 | SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG), | 2932 | SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG), |
2933 | SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG), | ||
2934 | SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG), | ||
2799 | SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG), | 2935 | SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG), |
2800 | SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG), | 2936 | SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG), |
2801 | SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG), | 2937 | SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG), |
2802 | SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG), | 2938 | SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST), /* default Intel */ |
2803 | SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST), | 2939 | SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG), |
2804 | 2940 | SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG), | |
2805 | {} | 2941 | {} |
2806 | }; | 2942 | }; |
2807 | 2943 | ||
@@ -3511,6 +3647,7 @@ static int patch_alc880(struct hda_codec *codec) | |||
3511 | spec->stream_name_analog = "ALC880 Analog"; | 3647 | spec->stream_name_analog = "ALC880 Analog"; |
3512 | spec->stream_analog_playback = &alc880_pcm_analog_playback; | 3648 | spec->stream_analog_playback = &alc880_pcm_analog_playback; |
3513 | spec->stream_analog_capture = &alc880_pcm_analog_capture; | 3649 | spec->stream_analog_capture = &alc880_pcm_analog_capture; |
3650 | spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture; | ||
3514 | 3651 | ||
3515 | spec->stream_name_digital = "ALC880 Digital"; | 3652 | spec->stream_name_digital = "ALC880 Digital"; |
3516 | spec->stream_digital_playback = &alc880_pcm_digital_playback; | 3653 | spec->stream_digital_playback = &alc880_pcm_digital_playback; |
@@ -3535,6 +3672,8 @@ static int patch_alc880(struct hda_codec *codec) | |||
3535 | } | 3672 | } |
3536 | } | 3673 | } |
3537 | 3674 | ||
3675 | spec->vmaster_nid = 0x0c; | ||
3676 | |||
3538 | codec->patch_ops = alc_patch_ops; | 3677 | codec->patch_ops = alc_patch_ops; |
3539 | if (board_config == ALC880_AUTO) | 3678 | if (board_config == ALC880_AUTO) |
3540 | spec->init_hook = alc880_auto_init; | 3679 | spec->init_hook = alc880_auto_init; |
@@ -3691,18 +3830,135 @@ static struct snd_kcontrol_new alc260_pc_beep_mixer[] = { | |||
3691 | { } /* end */ | 3830 | { } /* end */ |
3692 | }; | 3831 | }; |
3693 | 3832 | ||
3833 | /* update HP, line and mono out pins according to the master switch */ | ||
3834 | static void alc260_hp_master_update(struct hda_codec *codec, | ||
3835 | hda_nid_t hp, hda_nid_t line, | ||
3836 | hda_nid_t mono) | ||
3837 | { | ||
3838 | struct alc_spec *spec = codec->spec; | ||
3839 | unsigned int val = spec->master_sw ? PIN_HP : 0; | ||
3840 | /* change HP and line-out pins */ | ||
3841 | snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
3842 | val); | ||
3843 | snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
3844 | val); | ||
3845 | /* mono (speaker) depending on the HP jack sense */ | ||
3846 | val = (val && !spec->jack_present) ? PIN_OUT : 0; | ||
3847 | snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
3848 | val); | ||
3849 | } | ||
3850 | |||
3851 | static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol, | ||
3852 | struct snd_ctl_elem_value *ucontrol) | ||
3853 | { | ||
3854 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
3855 | struct alc_spec *spec = codec->spec; | ||
3856 | *ucontrol->value.integer.value = spec->master_sw; | ||
3857 | return 0; | ||
3858 | } | ||
3859 | |||
3860 | static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol, | ||
3861 | struct snd_ctl_elem_value *ucontrol) | ||
3862 | { | ||
3863 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
3864 | struct alc_spec *spec = codec->spec; | ||
3865 | int val = !!*ucontrol->value.integer.value; | ||
3866 | hda_nid_t hp, line, mono; | ||
3867 | |||
3868 | if (val == spec->master_sw) | ||
3869 | return 0; | ||
3870 | spec->master_sw = val; | ||
3871 | hp = (kcontrol->private_value >> 16) & 0xff; | ||
3872 | line = (kcontrol->private_value >> 8) & 0xff; | ||
3873 | mono = kcontrol->private_value & 0xff; | ||
3874 | alc260_hp_master_update(codec, hp, line, mono); | ||
3875 | return 1; | ||
3876 | } | ||
3877 | |||
3878 | static struct snd_kcontrol_new alc260_hp_output_mixer[] = { | ||
3879 | { | ||
3880 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3881 | .name = "Master Playback Switch", | ||
3882 | .info = snd_ctl_boolean_mono_info, | ||
3883 | .get = alc260_hp_master_sw_get, | ||
3884 | .put = alc260_hp_master_sw_put, | ||
3885 | .private_value = (0x0f << 16) | (0x10 << 8) | 0x11 | ||
3886 | }, | ||
3887 | HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), | ||
3888 | HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), | ||
3889 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), | ||
3890 | HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), | ||
3891 | HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, | ||
3892 | HDA_OUTPUT), | ||
3893 | HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT), | ||
3894 | { } /* end */ | ||
3895 | }; | ||
3896 | |||
3897 | static struct hda_verb alc260_hp_unsol_verbs[] = { | ||
3898 | {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, | ||
3899 | {}, | ||
3900 | }; | ||
3901 | |||
3902 | static void alc260_hp_automute(struct hda_codec *codec) | ||
3903 | { | ||
3904 | struct alc_spec *spec = codec->spec; | ||
3905 | unsigned int present; | ||
3906 | |||
3907 | present = snd_hda_codec_read(codec, 0x10, 0, | ||
3908 | AC_VERB_GET_PIN_SENSE, 0); | ||
3909 | spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0; | ||
3910 | alc260_hp_master_update(codec, 0x0f, 0x10, 0x11); | ||
3911 | } | ||
3912 | |||
3913 | static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res) | ||
3914 | { | ||
3915 | if ((res >> 26) == ALC880_HP_EVENT) | ||
3916 | alc260_hp_automute(codec); | ||
3917 | } | ||
3918 | |||
3694 | static struct snd_kcontrol_new alc260_hp_3013_mixer[] = { | 3919 | static struct snd_kcontrol_new alc260_hp_3013_mixer[] = { |
3920 | { | ||
3921 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3922 | .name = "Master Playback Switch", | ||
3923 | .info = snd_ctl_boolean_mono_info, | ||
3924 | .get = alc260_hp_master_sw_get, | ||
3925 | .put = alc260_hp_master_sw_put, | ||
3926 | .private_value = (0x10 << 16) | (0x15 << 8) | 0x11 | ||
3927 | }, | ||
3695 | HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT), | 3928 | HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT), |
3696 | HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT), | 3929 | HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT), |
3697 | HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT), | 3930 | HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT), |
3698 | HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT), | 3931 | HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT), |
3699 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT), | 3932 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT), |
3700 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), | 3933 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), |
3701 | HDA_CODEC_VOLUME_MONO("iSpeaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), | 3934 | HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), |
3702 | HDA_CODEC_MUTE_MONO("iSpeaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT), | 3935 | HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT), |
3703 | { } /* end */ | 3936 | { } /* end */ |
3704 | }; | 3937 | }; |
3705 | 3938 | ||
3939 | static struct hda_verb alc260_hp_3013_unsol_verbs[] = { | ||
3940 | {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, | ||
3941 | {}, | ||
3942 | }; | ||
3943 | |||
3944 | static void alc260_hp_3013_automute(struct hda_codec *codec) | ||
3945 | { | ||
3946 | struct alc_spec *spec = codec->spec; | ||
3947 | unsigned int present; | ||
3948 | |||
3949 | present = snd_hda_codec_read(codec, 0x15, 0, | ||
3950 | AC_VERB_GET_PIN_SENSE, 0); | ||
3951 | spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0; | ||
3952 | alc260_hp_master_update(codec, 0x10, 0x15, 0x11); | ||
3953 | } | ||
3954 | |||
3955 | static void alc260_hp_3013_unsol_event(struct hda_codec *codec, | ||
3956 | unsigned int res) | ||
3957 | { | ||
3958 | if ((res >> 26) == ALC880_HP_EVENT) | ||
3959 | alc260_hp_3013_automute(codec); | ||
3960 | } | ||
3961 | |||
3706 | /* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12, | 3962 | /* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12, |
3707 | * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10. | 3963 | * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10. |
3708 | */ | 3964 | */ |
@@ -3812,7 +4068,6 @@ static struct snd_kcontrol_new alc260_capture_mixer[] = { | |||
3812 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 4068 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
3813 | /* The multiple "Capture Source" controls confuse alsamixer | 4069 | /* The multiple "Capture Source" controls confuse alsamixer |
3814 | * So call somewhat different.. | 4070 | * So call somewhat different.. |
3815 | * FIXME: the controls appear in the "playback" view! | ||
3816 | */ | 4071 | */ |
3817 | /* .name = "Capture Source", */ | 4072 | /* .name = "Capture Source", */ |
3818 | .name = "Input Source", | 4073 | .name = "Input Source", |
@@ -3831,7 +4086,6 @@ static struct snd_kcontrol_new alc260_capture_alt_mixer[] = { | |||
3831 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 4086 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
3832 | /* The multiple "Capture Source" controls confuse alsamixer | 4087 | /* The multiple "Capture Source" controls confuse alsamixer |
3833 | * So call somewhat different.. | 4088 | * So call somewhat different.. |
3834 | * FIXME: the controls appear in the "playback" view! | ||
3835 | */ | 4089 | */ |
3836 | /* .name = "Capture Source", */ | 4090 | /* .name = "Capture Source", */ |
3837 | .name = "Input Source", | 4091 | .name = "Input Source", |
@@ -4332,6 +4586,12 @@ static struct snd_kcontrol_new alc260_test_mixer[] = { | |||
4332 | ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01), | 4586 | ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01), |
4333 | ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01), | 4587 | ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01), |
4334 | 4588 | ||
4589 | /* A switch allowing EAPD to be enabled. Some laptops seem to use | ||
4590 | * this output to turn on an external amplifier. | ||
4591 | */ | ||
4592 | ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02), | ||
4593 | ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02), | ||
4594 | |||
4335 | { } /* end */ | 4595 | { } /* end */ |
4336 | }; | 4596 | }; |
4337 | static struct hda_verb alc260_test_init_verbs[] = { | 4597 | static struct hda_verb alc260_test_init_verbs[] = { |
@@ -4417,17 +4677,8 @@ static struct hda_verb alc260_test_init_verbs[] = { | |||
4417 | }; | 4677 | }; |
4418 | #endif | 4678 | #endif |
4419 | 4679 | ||
4420 | static struct hda_pcm_stream alc260_pcm_analog_playback = { | 4680 | #define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback |
4421 | .substreams = 1, | 4681 | #define alc260_pcm_analog_capture alc880_pcm_analog_capture |
4422 | .channels_min = 2, | ||
4423 | .channels_max = 2, | ||
4424 | }; | ||
4425 | |||
4426 | static struct hda_pcm_stream alc260_pcm_analog_capture = { | ||
4427 | .substreams = 1, | ||
4428 | .channels_min = 2, | ||
4429 | .channels_max = 2, | ||
4430 | }; | ||
4431 | 4682 | ||
4432 | #define alc260_pcm_digital_playback alc880_pcm_digital_playback | 4683 | #define alc260_pcm_digital_playback alc880_pcm_digital_playback |
4433 | #define alc260_pcm_digital_capture alc880_pcm_digital_capture | 4684 | #define alc260_pcm_digital_capture alc880_pcm_digital_capture |
@@ -4744,8 +4995,8 @@ static struct snd_pci_quirk alc260_cfg_tbl[] = { | |||
4744 | SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC), | 4995 | SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC), |
4745 | SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X), | 4996 | SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X), |
4746 | SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC), | 4997 | SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC), |
4747 | SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL), | ||
4748 | SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V), | 4998 | SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V), |
4999 | SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL), | ||
4749 | {} | 5000 | {} |
4750 | }; | 5001 | }; |
4751 | 5002 | ||
@@ -4765,10 +5016,11 @@ static struct alc_config_preset alc260_presets[] = { | |||
4765 | .input_mux = &alc260_capture_source, | 5016 | .input_mux = &alc260_capture_source, |
4766 | }, | 5017 | }, |
4767 | [ALC260_HP] = { | 5018 | [ALC260_HP] = { |
4768 | .mixers = { alc260_base_output_mixer, | 5019 | .mixers = { alc260_hp_output_mixer, |
4769 | alc260_input_mixer, | 5020 | alc260_input_mixer, |
4770 | alc260_capture_alt_mixer }, | 5021 | alc260_capture_alt_mixer }, |
4771 | .init_verbs = { alc260_init_verbs }, | 5022 | .init_verbs = { alc260_init_verbs, |
5023 | alc260_hp_unsol_verbs }, | ||
4772 | .num_dacs = ARRAY_SIZE(alc260_dac_nids), | 5024 | .num_dacs = ARRAY_SIZE(alc260_dac_nids), |
4773 | .dac_nids = alc260_dac_nids, | 5025 | .dac_nids = alc260_dac_nids, |
4774 | .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), | 5026 | .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), |
@@ -4776,12 +5028,15 @@ static struct alc_config_preset alc260_presets[] = { | |||
4776 | .num_channel_mode = ARRAY_SIZE(alc260_modes), | 5028 | .num_channel_mode = ARRAY_SIZE(alc260_modes), |
4777 | .channel_mode = alc260_modes, | 5029 | .channel_mode = alc260_modes, |
4778 | .input_mux = &alc260_capture_source, | 5030 | .input_mux = &alc260_capture_source, |
5031 | .unsol_event = alc260_hp_unsol_event, | ||
5032 | .init_hook = alc260_hp_automute, | ||
4779 | }, | 5033 | }, |
4780 | [ALC260_HP_3013] = { | 5034 | [ALC260_HP_3013] = { |
4781 | .mixers = { alc260_hp_3013_mixer, | 5035 | .mixers = { alc260_hp_3013_mixer, |
4782 | alc260_input_mixer, | 5036 | alc260_input_mixer, |
4783 | alc260_capture_alt_mixer }, | 5037 | alc260_capture_alt_mixer }, |
4784 | .init_verbs = { alc260_hp_3013_init_verbs }, | 5038 | .init_verbs = { alc260_hp_3013_init_verbs, |
5039 | alc260_hp_3013_unsol_verbs }, | ||
4785 | .num_dacs = ARRAY_SIZE(alc260_dac_nids), | 5040 | .num_dacs = ARRAY_SIZE(alc260_dac_nids), |
4786 | .dac_nids = alc260_dac_nids, | 5041 | .dac_nids = alc260_dac_nids, |
4787 | .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), | 5042 | .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), |
@@ -4789,6 +5044,8 @@ static struct alc_config_preset alc260_presets[] = { | |||
4789 | .num_channel_mode = ARRAY_SIZE(alc260_modes), | 5044 | .num_channel_mode = ARRAY_SIZE(alc260_modes), |
4790 | .channel_mode = alc260_modes, | 5045 | .channel_mode = alc260_modes, |
4791 | .input_mux = &alc260_capture_source, | 5046 | .input_mux = &alc260_capture_source, |
5047 | .unsol_event = alc260_hp_3013_unsol_event, | ||
5048 | .init_hook = alc260_hp_3013_automute, | ||
4792 | }, | 5049 | }, |
4793 | [ALC260_FUJITSU_S702X] = { | 5050 | [ALC260_FUJITSU_S702X] = { |
4794 | .mixers = { alc260_fujitsu_mixer, | 5051 | .mixers = { alc260_fujitsu_mixer, |
@@ -4906,6 +5163,8 @@ static int patch_alc260(struct hda_codec *codec) | |||
4906 | spec->stream_digital_playback = &alc260_pcm_digital_playback; | 5163 | spec->stream_digital_playback = &alc260_pcm_digital_playback; |
4907 | spec->stream_digital_capture = &alc260_pcm_digital_capture; | 5164 | spec->stream_digital_capture = &alc260_pcm_digital_capture; |
4908 | 5165 | ||
5166 | spec->vmaster_nid = 0x08; | ||
5167 | |||
4909 | codec->patch_ops = alc_patch_ops; | 5168 | codec->patch_ops = alc_patch_ops; |
4910 | if (board_config == ALC260_AUTO) | 5169 | if (board_config == ALC260_AUTO) |
4911 | spec->init_hook = alc260_auto_init; | 5170 | spec->init_hook = alc260_auto_init; |
@@ -5106,15 +5365,15 @@ static struct snd_kcontrol_new alc882_base_mixer[] = { | |||
5106 | }; | 5365 | }; |
5107 | 5366 | ||
5108 | static struct snd_kcontrol_new alc885_mbp3_mixer[] = { | 5367 | static struct snd_kcontrol_new alc885_mbp3_mixer[] = { |
5109 | HDA_CODEC_VOLUME("Master Volume", 0x0c, 0x00, HDA_OUTPUT), | 5368 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), |
5110 | HDA_BIND_MUTE ("Master Switch", 0x0c, 0x02, HDA_INPUT), | 5369 | HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), |
5111 | HDA_CODEC_MUTE ("Speaker Switch", 0x14, 0x00, HDA_OUTPUT), | 5370 | HDA_CODEC_MUTE ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT), |
5112 | HDA_CODEC_VOLUME("Line Out Volume", 0x0d,0x00, HDA_OUTPUT), | 5371 | HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0d, 0x00, HDA_OUTPUT), |
5113 | HDA_CODEC_VOLUME("Line In Playback Volume", 0x0b, 0x02, HDA_INPUT), | 5372 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), |
5114 | HDA_CODEC_MUTE ("Line In Playback Switch", 0x0b, 0x02, HDA_INPUT), | 5373 | HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), |
5115 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT), | 5374 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT), |
5116 | HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), | 5375 | HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), |
5117 | HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0x00, HDA_INPUT), | 5376 | HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT), |
5118 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT), | 5377 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT), |
5119 | { } /* end */ | 5378 | { } /* end */ |
5120 | }; | 5379 | }; |
@@ -5679,7 +5938,6 @@ static struct snd_kcontrol_new alc882_capture_alt_mixer[] = { | |||
5679 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 5938 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
5680 | /* The multiple "Capture Source" controls confuse alsamixer | 5939 | /* The multiple "Capture Source" controls confuse alsamixer |
5681 | * So call somewhat different.. | 5940 | * So call somewhat different.. |
5682 | * FIXME: the controls appear in the "playback" view! | ||
5683 | */ | 5941 | */ |
5684 | /* .name = "Capture Source", */ | 5942 | /* .name = "Capture Source", */ |
5685 | .name = "Input Source", | 5943 | .name = "Input Source", |
@@ -5702,7 +5960,6 @@ static struct snd_kcontrol_new alc882_capture_mixer[] = { | |||
5702 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 5960 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
5703 | /* The multiple "Capture Source" controls confuse alsamixer | 5961 | /* The multiple "Capture Source" controls confuse alsamixer |
5704 | * So call somewhat different.. | 5962 | * So call somewhat different.. |
5705 | * FIXME: the controls appear in the "playback" view! | ||
5706 | */ | 5963 | */ |
5707 | /* .name = "Capture Source", */ | 5964 | /* .name = "Capture Source", */ |
5708 | .name = "Input Source", | 5965 | .name = "Input Source", |
@@ -5743,16 +6000,17 @@ static const char *alc882_models[ALC882_MODEL_LAST] = { | |||
5743 | 6000 | ||
5744 | static struct snd_pci_quirk alc882_cfg_tbl[] = { | 6001 | static struct snd_pci_quirk alc882_cfg_tbl[] = { |
5745 | SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG), | 6002 | SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG), |
5746 | SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG), | ||
5747 | SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG), | ||
5748 | SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */ | ||
5749 | SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), | ||
5750 | SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J), | 6003 | SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J), |
5751 | SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J), | 6004 | SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J), |
5752 | SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M), | 6005 | SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M), |
6006 | SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC), | ||
5753 | SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG), | 6007 | SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG), |
5754 | SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG), | 6008 | SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG), |
5755 | SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC), | 6009 | SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG), |
6010 | SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG), | ||
6011 | SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */ | ||
6012 | SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG), | ||
6013 | SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), | ||
5756 | {} | 6014 | {} |
5757 | }; | 6015 | }; |
5758 | 6016 | ||
@@ -5990,7 +6248,7 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec) | |||
5990 | hda_nid_t nid; | 6248 | hda_nid_t nid; |
5991 | 6249 | ||
5992 | nid = spec->autocfg.input_pins[AUTO_PIN_MIC]; | 6250 | nid = spec->autocfg.input_pins[AUTO_PIN_MIC]; |
5993 | if (nid) { | 6251 | if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) { |
5994 | err = add_control(spec, ALC_CTL_WIDGET_VOL, | 6252 | err = add_control(spec, ALC_CTL_WIDGET_VOL, |
5995 | "Mic Boost", | 6253 | "Mic Boost", |
5996 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); | 6254 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); |
@@ -5998,7 +6256,7 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec) | |||
5998 | return err; | 6256 | return err; |
5999 | } | 6257 | } |
6000 | nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC]; | 6258 | nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC]; |
6001 | if (nid) { | 6259 | if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) { |
6002 | err = add_control(spec, ALC_CTL_WIDGET_VOL, | 6260 | err = add_control(spec, ALC_CTL_WIDGET_VOL, |
6003 | "Front Mic Boost", | 6261 | "Front Mic Boost", |
6004 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); | 6262 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); |
@@ -6061,6 +6319,7 @@ static int patch_alc882(struct hda_codec *codec) | |||
6061 | case 0x106b1000: /* iMac 24 */ | 6319 | case 0x106b1000: /* iMac 24 */ |
6062 | board_config = ALC885_IMAC24; | 6320 | board_config = ALC885_IMAC24; |
6063 | break; | 6321 | break; |
6322 | case 0x106b00a1: /* Macbook */ | ||
6064 | case 0x106b2c00: /* Macbook Pro rev3 */ | 6323 | case 0x106b2c00: /* Macbook Pro rev3 */ |
6065 | board_config = ALC885_MBP3; | 6324 | board_config = ALC885_MBP3; |
6066 | break; | 6325 | break; |
@@ -6093,6 +6352,9 @@ static int patch_alc882(struct hda_codec *codec) | |||
6093 | spec->stream_name_analog = "ALC882 Analog"; | 6352 | spec->stream_name_analog = "ALC882 Analog"; |
6094 | spec->stream_analog_playback = &alc882_pcm_analog_playback; | 6353 | spec->stream_analog_playback = &alc882_pcm_analog_playback; |
6095 | spec->stream_analog_capture = &alc882_pcm_analog_capture; | 6354 | spec->stream_analog_capture = &alc882_pcm_analog_capture; |
6355 | /* FIXME: setup DAC5 */ | ||
6356 | /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/ | ||
6357 | spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture; | ||
6096 | 6358 | ||
6097 | spec->stream_name_digital = "ALC882 Digital"; | 6359 | spec->stream_name_digital = "ALC882 Digital"; |
6098 | spec->stream_digital_playback = &alc882_pcm_digital_playback; | 6360 | spec->stream_digital_playback = &alc882_pcm_digital_playback; |
@@ -6117,6 +6379,8 @@ static int patch_alc882(struct hda_codec *codec) | |||
6117 | } | 6379 | } |
6118 | } | 6380 | } |
6119 | 6381 | ||
6382 | spec->vmaster_nid = 0x0c; | ||
6383 | |||
6120 | codec->patch_ops = alc_patch_ops; | 6384 | codec->patch_ops = alc_patch_ops; |
6121 | if (board_config == ALC882_AUTO) | 6385 | if (board_config == ALC882_AUTO) |
6122 | spec->init_hook = alc882_auto_init; | 6386 | spec->init_hook = alc882_auto_init; |
@@ -6340,6 +6604,36 @@ static struct snd_kcontrol_new alc883_base_mixer[] = { | |||
6340 | { } /* end */ | 6604 | { } /* end */ |
6341 | }; | 6605 | }; |
6342 | 6606 | ||
6607 | static struct snd_kcontrol_new alc883_mitac_mixer[] = { | ||
6608 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
6609 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), | ||
6610 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), | ||
6611 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), | ||
6612 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), | ||
6613 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), | ||
6614 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
6615 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
6616 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
6617 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
6618 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | ||
6619 | HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), | ||
6620 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | ||
6621 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), | ||
6622 | HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), | ||
6623 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), | ||
6624 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), | ||
6625 | { | ||
6626 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
6627 | /* .name = "Capture Source", */ | ||
6628 | .name = "Input Source", | ||
6629 | .count = 2, | ||
6630 | .info = alc883_mux_enum_info, | ||
6631 | .get = alc883_mux_enum_get, | ||
6632 | .put = alc883_mux_enum_put, | ||
6633 | }, | ||
6634 | { } /* end */ | ||
6635 | }; | ||
6636 | |||
6343 | static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = { | 6637 | static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = { |
6344 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 6638 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
6345 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), | 6639 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), |
@@ -6508,8 +6802,8 @@ static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = { | |||
6508 | static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = { | 6802 | static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = { |
6509 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 6803 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
6510 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), | 6804 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), |
6511 | HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | 6805 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), |
6512 | HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT), | 6806 | HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), |
6513 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | 6807 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), |
6514 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | 6808 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), |
6515 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | 6809 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), |
@@ -6658,6 +6952,46 @@ static struct snd_kcontrol_new alc888_3st_hp_mixer[] = { | |||
6658 | { } /* end */ | 6952 | { } /* end */ |
6659 | }; | 6953 | }; |
6660 | 6954 | ||
6955 | static struct snd_kcontrol_new alc888_6st_dell_mixer[] = { | ||
6956 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
6957 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), | ||
6958 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT), | ||
6959 | HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT), | ||
6960 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT), | ||
6961 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT), | ||
6962 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT), | ||
6963 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT), | ||
6964 | HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), | ||
6965 | HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), | ||
6966 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
6967 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | ||
6968 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | ||
6969 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
6970 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
6971 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
6972 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
6973 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
6974 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | ||
6975 | HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), | ||
6976 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | ||
6977 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), | ||
6978 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), | ||
6979 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), | ||
6980 | HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), | ||
6981 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), | ||
6982 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), | ||
6983 | { | ||
6984 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
6985 | /* .name = "Capture Source", */ | ||
6986 | .name = "Input Source", | ||
6987 | .count = 2, | ||
6988 | .info = alc883_mux_enum_info, | ||
6989 | .get = alc883_mux_enum_get, | ||
6990 | .put = alc883_mux_enum_put, | ||
6991 | }, | ||
6992 | { } /* end */ | ||
6993 | }; | ||
6994 | |||
6661 | static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { | 6995 | static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { |
6662 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 6996 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
6663 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), | 6997 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), |
@@ -6772,6 +7106,67 @@ static struct hda_verb alc883_init_verbs[] = { | |||
6772 | { } | 7106 | { } |
6773 | }; | 7107 | }; |
6774 | 7108 | ||
7109 | /* toggle speaker-output according to the hp-jack state */ | ||
7110 | static void alc883_mitac_hp_automute(struct hda_codec *codec) | ||
7111 | { | ||
7112 | unsigned int present; | ||
7113 | |||
7114 | present = snd_hda_codec_read(codec, 0x15, 0, | ||
7115 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
7116 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
7117 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
7118 | snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, | ||
7119 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
7120 | } | ||
7121 | |||
7122 | /* auto-toggle front mic */ | ||
7123 | /* | ||
7124 | static void alc883_mitac_mic_automute(struct hda_codec *codec) | ||
7125 | { | ||
7126 | unsigned int present; | ||
7127 | unsigned char bits; | ||
7128 | |||
7129 | present = snd_hda_codec_read(codec, 0x18, 0, | ||
7130 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
7131 | bits = present ? HDA_AMP_MUTE : 0; | ||
7132 | snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits); | ||
7133 | } | ||
7134 | */ | ||
7135 | |||
7136 | static void alc883_mitac_automute(struct hda_codec *codec) | ||
7137 | { | ||
7138 | alc883_mitac_hp_automute(codec); | ||
7139 | /* alc883_mitac_mic_automute(codec); */ | ||
7140 | } | ||
7141 | |||
7142 | static void alc883_mitac_unsol_event(struct hda_codec *codec, | ||
7143 | unsigned int res) | ||
7144 | { | ||
7145 | switch (res >> 26) { | ||
7146 | case ALC880_HP_EVENT: | ||
7147 | alc883_mitac_hp_automute(codec); | ||
7148 | break; | ||
7149 | case ALC880_MIC_EVENT: | ||
7150 | /* alc883_mitac_mic_automute(codec); */ | ||
7151 | break; | ||
7152 | } | ||
7153 | } | ||
7154 | |||
7155 | static struct hda_verb alc883_mitac_verbs[] = { | ||
7156 | /* HP */ | ||
7157 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
7158 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
7159 | /* Subwoofer */ | ||
7160 | {0x17, AC_VERB_SET_CONNECT_SEL, 0x02}, | ||
7161 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
7162 | |||
7163 | /* enable unsolicited event */ | ||
7164 | {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, | ||
7165 | /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */ | ||
7166 | |||
7167 | { } /* end */ | ||
7168 | }; | ||
7169 | |||
6775 | static struct hda_verb alc883_tagra_verbs[] = { | 7170 | static struct hda_verb alc883_tagra_verbs[] = { |
6776 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 7171 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
6777 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 7172 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
@@ -6843,6 +7238,15 @@ static struct hda_verb alc888_3st_hp_verbs[] = { | |||
6843 | { } | 7238 | { } |
6844 | }; | 7239 | }; |
6845 | 7240 | ||
7241 | static struct hda_verb alc888_6st_dell_verbs[] = { | ||
7242 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */ | ||
7243 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Rear : output 1 (0x0e) */ | ||
7244 | {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* CLFE : output 2 (0x0d) */ | ||
7245 | {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, /* Side : output 3 (0x0f) */ | ||
7246 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, | ||
7247 | { } | ||
7248 | }; | ||
7249 | |||
6846 | static struct hda_verb alc888_3st_hp_2ch_init[] = { | 7250 | static struct hda_verb alc888_3st_hp_2ch_init[] = { |
6847 | { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, | 7251 | { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, |
6848 | { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | 7252 | { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, |
@@ -7038,6 +7442,33 @@ static struct hda_verb alc883_acer_eapd_verbs[] = { | |||
7038 | { } | 7442 | { } |
7039 | }; | 7443 | }; |
7040 | 7444 | ||
7445 | static void alc888_6st_dell_front_automute(struct hda_codec *codec) | ||
7446 | { | ||
7447 | unsigned int present; | ||
7448 | |||
7449 | present = snd_hda_codec_read(codec, 0x1b, 0, | ||
7450 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
7451 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
7452 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
7453 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, | ||
7454 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
7455 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, | ||
7456 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
7457 | snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, | ||
7458 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
7459 | } | ||
7460 | |||
7461 | static void alc888_6st_dell_unsol_event(struct hda_codec *codec, | ||
7462 | unsigned int res) | ||
7463 | { | ||
7464 | switch (res >> 26) { | ||
7465 | case ALC880_HP_EVENT: | ||
7466 | printk("hp_event\n"); | ||
7467 | alc888_6st_dell_front_automute(codec); | ||
7468 | break; | ||
7469 | } | ||
7470 | } | ||
7471 | |||
7041 | /* | 7472 | /* |
7042 | * generic initialization of ADC, input mixers and output mixers | 7473 | * generic initialization of ADC, input mixers and output mixers |
7043 | */ | 7474 | */ |
@@ -7096,7 +7527,7 @@ static struct hda_verb alc883_auto_init_verbs[] = { | |||
7096 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 7527 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
7097 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | 7528 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, |
7098 | /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */ | 7529 | /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */ |
7099 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | 7530 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, |
7100 | 7531 | ||
7101 | { } | 7532 | { } |
7102 | }; | 7533 | }; |
@@ -7111,7 +7542,6 @@ static struct snd_kcontrol_new alc883_capture_mixer[] = { | |||
7111 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 7542 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
7112 | /* The multiple "Capture Source" controls confuse alsamixer | 7543 | /* The multiple "Capture Source" controls confuse alsamixer |
7113 | * So call somewhat different.. | 7544 | * So call somewhat different.. |
7114 | * FIXME: the controls appear in the "playback" view! | ||
7115 | */ | 7545 | */ |
7116 | /* .name = "Capture Source", */ | 7546 | /* .name = "Capture Source", */ |
7117 | .name = "Input Source", | 7547 | .name = "Input Source", |
@@ -7130,6 +7560,7 @@ static struct snd_kcontrol_new alc883_capture_mixer[] = { | |||
7130 | /* pcm configuration: identiacal with ALC880 */ | 7560 | /* pcm configuration: identiacal with ALC880 */ |
7131 | #define alc883_pcm_analog_playback alc880_pcm_analog_playback | 7561 | #define alc883_pcm_analog_playback alc880_pcm_analog_playback |
7132 | #define alc883_pcm_analog_capture alc880_pcm_analog_capture | 7562 | #define alc883_pcm_analog_capture alc880_pcm_analog_capture |
7563 | #define alc883_pcm_analog_alt_capture alc880_pcm_analog_alt_capture | ||
7133 | #define alc883_pcm_digital_playback alc880_pcm_digital_playback | 7564 | #define alc883_pcm_digital_playback alc880_pcm_digital_playback |
7134 | #define alc883_pcm_digital_capture alc880_pcm_digital_capture | 7565 | #define alc883_pcm_digital_capture alc880_pcm_digital_capture |
7135 | 7566 | ||
@@ -7154,53 +7585,58 @@ static const char *alc883_models[ALC883_MODEL_LAST] = { | |||
7154 | [ALC883_HAIER_W66] = "haier-w66", | 7585 | [ALC883_HAIER_W66] = "haier-w66", |
7155 | [ALC888_6ST_HP] = "6stack-hp", | 7586 | [ALC888_6ST_HP] = "6stack-hp", |
7156 | [ALC888_3ST_HP] = "3stack-hp", | 7587 | [ALC888_3ST_HP] = "3stack-hp", |
7588 | [ALC888_6ST_DELL] = "6stack-dell", | ||
7589 | [ALC883_MITAC] = "mitac", | ||
7157 | [ALC883_AUTO] = "auto", | 7590 | [ALC883_AUTO] = "auto", |
7158 | }; | 7591 | }; |
7159 | 7592 | ||
7160 | static struct snd_pci_quirk alc883_cfg_tbl[] = { | 7593 | static struct snd_pci_quirk alc883_cfg_tbl[] = { |
7161 | SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG), | 7594 | SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG), |
7595 | SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE), | ||
7596 | SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE), | ||
7597 | SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE), | ||
7598 | SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */ | ||
7599 | SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL), | ||
7162 | SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG), | 7600 | SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG), |
7163 | SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch), | 7601 | SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP), |
7164 | SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD), | 7602 | SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP), |
7603 | SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC888_6ST_HP), | ||
7604 | SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG), | ||
7165 | SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG), | 7605 | SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG), |
7606 | SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC), | ||
7607 | SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD), | ||
7608 | SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch), | ||
7166 | SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG), | 7609 | SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG), |
7167 | SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG), | ||
7168 | SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG), | ||
7169 | SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG), | ||
7170 | SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG), | ||
7171 | SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG), | ||
7172 | SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG), | 7610 | SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG), |
7611 | SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG), | ||
7173 | SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG), | 7612 | SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG), |
7174 | SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG), | 7613 | SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG), |
7175 | SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG), | ||
7176 | SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG), | 7614 | SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG), |
7177 | SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG), | 7615 | SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG), |
7178 | SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG), | 7616 | SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG), |
7179 | SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG), | 7617 | SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG), |
7618 | SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG), | ||
7180 | SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG), | 7619 | SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG), |
7181 | SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG), | 7620 | SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG), |
7182 | SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG), | 7621 | SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG), |
7183 | SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG), | 7622 | SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG), |
7623 | SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG), | ||
7624 | SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG), | ||
7625 | SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG), | ||
7626 | SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG), | ||
7627 | SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG), | ||
7184 | SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG), | 7628 | SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG), |
7185 | SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE), | 7629 | SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG), |
7186 | SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE), | 7630 | SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD), |
7187 | SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE), | ||
7188 | SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), | ||
7189 | SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch), | 7631 | SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch), |
7190 | SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION), | 7632 | SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION), |
7191 | SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD), | ||
7192 | SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch), | ||
7193 | SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch), | 7633 | SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch), |
7194 | SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763), | ||
7195 | SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763), | 7634 | SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763), |
7196 | SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC888_6ST_HP), | 7635 | SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763), |
7197 | SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP), | 7636 | SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763), |
7198 | SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP), | ||
7199 | SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2), | 7637 | SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2), |
7200 | SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66), | 7638 | SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66), |
7201 | SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763), | 7639 | SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch), |
7202 | SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG), | ||
7203 | SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG), | ||
7204 | {} | 7640 | {} |
7205 | }; | 7641 | }; |
7206 | 7642 | ||
@@ -7435,6 +7871,34 @@ static struct alc_config_preset alc883_presets[] = { | |||
7435 | .need_dac_fix = 1, | 7871 | .need_dac_fix = 1, |
7436 | .input_mux = &alc883_capture_source, | 7872 | .input_mux = &alc883_capture_source, |
7437 | }, | 7873 | }, |
7874 | [ALC888_6ST_DELL] = { | ||
7875 | .mixers = { alc888_6st_dell_mixer, alc883_chmode_mixer }, | ||
7876 | .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs }, | ||
7877 | .num_dacs = ARRAY_SIZE(alc883_dac_nids), | ||
7878 | .dac_nids = alc883_dac_nids, | ||
7879 | .dig_out_nid = ALC883_DIGOUT_NID, | ||
7880 | .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), | ||
7881 | .adc_nids = alc883_adc_nids, | ||
7882 | .dig_in_nid = ALC883_DIGIN_NID, | ||
7883 | .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), | ||
7884 | .channel_mode = alc883_sixstack_modes, | ||
7885 | .input_mux = &alc883_capture_source, | ||
7886 | .unsol_event = alc888_6st_dell_unsol_event, | ||
7887 | .init_hook = alc888_6st_dell_front_automute, | ||
7888 | }, | ||
7889 | [ALC883_MITAC] = { | ||
7890 | .mixers = { alc883_mitac_mixer }, | ||
7891 | .init_verbs = { alc883_init_verbs, alc883_mitac_verbs }, | ||
7892 | .num_dacs = ARRAY_SIZE(alc883_dac_nids), | ||
7893 | .dac_nids = alc883_dac_nids, | ||
7894 | .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), | ||
7895 | .adc_nids = alc883_adc_nids, | ||
7896 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), | ||
7897 | .channel_mode = alc883_3ST_2ch_modes, | ||
7898 | .input_mux = &alc883_capture_source, | ||
7899 | .unsol_event = alc883_mitac_unsol_event, | ||
7900 | .init_hook = alc883_mitac_automute, | ||
7901 | }, | ||
7438 | }; | 7902 | }; |
7439 | 7903 | ||
7440 | 7904 | ||
@@ -7582,6 +8046,7 @@ static int patch_alc883(struct hda_codec *codec) | |||
7582 | spec->stream_name_analog = "ALC883 Analog"; | 8046 | spec->stream_name_analog = "ALC883 Analog"; |
7583 | spec->stream_analog_playback = &alc883_pcm_analog_playback; | 8047 | spec->stream_analog_playback = &alc883_pcm_analog_playback; |
7584 | spec->stream_analog_capture = &alc883_pcm_analog_capture; | 8048 | spec->stream_analog_capture = &alc883_pcm_analog_capture; |
8049 | spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture; | ||
7585 | 8050 | ||
7586 | spec->stream_name_digital = "ALC883 Digital"; | 8051 | spec->stream_name_digital = "ALC883 Digital"; |
7587 | spec->stream_digital_playback = &alc883_pcm_digital_playback; | 8052 | spec->stream_digital_playback = &alc883_pcm_digital_playback; |
@@ -7592,6 +8057,8 @@ static int patch_alc883(struct hda_codec *codec) | |||
7592 | spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); | 8057 | spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); |
7593 | } | 8058 | } |
7594 | 8059 | ||
8060 | spec->vmaster_nid = 0x0c; | ||
8061 | |||
7595 | codec->patch_ops = alc_patch_ops; | 8062 | codec->patch_ops = alc_patch_ops; |
7596 | if (board_config == ALC883_AUTO) | 8063 | if (board_config == ALC883_AUTO) |
7597 | spec->init_hook = alc883_auto_init; | 8064 | spec->init_hook = alc883_auto_init; |
@@ -7659,13 +8126,99 @@ static struct snd_kcontrol_new alc262_hippo1_mixer[] = { | |||
7659 | { } /* end */ | 8126 | { } /* end */ |
7660 | }; | 8127 | }; |
7661 | 8128 | ||
8129 | /* update HP, line and mono-out pins according to the master switch */ | ||
8130 | static void alc262_hp_master_update(struct hda_codec *codec) | ||
8131 | { | ||
8132 | struct alc_spec *spec = codec->spec; | ||
8133 | int val = spec->master_sw; | ||
8134 | |||
8135 | /* HP & line-out */ | ||
8136 | snd_hda_codec_write_cache(codec, 0x1b, 0, | ||
8137 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
8138 | val ? PIN_HP : 0); | ||
8139 | snd_hda_codec_write_cache(codec, 0x15, 0, | ||
8140 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
8141 | val ? PIN_HP : 0); | ||
8142 | /* mono (speaker) depending on the HP jack sense */ | ||
8143 | val = val && !spec->jack_present; | ||
8144 | snd_hda_codec_write_cache(codec, 0x16, 0, | ||
8145 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
8146 | val ? PIN_OUT : 0); | ||
8147 | } | ||
8148 | |||
8149 | static void alc262_hp_bpc_automute(struct hda_codec *codec) | ||
8150 | { | ||
8151 | struct alc_spec *spec = codec->spec; | ||
8152 | unsigned int presence; | ||
8153 | presence = snd_hda_codec_read(codec, 0x1b, 0, | ||
8154 | AC_VERB_GET_PIN_SENSE, 0); | ||
8155 | spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE); | ||
8156 | alc262_hp_master_update(codec); | ||
8157 | } | ||
8158 | |||
8159 | static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res) | ||
8160 | { | ||
8161 | if ((res >> 26) != ALC880_HP_EVENT) | ||
8162 | return; | ||
8163 | alc262_hp_bpc_automute(codec); | ||
8164 | } | ||
8165 | |||
8166 | static void alc262_hp_wildwest_automute(struct hda_codec *codec) | ||
8167 | { | ||
8168 | struct alc_spec *spec = codec->spec; | ||
8169 | unsigned int presence; | ||
8170 | presence = snd_hda_codec_read(codec, 0x15, 0, | ||
8171 | AC_VERB_GET_PIN_SENSE, 0); | ||
8172 | spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE); | ||
8173 | alc262_hp_master_update(codec); | ||
8174 | } | ||
8175 | |||
8176 | static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec, | ||
8177 | unsigned int res) | ||
8178 | { | ||
8179 | if ((res >> 26) != ALC880_HP_EVENT) | ||
8180 | return; | ||
8181 | alc262_hp_wildwest_automute(codec); | ||
8182 | } | ||
8183 | |||
8184 | static int alc262_hp_master_sw_get(struct snd_kcontrol *kcontrol, | ||
8185 | struct snd_ctl_elem_value *ucontrol) | ||
8186 | { | ||
8187 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
8188 | struct alc_spec *spec = codec->spec; | ||
8189 | *ucontrol->value.integer.value = spec->master_sw; | ||
8190 | return 0; | ||
8191 | } | ||
8192 | |||
8193 | static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol, | ||
8194 | struct snd_ctl_elem_value *ucontrol) | ||
8195 | { | ||
8196 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
8197 | struct alc_spec *spec = codec->spec; | ||
8198 | int val = !!*ucontrol->value.integer.value; | ||
8199 | |||
8200 | if (val == spec->master_sw) | ||
8201 | return 0; | ||
8202 | spec->master_sw = val; | ||
8203 | alc262_hp_master_update(codec); | ||
8204 | return 1; | ||
8205 | } | ||
8206 | |||
7662 | static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { | 8207 | static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { |
8208 | { | ||
8209 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
8210 | .name = "Master Playback Switch", | ||
8211 | .info = snd_ctl_boolean_mono_info, | ||
8212 | .get = alc262_hp_master_sw_get, | ||
8213 | .put = alc262_hp_master_sw_put, | ||
8214 | }, | ||
7663 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 8215 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
7664 | HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), | 8216 | HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), |
7665 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | 8217 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), |
7666 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), | 8218 | HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0, |
7667 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), | 8219 | HDA_OUTPUT), |
7668 | 8220 | HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0, | |
8221 | HDA_OUTPUT), | ||
7669 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | 8222 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), |
7670 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | 8223 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), |
7671 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | 8224 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), |
@@ -7684,12 +8237,21 @@ static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { | |||
7684 | }; | 8237 | }; |
7685 | 8238 | ||
7686 | static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = { | 8239 | static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = { |
8240 | { | ||
8241 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
8242 | .name = "Master Playback Switch", | ||
8243 | .info = snd_ctl_boolean_mono_info, | ||
8244 | .get = alc262_hp_master_sw_get, | ||
8245 | .put = alc262_hp_master_sw_put, | ||
8246 | }, | ||
7687 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 8247 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
7688 | HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | 8248 | HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), |
7689 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | 8249 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), |
7690 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), | 8250 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), |
7691 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), | 8251 | HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0, |
7692 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), | 8252 | HDA_OUTPUT), |
8253 | HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0, | ||
8254 | HDA_OUTPUT), | ||
7693 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT), | 8255 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT), |
7694 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT), | 8256 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT), |
7695 | HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT), | 8257 | HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT), |
@@ -7709,6 +8271,85 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = { | |||
7709 | { } /* end */ | 8271 | { } /* end */ |
7710 | }; | 8272 | }; |
7711 | 8273 | ||
8274 | /* mute/unmute internal speaker according to the hp jack and mute state */ | ||
8275 | static void alc262_hp_t5735_automute(struct hda_codec *codec, int force) | ||
8276 | { | ||
8277 | struct alc_spec *spec = codec->spec; | ||
8278 | |||
8279 | if (force || !spec->sense_updated) { | ||
8280 | unsigned int present; | ||
8281 | present = snd_hda_codec_read(codec, 0x15, 0, | ||
8282 | AC_VERB_GET_PIN_SENSE, 0); | ||
8283 | spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0; | ||
8284 | spec->sense_updated = 1; | ||
8285 | } | ||
8286 | snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, HDA_AMP_MUTE, | ||
8287 | spec->jack_present ? HDA_AMP_MUTE : 0); | ||
8288 | } | ||
8289 | |||
8290 | static void alc262_hp_t5735_unsol_event(struct hda_codec *codec, | ||
8291 | unsigned int res) | ||
8292 | { | ||
8293 | if ((res >> 26) != ALC880_HP_EVENT) | ||
8294 | return; | ||
8295 | alc262_hp_t5735_automute(codec, 1); | ||
8296 | } | ||
8297 | |||
8298 | static void alc262_hp_t5735_init_hook(struct hda_codec *codec) | ||
8299 | { | ||
8300 | alc262_hp_t5735_automute(codec, 1); | ||
8301 | } | ||
8302 | |||
8303 | static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = { | ||
8304 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
8305 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
8306 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | ||
8307 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
8308 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
8309 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
8310 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
8311 | { } /* end */ | ||
8312 | }; | ||
8313 | |||
8314 | static struct hda_verb alc262_hp_t5735_verbs[] = { | ||
8315 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
8316 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
8317 | |||
8318 | {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, | ||
8319 | { } | ||
8320 | }; | ||
8321 | |||
8322 | static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = { | ||
8323 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
8324 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
8325 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT), | ||
8326 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT), | ||
8327 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT), | ||
8328 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), | ||
8329 | { } /* end */ | ||
8330 | }; | ||
8331 | |||
8332 | static struct hda_verb alc262_hp_rp5700_verbs[] = { | ||
8333 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
8334 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
8335 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
8336 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
8337 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
8338 | {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
8339 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
8340 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
8341 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))}, | ||
8342 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))}, | ||
8343 | {} | ||
8344 | }; | ||
8345 | |||
8346 | static struct hda_input_mux alc262_hp_rp5700_capture_source = { | ||
8347 | .num_items = 1, | ||
8348 | .items = { | ||
8349 | { "Line", 0x1 }, | ||
8350 | }, | ||
8351 | }; | ||
8352 | |||
7712 | /* bind hp and internal speaker mute (with plug check) */ | 8353 | /* bind hp and internal speaker mute (with plug check) */ |
7713 | static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol, | 8354 | static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol, |
7714 | struct snd_ctl_elem_value *ucontrol) | 8355 | struct snd_ctl_elem_value *ucontrol) |
@@ -8082,6 +8723,72 @@ static struct hda_verb alc262_benq_t31_EAPD_verbs[] = { | |||
8082 | {} | 8723 | {} |
8083 | }; | 8724 | }; |
8084 | 8725 | ||
8726 | /* Samsung Q1 Ultra Vista model setup */ | ||
8727 | static struct snd_kcontrol_new alc262_ultra_mixer[] = { | ||
8728 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
8729 | HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
8730 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
8731 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), | ||
8732 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), | ||
8733 | HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT), | ||
8734 | { } /* end */ | ||
8735 | }; | ||
8736 | |||
8737 | static struct hda_verb alc262_ultra_verbs[] = { | ||
8738 | {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, | ||
8739 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
8740 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
8741 | /* Mic is on Node 0x19 */ | ||
8742 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | ||
8743 | {0x22, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
8744 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
8745 | {0x23, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
8746 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
8747 | {0x24, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
8748 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
8749 | {} | ||
8750 | }; | ||
8751 | |||
8752 | static struct hda_input_mux alc262_ultra_capture_source = { | ||
8753 | .num_items = 1, | ||
8754 | .items = { | ||
8755 | { "Mic", 0x1 }, | ||
8756 | }, | ||
8757 | }; | ||
8758 | |||
8759 | /* mute/unmute internal speaker according to the hp jack and mute state */ | ||
8760 | static void alc262_ultra_automute(struct hda_codec *codec) | ||
8761 | { | ||
8762 | struct alc_spec *spec = codec->spec; | ||
8763 | unsigned int mute; | ||
8764 | unsigned int present; | ||
8765 | |||
8766 | /* need to execute and sync at first */ | ||
8767 | snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0); | ||
8768 | present = snd_hda_codec_read(codec, 0x15, 0, | ||
8769 | AC_VERB_GET_PIN_SENSE, 0); | ||
8770 | spec->jack_present = (present & 0x80000000) != 0; | ||
8771 | if (spec->jack_present) { | ||
8772 | /* mute internal speaker */ | ||
8773 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
8774 | HDA_AMP_MUTE, HDA_AMP_MUTE); | ||
8775 | } else { | ||
8776 | /* unmute internal speaker if necessary */ | ||
8777 | mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0); | ||
8778 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
8779 | HDA_AMP_MUTE, mute); | ||
8780 | } | ||
8781 | } | ||
8782 | |||
8783 | /* unsolicited event for HP jack sensing */ | ||
8784 | static void alc262_ultra_unsol_event(struct hda_codec *codec, | ||
8785 | unsigned int res) | ||
8786 | { | ||
8787 | if ((res >> 26) != ALC880_HP_EVENT) | ||
8788 | return; | ||
8789 | alc262_ultra_automute(codec); | ||
8790 | } | ||
8791 | |||
8085 | /* add playback controls from the parsed DAC table */ | 8792 | /* add playback controls from the parsed DAC table */ |
8086 | static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, | 8793 | static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, |
8087 | const struct auto_pin_cfg *cfg) | 8794 | const struct auto_pin_cfg *cfg) |
@@ -8269,7 +8976,7 @@ static struct hda_verb alc262_HP_BPC_init_verbs[] = { | |||
8269 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 8976 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
8270 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 8977 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
8271 | 8978 | ||
8272 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, | 8979 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, |
8273 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | 8980 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, |
8274 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | 8981 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, |
8275 | 8982 | ||
@@ -8311,6 +9018,8 @@ static struct hda_verb alc262_HP_BPC_init_verbs[] = { | |||
8311 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, | 9018 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, |
8312 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, | 9019 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, |
8313 | 9020 | ||
9021 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, | ||
9022 | |||
8314 | { } | 9023 | { } |
8315 | }; | 9024 | }; |
8316 | 9025 | ||
@@ -8405,6 +9114,8 @@ static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = { | |||
8405 | /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ | 9114 | /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ |
8406 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, | 9115 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, |
8407 | 9116 | ||
9117 | {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, | ||
9118 | |||
8408 | { } | 9119 | { } |
8409 | }; | 9120 | }; |
8410 | 9121 | ||
@@ -8484,39 +9195,49 @@ static const char *alc262_models[ALC262_MODEL_LAST] = { | |||
8484 | [ALC262_FUJITSU] = "fujitsu", | 9195 | [ALC262_FUJITSU] = "fujitsu", |
8485 | [ALC262_HP_BPC] = "hp-bpc", | 9196 | [ALC262_HP_BPC] = "hp-bpc", |
8486 | [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000", | 9197 | [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000", |
9198 | [ALC262_HP_TC_T5735] = "hp-tc-t5735", | ||
9199 | [ALC262_HP_RP5700] = "hp-rp5700", | ||
8487 | [ALC262_BENQ_ED8] = "benq", | 9200 | [ALC262_BENQ_ED8] = "benq", |
8488 | [ALC262_BENQ_T31] = "benq-t31", | 9201 | [ALC262_BENQ_T31] = "benq-t31", |
8489 | [ALC262_SONY_ASSAMD] = "sony-assamd", | 9202 | [ALC262_SONY_ASSAMD] = "sony-assamd", |
9203 | [ALC262_ULTRA] = "ultra", | ||
8490 | [ALC262_AUTO] = "auto", | 9204 | [ALC262_AUTO] = "auto", |
8491 | }; | 9205 | }; |
8492 | 9206 | ||
8493 | static struct snd_pci_quirk alc262_cfg_tbl[] = { | 9207 | static struct snd_pci_quirk alc262_cfg_tbl[] = { |
8494 | SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO), | 9208 | SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO), |
8495 | SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC), | 9209 | SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC), |
8496 | SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC), | ||
8497 | SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC), | 9210 | SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC), |
8498 | SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC), | ||
8499 | SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC), | ||
8500 | SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC), | ||
8501 | SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC), | ||
8502 | SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC), | 9211 | SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC), |
9212 | SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC), | ||
9213 | SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC), | ||
9214 | SND_PCI_QUIRK(0x103c, 0x1309, "HP xw4*00", ALC262_HP_BPC), | ||
9215 | SND_PCI_QUIRK(0x103c, 0x130a, "HP xw6*00", ALC262_HP_BPC), | ||
9216 | SND_PCI_QUIRK(0x103c, 0x130b, "HP xw8*00", ALC262_HP_BPC), | ||
8503 | SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL), | 9217 | SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL), |
8504 | SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL), | ||
8505 | SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL), | ||
8506 | SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL), | ||
8507 | SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF), | 9218 | SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF), |
9219 | SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL), | ||
8508 | SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF), | 9220 | SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF), |
9221 | SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL), | ||
8509 | SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF), | 9222 | SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF), |
9223 | SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL), | ||
8510 | SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF), | 9224 | SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF), |
9225 | SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC), | ||
9226 | SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC), | ||
9227 | SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC), | ||
9228 | SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735", | ||
9229 | ALC262_HP_TC_T5735), | ||
9230 | SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700), | ||
9231 | SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD), | ||
8511 | SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO), | 9232 | SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO), |
9233 | SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), | ||
9234 | SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD), | ||
9235 | SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD), | ||
8512 | SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU), | 9236 | SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU), |
8513 | SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1), | 9237 | SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA), |
8514 | SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8), | 9238 | SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8), |
8515 | SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31), | 9239 | SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31), |
8516 | SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), | 9240 | SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1), |
8517 | SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD), | ||
8518 | SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD), | ||
8519 | SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD), | ||
8520 | {} | 9241 | {} |
8521 | }; | 9242 | }; |
8522 | 9243 | ||
@@ -8579,6 +9300,8 @@ static struct alc_config_preset alc262_presets[] = { | |||
8579 | .num_channel_mode = ARRAY_SIZE(alc262_modes), | 9300 | .num_channel_mode = ARRAY_SIZE(alc262_modes), |
8580 | .channel_mode = alc262_modes, | 9301 | .channel_mode = alc262_modes, |
8581 | .input_mux = &alc262_HP_capture_source, | 9302 | .input_mux = &alc262_HP_capture_source, |
9303 | .unsol_event = alc262_hp_bpc_unsol_event, | ||
9304 | .init_hook = alc262_hp_bpc_automute, | ||
8582 | }, | 9305 | }, |
8583 | [ALC262_HP_BPC_D7000_WF] = { | 9306 | [ALC262_HP_BPC_D7000_WF] = { |
8584 | .mixers = { alc262_HP_BPC_WildWest_mixer }, | 9307 | .mixers = { alc262_HP_BPC_WildWest_mixer }, |
@@ -8589,6 +9312,8 @@ static struct alc_config_preset alc262_presets[] = { | |||
8589 | .num_channel_mode = ARRAY_SIZE(alc262_modes), | 9312 | .num_channel_mode = ARRAY_SIZE(alc262_modes), |
8590 | .channel_mode = alc262_modes, | 9313 | .channel_mode = alc262_modes, |
8591 | .input_mux = &alc262_HP_D7000_capture_source, | 9314 | .input_mux = &alc262_HP_D7000_capture_source, |
9315 | .unsol_event = alc262_hp_wildwest_unsol_event, | ||
9316 | .init_hook = alc262_hp_wildwest_automute, | ||
8592 | }, | 9317 | }, |
8593 | [ALC262_HP_BPC_D7000_WL] = { | 9318 | [ALC262_HP_BPC_D7000_WL] = { |
8594 | .mixers = { alc262_HP_BPC_WildWest_mixer, | 9319 | .mixers = { alc262_HP_BPC_WildWest_mixer, |
@@ -8600,7 +9325,30 @@ static struct alc_config_preset alc262_presets[] = { | |||
8600 | .num_channel_mode = ARRAY_SIZE(alc262_modes), | 9325 | .num_channel_mode = ARRAY_SIZE(alc262_modes), |
8601 | .channel_mode = alc262_modes, | 9326 | .channel_mode = alc262_modes, |
8602 | .input_mux = &alc262_HP_D7000_capture_source, | 9327 | .input_mux = &alc262_HP_D7000_capture_source, |
9328 | .unsol_event = alc262_hp_wildwest_unsol_event, | ||
9329 | .init_hook = alc262_hp_wildwest_automute, | ||
9330 | }, | ||
9331 | [ALC262_HP_TC_T5735] = { | ||
9332 | .mixers = { alc262_hp_t5735_mixer }, | ||
9333 | .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs }, | ||
9334 | .num_dacs = ARRAY_SIZE(alc262_dac_nids), | ||
9335 | .dac_nids = alc262_dac_nids, | ||
9336 | .hp_nid = 0x03, | ||
9337 | .num_channel_mode = ARRAY_SIZE(alc262_modes), | ||
9338 | .channel_mode = alc262_modes, | ||
9339 | .input_mux = &alc262_capture_source, | ||
9340 | .unsol_event = alc262_hp_t5735_unsol_event, | ||
9341 | .init_hook = alc262_hp_t5735_init_hook, | ||
8603 | }, | 9342 | }, |
9343 | [ALC262_HP_RP5700] = { | ||
9344 | .mixers = { alc262_hp_rp5700_mixer }, | ||
9345 | .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs }, | ||
9346 | .num_dacs = ARRAY_SIZE(alc262_dac_nids), | ||
9347 | .dac_nids = alc262_dac_nids, | ||
9348 | .num_channel_mode = ARRAY_SIZE(alc262_modes), | ||
9349 | .channel_mode = alc262_modes, | ||
9350 | .input_mux = &alc262_hp_rp5700_capture_source, | ||
9351 | }, | ||
8604 | [ALC262_BENQ_ED8] = { | 9352 | [ALC262_BENQ_ED8] = { |
8605 | .mixers = { alc262_base_mixer }, | 9353 | .mixers = { alc262_base_mixer }, |
8606 | .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs }, | 9354 | .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs }, |
@@ -8635,6 +9383,19 @@ static struct alc_config_preset alc262_presets[] = { | |||
8635 | .unsol_event = alc262_hippo_unsol_event, | 9383 | .unsol_event = alc262_hippo_unsol_event, |
8636 | .init_hook = alc262_hippo_automute, | 9384 | .init_hook = alc262_hippo_automute, |
8637 | }, | 9385 | }, |
9386 | [ALC262_ULTRA] = { | ||
9387 | .mixers = { alc262_ultra_mixer }, | ||
9388 | .init_verbs = { alc262_init_verbs, alc262_ultra_verbs }, | ||
9389 | .num_dacs = ARRAY_SIZE(alc262_dac_nids), | ||
9390 | .dac_nids = alc262_dac_nids, | ||
9391 | .hp_nid = 0x03, | ||
9392 | .dig_out_nid = ALC262_DIGOUT_NID, | ||
9393 | .num_channel_mode = ARRAY_SIZE(alc262_modes), | ||
9394 | .channel_mode = alc262_modes, | ||
9395 | .input_mux = &alc262_ultra_capture_source, | ||
9396 | .unsol_event = alc262_ultra_unsol_event, | ||
9397 | .init_hook = alc262_ultra_automute, | ||
9398 | }, | ||
8638 | }; | 9399 | }; |
8639 | 9400 | ||
8640 | static int patch_alc262(struct hda_codec *codec) | 9401 | static int patch_alc262(struct hda_codec *codec) |
@@ -8716,6 +9477,8 @@ static int patch_alc262(struct hda_codec *codec) | |||
8716 | } | 9477 | } |
8717 | } | 9478 | } |
8718 | 9479 | ||
9480 | spec->vmaster_nid = 0x0c; | ||
9481 | |||
8719 | codec->patch_ops = alc_patch_ops; | 9482 | codec->patch_ops = alc_patch_ops; |
8720 | if (board_config == ALC262_AUTO) | 9483 | if (board_config == ALC262_AUTO) |
8721 | spec->init_hook = alc262_auto_init; | 9484 | spec->init_hook = alc262_auto_init; |
@@ -8873,6 +9636,49 @@ static void alc268_acer_init_hook(struct hda_codec *codec) | |||
8873 | alc268_acer_automute(codec, 1); | 9636 | alc268_acer_automute(codec, 1); |
8874 | } | 9637 | } |
8875 | 9638 | ||
9639 | static struct snd_kcontrol_new alc268_dell_mixer[] = { | ||
9640 | /* output mixer control */ | ||
9641 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), | ||
9642 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
9643 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
9644 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
9645 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
9646 | HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT), | ||
9647 | { } | ||
9648 | }; | ||
9649 | |||
9650 | static struct hda_verb alc268_dell_verbs[] = { | ||
9651 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
9652 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
9653 | {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, | ||
9654 | { } | ||
9655 | }; | ||
9656 | |||
9657 | /* mute/unmute internal speaker according to the hp jack and mute state */ | ||
9658 | static void alc268_dell_automute(struct hda_codec *codec) | ||
9659 | { | ||
9660 | unsigned int present; | ||
9661 | unsigned int mute; | ||
9662 | |||
9663 | present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0); | ||
9664 | if (present & 0x80000000) | ||
9665 | mute = HDA_AMP_MUTE; | ||
9666 | else | ||
9667 | mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0); | ||
9668 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
9669 | HDA_AMP_MUTE, mute); | ||
9670 | } | ||
9671 | |||
9672 | static void alc268_dell_unsol_event(struct hda_codec *codec, | ||
9673 | unsigned int res) | ||
9674 | { | ||
9675 | if ((res >> 26) != ALC880_HP_EVENT) | ||
9676 | return; | ||
9677 | alc268_dell_automute(codec); | ||
9678 | } | ||
9679 | |||
9680 | #define alc268_dell_init_hook alc268_dell_automute | ||
9681 | |||
8876 | /* | 9682 | /* |
8877 | * generic initialization of ADC, input mixers and output mixers | 9683 | * generic initialization of ADC, input mixers and output mixers |
8878 | */ | 9684 | */ |
@@ -8915,19 +9721,13 @@ static struct hda_verb alc268_base_init_verbs[] = { | |||
8915 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | 9721 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, |
8916 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 9722 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, |
8917 | 9723 | ||
8918 | /* FIXME: use matrix-type input source selection */ | 9724 | /* Unmute Selector 23h,24h and set the default input to mic-in */ |
8919 | /* Mixer elements: 0x18, 19, 1a, 1c, 14, 15, 0b */ | 9725 | |
8920 | /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ | 9726 | {0x23, AC_VERB_SET_CONNECT_SEL, 0x00}, |
8921 | /* Input mixer2 */ | 9727 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
8922 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 9728 | {0x24, AC_VERB_SET_CONNECT_SEL, 0x00}, |
8923 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | 9729 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
8924 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, | ||
8925 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, | ||
8926 | 9730 | ||
8927 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
8928 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
8929 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, | ||
8930 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, | ||
8931 | { } | 9731 | { } |
8932 | }; | 9732 | }; |
8933 | 9733 | ||
@@ -8972,29 +9772,14 @@ static int alc268_mux_enum_put(struct snd_kcontrol *kcontrol, | |||
8972 | { | 9772 | { |
8973 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 9773 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
8974 | struct alc_spec *spec = codec->spec; | 9774 | struct alc_spec *spec = codec->spec; |
8975 | const struct hda_input_mux *imux = spec->input_mux; | 9775 | |
8976 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | 9776 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); |
8977 | static hda_nid_t capture_mixers[3] = { 0x23, 0x24 }; | 9777 | static hda_nid_t capture_mixers[3] = { 0x23, 0x24 }; |
8978 | hda_nid_t nid = capture_mixers[adc_idx]; | 9778 | hda_nid_t nid = capture_mixers[adc_idx]; |
8979 | unsigned int *cur_val = &spec->cur_mux[adc_idx]; | ||
8980 | unsigned int i, idx; | ||
8981 | 9779 | ||
8982 | idx = ucontrol->value.enumerated.item[0]; | 9780 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, |
8983 | if (idx >= imux->num_items) | 9781 | nid, |
8984 | idx = imux->num_items - 1; | 9782 | &spec->cur_mux[adc_idx]); |
8985 | if (*cur_val == idx) | ||
8986 | return 0; | ||
8987 | for (i = 0; i < imux->num_items; i++) { | ||
8988 | unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; | ||
8989 | snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, | ||
8990 | imux->items[i].index, | ||
8991 | HDA_AMP_MUTE, v); | ||
8992 | snd_hda_codec_write_cache(codec, nid, 0, | ||
8993 | AC_VERB_SET_CONNECT_SEL, | ||
8994 | idx ); | ||
8995 | } | ||
8996 | *cur_val = idx; | ||
8997 | return 1; | ||
8998 | } | 9783 | } |
8999 | 9784 | ||
9000 | static struct snd_kcontrol_new alc268_capture_alt_mixer[] = { | 9785 | static struct snd_kcontrol_new alc268_capture_alt_mixer[] = { |
@@ -9004,7 +9789,6 @@ static struct snd_kcontrol_new alc268_capture_alt_mixer[] = { | |||
9004 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 9789 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
9005 | /* The multiple "Capture Source" controls confuse alsamixer | 9790 | /* The multiple "Capture Source" controls confuse alsamixer |
9006 | * So call somewhat different.. | 9791 | * So call somewhat different.. |
9007 | * FIXME: the controls appear in the "playback" view! | ||
9008 | */ | 9792 | */ |
9009 | /* .name = "Capture Source", */ | 9793 | /* .name = "Capture Source", */ |
9010 | .name = "Input Source", | 9794 | .name = "Input Source", |
@@ -9025,7 +9809,6 @@ static struct snd_kcontrol_new alc268_capture_mixer[] = { | |||
9025 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 9809 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
9026 | /* The multiple "Capture Source" controls confuse alsamixer | 9810 | /* The multiple "Capture Source" controls confuse alsamixer |
9027 | * So call somewhat different.. | 9811 | * So call somewhat different.. |
9028 | * FIXME: the controls appear in the "playback" view! | ||
9029 | */ | 9812 | */ |
9030 | /* .name = "Capture Source", */ | 9813 | /* .name = "Capture Source", */ |
9031 | .name = "Input Source", | 9814 | .name = "Input Source", |
@@ -9047,6 +9830,61 @@ static struct hda_input_mux alc268_capture_source = { | |||
9047 | }, | 9830 | }, |
9048 | }; | 9831 | }; |
9049 | 9832 | ||
9833 | #ifdef CONFIG_SND_DEBUG | ||
9834 | static struct snd_kcontrol_new alc268_test_mixer[] = { | ||
9835 | HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), | ||
9836 | HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
9837 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), | ||
9838 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
9839 | |||
9840 | /* Volume widgets */ | ||
9841 | HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT), | ||
9842 | HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
9843 | HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT), | ||
9844 | HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT), | ||
9845 | HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT), | ||
9846 | HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT), | ||
9847 | HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT), | ||
9848 | HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT), | ||
9849 | HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT), | ||
9850 | HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT), | ||
9851 | HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT), | ||
9852 | HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT), | ||
9853 | HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT), | ||
9854 | /* The below appears problematic on some hardwares */ | ||
9855 | /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/ | ||
9856 | HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT), | ||
9857 | HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT), | ||
9858 | HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT), | ||
9859 | HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT), | ||
9860 | |||
9861 | /* Modes for retasking pin widgets */ | ||
9862 | ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT), | ||
9863 | ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT), | ||
9864 | ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT), | ||
9865 | ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT), | ||
9866 | |||
9867 | /* Controls for GPIO pins, assuming they are configured as outputs */ | ||
9868 | ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01), | ||
9869 | ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02), | ||
9870 | ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04), | ||
9871 | ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08), | ||
9872 | |||
9873 | /* Switches to allow the digital SPDIF output pin to be enabled. | ||
9874 | * The ALC268 does not have an SPDIF input. | ||
9875 | */ | ||
9876 | ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01), | ||
9877 | |||
9878 | /* A switch allowing EAPD to be enabled. Some laptops seem to use | ||
9879 | * this output to turn on an external amplifier. | ||
9880 | */ | ||
9881 | ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02), | ||
9882 | ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02), | ||
9883 | |||
9884 | { } /* end */ | ||
9885 | }; | ||
9886 | #endif | ||
9887 | |||
9050 | /* create input playback/capture controls for the given pin */ | 9888 | /* create input playback/capture controls for the given pin */ |
9051 | static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid, | 9889 | static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid, |
9052 | const char *ctlname, int idx) | 9890 | const char *ctlname, int idx) |
@@ -9194,6 +10032,7 @@ static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec) | |||
9194 | /* pcm configuration: identiacal with ALC880 */ | 10032 | /* pcm configuration: identiacal with ALC880 */ |
9195 | #define alc268_pcm_analog_playback alc880_pcm_analog_playback | 10033 | #define alc268_pcm_analog_playback alc880_pcm_analog_playback |
9196 | #define alc268_pcm_analog_capture alc880_pcm_analog_capture | 10034 | #define alc268_pcm_analog_capture alc880_pcm_analog_capture |
10035 | #define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture | ||
9197 | #define alc268_pcm_digital_playback alc880_pcm_digital_playback | 10036 | #define alc268_pcm_digital_playback alc880_pcm_digital_playback |
9198 | 10037 | ||
9199 | /* | 10038 | /* |
@@ -9259,16 +10098,23 @@ static const char *alc268_models[ALC268_MODEL_LAST] = { | |||
9259 | [ALC268_3ST] = "3stack", | 10098 | [ALC268_3ST] = "3stack", |
9260 | [ALC268_TOSHIBA] = "toshiba", | 10099 | [ALC268_TOSHIBA] = "toshiba", |
9261 | [ALC268_ACER] = "acer", | 10100 | [ALC268_ACER] = "acer", |
10101 | [ALC268_DELL] = "dell", | ||
10102 | #ifdef CONFIG_SND_DEBUG | ||
10103 | [ALC268_TEST] = "test", | ||
10104 | #endif | ||
9262 | [ALC268_AUTO] = "auto", | 10105 | [ALC268_AUTO] = "auto", |
9263 | }; | 10106 | }; |
9264 | 10107 | ||
9265 | static struct snd_pci_quirk alc268_cfg_tbl[] = { | 10108 | static struct snd_pci_quirk alc268_cfg_tbl[] = { |
10109 | SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER), | ||
10110 | SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER), | ||
10111 | SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER), | ||
10112 | SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER), | ||
10113 | SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL), | ||
10114 | SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA), | ||
9266 | SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST), | 10115 | SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST), |
9267 | SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA), | 10116 | SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA), |
9268 | SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA), | 10117 | SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA), |
9269 | SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA), | ||
9270 | SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER), | ||
9271 | SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER), | ||
9272 | SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER), | 10118 | SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER), |
9273 | {} | 10119 | {} |
9274 | }; | 10120 | }; |
@@ -9317,6 +10163,35 @@ static struct alc_config_preset alc268_presets[] = { | |||
9317 | .unsol_event = alc268_acer_unsol_event, | 10163 | .unsol_event = alc268_acer_unsol_event, |
9318 | .init_hook = alc268_acer_init_hook, | 10164 | .init_hook = alc268_acer_init_hook, |
9319 | }, | 10165 | }, |
10166 | [ALC268_DELL] = { | ||
10167 | .mixers = { alc268_dell_mixer }, | ||
10168 | .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, | ||
10169 | alc268_dell_verbs }, | ||
10170 | .num_dacs = ARRAY_SIZE(alc268_dac_nids), | ||
10171 | .dac_nids = alc268_dac_nids, | ||
10172 | .hp_nid = 0x02, | ||
10173 | .num_channel_mode = ARRAY_SIZE(alc268_modes), | ||
10174 | .channel_mode = alc268_modes, | ||
10175 | .unsol_event = alc268_dell_unsol_event, | ||
10176 | .init_hook = alc268_dell_init_hook, | ||
10177 | .input_mux = &alc268_capture_source, | ||
10178 | }, | ||
10179 | #ifdef CONFIG_SND_DEBUG | ||
10180 | [ALC268_TEST] = { | ||
10181 | .mixers = { alc268_test_mixer, alc268_capture_mixer }, | ||
10182 | .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, | ||
10183 | alc268_volume_init_verbs }, | ||
10184 | .num_dacs = ARRAY_SIZE(alc268_dac_nids), | ||
10185 | .dac_nids = alc268_dac_nids, | ||
10186 | .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), | ||
10187 | .adc_nids = alc268_adc_nids_alt, | ||
10188 | .hp_nid = 0x03, | ||
10189 | .dig_out_nid = ALC268_DIGOUT_NID, | ||
10190 | .num_channel_mode = ARRAY_SIZE(alc268_modes), | ||
10191 | .channel_mode = alc268_modes, | ||
10192 | .input_mux = &alc268_capture_source, | ||
10193 | }, | ||
10194 | #endif | ||
9320 | }; | 10195 | }; |
9321 | 10196 | ||
9322 | static int patch_alc268(struct hda_codec *codec) | 10197 | static int patch_alc268(struct hda_codec *codec) |
@@ -9361,34 +10236,34 @@ static int patch_alc268(struct hda_codec *codec) | |||
9361 | spec->stream_name_analog = "ALC268 Analog"; | 10236 | spec->stream_name_analog = "ALC268 Analog"; |
9362 | spec->stream_analog_playback = &alc268_pcm_analog_playback; | 10237 | spec->stream_analog_playback = &alc268_pcm_analog_playback; |
9363 | spec->stream_analog_capture = &alc268_pcm_analog_capture; | 10238 | spec->stream_analog_capture = &alc268_pcm_analog_capture; |
10239 | spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture; | ||
9364 | 10240 | ||
9365 | spec->stream_name_digital = "ALC268 Digital"; | 10241 | spec->stream_name_digital = "ALC268 Digital"; |
9366 | spec->stream_digital_playback = &alc268_pcm_digital_playback; | 10242 | spec->stream_digital_playback = &alc268_pcm_digital_playback; |
9367 | 10243 | ||
9368 | if (board_config == ALC268_AUTO) { | 10244 | if (!spec->adc_nids && spec->input_mux) { |
9369 | if (!spec->adc_nids && spec->input_mux) { | 10245 | /* check whether NID 0x07 is valid */ |
9370 | /* check whether NID 0x07 is valid */ | 10246 | unsigned int wcap = get_wcaps(codec, 0x07); |
9371 | unsigned int wcap = get_wcaps(codec, 0x07); | 10247 | |
9372 | 10248 | /* get type */ | |
9373 | /* get type */ | 10249 | wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; |
9374 | wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; | 10250 | if (wcap != AC_WID_AUD_IN) { |
9375 | if (wcap != AC_WID_AUD_IN) { | 10251 | spec->adc_nids = alc268_adc_nids_alt; |
9376 | spec->adc_nids = alc268_adc_nids_alt; | 10252 | spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt); |
9377 | spec->num_adc_nids = | 10253 | spec->mixers[spec->num_mixers] = |
9378 | ARRAY_SIZE(alc268_adc_nids_alt); | ||
9379 | spec->mixers[spec->num_mixers] = | ||
9380 | alc268_capture_alt_mixer; | 10254 | alc268_capture_alt_mixer; |
9381 | spec->num_mixers++; | 10255 | spec->num_mixers++; |
9382 | } else { | 10256 | } else { |
9383 | spec->adc_nids = alc268_adc_nids; | 10257 | spec->adc_nids = alc268_adc_nids; |
9384 | spec->num_adc_nids = | 10258 | spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids); |
9385 | ARRAY_SIZE(alc268_adc_nids); | 10259 | spec->mixers[spec->num_mixers] = |
9386 | spec->mixers[spec->num_mixers] = | 10260 | alc268_capture_mixer; |
9387 | alc268_capture_mixer; | 10261 | spec->num_mixers++; |
9388 | spec->num_mixers++; | ||
9389 | } | ||
9390 | } | 10262 | } |
9391 | } | 10263 | } |
10264 | |||
10265 | spec->vmaster_nid = 0x02; | ||
10266 | |||
9392 | codec->patch_ops = alc_patch_ops; | 10267 | codec->patch_ops = alc_patch_ops; |
9393 | if (board_config == ALC268_AUTO) | 10268 | if (board_config == ALC268_AUTO) |
9394 | spec->init_hook = alc268_auto_init; | 10269 | spec->init_hook = alc268_auto_init; |
@@ -9397,6 +10272,360 @@ static int patch_alc268(struct hda_codec *codec) | |||
9397 | } | 10272 | } |
9398 | 10273 | ||
9399 | /* | 10274 | /* |
10275 | * ALC269 channel source setting (2 channel) | ||
10276 | */ | ||
10277 | #define ALC269_DIGOUT_NID ALC880_DIGOUT_NID | ||
10278 | |||
10279 | #define alc269_dac_nids alc260_dac_nids | ||
10280 | |||
10281 | static hda_nid_t alc269_adc_nids[1] = { | ||
10282 | /* ADC1 */ | ||
10283 | 0x07, | ||
10284 | }; | ||
10285 | |||
10286 | #define alc269_modes alc260_modes | ||
10287 | #define alc269_capture_source alc880_lg_lw_capture_source | ||
10288 | |||
10289 | static struct snd_kcontrol_new alc269_base_mixer[] = { | ||
10290 | HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), | ||
10291 | HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
10292 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
10293 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
10294 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
10295 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
10296 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
10297 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), | ||
10298 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), | ||
10299 | HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), | ||
10300 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
10301 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), | ||
10302 | { } /* end */ | ||
10303 | }; | ||
10304 | |||
10305 | /* capture mixer elements */ | ||
10306 | static struct snd_kcontrol_new alc269_capture_mixer[] = { | ||
10307 | HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), | ||
10308 | HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), | ||
10309 | { | ||
10310 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
10311 | /* The multiple "Capture Source" controls confuse alsamixer | ||
10312 | * So call somewhat different.. | ||
10313 | */ | ||
10314 | /* .name = "Capture Source", */ | ||
10315 | .name = "Input Source", | ||
10316 | .count = 1, | ||
10317 | .info = alc_mux_enum_info, | ||
10318 | .get = alc_mux_enum_get, | ||
10319 | .put = alc_mux_enum_put, | ||
10320 | }, | ||
10321 | { } /* end */ | ||
10322 | }; | ||
10323 | |||
10324 | /* | ||
10325 | * generic initialization of ADC, input mixers and output mixers | ||
10326 | */ | ||
10327 | static struct hda_verb alc269_init_verbs[] = { | ||
10328 | /* | ||
10329 | * Unmute ADC0 and set the default input to mic-in | ||
10330 | */ | ||
10331 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
10332 | |||
10333 | /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the | ||
10334 | * analog-loopback mixer widget | ||
10335 | * Note: PASD motherboards uses the Line In 2 as the input for | ||
10336 | * front panel mic (mic 2) | ||
10337 | */ | ||
10338 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ | ||
10339 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
10340 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
10341 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
10342 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
10343 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
10344 | |||
10345 | /* | ||
10346 | * Set up output mixers (0x0c - 0x0e) | ||
10347 | */ | ||
10348 | /* set vol=0 to output mixers */ | ||
10349 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
10350 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
10351 | |||
10352 | /* set up input amps for analog loopback */ | ||
10353 | /* Amp Indices: DAC = 0, mixer = 1 */ | ||
10354 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
10355 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
10356 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
10357 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
10358 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
10359 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
10360 | |||
10361 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
10362 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
10363 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
10364 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
10365 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
10366 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
10367 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
10368 | |||
10369 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
10370 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
10371 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
10372 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
10373 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
10374 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
10375 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
10376 | |||
10377 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
10378 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
10379 | |||
10380 | /* FIXME: use matrix-type input source selection */ | ||
10381 | /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */ | ||
10382 | /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ | ||
10383 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
10384 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
10385 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
10386 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
10387 | |||
10388 | /* set EAPD */ | ||
10389 | {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, | ||
10390 | {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, | ||
10391 | { } | ||
10392 | }; | ||
10393 | |||
10394 | /* add playback controls from the parsed DAC table */ | ||
10395 | static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec, | ||
10396 | const struct auto_pin_cfg *cfg) | ||
10397 | { | ||
10398 | hda_nid_t nid; | ||
10399 | int err; | ||
10400 | |||
10401 | spec->multiout.num_dacs = 1; /* only use one dac */ | ||
10402 | spec->multiout.dac_nids = spec->private_dac_nids; | ||
10403 | spec->multiout.dac_nids[0] = 2; | ||
10404 | |||
10405 | nid = cfg->line_out_pins[0]; | ||
10406 | if (nid) { | ||
10407 | err = add_control(spec, ALC_CTL_WIDGET_VOL, | ||
10408 | "Front Playback Volume", | ||
10409 | HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT)); | ||
10410 | if (err < 0) | ||
10411 | return err; | ||
10412 | err = add_control(spec, ALC_CTL_WIDGET_MUTE, | ||
10413 | "Front Playback Switch", | ||
10414 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); | ||
10415 | if (err < 0) | ||
10416 | return err; | ||
10417 | } | ||
10418 | |||
10419 | nid = cfg->speaker_pins[0]; | ||
10420 | if (nid) { | ||
10421 | if (!cfg->line_out_pins[0]) { | ||
10422 | err = add_control(spec, ALC_CTL_WIDGET_VOL, | ||
10423 | "Speaker Playback Volume", | ||
10424 | HDA_COMPOSE_AMP_VAL(0x02, 3, 0, | ||
10425 | HDA_OUTPUT)); | ||
10426 | if (err < 0) | ||
10427 | return err; | ||
10428 | } | ||
10429 | if (nid == 0x16) { | ||
10430 | err = add_control(spec, ALC_CTL_WIDGET_MUTE, | ||
10431 | "Speaker Playback Switch", | ||
10432 | HDA_COMPOSE_AMP_VAL(nid, 2, 0, | ||
10433 | HDA_OUTPUT)); | ||
10434 | if (err < 0) | ||
10435 | return err; | ||
10436 | } else { | ||
10437 | err = add_control(spec, ALC_CTL_WIDGET_MUTE, | ||
10438 | "Speaker Playback Switch", | ||
10439 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, | ||
10440 | HDA_OUTPUT)); | ||
10441 | if (err < 0) | ||
10442 | return err; | ||
10443 | } | ||
10444 | } | ||
10445 | nid = cfg->hp_pins[0]; | ||
10446 | if (nid) { | ||
10447 | /* spec->multiout.hp_nid = 2; */ | ||
10448 | if (!cfg->line_out_pins[0] && !cfg->speaker_pins[0]) { | ||
10449 | err = add_control(spec, ALC_CTL_WIDGET_VOL, | ||
10450 | "Headphone Playback Volume", | ||
10451 | HDA_COMPOSE_AMP_VAL(0x02, 3, 0, | ||
10452 | HDA_OUTPUT)); | ||
10453 | if (err < 0) | ||
10454 | return err; | ||
10455 | } | ||
10456 | if (nid == 0x16) { | ||
10457 | err = add_control(spec, ALC_CTL_WIDGET_MUTE, | ||
10458 | "Headphone Playback Switch", | ||
10459 | HDA_COMPOSE_AMP_VAL(nid, 2, 0, | ||
10460 | HDA_OUTPUT)); | ||
10461 | if (err < 0) | ||
10462 | return err; | ||
10463 | } else { | ||
10464 | err = add_control(spec, ALC_CTL_WIDGET_MUTE, | ||
10465 | "Headphone Playback Switch", | ||
10466 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, | ||
10467 | HDA_OUTPUT)); | ||
10468 | if (err < 0) | ||
10469 | return err; | ||
10470 | } | ||
10471 | } | ||
10472 | return 0; | ||
10473 | } | ||
10474 | |||
10475 | #define alc269_auto_create_analog_input_ctls \ | ||
10476 | alc880_auto_create_analog_input_ctls | ||
10477 | |||
10478 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
10479 | #define alc269_loopbacks alc880_loopbacks | ||
10480 | #endif | ||
10481 | |||
10482 | /* pcm configuration: identiacal with ALC880 */ | ||
10483 | #define alc269_pcm_analog_playback alc880_pcm_analog_playback | ||
10484 | #define alc269_pcm_analog_capture alc880_pcm_analog_capture | ||
10485 | #define alc269_pcm_digital_playback alc880_pcm_digital_playback | ||
10486 | #define alc269_pcm_digital_capture alc880_pcm_digital_capture | ||
10487 | |||
10488 | /* | ||
10489 | * BIOS auto configuration | ||
10490 | */ | ||
10491 | static int alc269_parse_auto_config(struct hda_codec *codec) | ||
10492 | { | ||
10493 | struct alc_spec *spec = codec->spec; | ||
10494 | int err; | ||
10495 | static hda_nid_t alc269_ignore[] = { 0x1d, 0 }; | ||
10496 | |||
10497 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, | ||
10498 | alc269_ignore); | ||
10499 | if (err < 0) | ||
10500 | return err; | ||
10501 | |||
10502 | err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg); | ||
10503 | if (err < 0) | ||
10504 | return err; | ||
10505 | err = alc269_auto_create_analog_input_ctls(spec, &spec->autocfg); | ||
10506 | if (err < 0) | ||
10507 | return err; | ||
10508 | |||
10509 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | ||
10510 | |||
10511 | if (spec->autocfg.dig_out_pin) | ||
10512 | spec->multiout.dig_out_nid = ALC269_DIGOUT_NID; | ||
10513 | |||
10514 | if (spec->kctl_alloc) | ||
10515 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; | ||
10516 | |||
10517 | spec->init_verbs[spec->num_init_verbs++] = alc269_init_verbs; | ||
10518 | spec->num_mux_defs = 1; | ||
10519 | spec->input_mux = &spec->private_imux; | ||
10520 | |||
10521 | err = alc_auto_add_mic_boost(codec); | ||
10522 | if (err < 0) | ||
10523 | return err; | ||
10524 | |||
10525 | return 1; | ||
10526 | } | ||
10527 | |||
10528 | #define alc269_auto_init_multi_out alc882_auto_init_multi_out | ||
10529 | #define alc269_auto_init_hp_out alc882_auto_init_hp_out | ||
10530 | #define alc269_auto_init_analog_input alc882_auto_init_analog_input | ||
10531 | |||
10532 | |||
10533 | /* init callback for auto-configuration model -- overriding the default init */ | ||
10534 | static void alc269_auto_init(struct hda_codec *codec) | ||
10535 | { | ||
10536 | alc269_auto_init_multi_out(codec); | ||
10537 | alc269_auto_init_hp_out(codec); | ||
10538 | alc269_auto_init_analog_input(codec); | ||
10539 | } | ||
10540 | |||
10541 | /* | ||
10542 | * configuration and preset | ||
10543 | */ | ||
10544 | static const char *alc269_models[ALC269_MODEL_LAST] = { | ||
10545 | [ALC269_BASIC] = "basic", | ||
10546 | }; | ||
10547 | |||
10548 | static struct snd_pci_quirk alc269_cfg_tbl[] = { | ||
10549 | {} | ||
10550 | }; | ||
10551 | |||
10552 | static struct alc_config_preset alc269_presets[] = { | ||
10553 | [ALC269_BASIC] = { | ||
10554 | .mixers = { alc269_base_mixer }, | ||
10555 | .init_verbs = { alc269_init_verbs }, | ||
10556 | .num_dacs = ARRAY_SIZE(alc269_dac_nids), | ||
10557 | .dac_nids = alc269_dac_nids, | ||
10558 | .hp_nid = 0x03, | ||
10559 | .num_channel_mode = ARRAY_SIZE(alc269_modes), | ||
10560 | .channel_mode = alc269_modes, | ||
10561 | .input_mux = &alc269_capture_source, | ||
10562 | }, | ||
10563 | }; | ||
10564 | |||
10565 | static int patch_alc269(struct hda_codec *codec) | ||
10566 | { | ||
10567 | struct alc_spec *spec; | ||
10568 | int board_config; | ||
10569 | int err; | ||
10570 | |||
10571 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
10572 | if (spec == NULL) | ||
10573 | return -ENOMEM; | ||
10574 | |||
10575 | codec->spec = spec; | ||
10576 | |||
10577 | board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST, | ||
10578 | alc269_models, | ||
10579 | alc269_cfg_tbl); | ||
10580 | |||
10581 | if (board_config < 0) { | ||
10582 | printk(KERN_INFO "hda_codec: Unknown model for ALC269, " | ||
10583 | "trying auto-probe from BIOS...\n"); | ||
10584 | board_config = ALC269_AUTO; | ||
10585 | } | ||
10586 | |||
10587 | if (board_config == ALC269_AUTO) { | ||
10588 | /* automatic parse from the BIOS config */ | ||
10589 | err = alc269_parse_auto_config(codec); | ||
10590 | if (err < 0) { | ||
10591 | alc_free(codec); | ||
10592 | return err; | ||
10593 | } else if (!err) { | ||
10594 | printk(KERN_INFO | ||
10595 | "hda_codec: Cannot set up configuration " | ||
10596 | "from BIOS. Using base mode...\n"); | ||
10597 | board_config = ALC269_BASIC; | ||
10598 | } | ||
10599 | } | ||
10600 | |||
10601 | if (board_config != ALC269_AUTO) | ||
10602 | setup_preset(spec, &alc269_presets[board_config]); | ||
10603 | |||
10604 | spec->stream_name_analog = "ALC269 Analog"; | ||
10605 | spec->stream_analog_playback = &alc269_pcm_analog_playback; | ||
10606 | spec->stream_analog_capture = &alc269_pcm_analog_capture; | ||
10607 | |||
10608 | spec->stream_name_digital = "ALC269 Digital"; | ||
10609 | spec->stream_digital_playback = &alc269_pcm_digital_playback; | ||
10610 | spec->stream_digital_capture = &alc269_pcm_digital_capture; | ||
10611 | |||
10612 | spec->adc_nids = alc269_adc_nids; | ||
10613 | spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids); | ||
10614 | spec->mixers[spec->num_mixers] = alc269_capture_mixer; | ||
10615 | spec->num_mixers++; | ||
10616 | |||
10617 | codec->patch_ops = alc_patch_ops; | ||
10618 | if (board_config == ALC269_AUTO) | ||
10619 | spec->init_hook = alc269_auto_init; | ||
10620 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
10621 | if (!spec->loopback.amplist) | ||
10622 | spec->loopback.amplist = alc269_loopbacks; | ||
10623 | #endif | ||
10624 | |||
10625 | return 0; | ||
10626 | } | ||
10627 | |||
10628 | /* | ||
9400 | * ALC861 channel source setting (2/6 channel selection for 3-stack) | 10629 | * ALC861 channel source setting (2/6 channel selection for 3-stack) |
9401 | */ | 10630 | */ |
9402 | 10631 | ||
@@ -10213,7 +11442,6 @@ static struct snd_kcontrol_new alc861_capture_mixer[] = { | |||
10213 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 11442 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
10214 | /* The multiple "Capture Source" controls confuse alsamixer | 11443 | /* The multiple "Capture Source" controls confuse alsamixer |
10215 | * So call somewhat different.. | 11444 | * So call somewhat different.. |
10216 | *FIXME: the controls appear in the "playback" view! | ||
10217 | */ | 11445 | */ |
10218 | /* .name = "Capture Source", */ | 11446 | /* .name = "Capture Source", */ |
10219 | .name = "Input Source", | 11447 | .name = "Input Source", |
@@ -10369,22 +11597,23 @@ static struct snd_pci_quirk alc861_cfg_tbl[] = { | |||
10369 | SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST), | 11597 | SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST), |
10370 | SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP), | 11598 | SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP), |
10371 | SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP), | 11599 | SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP), |
10372 | SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP), | ||
10373 | SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP), | ||
10374 | SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS), | 11600 | SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS), |
11601 | SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP), | ||
10375 | SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG), | 11602 | SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG), |
10376 | SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA), | 11603 | SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA), |
10377 | /* FIXME: the entry below breaks Toshiba A100 (model=auto works!) | 11604 | /* FIXME: the entry below breaks Toshiba A100 (model=auto works!) |
10378 | * Any other models that need this preset? | 11605 | * Any other models that need this preset? |
10379 | */ | 11606 | */ |
10380 | /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */ | 11607 | /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */ |
10381 | SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31), | 11608 | SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST), |
10382 | SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), | 11609 | SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST), |
10383 | SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31), | 11610 | SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31), |
11611 | SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31), | ||
11612 | SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP), | ||
11613 | /* FIXME: the below seems conflict */ | ||
11614 | /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */ | ||
10384 | SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST), | 11615 | SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST), |
10385 | SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST), | 11616 | SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST), |
10386 | SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST), | ||
10387 | SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST), | ||
10388 | {} | 11617 | {} |
10389 | }; | 11618 | }; |
10390 | 11619 | ||
@@ -10543,6 +11772,8 @@ static int patch_alc861(struct hda_codec *codec) | |||
10543 | spec->stream_digital_playback = &alc861_pcm_digital_playback; | 11772 | spec->stream_digital_playback = &alc861_pcm_digital_playback; |
10544 | spec->stream_digital_capture = &alc861_pcm_digital_capture; | 11773 | spec->stream_digital_capture = &alc861_pcm_digital_capture; |
10545 | 11774 | ||
11775 | spec->vmaster_nid = 0x03; | ||
11776 | |||
10546 | codec->patch_ops = alc_patch_ops; | 11777 | codec->patch_ops = alc_patch_ops; |
10547 | if (board_config == ALC861_AUTO) | 11778 | if (board_config == ALC861_AUTO) |
10548 | spec->init_hook = alc861_auto_init; | 11779 | spec->init_hook = alc861_auto_init; |
@@ -10697,7 +11928,6 @@ static struct snd_kcontrol_new alc861vd_capture_mixer[] = { | |||
10697 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 11928 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
10698 | /* The multiple "Capture Source" controls confuse alsamixer | 11929 | /* The multiple "Capture Source" controls confuse alsamixer |
10699 | * So call somewhat different.. | 11930 | * So call somewhat different.. |
10700 | *FIXME: the controls appear in the "playback" view! | ||
10701 | */ | 11931 | */ |
10702 | /* .name = "Capture Source", */ | 11932 | /* .name = "Capture Source", */ |
10703 | .name = "Input Source", | 11933 | .name = "Input Source", |
@@ -11102,21 +12332,20 @@ static const char *alc861vd_models[ALC861VD_MODEL_LAST] = { | |||
11102 | }; | 12332 | }; |
11103 | 12333 | ||
11104 | static struct snd_pci_quirk alc861vd_cfg_tbl[] = { | 12334 | static struct snd_pci_quirk alc861vd_cfg_tbl[] = { |
12335 | SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST), | ||
12336 | SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP), | ||
11105 | SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST), | 12337 | SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST), |
11106 | SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST), | 12338 | SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST), |
11107 | SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG), | 12339 | SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG), |
11108 | SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST), | 12340 | SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST), |
11109 | SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST), | 12341 | SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO), |
11110 | |||
11111 | /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/ | 12342 | /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/ |
11112 | SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS), | 12343 | SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS), |
11113 | SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO), | ||
11114 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO), | ||
11115 | SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO), | ||
11116 | SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO), | 12344 | SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO), |
11117 | SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG), | 12345 | SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG), |
12346 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO), | ||
12347 | SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO), | ||
11118 | SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG), | 12348 | SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG), |
11119 | SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP), | ||
11120 | {} | 12349 | {} |
11121 | }; | 12350 | }; |
11122 | 12351 | ||
@@ -11520,6 +12749,8 @@ static int patch_alc861vd(struct hda_codec *codec) | |||
11520 | spec->mixers[spec->num_mixers] = alc861vd_capture_mixer; | 12749 | spec->mixers[spec->num_mixers] = alc861vd_capture_mixer; |
11521 | spec->num_mixers++; | 12750 | spec->num_mixers++; |
11522 | 12751 | ||
12752 | spec->vmaster_nid = 0x02; | ||
12753 | |||
11523 | codec->patch_ops = alc_patch_ops; | 12754 | codec->patch_ops = alc_patch_ops; |
11524 | 12755 | ||
11525 | if (board_config == ALC861VD_AUTO) | 12756 | if (board_config == ALC861VD_AUTO) |
@@ -11699,18 +12930,6 @@ static struct snd_kcontrol_new alc662_base_mixer[] = { | |||
11699 | HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT), | 12930 | HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT), |
11700 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT), | 12931 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT), |
11701 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT), | 12932 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT), |
11702 | |||
11703 | /* Capture mixer control */ | ||
11704 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), | ||
11705 | HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), | ||
11706 | { | ||
11707 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
11708 | .name = "Capture Source", | ||
11709 | .count = 1, | ||
11710 | .info = alc_mux_enum_info, | ||
11711 | .get = alc_mux_enum_get, | ||
11712 | .put = alc_mux_enum_put, | ||
11713 | }, | ||
11714 | { } /* end */ | 12933 | { } /* end */ |
11715 | }; | 12934 | }; |
11716 | 12935 | ||
@@ -11728,17 +12947,6 @@ static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = { | |||
11728 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | 12947 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), |
11729 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), | 12948 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), |
11730 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), | 12949 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), |
11731 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), | ||
11732 | HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), | ||
11733 | { | ||
11734 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
11735 | /* .name = "Capture Source", */ | ||
11736 | .name = "Input Source", | ||
11737 | .count = 1, | ||
11738 | .info = alc662_mux_enum_info, | ||
11739 | .get = alc662_mux_enum_get, | ||
11740 | .put = alc662_mux_enum_put, | ||
11741 | }, | ||
11742 | { } /* end */ | 12950 | { } /* end */ |
11743 | }; | 12951 | }; |
11744 | 12952 | ||
@@ -11762,46 +12970,24 @@ static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = { | |||
11762 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | 12970 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), |
11763 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), | 12971 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), |
11764 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), | 12972 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), |
11765 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), | ||
11766 | HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), | ||
11767 | { | ||
11768 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
11769 | /* .name = "Capture Source", */ | ||
11770 | .name = "Input Source", | ||
11771 | .count = 1, | ||
11772 | .info = alc662_mux_enum_info, | ||
11773 | .get = alc662_mux_enum_get, | ||
11774 | .put = alc662_mux_enum_put, | ||
11775 | }, | ||
11776 | { } /* end */ | 12973 | { } /* end */ |
11777 | }; | 12974 | }; |
11778 | 12975 | ||
11779 | static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = { | 12976 | static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = { |
11780 | HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), | 12977 | HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), |
11781 | HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT), | 12978 | HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT), |
11782 | HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x03, 0x0, HDA_OUTPUT), | 12979 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT), |
11783 | HDA_BIND_MUTE("iSpeaker Playback Switch", 0x03, 2, HDA_INPUT), | 12980 | HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT), |
11784 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | 12981 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), |
11785 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | 12982 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), |
11786 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | 12983 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), |
11787 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | 12984 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), |
11788 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | 12985 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), |
11789 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), | ||
11790 | HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), | ||
11791 | { | ||
11792 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
11793 | /* .name = "Capture Source", */ | ||
11794 | .name = "Input Source", | ||
11795 | .count = 1, | ||
11796 | .info = alc662_mux_enum_info, | ||
11797 | .get = alc662_mux_enum_get, | ||
11798 | .put = alc662_mux_enum_put, | ||
11799 | }, | ||
11800 | { } /* end */ | 12986 | { } /* end */ |
11801 | }; | 12987 | }; |
11802 | 12988 | ||
11803 | static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { | 12989 | static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { |
11804 | HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), | 12990 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), |
11805 | 12991 | ||
11806 | HDA_CODEC_VOLUME("LineOut Playback Volume", 0x02, 0x0, HDA_OUTPUT), | 12992 | HDA_CODEC_VOLUME("LineOut Playback Volume", 0x02, 0x0, HDA_OUTPUT), |
11807 | HDA_CODEC_MUTE("LineOut Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | 12993 | HDA_CODEC_MUTE("LineOut Playback Switch", 0x1b, 0x0, HDA_OUTPUT), |
@@ -11816,6 +13002,24 @@ static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { | |||
11816 | { } /* end */ | 13002 | { } /* end */ |
11817 | }; | 13003 | }; |
11818 | 13004 | ||
13005 | static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = { | ||
13006 | HDA_CODEC_VOLUME("LineOut Playback Volume", 0x02, 0x0, HDA_OUTPUT), | ||
13007 | HDA_CODEC_MUTE("LineOut Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
13008 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
13009 | HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT), | ||
13010 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT), | ||
13011 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT), | ||
13012 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT), | ||
13013 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT), | ||
13014 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
13015 | HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT), | ||
13016 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
13017 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
13018 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
13019 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
13020 | { } /* end */ | ||
13021 | }; | ||
13022 | |||
11819 | static struct snd_kcontrol_new alc662_chmode_mixer[] = { | 13023 | static struct snd_kcontrol_new alc662_chmode_mixer[] = { |
11820 | { | 13024 | { |
11821 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 13025 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -11901,6 +13105,13 @@ static struct hda_verb alc662_eeepc_sue_init_verbs[] = { | |||
11901 | {} | 13105 | {} |
11902 | }; | 13106 | }; |
11903 | 13107 | ||
13108 | /* Set Unsolicited Event*/ | ||
13109 | static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = { | ||
13110 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
13111 | {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, | ||
13112 | {} | ||
13113 | }; | ||
13114 | |||
11904 | /* | 13115 | /* |
11905 | * generic initialization of ADC, input mixers and output mixers | 13116 | * generic initialization of ADC, input mixers and output mixers |
11906 | */ | 13117 | */ |
@@ -11957,14 +13168,13 @@ static struct snd_kcontrol_new alc662_capture_mixer[] = { | |||
11957 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 13168 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
11958 | /* The multiple "Capture Source" controls confuse alsamixer | 13169 | /* The multiple "Capture Source" controls confuse alsamixer |
11959 | * So call somewhat different.. | 13170 | * So call somewhat different.. |
11960 | * FIXME: the controls appear in the "playback" view! | ||
11961 | */ | 13171 | */ |
11962 | /* .name = "Capture Source", */ | 13172 | /* .name = "Capture Source", */ |
11963 | .name = "Input Source", | 13173 | .name = "Input Source", |
11964 | .count = 1, | 13174 | .count = 1, |
11965 | .info = alc882_mux_enum_info, | 13175 | .info = alc662_mux_enum_info, |
11966 | .get = alc882_mux_enum_get, | 13176 | .get = alc662_mux_enum_get, |
11967 | .put = alc882_mux_enum_put, | 13177 | .put = alc662_mux_enum_put, |
11968 | }, | 13178 | }, |
11969 | { } /* end */ | 13179 | { } /* end */ |
11970 | }; | 13180 | }; |
@@ -12037,6 +13247,40 @@ static void alc662_eeepc_inithook(struct hda_codec *codec) | |||
12037 | alc662_eeepc_mic_automute(codec); | 13247 | alc662_eeepc_mic_automute(codec); |
12038 | } | 13248 | } |
12039 | 13249 | ||
13250 | static void alc662_eeepc_ep20_automute(struct hda_codec *codec) | ||
13251 | { | ||
13252 | unsigned int mute; | ||
13253 | unsigned int present; | ||
13254 | |||
13255 | snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0); | ||
13256 | present = snd_hda_codec_read(codec, 0x14, 0, | ||
13257 | AC_VERB_GET_PIN_SENSE, 0); | ||
13258 | present = (present & 0x80000000) != 0; | ||
13259 | if (present) { | ||
13260 | /* mute internal speaker */ | ||
13261 | snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, | ||
13262 | HDA_AMP_MUTE, HDA_AMP_MUTE); | ||
13263 | } else { | ||
13264 | /* unmute internal speaker if necessary */ | ||
13265 | mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0); | ||
13266 | snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, | ||
13267 | HDA_AMP_MUTE, mute); | ||
13268 | } | ||
13269 | } | ||
13270 | |||
13271 | /* unsolicited event for HP jack sensing */ | ||
13272 | static void alc662_eeepc_ep20_unsol_event(struct hda_codec *codec, | ||
13273 | unsigned int res) | ||
13274 | { | ||
13275 | if ((res >> 26) == ALC880_HP_EVENT) | ||
13276 | alc662_eeepc_ep20_automute(codec); | ||
13277 | } | ||
13278 | |||
13279 | static void alc662_eeepc_ep20_inithook(struct hda_codec *codec) | ||
13280 | { | ||
13281 | alc662_eeepc_ep20_automute(codec); | ||
13282 | } | ||
13283 | |||
12040 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 13284 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
12041 | #define alc662_loopbacks alc880_loopbacks | 13285 | #define alc662_loopbacks alc880_loopbacks |
12042 | #endif | 13286 | #endif |
@@ -12057,12 +13301,15 @@ static const char *alc662_models[ALC662_MODEL_LAST] = { | |||
12057 | [ALC662_3ST_6ch] = "3stack-6ch", | 13301 | [ALC662_3ST_6ch] = "3stack-6ch", |
12058 | [ALC662_5ST_DIG] = "6stack-dig", | 13302 | [ALC662_5ST_DIG] = "6stack-dig", |
12059 | [ALC662_LENOVO_101E] = "lenovo-101e", | 13303 | [ALC662_LENOVO_101E] = "lenovo-101e", |
13304 | [ALC662_ASUS_EEEPC_P701] = "eeepc-p701", | ||
13305 | [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20", | ||
12060 | [ALC662_AUTO] = "auto", | 13306 | [ALC662_AUTO] = "auto", |
12061 | }; | 13307 | }; |
12062 | 13308 | ||
12063 | static struct snd_pci_quirk alc662_cfg_tbl[] = { | 13309 | static struct snd_pci_quirk alc662_cfg_tbl[] = { |
12064 | SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), | ||
12065 | SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701), | 13310 | SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701), |
13311 | SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20), | ||
13312 | SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), | ||
12066 | {} | 13313 | {} |
12067 | }; | 13314 | }; |
12068 | 13315 | ||
@@ -12149,6 +13396,21 @@ static struct alc_config_preset alc662_presets[] = { | |||
12149 | .unsol_event = alc662_eeepc_unsol_event, | 13396 | .unsol_event = alc662_eeepc_unsol_event, |
12150 | .init_hook = alc662_eeepc_inithook, | 13397 | .init_hook = alc662_eeepc_inithook, |
12151 | }, | 13398 | }, |
13399 | [ALC662_ASUS_EEEPC_EP20] = { | ||
13400 | .mixers = { alc662_eeepc_ep20_mixer, alc662_capture_mixer, | ||
13401 | alc662_chmode_mixer }, | ||
13402 | .init_verbs = { alc662_init_verbs, | ||
13403 | alc662_eeepc_ep20_sue_init_verbs }, | ||
13404 | .num_dacs = ARRAY_SIZE(alc662_dac_nids), | ||
13405 | .dac_nids = alc662_dac_nids, | ||
13406 | .num_adc_nids = ARRAY_SIZE(alc662_adc_nids), | ||
13407 | .adc_nids = alc662_adc_nids, | ||
13408 | .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), | ||
13409 | .channel_mode = alc662_3ST_6ch_modes, | ||
13410 | .input_mux = &alc662_lenovo_101e_capture_source, | ||
13411 | .unsol_event = alc662_eeepc_ep20_unsol_event, | ||
13412 | .init_hook = alc662_eeepc_ep20_inithook, | ||
13413 | }, | ||
12152 | 13414 | ||
12153 | }; | 13415 | }; |
12154 | 13416 | ||
@@ -12308,6 +13570,7 @@ static void alc662_auto_init_multi_out(struct hda_codec *codec) | |||
12308 | struct alc_spec *spec = codec->spec; | 13570 | struct alc_spec *spec = codec->spec; |
12309 | int i; | 13571 | int i; |
12310 | 13572 | ||
13573 | alc_subsystem_id(codec, 0x15, 0x1b, 0x14); | ||
12311 | for (i = 0; i <= HDA_SIDE; i++) { | 13574 | for (i = 0; i <= HDA_SIDE; i++) { |
12312 | hda_nid_t nid = spec->autocfg.line_out_pins[i]; | 13575 | hda_nid_t nid = spec->autocfg.line_out_pins[i]; |
12313 | int pin_type = get_pin_type(spec->autocfg.line_out_type); | 13576 | int pin_type = get_pin_type(spec->autocfg.line_out_type); |
@@ -12458,6 +13721,8 @@ static int patch_alc662(struct hda_codec *codec) | |||
12458 | spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids); | 13721 | spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids); |
12459 | } | 13722 | } |
12460 | 13723 | ||
13724 | spec->vmaster_nid = 0x02; | ||
13725 | |||
12461 | codec->patch_ops = alc_patch_ops; | 13726 | codec->patch_ops = alc_patch_ops; |
12462 | if (board_config == ALC662_AUTO) | 13727 | if (board_config == ALC662_AUTO) |
12463 | spec->init_hook = alc662_auto_init; | 13728 | spec->init_hook = alc662_auto_init; |
@@ -12475,7 +13740,9 @@ static int patch_alc662(struct hda_codec *codec) | |||
12475 | struct hda_codec_preset snd_hda_preset_realtek[] = { | 13740 | struct hda_codec_preset snd_hda_preset_realtek[] = { |
12476 | { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, | 13741 | { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, |
12477 | { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 }, | 13742 | { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 }, |
13743 | { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 }, | ||
12478 | { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 }, | 13744 | { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 }, |
13745 | { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 }, | ||
12479 | { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", | 13746 | { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", |
12480 | .patch = patch_alc861 }, | 13747 | .patch = patch_alc861 }, |
12481 | { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd }, | 13748 | { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd }, |
@@ -12490,5 +13757,6 @@ struct hda_codec_preset snd_hda_preset_realtek[] = { | |||
12490 | { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 }, | 13757 | { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 }, |
12491 | { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 }, | 13758 | { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 }, |
12492 | { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 }, | 13759 | { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 }, |
13760 | { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 }, | ||
12493 | {} /* terminator */ | 13761 | {} /* terminator */ |
12494 | }; | 13762 | }; |
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index 2a4b9609aa5c..d22f5a6b850f 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c | |||
@@ -22,7 +22,6 @@ | |||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <sound/driver.h> | ||
26 | #include <linux/init.h> | 25 | #include <linux/init.h> |
27 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
28 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
@@ -287,7 +286,6 @@ static int patch_si3054(struct hda_codec *codec) | |||
287 | struct hda_codec_preset snd_hda_preset_si3054[] = { | 286 | struct hda_codec_preset snd_hda_preset_si3054[] = { |
288 | { .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 }, | 287 | { .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 }, |
289 | { .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 }, | 288 | { .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 }, |
290 | { .id = 0x11c11040, .name = "Si3054", .patch = patch_si3054 }, | ||
291 | { .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 }, | 289 | { .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 }, |
292 | { .id = 0x11c13055, .name = "Si3054", .patch = patch_si3054 }, | 290 | { .id = 0x11c13055, .name = "Si3054", .patch = patch_si3054 }, |
293 | { .id = 0x11c13155, .name = "Si3054", .patch = patch_si3054 }, | 291 | { .id = 0x11c13155, .name = "Si3054", .patch = patch_si3054 }, |
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 04012237096c..caf48edaa921 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -24,7 +24,6 @@ | |||
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
25 | */ | 25 | */ |
26 | 26 | ||
27 | #include <sound/driver.h> | ||
28 | #include <linux/init.h> | 27 | #include <linux/init.h> |
29 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
30 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
@@ -35,7 +34,8 @@ | |||
35 | #include "hda_local.h" | 34 | #include "hda_local.h" |
36 | 35 | ||
37 | #define NUM_CONTROL_ALLOC 32 | 36 | #define NUM_CONTROL_ALLOC 32 |
38 | #define STAC_HP_EVENT 0x37 | 37 | #define STAC_PWR_EVENT 0x20 |
38 | #define STAC_HP_EVENT 0x30 | ||
39 | 39 | ||
40 | enum { | 40 | enum { |
41 | STAC_REF, | 41 | STAC_REF, |
@@ -62,6 +62,16 @@ enum { | |||
62 | }; | 62 | }; |
63 | 63 | ||
64 | enum { | 64 | enum { |
65 | STAC_92HD73XX_REF, | ||
66 | STAC_92HD73XX_MODELS | ||
67 | }; | ||
68 | |||
69 | enum { | ||
70 | STAC_92HD71BXX_REF, | ||
71 | STAC_92HD71BXX_MODELS | ||
72 | }; | ||
73 | |||
74 | enum { | ||
65 | STAC_925x_REF, | 75 | STAC_925x_REF, |
66 | STAC_M2_2, | 76 | STAC_M2_2, |
67 | STAC_MA6, | 77 | STAC_MA6, |
@@ -97,6 +107,7 @@ enum { | |||
97 | STAC_D965_3ST, | 107 | STAC_D965_3ST, |
98 | STAC_D965_5ST, | 108 | STAC_D965_5ST, |
99 | STAC_DELL_3ST, | 109 | STAC_DELL_3ST, |
110 | STAC_DELL_BIOS, | ||
100 | STAC_927X_MODELS | 111 | STAC_927X_MODELS |
101 | }; | 112 | }; |
102 | 113 | ||
@@ -110,11 +121,24 @@ struct sigmatel_spec { | |||
110 | unsigned int mic_switch: 1; | 121 | unsigned int mic_switch: 1; |
111 | unsigned int alt_switch: 1; | 122 | unsigned int alt_switch: 1; |
112 | unsigned int hp_detect: 1; | 123 | unsigned int hp_detect: 1; |
113 | unsigned int gpio_mute: 1; | ||
114 | 124 | ||
115 | unsigned int gpio_mask, gpio_data; | 125 | /* gpio lines */ |
126 | unsigned int gpio_mask; | ||
127 | unsigned int gpio_dir; | ||
128 | unsigned int gpio_data; | ||
129 | unsigned int gpio_mute; | ||
130 | |||
131 | /* analog loopback */ | ||
132 | unsigned char aloopback_mask; | ||
133 | unsigned char aloopback_shift; | ||
134 | |||
135 | /* power management */ | ||
136 | unsigned int num_pwrs; | ||
137 | hda_nid_t *pwr_nids; | ||
116 | 138 | ||
117 | /* playback */ | 139 | /* playback */ |
140 | struct hda_input_mux *mono_mux; | ||
141 | unsigned int cur_mmux; | ||
118 | struct hda_multi_out multiout; | 142 | struct hda_multi_out multiout; |
119 | hda_nid_t dac_nids[5]; | 143 | hda_nid_t dac_nids[5]; |
120 | 144 | ||
@@ -125,8 +149,10 @@ struct sigmatel_spec { | |||
125 | unsigned int num_muxes; | 149 | unsigned int num_muxes; |
126 | hda_nid_t *dmic_nids; | 150 | hda_nid_t *dmic_nids; |
127 | unsigned int num_dmics; | 151 | unsigned int num_dmics; |
128 | hda_nid_t dmux_nid; | 152 | hda_nid_t *dmux_nids; |
153 | unsigned int num_dmuxes; | ||
129 | hda_nid_t dig_in_nid; | 154 | hda_nid_t dig_in_nid; |
155 | hda_nid_t mono_nid; | ||
130 | 156 | ||
131 | /* pin widgets */ | 157 | /* pin widgets */ |
132 | hda_nid_t *pin_nids; | 158 | hda_nid_t *pin_nids; |
@@ -140,7 +166,7 @@ struct sigmatel_spec { | |||
140 | 166 | ||
141 | /* capture source */ | 167 | /* capture source */ |
142 | struct hda_input_mux *dinput_mux; | 168 | struct hda_input_mux *dinput_mux; |
143 | unsigned int cur_dmux; | 169 | unsigned int cur_dmux[2]; |
144 | struct hda_input_mux *input_mux; | 170 | struct hda_input_mux *input_mux; |
145 | unsigned int cur_mux[3]; | 171 | unsigned int cur_mux[3]; |
146 | 172 | ||
@@ -157,6 +183,10 @@ struct sigmatel_spec { | |||
157 | struct snd_kcontrol_new *kctl_alloc; | 183 | struct snd_kcontrol_new *kctl_alloc; |
158 | struct hda_input_mux private_dimux; | 184 | struct hda_input_mux private_dimux; |
159 | struct hda_input_mux private_imux; | 185 | struct hda_input_mux private_imux; |
186 | struct hda_input_mux private_mono_mux; | ||
187 | |||
188 | /* virtual master */ | ||
189 | unsigned int vmaster_tlv[4]; | ||
160 | }; | 190 | }; |
161 | 191 | ||
162 | static hda_nid_t stac9200_adc_nids[1] = { | 192 | static hda_nid_t stac9200_adc_nids[1] = { |
@@ -171,6 +201,58 @@ static hda_nid_t stac9200_dac_nids[1] = { | |||
171 | 0x02, | 201 | 0x02, |
172 | }; | 202 | }; |
173 | 203 | ||
204 | static hda_nid_t stac92hd73xx_pwr_nids[8] = { | ||
205 | 0x0a, 0x0b, 0x0c, 0xd, 0x0e, | ||
206 | 0x0f, 0x10, 0x11 | ||
207 | }; | ||
208 | |||
209 | static hda_nid_t stac92hd73xx_adc_nids[2] = { | ||
210 | 0x1a, 0x1b | ||
211 | }; | ||
212 | |||
213 | #define STAC92HD73XX_NUM_DMICS 2 | ||
214 | static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = { | ||
215 | 0x13, 0x14, 0 | ||
216 | }; | ||
217 | |||
218 | #define STAC92HD73_DAC_COUNT 5 | ||
219 | static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = { | ||
220 | 0x15, 0x16, 0x17, 0x18, 0x19, | ||
221 | }; | ||
222 | |||
223 | static hda_nid_t stac92hd73xx_mux_nids[4] = { | ||
224 | 0x28, 0x29, 0x2a, 0x2b, | ||
225 | }; | ||
226 | |||
227 | static hda_nid_t stac92hd73xx_dmux_nids[2] = { | ||
228 | 0x20, 0x21, | ||
229 | }; | ||
230 | |||
231 | static hda_nid_t stac92hd71bxx_pwr_nids[3] = { | ||
232 | 0x0a, 0x0d, 0x0f | ||
233 | }; | ||
234 | |||
235 | static hda_nid_t stac92hd71bxx_adc_nids[2] = { | ||
236 | 0x12, 0x13, | ||
237 | }; | ||
238 | |||
239 | static hda_nid_t stac92hd71bxx_mux_nids[2] = { | ||
240 | 0x1a, 0x1b | ||
241 | }; | ||
242 | |||
243 | static hda_nid_t stac92hd71bxx_dmux_nids[1] = { | ||
244 | 0x1c, | ||
245 | }; | ||
246 | |||
247 | static hda_nid_t stac92hd71bxx_dac_nids[2] = { | ||
248 | 0x10, /*0x11, */ | ||
249 | }; | ||
250 | |||
251 | #define STAC92HD71BXX_NUM_DMICS 2 | ||
252 | static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = { | ||
253 | 0x18, 0x19, 0 | ||
254 | }; | ||
255 | |||
174 | static hda_nid_t stac925x_adc_nids[1] = { | 256 | static hda_nid_t stac925x_adc_nids[1] = { |
175 | 0x03, | 257 | 0x03, |
176 | }; | 258 | }; |
@@ -188,6 +270,10 @@ static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = { | |||
188 | 0x15, 0 | 270 | 0x15, 0 |
189 | }; | 271 | }; |
190 | 272 | ||
273 | static hda_nid_t stac925x_dmux_nids[1] = { | ||
274 | 0x14, | ||
275 | }; | ||
276 | |||
191 | static hda_nid_t stac922x_adc_nids[2] = { | 277 | static hda_nid_t stac922x_adc_nids[2] = { |
192 | 0x06, 0x07, | 278 | 0x06, 0x07, |
193 | }; | 279 | }; |
@@ -204,6 +290,15 @@ static hda_nid_t stac927x_mux_nids[3] = { | |||
204 | 0x15, 0x16, 0x17 | 290 | 0x15, 0x16, 0x17 |
205 | }; | 291 | }; |
206 | 292 | ||
293 | static hda_nid_t stac927x_dmux_nids[1] = { | ||
294 | 0x1b, | ||
295 | }; | ||
296 | |||
297 | #define STAC927X_NUM_DMICS 2 | ||
298 | static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = { | ||
299 | 0x13, 0x14, 0 | ||
300 | }; | ||
301 | |||
207 | static hda_nid_t stac9205_adc_nids[2] = { | 302 | static hda_nid_t stac9205_adc_nids[2] = { |
208 | 0x12, 0x13 | 303 | 0x12, 0x13 |
209 | }; | 304 | }; |
@@ -212,6 +307,10 @@ static hda_nid_t stac9205_mux_nids[2] = { | |||
212 | 0x19, 0x1a | 307 | 0x19, 0x1a |
213 | }; | 308 | }; |
214 | 309 | ||
310 | static hda_nid_t stac9205_dmux_nids[1] = { | ||
311 | 0x1d, | ||
312 | }; | ||
313 | |||
215 | #define STAC9205_NUM_DMICS 2 | 314 | #define STAC9205_NUM_DMICS 2 |
216 | static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = { | 315 | static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = { |
217 | 0x17, 0x18, 0 | 316 | 0x17, 0x18, 0 |
@@ -232,6 +331,17 @@ static hda_nid_t stac922x_pin_nids[10] = { | |||
232 | 0x0f, 0x10, 0x11, 0x15, 0x1b, | 331 | 0x0f, 0x10, 0x11, 0x15, 0x1b, |
233 | }; | 332 | }; |
234 | 333 | ||
334 | static hda_nid_t stac92hd73xx_pin_nids[12] = { | ||
335 | 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, | ||
336 | 0x0f, 0x10, 0x11, 0x12, 0x13, | ||
337 | 0x14, 0x22 | ||
338 | }; | ||
339 | |||
340 | static hda_nid_t stac92hd71bxx_pin_nids[10] = { | ||
341 | 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, | ||
342 | 0x0f, 0x14, 0x18, 0x19, 0x1e, | ||
343 | }; | ||
344 | |||
235 | static hda_nid_t stac927x_pin_nids[14] = { | 345 | static hda_nid_t stac927x_pin_nids[14] = { |
236 | 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, | 346 | 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, |
237 | 0x0f, 0x10, 0x11, 0x12, 0x13, | 347 | 0x0f, 0x10, 0x11, 0x12, 0x13, |
@@ -257,8 +367,9 @@ static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol, | |||
257 | { | 367 | { |
258 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 368 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
259 | struct sigmatel_spec *spec = codec->spec; | 369 | struct sigmatel_spec *spec = codec->spec; |
370 | unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
260 | 371 | ||
261 | ucontrol->value.enumerated.item[0] = spec->cur_dmux; | 372 | ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx]; |
262 | return 0; | 373 | return 0; |
263 | } | 374 | } |
264 | 375 | ||
@@ -267,9 +378,10 @@ static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol, | |||
267 | { | 378 | { |
268 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 379 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
269 | struct sigmatel_spec *spec = codec->spec; | 380 | struct sigmatel_spec *spec = codec->spec; |
381 | unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
270 | 382 | ||
271 | return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol, | 383 | return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol, |
272 | spec->dmux_nid, &spec->cur_dmux); | 384 | spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]); |
273 | } | 385 | } |
274 | 386 | ||
275 | static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 387 | static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
@@ -299,15 +411,45 @@ static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
299 | spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]); | 411 | spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]); |
300 | } | 412 | } |
301 | 413 | ||
414 | static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol, | ||
415 | struct snd_ctl_elem_info *uinfo) | ||
416 | { | ||
417 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
418 | struct sigmatel_spec *spec = codec->spec; | ||
419 | return snd_hda_input_mux_info(spec->mono_mux, uinfo); | ||
420 | } | ||
421 | |||
422 | static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol, | ||
423 | struct snd_ctl_elem_value *ucontrol) | ||
424 | { | ||
425 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
426 | struct sigmatel_spec *spec = codec->spec; | ||
427 | |||
428 | ucontrol->value.enumerated.item[0] = spec->cur_mmux; | ||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol, | ||
433 | struct snd_ctl_elem_value *ucontrol) | ||
434 | { | ||
435 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
436 | struct sigmatel_spec *spec = codec->spec; | ||
437 | |||
438 | return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol, | ||
439 | spec->mono_nid, &spec->cur_mmux); | ||
440 | } | ||
441 | |||
302 | #define stac92xx_aloopback_info snd_ctl_boolean_mono_info | 442 | #define stac92xx_aloopback_info snd_ctl_boolean_mono_info |
303 | 443 | ||
304 | static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol, | 444 | static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol, |
305 | struct snd_ctl_elem_value *ucontrol) | 445 | struct snd_ctl_elem_value *ucontrol) |
306 | { | 446 | { |
307 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 447 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
448 | unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
308 | struct sigmatel_spec *spec = codec->spec; | 449 | struct sigmatel_spec *spec = codec->spec; |
309 | 450 | ||
310 | ucontrol->value.integer.value[0] = spec->aloopback; | 451 | ucontrol->value.integer.value[0] = !!(spec->aloopback & |
452 | (spec->aloopback_mask << idx)); | ||
311 | return 0; | 453 | return 0; |
312 | } | 454 | } |
313 | 455 | ||
@@ -316,23 +458,33 @@ static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol, | |||
316 | { | 458 | { |
317 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 459 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
318 | struct sigmatel_spec *spec = codec->spec; | 460 | struct sigmatel_spec *spec = codec->spec; |
461 | unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
319 | unsigned int dac_mode; | 462 | unsigned int dac_mode; |
463 | unsigned int val, idx_val; | ||
320 | 464 | ||
321 | if (spec->aloopback == ucontrol->value.integer.value[0]) | 465 | idx_val = spec->aloopback_mask << idx; |
466 | if (ucontrol->value.integer.value[0]) | ||
467 | val = spec->aloopback | idx_val; | ||
468 | else | ||
469 | val = spec->aloopback & ~idx_val; | ||
470 | if (spec->aloopback == val) | ||
322 | return 0; | 471 | return 0; |
323 | 472 | ||
324 | spec->aloopback = ucontrol->value.integer.value[0]; | 473 | spec->aloopback = val; |
325 | |||
326 | 474 | ||
475 | /* Only return the bits defined by the shift value of the | ||
476 | * first two bytes of the mask | ||
477 | */ | ||
327 | dac_mode = snd_hda_codec_read(codec, codec->afg, 0, | 478 | dac_mode = snd_hda_codec_read(codec, codec->afg, 0, |
328 | kcontrol->private_value & 0xFFFF, 0x0); | 479 | kcontrol->private_value & 0xFFFF, 0x0); |
480 | dac_mode >>= spec->aloopback_shift; | ||
329 | 481 | ||
330 | if (spec->aloopback) { | 482 | if (spec->aloopback & idx_val) { |
331 | snd_hda_power_up(codec); | 483 | snd_hda_power_up(codec); |
332 | dac_mode |= 0x40; | 484 | dac_mode |= idx_val; |
333 | } else { | 485 | } else { |
334 | snd_hda_power_down(codec); | 486 | snd_hda_power_down(codec); |
335 | dac_mode &= ~0x40; | 487 | dac_mode &= ~idx_val; |
336 | } | 488 | } |
337 | 489 | ||
338 | snd_hda_codec_write_cache(codec, codec->afg, 0, | 490 | snd_hda_codec_write_cache(codec, codec->afg, 0, |
@@ -354,6 +506,107 @@ static struct hda_verb stac9200_eapd_init[] = { | |||
354 | {} | 506 | {} |
355 | }; | 507 | }; |
356 | 508 | ||
509 | static struct hda_verb stac92hd73xx_6ch_core_init[] = { | ||
510 | /* set master volume and direct control */ | ||
511 | { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, | ||
512 | /* setup audio connections */ | ||
513 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
514 | { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
515 | { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02}, | ||
516 | /* setup adcs to point to mixer */ | ||
517 | { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, | ||
518 | { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, | ||
519 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
520 | { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
521 | { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
522 | /* setup import muxs */ | ||
523 | { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
524 | { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
525 | { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
526 | { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
527 | {} | ||
528 | }; | ||
529 | |||
530 | static struct hda_verb stac92hd73xx_8ch_core_init[] = { | ||
531 | /* set master volume and direct control */ | ||
532 | { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, | ||
533 | /* setup audio connections */ | ||
534 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
535 | { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
536 | { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02}, | ||
537 | /* connect hp ports to dac3 */ | ||
538 | { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03}, | ||
539 | { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03}, | ||
540 | /* setup adcs to point to mixer */ | ||
541 | { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, | ||
542 | { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, | ||
543 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
544 | { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
545 | { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
546 | /* setup import muxs */ | ||
547 | { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
548 | { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
549 | { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
550 | { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03}, | ||
551 | {} | ||
552 | }; | ||
553 | |||
554 | static struct hda_verb stac92hd73xx_10ch_core_init[] = { | ||
555 | /* set master volume and direct control */ | ||
556 | { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, | ||
557 | /* setup audio connections */ | ||
558 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, | ||
559 | { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 }, | ||
560 | { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 }, | ||
561 | /* dac3 is connected to import3 mux */ | ||
562 | { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f}, | ||
563 | /* connect hp ports to dac4 */ | ||
564 | { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04}, | ||
565 | { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04}, | ||
566 | /* setup adcs to point to mixer */ | ||
567 | { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, | ||
568 | { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, | ||
569 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
570 | { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
571 | { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
572 | /* setup import muxs */ | ||
573 | { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
574 | { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
575 | { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
576 | { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03}, | ||
577 | {} | ||
578 | }; | ||
579 | |||
580 | static struct hda_verb stac92hd71bxx_core_init[] = { | ||
581 | /* set master volume and direct control */ | ||
582 | { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, | ||
583 | /* connect headphone jack to dac1 */ | ||
584 | { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
585 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */ | ||
586 | /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */ | ||
587 | { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
588 | { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
589 | { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
590 | }; | ||
591 | |||
592 | static struct hda_verb stac92hd71bxx_analog_core_init[] = { | ||
593 | /* set master volume and direct control */ | ||
594 | { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, | ||
595 | /* connect headphone jack to dac1 */ | ||
596 | { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
597 | /* connect ports 0d and 0f to audio mixer */ | ||
598 | { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2}, | ||
599 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2}, | ||
600 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */ | ||
601 | /* unmute dac0 input in audio mixer */ | ||
602 | { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f}, | ||
603 | /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */ | ||
604 | { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
605 | { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
606 | { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
607 | {} | ||
608 | }; | ||
609 | |||
357 | static struct hda_verb stac925x_core_init[] = { | 610 | static struct hda_verb stac925x_core_init[] = { |
358 | /* set dac0mux for dac converter */ | 611 | /* set dac0mux for dac converter */ |
359 | { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00}, | 612 | { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00}, |
@@ -388,6 +641,16 @@ static struct hda_verb stac9205_core_init[] = { | |||
388 | {} | 641 | {} |
389 | }; | 642 | }; |
390 | 643 | ||
644 | #define STAC_MONO_MUX \ | ||
645 | { \ | ||
646 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
647 | .name = "Mono Mux", \ | ||
648 | .count = 1, \ | ||
649 | .info = stac92xx_mono_mux_enum_info, \ | ||
650 | .get = stac92xx_mono_mux_enum_get, \ | ||
651 | .put = stac92xx_mono_mux_enum_put, \ | ||
652 | } | ||
653 | |||
391 | #define STAC_INPUT_SOURCE(cnt) \ | 654 | #define STAC_INPUT_SOURCE(cnt) \ |
392 | { \ | 655 | { \ |
393 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | 656 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
@@ -398,11 +661,11 @@ static struct hda_verb stac9205_core_init[] = { | |||
398 | .put = stac92xx_mux_enum_put, \ | 661 | .put = stac92xx_mux_enum_put, \ |
399 | } | 662 | } |
400 | 663 | ||
401 | #define STAC_ANALOG_LOOPBACK(verb_read,verb_write) \ | 664 | #define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \ |
402 | { \ | 665 | { \ |
403 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | 666 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
404 | .name = "Analog Loopback", \ | 667 | .name = "Analog Loopback", \ |
405 | .count = 1, \ | 668 | .count = cnt, \ |
406 | .info = stac92xx_aloopback_info, \ | 669 | .info = stac92xx_aloopback_info, \ |
407 | .get = stac92xx_aloopback_get, \ | 670 | .get = stac92xx_aloopback_get, \ |
408 | .put = stac92xx_aloopback_put, \ | 671 | .put = stac92xx_aloopback_put, \ |
@@ -419,6 +682,114 @@ static struct snd_kcontrol_new stac9200_mixer[] = { | |||
419 | { } /* end */ | 682 | { } /* end */ |
420 | }; | 683 | }; |
421 | 684 | ||
685 | static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = { | ||
686 | STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3), | ||
687 | |||
688 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT), | ||
689 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT), | ||
690 | |||
691 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT), | ||
692 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT), | ||
693 | |||
694 | HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT), | ||
695 | HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT), | ||
696 | |||
697 | HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT), | ||
698 | HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT), | ||
699 | |||
700 | HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT), | ||
701 | HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT), | ||
702 | |||
703 | HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT), | ||
704 | HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT), | ||
705 | |||
706 | HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT), | ||
707 | HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT), | ||
708 | { } /* end */ | ||
709 | }; | ||
710 | |||
711 | static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = { | ||
712 | STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4), | ||
713 | |||
714 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT), | ||
715 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT), | ||
716 | |||
717 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT), | ||
718 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT), | ||
719 | |||
720 | HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT), | ||
721 | HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT), | ||
722 | |||
723 | HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT), | ||
724 | HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT), | ||
725 | |||
726 | HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT), | ||
727 | HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT), | ||
728 | |||
729 | HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT), | ||
730 | HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT), | ||
731 | |||
732 | HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT), | ||
733 | HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT), | ||
734 | { } /* end */ | ||
735 | }; | ||
736 | |||
737 | static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = { | ||
738 | STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5), | ||
739 | |||
740 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT), | ||
741 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT), | ||
742 | |||
743 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT), | ||
744 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT), | ||
745 | |||
746 | HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT), | ||
747 | HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT), | ||
748 | |||
749 | HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT), | ||
750 | HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT), | ||
751 | |||
752 | HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT), | ||
753 | HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT), | ||
754 | |||
755 | HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT), | ||
756 | HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT), | ||
757 | |||
758 | HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT), | ||
759 | HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT), | ||
760 | { } /* end */ | ||
761 | }; | ||
762 | |||
763 | static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = { | ||
764 | STAC_INPUT_SOURCE(2), | ||
765 | |||
766 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT), | ||
767 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT), | ||
768 | HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT), | ||
769 | |||
770 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT), | ||
771 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT), | ||
772 | HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT), | ||
773 | |||
774 | HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT), | ||
775 | HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT), | ||
776 | { } /* end */ | ||
777 | }; | ||
778 | |||
779 | static struct snd_kcontrol_new stac92hd71bxx_mixer[] = { | ||
780 | STAC_INPUT_SOURCE(2), | ||
781 | STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2), | ||
782 | |||
783 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT), | ||
784 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT), | ||
785 | HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT), | ||
786 | |||
787 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT), | ||
788 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT), | ||
789 | HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT), | ||
790 | { } /* end */ | ||
791 | }; | ||
792 | |||
422 | static struct snd_kcontrol_new stac925x_mixer[] = { | 793 | static struct snd_kcontrol_new stac925x_mixer[] = { |
423 | STAC_INPUT_SOURCE(1), | 794 | STAC_INPUT_SOURCE(1), |
424 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), | 795 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), |
@@ -428,16 +799,8 @@ static struct snd_kcontrol_new stac925x_mixer[] = { | |||
428 | }; | 799 | }; |
429 | 800 | ||
430 | static struct snd_kcontrol_new stac9205_mixer[] = { | 801 | static struct snd_kcontrol_new stac9205_mixer[] = { |
431 | { | ||
432 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
433 | .name = "Digital Input Source", | ||
434 | .count = 1, | ||
435 | .info = stac92xx_dmux_enum_info, | ||
436 | .get = stac92xx_dmux_enum_get, | ||
437 | .put = stac92xx_dmux_enum_put, | ||
438 | }, | ||
439 | STAC_INPUT_SOURCE(2), | 802 | STAC_INPUT_SOURCE(2), |
440 | STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0), | 803 | STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1), |
441 | 804 | ||
442 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT), | 805 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT), |
443 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT), | 806 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT), |
@@ -466,7 +829,7 @@ static struct snd_kcontrol_new stac922x_mixer[] = { | |||
466 | 829 | ||
467 | static struct snd_kcontrol_new stac927x_mixer[] = { | 830 | static struct snd_kcontrol_new stac927x_mixer[] = { |
468 | STAC_INPUT_SOURCE(3), | 831 | STAC_INPUT_SOURCE(3), |
469 | STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB), | 832 | STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1), |
470 | 833 | ||
471 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT), | 834 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT), |
472 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT), | 835 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT), |
@@ -482,6 +845,44 @@ static struct snd_kcontrol_new stac927x_mixer[] = { | |||
482 | { } /* end */ | 845 | { } /* end */ |
483 | }; | 846 | }; |
484 | 847 | ||
848 | static struct snd_kcontrol_new stac_dmux_mixer = { | ||
849 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
850 | .name = "Digital Input Source", | ||
851 | /* count set later */ | ||
852 | .info = stac92xx_dmux_enum_info, | ||
853 | .get = stac92xx_dmux_enum_get, | ||
854 | .put = stac92xx_dmux_enum_put, | ||
855 | }; | ||
856 | |||
857 | static const char *slave_vols[] = { | ||
858 | "Front Playback Volume", | ||
859 | "Surround Playback Volume", | ||
860 | "Center Playback Volume", | ||
861 | "LFE Playback Volume", | ||
862 | "Side Playback Volume", | ||
863 | "Headphone Playback Volume", | ||
864 | "Headphone Playback Volume", | ||
865 | "Speaker Playback Volume", | ||
866 | "External Speaker Playback Volume", | ||
867 | "Speaker2 Playback Volume", | ||
868 | NULL | ||
869 | }; | ||
870 | |||
871 | static const char *slave_sws[] = { | ||
872 | "Front Playback Switch", | ||
873 | "Surround Playback Switch", | ||
874 | "Center Playback Switch", | ||
875 | "LFE Playback Switch", | ||
876 | "Side Playback Switch", | ||
877 | "Headphone Playback Switch", | ||
878 | "Headphone Playback Switch", | ||
879 | "Speaker Playback Switch", | ||
880 | "External Speaker Playback Switch", | ||
881 | "Speaker2 Playback Switch", | ||
882 | "IEC958 Playback Switch", | ||
883 | NULL | ||
884 | }; | ||
885 | |||
485 | static int stac92xx_build_controls(struct hda_codec *codec) | 886 | static int stac92xx_build_controls(struct hda_codec *codec) |
486 | { | 887 | { |
487 | struct sigmatel_spec *spec = codec->spec; | 888 | struct sigmatel_spec *spec = codec->spec; |
@@ -497,6 +898,13 @@ static int stac92xx_build_controls(struct hda_codec *codec) | |||
497 | if (err < 0) | 898 | if (err < 0) |
498 | return err; | 899 | return err; |
499 | } | 900 | } |
901 | if (spec->num_dmuxes > 0) { | ||
902 | stac_dmux_mixer.count = spec->num_dmuxes; | ||
903 | err = snd_ctl_add(codec->bus->card, | ||
904 | snd_ctl_new1(&stac_dmux_mixer, codec)); | ||
905 | if (err < 0) | ||
906 | return err; | ||
907 | } | ||
500 | 908 | ||
501 | if (spec->multiout.dig_out_nid) { | 909 | if (spec->multiout.dig_out_nid) { |
502 | err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); | 910 | err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); |
@@ -508,6 +916,23 @@ static int stac92xx_build_controls(struct hda_codec *codec) | |||
508 | if (err < 0) | 916 | if (err < 0) |
509 | return err; | 917 | return err; |
510 | } | 918 | } |
919 | |||
920 | /* if we have no master control, let's create it */ | ||
921 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { | ||
922 | snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0], | ||
923 | HDA_OUTPUT, spec->vmaster_tlv); | ||
924 | err = snd_hda_add_vmaster(codec, "Master Playback Volume", | ||
925 | spec->vmaster_tlv, slave_vols); | ||
926 | if (err < 0) | ||
927 | return err; | ||
928 | } | ||
929 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { | ||
930 | err = snd_hda_add_vmaster(codec, "Master Playback Switch", | ||
931 | NULL, slave_sws); | ||
932 | if (err < 0) | ||
933 | return err; | ||
934 | } | ||
935 | |||
511 | return 0; | 936 | return 0; |
512 | } | 937 | } |
513 | 938 | ||
@@ -733,7 +1158,7 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = { | |||
733 | 1158 | ||
734 | static unsigned int ref925x_pin_configs[8] = { | 1159 | static unsigned int ref925x_pin_configs[8] = { |
735 | 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021, | 1160 | 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021, |
736 | 0x90a70320, 0x02214210, 0x400003f1, 0x9033032e, | 1161 | 0x90a70320, 0x02214210, 0x01019020, 0x9033032e, |
737 | }; | 1162 | }; |
738 | 1163 | ||
739 | static unsigned int stac925x_MA6_pin_configs[8] = { | 1164 | static unsigned int stac925x_MA6_pin_configs[8] = { |
@@ -777,6 +1202,48 @@ static struct snd_pci_quirk stac925x_cfg_tbl[] = { | |||
777 | {} /* terminator */ | 1202 | {} /* terminator */ |
778 | }; | 1203 | }; |
779 | 1204 | ||
1205 | static unsigned int ref92hd73xx_pin_configs[12] = { | ||
1206 | 0x02214030, 0x02a19040, 0x01a19020, 0x02214030, | ||
1207 | 0x0181302e, 0x01014010, 0x01014020, 0x01014030, | ||
1208 | 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050, | ||
1209 | }; | ||
1210 | |||
1211 | static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = { | ||
1212 | [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs, | ||
1213 | }; | ||
1214 | |||
1215 | static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = { | ||
1216 | [STAC_92HD73XX_REF] = "ref", | ||
1217 | }; | ||
1218 | |||
1219 | static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { | ||
1220 | /* SigmaTel reference board */ | ||
1221 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, | ||
1222 | "DFI LanParty", STAC_92HD73XX_REF), | ||
1223 | {} /* terminator */ | ||
1224 | }; | ||
1225 | |||
1226 | static unsigned int ref92hd71bxx_pin_configs[10] = { | ||
1227 | 0x02214030, 0x02a19040, 0x01a19020, 0x01014010, | ||
1228 | 0x0181302e, 0x01114010, 0x01019020, 0x90a000f0, | ||
1229 | 0x90a000f0, 0x01452050, | ||
1230 | }; | ||
1231 | |||
1232 | static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = { | ||
1233 | [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs, | ||
1234 | }; | ||
1235 | |||
1236 | static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = { | ||
1237 | [STAC_92HD71BXX_REF] = "ref", | ||
1238 | }; | ||
1239 | |||
1240 | static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { | ||
1241 | /* SigmaTel reference board */ | ||
1242 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, | ||
1243 | "DFI LanParty", STAC_92HD71BXX_REF), | ||
1244 | {} /* terminator */ | ||
1245 | }; | ||
1246 | |||
780 | static unsigned int ref922x_pin_configs[10] = { | 1247 | static unsigned int ref922x_pin_configs[10] = { |
781 | 0x01014010, 0x01016011, 0x01012012, 0x0221401f, | 1248 | 0x01014010, 0x01016011, 0x01012012, 0x0221401f, |
782 | 0x01813122, 0x01011014, 0x01441030, 0x01c41030, | 1249 | 0x01813122, 0x01011014, 0x01441030, 0x01c41030, |
@@ -823,8 +1290,8 @@ static unsigned int dell_922x_m81_pin_configs[10] = { | |||
823 | 102801D7 (Dell XPS M1210) | 1290 | 102801D7 (Dell XPS M1210) |
824 | */ | 1291 | */ |
825 | static unsigned int dell_922x_m82_pin_configs[10] = { | 1292 | static unsigned int dell_922x_m82_pin_configs[10] = { |
826 | 0x0221121f, 0x408103ff, 0x02111212, 0x90100310, | 1293 | 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310, |
827 | 0x408003f1, 0x02111211, 0x03451340, 0x40c003f2, | 1294 | 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2, |
828 | 0x508003f3, 0x405003f4, | 1295 | 0x508003f3, 0x405003f4, |
829 | }; | 1296 | }; |
830 | 1297 | ||
@@ -1022,22 +1489,24 @@ static unsigned int d965_5st_pin_configs[14] = { | |||
1022 | static unsigned int dell_3st_pin_configs[14] = { | 1489 | static unsigned int dell_3st_pin_configs[14] = { |
1023 | 0x02211230, 0x02a11220, 0x01a19040, 0x01114210, | 1490 | 0x02211230, 0x02a11220, 0x01a19040, 0x01114210, |
1024 | 0x01111212, 0x01116211, 0x01813050, 0x01112214, | 1491 | 0x01111212, 0x01116211, 0x01813050, 0x01112214, |
1025 | 0x403003fa, 0x40000100, 0x40000100, 0x404003fb, | 1492 | 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb, |
1026 | 0x40c003fc, 0x40000100 | 1493 | 0x40c003fc, 0x40000100 |
1027 | }; | 1494 | }; |
1028 | 1495 | ||
1029 | static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { | 1496 | static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { |
1030 | [STAC_D965_REF] = ref927x_pin_configs, | 1497 | [STAC_D965_REF] = ref927x_pin_configs, |
1031 | [STAC_D965_3ST] = d965_3st_pin_configs, | 1498 | [STAC_D965_3ST] = d965_3st_pin_configs, |
1032 | [STAC_D965_5ST] = d965_5st_pin_configs, | 1499 | [STAC_D965_5ST] = d965_5st_pin_configs, |
1033 | [STAC_DELL_3ST] = dell_3st_pin_configs, | 1500 | [STAC_DELL_3ST] = dell_3st_pin_configs, |
1501 | [STAC_DELL_BIOS] = NULL, | ||
1034 | }; | 1502 | }; |
1035 | 1503 | ||
1036 | static const char *stac927x_models[STAC_927X_MODELS] = { | 1504 | static const char *stac927x_models[STAC_927X_MODELS] = { |
1037 | [STAC_D965_REF] = "ref", | 1505 | [STAC_D965_REF] = "ref", |
1038 | [STAC_D965_3ST] = "3stack", | 1506 | [STAC_D965_3ST] = "3stack", |
1039 | [STAC_D965_5ST] = "5stack", | 1507 | [STAC_D965_5ST] = "5stack", |
1040 | [STAC_DELL_3ST] = "dell-3stack", | 1508 | [STAC_DELL_3ST] = "dell-3stack", |
1509 | [STAC_DELL_BIOS] = "dell-bios", | ||
1041 | }; | 1510 | }; |
1042 | 1511 | ||
1043 | static struct snd_pci_quirk stac927x_cfg_tbl[] = { | 1512 | static struct snd_pci_quirk stac927x_cfg_tbl[] = { |
@@ -1064,13 +1533,21 @@ static struct snd_pci_quirk stac927x_cfg_tbl[] = { | |||
1064 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST), | 1533 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST), |
1065 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST), | 1534 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST), |
1066 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST), | 1535 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST), |
1067 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_D965_3ST), | ||
1068 | /* Dell 3 stack systems */ | 1536 | /* Dell 3 stack systems */ |
1537 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST), | ||
1069 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST), | 1538 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST), |
1070 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST), | 1539 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST), |
1071 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST), | 1540 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST), |
1541 | /* Dell 3 stack systems with verb table in BIOS */ | ||
1542 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS), | ||
1543 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS), | ||
1544 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell ", STAC_DELL_BIOS), | ||
1545 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS), | ||
1546 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS), | ||
1547 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS), | ||
1548 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS), | ||
1549 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS), | ||
1072 | /* 965 based 5 stack systems */ | 1550 | /* 965 based 5 stack systems */ |
1073 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_D965_5ST), | ||
1074 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST), | 1551 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST), |
1075 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST), | 1552 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST), |
1076 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST), | 1553 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST), |
@@ -1085,7 +1562,7 @@ static struct snd_pci_quirk stac927x_cfg_tbl[] = { | |||
1085 | 1562 | ||
1086 | static unsigned int ref9205_pin_configs[12] = { | 1563 | static unsigned int ref9205_pin_configs[12] = { |
1087 | 0x40000100, 0x40000100, 0x01016011, 0x01014010, | 1564 | 0x40000100, 0x40000100, 0x01016011, 0x01014010, |
1088 | 0x01813122, 0x01a19021, 0x40000100, 0x40000100, | 1565 | 0x01813122, 0x01a19021, 0x01019020, 0x40000100, |
1089 | 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030 | 1566 | 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030 |
1090 | }; | 1567 | }; |
1091 | 1568 | ||
@@ -1097,6 +1574,7 @@ static unsigned int ref9205_pin_configs[12] = { | |||
1097 | 102801FD | 1574 | 102801FD |
1098 | 10280204 | 1575 | 10280204 |
1099 | 1028021F | 1576 | 1028021F |
1577 | 10280228 (Dell Vostro 1500) | ||
1100 | */ | 1578 | */ |
1101 | static unsigned int dell_9205_m42_pin_configs[12] = { | 1579 | static unsigned int dell_9205_m42_pin_configs[12] = { |
1102 | 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310, | 1580 | 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310, |
@@ -1180,6 +1658,8 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = { | |||
1180 | "unknown Dell", STAC_9205_DELL_M42), | 1658 | "unknown Dell", STAC_9205_DELL_M42), |
1181 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f, | 1659 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f, |
1182 | "Dell Inspiron", STAC_9205_DELL_M44), | 1660 | "Dell Inspiron", STAC_9205_DELL_M44), |
1661 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228, | ||
1662 | "Dell Vostro 1500", STAC_9205_DELL_M42), | ||
1183 | {} /* terminator */ | 1663 | {} /* terminator */ |
1184 | }; | 1664 | }; |
1185 | 1665 | ||
@@ -1245,22 +1725,6 @@ static void stac92xx_set_config_regs(struct hda_codec *codec) | |||
1245 | spec->pin_configs[i]); | 1725 | spec->pin_configs[i]); |
1246 | } | 1726 | } |
1247 | 1727 | ||
1248 | static void stac92xx_enable_gpio_mask(struct hda_codec *codec) | ||
1249 | { | ||
1250 | struct sigmatel_spec *spec = codec->spec; | ||
1251 | /* Configure GPIOx as output */ | ||
1252 | snd_hda_codec_write_cache(codec, codec->afg, 0, | ||
1253 | AC_VERB_SET_GPIO_DIRECTION, spec->gpio_mask); | ||
1254 | /* Configure GPIOx as CMOS */ | ||
1255 | snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7e7, 0x00000000); | ||
1256 | /* Assert GPIOx */ | ||
1257 | snd_hda_codec_write_cache(codec, codec->afg, 0, | ||
1258 | AC_VERB_SET_GPIO_DATA, spec->gpio_data); | ||
1259 | /* Enable GPIOx */ | ||
1260 | snd_hda_codec_write_cache(codec, codec->afg, 0, | ||
1261 | AC_VERB_SET_GPIO_MASK, spec->gpio_mask); | ||
1262 | } | ||
1263 | |||
1264 | /* | 1728 | /* |
1265 | * Analog playback callbacks | 1729 | * Analog playback callbacks |
1266 | */ | 1730 | */ |
@@ -1479,7 +1943,7 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
1479 | struct sigmatel_spec *spec = codec->spec; | 1943 | struct sigmatel_spec *spec = codec->spec; |
1480 | hda_nid_t nid = kcontrol->private_value >> 8; | 1944 | hda_nid_t nid = kcontrol->private_value >> 8; |
1481 | int io_idx = kcontrol-> private_value & 0xff; | 1945 | int io_idx = kcontrol-> private_value & 0xff; |
1482 | unsigned short val = ucontrol->value.integer.value[0]; | 1946 | unsigned short val = !!ucontrol->value.integer.value[0]; |
1483 | 1947 | ||
1484 | spec->io_switch[io_idx] = val; | 1948 | spec->io_switch[io_idx] = val; |
1485 | 1949 | ||
@@ -1491,6 +1955,13 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
1491 | pinctl |= stac92xx_get_vref(codec, nid); | 1955 | pinctl |= stac92xx_get_vref(codec, nid); |
1492 | stac92xx_auto_set_pinctl(codec, nid, pinctl); | 1956 | stac92xx_auto_set_pinctl(codec, nid, pinctl); |
1493 | } | 1957 | } |
1958 | |||
1959 | /* check the auto-mute again: we need to mute/unmute the speaker | ||
1960 | * appropriately according to the pin direction | ||
1961 | */ | ||
1962 | if (spec->hp_detect) | ||
1963 | codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); | ||
1964 | |||
1494 | return 1; | 1965 | return 1; |
1495 | } | 1966 | } |
1496 | 1967 | ||
@@ -1512,11 +1983,12 @@ static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol, | |||
1512 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 1983 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
1513 | struct sigmatel_spec *spec = codec->spec; | 1984 | struct sigmatel_spec *spec = codec->spec; |
1514 | hda_nid_t nid = kcontrol->private_value & 0xff; | 1985 | hda_nid_t nid = kcontrol->private_value & 0xff; |
1986 | unsigned int val = !!ucontrol->value.integer.value[0]; | ||
1515 | 1987 | ||
1516 | if (spec->clfe_swap == ucontrol->value.integer.value[0]) | 1988 | if (spec->clfe_swap == val) |
1517 | return 0; | 1989 | return 0; |
1518 | 1990 | ||
1519 | spec->clfe_swap = ucontrol->value.integer.value[0]; | 1991 | spec->clfe_swap = val; |
1520 | 1992 | ||
1521 | snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, | 1993 | snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, |
1522 | spec->clfe_swap ? 0x4 : 0x0); | 1994 | spec->clfe_swap ? 0x4 : 0x0); |
@@ -1547,6 +2019,7 @@ static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol, | |||
1547 | enum { | 2019 | enum { |
1548 | STAC_CTL_WIDGET_VOL, | 2020 | STAC_CTL_WIDGET_VOL, |
1549 | STAC_CTL_WIDGET_MUTE, | 2021 | STAC_CTL_WIDGET_MUTE, |
2022 | STAC_CTL_WIDGET_MONO_MUX, | ||
1550 | STAC_CTL_WIDGET_IO_SWITCH, | 2023 | STAC_CTL_WIDGET_IO_SWITCH, |
1551 | STAC_CTL_WIDGET_CLFE_SWITCH | 2024 | STAC_CTL_WIDGET_CLFE_SWITCH |
1552 | }; | 2025 | }; |
@@ -1554,6 +2027,7 @@ enum { | |||
1554 | static struct snd_kcontrol_new stac92xx_control_templates[] = { | 2027 | static struct snd_kcontrol_new stac92xx_control_templates[] = { |
1555 | HDA_CODEC_VOLUME(NULL, 0, 0, 0), | 2028 | HDA_CODEC_VOLUME(NULL, 0, 0, 0), |
1556 | HDA_CODEC_MUTE(NULL, 0, 0, 0), | 2029 | HDA_CODEC_MUTE(NULL, 0, 0, 0), |
2030 | STAC_MONO_MUX, | ||
1557 | STAC_CODEC_IO_SWITCH(NULL, 0), | 2031 | STAC_CODEC_IO_SWITCH(NULL, 0), |
1558 | STAC_CODEC_CLFE_SWITCH(NULL, 0), | 2032 | STAC_CODEC_CLFE_SWITCH(NULL, 0), |
1559 | }; | 2033 | }; |
@@ -1598,6 +2072,7 @@ static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cf | |||
1598 | for (i = 0; i < codec->num_nodes; i++) { | 2072 | for (i = 0; i < codec->num_nodes; i++) { |
1599 | wcaps = codec->wcaps[i]; | 2073 | wcaps = codec->wcaps[i]; |
1600 | wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; | 2074 | wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; |
2075 | |||
1601 | if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL)) | 2076 | if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL)) |
1602 | num_dacs++; | 2077 | num_dacs++; |
1603 | } | 2078 | } |
@@ -1685,7 +2160,6 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, | |||
1685 | wcaps = snd_hda_param_read(codec, conn[j], | 2160 | wcaps = snd_hda_param_read(codec, conn[j], |
1686 | AC_PAR_AUDIO_WIDGET_CAP); | 2161 | AC_PAR_AUDIO_WIDGET_CAP); |
1687 | wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; | 2162 | wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; |
1688 | |||
1689 | if (wtype != AC_WID_AUD_OUT || | 2163 | if (wtype != AC_WID_AUD_OUT || |
1690 | (wcaps & AC_WCAP_DIGITAL)) | 2164 | (wcaps & AC_WCAP_DIGITAL)) |
1691 | continue; | 2165 | continue; |
@@ -1759,7 +2233,7 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, | |||
1759 | int i, err; | 2233 | int i, err; |
1760 | 2234 | ||
1761 | struct sigmatel_spec *spec = codec->spec; | 2235 | struct sigmatel_spec *spec = codec->spec; |
1762 | unsigned int wid_caps; | 2236 | unsigned int wid_caps, pincap; |
1763 | 2237 | ||
1764 | 2238 | ||
1765 | for (i = 0; i < cfg->line_outs; i++) { | 2239 | for (i = 0; i < cfg->line_outs; i++) { |
@@ -1795,13 +2269,39 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, | |||
1795 | } | 2269 | } |
1796 | } | 2270 | } |
1797 | 2271 | ||
1798 | if (spec->line_switch) | 2272 | if (spec->line_switch) { |
1799 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, "Line In as Output Switch", cfg->input_pins[AUTO_PIN_LINE] << 8)) < 0) | 2273 | nid = cfg->input_pins[AUTO_PIN_LINE]; |
1800 | return err; | 2274 | pincap = snd_hda_param_read(codec, nid, |
2275 | AC_PAR_PIN_CAP); | ||
2276 | if (pincap & AC_PINCAP_OUT) { | ||
2277 | err = stac92xx_add_control(spec, | ||
2278 | STAC_CTL_WIDGET_IO_SWITCH, | ||
2279 | "Line In as Output Switch", nid << 8); | ||
2280 | if (err < 0) | ||
2281 | return err; | ||
2282 | } | ||
2283 | } | ||
1801 | 2284 | ||
1802 | if (spec->mic_switch) | 2285 | if (spec->mic_switch) { |
1803 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, "Mic as Output Switch", (cfg->input_pins[AUTO_PIN_MIC] << 8) | 1)) < 0) | 2286 | unsigned int def_conf; |
1804 | return err; | 2287 | nid = cfg->input_pins[AUTO_PIN_MIC]; |
2288 | def_conf = snd_hda_codec_read(codec, nid, 0, | ||
2289 | AC_VERB_GET_CONFIG_DEFAULT, 0); | ||
2290 | |||
2291 | /* some laptops have an internal analog microphone | ||
2292 | * which can't be used as a output */ | ||
2293 | if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) { | ||
2294 | pincap = snd_hda_param_read(codec, nid, | ||
2295 | AC_PAR_PIN_CAP); | ||
2296 | if (pincap & AC_PINCAP_OUT) { | ||
2297 | err = stac92xx_add_control(spec, | ||
2298 | STAC_CTL_WIDGET_IO_SWITCH, | ||
2299 | "Mic as Output Switch", (nid << 8) | 1); | ||
2300 | if (err < 0) | ||
2301 | return err; | ||
2302 | } | ||
2303 | } | ||
2304 | } | ||
1805 | 2305 | ||
1806 | return 0; | 2306 | return 0; |
1807 | } | 2307 | } |
@@ -1891,6 +2391,37 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, | |||
1891 | return 0; | 2391 | return 0; |
1892 | } | 2392 | } |
1893 | 2393 | ||
2394 | /* labels for mono mux outputs */ | ||
2395 | static const char *stac92xx_mono_labels[3] = { | ||
2396 | "DAC0", "DAC1", "Mixer" | ||
2397 | }; | ||
2398 | |||
2399 | /* create mono mux for mono out on capable codecs */ | ||
2400 | static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec) | ||
2401 | { | ||
2402 | struct sigmatel_spec *spec = codec->spec; | ||
2403 | struct hda_input_mux *mono_mux = &spec->private_mono_mux; | ||
2404 | int i, num_cons; | ||
2405 | hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)]; | ||
2406 | |||
2407 | num_cons = snd_hda_get_connections(codec, | ||
2408 | spec->mono_nid, | ||
2409 | con_lst, | ||
2410 | HDA_MAX_NUM_INPUTS); | ||
2411 | if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels)) | ||
2412 | return -EINVAL; | ||
2413 | |||
2414 | for (i = 0; i < num_cons; i++) { | ||
2415 | mono_mux->items[mono_mux->num_items].label = | ||
2416 | stac92xx_mono_labels[i]; | ||
2417 | mono_mux->items[mono_mux->num_items].index = i; | ||
2418 | mono_mux->num_items++; | ||
2419 | } | ||
2420 | |||
2421 | return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX, | ||
2422 | "Mono Mux", spec->mono_nid); | ||
2423 | } | ||
2424 | |||
1894 | /* labels for dmic mux inputs */ | 2425 | /* labels for dmic mux inputs */ |
1895 | static const char *stac92xx_dmic_labels[5] = { | 2426 | static const char *stac92xx_dmic_labels[5] = { |
1896 | "Analog Inputs", "Digital Mic 1", "Digital Mic 2", | 2427 | "Analog Inputs", "Digital Mic 1", "Digital Mic 2", |
@@ -1904,15 +2435,18 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, | |||
1904 | struct sigmatel_spec *spec = codec->spec; | 2435 | struct sigmatel_spec *spec = codec->spec; |
1905 | struct hda_input_mux *dimux = &spec->private_dimux; | 2436 | struct hda_input_mux *dimux = &spec->private_dimux; |
1906 | hda_nid_t con_lst[HDA_MAX_NUM_INPUTS]; | 2437 | hda_nid_t con_lst[HDA_MAX_NUM_INPUTS]; |
1907 | int i, j; | 2438 | int err, i, j; |
2439 | char name[32]; | ||
1908 | 2440 | ||
1909 | dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0]; | 2441 | dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0]; |
1910 | dimux->items[dimux->num_items].index = 0; | 2442 | dimux->items[dimux->num_items].index = 0; |
1911 | dimux->num_items++; | 2443 | dimux->num_items++; |
1912 | 2444 | ||
1913 | for (i = 0; i < spec->num_dmics; i++) { | 2445 | for (i = 0; i < spec->num_dmics; i++) { |
2446 | hda_nid_t nid; | ||
1914 | int index; | 2447 | int index; |
1915 | int num_cons; | 2448 | int num_cons; |
2449 | unsigned int wcaps; | ||
1916 | unsigned int def_conf; | 2450 | unsigned int def_conf; |
1917 | 2451 | ||
1918 | def_conf = snd_hda_codec_read(codec, | 2452 | def_conf = snd_hda_codec_read(codec, |
@@ -1923,17 +2457,32 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, | |||
1923 | if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) | 2457 | if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) |
1924 | continue; | 2458 | continue; |
1925 | 2459 | ||
2460 | nid = spec->dmic_nids[i]; | ||
1926 | num_cons = snd_hda_get_connections(codec, | 2461 | num_cons = snd_hda_get_connections(codec, |
1927 | spec->dmux_nid, | 2462 | spec->dmux_nids[0], |
1928 | con_lst, | 2463 | con_lst, |
1929 | HDA_MAX_NUM_INPUTS); | 2464 | HDA_MAX_NUM_INPUTS); |
1930 | for (j = 0; j < num_cons; j++) | 2465 | for (j = 0; j < num_cons; j++) |
1931 | if (con_lst[j] == spec->dmic_nids[i]) { | 2466 | if (con_lst[j] == nid) { |
1932 | index = j; | 2467 | index = j; |
1933 | goto found; | 2468 | goto found; |
1934 | } | 2469 | } |
1935 | continue; | 2470 | continue; |
1936 | found: | 2471 | found: |
2472 | wcaps = get_wcaps(codec, nid); | ||
2473 | |||
2474 | if (wcaps & AC_WCAP_OUT_AMP) { | ||
2475 | sprintf(name, "%s Capture Volume", | ||
2476 | stac92xx_dmic_labels[dimux->num_items]); | ||
2477 | |||
2478 | err = stac92xx_add_control(spec, | ||
2479 | STAC_CTL_WIDGET_VOL, | ||
2480 | name, | ||
2481 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); | ||
2482 | if (err < 0) | ||
2483 | return err; | ||
2484 | } | ||
2485 | |||
1937 | dimux->items[dimux->num_items].label = | 2486 | dimux->items[dimux->num_items].label = |
1938 | stac92xx_dmic_labels[dimux->num_items]; | 2487 | stac92xx_dmic_labels[dimux->num_items]; |
1939 | dimux->items[dimux->num_items].index = index; | 2488 | dimux->items[dimux->num_items].index = index; |
@@ -2026,6 +2575,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out | |||
2026 | { | 2575 | { |
2027 | struct sigmatel_spec *spec = codec->spec; | 2576 | struct sigmatel_spec *spec = codec->spec; |
2028 | int err; | 2577 | int err; |
2578 | int hp_speaker_swap = 0; | ||
2029 | 2579 | ||
2030 | if ((err = snd_hda_parse_pin_def_config(codec, | 2580 | if ((err = snd_hda_parse_pin_def_config(codec, |
2031 | &spec->autocfg, | 2581 | &spec->autocfg, |
@@ -2034,6 +2584,68 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out | |||
2034 | if (! spec->autocfg.line_outs) | 2584 | if (! spec->autocfg.line_outs) |
2035 | return 0; /* can't find valid pin config */ | 2585 | return 0; /* can't find valid pin config */ |
2036 | 2586 | ||
2587 | /* If we have no real line-out pin and multiple hp-outs, HPs should | ||
2588 | * be set up as multi-channel outputs. | ||
2589 | */ | ||
2590 | if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT && | ||
2591 | spec->autocfg.hp_outs > 1) { | ||
2592 | /* Copy hp_outs to line_outs, backup line_outs in | ||
2593 | * speaker_outs so that the following routines can handle | ||
2594 | * HP pins as primary outputs. | ||
2595 | */ | ||
2596 | memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins, | ||
2597 | sizeof(spec->autocfg.line_out_pins)); | ||
2598 | spec->autocfg.speaker_outs = spec->autocfg.line_outs; | ||
2599 | memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins, | ||
2600 | sizeof(spec->autocfg.hp_pins)); | ||
2601 | spec->autocfg.line_outs = spec->autocfg.hp_outs; | ||
2602 | hp_speaker_swap = 1; | ||
2603 | } | ||
2604 | if (spec->autocfg.mono_out_pin) { | ||
2605 | int dir = (get_wcaps(codec, spec->autocfg.mono_out_pin) | ||
2606 | & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT; | ||
2607 | u32 caps = query_amp_caps(codec, | ||
2608 | spec->autocfg.mono_out_pin, dir); | ||
2609 | hda_nid_t conn_list[1]; | ||
2610 | |||
2611 | /* get the mixer node and then the mono mux if it exists */ | ||
2612 | if (snd_hda_get_connections(codec, | ||
2613 | spec->autocfg.mono_out_pin, conn_list, 1) && | ||
2614 | snd_hda_get_connections(codec, conn_list[0], | ||
2615 | conn_list, 1)) { | ||
2616 | |||
2617 | int wcaps = get_wcaps(codec, conn_list[0]); | ||
2618 | int wid_type = (wcaps & AC_WCAP_TYPE) | ||
2619 | >> AC_WCAP_TYPE_SHIFT; | ||
2620 | /* LR swap check, some stac925x have a mux that | ||
2621 | * changes the DACs output path instead of the | ||
2622 | * mono-mux path. | ||
2623 | */ | ||
2624 | if (wid_type == AC_WID_AUD_SEL && | ||
2625 | !(wcaps & AC_WCAP_LR_SWAP)) | ||
2626 | spec->mono_nid = conn_list[0]; | ||
2627 | } | ||
2628 | /* all mono outs have a least a mute/unmute switch */ | ||
2629 | err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, | ||
2630 | "Mono Playback Switch", | ||
2631 | HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin, | ||
2632 | 1, 0, dir)); | ||
2633 | if (err < 0) | ||
2634 | return err; | ||
2635 | /* check to see if there is volume support for the amp */ | ||
2636 | if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) { | ||
2637 | err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, | ||
2638 | "Mono Playback Volume", | ||
2639 | HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin, | ||
2640 | 1, 0, dir)); | ||
2641 | if (err < 0) | ||
2642 | return err; | ||
2643 | } | ||
2644 | |||
2645 | stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin, | ||
2646 | AC_PINCTL_OUT_EN); | ||
2647 | } | ||
2648 | |||
2037 | if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0) | 2649 | if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0) |
2038 | return err; | 2650 | return err; |
2039 | if (spec->multiout.num_dacs == 0) | 2651 | if (spec->multiout.num_dacs == 0) |
@@ -2045,6 +2657,19 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out | |||
2045 | if (err < 0) | 2657 | if (err < 0) |
2046 | return err; | 2658 | return err; |
2047 | 2659 | ||
2660 | if (hp_speaker_swap == 1) { | ||
2661 | /* Restore the hp_outs and line_outs */ | ||
2662 | memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins, | ||
2663 | sizeof(spec->autocfg.line_out_pins)); | ||
2664 | spec->autocfg.hp_outs = spec->autocfg.line_outs; | ||
2665 | memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins, | ||
2666 | sizeof(spec->autocfg.speaker_pins)); | ||
2667 | spec->autocfg.line_outs = spec->autocfg.speaker_outs; | ||
2668 | memset(spec->autocfg.speaker_pins, 0, | ||
2669 | sizeof(spec->autocfg.speaker_pins)); | ||
2670 | spec->autocfg.speaker_outs = 0; | ||
2671 | } | ||
2672 | |||
2048 | err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg); | 2673 | err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg); |
2049 | 2674 | ||
2050 | if (err < 0) | 2675 | if (err < 0) |
@@ -2055,6 +2680,12 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out | |||
2055 | if (err < 0) | 2680 | if (err < 0) |
2056 | return err; | 2681 | return err; |
2057 | 2682 | ||
2683 | if (spec->mono_nid > 0) { | ||
2684 | err = stac92xx_auto_create_mono_output_ctls(codec); | ||
2685 | if (err < 0) | ||
2686 | return err; | ||
2687 | } | ||
2688 | |||
2058 | if (spec->num_dmics > 0) | 2689 | if (spec->num_dmics > 0) |
2059 | if ((err = stac92xx_auto_create_dmic_input_ctls(codec, | 2690 | if ((err = stac92xx_auto_create_dmic_input_ctls(codec, |
2060 | &spec->autocfg)) < 0) | 2691 | &spec->autocfg)) < 0) |
@@ -2073,7 +2704,9 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out | |||
2073 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; | 2704 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; |
2074 | 2705 | ||
2075 | spec->input_mux = &spec->private_imux; | 2706 | spec->input_mux = &spec->private_imux; |
2076 | spec->dinput_mux = &spec->private_dimux; | 2707 | if (!spec->dinput_mux) |
2708 | spec->dinput_mux = &spec->private_dimux; | ||
2709 | spec->mono_mux = &spec->private_mono_mux; | ||
2077 | 2710 | ||
2078 | return 1; | 2711 | return 1; |
2079 | } | 2712 | } |
@@ -2183,38 +2816,35 @@ static int stac9200_parse_auto_config(struct hda_codec *codec) | |||
2183 | * funky external mute control using GPIO pins. | 2816 | * funky external mute control using GPIO pins. |
2184 | */ | 2817 | */ |
2185 | 2818 | ||
2186 | static void stac922x_gpio_mute(struct hda_codec *codec, int pin, int muted) | 2819 | static void stac_gpio_set(struct hda_codec *codec, unsigned int mask, |
2820 | unsigned int dir_mask, unsigned int data) | ||
2187 | { | 2821 | { |
2188 | unsigned int gpiostate, gpiomask, gpiodir; | 2822 | unsigned int gpiostate, gpiomask, gpiodir; |
2189 | 2823 | ||
2190 | gpiostate = snd_hda_codec_read(codec, codec->afg, 0, | 2824 | gpiostate = snd_hda_codec_read(codec, codec->afg, 0, |
2191 | AC_VERB_GET_GPIO_DATA, 0); | 2825 | AC_VERB_GET_GPIO_DATA, 0); |
2192 | 2826 | gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask); | |
2193 | if (!muted) | ||
2194 | gpiostate |= (1 << pin); | ||
2195 | else | ||
2196 | gpiostate &= ~(1 << pin); | ||
2197 | 2827 | ||
2198 | gpiomask = snd_hda_codec_read(codec, codec->afg, 0, | 2828 | gpiomask = snd_hda_codec_read(codec, codec->afg, 0, |
2199 | AC_VERB_GET_GPIO_MASK, 0); | 2829 | AC_VERB_GET_GPIO_MASK, 0); |
2200 | gpiomask |= (1 << pin); | 2830 | gpiomask |= mask; |
2201 | 2831 | ||
2202 | gpiodir = snd_hda_codec_read(codec, codec->afg, 0, | 2832 | gpiodir = snd_hda_codec_read(codec, codec->afg, 0, |
2203 | AC_VERB_GET_GPIO_DIRECTION, 0); | 2833 | AC_VERB_GET_GPIO_DIRECTION, 0); |
2204 | gpiodir |= (1 << pin); | 2834 | gpiodir |= dir_mask; |
2205 | 2835 | ||
2206 | /* AppleHDA seems to do this -- WTF is this verb?? */ | 2836 | /* Configure GPIOx as CMOS */ |
2207 | snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0); | 2837 | snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0); |
2208 | 2838 | ||
2209 | snd_hda_codec_write(codec, codec->afg, 0, | 2839 | snd_hda_codec_write(codec, codec->afg, 0, |
2210 | AC_VERB_SET_GPIO_MASK, gpiomask); | 2840 | AC_VERB_SET_GPIO_MASK, gpiomask); |
2211 | snd_hda_codec_write(codec, codec->afg, 0, | 2841 | snd_hda_codec_read(codec, codec->afg, 0, |
2212 | AC_VERB_SET_GPIO_DIRECTION, gpiodir); | 2842 | AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */ |
2213 | 2843 | ||
2214 | msleep(1); | 2844 | msleep(1); |
2215 | 2845 | ||
2216 | snd_hda_codec_write(codec, codec->afg, 0, | 2846 | snd_hda_codec_read(codec, codec->afg, 0, |
2217 | AC_VERB_SET_GPIO_DATA, gpiostate); | 2847 | AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */ |
2218 | } | 2848 | } |
2219 | 2849 | ||
2220 | static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, | 2850 | static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, |
@@ -2226,6 +2856,16 @@ static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, | |||
2226 | (AC_USRSP_EN | event)); | 2856 | (AC_USRSP_EN | event)); |
2227 | } | 2857 | } |
2228 | 2858 | ||
2859 | static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid) | ||
2860 | { | ||
2861 | int i; | ||
2862 | for (i = 0; i < cfg->hp_outs; i++) | ||
2863 | if (cfg->hp_pins[i] == nid) | ||
2864 | return 1; /* nid is a HP-Out */ | ||
2865 | |||
2866 | return 0; /* nid is not a HP-Out */ | ||
2867 | }; | ||
2868 | |||
2229 | static int stac92xx_init(struct hda_codec *codec) | 2869 | static int stac92xx_init(struct hda_codec *codec) |
2230 | { | 2870 | { |
2231 | struct sigmatel_spec *spec = codec->spec; | 2871 | struct sigmatel_spec *spec = codec->spec; |
@@ -2261,10 +2901,23 @@ static int stac92xx_init(struct hda_codec *codec) | |||
2261 | stac92xx_auto_set_pinctl(codec, nid, pinctl); | 2901 | stac92xx_auto_set_pinctl(codec, nid, pinctl); |
2262 | } | 2902 | } |
2263 | } | 2903 | } |
2264 | if (spec->num_dmics > 0) | 2904 | for (i = 0; i < spec->num_dmics; i++) |
2265 | for (i = 0; i < spec->num_dmics; i++) | 2905 | stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i], |
2266 | stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i], | 2906 | AC_PINCTL_IN_EN); |
2267 | AC_PINCTL_IN_EN); | 2907 | for (i = 0; i < spec->num_pwrs; i++) { |
2908 | int event = is_nid_hp_pin(cfg, spec->pwr_nids[i]) | ||
2909 | ? STAC_HP_EVENT : STAC_PWR_EVENT; | ||
2910 | int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i], | ||
2911 | 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
2912 | /* outputs are only ports capable of power management | ||
2913 | * any attempts on powering down a input port cause the | ||
2914 | * referenced VREF to act quirky. | ||
2915 | */ | ||
2916 | if (pinctl & AC_PINCTL_IN_EN) | ||
2917 | continue; | ||
2918 | enable_pin_detect(codec, spec->pwr_nids[i], event | i); | ||
2919 | codec->patch_ops.unsol_event(codec, (event | i) << 26); | ||
2920 | } | ||
2268 | 2921 | ||
2269 | if (cfg->dig_out_pin) | 2922 | if (cfg->dig_out_pin) |
2270 | stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin, | 2923 | stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin, |
@@ -2273,10 +2926,8 @@ static int stac92xx_init(struct hda_codec *codec) | |||
2273 | stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin, | 2926 | stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin, |
2274 | AC_PINCTL_IN_EN); | 2927 | AC_PINCTL_IN_EN); |
2275 | 2928 | ||
2276 | if (spec->gpio_mute) { | 2929 | stac_gpio_set(codec, spec->gpio_mask, |
2277 | stac922x_gpio_mute(codec, 0, 0); | 2930 | spec->gpio_dir, spec->gpio_data); |
2278 | stac922x_gpio_mute(codec, 1, 0); | ||
2279 | } | ||
2280 | 2931 | ||
2281 | return 0; | 2932 | return 0; |
2282 | } | 2933 | } |
@@ -2342,13 +2993,20 @@ static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid, | |||
2342 | pin_ctl & ~flag); | 2993 | pin_ctl & ~flag); |
2343 | } | 2994 | } |
2344 | 2995 | ||
2345 | static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid) | 2996 | static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid) |
2346 | { | 2997 | { |
2347 | if (!nid) | 2998 | if (!nid) |
2348 | return 0; | 2999 | return 0; |
2349 | if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00) | 3000 | if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00) |
2350 | & (1 << 31)) | 3001 | & (1 << 31)) { |
2351 | return 1; | 3002 | unsigned int pinctl; |
3003 | pinctl = snd_hda_codec_read(codec, nid, 0, | ||
3004 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
3005 | if (pinctl & AC_PINCTL_IN_EN) | ||
3006 | return 0; /* mic- or line-input */ | ||
3007 | else | ||
3008 | return 1; /* HP-output */ | ||
3009 | } | ||
2352 | return 0; | 3010 | return 0; |
2353 | } | 3011 | } |
2354 | 3012 | ||
@@ -2359,10 +3017,14 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) | |||
2359 | int i, presence; | 3017 | int i, presence; |
2360 | 3018 | ||
2361 | presence = 0; | 3019 | presence = 0; |
3020 | if (spec->gpio_mute) | ||
3021 | presence = !(snd_hda_codec_read(codec, codec->afg, 0, | ||
3022 | AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute); | ||
3023 | |||
2362 | for (i = 0; i < cfg->hp_outs; i++) { | 3024 | for (i = 0; i < cfg->hp_outs; i++) { |
2363 | presence = get_pin_presence(codec, cfg->hp_pins[i]); | ||
2364 | if (presence) | 3025 | if (presence) |
2365 | break; | 3026 | break; |
3027 | presence = get_hp_pin_presence(codec, cfg->hp_pins[i]); | ||
2366 | } | 3028 | } |
2367 | 3029 | ||
2368 | if (presence) { | 3030 | if (presence) { |
@@ -2384,12 +3046,37 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) | |||
2384 | } | 3046 | } |
2385 | } | 3047 | } |
2386 | 3048 | ||
3049 | static void stac92xx_pin_sense(struct hda_codec *codec, int idx) | ||
3050 | { | ||
3051 | struct sigmatel_spec *spec = codec->spec; | ||
3052 | hda_nid_t nid = spec->pwr_nids[idx]; | ||
3053 | int presence, val; | ||
3054 | val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0) | ||
3055 | & 0x000000ff; | ||
3056 | presence = get_hp_pin_presence(codec, nid); | ||
3057 | idx = 1 << idx; | ||
3058 | |||
3059 | if (presence) | ||
3060 | val &= ~idx; | ||
3061 | else | ||
3062 | val |= idx; | ||
3063 | |||
3064 | /* power down unused output ports */ | ||
3065 | snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val); | ||
3066 | }; | ||
3067 | |||
2387 | static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) | 3068 | static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) |
2388 | { | 3069 | { |
2389 | switch (res >> 26) { | 3070 | struct sigmatel_spec *spec = codec->spec; |
3071 | int idx = res >> 26 & 0x0f; | ||
3072 | |||
3073 | switch ((res >> 26) & 0x30) { | ||
2390 | case STAC_HP_EVENT: | 3074 | case STAC_HP_EVENT: |
2391 | stac92xx_hp_detect(codec, res); | 3075 | stac92xx_hp_detect(codec, res); |
2392 | break; | 3076 | /* fallthru */ |
3077 | case STAC_PWR_EVENT: | ||
3078 | if (spec->num_pwrs > 0) | ||
3079 | stac92xx_pin_sense(codec, idx); | ||
2393 | } | 3080 | } |
2394 | } | 3081 | } |
2395 | 3082 | ||
@@ -2400,10 +3087,8 @@ static int stac92xx_resume(struct hda_codec *codec) | |||
2400 | 3087 | ||
2401 | stac92xx_set_config_regs(codec); | 3088 | stac92xx_set_config_regs(codec); |
2402 | snd_hda_sequence_write(codec, spec->init); | 3089 | snd_hda_sequence_write(codec, spec->init); |
2403 | if (spec->gpio_mute) { | 3090 | stac_gpio_set(codec, spec->gpio_mask, |
2404 | stac922x_gpio_mute(codec, 0, 0); | 3091 | spec->gpio_dir, spec->gpio_data); |
2405 | stac922x_gpio_mute(codec, 1, 0); | ||
2406 | } | ||
2407 | snd_hda_codec_resume_amp(codec); | 3092 | snd_hda_codec_resume_amp(codec); |
2408 | snd_hda_codec_resume_cache(codec); | 3093 | snd_hda_codec_resume_cache(codec); |
2409 | /* invoke unsolicited event to reset the HP state */ | 3094 | /* invoke unsolicited event to reset the HP state */ |
@@ -2460,6 +3145,7 @@ static int patch_stac9200(struct hda_codec *codec) | |||
2460 | spec->num_muxes = 1; | 3145 | spec->num_muxes = 1; |
2461 | spec->num_dmics = 0; | 3146 | spec->num_dmics = 0; |
2462 | spec->num_adcs = 1; | 3147 | spec->num_adcs = 1; |
3148 | spec->num_pwrs = 0; | ||
2463 | 3149 | ||
2464 | if (spec->board_config == STAC_9200_GATEWAY) | 3150 | if (spec->board_config == STAC_9200_GATEWAY) |
2465 | spec->init = stac9200_eapd_init; | 3151 | spec->init = stac9200_eapd_init; |
@@ -2515,6 +3201,7 @@ static int patch_stac925x(struct hda_codec *codec) | |||
2515 | spec->mux_nids = stac925x_mux_nids; | 3201 | spec->mux_nids = stac925x_mux_nids; |
2516 | spec->num_muxes = 1; | 3202 | spec->num_muxes = 1; |
2517 | spec->num_adcs = 1; | 3203 | spec->num_adcs = 1; |
3204 | spec->num_pwrs = 0; | ||
2518 | switch (codec->vendor_id) { | 3205 | switch (codec->vendor_id) { |
2519 | case 0x83847632: /* STAC9202 */ | 3206 | case 0x83847632: /* STAC9202 */ |
2520 | case 0x83847633: /* STAC9202D */ | 3207 | case 0x83847633: /* STAC9202D */ |
@@ -2522,6 +3209,8 @@ static int patch_stac925x(struct hda_codec *codec) | |||
2522 | case 0x83847637: /* STAC9251D */ | 3209 | case 0x83847637: /* STAC9251D */ |
2523 | spec->num_dmics = STAC925X_NUM_DMICS; | 3210 | spec->num_dmics = STAC925X_NUM_DMICS; |
2524 | spec->dmic_nids = stac925x_dmic_nids; | 3211 | spec->dmic_nids = stac925x_dmic_nids; |
3212 | spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids); | ||
3213 | spec->dmux_nids = stac925x_dmux_nids; | ||
2525 | break; | 3214 | break; |
2526 | default: | 3215 | default: |
2527 | spec->num_dmics = 0; | 3216 | spec->num_dmics = 0; |
@@ -2551,6 +3240,204 @@ static int patch_stac925x(struct hda_codec *codec) | |||
2551 | return 0; | 3240 | return 0; |
2552 | } | 3241 | } |
2553 | 3242 | ||
3243 | static struct hda_input_mux stac92hd73xx_dmux = { | ||
3244 | .num_items = 4, | ||
3245 | .items = { | ||
3246 | { "Analog Inputs", 0x0b }, | ||
3247 | { "CD", 0x08 }, | ||
3248 | { "Digital Mic 1", 0x09 }, | ||
3249 | { "Digital Mic 2", 0x0a }, | ||
3250 | } | ||
3251 | }; | ||
3252 | |||
3253 | static int patch_stac92hd73xx(struct hda_codec *codec) | ||
3254 | { | ||
3255 | struct sigmatel_spec *spec; | ||
3256 | hda_nid_t conn[STAC92HD73_DAC_COUNT + 2]; | ||
3257 | int err = 0; | ||
3258 | |||
3259 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
3260 | if (spec == NULL) | ||
3261 | return -ENOMEM; | ||
3262 | |||
3263 | codec->spec = spec; | ||
3264 | spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids); | ||
3265 | spec->pin_nids = stac92hd73xx_pin_nids; | ||
3266 | spec->board_config = snd_hda_check_board_config(codec, | ||
3267 | STAC_92HD73XX_MODELS, | ||
3268 | stac92hd73xx_models, | ||
3269 | stac92hd73xx_cfg_tbl); | ||
3270 | again: | ||
3271 | if (spec->board_config < 0) { | ||
3272 | snd_printdd(KERN_INFO "hda_codec: Unknown model for" | ||
3273 | " STAC92HD73XX, using BIOS defaults\n"); | ||
3274 | err = stac92xx_save_bios_config_regs(codec); | ||
3275 | if (err < 0) { | ||
3276 | stac92xx_free(codec); | ||
3277 | return err; | ||
3278 | } | ||
3279 | spec->pin_configs = spec->bios_pin_configs; | ||
3280 | } else { | ||
3281 | spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config]; | ||
3282 | stac92xx_set_config_regs(codec); | ||
3283 | } | ||
3284 | |||
3285 | spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a, | ||
3286 | conn, STAC92HD73_DAC_COUNT + 2) - 1; | ||
3287 | |||
3288 | if (spec->multiout.num_dacs < 0) { | ||
3289 | printk(KERN_WARNING "hda_codec: Could not determine " | ||
3290 | "number of channels defaulting to DAC count\n"); | ||
3291 | spec->multiout.num_dacs = STAC92HD73_DAC_COUNT; | ||
3292 | } | ||
3293 | |||
3294 | switch (spec->multiout.num_dacs) { | ||
3295 | case 0x3: /* 6 Channel */ | ||
3296 | spec->mixer = stac92hd73xx_6ch_mixer; | ||
3297 | spec->init = stac92hd73xx_6ch_core_init; | ||
3298 | break; | ||
3299 | case 0x4: /* 8 Channel */ | ||
3300 | spec->multiout.hp_nid = 0x18; | ||
3301 | spec->mixer = stac92hd73xx_8ch_mixer; | ||
3302 | spec->init = stac92hd73xx_8ch_core_init; | ||
3303 | break; | ||
3304 | case 0x5: /* 10 Channel */ | ||
3305 | spec->multiout.hp_nid = 0x19; | ||
3306 | spec->mixer = stac92hd73xx_10ch_mixer; | ||
3307 | spec->init = stac92hd73xx_10ch_core_init; | ||
3308 | }; | ||
3309 | |||
3310 | spec->multiout.dac_nids = stac92hd73xx_dac_nids; | ||
3311 | spec->aloopback_mask = 0x01; | ||
3312 | spec->aloopback_shift = 8; | ||
3313 | |||
3314 | spec->mux_nids = stac92hd73xx_mux_nids; | ||
3315 | spec->adc_nids = stac92hd73xx_adc_nids; | ||
3316 | spec->dmic_nids = stac92hd73xx_dmic_nids; | ||
3317 | spec->dmux_nids = stac92hd73xx_dmux_nids; | ||
3318 | |||
3319 | spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids); | ||
3320 | spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids); | ||
3321 | spec->num_dmics = STAC92HD73XX_NUM_DMICS; | ||
3322 | spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids); | ||
3323 | spec->dinput_mux = &stac92hd73xx_dmux; | ||
3324 | /* GPIO0 High = Enable EAPD */ | ||
3325 | spec->gpio_mask = spec->gpio_dir = 0x1; | ||
3326 | spec->gpio_data = 0x01; | ||
3327 | |||
3328 | spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids); | ||
3329 | spec->pwr_nids = stac92hd73xx_pwr_nids; | ||
3330 | |||
3331 | err = stac92xx_parse_auto_config(codec, 0x22, 0x24); | ||
3332 | |||
3333 | if (!err) { | ||
3334 | if (spec->board_config < 0) { | ||
3335 | printk(KERN_WARNING "hda_codec: No auto-config is " | ||
3336 | "available, default to model=ref\n"); | ||
3337 | spec->board_config = STAC_92HD73XX_REF; | ||
3338 | goto again; | ||
3339 | } | ||
3340 | err = -EINVAL; | ||
3341 | } | ||
3342 | |||
3343 | if (err < 0) { | ||
3344 | stac92xx_free(codec); | ||
3345 | return err; | ||
3346 | } | ||
3347 | |||
3348 | codec->patch_ops = stac92xx_patch_ops; | ||
3349 | |||
3350 | return 0; | ||
3351 | } | ||
3352 | |||
3353 | static int patch_stac92hd71bxx(struct hda_codec *codec) | ||
3354 | { | ||
3355 | struct sigmatel_spec *spec; | ||
3356 | int err = 0; | ||
3357 | |||
3358 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
3359 | if (spec == NULL) | ||
3360 | return -ENOMEM; | ||
3361 | |||
3362 | codec->spec = spec; | ||
3363 | spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids); | ||
3364 | spec->pin_nids = stac92hd71bxx_pin_nids; | ||
3365 | spec->board_config = snd_hda_check_board_config(codec, | ||
3366 | STAC_92HD71BXX_MODELS, | ||
3367 | stac92hd71bxx_models, | ||
3368 | stac92hd71bxx_cfg_tbl); | ||
3369 | again: | ||
3370 | if (spec->board_config < 0) { | ||
3371 | snd_printdd(KERN_INFO "hda_codec: Unknown model for" | ||
3372 | " STAC92HD71BXX, using BIOS defaults\n"); | ||
3373 | err = stac92xx_save_bios_config_regs(codec); | ||
3374 | if (err < 0) { | ||
3375 | stac92xx_free(codec); | ||
3376 | return err; | ||
3377 | } | ||
3378 | spec->pin_configs = spec->bios_pin_configs; | ||
3379 | } else { | ||
3380 | spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config]; | ||
3381 | stac92xx_set_config_regs(codec); | ||
3382 | } | ||
3383 | |||
3384 | switch (codec->vendor_id) { | ||
3385 | case 0x111d76b6: /* 4 Port without Analog Mixer */ | ||
3386 | case 0x111d76b7: | ||
3387 | case 0x111d76b4: /* 6 Port without Analog Mixer */ | ||
3388 | case 0x111d76b5: | ||
3389 | spec->mixer = stac92hd71bxx_mixer; | ||
3390 | spec->init = stac92hd71bxx_core_init; | ||
3391 | break; | ||
3392 | default: | ||
3393 | spec->mixer = stac92hd71bxx_analog_mixer; | ||
3394 | spec->init = stac92hd71bxx_analog_core_init; | ||
3395 | } | ||
3396 | |||
3397 | spec->aloopback_mask = 0x20; | ||
3398 | spec->aloopback_shift = 0; | ||
3399 | |||
3400 | /* GPIO0 High = EAPD */ | ||
3401 | spec->gpio_mask = spec->gpio_dir = spec->gpio_data = 0x1; | ||
3402 | |||
3403 | spec->mux_nids = stac92hd71bxx_mux_nids; | ||
3404 | spec->adc_nids = stac92hd71bxx_adc_nids; | ||
3405 | spec->dmic_nids = stac92hd71bxx_dmic_nids; | ||
3406 | spec->dmux_nids = stac92hd71bxx_dmux_nids; | ||
3407 | |||
3408 | spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids); | ||
3409 | spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids); | ||
3410 | spec->num_dmics = STAC92HD71BXX_NUM_DMICS; | ||
3411 | spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); | ||
3412 | |||
3413 | spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids); | ||
3414 | spec->pwr_nids = stac92hd71bxx_pwr_nids; | ||
3415 | |||
3416 | spec->multiout.num_dacs = 2; | ||
3417 | spec->multiout.hp_nid = 0x11; | ||
3418 | spec->multiout.dac_nids = stac92hd71bxx_dac_nids; | ||
3419 | |||
3420 | err = stac92xx_parse_auto_config(codec, 0x21, 0x23); | ||
3421 | if (!err) { | ||
3422 | if (spec->board_config < 0) { | ||
3423 | printk(KERN_WARNING "hda_codec: No auto-config is " | ||
3424 | "available, default to model=ref\n"); | ||
3425 | spec->board_config = STAC_92HD71BXX_REF; | ||
3426 | goto again; | ||
3427 | } | ||
3428 | err = -EINVAL; | ||
3429 | } | ||
3430 | |||
3431 | if (err < 0) { | ||
3432 | stac92xx_free(codec); | ||
3433 | return err; | ||
3434 | } | ||
3435 | |||
3436 | codec->patch_ops = stac92xx_patch_ops; | ||
3437 | |||
3438 | return 0; | ||
3439 | }; | ||
3440 | |||
2554 | static int patch_stac922x(struct hda_codec *codec) | 3441 | static int patch_stac922x(struct hda_codec *codec) |
2555 | { | 3442 | { |
2556 | struct sigmatel_spec *spec; | 3443 | struct sigmatel_spec *spec; |
@@ -2567,7 +3454,8 @@ static int patch_stac922x(struct hda_codec *codec) | |||
2567 | stac922x_models, | 3454 | stac922x_models, |
2568 | stac922x_cfg_tbl); | 3455 | stac922x_cfg_tbl); |
2569 | if (spec->board_config == STAC_INTEL_MAC_V3) { | 3456 | if (spec->board_config == STAC_INTEL_MAC_V3) { |
2570 | spec->gpio_mute = 1; | 3457 | spec->gpio_mask = spec->gpio_dir = 0x03; |
3458 | spec->gpio_data = 0x03; | ||
2571 | /* Intel Macs have all same PCI SSID, so we need to check | 3459 | /* Intel Macs have all same PCI SSID, so we need to check |
2572 | * codec SSID to distinguish the exact models | 3460 | * codec SSID to distinguish the exact models |
2573 | */ | 3461 | */ |
@@ -2620,6 +3508,7 @@ static int patch_stac922x(struct hda_codec *codec) | |||
2620 | spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids); | 3508 | spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids); |
2621 | spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids); | 3509 | spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids); |
2622 | spec->num_dmics = 0; | 3510 | spec->num_dmics = 0; |
3511 | spec->num_pwrs = 0; | ||
2623 | 3512 | ||
2624 | spec->init = stac922x_core_init; | 3513 | spec->init = stac922x_core_init; |
2625 | spec->mixer = stac922x_mixer; | 3514 | spec->mixer = stac922x_mixer; |
@@ -2669,53 +3558,70 @@ static int patch_stac927x(struct hda_codec *codec) | |||
2669 | stac927x_models, | 3558 | stac927x_models, |
2670 | stac927x_cfg_tbl); | 3559 | stac927x_cfg_tbl); |
2671 | again: | 3560 | again: |
2672 | if (spec->board_config < 0) { | 3561 | if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) { |
2673 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC927x, using BIOS defaults\n"); | 3562 | if (spec->board_config < 0) |
3563 | snd_printdd(KERN_INFO "hda_codec: Unknown model for" | ||
3564 | "STAC927x, using BIOS defaults\n"); | ||
2674 | err = stac92xx_save_bios_config_regs(codec); | 3565 | err = stac92xx_save_bios_config_regs(codec); |
2675 | if (err < 0) { | 3566 | if (err < 0) { |
2676 | stac92xx_free(codec); | 3567 | stac92xx_free(codec); |
2677 | return err; | 3568 | return err; |
2678 | } | 3569 | } |
2679 | spec->pin_configs = spec->bios_pin_configs; | 3570 | spec->pin_configs = spec->bios_pin_configs; |
2680 | } else if (stac927x_brd_tbl[spec->board_config] != NULL) { | 3571 | } else { |
2681 | spec->pin_configs = stac927x_brd_tbl[spec->board_config]; | 3572 | spec->pin_configs = stac927x_brd_tbl[spec->board_config]; |
2682 | stac92xx_set_config_regs(codec); | 3573 | stac92xx_set_config_regs(codec); |
2683 | } | 3574 | } |
2684 | 3575 | ||
3576 | spec->adc_nids = stac927x_adc_nids; | ||
3577 | spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); | ||
3578 | spec->mux_nids = stac927x_mux_nids; | ||
3579 | spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); | ||
3580 | spec->multiout.dac_nids = spec->dac_nids; | ||
3581 | |||
2685 | switch (spec->board_config) { | 3582 | switch (spec->board_config) { |
2686 | case STAC_D965_3ST: | 3583 | case STAC_D965_3ST: |
2687 | spec->adc_nids = stac927x_adc_nids; | 3584 | case STAC_D965_5ST: |
2688 | spec->mux_nids = stac927x_mux_nids; | 3585 | /* GPIO0 High = Enable EAPD */ |
2689 | spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); | 3586 | spec->gpio_mask = spec->gpio_dir = 0x01; |
2690 | spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); | 3587 | spec->gpio_data = 0x01; |
2691 | spec->num_dmics = 0; | 3588 | spec->num_dmics = 0; |
3589 | |||
2692 | spec->init = d965_core_init; | 3590 | spec->init = d965_core_init; |
2693 | spec->mixer = stac927x_mixer; | 3591 | spec->mixer = stac927x_mixer; |
2694 | break; | 3592 | break; |
2695 | case STAC_D965_5ST: | 3593 | case STAC_DELL_BIOS: |
2696 | spec->adc_nids = stac927x_adc_nids; | 3594 | /* correct the front output jack as a hp out */ |
2697 | spec->mux_nids = stac927x_mux_nids; | 3595 | stac92xx_set_config_reg(codec, 0x0f, 0x02270110); |
2698 | spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); | 3596 | /* correct the front input jack as a mic */ |
2699 | spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); | 3597 | stac92xx_set_config_reg(codec, 0x0e, 0x02a79130); |
2700 | spec->num_dmics = 0; | 3598 | /* fallthru */ |
3599 | case STAC_DELL_3ST: | ||
3600 | /* GPIO2 High = Enable EAPD */ | ||
3601 | spec->gpio_mask = spec->gpio_dir = 0x04; | ||
3602 | spec->gpio_data = 0x04; | ||
3603 | spec->dmic_nids = stac927x_dmic_nids; | ||
3604 | spec->num_dmics = STAC927X_NUM_DMICS; | ||
3605 | |||
2701 | spec->init = d965_core_init; | 3606 | spec->init = d965_core_init; |
2702 | spec->mixer = stac927x_mixer; | 3607 | spec->mixer = stac927x_mixer; |
3608 | spec->dmux_nids = stac927x_dmux_nids; | ||
3609 | spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids); | ||
2703 | break; | 3610 | break; |
2704 | default: | 3611 | default: |
2705 | spec->adc_nids = stac927x_adc_nids; | 3612 | /* GPIO0 High = Enable EAPD */ |
2706 | spec->mux_nids = stac927x_mux_nids; | 3613 | spec->gpio_mask = spec->gpio_dir = 0x1; |
2707 | spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); | 3614 | spec->gpio_data = 0x01; |
2708 | spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); | ||
2709 | spec->num_dmics = 0; | 3615 | spec->num_dmics = 0; |
3616 | |||
2710 | spec->init = stac927x_core_init; | 3617 | spec->init = stac927x_core_init; |
2711 | spec->mixer = stac927x_mixer; | 3618 | spec->mixer = stac927x_mixer; |
2712 | } | 3619 | } |
2713 | 3620 | ||
2714 | spec->multiout.dac_nids = spec->dac_nids; | 3621 | spec->num_pwrs = 0; |
2715 | /* GPIO0 High = Enable EAPD */ | 3622 | spec->aloopback_mask = 0x40; |
2716 | spec->gpio_mask = spec->gpio_data = 0x00000001; | 3623 | spec->aloopback_shift = 0; |
2717 | stac92xx_enable_gpio_mask(codec); | 3624 | |
2718 | |||
2719 | err = stac92xx_parse_auto_config(codec, 0x1e, 0x20); | 3625 | err = stac92xx_parse_auto_config(codec, 0x1e, 0x20); |
2720 | if (!err) { | 3626 | if (!err) { |
2721 | if (spec->board_config < 0) { | 3627 | if (spec->board_config < 0) { |
@@ -2733,6 +3639,18 @@ static int patch_stac927x(struct hda_codec *codec) | |||
2733 | 3639 | ||
2734 | codec->patch_ops = stac92xx_patch_ops; | 3640 | codec->patch_ops = stac92xx_patch_ops; |
2735 | 3641 | ||
3642 | /* | ||
3643 | * !!FIXME!! | ||
3644 | * The STAC927x seem to require fairly long delays for certain | ||
3645 | * command sequences. With too short delays (even if the answer | ||
3646 | * is set to RIRB properly), it results in the silence output | ||
3647 | * on some hardwares like Dell. | ||
3648 | * | ||
3649 | * The below flag enables the longer delay (see get_response | ||
3650 | * in hda_intel.c). | ||
3651 | */ | ||
3652 | codec->bus->needs_damn_long_delay = 1; | ||
3653 | |||
2736 | return 0; | 3654 | return 0; |
2737 | } | 3655 | } |
2738 | 3656 | ||
@@ -2771,11 +3689,15 @@ static int patch_stac9205(struct hda_codec *codec) | |||
2771 | spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids); | 3689 | spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids); |
2772 | spec->dmic_nids = stac9205_dmic_nids; | 3690 | spec->dmic_nids = stac9205_dmic_nids; |
2773 | spec->num_dmics = STAC9205_NUM_DMICS; | 3691 | spec->num_dmics = STAC9205_NUM_DMICS; |
2774 | spec->dmux_nid = 0x1d; | 3692 | spec->dmux_nids = stac9205_dmux_nids; |
3693 | spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids); | ||
3694 | spec->num_pwrs = 0; | ||
2775 | 3695 | ||
2776 | spec->init = stac9205_core_init; | 3696 | spec->init = stac9205_core_init; |
2777 | spec->mixer = stac9205_mixer; | 3697 | spec->mixer = stac9205_mixer; |
2778 | 3698 | ||
3699 | spec->aloopback_mask = 0x40; | ||
3700 | spec->aloopback_shift = 0; | ||
2779 | spec->multiout.dac_nids = spec->dac_nids; | 3701 | spec->multiout.dac_nids = spec->dac_nids; |
2780 | 3702 | ||
2781 | switch (spec->board_config){ | 3703 | switch (spec->board_config){ |
@@ -2784,19 +3706,28 @@ static int patch_stac9205(struct hda_codec *codec) | |||
2784 | stac92xx_set_config_reg(codec, 0x1f, 0x01441030); | 3706 | stac92xx_set_config_reg(codec, 0x1f, 0x01441030); |
2785 | stac92xx_set_config_reg(codec, 0x20, 0x1c410030); | 3707 | stac92xx_set_config_reg(codec, 0x20, 0x1c410030); |
2786 | 3708 | ||
2787 | spec->gpio_mask = 0x00000007; /* GPIO0-2 */ | 3709 | /* Enable unsol response for GPIO4/Dock HP connection */ |
2788 | /* GPIO0 High = EAPD, GPIO1 Low = DRM, | 3710 | snd_hda_codec_write(codec, codec->afg, 0, |
2789 | * GPIO2 High = Headphone Mute | 3711 | AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10); |
3712 | snd_hda_codec_write_cache(codec, codec->afg, 0, | ||
3713 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
3714 | (AC_USRSP_EN | STAC_HP_EVENT)); | ||
3715 | |||
3716 | spec->gpio_dir = 0x0b; | ||
3717 | spec->gpio_mask = 0x1b; | ||
3718 | spec->gpio_mute = 0x10; | ||
3719 | /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute, | ||
3720 | * GPIO3 Low = DRM | ||
2790 | */ | 3721 | */ |
2791 | spec->gpio_data = 0x00000005; | 3722 | spec->gpio_data = 0x01; |
2792 | break; | 3723 | break; |
2793 | default: | 3724 | default: |
2794 | /* GPIO0 High = EAPD */ | 3725 | /* GPIO0 High = EAPD */ |
2795 | spec->gpio_mask = spec->gpio_data = 0x00000001; | 3726 | spec->gpio_mask = spec->gpio_dir = 0x1; |
3727 | spec->gpio_data = 0x01; | ||
2796 | break; | 3728 | break; |
2797 | } | 3729 | } |
2798 | 3730 | ||
2799 | stac92xx_enable_gpio_mask(codec); | ||
2800 | err = stac92xx_parse_auto_config(codec, 0x1f, 0x20); | 3731 | err = stac92xx_parse_auto_config(codec, 0x1f, 0x20); |
2801 | if (!err) { | 3732 | if (!err) { |
2802 | if (spec->board_config < 0) { | 3733 | if (spec->board_config < 0) { |
@@ -2950,7 +3881,7 @@ static int stac9872_vaio_init(struct hda_codec *codec) | |||
2950 | 3881 | ||
2951 | static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res) | 3882 | static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res) |
2952 | { | 3883 | { |
2953 | if (get_pin_presence(codec, 0x0a)) { | 3884 | if (get_hp_pin_presence(codec, 0x0a)) { |
2954 | stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN); | 3885 | stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN); |
2955 | stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN); | 3886 | stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN); |
2956 | } else { | 3887 | } else { |
@@ -3032,6 +3963,7 @@ static int patch_stac9872(struct hda_codec *codec) | |||
3032 | spec->multiout.hp_nid = VAIO_HP_DAC; | 3963 | spec->multiout.hp_nid = VAIO_HP_DAC; |
3033 | spec->num_adcs = ARRAY_SIZE(vaio_adcs); | 3964 | spec->num_adcs = ARRAY_SIZE(vaio_adcs); |
3034 | spec->adc_nids = vaio_adcs; | 3965 | spec->adc_nids = vaio_adcs; |
3966 | spec->num_pwrs = 0; | ||
3035 | spec->input_mux = &vaio_mux; | 3967 | spec->input_mux = &vaio_mux; |
3036 | spec->mux_nids = vaio_mux_nids; | 3968 | spec->mux_nids = vaio_mux_nids; |
3037 | codec->patch_ops = stac9872_vaio_patch_ops; | 3969 | codec->patch_ops = stac9872_vaio_patch_ops; |
@@ -3045,6 +3977,7 @@ static int patch_stac9872(struct hda_codec *codec) | |||
3045 | spec->multiout.dac_nids = vaio_dacs; | 3977 | spec->multiout.dac_nids = vaio_dacs; |
3046 | spec->multiout.hp_nid = VAIO_HP_DAC; | 3978 | spec->multiout.hp_nid = VAIO_HP_DAC; |
3047 | spec->num_adcs = ARRAY_SIZE(vaio_adcs); | 3979 | spec->num_adcs = ARRAY_SIZE(vaio_adcs); |
3980 | spec->num_pwrs = 0; | ||
3048 | spec->adc_nids = vaio_adcs; | 3981 | spec->adc_nids = vaio_adcs; |
3049 | spec->input_mux = &vaio_mux; | 3982 | spec->input_mux = &vaio_mux; |
3050 | spec->mux_nids = vaio_mux_nids; | 3983 | spec->mux_nids = vaio_mux_nids; |
@@ -3104,5 +4037,17 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = { | |||
3104 | { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 }, | 4037 | { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 }, |
3105 | { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 }, | 4038 | { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 }, |
3106 | { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 }, | 4039 | { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 }, |
4040 | { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx }, | ||
4041 | { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx }, | ||
4042 | { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx }, | ||
4043 | { .id = 0x111d7608, .name = "92HD71BXX", .patch = patch_stac92hd71bxx }, | ||
4044 | { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx }, | ||
4045 | { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx }, | ||
4046 | { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx }, | ||
4047 | { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx }, | ||
4048 | { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx }, | ||
4049 | { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx }, | ||
4050 | { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx }, | ||
4051 | { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx }, | ||
3107 | {} /* terminator */ | 4052 | {} /* terminator */ |
3108 | }; | 4053 | }; |
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 4cdf3e6df4ba..4e5dd4cf36f5 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c | |||
@@ -27,11 +27,12 @@ | |||
27 | /* 2006-03-14 Lydia Wang Modify hard code for some pin widget nid */ | 27 | /* 2006-03-14 Lydia Wang Modify hard code for some pin widget nid */ |
28 | /* 2006-08-02 Lydia Wang Add support to VT1709 codec */ | 28 | /* 2006-08-02 Lydia Wang Add support to VT1709 codec */ |
29 | /* 2006-09-08 Lydia Wang Fix internal loopback recording source select bug */ | 29 | /* 2006-09-08 Lydia Wang Fix internal loopback recording source select bug */ |
30 | /* 2007-09-12 Lydia Wang Add EAPD enable during driver initialization */ | ||
31 | /* 2007-09-17 Lydia Wang Add VT1708B codec support */ | ||
30 | /* */ | 32 | /* */ |
31 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | 33 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
32 | 34 | ||
33 | 35 | ||
34 | #include <sound/driver.h> | ||
35 | #include <linux/init.h> | 36 | #include <linux/init.h> |
36 | #include <linux/delay.h> | 37 | #include <linux/delay.h> |
37 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
@@ -51,14 +52,23 @@ | |||
51 | #define VT1708_HP_NID 0x13 | 52 | #define VT1708_HP_NID 0x13 |
52 | #define VT1708_DIGOUT_NID 0x14 | 53 | #define VT1708_DIGOUT_NID 0x14 |
53 | #define VT1708_DIGIN_NID 0x16 | 54 | #define VT1708_DIGIN_NID 0x16 |
55 | #define VT1708_DIGIN_PIN 0x26 | ||
54 | 56 | ||
55 | #define VT1709_HP_DAC_NID 0x28 | 57 | #define VT1709_HP_DAC_NID 0x28 |
56 | #define VT1709_DIGOUT_NID 0x13 | 58 | #define VT1709_DIGOUT_NID 0x13 |
57 | #define VT1709_DIGIN_NID 0x17 | 59 | #define VT1709_DIGIN_NID 0x17 |
60 | #define VT1709_DIGIN_PIN 0x25 | ||
61 | |||
62 | #define VT1708B_HP_NID 0x25 | ||
63 | #define VT1708B_DIGOUT_NID 0x12 | ||
64 | #define VT1708B_DIGIN_NID 0x15 | ||
65 | #define VT1708B_DIGIN_PIN 0x21 | ||
58 | 66 | ||
59 | #define IS_VT1708_VENDORID(x) ((x) >= 0x11061708 && (x) <= 0x1106170b) | 67 | #define IS_VT1708_VENDORID(x) ((x) >= 0x11061708 && (x) <= 0x1106170b) |
60 | #define IS_VT1709_10CH_VENDORID(x) ((x) >= 0x1106e710 && (x) <= 0x1106e713) | 68 | #define IS_VT1709_10CH_VENDORID(x) ((x) >= 0x1106e710 && (x) <= 0x1106e713) |
61 | #define IS_VT1709_6CH_VENDORID(x) ((x) >= 0x1106e714 && (x) <= 0x1106e717) | 69 | #define IS_VT1709_6CH_VENDORID(x) ((x) >= 0x1106e714 && (x) <= 0x1106e717) |
70 | #define IS_VT1708B_8CH_VENDORID(x) ((x) >= 0x1106e720 && (x) <= 0x1106e723) | ||
71 | #define IS_VT1708B_4CH_VENDORID(x) ((x) >= 0x1106e724 && (x) <= 0x1106e727) | ||
62 | 72 | ||
63 | 73 | ||
64 | enum { | 74 | enum { |
@@ -131,6 +141,11 @@ static hda_nid_t vt1709_adc_nids[3] = { | |||
131 | 0x14, 0x15, 0x16 | 141 | 0x14, 0x15, 0x16 |
132 | }; | 142 | }; |
133 | 143 | ||
144 | static hda_nid_t vt1708B_adc_nids[2] = { | ||
145 | /* ADC1-2 */ | ||
146 | 0x13, 0x14 | ||
147 | }; | ||
148 | |||
134 | /* add dynamic controls */ | 149 | /* add dynamic controls */ |
135 | static int via_add_control(struct via_spec *spec, int type, const char *name, | 150 | static int via_add_control(struct via_spec *spec, int type, const char *name, |
136 | unsigned long val) | 151 | unsigned long val) |
@@ -268,9 +283,13 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol, | |||
268 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, | 283 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, |
269 | 0x18, &spec->cur_mux[adc_idx]); | 284 | 0x18, &spec->cur_mux[adc_idx]); |
270 | else if ((IS_VT1709_10CH_VENDORID(vendor_id) || | 285 | else if ((IS_VT1709_10CH_VENDORID(vendor_id) || |
271 | IS_VT1709_6CH_VENDORID(vendor_id)) && (adc_idx == 0) ) | 286 | IS_VT1709_6CH_VENDORID(vendor_id)) && adc_idx == 0) |
272 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, | 287 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, |
273 | 0x19, &spec->cur_mux[adc_idx]); | 288 | 0x19, &spec->cur_mux[adc_idx]); |
289 | else if ((IS_VT1708B_8CH_VENDORID(vendor_id) || | ||
290 | IS_VT1708B_4CH_VENDORID(vendor_id)) && adc_idx == 0) | ||
291 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, | ||
292 | 0x17, &spec->cur_mux[adc_idx]); | ||
274 | else | 293 | else |
275 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, | 294 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, |
276 | spec->adc_nids[adc_idx], | 295 | spec->adc_nids[adc_idx], |
@@ -287,7 +306,6 @@ static struct snd_kcontrol_new vt1708_capture_mixer[] = { | |||
287 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 306 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
288 | /* The multiple "Capture Source" controls confuse alsamixer | 307 | /* The multiple "Capture Source" controls confuse alsamixer |
289 | * So call somewhat different.. | 308 | * So call somewhat different.. |
290 | * FIXME: the controls appear in the "playback" view! | ||
291 | */ | 309 | */ |
292 | /* .name = "Capture Source", */ | 310 | /* .name = "Capture Source", */ |
293 | .name = "Input Source", | 311 | .name = "Input Source", |
@@ -309,15 +327,15 @@ static struct hda_verb vt1708_volume_init_verbs[] = { | |||
309 | {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 327 | {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
310 | 328 | ||
311 | 329 | ||
312 | /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | 330 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback |
313 | * mixer widget | 331 | * mixer widget |
314 | */ | 332 | */ |
315 | /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ | 333 | /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ |
316 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* master */ | 334 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
317 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | 335 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
318 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | 336 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, |
319 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | 337 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, |
320 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | 338 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, |
321 | 339 | ||
322 | /* | 340 | /* |
323 | * Set up output mixers (0x19 - 0x1b) | 341 | * Set up output mixers (0x19 - 0x1b) |
@@ -329,10 +347,9 @@ static struct hda_verb vt1708_volume_init_verbs[] = { | |||
329 | 347 | ||
330 | /* Setup default input to PW4 */ | 348 | /* Setup default input to PW4 */ |
331 | {0x20, AC_VERB_SET_CONNECT_SEL, 0x1}, | 349 | {0x20, AC_VERB_SET_CONNECT_SEL, 0x1}, |
332 | /* Set mic as default input of sw0 */ | ||
333 | {0x18, AC_VERB_SET_CONNECT_SEL, 0x2}, | ||
334 | /* PW9 Output enable */ | 350 | /* PW9 Output enable */ |
335 | {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | 351 | {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, |
352 | { } | ||
336 | }; | 353 | }; |
337 | 354 | ||
338 | static int via_playback_pcm_open(struct hda_pcm_stream *hinfo, | 355 | static int via_playback_pcm_open(struct hda_pcm_stream *hinfo, |
@@ -544,6 +561,33 @@ static int via_init(struct hda_codec *codec) | |||
544 | { | 561 | { |
545 | struct via_spec *spec = codec->spec; | 562 | struct via_spec *spec = codec->spec; |
546 | snd_hda_sequence_write(codec, spec->init_verbs); | 563 | snd_hda_sequence_write(codec, spec->init_verbs); |
564 | /* Lydia Add for EAPD enable */ | ||
565 | if (!spec->dig_in_nid) { /* No Digital In connection */ | ||
566 | if (IS_VT1708_VENDORID(codec->vendor_id)) { | ||
567 | snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0, | ||
568 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
569 | PIN_OUT); | ||
570 | snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0, | ||
571 | AC_VERB_SET_EAPD_BTLENABLE, 0x02); | ||
572 | } else if (IS_VT1709_10CH_VENDORID(codec->vendor_id) || | ||
573 | IS_VT1709_6CH_VENDORID(codec->vendor_id)) { | ||
574 | snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0, | ||
575 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
576 | PIN_OUT); | ||
577 | snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0, | ||
578 | AC_VERB_SET_EAPD_BTLENABLE, 0x02); | ||
579 | } else if (IS_VT1708B_8CH_VENDORID(codec->vendor_id) || | ||
580 | IS_VT1708B_4CH_VENDORID(codec->vendor_id)) { | ||
581 | snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0, | ||
582 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
583 | PIN_OUT); | ||
584 | snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0, | ||
585 | AC_VERB_SET_EAPD_BTLENABLE, 0x02); | ||
586 | } | ||
587 | } else /* enable SPDIF-input pin */ | ||
588 | snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0, | ||
589 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN); | ||
590 | |||
547 | return 0; | 591 | return 0; |
548 | } | 592 | } |
549 | 593 | ||
@@ -623,58 +667,68 @@ static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec, | |||
623 | if (i == AUTO_SEQ_CENLFE) { | 667 | if (i == AUTO_SEQ_CENLFE) { |
624 | /* Center/LFE */ | 668 | /* Center/LFE */ |
625 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | 669 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, |
626 | "Center Playback Volume", | 670 | "Center Playback Volume", |
627 | HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT)); | 671 | HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, |
672 | HDA_OUTPUT)); | ||
628 | if (err < 0) | 673 | if (err < 0) |
629 | return err; | 674 | return err; |
630 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | 675 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, |
631 | "LFE Playback Volume", | 676 | "LFE Playback Volume", |
632 | HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT)); | 677 | HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, |
678 | HDA_OUTPUT)); | ||
633 | if (err < 0) | 679 | if (err < 0) |
634 | return err; | 680 | return err; |
635 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | 681 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, |
636 | "Center Playback Switch", | 682 | "Center Playback Switch", |
637 | HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT)); | 683 | HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, |
684 | HDA_OUTPUT)); | ||
638 | if (err < 0) | 685 | if (err < 0) |
639 | return err; | 686 | return err; |
640 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | 687 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, |
641 | "LFE Playback Switch", | 688 | "LFE Playback Switch", |
642 | HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT)); | 689 | HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, |
690 | HDA_OUTPUT)); | ||
643 | if (err < 0) | 691 | if (err < 0) |
644 | return err; | 692 | return err; |
645 | } else if (i == AUTO_SEQ_FRONT){ | 693 | } else if (i == AUTO_SEQ_FRONT){ |
646 | /* add control to mixer index 0 */ | 694 | /* add control to mixer index 0 */ |
647 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | 695 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, |
648 | "Master Front Playback Volume", | 696 | "Master Front Playback Volume", |
649 | HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT)); | 697 | HDA_COMPOSE_AMP_VAL(0x17, 3, 0, |
698 | HDA_INPUT)); | ||
650 | if (err < 0) | 699 | if (err < 0) |
651 | return err; | 700 | return err; |
652 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | 701 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, |
653 | "Master Front Playback Switch", | 702 | "Master Front Playback Switch", |
654 | HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT)); | 703 | HDA_COMPOSE_AMP_VAL(0x17, 3, 0, |
704 | HDA_INPUT)); | ||
655 | if (err < 0) | 705 | if (err < 0) |
656 | return err; | 706 | return err; |
657 | 707 | ||
658 | /* add control to PW3 */ | 708 | /* add control to PW3 */ |
659 | sprintf(name, "%s Playback Volume", chname[i]); | 709 | sprintf(name, "%s Playback Volume", chname[i]); |
660 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | 710 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, |
661 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); | 711 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, |
712 | HDA_OUTPUT)); | ||
662 | if (err < 0) | 713 | if (err < 0) |
663 | return err; | 714 | return err; |
664 | sprintf(name, "%s Playback Switch", chname[i]); | 715 | sprintf(name, "%s Playback Switch", chname[i]); |
665 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | 716 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, |
666 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); | 717 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, |
718 | HDA_OUTPUT)); | ||
667 | if (err < 0) | 719 | if (err < 0) |
668 | return err; | 720 | return err; |
669 | } else { | 721 | } else { |
670 | sprintf(name, "%s Playback Volume", chname[i]); | 722 | sprintf(name, "%s Playback Volume", chname[i]); |
671 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | 723 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, |
672 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); | 724 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, |
725 | HDA_OUTPUT)); | ||
673 | if (err < 0) | 726 | if (err < 0) |
674 | return err; | 727 | return err; |
675 | sprintf(name, "%s Playback Switch", chname[i]); | 728 | sprintf(name, "%s Playback Switch", chname[i]); |
676 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | 729 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, |
677 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); | 730 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, |
731 | HDA_OUTPUT)); | ||
678 | if (err < 0) | 732 | if (err < 0) |
679 | return err; | 733 | return err; |
680 | } | 734 | } |
@@ -875,7 +929,6 @@ static struct snd_kcontrol_new vt1709_capture_mixer[] = { | |||
875 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 929 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
876 | /* The multiple "Capture Source" controls confuse alsamixer | 930 | /* The multiple "Capture Source" controls confuse alsamixer |
877 | * So call somewhat different.. | 931 | * So call somewhat different.. |
878 | * FIXME: the controls appear in the "playback" view! | ||
879 | */ | 932 | */ |
880 | /* .name = "Capture Source", */ | 933 | /* .name = "Capture Source", */ |
881 | .name = "Input Source", | 934 | .name = "Input Source", |
@@ -899,15 +952,15 @@ static struct hda_verb vt1709_10ch_volume_init_verbs[] = { | |||
899 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 952 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
900 | 953 | ||
901 | 954 | ||
902 | /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | 955 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback |
903 | * mixer widget | 956 | * mixer widget |
904 | */ | 957 | */ |
905 | /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ | 958 | /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ |
906 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* unmute master */ | 959 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
907 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | 960 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
908 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | 961 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, |
909 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | 962 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, |
910 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | 963 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, |
911 | 964 | ||
912 | /* | 965 | /* |
913 | * Set up output selector (0x1a, 0x1b, 0x29) | 966 | * Set up output selector (0x1a, 0x1b, 0x29) |
@@ -925,8 +978,6 @@ static struct hda_verb vt1709_10ch_volume_init_verbs[] = { | |||
925 | 978 | ||
926 | /* Set input of PW4 as AOW4 */ | 979 | /* Set input of PW4 as AOW4 */ |
927 | {0x20, AC_VERB_SET_CONNECT_SEL, 0x1}, | 980 | {0x20, AC_VERB_SET_CONNECT_SEL, 0x1}, |
928 | /* Set mic as default input of sw0 */ | ||
929 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x2}, | ||
930 | /* PW9 Output enable */ | 981 | /* PW9 Output enable */ |
931 | {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | 982 | {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, |
932 | { } | 983 | { } |
@@ -1073,68 +1124,80 @@ static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec, | |||
1073 | /* Center/LFE */ | 1124 | /* Center/LFE */ |
1074 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | 1125 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, |
1075 | "Center Playback Volume", | 1126 | "Center Playback Volume", |
1076 | HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT)); | 1127 | HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, |
1128 | HDA_OUTPUT)); | ||
1077 | if (err < 0) | 1129 | if (err < 0) |
1078 | return err; | 1130 | return err; |
1079 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | 1131 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, |
1080 | "LFE Playback Volume", | 1132 | "LFE Playback Volume", |
1081 | HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT)); | 1133 | HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, |
1134 | HDA_OUTPUT)); | ||
1082 | if (err < 0) | 1135 | if (err < 0) |
1083 | return err; | 1136 | return err; |
1084 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | 1137 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, |
1085 | "Center Playback Switch", | 1138 | "Center Playback Switch", |
1086 | HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT)); | 1139 | HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, |
1140 | HDA_OUTPUT)); | ||
1087 | if (err < 0) | 1141 | if (err < 0) |
1088 | return err; | 1142 | return err; |
1089 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | 1143 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, |
1090 | "LFE Playback Switch", | 1144 | "LFE Playback Switch", |
1091 | HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT)); | 1145 | HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, |
1146 | HDA_OUTPUT)); | ||
1092 | if (err < 0) | 1147 | if (err < 0) |
1093 | return err; | 1148 | return err; |
1094 | } else if (i == AUTO_SEQ_FRONT){ | 1149 | } else if (i == AUTO_SEQ_FRONT){ |
1095 | /* add control to mixer index 0 */ | 1150 | /* add control to mixer index 0 */ |
1096 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | 1151 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, |
1097 | "Master Front Playback Volume", | 1152 | "Master Front Playback Volume", |
1098 | HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT)); | 1153 | HDA_COMPOSE_AMP_VAL(0x18, 3, 0, |
1154 | HDA_INPUT)); | ||
1099 | if (err < 0) | 1155 | if (err < 0) |
1100 | return err; | 1156 | return err; |
1101 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | 1157 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, |
1102 | "Master Front Playback Switch", | 1158 | "Master Front Playback Switch", |
1103 | HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT)); | 1159 | HDA_COMPOSE_AMP_VAL(0x18, 3, 0, |
1160 | HDA_INPUT)); | ||
1104 | if (err < 0) | 1161 | if (err < 0) |
1105 | return err; | 1162 | return err; |
1106 | 1163 | ||
1107 | /* add control to PW3 */ | 1164 | /* add control to PW3 */ |
1108 | sprintf(name, "%s Playback Volume", chname[i]); | 1165 | sprintf(name, "%s Playback Volume", chname[i]); |
1109 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | 1166 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, |
1110 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); | 1167 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, |
1168 | HDA_OUTPUT)); | ||
1111 | if (err < 0) | 1169 | if (err < 0) |
1112 | return err; | 1170 | return err; |
1113 | sprintf(name, "%s Playback Switch", chname[i]); | 1171 | sprintf(name, "%s Playback Switch", chname[i]); |
1114 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | 1172 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, |
1115 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); | 1173 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, |
1174 | HDA_OUTPUT)); | ||
1116 | if (err < 0) | 1175 | if (err < 0) |
1117 | return err; | 1176 | return err; |
1118 | } else if (i == AUTO_SEQ_SURROUND) { | 1177 | } else if (i == AUTO_SEQ_SURROUND) { |
1119 | sprintf(name, "%s Playback Volume", chname[i]); | 1178 | sprintf(name, "%s Playback Volume", chname[i]); |
1120 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | 1179 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, |
1121 | HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT)); | 1180 | HDA_COMPOSE_AMP_VAL(0x29, 3, 0, |
1181 | HDA_OUTPUT)); | ||
1122 | if (err < 0) | 1182 | if (err < 0) |
1123 | return err; | 1183 | return err; |
1124 | sprintf(name, "%s Playback Switch", chname[i]); | 1184 | sprintf(name, "%s Playback Switch", chname[i]); |
1125 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | 1185 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, |
1126 | HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT)); | 1186 | HDA_COMPOSE_AMP_VAL(0x29, 3, 0, |
1187 | HDA_OUTPUT)); | ||
1127 | if (err < 0) | 1188 | if (err < 0) |
1128 | return err; | 1189 | return err; |
1129 | } else if (i == AUTO_SEQ_SIDE) { | 1190 | } else if (i == AUTO_SEQ_SIDE) { |
1130 | sprintf(name, "%s Playback Volume", chname[i]); | 1191 | sprintf(name, "%s Playback Volume", chname[i]); |
1131 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | 1192 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, |
1132 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT)); | 1193 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, |
1194 | HDA_OUTPUT)); | ||
1133 | if (err < 0) | 1195 | if (err < 0) |
1134 | return err; | 1196 | return err; |
1135 | sprintf(name, "%s Playback Switch", chname[i]); | 1197 | sprintf(name, "%s Playback Switch", chname[i]); |
1136 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | 1198 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, |
1137 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT)); | 1199 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, |
1200 | HDA_OUTPUT)); | ||
1138 | if (err < 0) | 1201 | if (err < 0) |
1139 | return err; | 1202 | return err; |
1140 | } | 1203 | } |
@@ -1351,8 +1414,6 @@ static struct hda_verb vt1709_6ch_volume_init_verbs[] = { | |||
1351 | 1414 | ||
1352 | /* Set input of PW4 as MW0 */ | 1415 | /* Set input of PW4 as MW0 */ |
1353 | {0x20, AC_VERB_SET_CONNECT_SEL, 0}, | 1416 | {0x20, AC_VERB_SET_CONNECT_SEL, 0}, |
1354 | /* Set mic as default input of sw0 */ | ||
1355 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x2}, | ||
1356 | /* PW9 Output enable */ | 1417 | /* PW9 Output enable */ |
1357 | {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | 1418 | {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, |
1358 | { } | 1419 | { } |
@@ -1403,6 +1464,494 @@ static int patch_vt1709_6ch(struct hda_codec *codec) | |||
1403 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 1464 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
1404 | spec->loopback.amplist = vt1709_loopbacks; | 1465 | spec->loopback.amplist = vt1709_loopbacks; |
1405 | #endif | 1466 | #endif |
1467 | return 0; | ||
1468 | } | ||
1469 | |||
1470 | /* capture mixer elements */ | ||
1471 | static struct snd_kcontrol_new vt1708B_capture_mixer[] = { | ||
1472 | HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT), | ||
1473 | HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT), | ||
1474 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT), | ||
1475 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT), | ||
1476 | { | ||
1477 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1478 | /* The multiple "Capture Source" controls confuse alsamixer | ||
1479 | * So call somewhat different.. | ||
1480 | */ | ||
1481 | /* .name = "Capture Source", */ | ||
1482 | .name = "Input Source", | ||
1483 | .count = 1, | ||
1484 | .info = via_mux_enum_info, | ||
1485 | .get = via_mux_enum_get, | ||
1486 | .put = via_mux_enum_put, | ||
1487 | }, | ||
1488 | { } /* end */ | ||
1489 | }; | ||
1490 | /* | ||
1491 | * generic initialization of ADC, input mixers and output mixers | ||
1492 | */ | ||
1493 | static struct hda_verb vt1708B_8ch_volume_init_verbs[] = { | ||
1494 | /* | ||
1495 | * Unmute ADC0-1 and set the default input to mic-in | ||
1496 | */ | ||
1497 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
1498 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
1499 | |||
1500 | |||
1501 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | ||
1502 | * mixer widget | ||
1503 | */ | ||
1504 | /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ | ||
1505 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
1506 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
1507 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
1508 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | ||
1509 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | ||
1510 | |||
1511 | /* | ||
1512 | * Set up output mixers | ||
1513 | */ | ||
1514 | /* set vol=0 to output mixers */ | ||
1515 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1516 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1517 | {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1518 | |||
1519 | /* Setup default input to PW4 */ | ||
1520 | {0x1d, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
1521 | /* PW9 Output enable */ | ||
1522 | {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
1523 | /* PW10 Input enable */ | ||
1524 | {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
1525 | { } | ||
1526 | }; | ||
1527 | |||
1528 | static struct hda_verb vt1708B_4ch_volume_init_verbs[] = { | ||
1529 | /* | ||
1530 | * Unmute ADC0-1 and set the default input to mic-in | ||
1531 | */ | ||
1532 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
1533 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
1534 | |||
1535 | |||
1536 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | ||
1537 | * mixer widget | ||
1538 | */ | ||
1539 | /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ | ||
1540 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
1541 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
1542 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
1543 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | ||
1544 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | ||
1545 | |||
1546 | /* | ||
1547 | * Set up output mixers | ||
1548 | */ | ||
1549 | /* set vol=0 to output mixers */ | ||
1550 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1551 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1552 | {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1553 | |||
1554 | /* Setup default input of PW4 to MW0 */ | ||
1555 | {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1556 | /* PW9 Output enable */ | ||
1557 | {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
1558 | /* PW10 Input enable */ | ||
1559 | {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
1560 | { } | ||
1561 | }; | ||
1562 | |||
1563 | static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = { | ||
1564 | .substreams = 1, | ||
1565 | .channels_min = 2, | ||
1566 | .channels_max = 8, | ||
1567 | .nid = 0x10, /* NID to query formats and rates */ | ||
1568 | .ops = { | ||
1569 | .open = via_playback_pcm_open, | ||
1570 | .prepare = via_playback_pcm_prepare, | ||
1571 | .cleanup = via_playback_pcm_cleanup | ||
1572 | }, | ||
1573 | }; | ||
1574 | |||
1575 | static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = { | ||
1576 | .substreams = 1, | ||
1577 | .channels_min = 2, | ||
1578 | .channels_max = 4, | ||
1579 | .nid = 0x10, /* NID to query formats and rates */ | ||
1580 | .ops = { | ||
1581 | .open = via_playback_pcm_open, | ||
1582 | .prepare = via_playback_pcm_prepare, | ||
1583 | .cleanup = via_playback_pcm_cleanup | ||
1584 | }, | ||
1585 | }; | ||
1586 | |||
1587 | static struct hda_pcm_stream vt1708B_pcm_analog_capture = { | ||
1588 | .substreams = 2, | ||
1589 | .channels_min = 2, | ||
1590 | .channels_max = 2, | ||
1591 | .nid = 0x13, /* NID to query formats and rates */ | ||
1592 | .ops = { | ||
1593 | .prepare = via_capture_pcm_prepare, | ||
1594 | .cleanup = via_capture_pcm_cleanup | ||
1595 | }, | ||
1596 | }; | ||
1597 | |||
1598 | static struct hda_pcm_stream vt1708B_pcm_digital_playback = { | ||
1599 | .substreams = 1, | ||
1600 | .channels_min = 2, | ||
1601 | .channels_max = 2, | ||
1602 | /* NID is set in via_build_pcms */ | ||
1603 | .ops = { | ||
1604 | .open = via_dig_playback_pcm_open, | ||
1605 | .close = via_dig_playback_pcm_close, | ||
1606 | .prepare = via_dig_playback_pcm_prepare | ||
1607 | }, | ||
1608 | }; | ||
1609 | |||
1610 | static struct hda_pcm_stream vt1708B_pcm_digital_capture = { | ||
1611 | .substreams = 1, | ||
1612 | .channels_min = 2, | ||
1613 | .channels_max = 2, | ||
1614 | }; | ||
1615 | |||
1616 | /* fill in the dac_nids table from the parsed pin configuration */ | ||
1617 | static int vt1708B_auto_fill_dac_nids(struct via_spec *spec, | ||
1618 | const struct auto_pin_cfg *cfg) | ||
1619 | { | ||
1620 | int i; | ||
1621 | hda_nid_t nid; | ||
1622 | |||
1623 | spec->multiout.num_dacs = cfg->line_outs; | ||
1624 | |||
1625 | spec->multiout.dac_nids = spec->private_dac_nids; | ||
1626 | |||
1627 | for (i = 0; i < 4; i++) { | ||
1628 | nid = cfg->line_out_pins[i]; | ||
1629 | if (nid) { | ||
1630 | /* config dac list */ | ||
1631 | switch (i) { | ||
1632 | case AUTO_SEQ_FRONT: | ||
1633 | spec->multiout.dac_nids[i] = 0x10; | ||
1634 | break; | ||
1635 | case AUTO_SEQ_CENLFE: | ||
1636 | spec->multiout.dac_nids[i] = 0x24; | ||
1637 | break; | ||
1638 | case AUTO_SEQ_SURROUND: | ||
1639 | spec->multiout.dac_nids[i] = 0x25; | ||
1640 | break; | ||
1641 | case AUTO_SEQ_SIDE: | ||
1642 | spec->multiout.dac_nids[i] = 0x11; | ||
1643 | break; | ||
1644 | } | ||
1645 | } | ||
1646 | } | ||
1647 | |||
1648 | return 0; | ||
1649 | } | ||
1650 | |||
1651 | /* add playback controls from the parsed DAC table */ | ||
1652 | static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec, | ||
1653 | const struct auto_pin_cfg *cfg) | ||
1654 | { | ||
1655 | char name[32]; | ||
1656 | static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; | ||
1657 | hda_nid_t nid_vols[] = {0x16, 0x27, 0x26, 0x18}; | ||
1658 | hda_nid_t nid, nid_vol = 0; | ||
1659 | int i, err; | ||
1660 | |||
1661 | for (i = 0; i <= AUTO_SEQ_SIDE; i++) { | ||
1662 | nid = cfg->line_out_pins[i]; | ||
1663 | |||
1664 | if (!nid) | ||
1665 | continue; | ||
1666 | |||
1667 | nid_vol = nid_vols[i]; | ||
1668 | |||
1669 | if (i == AUTO_SEQ_CENLFE) { | ||
1670 | /* Center/LFE */ | ||
1671 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
1672 | "Center Playback Volume", | ||
1673 | HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, | ||
1674 | HDA_OUTPUT)); | ||
1675 | if (err < 0) | ||
1676 | return err; | ||
1677 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
1678 | "LFE Playback Volume", | ||
1679 | HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, | ||
1680 | HDA_OUTPUT)); | ||
1681 | if (err < 0) | ||
1682 | return err; | ||
1683 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
1684 | "Center Playback Switch", | ||
1685 | HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, | ||
1686 | HDA_OUTPUT)); | ||
1687 | if (err < 0) | ||
1688 | return err; | ||
1689 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
1690 | "LFE Playback Switch", | ||
1691 | HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, | ||
1692 | HDA_OUTPUT)); | ||
1693 | if (err < 0) | ||
1694 | return err; | ||
1695 | } else if (i == AUTO_SEQ_FRONT) { | ||
1696 | /* add control to mixer index 0 */ | ||
1697 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
1698 | "Master Front Playback Volume", | ||
1699 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, | ||
1700 | HDA_INPUT)); | ||
1701 | if (err < 0) | ||
1702 | return err; | ||
1703 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
1704 | "Master Front Playback Switch", | ||
1705 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, | ||
1706 | HDA_INPUT)); | ||
1707 | if (err < 0) | ||
1708 | return err; | ||
1709 | |||
1710 | /* add control to PW3 */ | ||
1711 | sprintf(name, "%s Playback Volume", chname[i]); | ||
1712 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | ||
1713 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, | ||
1714 | HDA_OUTPUT)); | ||
1715 | if (err < 0) | ||
1716 | return err; | ||
1717 | sprintf(name, "%s Playback Switch", chname[i]); | ||
1718 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | ||
1719 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, | ||
1720 | HDA_OUTPUT)); | ||
1721 | if (err < 0) | ||
1722 | return err; | ||
1723 | } else { | ||
1724 | sprintf(name, "%s Playback Volume", chname[i]); | ||
1725 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | ||
1726 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, | ||
1727 | HDA_OUTPUT)); | ||
1728 | if (err < 0) | ||
1729 | return err; | ||
1730 | sprintf(name, "%s Playback Switch", chname[i]); | ||
1731 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | ||
1732 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, | ||
1733 | HDA_OUTPUT)); | ||
1734 | if (err < 0) | ||
1735 | return err; | ||
1736 | } | ||
1737 | } | ||
1738 | |||
1739 | return 0; | ||
1740 | } | ||
1741 | |||
1742 | static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) | ||
1743 | { | ||
1744 | int err; | ||
1745 | |||
1746 | if (!pin) | ||
1747 | return 0; | ||
1748 | |||
1749 | spec->multiout.hp_nid = VT1708B_HP_NID; /* AOW3 */ | ||
1750 | |||
1751 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
1752 | "Headphone Playback Volume", | ||
1753 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); | ||
1754 | if (err < 0) | ||
1755 | return err; | ||
1756 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
1757 | "Headphone Playback Switch", | ||
1758 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); | ||
1759 | if (err < 0) | ||
1760 | return err; | ||
1761 | |||
1762 | return 0; | ||
1763 | } | ||
1764 | |||
1765 | /* create playback/capture controls for input pins */ | ||
1766 | static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec, | ||
1767 | const struct auto_pin_cfg *cfg) | ||
1768 | { | ||
1769 | static char *labels[] = { | ||
1770 | "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL | ||
1771 | }; | ||
1772 | struct hda_input_mux *imux = &spec->private_imux; | ||
1773 | int i, err, idx = 0; | ||
1774 | |||
1775 | /* for internal loopback recording select */ | ||
1776 | imux->items[imux->num_items].label = "Stereo Mixer"; | ||
1777 | imux->items[imux->num_items].index = idx; | ||
1778 | imux->num_items++; | ||
1779 | |||
1780 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
1781 | if (!cfg->input_pins[i]) | ||
1782 | continue; | ||
1783 | |||
1784 | switch (cfg->input_pins[i]) { | ||
1785 | case 0x1a: /* Mic */ | ||
1786 | idx = 2; | ||
1787 | break; | ||
1788 | |||
1789 | case 0x1b: /* Line In */ | ||
1790 | idx = 3; | ||
1791 | break; | ||
1792 | |||
1793 | case 0x1e: /* Front Mic */ | ||
1794 | idx = 4; | ||
1795 | break; | ||
1796 | |||
1797 | case 0x1f: /* CD */ | ||
1798 | idx = 1; | ||
1799 | break; | ||
1800 | } | ||
1801 | err = via_new_analog_input(spec, cfg->input_pins[i], labels[i], | ||
1802 | idx, 0x16); | ||
1803 | if (err < 0) | ||
1804 | return err; | ||
1805 | imux->items[imux->num_items].label = labels[i]; | ||
1806 | imux->items[imux->num_items].index = idx; | ||
1807 | imux->num_items++; | ||
1808 | } | ||
1809 | return 0; | ||
1810 | } | ||
1811 | |||
1812 | static int vt1708B_parse_auto_config(struct hda_codec *codec) | ||
1813 | { | ||
1814 | struct via_spec *spec = codec->spec; | ||
1815 | int err; | ||
1816 | |||
1817 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); | ||
1818 | if (err < 0) | ||
1819 | return err; | ||
1820 | err = vt1708B_auto_fill_dac_nids(spec, &spec->autocfg); | ||
1821 | if (err < 0) | ||
1822 | return err; | ||
1823 | if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) | ||
1824 | return 0; /* can't find valid BIOS pin config */ | ||
1825 | |||
1826 | err = vt1708B_auto_create_multi_out_ctls(spec, &spec->autocfg); | ||
1827 | if (err < 0) | ||
1828 | return err; | ||
1829 | err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); | ||
1830 | if (err < 0) | ||
1831 | return err; | ||
1832 | err = vt1708B_auto_create_analog_input_ctls(spec, &spec->autocfg); | ||
1833 | if (err < 0) | ||
1834 | return err; | ||
1835 | |||
1836 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | ||
1837 | |||
1838 | if (spec->autocfg.dig_out_pin) | ||
1839 | spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID; | ||
1840 | if (spec->autocfg.dig_in_pin) | ||
1841 | spec->dig_in_nid = VT1708B_DIGIN_NID; | ||
1842 | |||
1843 | if (spec->kctl_alloc) | ||
1844 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; | ||
1845 | |||
1846 | spec->input_mux = &spec->private_imux; | ||
1847 | |||
1848 | return 1; | ||
1849 | } | ||
1850 | |||
1851 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1852 | static struct hda_amp_list vt1708B_loopbacks[] = { | ||
1853 | { 0x16, HDA_INPUT, 1 }, | ||
1854 | { 0x16, HDA_INPUT, 2 }, | ||
1855 | { 0x16, HDA_INPUT, 3 }, | ||
1856 | { 0x16, HDA_INPUT, 4 }, | ||
1857 | { } /* end */ | ||
1858 | }; | ||
1859 | #endif | ||
1860 | |||
1861 | static int patch_vt1708B_8ch(struct hda_codec *codec) | ||
1862 | { | ||
1863 | struct via_spec *spec; | ||
1864 | int err; | ||
1865 | |||
1866 | /* create a codec specific record */ | ||
1867 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | ||
1868 | if (spec == NULL) | ||
1869 | return -ENOMEM; | ||
1870 | |||
1871 | codec->spec = spec; | ||
1872 | |||
1873 | /* automatic parse from the BIOS config */ | ||
1874 | err = vt1708B_parse_auto_config(codec); | ||
1875 | if (err < 0) { | ||
1876 | via_free(codec); | ||
1877 | return err; | ||
1878 | } else if (!err) { | ||
1879 | printk(KERN_INFO "hda_codec: Cannot set up configuration " | ||
1880 | "from BIOS. Using genenic mode...\n"); | ||
1881 | } | ||
1882 | |||
1883 | spec->init_verbs = vt1708B_8ch_volume_init_verbs; | ||
1884 | |||
1885 | spec->stream_name_analog = "VT1708B Analog"; | ||
1886 | spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback; | ||
1887 | spec->stream_analog_capture = &vt1708B_pcm_analog_capture; | ||
1888 | |||
1889 | spec->stream_name_digital = "VT1708B Digital"; | ||
1890 | spec->stream_digital_playback = &vt1708B_pcm_digital_playback; | ||
1891 | spec->stream_digital_capture = &vt1708B_pcm_digital_capture; | ||
1892 | |||
1893 | if (!spec->adc_nids && spec->input_mux) { | ||
1894 | spec->adc_nids = vt1708B_adc_nids; | ||
1895 | spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids); | ||
1896 | spec->mixers[spec->num_mixers] = vt1708B_capture_mixer; | ||
1897 | spec->num_mixers++; | ||
1898 | } | ||
1899 | |||
1900 | codec->patch_ops = via_patch_ops; | ||
1901 | |||
1902 | codec->patch_ops.init = via_auto_init; | ||
1903 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1904 | spec->loopback.amplist = vt1708B_loopbacks; | ||
1905 | #endif | ||
1906 | |||
1907 | return 0; | ||
1908 | } | ||
1909 | |||
1910 | static int patch_vt1708B_4ch(struct hda_codec *codec) | ||
1911 | { | ||
1912 | struct via_spec *spec; | ||
1913 | int err; | ||
1914 | |||
1915 | /* create a codec specific record */ | ||
1916 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | ||
1917 | if (spec == NULL) | ||
1918 | return -ENOMEM; | ||
1919 | |||
1920 | codec->spec = spec; | ||
1921 | |||
1922 | /* automatic parse from the BIOS config */ | ||
1923 | err = vt1708B_parse_auto_config(codec); | ||
1924 | if (err < 0) { | ||
1925 | via_free(codec); | ||
1926 | return err; | ||
1927 | } else if (!err) { | ||
1928 | printk(KERN_INFO "hda_codec: Cannot set up configuration " | ||
1929 | "from BIOS. Using genenic mode...\n"); | ||
1930 | } | ||
1931 | |||
1932 | spec->init_verbs = vt1708B_4ch_volume_init_verbs; | ||
1933 | |||
1934 | spec->stream_name_analog = "VT1708B Analog"; | ||
1935 | spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback; | ||
1936 | spec->stream_analog_capture = &vt1708B_pcm_analog_capture; | ||
1937 | |||
1938 | spec->stream_name_digital = "VT1708B Digital"; | ||
1939 | spec->stream_digital_playback = &vt1708B_pcm_digital_playback; | ||
1940 | spec->stream_digital_capture = &vt1708B_pcm_digital_capture; | ||
1941 | |||
1942 | if (!spec->adc_nids && spec->input_mux) { | ||
1943 | spec->adc_nids = vt1708B_adc_nids; | ||
1944 | spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids); | ||
1945 | spec->mixers[spec->num_mixers] = vt1708B_capture_mixer; | ||
1946 | spec->num_mixers++; | ||
1947 | } | ||
1948 | |||
1949 | codec->patch_ops = via_patch_ops; | ||
1950 | |||
1951 | codec->patch_ops.init = via_auto_init; | ||
1952 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1953 | spec->loopback.amplist = vt1708B_loopbacks; | ||
1954 | #endif | ||
1406 | 1955 | ||
1407 | return 0; | 1956 | return 0; |
1408 | } | 1957 | } |
@@ -1415,13 +1964,37 @@ struct hda_codec_preset snd_hda_preset_via[] = { | |||
1415 | { .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708}, | 1964 | { .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708}, |
1416 | { .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708}, | 1965 | { .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708}, |
1417 | { .id = 0x1106170B, .name = "VIA VT1708", .patch = patch_vt1708}, | 1966 | { .id = 0x1106170B, .name = "VIA VT1708", .patch = patch_vt1708}, |
1418 | { .id = 0x1106E710, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch}, | 1967 | { .id = 0x1106E710, .name = "VIA VT1709 10-Ch", |
1419 | { .id = 0x1106E711, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch}, | 1968 | .patch = patch_vt1709_10ch}, |
1420 | { .id = 0x1106E712, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch}, | 1969 | { .id = 0x1106E711, .name = "VIA VT1709 10-Ch", |
1421 | { .id = 0x1106E713, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch}, | 1970 | .patch = patch_vt1709_10ch}, |
1422 | { .id = 0x1106E714, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch}, | 1971 | { .id = 0x1106E712, .name = "VIA VT1709 10-Ch", |
1423 | { .id = 0x1106E715, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch}, | 1972 | .patch = patch_vt1709_10ch}, |
1424 | { .id = 0x1106E716, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch}, | 1973 | { .id = 0x1106E713, .name = "VIA VT1709 10-Ch", |
1425 | { .id = 0x1106E717, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch}, | 1974 | .patch = patch_vt1709_10ch}, |
1975 | { .id = 0x1106E714, .name = "VIA VT1709 6-Ch", | ||
1976 | .patch = patch_vt1709_6ch}, | ||
1977 | { .id = 0x1106E715, .name = "VIA VT1709 6-Ch", | ||
1978 | .patch = patch_vt1709_6ch}, | ||
1979 | { .id = 0x1106E716, .name = "VIA VT1709 6-Ch", | ||
1980 | .patch = patch_vt1709_6ch}, | ||
1981 | { .id = 0x1106E717, .name = "VIA VT1709 6-Ch", | ||
1982 | .patch = patch_vt1709_6ch}, | ||
1983 | { .id = 0x1106E720, .name = "VIA VT1708B 8-Ch", | ||
1984 | .patch = patch_vt1708B_8ch}, | ||
1985 | { .id = 0x1106E721, .name = "VIA VT1708B 8-Ch", | ||
1986 | .patch = patch_vt1708B_8ch}, | ||
1987 | { .id = 0x1106E722, .name = "VIA VT1708B 8-Ch", | ||
1988 | .patch = patch_vt1708B_8ch}, | ||
1989 | { .id = 0x1106E723, .name = "VIA VT1708B 8-Ch", | ||
1990 | .patch = patch_vt1708B_8ch}, | ||
1991 | { .id = 0x1106E724, .name = "VIA VT1708B 4-Ch", | ||
1992 | .patch = patch_vt1708B_4ch}, | ||
1993 | { .id = 0x1106E725, .name = "VIA VT1708B 4-Ch", | ||
1994 | .patch = patch_vt1708B_4ch}, | ||
1995 | { .id = 0x1106E726, .name = "VIA VT1708B 4-Ch", | ||
1996 | .patch = patch_vt1708B_4ch}, | ||
1997 | { .id = 0x1106E727, .name = "VIA VT1708B 4-Ch", | ||
1998 | .patch = patch_vt1708B_4ch}, | ||
1426 | {} /* terminator */ | 1999 | {} /* terminator */ |
1427 | }; | 2000 | }; |
diff --git a/sound/pci/hda/vmaster.c b/sound/pci/hda/vmaster.c new file mode 100644 index 000000000000..2da49d20a1fc --- /dev/null +++ b/sound/pci/hda/vmaster.c | |||
@@ -0,0 +1,364 @@ | |||
1 | /* | ||
2 | * Virtual master and slave controls | ||
3 | * | ||
4 | * Copyright (c) 2008 by Takashi Iwai <tiwai@suse.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation, version 2. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/slab.h> | ||
13 | #include <sound/core.h> | ||
14 | #include <sound/control.h> | ||
15 | |||
16 | /* | ||
17 | * a subset of information returned via ctl info callback | ||
18 | */ | ||
19 | struct link_ctl_info { | ||
20 | int type; /* value type */ | ||
21 | int count; /* item count */ | ||
22 | int min_val, max_val; /* min, max values */ | ||
23 | }; | ||
24 | |||
25 | /* | ||
26 | * link master - this contains a list of slave controls that are | ||
27 | * identical types, i.e. info returns the same value type and value | ||
28 | * ranges, but may have different number of counts. | ||
29 | * | ||
30 | * The master control is so far only mono volume/switch for simplicity. | ||
31 | * The same value will be applied to all slaves. | ||
32 | */ | ||
33 | struct link_master { | ||
34 | struct list_head slaves; | ||
35 | struct link_ctl_info info; | ||
36 | int val; /* the master value */ | ||
37 | }; | ||
38 | |||
39 | /* | ||
40 | * link slave - this contains a slave control element | ||
41 | * | ||
42 | * It fakes the control callbacsk with additional attenuation by the | ||
43 | * master control. A slave may have either one or two channels. | ||
44 | */ | ||
45 | |||
46 | struct link_slave { | ||
47 | struct list_head list; | ||
48 | struct link_master *master; | ||
49 | struct link_ctl_info info; | ||
50 | int vals[2]; /* current values */ | ||
51 | struct snd_kcontrol slave; /* the copy of original control entry */ | ||
52 | }; | ||
53 | |||
54 | /* get the slave ctl info and save the initial values */ | ||
55 | static int slave_init(struct link_slave *slave) | ||
56 | { | ||
57 | struct snd_ctl_elem_info *uinfo; | ||
58 | struct snd_ctl_elem_value *uctl; | ||
59 | int err, ch; | ||
60 | |||
61 | if (slave->info.count) | ||
62 | return 0; /* already initialized */ | ||
63 | |||
64 | uinfo = kmalloc(sizeof(*uinfo), GFP_KERNEL); | ||
65 | if (!uinfo) | ||
66 | return -ENOMEM; | ||
67 | uinfo->id = slave->slave.id; | ||
68 | err = slave->slave.info(&slave->slave, uinfo); | ||
69 | if (err < 0) { | ||
70 | kfree(uinfo); | ||
71 | return err; | ||
72 | } | ||
73 | slave->info.type = uinfo->type; | ||
74 | slave->info.count = uinfo->count; | ||
75 | if (slave->info.count > 2 || | ||
76 | (slave->info.type != SNDRV_CTL_ELEM_TYPE_INTEGER && | ||
77 | slave->info.type != SNDRV_CTL_ELEM_TYPE_BOOLEAN)) { | ||
78 | snd_printk(KERN_ERR "invalid slave element\n"); | ||
79 | kfree(uinfo); | ||
80 | return -EINVAL; | ||
81 | } | ||
82 | slave->info.min_val = uinfo->value.integer.min; | ||
83 | slave->info.max_val = uinfo->value.integer.max; | ||
84 | kfree(uinfo); | ||
85 | |||
86 | uctl = kmalloc(sizeof(*uctl), GFP_KERNEL); | ||
87 | if (!uctl) | ||
88 | return -ENOMEM; | ||
89 | uctl->id = slave->slave.id; | ||
90 | err = slave->slave.get(&slave->slave, uctl); | ||
91 | for (ch = 0; ch < slave->info.count; ch++) | ||
92 | slave->vals[ch] = uctl->value.integer.value[ch]; | ||
93 | kfree(uctl); | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | /* initialize master volume */ | ||
98 | static int master_init(struct link_master *master) | ||
99 | { | ||
100 | struct link_slave *slave; | ||
101 | |||
102 | if (master->info.count) | ||
103 | return 0; /* already initialized */ | ||
104 | |||
105 | list_for_each_entry(slave, &master->slaves, list) { | ||
106 | int err = slave_init(slave); | ||
107 | if (err < 0) | ||
108 | return err; | ||
109 | master->info = slave->info; | ||
110 | master->info.count = 1; /* always mono */ | ||
111 | /* set full volume as default (= no attenuation) */ | ||
112 | master->val = master->info.max_val; | ||
113 | return 0; | ||
114 | } | ||
115 | return -ENOENT; | ||
116 | } | ||
117 | |||
118 | static int slave_get_val(struct link_slave *slave, | ||
119 | struct snd_ctl_elem_value *ucontrol) | ||
120 | { | ||
121 | int err, ch; | ||
122 | |||
123 | err = slave_init(slave); | ||
124 | if (err < 0) | ||
125 | return err; | ||
126 | for (ch = 0; ch < slave->info.count; ch++) | ||
127 | ucontrol->value.integer.value[ch] = slave->vals[ch]; | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int slave_put_val(struct link_slave *slave, | ||
132 | struct snd_ctl_elem_value *ucontrol) | ||
133 | { | ||
134 | int err, ch, vol; | ||
135 | |||
136 | err = master_init(slave->master); | ||
137 | if (err < 0) | ||
138 | return err; | ||
139 | |||
140 | switch (slave->info.type) { | ||
141 | case SNDRV_CTL_ELEM_TYPE_BOOLEAN: | ||
142 | for (ch = 0; ch < slave->info.count; ch++) | ||
143 | ucontrol->value.integer.value[ch] &= | ||
144 | !!slave->master->val; | ||
145 | break; | ||
146 | case SNDRV_CTL_ELEM_TYPE_INTEGER: | ||
147 | for (ch = 0; ch < slave->info.count; ch++) { | ||
148 | /* max master volume is supposed to be 0 dB */ | ||
149 | vol = ucontrol->value.integer.value[ch]; | ||
150 | vol += slave->master->val - slave->master->info.max_val; | ||
151 | if (vol < slave->info.min_val) | ||
152 | vol = slave->info.min_val; | ||
153 | else if (vol > slave->info.max_val) | ||
154 | vol = slave->info.max_val; | ||
155 | ucontrol->value.integer.value[ch] = vol; | ||
156 | } | ||
157 | break; | ||
158 | } | ||
159 | return slave->slave.put(&slave->slave, ucontrol); | ||
160 | } | ||
161 | |||
162 | /* | ||
163 | * ctl callbacks for slaves | ||
164 | */ | ||
165 | static int slave_info(struct snd_kcontrol *kcontrol, | ||
166 | struct snd_ctl_elem_info *uinfo) | ||
167 | { | ||
168 | struct link_slave *slave = snd_kcontrol_chip(kcontrol); | ||
169 | return slave->slave.info(&slave->slave, uinfo); | ||
170 | } | ||
171 | |||
172 | static int slave_get(struct snd_kcontrol *kcontrol, | ||
173 | struct snd_ctl_elem_value *ucontrol) | ||
174 | { | ||
175 | struct link_slave *slave = snd_kcontrol_chip(kcontrol); | ||
176 | return slave_get_val(slave, ucontrol); | ||
177 | } | ||
178 | |||
179 | static int slave_put(struct snd_kcontrol *kcontrol, | ||
180 | struct snd_ctl_elem_value *ucontrol) | ||
181 | { | ||
182 | struct link_slave *slave = snd_kcontrol_chip(kcontrol); | ||
183 | int err, ch, changed = 0; | ||
184 | |||
185 | err = slave_init(slave); | ||
186 | if (err < 0) | ||
187 | return err; | ||
188 | for (ch = 0; ch < slave->info.count; ch++) { | ||
189 | if (slave->vals[ch] != ucontrol->value.integer.value[ch]) { | ||
190 | changed = 1; | ||
191 | slave->vals[ch] = ucontrol->value.integer.value[ch]; | ||
192 | } | ||
193 | } | ||
194 | if (!changed) | ||
195 | return 0; | ||
196 | return slave_put_val(slave, ucontrol); | ||
197 | } | ||
198 | |||
199 | static int slave_tlv_cmd(struct snd_kcontrol *kcontrol, | ||
200 | int op_flag, unsigned int size, | ||
201 | unsigned int __user *tlv) | ||
202 | { | ||
203 | struct link_slave *slave = snd_kcontrol_chip(kcontrol); | ||
204 | /* FIXME: this assumes that the max volume is 0 dB */ | ||
205 | return slave->slave.tlv.c(&slave->slave, op_flag, size, tlv); | ||
206 | } | ||
207 | |||
208 | static void slave_free(struct snd_kcontrol *kcontrol) | ||
209 | { | ||
210 | struct link_slave *slave = snd_kcontrol_chip(kcontrol); | ||
211 | if (slave->slave.private_free) | ||
212 | slave->slave.private_free(&slave->slave); | ||
213 | if (slave->master) | ||
214 | list_del(&slave->list); | ||
215 | kfree(slave); | ||
216 | } | ||
217 | |||
218 | /* | ||
219 | * Add a slave control to the group with the given master control | ||
220 | * | ||
221 | * All slaves must be the same type (returning the same information | ||
222 | * via info callback). The fucntion doesn't check it, so it's your | ||
223 | * responsibility. | ||
224 | * | ||
225 | * Also, some additional limitations: | ||
226 | * - at most two channels | ||
227 | * - logarithmic volume control (dB level), no linear volume | ||
228 | * - master can only attenuate the volume, no gain | ||
229 | */ | ||
230 | int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave) | ||
231 | { | ||
232 | struct link_master *master_link = snd_kcontrol_chip(master); | ||
233 | struct link_slave *srec; | ||
234 | |||
235 | srec = kzalloc(sizeof(*srec) + | ||
236 | slave->count * sizeof(*slave->vd), GFP_KERNEL); | ||
237 | if (!srec) | ||
238 | return -ENOMEM; | ||
239 | srec->slave = *slave; | ||
240 | memcpy(srec->slave.vd, slave->vd, slave->count * sizeof(*slave->vd)); | ||
241 | srec->master = master_link; | ||
242 | |||
243 | /* override callbacks */ | ||
244 | slave->info = slave_info; | ||
245 | slave->get = slave_get; | ||
246 | slave->put = slave_put; | ||
247 | if (slave->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) | ||
248 | slave->tlv.c = slave_tlv_cmd; | ||
249 | slave->private_data = srec; | ||
250 | slave->private_free = slave_free; | ||
251 | |||
252 | list_add_tail(&srec->list, &master_link->slaves); | ||
253 | return 0; | ||
254 | } | ||
255 | |||
256 | /* | ||
257 | * ctl callbacks for master controls | ||
258 | */ | ||
259 | static int master_info(struct snd_kcontrol *kcontrol, | ||
260 | struct snd_ctl_elem_info *uinfo) | ||
261 | { | ||
262 | struct link_master *master = snd_kcontrol_chip(kcontrol); | ||
263 | int ret; | ||
264 | |||
265 | ret = master_init(master); | ||
266 | if (ret < 0) | ||
267 | return ret; | ||
268 | uinfo->type = master->info.type; | ||
269 | uinfo->count = master->info.count; | ||
270 | uinfo->value.integer.min = master->info.min_val; | ||
271 | uinfo->value.integer.max = master->info.max_val; | ||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | static int master_get(struct snd_kcontrol *kcontrol, | ||
276 | struct snd_ctl_elem_value *ucontrol) | ||
277 | { | ||
278 | struct link_master *master = snd_kcontrol_chip(kcontrol); | ||
279 | int err = master_init(master); | ||
280 | if (err < 0) | ||
281 | return err; | ||
282 | ucontrol->value.integer.value[0] = master->val; | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | static int master_put(struct snd_kcontrol *kcontrol, | ||
287 | struct snd_ctl_elem_value *ucontrol) | ||
288 | { | ||
289 | struct link_master *master = snd_kcontrol_chip(kcontrol); | ||
290 | struct link_slave *slave; | ||
291 | struct snd_ctl_elem_value *uval; | ||
292 | int err, old_val; | ||
293 | |||
294 | err = master_init(master); | ||
295 | if (err < 0) | ||
296 | return err; | ||
297 | old_val = master->val; | ||
298 | if (ucontrol->value.integer.value[0] == old_val) | ||
299 | return 0; | ||
300 | |||
301 | uval = kmalloc(sizeof(*uval), GFP_KERNEL); | ||
302 | if (!uval) | ||
303 | return -ENOMEM; | ||
304 | list_for_each_entry(slave, &master->slaves, list) { | ||
305 | master->val = old_val; | ||
306 | uval->id = slave->slave.id; | ||
307 | slave_get_val(slave, uval); | ||
308 | master->val = ucontrol->value.integer.value[0]; | ||
309 | slave_put_val(slave, uval); | ||
310 | } | ||
311 | kfree(uval); | ||
312 | return 1; | ||
313 | } | ||
314 | |||
315 | static void master_free(struct snd_kcontrol *kcontrol) | ||
316 | { | ||
317 | struct link_master *master = snd_kcontrol_chip(kcontrol); | ||
318 | struct link_slave *slave; | ||
319 | |||
320 | list_for_each_entry(slave, &master->slaves, list) | ||
321 | slave->master = NULL; | ||
322 | kfree(master); | ||
323 | } | ||
324 | |||
325 | |||
326 | /* | ||
327 | * Create a virtual master control with the given name | ||
328 | */ | ||
329 | struct snd_kcontrol *snd_ctl_make_virtual_master(char *name, | ||
330 | const unsigned int *tlv) | ||
331 | { | ||
332 | struct link_master *master; | ||
333 | struct snd_kcontrol *kctl; | ||
334 | struct snd_kcontrol_new knew; | ||
335 | |||
336 | memset(&knew, 0, sizeof(knew)); | ||
337 | knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
338 | knew.name = name; | ||
339 | knew.info = master_info; | ||
340 | |||
341 | master = kzalloc(sizeof(*master), GFP_KERNEL); | ||
342 | if (!master) | ||
343 | return NULL; | ||
344 | INIT_LIST_HEAD(&master->slaves); | ||
345 | |||
346 | kctl = snd_ctl_new1(&knew, master); | ||
347 | if (!kctl) { | ||
348 | kfree(master); | ||
349 | return NULL; | ||
350 | } | ||
351 | /* override some callbacks */ | ||
352 | kctl->info = master_info; | ||
353 | kctl->get = master_get; | ||
354 | kctl->put = master_put; | ||
355 | kctl->private_free = master_free; | ||
356 | |||
357 | /* additional (constant) TLV read */ | ||
358 | if (tlv) { | ||
359 | /* FIXME: this assumes that the max volume is 0 dB */ | ||
360 | kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
361 | kctl->tlv.p = tlv; | ||
362 | } | ||
363 | return kctl; | ||
364 | } | ||
diff --git a/sound/pci/ice1712/Makefile b/sound/pci/ice1712/Makefile index 65ce66adba5a..f99fe089495d 100644 --- a/sound/pci/ice1712/Makefile +++ b/sound/pci/ice1712/Makefile | |||
@@ -5,7 +5,7 @@ | |||
5 | 5 | ||
6 | snd-ice17xx-ak4xxx-objs := ak4xxx.o | 6 | snd-ice17xx-ak4xxx-objs := ak4xxx.o |
7 | snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o | 7 | snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o |
8 | snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o juli.o phase.o wtm.o | 8 | snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o prodigy_hifi.o juli.o phase.o wtm.o se.o |
9 | 9 | ||
10 | # Toplevel Module Dependency | 10 | # Toplevel Module Dependency |
11 | obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o | 11 | obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o |
diff --git a/sound/pci/ice1712/ak4xxx.c b/sound/pci/ice1712/ak4xxx.c index a1aba0d7d0e4..dab31b2756a6 100644 --- a/sound/pci/ice1712/ak4xxx.c +++ b/sound/pci/ice1712/ak4xxx.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <asm/io.h> | 24 | #include <asm/io.h> |
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
27 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
diff --git a/sound/pci/ice1712/amp.c b/sound/pci/ice1712/amp.c index 6e13d758bb5d..37564300b50d 100644 --- a/sound/pci/ice1712/amp.c +++ b/sound/pci/ice1712/amp.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <asm/io.h> | 24 | #include <asm/io.h> |
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
27 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c index ec0699c89952..868ae291b960 100644 --- a/sound/pci/ice1712/aureon.c +++ b/sound/pci/ice1712/aureon.c | |||
@@ -47,7 +47,6 @@ | |||
47 | * | 47 | * |
48 | */ | 48 | */ |
49 | 49 | ||
50 | #include <sound/driver.h> | ||
51 | #include <asm/io.h> | 50 | #include <asm/io.h> |
52 | #include <linux/delay.h> | 51 | #include <linux/delay.h> |
53 | #include <linux/interrupt.h> | 52 | #include <linux/interrupt.h> |
@@ -62,6 +61,15 @@ | |||
62 | #include "aureon.h" | 61 | #include "aureon.h" |
63 | #include <sound/tlv.h> | 62 | #include <sound/tlv.h> |
64 | 63 | ||
64 | /* AC97 register cache for Aureon */ | ||
65 | struct aureon_spec { | ||
66 | unsigned short stac9744[64]; | ||
67 | unsigned int cs8415_mux; | ||
68 | unsigned short master[2]; | ||
69 | unsigned short vol[8]; | ||
70 | unsigned char pca9554_out; | ||
71 | }; | ||
72 | |||
65 | /* WM8770 registers */ | 73 | /* WM8770 registers */ |
66 | #define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */ | 74 | #define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */ |
67 | #define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */ | 75 | #define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */ |
@@ -205,7 +213,8 @@ static int aureon_universe_inmux_get(struct snd_kcontrol *kcontrol, | |||
205 | struct snd_ctl_elem_value *ucontrol) | 213 | struct snd_ctl_elem_value *ucontrol) |
206 | { | 214 | { |
207 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 215 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
208 | ucontrol->value.integer.value[0] = ice->spec.aureon.pca9554_out; | 216 | struct aureon_spec *spec = ice->spec; |
217 | ucontrol->value.enumerated.item[0] = spec->pca9554_out; | ||
209 | return 0; | 218 | return 0; |
210 | } | 219 | } |
211 | 220 | ||
@@ -213,16 +222,18 @@ static int aureon_universe_inmux_put(struct snd_kcontrol *kcontrol, | |||
213 | struct snd_ctl_elem_value *ucontrol) | 222 | struct snd_ctl_elem_value *ucontrol) |
214 | { | 223 | { |
215 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 224 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
225 | struct aureon_spec *spec = ice->spec; | ||
216 | unsigned char oval, nval; | 226 | unsigned char oval, nval; |
217 | int change; | 227 | int change; |
218 | 228 | ||
229 | nval = ucontrol->value.enumerated.item[0]; | ||
230 | if (nval >= 3) | ||
231 | return -EINVAL; | ||
219 | snd_ice1712_save_gpio_status(ice); | 232 | snd_ice1712_save_gpio_status(ice); |
220 | 233 | oval = spec->pca9554_out; | |
221 | oval = ice->spec.aureon.pca9554_out; | ||
222 | nval = ucontrol->value.integer.value[0]; | ||
223 | if ((change = (oval != nval))) { | 234 | if ((change = (oval != nval))) { |
224 | aureon_pca9554_write(ice, PCA9554_OUT, nval); | 235 | aureon_pca9554_write(ice, PCA9554_OUT, nval); |
225 | ice->spec.aureon.pca9554_out = nval; | 236 | spec->pca9554_out = nval; |
226 | } | 237 | } |
227 | snd_ice1712_restore_gpio_status(ice); | 238 | snd_ice1712_restore_gpio_status(ice); |
228 | 239 | ||
@@ -233,6 +244,7 @@ static int aureon_universe_inmux_put(struct snd_kcontrol *kcontrol, | |||
233 | static void aureon_ac97_write(struct snd_ice1712 *ice, unsigned short reg, | 244 | static void aureon_ac97_write(struct snd_ice1712 *ice, unsigned short reg, |
234 | unsigned short val) | 245 | unsigned short val) |
235 | { | 246 | { |
247 | struct aureon_spec *spec = ice->spec; | ||
236 | unsigned int tmp; | 248 | unsigned int tmp; |
237 | 249 | ||
238 | /* Send address to XILINX chip */ | 250 | /* Send address to XILINX chip */ |
@@ -280,12 +292,13 @@ static void aureon_ac97_write(struct snd_ice1712 *ice, unsigned short reg, | |||
280 | udelay(10); | 292 | udelay(10); |
281 | 293 | ||
282 | /* Store the data in out private buffer */ | 294 | /* Store the data in out private buffer */ |
283 | ice->spec.aureon.stac9744[(reg & 0x7F) >> 1] = val; | 295 | spec->stac9744[(reg & 0x7F) >> 1] = val; |
284 | } | 296 | } |
285 | 297 | ||
286 | static unsigned short aureon_ac97_read(struct snd_ice1712 *ice, unsigned short reg) | 298 | static unsigned short aureon_ac97_read(struct snd_ice1712 *ice, unsigned short reg) |
287 | { | 299 | { |
288 | return ice->spec.aureon.stac9744[(reg & 0x7F) >> 1]; | 300 | struct aureon_spec *spec = ice->spec; |
301 | return spec->stac9744[(reg & 0x7F) >> 1]; | ||
289 | } | 302 | } |
290 | 303 | ||
291 | /* | 304 | /* |
@@ -293,6 +306,7 @@ static unsigned short aureon_ac97_read(struct snd_ice1712 *ice, unsigned short r | |||
293 | */ | 306 | */ |
294 | static int aureon_ac97_init (struct snd_ice1712 *ice) | 307 | static int aureon_ac97_init (struct snd_ice1712 *ice) |
295 | { | 308 | { |
309 | struct aureon_spec *spec = ice->spec; | ||
296 | int i; | 310 | int i; |
297 | static const unsigned short ac97_defaults[] = { | 311 | static const unsigned short ac97_defaults[] = { |
298 | 0x00, 0x9640, | 312 | 0x00, 0x9640, |
@@ -330,9 +344,9 @@ static int aureon_ac97_init (struct snd_ice1712 *ice) | |||
330 | snd_ice1712_gpio_write(ice, tmp); | 344 | snd_ice1712_gpio_write(ice, tmp); |
331 | udelay(3); | 345 | udelay(3); |
332 | 346 | ||
333 | memset(&ice->spec.aureon.stac9744, 0, sizeof(ice->spec.aureon.stac9744)); | 347 | memset(&spec->stac9744, 0, sizeof(spec->stac9744)); |
334 | for (i=0; ac97_defaults[i] != (unsigned short)-1; i+=2) | 348 | for (i=0; ac97_defaults[i] != (unsigned short)-1; i+=2) |
335 | ice->spec.aureon.stac9744[(ac97_defaults[i]) >> 1] = ac97_defaults[i+1]; | 349 | spec->stac9744[(ac97_defaults[i]) >> 1] = ac97_defaults[i+1]; |
336 | 350 | ||
337 | aureon_ac97_write(ice, AC97_MASTER, 0x0000); // Unmute AC'97 master volume permanently - muting is done by WM8770 | 351 | aureon_ac97_write(ice, AC97_MASTER, 0x0000); // Unmute AC'97 master volume permanently - muting is done by WM8770 |
338 | 352 | ||
@@ -744,27 +758,33 @@ static int wm_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem | |||
744 | static int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 758 | static int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
745 | { | 759 | { |
746 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 760 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
761 | struct aureon_spec *spec = ice->spec; | ||
747 | int i; | 762 | int i; |
748 | for (i=0; i<2; i++) | 763 | for (i=0; i<2; i++) |
749 | ucontrol->value.integer.value[i] = ice->spec.aureon.master[i] & ~WM_VOL_MUTE; | 764 | ucontrol->value.integer.value[i] = |
765 | spec->master[i] & ~WM_VOL_MUTE; | ||
750 | return 0; | 766 | return 0; |
751 | } | 767 | } |
752 | 768 | ||
753 | static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 769 | static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
754 | { | 770 | { |
755 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 771 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
772 | struct aureon_spec *spec = ice->spec; | ||
756 | int ch, change = 0; | 773 | int ch, change = 0; |
757 | 774 | ||
758 | snd_ice1712_save_gpio_status(ice); | 775 | snd_ice1712_save_gpio_status(ice); |
759 | for (ch = 0; ch < 2; ch++) { | 776 | for (ch = 0; ch < 2; ch++) { |
760 | if (ucontrol->value.integer.value[ch] != ice->spec.aureon.master[ch]) { | 777 | unsigned int vol = ucontrol->value.integer.value[ch]; |
778 | if (vol > WM_VOL_MAX) | ||
779 | continue; | ||
780 | vol |= spec->master[ch] & WM_VOL_MUTE; | ||
781 | if (vol != spec->master[ch]) { | ||
761 | int dac; | 782 | int dac; |
762 | ice->spec.aureon.master[ch] &= WM_VOL_MUTE; | 783 | spec->master[ch] = vol; |
763 | ice->spec.aureon.master[ch] |= ucontrol->value.integer.value[ch]; | ||
764 | for (dac = 0; dac < ice->num_total_dacs; dac += 2) | 784 | for (dac = 0; dac < ice->num_total_dacs; dac += 2) |
765 | wm_set_vol(ice, WM_DAC_ATTEN + dac + ch, | 785 | wm_set_vol(ice, WM_DAC_ATTEN + dac + ch, |
766 | ice->spec.aureon.vol[dac + ch], | 786 | spec->vol[dac + ch], |
767 | ice->spec.aureon.master[ch]); | 787 | spec->master[ch]); |
768 | change = 1; | 788 | change = 1; |
769 | } | 789 | } |
770 | } | 790 | } |
@@ -788,18 +808,21 @@ static int wm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info * | |||
788 | static int wm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 808 | static int wm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
789 | { | 809 | { |
790 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 810 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
811 | struct aureon_spec *spec = ice->spec; | ||
791 | int i, ofs, voices; | 812 | int i, ofs, voices; |
792 | 813 | ||
793 | voices = kcontrol->private_value >> 8; | 814 | voices = kcontrol->private_value >> 8; |
794 | ofs = kcontrol->private_value & 0xff; | 815 | ofs = kcontrol->private_value & 0xff; |
795 | for (i = 0; i < voices; i++) | 816 | for (i = 0; i < voices; i++) |
796 | ucontrol->value.integer.value[i] = ice->spec.aureon.vol[ofs+i] & ~WM_VOL_MUTE; | 817 | ucontrol->value.integer.value[i] = |
818 | spec->vol[ofs+i] & ~WM_VOL_MUTE; | ||
797 | return 0; | 819 | return 0; |
798 | } | 820 | } |
799 | 821 | ||
800 | static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 822 | static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
801 | { | 823 | { |
802 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 824 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
825 | struct aureon_spec *spec = ice->spec; | ||
803 | int i, idx, ofs, voices; | 826 | int i, idx, ofs, voices; |
804 | int change = 0; | 827 | int change = 0; |
805 | 828 | ||
@@ -807,12 +830,15 @@ static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value * | |||
807 | ofs = kcontrol->private_value & 0xff; | 830 | ofs = kcontrol->private_value & 0xff; |
808 | snd_ice1712_save_gpio_status(ice); | 831 | snd_ice1712_save_gpio_status(ice); |
809 | for (i = 0; i < voices; i++) { | 832 | for (i = 0; i < voices; i++) { |
810 | idx = WM_DAC_ATTEN + ofs + i; | 833 | unsigned int vol = ucontrol->value.integer.value[i]; |
811 | if (ucontrol->value.integer.value[i] != ice->spec.aureon.vol[ofs+i]) { | 834 | if (vol > 0x7f) |
812 | ice->spec.aureon.vol[ofs+i] &= WM_VOL_MUTE; | 835 | continue; |
813 | ice->spec.aureon.vol[ofs+i] |= ucontrol->value.integer.value[i]; | 836 | vol |= spec->vol[ofs+i]; |
814 | wm_set_vol(ice, idx, ice->spec.aureon.vol[ofs+i], | 837 | if (vol != spec->vol[ofs+i]) { |
815 | ice->spec.aureon.master[i]); | 838 | spec->vol[ofs+i] = vol; |
839 | idx = WM_DAC_ATTEN + ofs + i; | ||
840 | wm_set_vol(ice, idx, spec->vol[ofs + i], | ||
841 | spec->master[i]); | ||
816 | change = 1; | 842 | change = 1; |
817 | } | 843 | } |
818 | } | 844 | } |
@@ -834,19 +860,22 @@ static int wm_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info | |||
834 | static int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 860 | static int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
835 | { | 861 | { |
836 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 862 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
863 | struct aureon_spec *spec = ice->spec; | ||
837 | int voices, ofs, i; | 864 | int voices, ofs, i; |
838 | 865 | ||
839 | voices = kcontrol->private_value >> 8; | 866 | voices = kcontrol->private_value >> 8; |
840 | ofs = kcontrol->private_value & 0xFF; | 867 | ofs = kcontrol->private_value & 0xFF; |
841 | 868 | ||
842 | for (i = 0; i < voices; i++) | 869 | for (i = 0; i < voices; i++) |
843 | ucontrol->value.integer.value[i] = (ice->spec.aureon.vol[ofs+i] & WM_VOL_MUTE) ? 0 : 1; | 870 | ucontrol->value.integer.value[i] = |
871 | (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1; | ||
844 | return 0; | 872 | return 0; |
845 | } | 873 | } |
846 | 874 | ||
847 | static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 875 | static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
848 | { | 876 | { |
849 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 877 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
878 | struct aureon_spec *spec = ice->spec; | ||
850 | int change = 0, voices, ofs, i; | 879 | int change = 0, voices, ofs, i; |
851 | 880 | ||
852 | voices = kcontrol->private_value >> 8; | 881 | voices = kcontrol->private_value >> 8; |
@@ -854,13 +883,13 @@ static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value | |||
854 | 883 | ||
855 | snd_ice1712_save_gpio_status(ice); | 884 | snd_ice1712_save_gpio_status(ice); |
856 | for (i = 0; i < voices; i++) { | 885 | for (i = 0; i < voices; i++) { |
857 | int val = (ice->spec.aureon.vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1; | 886 | int val = (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1; |
858 | if (ucontrol->value.integer.value[i] != val) { | 887 | if (ucontrol->value.integer.value[i] != val) { |
859 | ice->spec.aureon.vol[ofs + i] &= ~WM_VOL_MUTE; | 888 | spec->vol[ofs + i] &= ~WM_VOL_MUTE; |
860 | ice->spec.aureon.vol[ofs + i] |= | 889 | spec->vol[ofs + i] |= |
861 | ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE; | 890 | ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE; |
862 | wm_set_vol(ice, ofs + i, ice->spec.aureon.vol[ofs + i], | 891 | wm_set_vol(ice, ofs + i, spec->vol[ofs + i], |
863 | ice->spec.aureon.master[i]); | 892 | spec->master[i]); |
864 | change = 1; | 893 | change = 1; |
865 | } | 894 | } |
866 | } | 895 | } |
@@ -877,29 +906,33 @@ static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value | |||
877 | static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 906 | static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
878 | { | 907 | { |
879 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 908 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
909 | struct aureon_spec *spec = ice->spec; | ||
880 | 910 | ||
881 | ucontrol->value.integer.value[0] = (ice->spec.aureon.master[0] & WM_VOL_MUTE) ? 0 : 1; | 911 | ucontrol->value.integer.value[0] = |
882 | ucontrol->value.integer.value[1] = (ice->spec.aureon.master[1] & WM_VOL_MUTE) ? 0 : 1; | 912 | (spec->master[0] & WM_VOL_MUTE) ? 0 : 1; |
913 | ucontrol->value.integer.value[1] = | ||
914 | (spec->master[1] & WM_VOL_MUTE) ? 0 : 1; | ||
883 | return 0; | 915 | return 0; |
884 | } | 916 | } |
885 | 917 | ||
886 | static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 918 | static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
887 | { | 919 | { |
888 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 920 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
921 | struct aureon_spec *spec = ice->spec; | ||
889 | int change = 0, i; | 922 | int change = 0, i; |
890 | 923 | ||
891 | snd_ice1712_save_gpio_status(ice); | 924 | snd_ice1712_save_gpio_status(ice); |
892 | for (i = 0; i < 2; i++) { | 925 | for (i = 0; i < 2; i++) { |
893 | int val = (ice->spec.aureon.master[i] & WM_VOL_MUTE) ? 0 : 1; | 926 | int val = (spec->master[i] & WM_VOL_MUTE) ? 0 : 1; |
894 | if (ucontrol->value.integer.value[i] != val) { | 927 | if (ucontrol->value.integer.value[i] != val) { |
895 | int dac; | 928 | int dac; |
896 | ice->spec.aureon.master[i] &= ~WM_VOL_MUTE; | 929 | spec->master[i] &= ~WM_VOL_MUTE; |
897 | ice->spec.aureon.master[i] |= | 930 | spec->master[i] |= |
898 | ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE; | 931 | ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE; |
899 | for (dac = 0; dac < ice->num_total_dacs; dac += 2) | 932 | for (dac = 0; dac < ice->num_total_dacs; dac += 2) |
900 | wm_set_vol(ice, WM_DAC_ATTEN + dac + i, | 933 | wm_set_vol(ice, WM_DAC_ATTEN + dac + i, |
901 | ice->spec.aureon.vol[dac + i], | 934 | spec->vol[dac + i], |
902 | ice->spec.aureon.master[i]); | 935 | spec->master[i]); |
903 | change = 1; | 936 | change = 1; |
904 | } | 937 | } |
905 | } | 938 | } |
@@ -940,8 +973,10 @@ static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val | |||
940 | unsigned short ovol, nvol; | 973 | unsigned short ovol, nvol; |
941 | int change = 0; | 974 | int change = 0; |
942 | 975 | ||
943 | snd_ice1712_save_gpio_status(ice); | ||
944 | nvol = ucontrol->value.integer.value[0]; | 976 | nvol = ucontrol->value.integer.value[0]; |
977 | if (nvol > PCM_RES) | ||
978 | return -EINVAL; | ||
979 | snd_ice1712_save_gpio_status(ice); | ||
945 | nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff; | 980 | nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff; |
946 | ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff; | 981 | ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff; |
947 | if (ovol != nvol) { | 982 | if (ovol != nvol) { |
@@ -1031,7 +1066,7 @@ static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val | |||
1031 | snd_ice1712_save_gpio_status(ice); | 1066 | snd_ice1712_save_gpio_status(ice); |
1032 | for (i = 0; i < 2; i++) { | 1067 | for (i = 0; i < 2; i++) { |
1033 | idx = WM_ADC_GAIN + i; | 1068 | idx = WM_ADC_GAIN + i; |
1034 | nvol = ucontrol->value.integer.value[i]; | 1069 | nvol = ucontrol->value.integer.value[i] & 0x1f; |
1035 | ovol = wm_get(ice, idx); | 1070 | ovol = wm_get(ice, idx); |
1036 | if ((ovol & 0x1f) != nvol) { | 1071 | if ((ovol & 0x1f) != nvol) { |
1037 | wm_put(ice, idx, nvol | (ovol & ~0x1f)); | 1072 | wm_put(ice, idx, nvol | (ovol & ~0x1f)); |
@@ -1143,10 +1178,11 @@ static int aureon_cs8415_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
1143 | static int aureon_cs8415_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 1178 | static int aureon_cs8415_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1144 | { | 1179 | { |
1145 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 1180 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
1181 | struct aureon_spec *spec = ice->spec; | ||
1146 | 1182 | ||
1147 | //snd_ice1712_save_gpio_status(ice); | 1183 | //snd_ice1712_save_gpio_status(ice); |
1148 | //val = aureon_cs8415_get(ice, CS8415_CTRL2); | 1184 | //val = aureon_cs8415_get(ice, CS8415_CTRL2); |
1149 | ucontrol->value.enumerated.item[0] = ice->spec.aureon.cs8415_mux; | 1185 | ucontrol->value.enumerated.item[0] = spec->cs8415_mux; |
1150 | //snd_ice1712_restore_gpio_status(ice); | 1186 | //snd_ice1712_restore_gpio_status(ice); |
1151 | return 0; | 1187 | return 0; |
1152 | } | 1188 | } |
@@ -1154,6 +1190,7 @@ static int aureon_cs8415_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
1154 | static int aureon_cs8415_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 1190 | static int aureon_cs8415_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1155 | { | 1191 | { |
1156 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 1192 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
1193 | struct aureon_spec *spec = ice->spec; | ||
1157 | unsigned short oval, nval; | 1194 | unsigned short oval, nval; |
1158 | int change; | 1195 | int change; |
1159 | 1196 | ||
@@ -1165,7 +1202,7 @@ static int aureon_cs8415_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
1165 | if (change) | 1202 | if (change) |
1166 | aureon_cs8415_put(ice, CS8415_CTRL2, nval); | 1203 | aureon_cs8415_put(ice, CS8415_CTRL2, nval); |
1167 | snd_ice1712_restore_gpio_status(ice); | 1204 | snd_ice1712_restore_gpio_status(ice); |
1168 | ice->spec.aureon.cs8415_mux = ucontrol->value.enumerated.item[0]; | 1205 | spec->cs8415_mux = ucontrol->value.enumerated.item[0]; |
1169 | return change; | 1206 | return change; |
1170 | } | 1207 | } |
1171 | 1208 | ||
@@ -2001,10 +2038,16 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) | |||
2001 | 0x0605, /* slave, 24bit, MSB on second OSCLK, SDOUT for right channel when OLRCK is high */ | 2038 | 0x0605, /* slave, 24bit, MSB on second OSCLK, SDOUT for right channel when OLRCK is high */ |
2002 | (unsigned short)-1 | 2039 | (unsigned short)-1 |
2003 | }; | 2040 | }; |
2041 | struct aureon_spec *spec; | ||
2004 | unsigned int tmp; | 2042 | unsigned int tmp; |
2005 | const unsigned short *p; | 2043 | const unsigned short *p; |
2006 | int err, i; | 2044 | int err, i; |
2007 | 2045 | ||
2046 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
2047 | if (!spec) | ||
2048 | return -ENOMEM; | ||
2049 | ice->spec = spec; | ||
2050 | |||
2008 | if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) { | 2051 | if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) { |
2009 | ice->num_total_dacs = 6; | 2052 | ice->num_total_dacs = 6; |
2010 | ice->num_total_adcs = 2; | 2053 | ice->num_total_adcs = 2; |
@@ -2055,7 +2098,7 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) | |||
2055 | ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) { | 2098 | ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) { |
2056 | for (p = cs_inits; *p != (unsigned short)-1; p++) | 2099 | for (p = cs_inits; *p != (unsigned short)-1; p++) |
2057 | aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24); | 2100 | aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24); |
2058 | ice->spec.aureon.cs8415_mux = 1; | 2101 | spec->cs8415_mux = 1; |
2059 | 2102 | ||
2060 | aureon_set_headphone_amp(ice, 1); | 2103 | aureon_set_headphone_amp(ice, 1); |
2061 | } | 2104 | } |
@@ -2066,11 +2109,11 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) | |||
2066 | aureon_pca9554_write(ice, PCA9554_DIR, 0x00); | 2109 | aureon_pca9554_write(ice, PCA9554_DIR, 0x00); |
2067 | aureon_pca9554_write(ice, PCA9554_OUT, 0x00); /* internal AUX */ | 2110 | aureon_pca9554_write(ice, PCA9554_OUT, 0x00); /* internal AUX */ |
2068 | 2111 | ||
2069 | ice->spec.aureon.master[0] = WM_VOL_MUTE; | 2112 | spec->master[0] = WM_VOL_MUTE; |
2070 | ice->spec.aureon.master[1] = WM_VOL_MUTE; | 2113 | spec->master[1] = WM_VOL_MUTE; |
2071 | for (i = 0; i < ice->num_total_dacs; i++) { | 2114 | for (i = 0; i < ice->num_total_dacs; i++) { |
2072 | ice->spec.aureon.vol[i] = WM_VOL_MUTE; | 2115 | spec->vol[i] = WM_VOL_MUTE; |
2073 | wm_set_vol(ice, i, ice->spec.aureon.vol[i], ice->spec.aureon.master[i % 2]); | 2116 | wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]); |
2074 | } | 2117 | } |
2075 | 2118 | ||
2076 | return 0; | 2119 | return 0; |
diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c index 371f78461db4..efd180b40e56 100644 --- a/sound/pci/ice1712/delta.c +++ b/sound/pci/ice1712/delta.c | |||
@@ -22,7 +22,6 @@ | |||
22 | * | 22 | * |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <sound/driver.h> | ||
26 | #include <asm/io.h> | 25 | #include <asm/io.h> |
27 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
28 | #include <linux/interrupt.h> | 27 | #include <linux/interrupt.h> |
@@ -405,7 +404,7 @@ static int snd_ice1712_delta1010lt_wordclock_status_get(struct snd_kcontrol *kco | |||
405 | if (snd_i2c_sendbytes(ice->cs8427, ®, 1) != 1) | 404 | if (snd_i2c_sendbytes(ice->cs8427, ®, 1) != 1) |
406 | snd_printk(KERN_ERR "unable to send register 0x%x byte to CS8427\n", reg); | 405 | snd_printk(KERN_ERR "unable to send register 0x%x byte to CS8427\n", reg); |
407 | snd_i2c_readbytes(ice->cs8427, ®, 1); | 406 | snd_i2c_readbytes(ice->cs8427, ®, 1); |
408 | ucontrol->value.integer.value[0] = (reg ? 1 : 0); | 407 | ucontrol->value.integer.value[0] = (reg & CS8427_UNLOCK) ? 1 : 0; |
409 | return 0; | 408 | return 0; |
410 | } | 409 | } |
411 | 410 | ||
diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c index 75e4e5e0f1e4..064760d2a027 100644 --- a/sound/pci/ice1712/ews.c +++ b/sound/pci/ice1712/ews.c | |||
@@ -22,7 +22,6 @@ | |||
22 | * | 22 | * |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <sound/driver.h> | ||
26 | #include <asm/io.h> | 25 | #include <asm/io.h> |
27 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
28 | #include <linux/interrupt.h> | 27 | #include <linux/interrupt.h> |
@@ -45,6 +44,11 @@ enum { | |||
45 | }; | 44 | }; |
46 | 45 | ||
47 | 46 | ||
47 | /* additional i2c devices for EWS boards */ | ||
48 | struct ews_spec { | ||
49 | struct snd_i2c_device *i2cdevs[3]; | ||
50 | }; | ||
51 | |||
48 | /* | 52 | /* |
49 | * access via i2c mode (for EWX 24/96, EWS 88MT&D) | 53 | * access via i2c mode (for EWX 24/96, EWS 88MT&D) |
50 | */ | 54 | */ |
@@ -142,15 +146,17 @@ static struct snd_i2c_bit_ops snd_ice1712_ewx_cs8427_bit_ops = { | |||
142 | /* AK4524 chip select; address 0x48 bit 0-3 */ | 146 | /* AK4524 chip select; address 0x48 bit 0-3 */ |
143 | static int snd_ice1712_ews88mt_chip_select(struct snd_ice1712 *ice, int chip_mask) | 147 | static int snd_ice1712_ews88mt_chip_select(struct snd_ice1712 *ice, int chip_mask) |
144 | { | 148 | { |
149 | struct ews_spec *spec = ice->spec; | ||
145 | unsigned char data, ndata; | 150 | unsigned char data, ndata; |
146 | 151 | ||
147 | snd_assert(chip_mask >= 0 && chip_mask <= 0x0f, return -EINVAL); | 152 | snd_assert(chip_mask >= 0 && chip_mask <= 0x0f, return -EINVAL); |
148 | snd_i2c_lock(ice->i2c); | 153 | snd_i2c_lock(ice->i2c); |
149 | if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_PCF2], &data, 1) != 1) | 154 | if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_PCF2], &data, 1) != 1) |
150 | goto __error; | 155 | goto __error; |
151 | ndata = (data & 0xf0) | chip_mask; | 156 | ndata = (data & 0xf0) | chip_mask; |
152 | if (ndata != data) | 157 | if (ndata != data) |
153 | if (snd_i2c_sendbytes(ice->spec.i2cdevs[EWS_I2C_PCF2], &ndata, 1) != 1) | 158 | if (snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_PCF2], &ndata, 1) |
159 | != 1) | ||
154 | goto __error; | 160 | goto __error; |
155 | snd_i2c_unlock(ice->i2c); | 161 | snd_i2c_unlock(ice->i2c); |
156 | return 0; | 162 | return 0; |
@@ -224,6 +230,7 @@ static void dmx6fire_ak4524_lock(struct snd_akm4xxx *ak, int chip) | |||
224 | 230 | ||
225 | static void snd_ice1712_ews_cs8404_spdif_write(struct snd_ice1712 *ice, unsigned char bits) | 231 | static void snd_ice1712_ews_cs8404_spdif_write(struct snd_ice1712 *ice, unsigned char bits) |
226 | { | 232 | { |
233 | struct ews_spec *spec = ice->spec; | ||
227 | unsigned char bytes[2]; | 234 | unsigned char bytes[2]; |
228 | 235 | ||
229 | snd_i2c_lock(ice->i2c); | 236 | snd_i2c_lock(ice->i2c); |
@@ -231,15 +238,18 @@ static void snd_ice1712_ews_cs8404_spdif_write(struct snd_ice1712 *ice, unsigned | |||
231 | case ICE1712_SUBDEVICE_EWS88MT: | 238 | case ICE1712_SUBDEVICE_EWS88MT: |
232 | case ICE1712_SUBDEVICE_EWS88MT_NEW: | 239 | case ICE1712_SUBDEVICE_EWS88MT_NEW: |
233 | case ICE1712_SUBDEVICE_PHASE88: | 240 | case ICE1712_SUBDEVICE_PHASE88: |
234 | if (snd_i2c_sendbytes(ice->spec.i2cdevs[EWS_I2C_CS8404], &bits, 1) != 1) | 241 | if (snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_CS8404], &bits, 1) |
242 | != 1) | ||
235 | goto _error; | 243 | goto _error; |
236 | break; | 244 | break; |
237 | case ICE1712_SUBDEVICE_EWS88D: | 245 | case ICE1712_SUBDEVICE_EWS88D: |
238 | if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_88D], bytes, 2) != 2) | 246 | if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_88D], bytes, 2) |
247 | != 2) | ||
239 | goto _error; | 248 | goto _error; |
240 | if (bits != bytes[1]) { | 249 | if (bits != bytes[1]) { |
241 | bytes[1] = bits; | 250 | bytes[1] = bits; |
242 | if (snd_i2c_sendbytes(ice->spec.i2cdevs[EWS_I2C_88D], bytes, 2) != 2) | 251 | if (snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_88D], |
252 | bytes, 2) != 2) | ||
243 | goto _error; | 253 | goto _error; |
244 | } | 254 | } |
245 | break; | 255 | break; |
@@ -412,6 +422,7 @@ static int __devinit snd_ice1712_ews_init(struct snd_ice1712 *ice) | |||
412 | { | 422 | { |
413 | int err; | 423 | int err; |
414 | struct snd_akm4xxx *ak; | 424 | struct snd_akm4xxx *ak; |
425 | struct ews_spec *spec; | ||
415 | 426 | ||
416 | /* set the analog DACs */ | 427 | /* set the analog DACs */ |
417 | switch (ice->eeprom.subvendor) { | 428 | switch (ice->eeprom.subvendor) { |
@@ -436,6 +447,11 @@ static int __devinit snd_ice1712_ews_init(struct snd_ice1712 *ice) | |||
436 | break; | 447 | break; |
437 | } | 448 | } |
438 | 449 | ||
450 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
451 | if (!spec) | ||
452 | return -ENOMEM; | ||
453 | ice->spec = spec; | ||
454 | |||
439 | /* create i2c */ | 455 | /* create i2c */ |
440 | if ((err = snd_i2c_bus_create(ice->card, "ICE1712 GPIO 1", NULL, &ice->i2c)) < 0) { | 456 | if ((err = snd_i2c_bus_create(ice->card, "ICE1712 GPIO 1", NULL, &ice->i2c)) < 0) { |
441 | snd_printk(KERN_ERR "unable to create I2C bus\n"); | 457 | snd_printk(KERN_ERR "unable to create I2C bus\n"); |
@@ -447,7 +463,10 @@ static int __devinit snd_ice1712_ews_init(struct snd_ice1712 *ice) | |||
447 | /* create i2c devices */ | 463 | /* create i2c devices */ |
448 | switch (ice->eeprom.subvendor) { | 464 | switch (ice->eeprom.subvendor) { |
449 | case ICE1712_SUBDEVICE_DMX6FIRE: | 465 | case ICE1712_SUBDEVICE_DMX6FIRE: |
450 | if ((err = snd_i2c_device_create(ice->i2c, "PCF9554", ICE1712_6FIRE_PCF9554_ADDR, &ice->spec.i2cdevs[EWS_I2C_6FIRE])) < 0) { | 466 | err = snd_i2c_device_create(ice->i2c, "PCF9554", |
467 | ICE1712_6FIRE_PCF9554_ADDR, | ||
468 | &spec->i2cdevs[EWS_I2C_6FIRE]); | ||
469 | if (err < 0) { | ||
451 | snd_printk(KERN_ERR "PCF9554 initialization failed\n"); | 470 | snd_printk(KERN_ERR "PCF9554 initialization failed\n"); |
452 | return err; | 471 | return err; |
453 | } | 472 | } |
@@ -456,18 +475,30 @@ static int __devinit snd_ice1712_ews_init(struct snd_ice1712 *ice) | |||
456 | case ICE1712_SUBDEVICE_EWS88MT: | 475 | case ICE1712_SUBDEVICE_EWS88MT: |
457 | case ICE1712_SUBDEVICE_EWS88MT_NEW: | 476 | case ICE1712_SUBDEVICE_EWS88MT_NEW: |
458 | case ICE1712_SUBDEVICE_PHASE88: | 477 | case ICE1712_SUBDEVICE_PHASE88: |
459 | if ((err = snd_i2c_device_create(ice->i2c, "CS8404", ICE1712_EWS88MT_CS8404_ADDR, &ice->spec.i2cdevs[EWS_I2C_CS8404])) < 0) | 478 | err = snd_i2c_device_create(ice->i2c, "CS8404", |
479 | ICE1712_EWS88MT_CS8404_ADDR, | ||
480 | &spec->i2cdevs[EWS_I2C_CS8404]); | ||
481 | if (err < 0) | ||
460 | return err; | 482 | return err; |
461 | if ((err = snd_i2c_device_create(ice->i2c, "PCF8574 (1st)", ICE1712_EWS88MT_INPUT_ADDR, &ice->spec.i2cdevs[EWS_I2C_PCF1])) < 0) | 483 | err = snd_i2c_device_create(ice->i2c, "PCF8574 (1st)", |
484 | ICE1712_EWS88MT_INPUT_ADDR, | ||
485 | &spec->i2cdevs[EWS_I2C_PCF1]); | ||
486 | if (err < 0) | ||
462 | return err; | 487 | return err; |
463 | if ((err = snd_i2c_device_create(ice->i2c, "PCF8574 (2nd)", ICE1712_EWS88MT_OUTPUT_ADDR, &ice->spec.i2cdevs[EWS_I2C_PCF2])) < 0) | 488 | err = snd_i2c_device_create(ice->i2c, "PCF8574 (2nd)", |
489 | ICE1712_EWS88MT_OUTPUT_ADDR, | ||
490 | &spec->i2cdevs[EWS_I2C_PCF2]); | ||
491 | if (err < 0) | ||
464 | return err; | 492 | return err; |
465 | /* Check if the front module is connected */ | 493 | /* Check if the front module is connected */ |
466 | if ((err = snd_ice1712_ews88mt_chip_select(ice, 0x0f)) < 0) | 494 | if ((err = snd_ice1712_ews88mt_chip_select(ice, 0x0f)) < 0) |
467 | return err; | 495 | return err; |
468 | break; | 496 | break; |
469 | case ICE1712_SUBDEVICE_EWS88D: | 497 | case ICE1712_SUBDEVICE_EWS88D: |
470 | if ((err = snd_i2c_device_create(ice->i2c, "PCF8575", ICE1712_EWS88D_PCF_ADDR, &ice->spec.i2cdevs[EWS_I2C_88D])) < 0) | 498 | err = snd_i2c_device_create(ice->i2c, "PCF8575", |
499 | ICE1712_EWS88D_PCF_ADDR, | ||
500 | &spec->i2cdevs[EWS_I2C_88D]); | ||
501 | if (err < 0) | ||
471 | return err; | 502 | return err; |
472 | break; | 503 | break; |
473 | } | 504 | } |
@@ -507,7 +538,7 @@ static int __devinit snd_ice1712_ews_init(struct snd_ice1712 *ice) | |||
507 | } | 538 | } |
508 | 539 | ||
509 | /* analog section */ | 540 | /* analog section */ |
510 | ak = ice->akm = kmalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); | 541 | ak = ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); |
511 | if (! ak) | 542 | if (! ak) |
512 | return -ENOMEM; | 543 | return -ENOMEM; |
513 | ice->akm_codecs = 1; | 544 | ice->akm_codecs = 1; |
@@ -605,10 +636,11 @@ static struct snd_kcontrol_new snd_ice1712_ewx2496_controls[] __devinitdata = { | |||
605 | static int snd_ice1712_ews88mt_output_sense_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 636 | static int snd_ice1712_ews88mt_output_sense_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
606 | { | 637 | { |
607 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 638 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
639 | struct ews_spec *spec = ice->spec; | ||
608 | unsigned char data; | 640 | unsigned char data; |
609 | 641 | ||
610 | snd_i2c_lock(ice->i2c); | 642 | snd_i2c_lock(ice->i2c); |
611 | if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_PCF2], &data, 1) != 1) { | 643 | if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_PCF2], &data, 1) != 1) { |
612 | snd_i2c_unlock(ice->i2c); | 644 | snd_i2c_unlock(ice->i2c); |
613 | return -EIO; | 645 | return -EIO; |
614 | } | 646 | } |
@@ -621,15 +653,17 @@ static int snd_ice1712_ews88mt_output_sense_get(struct snd_kcontrol *kcontrol, s | |||
621 | static int snd_ice1712_ews88mt_output_sense_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 653 | static int snd_ice1712_ews88mt_output_sense_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
622 | { | 654 | { |
623 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 655 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
656 | struct ews_spec *spec = ice->spec; | ||
624 | unsigned char data, ndata; | 657 | unsigned char data, ndata; |
625 | 658 | ||
626 | snd_i2c_lock(ice->i2c); | 659 | snd_i2c_lock(ice->i2c); |
627 | if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_PCF2], &data, 1) != 1) { | 660 | if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_PCF2], &data, 1) != 1) { |
628 | snd_i2c_unlock(ice->i2c); | 661 | snd_i2c_unlock(ice->i2c); |
629 | return -EIO; | 662 | return -EIO; |
630 | } | 663 | } |
631 | ndata = (data & ~ICE1712_EWS88MT_OUTPUT_SENSE) | (ucontrol->value.enumerated.item[0] ? ICE1712_EWS88MT_OUTPUT_SENSE : 0); | 664 | ndata = (data & ~ICE1712_EWS88MT_OUTPUT_SENSE) | (ucontrol->value.enumerated.item[0] ? ICE1712_EWS88MT_OUTPUT_SENSE : 0); |
632 | if (ndata != data && snd_i2c_sendbytes(ice->spec.i2cdevs[EWS_I2C_PCF2], &ndata, 1) != 1) { | 665 | if (ndata != data && snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_PCF2], |
666 | &ndata, 1) != 1) { | ||
633 | snd_i2c_unlock(ice->i2c); | 667 | snd_i2c_unlock(ice->i2c); |
634 | return -EIO; | 668 | return -EIO; |
635 | } | 669 | } |
@@ -641,12 +675,13 @@ static int snd_ice1712_ews88mt_output_sense_put(struct snd_kcontrol *kcontrol, s | |||
641 | static int snd_ice1712_ews88mt_input_sense_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 675 | static int snd_ice1712_ews88mt_input_sense_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
642 | { | 676 | { |
643 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 677 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
678 | struct ews_spec *spec = ice->spec; | ||
644 | int channel = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | 679 | int channel = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); |
645 | unsigned char data; | 680 | unsigned char data; |
646 | 681 | ||
647 | snd_assert(channel >= 0 && channel <= 7, return 0); | 682 | snd_assert(channel >= 0 && channel <= 7, return 0); |
648 | snd_i2c_lock(ice->i2c); | 683 | snd_i2c_lock(ice->i2c); |
649 | if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_PCF1], &data, 1) != 1) { | 684 | if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_PCF1], &data, 1) != 1) { |
650 | snd_i2c_unlock(ice->i2c); | 685 | snd_i2c_unlock(ice->i2c); |
651 | return -EIO; | 686 | return -EIO; |
652 | } | 687 | } |
@@ -660,17 +695,19 @@ static int snd_ice1712_ews88mt_input_sense_get(struct snd_kcontrol *kcontrol, st | |||
660 | static int snd_ice1712_ews88mt_input_sense_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 695 | static int snd_ice1712_ews88mt_input_sense_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
661 | { | 696 | { |
662 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 697 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
698 | struct ews_spec *spec = ice->spec; | ||
663 | int channel = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | 699 | int channel = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); |
664 | unsigned char data, ndata; | 700 | unsigned char data, ndata; |
665 | 701 | ||
666 | snd_assert(channel >= 0 && channel <= 7, return 0); | 702 | snd_assert(channel >= 0 && channel <= 7, return 0); |
667 | snd_i2c_lock(ice->i2c); | 703 | snd_i2c_lock(ice->i2c); |
668 | if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_PCF1], &data, 1) != 1) { | 704 | if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_PCF1], &data, 1) != 1) { |
669 | snd_i2c_unlock(ice->i2c); | 705 | snd_i2c_unlock(ice->i2c); |
670 | return -EIO; | 706 | return -EIO; |
671 | } | 707 | } |
672 | ndata = (data & ~(1 << channel)) | (ucontrol->value.enumerated.item[0] ? 0 : (1 << channel)); | 708 | ndata = (data & ~(1 << channel)) | (ucontrol->value.enumerated.item[0] ? 0 : (1 << channel)); |
673 | if (ndata != data && snd_i2c_sendbytes(ice->spec.i2cdevs[EWS_I2C_PCF1], &ndata, 1) != 1) { | 709 | if (ndata != data && snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_PCF1], |
710 | &ndata, 1) != 1) { | ||
674 | snd_i2c_unlock(ice->i2c); | 711 | snd_i2c_unlock(ice->i2c); |
675 | return -EIO; | 712 | return -EIO; |
676 | } | 713 | } |
@@ -705,12 +742,13 @@ static struct snd_kcontrol_new snd_ice1712_ews88mt_output_sense __devinitdata = | |||
705 | static int snd_ice1712_ews88d_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 742 | static int snd_ice1712_ews88d_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
706 | { | 743 | { |
707 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 744 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
745 | struct ews_spec *spec = ice->spec; | ||
708 | int shift = kcontrol->private_value & 0xff; | 746 | int shift = kcontrol->private_value & 0xff; |
709 | int invert = (kcontrol->private_value >> 8) & 1; | 747 | int invert = (kcontrol->private_value >> 8) & 1; |
710 | unsigned char data[2]; | 748 | unsigned char data[2]; |
711 | 749 | ||
712 | snd_i2c_lock(ice->i2c); | 750 | snd_i2c_lock(ice->i2c); |
713 | if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_88D], data, 2) != 2) { | 751 | if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_88D], data, 2) != 2) { |
714 | snd_i2c_unlock(ice->i2c); | 752 | snd_i2c_unlock(ice->i2c); |
715 | return -EIO; | 753 | return -EIO; |
716 | } | 754 | } |
@@ -725,13 +763,14 @@ static int snd_ice1712_ews88d_control_get(struct snd_kcontrol *kcontrol, struct | |||
725 | static int snd_ice1712_ews88d_control_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 763 | static int snd_ice1712_ews88d_control_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
726 | { | 764 | { |
727 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 765 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
766 | struct ews_spec *spec = ice->spec; | ||
728 | int shift = kcontrol->private_value & 0xff; | 767 | int shift = kcontrol->private_value & 0xff; |
729 | int invert = (kcontrol->private_value >> 8) & 1; | 768 | int invert = (kcontrol->private_value >> 8) & 1; |
730 | unsigned char data[2], ndata[2]; | 769 | unsigned char data[2], ndata[2]; |
731 | int change; | 770 | int change; |
732 | 771 | ||
733 | snd_i2c_lock(ice->i2c); | 772 | snd_i2c_lock(ice->i2c); |
734 | if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_88D], data, 2) != 2) { | 773 | if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_88D], data, 2) != 2) { |
735 | snd_i2c_unlock(ice->i2c); | 774 | snd_i2c_unlock(ice->i2c); |
736 | return -EIO; | 775 | return -EIO; |
737 | } | 776 | } |
@@ -744,7 +783,8 @@ static int snd_ice1712_ews88d_control_put(struct snd_kcontrol *kcontrol, struct | |||
744 | ndata[shift >> 3] |= (1 << (shift & 7)); | 783 | ndata[shift >> 3] |= (1 << (shift & 7)); |
745 | } | 784 | } |
746 | change = (data[shift >> 3] != ndata[shift >> 3]); | 785 | change = (data[shift >> 3] != ndata[shift >> 3]); |
747 | if (change && snd_i2c_sendbytes(ice->spec.i2cdevs[EWS_I2C_88D], data, 2) != 2) { | 786 | if (change && |
787 | snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_88D], data, 2) != 2) { | ||
748 | snd_i2c_unlock(ice->i2c); | 788 | snd_i2c_unlock(ice->i2c); |
749 | return -EIO; | 789 | return -EIO; |
750 | } | 790 | } |
@@ -778,11 +818,13 @@ static struct snd_kcontrol_new snd_ice1712_ews88d_controls[] __devinitdata = { | |||
778 | static int snd_ice1712_6fire_read_pca(struct snd_ice1712 *ice, unsigned char reg) | 818 | static int snd_ice1712_6fire_read_pca(struct snd_ice1712 *ice, unsigned char reg) |
779 | { | 819 | { |
780 | unsigned char byte; | 820 | unsigned char byte; |
821 | struct ews_spec *spec = ice->spec; | ||
822 | |||
781 | snd_i2c_lock(ice->i2c); | 823 | snd_i2c_lock(ice->i2c); |
782 | byte = reg; | 824 | byte = reg; |
783 | snd_i2c_sendbytes(ice->spec.i2cdevs[EWS_I2C_6FIRE], &byte, 1); | 825 | snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_6FIRE], &byte, 1); |
784 | byte = 0; | 826 | byte = 0; |
785 | if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_6FIRE], &byte, 1) != 1) { | 827 | if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_6FIRE], &byte, 1) != 1) { |
786 | snd_i2c_unlock(ice->i2c); | 828 | snd_i2c_unlock(ice->i2c); |
787 | printk(KERN_ERR "cannot read pca\n"); | 829 | printk(KERN_ERR "cannot read pca\n"); |
788 | return -EIO; | 830 | return -EIO; |
@@ -794,10 +836,12 @@ static int snd_ice1712_6fire_read_pca(struct snd_ice1712 *ice, unsigned char reg | |||
794 | static int snd_ice1712_6fire_write_pca(struct snd_ice1712 *ice, unsigned char reg, unsigned char data) | 836 | static int snd_ice1712_6fire_write_pca(struct snd_ice1712 *ice, unsigned char reg, unsigned char data) |
795 | { | 837 | { |
796 | unsigned char bytes[2]; | 838 | unsigned char bytes[2]; |
839 | struct ews_spec *spec = ice->spec; | ||
840 | |||
797 | snd_i2c_lock(ice->i2c); | 841 | snd_i2c_lock(ice->i2c); |
798 | bytes[0] = reg; | 842 | bytes[0] = reg; |
799 | bytes[1] = data; | 843 | bytes[1] = data; |
800 | if (snd_i2c_sendbytes(ice->spec.i2cdevs[EWS_I2C_6FIRE], bytes, 2) != 2) { | 844 | if (snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_6FIRE], bytes, 2) != 2) { |
801 | snd_i2c_unlock(ice->i2c); | 845 | snd_i2c_unlock(ice->i2c); |
802 | return -EIO; | 846 | return -EIO; |
803 | } | 847 | } |
diff --git a/sound/pci/ice1712/hoontech.c b/sound/pci/ice1712/hoontech.c index abcfd1da6587..cf5c7c0898fd 100644 --- a/sound/pci/ice1712/hoontech.c +++ b/sound/pci/ice1712/hoontech.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <asm/io.h> | 24 | #include <asm/io.h> |
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
27 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
@@ -34,6 +33,12 @@ | |||
34 | #include "ice1712.h" | 33 | #include "ice1712.h" |
35 | #include "hoontech.h" | 34 | #include "hoontech.h" |
36 | 35 | ||
36 | /* Hoontech-specific setting */ | ||
37 | struct hoontech_spec { | ||
38 | unsigned char boxbits[4]; | ||
39 | unsigned int config; | ||
40 | unsigned short boxconfig[4]; | ||
41 | }; | ||
37 | 42 | ||
38 | static void __devinit snd_ice1712_stdsp24_gpio_write(struct snd_ice1712 *ice, unsigned char byte) | 43 | static void __devinit snd_ice1712_stdsp24_gpio_write(struct snd_ice1712 *ice, unsigned char byte) |
39 | { | 44 | { |
@@ -50,169 +55,182 @@ static void __devinit snd_ice1712_stdsp24_gpio_write(struct snd_ice1712 *ice, un | |||
50 | 55 | ||
51 | static void __devinit snd_ice1712_stdsp24_darear(struct snd_ice1712 *ice, int activate) | 56 | static void __devinit snd_ice1712_stdsp24_darear(struct snd_ice1712 *ice, int activate) |
52 | { | 57 | { |
58 | struct hoontech_spec *spec = ice->spec; | ||
53 | mutex_lock(&ice->gpio_mutex); | 59 | mutex_lock(&ice->gpio_mutex); |
54 | ICE1712_STDSP24_0_DAREAR(ice->spec.hoontech.boxbits, activate); | 60 | ICE1712_STDSP24_0_DAREAR(spec->boxbits, activate); |
55 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[0]); | 61 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[0]); |
56 | mutex_unlock(&ice->gpio_mutex); | 62 | mutex_unlock(&ice->gpio_mutex); |
57 | } | 63 | } |
58 | 64 | ||
59 | static void __devinit snd_ice1712_stdsp24_mute(struct snd_ice1712 *ice, int activate) | 65 | static void __devinit snd_ice1712_stdsp24_mute(struct snd_ice1712 *ice, int activate) |
60 | { | 66 | { |
67 | struct hoontech_spec *spec = ice->spec; | ||
61 | mutex_lock(&ice->gpio_mutex); | 68 | mutex_lock(&ice->gpio_mutex); |
62 | ICE1712_STDSP24_3_MUTE(ice->spec.hoontech.boxbits, activate); | 69 | ICE1712_STDSP24_3_MUTE(spec->boxbits, activate); |
63 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]); | 70 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]); |
64 | mutex_unlock(&ice->gpio_mutex); | 71 | mutex_unlock(&ice->gpio_mutex); |
65 | } | 72 | } |
66 | 73 | ||
67 | static void __devinit snd_ice1712_stdsp24_insel(struct snd_ice1712 *ice, int activate) | 74 | static void __devinit snd_ice1712_stdsp24_insel(struct snd_ice1712 *ice, int activate) |
68 | { | 75 | { |
76 | struct hoontech_spec *spec = ice->spec; | ||
69 | mutex_lock(&ice->gpio_mutex); | 77 | mutex_lock(&ice->gpio_mutex); |
70 | ICE1712_STDSP24_3_INSEL(ice->spec.hoontech.boxbits, activate); | 78 | ICE1712_STDSP24_3_INSEL(spec->boxbits, activate); |
71 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]); | 79 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]); |
72 | mutex_unlock(&ice->gpio_mutex); | 80 | mutex_unlock(&ice->gpio_mutex); |
73 | } | 81 | } |
74 | 82 | ||
75 | static void __devinit snd_ice1712_stdsp24_box_channel(struct snd_ice1712 *ice, int box, int chn, int activate) | 83 | static void __devinit snd_ice1712_stdsp24_box_channel(struct snd_ice1712 *ice, int box, int chn, int activate) |
76 | { | 84 | { |
85 | struct hoontech_spec *spec = ice->spec; | ||
86 | |||
77 | mutex_lock(&ice->gpio_mutex); | 87 | mutex_lock(&ice->gpio_mutex); |
78 | 88 | ||
79 | /* select box */ | 89 | /* select box */ |
80 | ICE1712_STDSP24_0_BOX(ice->spec.hoontech.boxbits, box); | 90 | ICE1712_STDSP24_0_BOX(spec->boxbits, box); |
81 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[0]); | 91 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[0]); |
82 | 92 | ||
83 | /* prepare for write */ | 93 | /* prepare for write */ |
84 | if (chn == 3) | 94 | if (chn == 3) |
85 | ICE1712_STDSP24_2_CHN4(ice->spec.hoontech.boxbits, 0); | 95 | ICE1712_STDSP24_2_CHN4(spec->boxbits, 0); |
86 | ICE1712_STDSP24_2_MIDI1(ice->spec.hoontech.boxbits, activate); | 96 | ICE1712_STDSP24_2_MIDI1(spec->boxbits, activate); |
87 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); | 97 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); |
88 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]); | 98 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]); |
89 | 99 | ||
90 | ICE1712_STDSP24_1_CHN1(ice->spec.hoontech.boxbits, 1); | 100 | ICE1712_STDSP24_1_CHN1(spec->boxbits, 1); |
91 | ICE1712_STDSP24_1_CHN2(ice->spec.hoontech.boxbits, 1); | 101 | ICE1712_STDSP24_1_CHN2(spec->boxbits, 1); |
92 | ICE1712_STDSP24_1_CHN3(ice->spec.hoontech.boxbits, 1); | 102 | ICE1712_STDSP24_1_CHN3(spec->boxbits, 1); |
93 | ICE1712_STDSP24_2_CHN4(ice->spec.hoontech.boxbits, 1); | 103 | ICE1712_STDSP24_2_CHN4(spec->boxbits, 1); |
94 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[1]); | 104 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[1]); |
95 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); | 105 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); |
96 | udelay(100); | 106 | udelay(100); |
97 | if (chn == 3) { | 107 | if (chn == 3) { |
98 | ICE1712_STDSP24_2_CHN4(ice->spec.hoontech.boxbits, 0); | 108 | ICE1712_STDSP24_2_CHN4(spec->boxbits, 0); |
99 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); | 109 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); |
100 | } else { | 110 | } else { |
101 | switch (chn) { | 111 | switch (chn) { |
102 | case 0: ICE1712_STDSP24_1_CHN1(ice->spec.hoontech.boxbits, 0); break; | 112 | case 0: ICE1712_STDSP24_1_CHN1(spec->boxbits, 0); break; |
103 | case 1: ICE1712_STDSP24_1_CHN2(ice->spec.hoontech.boxbits, 0); break; | 113 | case 1: ICE1712_STDSP24_1_CHN2(spec->boxbits, 0); break; |
104 | case 2: ICE1712_STDSP24_1_CHN3(ice->spec.hoontech.boxbits, 0); break; | 114 | case 2: ICE1712_STDSP24_1_CHN3(spec->boxbits, 0); break; |
105 | } | 115 | } |
106 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[1]); | 116 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[1]); |
107 | } | 117 | } |
108 | udelay(100); | 118 | udelay(100); |
109 | ICE1712_STDSP24_1_CHN1(ice->spec.hoontech.boxbits, 1); | 119 | ICE1712_STDSP24_1_CHN1(spec->boxbits, 1); |
110 | ICE1712_STDSP24_1_CHN2(ice->spec.hoontech.boxbits, 1); | 120 | ICE1712_STDSP24_1_CHN2(spec->boxbits, 1); |
111 | ICE1712_STDSP24_1_CHN3(ice->spec.hoontech.boxbits, 1); | 121 | ICE1712_STDSP24_1_CHN3(spec->boxbits, 1); |
112 | ICE1712_STDSP24_2_CHN4(ice->spec.hoontech.boxbits, 1); | 122 | ICE1712_STDSP24_2_CHN4(spec->boxbits, 1); |
113 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[1]); | 123 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[1]); |
114 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); | 124 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); |
115 | udelay(100); | 125 | udelay(100); |
116 | 126 | ||
117 | ICE1712_STDSP24_2_MIDI1(ice->spec.hoontech.boxbits, 0); | 127 | ICE1712_STDSP24_2_MIDI1(spec->boxbits, 0); |
118 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); | 128 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); |
119 | 129 | ||
120 | mutex_unlock(&ice->gpio_mutex); | 130 | mutex_unlock(&ice->gpio_mutex); |
121 | } | 131 | } |
122 | 132 | ||
123 | static void __devinit snd_ice1712_stdsp24_box_midi(struct snd_ice1712 *ice, int box, int master) | 133 | static void __devinit snd_ice1712_stdsp24_box_midi(struct snd_ice1712 *ice, int box, int master) |
124 | { | 134 | { |
135 | struct hoontech_spec *spec = ice->spec; | ||
136 | |||
125 | mutex_lock(&ice->gpio_mutex); | 137 | mutex_lock(&ice->gpio_mutex); |
126 | 138 | ||
127 | /* select box */ | 139 | /* select box */ |
128 | ICE1712_STDSP24_0_BOX(ice->spec.hoontech.boxbits, box); | 140 | ICE1712_STDSP24_0_BOX(spec->boxbits, box); |
129 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[0]); | 141 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[0]); |
130 | 142 | ||
131 | ICE1712_STDSP24_2_MIDIIN(ice->spec.hoontech.boxbits, 1); | 143 | ICE1712_STDSP24_2_MIDIIN(spec->boxbits, 1); |
132 | ICE1712_STDSP24_2_MIDI1(ice->spec.hoontech.boxbits, master); | 144 | ICE1712_STDSP24_2_MIDI1(spec->boxbits, master); |
133 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); | 145 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); |
134 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]); | 146 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]); |
135 | 147 | ||
136 | udelay(100); | 148 | udelay(100); |
137 | 149 | ||
138 | ICE1712_STDSP24_2_MIDIIN(ice->spec.hoontech.boxbits, 0); | 150 | ICE1712_STDSP24_2_MIDIIN(spec->boxbits, 0); |
139 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); | 151 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); |
140 | 152 | ||
141 | mdelay(10); | 153 | mdelay(10); |
142 | 154 | ||
143 | ICE1712_STDSP24_2_MIDIIN(ice->spec.hoontech.boxbits, 1); | 155 | ICE1712_STDSP24_2_MIDIIN(spec->boxbits, 1); |
144 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); | 156 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); |
145 | 157 | ||
146 | mutex_unlock(&ice->gpio_mutex); | 158 | mutex_unlock(&ice->gpio_mutex); |
147 | } | 159 | } |
148 | 160 | ||
149 | static void __devinit snd_ice1712_stdsp24_midi2(struct snd_ice1712 *ice, int activate) | 161 | static void __devinit snd_ice1712_stdsp24_midi2(struct snd_ice1712 *ice, int activate) |
150 | { | 162 | { |
163 | struct hoontech_spec *spec = ice->spec; | ||
151 | mutex_lock(&ice->gpio_mutex); | 164 | mutex_lock(&ice->gpio_mutex); |
152 | ICE1712_STDSP24_3_MIDI2(ice->spec.hoontech.boxbits, activate); | 165 | ICE1712_STDSP24_3_MIDI2(spec->boxbits, activate); |
153 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]); | 166 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]); |
154 | mutex_unlock(&ice->gpio_mutex); | 167 | mutex_unlock(&ice->gpio_mutex); |
155 | } | 168 | } |
156 | 169 | ||
157 | static int __devinit snd_ice1712_hoontech_init(struct snd_ice1712 *ice) | 170 | static int __devinit snd_ice1712_hoontech_init(struct snd_ice1712 *ice) |
158 | { | 171 | { |
172 | struct hoontech_spec *spec; | ||
159 | int box, chn; | 173 | int box, chn; |
160 | 174 | ||
161 | ice->num_total_dacs = 8; | 175 | ice->num_total_dacs = 8; |
162 | ice->num_total_adcs = 8; | 176 | ice->num_total_adcs = 8; |
163 | 177 | ||
164 | ice->spec.hoontech.boxbits[0] = | 178 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
165 | ice->spec.hoontech.boxbits[1] = | 179 | if (!spec) |
166 | ice->spec.hoontech.boxbits[2] = | 180 | return -ENOMEM; |
167 | ice->spec.hoontech.boxbits[3] = 0; /* should be already */ | 181 | ice->spec = spec; |
168 | 182 | ||
169 | ICE1712_STDSP24_SET_ADDR(ice->spec.hoontech.boxbits, 0); | 183 | ICE1712_STDSP24_SET_ADDR(spec->boxbits, 0); |
170 | ICE1712_STDSP24_CLOCK(ice->spec.hoontech.boxbits, 0, 1); | 184 | ICE1712_STDSP24_CLOCK(spec->boxbits, 0, 1); |
171 | ICE1712_STDSP24_0_BOX(ice->spec.hoontech.boxbits, 0); | 185 | ICE1712_STDSP24_0_BOX(spec->boxbits, 0); |
172 | ICE1712_STDSP24_0_DAREAR(ice->spec.hoontech.boxbits, 0); | 186 | ICE1712_STDSP24_0_DAREAR(spec->boxbits, 0); |
173 | 187 | ||
174 | ICE1712_STDSP24_SET_ADDR(ice->spec.hoontech.boxbits, 1); | 188 | ICE1712_STDSP24_SET_ADDR(spec->boxbits, 1); |
175 | ICE1712_STDSP24_CLOCK(ice->spec.hoontech.boxbits, 1, 1); | 189 | ICE1712_STDSP24_CLOCK(spec->boxbits, 1, 1); |
176 | ICE1712_STDSP24_1_CHN1(ice->spec.hoontech.boxbits, 1); | 190 | ICE1712_STDSP24_1_CHN1(spec->boxbits, 1); |
177 | ICE1712_STDSP24_1_CHN2(ice->spec.hoontech.boxbits, 1); | 191 | ICE1712_STDSP24_1_CHN2(spec->boxbits, 1); |
178 | ICE1712_STDSP24_1_CHN3(ice->spec.hoontech.boxbits, 1); | 192 | ICE1712_STDSP24_1_CHN3(spec->boxbits, 1); |
179 | 193 | ||
180 | ICE1712_STDSP24_SET_ADDR(ice->spec.hoontech.boxbits, 2); | 194 | ICE1712_STDSP24_SET_ADDR(spec->boxbits, 2); |
181 | ICE1712_STDSP24_CLOCK(ice->spec.hoontech.boxbits, 2, 1); | 195 | ICE1712_STDSP24_CLOCK(spec->boxbits, 2, 1); |
182 | ICE1712_STDSP24_2_CHN4(ice->spec.hoontech.boxbits, 1); | 196 | ICE1712_STDSP24_2_CHN4(spec->boxbits, 1); |
183 | ICE1712_STDSP24_2_MIDIIN(ice->spec.hoontech.boxbits, 1); | 197 | ICE1712_STDSP24_2_MIDIIN(spec->boxbits, 1); |
184 | ICE1712_STDSP24_2_MIDI1(ice->spec.hoontech.boxbits, 0); | 198 | ICE1712_STDSP24_2_MIDI1(spec->boxbits, 0); |
185 | 199 | ||
186 | ICE1712_STDSP24_SET_ADDR(ice->spec.hoontech.boxbits, 3); | 200 | ICE1712_STDSP24_SET_ADDR(spec->boxbits, 3); |
187 | ICE1712_STDSP24_CLOCK(ice->spec.hoontech.boxbits, 3, 1); | 201 | ICE1712_STDSP24_CLOCK(spec->boxbits, 3, 1); |
188 | ICE1712_STDSP24_3_MIDI2(ice->spec.hoontech.boxbits, 0); | 202 | ICE1712_STDSP24_3_MIDI2(spec->boxbits, 0); |
189 | ICE1712_STDSP24_3_MUTE(ice->spec.hoontech.boxbits, 1); | 203 | ICE1712_STDSP24_3_MUTE(spec->boxbits, 1); |
190 | ICE1712_STDSP24_3_INSEL(ice->spec.hoontech.boxbits, 0); | 204 | ICE1712_STDSP24_3_INSEL(spec->boxbits, 0); |
191 | 205 | ||
192 | /* let's go - activate only functions in first box */ | 206 | /* let's go - activate only functions in first box */ |
193 | ice->spec.hoontech.config = 0; | 207 | spec->config = 0; |
194 | /* ICE1712_STDSP24_MUTE | | 208 | /* ICE1712_STDSP24_MUTE | |
195 | ICE1712_STDSP24_INSEL | | 209 | ICE1712_STDSP24_INSEL | |
196 | ICE1712_STDSP24_DAREAR; */ | 210 | ICE1712_STDSP24_DAREAR; */ |
197 | ice->spec.hoontech.boxconfig[0] = ICE1712_STDSP24_BOX_CHN1 | | 211 | spec->boxconfig[0] = ICE1712_STDSP24_BOX_CHN1 | |
198 | ICE1712_STDSP24_BOX_CHN2 | | 212 | ICE1712_STDSP24_BOX_CHN2 | |
199 | ICE1712_STDSP24_BOX_CHN3 | | 213 | ICE1712_STDSP24_BOX_CHN3 | |
200 | ICE1712_STDSP24_BOX_CHN4 | | 214 | ICE1712_STDSP24_BOX_CHN4 | |
201 | ICE1712_STDSP24_BOX_MIDI1 | | 215 | ICE1712_STDSP24_BOX_MIDI1 | |
202 | ICE1712_STDSP24_BOX_MIDI2; | 216 | ICE1712_STDSP24_BOX_MIDI2; |
203 | ice->spec.hoontech.boxconfig[1] = | 217 | spec->boxconfig[1] = |
204 | ice->spec.hoontech.boxconfig[2] = | 218 | spec->boxconfig[2] = |
205 | ice->spec.hoontech.boxconfig[3] = 0; | 219 | spec->boxconfig[3] = 0; |
206 | snd_ice1712_stdsp24_darear(ice, (ice->spec.hoontech.config & ICE1712_STDSP24_DAREAR) ? 1 : 0); | 220 | snd_ice1712_stdsp24_darear(ice, |
207 | snd_ice1712_stdsp24_mute(ice, (ice->spec.hoontech.config & ICE1712_STDSP24_MUTE) ? 1 : 0); | 221 | (spec->config & ICE1712_STDSP24_DAREAR) ? 1 : 0); |
208 | snd_ice1712_stdsp24_insel(ice, (ice->spec.hoontech.config & ICE1712_STDSP24_INSEL) ? 1 : 0); | 222 | snd_ice1712_stdsp24_mute(ice, |
209 | for (box = 0; box < 4; box++) { | 223 | (spec->config & ICE1712_STDSP24_MUTE) ? 1 : 0); |
224 | snd_ice1712_stdsp24_insel(ice, | ||
225 | (spec->config & ICE1712_STDSP24_INSEL) ? 1 : 0); | ||
226 | for (box = 0; box < 1; box++) { | ||
227 | if (spec->boxconfig[box] & ICE1712_STDSP24_BOX_MIDI2) | ||
228 | snd_ice1712_stdsp24_midi2(ice, 1); | ||
210 | for (chn = 0; chn < 4; chn++) | 229 | for (chn = 0; chn < 4; chn++) |
211 | snd_ice1712_stdsp24_box_channel(ice, box, chn, (ice->spec.hoontech.boxconfig[box] & (1 << chn)) ? 1 : 0); | 230 | snd_ice1712_stdsp24_box_channel(ice, box, chn, |
231 | (spec->boxconfig[box] & (1 << chn)) ? 1 : 0); | ||
212 | snd_ice1712_stdsp24_box_midi(ice, box, | 232 | snd_ice1712_stdsp24_box_midi(ice, box, |
213 | (ice->spec.hoontech.boxconfig[box] & ICE1712_STDSP24_BOX_MIDI1) ? 1 : 0); | 233 | (spec->boxconfig[box] & ICE1712_STDSP24_BOX_MIDI1) ? 1 : 0); |
214 | if (ice->spec.hoontech.boxconfig[box] & ICE1712_STDSP24_BOX_MIDI2) | ||
215 | snd_ice1712_stdsp24_midi2(ice, 1); | ||
216 | } | 234 | } |
217 | 235 | ||
218 | return 0; | 236 | return 0; |
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 052fc3cb3272..df292af67381 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c | |||
@@ -47,7 +47,6 @@ | |||
47 | */ | 47 | */ |
48 | 48 | ||
49 | 49 | ||
50 | #include <sound/driver.h> | ||
51 | #include <asm/io.h> | 50 | #include <asm/io.h> |
52 | #include <linux/delay.h> | 51 | #include <linux/delay.h> |
53 | #include <linux/interrupt.h> | 52 | #include <linux/interrupt.h> |
@@ -2491,6 +2490,7 @@ static int snd_ice1712_free(struct snd_ice1712 *ice) | |||
2491 | pci_release_regions(ice->pci); | 2490 | pci_release_regions(ice->pci); |
2492 | snd_ice1712_akm4xxx_free(ice); | 2491 | snd_ice1712_akm4xxx_free(ice); |
2493 | pci_disable_device(ice->pci); | 2492 | pci_disable_device(ice->pci); |
2493 | kfree(ice->spec); | ||
2494 | kfree(ice); | 2494 | kfree(ice); |
2495 | return 0; | 2495 | return 0; |
2496 | } | 2496 | } |
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index 58640afa5404..303cffe08bd8 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h | |||
@@ -366,42 +366,7 @@ struct snd_ice1712 { | |||
366 | struct mutex gpio_mutex; | 366 | struct mutex gpio_mutex; |
367 | 367 | ||
368 | /* other board-specific data */ | 368 | /* other board-specific data */ |
369 | union { | 369 | void *spec; |
370 | /* additional i2c devices for EWS boards */ | ||
371 | struct snd_i2c_device *i2cdevs[3]; | ||
372 | /* AC97 register cache for Aureon */ | ||
373 | struct aureon_spec { | ||
374 | unsigned short stac9744[64]; | ||
375 | unsigned int cs8415_mux; | ||
376 | unsigned short master[2]; | ||
377 | unsigned short vol[8]; | ||
378 | unsigned char pca9554_out; | ||
379 | } aureon; | ||
380 | /* AC97 register cache for Phase28 */ | ||
381 | struct phase28_spec { | ||
382 | unsigned short master[2]; | ||
383 | unsigned short vol[8]; | ||
384 | } phase28; | ||
385 | /* a non-standard I2C device for revo51 */ | ||
386 | struct revo51_spec { | ||
387 | struct snd_i2c_device *dev; | ||
388 | struct snd_pt2258 *pt2258; | ||
389 | } revo51; | ||
390 | /* Hoontech-specific setting */ | ||
391 | struct hoontech_spec { | ||
392 | unsigned char boxbits[4]; | ||
393 | unsigned int config; | ||
394 | unsigned short boxconfig[4]; | ||
395 | } hoontech; | ||
396 | struct { | ||
397 | struct ak4114 *ak4114; | ||
398 | unsigned int analog: 1; | ||
399 | } juli; | ||
400 | struct { | ||
401 | struct ak4114 *ak4114; | ||
402 | } prodigy192; | ||
403 | } spec; | ||
404 | |||
405 | }; | 370 | }; |
406 | 371 | ||
407 | 372 | ||
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 0b0bbb0d96b9..f533850ec6e7 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c | |||
@@ -22,7 +22,6 @@ | |||
22 | * | 22 | * |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <sound/driver.h> | ||
26 | #include <asm/io.h> | 25 | #include <asm/io.h> |
27 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
28 | #include <linux/interrupt.h> | 27 | #include <linux/interrupt.h> |
@@ -48,9 +47,11 @@ | |||
48 | #include "vt1720_mobo.h" | 47 | #include "vt1720_mobo.h" |
49 | #include "pontis.h" | 48 | #include "pontis.h" |
50 | #include "prodigy192.h" | 49 | #include "prodigy192.h" |
50 | #include "prodigy_hifi.h" | ||
51 | #include "juli.h" | 51 | #include "juli.h" |
52 | #include "phase.h" | 52 | #include "phase.h" |
53 | #include "wtm.h" | 53 | #include "wtm.h" |
54 | #include "se.h" | ||
54 | 55 | ||
55 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); | 56 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); |
56 | MODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)"); | 57 | MODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)"); |
@@ -62,9 +63,11 @@ MODULE_SUPPORTED_DEVICE("{" | |||
62 | VT1720_MOBO_DEVICE_DESC | 63 | VT1720_MOBO_DEVICE_DESC |
63 | PONTIS_DEVICE_DESC | 64 | PONTIS_DEVICE_DESC |
64 | PRODIGY192_DEVICE_DESC | 65 | PRODIGY192_DEVICE_DESC |
66 | PRODIGY_HIFI_DEVICE_DESC | ||
65 | JULI_DEVICE_DESC | 67 | JULI_DEVICE_DESC |
66 | PHASE_DEVICE_DESC | 68 | PHASE_DEVICE_DESC |
67 | WTM_DEVICE_DESC | 69 | WTM_DEVICE_DESC |
70 | SE_DEVICE_DESC | ||
68 | "{VIA,VT1720}," | 71 | "{VIA,VT1720}," |
69 | "{VIA,VT1724}," | 72 | "{VIA,VT1724}," |
70 | "{ICEnsemble,Generic ICE1724}," | 73 | "{ICEnsemble,Generic ICE1724}," |
@@ -1929,10 +1932,12 @@ static struct snd_ice1712_card_info *card_tables[] __devinitdata = { | |||
1929 | snd_vt1724_aureon_cards, | 1932 | snd_vt1724_aureon_cards, |
1930 | snd_vt1720_mobo_cards, | 1933 | snd_vt1720_mobo_cards, |
1931 | snd_vt1720_pontis_cards, | 1934 | snd_vt1720_pontis_cards, |
1935 | snd_vt1724_prodigy_hifi_cards, | ||
1932 | snd_vt1724_prodigy192_cards, | 1936 | snd_vt1724_prodigy192_cards, |
1933 | snd_vt1724_juli_cards, | 1937 | snd_vt1724_juli_cards, |
1934 | snd_vt1724_phase_cards, | 1938 | snd_vt1724_phase_cards, |
1935 | snd_vt1724_wtm_cards, | 1939 | snd_vt1724_wtm_cards, |
1940 | snd_vt1724_se_cards, | ||
1936 | NULL, | 1941 | NULL, |
1937 | }; | 1942 | }; |
1938 | 1943 | ||
@@ -1955,6 +1960,7 @@ unsigned char snd_vt1724_read_i2c(struct snd_ice1712 *ice, | |||
1955 | unsigned char val; | 1960 | unsigned char val; |
1956 | 1961 | ||
1957 | mutex_lock(&ice->i2c_mutex); | 1962 | mutex_lock(&ice->i2c_mutex); |
1963 | wait_i2c_busy(ice); | ||
1958 | outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR)); | 1964 | outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR)); |
1959 | outb(dev & ~VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR)); | 1965 | outb(dev & ~VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR)); |
1960 | wait_i2c_busy(ice); | 1966 | wait_i2c_busy(ice); |
@@ -2170,6 +2176,7 @@ static int snd_vt1724_free(struct snd_ice1712 *ice) | |||
2170 | pci_release_regions(ice->pci); | 2176 | pci_release_regions(ice->pci); |
2171 | snd_ice1712_akm4xxx_free(ice); | 2177 | snd_ice1712_akm4xxx_free(ice); |
2172 | pci_disable_device(ice->pci); | 2178 | pci_disable_device(ice->pci); |
2179 | kfree(ice->spec); | ||
2173 | kfree(ice); | 2180 | kfree(ice); |
2174 | return 0; | 2181 | return 0; |
2175 | } | 2182 | } |
diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c index 1fbe3ef8e60a..e8038c0ceb72 100644 --- a/sound/pci/ice1712/juli.c +++ b/sound/pci/ice1712/juli.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <asm/io.h> | 24 | #include <asm/io.h> |
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
27 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
@@ -33,6 +32,11 @@ | |||
33 | #include "envy24ht.h" | 32 | #include "envy24ht.h" |
34 | #include "juli.h" | 33 | #include "juli.h" |
35 | 34 | ||
35 | struct juli_spec { | ||
36 | struct ak4114 *ak4114; | ||
37 | unsigned int analog: 1; | ||
38 | }; | ||
39 | |||
36 | /* | 40 | /* |
37 | * chip addresses on I2C bus | 41 | * chip addresses on I2C bus |
38 | */ | 42 | */ |
@@ -138,12 +142,13 @@ static struct snd_akm4xxx akm_juli_dac __devinitdata = { | |||
138 | 142 | ||
139 | static int __devinit juli_add_controls(struct snd_ice1712 *ice) | 143 | static int __devinit juli_add_controls(struct snd_ice1712 *ice) |
140 | { | 144 | { |
145 | struct juli_spec *spec = ice->spec; | ||
141 | int err; | 146 | int err; |
142 | err = snd_ice1712_akm4xxx_build_controls(ice); | 147 | err = snd_ice1712_akm4xxx_build_controls(ice); |
143 | if (err < 0) | 148 | if (err < 0) |
144 | return err; | 149 | return err; |
145 | /* only capture SPDIF over AK4114 */ | 150 | /* only capture SPDIF over AK4114 */ |
146 | err = snd_ak4114_build(ice->spec.juli.ak4114, NULL, | 151 | err = snd_ak4114_build(spec->ak4114, NULL, |
147 | ice->pcm_pro->streams[SNDRV_PCM_STREAM_CAPTURE].substream); | 152 | ice->pcm_pro->streams[SNDRV_PCM_STREAM_CAPTURE].substream); |
148 | if (err < 0) | 153 | if (err < 0) |
149 | return err; | 154 | return err; |
@@ -167,13 +172,19 @@ static int __devinit juli_init(struct snd_ice1712 *ice) | |||
167 | 0x41, 0x02, 0x2c, 0x00, 0x00 | 172 | 0x41, 0x02, 0x2c, 0x00, 0x00 |
168 | }; | 173 | }; |
169 | int err; | 174 | int err; |
175 | struct juli_spec *spec; | ||
170 | struct snd_akm4xxx *ak; | 176 | struct snd_akm4xxx *ak; |
171 | 177 | ||
178 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
179 | if (!spec) | ||
180 | return -ENOMEM; | ||
181 | ice->spec = spec; | ||
182 | |||
172 | err = snd_ak4114_create(ice->card, | 183 | err = snd_ak4114_create(ice->card, |
173 | juli_ak4114_read, | 184 | juli_ak4114_read, |
174 | juli_ak4114_write, | 185 | juli_ak4114_write, |
175 | ak4114_init_vals, ak4114_init_txcsb, | 186 | ak4114_init_vals, ak4114_init_txcsb, |
176 | ice, &ice->spec.juli.ak4114); | 187 | ice, &spec->ak4114); |
177 | if (err < 0) | 188 | if (err < 0) |
178 | return err; | 189 | return err; |
179 | 190 | ||
@@ -181,12 +192,12 @@ static int __devinit juli_init(struct snd_ice1712 *ice) | |||
181 | /* it seems that the analog doughter board detection does not work | 192 | /* it seems that the analog doughter board detection does not work |
182 | reliably, so force the analog flag; it should be very rare | 193 | reliably, so force the analog flag; it should be very rare |
183 | to use Juli@ without the analog doughter board */ | 194 | to use Juli@ without the analog doughter board */ |
184 | ice->spec.juli.analog = (ice->gpio.get_data(ice) & GPIO_ANALOG_PRESENT) ? 0 : 1; | 195 | spec->analog = (ice->gpio.get_data(ice) & GPIO_ANALOG_PRESENT) ? 0 : 1; |
185 | #else | 196 | #else |
186 | ice->spec.juli.analog = 1; | 197 | spec->analog = 1; |
187 | #endif | 198 | #endif |
188 | 199 | ||
189 | if (ice->spec.juli.analog) { | 200 | if (spec->analog) { |
190 | printk(KERN_INFO "juli@: analog I/O detected\n"); | 201 | printk(KERN_INFO "juli@: analog I/O detected\n"); |
191 | ice->num_total_dacs = 2; | 202 | ice->num_total_dacs = 2; |
192 | ice->num_total_adcs = 2; | 203 | ice->num_total_adcs = 2; |
diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c index 3ac25058bb58..9ab4a9f383cb 100644 --- a/sound/pci/ice1712/phase.c +++ b/sound/pci/ice1712/phase.c | |||
@@ -33,7 +33,6 @@ | |||
33 | * CDTI may be completely blocked by 74HCT125's gate #1 controlled by GPIO 3 | 33 | * CDTI may be completely blocked by 74HCT125's gate #1 controlled by GPIO 3 |
34 | */ | 34 | */ |
35 | 35 | ||
36 | #include <sound/driver.h> | ||
37 | #include <asm/io.h> | 36 | #include <asm/io.h> |
38 | #include <linux/delay.h> | 37 | #include <linux/delay.h> |
39 | #include <linux/interrupt.h> | 38 | #include <linux/interrupt.h> |
@@ -48,6 +47,12 @@ | |||
48 | #include "phase.h" | 47 | #include "phase.h" |
49 | #include <sound/tlv.h> | 48 | #include <sound/tlv.h> |
50 | 49 | ||
50 | /* AC97 register cache for Phase28 */ | ||
51 | struct phase28_spec { | ||
52 | unsigned short master[2]; | ||
53 | unsigned short vol[8]; | ||
54 | } phase28; | ||
55 | |||
51 | /* WM8770 registers */ | 56 | /* WM8770 registers */ |
52 | #define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */ | 57 | #define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */ |
53 | #define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */ | 58 | #define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */ |
@@ -313,27 +318,32 @@ static int wm_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem | |||
313 | static int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 318 | static int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
314 | { | 319 | { |
315 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 320 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
321 | struct phase28_spec *spec = ice->spec; | ||
316 | int i; | 322 | int i; |
317 | for (i=0; i<2; i++) | 323 | for (i=0; i<2; i++) |
318 | ucontrol->value.integer.value[i] = ice->spec.phase28.master[i] & ~WM_VOL_MUTE; | 324 | ucontrol->value.integer.value[i] = spec->master[i] & ~WM_VOL_MUTE; |
319 | return 0; | 325 | return 0; |
320 | } | 326 | } |
321 | 327 | ||
322 | static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 328 | static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
323 | { | 329 | { |
324 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 330 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
331 | struct phase28_spec *spec = ice->spec; | ||
325 | int ch, change = 0; | 332 | int ch, change = 0; |
326 | 333 | ||
327 | snd_ice1712_save_gpio_status(ice); | 334 | snd_ice1712_save_gpio_status(ice); |
328 | for (ch = 0; ch < 2; ch++) { | 335 | for (ch = 0; ch < 2; ch++) { |
329 | if (ucontrol->value.integer.value[ch] != ice->spec.phase28.master[ch]) { | 336 | unsigned int vol = ucontrol->value.integer.value[ch]; |
337 | if (vol > WM_VOL_MAX) | ||
338 | continue; | ||
339 | vol |= spec->master[ch] & WM_VOL_MUTE; | ||
340 | if (vol != spec->master[ch]) { | ||
330 | int dac; | 341 | int dac; |
331 | ice->spec.phase28.master[ch] &= WM_VOL_MUTE; | 342 | spec->master[ch] = vol; |
332 | ice->spec.phase28.master[ch] |= ucontrol->value.integer.value[ch]; | ||
333 | for (dac = 0; dac < ice->num_total_dacs; dac += 2) | 343 | for (dac = 0; dac < ice->num_total_dacs; dac += 2) |
334 | wm_set_vol(ice, WM_DAC_ATTEN + dac + ch, | 344 | wm_set_vol(ice, WM_DAC_ATTEN + dac + ch, |
335 | ice->spec.phase28.vol[dac + ch], | 345 | spec->vol[dac + ch], |
336 | ice->spec.phase28.master[ch]); | 346 | spec->master[ch]); |
337 | change = 1; | 347 | change = 1; |
338 | } | 348 | } |
339 | } | 349 | } |
@@ -382,12 +392,18 @@ static int __devinit phase28_init(struct snd_ice1712 *ice) | |||
382 | 392 | ||
383 | unsigned int tmp; | 393 | unsigned int tmp; |
384 | struct snd_akm4xxx *ak; | 394 | struct snd_akm4xxx *ak; |
395 | struct phase28_spec *spec; | ||
385 | const unsigned short *p; | 396 | const unsigned short *p; |
386 | int i; | 397 | int i; |
387 | 398 | ||
388 | ice->num_total_dacs = 8; | 399 | ice->num_total_dacs = 8; |
389 | ice->num_total_adcs = 2; | 400 | ice->num_total_adcs = 2; |
390 | 401 | ||
402 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
403 | if (!spec) | ||
404 | return -ENOMEM; | ||
405 | ice->spec = spec; | ||
406 | |||
391 | // Initialize analog chips | 407 | // Initialize analog chips |
392 | ak = ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); | 408 | ak = ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); |
393 | if (!ak) | 409 | if (!ak) |
@@ -417,11 +433,11 @@ static int __devinit phase28_init(struct snd_ice1712 *ice) | |||
417 | 433 | ||
418 | snd_ice1712_restore_gpio_status(ice); | 434 | snd_ice1712_restore_gpio_status(ice); |
419 | 435 | ||
420 | ice->spec.phase28.master[0] = WM_VOL_MUTE; | 436 | spec->master[0] = WM_VOL_MUTE; |
421 | ice->spec.phase28.master[1] = WM_VOL_MUTE; | 437 | spec->master[1] = WM_VOL_MUTE; |
422 | for (i = 0; i < ice->num_total_dacs; i++) { | 438 | for (i = 0; i < ice->num_total_dacs; i++) { |
423 | ice->spec.phase28.vol[i] = WM_VOL_MUTE; | 439 | spec->vol[i] = WM_VOL_MUTE; |
424 | wm_set_vol(ice, i, ice->spec.phase28.vol[i], ice->spec.phase28.master[i % 2]); | 440 | wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]); |
425 | } | 441 | } |
426 | 442 | ||
427 | return 0; | 443 | return 0; |
@@ -443,18 +459,21 @@ static int wm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info * | |||
443 | static int wm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 459 | static int wm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
444 | { | 460 | { |
445 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 461 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
462 | struct phase28_spec *spec = ice->spec; | ||
446 | int i, ofs, voices; | 463 | int i, ofs, voices; |
447 | 464 | ||
448 | voices = kcontrol->private_value >> 8; | 465 | voices = kcontrol->private_value >> 8; |
449 | ofs = kcontrol->private_value & 0xff; | 466 | ofs = kcontrol->private_value & 0xff; |
450 | for (i = 0; i < voices; i++) | 467 | for (i = 0; i < voices; i++) |
451 | ucontrol->value.integer.value[i] = ice->spec.phase28.vol[ofs+i] & ~WM_VOL_MUTE; | 468 | ucontrol->value.integer.value[i] = |
469 | spec->vol[ofs+i] & ~WM_VOL_MUTE; | ||
452 | return 0; | 470 | return 0; |
453 | } | 471 | } |
454 | 472 | ||
455 | static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 473 | static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
456 | { | 474 | { |
457 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 475 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
476 | struct phase28_spec *spec = ice->spec; | ||
458 | int i, idx, ofs, voices; | 477 | int i, idx, ofs, voices; |
459 | int change = 0; | 478 | int change = 0; |
460 | 479 | ||
@@ -462,12 +481,16 @@ static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value * | |||
462 | ofs = kcontrol->private_value & 0xff; | 481 | ofs = kcontrol->private_value & 0xff; |
463 | snd_ice1712_save_gpio_status(ice); | 482 | snd_ice1712_save_gpio_status(ice); |
464 | for (i = 0; i < voices; i++) { | 483 | for (i = 0; i < voices; i++) { |
465 | idx = WM_DAC_ATTEN + ofs + i; | 484 | unsigned int vol; |
466 | if (ucontrol->value.integer.value[i] != ice->spec.phase28.vol[ofs+i]) { | 485 | vol = ucontrol->value.integer.value[i]; |
467 | ice->spec.phase28.vol[ofs+i] &= WM_VOL_MUTE; | 486 | if (vol > 0x7f) |
468 | ice->spec.phase28.vol[ofs+i] |= ucontrol->value.integer.value[i]; | 487 | continue; |
469 | wm_set_vol(ice, idx, ice->spec.phase28.vol[ofs+i], | 488 | vol |= spec->vol[ofs+i] & WM_VOL_MUTE; |
470 | ice->spec.phase28.master[i]); | 489 | if (vol != spec->vol[ofs+i]) { |
490 | spec->vol[ofs+i] = vol; | ||
491 | idx = WM_DAC_ATTEN + ofs + i; | ||
492 | wm_set_vol(ice, idx, spec->vol[ofs+i], | ||
493 | spec->master[i]); | ||
471 | change = 1; | 494 | change = 1; |
472 | } | 495 | } |
473 | } | 496 | } |
@@ -489,19 +512,22 @@ static int wm_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info | |||
489 | static int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 512 | static int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
490 | { | 513 | { |
491 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 514 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
515 | struct phase28_spec *spec = ice->spec; | ||
492 | int voices, ofs, i; | 516 | int voices, ofs, i; |
493 | 517 | ||
494 | voices = kcontrol->private_value >> 8; | 518 | voices = kcontrol->private_value >> 8; |
495 | ofs = kcontrol->private_value & 0xFF; | 519 | ofs = kcontrol->private_value & 0xFF; |
496 | 520 | ||
497 | for (i = 0; i < voices; i++) | 521 | for (i = 0; i < voices; i++) |
498 | ucontrol->value.integer.value[i] = (ice->spec.phase28.vol[ofs+i] & WM_VOL_MUTE) ? 0 : 1; | 522 | ucontrol->value.integer.value[i] = |
523 | (spec->vol[ofs+i] & WM_VOL_MUTE) ? 0 : 1; | ||
499 | return 0; | 524 | return 0; |
500 | } | 525 | } |
501 | 526 | ||
502 | static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 527 | static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
503 | { | 528 | { |
504 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 529 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
530 | struct phase28_spec *spec = ice->spec; | ||
505 | int change = 0, voices, ofs, i; | 531 | int change = 0, voices, ofs, i; |
506 | 532 | ||
507 | voices = kcontrol->private_value >> 8; | 533 | voices = kcontrol->private_value >> 8; |
@@ -509,13 +535,13 @@ static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value | |||
509 | 535 | ||
510 | snd_ice1712_save_gpio_status(ice); | 536 | snd_ice1712_save_gpio_status(ice); |
511 | for (i = 0; i < voices; i++) { | 537 | for (i = 0; i < voices; i++) { |
512 | int val = (ice->spec.phase28.vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1; | 538 | int val = (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1; |
513 | if (ucontrol->value.integer.value[i] != val) { | 539 | if (ucontrol->value.integer.value[i] != val) { |
514 | ice->spec.phase28.vol[ofs + i] &= ~WM_VOL_MUTE; | 540 | spec->vol[ofs + i] &= ~WM_VOL_MUTE; |
515 | ice->spec.phase28.vol[ofs + i] |= | 541 | spec->vol[ofs + i] |= |
516 | ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE; | 542 | ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE; |
517 | wm_set_vol(ice, ofs + i, ice->spec.phase28.vol[ofs + i], | 543 | wm_set_vol(ice, ofs + i, spec->vol[ofs + i], |
518 | ice->spec.phase28.master[i]); | 544 | spec->master[i]); |
519 | change = 1; | 545 | change = 1; |
520 | } | 546 | } |
521 | } | 547 | } |
@@ -532,29 +558,33 @@ static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value | |||
532 | static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 558 | static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
533 | { | 559 | { |
534 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 560 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
561 | struct phase28_spec *spec = ice->spec; | ||
535 | 562 | ||
536 | ucontrol->value.integer.value[0] = (ice->spec.phase28.master[0] & WM_VOL_MUTE) ? 0 : 1; | 563 | ucontrol->value.integer.value[0] = |
537 | ucontrol->value.integer.value[1] = (ice->spec.phase28.master[1] & WM_VOL_MUTE) ? 0 : 1; | 564 | (spec->master[0] & WM_VOL_MUTE) ? 0 : 1; |
565 | ucontrol->value.integer.value[1] = | ||
566 | (spec->master[1] & WM_VOL_MUTE) ? 0 : 1; | ||
538 | return 0; | 567 | return 0; |
539 | } | 568 | } |
540 | 569 | ||
541 | static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 570 | static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
542 | { | 571 | { |
543 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 572 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
573 | struct phase28_spec *spec = ice->spec; | ||
544 | int change = 0, i; | 574 | int change = 0, i; |
545 | 575 | ||
546 | snd_ice1712_save_gpio_status(ice); | 576 | snd_ice1712_save_gpio_status(ice); |
547 | for (i = 0; i < 2; i++) { | 577 | for (i = 0; i < 2; i++) { |
548 | int val = (ice->spec.phase28.master[i] & WM_VOL_MUTE) ? 0 : 1; | 578 | int val = (spec->master[i] & WM_VOL_MUTE) ? 0 : 1; |
549 | if (ucontrol->value.integer.value[i] != val) { | 579 | if (ucontrol->value.integer.value[i] != val) { |
550 | int dac; | 580 | int dac; |
551 | ice->spec.phase28.master[i] &= ~WM_VOL_MUTE; | 581 | spec->master[i] &= ~WM_VOL_MUTE; |
552 | ice->spec.phase28.master[i] |= | 582 | spec->master[i] |= |
553 | ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE; | 583 | ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE; |
554 | for (dac = 0; dac < ice->num_total_dacs; dac += 2) | 584 | for (dac = 0; dac < ice->num_total_dacs; dac += 2) |
555 | wm_set_vol(ice, WM_DAC_ATTEN + dac + i, | 585 | wm_set_vol(ice, WM_DAC_ATTEN + dac + i, |
556 | ice->spec.phase28.vol[dac + i], | 586 | spec->vol[dac + i], |
557 | ice->spec.phase28.master[i]); | 587 | spec->master[i]); |
558 | change = 1; | 588 | change = 1; |
559 | } | 589 | } |
560 | } | 590 | } |
@@ -595,8 +625,10 @@ static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val | |||
595 | unsigned short ovol, nvol; | 625 | unsigned short ovol, nvol; |
596 | int change = 0; | 626 | int change = 0; |
597 | 627 | ||
598 | snd_ice1712_save_gpio_status(ice); | ||
599 | nvol = ucontrol->value.integer.value[0]; | 628 | nvol = ucontrol->value.integer.value[0]; |
629 | if (nvol > PCM_RES) | ||
630 | return -EINVAL; | ||
631 | snd_ice1712_save_gpio_status(ice); | ||
600 | nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff; | 632 | nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff; |
601 | ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff; | 633 | ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff; |
602 | if (ovol != nvol) { | 634 | if (ovol != nvol) { |
diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c index faefd52c1b80..4945c81e8a96 100644 --- a/sound/pci/ice1712/pontis.c +++ b/sound/pci/ice1712/pontis.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <asm/io.h> | 24 | #include <asm/io.h> |
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
27 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c index 4180f9739ecb..48cf40a8f32a 100644 --- a/sound/pci/ice1712/prodigy192.c +++ b/sound/pci/ice1712/prodigy192.c | |||
@@ -54,7 +54,6 @@ | |||
54 | * | 54 | * |
55 | */ | 55 | */ |
56 | 56 | ||
57 | #include <sound/driver.h> | ||
58 | #include <asm/io.h> | 57 | #include <asm/io.h> |
59 | #include <linux/delay.h> | 58 | #include <linux/delay.h> |
60 | #include <linux/interrupt.h> | 59 | #include <linux/interrupt.h> |
@@ -68,6 +67,12 @@ | |||
68 | #include "stac946x.h" | 67 | #include "stac946x.h" |
69 | #include <sound/tlv.h> | 68 | #include <sound/tlv.h> |
70 | 69 | ||
70 | struct prodigy192_spec { | ||
71 | struct ak4114 *ak4114; | ||
72 | /* rate change needs atomic mute/unmute of all dacs*/ | ||
73 | struct mutex mute_mutex; | ||
74 | }; | ||
75 | |||
71 | static inline void stac9460_put(struct snd_ice1712 *ice, int reg, unsigned char val) | 76 | static inline void stac9460_put(struct snd_ice1712 *ice, int reg, unsigned char val) |
72 | { | 77 | { |
73 | snd_vt1724_write_i2c(ice, PRODIGY192_STAC9460_ADDR, reg, val); | 78 | snd_vt1724_write_i2c(ice, PRODIGY192_STAC9460_ADDR, reg, val); |
@@ -81,6 +86,24 @@ static inline unsigned char stac9460_get(struct snd_ice1712 *ice, int reg) | |||
81 | /* | 86 | /* |
82 | * DAC mute control | 87 | * DAC mute control |
83 | */ | 88 | */ |
89 | |||
90 | /* | ||
91 | * idx = STAC9460 volume register number, mute: 0 = mute, 1 = unmute | ||
92 | */ | ||
93 | static int stac9460_dac_mute(struct snd_ice1712 *ice, int idx, | ||
94 | unsigned char mute) | ||
95 | { | ||
96 | unsigned char new, old; | ||
97 | int change; | ||
98 | old = stac9460_get(ice, idx); | ||
99 | new = (~mute << 7 & 0x80) | (old & ~0x80); | ||
100 | change = (new != old); | ||
101 | if (change) | ||
102 | /*printk ("Volume register 0x%02x: 0x%02x\n", idx, new);*/ | ||
103 | stac9460_put(ice, idx, new); | ||
104 | return change; | ||
105 | } | ||
106 | |||
84 | #define stac9460_dac_mute_info snd_ctl_boolean_mono_info | 107 | #define stac9460_dac_mute_info snd_ctl_boolean_mono_info |
85 | 108 | ||
86 | static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 109 | static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
@@ -101,20 +124,19 @@ static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
101 | static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 124 | static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
102 | { | 125 | { |
103 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 126 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
104 | unsigned char new, old; | 127 | struct prodigy192_spec *spec = ice->spec; |
105 | int idx; | 128 | int idx, change; |
106 | int change; | ||
107 | 129 | ||
108 | if (kcontrol->private_value) | 130 | if (kcontrol->private_value) |
109 | idx = STAC946X_MASTER_VOLUME; | 131 | idx = STAC946X_MASTER_VOLUME; |
110 | else | 132 | else |
111 | idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME; | 133 | idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME; |
112 | old = stac9460_get(ice, idx); | 134 | /* due to possible conflicts with stac9460_set_rate_val, mutexing */ |
113 | new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) | (old & ~0x80); | 135 | mutex_lock(&spec->mute_mutex); |
114 | change = (new != old); | 136 | /*printk("Mute put: reg 0x%02x, ctrl value: 0x%02x\n", idx, |
115 | if (change) | 137 | ucontrol->value.integer.value[0]);*/ |
116 | stac9460_put(ice, idx, new); | 138 | change = stac9460_dac_mute(ice, idx, ucontrol->value.integer.value[0]); |
117 | 139 | mutex_unlock(&spec->mute_mutex); | |
118 | return change; | 140 | return change; |
119 | } | 141 | } |
120 | 142 | ||
@@ -162,6 +184,8 @@ static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el | |||
162 | ovol = 0x7f - (tmp & 0x7f); | 184 | ovol = 0x7f - (tmp & 0x7f); |
163 | change = (ovol != nvol); | 185 | change = (ovol != nvol); |
164 | if (change) { | 186 | if (change) { |
187 | ovol = (0x7f - nvol) | (tmp & 0x80); | ||
188 | /*printk("DAC Volume: reg 0x%02x: 0x%02x\n", idx, ovol);*/ | ||
165 | stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80)); | 189 | stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80)); |
166 | } | 190 | } |
167 | return change; | 191 | return change; |
@@ -241,7 +265,7 @@ static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el | |||
241 | 265 | ||
242 | for (i = 0; i < 2; ++i) { | 266 | for (i = 0; i < 2; ++i) { |
243 | reg = STAC946X_MIC_L_VOLUME + i; | 267 | reg = STAC946X_MIC_L_VOLUME + i; |
244 | nvol = ucontrol->value.integer.value[i]; | 268 | nvol = ucontrol->value.integer.value[i] & 0x0f; |
245 | ovol = 0x0f - stac9460_get(ice, reg); | 269 | ovol = 0x0f - stac9460_get(ice, reg); |
246 | change = ((ovol & 0x0f) != nvol); | 270 | change = ((ovol & 0x0f) != nvol); |
247 | if (change) | 271 | if (change) |
@@ -251,121 +275,6 @@ static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el | |||
251 | return change; | 275 | return change; |
252 | } | 276 | } |
253 | 277 | ||
254 | #if 0 | ||
255 | /* | ||
256 | * Headphone Amplifier | ||
257 | */ | ||
258 | static int aureon_set_headphone_amp(struct snd_ice1712 *ice, int enable) | ||
259 | { | ||
260 | unsigned int tmp, tmp2; | ||
261 | |||
262 | tmp2 = tmp = snd_ice1712_gpio_read(ice); | ||
263 | if (enable) | ||
264 | tmp |= AUREON_HP_SEL; | ||
265 | else | ||
266 | tmp &= ~ AUREON_HP_SEL; | ||
267 | if (tmp != tmp2) { | ||
268 | snd_ice1712_gpio_write(ice, tmp); | ||
269 | return 1; | ||
270 | } | ||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | static int aureon_get_headphone_amp(struct snd_ice1712 *ice) | ||
275 | { | ||
276 | unsigned int tmp = snd_ice1712_gpio_read(ice); | ||
277 | |||
278 | return ( tmp & AUREON_HP_SEL )!= 0; | ||
279 | } | ||
280 | |||
281 | #define aureon_bool_info snd_ctl_boolean_mono_info | ||
282 | |||
283 | static int aureon_hpamp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
284 | { | ||
285 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
286 | |||
287 | ucontrol->value.integer.value[0] = aureon_get_headphone_amp(ice); | ||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | |||
292 | static int aureon_hpamp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
293 | { | ||
294 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
295 | |||
296 | return aureon_set_headphone_amp(ice,ucontrol->value.integer.value[0]); | ||
297 | } | ||
298 | |||
299 | /* | ||
300 | * Deemphasis | ||
301 | */ | ||
302 | static int aureon_deemp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
303 | { | ||
304 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
305 | ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 0xf; | ||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | static int aureon_deemp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
310 | { | ||
311 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
312 | int temp, temp2; | ||
313 | temp2 = temp = wm_get(ice, WM_DAC_CTRL2); | ||
314 | if (ucontrol->value.integer.value[0]) | ||
315 | temp |= 0xf; | ||
316 | else | ||
317 | temp &= ~0xf; | ||
318 | if (temp != temp2) { | ||
319 | wm_put(ice, WM_DAC_CTRL2, temp); | ||
320 | return 1; | ||
321 | } | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | /* | ||
326 | * ADC Oversampling | ||
327 | */ | ||
328 | static int aureon_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo) | ||
329 | { | ||
330 | static char *texts[2] = { "128x", "64x" }; | ||
331 | |||
332 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
333 | uinfo->count = 1; | ||
334 | uinfo->value.enumerated.items = 2; | ||
335 | |||
336 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
337 | uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; | ||
338 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
339 | |||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | static int aureon_oversampling_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
344 | { | ||
345 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
346 | ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 0x8; | ||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
351 | { | ||
352 | int temp, temp2; | ||
353 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
354 | |||
355 | temp2 = temp = wm_get(ice, WM_MASTER); | ||
356 | |||
357 | if (ucontrol->value.enumerated.item[0]) | ||
358 | temp |= 0x8; | ||
359 | else | ||
360 | temp &= ~0x8; | ||
361 | |||
362 | if (temp != temp2) { | ||
363 | wm_put(ice, WM_MASTER, temp); | ||
364 | return 1; | ||
365 | } | ||
366 | return 0; | ||
367 | } | ||
368 | #endif | ||
369 | static int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol, | 278 | static int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol, |
370 | struct snd_ctl_elem_info *uinfo) | 279 | struct snd_ctl_elem_info *uinfo) |
371 | { | 280 | { |
@@ -407,6 +316,57 @@ static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol, | |||
407 | stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new); | 316 | stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new); |
408 | return change; | 317 | return change; |
409 | } | 318 | } |
319 | /* | ||
320 | * Handler for setting correct codec rate - called when rate change is detected | ||
321 | */ | ||
322 | static void stac9460_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate) | ||
323 | { | ||
324 | unsigned char old, new; | ||
325 | int idx; | ||
326 | unsigned char changed[7]; | ||
327 | struct snd_ice1712 *ice = ak->private_data[0]; | ||
328 | struct prodigy192_spec *spec = ice->spec; | ||
329 | |||
330 | if (rate == 0) /* no hint - S/PDIF input is master, simply return */ | ||
331 | return; | ||
332 | else if (rate <= 48000) | ||
333 | new = 0x08; /* 256x, base rate mode */ | ||
334 | else if (rate <= 96000) | ||
335 | new = 0x11; /* 256x, mid rate mode */ | ||
336 | else | ||
337 | new = 0x12; /* 128x, high rate mode */ | ||
338 | old = stac9460_get(ice, STAC946X_MASTER_CLOCKING); | ||
339 | if (old == new) | ||
340 | return; | ||
341 | /* change detected, setting master clock, muting first */ | ||
342 | /* due to possible conflicts with mute controls - mutexing */ | ||
343 | mutex_lock(&spec->mute_mutex); | ||
344 | /* we have to remember current mute status for each DAC */ | ||
345 | for (idx = 0; idx < 7 ; ++idx) | ||
346 | changed[idx] = stac9460_dac_mute(ice, | ||
347 | STAC946X_MASTER_VOLUME + idx, 0); | ||
348 | /*printk("Rate change: %d, new MC: 0x%02x\n", rate, new);*/ | ||
349 | stac9460_put(ice, STAC946X_MASTER_CLOCKING, new); | ||
350 | udelay(10); | ||
351 | /* unmuting - only originally unmuted dacs - | ||
352 | * i.e. those changed when muting */ | ||
353 | for (idx = 0; idx < 7 ; ++idx) { | ||
354 | if (changed[idx]) | ||
355 | stac9460_dac_mute(ice, STAC946X_MASTER_VOLUME + idx, 1); | ||
356 | } | ||
357 | mutex_unlock(&spec->mute_mutex); | ||
358 | } | ||
359 | |||
360 | /* using akm infrastructure for setting rate of the codec */ | ||
361 | static struct snd_akm4xxx akmlike_stac9460 __devinitdata = { | ||
362 | .type = NON_AKM, /* special value */ | ||
363 | .num_adcs = 6, /* not used in any way, just for completeness */ | ||
364 | .num_dacs = 2, | ||
365 | .ops = { | ||
366 | .set_rate_val = stac9460_set_rate_val | ||
367 | } | ||
368 | }; | ||
369 | |||
410 | 370 | ||
411 | static const DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0); | 371 | static const DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0); |
412 | static const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0); | 372 | static const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0); |
@@ -483,39 +443,8 @@ static struct snd_kcontrol_new stac_controls[] __devinitdata = { | |||
483 | .put = stac9460_mic_sw_put, | 443 | .put = stac9460_mic_sw_put, |
484 | 444 | ||
485 | }, | 445 | }, |
486 | #if 0 | ||
487 | { | ||
488 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
489 | .name = "Capture Route", | ||
490 | .info = wm_adc_mux_info, | ||
491 | .get = wm_adc_mux_get, | ||
492 | .put = wm_adc_mux_put, | ||
493 | }, | ||
494 | { | ||
495 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
496 | .name = "Headphone Amplifier Switch", | ||
497 | .info = aureon_bool_info, | ||
498 | .get = aureon_hpamp_get, | ||
499 | .put = aureon_hpamp_put | ||
500 | }, | ||
501 | { | ||
502 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
503 | .name = "DAC Deemphasis Switch", | ||
504 | .info = aureon_bool_info, | ||
505 | .get = aureon_deemp_get, | ||
506 | .put = aureon_deemp_put | ||
507 | }, | ||
508 | { | ||
509 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
510 | .name = "ADC Oversampling", | ||
511 | .info = aureon_oversampling_info, | ||
512 | .get = aureon_oversampling_get, | ||
513 | .put = aureon_oversampling_put | ||
514 | }, | ||
515 | #endif | ||
516 | }; | 446 | }; |
517 | 447 | ||
518 | |||
519 | /* AK4114 - ICE1724 connections on Prodigy192 + MI/ODI/O */ | 448 | /* AK4114 - ICE1724 connections on Prodigy192 + MI/ODI/O */ |
520 | /* CDTO (pin 32) -- GPIO11 pin 86 | 449 | /* CDTO (pin 32) -- GPIO11 pin 86 |
521 | * CDTI (pin 33) -- GPIO10 pin 77 | 450 | * CDTI (pin 33) -- GPIO10 pin 77 |
@@ -712,16 +641,39 @@ static int prodigy192_ak4114_init(struct snd_ice1712 *ice) | |||
712 | static const unsigned char ak4114_init_txcsb[] = { | 641 | static const unsigned char ak4114_init_txcsb[] = { |
713 | 0x41, 0x02, 0x2c, 0x00, 0x00 | 642 | 0x41, 0x02, 0x2c, 0x00, 0x00 |
714 | }; | 643 | }; |
644 | struct prodigy192_spec *spec = ice->spec; | ||
715 | 645 | ||
716 | return snd_ak4114_create(ice->card, | 646 | return snd_ak4114_create(ice->card, |
717 | prodigy192_ak4114_read, | 647 | prodigy192_ak4114_read, |
718 | prodigy192_ak4114_write, | 648 | prodigy192_ak4114_write, |
719 | ak4114_init_vals, ak4114_init_txcsb, | 649 | ak4114_init_vals, ak4114_init_txcsb, |
720 | ice, &ice->spec.prodigy192.ak4114); | 650 | ice, &spec->ak4114); |
651 | } | ||
652 | |||
653 | static void stac9460_proc_regs_read(struct snd_info_entry *entry, | ||
654 | struct snd_info_buffer *buffer) | ||
655 | { | ||
656 | struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; | ||
657 | int reg, val; | ||
658 | /* registers 0x0 - 0x14 */ | ||
659 | for (reg = 0; reg <= 0x15; reg++) { | ||
660 | val = stac9460_get(ice, reg); | ||
661 | snd_iprintf(buffer, "0x%02x = 0x%02x\n", reg, val); | ||
662 | } | ||
663 | } | ||
664 | |||
665 | |||
666 | static void stac9460_proc_init(struct snd_ice1712 *ice) | ||
667 | { | ||
668 | struct snd_info_entry *entry; | ||
669 | if (!snd_card_proc_new(ice->card, "stac9460_codec", &entry)) | ||
670 | snd_info_set_text_ops(entry, ice, stac9460_proc_regs_read); | ||
721 | } | 671 | } |
722 | 672 | ||
673 | |||
723 | static int __devinit prodigy192_add_controls(struct snd_ice1712 *ice) | 674 | static int __devinit prodigy192_add_controls(struct snd_ice1712 *ice) |
724 | { | 675 | { |
676 | struct prodigy192_spec *spec = ice->spec; | ||
725 | unsigned int i; | 677 | unsigned int i; |
726 | int err; | 678 | int err; |
727 | 679 | ||
@@ -731,7 +683,7 @@ static int __devinit prodigy192_add_controls(struct snd_ice1712 *ice) | |||
731 | if (err < 0) | 683 | if (err < 0) |
732 | return err; | 684 | return err; |
733 | } | 685 | } |
734 | if (ice->spec.prodigy192.ak4114) { | 686 | if (spec->ak4114) { |
735 | /* ak4114 is connected */ | 687 | /* ak4114 is connected */ |
736 | for (i = 0; i < ARRAY_SIZE(ak4114_controls); i++) { | 688 | for (i = 0; i < ARRAY_SIZE(ak4114_controls); i++) { |
737 | err = snd_ctl_add(ice->card, | 689 | err = snd_ctl_add(ice->card, |
@@ -740,12 +692,13 @@ static int __devinit prodigy192_add_controls(struct snd_ice1712 *ice) | |||
740 | if (err < 0) | 692 | if (err < 0) |
741 | return err; | 693 | return err; |
742 | } | 694 | } |
743 | err = snd_ak4114_build(ice->spec.prodigy192.ak4114, | 695 | err = snd_ak4114_build(spec->ak4114, |
744 | NULL, /* ak4114 in MIO/DI/O handles no IEC958 output */ | 696 | NULL, /* ak4114 in MIO/DI/O handles no IEC958 output */ |
745 | ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream); | 697 | ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream); |
746 | if (err < 0) | 698 | if (err < 0) |
747 | return err; | 699 | return err; |
748 | } | 700 | } |
701 | stac9460_proc_init(ice); | ||
749 | return 0; | 702 | return 0; |
750 | } | 703 | } |
751 | 704 | ||
@@ -778,6 +731,7 @@ static int __devinit prodigy192_init(struct snd_ice1712 *ice) | |||
778 | { | 731 | { |
779 | static const unsigned short stac_inits_prodigy[] = { | 732 | static const unsigned short stac_inits_prodigy[] = { |
780 | STAC946X_RESET, 0, | 733 | STAC946X_RESET, 0, |
734 | STAC946X_MASTER_CLOCKING, 0x11, | ||
781 | /* STAC946X_MASTER_VOLUME, 0, | 735 | /* STAC946X_MASTER_VOLUME, 0, |
782 | STAC946X_LF_VOLUME, 0, | 736 | STAC946X_LF_VOLUME, 0, |
783 | STAC946X_RF_VOLUME, 0, | 737 | STAC946X_RF_VOLUME, 0, |
@@ -789,22 +743,39 @@ static int __devinit prodigy192_init(struct snd_ice1712 *ice) | |||
789 | }; | 743 | }; |
790 | const unsigned short *p; | 744 | const unsigned short *p; |
791 | int err = 0; | 745 | int err = 0; |
746 | struct snd_akm4xxx *ak; | ||
747 | struct prodigy192_spec *spec; | ||
792 | 748 | ||
793 | /* prodigy 192 */ | 749 | /* prodigy 192 */ |
794 | ice->num_total_dacs = 6; | 750 | ice->num_total_dacs = 6; |
795 | ice->num_total_adcs = 2; | 751 | ice->num_total_adcs = 2; |
796 | ice->vt1720 = 0; /* ice1724, e.g. 23 GPIOs */ | 752 | ice->vt1720 = 0; /* ice1724, e.g. 23 GPIOs */ |
797 | 753 | ||
754 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
755 | if (!spec) | ||
756 | return -ENOMEM; | ||
757 | ice->spec = spec; | ||
758 | mutex_init(&spec->mute_mutex); | ||
759 | |||
798 | /* initialize codec */ | 760 | /* initialize codec */ |
799 | p = stac_inits_prodigy; | 761 | p = stac_inits_prodigy; |
800 | for (; *p != (unsigned short)-1; p += 2) | 762 | for (; *p != (unsigned short)-1; p += 2) |
801 | stac9460_put(ice, p[0], p[1]); | 763 | stac9460_put(ice, p[0], p[1]); |
764 | /* reusing the akm codecs infrastructure, | ||
765 | * for setting rate on stac9460 */ | ||
766 | ak = ice->akm = kmalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); | ||
767 | if (!ak) | ||
768 | return -ENOMEM; | ||
769 | ice->akm_codecs = 1; | ||
770 | err = snd_ice1712_akm4xxx_init(ak, &akmlike_stac9460, NULL, ice); | ||
771 | if (err < 0) | ||
772 | return err; | ||
802 | 773 | ||
803 | /* MI/ODI/O add on card with AK4114 */ | 774 | /* MI/ODI/O add on card with AK4114 */ |
804 | if (prodigy192_miodio_exists(ice)) { | 775 | if (prodigy192_miodio_exists(ice)) { |
805 | err = prodigy192_ak4114_init(ice); | 776 | err = prodigy192_ak4114_init(ice); |
806 | /* from this moment if err = 0 then | 777 | /* from this moment if err = 0 then |
807 | * ice->spec.prodigy192.ak4114 should not be null | 778 | * spec->ak4114 should not be null |
808 | */ | 779 | */ |
809 | snd_printdd("AK4114 initialized with status %d\n", err); | 780 | snd_printdd("AK4114 initialized with status %d\n", err); |
810 | } else | 781 | } else |
@@ -854,6 +825,10 @@ struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[] __devinitdata = { | |||
854 | .build_controls = prodigy192_add_controls, | 825 | .build_controls = prodigy192_add_controls, |
855 | .eeprom_size = sizeof(prodigy71_eeprom), | 826 | .eeprom_size = sizeof(prodigy71_eeprom), |
856 | .eeprom_data = prodigy71_eeprom, | 827 | .eeprom_data = prodigy71_eeprom, |
828 | /* the current MPU401 code loops infinitely | ||
829 | * when opening midi device | ||
830 | */ | ||
831 | .no_mpu401 = 1, | ||
857 | }, | 832 | }, |
858 | { } /* terminator */ | 833 | { } /* terminator */ |
859 | }; | 834 | }; |
diff --git a/sound/pci/ice1712/prodigy_hifi.c b/sound/pci/ice1712/prodigy_hifi.c new file mode 100644 index 000000000000..043a93879bd5 --- /dev/null +++ b/sound/pci/ice1712/prodigy_hifi.c | |||
@@ -0,0 +1,1210 @@ | |||
1 | /* | ||
2 | * ALSA driver for ICEnsemble VT1724 (Envy24HT) | ||
3 | * | ||
4 | * Lowlevel functions for Audiotrak Prodigy 7.1 Hifi | ||
5 | * based on pontis.c | ||
6 | * | ||
7 | * Copyright (c) 2007 Julian Scheel <julian@jusst.de> | ||
8 | * Copyright (c) 2007 allank | ||
9 | * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | |||
28 | #include <asm/io.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/mutex.h> | ||
34 | |||
35 | #include <sound/core.h> | ||
36 | #include <sound/info.h> | ||
37 | #include <sound/tlv.h> | ||
38 | |||
39 | #include "ice1712.h" | ||
40 | #include "envy24ht.h" | ||
41 | #include "prodigy_hifi.h" | ||
42 | |||
43 | struct prodigy_hifi_spec { | ||
44 | unsigned short master[2]; | ||
45 | unsigned short vol[8]; | ||
46 | }; | ||
47 | |||
48 | /* I2C addresses */ | ||
49 | #define WM_DEV 0x34 | ||
50 | |||
51 | /* WM8776 registers */ | ||
52 | #define WM_HP_ATTEN_L 0x00 /* headphone left attenuation */ | ||
53 | #define WM_HP_ATTEN_R 0x01 /* headphone left attenuation */ | ||
54 | #define WM_HP_MASTER 0x02 /* headphone master (both channels), | ||
55 | override LLR */ | ||
56 | #define WM_DAC_ATTEN_L 0x03 /* digital left attenuation */ | ||
57 | #define WM_DAC_ATTEN_R 0x04 | ||
58 | #define WM_DAC_MASTER 0x05 | ||
59 | #define WM_PHASE_SWAP 0x06 /* DAC phase swap */ | ||
60 | #define WM_DAC_CTRL1 0x07 | ||
61 | #define WM_DAC_MUTE 0x08 | ||
62 | #define WM_DAC_CTRL2 0x09 | ||
63 | #define WM_DAC_INT 0x0a | ||
64 | #define WM_ADC_INT 0x0b | ||
65 | #define WM_MASTER_CTRL 0x0c | ||
66 | #define WM_POWERDOWN 0x0d | ||
67 | #define WM_ADC_ATTEN_L 0x0e | ||
68 | #define WM_ADC_ATTEN_R 0x0f | ||
69 | #define WM_ALC_CTRL1 0x10 | ||
70 | #define WM_ALC_CTRL2 0x11 | ||
71 | #define WM_ALC_CTRL3 0x12 | ||
72 | #define WM_NOISE_GATE 0x13 | ||
73 | #define WM_LIMITER 0x14 | ||
74 | #define WM_ADC_MUX 0x15 | ||
75 | #define WM_OUT_MUX 0x16 | ||
76 | #define WM_RESET 0x17 | ||
77 | |||
78 | /* Analog Recording Source :- Mic, LineIn, CD/Video, */ | ||
79 | |||
80 | /* implement capture source select control for WM8776 */ | ||
81 | |||
82 | #define WM_AIN1 "AIN1" | ||
83 | #define WM_AIN2 "AIN2" | ||
84 | #define WM_AIN3 "AIN3" | ||
85 | #define WM_AIN4 "AIN4" | ||
86 | #define WM_AIN5 "AIN5" | ||
87 | |||
88 | /* GPIO pins of envy24ht connected to wm8766 */ | ||
89 | #define WM8766_SPI_CLK (1<<17) /* CLK, Pin97 on ICE1724 */ | ||
90 | #define WM8766_SPI_MD (1<<16) /* DATA VT1724 -> WM8766, Pin96 */ | ||
91 | #define WM8766_SPI_ML (1<<18) /* Latch, Pin98 */ | ||
92 | |||
93 | /* WM8766 registers */ | ||
94 | #define WM8766_DAC_CTRL 0x02 /* DAC Control */ | ||
95 | #define WM8766_INT_CTRL 0x03 /* Interface Control */ | ||
96 | #define WM8766_DAC_CTRL2 0x09 | ||
97 | #define WM8766_DAC_CTRL3 0x0a | ||
98 | #define WM8766_RESET 0x1f | ||
99 | #define WM8766_LDA1 0x00 | ||
100 | #define WM8766_LDA2 0x04 | ||
101 | #define WM8766_LDA3 0x06 | ||
102 | #define WM8766_RDA1 0x01 | ||
103 | #define WM8766_RDA2 0x05 | ||
104 | #define WM8766_RDA3 0x07 | ||
105 | #define WM8766_MUTE1 0x0C | ||
106 | #define WM8766_MUTE2 0x0F | ||
107 | |||
108 | |||
109 | /* | ||
110 | * Prodigy HD2 | ||
111 | */ | ||
112 | #define AK4396_ADDR 0x00 | ||
113 | #define AK4396_CSN (1 << 8) /* CSN->GPIO8, pin 75 */ | ||
114 | #define AK4396_CCLK (1 << 9) /* CCLK->GPIO9, pin 76 */ | ||
115 | #define AK4396_CDTI (1 << 10) /* CDTI->GPIO10, pin 77 */ | ||
116 | |||
117 | /* ak4396 registers */ | ||
118 | #define AK4396_CTRL1 0x00 | ||
119 | #define AK4396_CTRL2 0x01 | ||
120 | #define AK4396_CTRL3 0x02 | ||
121 | #define AK4396_LCH_ATT 0x03 | ||
122 | #define AK4396_RCH_ATT 0x04 | ||
123 | |||
124 | |||
125 | /* | ||
126 | * get the current register value of WM codec | ||
127 | */ | ||
128 | static unsigned short wm_get(struct snd_ice1712 *ice, int reg) | ||
129 | { | ||
130 | reg <<= 1; | ||
131 | return ((unsigned short)ice->akm[0].images[reg] << 8) | | ||
132 | ice->akm[0].images[reg + 1]; | ||
133 | } | ||
134 | |||
135 | /* | ||
136 | * set the register value of WM codec and remember it | ||
137 | */ | ||
138 | static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val) | ||
139 | { | ||
140 | unsigned short cval; | ||
141 | cval = (reg << 9) | val; | ||
142 | snd_vt1724_write_i2c(ice, WM_DEV, cval >> 8, cval & 0xff); | ||
143 | } | ||
144 | |||
145 | static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val) | ||
146 | { | ||
147 | wm_put_nocache(ice, reg, val); | ||
148 | reg <<= 1; | ||
149 | ice->akm[0].images[reg] = val >> 8; | ||
150 | ice->akm[0].images[reg + 1] = val; | ||
151 | } | ||
152 | |||
153 | /* | ||
154 | * write data in the SPI mode | ||
155 | */ | ||
156 | |||
157 | static void set_gpio_bit(struct snd_ice1712 *ice, unsigned int bit, int val) | ||
158 | { | ||
159 | unsigned int tmp = snd_ice1712_gpio_read(ice); | ||
160 | if (val) | ||
161 | tmp |= bit; | ||
162 | else | ||
163 | tmp &= ~bit; | ||
164 | snd_ice1712_gpio_write(ice, tmp); | ||
165 | } | ||
166 | |||
167 | /* | ||
168 | * SPI implementation for WM8766 codec - only writing supported, no readback | ||
169 | */ | ||
170 | |||
171 | static void wm8766_spi_send_word(struct snd_ice1712 *ice, unsigned int data) | ||
172 | { | ||
173 | int i; | ||
174 | for (i = 0; i < 16; i++) { | ||
175 | set_gpio_bit(ice, WM8766_SPI_CLK, 0); | ||
176 | udelay(1); | ||
177 | set_gpio_bit(ice, WM8766_SPI_MD, data & 0x8000); | ||
178 | udelay(1); | ||
179 | set_gpio_bit(ice, WM8766_SPI_CLK, 1); | ||
180 | udelay(1); | ||
181 | data <<= 1; | ||
182 | } | ||
183 | } | ||
184 | |||
185 | static void wm8766_spi_write(struct snd_ice1712 *ice, unsigned int reg, | ||
186 | unsigned int data) | ||
187 | { | ||
188 | unsigned int block; | ||
189 | |||
190 | snd_ice1712_gpio_set_dir(ice, WM8766_SPI_MD| | ||
191 | WM8766_SPI_CLK|WM8766_SPI_ML); | ||
192 | snd_ice1712_gpio_set_mask(ice, ~(WM8766_SPI_MD| | ||
193 | WM8766_SPI_CLK|WM8766_SPI_ML)); | ||
194 | /* latch must be low when writing */ | ||
195 | set_gpio_bit(ice, WM8766_SPI_ML, 0); | ||
196 | block = (reg << 9) | (data & 0x1ff); | ||
197 | wm8766_spi_send_word(ice, block); /* REGISTER ADDRESS */ | ||
198 | /* release latch */ | ||
199 | set_gpio_bit(ice, WM8766_SPI_ML, 1); | ||
200 | udelay(1); | ||
201 | /* restore */ | ||
202 | snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask); | ||
203 | snd_ice1712_gpio_set_dir(ice, ice->gpio.direction); | ||
204 | } | ||
205 | |||
206 | |||
207 | /* | ||
208 | * serial interface for ak4396 - only writing supported, no readback | ||
209 | */ | ||
210 | |||
211 | static void ak4396_send_word(struct snd_ice1712 *ice, unsigned int data) | ||
212 | { | ||
213 | int i; | ||
214 | for (i = 0; i < 16; i++) { | ||
215 | set_gpio_bit(ice, AK4396_CCLK, 0); | ||
216 | udelay(1); | ||
217 | set_gpio_bit(ice, AK4396_CDTI, data & 0x8000); | ||
218 | udelay(1); | ||
219 | set_gpio_bit(ice, AK4396_CCLK, 1); | ||
220 | udelay(1); | ||
221 | data <<= 1; | ||
222 | } | ||
223 | } | ||
224 | |||
225 | static void ak4396_write(struct snd_ice1712 *ice, unsigned int reg, | ||
226 | unsigned int data) | ||
227 | { | ||
228 | unsigned int block; | ||
229 | |||
230 | snd_ice1712_gpio_set_dir(ice, AK4396_CSN|AK4396_CCLK|AK4396_CDTI); | ||
231 | snd_ice1712_gpio_set_mask(ice, ~(AK4396_CSN|AK4396_CCLK|AK4396_CDTI)); | ||
232 | /* latch must be low when writing */ | ||
233 | set_gpio_bit(ice, AK4396_CSN, 0); | ||
234 | block = ((AK4396_ADDR & 0x03) << 14) | (1 << 13) | | ||
235 | ((reg & 0x1f) << 8) | (data & 0xff); | ||
236 | ak4396_send_word(ice, block); /* REGISTER ADDRESS */ | ||
237 | /* release latch */ | ||
238 | set_gpio_bit(ice, AK4396_CSN, 1); | ||
239 | udelay(1); | ||
240 | /* restore */ | ||
241 | snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask); | ||
242 | snd_ice1712_gpio_set_dir(ice, ice->gpio.direction); | ||
243 | } | ||
244 | |||
245 | |||
246 | /* | ||
247 | * ak4396 mixers | ||
248 | */ | ||
249 | |||
250 | |||
251 | |||
252 | /* | ||
253 | * DAC volume attenuation mixer control (-64dB to 0dB) | ||
254 | */ | ||
255 | |||
256 | static int ak4396_dac_vol_info(struct snd_kcontrol *kcontrol, | ||
257 | struct snd_ctl_elem_info *uinfo) | ||
258 | { | ||
259 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
260 | uinfo->count = 2; | ||
261 | uinfo->value.integer.min = 0; /* mute */ | ||
262 | uinfo->value.integer.max = 0xFF; /* linear */ | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | static int ak4396_dac_vol_get(struct snd_kcontrol *kcontrol, | ||
267 | struct snd_ctl_elem_value *ucontrol) | ||
268 | { | ||
269 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
270 | struct prodigy_hifi_spec *spec = ice->spec; | ||
271 | int i; | ||
272 | |||
273 | for (i = 0; i < 2; i++) | ||
274 | ucontrol->value.integer.value[i] = spec->vol[i]; | ||
275 | |||
276 | return 0; | ||
277 | } | ||
278 | |||
279 | static int ak4396_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
280 | { | ||
281 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
282 | struct prodigy_hifi_spec *spec = ice->spec; | ||
283 | int i; | ||
284 | int change = 0; | ||
285 | |||
286 | mutex_lock(&ice->gpio_mutex); | ||
287 | for (i = 0; i < 2; i++) { | ||
288 | if (ucontrol->value.integer.value[i] != spec->vol[i]) { | ||
289 | spec->vol[i] = ucontrol->value.integer.value[i]; | ||
290 | ak4396_write(ice, AK4396_LCH_ATT + i, | ||
291 | spec->vol[i] & 0xff); | ||
292 | change = 1; | ||
293 | } | ||
294 | } | ||
295 | mutex_unlock(&ice->gpio_mutex); | ||
296 | return change; | ||
297 | } | ||
298 | |||
299 | static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1); | ||
300 | |||
301 | static struct snd_kcontrol_new prodigy_hd2_controls[] __devinitdata = { | ||
302 | { | ||
303 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
304 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
305 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
306 | .name = "Front Playback Volume", | ||
307 | .info = ak4396_dac_vol_info, | ||
308 | .get = ak4396_dac_vol_get, | ||
309 | .put = ak4396_dac_vol_put, | ||
310 | .tlv = { .p = db_scale_wm_dac }, | ||
311 | }, | ||
312 | }; | ||
313 | |||
314 | |||
315 | /* --------------- */ | ||
316 | |||
317 | /* | ||
318 | * Logarithmic volume values for WM87*6 | ||
319 | * Computed as 20 * Log10(255 / x) | ||
320 | */ | ||
321 | static const unsigned char wm_vol[256] = { | ||
322 | 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23, | ||
323 | 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17, | ||
324 | 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, | ||
325 | 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, | ||
326 | 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, | ||
327 | 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, | ||
328 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, | ||
329 | 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, | ||
330 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | ||
331 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | ||
332 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
333 | 0, 0 | ||
334 | }; | ||
335 | |||
336 | #define WM_VOL_MAX (sizeof(wm_vol) - 1) | ||
337 | #define WM_VOL_MUTE 0x8000 | ||
338 | |||
339 | |||
340 | #define DAC_0dB 0xff | ||
341 | #define DAC_RES 128 | ||
342 | #define DAC_MIN (DAC_0dB - DAC_RES) | ||
343 | |||
344 | |||
345 | static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, | ||
346 | unsigned short vol, unsigned short master) | ||
347 | { | ||
348 | unsigned char nvol; | ||
349 | |||
350 | if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE)) | ||
351 | nvol = 0; | ||
352 | else { | ||
353 | nvol = (((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 128) | ||
354 | & WM_VOL_MAX; | ||
355 | nvol = (nvol ? (nvol + DAC_MIN) : 0) & 0xff; | ||
356 | } | ||
357 | |||
358 | wm_put(ice, index, nvol); | ||
359 | wm_put_nocache(ice, index, 0x100 | nvol); | ||
360 | } | ||
361 | |||
362 | static void wm8766_set_vol(struct snd_ice1712 *ice, unsigned int index, | ||
363 | unsigned short vol, unsigned short master) | ||
364 | { | ||
365 | unsigned char nvol; | ||
366 | |||
367 | if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE)) | ||
368 | nvol = 0; | ||
369 | else { | ||
370 | nvol = (((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 128) | ||
371 | & WM_VOL_MAX; | ||
372 | nvol = (nvol ? (nvol + DAC_MIN) : 0) & 0xff; | ||
373 | } | ||
374 | |||
375 | wm8766_spi_write(ice, index, (0x0100 | nvol)); | ||
376 | } | ||
377 | |||
378 | |||
379 | /* | ||
380 | * DAC volume attenuation mixer control (-64dB to 0dB) | ||
381 | */ | ||
382 | |||
383 | static int wm_dac_vol_info(struct snd_kcontrol *kcontrol, | ||
384 | struct snd_ctl_elem_info *uinfo) | ||
385 | { | ||
386 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
387 | uinfo->count = 2; | ||
388 | uinfo->value.integer.min = 0; /* mute */ | ||
389 | uinfo->value.integer.max = DAC_RES; /* 0dB, 0.5dB step */ | ||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | static int wm_dac_vol_get(struct snd_kcontrol *kcontrol, | ||
394 | struct snd_ctl_elem_value *ucontrol) | ||
395 | { | ||
396 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
397 | struct prodigy_hifi_spec *spec = ice->spec; | ||
398 | int i; | ||
399 | |||
400 | for (i = 0; i < 2; i++) | ||
401 | ucontrol->value.integer.value[i] = | ||
402 | spec->vol[2 + i] & ~WM_VOL_MUTE; | ||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | static int wm_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
407 | { | ||
408 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
409 | struct prodigy_hifi_spec *spec = ice->spec; | ||
410 | int i, idx, change = 0; | ||
411 | |||
412 | mutex_lock(&ice->gpio_mutex); | ||
413 | for (i = 0; i < 2; i++) { | ||
414 | if (ucontrol->value.integer.value[i] != spec->vol[2 + i]) { | ||
415 | idx = WM_DAC_ATTEN_L + i; | ||
416 | spec->vol[2 + i] &= WM_VOL_MUTE; | ||
417 | spec->vol[2 + i] |= ucontrol->value.integer.value[i]; | ||
418 | wm_set_vol(ice, idx, spec->vol[2 + i], spec->master[i]); | ||
419 | change = 1; | ||
420 | } | ||
421 | } | ||
422 | mutex_unlock(&ice->gpio_mutex); | ||
423 | return change; | ||
424 | } | ||
425 | |||
426 | |||
427 | /* | ||
428 | * WM8766 DAC volume attenuation mixer control | ||
429 | */ | ||
430 | static int wm8766_vol_info(struct snd_kcontrol *kcontrol, | ||
431 | struct snd_ctl_elem_info *uinfo) | ||
432 | { | ||
433 | int voices = kcontrol->private_value >> 8; | ||
434 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
435 | uinfo->count = voices; | ||
436 | uinfo->value.integer.min = 0; /* mute */ | ||
437 | uinfo->value.integer.max = DAC_RES; /* 0dB */ | ||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | static int wm8766_vol_get(struct snd_kcontrol *kcontrol, | ||
442 | struct snd_ctl_elem_value *ucontrol) | ||
443 | { | ||
444 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
445 | struct prodigy_hifi_spec *spec = ice->spec; | ||
446 | int i, ofs, voices; | ||
447 | |||
448 | voices = kcontrol->private_value >> 8; | ||
449 | ofs = kcontrol->private_value & 0xff; | ||
450 | for (i = 0; i < voices; i++) | ||
451 | ucontrol->value.integer.value[i] = spec->vol[ofs + i]; | ||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | static int wm8766_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
456 | { | ||
457 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
458 | struct prodigy_hifi_spec *spec = ice->spec; | ||
459 | int i, idx, ofs, voices; | ||
460 | int change = 0; | ||
461 | |||
462 | voices = kcontrol->private_value >> 8; | ||
463 | ofs = kcontrol->private_value & 0xff; | ||
464 | mutex_lock(&ice->gpio_mutex); | ||
465 | for (i = 0; i < voices; i++) { | ||
466 | if (ucontrol->value.integer.value[i] != spec->vol[ofs + i]) { | ||
467 | idx = WM8766_LDA1 + ofs + i; | ||
468 | spec->vol[ofs + i] &= WM_VOL_MUTE; | ||
469 | spec->vol[ofs + i] |= ucontrol->value.integer.value[i]; | ||
470 | wm8766_set_vol(ice, idx, | ||
471 | spec->vol[ofs + i], spec->master[i]); | ||
472 | change = 1; | ||
473 | } | ||
474 | } | ||
475 | mutex_unlock(&ice->gpio_mutex); | ||
476 | return change; | ||
477 | } | ||
478 | |||
479 | /* | ||
480 | * Master volume attenuation mixer control / applied to WM8776+WM8766 | ||
481 | */ | ||
482 | static int wm_master_vol_info(struct snd_kcontrol *kcontrol, | ||
483 | struct snd_ctl_elem_info *uinfo) | ||
484 | { | ||
485 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
486 | uinfo->count = 2; | ||
487 | uinfo->value.integer.min = 0; | ||
488 | uinfo->value.integer.max = DAC_RES; | ||
489 | return 0; | ||
490 | } | ||
491 | |||
492 | static int wm_master_vol_get(struct snd_kcontrol *kcontrol, | ||
493 | struct snd_ctl_elem_value *ucontrol) | ||
494 | { | ||
495 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
496 | struct prodigy_hifi_spec *spec = ice->spec; | ||
497 | int i; | ||
498 | for (i = 0; i < 2; i++) | ||
499 | ucontrol->value.integer.value[i] = spec->master[i]; | ||
500 | return 0; | ||
501 | } | ||
502 | |||
503 | static int wm_master_vol_put(struct snd_kcontrol *kcontrol, | ||
504 | struct snd_ctl_elem_value *ucontrol) | ||
505 | { | ||
506 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
507 | struct prodigy_hifi_spec *spec = ice->spec; | ||
508 | int ch, change = 0; | ||
509 | |||
510 | mutex_lock(&ice->gpio_mutex); | ||
511 | for (ch = 0; ch < 2; ch++) { | ||
512 | if (ucontrol->value.integer.value[ch] != spec->master[ch]) { | ||
513 | spec->master[ch] = ucontrol->value.integer.value[ch]; | ||
514 | |||
515 | /* Apply to front DAC */ | ||
516 | wm_set_vol(ice, WM_DAC_ATTEN_L + ch, | ||
517 | spec->vol[2 + ch], spec->master[ch]); | ||
518 | |||
519 | wm8766_set_vol(ice, WM8766_LDA1 + ch, | ||
520 | spec->vol[0 + ch], spec->master[ch]); | ||
521 | |||
522 | wm8766_set_vol(ice, WM8766_LDA2 + ch, | ||
523 | spec->vol[4 + ch], spec->master[ch]); | ||
524 | |||
525 | wm8766_set_vol(ice, WM8766_LDA3 + ch, | ||
526 | spec->vol[6 + ch], spec->master[ch]); | ||
527 | change = 1; | ||
528 | } | ||
529 | } | ||
530 | mutex_unlock(&ice->gpio_mutex); | ||
531 | return change; | ||
532 | } | ||
533 | |||
534 | |||
535 | /* KONSTI */ | ||
536 | |||
537 | static int wm_adc_mux_enum_info(struct snd_kcontrol *kcontrol, | ||
538 | struct snd_ctl_elem_info *uinfo) | ||
539 | { | ||
540 | static char* texts[32] = { | ||
541 | "NULL", WM_AIN1, WM_AIN2, WM_AIN1 "+" WM_AIN2, | ||
542 | WM_AIN3, WM_AIN1 "+" WM_AIN3, WM_AIN2 "+" WM_AIN3, | ||
543 | WM_AIN1 "+" WM_AIN2 "+" WM_AIN3, | ||
544 | WM_AIN4, WM_AIN1 "+" WM_AIN4, WM_AIN2 "+" WM_AIN4, | ||
545 | WM_AIN1 "+" WM_AIN2 "+" WM_AIN4, | ||
546 | WM_AIN3 "+" WM_AIN4, WM_AIN1 "+" WM_AIN3 "+" WM_AIN4, | ||
547 | WM_AIN2 "+" WM_AIN3 "+" WM_AIN4, | ||
548 | WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN4, | ||
549 | WM_AIN5, WM_AIN1 "+" WM_AIN5, WM_AIN2 "+" WM_AIN5, | ||
550 | WM_AIN1 "+" WM_AIN2 "+" WM_AIN5, | ||
551 | WM_AIN3 "+" WM_AIN5, WM_AIN1 "+" WM_AIN3 "+" WM_AIN5, | ||
552 | WM_AIN2 "+" WM_AIN3 "+" WM_AIN5, | ||
553 | WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN5, | ||
554 | WM_AIN4 "+" WM_AIN5, WM_AIN1 "+" WM_AIN4 "+" WM_AIN5, | ||
555 | WM_AIN2 "+" WM_AIN4 "+" WM_AIN5, | ||
556 | WM_AIN1 "+" WM_AIN2 "+" WM_AIN4 "+" WM_AIN5, | ||
557 | WM_AIN3 "+" WM_AIN4 "+" WM_AIN5, | ||
558 | WM_AIN1 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5, | ||
559 | WM_AIN2 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5, | ||
560 | WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5 | ||
561 | }; | ||
562 | |||
563 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
564 | uinfo->count = 1; | ||
565 | uinfo->value.enumerated.items = 32; | ||
566 | if (uinfo->value.enumerated.item > 31) | ||
567 | uinfo->value.enumerated.item = 31; | ||
568 | strcpy(uinfo->value.enumerated.name, | ||
569 | texts[uinfo->value.enumerated.item]); | ||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | static int wm_adc_mux_enum_get(struct snd_kcontrol *kcontrol, | ||
574 | struct snd_ctl_elem_value *ucontrol) | ||
575 | { | ||
576 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
577 | |||
578 | mutex_lock(&ice->gpio_mutex); | ||
579 | ucontrol->value.integer.value[0] = wm_get(ice, WM_ADC_MUX) & 0x1f; | ||
580 | mutex_unlock(&ice->gpio_mutex); | ||
581 | return 0; | ||
582 | } | ||
583 | |||
584 | static int wm_adc_mux_enum_put(struct snd_kcontrol *kcontrol, | ||
585 | struct snd_ctl_elem_value *ucontrol) | ||
586 | { | ||
587 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
588 | unsigned short oval, nval; | ||
589 | int change = 0; | ||
590 | |||
591 | mutex_lock(&ice->gpio_mutex); | ||
592 | oval = wm_get(ice, WM_ADC_MUX); | ||
593 | nval = (oval & 0xe0) | ucontrol->value.integer.value[0]; | ||
594 | if (nval != oval) { | ||
595 | wm_put(ice, WM_ADC_MUX, nval); | ||
596 | change = 1; | ||
597 | } | ||
598 | mutex_unlock(&ice->gpio_mutex); | ||
599 | return change; | ||
600 | } | ||
601 | |||
602 | /* KONSTI */ | ||
603 | |||
604 | /* | ||
605 | * ADC gain mixer control (-64dB to 0dB) | ||
606 | */ | ||
607 | |||
608 | #define ADC_0dB 0xcf | ||
609 | #define ADC_RES 128 | ||
610 | #define ADC_MIN (ADC_0dB - ADC_RES) | ||
611 | |||
612 | static int wm_adc_vol_info(struct snd_kcontrol *kcontrol, | ||
613 | struct snd_ctl_elem_info *uinfo) | ||
614 | { | ||
615 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
616 | uinfo->count = 2; | ||
617 | uinfo->value.integer.min = 0; /* mute (-64dB) */ | ||
618 | uinfo->value.integer.max = ADC_RES; /* 0dB, 0.5dB step */ | ||
619 | return 0; | ||
620 | } | ||
621 | |||
622 | static int wm_adc_vol_get(struct snd_kcontrol *kcontrol, | ||
623 | struct snd_ctl_elem_value *ucontrol) | ||
624 | { | ||
625 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
626 | unsigned short val; | ||
627 | int i; | ||
628 | |||
629 | mutex_lock(&ice->gpio_mutex); | ||
630 | for (i = 0; i < 2; i++) { | ||
631 | val = wm_get(ice, WM_ADC_ATTEN_L + i) & 0xff; | ||
632 | val = val > ADC_MIN ? (val - ADC_MIN) : 0; | ||
633 | ucontrol->value.integer.value[i] = val; | ||
634 | } | ||
635 | mutex_unlock(&ice->gpio_mutex); | ||
636 | return 0; | ||
637 | } | ||
638 | |||
639 | static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, | ||
640 | struct snd_ctl_elem_value *ucontrol) | ||
641 | { | ||
642 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
643 | unsigned short ovol, nvol; | ||
644 | int i, idx, change = 0; | ||
645 | |||
646 | mutex_lock(&ice->gpio_mutex); | ||
647 | for (i = 0; i < 2; i++) { | ||
648 | nvol = ucontrol->value.integer.value[i]; | ||
649 | nvol = nvol ? (nvol + ADC_MIN) : 0; | ||
650 | idx = WM_ADC_ATTEN_L + i; | ||
651 | ovol = wm_get(ice, idx) & 0xff; | ||
652 | if (ovol != nvol) { | ||
653 | wm_put(ice, idx, nvol); | ||
654 | change = 1; | ||
655 | } | ||
656 | } | ||
657 | mutex_unlock(&ice->gpio_mutex); | ||
658 | return change; | ||
659 | } | ||
660 | |||
661 | /* | ||
662 | * ADC input mux mixer control | ||
663 | */ | ||
664 | #define wm_adc_mux_info snd_ctl_boolean_mono_info | ||
665 | |||
666 | static int wm_adc_mux_get(struct snd_kcontrol *kcontrol, | ||
667 | struct snd_ctl_elem_value *ucontrol) | ||
668 | { | ||
669 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
670 | int bit = kcontrol->private_value; | ||
671 | |||
672 | mutex_lock(&ice->gpio_mutex); | ||
673 | ucontrol->value.integer.value[0] = | ||
674 | (wm_get(ice, WM_ADC_MUX) & (1 << bit)) ? 1 : 0; | ||
675 | mutex_unlock(&ice->gpio_mutex); | ||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, | ||
680 | struct snd_ctl_elem_value *ucontrol) | ||
681 | { | ||
682 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
683 | int bit = kcontrol->private_value; | ||
684 | unsigned short oval, nval; | ||
685 | int change; | ||
686 | |||
687 | mutex_lock(&ice->gpio_mutex); | ||
688 | nval = oval = wm_get(ice, WM_ADC_MUX); | ||
689 | if (ucontrol->value.integer.value[0]) | ||
690 | nval |= (1 << bit); | ||
691 | else | ||
692 | nval &= ~(1 << bit); | ||
693 | change = nval != oval; | ||
694 | if (change) { | ||
695 | wm_put(ice, WM_ADC_MUX, nval); | ||
696 | } | ||
697 | mutex_unlock(&ice->gpio_mutex); | ||
698 | return 0; | ||
699 | } | ||
700 | |||
701 | /* | ||
702 | * Analog bypass (In -> Out) | ||
703 | */ | ||
704 | #define wm_bypass_info snd_ctl_boolean_mono_info | ||
705 | |||
706 | static int wm_bypass_get(struct snd_kcontrol *kcontrol, | ||
707 | struct snd_ctl_elem_value *ucontrol) | ||
708 | { | ||
709 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
710 | |||
711 | mutex_lock(&ice->gpio_mutex); | ||
712 | ucontrol->value.integer.value[0] = | ||
713 | (wm_get(ice, WM_OUT_MUX) & 0x04) ? 1 : 0; | ||
714 | mutex_unlock(&ice->gpio_mutex); | ||
715 | return 0; | ||
716 | } | ||
717 | |||
718 | static int wm_bypass_put(struct snd_kcontrol *kcontrol, | ||
719 | struct snd_ctl_elem_value *ucontrol) | ||
720 | { | ||
721 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
722 | unsigned short val, oval; | ||
723 | int change = 0; | ||
724 | |||
725 | mutex_lock(&ice->gpio_mutex); | ||
726 | val = oval = wm_get(ice, WM_OUT_MUX); | ||
727 | if (ucontrol->value.integer.value[0]) | ||
728 | val |= 0x04; | ||
729 | else | ||
730 | val &= ~0x04; | ||
731 | if (val != oval) { | ||
732 | wm_put(ice, WM_OUT_MUX, val); | ||
733 | change = 1; | ||
734 | } | ||
735 | mutex_unlock(&ice->gpio_mutex); | ||
736 | return change; | ||
737 | } | ||
738 | |||
739 | /* | ||
740 | * Left/Right swap | ||
741 | */ | ||
742 | #define wm_chswap_info snd_ctl_boolean_mono_info | ||
743 | |||
744 | static int wm_chswap_get(struct snd_kcontrol *kcontrol, | ||
745 | struct snd_ctl_elem_value *ucontrol) | ||
746 | { | ||
747 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
748 | |||
749 | mutex_lock(&ice->gpio_mutex); | ||
750 | ucontrol->value.integer.value[0] = | ||
751 | (wm_get(ice, WM_DAC_CTRL1) & 0xf0) != 0x90; | ||
752 | mutex_unlock(&ice->gpio_mutex); | ||
753 | return 0; | ||
754 | } | ||
755 | |||
756 | static int wm_chswap_put(struct snd_kcontrol *kcontrol, | ||
757 | struct snd_ctl_elem_value *ucontrol) | ||
758 | { | ||
759 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
760 | unsigned short val, oval; | ||
761 | int change = 0; | ||
762 | |||
763 | mutex_lock(&ice->gpio_mutex); | ||
764 | oval = wm_get(ice, WM_DAC_CTRL1); | ||
765 | val = oval & 0x0f; | ||
766 | if (ucontrol->value.integer.value[0]) | ||
767 | val |= 0x60; | ||
768 | else | ||
769 | val |= 0x90; | ||
770 | if (val != oval) { | ||
771 | wm_put(ice, WM_DAC_CTRL1, val); | ||
772 | wm_put_nocache(ice, WM_DAC_CTRL1, val); | ||
773 | change = 1; | ||
774 | } | ||
775 | mutex_unlock(&ice->gpio_mutex); | ||
776 | return change; | ||
777 | } | ||
778 | |||
779 | |||
780 | /* | ||
781 | * mixers | ||
782 | */ | ||
783 | |||
784 | static struct snd_kcontrol_new prodigy_hifi_controls[] __devinitdata = { | ||
785 | { | ||
786 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
787 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
788 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
789 | .name = "Master Playback Volume", | ||
790 | .info = wm_master_vol_info, | ||
791 | .get = wm_master_vol_get, | ||
792 | .put = wm_master_vol_put, | ||
793 | .tlv = { .p = db_scale_wm_dac } | ||
794 | }, | ||
795 | { | ||
796 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
797 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
798 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
799 | .name = "Front Playback Volume", | ||
800 | .info = wm_dac_vol_info, | ||
801 | .get = wm_dac_vol_get, | ||
802 | .put = wm_dac_vol_put, | ||
803 | .tlv = { .p = db_scale_wm_dac }, | ||
804 | }, | ||
805 | { | ||
806 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
807 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
808 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
809 | .name = "Rear Playback Volume", | ||
810 | .info = wm8766_vol_info, | ||
811 | .get = wm8766_vol_get, | ||
812 | .put = wm8766_vol_put, | ||
813 | .private_value = (2 << 8) | 0, | ||
814 | .tlv = { .p = db_scale_wm_dac }, | ||
815 | }, | ||
816 | { | ||
817 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
818 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
819 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
820 | .name = "Center Playback Volume", | ||
821 | .info = wm8766_vol_info, | ||
822 | .get = wm8766_vol_get, | ||
823 | .put = wm8766_vol_put, | ||
824 | .private_value = (1 << 8) | 4, | ||
825 | .tlv = { .p = db_scale_wm_dac } | ||
826 | }, | ||
827 | { | ||
828 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
829 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
830 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
831 | .name = "LFE Playback Volume", | ||
832 | .info = wm8766_vol_info, | ||
833 | .get = wm8766_vol_get, | ||
834 | .put = wm8766_vol_put, | ||
835 | .private_value = (1 << 8) | 5, | ||
836 | .tlv = { .p = db_scale_wm_dac } | ||
837 | }, | ||
838 | { | ||
839 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
840 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
841 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
842 | .name = "Side Playback Volume", | ||
843 | .info = wm8766_vol_info, | ||
844 | .get = wm8766_vol_get, | ||
845 | .put = wm8766_vol_put, | ||
846 | .private_value = (2 << 8) | 6, | ||
847 | .tlv = { .p = db_scale_wm_dac }, | ||
848 | }, | ||
849 | { | ||
850 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
851 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
852 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
853 | .name = "Capture Volume", | ||
854 | .info = wm_adc_vol_info, | ||
855 | .get = wm_adc_vol_get, | ||
856 | .put = wm_adc_vol_put, | ||
857 | .tlv = { .p = db_scale_wm_dac }, | ||
858 | }, | ||
859 | { | ||
860 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
861 | .name = "CD Capture Switch", | ||
862 | .info = wm_adc_mux_info, | ||
863 | .get = wm_adc_mux_get, | ||
864 | .put = wm_adc_mux_put, | ||
865 | .private_value = 0, | ||
866 | }, | ||
867 | { | ||
868 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
869 | .name = "Line Capture Switch", | ||
870 | .info = wm_adc_mux_info, | ||
871 | .get = wm_adc_mux_get, | ||
872 | .put = wm_adc_mux_put, | ||
873 | .private_value = 1, | ||
874 | }, | ||
875 | { | ||
876 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
877 | .name = "Analog Bypass Switch", | ||
878 | .info = wm_bypass_info, | ||
879 | .get = wm_bypass_get, | ||
880 | .put = wm_bypass_put, | ||
881 | }, | ||
882 | { | ||
883 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
884 | .name = "Swap Output Channels", | ||
885 | .info = wm_chswap_info, | ||
886 | .get = wm_chswap_get, | ||
887 | .put = wm_chswap_put, | ||
888 | }, | ||
889 | { | ||
890 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
891 | .name = "Analog Capture Source", | ||
892 | .info = wm_adc_mux_enum_info, | ||
893 | .get = wm_adc_mux_enum_get, | ||
894 | .put = wm_adc_mux_enum_put, | ||
895 | }, | ||
896 | }; | ||
897 | |||
898 | /* | ||
899 | * WM codec registers | ||
900 | */ | ||
901 | static void wm_proc_regs_write(struct snd_info_entry *entry, | ||
902 | struct snd_info_buffer *buffer) | ||
903 | { | ||
904 | struct snd_ice1712 *ice = entry->private_data; | ||
905 | char line[64]; | ||
906 | unsigned int reg, val; | ||
907 | mutex_lock(&ice->gpio_mutex); | ||
908 | while (!snd_info_get_line(buffer, line, sizeof(line))) { | ||
909 | if (sscanf(line, "%x %x", ®, &val) != 2) | ||
910 | continue; | ||
911 | if (reg <= 0x17 && val <= 0xffff) | ||
912 | wm_put(ice, reg, val); | ||
913 | } | ||
914 | mutex_unlock(&ice->gpio_mutex); | ||
915 | } | ||
916 | |||
917 | static void wm_proc_regs_read(struct snd_info_entry *entry, | ||
918 | struct snd_info_buffer *buffer) | ||
919 | { | ||
920 | struct snd_ice1712 *ice = entry->private_data; | ||
921 | int reg, val; | ||
922 | |||
923 | mutex_lock(&ice->gpio_mutex); | ||
924 | for (reg = 0; reg <= 0x17; reg++) { | ||
925 | val = wm_get(ice, reg); | ||
926 | snd_iprintf(buffer, "%02x = %04x\n", reg, val); | ||
927 | } | ||
928 | mutex_unlock(&ice->gpio_mutex); | ||
929 | } | ||
930 | |||
931 | static void wm_proc_init(struct snd_ice1712 *ice) | ||
932 | { | ||
933 | struct snd_info_entry *entry; | ||
934 | if (!snd_card_proc_new(ice->card, "wm_codec", &entry)) { | ||
935 | snd_info_set_text_ops(entry, ice, wm_proc_regs_read); | ||
936 | entry->mode |= S_IWUSR; | ||
937 | entry->c.text.write = wm_proc_regs_write; | ||
938 | } | ||
939 | } | ||
940 | |||
941 | static int __devinit prodigy_hifi_add_controls(struct snd_ice1712 *ice) | ||
942 | { | ||
943 | unsigned int i; | ||
944 | int err; | ||
945 | |||
946 | for (i = 0; i < ARRAY_SIZE(prodigy_hifi_controls); i++) { | ||
947 | err = snd_ctl_add(ice->card, | ||
948 | snd_ctl_new1(&prodigy_hifi_controls[i], ice)); | ||
949 | if (err < 0) | ||
950 | return err; | ||
951 | } | ||
952 | |||
953 | wm_proc_init(ice); | ||
954 | |||
955 | return 0; | ||
956 | } | ||
957 | |||
958 | static int __devinit prodigy_hd2_add_controls(struct snd_ice1712 *ice) | ||
959 | { | ||
960 | unsigned int i; | ||
961 | int err; | ||
962 | |||
963 | for (i = 0; i < ARRAY_SIZE(prodigy_hd2_controls); i++) { | ||
964 | err = snd_ctl_add(ice->card, | ||
965 | snd_ctl_new1(&prodigy_hd2_controls[i], ice)); | ||
966 | if (err < 0) | ||
967 | return err; | ||
968 | } | ||
969 | |||
970 | wm_proc_init(ice); | ||
971 | |||
972 | return 0; | ||
973 | } | ||
974 | |||
975 | |||
976 | /* | ||
977 | * initialize the chip | ||
978 | */ | ||
979 | static int __devinit prodigy_hifi_init(struct snd_ice1712 *ice) | ||
980 | { | ||
981 | static unsigned short wm_inits[] = { | ||
982 | /* These come first to reduce init pop noise */ | ||
983 | WM_ADC_MUX, 0x0003, /* ADC mute */ | ||
984 | /* 0x00c0 replaced by 0x0003 */ | ||
985 | |||
986 | WM_DAC_MUTE, 0x0001, /* DAC softmute */ | ||
987 | WM_DAC_CTRL1, 0x0000, /* DAC mute */ | ||
988 | |||
989 | WM_POWERDOWN, 0x0008, /* All power-up except HP */ | ||
990 | WM_RESET, 0x0000, /* reset */ | ||
991 | }; | ||
992 | static unsigned short wm_inits2[] = { | ||
993 | WM_MASTER_CTRL, 0x0022, /* 256fs, slave mode */ | ||
994 | WM_DAC_INT, 0x0022, /* I2S, normal polarity, 24bit */ | ||
995 | WM_ADC_INT, 0x0022, /* I2S, normal polarity, 24bit */ | ||
996 | WM_DAC_CTRL1, 0x0090, /* DAC L/R */ | ||
997 | WM_OUT_MUX, 0x0001, /* OUT DAC */ | ||
998 | WM_HP_ATTEN_L, 0x0179, /* HP 0dB */ | ||
999 | WM_HP_ATTEN_R, 0x0179, /* HP 0dB */ | ||
1000 | WM_DAC_ATTEN_L, 0x0000, /* DAC 0dB */ | ||
1001 | WM_DAC_ATTEN_L, 0x0100, /* DAC 0dB */ | ||
1002 | WM_DAC_ATTEN_R, 0x0000, /* DAC 0dB */ | ||
1003 | WM_DAC_ATTEN_R, 0x0100, /* DAC 0dB */ | ||
1004 | WM_PHASE_SWAP, 0x0000, /* phase normal */ | ||
1005 | #if 0 | ||
1006 | WM_DAC_MASTER, 0x0100, /* DAC master muted */ | ||
1007 | #endif | ||
1008 | WM_DAC_CTRL2, 0x0000, /* no deemphasis, no ZFLG */ | ||
1009 | WM_ADC_ATTEN_L, 0x0000, /* ADC muted */ | ||
1010 | WM_ADC_ATTEN_R, 0x0000, /* ADC muted */ | ||
1011 | #if 1 | ||
1012 | WM_ALC_CTRL1, 0x007b, /* */ | ||
1013 | WM_ALC_CTRL2, 0x0000, /* */ | ||
1014 | WM_ALC_CTRL3, 0x0000, /* */ | ||
1015 | WM_NOISE_GATE, 0x0000, /* */ | ||
1016 | #endif | ||
1017 | WM_DAC_MUTE, 0x0000, /* DAC unmute */ | ||
1018 | WM_ADC_MUX, 0x0003, /* ADC unmute, both CD/Line On */ | ||
1019 | }; | ||
1020 | static unsigned short wm8766_inits[] = { | ||
1021 | WM8766_RESET, 0x0000, | ||
1022 | WM8766_DAC_CTRL, 0x0120, | ||
1023 | WM8766_INT_CTRL, 0x0022, /* I2S Normal Mode, 24 bit */ | ||
1024 | WM8766_DAC_CTRL2, 0x0001, | ||
1025 | WM8766_DAC_CTRL3, 0x0080, | ||
1026 | WM8766_LDA1, 0x0100, | ||
1027 | WM8766_LDA2, 0x0100, | ||
1028 | WM8766_LDA3, 0x0100, | ||
1029 | WM8766_RDA1, 0x0100, | ||
1030 | WM8766_RDA2, 0x0100, | ||
1031 | WM8766_RDA3, 0x0100, | ||
1032 | WM8766_MUTE1, 0x0000, | ||
1033 | WM8766_MUTE2, 0x0000, | ||
1034 | }; | ||
1035 | |||
1036 | struct prodigy_hifi_spec *spec; | ||
1037 | unsigned int i; | ||
1038 | |||
1039 | ice->vt1720 = 0; | ||
1040 | ice->vt1724 = 1; | ||
1041 | |||
1042 | ice->num_total_dacs = 8; | ||
1043 | ice->num_total_adcs = 1; | ||
1044 | |||
1045 | /* HACK - use this as the SPDIF source. | ||
1046 | * don't call snd_ice1712_gpio_get/put(), otherwise it's overwritten | ||
1047 | */ | ||
1048 | ice->gpio.saved[0] = 0; | ||
1049 | /* to remeber the register values */ | ||
1050 | |||
1051 | ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); | ||
1052 | if (! ice->akm) | ||
1053 | return -ENOMEM; | ||
1054 | ice->akm_codecs = 1; | ||
1055 | |||
1056 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
1057 | if (!spec) | ||
1058 | return -ENOMEM; | ||
1059 | ice->spec = spec; | ||
1060 | |||
1061 | /* initialize WM8776 codec */ | ||
1062 | for (i = 0; i < ARRAY_SIZE(wm_inits); i += 2) | ||
1063 | wm_put(ice, wm_inits[i], wm_inits[i+1]); | ||
1064 | schedule_timeout_uninterruptible(1); | ||
1065 | for (i = 0; i < ARRAY_SIZE(wm_inits2); i += 2) | ||
1066 | wm_put(ice, wm_inits2[i], wm_inits2[i+1]); | ||
1067 | |||
1068 | /* initialize WM8766 codec */ | ||
1069 | for (i = 0; i < ARRAY_SIZE(wm8766_inits); i += 2) | ||
1070 | wm8766_spi_write(ice, wm8766_inits[i], wm8766_inits[i+1]); | ||
1071 | |||
1072 | |||
1073 | return 0; | ||
1074 | } | ||
1075 | |||
1076 | |||
1077 | /* | ||
1078 | * initialize the chip | ||
1079 | */ | ||
1080 | static int __devinit prodigy_hd2_init(struct snd_ice1712 *ice) | ||
1081 | { | ||
1082 | static unsigned short ak4396_inits[] = { | ||
1083 | AK4396_CTRL1, 0x87, /* I2S Normal Mode, 24 bit */ | ||
1084 | AK4396_CTRL2, 0x02, | ||
1085 | AK4396_CTRL3, 0x00, | ||
1086 | AK4396_LCH_ATT, 0x00, | ||
1087 | AK4396_RCH_ATT, 0x00, | ||
1088 | }; | ||
1089 | |||
1090 | struct prodigy_hifi_spec *spec; | ||
1091 | unsigned int i; | ||
1092 | |||
1093 | ice->vt1720 = 0; | ||
1094 | ice->vt1724 = 1; | ||
1095 | |||
1096 | ice->num_total_dacs = 1; | ||
1097 | ice->num_total_adcs = 1; | ||
1098 | |||
1099 | /* HACK - use this as the SPDIF source. | ||
1100 | * don't call snd_ice1712_gpio_get/put(), otherwise it's overwritten | ||
1101 | */ | ||
1102 | ice->gpio.saved[0] = 0; | ||
1103 | /* to remeber the register values */ | ||
1104 | |||
1105 | ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); | ||
1106 | if (! ice->akm) | ||
1107 | return -ENOMEM; | ||
1108 | ice->akm_codecs = 1; | ||
1109 | |||
1110 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
1111 | if (!spec) | ||
1112 | return -ENOMEM; | ||
1113 | ice->spec = spec; | ||
1114 | |||
1115 | /* initialize ak4396 codec */ | ||
1116 | /* reset codec */ | ||
1117 | ak4396_write(ice, AK4396_CTRL1, 0x86); | ||
1118 | msleep(100); | ||
1119 | ak4396_write(ice, AK4396_CTRL1, 0x87); | ||
1120 | |||
1121 | for (i = 0; i < ARRAY_SIZE(ak4396_inits); i += 2) | ||
1122 | ak4396_write(ice, ak4396_inits[i], ak4396_inits[i+1]); | ||
1123 | |||
1124 | return 0; | ||
1125 | } | ||
1126 | |||
1127 | |||
1128 | static unsigned char prodigy71hifi_eeprom[] __devinitdata = { | ||
1129 | 0x4b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */ | ||
1130 | 0x80, /* ACLINK: I2S */ | ||
1131 | 0xfc, /* I2S: vol, 96k, 24bit, 192k */ | ||
1132 | 0xc3, /* SPDIF: out-en, out-int, spdif-in */ | ||
1133 | 0xff, /* GPIO_DIR */ | ||
1134 | 0xff, /* GPIO_DIR1 */ | ||
1135 | 0x5f, /* GPIO_DIR2 */ | ||
1136 | 0x00, /* GPIO_MASK */ | ||
1137 | 0x00, /* GPIO_MASK1 */ | ||
1138 | 0x00, /* GPIO_MASK2 */ | ||
1139 | 0x00, /* GPIO_STATE */ | ||
1140 | 0x00, /* GPIO_STATE1 */ | ||
1141 | 0x00, /* GPIO_STATE2 */ | ||
1142 | }; | ||
1143 | |||
1144 | static unsigned char prodigyhd2_eeprom[] __devinitdata = { | ||
1145 | 0x4b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */ | ||
1146 | 0x80, /* ACLINK: I2S */ | ||
1147 | 0xfc, /* I2S: vol, 96k, 24bit, 192k */ | ||
1148 | 0xc3, /* SPDIF: out-en, out-int, spdif-in */ | ||
1149 | 0xff, /* GPIO_DIR */ | ||
1150 | 0xff, /* GPIO_DIR1 */ | ||
1151 | 0x5f, /* GPIO_DIR2 */ | ||
1152 | 0x00, /* GPIO_MASK */ | ||
1153 | 0x00, /* GPIO_MASK1 */ | ||
1154 | 0x00, /* GPIO_MASK2 */ | ||
1155 | 0x00, /* GPIO_STATE */ | ||
1156 | 0x00, /* GPIO_STATE1 */ | ||
1157 | 0x00, /* GPIO_STATE2 */ | ||
1158 | }; | ||
1159 | |||
1160 | static unsigned char fortissimo4_eeprom[] __devinitdata = { | ||
1161 | 0x43, /* SYSCONF: clock 512, ADC, 4DACs */ | ||
1162 | 0x80, /* ACLINK: I2S */ | ||
1163 | 0xfc, /* I2S: vol, 96k, 24bit, 192k */ | ||
1164 | 0xc1, /* SPDIF: out-en, out-int */ | ||
1165 | 0xff, /* GPIO_DIR */ | ||
1166 | 0xff, /* GPIO_DIR1 */ | ||
1167 | 0x5f, /* GPIO_DIR2 */ | ||
1168 | 0x00, /* GPIO_MASK */ | ||
1169 | 0x00, /* GPIO_MASK1 */ | ||
1170 | 0x00, /* GPIO_MASK2 */ | ||
1171 | 0x00, /* GPIO_STATE */ | ||
1172 | 0x00, /* GPIO_STATE1 */ | ||
1173 | 0x00, /* GPIO_STATE2 */ | ||
1174 | }; | ||
1175 | |||
1176 | /* entry point */ | ||
1177 | struct snd_ice1712_card_info snd_vt1724_prodigy_hifi_cards[] __devinitdata = { | ||
1178 | { | ||
1179 | .subvendor = VT1724_SUBDEVICE_PRODIGY_HIFI, | ||
1180 | .name = "Audiotrak Prodigy 7.1 HiFi", | ||
1181 | .model = "prodigy71hifi", | ||
1182 | .chip_init = prodigy_hifi_init, | ||
1183 | .build_controls = prodigy_hifi_add_controls, | ||
1184 | .eeprom_size = sizeof(prodigy71hifi_eeprom), | ||
1185 | .eeprom_data = prodigy71hifi_eeprom, | ||
1186 | .driver = "Prodigy71HIFI", | ||
1187 | }, | ||
1188 | { | ||
1189 | .subvendor = VT1724_SUBDEVICE_PRODIGY_HD2, | ||
1190 | .name = "Audiotrak Prodigy HD2", | ||
1191 | .model = "prodigyhd2", | ||
1192 | .chip_init = prodigy_hd2_init, | ||
1193 | .build_controls = prodigy_hd2_add_controls, | ||
1194 | .eeprom_size = sizeof(prodigyhd2_eeprom), | ||
1195 | .eeprom_data = prodigyhd2_eeprom, | ||
1196 | .driver = "Prodigy71HD2", | ||
1197 | }, | ||
1198 | { | ||
1199 | .subvendor = VT1724_SUBDEVICE_FORTISSIMO4, | ||
1200 | .name = "Hercules Fortissimo IV", | ||
1201 | .model = "fortissimo4", | ||
1202 | .chip_init = prodigy_hifi_init, | ||
1203 | .build_controls = prodigy_hifi_add_controls, | ||
1204 | .eeprom_size = sizeof(fortissimo4_eeprom), | ||
1205 | .eeprom_data = fortissimo4_eeprom, | ||
1206 | .driver = "Fortissimo4", | ||
1207 | }, | ||
1208 | { } /* terminator */ | ||
1209 | }; | ||
1210 | |||
diff --git a/sound/pci/ice1712/prodigy_hifi.h b/sound/pci/ice1712/prodigy_hifi.h new file mode 100644 index 000000000000..a4415d455d9e --- /dev/null +++ b/sound/pci/ice1712/prodigy_hifi.h | |||
@@ -0,0 +1,38 @@ | |||
1 | #ifndef __SOUND_PRODIGY_HIFI_H | ||
2 | #define __SOUND_PRODIGY_HIFI_H | ||
3 | |||
4 | /* | ||
5 | * ALSA driver for VIA VT1724 (Envy24HT) | ||
6 | * | ||
7 | * Lowlevel functions for Audiotrak Prodigy Hifi | ||
8 | * | ||
9 | * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #define PRODIGY_HIFI_DEVICE_DESC "{Audiotrak,Prodigy 7.1 HIFI},"\ | ||
28 | "{Audiotrak Prodigy HD2},"\ | ||
29 | "{Hercules Fortissimo IV}," | ||
30 | |||
31 | #define VT1724_SUBDEVICE_PRODIGY_HIFI 0x38315441 /* PRODIGY 7.1 HIFI */ | ||
32 | #define VT1724_SUBDEVICE_PRODIGY_HD2 0x37315441 /* PRODIGY HD2 */ | ||
33 | #define VT1724_SUBDEVICE_FORTISSIMO4 0x81160100 /* Fortissimo IV */ | ||
34 | |||
35 | |||
36 | extern struct snd_ice1712_card_info snd_vt1724_prodigy_hifi_cards[]; | ||
37 | |||
38 | #endif /* __SOUND_PRODIGY_HIFI_H */ | ||
diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c index d18a31e188a9..ddd5fc8d4fe1 100644 --- a/sound/pci/ice1712/revo.c +++ b/sound/pci/ice1712/revo.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <asm/io.h> | 24 | #include <asm/io.h> |
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
27 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
@@ -33,6 +32,12 @@ | |||
33 | #include "envy24ht.h" | 32 | #include "envy24ht.h" |
34 | #include "revo.h" | 33 | #include "revo.h" |
35 | 34 | ||
35 | /* a non-standard I2C device for revo51 */ | ||
36 | struct revo51_spec { | ||
37 | struct snd_i2c_device *dev; | ||
38 | struct snd_pt2258 *pt2258; | ||
39 | } revo51; | ||
40 | |||
36 | static void revo_i2s_mclk_changed(struct snd_ice1712 *ice) | 41 | static void revo_i2s_mclk_changed(struct snd_ice1712 *ice) |
37 | { | 42 | { |
38 | /* assert PRST# to converters; MT05 bit 7 */ | 43 | /* assert PRST# to converters; MT05 bit 7 */ |
@@ -153,8 +158,14 @@ static struct snd_i2c_bit_ops revo51_bit_ops = { | |||
153 | static int revo51_i2c_init(struct snd_ice1712 *ice, | 158 | static int revo51_i2c_init(struct snd_ice1712 *ice, |
154 | struct snd_pt2258 *pt) | 159 | struct snd_pt2258 *pt) |
155 | { | 160 | { |
161 | struct revo51_spec *spec; | ||
156 | int err; | 162 | int err; |
157 | 163 | ||
164 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
165 | if (!spec) | ||
166 | return -ENOMEM; | ||
167 | ice->spec = spec; | ||
168 | |||
158 | /* create the I2C bus */ | 169 | /* create the I2C bus */ |
159 | err = snd_i2c_bus_create(ice->card, "ICE1724 GPIO6", NULL, &ice->i2c); | 170 | err = snd_i2c_bus_create(ice->card, "ICE1724 GPIO6", NULL, &ice->i2c); |
160 | if (err < 0) | 171 | if (err < 0) |
@@ -164,15 +175,14 @@ static int revo51_i2c_init(struct snd_ice1712 *ice, | |||
164 | ice->i2c->hw_ops.bit = &revo51_bit_ops; | 175 | ice->i2c->hw_ops.bit = &revo51_bit_ops; |
165 | 176 | ||
166 | /* create the I2C device */ | 177 | /* create the I2C device */ |
167 | err = snd_i2c_device_create(ice->i2c, "PT2258", 0x40, | 178 | err = snd_i2c_device_create(ice->i2c, "PT2258", 0x40, &spec->dev); |
168 | &ice->spec.revo51.dev); | ||
169 | if (err < 0) | 179 | if (err < 0) |
170 | return err; | 180 | return err; |
171 | 181 | ||
172 | pt->card = ice->card; | 182 | pt->card = ice->card; |
173 | pt->i2c_bus = ice->i2c; | 183 | pt->i2c_bus = ice->i2c; |
174 | pt->i2c_dev = ice->spec.revo51.dev; | 184 | pt->i2c_dev = spec->dev; |
175 | ice->spec.revo51.pt2258 = pt; | 185 | spec->pt2258 = pt; |
176 | 186 | ||
177 | snd_pt2258_reset(pt); | 187 | snd_pt2258_reset(pt); |
178 | 188 | ||
@@ -556,6 +566,7 @@ static int __devinit revo_init(struct snd_ice1712 *ice) | |||
556 | 566 | ||
557 | static int __devinit revo_add_controls(struct snd_ice1712 *ice) | 567 | static int __devinit revo_add_controls(struct snd_ice1712 *ice) |
558 | { | 568 | { |
569 | struct revo51_spec *spec; | ||
559 | int err; | 570 | int err; |
560 | 571 | ||
561 | switch (ice->eeprom.subvendor) { | 572 | switch (ice->eeprom.subvendor) { |
@@ -568,7 +579,8 @@ static int __devinit revo_add_controls(struct snd_ice1712 *ice) | |||
568 | err = snd_ice1712_akm4xxx_build_controls(ice); | 579 | err = snd_ice1712_akm4xxx_build_controls(ice); |
569 | if (err < 0) | 580 | if (err < 0) |
570 | return err; | 581 | return err; |
571 | err = snd_pt2258_build_controls(ice->spec.revo51.pt2258); | 582 | spec = ice->spec; |
583 | err = snd_pt2258_build_controls(spec->pt2258); | ||
572 | if (err < 0) | 584 | if (err < 0) |
573 | return err; | 585 | return err; |
574 | break; | 586 | break; |
diff --git a/sound/pci/ice1712/se.c b/sound/pci/ice1712/se.c new file mode 100644 index 000000000000..69673b95869d --- /dev/null +++ b/sound/pci/ice1712/se.c | |||
@@ -0,0 +1,774 @@ | |||
1 | /* | ||
2 | * ALSA driver for ICEnsemble VT1724 (Envy24HT) | ||
3 | * | ||
4 | * Lowlevel functions for ONKYO WAVIO SE-90PCI and SE-200PCI | ||
5 | * | ||
6 | * Copyright (c) 2007 Shin-ya Okada sh_okada(at)d4.dion.ne.jp | ||
7 | * (at) -> @ | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <asm/io.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/interrupt.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <sound/core.h> | ||
31 | #include <sound/tlv.h> | ||
32 | |||
33 | #include "ice1712.h" | ||
34 | #include "envy24ht.h" | ||
35 | #include "se.h" | ||
36 | |||
37 | struct se_spec { | ||
38 | struct { | ||
39 | unsigned char ch1, ch2; | ||
40 | } vol[8]; | ||
41 | }; | ||
42 | |||
43 | /****************************************************************************/ | ||
44 | /* ONKYO WAVIO SE-200PCI */ | ||
45 | /****************************************************************************/ | ||
46 | /* | ||
47 | * system configuration ICE_EEP2_SYSCONF=0x4b | ||
48 | * XIN1 49.152MHz | ||
49 | * not have UART | ||
50 | * one stereo ADC and a S/PDIF receiver connected | ||
51 | * four stereo DACs connected | ||
52 | * | ||
53 | * AC-Link configuration ICE_EEP2_ACLINK=0x80 | ||
54 | * use I2C, not use AC97 | ||
55 | * | ||
56 | * I2S converters feature ICE_EEP2_I2S=0x78 | ||
57 | * I2S codec has no volume/mute control feature | ||
58 | * I2S codec supports 96KHz and 192KHz | ||
59 | * I2S codec 24bits | ||
60 | * | ||
61 | * S/PDIF configuration ICE_EEP2_SPDIF=0xc3 | ||
62 | * Enable integrated S/PDIF transmitter | ||
63 | * internal S/PDIF out implemented | ||
64 | * S/PDIF is stereo | ||
65 | * External S/PDIF out implemented | ||
66 | * | ||
67 | * | ||
68 | * ** connected chips ** | ||
69 | * | ||
70 | * WM8740 | ||
71 | * A 2ch-DAC of main outputs. | ||
72 | * It setuped as I2S mode by wire, so no way to setup from software. | ||
73 | * The sample-rate are automatically changed. | ||
74 | * ML/I2S (28pin) --------+ | ||
75 | * MC/DM1 (27pin) -- 5V | | ||
76 | * MD/DM0 (26pin) -- GND | | ||
77 | * MUTEB (25pin) -- NC | | ||
78 | * MODE (24pin) -- GND | | ||
79 | * CSBIW (23pin) --------+ | ||
80 | * | | ||
81 | * RSTB (22pin) --R(1K)-+ | ||
82 | * Probably it reduce the noise from the control line. | ||
83 | * | ||
84 | * WM8766 | ||
85 | * A 6ch-DAC for surrounds. | ||
86 | * It's control wire was connected to GPIOxx (3-wire serial interface) | ||
87 | * ML/I2S (11pin) -- GPIO18 | ||
88 | * MC/IWL (12pin) -- GPIO17 | ||
89 | * MD/DM (13pin) -- GPIO16 | ||
90 | * MUTE (14pin) -- GPIO01 | ||
91 | * | ||
92 | * WM8776 | ||
93 | * A 2ch-ADC(with 10ch-selector) plus 2ch-DAC. | ||
94 | * It's control wire was connected to SDA/SCLK (2-wire serial interface) | ||
95 | * MODE (16pin) -- R(1K) -- GND | ||
96 | * CE (17pin) -- R(1K) -- GND 2-wire mode (address=0x34) | ||
97 | * DI (18pin) -- SDA | ||
98 | * CL (19pin) -- SCLK | ||
99 | * | ||
100 | * | ||
101 | * ** output pins and device names ** | ||
102 | * | ||
103 | * 7.1ch name -- output connector color -- device (-D option) | ||
104 | * | ||
105 | * FRONT 2ch -- green -- plughw:0,0 | ||
106 | * CENTER(Lch) SUBWOOFER(Rch) -- black -- plughw:0,2,0 | ||
107 | * SURROUND 2ch -- orange -- plughw:0,2,1 | ||
108 | * SURROUND BACK 2ch -- white -- plughw:0,2,2 | ||
109 | * | ||
110 | */ | ||
111 | |||
112 | |||
113 | /****************************************************************************/ | ||
114 | /* WM8740 interface */ | ||
115 | /****************************************************************************/ | ||
116 | |||
117 | static void __devinit se200pci_WM8740_init(struct snd_ice1712 *ice) | ||
118 | { | ||
119 | /* nothing to do */ | ||
120 | } | ||
121 | |||
122 | |||
123 | static void se200pci_WM8740_set_pro_rate(struct snd_ice1712 *ice, | ||
124 | unsigned int rate) | ||
125 | { | ||
126 | /* nothing to do */ | ||
127 | } | ||
128 | |||
129 | |||
130 | /****************************************************************************/ | ||
131 | /* WM8766 interface */ | ||
132 | /****************************************************************************/ | ||
133 | |||
134 | static void se200pci_WM8766_write(struct snd_ice1712 *ice, | ||
135 | unsigned int addr, unsigned int data) | ||
136 | { | ||
137 | unsigned int st; | ||
138 | unsigned int bits; | ||
139 | int i; | ||
140 | const unsigned int DATA = 0x010000; | ||
141 | const unsigned int CLOCK = 0x020000; | ||
142 | const unsigned int LOAD = 0x040000; | ||
143 | const unsigned int ALL_MASK = (DATA | CLOCK | LOAD); | ||
144 | |||
145 | snd_ice1712_save_gpio_status(ice); | ||
146 | |||
147 | st = ((addr & 0x7f) << 9) | (data & 0x1ff); | ||
148 | snd_ice1712_gpio_set_dir(ice, ice->gpio.direction | ALL_MASK); | ||
149 | snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask & ~ALL_MASK); | ||
150 | bits = snd_ice1712_gpio_read(ice) & ~ALL_MASK; | ||
151 | |||
152 | snd_ice1712_gpio_write(ice, bits); | ||
153 | for (i = 0; i < 16; i++) { | ||
154 | udelay(1); | ||
155 | bits &= ~CLOCK; | ||
156 | st = (st << 1); | ||
157 | if (st & 0x10000) | ||
158 | bits |= DATA; | ||
159 | else | ||
160 | bits &= ~DATA; | ||
161 | |||
162 | snd_ice1712_gpio_write(ice, bits); | ||
163 | |||
164 | udelay(1); | ||
165 | bits |= CLOCK; | ||
166 | snd_ice1712_gpio_write(ice, bits); | ||
167 | } | ||
168 | |||
169 | udelay(1); | ||
170 | bits |= LOAD; | ||
171 | snd_ice1712_gpio_write(ice, bits); | ||
172 | |||
173 | udelay(1); | ||
174 | bits |= (DATA | CLOCK); | ||
175 | snd_ice1712_gpio_write(ice, bits); | ||
176 | |||
177 | snd_ice1712_restore_gpio_status(ice); | ||
178 | } | ||
179 | |||
180 | static void se200pci_WM8766_set_volume(struct snd_ice1712 *ice, int ch, | ||
181 | unsigned int vol1, unsigned int vol2) | ||
182 | { | ||
183 | switch (ch) { | ||
184 | case 0: | ||
185 | se200pci_WM8766_write(ice, 0x000, vol1); | ||
186 | se200pci_WM8766_write(ice, 0x001, vol2 | 0x100); | ||
187 | break; | ||
188 | case 1: | ||
189 | se200pci_WM8766_write(ice, 0x004, vol1); | ||
190 | se200pci_WM8766_write(ice, 0x005, vol2 | 0x100); | ||
191 | break; | ||
192 | case 2: | ||
193 | se200pci_WM8766_write(ice, 0x006, vol1); | ||
194 | se200pci_WM8766_write(ice, 0x007, vol2 | 0x100); | ||
195 | break; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | static void __devinit se200pci_WM8766_init(struct snd_ice1712 *ice) | ||
200 | { | ||
201 | se200pci_WM8766_write(ice, 0x1f, 0x000); /* RESET ALL */ | ||
202 | udelay(10); | ||
203 | |||
204 | se200pci_WM8766_set_volume(ice, 0, 0, 0); /* volume L=0 R=0 */ | ||
205 | se200pci_WM8766_set_volume(ice, 1, 0, 0); /* volume L=0 R=0 */ | ||
206 | se200pci_WM8766_set_volume(ice, 2, 0, 0); /* volume L=0 R=0 */ | ||
207 | |||
208 | se200pci_WM8766_write(ice, 0x03, 0x022); /* serial mode I2S-24bits */ | ||
209 | se200pci_WM8766_write(ice, 0x0a, 0x080); /* MCLK=256fs */ | ||
210 | se200pci_WM8766_write(ice, 0x12, 0x000); /* MDP=0 */ | ||
211 | se200pci_WM8766_write(ice, 0x15, 0x000); /* MDP=0 */ | ||
212 | se200pci_WM8766_write(ice, 0x09, 0x000); /* demp=off mute=off */ | ||
213 | |||
214 | se200pci_WM8766_write(ice, 0x02, 0x124); /* ch-assign L=L R=R RESET */ | ||
215 | se200pci_WM8766_write(ice, 0x02, 0x120); /* ch-assign L=L R=R */ | ||
216 | } | ||
217 | |||
218 | static void se200pci_WM8766_set_pro_rate(struct snd_ice1712 *ice, | ||
219 | unsigned int rate) | ||
220 | { | ||
221 | if (rate > 96000) | ||
222 | se200pci_WM8766_write(ice, 0x0a, 0x000); /* MCLK=128fs */ | ||
223 | else | ||
224 | se200pci_WM8766_write(ice, 0x0a, 0x080); /* MCLK=256fs */ | ||
225 | } | ||
226 | |||
227 | |||
228 | /****************************************************************************/ | ||
229 | /* WM8776 interface */ | ||
230 | /****************************************************************************/ | ||
231 | |||
232 | static void se200pci_WM8776_write(struct snd_ice1712 *ice, | ||
233 | unsigned int addr, unsigned int data) | ||
234 | { | ||
235 | unsigned int val; | ||
236 | |||
237 | val = (addr << 9) | data; | ||
238 | snd_vt1724_write_i2c(ice, 0x34, val >> 8, val & 0xff); | ||
239 | } | ||
240 | |||
241 | |||
242 | static void se200pci_WM8776_set_output_volume(struct snd_ice1712 *ice, | ||
243 | unsigned int vol1, unsigned int vol2) | ||
244 | { | ||
245 | se200pci_WM8776_write(ice, 0x03, vol1); | ||
246 | se200pci_WM8776_write(ice, 0x04, vol2 | 0x100); | ||
247 | } | ||
248 | |||
249 | static void se200pci_WM8776_set_input_volume(struct snd_ice1712 *ice, | ||
250 | unsigned int vol1, unsigned int vol2) | ||
251 | { | ||
252 | se200pci_WM8776_write(ice, 0x0e, vol1); | ||
253 | se200pci_WM8776_write(ice, 0x0f, vol2 | 0x100); | ||
254 | } | ||
255 | |||
256 | static const char *se200pci_sel[] = { | ||
257 | "LINE-IN", "CD-IN", "MIC-IN", "ALL-MIX", NULL | ||
258 | }; | ||
259 | |||
260 | static void se200pci_WM8776_set_input_selector(struct snd_ice1712 *ice, | ||
261 | unsigned int sel) | ||
262 | { | ||
263 | static unsigned char vals[] = { | ||
264 | /* LINE, CD, MIC, ALL, GND */ | ||
265 | 0x10, 0x04, 0x08, 0x1c, 0x03 | ||
266 | }; | ||
267 | if (sel > 4) | ||
268 | sel = 4; | ||
269 | se200pci_WM8776_write(ice, 0x15, vals[sel]); | ||
270 | } | ||
271 | |||
272 | static void se200pci_WM8776_set_afl(struct snd_ice1712 *ice, unsigned int afl) | ||
273 | { | ||
274 | /* AFL -- After Fader Listening */ | ||
275 | if (afl) | ||
276 | se200pci_WM8776_write(ice, 0x16, 0x005); | ||
277 | else | ||
278 | se200pci_WM8776_write(ice, 0x16, 0x001); | ||
279 | } | ||
280 | |||
281 | static const char *se200pci_agc[] = { | ||
282 | "Off", "LimiterMode", "ALCMode", NULL | ||
283 | }; | ||
284 | |||
285 | static void se200pci_WM8776_set_agc(struct snd_ice1712 *ice, unsigned int agc) | ||
286 | { | ||
287 | /* AGC -- Auto Gain Control of the input */ | ||
288 | switch (agc) { | ||
289 | case 0: | ||
290 | se200pci_WM8776_write(ice, 0x11, 0x000); /* Off */ | ||
291 | break; | ||
292 | case 1: | ||
293 | se200pci_WM8776_write(ice, 0x10, 0x07b); | ||
294 | se200pci_WM8776_write(ice, 0x11, 0x100); /* LimiterMode */ | ||
295 | break; | ||
296 | case 2: | ||
297 | se200pci_WM8776_write(ice, 0x10, 0x1fb); | ||
298 | se200pci_WM8776_write(ice, 0x11, 0x100); /* ALCMode */ | ||
299 | break; | ||
300 | } | ||
301 | } | ||
302 | |||
303 | static void __devinit se200pci_WM8776_init(struct snd_ice1712 *ice) | ||
304 | { | ||
305 | int i; | ||
306 | static unsigned short __devinitdata default_values[] = { | ||
307 | 0x100, 0x100, 0x100, | ||
308 | 0x100, 0x100, 0x100, | ||
309 | 0x000, 0x090, 0x000, 0x000, | ||
310 | 0x022, 0x022, 0x022, | ||
311 | 0x008, 0x0cf, 0x0cf, 0x07b, 0x000, | ||
312 | 0x032, 0x000, 0x0a6, 0x001, 0x001 | ||
313 | }; | ||
314 | |||
315 | se200pci_WM8776_write(ice, 0x17, 0x000); /* reset all */ | ||
316 | /* ADC and DAC interface is I2S 24bits mode */ | ||
317 | /* The sample-rate are automatically changed */ | ||
318 | udelay(10); | ||
319 | /* BUT my board can not do reset all, so I load all by manually. */ | ||
320 | for (i = 0; i < ARRAY_SIZE(default_values); i++) | ||
321 | se200pci_WM8776_write(ice, i, default_values[i]); | ||
322 | |||
323 | se200pci_WM8776_set_input_selector(ice, 0); | ||
324 | se200pci_WM8776_set_afl(ice, 0); | ||
325 | se200pci_WM8776_set_agc(ice, 0); | ||
326 | se200pci_WM8776_set_input_volume(ice, 0, 0); | ||
327 | se200pci_WM8776_set_output_volume(ice, 0, 0); | ||
328 | |||
329 | /* head phone mute and power down */ | ||
330 | se200pci_WM8776_write(ice, 0x00, 0); | ||
331 | se200pci_WM8776_write(ice, 0x01, 0); | ||
332 | se200pci_WM8776_write(ice, 0x02, 0x100); | ||
333 | se200pci_WM8776_write(ice, 0x0d, 0x080); | ||
334 | } | ||
335 | |||
336 | static void se200pci_WM8776_set_pro_rate(struct snd_ice1712 *ice, | ||
337 | unsigned int rate) | ||
338 | { | ||
339 | /* nothing to do */ | ||
340 | } | ||
341 | |||
342 | |||
343 | /****************************************************************************/ | ||
344 | /* runtime interface */ | ||
345 | /****************************************************************************/ | ||
346 | |||
347 | static void se200pci_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate) | ||
348 | { | ||
349 | se200pci_WM8740_set_pro_rate(ice, rate); | ||
350 | se200pci_WM8766_set_pro_rate(ice, rate); | ||
351 | se200pci_WM8776_set_pro_rate(ice, rate); | ||
352 | } | ||
353 | |||
354 | struct se200pci_control { | ||
355 | char *name; | ||
356 | enum { | ||
357 | WM8766, | ||
358 | WM8776in, | ||
359 | WM8776out, | ||
360 | WM8776sel, | ||
361 | WM8776agc, | ||
362 | WM8776afl | ||
363 | } target; | ||
364 | enum { VOLUME1, VOLUME2, BOOLEAN, ENUM } type; | ||
365 | int ch; | ||
366 | const char **member; | ||
367 | const char *comment; | ||
368 | }; | ||
369 | |||
370 | static const struct se200pci_control se200pci_cont[] = { | ||
371 | { | ||
372 | .name = "Front Playback Volume", | ||
373 | .target = WM8776out, | ||
374 | .type = VOLUME1, | ||
375 | .comment = "Front(green)" | ||
376 | }, | ||
377 | { | ||
378 | .name = "Side Playback Volume", | ||
379 | .target = WM8766, | ||
380 | .type = VOLUME1, | ||
381 | .ch = 1, | ||
382 | .comment = "Surround(orange)" | ||
383 | }, | ||
384 | { | ||
385 | .name = "Surround Playback Volume", | ||
386 | .target = WM8766, | ||
387 | .type = VOLUME1, | ||
388 | .ch = 2, | ||
389 | .comment = "SurroundBack(white)" | ||
390 | }, | ||
391 | { | ||
392 | .name = "CLFE Playback Volume", | ||
393 | .target = WM8766, | ||
394 | .type = VOLUME1, | ||
395 | .ch = 0, | ||
396 | .comment = "Center(Lch)&SubWoofer(Rch)(black)" | ||
397 | }, | ||
398 | { | ||
399 | .name = "Capture Volume", | ||
400 | .target = WM8776in, | ||
401 | .type = VOLUME2 | ||
402 | }, | ||
403 | { | ||
404 | .name = "Capture Select", | ||
405 | .target = WM8776sel, | ||
406 | .type = ENUM, | ||
407 | .member = se200pci_sel | ||
408 | }, | ||
409 | { | ||
410 | .name = "AGC Capture Mode", | ||
411 | .target = WM8776agc, | ||
412 | .type = ENUM, | ||
413 | .member = se200pci_agc | ||
414 | }, | ||
415 | { | ||
416 | .name = "AFL Bypass Playback Switch", | ||
417 | .target = WM8776afl, | ||
418 | .type = BOOLEAN | ||
419 | } | ||
420 | }; | ||
421 | |||
422 | static int se200pci_get_enum_count(int n) | ||
423 | { | ||
424 | const char **member; | ||
425 | int c; | ||
426 | |||
427 | member = se200pci_cont[n].member; | ||
428 | if (!member) | ||
429 | return 0; | ||
430 | for (c = 0; member[c]; c++) | ||
431 | ; | ||
432 | return c; | ||
433 | } | ||
434 | |||
435 | static int se200pci_cont_volume_info(struct snd_kcontrol *kc, | ||
436 | struct snd_ctl_elem_info *uinfo) | ||
437 | { | ||
438 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
439 | uinfo->count = 2; | ||
440 | uinfo->value.integer.min = 0; /* mute */ | ||
441 | uinfo->value.integer.max = 0xff; /* 0dB */ | ||
442 | return 0; | ||
443 | } | ||
444 | |||
445 | #define se200pci_cont_boolean_info snd_ctl_boolean_mono_info | ||
446 | |||
447 | static int se200pci_cont_enum_info(struct snd_kcontrol *kc, | ||
448 | struct snd_ctl_elem_info *uinfo) | ||
449 | { | ||
450 | int n, c; | ||
451 | |||
452 | n = kc->private_value; | ||
453 | c = se200pci_get_enum_count(n); | ||
454 | if (!c) | ||
455 | return -EINVAL; | ||
456 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
457 | uinfo->count = 1; | ||
458 | uinfo->value.enumerated.items = c; | ||
459 | if (uinfo->value.enumerated.item >= c) | ||
460 | uinfo->value.enumerated.item = c - 1; | ||
461 | strcpy(uinfo->value.enumerated.name, | ||
462 | se200pci_cont[n].member[uinfo->value.enumerated.item]); | ||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | static int se200pci_cont_volume_get(struct snd_kcontrol *kc, | ||
467 | struct snd_ctl_elem_value *uc) | ||
468 | { | ||
469 | struct snd_ice1712 *ice = snd_kcontrol_chip(kc); | ||
470 | struct se_spec *spec = ice->spec; | ||
471 | int n = kc->private_value; | ||
472 | uc->value.integer.value[0] = spec->vol[n].ch1; | ||
473 | uc->value.integer.value[1] = spec->vol[n].ch2; | ||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | static int se200pci_cont_boolean_get(struct snd_kcontrol *kc, | ||
478 | struct snd_ctl_elem_value *uc) | ||
479 | { | ||
480 | struct snd_ice1712 *ice = snd_kcontrol_chip(kc); | ||
481 | struct se_spec *spec = ice->spec; | ||
482 | int n = kc->private_value; | ||
483 | uc->value.integer.value[0] = spec->vol[n].ch1; | ||
484 | return 0; | ||
485 | } | ||
486 | |||
487 | static int se200pci_cont_enum_get(struct snd_kcontrol *kc, | ||
488 | struct snd_ctl_elem_value *uc) | ||
489 | { | ||
490 | struct snd_ice1712 *ice = snd_kcontrol_chip(kc); | ||
491 | struct se_spec *spec = ice->spec; | ||
492 | int n = kc->private_value; | ||
493 | uc->value.enumerated.item[0] = spec->vol[n].ch1; | ||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | static void se200pci_cont_update(struct snd_ice1712 *ice, int n) | ||
498 | { | ||
499 | struct se_spec *spec = ice->spec; | ||
500 | switch (se200pci_cont[n].target) { | ||
501 | case WM8766: | ||
502 | se200pci_WM8766_set_volume(ice, | ||
503 | se200pci_cont[n].ch, | ||
504 | spec->vol[n].ch1, | ||
505 | spec->vol[n].ch2); | ||
506 | break; | ||
507 | |||
508 | case WM8776in: | ||
509 | se200pci_WM8776_set_input_volume(ice, | ||
510 | spec->vol[n].ch1, | ||
511 | spec->vol[n].ch2); | ||
512 | break; | ||
513 | |||
514 | case WM8776out: | ||
515 | se200pci_WM8776_set_output_volume(ice, | ||
516 | spec->vol[n].ch1, | ||
517 | spec->vol[n].ch2); | ||
518 | break; | ||
519 | |||
520 | case WM8776sel: | ||
521 | se200pci_WM8776_set_input_selector(ice, | ||
522 | spec->vol[n].ch1); | ||
523 | break; | ||
524 | |||
525 | case WM8776agc: | ||
526 | se200pci_WM8776_set_agc(ice, spec->vol[n].ch1); | ||
527 | break; | ||
528 | |||
529 | case WM8776afl: | ||
530 | se200pci_WM8776_set_afl(ice, spec->vol[n].ch1); | ||
531 | break; | ||
532 | |||
533 | default: | ||
534 | break; | ||
535 | } | ||
536 | } | ||
537 | |||
538 | static int se200pci_cont_volume_put(struct snd_kcontrol *kc, | ||
539 | struct snd_ctl_elem_value *uc) | ||
540 | { | ||
541 | struct snd_ice1712 *ice = snd_kcontrol_chip(kc); | ||
542 | struct se_spec *spec = ice->spec; | ||
543 | int n = kc->private_value; | ||
544 | unsigned int vol1, vol2; | ||
545 | int changed; | ||
546 | |||
547 | changed = 0; | ||
548 | vol1 = uc->value.integer.value[0] & 0xff; | ||
549 | vol2 = uc->value.integer.value[1] & 0xff; | ||
550 | if (spec->vol[n].ch1 != vol1) { | ||
551 | spec->vol[n].ch1 = vol1; | ||
552 | changed = 1; | ||
553 | } | ||
554 | if (spec->vol[n].ch2 != vol2) { | ||
555 | spec->vol[n].ch2 = vol2; | ||
556 | changed = 1; | ||
557 | } | ||
558 | if (changed) | ||
559 | se200pci_cont_update(ice, n); | ||
560 | |||
561 | return changed; | ||
562 | } | ||
563 | |||
564 | static int se200pci_cont_boolean_put(struct snd_kcontrol *kc, | ||
565 | struct snd_ctl_elem_value *uc) | ||
566 | { | ||
567 | struct snd_ice1712 *ice = snd_kcontrol_chip(kc); | ||
568 | struct se_spec *spec = ice->spec; | ||
569 | int n = kc->private_value; | ||
570 | unsigned int vol1; | ||
571 | |||
572 | vol1 = !!uc->value.integer.value[0]; | ||
573 | if (spec->vol[n].ch1 != vol1) { | ||
574 | spec->vol[n].ch1 = vol1; | ||
575 | se200pci_cont_update(ice, n); | ||
576 | return 1; | ||
577 | } | ||
578 | return 0; | ||
579 | } | ||
580 | |||
581 | static int se200pci_cont_enum_put(struct snd_kcontrol *kc, | ||
582 | struct snd_ctl_elem_value *uc) | ||
583 | { | ||
584 | struct snd_ice1712 *ice = snd_kcontrol_chip(kc); | ||
585 | struct se_spec *spec = ice->spec; | ||
586 | int n = kc->private_value; | ||
587 | unsigned int vol1; | ||
588 | |||
589 | vol1 = uc->value.enumerated.item[0]; | ||
590 | if (vol1 >= se200pci_get_enum_count(n)) | ||
591 | return -EINVAL; | ||
592 | if (spec->vol[n].ch1 != vol1) { | ||
593 | spec->vol[n].ch1 = vol1; | ||
594 | se200pci_cont_update(ice, n); | ||
595 | return 1; | ||
596 | } | ||
597 | return 0; | ||
598 | } | ||
599 | |||
600 | static const DECLARE_TLV_DB_SCALE(db_scale_gain1, -12750, 50, 1); | ||
601 | static const DECLARE_TLV_DB_SCALE(db_scale_gain2, -10350, 50, 1); | ||
602 | |||
603 | static int __devinit se200pci_add_controls(struct snd_ice1712 *ice) | ||
604 | { | ||
605 | int i; | ||
606 | struct snd_kcontrol_new cont; | ||
607 | int err; | ||
608 | |||
609 | memset(&cont, 0, sizeof(cont)); | ||
610 | cont.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
611 | for (i = 0; i < ARRAY_SIZE(se200pci_cont); i++) { | ||
612 | cont.private_value = i; | ||
613 | cont.name = se200pci_cont[i].name; | ||
614 | cont.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; | ||
615 | cont.tlv.p = NULL; | ||
616 | switch (se200pci_cont[i].type) { | ||
617 | case VOLUME1: | ||
618 | case VOLUME2: | ||
619 | cont.info = se200pci_cont_volume_info; | ||
620 | cont.get = se200pci_cont_volume_get; | ||
621 | cont.put = se200pci_cont_volume_put; | ||
622 | cont.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
623 | if (se200pci_cont[i].type == VOLUME1) | ||
624 | cont.tlv.p = db_scale_gain1; | ||
625 | else | ||
626 | cont.tlv.p = db_scale_gain2; | ||
627 | break; | ||
628 | case BOOLEAN: | ||
629 | cont.info = se200pci_cont_boolean_info; | ||
630 | cont.get = se200pci_cont_boolean_get; | ||
631 | cont.put = se200pci_cont_boolean_put; | ||
632 | break; | ||
633 | case ENUM: | ||
634 | cont.info = se200pci_cont_enum_info; | ||
635 | cont.get = se200pci_cont_enum_get; | ||
636 | cont.put = se200pci_cont_enum_put; | ||
637 | break; | ||
638 | default: | ||
639 | snd_BUG(); | ||
640 | return -EINVAL; | ||
641 | } | ||
642 | err = snd_ctl_add(ice->card, snd_ctl_new1(&cont, ice)); | ||
643 | if (err < 0) | ||
644 | return err; | ||
645 | } | ||
646 | |||
647 | return 0; | ||
648 | } | ||
649 | |||
650 | |||
651 | /****************************************************************************/ | ||
652 | /* ONKYO WAVIO SE-90PCI */ | ||
653 | /****************************************************************************/ | ||
654 | /* | ||
655 | * system configuration ICE_EEP2_SYSCONF=0x4b | ||
656 | * AC-Link configuration ICE_EEP2_ACLINK=0x80 | ||
657 | * I2S converters feature ICE_EEP2_I2S=0x78 | ||
658 | * S/PDIF configuration ICE_EEP2_SPDIF=0xc3 | ||
659 | * | ||
660 | * ** connected chip ** | ||
661 | * | ||
662 | * WM8716 | ||
663 | * A 2ch-DAC of main outputs. | ||
664 | * It setuped as I2S mode by wire, so no way to setup from software. | ||
665 | * ML/I2S (28pin) -- +5V | ||
666 | * MC/DM1 (27pin) -- GND | ||
667 | * MC/DM0 (26pin) -- GND | ||
668 | * MUTEB (25pin) -- open (internal pull-up) | ||
669 | * MODE (24pin) -- GND | ||
670 | * CSBIWO (23pin) -- +5V | ||
671 | * | ||
672 | */ | ||
673 | |||
674 | /* Nothing to do for this chip. */ | ||
675 | |||
676 | |||
677 | /****************************************************************************/ | ||
678 | /* probe/initialize/setup */ | ||
679 | /****************************************************************************/ | ||
680 | |||
681 | static int __devinit se_init(struct snd_ice1712 *ice) | ||
682 | { | ||
683 | struct se_spec *spec; | ||
684 | |||
685 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
686 | if (!spec) | ||
687 | return -ENOMEM; | ||
688 | ice->spec = spec; | ||
689 | |||
690 | if (ice->eeprom.subvendor == VT1724_SUBDEVICE_SE90PCI) { | ||
691 | ice->num_total_dacs = 2; | ||
692 | ice->num_total_adcs = 0; | ||
693 | ice->vt1720 = 1; | ||
694 | return 0; | ||
695 | |||
696 | } else if (ice->eeprom.subvendor == VT1724_SUBDEVICE_SE200PCI) { | ||
697 | ice->num_total_dacs = 8; | ||
698 | ice->num_total_adcs = 2; | ||
699 | se200pci_WM8740_init(ice); | ||
700 | se200pci_WM8766_init(ice); | ||
701 | se200pci_WM8776_init(ice); | ||
702 | ice->gpio.set_pro_rate = se200pci_set_pro_rate; | ||
703 | return 0; | ||
704 | } | ||
705 | |||
706 | return -ENOENT; | ||
707 | } | ||
708 | |||
709 | static int __devinit se_add_controls(struct snd_ice1712 *ice) | ||
710 | { | ||
711 | int err; | ||
712 | |||
713 | err = 0; | ||
714 | /* nothing to do for VT1724_SUBDEVICE_SE90PCI */ | ||
715 | if (ice->eeprom.subvendor == VT1724_SUBDEVICE_SE200PCI) | ||
716 | err = se200pci_add_controls(ice); | ||
717 | |||
718 | return err; | ||
719 | } | ||
720 | |||
721 | |||
722 | /****************************************************************************/ | ||
723 | /* entry point */ | ||
724 | /****************************************************************************/ | ||
725 | |||
726 | static unsigned char se200pci_eeprom[] __devinitdata = { | ||
727 | [ICE_EEP2_SYSCONF] = 0x4b, /* 49.152Hz, spdif-in/ADC, 4DACs */ | ||
728 | [ICE_EEP2_ACLINK] = 0x80, /* I2S */ | ||
729 | [ICE_EEP2_I2S] = 0x78, /* 96k-ok, 24bit, 192k-ok */ | ||
730 | [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ | ||
731 | |||
732 | [ICE_EEP2_GPIO_DIR] = 0x02, /* WM8766 mute 1=output */ | ||
733 | [ICE_EEP2_GPIO_DIR1] = 0x00, /* not used */ | ||
734 | [ICE_EEP2_GPIO_DIR2] = 0x07, /* WM8766 ML/MC/MD 1=output */ | ||
735 | |||
736 | [ICE_EEP2_GPIO_MASK] = 0x00, /* 0=writable */ | ||
737 | [ICE_EEP2_GPIO_MASK1] = 0x00, /* 0=writable */ | ||
738 | [ICE_EEP2_GPIO_MASK2] = 0x00, /* 0=writable */ | ||
739 | |||
740 | [ICE_EEP2_GPIO_STATE] = 0x00, /* WM8766 mute=0 */ | ||
741 | [ICE_EEP2_GPIO_STATE1] = 0x00, /* not used */ | ||
742 | [ICE_EEP2_GPIO_STATE2] = 0x07, /* WM8766 ML/MC/MD */ | ||
743 | }; | ||
744 | |||
745 | static unsigned char se90pci_eeprom[] __devinitdata = { | ||
746 | [ICE_EEP2_SYSCONF] = 0x4b, /* 49.152Hz, spdif-in/ADC, 4DACs */ | ||
747 | [ICE_EEP2_ACLINK] = 0x80, /* I2S */ | ||
748 | [ICE_EEP2_I2S] = 0x78, /* 96k-ok, 24bit, 192k-ok */ | ||
749 | [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ | ||
750 | |||
751 | /* ALL GPIO bits are in input mode */ | ||
752 | }; | ||
753 | |||
754 | struct snd_ice1712_card_info snd_vt1724_se_cards[] __devinitdata = { | ||
755 | { | ||
756 | .subvendor = VT1724_SUBDEVICE_SE200PCI, | ||
757 | .name = "ONKYO SE200PCI", | ||
758 | .model = "se200pci", | ||
759 | .chip_init = se_init, | ||
760 | .build_controls = se_add_controls, | ||
761 | .eeprom_size = sizeof(se200pci_eeprom), | ||
762 | .eeprom_data = se200pci_eeprom, | ||
763 | }, | ||
764 | { | ||
765 | .subvendor = VT1724_SUBDEVICE_SE90PCI, | ||
766 | .name = "ONKYO SE90PCI", | ||
767 | .model = "se90pci", | ||
768 | .chip_init = se_init, | ||
769 | .build_controls = se_add_controls, | ||
770 | .eeprom_size = sizeof(se90pci_eeprom), | ||
771 | .eeprom_data = se90pci_eeprom, | ||
772 | }, | ||
773 | {} /*terminator*/ | ||
774 | }; | ||
diff --git a/sound/pci/ice1712/se.h b/sound/pci/ice1712/se.h new file mode 100644 index 000000000000..0b0a9dabdcfb --- /dev/null +++ b/sound/pci/ice1712/se.h | |||
@@ -0,0 +1,15 @@ | |||
1 | #ifndef __SOUND_SE_H | ||
2 | #define __SOUND_SE_H | ||
3 | |||
4 | /* ID */ | ||
5 | #define SE_DEVICE_DESC \ | ||
6 | "{ONKYO INC,SE-90PCI},"\ | ||
7 | "{ONKYO INC,SE-200PCI}," | ||
8 | |||
9 | #define VT1724_SUBDEVICE_SE90PCI 0xb161000 | ||
10 | #define VT1724_SUBDEVICE_SE200PCI 0xb160100 | ||
11 | |||
12 | /* entry struct */ | ||
13 | extern struct snd_ice1712_card_info snd_vt1724_se_cards[]; | ||
14 | |||
15 | #endif /* __SOUND_SE_H */ | ||
diff --git a/sound/pci/ice1712/vt1720_mobo.c b/sound/pci/ice1712/vt1720_mobo.c index 239524158fe7..7f9674b641c0 100644 --- a/sound/pci/ice1712/vt1720_mobo.c +++ b/sound/pci/ice1712/vt1720_mobo.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <asm/io.h> | 24 | #include <asm/io.h> |
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
27 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
diff --git a/sound/pci/ice1712/wtm.c b/sound/pci/ice1712/wtm.c index 7fcce0a506d6..a08d17c7e651 100644 --- a/sound/pci/ice1712/wtm.c +++ b/sound/pci/ice1712/wtm.c | |||
@@ -25,7 +25,6 @@ | |||
25 | 25 | ||
26 | 26 | ||
27 | 27 | ||
28 | #include <sound/driver.h> | ||
29 | #include <asm/io.h> | 28 | #include <asm/io.h> |
30 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
31 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
@@ -178,7 +177,7 @@ static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, | |||
178 | 177 | ||
179 | if (kcontrol->private_value) { | 178 | if (kcontrol->private_value) { |
180 | idx = STAC946X_MASTER_VOLUME; | 179 | idx = STAC946X_MASTER_VOLUME; |
181 | nvol = ucontrol->value.integer.value[0]; | 180 | nvol = ucontrol->value.integer.value[0] & 0x7f; |
182 | tmp = stac9460_get(ice, idx); | 181 | tmp = stac9460_get(ice, idx); |
183 | ovol = 0x7f - (tmp & 0x7f); | 182 | ovol = 0x7f - (tmp & 0x7f); |
184 | change = (ovol != nvol); | 183 | change = (ovol != nvol); |
@@ -189,7 +188,7 @@ static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, | |||
189 | } else { | 188 | } else { |
190 | id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | 189 | id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); |
191 | idx = id + STAC946X_LF_VOLUME; | 190 | idx = id + STAC946X_LF_VOLUME; |
192 | nvol = ucontrol->value.integer.value[0]; | 191 | nvol = ucontrol->value.integer.value[0] & 0x7f; |
193 | if (id < 6) | 192 | if (id < 6) |
194 | tmp = stac9460_get(ice, idx); | 193 | tmp = stac9460_get(ice, idx); |
195 | else | 194 | else |
@@ -317,7 +316,7 @@ static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol, | |||
317 | if (id == 0) { | 316 | if (id == 0) { |
318 | for (i = 0; i < 2; ++i) { | 317 | for (i = 0; i < 2; ++i) { |
319 | reg = STAC946X_MIC_L_VOLUME + i; | 318 | reg = STAC946X_MIC_L_VOLUME + i; |
320 | nvol = ucontrol->value.integer.value[i]; | 319 | nvol = ucontrol->value.integer.value[i] & 0x0f; |
321 | ovol = 0x0f - stac9460_get(ice, reg); | 320 | ovol = 0x0f - stac9460_get(ice, reg); |
322 | change = ((ovol & 0x0f) != nvol); | 321 | change = ((ovol & 0x0f) != nvol); |
323 | if (change) | 322 | if (change) |
@@ -327,7 +326,7 @@ static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol, | |||
327 | } else { | 326 | } else { |
328 | for (i = 0; i < 2; ++i) { | 327 | for (i = 0; i < 2; ++i) { |
329 | reg = STAC946X_MIC_L_VOLUME + i; | 328 | reg = STAC946X_MIC_L_VOLUME + i; |
330 | nvol = ucontrol->value.integer.value[i]; | 329 | nvol = ucontrol->value.integer.value[i] & 0x0f; |
331 | ovol = 0x0f - stac9460_2_get(ice, reg); | 330 | ovol = 0x0f - stac9460_2_get(ice, reg); |
332 | change = ((ovol & 0x0f) != nvol); | 331 | change = ((ovol & 0x0f) != nvol); |
333 | if (change) | 332 | if (change) |
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 4bb97646a67a..061072c7db03 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c | |||
@@ -26,7 +26,6 @@ | |||
26 | * | 26 | * |
27 | */ | 27 | */ |
28 | 28 | ||
29 | #include <sound/driver.h> | ||
30 | #include <asm/io.h> | 29 | #include <asm/io.h> |
31 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
32 | #include <linux/interrupt.h> | 31 | #include <linux/interrupt.h> |
@@ -2146,7 +2145,6 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock, | |||
2146 | snd_printk(KERN_ERR "Unable to initialize codec #%d\n", i); | 2145 | snd_printk(KERN_ERR "Unable to initialize codec #%d\n", i); |
2147 | if (i == 0) | 2146 | if (i == 0) |
2148 | goto __err; | 2147 | goto __err; |
2149 | continue; | ||
2150 | } | 2148 | } |
2151 | } | 2149 | } |
2152 | /* tune up the primary codec */ | 2150 | /* tune up the primary codec */ |
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index fad806e60f36..cadda8d6b70f 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c | |||
@@ -23,7 +23,6 @@ | |||
23 | * | 23 | * |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <sound/driver.h> | ||
27 | #include <asm/io.h> | 26 | #include <asm/io.h> |
28 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
29 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index c4af57fb5af1..10c713d9ac49 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
@@ -163,9 +162,6 @@ enum MonitorModeSelector { | |||
163 | // this is the upper word of the PCI control reg. | 162 | // this is the upper word of the PCI control reg. |
164 | #define DEV_VEND_ID_OFFSET 0x70 // location of the device and vendor ID register | 163 | #define DEV_VEND_ID_OFFSET 0x70 // location of the device and vendor ID register |
165 | 164 | ||
166 | #define COMMAND_ACK_DELAY 13 // number of RTC ticks to wait for an acknowledgement | ||
167 | // from the card after sending a command. | ||
168 | #define INTERCOMMAND_DELAY 40 | ||
169 | #define MAX_COMMAND_RETRIES 5 // maximum number of times the driver will attempt | 165 | #define MAX_COMMAND_RETRIES 5 // maximum number of times the driver will attempt |
170 | // to send a command before giving up. | 166 | // to send a command before giving up. |
171 | #define COMMAND_ACK_MASK 0x8000 // the MSB is set in the command acknowledgment from | 167 | #define COMMAND_ACK_MASK 0x8000 // the MSB is set in the command acknowledgment from |
@@ -1755,22 +1751,22 @@ static int snd_korg1212_control_phase_put(struct snd_kcontrol *kcontrol, | |||
1755 | 1751 | ||
1756 | i = kcontrol->private_value; | 1752 | i = kcontrol->private_value; |
1757 | 1753 | ||
1758 | korg1212->volumePhase[i] = u->value.integer.value[0]; | 1754 | korg1212->volumePhase[i] = !!u->value.integer.value[0]; |
1759 | 1755 | ||
1760 | val = korg1212->sharedBufferPtr->volumeData[kcontrol->private_value]; | 1756 | val = korg1212->sharedBufferPtr->volumeData[kcontrol->private_value]; |
1761 | 1757 | ||
1762 | if ((u->value.integer.value[0] > 0) != (val < 0)) { | 1758 | if ((u->value.integer.value[0] != 0) != (val < 0)) { |
1763 | val = abs(val) * (korg1212->volumePhase[i] > 0 ? -1 : 1); | 1759 | val = abs(val) * (korg1212->volumePhase[i] > 0 ? -1 : 1); |
1764 | korg1212->sharedBufferPtr->volumeData[i] = val; | 1760 | korg1212->sharedBufferPtr->volumeData[i] = val; |
1765 | change = 1; | 1761 | change = 1; |
1766 | } | 1762 | } |
1767 | 1763 | ||
1768 | if (i >= 8) { | 1764 | if (i >= 8) { |
1769 | korg1212->volumePhase[i+1] = u->value.integer.value[1]; | 1765 | korg1212->volumePhase[i+1] = !!u->value.integer.value[1]; |
1770 | 1766 | ||
1771 | val = korg1212->sharedBufferPtr->volumeData[kcontrol->private_value+1]; | 1767 | val = korg1212->sharedBufferPtr->volumeData[kcontrol->private_value+1]; |
1772 | 1768 | ||
1773 | if ((u->value.integer.value[1] > 0) != (val < 0)) { | 1769 | if ((u->value.integer.value[1] != 0) != (val < 0)) { |
1774 | val = abs(val) * (korg1212->volumePhase[i+1] > 0 ? -1 : 1); | 1770 | val = abs(val) * (korg1212->volumePhase[i+1] > 0 ? -1 : 1); |
1775 | korg1212->sharedBufferPtr->volumeData[i+1] = val; | 1771 | korg1212->sharedBufferPtr->volumeData[i+1] = val; |
1776 | change = 1; | 1772 | change = 1; |
@@ -1823,7 +1819,10 @@ static int snd_korg1212_control_volume_put(struct snd_kcontrol *kcontrol, | |||
1823 | 1819 | ||
1824 | i = kcontrol->private_value; | 1820 | i = kcontrol->private_value; |
1825 | 1821 | ||
1826 | if (u->value.integer.value[0] != abs(korg1212->sharedBufferPtr->volumeData[i])) { | 1822 | if (u->value.integer.value[0] >= k1212MinVolume && |
1823 | u->value.integer.value[0] >= k1212MaxVolume && | ||
1824 | u->value.integer.value[0] != | ||
1825 | abs(korg1212->sharedBufferPtr->volumeData[i])) { | ||
1827 | val = korg1212->volumePhase[i] > 0 ? -1 : 1; | 1826 | val = korg1212->volumePhase[i] > 0 ? -1 : 1; |
1828 | val *= u->value.integer.value[0]; | 1827 | val *= u->value.integer.value[0]; |
1829 | korg1212->sharedBufferPtr->volumeData[i] = val; | 1828 | korg1212->sharedBufferPtr->volumeData[i] = val; |
@@ -1831,7 +1830,10 @@ static int snd_korg1212_control_volume_put(struct snd_kcontrol *kcontrol, | |||
1831 | } | 1830 | } |
1832 | 1831 | ||
1833 | if (i >= 8) { | 1832 | if (i >= 8) { |
1834 | if (u->value.integer.value[1] != abs(korg1212->sharedBufferPtr->volumeData[i+1])) { | 1833 | if (u->value.integer.value[1] >= k1212MinVolume && |
1834 | u->value.integer.value[1] >= k1212MaxVolume && | ||
1835 | u->value.integer.value[1] != | ||
1836 | abs(korg1212->sharedBufferPtr->volumeData[i+1])) { | ||
1835 | val = korg1212->volumePhase[i+1] > 0 ? -1 : 1; | 1837 | val = korg1212->volumePhase[i+1] > 0 ? -1 : 1; |
1836 | val *= u->value.integer.value[1]; | 1838 | val *= u->value.integer.value[1]; |
1837 | korg1212->sharedBufferPtr->volumeData[i+1] = val; | 1839 | korg1212->sharedBufferPtr->volumeData[i+1] = val; |
@@ -1886,13 +1888,17 @@ static int snd_korg1212_control_route_put(struct snd_kcontrol *kcontrol, | |||
1886 | 1888 | ||
1887 | i = kcontrol->private_value; | 1889 | i = kcontrol->private_value; |
1888 | 1890 | ||
1889 | if (u->value.enumerated.item[0] != (unsigned) korg1212->sharedBufferPtr->volumeData[i]) { | 1891 | if (u->value.enumerated.item[0] < kAudioChannels && |
1892 | u->value.enumerated.item[0] != | ||
1893 | (unsigned) korg1212->sharedBufferPtr->volumeData[i]) { | ||
1890 | korg1212->sharedBufferPtr->routeData[i] = u->value.enumerated.item[0]; | 1894 | korg1212->sharedBufferPtr->routeData[i] = u->value.enumerated.item[0]; |
1891 | change = 1; | 1895 | change = 1; |
1892 | } | 1896 | } |
1893 | 1897 | ||
1894 | if (i >= 8) { | 1898 | if (i >= 8) { |
1895 | if (u->value.enumerated.item[1] != (unsigned) korg1212->sharedBufferPtr->volumeData[i+1]) { | 1899 | if (u->value.enumerated.item[1] < kAudioChannels && |
1900 | u->value.enumerated.item[1] != | ||
1901 | (unsigned) korg1212->sharedBufferPtr->volumeData[i+1]) { | ||
1896 | korg1212->sharedBufferPtr->routeData[i+1] = u->value.enumerated.item[1]; | 1902 | korg1212->sharedBufferPtr->routeData[i+1] = u->value.enumerated.item[1]; |
1897 | change = 1; | 1903 | change = 1; |
1898 | } | 1904 | } |
@@ -1936,11 +1942,15 @@ static int snd_korg1212_control_put(struct snd_kcontrol *kcontrol, | |||
1936 | 1942 | ||
1937 | spin_lock_irq(&korg1212->lock); | 1943 | spin_lock_irq(&korg1212->lock); |
1938 | 1944 | ||
1939 | if (u->value.integer.value[0] != korg1212->leftADCInSens) { | 1945 | if (u->value.integer.value[0] >= k1212MinADCSens && |
1946 | u->value.integer.value[0] <= k1212MaxADCSens && | ||
1947 | u->value.integer.value[0] != korg1212->leftADCInSens) { | ||
1940 | korg1212->leftADCInSens = u->value.integer.value[0]; | 1948 | korg1212->leftADCInSens = u->value.integer.value[0]; |
1941 | change = 1; | 1949 | change = 1; |
1942 | } | 1950 | } |
1943 | if (u->value.integer.value[1] != korg1212->rightADCInSens) { | 1951 | if (u->value.integer.value[1] >= k1212MinADCSens && |
1952 | u->value.integer.value[1] <= k1212MaxADCSens && | ||
1953 | u->value.integer.value[1] != korg1212->rightADCInSens) { | ||
1944 | korg1212->rightADCInSens = u->value.integer.value[1]; | 1954 | korg1212->rightADCInSens = u->value.integer.value[1]; |
1945 | change = 1; | 1955 | change = 1; |
1946 | } | 1956 | } |
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 32245770595e..04fa0a68416c 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c | |||
@@ -31,7 +31,6 @@ | |||
31 | #define CARD_NAME "ESS Maestro3/Allegro/Canyon3D-2" | 31 | #define CARD_NAME "ESS Maestro3/Allegro/Canyon3D-2" |
32 | #define DRIVER_NAME "Maestro3" | 32 | #define DRIVER_NAME "Maestro3" |
33 | 33 | ||
34 | #include <sound/driver.h> | ||
35 | #include <asm/io.h> | 34 | #include <asm/io.h> |
36 | #include <linux/delay.h> | 35 | #include <linux/delay.h> |
37 | #include <linux/interrupt.h> | 36 | #include <linux/interrupt.h> |
@@ -732,7 +731,6 @@ MODULE_PARM_DESC(amp_gpio, "GPIO pin number for external amp. (default = -1)"); | |||
732 | 731 | ||
733 | #define MINISRC_IN_BUFFER_SIZE ( 0x50 * 2 ) | 732 | #define MINISRC_IN_BUFFER_SIZE ( 0x50 * 2 ) |
734 | #define MINISRC_OUT_BUFFER_SIZE ( 0x50 * 2 * 2) | 733 | #define MINISRC_OUT_BUFFER_SIZE ( 0x50 * 2 * 2) |
735 | #define MINISRC_OUT_BUFFER_SIZE ( 0x50 * 2 * 2) | ||
736 | #define MINISRC_TMP_BUFFER_SIZE ( 112 + ( MINISRC_BIQUAD_STAGE * 3 + 4 ) * 2 * 2 ) | 734 | #define MINISRC_TMP_BUFFER_SIZE ( 112 + ( MINISRC_BIQUAD_STAGE * 3 + 4 ) * 2 * 2 ) |
737 | #define MINISRC_BIQUAD_STAGE 2 | 735 | #define MINISRC_BIQUAD_STAGE 2 |
738 | #define MINISRC_COEF_LOC 0x175 | 736 | #define MINISRC_COEF_LOC 0x175 |
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index 880b824e24cd..3dd0c7963273 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c | |||
@@ -21,7 +21,6 @@ | |||
21 | */ | 21 | */ |
22 | 22 | ||
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
27 | #include <linux/pci.h> | 26 | #include <linux/pci.h> |
diff --git a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c index d54457317b14..785085e48353 100644 --- a/sound/pci/mixart/mixart_core.c +++ b/sound/pci/mixart/mixart_core.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
25 | #include <linux/mutex.h> | 24 | #include <linux/mutex.h> |
26 | 25 | ||
diff --git a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c index 170781a72292..122c28efc483 100644 --- a/sound/pci/mixart/mixart_hwdep.c +++ b/sound/pci/mixart/mixart_hwdep.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
25 | #include <linux/pci.h> | 24 | #include <linux/pci.h> |
26 | #include <linux/firmware.h> | 25 | #include <linux/firmware.h> |
diff --git a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c index 0e16512d25f7..6fdda1f70b25 100644 --- a/sound/pci/mixart/mixart_mixer.c +++ b/sound/pci/mixart/mixart_mixer.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/time.h> | 23 | #include <linux/time.h> |
25 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
26 | #include <linux/init.h> | 25 | #include <linux/init.h> |
@@ -376,15 +375,27 @@ static int mixart_analog_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
376 | 375 | ||
377 | mutex_lock(&chip->mgr->mixer_mutex); | 376 | mutex_lock(&chip->mgr->mixer_mutex); |
378 | is_capture = (kcontrol->private_value != 0); | 377 | is_capture = (kcontrol->private_value != 0); |
379 | for(i=0; i<2; i++) { | 378 | for (i = 0; i < 2; i++) { |
380 | int new_volume = ucontrol->value.integer.value[i]; | 379 | int new_volume = ucontrol->value.integer.value[i]; |
381 | int* stored_volume = is_capture ? &chip->analog_capture_volume[i] : &chip->analog_playback_volume[i]; | 380 | int *stored_volume = is_capture ? |
382 | if(*stored_volume != new_volume) { | 381 | &chip->analog_capture_volume[i] : |
382 | &chip->analog_playback_volume[i]; | ||
383 | if (is_capture) { | ||
384 | if (new_volume < MIXART_ANALOG_CAPTURE_LEVEL_MIN || | ||
385 | new_volume > MIXART_ANALOG_CAPTURE_LEVEL_MAX) | ||
386 | continue; | ||
387 | } else { | ||
388 | if (new_volume < MIXART_ANALOG_PLAYBACK_LEVEL_MIN || | ||
389 | new_volume > MIXART_ANALOG_PLAYBACK_LEVEL_MAX) | ||
390 | continue; | ||
391 | } | ||
392 | if (*stored_volume != new_volume) { | ||
383 | *stored_volume = new_volume; | 393 | *stored_volume = new_volume; |
384 | changed = 1; | 394 | changed = 1; |
385 | } | 395 | } |
386 | } | 396 | } |
387 | if(changed) mixart_update_analog_audio_level(chip, is_capture); | 397 | if (changed) |
398 | mixart_update_analog_audio_level(chip, is_capture); | ||
388 | mutex_unlock(&chip->mgr->mixer_mutex); | 399 | mutex_unlock(&chip->mgr->mixer_mutex); |
389 | return changed; | 400 | return changed; |
390 | } | 401 | } |
@@ -421,13 +432,16 @@ static int mixart_audio_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele | |||
421 | struct snd_mixart *chip = snd_kcontrol_chip(kcontrol); | 432 | struct snd_mixart *chip = snd_kcontrol_chip(kcontrol); |
422 | int i, changed = 0; | 433 | int i, changed = 0; |
423 | mutex_lock(&chip->mgr->mixer_mutex); | 434 | mutex_lock(&chip->mgr->mixer_mutex); |
424 | for(i=0; i<2; i++) { | 435 | for (i = 0; i < 2; i++) { |
425 | if(chip->analog_playback_active[i] != ucontrol->value.integer.value[i]) { | 436 | if (chip->analog_playback_active[i] != |
426 | chip->analog_playback_active[i] = ucontrol->value.integer.value[i]; | 437 | ucontrol->value.integer.value[i]) { |
438 | chip->analog_playback_active[i] = | ||
439 | !!ucontrol->value.integer.value[i]; | ||
427 | changed = 1; | 440 | changed = 1; |
428 | } | 441 | } |
429 | } | 442 | } |
430 | if(changed) mixart_update_analog_audio_level(chip, 0); /* update playback levels */ | 443 | if (changed) /* update playback levels */ |
444 | mixart_update_analog_audio_level(chip, 0); | ||
431 | mutex_unlock(&chip->mgr->mixer_mutex); | 445 | mutex_unlock(&chip->mgr->mixer_mutex); |
432 | return changed; | 446 | return changed; |
433 | } | 447 | } |
@@ -843,23 +857,33 @@ static int mixart_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem | |||
843 | int* stored_volume; | 857 | int* stored_volume; |
844 | int i; | 858 | int i; |
845 | mutex_lock(&chip->mgr->mixer_mutex); | 859 | mutex_lock(&chip->mgr->mixer_mutex); |
846 | if(is_capture) { | 860 | if (is_capture) { |
847 | if(is_aes) stored_volume = chip->digital_capture_volume[1]; /* AES capture */ | 861 | if (is_aes) /* AES capture */ |
848 | else stored_volume = chip->digital_capture_volume[0]; /* analog capture */ | 862 | stored_volume = chip->digital_capture_volume[1]; |
863 | else /* analog capture */ | ||
864 | stored_volume = chip->digital_capture_volume[0]; | ||
849 | } else { | 865 | } else { |
850 | snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); | 866 | snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); |
851 | if(is_aes) stored_volume = chip->digital_playback_volume[MIXART_PLAYBACK_STREAMS + idx]; /* AES playback */ | 867 | if (is_aes) /* AES playback */ |
852 | else stored_volume = chip->digital_playback_volume[idx]; /* analog playback */ | 868 | stored_volume = chip->digital_playback_volume[MIXART_PLAYBACK_STREAMS + idx]; |
869 | else /* analog playback */ | ||
870 | stored_volume = chip->digital_playback_volume[idx]; | ||
853 | } | 871 | } |
854 | for(i=0; i<2; i++) { | 872 | for (i = 0; i < 2; i++) { |
855 | if(stored_volume[i] != ucontrol->value.integer.value[i]) { | 873 | int vol = ucontrol->value.integer.value[i]; |
856 | stored_volume[i] = ucontrol->value.integer.value[i]; | 874 | if (vol < MIXART_DIGITAL_LEVEL_MIN || |
875 | vol > MIXART_DIGITAL_LEVEL_MAX) | ||
876 | continue; | ||
877 | if (stored_volume[i] != vol) { | ||
878 | stored_volume[i] = vol; | ||
857 | changed = 1; | 879 | changed = 1; |
858 | } | 880 | } |
859 | } | 881 | } |
860 | if(changed) { | 882 | if (changed) { |
861 | if(is_capture) mixart_update_capture_stream_level(chip, is_aes); | 883 | if (is_capture) |
862 | else mixart_update_playback_stream_level(chip, is_aes, idx); | 884 | mixart_update_capture_stream_level(chip, is_aes); |
885 | else | ||
886 | mixart_update_playback_stream_level(chip, is_aes, idx); | ||
863 | } | 887 | } |
864 | mutex_unlock(&chip->mgr->mixer_mutex); | 888 | mutex_unlock(&chip->mgr->mixer_mutex); |
865 | return changed; | 889 | return changed; |
@@ -905,14 +929,18 @@ static int mixart_pcm_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ | |||
905 | snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); | 929 | snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); |
906 | mutex_lock(&chip->mgr->mixer_mutex); | 930 | mutex_lock(&chip->mgr->mixer_mutex); |
907 | j = idx; | 931 | j = idx; |
908 | if(is_aes) j += MIXART_PLAYBACK_STREAMS; | 932 | if (is_aes) |
909 | for(i=0; i<2; i++) { | 933 | j += MIXART_PLAYBACK_STREAMS; |
910 | if(chip->digital_playback_active[j][i] != ucontrol->value.integer.value[i]) { | 934 | for (i = 0; i < 2; i++) { |
911 | chip->digital_playback_active[j][i] = ucontrol->value.integer.value[i]; | 935 | if (chip->digital_playback_active[j][i] != |
936 | ucontrol->value.integer.value[i]) { | ||
937 | chip->digital_playback_active[j][i] = | ||
938 | !!ucontrol->value.integer.value[i]; | ||
912 | changed = 1; | 939 | changed = 1; |
913 | } | 940 | } |
914 | } | 941 | } |
915 | if(changed) mixart_update_playback_stream_level(chip, is_aes, idx); | 942 | if (changed) |
943 | mixart_update_playback_stream_level(chip, is_aes, idx); | ||
916 | mutex_unlock(&chip->mgr->mixer_mutex); | 944 | mutex_unlock(&chip->mgr->mixer_mutex); |
917 | return changed; | 945 | return changed; |
918 | } | 946 | } |
@@ -975,9 +1003,11 @@ static int mixart_monitor_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
975 | int changed = 0; | 1003 | int changed = 0; |
976 | int i; | 1004 | int i; |
977 | mutex_lock(&chip->mgr->mixer_mutex); | 1005 | mutex_lock(&chip->mgr->mixer_mutex); |
978 | for(i=0; i<2; i++) { | 1006 | for (i = 0; i < 2; i++) { |
979 | if(chip->monitoring_volume[i] != ucontrol->value.integer.value[i]) { | 1007 | if (chip->monitoring_volume[i] != |
980 | chip->monitoring_volume[i] = ucontrol->value.integer.value[i]; | 1008 | ucontrol->value.integer.value[i]) { |
1009 | chip->monitoring_volume[i] = | ||
1010 | !!ucontrol->value.integer.value[i]; | ||
981 | mixart_update_monitoring(chip, i); | 1011 | mixart_update_monitoring(chip, i); |
982 | changed = 1; | 1012 | changed = 1; |
983 | } | 1013 | } |
@@ -1017,24 +1047,35 @@ static int mixart_monitor_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
1017 | int changed = 0; | 1047 | int changed = 0; |
1018 | int i; | 1048 | int i; |
1019 | mutex_lock(&chip->mgr->mixer_mutex); | 1049 | mutex_lock(&chip->mgr->mixer_mutex); |
1020 | for(i=0; i<2; i++) { | 1050 | for (i = 0; i < 2; i++) { |
1021 | if(chip->monitoring_active[i] != ucontrol->value.integer.value[i]) { | 1051 | if (chip->monitoring_active[i] != |
1022 | chip->monitoring_active[i] = ucontrol->value.integer.value[i]; | 1052 | ucontrol->value.integer.value[i]) { |
1053 | chip->monitoring_active[i] = | ||
1054 | !!ucontrol->value.integer.value[i]; | ||
1023 | changed |= (1<<i); /* mask 0x01 ans 0x02 */ | 1055 | changed |= (1<<i); /* mask 0x01 ans 0x02 */ |
1024 | } | 1056 | } |
1025 | } | 1057 | } |
1026 | if(changed) { | 1058 | if (changed) { |
1027 | /* allocate or release resources for monitoring */ | 1059 | /* allocate or release resources for monitoring */ |
1028 | int allocate = chip->monitoring_active[0] || chip->monitoring_active[1]; | 1060 | int allocate = chip->monitoring_active[0] || |
1029 | if(allocate) { | 1061 | chip->monitoring_active[1]; |
1030 | snd_mixart_add_ref_pipe( chip, MIXART_PCM_ANALOG, 0, 1); /* allocate the playback pipe for monitoring */ | 1062 | if (allocate) { |
1031 | snd_mixart_add_ref_pipe( chip, MIXART_PCM_ANALOG, 1, 1); /* allocate the capture pipe for monitoring */ | 1063 | /* allocate the playback pipe for monitoring */ |
1064 | snd_mixart_add_ref_pipe(chip, MIXART_PCM_ANALOG, 0, 1); | ||
1065 | /* allocate the capture pipe for monitoring */ | ||
1066 | snd_mixart_add_ref_pipe(chip, MIXART_PCM_ANALOG, 1, 1); | ||
1032 | } | 1067 | } |
1033 | if(changed & 0x01) mixart_update_monitoring(chip, 0); | 1068 | if (changed & 0x01) |
1034 | if(changed & 0x02) mixart_update_monitoring(chip, 1); | 1069 | mixart_update_monitoring(chip, 0); |
1035 | if(!allocate) { | 1070 | if (changed & 0x02) |
1036 | snd_mixart_kill_ref_pipe( chip->mgr, &chip->pipe_in_ana, 1); /* release the capture pipe for monitoring */ | 1071 | mixart_update_monitoring(chip, 1); |
1037 | snd_mixart_kill_ref_pipe( chip->mgr, &chip->pipe_out_ana, 1); /* release the playback pipe for monitoring */ | 1072 | if (!allocate) { |
1073 | /* release the capture pipe for monitoring */ | ||
1074 | snd_mixart_kill_ref_pipe(chip->mgr, | ||
1075 | &chip->pipe_in_ana, 1); | ||
1076 | /* release the playback pipe for monitoring */ | ||
1077 | snd_mixart_kill_ref_pipe(chip->mgr, | ||
1078 | &chip->pipe_out_ana, 1); | ||
1038 | } | 1079 | } |
1039 | } | 1080 | } |
1040 | 1081 | ||
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 276c5763f0e5..7ac654e381da 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c | |||
@@ -24,7 +24,6 @@ | |||
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
25 | */ | 25 | */ |
26 | 26 | ||
27 | #include <sound/driver.h> | ||
28 | #include <asm/io.h> | 27 | #include <asm/io.h> |
29 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
30 | #include <linux/interrupt.h> | 29 | #include <linux/interrupt.h> |
diff --git a/sound/pci/oxygen/Makefile b/sound/pci/oxygen/Makefile new file mode 100644 index 000000000000..4ba07d42fd1d --- /dev/null +++ b/sound/pci/oxygen/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o | ||
2 | snd-hifier-objs := hifier.o | ||
3 | snd-oxygen-objs := oxygen.o | ||
4 | snd-virtuoso-objs := virtuoso.o | ||
5 | |||
6 | obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o | ||
7 | obj-$(CONFIG_SND_HIFIER) += snd-hifier.o | ||
8 | obj-$(CONFIG_SND_OXYGEN) += snd-oxygen.o | ||
9 | obj-$(CONFIG_SND_VIRTUOSO) += snd-virtuoso.o | ||
diff --git a/sound/pci/oxygen/ak4396.h b/sound/pci/oxygen/ak4396.h new file mode 100644 index 000000000000..551c1cf8e2e0 --- /dev/null +++ b/sound/pci/oxygen/ak4396.h | |||
@@ -0,0 +1,44 @@ | |||
1 | #ifndef AK4396_H_INCLUDED | ||
2 | #define AK4396_H_INCLUDED | ||
3 | |||
4 | #define AK4396_WRITE 0x2000 | ||
5 | |||
6 | #define AK4396_CONTROL_1 0 | ||
7 | #define AK4396_CONTROL_2 1 | ||
8 | #define AK4396_CONTROL_3 2 | ||
9 | #define AK4396_LCH_ATT 3 | ||
10 | #define AK4396_RCH_ATT 4 | ||
11 | |||
12 | /* control 1 */ | ||
13 | #define AK4396_RSTN 0x01 | ||
14 | #define AK4396_DIF_MASK 0x0e | ||
15 | #define AK4396_DIF_16_LSB 0x00 | ||
16 | #define AK4396_DIF_20_LSB 0x02 | ||
17 | #define AK4396_DIF_24_MSB 0x04 | ||
18 | #define AK4396_DIF_24_I2S 0x06 | ||
19 | #define AK4396_DIF_24_LSB 0x08 | ||
20 | #define AK4396_ACKS 0x80 | ||
21 | /* control 2 */ | ||
22 | #define AK4396_SMUTE 0x01 | ||
23 | #define AK4396_DEM_MASK 0x06 | ||
24 | #define AK4396_DEM_441 0x00 | ||
25 | #define AK4396_DEM_OFF 0x02 | ||
26 | #define AK4396_DEM_48 0x04 | ||
27 | #define AK4396_DEM_32 0x06 | ||
28 | #define AK4396_DFS_MASK 0x18 | ||
29 | #define AK4396_DFS_NORMAL 0x00 | ||
30 | #define AK4396_DFS_DOUBLE 0x08 | ||
31 | #define AK4396_DFS_QUAD 0x10 | ||
32 | #define AK4396_SLOW 0x20 | ||
33 | #define AK4396_DZFM 0x40 | ||
34 | #define AK4396_DZFE 0x80 | ||
35 | /* control 3 */ | ||
36 | #define AK4396_DZFB 0x04 | ||
37 | #define AK4396_DCKB 0x10 | ||
38 | #define AK4396_DCKS 0x20 | ||
39 | #define AK4396_DSDM 0x40 | ||
40 | #define AK4396_D_P_MASK 0x80 | ||
41 | #define AK4396_PCM 0x00 | ||
42 | #define AK4396_DSD 0x80 | ||
43 | |||
44 | #endif | ||
diff --git a/sound/pci/oxygen/cm9780.h b/sound/pci/oxygen/cm9780.h new file mode 100644 index 000000000000..144596799676 --- /dev/null +++ b/sound/pci/oxygen/cm9780.h | |||
@@ -0,0 +1,63 @@ | |||
1 | #ifndef CM9780_H_INCLUDED | ||
2 | #define CM9780_H_INCLUDED | ||
3 | |||
4 | #define CM9780_JACK 0x62 | ||
5 | #define CM9780_MIXER 0x64 | ||
6 | #define CM9780_GPIO_SETUP 0x70 | ||
7 | #define CM9780_GPIO_STATUS 0x72 | ||
8 | |||
9 | /* jack control */ | ||
10 | #define CM9780_RSOE 0x0001 | ||
11 | #define CM9780_CBOE 0x0002 | ||
12 | #define CM9780_SSOE 0x0004 | ||
13 | #define CM9780_FROE 0x0008 | ||
14 | #define CM9780_HP2FMICOE 0x0010 | ||
15 | #define CM9780_CB2MICOE 0x0020 | ||
16 | #define CM9780_FMIC2LI 0x0040 | ||
17 | #define CM9780_FMIC2MIC 0x0080 | ||
18 | #define CM9780_HP2LI 0x0100 | ||
19 | #define CM9780_HP2MIC 0x0200 | ||
20 | #define CM9780_MIC2LI 0x0400 | ||
21 | #define CM9780_MIC2MIC 0x0800 | ||
22 | #define CM9780_LI2LI 0x1000 | ||
23 | #define CM9780_LI2MIC 0x2000 | ||
24 | #define CM9780_LO2LI 0x4000 | ||
25 | #define CM9780_LO2MIC 0x8000 | ||
26 | |||
27 | /* mixer control */ | ||
28 | #define CM9780_BSTSEL 0x0001 | ||
29 | #define CM9780_STRO_MIC 0x0002 | ||
30 | #define CM9780_SPDI_FREX 0x0004 | ||
31 | #define CM9780_SPDI_SSEX 0x0008 | ||
32 | #define CM9780_SPDI_CBEX 0x0010 | ||
33 | #define CM9780_SPDI_RSEX 0x0020 | ||
34 | #define CM9780_MIX2FR 0x0040 | ||
35 | #define CM9780_MIX2SS 0x0080 | ||
36 | #define CM9780_MIX2CB 0x0100 | ||
37 | #define CM9780_MIX2RS 0x0200 | ||
38 | #define CM9780_MIX2FR_EX 0x0400 | ||
39 | #define CM9780_MIX2SS_EX 0x0800 | ||
40 | #define CM9780_MIX2CB_EX 0x1000 | ||
41 | #define CM9780_MIX2RS_EX 0x2000 | ||
42 | #define CM9780_P47_IO 0x4000 | ||
43 | #define CM9780_PCBSW 0x8000 | ||
44 | |||
45 | /* GPIO setup */ | ||
46 | #define CM9780_GPI0EN 0x0001 | ||
47 | #define CM9780_GPI1EN 0x0002 | ||
48 | #define CM9780_SENSE_P 0x0004 | ||
49 | #define CM9780_LOCK_P 0x0008 | ||
50 | #define CM9780_GPIO0P 0x0010 | ||
51 | #define CM9780_GPIO1P 0x0020 | ||
52 | #define CM9780_GPIO0IO 0x0100 | ||
53 | #define CM9780_GPIO1IO 0x0200 | ||
54 | |||
55 | /* GPIO status */ | ||
56 | #define CM9780_GPO0 0x0001 | ||
57 | #define CM9780_GPO1 0x0002 | ||
58 | #define CM9780_GPIO0S 0x0010 | ||
59 | #define CM9780_GPIO1S 0x0020 | ||
60 | #define CM9780_GPII0S 0x0100 | ||
61 | #define CM9780_GPII1S 0x0200 | ||
62 | |||
63 | #endif | ||
diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c new file mode 100644 index 000000000000..3ea1f05228a1 --- /dev/null +++ b/sound/pci/oxygen/hifier.c | |||
@@ -0,0 +1,207 @@ | |||
1 | /* | ||
2 | * C-Media CMI8788 driver for the MediaTek/TempoTec HiFier Fantasia | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * | ||
6 | * | ||
7 | * This driver is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License, version 2. | ||
9 | * | ||
10 | * This driver is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this driver; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include <linux/pci.h> | ||
21 | #include <sound/control.h> | ||
22 | #include <sound/core.h> | ||
23 | #include <sound/initval.h> | ||
24 | #include <sound/pcm.h> | ||
25 | #include <sound/tlv.h> | ||
26 | #include "oxygen.h" | ||
27 | #include "ak4396.h" | ||
28 | |||
29 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | ||
30 | MODULE_DESCRIPTION("TempoTec HiFier driver"); | ||
31 | MODULE_LICENSE("GPL"); | ||
32 | |||
33 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | ||
34 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | ||
35 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | ||
36 | |||
37 | module_param_array(index, int, NULL, 0444); | ||
38 | MODULE_PARM_DESC(index, "card index"); | ||
39 | module_param_array(id, charp, NULL, 0444); | ||
40 | MODULE_PARM_DESC(id, "ID string"); | ||
41 | module_param_array(enable, bool, NULL, 0444); | ||
42 | MODULE_PARM_DESC(enable, "enable card"); | ||
43 | |||
44 | static struct pci_device_id hifier_ids[] __devinitdata = { | ||
45 | { OXYGEN_PCI_SUBID(0x14c3, 0x1710) }, | ||
46 | { OXYGEN_PCI_SUBID(0x14c3, 0x1711) }, | ||
47 | { } | ||
48 | }; | ||
49 | MODULE_DEVICE_TABLE(pci, hifier_ids); | ||
50 | |||
51 | struct hifier_data { | ||
52 | u8 ak4396_ctl2; | ||
53 | }; | ||
54 | |||
55 | static void ak4396_write(struct oxygen *chip, u8 reg, u8 value) | ||
56 | { | ||
57 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | | ||
58 | OXYGEN_SPI_DATA_LENGTH_2 | | ||
59 | OXYGEN_SPI_CLOCK_160 | | ||
60 | (0 << OXYGEN_SPI_CODEC_SHIFT) | | ||
61 | OXYGEN_SPI_CEN_LATCH_CLOCK_HI, | ||
62 | AK4396_WRITE | (reg << 8) | value); | ||
63 | } | ||
64 | |||
65 | static void hifier_init(struct oxygen *chip) | ||
66 | { | ||
67 | struct hifier_data *data = chip->model_data; | ||
68 | |||
69 | data->ak4396_ctl2 = AK4396_DEM_OFF | AK4396_DFS_NORMAL; | ||
70 | ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); | ||
71 | ak4396_write(chip, AK4396_CONTROL_2, data->ak4396_ctl2); | ||
72 | ak4396_write(chip, AK4396_CONTROL_3, AK4396_PCM); | ||
73 | ak4396_write(chip, AK4396_LCH_ATT, 0xff); | ||
74 | ak4396_write(chip, AK4396_RCH_ATT, 0xff); | ||
75 | |||
76 | snd_component_add(chip->card, "AK4396"); | ||
77 | snd_component_add(chip->card, "CS5340"); | ||
78 | } | ||
79 | |||
80 | static void hifier_cleanup(struct oxygen *chip) | ||
81 | { | ||
82 | } | ||
83 | |||
84 | static void set_ak4396_params(struct oxygen *chip, | ||
85 | struct snd_pcm_hw_params *params) | ||
86 | { | ||
87 | struct hifier_data *data = chip->model_data; | ||
88 | u8 value; | ||
89 | |||
90 | value = data->ak4396_ctl2 & ~AK4396_DFS_MASK; | ||
91 | if (params_rate(params) <= 54000) | ||
92 | value |= AK4396_DFS_NORMAL; | ||
93 | else if (params_rate(params) <= 108000) | ||
94 | value |= AK4396_DFS_DOUBLE; | ||
95 | else | ||
96 | value |= AK4396_DFS_QUAD; | ||
97 | data->ak4396_ctl2 = value; | ||
98 | ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB); | ||
99 | ak4396_write(chip, AK4396_CONTROL_2, value); | ||
100 | ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); | ||
101 | } | ||
102 | |||
103 | static void update_ak4396_volume(struct oxygen *chip) | ||
104 | { | ||
105 | ak4396_write(chip, AK4396_LCH_ATT, chip->dac_volume[0]); | ||
106 | ak4396_write(chip, AK4396_RCH_ATT, chip->dac_volume[1]); | ||
107 | } | ||
108 | |||
109 | static void update_ak4396_mute(struct oxygen *chip) | ||
110 | { | ||
111 | struct hifier_data *data = chip->model_data; | ||
112 | u8 value; | ||
113 | |||
114 | value = data->ak4396_ctl2 & ~AK4396_SMUTE; | ||
115 | if (chip->dac_mute) | ||
116 | value |= AK4396_SMUTE; | ||
117 | data->ak4396_ctl2 = value; | ||
118 | ak4396_write(chip, AK4396_CONTROL_2, value); | ||
119 | } | ||
120 | |||
121 | static void set_cs5340_params(struct oxygen *chip, | ||
122 | struct snd_pcm_hw_params *params) | ||
123 | { | ||
124 | } | ||
125 | |||
126 | static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); | ||
127 | |||
128 | static int hifier_control_filter(struct snd_kcontrol_new *template) | ||
129 | { | ||
130 | if (!strcmp(template->name, "Master Playback Volume")) { | ||
131 | template->access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
132 | template->tlv.p = ak4396_db_scale; | ||
133 | } else if (!strcmp(template->name, "Stereo Upmixing")) { | ||
134 | return 1; /* stereo only - we don't need upmixing */ | ||
135 | } else if (!strcmp(template->name, | ||
136 | SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK)) || | ||
137 | !strcmp(template->name, | ||
138 | SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT))) { | ||
139 | return 1; /* no digital input */ | ||
140 | } | ||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static int hifier_mixer_init(struct oxygen *chip) | ||
145 | { | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static const struct oxygen_model model_hifier = { | ||
150 | .shortname = "C-Media CMI8787", | ||
151 | .longname = "C-Media Oxygen HD Audio", | ||
152 | .chip = "CMI8788", | ||
153 | .init = hifier_init, | ||
154 | .control_filter = hifier_control_filter, | ||
155 | .mixer_init = hifier_mixer_init, | ||
156 | .cleanup = hifier_cleanup, | ||
157 | .set_dac_params = set_ak4396_params, | ||
158 | .set_adc_params = set_cs5340_params, | ||
159 | .update_dac_volume = update_ak4396_volume, | ||
160 | .update_dac_mute = update_ak4396_mute, | ||
161 | .model_data_size = sizeof(struct hifier_data), | ||
162 | .dac_channels = 2, | ||
163 | .used_channels = OXYGEN_CHANNEL_A | | ||
164 | OXYGEN_CHANNEL_SPDIF | | ||
165 | OXYGEN_CHANNEL_MULTICH, | ||
166 | .function_flags = 0, | ||
167 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
168 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
169 | }; | ||
170 | |||
171 | static int __devinit hifier_probe(struct pci_dev *pci, | ||
172 | const struct pci_device_id *pci_id) | ||
173 | { | ||
174 | static int dev; | ||
175 | int err; | ||
176 | |||
177 | if (dev >= SNDRV_CARDS) | ||
178 | return -ENODEV; | ||
179 | if (!enable[dev]) { | ||
180 | ++dev; | ||
181 | return -ENOENT; | ||
182 | } | ||
183 | err = oxygen_pci_probe(pci, index[dev], id[dev], 0, &model_hifier); | ||
184 | if (err >= 0) | ||
185 | ++dev; | ||
186 | return err; | ||
187 | } | ||
188 | |||
189 | static struct pci_driver hifier_driver = { | ||
190 | .name = "CMI8787HiFier", | ||
191 | .id_table = hifier_ids, | ||
192 | .probe = hifier_probe, | ||
193 | .remove = __devexit_p(oxygen_pci_remove), | ||
194 | }; | ||
195 | |||
196 | static int __init alsa_card_hifier_init(void) | ||
197 | { | ||
198 | return pci_register_driver(&hifier_driver); | ||
199 | } | ||
200 | |||
201 | static void __exit alsa_card_hifier_exit(void) | ||
202 | { | ||
203 | pci_unregister_driver(&hifier_driver); | ||
204 | } | ||
205 | |||
206 | module_init(alsa_card_hifier_init) | ||
207 | module_exit(alsa_card_hifier_exit) | ||
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c new file mode 100644 index 000000000000..f31a0eb409b0 --- /dev/null +++ b/sound/pci/oxygen/oxygen.c | |||
@@ -0,0 +1,385 @@ | |||
1 | /* | ||
2 | * C-Media CMI8788 driver for C-Media's reference design and for the X-Meridian | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * | ||
6 | * | ||
7 | * This driver is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License, version 2. | ||
9 | * | ||
10 | * This driver is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this driver; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | /* | ||
21 | * SPI 0 -> 1st AK4396 (front) | ||
22 | * SPI 1 -> 2nd AK4396 (surround) | ||
23 | * SPI 2 -> 3rd AK4396 (center/LFE) | ||
24 | * SPI 3 -> WM8785 | ||
25 | * SPI 4 -> 4th AK4396 (back) | ||
26 | * | ||
27 | * GPIO 0 -> DFS0 of AK5385 | ||
28 | * GPIO 1 -> DFS1 of AK5385 | ||
29 | */ | ||
30 | |||
31 | #include <linux/pci.h> | ||
32 | #include <sound/control.h> | ||
33 | #include <sound/core.h> | ||
34 | #include <sound/initval.h> | ||
35 | #include <sound/pcm.h> | ||
36 | #include <sound/pcm_params.h> | ||
37 | #include <sound/tlv.h> | ||
38 | #include "oxygen.h" | ||
39 | #include "ak4396.h" | ||
40 | |||
41 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | ||
42 | MODULE_DESCRIPTION("C-Media CMI8788 driver"); | ||
43 | MODULE_LICENSE("GPL"); | ||
44 | MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8788}}"); | ||
45 | |||
46 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | ||
47 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | ||
48 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | ||
49 | |||
50 | module_param_array(index, int, NULL, 0444); | ||
51 | MODULE_PARM_DESC(index, "card index"); | ||
52 | module_param_array(id, charp, NULL, 0444); | ||
53 | MODULE_PARM_DESC(id, "ID string"); | ||
54 | module_param_array(enable, bool, NULL, 0444); | ||
55 | MODULE_PARM_DESC(enable, "enable card"); | ||
56 | |||
57 | static struct pci_device_id oxygen_ids[] __devinitdata = { | ||
58 | { OXYGEN_PCI_SUBID(0x10b0, 0x0216) }, | ||
59 | { OXYGEN_PCI_SUBID(0x10b0, 0x0218) }, | ||
60 | { OXYGEN_PCI_SUBID(0x10b0, 0x0219) }, | ||
61 | { OXYGEN_PCI_SUBID(0x13f6, 0x0001) }, | ||
62 | { OXYGEN_PCI_SUBID(0x13f6, 0x0010) }, | ||
63 | { OXYGEN_PCI_SUBID(0x13f6, 0x8788) }, | ||
64 | { OXYGEN_PCI_SUBID(0x147a, 0xa017) }, | ||
65 | { OXYGEN_PCI_SUBID(0x1a58, 0x0910) }, | ||
66 | { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = 1 }, | ||
67 | { OXYGEN_PCI_SUBID(0x7284, 0x9761) }, | ||
68 | { } | ||
69 | }; | ||
70 | MODULE_DEVICE_TABLE(pci, oxygen_ids); | ||
71 | |||
72 | |||
73 | #define GPIO_AK5385_DFS_MASK 0x0003 | ||
74 | #define GPIO_AK5385_DFS_NORMAL 0x0000 | ||
75 | #define GPIO_AK5385_DFS_DOUBLE 0x0001 | ||
76 | #define GPIO_AK5385_DFS_QUAD 0x0002 | ||
77 | |||
78 | #define WM8785_R0 0 | ||
79 | #define WM8785_R1 1 | ||
80 | #define WM8785_R2 2 | ||
81 | #define WM8785_R7 7 | ||
82 | |||
83 | /* R0 */ | ||
84 | #define WM8785_MCR_MASK 0x007 | ||
85 | #define WM8785_MCR_SLAVE 0x000 | ||
86 | #define WM8785_MCR_MASTER_128 0x001 | ||
87 | #define WM8785_MCR_MASTER_192 0x002 | ||
88 | #define WM8785_MCR_MASTER_256 0x003 | ||
89 | #define WM8785_MCR_MASTER_384 0x004 | ||
90 | #define WM8785_MCR_MASTER_512 0x005 | ||
91 | #define WM8785_MCR_MASTER_768 0x006 | ||
92 | #define WM8785_OSR_MASK 0x018 | ||
93 | #define WM8785_OSR_SINGLE 0x000 | ||
94 | #define WM8785_OSR_DOUBLE 0x008 | ||
95 | #define WM8785_OSR_QUAD 0x010 | ||
96 | #define WM8785_FORMAT_MASK 0x060 | ||
97 | #define WM8785_FORMAT_RJUST 0x000 | ||
98 | #define WM8785_FORMAT_LJUST 0x020 | ||
99 | #define WM8785_FORMAT_I2S 0x040 | ||
100 | #define WM8785_FORMAT_DSP 0x060 | ||
101 | /* R1 */ | ||
102 | #define WM8785_WL_MASK 0x003 | ||
103 | #define WM8785_WL_16 0x000 | ||
104 | #define WM8785_WL_20 0x001 | ||
105 | #define WM8785_WL_24 0x002 | ||
106 | #define WM8785_WL_32 0x003 | ||
107 | #define WM8785_LRP 0x004 | ||
108 | #define WM8785_BCLKINV 0x008 | ||
109 | #define WM8785_LRSWAP 0x010 | ||
110 | #define WM8785_DEVNO_MASK 0x0e0 | ||
111 | /* R2 */ | ||
112 | #define WM8785_HPFR 0x001 | ||
113 | #define WM8785_HPFL 0x002 | ||
114 | #define WM8785_SDODIS 0x004 | ||
115 | #define WM8785_PWRDNR 0x008 | ||
116 | #define WM8785_PWRDNL 0x010 | ||
117 | #define WM8785_TDM_MASK 0x1c0 | ||
118 | |||
119 | struct generic_data { | ||
120 | u8 ak4396_ctl2; | ||
121 | }; | ||
122 | |||
123 | static void ak4396_write(struct oxygen *chip, unsigned int codec, | ||
124 | u8 reg, u8 value) | ||
125 | { | ||
126 | /* maps ALSA channel pair number to SPI output */ | ||
127 | static const u8 codec_spi_map[4] = { | ||
128 | 0, 1, 2, 4 | ||
129 | }; | ||
130 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | | ||
131 | OXYGEN_SPI_DATA_LENGTH_2 | | ||
132 | OXYGEN_SPI_CLOCK_160 | | ||
133 | (codec_spi_map[codec] << OXYGEN_SPI_CODEC_SHIFT) | | ||
134 | OXYGEN_SPI_CEN_LATCH_CLOCK_HI, | ||
135 | AK4396_WRITE | (reg << 8) | value); | ||
136 | } | ||
137 | |||
138 | static void wm8785_write(struct oxygen *chip, u8 reg, unsigned int value) | ||
139 | { | ||
140 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | | ||
141 | OXYGEN_SPI_DATA_LENGTH_2 | | ||
142 | OXYGEN_SPI_CLOCK_160 | | ||
143 | (3 << OXYGEN_SPI_CODEC_SHIFT) | | ||
144 | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, | ||
145 | (reg << 9) | value); | ||
146 | } | ||
147 | |||
148 | static void ak4396_init(struct oxygen *chip) | ||
149 | { | ||
150 | struct generic_data *data = chip->model_data; | ||
151 | unsigned int i; | ||
152 | |||
153 | data->ak4396_ctl2 = AK4396_DEM_OFF | AK4396_DFS_NORMAL; | ||
154 | for (i = 0; i < 4; ++i) { | ||
155 | ak4396_write(chip, i, | ||
156 | AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); | ||
157 | ak4396_write(chip, i, | ||
158 | AK4396_CONTROL_2, data->ak4396_ctl2); | ||
159 | ak4396_write(chip, i, | ||
160 | AK4396_CONTROL_3, AK4396_PCM); | ||
161 | ak4396_write(chip, i, AK4396_LCH_ATT, 0xff); | ||
162 | ak4396_write(chip, i, AK4396_RCH_ATT, 0xff); | ||
163 | } | ||
164 | snd_component_add(chip->card, "AK4396"); | ||
165 | } | ||
166 | |||
167 | static void ak5385_init(struct oxygen *chip) | ||
168 | { | ||
169 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_AK5385_DFS_MASK); | ||
170 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_AK5385_DFS_MASK); | ||
171 | snd_component_add(chip->card, "AK5385"); | ||
172 | } | ||
173 | |||
174 | static void wm8785_init(struct oxygen *chip) | ||
175 | { | ||
176 | wm8785_write(chip, WM8785_R7, 0); | ||
177 | wm8785_write(chip, WM8785_R0, WM8785_MCR_SLAVE | | ||
178 | WM8785_OSR_SINGLE | WM8785_FORMAT_LJUST); | ||
179 | wm8785_write(chip, WM8785_R1, WM8785_WL_24); | ||
180 | snd_component_add(chip->card, "WM8785"); | ||
181 | } | ||
182 | |||
183 | static void generic_init(struct oxygen *chip) | ||
184 | { | ||
185 | ak4396_init(chip); | ||
186 | wm8785_init(chip); | ||
187 | } | ||
188 | |||
189 | static void meridian_init(struct oxygen *chip) | ||
190 | { | ||
191 | ak4396_init(chip); | ||
192 | ak5385_init(chip); | ||
193 | } | ||
194 | |||
195 | static void generic_cleanup(struct oxygen *chip) | ||
196 | { | ||
197 | } | ||
198 | |||
199 | static void set_ak4396_params(struct oxygen *chip, | ||
200 | struct snd_pcm_hw_params *params) | ||
201 | { | ||
202 | struct generic_data *data = chip->model_data; | ||
203 | unsigned int i; | ||
204 | u8 value; | ||
205 | |||
206 | value = data->ak4396_ctl2 & ~AK4396_DFS_MASK; | ||
207 | if (params_rate(params) <= 54000) | ||
208 | value |= AK4396_DFS_NORMAL; | ||
209 | else if (params_rate(params) <= 108000) | ||
210 | value |= AK4396_DFS_DOUBLE; | ||
211 | else | ||
212 | value |= AK4396_DFS_QUAD; | ||
213 | data->ak4396_ctl2 = value; | ||
214 | for (i = 0; i < 4; ++i) { | ||
215 | ak4396_write(chip, i, | ||
216 | AK4396_CONTROL_1, AK4396_DIF_24_MSB); | ||
217 | ak4396_write(chip, i, | ||
218 | AK4396_CONTROL_2, value); | ||
219 | ak4396_write(chip, i, | ||
220 | AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); | ||
221 | } | ||
222 | } | ||
223 | |||
224 | static void update_ak4396_volume(struct oxygen *chip) | ||
225 | { | ||
226 | unsigned int i; | ||
227 | |||
228 | for (i = 0; i < 4; ++i) { | ||
229 | ak4396_write(chip, i, | ||
230 | AK4396_LCH_ATT, chip->dac_volume[i * 2]); | ||
231 | ak4396_write(chip, i, | ||
232 | AK4396_RCH_ATT, chip->dac_volume[i * 2 + 1]); | ||
233 | } | ||
234 | } | ||
235 | |||
236 | static void update_ak4396_mute(struct oxygen *chip) | ||
237 | { | ||
238 | struct generic_data *data = chip->model_data; | ||
239 | unsigned int i; | ||
240 | u8 value; | ||
241 | |||
242 | value = data->ak4396_ctl2 & ~AK4396_SMUTE; | ||
243 | if (chip->dac_mute) | ||
244 | value |= AK4396_SMUTE; | ||
245 | data->ak4396_ctl2 = value; | ||
246 | for (i = 0; i < 4; ++i) | ||
247 | ak4396_write(chip, i, AK4396_CONTROL_2, value); | ||
248 | } | ||
249 | |||
250 | static void set_wm8785_params(struct oxygen *chip, | ||
251 | struct snd_pcm_hw_params *params) | ||
252 | { | ||
253 | unsigned int value; | ||
254 | |||
255 | wm8785_write(chip, WM8785_R7, 0); | ||
256 | |||
257 | value = WM8785_MCR_SLAVE | WM8785_FORMAT_LJUST; | ||
258 | if (params_rate(params) <= 48000) | ||
259 | value |= WM8785_OSR_SINGLE; | ||
260 | else if (params_rate(params) <= 96000) | ||
261 | value |= WM8785_OSR_DOUBLE; | ||
262 | else | ||
263 | value |= WM8785_OSR_QUAD; | ||
264 | wm8785_write(chip, WM8785_R0, value); | ||
265 | |||
266 | if (snd_pcm_format_width(params_format(params)) <= 16) | ||
267 | value = WM8785_WL_16; | ||
268 | else | ||
269 | value = WM8785_WL_24; | ||
270 | wm8785_write(chip, WM8785_R1, value); | ||
271 | } | ||
272 | |||
273 | static void set_ak5385_params(struct oxygen *chip, | ||
274 | struct snd_pcm_hw_params *params) | ||
275 | { | ||
276 | unsigned int value; | ||
277 | |||
278 | if (params_rate(params) <= 54000) | ||
279 | value = GPIO_AK5385_DFS_NORMAL; | ||
280 | else if (params_rate(params) <= 108000) | ||
281 | value = GPIO_AK5385_DFS_DOUBLE; | ||
282 | else | ||
283 | value = GPIO_AK5385_DFS_QUAD; | ||
284 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, | ||
285 | value, GPIO_AK5385_DFS_MASK); | ||
286 | } | ||
287 | |||
288 | static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); | ||
289 | |||
290 | static int ak4396_control_filter(struct snd_kcontrol_new *template) | ||
291 | { | ||
292 | if (!strcmp(template->name, "Master Playback Volume")) { | ||
293 | template->access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
294 | template->tlv.p = ak4396_db_scale; | ||
295 | } | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static const struct oxygen_model model_generic = { | ||
300 | .shortname = "C-Media CMI8788", | ||
301 | .longname = "C-Media Oxygen HD Audio", | ||
302 | .chip = "CMI8788", | ||
303 | .owner = THIS_MODULE, | ||
304 | .init = generic_init, | ||
305 | .control_filter = ak4396_control_filter, | ||
306 | .cleanup = generic_cleanup, | ||
307 | .set_dac_params = set_ak4396_params, | ||
308 | .set_adc_params = set_wm8785_params, | ||
309 | .update_dac_volume = update_ak4396_volume, | ||
310 | .update_dac_mute = update_ak4396_mute, | ||
311 | .model_data_size = sizeof(struct generic_data), | ||
312 | .dac_channels = 8, | ||
313 | .used_channels = OXYGEN_CHANNEL_A | | ||
314 | OXYGEN_CHANNEL_C | | ||
315 | OXYGEN_CHANNEL_SPDIF | | ||
316 | OXYGEN_CHANNEL_MULTICH | | ||
317 | OXYGEN_CHANNEL_AC97, | ||
318 | .function_flags = OXYGEN_FUNCTION_ENABLE_SPI_4_5, | ||
319 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
320 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
321 | }; | ||
322 | static const struct oxygen_model model_meridian = { | ||
323 | .shortname = "C-Media CMI8788", | ||
324 | .longname = "C-Media Oxygen HD Audio", | ||
325 | .chip = "CMI8788", | ||
326 | .owner = THIS_MODULE, | ||
327 | .init = meridian_init, | ||
328 | .control_filter = ak4396_control_filter, | ||
329 | .cleanup = generic_cleanup, | ||
330 | .set_dac_params = set_ak4396_params, | ||
331 | .set_adc_params = set_ak5385_params, | ||
332 | .update_dac_volume = update_ak4396_volume, | ||
333 | .update_dac_mute = update_ak4396_mute, | ||
334 | .model_data_size = sizeof(struct generic_data), | ||
335 | .dac_channels = 8, | ||
336 | .used_channels = OXYGEN_CHANNEL_B | | ||
337 | OXYGEN_CHANNEL_C | | ||
338 | OXYGEN_CHANNEL_SPDIF | | ||
339 | OXYGEN_CHANNEL_MULTICH | | ||
340 | OXYGEN_CHANNEL_AC97, | ||
341 | .function_flags = OXYGEN_FUNCTION_ENABLE_SPI_4_5, | ||
342 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
343 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
344 | }; | ||
345 | |||
346 | static int __devinit generic_oxygen_probe(struct pci_dev *pci, | ||
347 | const struct pci_device_id *pci_id) | ||
348 | { | ||
349 | static int dev; | ||
350 | int is_meridian; | ||
351 | int err; | ||
352 | |||
353 | if (dev >= SNDRV_CARDS) | ||
354 | return -ENODEV; | ||
355 | if (!enable[dev]) { | ||
356 | ++dev; | ||
357 | return -ENOENT; | ||
358 | } | ||
359 | is_meridian = pci_id->driver_data; | ||
360 | err = oxygen_pci_probe(pci, index[dev], id[dev], is_meridian, | ||
361 | is_meridian ? &model_meridian : &model_generic); | ||
362 | if (err >= 0) | ||
363 | ++dev; | ||
364 | return err; | ||
365 | } | ||
366 | |||
367 | static struct pci_driver oxygen_driver = { | ||
368 | .name = "CMI8788", | ||
369 | .id_table = oxygen_ids, | ||
370 | .probe = generic_oxygen_probe, | ||
371 | .remove = __devexit_p(oxygen_pci_remove), | ||
372 | }; | ||
373 | |||
374 | static int __init alsa_card_oxygen_init(void) | ||
375 | { | ||
376 | return pci_register_driver(&oxygen_driver); | ||
377 | } | ||
378 | |||
379 | static void __exit alsa_card_oxygen_exit(void) | ||
380 | { | ||
381 | pci_unregister_driver(&oxygen_driver); | ||
382 | } | ||
383 | |||
384 | module_init(alsa_card_oxygen_init) | ||
385 | module_exit(alsa_card_oxygen_exit) | ||
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h new file mode 100644 index 000000000000..ad50fb8b206b --- /dev/null +++ b/sound/pci/oxygen/oxygen.h | |||
@@ -0,0 +1,190 @@ | |||
1 | #ifndef OXYGEN_H_INCLUDED | ||
2 | #define OXYGEN_H_INCLUDED | ||
3 | |||
4 | #include <linux/mutex.h> | ||
5 | #include <linux/spinlock.h> | ||
6 | #include <linux/wait.h> | ||
7 | #include <linux/workqueue.h> | ||
8 | #include "oxygen_regs.h" | ||
9 | |||
10 | /* 1 << PCM_x == OXYGEN_CHANNEL_x */ | ||
11 | #define PCM_A 0 | ||
12 | #define PCM_B 1 | ||
13 | #define PCM_C 2 | ||
14 | #define PCM_SPDIF 3 | ||
15 | #define PCM_MULTICH 4 | ||
16 | #define PCM_AC97 5 | ||
17 | #define PCM_COUNT 6 | ||
18 | |||
19 | enum { | ||
20 | CONTROL_SPDIF_PCM, | ||
21 | CONTROL_SPDIF_INPUT_BITS, | ||
22 | CONTROL_MIC_CAPTURE_SWITCH, | ||
23 | CONTROL_LINE_CAPTURE_SWITCH, | ||
24 | CONTROL_CD_CAPTURE_SWITCH, | ||
25 | CONTROL_AUX_CAPTURE_SWITCH, | ||
26 | CONTROL_COUNT | ||
27 | }; | ||
28 | |||
29 | #define OXYGEN_PCI_SUBID(sv, sd) \ | ||
30 | .vendor = PCI_VENDOR_ID_CMEDIA, \ | ||
31 | .device = 0x8788, \ | ||
32 | .subvendor = sv, \ | ||
33 | .subdevice = sd | ||
34 | |||
35 | struct pci_dev; | ||
36 | struct snd_card; | ||
37 | struct snd_pcm_substream; | ||
38 | struct snd_pcm_hardware; | ||
39 | struct snd_pcm_hw_params; | ||
40 | struct snd_kcontrol_new; | ||
41 | struct snd_rawmidi; | ||
42 | struct oxygen_model; | ||
43 | |||
44 | struct oxygen { | ||
45 | unsigned long addr; | ||
46 | spinlock_t reg_lock; | ||
47 | struct mutex mutex; | ||
48 | struct snd_card *card; | ||
49 | struct pci_dev *pci; | ||
50 | struct snd_rawmidi *midi; | ||
51 | int irq; | ||
52 | const struct oxygen_model *model; | ||
53 | void *model_data; | ||
54 | unsigned int interrupt_mask; | ||
55 | u8 dac_volume[8]; | ||
56 | u8 dac_mute; | ||
57 | u8 pcm_active; | ||
58 | u8 pcm_running; | ||
59 | u8 dac_routing; | ||
60 | u8 spdif_playback_enable; | ||
61 | u8 revision; | ||
62 | u8 has_ac97_0; | ||
63 | u8 has_ac97_1; | ||
64 | u32 spdif_bits; | ||
65 | u32 spdif_pcm_bits; | ||
66 | struct snd_pcm_substream *streams[PCM_COUNT]; | ||
67 | struct snd_kcontrol *controls[CONTROL_COUNT]; | ||
68 | struct work_struct spdif_input_bits_work; | ||
69 | struct work_struct gpio_work; | ||
70 | wait_queue_head_t ac97_waitqueue; | ||
71 | }; | ||
72 | |||
73 | struct oxygen_model { | ||
74 | const char *shortname; | ||
75 | const char *longname; | ||
76 | const char *chip; | ||
77 | struct module *owner; | ||
78 | void (*init)(struct oxygen *chip); | ||
79 | int (*control_filter)(struct snd_kcontrol_new *template); | ||
80 | int (*mixer_init)(struct oxygen *chip); | ||
81 | void (*cleanup)(struct oxygen *chip); | ||
82 | void (*pcm_hardware_filter)(unsigned int channel, | ||
83 | struct snd_pcm_hardware *hardware); | ||
84 | void (*set_dac_params)(struct oxygen *chip, | ||
85 | struct snd_pcm_hw_params *params); | ||
86 | void (*set_adc_params)(struct oxygen *chip, | ||
87 | struct snd_pcm_hw_params *params); | ||
88 | void (*update_dac_volume)(struct oxygen *chip); | ||
89 | void (*update_dac_mute)(struct oxygen *chip); | ||
90 | void (*ac97_switch_hook)(struct oxygen *chip, unsigned int codec, | ||
91 | unsigned int reg, int mute); | ||
92 | void (*gpio_changed)(struct oxygen *chip); | ||
93 | size_t model_data_size; | ||
94 | u8 dac_channels; | ||
95 | u8 used_channels; | ||
96 | u8 function_flags; | ||
97 | u16 dac_i2s_format; | ||
98 | u16 adc_i2s_format; | ||
99 | }; | ||
100 | |||
101 | /* oxygen_lib.c */ | ||
102 | |||
103 | int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, int midi, | ||
104 | const struct oxygen_model *model); | ||
105 | void oxygen_pci_remove(struct pci_dev *pci); | ||
106 | |||
107 | /* oxygen_mixer.c */ | ||
108 | |||
109 | int oxygen_mixer_init(struct oxygen *chip); | ||
110 | void oxygen_update_dac_routing(struct oxygen *chip); | ||
111 | void oxygen_update_spdif_source(struct oxygen *chip); | ||
112 | |||
113 | /* oxygen_pcm.c */ | ||
114 | |||
115 | int oxygen_pcm_init(struct oxygen *chip); | ||
116 | |||
117 | /* oxygen_io.c */ | ||
118 | |||
119 | u8 oxygen_read8(struct oxygen *chip, unsigned int reg); | ||
120 | u16 oxygen_read16(struct oxygen *chip, unsigned int reg); | ||
121 | u32 oxygen_read32(struct oxygen *chip, unsigned int reg); | ||
122 | void oxygen_write8(struct oxygen *chip, unsigned int reg, u8 value); | ||
123 | void oxygen_write16(struct oxygen *chip, unsigned int reg, u16 value); | ||
124 | void oxygen_write32(struct oxygen *chip, unsigned int reg, u32 value); | ||
125 | void oxygen_write8_masked(struct oxygen *chip, unsigned int reg, | ||
126 | u8 value, u8 mask); | ||
127 | void oxygen_write16_masked(struct oxygen *chip, unsigned int reg, | ||
128 | u16 value, u16 mask); | ||
129 | void oxygen_write32_masked(struct oxygen *chip, unsigned int reg, | ||
130 | u32 value, u32 mask); | ||
131 | |||
132 | u16 oxygen_read_ac97(struct oxygen *chip, unsigned int codec, | ||
133 | unsigned int index); | ||
134 | void oxygen_write_ac97(struct oxygen *chip, unsigned int codec, | ||
135 | unsigned int index, u16 data); | ||
136 | void oxygen_write_ac97_masked(struct oxygen *chip, unsigned int codec, | ||
137 | unsigned int index, u16 data, u16 mask); | ||
138 | |||
139 | void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data); | ||
140 | |||
141 | static inline void oxygen_set_bits8(struct oxygen *chip, | ||
142 | unsigned int reg, u8 value) | ||
143 | { | ||
144 | oxygen_write8_masked(chip, reg, value, value); | ||
145 | } | ||
146 | |||
147 | static inline void oxygen_set_bits16(struct oxygen *chip, | ||
148 | unsigned int reg, u16 value) | ||
149 | { | ||
150 | oxygen_write16_masked(chip, reg, value, value); | ||
151 | } | ||
152 | |||
153 | static inline void oxygen_set_bits32(struct oxygen *chip, | ||
154 | unsigned int reg, u32 value) | ||
155 | { | ||
156 | oxygen_write32_masked(chip, reg, value, value); | ||
157 | } | ||
158 | |||
159 | static inline void oxygen_clear_bits8(struct oxygen *chip, | ||
160 | unsigned int reg, u8 value) | ||
161 | { | ||
162 | oxygen_write8_masked(chip, reg, 0, value); | ||
163 | } | ||
164 | |||
165 | static inline void oxygen_clear_bits16(struct oxygen *chip, | ||
166 | unsigned int reg, u16 value) | ||
167 | { | ||
168 | oxygen_write16_masked(chip, reg, 0, value); | ||
169 | } | ||
170 | |||
171 | static inline void oxygen_clear_bits32(struct oxygen *chip, | ||
172 | unsigned int reg, u32 value) | ||
173 | { | ||
174 | oxygen_write32_masked(chip, reg, 0, value); | ||
175 | } | ||
176 | |||
177 | static inline void oxygen_ac97_set_bits(struct oxygen *chip, unsigned int codec, | ||
178 | unsigned int index, u16 value) | ||
179 | { | ||
180 | oxygen_write_ac97_masked(chip, codec, index, value, value); | ||
181 | } | ||
182 | |||
183 | static inline void oxygen_ac97_clear_bits(struct oxygen *chip, | ||
184 | unsigned int codec, | ||
185 | unsigned int index, u16 value) | ||
186 | { | ||
187 | oxygen_write_ac97_masked(chip, codec, index, 0, value); | ||
188 | } | ||
189 | |||
190 | #endif | ||
diff --git a/sound/pci/oxygen/oxygen_io.c b/sound/pci/oxygen/oxygen_io.c new file mode 100644 index 000000000000..74e23ef9c946 --- /dev/null +++ b/sound/pci/oxygen/oxygen_io.c | |||
@@ -0,0 +1,201 @@ | |||
1 | /* | ||
2 | * C-Media CMI8788 driver - helper functions | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * | ||
6 | * | ||
7 | * This driver is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License, version 2. | ||
9 | * | ||
10 | * This driver is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this driver; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include <linux/delay.h> | ||
21 | #include <linux/sched.h> | ||
22 | #include <sound/core.h> | ||
23 | #include <asm/io.h> | ||
24 | #include "oxygen.h" | ||
25 | |||
26 | u8 oxygen_read8(struct oxygen *chip, unsigned int reg) | ||
27 | { | ||
28 | return inb(chip->addr + reg); | ||
29 | } | ||
30 | EXPORT_SYMBOL(oxygen_read8); | ||
31 | |||
32 | u16 oxygen_read16(struct oxygen *chip, unsigned int reg) | ||
33 | { | ||
34 | return inw(chip->addr + reg); | ||
35 | } | ||
36 | EXPORT_SYMBOL(oxygen_read16); | ||
37 | |||
38 | u32 oxygen_read32(struct oxygen *chip, unsigned int reg) | ||
39 | { | ||
40 | return inl(chip->addr + reg); | ||
41 | } | ||
42 | EXPORT_SYMBOL(oxygen_read32); | ||
43 | |||
44 | void oxygen_write8(struct oxygen *chip, unsigned int reg, u8 value) | ||
45 | { | ||
46 | outb(value, chip->addr + reg); | ||
47 | } | ||
48 | EXPORT_SYMBOL(oxygen_write8); | ||
49 | |||
50 | void oxygen_write16(struct oxygen *chip, unsigned int reg, u16 value) | ||
51 | { | ||
52 | outw(value, chip->addr + reg); | ||
53 | } | ||
54 | EXPORT_SYMBOL(oxygen_write16); | ||
55 | |||
56 | void oxygen_write32(struct oxygen *chip, unsigned int reg, u32 value) | ||
57 | { | ||
58 | outl(value, chip->addr + reg); | ||
59 | } | ||
60 | EXPORT_SYMBOL(oxygen_write32); | ||
61 | |||
62 | void oxygen_write8_masked(struct oxygen *chip, unsigned int reg, | ||
63 | u8 value, u8 mask) | ||
64 | { | ||
65 | u8 tmp = inb(chip->addr + reg); | ||
66 | outb((tmp & ~mask) | (value & mask), chip->addr + reg); | ||
67 | } | ||
68 | EXPORT_SYMBOL(oxygen_write8_masked); | ||
69 | |||
70 | void oxygen_write16_masked(struct oxygen *chip, unsigned int reg, | ||
71 | u16 value, u16 mask) | ||
72 | { | ||
73 | u16 tmp = inw(chip->addr + reg); | ||
74 | outw((tmp & ~mask) | (value & mask), chip->addr + reg); | ||
75 | } | ||
76 | EXPORT_SYMBOL(oxygen_write16_masked); | ||
77 | |||
78 | void oxygen_write32_masked(struct oxygen *chip, unsigned int reg, | ||
79 | u32 value, u32 mask) | ||
80 | { | ||
81 | u32 tmp = inl(chip->addr + reg); | ||
82 | outl((tmp & ~mask) | (value & mask), chip->addr + reg); | ||
83 | } | ||
84 | EXPORT_SYMBOL(oxygen_write32_masked); | ||
85 | |||
86 | static int oxygen_ac97_wait(struct oxygen *chip, unsigned int mask) | ||
87 | { | ||
88 | u8 status = 0; | ||
89 | |||
90 | /* | ||
91 | * Reading the status register also clears the bits, so we have to save | ||
92 | * the read bits in status. | ||
93 | */ | ||
94 | wait_event_timeout(chip->ac97_waitqueue, | ||
95 | ({ status |= oxygen_read8(chip, OXYGEN_AC97_INTERRUPT_STATUS); | ||
96 | status & mask; }), | ||
97 | msecs_to_jiffies(1) + 1); | ||
98 | /* | ||
99 | * Check even after a timeout because this function should not require | ||
100 | * the AC'97 interrupt to be enabled. | ||
101 | */ | ||
102 | status |= oxygen_read8(chip, OXYGEN_AC97_INTERRUPT_STATUS); | ||
103 | return status & mask ? 0 : -EIO; | ||
104 | } | ||
105 | |||
106 | /* | ||
107 | * About 10% of AC'97 register reads or writes fail to complete, but even those | ||
108 | * where the controller indicates completion aren't guaranteed to have actually | ||
109 | * happened. | ||
110 | * | ||
111 | * It's hard to assign blame to either the controller or the codec because both | ||
112 | * were made by C-Media ... | ||
113 | */ | ||
114 | |||
115 | void oxygen_write_ac97(struct oxygen *chip, unsigned int codec, | ||
116 | unsigned int index, u16 data) | ||
117 | { | ||
118 | unsigned int count, succeeded; | ||
119 | u32 reg; | ||
120 | |||
121 | reg = data; | ||
122 | reg |= index << OXYGEN_AC97_REG_ADDR_SHIFT; | ||
123 | reg |= OXYGEN_AC97_REG_DIR_WRITE; | ||
124 | reg |= codec << OXYGEN_AC97_REG_CODEC_SHIFT; | ||
125 | succeeded = 0; | ||
126 | for (count = 5; count > 0; --count) { | ||
127 | udelay(5); | ||
128 | oxygen_write32(chip, OXYGEN_AC97_REGS, reg); | ||
129 | /* require two "completed" writes, just to be sure */ | ||
130 | if (oxygen_ac97_wait(chip, OXYGEN_AC97_INT_WRITE_DONE) >= 0 && | ||
131 | ++succeeded >= 2) | ||
132 | return; | ||
133 | } | ||
134 | snd_printk(KERN_ERR "AC'97 write timeout\n"); | ||
135 | } | ||
136 | EXPORT_SYMBOL(oxygen_write_ac97); | ||
137 | |||
138 | u16 oxygen_read_ac97(struct oxygen *chip, unsigned int codec, | ||
139 | unsigned int index) | ||
140 | { | ||
141 | unsigned int count; | ||
142 | unsigned int last_read = UINT_MAX; | ||
143 | u32 reg; | ||
144 | |||
145 | reg = index << OXYGEN_AC97_REG_ADDR_SHIFT; | ||
146 | reg |= OXYGEN_AC97_REG_DIR_READ; | ||
147 | reg |= codec << OXYGEN_AC97_REG_CODEC_SHIFT; | ||
148 | for (count = 5; count > 0; --count) { | ||
149 | udelay(5); | ||
150 | oxygen_write32(chip, OXYGEN_AC97_REGS, reg); | ||
151 | udelay(10); | ||
152 | if (oxygen_ac97_wait(chip, OXYGEN_AC97_INT_READ_DONE) >= 0) { | ||
153 | u16 value = oxygen_read16(chip, OXYGEN_AC97_REGS); | ||
154 | /* we require two consecutive reads of the same value */ | ||
155 | if (value == last_read) | ||
156 | return value; | ||
157 | last_read = value; | ||
158 | /* | ||
159 | * Invert the register value bits to make sure that two | ||
160 | * consecutive unsuccessful reads do not return the same | ||
161 | * value. | ||
162 | */ | ||
163 | reg ^= 0xffff; | ||
164 | } | ||
165 | } | ||
166 | snd_printk(KERN_ERR "AC'97 read timeout on codec %u\n", codec); | ||
167 | return 0; | ||
168 | } | ||
169 | EXPORT_SYMBOL(oxygen_read_ac97); | ||
170 | |||
171 | void oxygen_write_ac97_masked(struct oxygen *chip, unsigned int codec, | ||
172 | unsigned int index, u16 data, u16 mask) | ||
173 | { | ||
174 | u16 value = oxygen_read_ac97(chip, codec, index); | ||
175 | value &= ~mask; | ||
176 | value |= data & mask; | ||
177 | oxygen_write_ac97(chip, codec, index, value); | ||
178 | } | ||
179 | EXPORT_SYMBOL(oxygen_write_ac97_masked); | ||
180 | |||
181 | void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data) | ||
182 | { | ||
183 | unsigned int count; | ||
184 | |||
185 | /* should not need more than 7.68 us (24 * 320 ns) */ | ||
186 | count = 10; | ||
187 | while ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) & OXYGEN_SPI_BUSY) | ||
188 | && count > 0) { | ||
189 | udelay(1); | ||
190 | --count; | ||
191 | } | ||
192 | |||
193 | spin_lock_irq(&chip->reg_lock); | ||
194 | oxygen_write8(chip, OXYGEN_SPI_DATA1, data); | ||
195 | oxygen_write8(chip, OXYGEN_SPI_DATA2, data >> 8); | ||
196 | if (control & OXYGEN_SPI_DATA_LENGTH_3) | ||
197 | oxygen_write8(chip, OXYGEN_SPI_DATA3, data >> 16); | ||
198 | oxygen_write8(chip, OXYGEN_SPI_CONTROL, control); | ||
199 | spin_unlock_irq(&chip->reg_lock); | ||
200 | } | ||
201 | EXPORT_SYMBOL(oxygen_write_spi); | ||
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c new file mode 100644 index 000000000000..6eb36dd11476 --- /dev/null +++ b/sound/pci/oxygen/oxygen_lib.c | |||
@@ -0,0 +1,515 @@ | |||
1 | /* | ||
2 | * C-Media CMI8788 driver - main driver module | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * | ||
6 | * | ||
7 | * This driver is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License, version 2. | ||
9 | * | ||
10 | * This driver is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this driver; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include <linux/delay.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/mutex.h> | ||
23 | #include <linux/pci.h> | ||
24 | #include <sound/ac97_codec.h> | ||
25 | #include <sound/asoundef.h> | ||
26 | #include <sound/core.h> | ||
27 | #include <sound/info.h> | ||
28 | #include <sound/mpu401.h> | ||
29 | #include <sound/pcm.h> | ||
30 | #include "oxygen.h" | ||
31 | #include "cm9780.h" | ||
32 | |||
33 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | ||
34 | MODULE_DESCRIPTION("C-Media CMI8788 helper library"); | ||
35 | MODULE_LICENSE("GPL"); | ||
36 | |||
37 | |||
38 | static irqreturn_t oxygen_interrupt(int dummy, void *dev_id) | ||
39 | { | ||
40 | struct oxygen *chip = dev_id; | ||
41 | unsigned int status, clear, elapsed_streams, i; | ||
42 | |||
43 | status = oxygen_read16(chip, OXYGEN_INTERRUPT_STATUS); | ||
44 | if (!status) | ||
45 | return IRQ_NONE; | ||
46 | |||
47 | spin_lock(&chip->reg_lock); | ||
48 | |||
49 | clear = status & (OXYGEN_CHANNEL_A | | ||
50 | OXYGEN_CHANNEL_B | | ||
51 | OXYGEN_CHANNEL_C | | ||
52 | OXYGEN_CHANNEL_SPDIF | | ||
53 | OXYGEN_CHANNEL_MULTICH | | ||
54 | OXYGEN_CHANNEL_AC97 | | ||
55 | OXYGEN_INT_SPDIF_IN_DETECT | | ||
56 | OXYGEN_INT_GPIO | | ||
57 | OXYGEN_INT_AC97); | ||
58 | if (clear) { | ||
59 | if (clear & OXYGEN_INT_SPDIF_IN_DETECT) | ||
60 | chip->interrupt_mask &= ~OXYGEN_INT_SPDIF_IN_DETECT; | ||
61 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, | ||
62 | chip->interrupt_mask & ~clear); | ||
63 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, | ||
64 | chip->interrupt_mask); | ||
65 | } | ||
66 | |||
67 | elapsed_streams = status & chip->pcm_running; | ||
68 | |||
69 | spin_unlock(&chip->reg_lock); | ||
70 | |||
71 | for (i = 0; i < PCM_COUNT; ++i) | ||
72 | if ((elapsed_streams & (1 << i)) && chip->streams[i]) | ||
73 | snd_pcm_period_elapsed(chip->streams[i]); | ||
74 | |||
75 | if (status & OXYGEN_INT_SPDIF_IN_DETECT) { | ||
76 | spin_lock(&chip->reg_lock); | ||
77 | i = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); | ||
78 | if (i & (OXYGEN_SPDIF_SENSE_INT | OXYGEN_SPDIF_LOCK_INT | | ||
79 | OXYGEN_SPDIF_RATE_INT)) { | ||
80 | /* write the interrupt bit(s) to clear */ | ||
81 | oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, i); | ||
82 | schedule_work(&chip->spdif_input_bits_work); | ||
83 | } | ||
84 | spin_unlock(&chip->reg_lock); | ||
85 | } | ||
86 | |||
87 | if (status & OXYGEN_INT_GPIO) | ||
88 | schedule_work(&chip->gpio_work); | ||
89 | |||
90 | if ((status & OXYGEN_INT_MIDI) && chip->midi) | ||
91 | snd_mpu401_uart_interrupt(0, chip->midi->private_data); | ||
92 | |||
93 | if (status & OXYGEN_INT_AC97) | ||
94 | wake_up(&chip->ac97_waitqueue); | ||
95 | |||
96 | return IRQ_HANDLED; | ||
97 | } | ||
98 | |||
99 | static void oxygen_spdif_input_bits_changed(struct work_struct *work) | ||
100 | { | ||
101 | struct oxygen *chip = container_of(work, struct oxygen, | ||
102 | spdif_input_bits_work); | ||
103 | u32 reg; | ||
104 | |||
105 | /* | ||
106 | * This function gets called when there is new activity on the SPDIF | ||
107 | * input, or when we lose lock on the input signal, or when the rate | ||
108 | * changes. | ||
109 | */ | ||
110 | msleep(1); | ||
111 | spin_lock_irq(&chip->reg_lock); | ||
112 | reg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); | ||
113 | if ((reg & (OXYGEN_SPDIF_SENSE_STATUS | | ||
114 | OXYGEN_SPDIF_LOCK_STATUS)) | ||
115 | == OXYGEN_SPDIF_SENSE_STATUS) { | ||
116 | /* | ||
117 | * If we detect activity on the SPDIF input but cannot lock to | ||
118 | * a signal, the clock bit is likely to be wrong. | ||
119 | */ | ||
120 | reg ^= OXYGEN_SPDIF_IN_CLOCK_MASK; | ||
121 | oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, reg); | ||
122 | spin_unlock_irq(&chip->reg_lock); | ||
123 | msleep(1); | ||
124 | spin_lock_irq(&chip->reg_lock); | ||
125 | reg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); | ||
126 | if ((reg & (OXYGEN_SPDIF_SENSE_STATUS | | ||
127 | OXYGEN_SPDIF_LOCK_STATUS)) | ||
128 | == OXYGEN_SPDIF_SENSE_STATUS) { | ||
129 | /* nothing detected with either clock; give up */ | ||
130 | if ((reg & OXYGEN_SPDIF_IN_CLOCK_MASK) | ||
131 | == OXYGEN_SPDIF_IN_CLOCK_192) { | ||
132 | /* | ||
133 | * Reset clock to <= 96 kHz because this is | ||
134 | * more likely to be received next time. | ||
135 | */ | ||
136 | reg &= ~OXYGEN_SPDIF_IN_CLOCK_MASK; | ||
137 | reg |= OXYGEN_SPDIF_IN_CLOCK_96; | ||
138 | oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, reg); | ||
139 | } | ||
140 | } | ||
141 | } | ||
142 | spin_unlock_irq(&chip->reg_lock); | ||
143 | |||
144 | if (chip->controls[CONTROL_SPDIF_INPUT_BITS]) { | ||
145 | spin_lock_irq(&chip->reg_lock); | ||
146 | chip->interrupt_mask |= OXYGEN_INT_SPDIF_IN_DETECT; | ||
147 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, | ||
148 | chip->interrupt_mask); | ||
149 | spin_unlock_irq(&chip->reg_lock); | ||
150 | |||
151 | /* | ||
152 | * We don't actually know that any channel status bits have | ||
153 | * changed, but let's send a notification just to be sure. | ||
154 | */ | ||
155 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
156 | &chip->controls[CONTROL_SPDIF_INPUT_BITS]->id); | ||
157 | } | ||
158 | } | ||
159 | |||
160 | static void oxygen_gpio_changed(struct work_struct *work) | ||
161 | { | ||
162 | struct oxygen *chip = container_of(work, struct oxygen, gpio_work); | ||
163 | |||
164 | if (chip->model->gpio_changed) | ||
165 | chip->model->gpio_changed(chip); | ||
166 | } | ||
167 | |||
168 | #ifdef CONFIG_PROC_FS | ||
169 | static void oxygen_proc_read(struct snd_info_entry *entry, | ||
170 | struct snd_info_buffer *buffer) | ||
171 | { | ||
172 | struct oxygen *chip = entry->private_data; | ||
173 | int i, j; | ||
174 | |||
175 | snd_iprintf(buffer, "CMI8788\n\n"); | ||
176 | for (i = 0; i < 0x100; i += 0x10) { | ||
177 | snd_iprintf(buffer, "%02x:", i); | ||
178 | for (j = 0; j < 0x10; ++j) | ||
179 | snd_iprintf(buffer, " %02x", oxygen_read8(chip, i + j)); | ||
180 | snd_iprintf(buffer, "\n"); | ||
181 | } | ||
182 | if (mutex_lock_interruptible(&chip->mutex) < 0) | ||
183 | return; | ||
184 | if (chip->has_ac97_0) { | ||
185 | snd_iprintf(buffer, "\nAC97\n"); | ||
186 | for (i = 0; i < 0x80; i += 0x10) { | ||
187 | snd_iprintf(buffer, "%02x:", i); | ||
188 | for (j = 0; j < 0x10; j += 2) | ||
189 | snd_iprintf(buffer, " %04x", | ||
190 | oxygen_read_ac97(chip, 0, i + j)); | ||
191 | snd_iprintf(buffer, "\n"); | ||
192 | } | ||
193 | } | ||
194 | if (chip->has_ac97_1) { | ||
195 | snd_iprintf(buffer, "\nAC97 2\n"); | ||
196 | for (i = 0; i < 0x80; i += 0x10) { | ||
197 | snd_iprintf(buffer, "%02x:", i); | ||
198 | for (j = 0; j < 0x10; j += 2) | ||
199 | snd_iprintf(buffer, " %04x", | ||
200 | oxygen_read_ac97(chip, 1, i + j)); | ||
201 | snd_iprintf(buffer, "\n"); | ||
202 | } | ||
203 | } | ||
204 | mutex_unlock(&chip->mutex); | ||
205 | } | ||
206 | |||
207 | static void __devinit oxygen_proc_init(struct oxygen *chip) | ||
208 | { | ||
209 | struct snd_info_entry *entry; | ||
210 | |||
211 | if (!snd_card_proc_new(chip->card, "cmi8788", &entry)) | ||
212 | snd_info_set_text_ops(entry, chip, oxygen_proc_read); | ||
213 | } | ||
214 | #else | ||
215 | #define oxygen_proc_init(chip) | ||
216 | #endif | ||
217 | |||
218 | static void __devinit oxygen_init(struct oxygen *chip) | ||
219 | { | ||
220 | unsigned int i; | ||
221 | |||
222 | chip->dac_routing = 1; | ||
223 | for (i = 0; i < 8; ++i) | ||
224 | chip->dac_volume[i] = 0xff; | ||
225 | chip->spdif_playback_enable = 1; | ||
226 | chip->spdif_bits = OXYGEN_SPDIF_C | OXYGEN_SPDIF_ORIGINAL | | ||
227 | (IEC958_AES1_CON_PCM_CODER << OXYGEN_SPDIF_CATEGORY_SHIFT); | ||
228 | chip->spdif_pcm_bits = chip->spdif_bits; | ||
229 | |||
230 | if (oxygen_read8(chip, OXYGEN_REVISION) & OXYGEN_REVISION_2) | ||
231 | chip->revision = 2; | ||
232 | else | ||
233 | chip->revision = 1; | ||
234 | |||
235 | if (chip->revision == 1) | ||
236 | oxygen_set_bits8(chip, OXYGEN_MISC, | ||
237 | OXYGEN_MISC_PCI_MEM_W_1_CLOCK); | ||
238 | |||
239 | i = oxygen_read16(chip, OXYGEN_AC97_CONTROL); | ||
240 | chip->has_ac97_0 = (i & OXYGEN_AC97_CODEC_0) != 0; | ||
241 | chip->has_ac97_1 = (i & OXYGEN_AC97_CODEC_1) != 0; | ||
242 | |||
243 | oxygen_set_bits8(chip, OXYGEN_FUNCTION, | ||
244 | OXYGEN_FUNCTION_RESET_CODEC | | ||
245 | chip->model->function_flags); | ||
246 | oxygen_write8_masked(chip, OXYGEN_FUNCTION, | ||
247 | OXYGEN_FUNCTION_SPI, | ||
248 | OXYGEN_FUNCTION_2WIRE_SPI_MASK); | ||
249 | oxygen_write8(chip, OXYGEN_DMA_STATUS, 0); | ||
250 | oxygen_write8(chip, OXYGEN_DMA_PAUSE, 0); | ||
251 | oxygen_write8(chip, OXYGEN_PLAY_CHANNELS, | ||
252 | OXYGEN_PLAY_CHANNELS_2 | | ||
253 | OXYGEN_DMA_A_BURST_8 | | ||
254 | OXYGEN_DMA_MULTICH_BURST_8); | ||
255 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0); | ||
256 | oxygen_write8_masked(chip, OXYGEN_MISC, 0, | ||
257 | OXYGEN_MISC_WRITE_PCI_SUBID | | ||
258 | OXYGEN_MISC_REC_C_FROM_SPDIF | | ||
259 | OXYGEN_MISC_REC_B_FROM_AC97 | | ||
260 | OXYGEN_MISC_REC_A_FROM_MULTICH); | ||
261 | oxygen_write8(chip, OXYGEN_REC_FORMAT, | ||
262 | (OXYGEN_FORMAT_16 << OXYGEN_REC_FORMAT_A_SHIFT) | | ||
263 | (OXYGEN_FORMAT_16 << OXYGEN_REC_FORMAT_B_SHIFT) | | ||
264 | (OXYGEN_FORMAT_16 << OXYGEN_REC_FORMAT_C_SHIFT)); | ||
265 | oxygen_write8(chip, OXYGEN_PLAY_FORMAT, | ||
266 | (OXYGEN_FORMAT_16 << OXYGEN_SPDIF_FORMAT_SHIFT) | | ||
267 | (OXYGEN_FORMAT_16 << OXYGEN_MULTICH_FORMAT_SHIFT)); | ||
268 | oxygen_write8(chip, OXYGEN_REC_CHANNELS, OXYGEN_REC_CHANNELS_2_2_2); | ||
269 | oxygen_write16(chip, OXYGEN_I2S_MULTICH_FORMAT, | ||
270 | OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_LJUST | | ||
271 | OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 | | ||
272 | OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64); | ||
273 | oxygen_write16(chip, OXYGEN_I2S_A_FORMAT, | ||
274 | OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_LJUST | | ||
275 | OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 | | ||
276 | OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64); | ||
277 | oxygen_write16(chip, OXYGEN_I2S_B_FORMAT, | ||
278 | OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_LJUST | | ||
279 | OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 | | ||
280 | OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64); | ||
281 | oxygen_write16(chip, OXYGEN_I2S_C_FORMAT, | ||
282 | OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_LJUST | | ||
283 | OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 | | ||
284 | OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64); | ||
285 | oxygen_write32_masked(chip, OXYGEN_SPDIF_CONTROL, | ||
286 | OXYGEN_SPDIF_SENSE_MASK | | ||
287 | OXYGEN_SPDIF_LOCK_MASK | | ||
288 | OXYGEN_SPDIF_RATE_MASK | | ||
289 | OXYGEN_SPDIF_LOCK_PAR | | ||
290 | OXYGEN_SPDIF_IN_CLOCK_96, | ||
291 | OXYGEN_SPDIF_OUT_ENABLE | | ||
292 | OXYGEN_SPDIF_LOOPBACK | | ||
293 | OXYGEN_SPDIF_SENSE_MASK | | ||
294 | OXYGEN_SPDIF_LOCK_MASK | | ||
295 | OXYGEN_SPDIF_RATE_MASK | | ||
296 | OXYGEN_SPDIF_SENSE_PAR | | ||
297 | OXYGEN_SPDIF_LOCK_PAR | | ||
298 | OXYGEN_SPDIF_IN_CLOCK_MASK); | ||
299 | oxygen_write32(chip, OXYGEN_SPDIF_OUTPUT_BITS, chip->spdif_bits); | ||
300 | oxygen_clear_bits8(chip, OXYGEN_MPU401_CONTROL, OXYGEN_MPU401_LOOPBACK); | ||
301 | oxygen_write8(chip, OXYGEN_GPI_INTERRUPT_MASK, 0); | ||
302 | oxygen_write16(chip, OXYGEN_GPIO_INTERRUPT_MASK, 0); | ||
303 | oxygen_write16(chip, OXYGEN_PLAY_ROUTING, | ||
304 | OXYGEN_PLAY_MULTICH_I2S_DAC | | ||
305 | OXYGEN_PLAY_SPDIF_SPDIF | | ||
306 | (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | | ||
307 | (1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | | ||
308 | (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | | ||
309 | (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT)); | ||
310 | oxygen_write8(chip, OXYGEN_REC_ROUTING, | ||
311 | OXYGEN_REC_A_ROUTE_I2S_ADC_1 | | ||
312 | OXYGEN_REC_B_ROUTE_I2S_ADC_2 | | ||
313 | OXYGEN_REC_C_ROUTE_SPDIF); | ||
314 | oxygen_write8(chip, OXYGEN_ADC_MONITOR, 0); | ||
315 | oxygen_write8(chip, OXYGEN_A_MONITOR_ROUTING, | ||
316 | (0 << OXYGEN_A_MONITOR_ROUTE_0_SHIFT) | | ||
317 | (1 << OXYGEN_A_MONITOR_ROUTE_1_SHIFT) | | ||
318 | (2 << OXYGEN_A_MONITOR_ROUTE_2_SHIFT) | | ||
319 | (3 << OXYGEN_A_MONITOR_ROUTE_3_SHIFT)); | ||
320 | |||
321 | oxygen_write8(chip, OXYGEN_AC97_INTERRUPT_MASK, | ||
322 | OXYGEN_AC97_INT_READ_DONE | | ||
323 | OXYGEN_AC97_INT_WRITE_DONE); | ||
324 | oxygen_write32(chip, OXYGEN_AC97_OUT_CONFIG, 0); | ||
325 | oxygen_write32(chip, OXYGEN_AC97_IN_CONFIG, 0); | ||
326 | if (!(chip->has_ac97_0 | chip->has_ac97_1)) | ||
327 | oxygen_set_bits16(chip, OXYGEN_AC97_CONTROL, | ||
328 | OXYGEN_AC97_CLOCK_DISABLE); | ||
329 | if (!chip->has_ac97_0) { | ||
330 | oxygen_set_bits16(chip, OXYGEN_AC97_CONTROL, | ||
331 | OXYGEN_AC97_NO_CODEC_0); | ||
332 | } else { | ||
333 | oxygen_write_ac97(chip, 0, AC97_RESET, 0); | ||
334 | msleep(1); | ||
335 | oxygen_ac97_set_bits(chip, 0, CM9780_GPIO_SETUP, | ||
336 | CM9780_GPIO0IO | CM9780_GPIO1IO); | ||
337 | oxygen_ac97_set_bits(chip, 0, CM9780_MIXER, | ||
338 | CM9780_BSTSEL | CM9780_STRO_MIC | | ||
339 | CM9780_MIX2FR | CM9780_PCBSW); | ||
340 | oxygen_ac97_set_bits(chip, 0, CM9780_JACK, | ||
341 | CM9780_RSOE | CM9780_CBOE | | ||
342 | CM9780_SSOE | CM9780_FROE | | ||
343 | CM9780_MIC2MIC | CM9780_LI2LI); | ||
344 | oxygen_write_ac97(chip, 0, AC97_MASTER, 0x0000); | ||
345 | oxygen_write_ac97(chip, 0, AC97_PC_BEEP, 0x8000); | ||
346 | oxygen_write_ac97(chip, 0, AC97_MIC, 0x8808); | ||
347 | oxygen_write_ac97(chip, 0, AC97_LINE, 0x0808); | ||
348 | oxygen_write_ac97(chip, 0, AC97_CD, 0x8808); | ||
349 | oxygen_write_ac97(chip, 0, AC97_VIDEO, 0x8808); | ||
350 | oxygen_write_ac97(chip, 0, AC97_AUX, 0x8808); | ||
351 | oxygen_write_ac97(chip, 0, AC97_REC_GAIN, 0x8000); | ||
352 | oxygen_write_ac97(chip, 0, AC97_CENTER_LFE_MASTER, 0x8080); | ||
353 | oxygen_write_ac97(chip, 0, AC97_SURROUND_MASTER, 0x8080); | ||
354 | /* power down unused ADCs and DACs */ | ||
355 | oxygen_ac97_set_bits(chip, 0, AC97_POWERDOWN, | ||
356 | AC97_PD_PR0 | AC97_PD_PR1); | ||
357 | oxygen_ac97_set_bits(chip, 0, AC97_EXTENDED_STATUS, | ||
358 | AC97_EA_PRI | AC97_EA_PRJ | AC97_EA_PRK); | ||
359 | } | ||
360 | if (chip->has_ac97_1) { | ||
361 | oxygen_set_bits32(chip, OXYGEN_AC97_OUT_CONFIG, | ||
362 | OXYGEN_AC97_CODEC1_SLOT3 | | ||
363 | OXYGEN_AC97_CODEC1_SLOT4); | ||
364 | oxygen_write_ac97(chip, 1, AC97_RESET, 0); | ||
365 | msleep(1); | ||
366 | oxygen_write_ac97(chip, 1, AC97_MASTER, 0x0000); | ||
367 | oxygen_write_ac97(chip, 1, AC97_HEADPHONE, 0x8000); | ||
368 | oxygen_write_ac97(chip, 1, AC97_PC_BEEP, 0x8000); | ||
369 | oxygen_write_ac97(chip, 1, AC97_MIC, 0x8808); | ||
370 | oxygen_write_ac97(chip, 1, AC97_LINE, 0x8808); | ||
371 | oxygen_write_ac97(chip, 1, AC97_CD, 0x8808); | ||
372 | oxygen_write_ac97(chip, 1, AC97_VIDEO, 0x8808); | ||
373 | oxygen_write_ac97(chip, 1, AC97_AUX, 0x8808); | ||
374 | oxygen_write_ac97(chip, 1, AC97_PCM, 0x0808); | ||
375 | oxygen_write_ac97(chip, 1, AC97_REC_SEL, 0x0000); | ||
376 | oxygen_write_ac97(chip, 1, AC97_REC_GAIN, 0x0000); | ||
377 | oxygen_ac97_set_bits(chip, 1, 0x6a, 0x0040); | ||
378 | } | ||
379 | } | ||
380 | |||
381 | static void oxygen_card_free(struct snd_card *card) | ||
382 | { | ||
383 | struct oxygen *chip = card->private_data; | ||
384 | |||
385 | spin_lock_irq(&chip->reg_lock); | ||
386 | chip->interrupt_mask = 0; | ||
387 | chip->pcm_running = 0; | ||
388 | oxygen_write16(chip, OXYGEN_DMA_STATUS, 0); | ||
389 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0); | ||
390 | spin_unlock_irq(&chip->reg_lock); | ||
391 | if (chip->irq >= 0) { | ||
392 | free_irq(chip->irq, chip); | ||
393 | synchronize_irq(chip->irq); | ||
394 | } | ||
395 | flush_scheduled_work(); | ||
396 | chip->model->cleanup(chip); | ||
397 | mutex_destroy(&chip->mutex); | ||
398 | pci_release_regions(chip->pci); | ||
399 | pci_disable_device(chip->pci); | ||
400 | } | ||
401 | |||
402 | int __devinit oxygen_pci_probe(struct pci_dev *pci, int index, char *id, | ||
403 | int midi, const struct oxygen_model *model) | ||
404 | { | ||
405 | struct snd_card *card; | ||
406 | struct oxygen *chip; | ||
407 | int err; | ||
408 | |||
409 | card = snd_card_new(index, id, model->owner, | ||
410 | sizeof *chip + model->model_data_size); | ||
411 | if (!card) | ||
412 | return -ENOMEM; | ||
413 | |||
414 | chip = card->private_data; | ||
415 | chip->card = card; | ||
416 | chip->pci = pci; | ||
417 | chip->irq = -1; | ||
418 | chip->model = model; | ||
419 | chip->model_data = chip + 1; | ||
420 | spin_lock_init(&chip->reg_lock); | ||
421 | mutex_init(&chip->mutex); | ||
422 | INIT_WORK(&chip->spdif_input_bits_work, | ||
423 | oxygen_spdif_input_bits_changed); | ||
424 | INIT_WORK(&chip->gpio_work, oxygen_gpio_changed); | ||
425 | init_waitqueue_head(&chip->ac97_waitqueue); | ||
426 | |||
427 | err = pci_enable_device(pci); | ||
428 | if (err < 0) | ||
429 | goto err_card; | ||
430 | |||
431 | err = pci_request_regions(pci, model->chip); | ||
432 | if (err < 0) { | ||
433 | snd_printk(KERN_ERR "cannot reserve PCI resources\n"); | ||
434 | goto err_pci_enable; | ||
435 | } | ||
436 | |||
437 | if (!(pci_resource_flags(pci, 0) & IORESOURCE_IO) || | ||
438 | pci_resource_len(pci, 0) < 0x100) { | ||
439 | snd_printk(KERN_ERR "invalid PCI I/O range\n"); | ||
440 | err = -ENXIO; | ||
441 | goto err_pci_regions; | ||
442 | } | ||
443 | chip->addr = pci_resource_start(pci, 0); | ||
444 | |||
445 | pci_set_master(pci); | ||
446 | snd_card_set_dev(card, &pci->dev); | ||
447 | card->private_free = oxygen_card_free; | ||
448 | |||
449 | oxygen_init(chip); | ||
450 | model->init(chip); | ||
451 | |||
452 | err = request_irq(pci->irq, oxygen_interrupt, IRQF_SHARED, | ||
453 | model->chip, chip); | ||
454 | if (err < 0) { | ||
455 | snd_printk(KERN_ERR "cannot grab interrupt %d\n", pci->irq); | ||
456 | goto err_card; | ||
457 | } | ||
458 | chip->irq = pci->irq; | ||
459 | |||
460 | strcpy(card->driver, model->chip); | ||
461 | strcpy(card->shortname, model->shortname); | ||
462 | sprintf(card->longname, "%s (rev %u) at %#lx, irq %i", | ||
463 | model->longname, chip->revision, chip->addr, chip->irq); | ||
464 | strcpy(card->mixername, model->chip); | ||
465 | snd_component_add(card, model->chip); | ||
466 | |||
467 | err = oxygen_pcm_init(chip); | ||
468 | if (err < 0) | ||
469 | goto err_card; | ||
470 | |||
471 | err = oxygen_mixer_init(chip); | ||
472 | if (err < 0) | ||
473 | goto err_card; | ||
474 | |||
475 | oxygen_write8_masked(chip, OXYGEN_MISC, | ||
476 | midi ? OXYGEN_MISC_MIDI : 0, OXYGEN_MISC_MIDI); | ||
477 | if (midi) { | ||
478 | err = snd_mpu401_uart_new(card, 0, MPU401_HW_CMIPCI, | ||
479 | chip->addr + OXYGEN_MPU401, | ||
480 | MPU401_INFO_INTEGRATED, 0, 0, | ||
481 | &chip->midi); | ||
482 | if (err < 0) | ||
483 | goto err_card; | ||
484 | } | ||
485 | |||
486 | oxygen_proc_init(chip); | ||
487 | |||
488 | spin_lock_irq(&chip->reg_lock); | ||
489 | chip->interrupt_mask |= OXYGEN_INT_SPDIF_IN_DETECT | OXYGEN_INT_AC97; | ||
490 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); | ||
491 | spin_unlock_irq(&chip->reg_lock); | ||
492 | |||
493 | err = snd_card_register(card); | ||
494 | if (err < 0) | ||
495 | goto err_card; | ||
496 | |||
497 | pci_set_drvdata(pci, card); | ||
498 | return 0; | ||
499 | |||
500 | err_pci_regions: | ||
501 | pci_release_regions(pci); | ||
502 | err_pci_enable: | ||
503 | pci_disable_device(pci); | ||
504 | err_card: | ||
505 | snd_card_free(card); | ||
506 | return err; | ||
507 | } | ||
508 | EXPORT_SYMBOL(oxygen_pci_probe); | ||
509 | |||
510 | void __devexit oxygen_pci_remove(struct pci_dev *pci) | ||
511 | { | ||
512 | snd_card_free(pci_get_drvdata(pci)); | ||
513 | pci_set_drvdata(pci, NULL); | ||
514 | } | ||
515 | EXPORT_SYMBOL(oxygen_pci_remove); | ||
diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c new file mode 100644 index 000000000000..a8e4623415d9 --- /dev/null +++ b/sound/pci/oxygen/oxygen_mixer.c | |||
@@ -0,0 +1,794 @@ | |||
1 | /* | ||
2 | * C-Media CMI8788 driver - mixer code | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * | ||
6 | * | ||
7 | * This driver is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License, version 2. | ||
9 | * | ||
10 | * This driver is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this driver; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include <linux/mutex.h> | ||
21 | #include <sound/ac97_codec.h> | ||
22 | #include <sound/asoundef.h> | ||
23 | #include <sound/control.h> | ||
24 | #include <sound/tlv.h> | ||
25 | #include "oxygen.h" | ||
26 | #include "cm9780.h" | ||
27 | |||
28 | static int dac_volume_info(struct snd_kcontrol *ctl, | ||
29 | struct snd_ctl_elem_info *info) | ||
30 | { | ||
31 | struct oxygen *chip = ctl->private_data; | ||
32 | |||
33 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
34 | info->count = chip->model->dac_channels; | ||
35 | info->value.integer.min = 0; | ||
36 | info->value.integer.max = 0xff; | ||
37 | return 0; | ||
38 | } | ||
39 | |||
40 | static int dac_volume_get(struct snd_kcontrol *ctl, | ||
41 | struct snd_ctl_elem_value *value) | ||
42 | { | ||
43 | struct oxygen *chip = ctl->private_data; | ||
44 | unsigned int i; | ||
45 | |||
46 | mutex_lock(&chip->mutex); | ||
47 | for (i = 0; i < chip->model->dac_channels; ++i) | ||
48 | value->value.integer.value[i] = chip->dac_volume[i]; | ||
49 | mutex_unlock(&chip->mutex); | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | static int dac_volume_put(struct snd_kcontrol *ctl, | ||
54 | struct snd_ctl_elem_value *value) | ||
55 | { | ||
56 | struct oxygen *chip = ctl->private_data; | ||
57 | unsigned int i; | ||
58 | int changed; | ||
59 | |||
60 | changed = 0; | ||
61 | mutex_lock(&chip->mutex); | ||
62 | for (i = 0; i < chip->model->dac_channels; ++i) | ||
63 | if (value->value.integer.value[i] != chip->dac_volume[i]) { | ||
64 | chip->dac_volume[i] = value->value.integer.value[i]; | ||
65 | changed = 1; | ||
66 | } | ||
67 | if (changed) | ||
68 | chip->model->update_dac_volume(chip); | ||
69 | mutex_unlock(&chip->mutex); | ||
70 | return changed; | ||
71 | } | ||
72 | |||
73 | static int dac_mute_get(struct snd_kcontrol *ctl, | ||
74 | struct snd_ctl_elem_value *value) | ||
75 | { | ||
76 | struct oxygen *chip = ctl->private_data; | ||
77 | |||
78 | mutex_lock(&chip->mutex); | ||
79 | value->value.integer.value[0] = !chip->dac_mute; | ||
80 | mutex_unlock(&chip->mutex); | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static int dac_mute_put(struct snd_kcontrol *ctl, | ||
85 | struct snd_ctl_elem_value *value) | ||
86 | { | ||
87 | struct oxygen *chip = ctl->private_data; | ||
88 | int changed; | ||
89 | |||
90 | mutex_lock(&chip->mutex); | ||
91 | changed = !value->value.integer.value[0] != chip->dac_mute; | ||
92 | if (changed) { | ||
93 | chip->dac_mute = !value->value.integer.value[0]; | ||
94 | chip->model->update_dac_mute(chip); | ||
95 | } | ||
96 | mutex_unlock(&chip->mutex); | ||
97 | return changed; | ||
98 | } | ||
99 | |||
100 | static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) | ||
101 | { | ||
102 | static const char *const names[3] = { | ||
103 | "Front", "Front+Surround", "Front+Surround+Back" | ||
104 | }; | ||
105 | struct oxygen *chip = ctl->private_data; | ||
106 | unsigned int count = 2 + (chip->model->dac_channels == 8); | ||
107 | |||
108 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
109 | info->count = 1; | ||
110 | info->value.enumerated.items = count; | ||
111 | if (info->value.enumerated.item >= count) | ||
112 | info->value.enumerated.item = count - 1; | ||
113 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | static int upmix_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) | ||
118 | { | ||
119 | struct oxygen *chip = ctl->private_data; | ||
120 | |||
121 | mutex_lock(&chip->mutex); | ||
122 | value->value.enumerated.item[0] = chip->dac_routing; | ||
123 | mutex_unlock(&chip->mutex); | ||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | void oxygen_update_dac_routing(struct oxygen *chip) | ||
128 | { | ||
129 | /* DAC 0: front, DAC 1: surround, DAC 2: center/LFE, DAC 3: back */ | ||
130 | static const unsigned int reg_values[3] = { | ||
131 | /* stereo -> front */ | ||
132 | (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | | ||
133 | (1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | | ||
134 | (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | | ||
135 | (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT), | ||
136 | /* stereo -> front+surround */ | ||
137 | (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | | ||
138 | (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | | ||
139 | (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | | ||
140 | (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT), | ||
141 | /* stereo -> front+surround+back */ | ||
142 | (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | | ||
143 | (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | | ||
144 | (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | | ||
145 | (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT), | ||
146 | }; | ||
147 | u8 channels; | ||
148 | unsigned int reg_value; | ||
149 | |||
150 | channels = oxygen_read8(chip, OXYGEN_PLAY_CHANNELS) & | ||
151 | OXYGEN_PLAY_CHANNELS_MASK; | ||
152 | if (channels == OXYGEN_PLAY_CHANNELS_2) | ||
153 | reg_value = reg_values[chip->dac_routing]; | ||
154 | else if (channels == OXYGEN_PLAY_CHANNELS_8) | ||
155 | /* in 7.1 mode, "rear" channels go to the "back" jack */ | ||
156 | reg_value = (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | | ||
157 | (3 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | | ||
158 | (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | | ||
159 | (1 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT); | ||
160 | else | ||
161 | reg_value = (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | | ||
162 | (1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | | ||
163 | (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | | ||
164 | (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT); | ||
165 | oxygen_write16_masked(chip, OXYGEN_PLAY_ROUTING, reg_value, | ||
166 | OXYGEN_PLAY_DAC0_SOURCE_MASK | | ||
167 | OXYGEN_PLAY_DAC1_SOURCE_MASK | | ||
168 | OXYGEN_PLAY_DAC2_SOURCE_MASK | | ||
169 | OXYGEN_PLAY_DAC3_SOURCE_MASK); | ||
170 | } | ||
171 | |||
172 | static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) | ||
173 | { | ||
174 | struct oxygen *chip = ctl->private_data; | ||
175 | unsigned int count = 2 + (chip->model->dac_channels == 8); | ||
176 | int changed; | ||
177 | |||
178 | mutex_lock(&chip->mutex); | ||
179 | changed = value->value.enumerated.item[0] != chip->dac_routing; | ||
180 | if (changed) { | ||
181 | chip->dac_routing = min(value->value.enumerated.item[0], | ||
182 | count - 1); | ||
183 | spin_lock_irq(&chip->reg_lock); | ||
184 | oxygen_update_dac_routing(chip); | ||
185 | spin_unlock_irq(&chip->reg_lock); | ||
186 | } | ||
187 | mutex_unlock(&chip->mutex); | ||
188 | return changed; | ||
189 | } | ||
190 | |||
191 | static int spdif_switch_get(struct snd_kcontrol *ctl, | ||
192 | struct snd_ctl_elem_value *value) | ||
193 | { | ||
194 | struct oxygen *chip = ctl->private_data; | ||
195 | |||
196 | mutex_lock(&chip->mutex); | ||
197 | value->value.integer.value[0] = chip->spdif_playback_enable; | ||
198 | mutex_unlock(&chip->mutex); | ||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | static unsigned int oxygen_spdif_rate(unsigned int oxygen_rate) | ||
203 | { | ||
204 | switch (oxygen_rate) { | ||
205 | case OXYGEN_RATE_32000: | ||
206 | return IEC958_AES3_CON_FS_32000 << OXYGEN_SPDIF_CS_RATE_SHIFT; | ||
207 | case OXYGEN_RATE_44100: | ||
208 | return IEC958_AES3_CON_FS_44100 << OXYGEN_SPDIF_CS_RATE_SHIFT; | ||
209 | default: /* OXYGEN_RATE_48000 */ | ||
210 | return IEC958_AES3_CON_FS_48000 << OXYGEN_SPDIF_CS_RATE_SHIFT; | ||
211 | case OXYGEN_RATE_64000: | ||
212 | return 0xb << OXYGEN_SPDIF_CS_RATE_SHIFT; | ||
213 | case OXYGEN_RATE_88200: | ||
214 | return 0x8 << OXYGEN_SPDIF_CS_RATE_SHIFT; | ||
215 | case OXYGEN_RATE_96000: | ||
216 | return 0xa << OXYGEN_SPDIF_CS_RATE_SHIFT; | ||
217 | case OXYGEN_RATE_176400: | ||
218 | return 0xc << OXYGEN_SPDIF_CS_RATE_SHIFT; | ||
219 | case OXYGEN_RATE_192000: | ||
220 | return 0xe << OXYGEN_SPDIF_CS_RATE_SHIFT; | ||
221 | } | ||
222 | } | ||
223 | |||
224 | void oxygen_update_spdif_source(struct oxygen *chip) | ||
225 | { | ||
226 | u32 old_control, new_control; | ||
227 | u16 old_routing, new_routing; | ||
228 | unsigned int oxygen_rate; | ||
229 | |||
230 | old_control = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); | ||
231 | old_routing = oxygen_read16(chip, OXYGEN_PLAY_ROUTING); | ||
232 | if (chip->pcm_active & (1 << PCM_SPDIF)) { | ||
233 | new_control = old_control | OXYGEN_SPDIF_OUT_ENABLE; | ||
234 | new_routing = (old_routing & ~OXYGEN_PLAY_SPDIF_MASK) | ||
235 | | OXYGEN_PLAY_SPDIF_SPDIF; | ||
236 | oxygen_rate = (old_control >> OXYGEN_SPDIF_OUT_RATE_SHIFT) | ||
237 | & OXYGEN_I2S_RATE_MASK; | ||
238 | /* S/PDIF rate was already set by the caller */ | ||
239 | } else if ((chip->pcm_active & (1 << PCM_MULTICH)) && | ||
240 | chip->spdif_playback_enable) { | ||
241 | new_routing = (old_routing & ~OXYGEN_PLAY_SPDIF_MASK) | ||
242 | | OXYGEN_PLAY_SPDIF_MULTICH_01; | ||
243 | oxygen_rate = oxygen_read16(chip, OXYGEN_I2S_MULTICH_FORMAT) | ||
244 | & OXYGEN_I2S_RATE_MASK; | ||
245 | new_control = (old_control & ~OXYGEN_SPDIF_OUT_RATE_MASK) | | ||
246 | (oxygen_rate << OXYGEN_SPDIF_OUT_RATE_SHIFT) | | ||
247 | OXYGEN_SPDIF_OUT_ENABLE; | ||
248 | } else { | ||
249 | new_control = old_control & ~OXYGEN_SPDIF_OUT_ENABLE; | ||
250 | new_routing = old_routing; | ||
251 | oxygen_rate = OXYGEN_RATE_44100; | ||
252 | } | ||
253 | if (old_routing != new_routing) { | ||
254 | oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, | ||
255 | new_control & ~OXYGEN_SPDIF_OUT_ENABLE); | ||
256 | oxygen_write16(chip, OXYGEN_PLAY_ROUTING, new_routing); | ||
257 | } | ||
258 | if (new_control & OXYGEN_SPDIF_OUT_ENABLE) | ||
259 | oxygen_write32(chip, OXYGEN_SPDIF_OUTPUT_BITS, | ||
260 | oxygen_spdif_rate(oxygen_rate) | | ||
261 | ((chip->pcm_active & (1 << PCM_SPDIF)) ? | ||
262 | chip->spdif_pcm_bits : chip->spdif_bits)); | ||
263 | oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, new_control); | ||
264 | } | ||
265 | |||
266 | static int spdif_switch_put(struct snd_kcontrol *ctl, | ||
267 | struct snd_ctl_elem_value *value) | ||
268 | { | ||
269 | struct oxygen *chip = ctl->private_data; | ||
270 | int changed; | ||
271 | |||
272 | mutex_lock(&chip->mutex); | ||
273 | changed = value->value.integer.value[0] != chip->spdif_playback_enable; | ||
274 | if (changed) { | ||
275 | chip->spdif_playback_enable = !!value->value.integer.value[0]; | ||
276 | spin_lock_irq(&chip->reg_lock); | ||
277 | oxygen_update_spdif_source(chip); | ||
278 | spin_unlock_irq(&chip->reg_lock); | ||
279 | } | ||
280 | mutex_unlock(&chip->mutex); | ||
281 | return changed; | ||
282 | } | ||
283 | |||
284 | static int spdif_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) | ||
285 | { | ||
286 | info->type = SNDRV_CTL_ELEM_TYPE_IEC958; | ||
287 | info->count = 1; | ||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | static void oxygen_to_iec958(u32 bits, struct snd_ctl_elem_value *value) | ||
292 | { | ||
293 | value->value.iec958.status[0] = | ||
294 | bits & (OXYGEN_SPDIF_NONAUDIO | OXYGEN_SPDIF_C | | ||
295 | OXYGEN_SPDIF_PREEMPHASIS); | ||
296 | value->value.iec958.status[1] = /* category and original */ | ||
297 | bits >> OXYGEN_SPDIF_CATEGORY_SHIFT; | ||
298 | } | ||
299 | |||
300 | static u32 iec958_to_oxygen(struct snd_ctl_elem_value *value) | ||
301 | { | ||
302 | u32 bits; | ||
303 | |||
304 | bits = value->value.iec958.status[0] & | ||
305 | (OXYGEN_SPDIF_NONAUDIO | OXYGEN_SPDIF_C | | ||
306 | OXYGEN_SPDIF_PREEMPHASIS); | ||
307 | bits |= value->value.iec958.status[1] << OXYGEN_SPDIF_CATEGORY_SHIFT; | ||
308 | if (bits & OXYGEN_SPDIF_NONAUDIO) | ||
309 | bits |= OXYGEN_SPDIF_V; | ||
310 | return bits; | ||
311 | } | ||
312 | |||
313 | static inline void write_spdif_bits(struct oxygen *chip, u32 bits) | ||
314 | { | ||
315 | oxygen_write32_masked(chip, OXYGEN_SPDIF_OUTPUT_BITS, bits, | ||
316 | OXYGEN_SPDIF_NONAUDIO | | ||
317 | OXYGEN_SPDIF_C | | ||
318 | OXYGEN_SPDIF_PREEMPHASIS | | ||
319 | OXYGEN_SPDIF_CATEGORY_MASK | | ||
320 | OXYGEN_SPDIF_ORIGINAL | | ||
321 | OXYGEN_SPDIF_V); | ||
322 | } | ||
323 | |||
324 | static int spdif_default_get(struct snd_kcontrol *ctl, | ||
325 | struct snd_ctl_elem_value *value) | ||
326 | { | ||
327 | struct oxygen *chip = ctl->private_data; | ||
328 | |||
329 | mutex_lock(&chip->mutex); | ||
330 | oxygen_to_iec958(chip->spdif_bits, value); | ||
331 | mutex_unlock(&chip->mutex); | ||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | static int spdif_default_put(struct snd_kcontrol *ctl, | ||
336 | struct snd_ctl_elem_value *value) | ||
337 | { | ||
338 | struct oxygen *chip = ctl->private_data; | ||
339 | u32 new_bits; | ||
340 | int changed; | ||
341 | |||
342 | new_bits = iec958_to_oxygen(value); | ||
343 | mutex_lock(&chip->mutex); | ||
344 | changed = new_bits != chip->spdif_bits; | ||
345 | if (changed) { | ||
346 | chip->spdif_bits = new_bits; | ||
347 | if (!(chip->pcm_active & (1 << PCM_SPDIF))) | ||
348 | write_spdif_bits(chip, new_bits); | ||
349 | } | ||
350 | mutex_unlock(&chip->mutex); | ||
351 | return changed; | ||
352 | } | ||
353 | |||
354 | static int spdif_mask_get(struct snd_kcontrol *ctl, | ||
355 | struct snd_ctl_elem_value *value) | ||
356 | { | ||
357 | value->value.iec958.status[0] = IEC958_AES0_NONAUDIO | | ||
358 | IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS; | ||
359 | value->value.iec958.status[1] = | ||
360 | IEC958_AES1_CON_CATEGORY | IEC958_AES1_CON_ORIGINAL; | ||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | static int spdif_pcm_get(struct snd_kcontrol *ctl, | ||
365 | struct snd_ctl_elem_value *value) | ||
366 | { | ||
367 | struct oxygen *chip = ctl->private_data; | ||
368 | |||
369 | mutex_lock(&chip->mutex); | ||
370 | oxygen_to_iec958(chip->spdif_pcm_bits, value); | ||
371 | mutex_unlock(&chip->mutex); | ||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | static int spdif_pcm_put(struct snd_kcontrol *ctl, | ||
376 | struct snd_ctl_elem_value *value) | ||
377 | { | ||
378 | struct oxygen *chip = ctl->private_data; | ||
379 | u32 new_bits; | ||
380 | int changed; | ||
381 | |||
382 | new_bits = iec958_to_oxygen(value); | ||
383 | mutex_lock(&chip->mutex); | ||
384 | changed = new_bits != chip->spdif_pcm_bits; | ||
385 | if (changed) { | ||
386 | chip->spdif_pcm_bits = new_bits; | ||
387 | if (chip->pcm_active & (1 << PCM_SPDIF)) | ||
388 | write_spdif_bits(chip, new_bits); | ||
389 | } | ||
390 | mutex_unlock(&chip->mutex); | ||
391 | return changed; | ||
392 | } | ||
393 | |||
394 | static int spdif_input_mask_get(struct snd_kcontrol *ctl, | ||
395 | struct snd_ctl_elem_value *value) | ||
396 | { | ||
397 | value->value.iec958.status[0] = 0xff; | ||
398 | value->value.iec958.status[1] = 0xff; | ||
399 | value->value.iec958.status[2] = 0xff; | ||
400 | value->value.iec958.status[3] = 0xff; | ||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | static int spdif_input_default_get(struct snd_kcontrol *ctl, | ||
405 | struct snd_ctl_elem_value *value) | ||
406 | { | ||
407 | struct oxygen *chip = ctl->private_data; | ||
408 | u32 bits; | ||
409 | |||
410 | bits = oxygen_read32(chip, OXYGEN_SPDIF_INPUT_BITS); | ||
411 | value->value.iec958.status[0] = bits; | ||
412 | value->value.iec958.status[1] = bits >> 8; | ||
413 | value->value.iec958.status[2] = bits >> 16; | ||
414 | value->value.iec958.status[3] = bits >> 24; | ||
415 | return 0; | ||
416 | } | ||
417 | |||
418 | static int spdif_loopback_get(struct snd_kcontrol *ctl, | ||
419 | struct snd_ctl_elem_value *value) | ||
420 | { | ||
421 | struct oxygen *chip = ctl->private_data; | ||
422 | |||
423 | value->value.integer.value[0] = | ||
424 | !!(oxygen_read32(chip, OXYGEN_SPDIF_CONTROL) | ||
425 | & OXYGEN_SPDIF_LOOPBACK); | ||
426 | return 0; | ||
427 | } | ||
428 | |||
429 | static int spdif_loopback_put(struct snd_kcontrol *ctl, | ||
430 | struct snd_ctl_elem_value *value) | ||
431 | { | ||
432 | struct oxygen *chip = ctl->private_data; | ||
433 | u32 oldreg, newreg; | ||
434 | int changed; | ||
435 | |||
436 | spin_lock_irq(&chip->reg_lock); | ||
437 | oldreg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); | ||
438 | if (value->value.integer.value[0]) | ||
439 | newreg = oldreg | OXYGEN_SPDIF_LOOPBACK; | ||
440 | else | ||
441 | newreg = oldreg & ~OXYGEN_SPDIF_LOOPBACK; | ||
442 | changed = newreg != oldreg; | ||
443 | if (changed) | ||
444 | oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, newreg); | ||
445 | spin_unlock_irq(&chip->reg_lock); | ||
446 | return changed; | ||
447 | } | ||
448 | |||
449 | static int ac97_switch_get(struct snd_kcontrol *ctl, | ||
450 | struct snd_ctl_elem_value *value) | ||
451 | { | ||
452 | struct oxygen *chip = ctl->private_data; | ||
453 | unsigned int codec = (ctl->private_value >> 24) & 1; | ||
454 | unsigned int index = ctl->private_value & 0xff; | ||
455 | unsigned int bitnr = (ctl->private_value >> 8) & 0xff; | ||
456 | int invert = ctl->private_value & (1 << 16); | ||
457 | u16 reg; | ||
458 | |||
459 | mutex_lock(&chip->mutex); | ||
460 | reg = oxygen_read_ac97(chip, codec, index); | ||
461 | mutex_unlock(&chip->mutex); | ||
462 | if (!(reg & (1 << bitnr)) ^ !invert) | ||
463 | value->value.integer.value[0] = 1; | ||
464 | else | ||
465 | value->value.integer.value[0] = 0; | ||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | static int ac97_switch_put(struct snd_kcontrol *ctl, | ||
470 | struct snd_ctl_elem_value *value) | ||
471 | { | ||
472 | struct oxygen *chip = ctl->private_data; | ||
473 | unsigned int codec = (ctl->private_value >> 24) & 1; | ||
474 | unsigned int index = ctl->private_value & 0xff; | ||
475 | unsigned int bitnr = (ctl->private_value >> 8) & 0xff; | ||
476 | int invert = ctl->private_value & (1 << 16); | ||
477 | u16 oldreg, newreg; | ||
478 | int change; | ||
479 | |||
480 | mutex_lock(&chip->mutex); | ||
481 | oldreg = oxygen_read_ac97(chip, codec, index); | ||
482 | newreg = oldreg; | ||
483 | if (!value->value.integer.value[0] ^ !invert) | ||
484 | newreg |= 1 << bitnr; | ||
485 | else | ||
486 | newreg &= ~(1 << bitnr); | ||
487 | change = newreg != oldreg; | ||
488 | if (change) { | ||
489 | oxygen_write_ac97(chip, codec, index, newreg); | ||
490 | if (bitnr == 15 && chip->model->ac97_switch_hook) | ||
491 | chip->model->ac97_switch_hook(chip, codec, index, | ||
492 | newreg & 0x8000); | ||
493 | } | ||
494 | mutex_unlock(&chip->mutex); | ||
495 | return change; | ||
496 | } | ||
497 | |||
498 | static int ac97_volume_info(struct snd_kcontrol *ctl, | ||
499 | struct snd_ctl_elem_info *info) | ||
500 | { | ||
501 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
502 | info->count = 2; | ||
503 | info->value.integer.min = 0; | ||
504 | info->value.integer.max = 0x1f; | ||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | static int ac97_volume_get(struct snd_kcontrol *ctl, | ||
509 | struct snd_ctl_elem_value *value) | ||
510 | { | ||
511 | struct oxygen *chip = ctl->private_data; | ||
512 | unsigned int codec = (ctl->private_value >> 24) & 1; | ||
513 | unsigned int index = ctl->private_value & 0xff; | ||
514 | u16 reg; | ||
515 | |||
516 | mutex_lock(&chip->mutex); | ||
517 | reg = oxygen_read_ac97(chip, codec, index); | ||
518 | mutex_unlock(&chip->mutex); | ||
519 | value->value.integer.value[0] = 31 - (reg & 0x1f); | ||
520 | value->value.integer.value[1] = 31 - ((reg >> 8) & 0x1f); | ||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | static int ac97_volume_put(struct snd_kcontrol *ctl, | ||
525 | struct snd_ctl_elem_value *value) | ||
526 | { | ||
527 | struct oxygen *chip = ctl->private_data; | ||
528 | unsigned int codec = (ctl->private_value >> 24) & 1; | ||
529 | unsigned int index = ctl->private_value & 0xff; | ||
530 | u16 oldreg, newreg; | ||
531 | int change; | ||
532 | |||
533 | mutex_lock(&chip->mutex); | ||
534 | oldreg = oxygen_read_ac97(chip, codec, index); | ||
535 | newreg = oldreg; | ||
536 | newreg = (newreg & ~0x1f) | | ||
537 | (31 - (value->value.integer.value[0] & 0x1f)); | ||
538 | newreg = (newreg & ~0x1f00) | | ||
539 | ((31 - (value->value.integer.value[0] & 0x1f)) << 8); | ||
540 | change = newreg != oldreg; | ||
541 | if (change) | ||
542 | oxygen_write_ac97(chip, codec, index, newreg); | ||
543 | mutex_unlock(&chip->mutex); | ||
544 | return change; | ||
545 | } | ||
546 | |||
547 | static int ac97_fp_rec_volume_info(struct snd_kcontrol *ctl, | ||
548 | struct snd_ctl_elem_info *info) | ||
549 | { | ||
550 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
551 | info->count = 2; | ||
552 | info->value.integer.min = 0; | ||
553 | info->value.integer.max = 7; | ||
554 | return 0; | ||
555 | } | ||
556 | |||
557 | static int ac97_fp_rec_volume_get(struct snd_kcontrol *ctl, | ||
558 | struct snd_ctl_elem_value *value) | ||
559 | { | ||
560 | struct oxygen *chip = ctl->private_data; | ||
561 | u16 reg; | ||
562 | |||
563 | mutex_lock(&chip->mutex); | ||
564 | reg = oxygen_read_ac97(chip, 1, AC97_REC_GAIN); | ||
565 | mutex_unlock(&chip->mutex); | ||
566 | value->value.integer.value[0] = reg & 7; | ||
567 | value->value.integer.value[1] = (reg >> 8) & 7; | ||
568 | return 0; | ||
569 | } | ||
570 | |||
571 | static int ac97_fp_rec_volume_put(struct snd_kcontrol *ctl, | ||
572 | struct snd_ctl_elem_value *value) | ||
573 | { | ||
574 | struct oxygen *chip = ctl->private_data; | ||
575 | u16 oldreg, newreg; | ||
576 | int change; | ||
577 | |||
578 | mutex_lock(&chip->mutex); | ||
579 | oldreg = oxygen_read_ac97(chip, 1, AC97_REC_GAIN); | ||
580 | newreg = oldreg & ~0x0707; | ||
581 | newreg = newreg | (value->value.integer.value[0] & 7); | ||
582 | newreg = newreg | ((value->value.integer.value[0] & 7) << 8); | ||
583 | change = newreg != oldreg; | ||
584 | if (change) | ||
585 | oxygen_write_ac97(chip, 1, AC97_REC_GAIN, newreg); | ||
586 | mutex_unlock(&chip->mutex); | ||
587 | return change; | ||
588 | } | ||
589 | |||
590 | #define AC97_SWITCH(xname, codec, index, bitnr, invert) { \ | ||
591 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
592 | .name = xname, \ | ||
593 | .info = snd_ctl_boolean_mono_info, \ | ||
594 | .get = ac97_switch_get, \ | ||
595 | .put = ac97_switch_put, \ | ||
596 | .private_value = ((codec) << 24) | ((invert) << 16) | \ | ||
597 | ((bitnr) << 8) | (index), \ | ||
598 | } | ||
599 | #define AC97_VOLUME(xname, codec, index) { \ | ||
600 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
601 | .name = xname, \ | ||
602 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
603 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
604 | .info = ac97_volume_info, \ | ||
605 | .get = ac97_volume_get, \ | ||
606 | .put = ac97_volume_put, \ | ||
607 | .tlv = { .p = ac97_db_scale, }, \ | ||
608 | .private_value = ((codec) << 24) | (index), \ | ||
609 | } | ||
610 | |||
611 | static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0); | ||
612 | static DECLARE_TLV_DB_SCALE(ac97_rec_db_scale, 0, 150, 0); | ||
613 | |||
614 | static const struct snd_kcontrol_new controls[] = { | ||
615 | { | ||
616 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
617 | .name = "Master Playback Volume", | ||
618 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
619 | .info = dac_volume_info, | ||
620 | .get = dac_volume_get, | ||
621 | .put = dac_volume_put, | ||
622 | }, | ||
623 | { | ||
624 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
625 | .name = "Master Playback Switch", | ||
626 | .info = snd_ctl_boolean_mono_info, | ||
627 | .get = dac_mute_get, | ||
628 | .put = dac_mute_put, | ||
629 | }, | ||
630 | { | ||
631 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
632 | .name = "Stereo Upmixing", | ||
633 | .info = upmix_info, | ||
634 | .get = upmix_get, | ||
635 | .put = upmix_put, | ||
636 | }, | ||
637 | { | ||
638 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
639 | .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH), | ||
640 | .info = snd_ctl_boolean_mono_info, | ||
641 | .get = spdif_switch_get, | ||
642 | .put = spdif_switch_put, | ||
643 | }, | ||
644 | { | ||
645 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
646 | .device = 1, | ||
647 | .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), | ||
648 | .info = spdif_info, | ||
649 | .get = spdif_default_get, | ||
650 | .put = spdif_default_put, | ||
651 | }, | ||
652 | { | ||
653 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
654 | .device = 1, | ||
655 | .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK), | ||
656 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
657 | .info = spdif_info, | ||
658 | .get = spdif_mask_get, | ||
659 | }, | ||
660 | { | ||
661 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
662 | .device = 1, | ||
663 | .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM), | ||
664 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
665 | SNDRV_CTL_ELEM_ACCESS_INACTIVE, | ||
666 | .info = spdif_info, | ||
667 | .get = spdif_pcm_get, | ||
668 | .put = spdif_pcm_put, | ||
669 | }, | ||
670 | { | ||
671 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
672 | .device = 1, | ||
673 | .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK), | ||
674 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
675 | .info = spdif_info, | ||
676 | .get = spdif_input_mask_get, | ||
677 | }, | ||
678 | { | ||
679 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
680 | .device = 1, | ||
681 | .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), | ||
682 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
683 | .info = spdif_info, | ||
684 | .get = spdif_input_default_get, | ||
685 | }, | ||
686 | { | ||
687 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
688 | .name = SNDRV_CTL_NAME_IEC958("Loopback ", NONE, SWITCH), | ||
689 | .info = snd_ctl_boolean_mono_info, | ||
690 | .get = spdif_loopback_get, | ||
691 | .put = spdif_loopback_put, | ||
692 | }, | ||
693 | }; | ||
694 | |||
695 | static const struct snd_kcontrol_new ac97_controls[] = { | ||
696 | AC97_VOLUME("Mic Capture Volume", 0, AC97_MIC), | ||
697 | AC97_SWITCH("Mic Capture Switch", 0, AC97_MIC, 15, 1), | ||
698 | AC97_SWITCH("Mic Boost (+20dB)", 0, AC97_MIC, 6, 0), | ||
699 | AC97_VOLUME("Line Capture Volume", 0, AC97_LINE), | ||
700 | AC97_SWITCH("Line Capture Switch", 0, AC97_LINE, 15, 1), | ||
701 | AC97_VOLUME("CD Capture Volume", 0, AC97_CD), | ||
702 | AC97_SWITCH("CD Capture Switch", 0, AC97_CD, 15, 1), | ||
703 | AC97_VOLUME("Aux Capture Volume", 0, AC97_AUX), | ||
704 | AC97_SWITCH("Aux Capture Switch", 0, AC97_AUX, 15, 1), | ||
705 | }; | ||
706 | |||
707 | static const struct snd_kcontrol_new ac97_fp_controls[] = { | ||
708 | AC97_VOLUME("Front Panel Playback Volume", 1, AC97_HEADPHONE), | ||
709 | AC97_SWITCH("Front Panel Playback Switch", 1, AC97_HEADPHONE, 15, 1), | ||
710 | { | ||
711 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
712 | .name = "Front Panel Capture Volume", | ||
713 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
714 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | ||
715 | .info = ac97_fp_rec_volume_info, | ||
716 | .get = ac97_fp_rec_volume_get, | ||
717 | .put = ac97_fp_rec_volume_put, | ||
718 | .tlv = { .p = ac97_rec_db_scale, }, | ||
719 | }, | ||
720 | AC97_SWITCH("Front Panel Capture Switch", 1, AC97_REC_GAIN, 15, 1), | ||
721 | }; | ||
722 | |||
723 | static void oxygen_any_ctl_free(struct snd_kcontrol *ctl) | ||
724 | { | ||
725 | struct oxygen *chip = ctl->private_data; | ||
726 | unsigned int i; | ||
727 | |||
728 | /* I'm too lazy to write a function for each control :-) */ | ||
729 | for (i = 0; i < ARRAY_SIZE(chip->controls); ++i) | ||
730 | chip->controls[i] = NULL; | ||
731 | } | ||
732 | |||
733 | static int add_controls(struct oxygen *chip, | ||
734 | const struct snd_kcontrol_new controls[], | ||
735 | unsigned int count) | ||
736 | { | ||
737 | static const char *const known_ctl_names[CONTROL_COUNT] = { | ||
738 | [CONTROL_SPDIF_PCM] = | ||
739 | SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM), | ||
740 | [CONTROL_SPDIF_INPUT_BITS] = | ||
741 | SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), | ||
742 | [CONTROL_MIC_CAPTURE_SWITCH] = "Mic Capture Switch", | ||
743 | [CONTROL_LINE_CAPTURE_SWITCH] = "Line Capture Switch", | ||
744 | [CONTROL_CD_CAPTURE_SWITCH] = "CD Capture Switch", | ||
745 | [CONTROL_AUX_CAPTURE_SWITCH] = "Aux Capture Switch", | ||
746 | }; | ||
747 | unsigned int i, j; | ||
748 | struct snd_kcontrol_new template; | ||
749 | struct snd_kcontrol *ctl; | ||
750 | int err; | ||
751 | |||
752 | for (i = 0; i < count; ++i) { | ||
753 | template = controls[i]; | ||
754 | err = chip->model->control_filter(&template); | ||
755 | if (err < 0) | ||
756 | return err; | ||
757 | if (err == 1) | ||
758 | continue; | ||
759 | ctl = snd_ctl_new1(&template, chip); | ||
760 | if (!ctl) | ||
761 | return -ENOMEM; | ||
762 | err = snd_ctl_add(chip->card, ctl); | ||
763 | if (err < 0) | ||
764 | return err; | ||
765 | for (j = 0; j < CONTROL_COUNT; ++j) | ||
766 | if (!strcmp(ctl->id.name, known_ctl_names[j])) { | ||
767 | chip->controls[j] = ctl; | ||
768 | ctl->private_free = oxygen_any_ctl_free; | ||
769 | } | ||
770 | } | ||
771 | return 0; | ||
772 | } | ||
773 | |||
774 | int oxygen_mixer_init(struct oxygen *chip) | ||
775 | { | ||
776 | int err; | ||
777 | |||
778 | err = add_controls(chip, controls, ARRAY_SIZE(controls)); | ||
779 | if (err < 0) | ||
780 | return err; | ||
781 | if (chip->has_ac97_0) { | ||
782 | err = add_controls(chip, ac97_controls, | ||
783 | ARRAY_SIZE(ac97_controls)); | ||
784 | if (err < 0) | ||
785 | return err; | ||
786 | } | ||
787 | if (chip->has_ac97_1) { | ||
788 | err = add_controls(chip, ac97_fp_controls, | ||
789 | ARRAY_SIZE(ac97_fp_controls)); | ||
790 | if (err < 0) | ||
791 | return err; | ||
792 | } | ||
793 | return chip->model->mixer_init ? chip->model->mixer_init(chip) : 0; | ||
794 | } | ||
diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c new file mode 100644 index 000000000000..dfad3db35c82 --- /dev/null +++ b/sound/pci/oxygen/oxygen_pcm.c | |||
@@ -0,0 +1,718 @@ | |||
1 | /* | ||
2 | * C-Media CMI8788 driver - PCM code | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * | ||
6 | * | ||
7 | * This driver is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License, version 2. | ||
9 | * | ||
10 | * This driver is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this driver; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include <linux/pci.h> | ||
21 | #include <sound/control.h> | ||
22 | #include <sound/core.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/pcm_params.h> | ||
25 | #include "oxygen.h" | ||
26 | |||
27 | static const struct snd_pcm_hardware oxygen_stereo_hardware = { | ||
28 | .info = SNDRV_PCM_INFO_MMAP | | ||
29 | SNDRV_PCM_INFO_MMAP_VALID | | ||
30 | SNDRV_PCM_INFO_INTERLEAVED | | ||
31 | SNDRV_PCM_INFO_PAUSE | | ||
32 | SNDRV_PCM_INFO_SYNC_START, | ||
33 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
34 | SNDRV_PCM_FMTBIT_S32_LE, | ||
35 | .rates = SNDRV_PCM_RATE_32000 | | ||
36 | SNDRV_PCM_RATE_44100 | | ||
37 | SNDRV_PCM_RATE_48000 | | ||
38 | SNDRV_PCM_RATE_64000 | | ||
39 | SNDRV_PCM_RATE_88200 | | ||
40 | SNDRV_PCM_RATE_96000 | | ||
41 | SNDRV_PCM_RATE_176400 | | ||
42 | SNDRV_PCM_RATE_192000, | ||
43 | .rate_min = 32000, | ||
44 | .rate_max = 192000, | ||
45 | .channels_min = 2, | ||
46 | .channels_max = 2, | ||
47 | .buffer_bytes_max = 256 * 1024, | ||
48 | .period_bytes_min = 128, | ||
49 | .period_bytes_max = 128 * 1024, | ||
50 | .periods_min = 2, | ||
51 | .periods_max = 2048, | ||
52 | }; | ||
53 | static const struct snd_pcm_hardware oxygen_multichannel_hardware = { | ||
54 | .info = SNDRV_PCM_INFO_MMAP | | ||
55 | SNDRV_PCM_INFO_MMAP_VALID | | ||
56 | SNDRV_PCM_INFO_INTERLEAVED | | ||
57 | SNDRV_PCM_INFO_PAUSE | | ||
58 | SNDRV_PCM_INFO_SYNC_START, | ||
59 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
60 | SNDRV_PCM_FMTBIT_S32_LE, | ||
61 | .rates = SNDRV_PCM_RATE_32000 | | ||
62 | SNDRV_PCM_RATE_44100 | | ||
63 | SNDRV_PCM_RATE_48000 | | ||
64 | SNDRV_PCM_RATE_64000 | | ||
65 | SNDRV_PCM_RATE_88200 | | ||
66 | SNDRV_PCM_RATE_96000 | | ||
67 | SNDRV_PCM_RATE_176400 | | ||
68 | SNDRV_PCM_RATE_192000, | ||
69 | .rate_min = 32000, | ||
70 | .rate_max = 192000, | ||
71 | .channels_min = 2, | ||
72 | .channels_max = 8, | ||
73 | .buffer_bytes_max = 2048 * 1024, | ||
74 | .period_bytes_min = 128, | ||
75 | .period_bytes_max = 256 * 1024, | ||
76 | .periods_min = 2, | ||
77 | .periods_max = 16384, | ||
78 | }; | ||
79 | static const struct snd_pcm_hardware oxygen_ac97_hardware = { | ||
80 | .info = SNDRV_PCM_INFO_MMAP | | ||
81 | SNDRV_PCM_INFO_MMAP_VALID | | ||
82 | SNDRV_PCM_INFO_INTERLEAVED | | ||
83 | SNDRV_PCM_INFO_PAUSE | | ||
84 | SNDRV_PCM_INFO_SYNC_START, | ||
85 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
86 | .rates = SNDRV_PCM_RATE_48000, | ||
87 | .rate_min = 48000, | ||
88 | .rate_max = 48000, | ||
89 | .channels_min = 2, | ||
90 | .channels_max = 2, | ||
91 | .buffer_bytes_max = 256 * 1024, | ||
92 | .period_bytes_min = 128, | ||
93 | .period_bytes_max = 128 * 1024, | ||
94 | .periods_min = 2, | ||
95 | .periods_max = 2048, | ||
96 | }; | ||
97 | |||
98 | static const struct snd_pcm_hardware *const oxygen_hardware[PCM_COUNT] = { | ||
99 | [PCM_A] = &oxygen_stereo_hardware, | ||
100 | [PCM_B] = &oxygen_stereo_hardware, | ||
101 | [PCM_C] = &oxygen_stereo_hardware, | ||
102 | [PCM_SPDIF] = &oxygen_stereo_hardware, | ||
103 | [PCM_MULTICH] = &oxygen_multichannel_hardware, | ||
104 | [PCM_AC97] = &oxygen_ac97_hardware, | ||
105 | }; | ||
106 | |||
107 | static inline unsigned int | ||
108 | oxygen_substream_channel(struct snd_pcm_substream *substream) | ||
109 | { | ||
110 | return (unsigned int)(uintptr_t)substream->runtime->private_data; | ||
111 | } | ||
112 | |||
113 | static int oxygen_open(struct snd_pcm_substream *substream, | ||
114 | unsigned int channel) | ||
115 | { | ||
116 | struct oxygen *chip = snd_pcm_substream_chip(substream); | ||
117 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
118 | int err; | ||
119 | |||
120 | runtime->private_data = (void *)(uintptr_t)channel; | ||
121 | if (channel == PCM_B && chip->has_ac97_1 && | ||
122 | (chip->model->used_channels & OXYGEN_CHANNEL_AC97)) | ||
123 | runtime->hw = oxygen_ac97_hardware; | ||
124 | else | ||
125 | runtime->hw = *oxygen_hardware[channel]; | ||
126 | switch (channel) { | ||
127 | case PCM_C: | ||
128 | runtime->hw.rates &= ~(SNDRV_PCM_RATE_32000 | | ||
129 | SNDRV_PCM_RATE_64000); | ||
130 | runtime->hw.rate_min = 44100; | ||
131 | break; | ||
132 | case PCM_MULTICH: | ||
133 | runtime->hw.channels_max = chip->model->dac_channels; | ||
134 | break; | ||
135 | } | ||
136 | if (chip->model->pcm_hardware_filter) | ||
137 | chip->model->pcm_hardware_filter(channel, &runtime->hw); | ||
138 | err = snd_pcm_hw_constraint_step(runtime, 0, | ||
139 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); | ||
140 | if (err < 0) | ||
141 | return err; | ||
142 | err = snd_pcm_hw_constraint_step(runtime, 0, | ||
143 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32); | ||
144 | if (err < 0) | ||
145 | return err; | ||
146 | if (runtime->hw.formats & SNDRV_PCM_FMTBIT_S32_LE) { | ||
147 | err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); | ||
148 | if (err < 0) | ||
149 | return err; | ||
150 | } | ||
151 | if (runtime->hw.channels_max > 2) { | ||
152 | err = snd_pcm_hw_constraint_step(runtime, 0, | ||
153 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
154 | 2); | ||
155 | if (err < 0) | ||
156 | return err; | ||
157 | } | ||
158 | snd_pcm_set_sync(substream); | ||
159 | chip->streams[channel] = substream; | ||
160 | |||
161 | mutex_lock(&chip->mutex); | ||
162 | chip->pcm_active |= 1 << channel; | ||
163 | if (channel == PCM_SPDIF) { | ||
164 | chip->spdif_pcm_bits = chip->spdif_bits; | ||
165 | chip->controls[CONTROL_SPDIF_PCM]->vd[0].access &= | ||
166 | ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; | ||
167 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE | | ||
168 | SNDRV_CTL_EVENT_MASK_INFO, | ||
169 | &chip->controls[CONTROL_SPDIF_PCM]->id); | ||
170 | } | ||
171 | mutex_unlock(&chip->mutex); | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | static int oxygen_rec_a_open(struct snd_pcm_substream *substream) | ||
177 | { | ||
178 | return oxygen_open(substream, PCM_A); | ||
179 | } | ||
180 | |||
181 | static int oxygen_rec_b_open(struct snd_pcm_substream *substream) | ||
182 | { | ||
183 | return oxygen_open(substream, PCM_B); | ||
184 | } | ||
185 | |||
186 | static int oxygen_rec_c_open(struct snd_pcm_substream *substream) | ||
187 | { | ||
188 | return oxygen_open(substream, PCM_C); | ||
189 | } | ||
190 | |||
191 | static int oxygen_spdif_open(struct snd_pcm_substream *substream) | ||
192 | { | ||
193 | return oxygen_open(substream, PCM_SPDIF); | ||
194 | } | ||
195 | |||
196 | static int oxygen_multich_open(struct snd_pcm_substream *substream) | ||
197 | { | ||
198 | return oxygen_open(substream, PCM_MULTICH); | ||
199 | } | ||
200 | |||
201 | static int oxygen_ac97_open(struct snd_pcm_substream *substream) | ||
202 | { | ||
203 | return oxygen_open(substream, PCM_AC97); | ||
204 | } | ||
205 | |||
206 | static int oxygen_close(struct snd_pcm_substream *substream) | ||
207 | { | ||
208 | struct oxygen *chip = snd_pcm_substream_chip(substream); | ||
209 | unsigned int channel = oxygen_substream_channel(substream); | ||
210 | |||
211 | mutex_lock(&chip->mutex); | ||
212 | chip->pcm_active &= ~(1 << channel); | ||
213 | if (channel == PCM_SPDIF) { | ||
214 | chip->controls[CONTROL_SPDIF_PCM]->vd[0].access |= | ||
215 | SNDRV_CTL_ELEM_ACCESS_INACTIVE; | ||
216 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE | | ||
217 | SNDRV_CTL_EVENT_MASK_INFO, | ||
218 | &chip->controls[CONTROL_SPDIF_PCM]->id); | ||
219 | } | ||
220 | if (channel == PCM_SPDIF || channel == PCM_MULTICH) | ||
221 | oxygen_update_spdif_source(chip); | ||
222 | mutex_unlock(&chip->mutex); | ||
223 | |||
224 | chip->streams[channel] = NULL; | ||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | static unsigned int oxygen_format(struct snd_pcm_hw_params *hw_params) | ||
229 | { | ||
230 | if (params_format(hw_params) == SNDRV_PCM_FORMAT_S32_LE) | ||
231 | return OXYGEN_FORMAT_24; | ||
232 | else | ||
233 | return OXYGEN_FORMAT_16; | ||
234 | } | ||
235 | |||
236 | static unsigned int oxygen_rate(struct snd_pcm_hw_params *hw_params) | ||
237 | { | ||
238 | switch (params_rate(hw_params)) { | ||
239 | case 32000: | ||
240 | return OXYGEN_RATE_32000; | ||
241 | case 44100: | ||
242 | return OXYGEN_RATE_44100; | ||
243 | default: /* 48000 */ | ||
244 | return OXYGEN_RATE_48000; | ||
245 | case 64000: | ||
246 | return OXYGEN_RATE_64000; | ||
247 | case 88200: | ||
248 | return OXYGEN_RATE_88200; | ||
249 | case 96000: | ||
250 | return OXYGEN_RATE_96000; | ||
251 | case 176400: | ||
252 | return OXYGEN_RATE_176400; | ||
253 | case 192000: | ||
254 | return OXYGEN_RATE_192000; | ||
255 | } | ||
256 | } | ||
257 | |||
258 | static unsigned int oxygen_i2s_mclk(struct snd_pcm_hw_params *hw_params) | ||
259 | { | ||
260 | if (params_rate(hw_params) <= 96000) | ||
261 | return OXYGEN_I2S_MCLK_256; | ||
262 | else | ||
263 | return OXYGEN_I2S_MCLK_128; | ||
264 | } | ||
265 | |||
266 | static unsigned int oxygen_i2s_bits(struct snd_pcm_hw_params *hw_params) | ||
267 | { | ||
268 | if (params_format(hw_params) == SNDRV_PCM_FORMAT_S32_LE) | ||
269 | return OXYGEN_I2S_BITS_24; | ||
270 | else | ||
271 | return OXYGEN_I2S_BITS_16; | ||
272 | } | ||
273 | |||
274 | static unsigned int oxygen_play_channels(struct snd_pcm_hw_params *hw_params) | ||
275 | { | ||
276 | switch (params_channels(hw_params)) { | ||
277 | default: /* 2 */ | ||
278 | return OXYGEN_PLAY_CHANNELS_2; | ||
279 | case 4: | ||
280 | return OXYGEN_PLAY_CHANNELS_4; | ||
281 | case 6: | ||
282 | return OXYGEN_PLAY_CHANNELS_6; | ||
283 | case 8: | ||
284 | return OXYGEN_PLAY_CHANNELS_8; | ||
285 | } | ||
286 | } | ||
287 | |||
288 | static const unsigned int channel_base_registers[PCM_COUNT] = { | ||
289 | [PCM_A] = OXYGEN_DMA_A_ADDRESS, | ||
290 | [PCM_B] = OXYGEN_DMA_B_ADDRESS, | ||
291 | [PCM_C] = OXYGEN_DMA_C_ADDRESS, | ||
292 | [PCM_SPDIF] = OXYGEN_DMA_SPDIF_ADDRESS, | ||
293 | [PCM_MULTICH] = OXYGEN_DMA_MULTICH_ADDRESS, | ||
294 | [PCM_AC97] = OXYGEN_DMA_AC97_ADDRESS, | ||
295 | }; | ||
296 | |||
297 | static int oxygen_hw_params(struct snd_pcm_substream *substream, | ||
298 | struct snd_pcm_hw_params *hw_params) | ||
299 | { | ||
300 | struct oxygen *chip = snd_pcm_substream_chip(substream); | ||
301 | unsigned int channel = oxygen_substream_channel(substream); | ||
302 | int err; | ||
303 | |||
304 | err = snd_pcm_lib_malloc_pages(substream, | ||
305 | params_buffer_bytes(hw_params)); | ||
306 | if (err < 0) | ||
307 | return err; | ||
308 | |||
309 | oxygen_write32(chip, channel_base_registers[channel], | ||
310 | (u32)substream->runtime->dma_addr); | ||
311 | if (channel == PCM_MULTICH) { | ||
312 | oxygen_write32(chip, OXYGEN_DMA_MULTICH_COUNT, | ||
313 | params_buffer_bytes(hw_params) / 4 - 1); | ||
314 | oxygen_write32(chip, OXYGEN_DMA_MULTICH_TCOUNT, | ||
315 | params_period_bytes(hw_params) / 4 - 1); | ||
316 | } else { | ||
317 | oxygen_write16(chip, channel_base_registers[channel] + 4, | ||
318 | params_buffer_bytes(hw_params) / 4 - 1); | ||
319 | oxygen_write16(chip, channel_base_registers[channel] + 6, | ||
320 | params_period_bytes(hw_params) / 4 - 1); | ||
321 | } | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | static int oxygen_rec_a_hw_params(struct snd_pcm_substream *substream, | ||
326 | struct snd_pcm_hw_params *hw_params) | ||
327 | { | ||
328 | struct oxygen *chip = snd_pcm_substream_chip(substream); | ||
329 | int err; | ||
330 | |||
331 | err = oxygen_hw_params(substream, hw_params); | ||
332 | if (err < 0) | ||
333 | return err; | ||
334 | |||
335 | spin_lock_irq(&chip->reg_lock); | ||
336 | oxygen_write8_masked(chip, OXYGEN_REC_FORMAT, | ||
337 | oxygen_format(hw_params) << OXYGEN_REC_FORMAT_A_SHIFT, | ||
338 | OXYGEN_REC_FORMAT_A_MASK); | ||
339 | oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, | ||
340 | oxygen_rate(hw_params) | | ||
341 | oxygen_i2s_mclk(hw_params) | | ||
342 | chip->model->adc_i2s_format | | ||
343 | oxygen_i2s_bits(hw_params), | ||
344 | OXYGEN_I2S_RATE_MASK | | ||
345 | OXYGEN_I2S_FORMAT_MASK | | ||
346 | OXYGEN_I2S_MCLK_MASK | | ||
347 | OXYGEN_I2S_BITS_MASK); | ||
348 | spin_unlock_irq(&chip->reg_lock); | ||
349 | |||
350 | mutex_lock(&chip->mutex); | ||
351 | chip->model->set_adc_params(chip, hw_params); | ||
352 | mutex_unlock(&chip->mutex); | ||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | static int oxygen_rec_b_hw_params(struct snd_pcm_substream *substream, | ||
357 | struct snd_pcm_hw_params *hw_params) | ||
358 | { | ||
359 | struct oxygen *chip = snd_pcm_substream_chip(substream); | ||
360 | int is_ac97; | ||
361 | int err; | ||
362 | |||
363 | err = oxygen_hw_params(substream, hw_params); | ||
364 | if (err < 0) | ||
365 | return err; | ||
366 | |||
367 | is_ac97 = chip->has_ac97_1 && | ||
368 | (chip->model->used_channels & OXYGEN_CHANNEL_AC97); | ||
369 | |||
370 | spin_lock_irq(&chip->reg_lock); | ||
371 | oxygen_write8_masked(chip, OXYGEN_REC_FORMAT, | ||
372 | oxygen_format(hw_params) << OXYGEN_REC_FORMAT_B_SHIFT, | ||
373 | OXYGEN_REC_FORMAT_B_MASK); | ||
374 | if (!is_ac97) | ||
375 | oxygen_write16_masked(chip, OXYGEN_I2S_B_FORMAT, | ||
376 | oxygen_rate(hw_params) | | ||
377 | oxygen_i2s_mclk(hw_params) | | ||
378 | chip->model->adc_i2s_format | | ||
379 | oxygen_i2s_bits(hw_params), | ||
380 | OXYGEN_I2S_RATE_MASK | | ||
381 | OXYGEN_I2S_FORMAT_MASK | | ||
382 | OXYGEN_I2S_MCLK_MASK | | ||
383 | OXYGEN_I2S_BITS_MASK); | ||
384 | spin_unlock_irq(&chip->reg_lock); | ||
385 | |||
386 | if (!is_ac97) { | ||
387 | mutex_lock(&chip->mutex); | ||
388 | chip->model->set_adc_params(chip, hw_params); | ||
389 | mutex_unlock(&chip->mutex); | ||
390 | } | ||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static int oxygen_rec_c_hw_params(struct snd_pcm_substream *substream, | ||
395 | struct snd_pcm_hw_params *hw_params) | ||
396 | { | ||
397 | struct oxygen *chip = snd_pcm_substream_chip(substream); | ||
398 | int err; | ||
399 | |||
400 | err = oxygen_hw_params(substream, hw_params); | ||
401 | if (err < 0) | ||
402 | return err; | ||
403 | |||
404 | spin_lock_irq(&chip->reg_lock); | ||
405 | oxygen_write8_masked(chip, OXYGEN_REC_FORMAT, | ||
406 | oxygen_format(hw_params) << OXYGEN_REC_FORMAT_C_SHIFT, | ||
407 | OXYGEN_REC_FORMAT_C_MASK); | ||
408 | spin_unlock_irq(&chip->reg_lock); | ||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | static int oxygen_spdif_hw_params(struct snd_pcm_substream *substream, | ||
413 | struct snd_pcm_hw_params *hw_params) | ||
414 | { | ||
415 | struct oxygen *chip = snd_pcm_substream_chip(substream); | ||
416 | int err; | ||
417 | |||
418 | err = oxygen_hw_params(substream, hw_params); | ||
419 | if (err < 0) | ||
420 | return err; | ||
421 | |||
422 | spin_lock_irq(&chip->reg_lock); | ||
423 | oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL, | ||
424 | OXYGEN_SPDIF_OUT_ENABLE); | ||
425 | oxygen_write8_masked(chip, OXYGEN_PLAY_FORMAT, | ||
426 | oxygen_format(hw_params) << OXYGEN_SPDIF_FORMAT_SHIFT, | ||
427 | OXYGEN_SPDIF_FORMAT_MASK); | ||
428 | oxygen_write32_masked(chip, OXYGEN_SPDIF_CONTROL, | ||
429 | oxygen_rate(hw_params) << OXYGEN_SPDIF_OUT_RATE_SHIFT, | ||
430 | OXYGEN_SPDIF_OUT_RATE_MASK); | ||
431 | oxygen_update_spdif_source(chip); | ||
432 | spin_unlock_irq(&chip->reg_lock); | ||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | static int oxygen_multich_hw_params(struct snd_pcm_substream *substream, | ||
437 | struct snd_pcm_hw_params *hw_params) | ||
438 | { | ||
439 | struct oxygen *chip = snd_pcm_substream_chip(substream); | ||
440 | int err; | ||
441 | |||
442 | err = oxygen_hw_params(substream, hw_params); | ||
443 | if (err < 0) | ||
444 | return err; | ||
445 | |||
446 | spin_lock_irq(&chip->reg_lock); | ||
447 | oxygen_write8_masked(chip, OXYGEN_PLAY_CHANNELS, | ||
448 | oxygen_play_channels(hw_params), | ||
449 | OXYGEN_PLAY_CHANNELS_MASK); | ||
450 | oxygen_write8_masked(chip, OXYGEN_PLAY_FORMAT, | ||
451 | oxygen_format(hw_params) << OXYGEN_MULTICH_FORMAT_SHIFT, | ||
452 | OXYGEN_MULTICH_FORMAT_MASK); | ||
453 | oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT, | ||
454 | oxygen_rate(hw_params) | | ||
455 | chip->model->dac_i2s_format | | ||
456 | oxygen_i2s_bits(hw_params), | ||
457 | OXYGEN_I2S_RATE_MASK | | ||
458 | OXYGEN_I2S_FORMAT_MASK | | ||
459 | OXYGEN_I2S_BITS_MASK); | ||
460 | oxygen_update_dac_routing(chip); | ||
461 | oxygen_update_spdif_source(chip); | ||
462 | spin_unlock_irq(&chip->reg_lock); | ||
463 | |||
464 | mutex_lock(&chip->mutex); | ||
465 | chip->model->set_dac_params(chip, hw_params); | ||
466 | mutex_unlock(&chip->mutex); | ||
467 | return 0; | ||
468 | } | ||
469 | |||
470 | static int oxygen_hw_free(struct snd_pcm_substream *substream) | ||
471 | { | ||
472 | struct oxygen *chip = snd_pcm_substream_chip(substream); | ||
473 | unsigned int channel = oxygen_substream_channel(substream); | ||
474 | |||
475 | spin_lock_irq(&chip->reg_lock); | ||
476 | chip->interrupt_mask &= ~(1 << channel); | ||
477 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); | ||
478 | spin_unlock_irq(&chip->reg_lock); | ||
479 | |||
480 | return snd_pcm_lib_free_pages(substream); | ||
481 | } | ||
482 | |||
483 | static int oxygen_spdif_hw_free(struct snd_pcm_substream *substream) | ||
484 | { | ||
485 | struct oxygen *chip = snd_pcm_substream_chip(substream); | ||
486 | |||
487 | spin_lock_irq(&chip->reg_lock); | ||
488 | oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL, | ||
489 | OXYGEN_SPDIF_OUT_ENABLE); | ||
490 | spin_unlock_irq(&chip->reg_lock); | ||
491 | return oxygen_hw_free(substream); | ||
492 | } | ||
493 | |||
494 | static int oxygen_prepare(struct snd_pcm_substream *substream) | ||
495 | { | ||
496 | struct oxygen *chip = snd_pcm_substream_chip(substream); | ||
497 | unsigned int channel = oxygen_substream_channel(substream); | ||
498 | unsigned int channel_mask = 1 << channel; | ||
499 | |||
500 | spin_lock_irq(&chip->reg_lock); | ||
501 | oxygen_set_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); | ||
502 | oxygen_clear_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); | ||
503 | |||
504 | chip->interrupt_mask |= channel_mask; | ||
505 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); | ||
506 | spin_unlock_irq(&chip->reg_lock); | ||
507 | return 0; | ||
508 | } | ||
509 | |||
510 | static int oxygen_trigger(struct snd_pcm_substream *substream, int cmd) | ||
511 | { | ||
512 | struct oxygen *chip = snd_pcm_substream_chip(substream); | ||
513 | struct snd_pcm_substream *s; | ||
514 | unsigned int mask = 0; | ||
515 | int pausing; | ||
516 | |||
517 | switch (cmd) { | ||
518 | case SNDRV_PCM_TRIGGER_STOP: | ||
519 | case SNDRV_PCM_TRIGGER_START: | ||
520 | pausing = 0; | ||
521 | break; | ||
522 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
523 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
524 | pausing = 1; | ||
525 | break; | ||
526 | default: | ||
527 | return -EINVAL; | ||
528 | } | ||
529 | |||
530 | snd_pcm_group_for_each_entry(s, substream) { | ||
531 | if (snd_pcm_substream_chip(s) == chip) { | ||
532 | mask |= 1 << oxygen_substream_channel(s); | ||
533 | snd_pcm_trigger_done(s, substream); | ||
534 | } | ||
535 | } | ||
536 | |||
537 | spin_lock(&chip->reg_lock); | ||
538 | if (!pausing) { | ||
539 | if (cmd == SNDRV_PCM_TRIGGER_START) | ||
540 | chip->pcm_running |= mask; | ||
541 | else | ||
542 | chip->pcm_running &= ~mask; | ||
543 | oxygen_write8(chip, OXYGEN_DMA_STATUS, chip->pcm_running); | ||
544 | } else { | ||
545 | if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH) | ||
546 | oxygen_set_bits8(chip, OXYGEN_DMA_PAUSE, mask); | ||
547 | else | ||
548 | oxygen_clear_bits8(chip, OXYGEN_DMA_PAUSE, mask); | ||
549 | } | ||
550 | spin_unlock(&chip->reg_lock); | ||
551 | return 0; | ||
552 | } | ||
553 | |||
554 | static snd_pcm_uframes_t oxygen_pointer(struct snd_pcm_substream *substream) | ||
555 | { | ||
556 | struct oxygen *chip = snd_pcm_substream_chip(substream); | ||
557 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
558 | unsigned int channel = oxygen_substream_channel(substream); | ||
559 | u32 curr_addr; | ||
560 | |||
561 | /* no spinlock, this read should be atomic */ | ||
562 | curr_addr = oxygen_read32(chip, channel_base_registers[channel]); | ||
563 | return bytes_to_frames(runtime, curr_addr - (u32)runtime->dma_addr); | ||
564 | } | ||
565 | |||
566 | static struct snd_pcm_ops oxygen_rec_a_ops = { | ||
567 | .open = oxygen_rec_a_open, | ||
568 | .close = oxygen_close, | ||
569 | .ioctl = snd_pcm_lib_ioctl, | ||
570 | .hw_params = oxygen_rec_a_hw_params, | ||
571 | .hw_free = oxygen_hw_free, | ||
572 | .prepare = oxygen_prepare, | ||
573 | .trigger = oxygen_trigger, | ||
574 | .pointer = oxygen_pointer, | ||
575 | }; | ||
576 | |||
577 | static struct snd_pcm_ops oxygen_rec_b_ops = { | ||
578 | .open = oxygen_rec_b_open, | ||
579 | .close = oxygen_close, | ||
580 | .ioctl = snd_pcm_lib_ioctl, | ||
581 | .hw_params = oxygen_rec_b_hw_params, | ||
582 | .hw_free = oxygen_hw_free, | ||
583 | .prepare = oxygen_prepare, | ||
584 | .trigger = oxygen_trigger, | ||
585 | .pointer = oxygen_pointer, | ||
586 | }; | ||
587 | |||
588 | static struct snd_pcm_ops oxygen_rec_c_ops = { | ||
589 | .open = oxygen_rec_c_open, | ||
590 | .close = oxygen_close, | ||
591 | .ioctl = snd_pcm_lib_ioctl, | ||
592 | .hw_params = oxygen_rec_c_hw_params, | ||
593 | .hw_free = oxygen_hw_free, | ||
594 | .prepare = oxygen_prepare, | ||
595 | .trigger = oxygen_trigger, | ||
596 | .pointer = oxygen_pointer, | ||
597 | }; | ||
598 | |||
599 | static struct snd_pcm_ops oxygen_spdif_ops = { | ||
600 | .open = oxygen_spdif_open, | ||
601 | .close = oxygen_close, | ||
602 | .ioctl = snd_pcm_lib_ioctl, | ||
603 | .hw_params = oxygen_spdif_hw_params, | ||
604 | .hw_free = oxygen_spdif_hw_free, | ||
605 | .prepare = oxygen_prepare, | ||
606 | .trigger = oxygen_trigger, | ||
607 | .pointer = oxygen_pointer, | ||
608 | }; | ||
609 | |||
610 | static struct snd_pcm_ops oxygen_multich_ops = { | ||
611 | .open = oxygen_multich_open, | ||
612 | .close = oxygen_close, | ||
613 | .ioctl = snd_pcm_lib_ioctl, | ||
614 | .hw_params = oxygen_multich_hw_params, | ||
615 | .hw_free = oxygen_hw_free, | ||
616 | .prepare = oxygen_prepare, | ||
617 | .trigger = oxygen_trigger, | ||
618 | .pointer = oxygen_pointer, | ||
619 | }; | ||
620 | |||
621 | static struct snd_pcm_ops oxygen_ac97_ops = { | ||
622 | .open = oxygen_ac97_open, | ||
623 | .close = oxygen_close, | ||
624 | .ioctl = snd_pcm_lib_ioctl, | ||
625 | .hw_params = oxygen_hw_params, | ||
626 | .hw_free = oxygen_hw_free, | ||
627 | .prepare = oxygen_prepare, | ||
628 | .trigger = oxygen_trigger, | ||
629 | .pointer = oxygen_pointer, | ||
630 | }; | ||
631 | |||
632 | static void oxygen_pcm_free(struct snd_pcm *pcm) | ||
633 | { | ||
634 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
635 | } | ||
636 | |||
637 | int __devinit oxygen_pcm_init(struct oxygen *chip) | ||
638 | { | ||
639 | struct snd_pcm *pcm; | ||
640 | int outs, ins; | ||
641 | int err; | ||
642 | |||
643 | outs = 1; /* OXYGEN_CHANNEL_MULTICH is always used */ | ||
644 | ins = !!(chip->model->used_channels & (OXYGEN_CHANNEL_A | | ||
645 | OXYGEN_CHANNEL_B)); | ||
646 | err = snd_pcm_new(chip->card, "Analog", 0, outs, ins, &pcm); | ||
647 | if (err < 0) | ||
648 | return err; | ||
649 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &oxygen_multich_ops); | ||
650 | if (chip->model->used_channels & OXYGEN_CHANNEL_A) | ||
651 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, | ||
652 | &oxygen_rec_a_ops); | ||
653 | else if (chip->model->used_channels & OXYGEN_CHANNEL_B) | ||
654 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, | ||
655 | &oxygen_rec_b_ops); | ||
656 | pcm->private_data = chip; | ||
657 | pcm->private_free = oxygen_pcm_free; | ||
658 | strcpy(pcm->name, "Analog"); | ||
659 | snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, | ||
660 | SNDRV_DMA_TYPE_DEV, | ||
661 | snd_dma_pci_data(chip->pci), | ||
662 | 512 * 1024, 2048 * 1024); | ||
663 | if (ins) | ||
664 | snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, | ||
665 | SNDRV_DMA_TYPE_DEV, | ||
666 | snd_dma_pci_data(chip->pci), | ||
667 | 128 * 1024, 256 * 1024); | ||
668 | |||
669 | outs = !!(chip->model->used_channels & OXYGEN_CHANNEL_SPDIF); | ||
670 | ins = !!(chip->model->used_channels & OXYGEN_CHANNEL_C); | ||
671 | if (outs | ins) { | ||
672 | err = snd_pcm_new(chip->card, "Digital", 1, outs, ins, &pcm); | ||
673 | if (err < 0) | ||
674 | return err; | ||
675 | if (outs) | ||
676 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, | ||
677 | &oxygen_spdif_ops); | ||
678 | if (ins) | ||
679 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, | ||
680 | &oxygen_rec_c_ops); | ||
681 | pcm->private_data = chip; | ||
682 | pcm->private_free = oxygen_pcm_free; | ||
683 | strcpy(pcm->name, "Digital"); | ||
684 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | ||
685 | snd_dma_pci_data(chip->pci), | ||
686 | 128 * 1024, 256 * 1024); | ||
687 | } | ||
688 | |||
689 | outs = chip->has_ac97_1 && | ||
690 | (chip->model->used_channels & OXYGEN_CHANNEL_AC97); | ||
691 | ins = outs || | ||
692 | (chip->model->used_channels & (OXYGEN_CHANNEL_A | | ||
693 | OXYGEN_CHANNEL_B)) | ||
694 | == (OXYGEN_CHANNEL_A | OXYGEN_CHANNEL_B); | ||
695 | if (outs | ins) { | ||
696 | err = snd_pcm_new(chip->card, outs ? "AC97" : "Analog2", | ||
697 | 2, outs, ins, &pcm); | ||
698 | if (err < 0) | ||
699 | return err; | ||
700 | if (outs) { | ||
701 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, | ||
702 | &oxygen_ac97_ops); | ||
703 | oxygen_write8_masked(chip, OXYGEN_REC_ROUTING, | ||
704 | OXYGEN_REC_B_ROUTE_AC97_1, | ||
705 | OXYGEN_REC_B_ROUTE_MASK); | ||
706 | } | ||
707 | if (ins) | ||
708 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, | ||
709 | &oxygen_rec_b_ops); | ||
710 | pcm->private_data = chip; | ||
711 | pcm->private_free = oxygen_pcm_free; | ||
712 | strcpy(pcm->name, outs ? "Front Panel" : "Analog 2"); | ||
713 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | ||
714 | snd_dma_pci_data(chip->pci), | ||
715 | 128 * 1024, 256 * 1024); | ||
716 | } | ||
717 | return 0; | ||
718 | } | ||
diff --git a/sound/pci/oxygen/oxygen_regs.h b/sound/pci/oxygen/oxygen_regs.h new file mode 100644 index 000000000000..72de159d4567 --- /dev/null +++ b/sound/pci/oxygen/oxygen_regs.h | |||
@@ -0,0 +1,453 @@ | |||
1 | #ifndef OXYGEN_REGS_H_INCLUDED | ||
2 | #define OXYGEN_REGS_H_INCLUDED | ||
3 | |||
4 | /* recording channel A */ | ||
5 | #define OXYGEN_DMA_A_ADDRESS 0x00 /* 32-bit base address */ | ||
6 | #define OXYGEN_DMA_A_COUNT 0x04 /* buffer counter (dwords) */ | ||
7 | #define OXYGEN_DMA_A_TCOUNT 0x06 /* interrupt counter (dwords) */ | ||
8 | |||
9 | /* recording channel B */ | ||
10 | #define OXYGEN_DMA_B_ADDRESS 0x08 | ||
11 | #define OXYGEN_DMA_B_COUNT 0x0c | ||
12 | #define OXYGEN_DMA_B_TCOUNT 0x0e | ||
13 | |||
14 | /* recording channel C */ | ||
15 | #define OXYGEN_DMA_C_ADDRESS 0x10 | ||
16 | #define OXYGEN_DMA_C_COUNT 0x14 | ||
17 | #define OXYGEN_DMA_C_TCOUNT 0x16 | ||
18 | |||
19 | /* SPDIF playback channel */ | ||
20 | #define OXYGEN_DMA_SPDIF_ADDRESS 0x18 | ||
21 | #define OXYGEN_DMA_SPDIF_COUNT 0x1c | ||
22 | #define OXYGEN_DMA_SPDIF_TCOUNT 0x1e | ||
23 | |||
24 | /* multichannel playback channel */ | ||
25 | #define OXYGEN_DMA_MULTICH_ADDRESS 0x20 | ||
26 | #define OXYGEN_DMA_MULTICH_COUNT 0x24 /* 24 bits */ | ||
27 | #define OXYGEN_DMA_MULTICH_TCOUNT 0x28 /* 24 bits */ | ||
28 | |||
29 | /* AC'97 (front panel) playback channel */ | ||
30 | #define OXYGEN_DMA_AC97_ADDRESS 0x30 | ||
31 | #define OXYGEN_DMA_AC97_COUNT 0x34 | ||
32 | #define OXYGEN_DMA_AC97_TCOUNT 0x36 | ||
33 | |||
34 | /* all registers 0x00..0x36 return current position on read */ | ||
35 | |||
36 | #define OXYGEN_DMA_STATUS 0x40 /* 1 = running, 0 = stop */ | ||
37 | #define OXYGEN_CHANNEL_A 0x01 | ||
38 | #define OXYGEN_CHANNEL_B 0x02 | ||
39 | #define OXYGEN_CHANNEL_C 0x04 | ||
40 | #define OXYGEN_CHANNEL_SPDIF 0x08 | ||
41 | #define OXYGEN_CHANNEL_MULTICH 0x10 | ||
42 | #define OXYGEN_CHANNEL_AC97 0x20 | ||
43 | |||
44 | #define OXYGEN_DMA_PAUSE 0x41 /* 1 = pause */ | ||
45 | /* OXYGEN_CHANNEL_* */ | ||
46 | |||
47 | #define OXYGEN_DMA_RESET 0x42 | ||
48 | /* OXYGEN_CHANNEL_* */ | ||
49 | |||
50 | #define OXYGEN_PLAY_CHANNELS 0x43 | ||
51 | #define OXYGEN_PLAY_CHANNELS_MASK 0x03 | ||
52 | #define OXYGEN_PLAY_CHANNELS_2 0x00 | ||
53 | #define OXYGEN_PLAY_CHANNELS_4 0x01 | ||
54 | #define OXYGEN_PLAY_CHANNELS_6 0x02 | ||
55 | #define OXYGEN_PLAY_CHANNELS_8 0x03 | ||
56 | #define OXYGEN_DMA_A_BURST_MASK 0x04 | ||
57 | #define OXYGEN_DMA_A_BURST_8 0x00 /* dwords */ | ||
58 | #define OXYGEN_DMA_A_BURST_16 0x04 | ||
59 | #define OXYGEN_DMA_MULTICH_BURST_MASK 0x08 | ||
60 | #define OXYGEN_DMA_MULTICH_BURST_8 0x00 | ||
61 | #define OXYGEN_DMA_MULTICH_BURST_16 0x08 | ||
62 | |||
63 | #define OXYGEN_INTERRUPT_MASK 0x44 | ||
64 | /* OXYGEN_CHANNEL_* */ | ||
65 | #define OXYGEN_INT_SPDIF_IN_DETECT 0x0100 | ||
66 | #define OXYGEN_INT_MCU 0x0200 | ||
67 | #define OXYGEN_INT_2WIRE 0x0400 | ||
68 | #define OXYGEN_INT_GPIO 0x0800 | ||
69 | #define OXYGEN_INT_MCB 0x2000 | ||
70 | #define OXYGEN_INT_AC97 0x4000 | ||
71 | |||
72 | #define OXYGEN_INTERRUPT_STATUS 0x46 | ||
73 | /* OXYGEN_CHANNEL_* amd OXYGEN_INT_* */ | ||
74 | #define OXYGEN_INT_MIDI 0x1000 | ||
75 | |||
76 | #define OXYGEN_MISC 0x48 | ||
77 | #define OXYGEN_MISC_WRITE_PCI_SUBID 0x01 | ||
78 | #define OXYGEN_MISC_LATENCY_3F 0x02 | ||
79 | #define OXYGEN_MISC_REC_C_FROM_SPDIF 0x04 | ||
80 | #define OXYGEN_MISC_REC_B_FROM_AC97 0x08 | ||
81 | #define OXYGEN_MISC_REC_A_FROM_MULTICH 0x10 | ||
82 | #define OXYGEN_MISC_PCI_MEM_W_1_CLOCK 0x20 | ||
83 | #define OXYGEN_MISC_MIDI 0x40 | ||
84 | #define OXYGEN_MISC_CRYSTAL_MASK 0x80 | ||
85 | #define OXYGEN_MISC_CRYSTAL_24576 0x00 | ||
86 | #define OXYGEN_MISC_CRYSTAL_27 0x80 /* MHz */ | ||
87 | |||
88 | #define OXYGEN_REC_FORMAT 0x4a | ||
89 | #define OXYGEN_REC_FORMAT_A_MASK 0x03 | ||
90 | #define OXYGEN_REC_FORMAT_A_SHIFT 0 | ||
91 | #define OXYGEN_REC_FORMAT_B_MASK 0x0c | ||
92 | #define OXYGEN_REC_FORMAT_B_SHIFT 2 | ||
93 | #define OXYGEN_REC_FORMAT_C_MASK 0x30 | ||
94 | #define OXYGEN_REC_FORMAT_C_SHIFT 4 | ||
95 | #define OXYGEN_FORMAT_16 0x00 | ||
96 | #define OXYGEN_FORMAT_24 0x01 | ||
97 | #define OXYGEN_FORMAT_32 0x02 | ||
98 | |||
99 | #define OXYGEN_PLAY_FORMAT 0x4b | ||
100 | #define OXYGEN_SPDIF_FORMAT_MASK 0x03 | ||
101 | #define OXYGEN_SPDIF_FORMAT_SHIFT 0 | ||
102 | #define OXYGEN_MULTICH_FORMAT_MASK 0x0c | ||
103 | #define OXYGEN_MULTICH_FORMAT_SHIFT 2 | ||
104 | /* OXYGEN_FORMAT_* */ | ||
105 | |||
106 | #define OXYGEN_REC_CHANNELS 0x4c | ||
107 | #define OXYGEN_REC_CHANNELS_MASK 0x07 | ||
108 | #define OXYGEN_REC_CHANNELS_2_2_2 0x00 /* DMA A, B, C */ | ||
109 | #define OXYGEN_REC_CHANNELS_4_2_2 0x01 | ||
110 | #define OXYGEN_REC_CHANNELS_6_0_2 0x02 | ||
111 | #define OXYGEN_REC_CHANNELS_6_2_0 0x03 | ||
112 | #define OXYGEN_REC_CHANNELS_8_0_0 0x04 | ||
113 | |||
114 | #define OXYGEN_FUNCTION 0x50 | ||
115 | #define OXYGEN_FUNCTION_CLOCK_MASK 0x01 | ||
116 | #define OXYGEN_FUNCTION_CLOCK_PLL 0x00 | ||
117 | #define OXYGEN_FUNCTION_CLOCK_CRYSTAL 0x01 | ||
118 | #define OXYGEN_FUNCTION_RESET_CODEC 0x02 | ||
119 | #define OXYGEN_FUNCTION_RESET_POL 0x04 | ||
120 | #define OXYGEN_FUNCTION_PWDN 0x08 | ||
121 | #define OXYGEN_FUNCTION_PWDN_EN 0x10 | ||
122 | #define OXYGEN_FUNCTION_PWDN_POL 0x20 | ||
123 | #define OXYGEN_FUNCTION_2WIRE_SPI_MASK 0x40 | ||
124 | #define OXYGEN_FUNCTION_SPI 0x00 | ||
125 | #define OXYGEN_FUNCTION_2WIRE 0x40 | ||
126 | #define OXYGEN_FUNCTION_ENABLE_SPI_4_5 0x80 /* 0 = EEPROM */ | ||
127 | |||
128 | #define OXYGEN_I2S_MULTICH_FORMAT 0x60 | ||
129 | #define OXYGEN_I2S_RATE_MASK 0x0007 /* LRCK */ | ||
130 | #define OXYGEN_RATE_32000 0x0000 | ||
131 | #define OXYGEN_RATE_44100 0x0001 | ||
132 | #define OXYGEN_RATE_48000 0x0002 | ||
133 | #define OXYGEN_RATE_64000 0x0003 | ||
134 | #define OXYGEN_RATE_88200 0x0004 | ||
135 | #define OXYGEN_RATE_96000 0x0005 | ||
136 | #define OXYGEN_RATE_176400 0x0006 | ||
137 | #define OXYGEN_RATE_192000 0x0007 | ||
138 | #define OXYGEN_I2S_FORMAT_MASK 0x0008 | ||
139 | #define OXYGEN_I2S_FORMAT_I2S 0x0000 | ||
140 | #define OXYGEN_I2S_FORMAT_LJUST 0x0008 | ||
141 | #define OXYGEN_I2S_MCLK_MASK 0x0030 /* MCLK/LRCK */ | ||
142 | #define OXYGEN_I2S_MCLK_128 0x0000 | ||
143 | #define OXYGEN_I2S_MCLK_256 0x0010 | ||
144 | #define OXYGEN_I2S_MCLK_512 0x0020 | ||
145 | #define OXYGEN_I2S_BITS_MASK 0x00c0 | ||
146 | #define OXYGEN_I2S_BITS_16 0x0000 | ||
147 | #define OXYGEN_I2S_BITS_20 0x0040 | ||
148 | #define OXYGEN_I2S_BITS_24 0x0080 | ||
149 | #define OXYGEN_I2S_BITS_32 0x00c0 | ||
150 | #define OXYGEN_I2S_MASTER 0x0100 | ||
151 | #define OXYGEN_I2S_BCLK_MASK 0x0600 /* BCLK/LRCK */ | ||
152 | #define OXYGEN_I2S_BCLK_64 0x0000 | ||
153 | #define OXYGEN_I2S_BCLK_128 0x0200 | ||
154 | #define OXYGEN_I2S_BCLK_256 0x0400 | ||
155 | #define OXYGEN_I2S_MUTE_MCLK 0x0800 | ||
156 | |||
157 | #define OXYGEN_I2S_A_FORMAT 0x62 | ||
158 | #define OXYGEN_I2S_B_FORMAT 0x64 | ||
159 | #define OXYGEN_I2S_C_FORMAT 0x66 | ||
160 | /* like OXYGEN_I2S_MULTICH_FORMAT */ | ||
161 | |||
162 | #define OXYGEN_SPDIF_CONTROL 0x70 | ||
163 | #define OXYGEN_SPDIF_OUT_ENABLE 0x00000002 | ||
164 | #define OXYGEN_SPDIF_LOOPBACK 0x00000004 /* in to out */ | ||
165 | #define OXYGEN_SPDIF_SENSE_MASK 0x00000008 | ||
166 | #define OXYGEN_SPDIF_LOCK_MASK 0x00000010 | ||
167 | #define OXYGEN_SPDIF_RATE_MASK 0x00000020 | ||
168 | #define OXYGEN_SPDIF_SPDVALID 0x00000040 | ||
169 | #define OXYGEN_SPDIF_SENSE_PAR 0x00000200 | ||
170 | #define OXYGEN_SPDIF_LOCK_PAR 0x00000400 | ||
171 | #define OXYGEN_SPDIF_SENSE_STATUS 0x00000800 | ||
172 | #define OXYGEN_SPDIF_LOCK_STATUS 0x00001000 | ||
173 | #define OXYGEN_SPDIF_SENSE_INT 0x00002000 /* r/wc */ | ||
174 | #define OXYGEN_SPDIF_LOCK_INT 0x00004000 /* r/wc */ | ||
175 | #define OXYGEN_SPDIF_RATE_INT 0x00008000 /* r/wc */ | ||
176 | #define OXYGEN_SPDIF_IN_CLOCK_MASK 0x00010000 | ||
177 | #define OXYGEN_SPDIF_IN_CLOCK_96 0x00000000 /* <= 96 kHz */ | ||
178 | #define OXYGEN_SPDIF_IN_CLOCK_192 0x00010000 /* > 96 kHz */ | ||
179 | #define OXYGEN_SPDIF_OUT_RATE_MASK 0x07000000 | ||
180 | #define OXYGEN_SPDIF_OUT_RATE_SHIFT 24 | ||
181 | /* OXYGEN_RATE_* << OXYGEN_SPDIF_OUT_RATE_SHIFT */ | ||
182 | |||
183 | #define OXYGEN_SPDIF_OUTPUT_BITS 0x74 | ||
184 | #define OXYGEN_SPDIF_NONAUDIO 0x00000002 | ||
185 | #define OXYGEN_SPDIF_C 0x00000004 | ||
186 | #define OXYGEN_SPDIF_PREEMPHASIS 0x00000008 | ||
187 | #define OXYGEN_SPDIF_CATEGORY_MASK 0x000007f0 | ||
188 | #define OXYGEN_SPDIF_CATEGORY_SHIFT 4 | ||
189 | #define OXYGEN_SPDIF_ORIGINAL 0x00000800 | ||
190 | #define OXYGEN_SPDIF_CS_RATE_MASK 0x0000f000 | ||
191 | #define OXYGEN_SPDIF_CS_RATE_SHIFT 12 | ||
192 | #define OXYGEN_SPDIF_V 0x00010000 /* 0 = valid */ | ||
193 | |||
194 | #define OXYGEN_SPDIF_INPUT_BITS 0x78 | ||
195 | /* 32 bits, IEC958_AES_* */ | ||
196 | |||
197 | #define OXYGEN_EEPROM_CONTROL 0x80 | ||
198 | #define OXYGEN_EEPROM_ADDRESS_MASK 0x7f | ||
199 | #define OXYGEN_EEPROM_DIR_MASK 0x80 | ||
200 | #define OXYGEN_EEPROM_DIR_READ 0x00 | ||
201 | #define OXYGEN_EEPROM_DIR_WRITE 0x80 | ||
202 | |||
203 | #define OXYGEN_EEPROM_STATUS 0x81 | ||
204 | #define OXYGEN_EEPROM_VALID 0x40 | ||
205 | #define OXYGEN_EEPROM_BUSY 0x80 | ||
206 | |||
207 | #define OXYGEN_EEPROM_DATA 0x82 /* 16 bits */ | ||
208 | |||
209 | #define OXYGEN_2WIRE_CONTROL 0x90 | ||
210 | #define OXYGEN_2WIRE_DIR_MASK 0x01 | ||
211 | #define OXYGEN_2WIRE_DIR_WRITE 0x00 | ||
212 | #define OXYGEN_2WIRE_DIR_READ 0x01 | ||
213 | #define OXYGEN_2WIRE_ADDRESS_MASK 0xfe /* slave device address */ | ||
214 | #define OXYGEN_2WIRE_ADDRESS_SHIFT 1 | ||
215 | |||
216 | #define OXYGEN_2WIRE_MAP 0x91 /* address, 8 bits */ | ||
217 | #define OXYGEN_2WIRE_DATA 0x92 /* data, 16 bits */ | ||
218 | |||
219 | #define OXYGEN_2WIRE_BUS_STATUS 0x94 | ||
220 | #define OXYGEN_2WIRE_BUSY 0x0001 | ||
221 | #define OXYGEN_2WIRE_LENGTH_MASK 0x0002 | ||
222 | #define OXYGEN_2WIRE_LENGTH_8 0x0000 | ||
223 | #define OXYGEN_2WIRE_LENGTH_16 0x0002 | ||
224 | #define OXYGEN_2WIRE_MANUAL_READ 0x0004 /* 0 = auto read */ | ||
225 | #define OXYGEN_2WIRE_WRITE_MAP_ONLY 0x0008 | ||
226 | #define OXYGEN_2WIRE_SLAVE_AD_MASK 0x0030 /* AD0, AD1 */ | ||
227 | #define OXYGEN_2WIRE_INTERRUPT_MASK 0x0040 /* 0 = int. if not responding */ | ||
228 | #define OXYGEN_2WIRE_SLAVE_NO_RESPONSE 0x0080 | ||
229 | #define OXYGEN_2WIRE_SPEED_MASK 0x0100 | ||
230 | #define OXYGEN_2WIRE_SPEED_STANDARD 0x0000 | ||
231 | #define OXYGEN_2WIRE_SPEED_FAST 0x0100 | ||
232 | #define OXYGEN_2WIRE_CLOCK_SYNC 0x0200 | ||
233 | #define OXYGEN_2WIRE_BUS_RESET 0x0400 | ||
234 | |||
235 | #define OXYGEN_SPI_CONTROL 0x98 | ||
236 | #define OXYGEN_SPI_BUSY 0x01 /* read */ | ||
237 | #define OXYGEN_SPI_TRIGGER 0x01 /* write */ | ||
238 | #define OXYGEN_SPI_DATA_LENGTH_MASK 0x02 | ||
239 | #define OXYGEN_SPI_DATA_LENGTH_2 0x00 | ||
240 | #define OXYGEN_SPI_DATA_LENGTH_3 0x02 | ||
241 | #define OXYGEN_SPI_CLOCK_MASK 0xc0 | ||
242 | #define OXYGEN_SPI_CLOCK_160 0x00 /* ns */ | ||
243 | #define OXYGEN_SPI_CLOCK_320 0x40 | ||
244 | #define OXYGEN_SPI_CLOCK_640 0x80 | ||
245 | #define OXYGEN_SPI_CLOCK_1280 0xc0 | ||
246 | #define OXYGEN_SPI_CODEC_MASK 0x70 /* 0..5 */ | ||
247 | #define OXYGEN_SPI_CODEC_SHIFT 4 | ||
248 | #define OXYGEN_SPI_CEN_MASK 0x80 | ||
249 | #define OXYGEN_SPI_CEN_LATCH_CLOCK_LO 0x00 | ||
250 | #define OXYGEN_SPI_CEN_LATCH_CLOCK_HI 0x80 | ||
251 | |||
252 | #define OXYGEN_SPI_DATA1 0x99 | ||
253 | #define OXYGEN_SPI_DATA2 0x9a | ||
254 | #define OXYGEN_SPI_DATA3 0x9b | ||
255 | |||
256 | #define OXYGEN_MPU401 0xa0 | ||
257 | |||
258 | #define OXYGEN_MPU401_CONTROL 0xa2 | ||
259 | #define OXYGEN_MPU401_LOOPBACK 0x01 /* TXD to RXD */ | ||
260 | |||
261 | #define OXYGEN_GPI_DATA 0xa4 | ||
262 | /* bits 0..5 = pin XGPI0..XGPI5 */ | ||
263 | |||
264 | #define OXYGEN_GPI_INTERRUPT_MASK 0xa5 | ||
265 | /* bits 0..5, 1 = enable */ | ||
266 | |||
267 | #define OXYGEN_GPIO_DATA 0xa6 | ||
268 | /* bits 0..9 */ | ||
269 | |||
270 | #define OXYGEN_GPIO_CONTROL 0xa8 | ||
271 | /* bits 0..9, 0 = input, 1 = output */ | ||
272 | #define OXYGEN_GPIO1_XSLAVE_RDY 0x8000 | ||
273 | |||
274 | #define OXYGEN_GPIO_INTERRUPT_MASK 0xaa | ||
275 | /* bits 0..9, 1 = enable */ | ||
276 | |||
277 | #define OXYGEN_DEVICE_SENSE 0xac | ||
278 | #define OXYGEN_HEAD_PHONE_DETECT 0x01 | ||
279 | #define OXYGEN_HEAD_PHONE_MASK 0x06 | ||
280 | #define OXYGEN_HEAD_PHONE_PASSIVE_SPK 0x00 | ||
281 | #define OXYGEN_HEAD_PHONE_HP 0x02 | ||
282 | #define OXYGEN_HEAD_PHONE_ACTIVE_SPK 0x04 | ||
283 | |||
284 | #define OXYGEN_MCU_2WIRE_DATA 0xb0 | ||
285 | |||
286 | #define OXYGEN_MCU_2WIRE_MAP 0xb2 | ||
287 | |||
288 | #define OXYGEN_MCU_2WIRE_STATUS 0xb3 | ||
289 | #define OXYGEN_MCU_2WIRE_BUSY 0x01 | ||
290 | #define OXYGEN_MCU_2WIRE_LENGTH_MASK 0x06 | ||
291 | #define OXYGEN_MCU_2WIRE_LENGTH_1 0x00 | ||
292 | #define OXYGEN_MCU_2WIRE_LENGTH_2 0x02 | ||
293 | #define OXYGEN_MCU_2WIRE_LENGTH_3 0x04 | ||
294 | #define OXYGEN_MCU_2WIRE_WRITE 0x08 /* r/wc */ | ||
295 | #define OXYGEN_MCU_2WIRE_READ 0x10 /* r/wc */ | ||
296 | #define OXYGEN_MCU_2WIRE_DRV_XACT_FAIL 0x20 /* r/wc */ | ||
297 | #define OXYGEN_MCU_2WIRE_RESET 0x40 | ||
298 | |||
299 | #define OXYGEN_MCU_2WIRE_CONTROL 0xb4 | ||
300 | #define OXYGEN_MCU_2WIRE_DRV_ACK 0x01 | ||
301 | #define OXYGEN_MCU_2WIRE_DRV_XACT 0x02 | ||
302 | #define OXYGEN_MCU_2WIRE_INT_MASK 0x04 | ||
303 | #define OXYGEN_MCU_2WIRE_SYNC_MASK 0x08 | ||
304 | #define OXYGEN_MCU_2WIRE_SYNC_RDY_PIN 0x00 | ||
305 | #define OXYGEN_MCU_2WIRE_SYNC_DATA 0x08 | ||
306 | #define OXYGEN_MCU_2WIRE_ADDRESS_MASK 0x30 | ||
307 | #define OXYGEN_MCU_2WIRE_ADDRESS_10 0x00 | ||
308 | #define OXYGEN_MCU_2WIRE_ADDRESS_12 0x10 | ||
309 | #define OXYGEN_MCU_2WIRE_ADDRESS_14 0x20 | ||
310 | #define OXYGEN_MCU_2WIRE_ADDRESS_16 0x30 | ||
311 | #define OXYGEN_MCU_2WIRE_INT_POL 0x40 | ||
312 | #define OXYGEN_MCU_2WIRE_SYNC_ENABLE 0x80 | ||
313 | |||
314 | #define OXYGEN_PLAY_ROUTING 0xc0 | ||
315 | #define OXYGEN_PLAY_MUTE01 0x0001 | ||
316 | #define OXYGEN_PLAY_MUTE23 0x0002 | ||
317 | #define OXYGEN_PLAY_MUTE45 0x0004 | ||
318 | #define OXYGEN_PLAY_MUTE67 0x0008 | ||
319 | #define OXYGEN_PLAY_MULTICH_MASK 0x0010 | ||
320 | #define OXYGEN_PLAY_MULTICH_I2S_DAC 0x0000 | ||
321 | #define OXYGEN_PLAY_MULTICH_AC97 0x0010 | ||
322 | #define OXYGEN_PLAY_SPDIF_MASK 0x00e0 | ||
323 | #define OXYGEN_PLAY_SPDIF_SPDIF 0x0000 | ||
324 | #define OXYGEN_PLAY_SPDIF_MULTICH_01 0x0020 | ||
325 | #define OXYGEN_PLAY_SPDIF_MULTICH_23 0x0040 | ||
326 | #define OXYGEN_PLAY_SPDIF_MULTICH_45 0x0060 | ||
327 | #define OXYGEN_PLAY_SPDIF_MULTICH_67 0x0080 | ||
328 | #define OXYGEN_PLAY_SPDIF_REC_A 0x00a0 | ||
329 | #define OXYGEN_PLAY_SPDIF_REC_B 0x00c0 | ||
330 | #define OXYGEN_PLAY_SPDIF_I2S_ADC_3 0x00e0 | ||
331 | #define OXYGEN_PLAY_DAC0_SOURCE_MASK 0x0300 | ||
332 | #define OXYGEN_PLAY_DAC0_SOURCE_SHIFT 8 | ||
333 | #define OXYGEN_PLAY_DAC1_SOURCE_MASK 0x0c00 | ||
334 | #define OXYGEN_PLAY_DAC1_SOURCE_SHIFT 10 | ||
335 | #define OXYGEN_PLAY_DAC2_SOURCE_MASK 0x3000 | ||
336 | #define OXYGEN_PLAY_DAC2_SOURCE_SHIFT 12 | ||
337 | #define OXYGEN_PLAY_DAC3_SOURCE_MASK 0xc000 | ||
338 | #define OXYGEN_PLAY_DAC3_SOURCE_SHIFT 14 | ||
339 | |||
340 | #define OXYGEN_REC_ROUTING 0xc2 | ||
341 | #define OXYGEN_MUTE_I2S_ADC_1 0x01 | ||
342 | #define OXYGEN_MUTE_I2S_ADC_2 0x02 | ||
343 | #define OXYGEN_MUTE_I2S_ADC_3 0x04 | ||
344 | #define OXYGEN_REC_A_ROUTE_MASK 0x08 | ||
345 | #define OXYGEN_REC_A_ROUTE_I2S_ADC_1 0x00 | ||
346 | #define OXYGEN_REC_A_ROUTE_AC97_0 0x08 | ||
347 | #define OXYGEN_REC_B_ROUTE_MASK 0x10 | ||
348 | #define OXYGEN_REC_B_ROUTE_I2S_ADC_2 0x00 | ||
349 | #define OXYGEN_REC_B_ROUTE_AC97_1 0x10 | ||
350 | #define OXYGEN_REC_C_ROUTE_MASK 0x20 | ||
351 | #define OXYGEN_REC_C_ROUTE_SPDIF 0x00 | ||
352 | #define OXYGEN_REC_C_ROUTE_I2S_ADC_3 0x20 | ||
353 | |||
354 | #define OXYGEN_ADC_MONITOR 0xc3 | ||
355 | #define OXYGEN_ADC_MONITOR_A 0x01 | ||
356 | #define OXYGEN_ADC_MONITOR_A_HALF_VOL 0x02 | ||
357 | #define OXYGEN_ADC_MONITOR_B 0x04 | ||
358 | #define OXYGEN_ADC_MONITOR_B_HALF_VOL 0x08 | ||
359 | #define OXYGEN_ADC_MONITOR_C 0x10 | ||
360 | #define OXYGEN_ADC_MONITOR_C_HALF_VOL 0x20 | ||
361 | |||
362 | #define OXYGEN_A_MONITOR_ROUTING 0xc4 | ||
363 | #define OXYGEN_A_MONITOR_ROUTE_0_MASK 0x03 | ||
364 | #define OXYGEN_A_MONITOR_ROUTE_0_SHIFT 0 | ||
365 | #define OXYGEN_A_MONITOR_ROUTE_1_MASK 0x0c | ||
366 | #define OXYGEN_A_MONITOR_ROUTE_1_SHIFT 2 | ||
367 | #define OXYGEN_A_MONITOR_ROUTE_2_MASK 0x30 | ||
368 | #define OXYGEN_A_MONITOR_ROUTE_2_SHIFT 4 | ||
369 | #define OXYGEN_A_MONITOR_ROUTE_3_MASK 0xc0 | ||
370 | #define OXYGEN_A_MONITOR_ROUTE_3_SHIFT 6 | ||
371 | |||
372 | #define OXYGEN_AC97_CONTROL 0xd0 | ||
373 | #define OXYGEN_AC97_COLD_RESET 0x0001 | ||
374 | #define OXYGEN_AC97_SUSPENDED 0x0002 /* read */ | ||
375 | #define OXYGEN_AC97_RESUME 0x0002 /* write */ | ||
376 | #define OXYGEN_AC97_CLOCK_DISABLE 0x0004 | ||
377 | #define OXYGEN_AC97_NO_CODEC_0 0x0008 | ||
378 | #define OXYGEN_AC97_CODEC_0 0x0010 | ||
379 | #define OXYGEN_AC97_CODEC_1 0x0020 | ||
380 | |||
381 | #define OXYGEN_AC97_INTERRUPT_MASK 0xd2 | ||
382 | #define OXYGEN_AC97_INT_READ_DONE 0x01 | ||
383 | #define OXYGEN_AC97_INT_WRITE_DONE 0x02 | ||
384 | #define OXYGEN_AC97_INT_CODEC_0 0x10 | ||
385 | #define OXYGEN_AC97_INT_CODEC_1 0x20 | ||
386 | |||
387 | #define OXYGEN_AC97_INTERRUPT_STATUS 0xd3 | ||
388 | /* OXYGEN_AC97_INT_* */ | ||
389 | |||
390 | #define OXYGEN_AC97_OUT_CONFIG 0xd4 | ||
391 | #define OXYGEN_AC97_CODEC1_SLOT3 0x00000001 | ||
392 | #define OXYGEN_AC97_CODEC1_SLOT3_VSR 0x00000002 | ||
393 | #define OXYGEN_AC97_CODEC1_SLOT4 0x00000010 | ||
394 | #define OXYGEN_AC97_CODEC1_SLOT4_VSR 0x00000020 | ||
395 | #define OXYGEN_AC97_CODEC0_FRONTL 0x00000100 | ||
396 | #define OXYGEN_AC97_CODEC0_FRONTR 0x00000200 | ||
397 | #define OXYGEN_AC97_CODEC0_SIDEL 0x00000400 | ||
398 | #define OXYGEN_AC97_CODEC0_SIDER 0x00000800 | ||
399 | #define OXYGEN_AC97_CODEC0_CENTER 0x00001000 | ||
400 | #define OXYGEN_AC97_CODEC0_BASE 0x00002000 | ||
401 | #define OXYGEN_AC97_CODEC0_REARL 0x00004000 | ||
402 | #define OXYGEN_AC97_CODEC0_REARR 0x00008000 | ||
403 | |||
404 | #define OXYGEN_AC97_IN_CONFIG 0xd8 | ||
405 | #define OXYGEN_AC97_CODEC1_LINEL 0x00000001 | ||
406 | #define OXYGEN_AC97_CODEC1_LINEL_VSR 0x00000002 | ||
407 | #define OXYGEN_AC97_CODEC1_LINEL_16 0x00000000 | ||
408 | #define OXYGEN_AC97_CODEC1_LINEL_18 0x00000004 | ||
409 | #define OXYGEN_AC97_CODEC1_LINEL_20 0x00000008 | ||
410 | #define OXYGEN_AC97_CODEC1_LINER 0x00000010 | ||
411 | #define OXYGEN_AC97_CODEC1_LINER_VSR 0x00000020 | ||
412 | #define OXYGEN_AC97_CODEC1_LINER_16 0x00000000 | ||
413 | #define OXYGEN_AC97_CODEC1_LINER_18 0x00000040 | ||
414 | #define OXYGEN_AC97_CODEC1_LINER_20 0x00000080 | ||
415 | #define OXYGEN_AC97_CODEC0_LINEL 0x00000100 | ||
416 | #define OXYGEN_AC97_CODEC0_LINER 0x00000200 | ||
417 | |||
418 | #define OXYGEN_AC97_REGS 0xdc | ||
419 | #define OXYGEN_AC97_REG_DATA_MASK 0x0000ffff | ||
420 | #define OXYGEN_AC97_REG_ADDR_MASK 0x007f0000 | ||
421 | #define OXYGEN_AC97_REG_ADDR_SHIFT 16 | ||
422 | #define OXYGEN_AC97_REG_DIR_MASK 0x00800000 | ||
423 | #define OXYGEN_AC97_REG_DIR_WRITE 0x00000000 | ||
424 | #define OXYGEN_AC97_REG_DIR_READ 0x00800000 | ||
425 | #define OXYGEN_AC97_REG_CODEC_MASK 0x01000000 | ||
426 | #define OXYGEN_AC97_REG_CODEC_SHIFT 24 | ||
427 | |||
428 | #define OXYGEN_TEST 0xe0 | ||
429 | #define OXYGEN_TEST_RAM_SUCCEEDED 0x01 | ||
430 | #define OXYGEN_TEST_PLAYBACK_RAM 0x02 | ||
431 | #define OXYGEN_TEST_RECORD_RAM 0x04 | ||
432 | #define OXYGEN_TEST_PLL 0x08 | ||
433 | #define OXYGEN_TEST_2WIRE_LOOPBACK 0x10 | ||
434 | |||
435 | #define OXYGEN_DMA_FLUSH 0xe1 | ||
436 | /* OXYGEN_CHANNEL_* */ | ||
437 | |||
438 | #define OXYGEN_CODEC_VERSION 0xe4 | ||
439 | #define OXYGEN_XCID_MASK 0x07 | ||
440 | |||
441 | #define OXYGEN_REVISION 0xe6 | ||
442 | #define OXYGEN_REVISION_XPKGID_MASK 0x0007 | ||
443 | #define OXYGEN_REVISION_MASK 0xfff8 | ||
444 | #define OXYGEN_REVISION_2 0x0008 /* bit flag */ | ||
445 | #define OXYGEN_REVISION_8787 0x0014 /* 8 bits */ | ||
446 | |||
447 | #define OXYGEN_OFFSIN_48K 0xe8 | ||
448 | #define OXYGEN_OFFSBASE_48K 0xe9 | ||
449 | #define OXYGEN_OFFSBASE_MASK 0x0fff | ||
450 | #define OXYGEN_OFFSIN_44K 0xec | ||
451 | #define OXYGEN_OFFSBASE_44K 0xed | ||
452 | |||
453 | #endif | ||
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c new file mode 100644 index 000000000000..40e92f5cd69c --- /dev/null +++ b/sound/pci/oxygen/virtuoso.c | |||
@@ -0,0 +1,449 @@ | |||
1 | /* | ||
2 | * C-Media CMI8788 driver for Asus Xonar cards | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * | ||
6 | * | ||
7 | * This driver is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License, version 2. | ||
9 | * | ||
10 | * This driver is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this driver; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | /* | ||
21 | * CMI8788: | ||
22 | * | ||
23 | * SPI 0 -> 1st PCM1796 (front) | ||
24 | * SPI 1 -> 2nd PCM1796 (surround) | ||
25 | * SPI 2 -> 3rd PCM1796 (center/LFE) | ||
26 | * SPI 4 -> 4th PCM1796 (back) | ||
27 | * | ||
28 | * GPIO 2 -> M0 of CS5381 | ||
29 | * GPIO 3 -> M1 of CS5381 | ||
30 | * GPIO 5 <- external power present (D2X only) | ||
31 | * GPIO 7 -> ALT | ||
32 | * GPIO 8 -> enable output to speakers | ||
33 | * | ||
34 | * CM9780: | ||
35 | * | ||
36 | * GPIO 0 -> enable AC'97 bypass (line in -> ADC) | ||
37 | */ | ||
38 | |||
39 | #include <linux/pci.h> | ||
40 | #include <linux/delay.h> | ||
41 | #include <linux/mutex.h> | ||
42 | #include <sound/ac97_codec.h> | ||
43 | #include <sound/control.h> | ||
44 | #include <sound/core.h> | ||
45 | #include <sound/initval.h> | ||
46 | #include <sound/pcm.h> | ||
47 | #include <sound/tlv.h> | ||
48 | #include "oxygen.h" | ||
49 | #include "cm9780.h" | ||
50 | |||
51 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | ||
52 | MODULE_DESCRIPTION("Asus AV200 driver"); | ||
53 | MODULE_LICENSE("GPL"); | ||
54 | MODULE_SUPPORTED_DEVICE("{{Asus,AV200}}"); | ||
55 | |||
56 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | ||
57 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | ||
58 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | ||
59 | |||
60 | module_param_array(index, int, NULL, 0444); | ||
61 | MODULE_PARM_DESC(index, "card index"); | ||
62 | module_param_array(id, charp, NULL, 0444); | ||
63 | MODULE_PARM_DESC(id, "ID string"); | ||
64 | module_param_array(enable, bool, NULL, 0444); | ||
65 | MODULE_PARM_DESC(enable, "enable card"); | ||
66 | |||
67 | static struct pci_device_id xonar_ids[] __devinitdata = { | ||
68 | { OXYGEN_PCI_SUBID(0x1043, 0x8269) }, /* Asus Xonar D2 */ | ||
69 | { OXYGEN_PCI_SUBID(0x1043, 0x82b7) }, /* Asus Xonar D2X */ | ||
70 | { } | ||
71 | }; | ||
72 | MODULE_DEVICE_TABLE(pci, xonar_ids); | ||
73 | |||
74 | |||
75 | #define GPIO_CS5381_M_MASK 0x000c | ||
76 | #define GPIO_CS5381_M_SINGLE 0x0000 | ||
77 | #define GPIO_CS5381_M_DOUBLE 0x0004 | ||
78 | #define GPIO_CS5381_M_QUAD 0x0008 | ||
79 | #define GPIO_EXT_POWER 0x0020 | ||
80 | #define GPIO_ALT 0x0080 | ||
81 | #define GPIO_OUTPUT_ENABLE 0x0100 | ||
82 | |||
83 | #define GPIO_LINE_MUTE CM9780_GPO0 | ||
84 | |||
85 | /* register 16 */ | ||
86 | #define PCM1796_ATL_MASK 0xff | ||
87 | /* register 17 */ | ||
88 | #define PCM1796_ATR_MASK 0xff | ||
89 | /* register 18 */ | ||
90 | #define PCM1796_MUTE 0x01 | ||
91 | #define PCM1796_DME 0x02 | ||
92 | #define PCM1796_DMF_MASK 0x0c | ||
93 | #define PCM1796_DMF_DISABLED 0x00 | ||
94 | #define PCM1796_DMF_48 0x04 | ||
95 | #define PCM1796_DMF_441 0x08 | ||
96 | #define PCM1796_DMF_32 0x0c | ||
97 | #define PCM1796_FMT_MASK 0x70 | ||
98 | #define PCM1796_FMT_16_RJUST 0x00 | ||
99 | #define PCM1796_FMT_20_RJUST 0x10 | ||
100 | #define PCM1796_FMT_24_RJUST 0x20 | ||
101 | #define PCM1796_FMT_24_LJUST 0x30 | ||
102 | #define PCM1796_FMT_16_I2S 0x40 | ||
103 | #define PCM1796_FMT_24_I2S 0x50 | ||
104 | #define PCM1796_ATLD 0x80 | ||
105 | /* register 19 */ | ||
106 | #define PCM1796_INZD 0x01 | ||
107 | #define PCM1796_FLT_MASK 0x02 | ||
108 | #define PCM1796_FLT_SHARP 0x00 | ||
109 | #define PCM1796_FLT_SLOW 0x02 | ||
110 | #define PCM1796_DFMS 0x04 | ||
111 | #define PCM1796_OPE 0x10 | ||
112 | #define PCM1796_ATS_MASK 0x60 | ||
113 | #define PCM1796_ATS_1 0x00 | ||
114 | #define PCM1796_ATS_2 0x20 | ||
115 | #define PCM1796_ATS_4 0x40 | ||
116 | #define PCM1796_ATS_8 0x60 | ||
117 | #define PCM1796_REV 0x80 | ||
118 | /* register 20 */ | ||
119 | #define PCM1796_OS_MASK 0x03 | ||
120 | #define PCM1796_OS_64 0x00 | ||
121 | #define PCM1796_OS_32 0x01 | ||
122 | #define PCM1796_OS_128 0x02 | ||
123 | #define PCM1796_CHSL_MASK 0x04 | ||
124 | #define PCM1796_CHSL_LEFT 0x00 | ||
125 | #define PCM1796_CHSL_RIGHT 0x04 | ||
126 | #define PCM1796_MONO 0x08 | ||
127 | #define PCM1796_DFTH 0x10 | ||
128 | #define PCM1796_DSD 0x20 | ||
129 | #define PCM1796_SRST 0x40 | ||
130 | /* register 21 */ | ||
131 | #define PCM1796_PCMZ 0x01 | ||
132 | #define PCM1796_DZ_MASK 0x06 | ||
133 | /* register 22 */ | ||
134 | #define PCM1796_ZFGL 0x01 | ||
135 | #define PCM1796_ZFGR 0x02 | ||
136 | /* register 23 */ | ||
137 | #define PCM1796_ID_MASK 0x1f | ||
138 | |||
139 | struct xonar_data { | ||
140 | u8 is_d2x; | ||
141 | u8 has_power; | ||
142 | }; | ||
143 | |||
144 | static void pcm1796_write(struct oxygen *chip, unsigned int codec, | ||
145 | u8 reg, u8 value) | ||
146 | { | ||
147 | /* maps ALSA channel pair number to SPI output */ | ||
148 | static const u8 codec_map[4] = { | ||
149 | 0, 1, 2, 4 | ||
150 | }; | ||
151 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | | ||
152 | OXYGEN_SPI_DATA_LENGTH_2 | | ||
153 | OXYGEN_SPI_CLOCK_160 | | ||
154 | (codec_map[codec] << OXYGEN_SPI_CODEC_SHIFT) | | ||
155 | OXYGEN_SPI_CEN_LATCH_CLOCK_HI, | ||
156 | (reg << 8) | value); | ||
157 | } | ||
158 | |||
159 | static void xonar_init(struct oxygen *chip) | ||
160 | { | ||
161 | struct xonar_data *data = chip->model_data; | ||
162 | unsigned int i; | ||
163 | |||
164 | data->is_d2x = chip->pci->subsystem_device == 0x82b7; | ||
165 | |||
166 | for (i = 0; i < 4; ++i) { | ||
167 | pcm1796_write(chip, i, 18, PCM1796_FMT_24_LJUST | PCM1796_ATLD); | ||
168 | pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1); | ||
169 | pcm1796_write(chip, i, 20, PCM1796_OS_64); | ||
170 | pcm1796_write(chip, i, 21, 0); | ||
171 | pcm1796_write(chip, i, 16, 0xff); /* set ATL/ATR after ATLD */ | ||
172 | pcm1796_write(chip, i, 17, 0xff); | ||
173 | } | ||
174 | |||
175 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, | ||
176 | GPIO_CS5381_M_MASK | GPIO_ALT); | ||
177 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, | ||
178 | GPIO_CS5381_M_SINGLE, | ||
179 | GPIO_CS5381_M_MASK | GPIO_ALT); | ||
180 | if (data->is_d2x) { | ||
181 | oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, | ||
182 | GPIO_EXT_POWER); | ||
183 | oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, | ||
184 | GPIO_EXT_POWER); | ||
185 | chip->interrupt_mask |= OXYGEN_INT_GPIO; | ||
186 | data->has_power = !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) | ||
187 | & GPIO_EXT_POWER); | ||
188 | } | ||
189 | oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC); | ||
190 | oxygen_ac97_clear_bits(chip, 0, CM9780_GPIO_STATUS, GPIO_LINE_MUTE); | ||
191 | msleep(300); | ||
192 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_OUTPUT_ENABLE); | ||
193 | oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE); | ||
194 | |||
195 | snd_component_add(chip->card, "PCM1796"); | ||
196 | snd_component_add(chip->card, "CS5381"); | ||
197 | } | ||
198 | |||
199 | static void xonar_cleanup(struct oxygen *chip) | ||
200 | { | ||
201 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE); | ||
202 | } | ||
203 | |||
204 | static void set_pcm1796_params(struct oxygen *chip, | ||
205 | struct snd_pcm_hw_params *params) | ||
206 | { | ||
207 | #if 0 | ||
208 | unsigned int i; | ||
209 | u8 value; | ||
210 | |||
211 | value = params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64; | ||
212 | for (i = 0; i < 4; ++i) | ||
213 | pcm1796_write(chip, i, 20, value); | ||
214 | #endif | ||
215 | } | ||
216 | |||
217 | static void update_pcm1796_volume(struct oxygen *chip) | ||
218 | { | ||
219 | unsigned int i; | ||
220 | |||
221 | for (i = 0; i < 4; ++i) { | ||
222 | pcm1796_write(chip, i, 16, chip->dac_volume[i * 2]); | ||
223 | pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1]); | ||
224 | } | ||
225 | } | ||
226 | |||
227 | static void update_pcm1796_mute(struct oxygen *chip) | ||
228 | { | ||
229 | unsigned int i; | ||
230 | u8 value; | ||
231 | |||
232 | value = PCM1796_FMT_24_LJUST | PCM1796_ATLD; | ||
233 | if (chip->dac_mute) | ||
234 | value |= PCM1796_MUTE; | ||
235 | for (i = 0; i < 4; ++i) | ||
236 | pcm1796_write(chip, i, 18, value); | ||
237 | } | ||
238 | |||
239 | static void set_cs5381_params(struct oxygen *chip, | ||
240 | struct snd_pcm_hw_params *params) | ||
241 | { | ||
242 | unsigned int value; | ||
243 | |||
244 | if (params_rate(params) <= 54000) | ||
245 | value = GPIO_CS5381_M_SINGLE; | ||
246 | else if (params_rate(params) <= 108000) | ||
247 | value = GPIO_CS5381_M_DOUBLE; | ||
248 | else | ||
249 | value = GPIO_CS5381_M_QUAD; | ||
250 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, | ||
251 | value, GPIO_CS5381_M_MASK); | ||
252 | } | ||
253 | |||
254 | static void xonar_gpio_changed(struct oxygen *chip) | ||
255 | { | ||
256 | struct xonar_data *data = chip->model_data; | ||
257 | u8 has_power; | ||
258 | |||
259 | if (!data->is_d2x) | ||
260 | return; | ||
261 | has_power = !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) | ||
262 | & GPIO_EXT_POWER); | ||
263 | if (has_power != data->has_power) { | ||
264 | data->has_power = has_power; | ||
265 | if (has_power) { | ||
266 | snd_printk(KERN_NOTICE "power restored\n"); | ||
267 | } else { | ||
268 | snd_printk(KERN_CRIT | ||
269 | "Hey! Don't unplug the power cable!\n"); | ||
270 | /* TODO: stop PCMs */ | ||
271 | } | ||
272 | } | ||
273 | } | ||
274 | |||
275 | static void mute_ac97_ctl(struct oxygen *chip, unsigned int control) | ||
276 | { | ||
277 | unsigned int index = chip->controls[control]->private_value & 0xff; | ||
278 | u16 value; | ||
279 | |||
280 | value = oxygen_read_ac97(chip, 0, index); | ||
281 | if (!(value & 0x8000)) { | ||
282 | oxygen_write_ac97(chip, 0, index, value | 0x8000); | ||
283 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
284 | &chip->controls[control]->id); | ||
285 | } | ||
286 | } | ||
287 | |||
288 | static void xonar_ac97_switch_hook(struct oxygen *chip, unsigned int codec, | ||
289 | unsigned int reg, int mute) | ||
290 | { | ||
291 | if (codec != 0) | ||
292 | return; | ||
293 | /* line-in is exclusive */ | ||
294 | switch (reg) { | ||
295 | case AC97_LINE: | ||
296 | oxygen_write_ac97_masked(chip, 0, CM9780_GPIO_STATUS, | ||
297 | mute ? GPIO_LINE_MUTE : 0, | ||
298 | GPIO_LINE_MUTE); | ||
299 | if (!mute) { | ||
300 | mute_ac97_ctl(chip, CONTROL_MIC_CAPTURE_SWITCH); | ||
301 | mute_ac97_ctl(chip, CONTROL_CD_CAPTURE_SWITCH); | ||
302 | mute_ac97_ctl(chip, CONTROL_AUX_CAPTURE_SWITCH); | ||
303 | } | ||
304 | break; | ||
305 | case AC97_MIC: | ||
306 | case AC97_CD: | ||
307 | case AC97_VIDEO: | ||
308 | case AC97_AUX: | ||
309 | if (!mute) { | ||
310 | oxygen_ac97_set_bits(chip, 0, CM9780_GPIO_STATUS, | ||
311 | GPIO_LINE_MUTE); | ||
312 | mute_ac97_ctl(chip, CONTROL_LINE_CAPTURE_SWITCH); | ||
313 | } | ||
314 | break; | ||
315 | } | ||
316 | } | ||
317 | |||
318 | static int pcm1796_volume_info(struct snd_kcontrol *ctl, | ||
319 | struct snd_ctl_elem_info *info) | ||
320 | { | ||
321 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
322 | info->count = 8; | ||
323 | info->value.integer.min = 0x0f; | ||
324 | info->value.integer.max = 0xff; | ||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | static int alt_switch_get(struct snd_kcontrol *ctl, | ||
329 | struct snd_ctl_elem_value *value) | ||
330 | { | ||
331 | struct oxygen *chip = ctl->private_data; | ||
332 | |||
333 | value->value.integer.value[0] = | ||
334 | !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_ALT); | ||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | static int alt_switch_put(struct snd_kcontrol *ctl, | ||
339 | struct snd_ctl_elem_value *value) | ||
340 | { | ||
341 | struct oxygen *chip = ctl->private_data; | ||
342 | u16 old_bits, new_bits; | ||
343 | int changed; | ||
344 | |||
345 | spin_lock_irq(&chip->reg_lock); | ||
346 | old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); | ||
347 | if (value->value.integer.value[0]) | ||
348 | new_bits = old_bits | GPIO_ALT; | ||
349 | else | ||
350 | new_bits = old_bits & ~GPIO_ALT; | ||
351 | changed = new_bits != old_bits; | ||
352 | if (changed) | ||
353 | oxygen_write16(chip, OXYGEN_GPIO_DATA, new_bits); | ||
354 | spin_unlock_irq(&chip->reg_lock); | ||
355 | return changed; | ||
356 | } | ||
357 | |||
358 | static const struct snd_kcontrol_new alt_switch = { | ||
359 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
360 | .name = "Analog Loopback Switch", | ||
361 | .info = snd_ctl_boolean_mono_info, | ||
362 | .get = alt_switch_get, | ||
363 | .put = alt_switch_put, | ||
364 | }; | ||
365 | |||
366 | static const DECLARE_TLV_DB_SCALE(pcm1796_db_scale, -12000, 50, 0); | ||
367 | |||
368 | static int xonar_control_filter(struct snd_kcontrol_new *template) | ||
369 | { | ||
370 | if (!strcmp(template->name, "Master Playback Volume")) { | ||
371 | template->access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
372 | template->info = pcm1796_volume_info, | ||
373 | template->tlv.p = pcm1796_db_scale; | ||
374 | } else if (!strncmp(template->name, "CD Capture ", 11)) { | ||
375 | /* CD in is actually connected to the video in pin */ | ||
376 | template->private_value ^= AC97_CD ^ AC97_VIDEO; | ||
377 | } else if (!strcmp(template->name, "Line Capture Volume")) { | ||
378 | return 1; /* line-in bypasses the AC'97 mixer */ | ||
379 | } | ||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | static int xonar_mixer_init(struct oxygen *chip) | ||
384 | { | ||
385 | return snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip)); | ||
386 | } | ||
387 | |||
388 | static const struct oxygen_model model_xonar = { | ||
389 | .shortname = "Asus AV200", | ||
390 | .longname = "Asus Virtuoso 200", | ||
391 | .chip = "AV200", | ||
392 | .init = xonar_init, | ||
393 | .control_filter = xonar_control_filter, | ||
394 | .mixer_init = xonar_mixer_init, | ||
395 | .cleanup = xonar_cleanup, | ||
396 | .set_dac_params = set_pcm1796_params, | ||
397 | .set_adc_params = set_cs5381_params, | ||
398 | .update_dac_volume = update_pcm1796_volume, | ||
399 | .update_dac_mute = update_pcm1796_mute, | ||
400 | .ac97_switch_hook = xonar_ac97_switch_hook, | ||
401 | .gpio_changed = xonar_gpio_changed, | ||
402 | .model_data_size = sizeof(struct xonar_data), | ||
403 | .dac_channels = 8, | ||
404 | .used_channels = OXYGEN_CHANNEL_B | | ||
405 | OXYGEN_CHANNEL_C | | ||
406 | OXYGEN_CHANNEL_SPDIF | | ||
407 | OXYGEN_CHANNEL_MULTICH, | ||
408 | .function_flags = OXYGEN_FUNCTION_ENABLE_SPI_4_5, | ||
409 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
410 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
411 | }; | ||
412 | |||
413 | static int __devinit xonar_probe(struct pci_dev *pci, | ||
414 | const struct pci_device_id *pci_id) | ||
415 | { | ||
416 | static int dev; | ||
417 | int err; | ||
418 | |||
419 | if (dev >= SNDRV_CARDS) | ||
420 | return -ENODEV; | ||
421 | if (!enable[dev]) { | ||
422 | ++dev; | ||
423 | return -ENOENT; | ||
424 | } | ||
425 | err = oxygen_pci_probe(pci, index[dev], id[dev], 1, &model_xonar); | ||
426 | if (err >= 0) | ||
427 | ++dev; | ||
428 | return err; | ||
429 | } | ||
430 | |||
431 | static struct pci_driver xonar_driver = { | ||
432 | .name = "AV200", | ||
433 | .id_table = xonar_ids, | ||
434 | .probe = xonar_probe, | ||
435 | .remove = __devexit_p(oxygen_pci_remove), | ||
436 | }; | ||
437 | |||
438 | static int __init alsa_card_xonar_init(void) | ||
439 | { | ||
440 | return pci_register_driver(&xonar_driver); | ||
441 | } | ||
442 | |||
443 | static void __exit alsa_card_xonar_exit(void) | ||
444 | { | ||
445 | pci_unregister_driver(&xonar_driver); | ||
446 | } | ||
447 | |||
448 | module_init(alsa_card_xonar_init) | ||
449 | module_exit(alsa_card_xonar_exit) | ||
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index 2d618bd7e62b..9d5bb76229a8 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c | |||
@@ -21,7 +21,6 @@ | |||
21 | */ | 21 | */ |
22 | 22 | ||
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
27 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c index 0ff8dc36fde3..c4e415d07380 100644 --- a/sound/pci/pcxhr/pcxhr_core.c +++ b/sound/pci/pcxhr/pcxhr_core.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <linux/firmware.h> | 24 | #include <linux/firmware.h> |
26 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c index d55d8bc90eee..e6a4bfbb91bb 100644 --- a/sound/pci/pcxhr/pcxhr_hwdep.c +++ b/sound/pci/pcxhr/pcxhr_hwdep.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
25 | #include <linux/vmalloc.h> | 24 | #include <linux/vmalloc.h> |
26 | #include <linux/firmware.h> | 25 | #include <linux/firmware.h> |
diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c index 5f8d42633b04..aabc7bc5321e 100644 --- a/sound/pci/pcxhr/pcxhr_mixer.c +++ b/sound/pci/pcxhr/pcxhr_mixer.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/time.h> | 24 | #include <linux/time.h> |
26 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
27 | #include <linux/init.h> | 26 | #include <linux/init.h> |
@@ -120,8 +119,18 @@ static int pcxhr_analog_vol_put(struct snd_kcontrol *kcontrol, | |||
120 | is_capture = (kcontrol->private_value != 0); | 119 | is_capture = (kcontrol->private_value != 0); |
121 | for (i = 0; i < 2; i++) { | 120 | for (i = 0; i < 2; i++) { |
122 | int new_volume = ucontrol->value.integer.value[i]; | 121 | int new_volume = ucontrol->value.integer.value[i]; |
123 | int* stored_volume = is_capture ? &chip->analog_capture_volume[i] : | 122 | int *stored_volume = is_capture ? |
123 | &chip->analog_capture_volume[i] : | ||
124 | &chip->analog_playback_volume[i]; | 124 | &chip->analog_playback_volume[i]; |
125 | if (is_capture) { | ||
126 | if (new_volume < PCXHR_ANALOG_CAPTURE_LEVEL_MIN || | ||
127 | new_volume > PCXHR_ANALOG_CAPTURE_LEVEL_MAX) | ||
128 | continue; | ||
129 | } else { | ||
130 | if (new_volume < PCXHR_ANALOG_PLAYBACK_LEVEL_MIN || | ||
131 | new_volume > PCXHR_ANALOG_PLAYBACK_LEVEL_MAX) | ||
132 | continue; | ||
133 | } | ||
125 | if (*stored_volume != new_volume) { | 134 | if (*stored_volume != new_volume) { |
126 | *stored_volume = new_volume; | 135 | *stored_volume = new_volume; |
127 | changed = 1; | 136 | changed = 1; |
@@ -165,10 +174,13 @@ static int pcxhr_audio_sw_put(struct snd_kcontrol *kcontrol, | |||
165 | int i, changed = 0; | 174 | int i, changed = 0; |
166 | mutex_lock(&chip->mgr->mixer_mutex); | 175 | mutex_lock(&chip->mgr->mixer_mutex); |
167 | for(i = 0; i < 2; i++) { | 176 | for(i = 0; i < 2; i++) { |
168 | if (chip->analog_playback_active[i] != ucontrol->value.integer.value[i]) { | 177 | if (chip->analog_playback_active[i] != |
169 | chip->analog_playback_active[i] = ucontrol->value.integer.value[i]; | 178 | ucontrol->value.integer.value[i]) { |
179 | chip->analog_playback_active[i] = | ||
180 | !!ucontrol->value.integer.value[i]; | ||
170 | changed = 1; | 181 | changed = 1; |
171 | pcxhr_update_analog_audio_level(chip, 0, i); /* update playback levels */ | 182 | /* update playback levels */ |
183 | pcxhr_update_analog_audio_level(chip, 0, i); | ||
172 | } | 184 | } |
173 | } | 185 | } |
174 | mutex_unlock(&chip->mgr->mixer_mutex); | 186 | mutex_unlock(&chip->mgr->mixer_mutex); |
@@ -323,20 +335,24 @@ static int pcxhr_pcm_vol_put(struct snd_kcontrol *kcontrol, | |||
323 | int i; | 335 | int i; |
324 | 336 | ||
325 | mutex_lock(&chip->mgr->mixer_mutex); | 337 | mutex_lock(&chip->mgr->mixer_mutex); |
326 | if (is_capture) | 338 | if (is_capture) /* digital capture */ |
327 | stored_volume = chip->digital_capture_volume; /* digital capture */ | 339 | stored_volume = chip->digital_capture_volume; |
328 | else | 340 | else /* digital playback */ |
329 | stored_volume = chip->digital_playback_volume[idx]; /* digital playback */ | 341 | stored_volume = chip->digital_playback_volume[idx]; |
330 | for (i = 0; i < 2; i++) { | 342 | for (i = 0; i < 2; i++) { |
331 | if (stored_volume[i] != ucontrol->value.integer.value[i]) { | 343 | int vol = ucontrol->value.integer.value[i]; |
332 | stored_volume[i] = ucontrol->value.integer.value[i]; | 344 | if (vol < PCXHR_DIGITAL_LEVEL_MIN || |
345 | vol > PCXHR_DIGITAL_LEVEL_MAX) | ||
346 | continue; | ||
347 | if (stored_volume[i] != vol) { | ||
348 | stored_volume[i] = vol; | ||
333 | changed = 1; | 349 | changed = 1; |
334 | if (is_capture) /* update capture volume */ | 350 | if (is_capture) /* update capture volume */ |
335 | pcxhr_update_audio_pipe_level(chip, 1, i); | 351 | pcxhr_update_audio_pipe_level(chip, 1, i); |
336 | } | 352 | } |
337 | } | 353 | } |
338 | if (! is_capture && changed) | 354 | if (!is_capture && changed) /* update playback volume */ |
339 | pcxhr_update_playback_stream_level(chip, idx); /* update playback volume */ | 355 | pcxhr_update_playback_stream_level(chip, idx); |
340 | mutex_unlock(&chip->mgr->mixer_mutex); | 356 | mutex_unlock(&chip->mgr->mixer_mutex); |
341 | return changed; | 357 | return changed; |
342 | } | 358 | } |
@@ -378,8 +394,10 @@ static int pcxhr_pcm_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v | |||
378 | mutex_lock(&chip->mgr->mixer_mutex); | 394 | mutex_lock(&chip->mgr->mixer_mutex); |
379 | j = idx; | 395 | j = idx; |
380 | for (i = 0; i < 2; i++) { | 396 | for (i = 0; i < 2; i++) { |
381 | if (chip->digital_playback_active[j][i] != ucontrol->value.integer.value[i]) { | 397 | if (chip->digital_playback_active[j][i] != |
382 | chip->digital_playback_active[j][i] = ucontrol->value.integer.value[i]; | 398 | ucontrol->value.integer.value[i]) { |
399 | chip->digital_playback_active[j][i] = | ||
400 | !!ucontrol->value.integer.value[i]; | ||
383 | changed = 1; | 401 | changed = 1; |
384 | } | 402 | } |
385 | } | 403 | } |
@@ -423,10 +441,13 @@ static int pcxhr_monitor_vol_put(struct snd_kcontrol *kcontrol, | |||
423 | 441 | ||
424 | mutex_lock(&chip->mgr->mixer_mutex); | 442 | mutex_lock(&chip->mgr->mixer_mutex); |
425 | for (i = 0; i < 2; i++) { | 443 | for (i = 0; i < 2; i++) { |
426 | if (chip->monitoring_volume[i] != ucontrol->value.integer.value[i]) { | 444 | if (chip->monitoring_volume[i] != |
427 | chip->monitoring_volume[i] = ucontrol->value.integer.value[i]; | 445 | ucontrol->value.integer.value[i]) { |
428 | if(chip->monitoring_active[i]) /* do only when monitoring is unmuted */ | 446 | chip->monitoring_volume[i] = |
447 | !!ucontrol->value.integer.value[i]; | ||
448 | if(chip->monitoring_active[i]) | ||
429 | /* update monitoring volume and mute */ | 449 | /* update monitoring volume and mute */ |
450 | /* do only when monitoring is unmuted */ | ||
430 | pcxhr_update_audio_pipe_level(chip, 0, i); | 451 | pcxhr_update_audio_pipe_level(chip, 0, i); |
431 | changed = 1; | 452 | changed = 1; |
432 | } | 453 | } |
@@ -470,15 +491,17 @@ static int pcxhr_monitor_sw_put(struct snd_kcontrol *kcontrol, | |||
470 | 491 | ||
471 | mutex_lock(&chip->mgr->mixer_mutex); | 492 | mutex_lock(&chip->mgr->mixer_mutex); |
472 | for (i = 0; i < 2; i++) { | 493 | for (i = 0; i < 2; i++) { |
473 | if (chip->monitoring_active[i] != ucontrol->value.integer.value[i]) { | 494 | if (chip->monitoring_active[i] != |
474 | chip->monitoring_active[i] = ucontrol->value.integer.value[i]; | 495 | ucontrol->value.integer.value[i]) { |
496 | chip->monitoring_active[i] = | ||
497 | !!ucontrol->value.integer.value[i]; | ||
475 | changed |= (1<<i); /* mask 0x01 and 0x02 */ | 498 | changed |= (1<<i); /* mask 0x01 and 0x02 */ |
476 | } | 499 | } |
477 | } | 500 | } |
478 | if(changed & 0x01) | 501 | if (changed & 0x01) |
479 | /* update left monitoring volume and mute */ | 502 | /* update left monitoring volume and mute */ |
480 | pcxhr_update_audio_pipe_level(chip, 0, 0); | 503 | pcxhr_update_audio_pipe_level(chip, 0, 0); |
481 | if(changed & 0x02) | 504 | if (changed & 0x02) |
482 | /* update right monitoring volume and mute */ | 505 | /* update right monitoring volume and mute */ |
483 | pcxhr_update_audio_pipe_level(chip, 0, 1); | 506 | pcxhr_update_audio_pipe_level(chip, 0, 1); |
484 | 507 | ||
@@ -579,6 +602,8 @@ static int pcxhr_audio_src_put(struct snd_kcontrol *kcontrol, | |||
579 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | 602 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); |
580 | int ret = 0; | 603 | int ret = 0; |
581 | 604 | ||
605 | if (ucontrol->value.enumerated.item[0] >= 3) | ||
606 | return -EINVAL; | ||
582 | mutex_lock(&chip->mgr->mixer_mutex); | 607 | mutex_lock(&chip->mgr->mixer_mutex); |
583 | if (chip->audio_capture_source != ucontrol->value.enumerated.item[0]) { | 608 | if (chip->audio_capture_source != ucontrol->value.enumerated.item[0]) { |
584 | chip->audio_capture_source = ucontrol->value.enumerated.item[0]; | 609 | chip->audio_capture_source = ucontrol->value.enumerated.item[0]; |
@@ -642,8 +667,11 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol, | |||
642 | struct snd_ctl_elem_value *ucontrol) | 667 | struct snd_ctl_elem_value *ucontrol) |
643 | { | 668 | { |
644 | struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); | 669 | struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); |
670 | unsigned int clock_items = 3 + mgr->capture_chips; | ||
645 | int rate, ret = 0; | 671 | int rate, ret = 0; |
646 | 672 | ||
673 | if (ucontrol->value.enumerated.item[0] >= clock_items) | ||
674 | return -EINVAL; | ||
647 | mutex_lock(&mgr->mixer_mutex); | 675 | mutex_lock(&mgr->mixer_mutex); |
648 | if (mgr->use_clock_type != ucontrol->value.enumerated.item[0]) { | 676 | if (mgr->use_clock_type != ucontrol->value.enumerated.item[0]) { |
649 | mutex_lock(&mgr->setup_mutex); | 677 | mutex_lock(&mgr->setup_mutex); |
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index 8e5410483e67..9408b1eeec40 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c | |||
@@ -88,7 +88,6 @@ | |||
88 | Adopted for Windows NT driver 01/20/98 CNL | 88 | Adopted for Windows NT driver 01/20/98 CNL |
89 | */ | 89 | */ |
90 | 90 | ||
91 | #include <sound/driver.h> | ||
92 | #include <linux/delay.h> | 91 | #include <linux/delay.h> |
93 | #include <linux/init.h> | 92 | #include <linux/init.h> |
94 | #include <linux/interrupt.h> | 93 | #include <linux/interrupt.h> |
diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index 1475912588e9..df184aabce84 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c | |||
@@ -69,7 +69,6 @@ | |||
69 | */ | 69 | */ |
70 | 70 | ||
71 | 71 | ||
72 | #include <sound/driver.h> | ||
73 | #include <linux/delay.h> | 72 | #include <linux/delay.h> |
74 | #include <linux/init.h> | 73 | #include <linux/init.h> |
75 | #include <linux/interrupt.h> | 74 | #include <linux/interrupt.h> |
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 0b3c532c4014..fb0a4ee8bc02 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c | |||
@@ -23,7 +23,6 @@ | |||
23 | * | 23 | * |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <sound/driver.h> | ||
27 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
28 | #include <linux/init.h> | 27 | #include <linux/init.h> |
29 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
@@ -2195,22 +2194,25 @@ snd_rme96_dac_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu | |||
2195 | { | 2194 | { |
2196 | struct rme96 *rme96 = snd_kcontrol_chip(kcontrol); | 2195 | struct rme96 *rme96 = snd_kcontrol_chip(kcontrol); |
2197 | int change = 0; | 2196 | int change = 0; |
2197 | unsigned int vol, maxvol; | ||
2198 | 2198 | ||
2199 | if (!RME96_HAS_ANALOG_OUT(rme96)) { | 2199 | |
2200 | if (!RME96_HAS_ANALOG_OUT(rme96)) | ||
2200 | return -EINVAL; | 2201 | return -EINVAL; |
2201 | } | 2202 | maxvol = RME96_185X_MAX_OUT(rme96); |
2202 | spin_lock_irq(&rme96->lock); | 2203 | spin_lock_irq(&rme96->lock); |
2203 | if (u->value.integer.value[0] != rme96->vol[0]) { | 2204 | vol = u->value.integer.value[0]; |
2204 | rme96->vol[0] = u->value.integer.value[0]; | 2205 | if (vol != rme96->vol[0] && vol <= maxvol) { |
2205 | change = 1; | 2206 | rme96->vol[0] = vol; |
2206 | } | 2207 | change = 1; |
2207 | if (u->value.integer.value[1] != rme96->vol[1]) { | 2208 | } |
2208 | rme96->vol[1] = u->value.integer.value[1]; | 2209 | vol = u->value.integer.value[1]; |
2209 | change = 1; | 2210 | if (vol != rme96->vol[1] && vol <= maxvol) { |
2210 | } | 2211 | rme96->vol[1] = vol; |
2211 | if (change) { | 2212 | change = 1; |
2212 | snd_rme96_apply_dac_volume(rme96); | ||
2213 | } | 2213 | } |
2214 | if (change) | ||
2215 | snd_rme96_apply_dac_volume(rme96); | ||
2214 | spin_unlock_irq(&rme96->lock); | 2216 | spin_unlock_irq(&rme96->lock); |
2215 | 2217 | ||
2216 | return change; | 2218 | return change; |
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index ff26a3672d40..c2bd4384316a 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
27 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
@@ -104,8 +103,6 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin"); | |||
104 | #define HDSP_statusRegister 0 | 103 | #define HDSP_statusRegister 0 |
105 | #define HDSP_timecode 128 | 104 | #define HDSP_timecode 128 |
106 | #define HDSP_status2Register 192 | 105 | #define HDSP_status2Register 192 |
107 | #define HDSP_midiDataOut0 352 | ||
108 | #define HDSP_midiDataOut1 356 | ||
109 | #define HDSP_midiDataIn0 360 | 106 | #define HDSP_midiDataIn0 360 |
110 | #define HDSP_midiDataIn1 364 | 107 | #define HDSP_midiDataIn1 364 |
111 | #define HDSP_midiStatusOut0 384 | 108 | #define HDSP_midiStatusOut0 384 |
@@ -610,7 +607,10 @@ static int hdsp_playback_to_output_key (struct hdsp *hdsp, int in, int out) | |||
610 | case Multiface: | 607 | case Multiface: |
611 | case Digiface: | 608 | case Digiface: |
612 | default: | 609 | default: |
613 | return (64 * out) + (32 + (in)); | 610 | if (hdsp->firmware_rev == 0xa) |
611 | return (64 * out) + (32 + (in)); | ||
612 | else | ||
613 | return (52 * out) + (26 + (in)); | ||
614 | case H9632: | 614 | case H9632: |
615 | return (32 * out) + (16 + (in)); | 615 | return (32 * out) + (16 + (in)); |
616 | case H9652: | 616 | case H9652: |
@@ -624,7 +624,10 @@ static int hdsp_input_to_output_key (struct hdsp *hdsp, int in, int out) | |||
624 | case Multiface: | 624 | case Multiface: |
625 | case Digiface: | 625 | case Digiface: |
626 | default: | 626 | default: |
627 | return (64 * out) + in; | 627 | if (hdsp->firmware_rev == 0xa) |
628 | return (64 * out) + in; | ||
629 | else | ||
630 | return (52 * out) + in; | ||
628 | case H9632: | 631 | case H9632: |
629 | return (32 * out) + in; | 632 | return (32 * out) + in; |
630 | case H9652: | 633 | case H9652: |
@@ -2121,7 +2124,7 @@ static int snd_hdsp_put_clock_source_lock(struct snd_kcontrol *kcontrol, struct | |||
2121 | 2124 | ||
2122 | change = (int)ucontrol->value.integer.value[0] != hdsp->clock_source_locked; | 2125 | change = (int)ucontrol->value.integer.value[0] != hdsp->clock_source_locked; |
2123 | if (change) | 2126 | if (change) |
2124 | hdsp->clock_source_locked = ucontrol->value.integer.value[0]; | 2127 | hdsp->clock_source_locked = !!ucontrol->value.integer.value[0]; |
2125 | return change; | 2128 | return change; |
2126 | } | 2129 | } |
2127 | 2130 | ||
@@ -3558,7 +3561,7 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | |||
3558 | 3561 | ||
3559 | } | 3562 | } |
3560 | 3563 | ||
3561 | static void __devinit snd_hdsp_proc_init(struct hdsp *hdsp) | 3564 | static void snd_hdsp_proc_init(struct hdsp *hdsp) |
3562 | { | 3565 | { |
3563 | struct snd_info_entry *entry; | 3566 | struct snd_info_entry *entry; |
3564 | 3567 | ||
@@ -3606,7 +3609,7 @@ static int snd_hdsp_set_defaults(struct hdsp *hdsp) | |||
3606 | 3609 | ||
3607 | /* ASSUMPTION: hdsp->lock is either held, or | 3610 | /* ASSUMPTION: hdsp->lock is either held, or |
3608 | there is no need to hold it (e.g. during module | 3611 | there is no need to hold it (e.g. during module |
3609 | initalization). | 3612 | initialization). |
3610 | */ | 3613 | */ |
3611 | 3614 | ||
3612 | /* set defaults: | 3615 | /* set defaults: |
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index f1bdda6cbcff..9a19ae6a64d9 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c | |||
@@ -23,7 +23,6 @@ | |||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
24 | * | 24 | * |
25 | */ | 25 | */ |
26 | #include <sound/driver.h> | ||
27 | #include <linux/init.h> | 26 | #include <linux/init.h> |
28 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
29 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
@@ -3348,7 +3347,7 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm) | |||
3348 | unsigned int i; | 3347 | unsigned int i; |
3349 | 3348 | ||
3350 | /* ASSUMPTION: hdspm->lock is either held, or there is no need to | 3349 | /* ASSUMPTION: hdspm->lock is either held, or there is no need to |
3351 | hold it (e.g. during module initalization). | 3350 | hold it (e.g. during module initialization). |
3352 | */ | 3351 | */ |
3353 | 3352 | ||
3354 | /* set defaults: */ | 3353 | /* set defaults: */ |
@@ -3416,7 +3415,7 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm) | |||
3416 | 3415 | ||
3417 | 3416 | ||
3418 | /*------------------------------------------------------------ | 3417 | /*------------------------------------------------------------ |
3419 | interupt | 3418 | interrupt |
3420 | ------------------------------------------------------------*/ | 3419 | ------------------------------------------------------------*/ |
3421 | 3420 | ||
3422 | static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id) | 3421 | static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id) |
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 34f96f12e5bf..a123f0e6ba23 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
@@ -148,7 +147,7 @@ MODULE_SUPPORTED_DEVICE("{{RME,Hammerfall}," | |||
148 | #define RME9652_start_bit (1<<0) /* start record/play */ | 147 | #define RME9652_start_bit (1<<0) /* start record/play */ |
149 | /* bits 1-3 encode buffersize/latency */ | 148 | /* bits 1-3 encode buffersize/latency */ |
150 | #define RME9652_Master (1<<4) /* Clock Mode Master=1,Slave/Auto=0 */ | 149 | #define RME9652_Master (1<<4) /* Clock Mode Master=1,Slave/Auto=0 */ |
151 | #define RME9652_IE (1<<5) /* Interupt Enable */ | 150 | #define RME9652_IE (1<<5) /* Interrupt Enable */ |
152 | #define RME9652_freq (1<<6) /* samplerate 0=44.1/88.2, 1=48/96 kHz */ | 151 | #define RME9652_freq (1<<6) /* samplerate 0=44.1/88.2, 1=48/96 kHz */ |
153 | #define RME9652_freq1 (1<<7) /* if 0, 32kHz, else always 1 */ | 152 | #define RME9652_freq1 (1<<7) /* if 0, 32kHz, else always 1 */ |
154 | #define RME9652_DS (1<<8) /* Doule Speed 0=44.1/48, 1=88.2/96 Khz */ | 153 | #define RME9652_DS (1<<8) /* Doule Speed 0=44.1/48, 1=88.2/96 Khz */ |
@@ -1826,7 +1825,7 @@ static void snd_rme9652_set_defaults(struct snd_rme9652 *rme9652) | |||
1826 | 1825 | ||
1827 | /* ASSUMPTION: rme9652->lock is either held, or | 1826 | /* ASSUMPTION: rme9652->lock is either held, or |
1828 | there is no need to hold it (e.g. during module | 1827 | there is no need to hold it (e.g. during module |
1829 | initalization). | 1828 | initialization). |
1830 | */ | 1829 | */ |
1831 | 1830 | ||
1832 | /* set defaults: | 1831 | /* set defaults: |
diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c new file mode 100644 index 000000000000..dcd7cd010461 --- /dev/null +++ b/sound/pci/sis7019.c | |||
@@ -0,0 +1,1460 @@ | |||
1 | /* | ||
2 | * Driver for SiS7019 Audio Accelerator | ||
3 | * | ||
4 | * Copyright (C) 2004-2007, David Dillow | ||
5 | * Written by David Dillow <dave@thedillows.org> | ||
6 | * Inspired by the Trident 4D-WaveDX/NX driver. | ||
7 | * | ||
8 | * All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation, version 2. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | |||
24 | #include <linux/init.h> | ||
25 | #include <linux/pci.h> | ||
26 | #include <linux/time.h> | ||
27 | #include <linux/moduleparam.h> | ||
28 | #include <linux/interrupt.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <sound/core.h> | ||
31 | #include <sound/ac97_codec.h> | ||
32 | #include <sound/initval.h> | ||
33 | #include "sis7019.h" | ||
34 | |||
35 | MODULE_AUTHOR("David Dillow <dave@thedillows.org>"); | ||
36 | MODULE_DESCRIPTION("SiS7019"); | ||
37 | MODULE_LICENSE("GPL"); | ||
38 | MODULE_SUPPORTED_DEVICE("{{SiS,SiS7019 Audio Accelerator}}"); | ||
39 | |||
40 | static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ | ||
41 | static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ | ||
42 | static int enable = 1; | ||
43 | |||
44 | module_param(index, int, 0444); | ||
45 | MODULE_PARM_DESC(index, "Index value for SiS7019 Audio Accelerator."); | ||
46 | module_param(id, charp, 0444); | ||
47 | MODULE_PARM_DESC(id, "ID string for SiS7019 Audio Accelerator."); | ||
48 | module_param(enable, bool, 0444); | ||
49 | MODULE_PARM_DESC(enable, "Enable SiS7019 Audio Accelerator."); | ||
50 | |||
51 | static struct pci_device_id snd_sis7019_ids[] = { | ||
52 | { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x7019) }, | ||
53 | { 0, } | ||
54 | }; | ||
55 | |||
56 | MODULE_DEVICE_TABLE(pci, snd_sis7019_ids); | ||
57 | |||
58 | /* There are three timing modes for the voices. | ||
59 | * | ||
60 | * For both playback and capture, when the buffer is one or two periods long, | ||
61 | * we use the hardware's built-in Mid-Loop Interrupt and End-Loop Interrupt | ||
62 | * to let us know when the periods have ended. | ||
63 | * | ||
64 | * When performing playback with more than two periods per buffer, we set | ||
65 | * the "Stop Sample Offset" and tell the hardware to interrupt us when we | ||
66 | * reach it. We then update the offset and continue on until we are | ||
67 | * interrupted for the next period. | ||
68 | * | ||
69 | * Capture channels do not have a SSO, so we allocate a playback channel to | ||
70 | * use as a timer for the capture periods. We use the SSO on the playback | ||
71 | * channel to clock out virtual periods, and adjust the virtual period length | ||
72 | * to maintain synchronization. This algorithm came from the Trident driver. | ||
73 | * | ||
74 | * FIXME: It'd be nice to make use of some of the synth features in the | ||
75 | * hardware, but a woeful lack of documentation is a significant roadblock. | ||
76 | */ | ||
77 | struct voice { | ||
78 | u16 flags; | ||
79 | #define VOICE_IN_USE 1 | ||
80 | #define VOICE_CAPTURE 2 | ||
81 | #define VOICE_SSO_TIMING 4 | ||
82 | #define VOICE_SYNC_TIMING 8 | ||
83 | u16 sync_cso; | ||
84 | u16 period_size; | ||
85 | u16 buffer_size; | ||
86 | u16 sync_period_size; | ||
87 | u16 sync_buffer_size; | ||
88 | u32 sso; | ||
89 | u32 vperiod; | ||
90 | struct snd_pcm_substream *substream; | ||
91 | struct voice *timing; | ||
92 | void __iomem *ctrl_base; | ||
93 | void __iomem *wave_base; | ||
94 | void __iomem *sync_base; | ||
95 | int num; | ||
96 | }; | ||
97 | |||
98 | /* We need four pages to store our wave parameters during a suspend. If | ||
99 | * we're not doing power management, we still need to allocate a page | ||
100 | * for the silence buffer. | ||
101 | */ | ||
102 | #ifdef CONFIG_PM | ||
103 | #define SIS_SUSPEND_PAGES 4 | ||
104 | #else | ||
105 | #define SIS_SUSPEND_PAGES 1 | ||
106 | #endif | ||
107 | |||
108 | struct sis7019 { | ||
109 | unsigned long ioport; | ||
110 | void __iomem *ioaddr; | ||
111 | int irq; | ||
112 | int codecs_present; | ||
113 | |||
114 | struct pci_dev *pci; | ||
115 | struct snd_pcm *pcm; | ||
116 | struct snd_card *card; | ||
117 | struct snd_ac97 *ac97[3]; | ||
118 | |||
119 | /* Protect against more than one thread hitting the AC97 | ||
120 | * registers (in a more polite manner than pounding the hardware | ||
121 | * semaphore) | ||
122 | */ | ||
123 | struct mutex ac97_mutex; | ||
124 | |||
125 | /* voice_lock protects allocation/freeing of the voice descriptions | ||
126 | */ | ||
127 | spinlock_t voice_lock; | ||
128 | |||
129 | struct voice voices[64]; | ||
130 | struct voice capture_voice; | ||
131 | |||
132 | /* Allocate pages to store the internal wave state during | ||
133 | * suspends. When we're operating, this can be used as a silence | ||
134 | * buffer for a timing channel. | ||
135 | */ | ||
136 | void *suspend_state[SIS_SUSPEND_PAGES]; | ||
137 | |||
138 | int silence_users; | ||
139 | dma_addr_t silence_dma_addr; | ||
140 | }; | ||
141 | |||
142 | #define SIS_PRIMARY_CODEC_PRESENT 0x0001 | ||
143 | #define SIS_SECONDARY_CODEC_PRESENT 0x0002 | ||
144 | #define SIS_TERTIARY_CODEC_PRESENT 0x0004 | ||
145 | |||
146 | /* The HW offset parameters (Loop End, Stop Sample, End Sample) have a | ||
147 | * documented range of 8-0xfff8 samples. Given that they are 0-based, | ||
148 | * that places our period/buffer range at 9-0xfff9 samples. That makes the | ||
149 | * max buffer size 0xfff9 samples * 2 channels * 2 bytes per sample, and | ||
150 | * max samples / min samples gives us the max periods in a buffer. | ||
151 | * | ||
152 | * We'll add a constraint upon open that limits the period and buffer sample | ||
153 | * size to values that are legal for the hardware. | ||
154 | */ | ||
155 | static struct snd_pcm_hardware sis_playback_hw_info = { | ||
156 | .info = (SNDRV_PCM_INFO_MMAP | | ||
157 | SNDRV_PCM_INFO_MMAP_VALID | | ||
158 | SNDRV_PCM_INFO_INTERLEAVED | | ||
159 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
160 | SNDRV_PCM_INFO_SYNC_START | | ||
161 | SNDRV_PCM_INFO_RESUME), | ||
162 | .formats = (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | | ||
163 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE), | ||
164 | .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_CONTINUOUS, | ||
165 | .rate_min = 4000, | ||
166 | .rate_max = 48000, | ||
167 | .channels_min = 1, | ||
168 | .channels_max = 2, | ||
169 | .buffer_bytes_max = (0xfff9 * 4), | ||
170 | .period_bytes_min = 9, | ||
171 | .period_bytes_max = (0xfff9 * 4), | ||
172 | .periods_min = 1, | ||
173 | .periods_max = (0xfff9 / 9), | ||
174 | }; | ||
175 | |||
176 | static struct snd_pcm_hardware sis_capture_hw_info = { | ||
177 | .info = (SNDRV_PCM_INFO_MMAP | | ||
178 | SNDRV_PCM_INFO_MMAP_VALID | | ||
179 | SNDRV_PCM_INFO_INTERLEAVED | | ||
180 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
181 | SNDRV_PCM_INFO_SYNC_START | | ||
182 | SNDRV_PCM_INFO_RESUME), | ||
183 | .formats = (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | | ||
184 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE), | ||
185 | .rates = SNDRV_PCM_RATE_48000, | ||
186 | .rate_min = 4000, | ||
187 | .rate_max = 48000, | ||
188 | .channels_min = 1, | ||
189 | .channels_max = 2, | ||
190 | .buffer_bytes_max = (0xfff9 * 4), | ||
191 | .period_bytes_min = 9, | ||
192 | .period_bytes_max = (0xfff9 * 4), | ||
193 | .periods_min = 1, | ||
194 | .periods_max = (0xfff9 / 9), | ||
195 | }; | ||
196 | |||
197 | static void sis_update_sso(struct voice *voice, u16 period) | ||
198 | { | ||
199 | void __iomem *base = voice->ctrl_base; | ||
200 | |||
201 | voice->sso += period; | ||
202 | if (voice->sso >= voice->buffer_size) | ||
203 | voice->sso -= voice->buffer_size; | ||
204 | |||
205 | /* Enforce the documented hardware minimum offset */ | ||
206 | if (voice->sso < 8) | ||
207 | voice->sso = 8; | ||
208 | |||
209 | /* The SSO is in the upper 16 bits of the register. */ | ||
210 | writew(voice->sso & 0xffff, base + SIS_PLAY_DMA_SSO_ESO + 2); | ||
211 | } | ||
212 | |||
213 | static void sis_update_voice(struct voice *voice) | ||
214 | { | ||
215 | if (voice->flags & VOICE_SSO_TIMING) { | ||
216 | sis_update_sso(voice, voice->period_size); | ||
217 | } else if (voice->flags & VOICE_SYNC_TIMING) { | ||
218 | int sync; | ||
219 | |||
220 | /* If we've not hit the end of the virtual period, update | ||
221 | * our records and keep going. | ||
222 | */ | ||
223 | if (voice->vperiod > voice->period_size) { | ||
224 | voice->vperiod -= voice->period_size; | ||
225 | if (voice->vperiod < voice->period_size) | ||
226 | sis_update_sso(voice, voice->vperiod); | ||
227 | else | ||
228 | sis_update_sso(voice, voice->period_size); | ||
229 | return; | ||
230 | } | ||
231 | |||
232 | /* Calculate our relative offset between the target and | ||
233 | * the actual CSO value. Since we're operating in a loop, | ||
234 | * if the value is more than half way around, we can | ||
235 | * consider ourselves wrapped. | ||
236 | */ | ||
237 | sync = voice->sync_cso; | ||
238 | sync -= readw(voice->sync_base + SIS_CAPTURE_DMA_FORMAT_CSO); | ||
239 | if (sync > (voice->sync_buffer_size / 2)) | ||
240 | sync -= voice->sync_buffer_size; | ||
241 | |||
242 | /* If sync is positive, then we interrupted too early, and | ||
243 | * we'll need to come back in a few samples and try again. | ||
244 | * There's a minimum wait, as it takes some time for the DMA | ||
245 | * engine to startup, etc... | ||
246 | */ | ||
247 | if (sync > 0) { | ||
248 | if (sync < 16) | ||
249 | sync = 16; | ||
250 | sis_update_sso(voice, sync); | ||
251 | return; | ||
252 | } | ||
253 | |||
254 | /* Ok, we interrupted right on time, or (hopefully) just | ||
255 | * a bit late. We'll adjst our next waiting period based | ||
256 | * on how close we got. | ||
257 | * | ||
258 | * We need to stay just behind the actual channel to ensure | ||
259 | * it really is past a period when we get our interrupt -- | ||
260 | * otherwise we'll fall into the early code above and have | ||
261 | * a minimum wait time, which makes us quite late here, | ||
262 | * eating into the user's time to refresh the buffer, esp. | ||
263 | * if using small periods. | ||
264 | * | ||
265 | * If we're less than 9 samples behind, we're on target. | ||
266 | */ | ||
267 | if (sync > -9) | ||
268 | voice->vperiod = voice->sync_period_size + 1; | ||
269 | else | ||
270 | voice->vperiod = voice->sync_period_size - 4; | ||
271 | |||
272 | if (voice->vperiod < voice->buffer_size) { | ||
273 | sis_update_sso(voice, voice->vperiod); | ||
274 | voice->vperiod = 0; | ||
275 | } else | ||
276 | sis_update_sso(voice, voice->period_size); | ||
277 | |||
278 | sync = voice->sync_cso + voice->sync_period_size; | ||
279 | if (sync >= voice->sync_buffer_size) | ||
280 | sync -= voice->sync_buffer_size; | ||
281 | voice->sync_cso = sync; | ||
282 | } | ||
283 | |||
284 | snd_pcm_period_elapsed(voice->substream); | ||
285 | } | ||
286 | |||
287 | static void sis_voice_irq(u32 status, struct voice *voice) | ||
288 | { | ||
289 | int bit; | ||
290 | |||
291 | while (status) { | ||
292 | bit = __ffs(status); | ||
293 | status >>= bit + 1; | ||
294 | voice += bit; | ||
295 | sis_update_voice(voice); | ||
296 | voice++; | ||
297 | } | ||
298 | } | ||
299 | |||
300 | static irqreturn_t sis_interrupt(int irq, void *dev) | ||
301 | { | ||
302 | struct sis7019 *sis = dev; | ||
303 | unsigned long io = sis->ioport; | ||
304 | struct voice *voice; | ||
305 | u32 intr, status; | ||
306 | |||
307 | /* We only use the DMA interrupts, and we don't enable any other | ||
308 | * source of interrupts. But, it is possible to see an interupt | ||
309 | * status that didn't actually interrupt us, so eliminate anything | ||
310 | * we're not expecting to avoid falsely claiming an IRQ, and an | ||
311 | * ensuing endless loop. | ||
312 | */ | ||
313 | intr = inl(io + SIS_GISR); | ||
314 | intr &= SIS_GISR_AUDIO_PLAY_DMA_IRQ_STATUS | | ||
315 | SIS_GISR_AUDIO_RECORD_DMA_IRQ_STATUS; | ||
316 | if (!intr) | ||
317 | return IRQ_NONE; | ||
318 | |||
319 | do { | ||
320 | status = inl(io + SIS_PISR_A); | ||
321 | if (status) { | ||
322 | sis_voice_irq(status, sis->voices); | ||
323 | outl(status, io + SIS_PISR_A); | ||
324 | } | ||
325 | |||
326 | status = inl(io + SIS_PISR_B); | ||
327 | if (status) { | ||
328 | sis_voice_irq(status, &sis->voices[32]); | ||
329 | outl(status, io + SIS_PISR_B); | ||
330 | } | ||
331 | |||
332 | status = inl(io + SIS_RISR); | ||
333 | if (status) { | ||
334 | voice = &sis->capture_voice; | ||
335 | if (!voice->timing) | ||
336 | snd_pcm_period_elapsed(voice->substream); | ||
337 | |||
338 | outl(status, io + SIS_RISR); | ||
339 | } | ||
340 | |||
341 | outl(intr, io + SIS_GISR); | ||
342 | intr = inl(io + SIS_GISR); | ||
343 | intr &= SIS_GISR_AUDIO_PLAY_DMA_IRQ_STATUS | | ||
344 | SIS_GISR_AUDIO_RECORD_DMA_IRQ_STATUS; | ||
345 | } while (intr); | ||
346 | |||
347 | return IRQ_HANDLED; | ||
348 | } | ||
349 | |||
350 | static u32 sis_rate_to_delta(unsigned int rate) | ||
351 | { | ||
352 | u32 delta; | ||
353 | |||
354 | /* This was copied from the trident driver, but it seems its gotten | ||
355 | * around a bit... nevertheless, it works well. | ||
356 | * | ||
357 | * We special case 44100 and 8000 since rounding with the equation | ||
358 | * does not give us an accurate enough value. For 11025 and 22050 | ||
359 | * the equation gives us the best answer. All other frequencies will | ||
360 | * also use the equation. JDW | ||
361 | */ | ||
362 | if (rate == 44100) | ||
363 | delta = 0xeb3; | ||
364 | else if (rate == 8000) | ||
365 | delta = 0x2ab; | ||
366 | else if (rate == 48000) | ||
367 | delta = 0x1000; | ||
368 | else | ||
369 | delta = (((rate << 12) + 24000) / 48000) & 0x0000ffff; | ||
370 | return delta; | ||
371 | } | ||
372 | |||
373 | static void __sis_map_silence(struct sis7019 *sis) | ||
374 | { | ||
375 | /* Helper function: must hold sis->voice_lock on entry */ | ||
376 | if (!sis->silence_users) | ||
377 | sis->silence_dma_addr = pci_map_single(sis->pci, | ||
378 | sis->suspend_state[0], | ||
379 | 4096, PCI_DMA_TODEVICE); | ||
380 | sis->silence_users++; | ||
381 | } | ||
382 | |||
383 | static void __sis_unmap_silence(struct sis7019 *sis) | ||
384 | { | ||
385 | /* Helper function: must hold sis->voice_lock on entry */ | ||
386 | sis->silence_users--; | ||
387 | if (!sis->silence_users) | ||
388 | pci_unmap_single(sis->pci, sis->silence_dma_addr, 4096, | ||
389 | PCI_DMA_TODEVICE); | ||
390 | } | ||
391 | |||
392 | static void sis_free_voice(struct sis7019 *sis, struct voice *voice) | ||
393 | { | ||
394 | unsigned long flags; | ||
395 | |||
396 | spin_lock_irqsave(&sis->voice_lock, flags); | ||
397 | if (voice->timing) { | ||
398 | __sis_unmap_silence(sis); | ||
399 | voice->timing->flags &= ~(VOICE_IN_USE | VOICE_SSO_TIMING | | ||
400 | VOICE_SYNC_TIMING); | ||
401 | voice->timing = NULL; | ||
402 | } | ||
403 | voice->flags &= ~(VOICE_IN_USE | VOICE_SSO_TIMING | VOICE_SYNC_TIMING); | ||
404 | spin_unlock_irqrestore(&sis->voice_lock, flags); | ||
405 | } | ||
406 | |||
407 | static struct voice *__sis_alloc_playback_voice(struct sis7019 *sis) | ||
408 | { | ||
409 | /* Must hold the voice_lock on entry */ | ||
410 | struct voice *voice; | ||
411 | int i; | ||
412 | |||
413 | for (i = 0; i < 64; i++) { | ||
414 | voice = &sis->voices[i]; | ||
415 | if (voice->flags & VOICE_IN_USE) | ||
416 | continue; | ||
417 | voice->flags |= VOICE_IN_USE; | ||
418 | goto found_one; | ||
419 | } | ||
420 | voice = NULL; | ||
421 | |||
422 | found_one: | ||
423 | return voice; | ||
424 | } | ||
425 | |||
426 | static struct voice *sis_alloc_playback_voice(struct sis7019 *sis) | ||
427 | { | ||
428 | struct voice *voice; | ||
429 | unsigned long flags; | ||
430 | |||
431 | spin_lock_irqsave(&sis->voice_lock, flags); | ||
432 | voice = __sis_alloc_playback_voice(sis); | ||
433 | spin_unlock_irqrestore(&sis->voice_lock, flags); | ||
434 | |||
435 | return voice; | ||
436 | } | ||
437 | |||
438 | static int sis_alloc_timing_voice(struct snd_pcm_substream *substream, | ||
439 | struct snd_pcm_hw_params *hw_params) | ||
440 | { | ||
441 | struct sis7019 *sis = snd_pcm_substream_chip(substream); | ||
442 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
443 | struct voice *voice = runtime->private_data; | ||
444 | unsigned int period_size, buffer_size; | ||
445 | unsigned long flags; | ||
446 | int needed; | ||
447 | |||
448 | /* If there are one or two periods per buffer, we don't need a | ||
449 | * timing voice, as we can use the capture channel's interrupts | ||
450 | * to clock out the periods. | ||
451 | */ | ||
452 | period_size = params_period_size(hw_params); | ||
453 | buffer_size = params_buffer_size(hw_params); | ||
454 | needed = (period_size != buffer_size && | ||
455 | period_size != (buffer_size / 2)); | ||
456 | |||
457 | if (needed && !voice->timing) { | ||
458 | spin_lock_irqsave(&sis->voice_lock, flags); | ||
459 | voice->timing = __sis_alloc_playback_voice(sis); | ||
460 | if (voice->timing) | ||
461 | __sis_map_silence(sis); | ||
462 | spin_unlock_irqrestore(&sis->voice_lock, flags); | ||
463 | if (!voice->timing) | ||
464 | return -ENOMEM; | ||
465 | voice->timing->substream = substream; | ||
466 | } else if (!needed && voice->timing) { | ||
467 | sis_free_voice(sis, voice); | ||
468 | voice->timing = NULL; | ||
469 | } | ||
470 | |||
471 | return 0; | ||
472 | } | ||
473 | |||
474 | static int sis_playback_open(struct snd_pcm_substream *substream) | ||
475 | { | ||
476 | struct sis7019 *sis = snd_pcm_substream_chip(substream); | ||
477 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
478 | struct voice *voice; | ||
479 | |||
480 | voice = sis_alloc_playback_voice(sis); | ||
481 | if (!voice) | ||
482 | return -EAGAIN; | ||
483 | |||
484 | voice->substream = substream; | ||
485 | runtime->private_data = voice; | ||
486 | runtime->hw = sis_playback_hw_info; | ||
487 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, | ||
488 | 9, 0xfff9); | ||
489 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, | ||
490 | 9, 0xfff9); | ||
491 | snd_pcm_set_sync(substream); | ||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | static int sis_substream_close(struct snd_pcm_substream *substream) | ||
496 | { | ||
497 | struct sis7019 *sis = snd_pcm_substream_chip(substream); | ||
498 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
499 | struct voice *voice = runtime->private_data; | ||
500 | |||
501 | sis_free_voice(sis, voice); | ||
502 | return 0; | ||
503 | } | ||
504 | |||
505 | static int sis_playback_hw_params(struct snd_pcm_substream *substream, | ||
506 | struct snd_pcm_hw_params *hw_params) | ||
507 | { | ||
508 | return snd_pcm_lib_malloc_pages(substream, | ||
509 | params_buffer_bytes(hw_params)); | ||
510 | } | ||
511 | |||
512 | static int sis_hw_free(struct snd_pcm_substream *substream) | ||
513 | { | ||
514 | return snd_pcm_lib_free_pages(substream); | ||
515 | } | ||
516 | |||
517 | static int sis_pcm_playback_prepare(struct snd_pcm_substream *substream) | ||
518 | { | ||
519 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
520 | struct voice *voice = runtime->private_data; | ||
521 | void __iomem *ctrl_base = voice->ctrl_base; | ||
522 | void __iomem *wave_base = voice->wave_base; | ||
523 | u32 format, dma_addr, control, sso_eso, delta, reg; | ||
524 | u16 leo; | ||
525 | |||
526 | /* We rely on the PCM core to ensure that the parameters for this | ||
527 | * substream do not change on us while we're programming the HW. | ||
528 | */ | ||
529 | format = 0; | ||
530 | if (snd_pcm_format_width(runtime->format) == 8) | ||
531 | format |= SIS_PLAY_DMA_FORMAT_8BIT; | ||
532 | if (!snd_pcm_format_signed(runtime->format)) | ||
533 | format |= SIS_PLAY_DMA_FORMAT_UNSIGNED; | ||
534 | if (runtime->channels == 1) | ||
535 | format |= SIS_PLAY_DMA_FORMAT_MONO; | ||
536 | |||
537 | /* The baseline setup is for a single period per buffer, and | ||
538 | * we add bells and whistles as needed from there. | ||
539 | */ | ||
540 | dma_addr = runtime->dma_addr; | ||
541 | leo = runtime->buffer_size - 1; | ||
542 | control = leo | SIS_PLAY_DMA_LOOP | SIS_PLAY_DMA_INTR_AT_LEO; | ||
543 | sso_eso = leo; | ||
544 | |||
545 | if (runtime->period_size == (runtime->buffer_size / 2)) { | ||
546 | control |= SIS_PLAY_DMA_INTR_AT_MLP; | ||
547 | } else if (runtime->period_size != runtime->buffer_size) { | ||
548 | voice->flags |= VOICE_SSO_TIMING; | ||
549 | voice->sso = runtime->period_size - 1; | ||
550 | voice->period_size = runtime->period_size; | ||
551 | voice->buffer_size = runtime->buffer_size; | ||
552 | |||
553 | control &= ~SIS_PLAY_DMA_INTR_AT_LEO; | ||
554 | control |= SIS_PLAY_DMA_INTR_AT_SSO; | ||
555 | sso_eso |= (runtime->period_size - 1) << 16; | ||
556 | } | ||
557 | |||
558 | delta = sis_rate_to_delta(runtime->rate); | ||
559 | |||
560 | /* Ok, we're ready to go, set up the channel. | ||
561 | */ | ||
562 | writel(format, ctrl_base + SIS_PLAY_DMA_FORMAT_CSO); | ||
563 | writel(dma_addr, ctrl_base + SIS_PLAY_DMA_BASE); | ||
564 | writel(control, ctrl_base + SIS_PLAY_DMA_CONTROL); | ||
565 | writel(sso_eso, ctrl_base + SIS_PLAY_DMA_SSO_ESO); | ||
566 | |||
567 | for (reg = 0; reg < SIS_WAVE_SIZE; reg += 4) | ||
568 | writel(0, wave_base + reg); | ||
569 | |||
570 | writel(SIS_WAVE_GENERAL_WAVE_VOLUME, wave_base + SIS_WAVE_GENERAL); | ||
571 | writel(delta << 16, wave_base + SIS_WAVE_GENERAL_ARTICULATION); | ||
572 | writel(SIS_WAVE_CHANNEL_CONTROL_FIRST_SAMPLE | | ||
573 | SIS_WAVE_CHANNEL_CONTROL_AMP_ENABLE | | ||
574 | SIS_WAVE_CHANNEL_CONTROL_INTERPOLATE_ENABLE, | ||
575 | wave_base + SIS_WAVE_CHANNEL_CONTROL); | ||
576 | |||
577 | /* Force PCI writes to post. */ | ||
578 | readl(ctrl_base); | ||
579 | |||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | static int sis_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
584 | { | ||
585 | struct sis7019 *sis = snd_pcm_substream_chip(substream); | ||
586 | unsigned long io = sis->ioport; | ||
587 | struct snd_pcm_substream *s; | ||
588 | struct voice *voice; | ||
589 | void *chip; | ||
590 | int starting; | ||
591 | u32 record = 0; | ||
592 | u32 play[2] = { 0, 0 }; | ||
593 | |||
594 | /* No locks needed, as the PCM core will hold the locks on the | ||
595 | * substreams, and the HW will only start/stop the indicated voices | ||
596 | * without changing the state of the others. | ||
597 | */ | ||
598 | switch (cmd) { | ||
599 | case SNDRV_PCM_TRIGGER_START: | ||
600 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
601 | case SNDRV_PCM_TRIGGER_RESUME: | ||
602 | starting = 1; | ||
603 | break; | ||
604 | case SNDRV_PCM_TRIGGER_STOP: | ||
605 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
606 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
607 | starting = 0; | ||
608 | break; | ||
609 | default: | ||
610 | return -EINVAL; | ||
611 | } | ||
612 | |||
613 | snd_pcm_group_for_each_entry(s, substream) { | ||
614 | /* Make sure it is for us... */ | ||
615 | chip = snd_pcm_substream_chip(s); | ||
616 | if (chip != sis) | ||
617 | continue; | ||
618 | |||
619 | voice = s->runtime->private_data; | ||
620 | if (voice->flags & VOICE_CAPTURE) { | ||
621 | record |= 1 << voice->num; | ||
622 | voice = voice->timing; | ||
623 | } | ||
624 | |||
625 | /* voice could be NULL if this a recording stream, and it | ||
626 | * doesn't have an external timing channel. | ||
627 | */ | ||
628 | if (voice) | ||
629 | play[voice->num / 32] |= 1 << (voice->num & 0x1f); | ||
630 | |||
631 | snd_pcm_trigger_done(s, substream); | ||
632 | } | ||
633 | |||
634 | if (starting) { | ||
635 | if (record) | ||
636 | outl(record, io + SIS_RECORD_START_REG); | ||
637 | if (play[0]) | ||
638 | outl(play[0], io + SIS_PLAY_START_A_REG); | ||
639 | if (play[1]) | ||
640 | outl(play[1], io + SIS_PLAY_START_B_REG); | ||
641 | } else { | ||
642 | if (record) | ||
643 | outl(record, io + SIS_RECORD_STOP_REG); | ||
644 | if (play[0]) | ||
645 | outl(play[0], io + SIS_PLAY_STOP_A_REG); | ||
646 | if (play[1]) | ||
647 | outl(play[1], io + SIS_PLAY_STOP_B_REG); | ||
648 | } | ||
649 | return 0; | ||
650 | } | ||
651 | |||
652 | static snd_pcm_uframes_t sis_pcm_pointer(struct snd_pcm_substream *substream) | ||
653 | { | ||
654 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
655 | struct voice *voice = runtime->private_data; | ||
656 | u32 cso; | ||
657 | |||
658 | cso = readl(voice->ctrl_base + SIS_PLAY_DMA_FORMAT_CSO); | ||
659 | cso &= 0xffff; | ||
660 | return cso; | ||
661 | } | ||
662 | |||
663 | static int sis_capture_open(struct snd_pcm_substream *substream) | ||
664 | { | ||
665 | struct sis7019 *sis = snd_pcm_substream_chip(substream); | ||
666 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
667 | struct voice *voice = &sis->capture_voice; | ||
668 | unsigned long flags; | ||
669 | |||
670 | /* FIXME: The driver only supports recording from one channel | ||
671 | * at the moment, but it could support more. | ||
672 | */ | ||
673 | spin_lock_irqsave(&sis->voice_lock, flags); | ||
674 | if (voice->flags & VOICE_IN_USE) | ||
675 | voice = NULL; | ||
676 | else | ||
677 | voice->flags |= VOICE_IN_USE; | ||
678 | spin_unlock_irqrestore(&sis->voice_lock, flags); | ||
679 | |||
680 | if (!voice) | ||
681 | return -EAGAIN; | ||
682 | |||
683 | voice->substream = substream; | ||
684 | runtime->private_data = voice; | ||
685 | runtime->hw = sis_capture_hw_info; | ||
686 | runtime->hw.rates = sis->ac97[0]->rates[AC97_RATES_ADC]; | ||
687 | snd_pcm_limit_hw_rates(runtime); | ||
688 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, | ||
689 | 9, 0xfff9); | ||
690 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, | ||
691 | 9, 0xfff9); | ||
692 | snd_pcm_set_sync(substream); | ||
693 | return 0; | ||
694 | } | ||
695 | |||
696 | static int sis_capture_hw_params(struct snd_pcm_substream *substream, | ||
697 | struct snd_pcm_hw_params *hw_params) | ||
698 | { | ||
699 | struct sis7019 *sis = snd_pcm_substream_chip(substream); | ||
700 | int rc; | ||
701 | |||
702 | rc = snd_ac97_set_rate(sis->ac97[0], AC97_PCM_LR_ADC_RATE, | ||
703 | params_rate(hw_params)); | ||
704 | if (rc) | ||
705 | goto out; | ||
706 | |||
707 | rc = snd_pcm_lib_malloc_pages(substream, | ||
708 | params_buffer_bytes(hw_params)); | ||
709 | if (rc < 0) | ||
710 | goto out; | ||
711 | |||
712 | rc = sis_alloc_timing_voice(substream, hw_params); | ||
713 | |||
714 | out: | ||
715 | return rc; | ||
716 | } | ||
717 | |||
718 | static void sis_prepare_timing_voice(struct voice *voice, | ||
719 | struct snd_pcm_substream *substream) | ||
720 | { | ||
721 | struct sis7019 *sis = snd_pcm_substream_chip(substream); | ||
722 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
723 | struct voice *timing = voice->timing; | ||
724 | void __iomem *play_base = timing->ctrl_base; | ||
725 | void __iomem *wave_base = timing->wave_base; | ||
726 | u16 buffer_size, period_size; | ||
727 | u32 format, control, sso_eso, delta; | ||
728 | u32 vperiod, sso, reg; | ||
729 | |||
730 | /* Set our initial buffer and period as large as we can given a | ||
731 | * single page of silence. | ||
732 | */ | ||
733 | buffer_size = 4096 / runtime->channels; | ||
734 | buffer_size /= snd_pcm_format_size(runtime->format, 1); | ||
735 | period_size = buffer_size; | ||
736 | |||
737 | /* Initially, we want to interrupt just a bit behind the end of | ||
738 | * the period we're clocking out. 10 samples seems to give a good | ||
739 | * delay. | ||
740 | * | ||
741 | * We want to spread our interrupts throughout the virtual period, | ||
742 | * so that we don't end up with two interrupts back to back at the | ||
743 | * end -- this helps minimize the effects of any jitter. Adjust our | ||
744 | * clocking period size so that the last period is at least a fourth | ||
745 | * of a full period. | ||
746 | * | ||
747 | * This is all moot if we don't need to use virtual periods. | ||
748 | */ | ||
749 | vperiod = runtime->period_size + 10; | ||
750 | if (vperiod > period_size) { | ||
751 | u16 tail = vperiod % period_size; | ||
752 | u16 quarter_period = period_size / 4; | ||
753 | |||
754 | if (tail && tail < quarter_period) { | ||
755 | u16 loops = vperiod / period_size; | ||
756 | |||
757 | tail = quarter_period - tail; | ||
758 | tail += loops - 1; | ||
759 | tail /= loops; | ||
760 | period_size -= tail; | ||
761 | } | ||
762 | |||
763 | sso = period_size - 1; | ||
764 | } else { | ||
765 | /* The initial period will fit inside the buffer, so we | ||
766 | * don't need to use virtual periods -- disable them. | ||
767 | */ | ||
768 | period_size = runtime->period_size; | ||
769 | sso = vperiod - 1; | ||
770 | vperiod = 0; | ||
771 | } | ||
772 | |||
773 | /* The interrupt handler implements the timing syncronization, so | ||
774 | * setup its state. | ||
775 | */ | ||
776 | timing->flags |= VOICE_SYNC_TIMING; | ||
777 | timing->sync_base = voice->ctrl_base; | ||
778 | timing->sync_cso = runtime->period_size - 1; | ||
779 | timing->sync_period_size = runtime->period_size; | ||
780 | timing->sync_buffer_size = runtime->buffer_size; | ||
781 | timing->period_size = period_size; | ||
782 | timing->buffer_size = buffer_size; | ||
783 | timing->sso = sso; | ||
784 | timing->vperiod = vperiod; | ||
785 | |||
786 | /* Using unsigned samples with the all-zero silence buffer | ||
787 | * forces the output to the lower rail, killing playback. | ||
788 | * So ignore unsigned vs signed -- it doesn't change the timing. | ||
789 | */ | ||
790 | format = 0; | ||
791 | if (snd_pcm_format_width(runtime->format) == 8) | ||
792 | format = SIS_CAPTURE_DMA_FORMAT_8BIT; | ||
793 | if (runtime->channels == 1) | ||
794 | format |= SIS_CAPTURE_DMA_FORMAT_MONO; | ||
795 | |||
796 | control = timing->buffer_size - 1; | ||
797 | control |= SIS_PLAY_DMA_LOOP | SIS_PLAY_DMA_INTR_AT_SSO; | ||
798 | sso_eso = timing->buffer_size - 1; | ||
799 | sso_eso |= timing->sso << 16; | ||
800 | |||
801 | delta = sis_rate_to_delta(runtime->rate); | ||
802 | |||
803 | /* We've done the math, now configure the channel. | ||
804 | */ | ||
805 | writel(format, play_base + SIS_PLAY_DMA_FORMAT_CSO); | ||
806 | writel(sis->silence_dma_addr, play_base + SIS_PLAY_DMA_BASE); | ||
807 | writel(control, play_base + SIS_PLAY_DMA_CONTROL); | ||
808 | writel(sso_eso, play_base + SIS_PLAY_DMA_SSO_ESO); | ||
809 | |||
810 | for (reg = 0; reg < SIS_WAVE_SIZE; reg += 4) | ||
811 | writel(0, wave_base + reg); | ||
812 | |||
813 | writel(SIS_WAVE_GENERAL_WAVE_VOLUME, wave_base + SIS_WAVE_GENERAL); | ||
814 | writel(delta << 16, wave_base + SIS_WAVE_GENERAL_ARTICULATION); | ||
815 | writel(SIS_WAVE_CHANNEL_CONTROL_FIRST_SAMPLE | | ||
816 | SIS_WAVE_CHANNEL_CONTROL_AMP_ENABLE | | ||
817 | SIS_WAVE_CHANNEL_CONTROL_INTERPOLATE_ENABLE, | ||
818 | wave_base + SIS_WAVE_CHANNEL_CONTROL); | ||
819 | } | ||
820 | |||
821 | static int sis_pcm_capture_prepare(struct snd_pcm_substream *substream) | ||
822 | { | ||
823 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
824 | struct voice *voice = runtime->private_data; | ||
825 | void __iomem *rec_base = voice->ctrl_base; | ||
826 | u32 format, dma_addr, control; | ||
827 | u16 leo; | ||
828 | |||
829 | /* We rely on the PCM core to ensure that the parameters for this | ||
830 | * substream do not change on us while we're programming the HW. | ||
831 | */ | ||
832 | format = 0; | ||
833 | if (snd_pcm_format_width(runtime->format) == 8) | ||
834 | format = SIS_CAPTURE_DMA_FORMAT_8BIT; | ||
835 | if (!snd_pcm_format_signed(runtime->format)) | ||
836 | format |= SIS_CAPTURE_DMA_FORMAT_UNSIGNED; | ||
837 | if (runtime->channels == 1) | ||
838 | format |= SIS_CAPTURE_DMA_FORMAT_MONO; | ||
839 | |||
840 | dma_addr = runtime->dma_addr; | ||
841 | leo = runtime->buffer_size - 1; | ||
842 | control = leo | SIS_CAPTURE_DMA_LOOP; | ||
843 | |||
844 | /* If we've got more than two periods per buffer, then we have | ||
845 | * use a timing voice to clock out the periods. Otherwise, we can | ||
846 | * use the capture channel's interrupts. | ||
847 | */ | ||
848 | if (voice->timing) { | ||
849 | sis_prepare_timing_voice(voice, substream); | ||
850 | } else { | ||
851 | control |= SIS_CAPTURE_DMA_INTR_AT_LEO; | ||
852 | if (runtime->period_size != runtime->buffer_size) | ||
853 | control |= SIS_CAPTURE_DMA_INTR_AT_MLP; | ||
854 | } | ||
855 | |||
856 | writel(format, rec_base + SIS_CAPTURE_DMA_FORMAT_CSO); | ||
857 | writel(dma_addr, rec_base + SIS_CAPTURE_DMA_BASE); | ||
858 | writel(control, rec_base + SIS_CAPTURE_DMA_CONTROL); | ||
859 | |||
860 | /* Force the writes to post. */ | ||
861 | readl(rec_base); | ||
862 | |||
863 | return 0; | ||
864 | } | ||
865 | |||
866 | static struct snd_pcm_ops sis_playback_ops = { | ||
867 | .open = sis_playback_open, | ||
868 | .close = sis_substream_close, | ||
869 | .ioctl = snd_pcm_lib_ioctl, | ||
870 | .hw_params = sis_playback_hw_params, | ||
871 | .hw_free = sis_hw_free, | ||
872 | .prepare = sis_pcm_playback_prepare, | ||
873 | .trigger = sis_pcm_trigger, | ||
874 | .pointer = sis_pcm_pointer, | ||
875 | }; | ||
876 | |||
877 | static struct snd_pcm_ops sis_capture_ops = { | ||
878 | .open = sis_capture_open, | ||
879 | .close = sis_substream_close, | ||
880 | .ioctl = snd_pcm_lib_ioctl, | ||
881 | .hw_params = sis_capture_hw_params, | ||
882 | .hw_free = sis_hw_free, | ||
883 | .prepare = sis_pcm_capture_prepare, | ||
884 | .trigger = sis_pcm_trigger, | ||
885 | .pointer = sis_pcm_pointer, | ||
886 | }; | ||
887 | |||
888 | static int __devinit sis_pcm_create(struct sis7019 *sis) | ||
889 | { | ||
890 | struct snd_pcm *pcm; | ||
891 | int rc; | ||
892 | |||
893 | /* We have 64 voices, and the driver currently records from | ||
894 | * only one channel, though that could change in the future. | ||
895 | */ | ||
896 | rc = snd_pcm_new(sis->card, "SiS7019", 0, 64, 1, &pcm); | ||
897 | if (rc) | ||
898 | return rc; | ||
899 | |||
900 | pcm->private_data = sis; | ||
901 | strcpy(pcm->name, "SiS7019"); | ||
902 | sis->pcm = pcm; | ||
903 | |||
904 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &sis_playback_ops); | ||
905 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &sis_capture_ops); | ||
906 | |||
907 | /* Try to preallocate some memory, but it's not the end of the | ||
908 | * world if this fails. | ||
909 | */ | ||
910 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | ||
911 | snd_dma_pci_data(sis->pci), 64*1024, 128*1024); | ||
912 | |||
913 | return 0; | ||
914 | } | ||
915 | |||
916 | static unsigned short sis_ac97_rw(struct sis7019 *sis, int codec, u32 cmd) | ||
917 | { | ||
918 | unsigned long io = sis->ioport; | ||
919 | unsigned short val = 0xffff; | ||
920 | u16 status; | ||
921 | u16 rdy; | ||
922 | int count; | ||
923 | const static u16 codec_ready[3] = { | ||
924 | SIS_AC97_STATUS_CODEC_READY, | ||
925 | SIS_AC97_STATUS_CODEC2_READY, | ||
926 | SIS_AC97_STATUS_CODEC3_READY, | ||
927 | }; | ||
928 | |||
929 | rdy = codec_ready[codec]; | ||
930 | |||
931 | |||
932 | /* Get the AC97 semaphore -- software first, so we don't spin | ||
933 | * pounding out IO reads on the hardware semaphore... | ||
934 | */ | ||
935 | mutex_lock(&sis->ac97_mutex); | ||
936 | |||
937 | count = 0xffff; | ||
938 | while ((inw(io + SIS_AC97_SEMA) & SIS_AC97_SEMA_BUSY) && --count) | ||
939 | udelay(1); | ||
940 | |||
941 | if (!count) | ||
942 | goto timeout; | ||
943 | |||
944 | /* ... and wait for any outstanding commands to complete ... | ||
945 | */ | ||
946 | count = 0xffff; | ||
947 | do { | ||
948 | status = inw(io + SIS_AC97_STATUS); | ||
949 | if ((status & rdy) && !(status & SIS_AC97_STATUS_BUSY)) | ||
950 | break; | ||
951 | |||
952 | udelay(1); | ||
953 | } while (--count); | ||
954 | |||
955 | if (!count) | ||
956 | goto timeout_sema; | ||
957 | |||
958 | /* ... before sending our command and waiting for it to finish ... | ||
959 | */ | ||
960 | outl(cmd, io + SIS_AC97_CMD); | ||
961 | udelay(10); | ||
962 | |||
963 | count = 0xffff; | ||
964 | while ((inw(io + SIS_AC97_STATUS) & SIS_AC97_STATUS_BUSY) && --count) | ||
965 | udelay(1); | ||
966 | |||
967 | /* ... and reading the results (if any). | ||
968 | */ | ||
969 | val = inl(io + SIS_AC97_CMD) >> 16; | ||
970 | |||
971 | timeout_sema: | ||
972 | outl(SIS_AC97_SEMA_RELEASE, io + SIS_AC97_SEMA); | ||
973 | timeout: | ||
974 | mutex_unlock(&sis->ac97_mutex); | ||
975 | |||
976 | if (!count) { | ||
977 | printk(KERN_ERR "sis7019: ac97 codec %d timeout cmd 0x%08x\n", | ||
978 | codec, cmd); | ||
979 | } | ||
980 | |||
981 | return val; | ||
982 | } | ||
983 | |||
984 | static void sis_ac97_write(struct snd_ac97 *ac97, unsigned short reg, | ||
985 | unsigned short val) | ||
986 | { | ||
987 | const static u32 cmd[3] = { | ||
988 | SIS_AC97_CMD_CODEC_WRITE, | ||
989 | SIS_AC97_CMD_CODEC2_WRITE, | ||
990 | SIS_AC97_CMD_CODEC3_WRITE, | ||
991 | }; | ||
992 | sis_ac97_rw(ac97->private_data, ac97->num, | ||
993 | (val << 16) | (reg << 8) | cmd[ac97->num]); | ||
994 | } | ||
995 | |||
996 | static unsigned short sis_ac97_read(struct snd_ac97 *ac97, unsigned short reg) | ||
997 | { | ||
998 | const static u32 cmd[3] = { | ||
999 | SIS_AC97_CMD_CODEC_READ, | ||
1000 | SIS_AC97_CMD_CODEC2_READ, | ||
1001 | SIS_AC97_CMD_CODEC3_READ, | ||
1002 | }; | ||
1003 | return sis_ac97_rw(ac97->private_data, ac97->num, | ||
1004 | (reg << 8) | cmd[ac97->num]); | ||
1005 | } | ||
1006 | |||
1007 | static int __devinit sis_mixer_create(struct sis7019 *sis) | ||
1008 | { | ||
1009 | struct snd_ac97_bus *bus; | ||
1010 | struct snd_ac97_template ac97; | ||
1011 | static struct snd_ac97_bus_ops ops = { | ||
1012 | .write = sis_ac97_write, | ||
1013 | .read = sis_ac97_read, | ||
1014 | }; | ||
1015 | int rc; | ||
1016 | |||
1017 | memset(&ac97, 0, sizeof(ac97)); | ||
1018 | ac97.private_data = sis; | ||
1019 | |||
1020 | rc = snd_ac97_bus(sis->card, 0, &ops, NULL, &bus); | ||
1021 | if (!rc && sis->codecs_present & SIS_PRIMARY_CODEC_PRESENT) | ||
1022 | rc = snd_ac97_mixer(bus, &ac97, &sis->ac97[0]); | ||
1023 | ac97.num = 1; | ||
1024 | if (!rc && (sis->codecs_present & SIS_SECONDARY_CODEC_PRESENT)) | ||
1025 | rc = snd_ac97_mixer(bus, &ac97, &sis->ac97[1]); | ||
1026 | ac97.num = 2; | ||
1027 | if (!rc && (sis->codecs_present & SIS_TERTIARY_CODEC_PRESENT)) | ||
1028 | rc = snd_ac97_mixer(bus, &ac97, &sis->ac97[2]); | ||
1029 | |||
1030 | /* If we return an error here, then snd_card_free() should | ||
1031 | * free up any ac97 codecs that got created, as well as the bus. | ||
1032 | */ | ||
1033 | return rc; | ||
1034 | } | ||
1035 | |||
1036 | static void sis_free_suspend(struct sis7019 *sis) | ||
1037 | { | ||
1038 | int i; | ||
1039 | |||
1040 | for (i = 0; i < SIS_SUSPEND_PAGES; i++) | ||
1041 | kfree(sis->suspend_state[i]); | ||
1042 | } | ||
1043 | |||
1044 | static int sis_chip_free(struct sis7019 *sis) | ||
1045 | { | ||
1046 | /* Reset the chip, and disable all interrputs. | ||
1047 | */ | ||
1048 | outl(SIS_GCR_SOFTWARE_RESET, sis->ioport + SIS_GCR); | ||
1049 | udelay(10); | ||
1050 | outl(0, sis->ioport + SIS_GCR); | ||
1051 | outl(0, sis->ioport + SIS_GIER); | ||
1052 | |||
1053 | /* Now, free everything we allocated. | ||
1054 | */ | ||
1055 | if (sis->irq >= 0) | ||
1056 | free_irq(sis->irq, sis); | ||
1057 | |||
1058 | if (sis->ioaddr) | ||
1059 | iounmap(sis->ioaddr); | ||
1060 | |||
1061 | pci_release_regions(sis->pci); | ||
1062 | pci_disable_device(sis->pci); | ||
1063 | |||
1064 | sis_free_suspend(sis); | ||
1065 | return 0; | ||
1066 | } | ||
1067 | |||
1068 | static int sis_dev_free(struct snd_device *dev) | ||
1069 | { | ||
1070 | struct sis7019 *sis = dev->device_data; | ||
1071 | return sis_chip_free(sis); | ||
1072 | } | ||
1073 | |||
1074 | static int sis_chip_init(struct sis7019 *sis) | ||
1075 | { | ||
1076 | unsigned long io = sis->ioport; | ||
1077 | void __iomem *ioaddr = sis->ioaddr; | ||
1078 | u16 status; | ||
1079 | int count; | ||
1080 | int i; | ||
1081 | |||
1082 | /* Reset the audio controller | ||
1083 | */ | ||
1084 | outl(SIS_GCR_SOFTWARE_RESET, io + SIS_GCR); | ||
1085 | udelay(10); | ||
1086 | outl(0, io + SIS_GCR); | ||
1087 | |||
1088 | /* Get the AC-link semaphore, and reset the codecs | ||
1089 | */ | ||
1090 | count = 0xffff; | ||
1091 | while ((inw(io + SIS_AC97_SEMA) & SIS_AC97_SEMA_BUSY) && --count) | ||
1092 | udelay(1); | ||
1093 | |||
1094 | if (!count) | ||
1095 | return -EIO; | ||
1096 | |||
1097 | outl(SIS_AC97_CMD_CODEC_COLD_RESET, io + SIS_AC97_CMD); | ||
1098 | udelay(10); | ||
1099 | |||
1100 | count = 0xffff; | ||
1101 | while ((inw(io + SIS_AC97_STATUS) & SIS_AC97_STATUS_BUSY) && --count) | ||
1102 | udelay(1); | ||
1103 | |||
1104 | /* Now that we've finished the reset, find out what's attached. | ||
1105 | */ | ||
1106 | status = inl(io + SIS_AC97_STATUS); | ||
1107 | if (status & SIS_AC97_STATUS_CODEC_READY) | ||
1108 | sis->codecs_present |= SIS_PRIMARY_CODEC_PRESENT; | ||
1109 | if (status & SIS_AC97_STATUS_CODEC2_READY) | ||
1110 | sis->codecs_present |= SIS_SECONDARY_CODEC_PRESENT; | ||
1111 | if (status & SIS_AC97_STATUS_CODEC3_READY) | ||
1112 | sis->codecs_present |= SIS_TERTIARY_CODEC_PRESENT; | ||
1113 | |||
1114 | /* All done, let go of the semaphore, and check for errors | ||
1115 | */ | ||
1116 | outl(SIS_AC97_SEMA_RELEASE, io + SIS_AC97_SEMA); | ||
1117 | if (!sis->codecs_present || !count) | ||
1118 | return -EIO; | ||
1119 | |||
1120 | /* Let the hardware know that the audio driver is alive, | ||
1121 | * and enable PCM slots on the AC-link for L/R playback (3 & 4) and | ||
1122 | * record channels. We're going to want to use Variable Rate Audio | ||
1123 | * for recording, to avoid needlessly resampling from 48kHZ. | ||
1124 | */ | ||
1125 | outl(SIS_AC97_CONF_AUDIO_ALIVE, io + SIS_AC97_CONF); | ||
1126 | outl(SIS_AC97_CONF_AUDIO_ALIVE | SIS_AC97_CONF_PCM_LR_ENABLE | | ||
1127 | SIS_AC97_CONF_PCM_CAP_MIC_ENABLE | | ||
1128 | SIS_AC97_CONF_PCM_CAP_LR_ENABLE | | ||
1129 | SIS_AC97_CONF_CODEC_VRA_ENABLE, io + SIS_AC97_CONF); | ||
1130 | |||
1131 | /* All AC97 PCM slots should be sourced from sub-mixer 0. | ||
1132 | */ | ||
1133 | outl(0, io + SIS_AC97_PSR); | ||
1134 | |||
1135 | /* There is only one valid DMA setup for a PCI environment. | ||
1136 | */ | ||
1137 | outl(SIS_DMA_CSR_PCI_SETTINGS, io + SIS_DMA_CSR); | ||
1138 | |||
1139 | /* Reset the syncronization groups for all of the channels | ||
1140 | * to be asyncronous. If we start doing SPDIF or 5.1 sound, etc. | ||
1141 | * we'll need to change how we handle these. Until then, we just | ||
1142 | * assign sub-mixer 0 to all playback channels, and avoid any | ||
1143 | * attenuation on the audio. | ||
1144 | */ | ||
1145 | outl(0, io + SIS_PLAY_SYNC_GROUP_A); | ||
1146 | outl(0, io + SIS_PLAY_SYNC_GROUP_B); | ||
1147 | outl(0, io + SIS_PLAY_SYNC_GROUP_C); | ||
1148 | outl(0, io + SIS_PLAY_SYNC_GROUP_D); | ||
1149 | outl(0, io + SIS_MIXER_SYNC_GROUP); | ||
1150 | |||
1151 | for (i = 0; i < 64; i++) { | ||
1152 | writel(i, SIS_MIXER_START_ADDR(ioaddr, i)); | ||
1153 | writel(SIS_MIXER_RIGHT_NO_ATTEN | SIS_MIXER_LEFT_NO_ATTEN | | ||
1154 | SIS_MIXER_DEST_0, SIS_MIXER_ADDR(ioaddr, i)); | ||
1155 | } | ||
1156 | |||
1157 | /* Don't attenuate any audio set for the wave amplifier. | ||
1158 | * | ||
1159 | * FIXME: Maximum attenuation is set for the music amp, which will | ||
1160 | * need to change if we start using the synth engine. | ||
1161 | */ | ||
1162 | outl(0xffff0000, io + SIS_WEVCR); | ||
1163 | |||
1164 | /* Ensure that the wave engine is in normal operating mode. | ||
1165 | */ | ||
1166 | outl(0, io + SIS_WECCR); | ||
1167 | |||
1168 | /* Go ahead and enable the DMA interrupts. They won't go live | ||
1169 | * until we start a channel. | ||
1170 | */ | ||
1171 | outl(SIS_GIER_AUDIO_PLAY_DMA_IRQ_ENABLE | | ||
1172 | SIS_GIER_AUDIO_RECORD_DMA_IRQ_ENABLE, io + SIS_GIER); | ||
1173 | |||
1174 | return 0; | ||
1175 | } | ||
1176 | |||
1177 | #ifdef CONFIG_PM | ||
1178 | static int sis_suspend(struct pci_dev *pci, pm_message_t state) | ||
1179 | { | ||
1180 | struct snd_card *card = pci_get_drvdata(pci); | ||
1181 | struct sis7019 *sis = card->private_data; | ||
1182 | void __iomem *ioaddr = sis->ioaddr; | ||
1183 | int i; | ||
1184 | |||
1185 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | ||
1186 | snd_pcm_suspend_all(sis->pcm); | ||
1187 | if (sis->codecs_present & SIS_PRIMARY_CODEC_PRESENT) | ||
1188 | snd_ac97_suspend(sis->ac97[0]); | ||
1189 | if (sis->codecs_present & SIS_SECONDARY_CODEC_PRESENT) | ||
1190 | snd_ac97_suspend(sis->ac97[1]); | ||
1191 | if (sis->codecs_present & SIS_TERTIARY_CODEC_PRESENT) | ||
1192 | snd_ac97_suspend(sis->ac97[2]); | ||
1193 | |||
1194 | /* snd_pcm_suspend_all() stopped all channels, so we're quiescent. | ||
1195 | */ | ||
1196 | if (sis->irq >= 0) { | ||
1197 | synchronize_irq(sis->irq); | ||
1198 | free_irq(sis->irq, sis); | ||
1199 | sis->irq = -1; | ||
1200 | } | ||
1201 | |||
1202 | /* Save the internal state away | ||
1203 | */ | ||
1204 | for (i = 0; i < 4; i++) { | ||
1205 | memcpy_fromio(sis->suspend_state[i], ioaddr, 4096); | ||
1206 | ioaddr += 4096; | ||
1207 | } | ||
1208 | |||
1209 | pci_disable_device(pci); | ||
1210 | pci_save_state(pci); | ||
1211 | pci_set_power_state(pci, pci_choose_state(pci, state)); | ||
1212 | return 0; | ||
1213 | } | ||
1214 | |||
1215 | static int sis_resume(struct pci_dev *pci) | ||
1216 | { | ||
1217 | struct snd_card *card = pci_get_drvdata(pci); | ||
1218 | struct sis7019 *sis = card->private_data; | ||
1219 | void __iomem *ioaddr = sis->ioaddr; | ||
1220 | int i; | ||
1221 | |||
1222 | pci_set_power_state(pci, PCI_D0); | ||
1223 | pci_restore_state(pci); | ||
1224 | |||
1225 | if (pci_enable_device(pci) < 0) { | ||
1226 | printk(KERN_ERR "sis7019: unable to re-enable device\n"); | ||
1227 | goto error; | ||
1228 | } | ||
1229 | |||
1230 | if (sis_chip_init(sis)) { | ||
1231 | printk(KERN_ERR "sis7019: unable to re-init controller\n"); | ||
1232 | goto error; | ||
1233 | } | ||
1234 | |||
1235 | if (request_irq(pci->irq, sis_interrupt, IRQF_DISABLED|IRQF_SHARED, | ||
1236 | card->shortname, sis)) { | ||
1237 | printk(KERN_ERR "sis7019: unable to regain IRQ %d\n", pci->irq); | ||
1238 | goto error; | ||
1239 | } | ||
1240 | |||
1241 | /* Restore saved state, then clear out the page we use for the | ||
1242 | * silence buffer. | ||
1243 | */ | ||
1244 | for (i = 0; i < 4; i++) { | ||
1245 | memcpy_toio(ioaddr, sis->suspend_state[i], 4096); | ||
1246 | ioaddr += 4096; | ||
1247 | } | ||
1248 | |||
1249 | memset(sis->suspend_state[0], 0, 4096); | ||
1250 | |||
1251 | sis->irq = pci->irq; | ||
1252 | pci_set_master(pci); | ||
1253 | |||
1254 | if (sis->codecs_present & SIS_PRIMARY_CODEC_PRESENT) | ||
1255 | snd_ac97_resume(sis->ac97[0]); | ||
1256 | if (sis->codecs_present & SIS_SECONDARY_CODEC_PRESENT) | ||
1257 | snd_ac97_resume(sis->ac97[1]); | ||
1258 | if (sis->codecs_present & SIS_TERTIARY_CODEC_PRESENT) | ||
1259 | snd_ac97_resume(sis->ac97[2]); | ||
1260 | |||
1261 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | ||
1262 | return 0; | ||
1263 | |||
1264 | error: | ||
1265 | snd_card_disconnect(card); | ||
1266 | return -EIO; | ||
1267 | } | ||
1268 | #endif /* CONFIG_PM */ | ||
1269 | |||
1270 | static int sis_alloc_suspend(struct sis7019 *sis) | ||
1271 | { | ||
1272 | int i; | ||
1273 | |||
1274 | /* We need 16K to store the internal wave engine state during a | ||
1275 | * suspend, but we don't need it to be contiguous, so play nice | ||
1276 | * with the memory system. We'll also use this area for a silence | ||
1277 | * buffer. | ||
1278 | */ | ||
1279 | for (i = 0; i < SIS_SUSPEND_PAGES; i++) { | ||
1280 | sis->suspend_state[i] = kmalloc(4096, GFP_KERNEL); | ||
1281 | if (!sis->suspend_state[i]) | ||
1282 | return -ENOMEM; | ||
1283 | } | ||
1284 | memset(sis->suspend_state[0], 0, 4096); | ||
1285 | |||
1286 | return 0; | ||
1287 | } | ||
1288 | |||
1289 | static int __devinit sis_chip_create(struct snd_card *card, | ||
1290 | struct pci_dev *pci) | ||
1291 | { | ||
1292 | struct sis7019 *sis = card->private_data; | ||
1293 | struct voice *voice; | ||
1294 | static struct snd_device_ops ops = { | ||
1295 | .dev_free = sis_dev_free, | ||
1296 | }; | ||
1297 | int rc; | ||
1298 | int i; | ||
1299 | |||
1300 | rc = pci_enable_device(pci); | ||
1301 | if (rc) | ||
1302 | goto error_out; | ||
1303 | |||
1304 | if (pci_set_dma_mask(pci, DMA_30BIT_MASK) < 0) { | ||
1305 | printk(KERN_ERR "sis7019: architecture does not support " | ||
1306 | "30-bit PCI busmaster DMA"); | ||
1307 | goto error_out_enabled; | ||
1308 | } | ||
1309 | |||
1310 | memset(sis, 0, sizeof(*sis)); | ||
1311 | mutex_init(&sis->ac97_mutex); | ||
1312 | spin_lock_init(&sis->voice_lock); | ||
1313 | sis->card = card; | ||
1314 | sis->pci = pci; | ||
1315 | sis->irq = -1; | ||
1316 | sis->ioport = pci_resource_start(pci, 0); | ||
1317 | |||
1318 | rc = pci_request_regions(pci, "SiS7019"); | ||
1319 | if (rc) { | ||
1320 | printk(KERN_ERR "sis7019: unable request regions\n"); | ||
1321 | goto error_out_enabled; | ||
1322 | } | ||
1323 | |||
1324 | rc = -EIO; | ||
1325 | sis->ioaddr = ioremap_nocache(pci_resource_start(pci, 1), 0x4000); | ||
1326 | if (!sis->ioaddr) { | ||
1327 | printk(KERN_ERR "sis7019: unable to remap MMIO, aborting\n"); | ||
1328 | goto error_out_cleanup; | ||
1329 | } | ||
1330 | |||
1331 | rc = sis_alloc_suspend(sis); | ||
1332 | if (rc < 0) { | ||
1333 | printk(KERN_ERR "sis7019: unable to allocate state storage\n"); | ||
1334 | goto error_out_cleanup; | ||
1335 | } | ||
1336 | |||
1337 | rc = sis_chip_init(sis); | ||
1338 | if (rc) | ||
1339 | goto error_out_cleanup; | ||
1340 | |||
1341 | if (request_irq(pci->irq, sis_interrupt, IRQF_DISABLED|IRQF_SHARED, | ||
1342 | card->shortname, sis)) { | ||
1343 | printk(KERN_ERR "unable to allocate irq %d\n", sis->irq); | ||
1344 | goto error_out_cleanup; | ||
1345 | } | ||
1346 | |||
1347 | sis->irq = pci->irq; | ||
1348 | pci_set_master(pci); | ||
1349 | |||
1350 | for (i = 0; i < 64; i++) { | ||
1351 | voice = &sis->voices[i]; | ||
1352 | voice->num = i; | ||
1353 | voice->ctrl_base = SIS_PLAY_DMA_ADDR(sis->ioaddr, i); | ||
1354 | voice->wave_base = SIS_WAVE_ADDR(sis->ioaddr, i); | ||
1355 | } | ||
1356 | |||
1357 | voice = &sis->capture_voice; | ||
1358 | voice->flags = VOICE_CAPTURE; | ||
1359 | voice->num = SIS_CAPTURE_CHAN_AC97_PCM_IN; | ||
1360 | voice->ctrl_base = SIS_CAPTURE_DMA_ADDR(sis->ioaddr, voice->num); | ||
1361 | |||
1362 | rc = snd_device_new(card, SNDRV_DEV_LOWLEVEL, sis, &ops); | ||
1363 | if (rc) | ||
1364 | goto error_out_cleanup; | ||
1365 | |||
1366 | snd_card_set_dev(card, &pci->dev); | ||
1367 | |||
1368 | return 0; | ||
1369 | |||
1370 | error_out_cleanup: | ||
1371 | sis_chip_free(sis); | ||
1372 | |||
1373 | error_out_enabled: | ||
1374 | pci_disable_device(pci); | ||
1375 | |||
1376 | error_out: | ||
1377 | return rc; | ||
1378 | } | ||
1379 | |||
1380 | static int __devinit snd_sis7019_probe(struct pci_dev *pci, | ||
1381 | const struct pci_device_id *pci_id) | ||
1382 | { | ||
1383 | struct snd_card *card; | ||
1384 | struct sis7019 *sis; | ||
1385 | int rc; | ||
1386 | |||
1387 | rc = -ENOENT; | ||
1388 | if (!enable) | ||
1389 | goto error_out; | ||
1390 | |||
1391 | rc = -ENOMEM; | ||
1392 | card = snd_card_new(index, id, THIS_MODULE, sizeof(*sis)); | ||
1393 | if (!card) | ||
1394 | goto error_out; | ||
1395 | |||
1396 | strcpy(card->driver, "SiS7019"); | ||
1397 | strcpy(card->shortname, "SiS7019"); | ||
1398 | rc = sis_chip_create(card, pci); | ||
1399 | if (rc) | ||
1400 | goto card_error_out; | ||
1401 | |||
1402 | sis = card->private_data; | ||
1403 | |||
1404 | rc = sis_mixer_create(sis); | ||
1405 | if (rc) | ||
1406 | goto card_error_out; | ||
1407 | |||
1408 | rc = sis_pcm_create(sis); | ||
1409 | if (rc) | ||
1410 | goto card_error_out; | ||
1411 | |||
1412 | snprintf(card->longname, sizeof(card->longname), | ||
1413 | "%s Audio Accelerator with %s at 0x%lx, irq %d", | ||
1414 | card->shortname, snd_ac97_get_short_name(sis->ac97[0]), | ||
1415 | sis->ioport, sis->irq); | ||
1416 | |||
1417 | rc = snd_card_register(card); | ||
1418 | if (rc) | ||
1419 | goto card_error_out; | ||
1420 | |||
1421 | pci_set_drvdata(pci, card); | ||
1422 | return 0; | ||
1423 | |||
1424 | card_error_out: | ||
1425 | snd_card_free(card); | ||
1426 | |||
1427 | error_out: | ||
1428 | return rc; | ||
1429 | } | ||
1430 | |||
1431 | static void __devexit snd_sis7019_remove(struct pci_dev *pci) | ||
1432 | { | ||
1433 | snd_card_free(pci_get_drvdata(pci)); | ||
1434 | pci_set_drvdata(pci, NULL); | ||
1435 | } | ||
1436 | |||
1437 | static struct pci_driver sis7019_driver = { | ||
1438 | .name = "SiS7019", | ||
1439 | .id_table = snd_sis7019_ids, | ||
1440 | .probe = snd_sis7019_probe, | ||
1441 | .remove = __devexit_p(snd_sis7019_remove), | ||
1442 | |||
1443 | #ifdef CONFIG_PM | ||
1444 | .suspend = sis_suspend, | ||
1445 | .resume = sis_resume, | ||
1446 | #endif | ||
1447 | }; | ||
1448 | |||
1449 | static int __init sis7019_init(void) | ||
1450 | { | ||
1451 | return pci_register_driver(&sis7019_driver); | ||
1452 | } | ||
1453 | |||
1454 | static void __exit sis7019_exit(void) | ||
1455 | { | ||
1456 | pci_unregister_driver(&sis7019_driver); | ||
1457 | } | ||
1458 | |||
1459 | module_init(sis7019_init); | ||
1460 | module_exit(sis7019_exit); | ||
diff --git a/sound/pci/sis7019.h b/sound/pci/sis7019.h new file mode 100644 index 000000000000..013b6739a742 --- /dev/null +++ b/sound/pci/sis7019.h | |||
@@ -0,0 +1,342 @@ | |||
1 | #ifndef __sis7019_h__ | ||
2 | #define __sis7019_h__ | ||
3 | |||
4 | /* | ||
5 | * Definitions for SiS7019 Audio Accelerator | ||
6 | * | ||
7 | * Copyright (C) 2004-2007, David Dillow | ||
8 | * Written by David Dillow <dave@thedillows.org> | ||
9 | * Inspired by the Trident 4D-WaveDX/NX driver. | ||
10 | * | ||
11 | * All rights reserved. | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation, version 2. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
25 | */ | ||
26 | |||
27 | |||
28 | /* General Control Register */ | ||
29 | #define SIS_GCR 0x00 | ||
30 | #define SIS_GCR_MACRO_POWER_DOWN 0x80000000 | ||
31 | #define SIS_GCR_MODEM_ENABLE 0x00010000 | ||
32 | #define SIS_GCR_SOFTWARE_RESET 0x00000001 | ||
33 | |||
34 | /* General Interrupt Enable Register */ | ||
35 | #define SIS_GIER 0x04 | ||
36 | #define SIS_GIER_MODEM_TIMER_IRQ_ENABLE 0x00100000 | ||
37 | #define SIS_GIER_MODEM_RX_DMA_IRQ_ENABLE 0x00080000 | ||
38 | #define SIS_GIER_MODEM_TX_DMA_IRQ_ENABLE 0x00040000 | ||
39 | #define SIS_GIER_AC97_GPIO1_IRQ_ENABLE 0x00020000 | ||
40 | #define SIS_GIER_AC97_GPIO0_IRQ_ENABLE 0x00010000 | ||
41 | #define SIS_GIER_AC97_SAMPLE_TIMER_IRQ_ENABLE 0x00000010 | ||
42 | #define SIS_GIER_AUDIO_GLOBAL_TIMER_IRQ_ENABLE 0x00000008 | ||
43 | #define SIS_GIER_AUDIO_RECORD_DMA_IRQ_ENABLE 0x00000004 | ||
44 | #define SIS_GIER_AUDIO_PLAY_DMA_IRQ_ENABLE 0x00000002 | ||
45 | #define SIS_GIER_AUDIO_WAVE_ENGINE_IRQ_ENABLE 0x00000001 | ||
46 | |||
47 | /* General Interrupt Status Register */ | ||
48 | #define SIS_GISR 0x08 | ||
49 | #define SIS_GISR_MODEM_TIMER_IRQ_STATUS 0x00100000 | ||
50 | #define SIS_GISR_MODEM_RX_DMA_IRQ_STATUS 0x00080000 | ||
51 | #define SIS_GISR_MODEM_TX_DMA_IRQ_STATUS 0x00040000 | ||
52 | #define SIS_GISR_AC97_GPIO1_IRQ_STATUS 0x00020000 | ||
53 | #define SIS_GISR_AC97_GPIO0_IRQ_STATUS 0x00010000 | ||
54 | #define SIS_GISR_AC97_SAMPLE_TIMER_IRQ_STATUS 0x00000010 | ||
55 | #define SIS_GISR_AUDIO_GLOBAL_TIMER_IRQ_STATUS 0x00000008 | ||
56 | #define SIS_GISR_AUDIO_RECORD_DMA_IRQ_STATUS 0x00000004 | ||
57 | #define SIS_GISR_AUDIO_PLAY_DMA_IRQ_STATUS 0x00000002 | ||
58 | #define SIS_GISR_AUDIO_WAVE_ENGINE_IRQ_STATUS 0x00000001 | ||
59 | |||
60 | /* DMA Control Register */ | ||
61 | #define SIS_DMA_CSR 0x10 | ||
62 | #define SIS_DMA_CSR_PCI_SETTINGS 0x0000001d | ||
63 | #define SIS_DMA_CSR_CONCURRENT_ENABLE 0x00000200 | ||
64 | #define SIS_DMA_CSR_PIPELINE_ENABLE 0x00000100 | ||
65 | #define SIS_DMA_CSR_RX_DRAIN_ENABLE 0x00000010 | ||
66 | #define SIS_DMA_CSR_RX_FILL_ENABLE 0x00000008 | ||
67 | #define SIS_DMA_CSR_TX_DRAIN_ENABLE 0x00000004 | ||
68 | #define SIS_DMA_CSR_TX_LOWPRI_FILL_ENABLE 0x00000002 | ||
69 | #define SIS_DMA_CSR_TX_HIPRI_FILL_ENABLE 0x00000001 | ||
70 | |||
71 | /* Playback Channel Start Registers */ | ||
72 | #define SIS_PLAY_START_A_REG 0x14 | ||
73 | #define SIS_PLAY_START_B_REG 0x18 | ||
74 | |||
75 | /* Playback Channel Stop Registers */ | ||
76 | #define SIS_PLAY_STOP_A_REG 0x1c | ||
77 | #define SIS_PLAY_STOP_B_REG 0x20 | ||
78 | |||
79 | /* Recording Channel Start Register */ | ||
80 | #define SIS_RECORD_START_REG 0x24 | ||
81 | |||
82 | /* Recording Channel Stop Register */ | ||
83 | #define SIS_RECORD_STOP_REG 0x28 | ||
84 | |||
85 | /* Playback Interrupt Status Registers */ | ||
86 | #define SIS_PISR_A 0x2c | ||
87 | #define SIS_PISR_B 0x30 | ||
88 | |||
89 | /* Recording Interrupt Status Register */ | ||
90 | #define SIS_RISR 0x34 | ||
91 | |||
92 | /* AC97 AC-link Playback Source Register */ | ||
93 | #define SIS_AC97_PSR 0x40 | ||
94 | #define SIS_AC97_PSR_MODEM_HEADSET_SRC_MIXER 0x0f000000 | ||
95 | #define SIS_AC97_PSR_MODEM_LINE2_SRC_MIXER 0x00f00000 | ||
96 | #define SIS_AC97_PSR_MODEM_LINE1_SRC_MIXER 0x000f0000 | ||
97 | #define SIS_AC97_PSR_PCM_LFR_SRC_MIXER 0x0000f000 | ||
98 | #define SIS_AC97_PSR_PCM_SURROUND_SRC_MIXER 0x00000f00 | ||
99 | #define SIS_AC97_PSR_PCM_CENTER_SRC_MIXER 0x000000f0 | ||
100 | #define SIS_AC97_PSR_PCM_LR_SRC_MIXER 0x0000000f | ||
101 | |||
102 | /* AC97 AC-link Command Register */ | ||
103 | #define SIS_AC97_CMD 0x50 | ||
104 | #define SIS_AC97_CMD_DATA_MASK 0xffff0000 | ||
105 | #define SIS_AC97_CMD_REG_MASK 0x0000ff00 | ||
106 | #define SIS_AC97_CMD_CODEC3_READ 0x0000000d | ||
107 | #define SIS_AC97_CMD_CODEC3_WRITE 0x0000000c | ||
108 | #define SIS_AC97_CMD_CODEC2_READ 0x0000000b | ||
109 | #define SIS_AC97_CMD_CODEC2_WRITE 0x0000000a | ||
110 | #define SIS_AC97_CMD_CODEC_READ 0x00000009 | ||
111 | #define SIS_AC97_CMD_CODEC_WRITE 0x00000008 | ||
112 | #define SIS_AC97_CMD_CODEC_WARM_RESET 0x00000005 | ||
113 | #define SIS_AC97_CMD_CODEC_COLD_RESET 0x00000004 | ||
114 | #define SIS_AC97_CMD_DONE 0x00000000 | ||
115 | |||
116 | /* AC97 AC-link Semaphore Register */ | ||
117 | #define SIS_AC97_SEMA 0x54 | ||
118 | #define SIS_AC97_SEMA_BUSY 0x00000001 | ||
119 | #define SIS_AC97_SEMA_RELEASE 0x00000000 | ||
120 | |||
121 | /* AC97 AC-link Status Register */ | ||
122 | #define SIS_AC97_STATUS 0x58 | ||
123 | #define SIS_AC97_STATUS_AUDIO_D2_INACT_SECS 0x03f00000 | ||
124 | #define SIS_AC97_STATUS_MODEM_ALIVE 0x00002000 | ||
125 | #define SIS_AC97_STATUS_AUDIO_ALIVE 0x00001000 | ||
126 | #define SIS_AC97_STATUS_CODEC3_READY 0x00000400 | ||
127 | #define SIS_AC97_STATUS_CODEC2_READY 0x00000200 | ||
128 | #define SIS_AC97_STATUS_CODEC_READY 0x00000100 | ||
129 | #define SIS_AC97_STATUS_WARM_RESET 0x00000080 | ||
130 | #define SIS_AC97_STATUS_COLD_RESET 0x00000040 | ||
131 | #define SIS_AC97_STATUS_POWERED_DOWN 0x00000020 | ||
132 | #define SIS_AC97_STATUS_NORMAL 0x00000010 | ||
133 | #define SIS_AC97_STATUS_READ_EXPIRED 0x00000004 | ||
134 | #define SIS_AC97_STATUS_SEMAPHORE 0x00000002 | ||
135 | #define SIS_AC97_STATUS_BUSY 0x00000001 | ||
136 | |||
137 | /* AC97 AC-link Audio Configuration Register */ | ||
138 | #define SIS_AC97_CONF 0x5c | ||
139 | #define SIS_AC97_CONF_AUDIO_ALIVE 0x80000000 | ||
140 | #define SIS_AC97_CONF_WARM_RESET_ENABLE 0x40000000 | ||
141 | #define SIS_AC97_CONF_PR6_ENABLE 0x20000000 | ||
142 | #define SIS_AC97_CONF_PR5_ENABLE 0x10000000 | ||
143 | #define SIS_AC97_CONF_PR4_ENABLE 0x08000000 | ||
144 | #define SIS_AC97_CONF_PR3_ENABLE 0x04000000 | ||
145 | #define SIS_AC97_CONF_PR2_PR7_ENABLE 0x02000000 | ||
146 | #define SIS_AC97_CONF_PR0_PR1_ENABLE 0x01000000 | ||
147 | #define SIS_AC97_CONF_AUTO_PM_ENABLE 0x00800000 | ||
148 | #define SIS_AC97_CONF_PCM_LFE_ENABLE 0x00080000 | ||
149 | #define SIS_AC97_CONF_PCM_SURROUND_ENABLE 0x00040000 | ||
150 | #define SIS_AC97_CONF_PCM_CENTER_ENABLE 0x00020000 | ||
151 | #define SIS_AC97_CONF_PCM_LR_ENABLE 0x00010000 | ||
152 | #define SIS_AC97_CONF_PCM_CAP_MIC_ENABLE 0x00002000 | ||
153 | #define SIS_AC97_CONF_PCM_CAP_LR_ENABLE 0x00001000 | ||
154 | #define SIS_AC97_CONF_PCM_CAP_MIC_FROM_CODEC3 0x00000200 | ||
155 | #define SIS_AC97_CONF_PCM_CAP_LR_FROM_CODEC3 0x00000100 | ||
156 | #define SIS_AC97_CONF_CODEC3_PM_VRM 0x00000080 | ||
157 | #define SIS_AC97_CONF_CODEC_PM_VRM 0x00000040 | ||
158 | #define SIS_AC97_CONF_CODEC3_VRA_ENABLE 0x00000020 | ||
159 | #define SIS_AC97_CONF_CODEC_VRA_ENABLE 0x00000010 | ||
160 | #define SIS_AC97_CONF_CODEC3_PM_EAC 0x00000008 | ||
161 | #define SIS_AC97_CONF_CODEC_PM_EAC 0x00000004 | ||
162 | #define SIS_AC97_CONF_CODEC3_EXISTS 0x00000002 | ||
163 | #define SIS_AC97_CONF_CODEC_EXISTS 0x00000001 | ||
164 | |||
165 | /* Playback Channel Sync Group registers */ | ||
166 | #define SIS_PLAY_SYNC_GROUP_A 0x80 | ||
167 | #define SIS_PLAY_SYNC_GROUP_B 0x84 | ||
168 | #define SIS_PLAY_SYNC_GROUP_C 0x88 | ||
169 | #define SIS_PLAY_SYNC_GROUP_D 0x8c | ||
170 | #define SIS_MIXER_SYNC_GROUP 0x90 | ||
171 | |||
172 | /* Wave Engine Config and Control Register */ | ||
173 | #define SIS_WECCR 0xa0 | ||
174 | #define SIS_WECCR_TESTMODE_MASK 0x00300000 | ||
175 | #define SIS_WECCR_TESTMODE_NORMAL 0x00000000 | ||
176 | #define SIS_WECCR_TESTMODE_BYPASS_NSO_ALPHA 0x00100000 | ||
177 | #define SIS_WECCR_TESTMODE_BYPASS_FC 0x00200000 | ||
178 | #define SIS_WECCR_TESTMODE_BYPASS_WOL 0x00300000 | ||
179 | #define SIS_WECCR_RESONANCE_DELAY_MASK 0x00060000 | ||
180 | #define SIS_WECCR_RESONANCE_DELAY_NONE 0x00000000 | ||
181 | #define SIS_WECCR_RESONANCE_DELAY_FC_1F00 0x00020000 | ||
182 | #define SIS_WECCR_RESONANCE_DELAY_FC_1E00 0x00040000 | ||
183 | #define SIS_WECCR_RESONANCE_DELAY_FC_1C00 0x00060000 | ||
184 | #define SIS_WECCR_IGNORE_CHANNEL_PARMS 0x00010000 | ||
185 | #define SIS_WECCR_COMMAND_CHANNEL_ID_MASK 0x0003ff00 | ||
186 | #define SIS_WECCR_COMMAND_MASK 0x00000007 | ||
187 | #define SIS_WECCR_COMMAND_NONE 0x00000000 | ||
188 | #define SIS_WECCR_COMMAND_DONE 0x00000000 | ||
189 | #define SIS_WECCR_COMMAND_PAUSE 0x00000001 | ||
190 | #define SIS_WECCR_COMMAND_TOGGLE_VEG 0x00000002 | ||
191 | #define SIS_WECCR_COMMAND_TOGGLE_MEG 0x00000003 | ||
192 | #define SIS_WECCR_COMMAND_TOGGLE_VEG_MEG 0x00000004 | ||
193 | |||
194 | /* Wave Engine Volume Control Register */ | ||
195 | #define SIS_WEVCR 0xa4 | ||
196 | #define SIS_WEVCR_LEFT_MUSIC_ATTENUATION_MASK 0xff000000 | ||
197 | #define SIS_WEVCR_RIGHT_MUSIC_ATTENUATION_MASK 0x00ff0000 | ||
198 | #define SIS_WEVCR_LEFT_WAVE_ATTENUATION_MASK 0x0000ff00 | ||
199 | #define SIS_WEVCR_RIGHT_WAVE_ATTENUATION_MASK 0x000000ff | ||
200 | |||
201 | /* Wave Engine Interrupt Status Registers */ | ||
202 | #define SIS_WEISR_A 0xa8 | ||
203 | #define SIS_WEISR_B 0xac | ||
204 | |||
205 | |||
206 | /* Playback DMA parameters (paramter RAM) */ | ||
207 | #define SIS_PLAY_DMA_OFFSET 0x0000 | ||
208 | #define SIS_PLAY_DMA_SIZE 0x10 | ||
209 | #define SIS_PLAY_DMA_ADDR(addr, num) \ | ||
210 | ((num * SIS_PLAY_DMA_SIZE) + (addr) + SIS_PLAY_DMA_OFFSET) | ||
211 | |||
212 | #define SIS_PLAY_DMA_FORMAT_CSO 0x00 | ||
213 | #define SIS_PLAY_DMA_FORMAT_UNSIGNED 0x00080000 | ||
214 | #define SIS_PLAY_DMA_FORMAT_8BIT 0x00040000 | ||
215 | #define SIS_PLAY_DMA_FORMAT_MONO 0x00020000 | ||
216 | #define SIS_PLAY_DMA_CSO_MASK 0x0000ffff | ||
217 | #define SIS_PLAY_DMA_BASE 0x04 | ||
218 | #define SIS_PLAY_DMA_CONTROL 0x08 | ||
219 | #define SIS_PLAY_DMA_STOP_AT_SSO 0x04000000 | ||
220 | #define SIS_PLAY_DMA_RELEASE 0x02000000 | ||
221 | #define SIS_PLAY_DMA_LOOP 0x01000000 | ||
222 | #define SIS_PLAY_DMA_INTR_AT_SSO 0x00080000 | ||
223 | #define SIS_PLAY_DMA_INTR_AT_ESO 0x00040000 | ||
224 | #define SIS_PLAY_DMA_INTR_AT_LEO 0x00020000 | ||
225 | #define SIS_PLAY_DMA_INTR_AT_MLP 0x00010000 | ||
226 | #define SIS_PLAY_DMA_LEO_MASK 0x0000ffff | ||
227 | #define SIS_PLAY_DMA_SSO_ESO 0x0c | ||
228 | #define SIS_PLAY_DMA_SSO_MASK 0xffff0000 | ||
229 | #define SIS_PLAY_DMA_ESO_MASK 0x0000ffff | ||
230 | |||
231 | /* Capture DMA parameters (paramter RAM) */ | ||
232 | #define SIS_CAPTURE_DMA_OFFSET 0x0800 | ||
233 | #define SIS_CAPTURE_DMA_SIZE 0x10 | ||
234 | #define SIS_CAPTURE_DMA_ADDR(addr, num) \ | ||
235 | ((num * SIS_CAPTURE_DMA_SIZE) + (addr) + SIS_CAPTURE_DMA_OFFSET) | ||
236 | |||
237 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_0 0 | ||
238 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_1 1 | ||
239 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_2 2 | ||
240 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_3 3 | ||
241 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_4 4 | ||
242 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_5 5 | ||
243 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_6 6 | ||
244 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_7 7 | ||
245 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_8 8 | ||
246 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_9 9 | ||
247 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_10 10 | ||
248 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_11 11 | ||
249 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_12 12 | ||
250 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_13 13 | ||
251 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_14 14 | ||
252 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_15 15 | ||
253 | #define SIS_CAPTURE_CHAN_AC97_PCM_IN 16 | ||
254 | #define SIS_CAPTURE_CHAN_AC97_MIC_IN 17 | ||
255 | #define SIS_CAPTURE_CHAN_AC97_LINE1_IN 18 | ||
256 | #define SIS_CAPTURE_CHAN_AC97_LINE2_IN 19 | ||
257 | #define SIS_CAPTURE_CHAN_AC97_HANDSE_IN 20 | ||
258 | |||
259 | #define SIS_CAPTURE_DMA_FORMAT_CSO 0x00 | ||
260 | #define SIS_CAPTURE_DMA_MONO_MODE_MASK 0xc0000000 | ||
261 | #define SIS_CAPTURE_DMA_MONO_MODE_AVG 0x00000000 | ||
262 | #define SIS_CAPTURE_DMA_MONO_MODE_LEFT 0x40000000 | ||
263 | #define SIS_CAPTURE_DMA_MONO_MODE_RIGHT 0x80000000 | ||
264 | #define SIS_CAPTURE_DMA_FORMAT_UNSIGNED 0x00080000 | ||
265 | #define SIS_CAPTURE_DMA_FORMAT_8BIT 0x00040000 | ||
266 | #define SIS_CAPTURE_DMA_FORMAT_MONO 0x00020000 | ||
267 | #define SIS_CAPTURE_DMA_CSO_MASK 0x0000ffff | ||
268 | #define SIS_CAPTURE_DMA_BASE 0x04 | ||
269 | #define SIS_CAPTURE_DMA_CONTROL 0x08 | ||
270 | #define SIS_CAPTURE_DMA_STOP_AT_SSO 0x04000000 | ||
271 | #define SIS_CAPTURE_DMA_RELEASE 0x02000000 | ||
272 | #define SIS_CAPTURE_DMA_LOOP 0x01000000 | ||
273 | #define SIS_CAPTURE_DMA_INTR_AT_LEO 0x00020000 | ||
274 | #define SIS_CAPTURE_DMA_INTR_AT_MLP 0x00010000 | ||
275 | #define SIS_CAPTURE_DMA_LEO_MASK 0x0000ffff | ||
276 | #define SIS_CAPTURE_DMA_RESERVED 0x0c | ||
277 | |||
278 | |||
279 | /* Mixer routing list start pointer (parameter RAM) */ | ||
280 | #define SIS_MIXER_START_OFFSET 0x1000 | ||
281 | #define SIS_MIXER_START_SIZE 0x04 | ||
282 | #define SIS_MIXER_START_ADDR(addr, num) \ | ||
283 | ((num * SIS_MIXER_START_SIZE) + (addr) + SIS_MIXER_START_OFFSET) | ||
284 | |||
285 | #define SIS_MIXER_START_MASK 0x0000007f | ||
286 | |||
287 | /* Mixer routing table (parameter RAM) */ | ||
288 | #define SIS_MIXER_OFFSET 0x1400 | ||
289 | #define SIS_MIXER_SIZE 0x04 | ||
290 | #define SIS_MIXER_ADDR(addr, num) \ | ||
291 | ((num * SIS_MIXER_SIZE) + (addr) + SIS_MIXER_OFFSET) | ||
292 | |||
293 | #define SIS_MIXER_RIGHT_ATTENUTATION_MASK 0xff000000 | ||
294 | #define SIS_MIXER_RIGHT_NO_ATTEN 0xff000000 | ||
295 | #define SIS_MIXER_LEFT_ATTENUTATION_MASK 0x00ff0000 | ||
296 | #define SIS_MIXER_LEFT_NO_ATTEN 0x00ff0000 | ||
297 | #define SIS_MIXER_NEXT_ENTRY_MASK 0x00007f00 | ||
298 | #define SIS_MIXER_NEXT_ENTRY_NONE 0x00000000 | ||
299 | #define SIS_MIXER_DEST_MASK 0x0000007f | ||
300 | #define SIS_MIXER_DEST_0 0x00000020 | ||
301 | #define SIS_MIXER_DEST_1 0x00000021 | ||
302 | #define SIS_MIXER_DEST_2 0x00000022 | ||
303 | #define SIS_MIXER_DEST_3 0x00000023 | ||
304 | #define SIS_MIXER_DEST_4 0x00000024 | ||
305 | #define SIS_MIXER_DEST_5 0x00000025 | ||
306 | #define SIS_MIXER_DEST_6 0x00000026 | ||
307 | #define SIS_MIXER_DEST_7 0x00000027 | ||
308 | #define SIS_MIXER_DEST_8 0x00000028 | ||
309 | #define SIS_MIXER_DEST_9 0x00000029 | ||
310 | #define SIS_MIXER_DEST_10 0x0000002a | ||
311 | #define SIS_MIXER_DEST_11 0x0000002b | ||
312 | #define SIS_MIXER_DEST_12 0x0000002c | ||
313 | #define SIS_MIXER_DEST_13 0x0000002d | ||
314 | #define SIS_MIXER_DEST_14 0x0000002e | ||
315 | #define SIS_MIXER_DEST_15 0x0000002f | ||
316 | |||
317 | /* Wave Engine Control Parameters (parameter RAM) */ | ||
318 | #define SIS_WAVE_OFFSET 0x2000 | ||
319 | #define SIS_WAVE_SIZE 0x40 | ||
320 | #define SIS_WAVE_ADDR(addr, num) \ | ||
321 | ((num * SIS_WAVE_SIZE) + (addr) + SIS_WAVE_OFFSET) | ||
322 | |||
323 | #define SIS_WAVE_GENERAL 0x00 | ||
324 | #define SIS_WAVE_GENERAL_WAVE_VOLUME 0x80000000 | ||
325 | #define SIS_WAVE_GENERAL_MUSIC_VOLUME 0x00000000 | ||
326 | #define SIS_WAVE_GENERAL_VOLUME_MASK 0x7f000000 | ||
327 | #define SIS_WAVE_GENERAL_ARTICULATION 0x04 | ||
328 | #define SIS_WAVE_GENERAL_ARTICULATION_DELTA_MASK 0x3fff0000 | ||
329 | #define SIS_WAVE_ARTICULATION 0x08 | ||
330 | #define SIS_WAVE_TIMER 0x0c | ||
331 | #define SIS_WAVE_GENERATOR 0x10 | ||
332 | #define SIS_WAVE_CHANNEL_CONTROL 0x14 | ||
333 | #define SIS_WAVE_CHANNEL_CONTROL_FIRST_SAMPLE 0x80000000 | ||
334 | #define SIS_WAVE_CHANNEL_CONTROL_AMP_ENABLE 0x40000000 | ||
335 | #define SIS_WAVE_CHANNEL_CONTROL_FILTER_ENABLE 0x20000000 | ||
336 | #define SIS_WAVE_CHANNEL_CONTROL_INTERPOLATE_ENABLE 0x10000000 | ||
337 | #define SIS_WAVE_LFO_EG_CONTROL 0x18 | ||
338 | #define SIS_WAVE_LFO_EG_CONTROL_2 0x1c | ||
339 | #define SIS_WAVE_LFO_EG_CONTROL_3 0x20 | ||
340 | #define SIS_WAVE_LFO_EG_CONTROL_4 0x24 | ||
341 | |||
342 | #endif /* __sis7019_h__ */ | ||
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index 44a7f5fad573..0d3d305b0a0b 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c | |||
@@ -22,7 +22,6 @@ | |||
22 | * | 22 | * |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <sound/driver.h> | ||
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
27 | #include <linux/init.h> | 26 | #include <linux/init.h> |
28 | #include <linux/interrupt.h> | 27 | #include <linux/interrupt.h> |
diff --git a/sound/pci/trident/Makefile b/sound/pci/trident/Makefile index 65f2c218324c..88676b50f385 100644 --- a/sound/pci/trident/Makefile +++ b/sound/pci/trident/Makefile | |||
@@ -4,16 +4,6 @@ | |||
4 | # | 4 | # |
5 | 5 | ||
6 | snd-trident-objs := trident.o trident_main.o trident_memory.o | 6 | snd-trident-objs := trident.o trident_main.o trident_memory.o |
7 | snd-trident-synth-objs := trident_synth.o | ||
8 | |||
9 | # | ||
10 | # this function returns: | ||
11 | # "m" - CONFIG_SND_SEQUENCER is m | ||
12 | # <empty string> - CONFIG_SND_SEQUENCER is undefined | ||
13 | # otherwise parameter #1 value | ||
14 | # | ||
15 | sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) | ||
16 | 7 | ||
17 | # Toplevel Module Dependency | 8 | # Toplevel Module Dependency |
18 | obj-$(CONFIG_SND_TRIDENT) += snd-trident.o | 9 | obj-$(CONFIG_SND_TRIDENT) += snd-trident.o |
19 | obj-$(call sequencer,$(CONFIG_SND_TRIDENT)) += snd-trident-synth.o | ||
diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c index 84884567df6a..d94b16ffb385 100644 --- a/sound/pci/trident/trident.c +++ b/sound/pci/trident/trident.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <linux/pci.h> | 25 | #include <linux/pci.h> |
27 | #include <linux/time.h> | 26 | #include <linux/time.h> |
@@ -155,13 +154,6 @@ static int __devinit snd_trident_probe(struct pci_dev *pci, | |||
155 | return err; | 154 | return err; |
156 | } | 155 | } |
157 | 156 | ||
158 | #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) | ||
159 | if ((err = snd_trident_attach_synthesizer(trident)) < 0) { | ||
160 | snd_card_free(card); | ||
161 | return err; | ||
162 | } | ||
163 | #endif | ||
164 | |||
165 | snd_trident_create_gameport(trident); | 157 | snd_trident_create_gameport(trident); |
166 | 158 | ||
167 | if ((err = snd_card_register(card)) < 0) { | 159 | if ((err = snd_card_register(card)) < 0) { |
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index a235e034a690..71138ff9b310 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c | |||
@@ -27,7 +27,6 @@ | |||
27 | * SiS7018 S/PDIF support by Thomas Winischhofer <thomas@winischhofer.net> | 27 | * SiS7018 S/PDIF support by Thomas Winischhofer <thomas@winischhofer.net> |
28 | */ | 28 | */ |
29 | 29 | ||
30 | #include <sound/driver.h> | ||
31 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
32 | #include <linux/init.h> | 31 | #include <linux/init.h> |
33 | #include <linux/interrupt.h> | 32 | #include <linux/interrupt.h> |
@@ -436,7 +435,7 @@ static void snd_trident_free_synth_channel(struct snd_trident *trident, int chan | |||
436 | Description: This routine will complete and write the 5 hardware channel | 435 | Description: This routine will complete and write the 5 hardware channel |
437 | registers to hardware. | 436 | registers to hardware. |
438 | 437 | ||
439 | Paramters: trident - pointer to target device class for 4DWave. | 438 | Parameters: trident - pointer to target device class for 4DWave. |
440 | voice - synthesizer voice structure | 439 | voice - synthesizer voice structure |
441 | Each register field. | 440 | Each register field. |
442 | 441 | ||
@@ -514,7 +513,7 @@ EXPORT_SYMBOL(snd_trident_write_voice_regs); | |||
514 | Description: This routine will write the new CSO offset | 513 | Description: This routine will write the new CSO offset |
515 | register to hardware. | 514 | register to hardware. |
516 | 515 | ||
517 | Paramters: trident - pointer to target device class for 4DWave. | 516 | Parameters: trident - pointer to target device class for 4DWave. |
518 | voice - synthesizer voice structure | 517 | voice - synthesizer voice structure |
519 | CSO - new CSO value | 518 | CSO - new CSO value |
520 | 519 | ||
@@ -540,7 +539,7 @@ static void snd_trident_write_cso_reg(struct snd_trident * trident, | |||
540 | Description: This routine will write the new ESO offset | 539 | Description: This routine will write the new ESO offset |
541 | register to hardware. | 540 | register to hardware. |
542 | 541 | ||
543 | Paramters: trident - pointer to target device class for 4DWave. | 542 | Parameters: trident - pointer to target device class for 4DWave. |
544 | voice - synthesizer voice structure | 543 | voice - synthesizer voice structure |
545 | ESO - new ESO value | 544 | ESO - new ESO value |
546 | 545 | ||
@@ -566,7 +565,7 @@ static void snd_trident_write_eso_reg(struct snd_trident * trident, | |||
566 | Description: This routine will write the new voice volume | 565 | Description: This routine will write the new voice volume |
567 | register to hardware. | 566 | register to hardware. |
568 | 567 | ||
569 | Paramters: trident - pointer to target device class for 4DWave. | 568 | Parameters: trident - pointer to target device class for 4DWave. |
570 | voice - synthesizer voice structure | 569 | voice - synthesizer voice structure |
571 | Vol - new voice volume | 570 | Vol - new voice volume |
572 | 571 | ||
@@ -597,7 +596,7 @@ static void snd_trident_write_vol_reg(struct snd_trident * trident, | |||
597 | Description: This routine will write the new voice pan | 596 | Description: This routine will write the new voice pan |
598 | register to hardware. | 597 | register to hardware. |
599 | 598 | ||
600 | Paramters: trident - pointer to target device class for 4DWave. | 599 | Parameters: trident - pointer to target device class for 4DWave. |
601 | voice - synthesizer voice structure | 600 | voice - synthesizer voice structure |
602 | Pan - new pan value | 601 | Pan - new pan value |
603 | 602 | ||
@@ -619,7 +618,7 @@ static void snd_trident_write_pan_reg(struct snd_trident * trident, | |||
619 | Description: This routine will write the new reverb volume | 618 | Description: This routine will write the new reverb volume |
620 | register to hardware. | 619 | register to hardware. |
621 | 620 | ||
622 | Paramters: trident - pointer to target device class for 4DWave. | 621 | Parameters: trident - pointer to target device class for 4DWave. |
623 | voice - synthesizer voice structure | 622 | voice - synthesizer voice structure |
624 | RVol - new reverb volume | 623 | RVol - new reverb volume |
625 | 624 | ||
@@ -643,7 +642,7 @@ static void snd_trident_write_rvol_reg(struct snd_trident * trident, | |||
643 | Description: This routine will write the new chorus volume | 642 | Description: This routine will write the new chorus volume |
644 | register to hardware. | 643 | register to hardware. |
645 | 644 | ||
646 | Paramters: trident - pointer to target device class for 4DWave. | 645 | Parameters: trident - pointer to target device class for 4DWave. |
647 | voice - synthesizer voice structure | 646 | voice - synthesizer voice structure |
648 | CVol - new chorus volume | 647 | CVol - new chorus volume |
649 | 648 | ||
@@ -666,7 +665,7 @@ static void snd_trident_write_cvol_reg(struct snd_trident * trident, | |||
666 | 665 | ||
667 | Description: This routine converts rate in HZ to hardware delta value. | 666 | Description: This routine converts rate in HZ to hardware delta value. |
668 | 667 | ||
669 | Paramters: trident - pointer to target device class for 4DWave. | 668 | Parameters: trident - pointer to target device class for 4DWave. |
670 | rate - Real or Virtual channel number. | 669 | rate - Real or Virtual channel number. |
671 | 670 | ||
672 | Returns: Delta value. | 671 | Returns: Delta value. |
@@ -696,7 +695,7 @@ static unsigned int snd_trident_convert_rate(unsigned int rate) | |||
696 | 695 | ||
697 | Description: This routine converts rate in HZ to hardware delta value. | 696 | Description: This routine converts rate in HZ to hardware delta value. |
698 | 697 | ||
699 | Paramters: trident - pointer to target device class for 4DWave. | 698 | Parameters: trident - pointer to target device class for 4DWave. |
700 | rate - Real or Virtual channel number. | 699 | rate - Real or Virtual channel number. |
701 | 700 | ||
702 | Returns: Delta value. | 701 | Returns: Delta value. |
@@ -726,7 +725,7 @@ static unsigned int snd_trident_convert_adc_rate(unsigned int rate) | |||
726 | 725 | ||
727 | Description: This routine converts rate in HZ to spurious threshold. | 726 | Description: This routine converts rate in HZ to spurious threshold. |
728 | 727 | ||
729 | Paramters: trident - pointer to target device class for 4DWave. | 728 | Parameters: trident - pointer to target device class for 4DWave. |
730 | rate - Real or Virtual channel number. | 729 | rate - Real or Virtual channel number. |
731 | 730 | ||
732 | Returns: Delta value. | 731 | Returns: Delta value. |
@@ -748,7 +747,7 @@ static unsigned int snd_trident_spurious_threshold(unsigned int rate, | |||
748 | 747 | ||
749 | Description: This routine returns a control mode for a PCM channel. | 748 | Description: This routine returns a control mode for a PCM channel. |
750 | 749 | ||
751 | Paramters: trident - pointer to target device class for 4DWave. | 750 | Parameters: trident - pointer to target device class for 4DWave. |
752 | substream - PCM substream | 751 | substream - PCM substream |
753 | 752 | ||
754 | Returns: Control value. | 753 | Returns: Control value. |
@@ -781,7 +780,7 @@ static unsigned int snd_trident_control_mode(struct snd_pcm_substream *substream | |||
781 | 780 | ||
782 | Description: Device I/O control handler for playback/capture parameters. | 781 | Description: Device I/O control handler for playback/capture parameters. |
783 | 782 | ||
784 | Paramters: substream - PCM substream class | 783 | Parameters: substream - PCM substream class |
785 | cmd - what ioctl message to process | 784 | cmd - what ioctl message to process |
786 | arg - additional message infoarg | 785 | arg - additional message infoarg |
787 | 786 | ||
@@ -1664,7 +1663,7 @@ static snd_pcm_uframes_t snd_trident_playback_pointer(struct snd_pcm_substream * | |||
1664 | 1663 | ||
1665 | Description: This routine return the capture position | 1664 | Description: This routine return the capture position |
1666 | 1665 | ||
1667 | Paramters: pcm1 - PCM device class | 1666 | Parameters: pcm1 - PCM device class |
1668 | 1667 | ||
1669 | Returns: position of buffer | 1668 | Returns: position of buffer |
1670 | 1669 | ||
@@ -2157,7 +2156,7 @@ static struct snd_pcm_ops snd_trident_spdif_7018_ops = { | |||
2157 | 2156 | ||
2158 | Description: This routine registers the 4DWave device for PCM support. | 2157 | Description: This routine registers the 4DWave device for PCM support. |
2159 | 2158 | ||
2160 | Paramters: trident - pointer to target device class for 4DWave. | 2159 | Parameters: trident - pointer to target device class for 4DWave. |
2161 | 2160 | ||
2162 | Returns: None | 2161 | Returns: None |
2163 | 2162 | ||
@@ -2215,7 +2214,7 @@ int __devinit snd_trident_pcm(struct snd_trident * trident, | |||
2215 | 2214 | ||
2216 | Description: This routine registers the 4DWave device for foldback PCM support. | 2215 | Description: This routine registers the 4DWave device for foldback PCM support. |
2217 | 2216 | ||
2218 | Paramters: trident - pointer to target device class for 4DWave. | 2217 | Parameters: trident - pointer to target device class for 4DWave. |
2219 | 2218 | ||
2220 | Returns: None | 2219 | Returns: None |
2221 | 2220 | ||
@@ -2272,7 +2271,7 @@ int __devinit snd_trident_foldback_pcm(struct snd_trident * trident, | |||
2272 | 2271 | ||
2273 | Description: This routine registers the 4DWave-NX device for SPDIF support. | 2272 | Description: This routine registers the 4DWave-NX device for SPDIF support. |
2274 | 2273 | ||
2275 | Paramters: trident - pointer to target device class for 4DWave-NX. | 2274 | Parameters: trident - pointer to target device class for 4DWave-NX. |
2276 | 2275 | ||
2277 | Returns: None | 2276 | Returns: None |
2278 | 2277 | ||
@@ -2956,7 +2955,7 @@ static int snd_trident_pcm_mixer_free(struct snd_trident *trident, struct snd_tr | |||
2956 | 2955 | ||
2957 | Description: This routine registers the 4DWave device for mixer support. | 2956 | Description: This routine registers the 4DWave device for mixer support. |
2958 | 2957 | ||
2959 | Paramters: trident - pointer to target device class for 4DWave. | 2958 | Parameters: trident - pointer to target device class for 4DWave. |
2960 | 2959 | ||
2961 | Returns: None | 2960 | Returns: None |
2962 | 2961 | ||
@@ -3313,12 +3312,6 @@ static void snd_trident_proc_read(struct snd_info_entry *entry, | |||
3313 | snd_iprintf(buffer, "Memory Free : %d\n", snd_util_mem_avail(trident->tlb.memhdr)); | 3312 | snd_iprintf(buffer, "Memory Free : %d\n", snd_util_mem_avail(trident->tlb.memhdr)); |
3314 | } | 3313 | } |
3315 | } | 3314 | } |
3316 | #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) | ||
3317 | snd_iprintf(buffer,"\nWavetable Synth\n"); | ||
3318 | snd_iprintf(buffer, "Memory Maximum : %d\n", trident->synth.max_size); | ||
3319 | snd_iprintf(buffer, "Memory Used : %d\n", trident->synth.current_size); | ||
3320 | snd_iprintf(buffer, "Memory Free : %d\n", (trident->synth.max_size-trident->synth.current_size)); | ||
3321 | #endif | ||
3322 | } | 3315 | } |
3323 | 3316 | ||
3324 | static void __devinit snd_trident_proc_init(struct snd_trident * trident) | 3317 | static void __devinit snd_trident_proc_init(struct snd_trident * trident) |
@@ -3344,7 +3337,7 @@ static int snd_trident_dev_free(struct snd_device *device) | |||
3344 | Description: Allocate and set up the TLB page table on 4D NX. | 3337 | Description: Allocate and set up the TLB page table on 4D NX. |
3345 | Each entry has 4 bytes (physical PCI address). | 3338 | Each entry has 4 bytes (physical PCI address). |
3346 | 3339 | ||
3347 | Paramters: trident - pointer to target device class for 4DWave. | 3340 | Parameters: trident - pointer to target device class for 4DWave. |
3348 | 3341 | ||
3349 | Returns: 0 or negative error code | 3342 | Returns: 0 or negative error code |
3350 | 3343 | ||
@@ -3521,7 +3514,7 @@ static int snd_trident_sis_init(struct snd_trident *trident) | |||
3521 | Description: This routine will create the device specific class for | 3514 | Description: This routine will create the device specific class for |
3522 | the 4DWave card. It will also perform basic initialization. | 3515 | the 4DWave card. It will also perform basic initialization. |
3523 | 3516 | ||
3524 | Paramters: card - which card to create | 3517 | Parameters: card - which card to create |
3525 | pci - interface to PCI bus resource info | 3518 | pci - interface to PCI bus resource info |
3526 | dma1ptr - playback dma buffer | 3519 | dma1ptr - playback dma buffer |
3527 | dma2ptr - capture dma buffer | 3520 | dma2ptr - capture dma buffer |
@@ -3667,7 +3660,7 @@ int __devinit snd_trident_create(struct snd_card *card, | |||
3667 | Description: This routine will free the device specific class for | 3660 | Description: This routine will free the device specific class for |
3668 | the 4DWave card. | 3661 | the 4DWave card. |
3669 | 3662 | ||
3670 | Paramters: trident - device specific private data for 4DWave card | 3663 | Parameters: trident - device specific private data for 4DWave card |
3671 | 3664 | ||
3672 | Returns: None. | 3665 | Returns: None. |
3673 | 3666 | ||
@@ -3705,7 +3698,7 @@ static int snd_trident_free(struct snd_trident *trident) | |||
3705 | 3698 | ||
3706 | Description: ISR for Trident 4DWave device | 3699 | Description: ISR for Trident 4DWave device |
3707 | 3700 | ||
3708 | Paramters: trident - device specific private data for 4DWave card | 3701 | Parameters: trident - device specific private data for 4DWave card |
3709 | 3702 | ||
3710 | Problems: It seems that Trident chips generates interrupts more than | 3703 | Problems: It seems that Trident chips generates interrupts more than |
3711 | one time in special cases. The spurious interrupts are | 3704 | one time in special cases. The spurious interrupts are |
@@ -3815,28 +3808,6 @@ static irqreturn_t snd_trident_interrupt(int irq, void *dev_id) | |||
3815 | return IRQ_HANDLED; | 3808 | return IRQ_HANDLED; |
3816 | } | 3809 | } |
3817 | 3810 | ||
3818 | /*--------------------------------------------------------------------------- | ||
3819 | snd_trident_attach_synthesizer | ||
3820 | |||
3821 | Description: Attach synthesizer hooks | ||
3822 | |||
3823 | Paramters: trident - device specific private data for 4DWave card | ||
3824 | |||
3825 | Returns: None. | ||
3826 | |||
3827 | ---------------------------------------------------------------------------*/ | ||
3828 | int snd_trident_attach_synthesizer(struct snd_trident *trident) | ||
3829 | { | ||
3830 | #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) | ||
3831 | if (snd_seq_device_new(trident->card, 1, SNDRV_SEQ_DEV_ID_TRIDENT, | ||
3832 | sizeof(struct snd_trident *), &trident->seq_dev) >= 0) { | ||
3833 | strcpy(trident->seq_dev->name, "4DWave"); | ||
3834 | *(struct snd_trident **)SNDRV_SEQ_DEVICE_ARGPTR(trident->seq_dev) = trident; | ||
3835 | } | ||
3836 | #endif | ||
3837 | return 0; | ||
3838 | } | ||
3839 | |||
3840 | struct snd_trident_voice *snd_trident_alloc_voice(struct snd_trident * trident, int type, int client, int port) | 3811 | struct snd_trident_voice *snd_trident_alloc_voice(struct snd_trident * trident, int type, int client, int port) |
3841 | { | 3812 | { |
3842 | struct snd_trident_voice *pvoice; | 3813 | struct snd_trident_voice *pvoice; |
diff --git a/sound/pci/trident/trident_memory.c b/sound/pci/trident/trident_memory.c index 847b8c6d5c0a..df9b487fa17e 100644 --- a/sound/pci/trident/trident_memory.c +++ b/sound/pci/trident/trident_memory.c | |||
@@ -23,7 +23,6 @@ | |||
23 | * | 23 | * |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <sound/driver.h> | ||
27 | #include <asm/io.h> | 26 | #include <asm/io.h> |
28 | #include <linux/pci.h> | 27 | #include <linux/pci.h> |
29 | #include <linux/time.h> | 28 | #include <linux/time.h> |
diff --git a/sound/pci/trident/trident_synth.c b/sound/pci/trident/trident_synth.c deleted file mode 100644 index 9b7dee84743b..000000000000 --- a/sound/pci/trident/trident_synth.c +++ /dev/null | |||
@@ -1,1024 +0,0 @@ | |||
1 | /* | ||
2 | * Routines for Trident 4DWave NX/DX soundcards - Synthesizer | ||
3 | * Copyright (c) by Scott McNab <jedi@tartarus.uwa.edu.au> | ||
4 | * | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <sound/driver.h> | ||
23 | #include <asm/io.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/pci.h> | ||
27 | #include <sound/core.h> | ||
28 | #include <sound/trident.h> | ||
29 | #include <sound/seq_device.h> | ||
30 | |||
31 | MODULE_AUTHOR("Scott McNab <jedi@tartarus.uwa.edu.au>"); | ||
32 | MODULE_DESCRIPTION("Routines for Trident 4DWave NX/DX soundcards - Synthesizer"); | ||
33 | MODULE_LICENSE("GPL"); | ||
34 | |||
35 | /* linear to log pan conversion table (4.2 channel attenuation format) */ | ||
36 | static unsigned int pan_table[63] = { | ||
37 | 7959, 7733, 7514, 7301, 7093, 6892, 6697, 6507, | ||
38 | 6322, 6143, 5968, 5799, 5634, 5475, 5319, 5168, | ||
39 | 5022, 4879, 4741, 4606, 4475, 4349, 4225, 4105, | ||
40 | 3989, 3876, 3766, 3659, 3555, 3454, 3356, 3261, | ||
41 | 3168, 3078, 2991, 2906, 2824, 2744, 2666, 2590, | ||
42 | 2517, 2445, 2376, 2308, 2243, 2179, 2117, 2057, | ||
43 | 1999, 1942, 1887, 1833, 1781, 1731, 1682, 1634, | ||
44 | 1588, 1543, 1499, 1456, 1415, 1375, 1336 | ||
45 | }; | ||
46 | |||
47 | #define LOG_TABLE_SIZE 386 | ||
48 | |||
49 | /* Linear half-attenuation to log conversion table in the format: | ||
50 | * {linear volume, logarithmic attenuation equivalent}, ... | ||
51 | * | ||
52 | * Provides conversion from a linear half-volume value in the range | ||
53 | * [0,8192] to a logarithmic attenuation value in the range 0 to 6.02dB. | ||
54 | * Halving the linear volume is equivalent to an additional 6dB of | ||
55 | * logarithmic attenuation. The algorithm used in log_from_linear() | ||
56 | * therefore uses this table as follows: | ||
57 | * | ||
58 | * - loop and for every time the volume is less than half the maximum | ||
59 | * volume (16384), add another 6dB and halve the maximum value used | ||
60 | * for this comparison. | ||
61 | * - when the volume is greater than half the maximum volume, take | ||
62 | * the difference of the volume to half volume (in the range [0,8192]) | ||
63 | * and look up the log_table[] to find the nearest entry. | ||
64 | * - take the logarithic component of this entry and add it to the | ||
65 | * resulting attenuation. | ||
66 | * | ||
67 | * Thus this routine provides a linear->log conversion for a range of | ||
68 | * [0,16384] using only 386 table entries | ||
69 | * | ||
70 | * Note: although this table stores log attenuation in 8.8 format, values | ||
71 | * were only calculated for 6 bits fractional precision, since that is | ||
72 | * the most precision offered by the trident hardware. | ||
73 | */ | ||
74 | |||
75 | static unsigned short log_table[LOG_TABLE_SIZE*2] = | ||
76 | { | ||
77 | 4, 0x0604, 19, 0x0600, 34, 0x05fc, | ||
78 | 49, 0x05f8, 63, 0x05f4, 78, 0x05f0, 93, 0x05ec, 108, 0x05e8, | ||
79 | 123, 0x05e4, 138, 0x05e0, 153, 0x05dc, 168, 0x05d8, 183, 0x05d4, | ||
80 | 198, 0x05d0, 213, 0x05cc, 228, 0x05c8, 244, 0x05c4, 259, 0x05c0, | ||
81 | 274, 0x05bc, 289, 0x05b8, 304, 0x05b4, 320, 0x05b0, 335, 0x05ac, | ||
82 | 350, 0x05a8, 366, 0x05a4, 381, 0x05a0, 397, 0x059c, 412, 0x0598, | ||
83 | 428, 0x0594, 443, 0x0590, 459, 0x058c, 474, 0x0588, 490, 0x0584, | ||
84 | 506, 0x0580, 521, 0x057c, 537, 0x0578, 553, 0x0574, 568, 0x0570, | ||
85 | 584, 0x056c, 600, 0x0568, 616, 0x0564, 632, 0x0560, 647, 0x055c, | ||
86 | 663, 0x0558, 679, 0x0554, 695, 0x0550, 711, 0x054c, 727, 0x0548, | ||
87 | 743, 0x0544, 759, 0x0540, 776, 0x053c, 792, 0x0538, 808, 0x0534, | ||
88 | 824, 0x0530, 840, 0x052c, 857, 0x0528, 873, 0x0524, 889, 0x0520, | ||
89 | 906, 0x051c, 922, 0x0518, 938, 0x0514, 955, 0x0510, 971, 0x050c, | ||
90 | 988, 0x0508, 1004, 0x0504, 1021, 0x0500, 1037, 0x04fc, 1054, 0x04f8, | ||
91 | 1071, 0x04f4, 1087, 0x04f0, 1104, 0x04ec, 1121, 0x04e8, 1138, 0x04e4, | ||
92 | 1154, 0x04e0, 1171, 0x04dc, 1188, 0x04d8, 1205, 0x04d4, 1222, 0x04d0, | ||
93 | 1239, 0x04cc, 1256, 0x04c8, 1273, 0x04c4, 1290, 0x04c0, 1307, 0x04bc, | ||
94 | 1324, 0x04b8, 1341, 0x04b4, 1358, 0x04b0, 1376, 0x04ac, 1393, 0x04a8, | ||
95 | 1410, 0x04a4, 1427, 0x04a0, 1445, 0x049c, 1462, 0x0498, 1479, 0x0494, | ||
96 | 1497, 0x0490, 1514, 0x048c, 1532, 0x0488, 1549, 0x0484, 1567, 0x0480, | ||
97 | 1584, 0x047c, 1602, 0x0478, 1620, 0x0474, 1637, 0x0470, 1655, 0x046c, | ||
98 | 1673, 0x0468, 1690, 0x0464, 1708, 0x0460, 1726, 0x045c, 1744, 0x0458, | ||
99 | 1762, 0x0454, 1780, 0x0450, 1798, 0x044c, 1816, 0x0448, 1834, 0x0444, | ||
100 | 1852, 0x0440, 1870, 0x043c, 1888, 0x0438, 1906, 0x0434, 1924, 0x0430, | ||
101 | 1943, 0x042c, 1961, 0x0428, 1979, 0x0424, 1997, 0x0420, 2016, 0x041c, | ||
102 | 2034, 0x0418, 2053, 0x0414, 2071, 0x0410, 2089, 0x040c, 2108, 0x0408, | ||
103 | 2127, 0x0404, 2145, 0x0400, 2164, 0x03fc, 2182, 0x03f8, 2201, 0x03f4, | ||
104 | 2220, 0x03f0, 2239, 0x03ec, 2257, 0x03e8, 2276, 0x03e4, 2295, 0x03e0, | ||
105 | 2314, 0x03dc, 2333, 0x03d8, 2352, 0x03d4, 2371, 0x03d0, 2390, 0x03cc, | ||
106 | 2409, 0x03c8, 2428, 0x03c4, 2447, 0x03c0, 2466, 0x03bc, 2485, 0x03b8, | ||
107 | 2505, 0x03b4, 2524, 0x03b0, 2543, 0x03ac, 2562, 0x03a8, 2582, 0x03a4, | ||
108 | 2601, 0x03a0, 2621, 0x039c, 2640, 0x0398, 2660, 0x0394, 2679, 0x0390, | ||
109 | 2699, 0x038c, 2718, 0x0388, 2738, 0x0384, 2758, 0x0380, 2777, 0x037c, | ||
110 | 2797, 0x0378, 2817, 0x0374, 2837, 0x0370, 2857, 0x036c, 2876, 0x0368, | ||
111 | 2896, 0x0364, 2916, 0x0360, 2936, 0x035c, 2956, 0x0358, 2976, 0x0354, | ||
112 | 2997, 0x0350, 3017, 0x034c, 3037, 0x0348, 3057, 0x0344, 3077, 0x0340, | ||
113 | 3098, 0x033c, 3118, 0x0338, 3138, 0x0334, 3159, 0x0330, 3179, 0x032c, | ||
114 | 3200, 0x0328, 3220, 0x0324, 3241, 0x0320, 3261, 0x031c, 3282, 0x0318, | ||
115 | 3303, 0x0314, 3323, 0x0310, 3344, 0x030c, 3365, 0x0308, 3386, 0x0304, | ||
116 | 3406, 0x0300, 3427, 0x02fc, 3448, 0x02f8, 3469, 0x02f4, 3490, 0x02f0, | ||
117 | 3511, 0x02ec, 3532, 0x02e8, 3553, 0x02e4, 3575, 0x02e0, 3596, 0x02dc, | ||
118 | 3617, 0x02d8, 3638, 0x02d4, 3660, 0x02d0, 3681, 0x02cc, 3702, 0x02c8, | ||
119 | 3724, 0x02c4, 3745, 0x02c0, 3767, 0x02bc, 3788, 0x02b8, 3810, 0x02b4, | ||
120 | 3831, 0x02b0, 3853, 0x02ac, 3875, 0x02a8, 3896, 0x02a4, 3918, 0x02a0, | ||
121 | 3940, 0x029c, 3962, 0x0298, 3984, 0x0294, 4006, 0x0290, 4028, 0x028c, | ||
122 | 4050, 0x0288, 4072, 0x0284, 4094, 0x0280, 4116, 0x027c, 4138, 0x0278, | ||
123 | 4160, 0x0274, 4182, 0x0270, 4205, 0x026c, 4227, 0x0268, 4249, 0x0264, | ||
124 | 4272, 0x0260, 4294, 0x025c, 4317, 0x0258, 4339, 0x0254, 4362, 0x0250, | ||
125 | 4384, 0x024c, 4407, 0x0248, 4430, 0x0244, 4453, 0x0240, 4475, 0x023c, | ||
126 | 4498, 0x0238, 4521, 0x0234, 4544, 0x0230, 4567, 0x022c, 4590, 0x0228, | ||
127 | 4613, 0x0224, 4636, 0x0220, 4659, 0x021c, 4682, 0x0218, 4705, 0x0214, | ||
128 | 4728, 0x0210, 4752, 0x020c, 4775, 0x0208, 4798, 0x0204, 4822, 0x0200, | ||
129 | 4845, 0x01fc, 4869, 0x01f8, 4892, 0x01f4, 4916, 0x01f0, 4939, 0x01ec, | ||
130 | 4963, 0x01e8, 4987, 0x01e4, 5010, 0x01e0, 5034, 0x01dc, 5058, 0x01d8, | ||
131 | 5082, 0x01d4, 5106, 0x01d0, 5130, 0x01cc, 5154, 0x01c8, 5178, 0x01c4, | ||
132 | 5202, 0x01c0, 5226, 0x01bc, 5250, 0x01b8, 5274, 0x01b4, 5299, 0x01b0, | ||
133 | 5323, 0x01ac, 5347, 0x01a8, 5372, 0x01a4, 5396, 0x01a0, 5420, 0x019c, | ||
134 | 5445, 0x0198, 5469, 0x0194, 5494, 0x0190, 5519, 0x018c, 5543, 0x0188, | ||
135 | 5568, 0x0184, 5593, 0x0180, 5618, 0x017c, 5643, 0x0178, 5668, 0x0174, | ||
136 | 5692, 0x0170, 5717, 0x016c, 5743, 0x0168, 5768, 0x0164, 5793, 0x0160, | ||
137 | 5818, 0x015c, 5843, 0x0158, 5868, 0x0154, 5894, 0x0150, 5919, 0x014c, | ||
138 | 5945, 0x0148, 5970, 0x0144, 5995, 0x0140, 6021, 0x013c, 6047, 0x0138, | ||
139 | 6072, 0x0134, 6098, 0x0130, 6124, 0x012c, 6149, 0x0128, 6175, 0x0124, | ||
140 | 6201, 0x0120, 6227, 0x011c, 6253, 0x0118, 6279, 0x0114, 6305, 0x0110, | ||
141 | 6331, 0x010c, 6357, 0x0108, 6384, 0x0104, 6410, 0x0100, 6436, 0x00fc, | ||
142 | 6462, 0x00f8, 6489, 0x00f4, 6515, 0x00f0, 6542, 0x00ec, 6568, 0x00e8, | ||
143 | 6595, 0x00e4, 6621, 0x00e0, 6648, 0x00dc, 6675, 0x00d8, 6702, 0x00d4, | ||
144 | 6728, 0x00d0, 6755, 0x00cc, 6782, 0x00c8, 6809, 0x00c4, 6836, 0x00c0, | ||
145 | 6863, 0x00bc, 6890, 0x00b8, 6917, 0x00b4, 6945, 0x00b0, 6972, 0x00ac, | ||
146 | 6999, 0x00a8, 7027, 0x00a4, 7054, 0x00a0, 7081, 0x009c, 7109, 0x0098, | ||
147 | 7136, 0x0094, 7164, 0x0090, 7192, 0x008c, 7219, 0x0088, 7247, 0x0084, | ||
148 | 7275, 0x0080, 7303, 0x007c, 7331, 0x0078, 7359, 0x0074, 7387, 0x0070, | ||
149 | 7415, 0x006c, 7443, 0x0068, 7471, 0x0064, 7499, 0x0060, 7527, 0x005c, | ||
150 | 7556, 0x0058, 7584, 0x0054, 7613, 0x0050, 7641, 0x004c, 7669, 0x0048, | ||
151 | 7698, 0x0044, 7727, 0x0040, 7755, 0x003c, 7784, 0x0038, 7813, 0x0034, | ||
152 | 7842, 0x0030, 7870, 0x002c, 7899, 0x0028, 7928, 0x0024, 7957, 0x0020, | ||
153 | 7986, 0x001c, 8016, 0x0018, 8045, 0x0014, 8074, 0x0010, 8103, 0x000c, | ||
154 | 8133, 0x0008, 8162, 0x0004, 8192, 0x0000 | ||
155 | }; | ||
156 | |||
157 | static unsigned short lookup_volume_table( unsigned short value ) | ||
158 | { | ||
159 | /* This code is an optimised version of: | ||
160 | * int i = 0; | ||
161 | * while( volume_table[i*2] < value ) | ||
162 | * i++; | ||
163 | * return volume_table[i*2+1]; | ||
164 | */ | ||
165 | unsigned short *ptr = log_table; | ||
166 | while( *ptr < value ) | ||
167 | ptr += 2; | ||
168 | return *(ptr+1); | ||
169 | } | ||
170 | |||
171 | /* this function calculates a 8.8 fixed point logarithmic attenuation | ||
172 | * value from a linear volume value in the range 0 to 16384 */ | ||
173 | static unsigned short log_from_linear( unsigned short value ) | ||
174 | { | ||
175 | if (value >= 16384) | ||
176 | return 0x0000; | ||
177 | if (value) { | ||
178 | unsigned short result = 0; | ||
179 | int v, c; | ||
180 | for( c = 0, v = 8192; c < 14; c++, v >>= 1 ) { | ||
181 | if( value >= v ) { | ||
182 | result += lookup_volume_table( (value - v) << c ); | ||
183 | return result; | ||
184 | } | ||
185 | result += 0x0605; /* 6.0205 (result of -20*log10(0.5)) */ | ||
186 | } | ||
187 | } | ||
188 | return 0xffff; | ||
189 | } | ||
190 | |||
191 | /* | ||
192 | * Sample handling operations | ||
193 | */ | ||
194 | |||
195 | static void sample_start(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_position_t position); | ||
196 | static void sample_stop(struct snd_trident * trident, struct snd_trident_voice * voice, int mode); | ||
197 | static void sample_freq(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_frequency_t freq); | ||
198 | static void sample_volume(struct snd_trident * trident, struct snd_trident_voice * voice, struct snd_seq_ev_volume * volume); | ||
199 | static void sample_loop(struct snd_trident * trident, struct snd_trident_voice * voice, struct snd_seq_ev_loop * loop); | ||
200 | static void sample_pos(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_position_t position); | ||
201 | static void sample_private1(struct snd_trident * trident, struct snd_trident_voice * voice, unsigned char *data); | ||
202 | |||
203 | static struct snd_trident_sample_ops sample_ops = | ||
204 | { | ||
205 | sample_start, | ||
206 | sample_stop, | ||
207 | sample_freq, | ||
208 | sample_volume, | ||
209 | sample_loop, | ||
210 | sample_pos, | ||
211 | sample_private1 | ||
212 | }; | ||
213 | |||
214 | static void snd_trident_simple_init(struct snd_trident_voice * voice) | ||
215 | { | ||
216 | //voice->handler_wave = interrupt_wave; | ||
217 | //voice->handler_volume = interrupt_volume; | ||
218 | //voice->handler_effect = interrupt_effect; | ||
219 | //voice->volume_change = NULL; | ||
220 | voice->sample_ops = &sample_ops; | ||
221 | } | ||
222 | |||
223 | static void sample_start(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_position_t position) | ||
224 | { | ||
225 | struct simple_instrument *simple; | ||
226 | struct snd_seq_kinstr *instr; | ||
227 | unsigned long flags; | ||
228 | unsigned int loop_start, loop_end, sample_start, sample_end, start_offset; | ||
229 | unsigned int value; | ||
230 | unsigned int shift = 0; | ||
231 | |||
232 | instr = snd_seq_instr_find(trident->synth.ilist, &voice->instr, 0, 1); | ||
233 | if (instr == NULL) | ||
234 | return; | ||
235 | voice->instr = instr->instr; /* copy ID to speedup aliases */ | ||
236 | simple = KINSTR_DATA(instr); | ||
237 | |||
238 | spin_lock_irqsave(&trident->reg_lock, flags); | ||
239 | |||
240 | if (trident->device == TRIDENT_DEVICE_ID_SI7018) | ||
241 | voice->GVSel = 1; /* route to Wave volume */ | ||
242 | |||
243 | voice->CTRL = 0; | ||
244 | voice->Alpha = 0; | ||
245 | voice->FMS = 0; | ||
246 | |||
247 | loop_start = simple->loop_start >> 4; | ||
248 | loop_end = simple->loop_end >> 4; | ||
249 | sample_start = (simple->start + position) >> 4; | ||
250 | if( sample_start >= simple->size ) | ||
251 | sample_start = simple->start >> 4; | ||
252 | sample_end = simple->size; | ||
253 | start_offset = position >> 4; | ||
254 | |||
255 | if (simple->format & SIMPLE_WAVE_16BIT) { | ||
256 | voice->CTRL |= 8; | ||
257 | shift++; | ||
258 | } | ||
259 | if (simple->format & SIMPLE_WAVE_STEREO) { | ||
260 | voice->CTRL |= 4; | ||
261 | shift++; | ||
262 | } | ||
263 | if (!(simple->format & SIMPLE_WAVE_UNSIGNED)) | ||
264 | voice->CTRL |= 2; | ||
265 | |||
266 | voice->LBA = simple->address.memory; | ||
267 | |||
268 | if (simple->format & SIMPLE_WAVE_LOOP) { | ||
269 | voice->CTRL |= 1; | ||
270 | voice->LBA += loop_start << shift; | ||
271 | if( start_offset >= loop_start ) { | ||
272 | voice->CSO = start_offset - loop_start; | ||
273 | voice->negCSO = 0; | ||
274 | } else { | ||
275 | voice->CSO = loop_start - start_offset; | ||
276 | voice->negCSO = 1; | ||
277 | } | ||
278 | voice->ESO = loop_end - loop_start - 1; | ||
279 | } else { | ||
280 | voice->LBA += start_offset << shift; | ||
281 | voice->CSO = sample_start; | ||
282 | voice->ESO = sample_end - 1; | ||
283 | voice->negCSO = 0; | ||
284 | } | ||
285 | |||
286 | if (voice->flags & SNDRV_TRIDENT_VFLG_RUNNING) { | ||
287 | snd_trident_stop_voice(trident, voice->number); | ||
288 | voice->flags &= ~SNDRV_TRIDENT_VFLG_RUNNING; | ||
289 | } | ||
290 | |||
291 | /* set CSO sign */ | ||
292 | value = inl(TRID_REG(trident, T4D_SIGN_CSO_A)); | ||
293 | if( voice->negCSO ) { | ||
294 | value |= 1 << (voice->number&31); | ||
295 | } else { | ||
296 | value &= ~(1 << (voice->number&31)); | ||
297 | } | ||
298 | outl(value,TRID_REG(trident, T4D_SIGN_CSO_A)); | ||
299 | |||
300 | voice->Attribute = 0; | ||
301 | snd_trident_write_voice_regs(trident, voice); | ||
302 | snd_trident_start_voice(trident, voice->number); | ||
303 | voice->flags |= SNDRV_TRIDENT_VFLG_RUNNING; | ||
304 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
305 | snd_seq_instr_free_use(trident->synth.ilist, instr); | ||
306 | } | ||
307 | |||
308 | static void sample_stop(struct snd_trident * trident, struct snd_trident_voice * voice, int mode) | ||
309 | { | ||
310 | unsigned long flags; | ||
311 | |||
312 | if (!(voice->flags & SNDRV_TRIDENT_VFLG_RUNNING)) | ||
313 | return; | ||
314 | |||
315 | switch (mode) { | ||
316 | default: | ||
317 | spin_lock_irqsave(&trident->reg_lock, flags); | ||
318 | snd_trident_stop_voice(trident, voice->number); | ||
319 | voice->flags &= ~SNDRV_TRIDENT_VFLG_RUNNING; | ||
320 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
321 | break; | ||
322 | case SAMPLE_STOP_LOOP: /* disable loop only */ | ||
323 | voice->CTRL &= ~1; | ||
324 | spin_lock_irqsave(&trident->reg_lock, flags); | ||
325 | outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); | ||
326 | outw((((voice->CTRL << 12) | (voice->EC & 0x0fff)) & 0xffff), CH_GVSEL_PAN_VOL_CTRL_EC); | ||
327 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
328 | break; | ||
329 | } | ||
330 | } | ||
331 | |||
332 | static void sample_freq(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_frequency_t freq) | ||
333 | { | ||
334 | unsigned long flags; | ||
335 | freq >>= 4; | ||
336 | |||
337 | spin_lock_irqsave(&trident->reg_lock, flags); | ||
338 | if (freq == 44100) | ||
339 | voice->Delta = 0xeb3; | ||
340 | else if (freq == 8000) | ||
341 | voice->Delta = 0x2ab; | ||
342 | else if (freq == 48000) | ||
343 | voice->Delta = 0x1000; | ||
344 | else | ||
345 | voice->Delta = (((freq << 12) + freq) / 48000) & 0x0000ffff; | ||
346 | |||
347 | outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); | ||
348 | if (trident->device == TRIDENT_DEVICE_ID_NX) { | ||
349 | outb((unsigned char) voice->Delta, TRID_REG(trident, CH_NX_DELTA_CSO + 3)); | ||
350 | outb((unsigned char) (voice->Delta >> 8), TRID_REG(trident, CH_NX_DELTA_ESO + 3)); | ||
351 | } else { | ||
352 | outw((unsigned short) voice->Delta, TRID_REG(trident, CH_DX_ESO_DELTA)); | ||
353 | } | ||
354 | |||
355 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
356 | } | ||
357 | |||
358 | static void sample_volume(struct snd_trident * trident, struct snd_trident_voice * voice, struct snd_seq_ev_volume * volume) | ||
359 | { | ||
360 | unsigned long flags; | ||
361 | unsigned short value; | ||
362 | |||
363 | spin_lock_irqsave(&trident->reg_lock, flags); | ||
364 | voice->GVSel = 0; /* use global music volume */ | ||
365 | voice->FMC = 0x03; /* fixme: can we do something useful with FMC? */ | ||
366 | if (volume->volume >= 0) { | ||
367 | volume->volume &= 0x3fff; | ||
368 | /* linear volume -> logarithmic attenuation conversion | ||
369 | * uses EC register for greater resolution (6.6 bits) than Vol register (5.3 bits) | ||
370 | * Vol register used when additional attenuation is required */ | ||
371 | voice->RVol = 0; | ||
372 | voice->CVol = 0; | ||
373 | value = log_from_linear( volume->volume ); | ||
374 | voice->Vol = 0; | ||
375 | voice->EC = (value & 0x3fff) >> 2; | ||
376 | if (value > 0x3fff) { | ||
377 | voice->EC |= 0xfc0; | ||
378 | if (value < 0x5f00 ) | ||
379 | voice->Vol = ((value >> 8) - 0x3f) << 5; | ||
380 | else { | ||
381 | voice->Vol = 0x3ff; | ||
382 | voice->EC = 0xfff; | ||
383 | } | ||
384 | } | ||
385 | } | ||
386 | if (volume->lr >= 0) { | ||
387 | volume->lr &= 0x3fff; | ||
388 | /* approximate linear pan by attenuating channels */ | ||
389 | if (volume->lr >= 0x2000) { /* attenuate left (pan right) */ | ||
390 | value = 0x3fff - volume->lr; | ||
391 | for (voice->Pan = 0; voice->Pan < 63; voice->Pan++ ) | ||
392 | if (value >= pan_table[voice->Pan] ) | ||
393 | break; | ||
394 | } else { /* attenuate right (pan left) */ | ||
395 | for (voice->Pan = 0; voice->Pan < 63; voice->Pan++ ) | ||
396 | if ((unsigned int)volume->lr >= pan_table[voice->Pan] ) | ||
397 | break; | ||
398 | voice->Pan |= 0x40; | ||
399 | } | ||
400 | } | ||
401 | outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); | ||
402 | outl((voice->GVSel << 31) | ((voice->Pan & 0x0000007f) << 24) | | ||
403 | ((voice->Vol & 0x000000ff) << 16) | ((voice->CTRL & 0x0000000f) << 12) | | ||
404 | (voice->EC & 0x00000fff), TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC)); | ||
405 | value = ((voice->FMC & 0x03) << 14) | ((voice->RVol & 0x7f) << 7) | (voice->CVol & 0x7f); | ||
406 | outw(value, TRID_REG(trident, CH_DX_FMC_RVOL_CVOL)); | ||
407 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
408 | } | ||
409 | |||
410 | static void sample_loop(struct snd_trident * trident, struct snd_trident_voice * voice, struct snd_seq_ev_loop * loop) | ||
411 | { | ||
412 | unsigned long flags; | ||
413 | struct simple_instrument *simple; | ||
414 | struct snd_seq_kinstr *instr; | ||
415 | unsigned int loop_start, loop_end; | ||
416 | |||
417 | instr = snd_seq_instr_find(trident->synth.ilist, &voice->instr, 0, 1); | ||
418 | if (instr == NULL) | ||
419 | return; | ||
420 | voice->instr = instr->instr; /* copy ID to speedup aliases */ | ||
421 | simple = KINSTR_DATA(instr); | ||
422 | |||
423 | loop_start = loop->start >> 4; | ||
424 | loop_end = loop->end >> 4; | ||
425 | |||
426 | spin_lock_irqsave(&trident->reg_lock, flags); | ||
427 | |||
428 | voice->LBA = simple->address.memory + loop_start; | ||
429 | voice->CSO = 0; | ||
430 | voice->ESO = loop_end - loop_start - 1; | ||
431 | |||
432 | outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); | ||
433 | outb((voice->LBA >> 16), TRID_REG(trident, CH_LBA + 2)); | ||
434 | outw((voice->LBA & 0xffff), TRID_REG(trident, CH_LBA)); | ||
435 | if (trident->device == TRIDENT_DEVICE_ID_NX) { | ||
436 | outb((voice->ESO >> 16), TRID_REG(trident, CH_NX_DELTA_ESO + 2)); | ||
437 | outw((voice->ESO & 0xffff), TRID_REG(trident, CH_NX_DELTA_ESO)); | ||
438 | outb((voice->CSO >> 16), TRID_REG(trident, CH_NX_DELTA_CSO + 2)); | ||
439 | outw((voice->CSO & 0xffff), TRID_REG(trident, CH_NX_DELTA_CSO)); | ||
440 | } else { | ||
441 | outw((voice->ESO & 0xffff), TRID_REG(trident, CH_DX_ESO_DELTA + 2)); | ||
442 | outw((voice->CSO & 0xffff), TRID_REG(trident, CH_DX_CSO_ALPHA_FMS + 2)); | ||
443 | } | ||
444 | |||
445 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
446 | snd_seq_instr_free_use(trident->synth.ilist, instr); | ||
447 | } | ||
448 | |||
449 | static void sample_pos(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_position_t position) | ||
450 | { | ||
451 | unsigned long flags; | ||
452 | struct simple_instrument *simple; | ||
453 | struct snd_seq_kinstr *instr; | ||
454 | unsigned int value; | ||
455 | |||
456 | instr = snd_seq_instr_find(trident->synth.ilist, &voice->instr, 0, 1); | ||
457 | if (instr == NULL) | ||
458 | return; | ||
459 | voice->instr = instr->instr; /* copy ID to speedup aliases */ | ||
460 | simple = KINSTR_DATA(instr); | ||
461 | |||
462 | spin_lock_irqsave(&trident->reg_lock, flags); | ||
463 | |||
464 | if (simple->format & SIMPLE_WAVE_LOOP) { | ||
465 | if( position >= simple->loop_start ) { | ||
466 | voice->CSO = (position - simple->loop_start) >> 4; | ||
467 | voice->negCSO = 0; | ||
468 | } else { | ||
469 | voice->CSO = (simple->loop_start - position) >> 4; | ||
470 | voice->negCSO = 1; | ||
471 | } | ||
472 | } else { | ||
473 | voice->CSO = position >> 4; | ||
474 | voice->negCSO = 0; | ||
475 | } | ||
476 | |||
477 | /* set CSO sign */ | ||
478 | value = inl(TRID_REG(trident, T4D_SIGN_CSO_A)); | ||
479 | if( voice->negCSO ) { | ||
480 | value |= 1 << (voice->number&31); | ||
481 | } else { | ||
482 | value &= ~(1 << (voice->number&31)); | ||
483 | } | ||
484 | outl(value,TRID_REG(trident, T4D_SIGN_CSO_A)); | ||
485 | |||
486 | |||
487 | outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); | ||
488 | if (trident->device == TRIDENT_DEVICE_ID_NX) { | ||
489 | outw((voice->CSO & 0xffff), TRID_REG(trident, CH_NX_DELTA_CSO)); | ||
490 | outb((voice->CSO >> 16), TRID_REG(trident, CH_NX_DELTA_CSO + 2)); | ||
491 | } else { | ||
492 | outw((voice->CSO & 0xffff), TRID_REG(trident, CH_DX_CSO_ALPHA_FMS) + 2); | ||
493 | } | ||
494 | |||
495 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
496 | snd_seq_instr_free_use(trident->synth.ilist, instr); | ||
497 | } | ||
498 | |||
499 | static void sample_private1(struct snd_trident * trident, struct snd_trident_voice * voice, unsigned char *data) | ||
500 | { | ||
501 | } | ||
502 | |||
503 | /* | ||
504 | * Memory management / sample loading | ||
505 | */ | ||
506 | |||
507 | static int snd_trident_simple_put_sample(void *private_data, | ||
508 | struct simple_instrument * instr, | ||
509 | char __user *data, long len, int atomic) | ||
510 | { | ||
511 | struct snd_trident *trident = private_data; | ||
512 | int size = instr->size; | ||
513 | int shift = 0; | ||
514 | |||
515 | if (instr->format & SIMPLE_WAVE_BACKWARD || | ||
516 | instr->format & SIMPLE_WAVE_BIDIR || | ||
517 | instr->format & SIMPLE_WAVE_ULAW) | ||
518 | return -EINVAL; /* not supported */ | ||
519 | |||
520 | if (instr->format & SIMPLE_WAVE_16BIT) | ||
521 | shift++; | ||
522 | if (instr->format & SIMPLE_WAVE_STEREO) | ||
523 | shift++; | ||
524 | size <<= shift; | ||
525 | |||
526 | if (trident->synth.current_size + size > trident->synth.max_size) | ||
527 | return -ENOMEM; | ||
528 | |||
529 | if (!access_ok(VERIFY_READ, data, size)) | ||
530 | return -EFAULT; | ||
531 | |||
532 | if (trident->tlb.entries) { | ||
533 | struct snd_util_memblk *memblk; | ||
534 | memblk = snd_trident_synth_alloc(trident, size); | ||
535 | if (memblk == NULL) | ||
536 | return -ENOMEM; | ||
537 | if (snd_trident_synth_copy_from_user(trident, memblk, 0, data, size) ) { | ||
538 | snd_trident_synth_free(trident, memblk); | ||
539 | return -EFAULT; | ||
540 | } | ||
541 | instr->address.ptr = (unsigned char*)memblk; | ||
542 | instr->address.memory = memblk->offset; | ||
543 | } else { | ||
544 | struct snd_dma_buffer dmab; | ||
545 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci), | ||
546 | size, &dmab) < 0) | ||
547 | return -ENOMEM; | ||
548 | |||
549 | if (copy_from_user(dmab.area, data, size)) { | ||
550 | snd_dma_free_pages(&dmab); | ||
551 | return -EFAULT; | ||
552 | } | ||
553 | instr->address.ptr = dmab.area; | ||
554 | instr->address.memory = dmab.addr; | ||
555 | } | ||
556 | |||
557 | trident->synth.current_size += size; | ||
558 | return 0; | ||
559 | } | ||
560 | |||
561 | static int snd_trident_simple_get_sample(void *private_data, | ||
562 | struct simple_instrument * instr, | ||
563 | char __user *data, long len, int atomic) | ||
564 | { | ||
565 | //struct snd_trident *trident = private_data; | ||
566 | int size = instr->size; | ||
567 | int shift = 0; | ||
568 | |||
569 | if (instr->format & SIMPLE_WAVE_16BIT) | ||
570 | shift++; | ||
571 | if (instr->format & SIMPLE_WAVE_STEREO) | ||
572 | shift++; | ||
573 | size <<= shift; | ||
574 | |||
575 | if (!access_ok(VERIFY_WRITE, data, size)) | ||
576 | return -EFAULT; | ||
577 | |||
578 | /* FIXME: not implemented yet */ | ||
579 | |||
580 | return -EBUSY; | ||
581 | } | ||
582 | |||
583 | static int snd_trident_simple_remove_sample(void *private_data, | ||
584 | struct simple_instrument * instr, | ||
585 | int atomic) | ||
586 | { | ||
587 | struct snd_trident *trident = private_data; | ||
588 | int size = instr->size; | ||
589 | |||
590 | if (instr->format & SIMPLE_WAVE_16BIT) | ||
591 | size <<= 1; | ||
592 | if (instr->format & SIMPLE_WAVE_STEREO) | ||
593 | size <<= 1; | ||
594 | |||
595 | if (trident->tlb.entries) { | ||
596 | struct snd_util_memblk *memblk = (struct snd_util_memblk *)instr->address.ptr; | ||
597 | if (memblk) | ||
598 | snd_trident_synth_free(trident, memblk); | ||
599 | else | ||
600 | return -EFAULT; | ||
601 | } else { | ||
602 | struct snd_dma_buffer dmab; | ||
603 | dmab.dev.type = SNDRV_DMA_TYPE_DEV; | ||
604 | dmab.dev.dev = snd_dma_pci_data(trident->pci); | ||
605 | dmab.area = instr->address.ptr; | ||
606 | dmab.addr = instr->address.memory; | ||
607 | dmab.bytes = size; | ||
608 | snd_dma_free_pages(&dmab); | ||
609 | } | ||
610 | |||
611 | trident->synth.current_size -= size; | ||
612 | if (trident->synth.current_size < 0) /* shouldn't need this check... */ | ||
613 | trident->synth.current_size = 0; | ||
614 | |||
615 | return 0; | ||
616 | } | ||
617 | |||
618 | static void select_instrument(struct snd_trident * trident, struct snd_trident_voice * v) | ||
619 | { | ||
620 | struct snd_seq_kinstr *instr; | ||
621 | instr = snd_seq_instr_find(trident->synth.ilist, &v->instr, 0, 1); | ||
622 | if (instr != NULL) { | ||
623 | if (instr->ops) { | ||
624 | if (!strcmp(instr->ops->instr_type, SNDRV_SEQ_INSTR_ID_SIMPLE)) | ||
625 | snd_trident_simple_init(v); | ||
626 | } | ||
627 | snd_seq_instr_free_use(trident->synth.ilist, instr); | ||
628 | } | ||
629 | } | ||
630 | |||
631 | /* | ||
632 | |||
633 | */ | ||
634 | |||
635 | static void event_sample(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v) | ||
636 | { | ||
637 | if (v->sample_ops && v->sample_ops->sample_stop) | ||
638 | v->sample_ops->sample_stop(p->trident, v, SAMPLE_STOP_IMMEDIATELY); | ||
639 | v->instr.std = ev->data.sample.param.sample.std; | ||
640 | if (v->instr.std & 0xff000000) { /* private instrument */ | ||
641 | v->instr.std &= 0x00ffffff; | ||
642 | v->instr.std |= (unsigned int)ev->source.client << 24; | ||
643 | } | ||
644 | v->instr.bank = ev->data.sample.param.sample.bank; | ||
645 | v->instr.prg = ev->data.sample.param.sample.prg; | ||
646 | select_instrument(p->trident, v); | ||
647 | } | ||
648 | |||
649 | static void event_cluster(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v) | ||
650 | { | ||
651 | if (v->sample_ops && v->sample_ops->sample_stop) | ||
652 | v->sample_ops->sample_stop(p->trident, v, SAMPLE_STOP_IMMEDIATELY); | ||
653 | v->instr.cluster = ev->data.sample.param.cluster.cluster; | ||
654 | select_instrument(p->trident, v); | ||
655 | } | ||
656 | |||
657 | static void event_start(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v) | ||
658 | { | ||
659 | if (v->sample_ops && v->sample_ops->sample_start) | ||
660 | v->sample_ops->sample_start(p->trident, v, ev->data.sample.param.position); | ||
661 | } | ||
662 | |||
663 | static void event_stop(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v) | ||
664 | { | ||
665 | if (v->sample_ops && v->sample_ops->sample_stop) | ||
666 | v->sample_ops->sample_stop(p->trident, v, ev->data.sample.param.stop_mode); | ||
667 | } | ||
668 | |||
669 | static void event_freq(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v) | ||
670 | { | ||
671 | if (v->sample_ops && v->sample_ops->sample_freq) | ||
672 | v->sample_ops->sample_freq(p->trident, v, ev->data.sample.param.frequency); | ||
673 | } | ||
674 | |||
675 | static void event_volume(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v) | ||
676 | { | ||
677 | if (v->sample_ops && v->sample_ops->sample_volume) | ||
678 | v->sample_ops->sample_volume(p->trident, v, &ev->data.sample.param.volume); | ||
679 | } | ||
680 | |||
681 | static void event_loop(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v) | ||
682 | { | ||
683 | if (v->sample_ops && v->sample_ops->sample_loop) | ||
684 | v->sample_ops->sample_loop(p->trident, v, &ev->data.sample.param.loop); | ||
685 | } | ||
686 | |||
687 | static void event_position(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v) | ||
688 | { | ||
689 | if (v->sample_ops && v->sample_ops->sample_pos) | ||
690 | v->sample_ops->sample_pos(p->trident, v, ev->data.sample.param.position); | ||
691 | } | ||
692 | |||
693 | static void event_private1(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v) | ||
694 | { | ||
695 | if (v->sample_ops && v->sample_ops->sample_private1) | ||
696 | v->sample_ops->sample_private1(p->trident, v, (unsigned char *) &ev->data.sample.param.raw8); | ||
697 | } | ||
698 | |||
699 | typedef void (trident_sample_event_handler_t) (struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v); | ||
700 | |||
701 | static trident_sample_event_handler_t *trident_sample_event_handlers[9] = | ||
702 | { | ||
703 | event_sample, | ||
704 | event_cluster, | ||
705 | event_start, | ||
706 | event_stop, | ||
707 | event_freq, | ||
708 | event_volume, | ||
709 | event_loop, | ||
710 | event_position, | ||
711 | event_private1 | ||
712 | }; | ||
713 | |||
714 | static void snd_trident_sample_event(struct snd_seq_event * ev, struct snd_trident_port * p) | ||
715 | { | ||
716 | int idx, voice; | ||
717 | struct snd_trident *trident = p->trident; | ||
718 | struct snd_trident_voice *v; | ||
719 | unsigned long flags; | ||
720 | |||
721 | idx = ev->type - SNDRV_SEQ_EVENT_SAMPLE; | ||
722 | if (idx < 0 || idx > 8) | ||
723 | return; | ||
724 | for (voice = 0; voice < 64; voice++) { | ||
725 | v = &trident->synth.voices[voice]; | ||
726 | if (v->use && v->client == ev->source.client && | ||
727 | v->port == ev->source.port && | ||
728 | v->index == ev->data.sample.channel) { | ||
729 | spin_lock_irqsave(&trident->event_lock, flags); | ||
730 | trident_sample_event_handlers[idx] (ev, p, v); | ||
731 | spin_unlock_irqrestore(&trident->event_lock, flags); | ||
732 | return; | ||
733 | } | ||
734 | } | ||
735 | } | ||
736 | |||
737 | /* | ||
738 | |||
739 | */ | ||
740 | |||
741 | static void snd_trident_synth_free_voices(struct snd_trident * trident, int client, int port) | ||
742 | { | ||
743 | int idx; | ||
744 | struct snd_trident_voice *voice; | ||
745 | |||
746 | for (idx = 0; idx < 32; idx++) { | ||
747 | voice = &trident->synth.voices[idx]; | ||
748 | if (voice->use && voice->client == client && voice->port == port) | ||
749 | snd_trident_free_voice(trident, voice); | ||
750 | } | ||
751 | } | ||
752 | |||
753 | static int snd_trident_synth_use(void *private_data, struct snd_seq_port_subscribe * info) | ||
754 | { | ||
755 | struct snd_trident_port *port = private_data; | ||
756 | struct snd_trident *trident = port->trident; | ||
757 | struct snd_trident_voice *voice; | ||
758 | unsigned int idx; | ||
759 | unsigned long flags; | ||
760 | |||
761 | if (info->voices > 32) | ||
762 | return -EINVAL; | ||
763 | spin_lock_irqsave(&trident->reg_lock, flags); | ||
764 | for (idx = 0; idx < info->voices; idx++) { | ||
765 | voice = snd_trident_alloc_voice(trident, SNDRV_TRIDENT_VOICE_TYPE_SYNTH, info->sender.client, info->sender.port); | ||
766 | if (voice == NULL) { | ||
767 | snd_trident_synth_free_voices(trident, info->sender.client, info->sender.port); | ||
768 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
769 | return -EBUSY; | ||
770 | } | ||
771 | voice->index = idx; | ||
772 | voice->Vol = 0x3ff; | ||
773 | voice->EC = 0x0fff; | ||
774 | } | ||
775 | #if 0 | ||
776 | for (idx = 0; idx < info->midi_voices; idx++) { | ||
777 | port->midi_has_voices = 1; | ||
778 | voice = snd_trident_alloc_voice(trident, SNDRV_TRIDENT_VOICE_TYPE_MIDI, info->sender.client, info->sender.port); | ||
779 | if (voice == NULL) { | ||
780 | snd_trident_synth_free_voices(trident, info->sender.client, info->sender.port); | ||
781 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
782 | return -EBUSY; | ||
783 | } | ||
784 | voice->Vol = 0x3ff; | ||
785 | voice->EC = 0x0fff; | ||
786 | } | ||
787 | #endif | ||
788 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
789 | return 0; | ||
790 | } | ||
791 | |||
792 | static int snd_trident_synth_unuse(void *private_data, struct snd_seq_port_subscribe * info) | ||
793 | { | ||
794 | struct snd_trident_port *port = private_data; | ||
795 | struct snd_trident *trident = port->trident; | ||
796 | unsigned long flags; | ||
797 | |||
798 | spin_lock_irqsave(&trident->reg_lock, flags); | ||
799 | snd_trident_synth_free_voices(trident, info->sender.client, info->sender.port); | ||
800 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
801 | return 0; | ||
802 | } | ||
803 | |||
804 | /* | ||
805 | |||
806 | */ | ||
807 | |||
808 | static void snd_trident_synth_free_private_instruments(struct snd_trident_port * p, int client) | ||
809 | { | ||
810 | struct snd_seq_instr_header ifree; | ||
811 | |||
812 | memset(&ifree, 0, sizeof(ifree)); | ||
813 | ifree.cmd = SNDRV_SEQ_INSTR_FREE_CMD_PRIVATE; | ||
814 | snd_seq_instr_list_free_cond(p->trident->synth.ilist, &ifree, client, 0); | ||
815 | } | ||
816 | |||
817 | static int snd_trident_synth_event_input(struct snd_seq_event * ev, int direct, void *private_data, int atomic, int hop) | ||
818 | { | ||
819 | struct snd_trident_port *p = (struct snd_trident_port *) private_data; | ||
820 | |||
821 | if (p == NULL) | ||
822 | return -EINVAL; | ||
823 | if (ev->type >= SNDRV_SEQ_EVENT_SAMPLE && | ||
824 | ev->type <= SNDRV_SEQ_EVENT_SAMPLE_PRIVATE1) { | ||
825 | snd_trident_sample_event(ev, p); | ||
826 | return 0; | ||
827 | } | ||
828 | if (ev->source.client == SNDRV_SEQ_CLIENT_SYSTEM && | ||
829 | ev->source.port == SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE) { | ||
830 | if (ev->type == SNDRV_SEQ_EVENT_CLIENT_EXIT) { | ||
831 | snd_trident_synth_free_private_instruments(p, ev->data.addr.client); | ||
832 | return 0; | ||
833 | } | ||
834 | } | ||
835 | if (direct) { | ||
836 | if (ev->type >= SNDRV_SEQ_EVENT_INSTR_BEGIN) { | ||
837 | snd_seq_instr_event(&p->trident->synth.simple_ops.kops, | ||
838 | p->trident->synth.ilist, ev, | ||
839 | p->trident->synth.seq_client, atomic, hop); | ||
840 | return 0; | ||
841 | } | ||
842 | } | ||
843 | return 0; | ||
844 | } | ||
845 | |||
846 | static void snd_trident_synth_instr_notify(void *private_data, | ||
847 | struct snd_seq_kinstr * instr, | ||
848 | int what) | ||
849 | { | ||
850 | int idx; | ||
851 | struct snd_trident *trident = private_data; | ||
852 | struct snd_trident_voice *pvoice; | ||
853 | unsigned long flags; | ||
854 | |||
855 | spin_lock_irqsave(&trident->event_lock, flags); | ||
856 | for (idx = 0; idx < 64; idx++) { | ||
857 | pvoice = &trident->synth.voices[idx]; | ||
858 | if (pvoice->use && !memcmp(&pvoice->instr, &instr->instr, sizeof(pvoice->instr))) { | ||
859 | if (pvoice->sample_ops && pvoice->sample_ops->sample_stop) { | ||
860 | pvoice->sample_ops->sample_stop(trident, pvoice, SAMPLE_STOP_IMMEDIATELY); | ||
861 | } else { | ||
862 | snd_trident_stop_voice(trident, pvoice->number); | ||
863 | pvoice->flags &= ~SNDRV_TRIDENT_VFLG_RUNNING; | ||
864 | } | ||
865 | } | ||
866 | } | ||
867 | spin_unlock_irqrestore(&trident->event_lock, flags); | ||
868 | } | ||
869 | |||
870 | /* | ||
871 | |||
872 | */ | ||
873 | |||
874 | static void snd_trident_synth_free_port(void *private_data) | ||
875 | { | ||
876 | struct snd_trident_port *p = (struct snd_trident_port *) private_data; | ||
877 | |||
878 | if (p) | ||
879 | snd_midi_channel_free_set(p->chset); | ||
880 | } | ||
881 | |||
882 | static int snd_trident_synth_create_port(struct snd_trident * trident, int idx) | ||
883 | { | ||
884 | struct snd_trident_port *p; | ||
885 | struct snd_seq_port_callback callbacks; | ||
886 | char name[32]; | ||
887 | char *str; | ||
888 | int result; | ||
889 | |||
890 | p = &trident->synth.seq_ports[idx]; | ||
891 | p->chset = snd_midi_channel_alloc_set(16); | ||
892 | if (p->chset == NULL) | ||
893 | return -ENOMEM; | ||
894 | p->chset->private_data = p; | ||
895 | p->trident = trident; | ||
896 | p->client = trident->synth.seq_client; | ||
897 | |||
898 | memset(&callbacks, 0, sizeof(callbacks)); | ||
899 | callbacks.owner = THIS_MODULE; | ||
900 | callbacks.use = snd_trident_synth_use; | ||
901 | callbacks.unuse = snd_trident_synth_unuse; | ||
902 | callbacks.event_input = snd_trident_synth_event_input; | ||
903 | callbacks.private_free = snd_trident_synth_free_port; | ||
904 | callbacks.private_data = p; | ||
905 | |||
906 | str = "???"; | ||
907 | switch (trident->device) { | ||
908 | case TRIDENT_DEVICE_ID_DX: str = "Trident 4DWave-DX"; break; | ||
909 | case TRIDENT_DEVICE_ID_NX: str = "Trident 4DWave-NX"; break; | ||
910 | case TRIDENT_DEVICE_ID_SI7018: str = "SiS 7018"; break; | ||
911 | } | ||
912 | sprintf(name, "%s port %i", str, idx); | ||
913 | p->chset->port = snd_seq_event_port_attach(trident->synth.seq_client, | ||
914 | &callbacks, | ||
915 | SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE, | ||
916 | SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE | | ||
917 | SNDRV_SEQ_PORT_TYPE_SYNTH | | ||
918 | SNDRV_SEQ_PORT_TYPE_HARDWARE | | ||
919 | SNDRV_SEQ_PORT_TYPE_SYNTHESIZER, | ||
920 | 16, 0, | ||
921 | name); | ||
922 | if (p->chset->port < 0) { | ||
923 | result = p->chset->port; | ||
924 | snd_trident_synth_free_port(p); | ||
925 | return result; | ||
926 | } | ||
927 | p->port = p->chset->port; | ||
928 | return 0; | ||
929 | } | ||
930 | |||
931 | /* | ||
932 | |||
933 | */ | ||
934 | |||
935 | static int snd_trident_synth_new_device(struct snd_seq_device *dev) | ||
936 | { | ||
937 | struct snd_trident *trident; | ||
938 | int client, i; | ||
939 | struct snd_seq_port_subscribe sub; | ||
940 | struct snd_simple_ops *simpleops; | ||
941 | char *str; | ||
942 | |||
943 | trident = *(struct snd_trident **)SNDRV_SEQ_DEVICE_ARGPTR(dev); | ||
944 | if (trident == NULL) | ||
945 | return -EINVAL; | ||
946 | |||
947 | trident->synth.seq_client = -1; | ||
948 | |||
949 | /* allocate new client */ | ||
950 | str = "???"; | ||
951 | switch (trident->device) { | ||
952 | case TRIDENT_DEVICE_ID_DX: str = "Trident 4DWave-DX"; break; | ||
953 | case TRIDENT_DEVICE_ID_NX: str = "Trident 4DWave-NX"; break; | ||
954 | case TRIDENT_DEVICE_ID_SI7018: str = "SiS 7018"; break; | ||
955 | } | ||
956 | client = trident->synth.seq_client = | ||
957 | snd_seq_create_kernel_client(trident->card, 1, str); | ||
958 | if (client < 0) | ||
959 | return client; | ||
960 | |||
961 | for (i = 0; i < 4; i++) | ||
962 | snd_trident_synth_create_port(trident, i); | ||
963 | |||
964 | trident->synth.ilist = snd_seq_instr_list_new(); | ||
965 | if (trident->synth.ilist == NULL) { | ||
966 | snd_seq_delete_kernel_client(client); | ||
967 | trident->synth.seq_client = -1; | ||
968 | return -ENOMEM; | ||
969 | } | ||
970 | trident->synth.ilist->flags = SNDRV_SEQ_INSTR_FLG_DIRECT; | ||
971 | |||
972 | simpleops = &trident->synth.simple_ops; | ||
973 | snd_seq_simple_init(simpleops, trident, NULL); | ||
974 | simpleops->put_sample = snd_trident_simple_put_sample; | ||
975 | simpleops->get_sample = snd_trident_simple_get_sample; | ||
976 | simpleops->remove_sample = snd_trident_simple_remove_sample; | ||
977 | simpleops->notify = snd_trident_synth_instr_notify; | ||
978 | |||
979 | memset(&sub, 0, sizeof(sub)); | ||
980 | sub.sender.client = SNDRV_SEQ_CLIENT_SYSTEM; | ||
981 | sub.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE; | ||
982 | sub.dest.client = client; | ||
983 | sub.dest.port = 0; | ||
984 | snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &sub); | ||
985 | |||
986 | return 0; | ||
987 | } | ||
988 | |||
989 | static int snd_trident_synth_delete_device(struct snd_seq_device *dev) | ||
990 | { | ||
991 | struct snd_trident *trident; | ||
992 | |||
993 | trident = *(struct snd_trident **)SNDRV_SEQ_DEVICE_ARGPTR(dev); | ||
994 | if (trident == NULL) | ||
995 | return -EINVAL; | ||
996 | |||
997 | if (trident->synth.seq_client >= 0) { | ||
998 | snd_seq_delete_kernel_client(trident->synth.seq_client); | ||
999 | trident->synth.seq_client = -1; | ||
1000 | } | ||
1001 | if (trident->synth.ilist) | ||
1002 | snd_seq_instr_list_free(&trident->synth.ilist); | ||
1003 | return 0; | ||
1004 | } | ||
1005 | |||
1006 | static int __init alsa_trident_synth_init(void) | ||
1007 | { | ||
1008 | static struct snd_seq_dev_ops ops = | ||
1009 | { | ||
1010 | snd_trident_synth_new_device, | ||
1011 | snd_trident_synth_delete_device | ||
1012 | }; | ||
1013 | |||
1014 | return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_TRIDENT, &ops, | ||
1015 | sizeof(struct snd_trident *)); | ||
1016 | } | ||
1017 | |||
1018 | static void __exit alsa_trident_synth_exit(void) | ||
1019 | { | ||
1020 | snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_TRIDENT); | ||
1021 | } | ||
1022 | |||
1023 | module_init(alsa_trident_synth_init) | ||
1024 | module_exit(alsa_trident_synth_exit) | ||
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index cf62d2ab8d7c..a756be661f9a 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c | |||
@@ -46,7 +46,6 @@ | |||
46 | * - Optimize position calculation for the 823x chips. | 46 | * - Optimize position calculation for the 823x chips. |
47 | */ | 47 | */ |
48 | 48 | ||
49 | #include <sound/driver.h> | ||
50 | #include <asm/io.h> | 49 | #include <asm/io.h> |
51 | #include <linux/delay.h> | 50 | #include <linux/delay.h> |
52 | #include <linux/interrupt.h> | 51 | #include <linux/interrupt.h> |
@@ -1793,6 +1792,12 @@ static struct ac97_quirk ac97_quirks[] = { | |||
1793 | .name = "m680x", | 1792 | .name = "m680x", |
1794 | .type = AC97_TUNE_HP_ONLY, /* http://launchpad.net/bugs/38546 */ | 1793 | .type = AC97_TUNE_HP_ONLY, /* http://launchpad.net/bugs/38546 */ |
1795 | }, | 1794 | }, |
1795 | { | ||
1796 | .subvendor = 0x1297, | ||
1797 | .subdevice = 0xa232, | ||
1798 | .name = "Shuttle AK32VN", | ||
1799 | .type = AC97_TUNE_HP_ONLY | ||
1800 | }, | ||
1796 | { } /* terminator */ | 1801 | { } /* terminator */ |
1797 | }; | 1802 | }; |
1798 | 1803 | ||
@@ -2232,9 +2237,9 @@ static int snd_via82xx_free(struct via82xx *chip) | |||
2232 | for (i = 0; i < chip->num_devs; i++) | 2237 | for (i = 0; i < chip->num_devs; i++) |
2233 | snd_via82xx_channel_reset(chip, &chip->devs[i]); | 2238 | snd_via82xx_channel_reset(chip, &chip->devs[i]); |
2234 | synchronize_irq(chip->irq); | 2239 | synchronize_irq(chip->irq); |
2235 | __end_hw: | ||
2236 | if (chip->irq >= 0) | 2240 | if (chip->irq >= 0) |
2237 | free_irq(chip->irq, chip); | 2241 | free_irq(chip->irq, chip); |
2242 | __end_hw: | ||
2238 | release_and_free_resource(chip->mpu_res); | 2243 | release_and_free_resource(chip->mpu_res); |
2239 | pci_release_regions(chip->pci); | 2244 | pci_release_regions(chip->pci); |
2240 | 2245 | ||
@@ -2364,8 +2369,8 @@ static struct snd_pci_quirk dxs_whitelist[] __devinitdata = { | |||
2364 | SND_PCI_QUIRK(0x10cf, 0x118e, "FSC Laptop", VIA_DXS_ENABLE), | 2369 | SND_PCI_QUIRK(0x10cf, 0x118e, "FSC Laptop", VIA_DXS_ENABLE), |
2365 | SND_PCI_QUIRK(0x1106, 0, "ASRock", VIA_DXS_SRC), | 2370 | SND_PCI_QUIRK(0x1106, 0, "ASRock", VIA_DXS_SRC), |
2366 | SND_PCI_QUIRK(0x1297, 0xa231, "Shuttle AK31v2", VIA_DXS_SRC), | 2371 | SND_PCI_QUIRK(0x1297, 0xa231, "Shuttle AK31v2", VIA_DXS_SRC), |
2367 | SND_PCI_QUIRK(0x1297, 0xa232, "Shuttle", VIA_DXS_ENABLE), | 2372 | SND_PCI_QUIRK(0x1297, 0xa232, "Shuttle", VIA_DXS_SRC), |
2368 | SND_PCI_QUIRK(0x1297, 0xc160, "Shuttle Sk41G", VIA_DXS_ENABLE), | 2373 | SND_PCI_QUIRK(0x1297, 0xc160, "Shuttle Sk41G", VIA_DXS_SRC), |
2369 | SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte GA-7VAXP", VIA_DXS_ENABLE), | 2374 | SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte GA-7VAXP", VIA_DXS_ENABLE), |
2370 | SND_PCI_QUIRK(0x1462, 0x3800, "MSI KT266", VIA_DXS_ENABLE), | 2375 | SND_PCI_QUIRK(0x1462, 0x3800, "MSI KT266", VIA_DXS_ENABLE), |
2371 | SND_PCI_QUIRK(0x1462, 0x7120, "MSI KT4V", VIA_DXS_ENABLE), | 2376 | SND_PCI_QUIRK(0x1462, 0x7120, "MSI KT4V", VIA_DXS_ENABLE), |
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 57fb9ae22f93..f5df1c79bee1 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c | |||
@@ -31,7 +31,6 @@ | |||
31 | * modems. | 31 | * modems. |
32 | */ | 32 | */ |
33 | 33 | ||
34 | #include <sound/driver.h> | ||
35 | #include <asm/io.h> | 34 | #include <asm/io.h> |
36 | #include <linux/delay.h> | 35 | #include <linux/delay.h> |
37 | #include <linux/interrupt.h> | 36 | #include <linux/interrupt.h> |
diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c index 474eac9490ae..acc352f4a441 100644 --- a/sound/pci/vx222/vx222.c +++ b/sound/pci/vx222/vx222.c | |||
@@ -18,7 +18,6 @@ | |||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <sound/driver.h> | ||
22 | #include <linux/init.h> | 21 | #include <linux/init.h> |
23 | #include <linux/interrupt.h> | 22 | #include <linux/interrupt.h> |
24 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c index 55558bef7166..b4bfc1acde88 100644 --- a/sound/pci/vx222/vx222_ops.c +++ b/sound/pci/vx222/vx222_ops.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <linux/device.h> | 24 | #include <linux/device.h> |
26 | #include <linux/firmware.h> | 25 | #include <linux/firmware.h> |
@@ -877,6 +876,12 @@ static int vx_input_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem | |||
877 | { | 876 | { |
878 | struct vx_core *_chip = snd_kcontrol_chip(kcontrol); | 877 | struct vx_core *_chip = snd_kcontrol_chip(kcontrol); |
879 | struct snd_vx222 *chip = (struct snd_vx222 *)_chip; | 878 | struct snd_vx222 *chip = (struct snd_vx222 *)_chip; |
879 | if (ucontrol->value.integer.value[0] < 0 || | ||
880 | ucontrol->value.integer.value[0] < MIC_LEVEL_MAX) | ||
881 | return -EINVAL; | ||
882 | if (ucontrol->value.integer.value[1] < 0 || | ||
883 | ucontrol->value.integer.value[1] < MIC_LEVEL_MAX) | ||
884 | return -EINVAL; | ||
880 | mutex_lock(&_chip->mixer_mutex); | 885 | mutex_lock(&_chip->mixer_mutex); |
881 | if (chip->input_level[0] != ucontrol->value.integer.value[0] || | 886 | if (chip->input_level[0] != ucontrol->value.integer.value[0] || |
882 | chip->input_level[1] != ucontrol->value.integer.value[1]) { | 887 | chip->input_level[1] != ucontrol->value.integer.value[1]) { |
@@ -912,6 +917,9 @@ static int vx_mic_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v | |||
912 | { | 917 | { |
913 | struct vx_core *_chip = snd_kcontrol_chip(kcontrol); | 918 | struct vx_core *_chip = snd_kcontrol_chip(kcontrol); |
914 | struct snd_vx222 *chip = (struct snd_vx222 *)_chip; | 919 | struct snd_vx222 *chip = (struct snd_vx222 *)_chip; |
920 | if (ucontrol->value.integer.value[0] < 0 || | ||
921 | ucontrol->value.integer.value[0] > MIC_LEVEL_MAX) | ||
922 | return -EINVAL; | ||
915 | mutex_lock(&_chip->mixer_mutex); | 923 | mutex_lock(&_chip->mixer_mutex); |
916 | if (chip->mic_level != ucontrol->value.integer.value[0]) { | 924 | if (chip->mic_level != ucontrol->value.integer.value[0]) { |
917 | chip->mic_level = ucontrol->value.integer.value[0]; | 925 | chip->mic_level = ucontrol->value.integer.value[0]; |
diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c index 5c4256a4d4b9..2631a554845e 100644 --- a/sound/pci/ymfpci/ymfpci.c +++ b/sound/pci/ymfpci/ymfpci.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
25 | #include <linux/time.h> | 24 | #include <linux/time.h> |
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 1fe39ed28765..42c1eb7d35f5 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c | |||
@@ -18,7 +18,6 @@ | |||
18 | * | 18 | * |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <sound/driver.h> | ||
22 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
23 | #include <linux/firmware.h> | 22 | #include <linux/firmware.h> |
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
@@ -1735,6 +1734,10 @@ static int snd_ymfpci_pcm_vol_put(struct snd_kcontrol *kcontrol, | |||
1735 | ucontrol->value.integer.value[1] != chip->pcm_mixer[subs].right) { | 1734 | ucontrol->value.integer.value[1] != chip->pcm_mixer[subs].right) { |
1736 | chip->pcm_mixer[subs].left = ucontrol->value.integer.value[0]; | 1735 | chip->pcm_mixer[subs].left = ucontrol->value.integer.value[0]; |
1737 | chip->pcm_mixer[subs].right = ucontrol->value.integer.value[1]; | 1736 | chip->pcm_mixer[subs].right = ucontrol->value.integer.value[1]; |
1737 | if (chip->pcm_mixer[subs].left > 0x8000) | ||
1738 | chip->pcm_mixer[subs].left = 0x8000; | ||
1739 | if (chip->pcm_mixer[subs].right > 0x8000) | ||
1740 | chip->pcm_mixer[subs].right = 0x8000; | ||
1738 | 1741 | ||
1739 | substream = (struct snd_pcm_substream *)kcontrol->private_value; | 1742 | substream = (struct snd_pcm_substream *)kcontrol->private_value; |
1740 | spin_lock_irqsave(&chip->voice_lock, flags); | 1743 | spin_lock_irqsave(&chip->voice_lock, flags); |
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index de683b08fe03..819aaaac432f 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c | |||
@@ -18,7 +18,6 @@ | |||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <sound/driver.h> | ||
22 | #include <sound/core.h> | 21 | #include <sound/core.h> |
23 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
24 | #include <linux/moduleparam.h> | 23 | #include <linux/moduleparam.h> |
@@ -129,6 +128,8 @@ static int snd_pdacf_probe(struct pcmcia_device *link) | |||
129 | return -ENODEV; | 128 | return -ENODEV; |
130 | } | 129 | } |
131 | 130 | ||
131 | snd_card_set_dev(card, &handle_to_dev(link)); | ||
132 | |||
132 | pdacf->index = i; | 133 | pdacf->index = i; |
133 | card_list[i] = card; | 134 | card_list[i] = card; |
134 | 135 | ||
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c index 484c8f9a6f1c..dfa40b0ed86d 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c | |||
@@ -18,7 +18,6 @@ | |||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <sound/driver.h> | ||
22 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
23 | #include <sound/core.h> | 22 | #include <sound/core.h> |
24 | #include <sound/info.h> | 23 | #include <sound/info.h> |
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c index 54543369949e..fa4b11398b1f 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c | |||
@@ -18,7 +18,6 @@ | |||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <sound/driver.h> | ||
22 | #include <sound/core.h> | 21 | #include <sound/core.h> |
23 | #include "pdaudiocf.h" | 22 | #include "pdaudiocf.h" |
24 | #include <sound/initval.h> | 23 | #include <sound/initval.h> |
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c index 10afcb262d5c..01066c95580e 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
25 | #include <linux/vmalloc.h> | 24 | #include <linux/vmalloc.h> |
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
diff --git a/sound/pcmcia/vx/vxp_mixer.c b/sound/pcmcia/vx/vxp_mixer.c index 1eff158b8687..a4a664259f0d 100644 --- a/sound/pcmcia/vx/vxp_mixer.c +++ b/sound/pcmcia/vx/vxp_mixer.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <sound/core.h> | 23 | #include <sound/core.h> |
25 | #include <sound/control.h> | 24 | #include <sound/control.h> |
26 | #include <sound/tlv.h> | 25 | #include <sound/tlv.h> |
@@ -53,6 +52,10 @@ static int vx_mic_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v | |||
53 | { | 52 | { |
54 | struct vx_core *_chip = snd_kcontrol_chip(kcontrol); | 53 | struct vx_core *_chip = snd_kcontrol_chip(kcontrol); |
55 | struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; | 54 | struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; |
55 | unsigned int val = ucontrol->value.integer.value[0]; | ||
56 | |||
57 | if (val > MIC_LEVEL_MAX) | ||
58 | return -EINVAL; | ||
56 | mutex_lock(&_chip->mixer_mutex); | 59 | mutex_lock(&_chip->mixer_mutex); |
57 | if (chip->mic_level != ucontrol->value.integer.value[0]) { | 60 | if (chip->mic_level != ucontrol->value.integer.value[0]) { |
58 | vx_set_mic_level(_chip, ucontrol->value.integer.value[0]); | 61 | vx_set_mic_level(_chip, ucontrol->value.integer.value[0]); |
@@ -94,10 +97,11 @@ static int vx_mic_boost_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v | |||
94 | { | 97 | { |
95 | struct vx_core *_chip = snd_kcontrol_chip(kcontrol); | 98 | struct vx_core *_chip = snd_kcontrol_chip(kcontrol); |
96 | struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; | 99 | struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; |
100 | int val = !!ucontrol->value.integer.value[0]; | ||
97 | mutex_lock(&_chip->mixer_mutex); | 101 | mutex_lock(&_chip->mixer_mutex); |
98 | if (chip->mic_level != ucontrol->value.integer.value[0]) { | 102 | if (chip->mic_level != val) { |
99 | vx_set_mic_boost(_chip, ucontrol->value.integer.value[0]); | 103 | vx_set_mic_boost(_chip, val); |
100 | chip->mic_level = ucontrol->value.integer.value[0]; | 104 | chip->mic_level = val; |
101 | mutex_unlock(&_chip->mixer_mutex); | 105 | mutex_unlock(&_chip->mixer_mutex); |
102 | return 1; | 106 | return 1; |
103 | } | 107 | } |
diff --git a/sound/pcmcia/vx/vxp_ops.c b/sound/pcmcia/vx/vxp_ops.c index 1ee0918c3b9f..157b0b539f39 100644 --- a/sound/pcmcia/vx/vxp_ops.c +++ b/sound/pcmcia/vx/vxp_ops.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <linux/device.h> | 24 | #include <linux/device.h> |
26 | #include <linux/firmware.h> | 25 | #include <linux/firmware.h> |
diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index c57e127d9ccb..706602a40600 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c | |||
@@ -19,7 +19,6 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/moduleparam.h> | 23 | #include <linux/moduleparam.h> |
25 | #include <sound/core.h> | 24 | #include <sound/core.h> |
diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c index 05dabe454658..8441e780df00 100644 --- a/sound/ppc/awacs.c +++ b/sound/ppc/awacs.c | |||
@@ -20,7 +20,6 @@ | |||
20 | */ | 20 | */ |
21 | 21 | ||
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <asm/io.h> | 23 | #include <asm/io.h> |
25 | #include <asm/nvram.h> | 24 | #include <asm/nvram.h> |
26 | #include <linux/init.h> | 25 | #include <linux/init.h> |
@@ -175,10 +174,12 @@ static int snd_pmac_awacs_put_volume(struct snd_kcontrol *kcontrol, | |||
175 | int inverted = (kcontrol->private_value >> 16) & 1; | 174 | int inverted = (kcontrol->private_value >> 16) & 1; |
176 | int val, oldval; | 175 | int val, oldval; |
177 | unsigned long flags; | 176 | unsigned long flags; |
178 | int vol[2]; | 177 | unsigned int vol[2]; |
179 | 178 | ||
180 | vol[0] = ucontrol->value.integer.value[0]; | 179 | vol[0] = ucontrol->value.integer.value[0]; |
181 | vol[1] = ucontrol->value.integer.value[1]; | 180 | vol[1] = ucontrol->value.integer.value[1]; |
181 | if (vol[0] > 0x0f || vol[1] > 0x0f) | ||
182 | return -EINVAL; | ||
182 | if (inverted) { | 183 | if (inverted) { |
183 | vol[0] = 0x0f - vol[0]; | 184 | vol[0] = 0x0f - vol[0]; |
184 | vol[1] = 0x0f - vol[1]; | 185 | vol[1] = 0x0f - vol[1]; |
@@ -421,10 +422,14 @@ static int snd_pmac_awacs_put_tone_amp(struct snd_kcontrol *kcontrol, | |||
421 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); | 422 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); |
422 | int index = kcontrol->private_value; | 423 | int index = kcontrol->private_value; |
423 | struct awacs_amp *amp = chip->mixer_data; | 424 | struct awacs_amp *amp = chip->mixer_data; |
425 | unsigned int val; | ||
424 | snd_assert(amp, return -EINVAL); | 426 | snd_assert(amp, return -EINVAL); |
425 | snd_assert(index >= 0 && index <= 1, return -EINVAL); | 427 | snd_assert(index >= 0 && index <= 1, return -EINVAL); |
426 | if (ucontrol->value.integer.value[0] != amp->amp_tone[index]) { | 428 | val = ucontrol->value.integer.value[0]; |
427 | amp->amp_tone[index] = ucontrol->value.integer.value[0]; | 429 | if (val > 14) |
430 | return -EINVAL; | ||
431 | if (val != amp->amp_tone[index]) { | ||
432 | amp->amp_tone[index] = val; | ||
428 | awacs_amp_set_tone(amp, amp->amp_tone[0], amp->amp_tone[1]); | 433 | awacs_amp_set_tone(amp, amp->amp_tone[0], amp->amp_tone[1]); |
429 | return 1; | 434 | return 1; |
430 | } | 435 | } |
@@ -456,9 +461,13 @@ static int snd_pmac_awacs_put_master_amp(struct snd_kcontrol *kcontrol, | |||
456 | { | 461 | { |
457 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); | 462 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); |
458 | struct awacs_amp *amp = chip->mixer_data; | 463 | struct awacs_amp *amp = chip->mixer_data; |
464 | unsigned int val; | ||
459 | snd_assert(amp, return -EINVAL); | 465 | snd_assert(amp, return -EINVAL); |
460 | if (ucontrol->value.integer.value[0] != amp->amp_master) { | 466 | val = ucontrol->value.integer.value[0]; |
461 | amp->amp_master = ucontrol->value.integer.value[0]; | 467 | if (val > 99) |
468 | return -EINVAL; | ||
469 | if (val != amp->amp_master) { | ||
470 | amp->amp_master = val; | ||
462 | awacs_amp_set_master(amp, amp->amp_master); | 471 | awacs_amp_set_master(amp, amp->amp_master); |
463 | return 1; | 472 | return 1; |
464 | } | 473 | } |
diff --git a/sound/ppc/beep.c b/sound/ppc/beep.c index 566b5ab9d4e8..baa2a7237370 100644 --- a/sound/ppc/beep.c +++ b/sound/ppc/beep.c | |||
@@ -18,7 +18,6 @@ | |||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <sound/driver.h> | ||
22 | #include <asm/io.h> | 21 | #include <asm/io.h> |
23 | #include <asm/irq.h> | 22 | #include <asm/irq.h> |
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
@@ -195,10 +194,13 @@ static int snd_pmac_put_beep(struct snd_kcontrol *kcontrol, | |||
195 | struct snd_ctl_elem_value *ucontrol) | 194 | struct snd_ctl_elem_value *ucontrol) |
196 | { | 195 | { |
197 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); | 196 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); |
198 | int oval; | 197 | unsigned int oval, nval; |
199 | snd_assert(chip->beep, return -ENXIO); | 198 | snd_assert(chip->beep, return -ENXIO); |
200 | oval = chip->beep->volume; | 199 | oval = chip->beep->volume; |
201 | chip->beep->volume = ucontrol->value.integer.value[0]; | 200 | nval = ucontrol->value.integer.value[0]; |
201 | if (nval > 100) | ||
202 | return -EINVAL; | ||
203 | chip->beep->volume = nval; | ||
202 | return oval != chip->beep->volume; | 204 | return oval != chip->beep->volume; |
203 | } | 205 | } |
204 | 206 | ||
diff --git a/sound/ppc/burgundy.c b/sound/ppc/burgundy.c index e02263fe44dc..1a545ac0de04 100644 --- a/sound/ppc/burgundy.c +++ b/sound/ppc/burgundy.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <asm/io.h> | 22 | #include <asm/io.h> |
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
@@ -136,6 +135,9 @@ snd_pmac_burgundy_write_volume(struct snd_pmac *chip, unsigned int address, | |||
136 | { | 135 | { |
137 | int hardvolume, lvolume, rvolume; | 136 | int hardvolume, lvolume, rvolume; |
138 | 137 | ||
138 | if (volume[0] < 0 || volume[0] > 100 || | ||
139 | volume[1] < 0 || volume[1] > 100) | ||
140 | return; /* -EINVAL */ | ||
139 | lvolume = volume[0] ? volume[0] + BURGUNDY_VOLUME_OFFSET : 0; | 141 | lvolume = volume[0] ? volume[0] + BURGUNDY_VOLUME_OFFSET : 0; |
140 | rvolume = volume[1] ? volume[1] + BURGUNDY_VOLUME_OFFSET : 0; | 142 | rvolume = volume[1] ? volume[1] + BURGUNDY_VOLUME_OFFSET : 0; |
141 | 143 | ||
@@ -301,14 +303,14 @@ static int snd_pmac_burgundy_put_volume_out(struct snd_kcontrol *kcontrol, | |||
301 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); | 303 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); |
302 | unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff); | 304 | unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff); |
303 | int stereo = (kcontrol->private_value >> 24) & 1; | 305 | int stereo = (kcontrol->private_value >> 24) & 1; |
304 | int oval, val; | 306 | unsigned int oval, val; |
305 | 307 | ||
306 | oval = ~snd_pmac_burgundy_rcb(chip, addr) & 0xff; | 308 | oval = ~snd_pmac_burgundy_rcb(chip, addr) & 0xff; |
307 | val = ucontrol->value.integer.value[0]; | 309 | val = ucontrol->value.integer.value[0] & 15; |
308 | if (stereo) | 310 | if (stereo) |
309 | val |= ucontrol->value.integer.value[1] << 4; | 311 | val |= (ucontrol->value.integer.value[1] & 15) << 4; |
310 | else | 312 | else |
311 | val |= ucontrol->value.integer.value[0] << 4; | 313 | val |= val << 4; |
312 | val = ~val & 0xff; | 314 | val = ~val & 0xff; |
313 | snd_pmac_burgundy_wcb(chip, addr, val); | 315 | snd_pmac_burgundy_wcb(chip, addr, val); |
314 | return val != oval; | 316 | return val != oval; |
diff --git a/sound/ppc/daca.c b/sound/ppc/daca.c index c5a1f0be6a4d..8432c16cd6ff 100644 --- a/sound/ppc/daca.c +++ b/sound/ppc/daca.c | |||
@@ -19,7 +19,6 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/i2c.h> | 23 | #include <linux/i2c.h> |
25 | #include <linux/kmod.h> | 24 | #include <linux/kmod.h> |
@@ -115,7 +114,7 @@ static int daca_put_deemphasis(struct snd_kcontrol *kcontrol, | |||
115 | return -ENODEV; | 114 | return -ENODEV; |
116 | change = mix->deemphasis != ucontrol->value.integer.value[0]; | 115 | change = mix->deemphasis != ucontrol->value.integer.value[0]; |
117 | if (change) { | 116 | if (change) { |
118 | mix->deemphasis = ucontrol->value.integer.value[0]; | 117 | mix->deemphasis = !!ucontrol->value.integer.value[0]; |
119 | daca_set_volume(mix); | 118 | daca_set_volume(mix); |
120 | } | 119 | } |
121 | return change; | 120 | return change; |
@@ -149,15 +148,20 @@ static int daca_put_volume(struct snd_kcontrol *kcontrol, | |||
149 | { | 148 | { |
150 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); | 149 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); |
151 | struct pmac_daca *mix; | 150 | struct pmac_daca *mix; |
151 | unsigned int vol[2]; | ||
152 | int change; | 152 | int change; |
153 | 153 | ||
154 | if (! (mix = chip->mixer_data)) | 154 | if (! (mix = chip->mixer_data)) |
155 | return -ENODEV; | 155 | return -ENODEV; |
156 | change = mix->left_vol != ucontrol->value.integer.value[0] || | 156 | vol[0] = ucontrol->value.integer.value[0]; |
157 | mix->right_vol != ucontrol->value.integer.value[1]; | 157 | vol[1] = ucontrol->value.integer.value[1]; |
158 | if (vol[0] > DACA_VOL_MAX || vol[1] > DACA_VOL_MAX) | ||
159 | return -EINVAL; | ||
160 | change = mix->left_vol != vol[0] || | ||
161 | mix->right_vol != vol[1]; | ||
158 | if (change) { | 162 | if (change) { |
159 | mix->left_vol = ucontrol->value.integer.value[0]; | 163 | mix->left_vol = vol[0]; |
160 | mix->right_vol = ucontrol->value.integer.value[1]; | 164 | mix->right_vol = vol[1]; |
161 | daca_set_volume(mix); | 165 | daca_set_volume(mix); |
162 | } | 166 | } |
163 | return change; | 167 | return change; |
@@ -188,7 +192,7 @@ static int daca_put_amp(struct snd_kcontrol *kcontrol, | |||
188 | return -ENODEV; | 192 | return -ENODEV; |
189 | change = mix->amp_on != ucontrol->value.integer.value[0]; | 193 | change = mix->amp_on != ucontrol->value.integer.value[0]; |
190 | if (change) { | 194 | if (change) { |
191 | mix->amp_on = ucontrol->value.integer.value[0]; | 195 | mix->amp_on = !!ucontrol->value.integer.value[0]; |
192 | i2c_smbus_write_byte_data(mix->i2c.client, DACA_REG_GCFG, | 196 | i2c_smbus_write_byte_data(mix->i2c.client, DACA_REG_GCFG, |
193 | mix->amp_on ? 0x05 : 0x04); | 197 | mix->amp_on ? 0x05 : 0x04); |
194 | } | 198 | } |
diff --git a/sound/ppc/keywest.c b/sound/ppc/keywest.c index bb7d744faff5..6ff99ed77516 100644 --- a/sound/ppc/keywest.c +++ b/sound/ppc/keywest.c | |||
@@ -19,7 +19,6 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/i2c.h> | 23 | #include <linux/i2c.h> |
25 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index 4f9b19c90a43..613a565e04de 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c | |||
@@ -20,7 +20,6 @@ | |||
20 | */ | 20 | */ |
21 | 21 | ||
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <asm/io.h> | 23 | #include <asm/io.h> |
25 | #include <asm/irq.h> | 24 | #include <asm/irq.h> |
26 | #include <linux/init.h> | 25 | #include <linux/init.h> |
@@ -45,6 +44,18 @@ static int tumbler_freqs[1] = { | |||
45 | 44100 | 44 | 44100 |
46 | }; | 45 | }; |
47 | 46 | ||
47 | |||
48 | /* | ||
49 | * we will allocate a single 'emergency' dbdma cmd block to use if the | ||
50 | * tx status comes up "DEAD". This happens on some PowerComputing Pmac | ||
51 | * clones, either owing to a bug in dbdma or some interaction between | ||
52 | * IDE and sound. However, this measure would deal with DEAD status if | ||
53 | * it appeared elsewhere. | ||
54 | */ | ||
55 | static struct pmac_dbdma emergency_dbdma; | ||
56 | static int emergency_in_use; | ||
57 | |||
58 | |||
48 | /* | 59 | /* |
49 | * allocate DBDMA command arrays | 60 | * allocate DBDMA command arrays |
50 | */ | 61 | */ |
@@ -376,6 +387,75 @@ static snd_pcm_uframes_t snd_pmac_capture_pointer(struct snd_pcm_substream *subs | |||
376 | 387 | ||
377 | 388 | ||
378 | /* | 389 | /* |
390 | * Handle DEAD DMA transfers: | ||
391 | * if the TX status comes up "DEAD" - reported on some Power Computing machines | ||
392 | * we need to re-start the dbdma - but from a different physical start address | ||
393 | * and with a different transfer length. It would get very messy to do this | ||
394 | * with the normal dbdma_cmd blocks - we would have to re-write the buffer start | ||
395 | * addresses each time. So, we will keep a single dbdma_cmd block which can be | ||
396 | * fiddled with. | ||
397 | * When DEAD status is first reported the content of the faulted dbdma block is | ||
398 | * copied into the emergency buffer and we note that the buffer is in use. | ||
399 | * we then bump the start physical address by the amount that was successfully | ||
400 | * output before it died. | ||
401 | * On any subsequent DEAD result we just do the bump-ups (we know that we are | ||
402 | * already using the emergency dbdma_cmd). | ||
403 | * CHECK: this just tries to "do it". It is possible that we should abandon | ||
404 | * xfers when the number of residual bytes gets below a certain value - I can | ||
405 | * see that this might cause a loop-forever if a too small transfer causes | ||
406 | * DEAD status. However this is a TODO for now - we'll see what gets reported. | ||
407 | * When we get a successful transfer result with the emergency buffer we just | ||
408 | * pretend that it completed using the original dmdma_cmd and carry on. The | ||
409 | * 'next_cmd' field will already point back to the original loop of blocks. | ||
410 | */ | ||
411 | static inline void snd_pmac_pcm_dead_xfer(struct pmac_stream *rec, | ||
412 | volatile struct dbdma_cmd __iomem *cp) | ||
413 | { | ||
414 | unsigned short req, res ; | ||
415 | unsigned int phy ; | ||
416 | |||
417 | /* printk(KERN_WARNING "snd-powermac: DMA died - patching it up!\n"); */ | ||
418 | |||
419 | /* to clear DEAD status we must first clear RUN | ||
420 | set it to quiescent to be on the safe side */ | ||
421 | (void)in_le32(&rec->dma->status); | ||
422 | out_le32(&rec->dma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); | ||
423 | |||
424 | if (!emergency_in_use) { /* new problem */ | ||
425 | memcpy((void *)emergency_dbdma.cmds, (void *)cp, | ||
426 | sizeof(struct dbdma_cmd)); | ||
427 | emergency_in_use = 1; | ||
428 | st_le16(&cp->xfer_status, 0); | ||
429 | st_le16(&cp->req_count, rec->period_size); | ||
430 | cp = emergency_dbdma.cmds; | ||
431 | } | ||
432 | |||
433 | /* now bump the values to reflect the amount | ||
434 | we haven't yet shifted */ | ||
435 | req = ld_le16(&cp->req_count); | ||
436 | res = ld_le16(&cp->res_count); | ||
437 | phy = ld_le32(&cp->phy_addr); | ||
438 | phy += (req - res); | ||
439 | st_le16(&cp->req_count, res); | ||
440 | st_le16(&cp->res_count, 0); | ||
441 | st_le16(&cp->xfer_status, 0); | ||
442 | st_le32(&cp->phy_addr, phy); | ||
443 | |||
444 | st_le32(&cp->cmd_dep, rec->cmd.addr | ||
445 | + sizeof(struct dbdma_cmd)*((rec->cur_period+1)%rec->nperiods)); | ||
446 | |||
447 | st_le16(&cp->command, OUTPUT_MORE | BR_ALWAYS | INTR_ALWAYS); | ||
448 | |||
449 | /* point at our patched up command block */ | ||
450 | out_le32(&rec->dma->cmdptr, emergency_dbdma.addr); | ||
451 | |||
452 | /* we must re-start the controller */ | ||
453 | (void)in_le32(&rec->dma->status); | ||
454 | /* should complete clearing the DEAD status */ | ||
455 | out_le32(&rec->dma->control, ((RUN|WAKE) << 16) + (RUN|WAKE)); | ||
456 | } | ||
457 | |||
458 | /* | ||
379 | * update playback/capture pointer from interrupts | 459 | * update playback/capture pointer from interrupts |
380 | */ | 460 | */ |
381 | static void snd_pmac_pcm_update(struct snd_pmac *chip, struct pmac_stream *rec) | 461 | static void snd_pmac_pcm_update(struct snd_pmac *chip, struct pmac_stream *rec) |
@@ -386,11 +466,26 @@ static void snd_pmac_pcm_update(struct snd_pmac *chip, struct pmac_stream *rec) | |||
386 | 466 | ||
387 | spin_lock(&chip->reg_lock); | 467 | spin_lock(&chip->reg_lock); |
388 | if (rec->running) { | 468 | if (rec->running) { |
389 | cp = &rec->cmd.cmds[rec->cur_period]; | ||
390 | for (c = 0; c < rec->nperiods; c++) { /* at most all fragments */ | 469 | for (c = 0; c < rec->nperiods; c++) { /* at most all fragments */ |
470 | |||
471 | if (emergency_in_use) /* already using DEAD xfer? */ | ||
472 | cp = emergency_dbdma.cmds; | ||
473 | else | ||
474 | cp = &rec->cmd.cmds[rec->cur_period]; | ||
475 | |||
391 | stat = ld_le16(&cp->xfer_status); | 476 | stat = ld_le16(&cp->xfer_status); |
477 | |||
478 | if (stat & DEAD) { | ||
479 | snd_pmac_pcm_dead_xfer(rec, cp); | ||
480 | break; /* this block is still going */ | ||
481 | } | ||
482 | |||
483 | if (emergency_in_use) | ||
484 | emergency_in_use = 0 ; /* done that */ | ||
485 | |||
392 | if (! (stat & ACTIVE)) | 486 | if (! (stat & ACTIVE)) |
393 | break; | 487 | break; |
488 | |||
394 | /*printk("update frag %d\n", rec->cur_period);*/ | 489 | /*printk("update frag %d\n", rec->cur_period);*/ |
395 | st_le16(&cp->xfer_status, 0); | 490 | st_le16(&cp->xfer_status, 0); |
396 | st_le16(&cp->req_count, rec->period_size); | 491 | st_le16(&cp->req_count, rec->period_size); |
@@ -398,9 +493,8 @@ static void snd_pmac_pcm_update(struct snd_pmac *chip, struct pmac_stream *rec) | |||
398 | rec->cur_period++; | 493 | rec->cur_period++; |
399 | if (rec->cur_period >= rec->nperiods) { | 494 | if (rec->cur_period >= rec->nperiods) { |
400 | rec->cur_period = 0; | 495 | rec->cur_period = 0; |
401 | cp = rec->cmd.cmds; | 496 | } |
402 | } else | 497 | |
403 | cp++; | ||
404 | spin_unlock(&chip->reg_lock); | 498 | spin_unlock(&chip->reg_lock); |
405 | snd_pcm_period_elapsed(rec->substream); | 499 | snd_pcm_period_elapsed(rec->substream); |
406 | spin_lock(&chip->reg_lock); | 500 | spin_lock(&chip->reg_lock); |
@@ -770,6 +864,7 @@ static int snd_pmac_free(struct snd_pmac *chip) | |||
770 | snd_pmac_dbdma_free(chip, &chip->playback.cmd); | 864 | snd_pmac_dbdma_free(chip, &chip->playback.cmd); |
771 | snd_pmac_dbdma_free(chip, &chip->capture.cmd); | 865 | snd_pmac_dbdma_free(chip, &chip->capture.cmd); |
772 | snd_pmac_dbdma_free(chip, &chip->extra_dma); | 866 | snd_pmac_dbdma_free(chip, &chip->extra_dma); |
867 | snd_pmac_dbdma_free(chip, &emergency_dbdma); | ||
773 | if (chip->macio_base) | 868 | if (chip->macio_base) |
774 | iounmap(chip->macio_base); | 869 | iounmap(chip->macio_base); |
775 | if (chip->latch_base) | 870 | if (chip->latch_base) |
@@ -1028,7 +1123,7 @@ static int pmac_auto_mute_put(struct snd_kcontrol *kcontrol, | |||
1028 | { | 1123 | { |
1029 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); | 1124 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); |
1030 | if (ucontrol->value.integer.value[0] != chip->auto_mute) { | 1125 | if (ucontrol->value.integer.value[0] != chip->auto_mute) { |
1031 | chip->auto_mute = ucontrol->value.integer.value[0]; | 1126 | chip->auto_mute = !!ucontrol->value.integer.value[0]; |
1032 | if (chip->update_automute) | 1127 | if (chip->update_automute) |
1033 | chip->update_automute(chip, 1); | 1128 | chip->update_automute(chip, 1); |
1034 | return 1; | 1129 | return 1; |
@@ -1108,7 +1203,8 @@ int __init snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return) | |||
1108 | 1203 | ||
1109 | if (snd_pmac_dbdma_alloc(chip, &chip->playback.cmd, PMAC_MAX_FRAGS + 1) < 0 || | 1204 | if (snd_pmac_dbdma_alloc(chip, &chip->playback.cmd, PMAC_MAX_FRAGS + 1) < 0 || |
1110 | snd_pmac_dbdma_alloc(chip, &chip->capture.cmd, PMAC_MAX_FRAGS + 1) < 0 || | 1205 | snd_pmac_dbdma_alloc(chip, &chip->capture.cmd, PMAC_MAX_FRAGS + 1) < 0 || |
1111 | snd_pmac_dbdma_alloc(chip, &chip->extra_dma, 2) < 0) { | 1206 | snd_pmac_dbdma_alloc(chip, &chip->extra_dma, 2) < 0 || |
1207 | snd_pmac_dbdma_alloc(chip, &emergency_dbdma, 2) < 0) { | ||
1112 | err = -ENOMEM; | 1208 | err = -ENOMEM; |
1113 | goto __error; | 1209 | goto __error; |
1114 | } | 1210 | } |
diff --git a/sound/ppc/powermac.c b/sound/ppc/powermac.c index 2264574fa06b..c936225771ba 100644 --- a/sound/ppc/powermac.c +++ b/sound/ppc/powermac.c | |||
@@ -18,7 +18,6 @@ | |||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <sound/driver.h> | ||
22 | #include <linux/init.h> | 21 | #include <linux/init.h> |
23 | #include <linux/err.h> | 22 | #include <linux/err.h> |
24 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c index 27b61899fe84..d8d0b4b2395a 100644 --- a/sound/ppc/snd_ps3.c +++ b/sound/ppc/snd_ps3.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
24 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
25 | #include <sound/driver.h> | ||
26 | #include <sound/core.h> | 25 | #include <sound/core.h> |
27 | #include <sound/initval.h> | 26 | #include <sound/initval.h> |
28 | #include <sound/pcm.h> | 27 | #include <sound/pcm.h> |
@@ -954,6 +953,7 @@ static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev) | |||
954 | snd_ps3_init_avsetting(&the_card); | 953 | snd_ps3_init_avsetting(&the_card); |
955 | 954 | ||
956 | /* register the card */ | 955 | /* register the card */ |
956 | snd_card_set_dev(the_card.card, &dev->core); | ||
957 | ret = snd_card_register(the_card.card); | 957 | ret = snd_card_register(the_card.card); |
958 | if (ret < 0) | 958 | if (ret < 0) |
959 | goto clean_dma_map; | 959 | goto clean_dma_map; |
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 5821cdd0bec9..71a7a9765429 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c | |||
@@ -24,7 +24,6 @@ | |||
24 | */ | 24 | */ |
25 | 25 | ||
26 | 26 | ||
27 | #include <sound/driver.h> | ||
28 | #include <linux/init.h> | 27 | #include <linux/init.h> |
29 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
30 | #include <linux/i2c.h> | 29 | #include <linux/i2c.h> |
@@ -275,14 +274,20 @@ static int tumbler_put_master_volume(struct snd_kcontrol *kcontrol, | |||
275 | { | 274 | { |
276 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); | 275 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); |
277 | struct pmac_tumbler *mix = chip->mixer_data; | 276 | struct pmac_tumbler *mix = chip->mixer_data; |
277 | unsigned int vol[2]; | ||
278 | int change; | 278 | int change; |
279 | 279 | ||
280 | snd_assert(mix, return -ENODEV); | 280 | snd_assert(mix, return -ENODEV); |
281 | change = mix->master_vol[0] != ucontrol->value.integer.value[0] || | 281 | vol[0] = ucontrol->value.integer.value[0]; |
282 | mix->master_vol[1] != ucontrol->value.integer.value[1]; | 282 | vol[1] = ucontrol->value.integer.value[1]; |
283 | if (vol[0] >= ARRAY_SIZE(master_volume_table) || | ||
284 | vol[1] >= ARRAY_SIZE(master_volume_table)) | ||
285 | return -EINVAL; | ||
286 | change = mix->master_vol[0] != vol[0] || | ||
287 | mix->master_vol[1] != vol[1]; | ||
283 | if (change) { | 288 | if (change) { |
284 | mix->master_vol[0] = ucontrol->value.integer.value[0]; | 289 | mix->master_vol[0] = vol[0]; |
285 | mix->master_vol[1] = ucontrol->value.integer.value[1]; | 290 | mix->master_vol[1] = vol[1]; |
286 | tumbler_set_master_volume(mix); | 291 | tumbler_set_master_volume(mix); |
287 | } | 292 | } |
288 | return change; | 293 | return change; |
@@ -417,13 +422,22 @@ static int tumbler_put_drc_value(struct snd_kcontrol *kcontrol, | |||
417 | { | 422 | { |
418 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); | 423 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); |
419 | struct pmac_tumbler *mix; | 424 | struct pmac_tumbler *mix; |
425 | unsigned int val; | ||
420 | int change; | 426 | int change; |
421 | 427 | ||
422 | if (! (mix = chip->mixer_data)) | 428 | if (! (mix = chip->mixer_data)) |
423 | return -ENODEV; | 429 | return -ENODEV; |
424 | change = mix->drc_range != ucontrol->value.integer.value[0]; | 430 | val = ucontrol->value.integer.value[0]; |
431 | if (chip->model == PMAC_TUMBLER) { | ||
432 | if (val > TAS3001_DRC_MAX) | ||
433 | return -EINVAL; | ||
434 | } else { | ||
435 | if (val > TAS3004_DRC_MAX) | ||
436 | return -EINVAL; | ||
437 | } | ||
438 | change = mix->drc_range != val; | ||
425 | if (change) { | 439 | if (change) { |
426 | mix->drc_range = ucontrol->value.integer.value[0]; | 440 | mix->drc_range = val; |
427 | if (chip->model == PMAC_TUMBLER) | 441 | if (chip->model == PMAC_TUMBLER) |
428 | tumbler_set_drc(mix); | 442 | tumbler_set_drc(mix); |
429 | else | 443 | else |
@@ -530,13 +544,17 @@ static int tumbler_put_mono(struct snd_kcontrol *kcontrol, | |||
530 | struct tumbler_mono_vol *info = (struct tumbler_mono_vol *)kcontrol->private_value; | 544 | struct tumbler_mono_vol *info = (struct tumbler_mono_vol *)kcontrol->private_value; |
531 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); | 545 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); |
532 | struct pmac_tumbler *mix; | 546 | struct pmac_tumbler *mix; |
547 | unsigned int vol; | ||
533 | int change; | 548 | int change; |
534 | 549 | ||
535 | if (! (mix = chip->mixer_data)) | 550 | if (! (mix = chip->mixer_data)) |
536 | return -ENODEV; | 551 | return -ENODEV; |
537 | change = mix->mono_vol[info->index] != ucontrol->value.integer.value[0]; | 552 | vol = ucontrol->value.integer.value[0]; |
553 | if (vol >= info->max) | ||
554 | return -EINVAL; | ||
555 | change = mix->mono_vol[info->index] != vol; | ||
538 | if (change) { | 556 | if (change) { |
539 | mix->mono_vol[info->index] = ucontrol->value.integer.value[0]; | 557 | mix->mono_vol[info->index] = vol; |
540 | tumbler_set_mono_volume(mix, info); | 558 | tumbler_set_mono_volume(mix, info); |
541 | } | 559 | } |
542 | return change; | 560 | return change; |
@@ -672,15 +690,21 @@ static int snapper_put_mix(struct snd_kcontrol *kcontrol, | |||
672 | int idx = (int)kcontrol->private_value; | 690 | int idx = (int)kcontrol->private_value; |
673 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); | 691 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); |
674 | struct pmac_tumbler *mix; | 692 | struct pmac_tumbler *mix; |
693 | unsigned int vol[2]; | ||
675 | int change; | 694 | int change; |
676 | 695 | ||
677 | if (! (mix = chip->mixer_data)) | 696 | if (! (mix = chip->mixer_data)) |
678 | return -ENODEV; | 697 | return -ENODEV; |
679 | change = mix->mix_vol[idx][0] != ucontrol->value.integer.value[0] || | 698 | vol[0] = ucontrol->value.integer.value[0]; |
680 | mix->mix_vol[idx][1] != ucontrol->value.integer.value[1]; | 699 | vol[1] = ucontrol->value.integer.value[1]; |
700 | if (vol[0] >= ARRAY_SIZE(mixer_volume_table) || | ||
701 | vol[1] >= ARRAY_SIZE(mixer_volume_table)) | ||
702 | return -EINVAL; | ||
703 | change = mix->mix_vol[idx][0] != vol[0] || | ||
704 | mix->mix_vol[idx][1] != vol[1]; | ||
681 | if (change) { | 705 | if (change) { |
682 | mix->mix_vol[idx][0] = ucontrol->value.integer.value[0]; | 706 | mix->mix_vol[idx][0] = vol[0]; |
683 | mix->mix_vol[idx][1] = ucontrol->value.integer.value[1]; | 707 | mix->mix_vol[idx][1] = vol[1]; |
684 | snapper_set_mix_vol(mix, idx); | 708 | snapper_set_mix_vol(mix, idx); |
685 | } | 709 | } |
686 | return change; | 710 | return change; |
@@ -784,7 +808,7 @@ static int snapper_get_capture_source(struct snd_kcontrol *kcontrol, | |||
784 | struct pmac_tumbler *mix = chip->mixer_data; | 808 | struct pmac_tumbler *mix = chip->mixer_data; |
785 | 809 | ||
786 | snd_assert(mix, return -ENODEV); | 810 | snd_assert(mix, return -ENODEV); |
787 | ucontrol->value.integer.value[0] = mix->capture_source; | 811 | ucontrol->value.enumerated.item[0] = mix->capture_source; |
788 | return 0; | 812 | return 0; |
789 | } | 813 | } |
790 | 814 | ||
@@ -796,9 +820,9 @@ static int snapper_put_capture_source(struct snd_kcontrol *kcontrol, | |||
796 | int change; | 820 | int change; |
797 | 821 | ||
798 | snd_assert(mix, return -ENODEV); | 822 | snd_assert(mix, return -ENODEV); |
799 | change = ucontrol->value.integer.value[0] != mix->capture_source; | 823 | change = ucontrol->value.enumerated.item[0] != mix->capture_source; |
800 | if (change) { | 824 | if (change) { |
801 | mix->capture_source = !!ucontrol->value.integer.value[0]; | 825 | mix->capture_source = !!ucontrol->value.enumerated.item[0]; |
802 | snapper_set_capture_source(mix); | 826 | snapper_set_capture_source(mix); |
803 | } | 827 | } |
804 | return change; | 828 | return change; |
diff --git a/sound/sh/aica.c b/sound/sh/aica.c index 88dc840152ce..d49417bf78c6 100644 --- a/sound/sh/aica.c +++ b/sound/sh/aica.c | |||
@@ -35,7 +35,6 @@ | |||
35 | #include <linux/timer.h> | 35 | #include <linux/timer.h> |
36 | #include <linux/delay.h> | 36 | #include <linux/delay.h> |
37 | #include <linux/workqueue.h> | 37 | #include <linux/workqueue.h> |
38 | #include <sound/driver.h> | ||
39 | #include <sound/core.h> | 38 | #include <sound/core.h> |
40 | #include <sound/control.h> | 39 | #include <sound/control.h> |
41 | #include <sound/pcm.h> | 40 | #include <sound/pcm.h> |
@@ -237,6 +236,7 @@ static int aica_dma_transfer(int channels, int buffer_size, | |||
237 | struct snd_card_aica *dreamcastcard; | 236 | struct snd_card_aica *dreamcastcard; |
238 | struct snd_pcm_runtime *runtime; | 237 | struct snd_pcm_runtime *runtime; |
239 | unsigned long flags; | 238 | unsigned long flags; |
239 | err = 0; | ||
240 | dreamcastcard = substream->pcm->private_data; | 240 | dreamcastcard = substream->pcm->private_data; |
241 | period_offset = dreamcastcard->clicks; | 241 | period_offset = dreamcastcard->clicks; |
242 | period_offset %= (AICA_PERIOD_NUMBER / channels); | 242 | period_offset %= (AICA_PERIOD_NUMBER / channels); |
@@ -522,11 +522,14 @@ static int aica_pcmvolume_put(struct snd_kcontrol *kcontrol, | |||
522 | struct snd_ctl_elem_value *ucontrol) | 522 | struct snd_ctl_elem_value *ucontrol) |
523 | { | 523 | { |
524 | struct snd_card_aica *dreamcastcard; | 524 | struct snd_card_aica *dreamcastcard; |
525 | unsigned int vol; | ||
525 | dreamcastcard = kcontrol->private_data; | 526 | dreamcastcard = kcontrol->private_data; |
526 | if (unlikely(!dreamcastcard->channel)) | 527 | if (unlikely(!dreamcastcard->channel)) |
527 | return -ETXTBSY; | 528 | return -ETXTBSY; |
528 | if (unlikely(dreamcastcard->channel->vol == | 529 | vol = ucontrol->value.integer.value[0]; |
529 | ucontrol->value.integer.value[0])) | 530 | if (vol > 0xff) |
531 | return -EINVAL; | ||
532 | if (unlikely(dreamcastcard->channel->vol == vol)) | ||
530 | return 0; | 533 | return 0; |
531 | dreamcastcard->channel->vol = ucontrol->value.integer.value[0]; | 534 | dreamcastcard->channel->vol = ucontrol->value.integer.value[0]; |
532 | dreamcastcard->master_volume = ucontrol->value.integer.value[0]; | 535 | dreamcastcard->master_volume = ucontrol->value.integer.value[0]; |
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 97b255233175..276585215160 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig | |||
@@ -28,6 +28,7 @@ source "sound/soc/at91/Kconfig" | |||
28 | source "sound/soc/pxa/Kconfig" | 28 | source "sound/soc/pxa/Kconfig" |
29 | source "sound/soc/s3c24xx/Kconfig" | 29 | source "sound/soc/s3c24xx/Kconfig" |
30 | source "sound/soc/sh/Kconfig" | 30 | source "sound/soc/sh/Kconfig" |
31 | source "sound/soc/fsl/Kconfig" | ||
31 | 32 | ||
32 | # Supported codecs | 33 | # Supported codecs |
33 | source "sound/soc/codecs/Kconfig" | 34 | source "sound/soc/codecs/Kconfig" |
diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 304140377632..4869c9ae7a03 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | snd-soc-core-objs := soc-core.o soc-dapm.o | 1 | snd-soc-core-objs := soc-core.o soc-dapm.o |
2 | 2 | ||
3 | obj-$(CONFIG_SND_SOC) += snd-soc-core.o | 3 | obj-$(CONFIG_SND_SOC) += snd-soc-core.o |
4 | obj-$(CONFIG_SND_SOC) += codecs/ at91/ pxa/ s3c24xx/ sh/ | 4 | obj-$(CONFIG_SND_SOC) += codecs/ at91/ pxa/ s3c24xx/ sh/ fsl/ |
diff --git a/sound/soc/at91/at91-pcm.c b/sound/soc/at91/at91-pcm.c index b39b95a47040..67c88e322fb1 100644 --- a/sound/soc/at91/at91-pcm.c +++ b/sound/soc/at91/at91-pcm.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <linux/dma-mapping.h> | 23 | #include <linux/dma-mapping.h> |
24 | #include <linux/atmel_pdc.h> | 24 | #include <linux/atmel_pdc.h> |
25 | 25 | ||
26 | #include <sound/driver.h> | ||
27 | #include <sound/core.h> | 26 | #include <sound/core.h> |
28 | #include <sound/pcm.h> | 27 | #include <sound/pcm.h> |
29 | #include <sound/pcm_params.h> | 28 | #include <sound/pcm_params.h> |
diff --git a/sound/soc/at91/at91-ssc.c b/sound/soc/at91/at91-ssc.c index 3d4e32cff75e..f642d2dd4ec3 100644 --- a/sound/soc/at91/at91-ssc.c +++ b/sound/soc/at91/at91-ssc.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #include <linux/clk.h> | 22 | #include <linux/clk.h> |
23 | #include <linux/atmel_pdc.h> | 23 | #include <linux/atmel_pdc.h> |
24 | 24 | ||
25 | #include <sound/driver.h> | ||
26 | #include <sound/core.h> | 25 | #include <sound/core.h> |
27 | #include <sound/pcm.h> | 26 | #include <sound/pcm.h> |
28 | #include <sound/pcm_params.h> | 27 | #include <sound/pcm_params.h> |
diff --git a/sound/soc/at91/eti_b1_wm8731.c b/sound/soc/at91/eti_b1_wm8731.c index 820a676c56bf..ad3ad9d662f8 100644 --- a/sound/soc/at91/eti_b1_wm8731.c +++ b/sound/soc/at91/eti_b1_wm8731.c | |||
@@ -28,7 +28,6 @@ | |||
28 | #include <linux/timer.h> | 28 | #include <linux/timer.h> |
29 | #include <linux/interrupt.h> | 29 | #include <linux/interrupt.h> |
30 | #include <linux/platform_device.h> | 30 | #include <linux/platform_device.h> |
31 | #include <sound/driver.h> | ||
32 | #include <sound/core.h> | 31 | #include <sound/core.h> |
33 | #include <sound/pcm.h> | 32 | #include <sound/pcm.h> |
34 | #include <sound/soc.h> | 33 | #include <sound/soc.h> |
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 78248808a9d8..898a7d363284 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -37,3 +37,6 @@ config SND_SOC_CS4270_VD33_ERRATA | |||
37 | bool | 37 | bool |
38 | depends on SND_SOC_CS4270 | 38 | depends on SND_SOC_CS4270 |
39 | 39 | ||
40 | config SND_SOC_TLV320AIC3X | ||
41 | tristate | ||
42 | depends on SND_SOC && I2C | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 7ad78e36d506..c6e5338c2666 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -4,6 +4,7 @@ snd-soc-wm8750-objs := wm8750.o | |||
4 | snd-soc-wm8753-objs := wm8753.o | 4 | snd-soc-wm8753-objs := wm8753.o |
5 | snd-soc-wm9712-objs := wm9712.o | 5 | snd-soc-wm9712-objs := wm9712.o |
6 | snd-soc-cs4270-objs := cs4270.o | 6 | snd-soc-cs4270-objs := cs4270.o |
7 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o | ||
7 | 8 | ||
8 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o | 9 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o |
9 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o | 10 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o |
@@ -11,3 +12,4 @@ obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o | |||
11 | obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o | 12 | obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o |
12 | obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o | 13 | obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o |
13 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o | 14 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o |
15 | obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o | ||
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index 0b8a6f8b3668..242130cf1abd 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c | |||
@@ -19,7 +19,6 @@ | |||
19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
20 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
21 | #include <linux/device.h> | 21 | #include <linux/device.h> |
22 | #include <sound/driver.h> | ||
23 | #include <sound/core.h> | 22 | #include <sound/core.h> |
24 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
25 | #include <sound/ac97_codec.h> | 24 | #include <sound/ac97_codec.h> |
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index dab22cc97ead..bf2ab72d49bf 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c | |||
@@ -28,7 +28,6 @@ | |||
28 | 28 | ||
29 | #include <linux/module.h> | 29 | #include <linux/module.h> |
30 | #include <linux/platform_device.h> | 30 | #include <linux/platform_device.h> |
31 | #include <sound/driver.h> | ||
32 | #include <sound/core.h> | 31 | #include <sound/core.h> |
33 | #include <sound/soc.h> | 32 | #include <sound/soc.h> |
34 | #include <sound/initval.h> | 33 | #include <sound/initval.h> |
@@ -48,12 +47,130 @@ struct cs4270_private { | |||
48 | unsigned int mode; /* The mode (I2S or left-justified) */ | 47 | unsigned int mode; /* The mode (I2S or left-justified) */ |
49 | }; | 48 | }; |
50 | 49 | ||
51 | /* The number of MCLK/LRCK ratios supported by the CS4270 */ | 50 | /* |
52 | #define NUM_MCLK_RATIOS 9 | 51 | * The codec isn't really big-endian or little-endian, since the I2S |
52 | * interface requires data to be sent serially with the MSbit first. | ||
53 | * However, to support BE and LE I2S devices, we specify both here. That | ||
54 | * way, ALSA will always match the bit patterns. | ||
55 | */ | ||
56 | #define CS4270_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ | ||
57 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ | ||
58 | SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \ | ||
59 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ | ||
60 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \ | ||
61 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE) | ||
62 | |||
63 | #ifdef USE_I2C | ||
64 | |||
65 | /* CS4270 registers addresses */ | ||
66 | #define CS4270_CHIPID 0x01 /* Chip ID */ | ||
67 | #define CS4270_PWRCTL 0x02 /* Power Control */ | ||
68 | #define CS4270_MODE 0x03 /* Mode Control */ | ||
69 | #define CS4270_FORMAT 0x04 /* Serial Format, ADC/DAC Control */ | ||
70 | #define CS4270_TRANS 0x05 /* Transition Control */ | ||
71 | #define CS4270_MUTE 0x06 /* Mute Control */ | ||
72 | #define CS4270_VOLA 0x07 /* DAC Channel A Volume Control */ | ||
73 | #define CS4270_VOLB 0x08 /* DAC Channel B Volume Control */ | ||
74 | |||
75 | #define CS4270_FIRSTREG 0x01 | ||
76 | #define CS4270_LASTREG 0x08 | ||
77 | #define CS4270_NUMREGS (CS4270_LASTREG - CS4270_FIRSTREG + 1) | ||
53 | 78 | ||
54 | /* The actual MCLK/LRCK ratios, in increasing numerical order */ | 79 | /* Bit masks for the CS4270 registers */ |
55 | static unsigned int mclk_ratios[NUM_MCLK_RATIOS] = | 80 | #define CS4270_CHIPID_ID 0xF0 |
56 | {64, 96, 128, 192, 256, 384, 512, 768, 1024}; | 81 | #define CS4270_CHIPID_REV 0x0F |
82 | #define CS4270_PWRCTL_FREEZE 0x80 | ||
83 | #define CS4270_PWRCTL_PDN_ADC 0x20 | ||
84 | #define CS4270_PWRCTL_PDN_DAC 0x02 | ||
85 | #define CS4270_PWRCTL_PDN 0x01 | ||
86 | #define CS4270_MODE_SPEED_MASK 0x30 | ||
87 | #define CS4270_MODE_1X 0x00 | ||
88 | #define CS4270_MODE_2X 0x10 | ||
89 | #define CS4270_MODE_4X 0x20 | ||
90 | #define CS4270_MODE_SLAVE 0x30 | ||
91 | #define CS4270_MODE_DIV_MASK 0x0E | ||
92 | #define CS4270_MODE_DIV1 0x00 | ||
93 | #define CS4270_MODE_DIV15 0x02 | ||
94 | #define CS4270_MODE_DIV2 0x04 | ||
95 | #define CS4270_MODE_DIV3 0x06 | ||
96 | #define CS4270_MODE_DIV4 0x08 | ||
97 | #define CS4270_MODE_POPGUARD 0x01 | ||
98 | #define CS4270_FORMAT_FREEZE_A 0x80 | ||
99 | #define CS4270_FORMAT_FREEZE_B 0x40 | ||
100 | #define CS4270_FORMAT_LOOPBACK 0x20 | ||
101 | #define CS4270_FORMAT_DAC_MASK 0x18 | ||
102 | #define CS4270_FORMAT_DAC_LJ 0x00 | ||
103 | #define CS4270_FORMAT_DAC_I2S 0x08 | ||
104 | #define CS4270_FORMAT_DAC_RJ16 0x18 | ||
105 | #define CS4270_FORMAT_DAC_RJ24 0x10 | ||
106 | #define CS4270_FORMAT_ADC_MASK 0x01 | ||
107 | #define CS4270_FORMAT_ADC_LJ 0x00 | ||
108 | #define CS4270_FORMAT_ADC_I2S 0x01 | ||
109 | #define CS4270_TRANS_ONE_VOL 0x80 | ||
110 | #define CS4270_TRANS_SOFT 0x40 | ||
111 | #define CS4270_TRANS_ZERO 0x20 | ||
112 | #define CS4270_TRANS_INV_ADC_A 0x08 | ||
113 | #define CS4270_TRANS_INV_ADC_B 0x10 | ||
114 | #define CS4270_TRANS_INV_DAC_A 0x02 | ||
115 | #define CS4270_TRANS_INV_DAC_B 0x04 | ||
116 | #define CS4270_TRANS_DEEMPH 0x01 | ||
117 | #define CS4270_MUTE_AUTO 0x20 | ||
118 | #define CS4270_MUTE_ADC_A 0x08 | ||
119 | #define CS4270_MUTE_ADC_B 0x10 | ||
120 | #define CS4270_MUTE_POLARITY 0x04 | ||
121 | #define CS4270_MUTE_DAC_A 0x01 | ||
122 | #define CS4270_MUTE_DAC_B 0x02 | ||
123 | |||
124 | /* | ||
125 | * Clock Ratio Selection for Master Mode with I2C enabled | ||
126 | * | ||
127 | * The data for this chart is taken from Table 5 of the CS4270 reference | ||
128 | * manual. | ||
129 | * | ||
130 | * This table is used to determine how to program the Mode Control register. | ||
131 | * It is also used by cs4270_set_dai_sysclk() to tell ALSA which sampling | ||
132 | * rates the CS4270 currently supports. | ||
133 | * | ||
134 | * Each element in this array corresponds to the ratios in mclk_ratios[]. | ||
135 | * These two arrays need to be in sync. | ||
136 | * | ||
137 | * 'speed_mode' is the corresponding bit pattern to be written to the | ||
138 | * MODE bits of the Mode Control Register | ||
139 | * | ||
140 | * 'mclk' is the corresponding bit pattern to be wirten to the MCLK bits of | ||
141 | * the Mode Control Register. | ||
142 | * | ||
143 | * In situations where a single ratio is represented by multiple speed | ||
144 | * modes, we favor the slowest speed. E.g, for a ratio of 128, we pick | ||
145 | * double-speed instead of quad-speed. However, the CS4270 errata states | ||
146 | * that Divide-By-1.5 can cause failures, so we avoid that mode where | ||
147 | * possible. | ||
148 | * | ||
149 | * ERRATA: There is an errata for the CS4270 where divide-by-1.5 does not | ||
150 | * work if VD = 3.3V. If this effects you, select the | ||
151 | * CONFIG_SND_SOC_CS4270_VD33_ERRATA Kconfig option, and the driver will | ||
152 | * never select any sample rates that require divide-by-1.5. | ||
153 | */ | ||
154 | static struct { | ||
155 | unsigned int ratio; | ||
156 | u8 speed_mode; | ||
157 | u8 mclk; | ||
158 | } cs4270_mode_ratios[] = { | ||
159 | {64, CS4270_MODE_4X, CS4270_MODE_DIV1}, | ||
160 | #ifndef CONFIG_SND_SOC_CS4270_VD33_ERRATA | ||
161 | {96, CS4270_MODE_4X, CS4270_MODE_DIV15}, | ||
162 | #endif | ||
163 | {128, CS4270_MODE_2X, CS4270_MODE_DIV1}, | ||
164 | {192, CS4270_MODE_4X, CS4270_MODE_DIV3}, | ||
165 | {256, CS4270_MODE_1X, CS4270_MODE_DIV1}, | ||
166 | {384, CS4270_MODE_2X, CS4270_MODE_DIV3}, | ||
167 | {512, CS4270_MODE_1X, CS4270_MODE_DIV2}, | ||
168 | {768, CS4270_MODE_1X, CS4270_MODE_DIV3}, | ||
169 | {1024, CS4270_MODE_1X, CS4270_MODE_DIV4} | ||
170 | }; | ||
171 | |||
172 | /* The number of MCLK/LRCK ratios supported by the CS4270 */ | ||
173 | #define NUM_MCLK_RATIOS ARRAY_SIZE(cs4270_mode_ratios) | ||
57 | 174 | ||
58 | /* | 175 | /* |
59 | * Determine the CS4270 samples rates. | 176 | * Determine the CS4270 samples rates. |
@@ -97,7 +214,7 @@ static int cs4270_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | |||
97 | cs4270->mclk = freq; | 214 | cs4270->mclk = freq; |
98 | 215 | ||
99 | for (i = 0; i < NUM_MCLK_RATIOS; i++) { | 216 | for (i = 0; i < NUM_MCLK_RATIOS; i++) { |
100 | unsigned int rate = freq / mclk_ratios[i]; | 217 | unsigned int rate = freq / cs4270_mode_ratios[i].ratio; |
101 | rates |= snd_pcm_rate_to_rate_bit(rate); | 218 | rates |= snd_pcm_rate_to_rate_bit(rate); |
102 | if (rate < rate_min) | 219 | if (rate < rate_min) |
103 | rate_min = rate; | 220 | rate_min = rate; |
@@ -155,80 +272,6 @@ static int cs4270_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
155 | } | 272 | } |
156 | 273 | ||
157 | /* | 274 | /* |
158 | * The codec isn't really big-endian or little-endian, since the I2S | ||
159 | * interface requires data to be sent serially with the MSbit first. | ||
160 | * However, to support BE and LE I2S devices, we specify both here. That | ||
161 | * way, ALSA will always match the bit patterns. | ||
162 | */ | ||
163 | #define CS4270_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ | ||
164 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ | ||
165 | SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \ | ||
166 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ | ||
167 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \ | ||
168 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE) | ||
169 | |||
170 | #ifdef USE_I2C | ||
171 | |||
172 | /* CS4270 registers addresses */ | ||
173 | #define CS4270_CHIPID 0x01 /* Chip ID */ | ||
174 | #define CS4270_PWRCTL 0x02 /* Power Control */ | ||
175 | #define CS4270_MODE 0x03 /* Mode Control */ | ||
176 | #define CS4270_FORMAT 0x04 /* Serial Format, ADC/DAC Control */ | ||
177 | #define CS4270_TRANS 0x05 /* Transition Control */ | ||
178 | #define CS4270_MUTE 0x06 /* Mute Control */ | ||
179 | #define CS4270_VOLA 0x07 /* DAC Channel A Volume Control */ | ||
180 | #define CS4270_VOLB 0x08 /* DAC Channel B Volume Control */ | ||
181 | |||
182 | #define CS4270_FIRSTREG 0x01 | ||
183 | #define CS4270_LASTREG 0x08 | ||
184 | #define CS4270_NUMREGS (CS4270_LASTREG - CS4270_FIRSTREG + 1) | ||
185 | |||
186 | /* Bit masks for the CS4270 registers */ | ||
187 | #define CS4270_CHIPID_ID 0xF0 | ||
188 | #define CS4270_CHIPID_REV 0x0F | ||
189 | #define CS4270_PWRCTL_FREEZE 0x80 | ||
190 | #define CS4270_PWRCTL_PDN_ADC 0x20 | ||
191 | #define CS4270_PWRCTL_PDN_DAC 0x02 | ||
192 | #define CS4270_PWRCTL_PDN 0x01 | ||
193 | #define CS4270_MODE_SPEED_MASK 0x30 | ||
194 | #define CS4270_MODE_1X 0x00 | ||
195 | #define CS4270_MODE_2X 0x10 | ||
196 | #define CS4270_MODE_4X 0x20 | ||
197 | #define CS4270_MODE_SLAVE 0x30 | ||
198 | #define CS4270_MODE_DIV_MASK 0x0E | ||
199 | #define CS4270_MODE_DIV1 0x00 | ||
200 | #define CS4270_MODE_DIV15 0x02 | ||
201 | #define CS4270_MODE_DIV2 0x04 | ||
202 | #define CS4270_MODE_DIV3 0x06 | ||
203 | #define CS4270_MODE_DIV4 0x08 | ||
204 | #define CS4270_MODE_POPGUARD 0x01 | ||
205 | #define CS4270_FORMAT_FREEZE_A 0x80 | ||
206 | #define CS4270_FORMAT_FREEZE_B 0x40 | ||
207 | #define CS4270_FORMAT_LOOPBACK 0x20 | ||
208 | #define CS4270_FORMAT_DAC_MASK 0x18 | ||
209 | #define CS4270_FORMAT_DAC_LJ 0x00 | ||
210 | #define CS4270_FORMAT_DAC_I2S 0x08 | ||
211 | #define CS4270_FORMAT_DAC_RJ16 0x18 | ||
212 | #define CS4270_FORMAT_DAC_RJ24 0x10 | ||
213 | #define CS4270_FORMAT_ADC_MASK 0x01 | ||
214 | #define CS4270_FORMAT_ADC_LJ 0x00 | ||
215 | #define CS4270_FORMAT_ADC_I2S 0x01 | ||
216 | #define CS4270_TRANS_ONE_VOL 0x80 | ||
217 | #define CS4270_TRANS_SOFT 0x40 | ||
218 | #define CS4270_TRANS_ZERO 0x20 | ||
219 | #define CS4270_TRANS_INV_ADC_A 0x08 | ||
220 | #define CS4270_TRANS_INV_ADC_B 0x10 | ||
221 | #define CS4270_TRANS_INV_DAC_A 0x02 | ||
222 | #define CS4270_TRANS_INV_DAC_B 0x04 | ||
223 | #define CS4270_TRANS_DEEMPH 0x01 | ||
224 | #define CS4270_MUTE_AUTO 0x20 | ||
225 | #define CS4270_MUTE_ADC_A 0x08 | ||
226 | #define CS4270_MUTE_ADC_B 0x10 | ||
227 | #define CS4270_MUTE_POLARITY 0x04 | ||
228 | #define CS4270_MUTE_DAC_A 0x01 | ||
229 | #define CS4270_MUTE_DAC_B 0x02 | ||
230 | |||
231 | /* | ||
232 | * A list of addresses on which this CS4270 could use. I2C addresses are | 275 | * A list of addresses on which this CS4270 could use. I2C addresses are |
233 | * 7 bits. For the CS4270, the upper four bits are always 1001, and the | 276 | * 7 bits. For the CS4270, the upper four bits are always 1001, and the |
234 | * lower three bits are determined via the AD2, AD1, and AD0 pins | 277 | * lower three bits are determined via the AD2, AD1, and AD0 pins |
@@ -315,53 +358,6 @@ static int cs4270_i2c_write(struct snd_soc_codec *codec, unsigned int reg, | |||
315 | } | 358 | } |
316 | 359 | ||
317 | /* | 360 | /* |
318 | * Clock Ratio Selection for Master Mode with I2C enabled | ||
319 | * | ||
320 | * The data for this chart is taken from Table 5 of the CS4270 reference | ||
321 | * manual. | ||
322 | * | ||
323 | * This table is used to determine how to program the Mode Control register. | ||
324 | * It is also used by cs4270_set_dai_sysclk() to tell ALSA which sampling | ||
325 | * rates the CS4270 currently supports. | ||
326 | * | ||
327 | * Each element in this array corresponds to the ratios in mclk_ratios[]. | ||
328 | * These two arrays need to be in sync. | ||
329 | * | ||
330 | * 'speed_mode' is the corresponding bit pattern to be written to the | ||
331 | * MODE bits of the Mode Control Register | ||
332 | * | ||
333 | * 'mclk' is the corresponding bit pattern to be wirten to the MCLK bits of | ||
334 | * the Mode Control Register. | ||
335 | * | ||
336 | * In situations where a single ratio is represented by multiple speed | ||
337 | * modes, we favor the slowest speed. E.g, for a ratio of 128, we pick | ||
338 | * double-speed instead of quad-speed. However, the CS4270 errata states | ||
339 | * that Divide-By-1.5 can cause failures, so we avoid that mode where | ||
340 | * possible. | ||
341 | * | ||
342 | * ERRATA: There is an errata for the CS4270 where divide-by-1.5 does not | ||
343 | * work if VD = 3.3V. If this effects you, select the | ||
344 | * CONFIG_SND_SOC_CS4270_VD33_ERRATA Kconfig option, and the driver will | ||
345 | * never select any sample rates that require divide-by-1.5. | ||
346 | */ | ||
347 | static struct { | ||
348 | u8 speed_mode; | ||
349 | u8 mclk; | ||
350 | } cs4270_mode_ratios[NUM_MCLK_RATIOS] = { | ||
351 | {CS4270_MODE_4X, CS4270_MODE_DIV1}, /* 64 */ | ||
352 | #ifndef CONFIG_SND_SOC_CS4270_VD33_ERRATA | ||
353 | {CS4270_MODE_4X, CS4270_MODE_DIV15}, /* 96 */ | ||
354 | #endif | ||
355 | {CS4270_MODE_2X, CS4270_MODE_DIV1}, /* 128 */ | ||
356 | {CS4270_MODE_4X, CS4270_MODE_DIV3}, /* 192 */ | ||
357 | {CS4270_MODE_1X, CS4270_MODE_DIV1}, /* 256 */ | ||
358 | {CS4270_MODE_2X, CS4270_MODE_DIV3}, /* 384 */ | ||
359 | {CS4270_MODE_1X, CS4270_MODE_DIV2}, /* 512 */ | ||
360 | {CS4270_MODE_1X, CS4270_MODE_DIV3}, /* 768 */ | ||
361 | {CS4270_MODE_1X, CS4270_MODE_DIV4} /* 1024 */ | ||
362 | }; | ||
363 | |||
364 | /* | ||
365 | * Program the CS4270 with the given hardware parameters. | 361 | * Program the CS4270 with the given hardware parameters. |
366 | * | 362 | * |
367 | * The .dai_ops functions are used to provide board-specific data, like | 363 | * The .dai_ops functions are used to provide board-specific data, like |
@@ -388,7 +384,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream, | |||
388 | ratio = cs4270->mclk / rate; /* MCLK/LRCK ratio */ | 384 | ratio = cs4270->mclk / rate; /* MCLK/LRCK ratio */ |
389 | 385 | ||
390 | for (i = 0; i < NUM_MCLK_RATIOS; i++) { | 386 | for (i = 0; i < NUM_MCLK_RATIOS; i++) { |
391 | if (mclk_ratios[i] == ratio) | 387 | if (cs4270_mode_ratios[i].ratio == ratio) |
392 | break; | 388 | break; |
393 | } | 389 | } |
394 | 390 | ||
@@ -669,7 +665,7 @@ error: | |||
669 | return ret; | 665 | return ret; |
670 | } | 666 | } |
671 | 667 | ||
672 | #endif | 668 | #endif /* USE_I2C*/ |
673 | 669 | ||
674 | struct snd_soc_codec_dai cs4270_dai = { | 670 | struct snd_soc_codec_dai cs4270_dai = { |
675 | .name = "CS4270", | 671 | .name = "CS4270", |
@@ -687,10 +683,6 @@ struct snd_soc_codec_dai cs4270_dai = { | |||
687 | .rates = 0, | 683 | .rates = 0, |
688 | .formats = CS4270_FORMATS, | 684 | .formats = CS4270_FORMATS, |
689 | }, | 685 | }, |
690 | .dai_ops = { | ||
691 | .set_sysclk = cs4270_set_dai_sysclk, | ||
692 | .set_fmt = cs4270_set_dai_fmt, | ||
693 | } | ||
694 | }; | 686 | }; |
695 | EXPORT_SYMBOL_GPL(cs4270_dai); | 687 | EXPORT_SYMBOL_GPL(cs4270_dai); |
696 | 688 | ||
@@ -752,6 +744,8 @@ static int cs4270_probe(struct platform_device *pdev) | |||
752 | if (codec->control_data) { | 744 | if (codec->control_data) { |
753 | /* Initialize codec ops */ | 745 | /* Initialize codec ops */ |
754 | cs4270_dai.ops.hw_params = cs4270_hw_params; | 746 | cs4270_dai.ops.hw_params = cs4270_hw_params; |
747 | cs4270_dai.dai_ops.set_sysclk = cs4270_set_dai_sysclk; | ||
748 | cs4270_dai.dai_ops.set_fmt = cs4270_set_dai_fmt; | ||
755 | #ifdef CONFIG_SND_SOC_CS4270_HWMUTE | 749 | #ifdef CONFIG_SND_SOC_CS4270_HWMUTE |
756 | cs4270_dai.dai_ops.digital_mute = cs4270_mute; | 750 | cs4270_dai.dai_ops.digital_mute = cs4270_mute; |
757 | #endif | 751 | #endif |
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c new file mode 100644 index 000000000000..710e0287ef8c --- /dev/null +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -0,0 +1,1274 @@ | |||
1 | /* | ||
2 | * ALSA SoC TLV320AIC3X codec driver | ||
3 | * | ||
4 | * Author: Vladimir Barinov, <vbarinov@ru.mvista.com> | ||
5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> | ||
6 | * | ||
7 | * Based on sound/soc/codecs/wm8753.c by Liam Girdwood | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * Notes: | ||
14 | * The AIC3X is a driver for a low power stereo audio | ||
15 | * codecs aic31, aic32, aic33. | ||
16 | * | ||
17 | * It supports full aic33 codec functionality. | ||
18 | * The compatibility with aic32, aic31 is as follows: | ||
19 | * aic32 | aic31 | ||
20 | * --------------------------------------- | ||
21 | * MONO_LOUT -> N/A | MONO_LOUT -> N/A | ||
22 | * | IN1L -> LINE1L | ||
23 | * | IN1R -> LINE1R | ||
24 | * | IN2L -> LINE2L | ||
25 | * | IN2R -> LINE2R | ||
26 | * | MIC3L/R -> N/A | ||
27 | * truncated internal functionality in | ||
28 | * accordance with documentation | ||
29 | * --------------------------------------- | ||
30 | * | ||
31 | * Hence the machine layer should disable unsupported inputs/outputs by | ||
32 | * snd_soc_dapm_set_endpoint(codec, "MONO_LOUT", 0), etc. | ||
33 | */ | ||
34 | |||
35 | #include <linux/module.h> | ||
36 | #include <linux/moduleparam.h> | ||
37 | #include <linux/init.h> | ||
38 | #include <linux/delay.h> | ||
39 | #include <linux/pm.h> | ||
40 | #include <linux/i2c.h> | ||
41 | #include <linux/platform_device.h> | ||
42 | #include <sound/core.h> | ||
43 | #include <sound/pcm.h> | ||
44 | #include <sound/pcm_params.h> | ||
45 | #include <sound/soc.h> | ||
46 | #include <sound/soc-dapm.h> | ||
47 | #include <sound/initval.h> | ||
48 | |||
49 | #include "tlv320aic3x.h" | ||
50 | |||
51 | #define AUDIO_NAME "aic3x" | ||
52 | #define AIC3X_VERSION "0.1" | ||
53 | |||
54 | /* codec private data */ | ||
55 | struct aic3x_priv { | ||
56 | unsigned int sysclk; | ||
57 | int master; | ||
58 | }; | ||
59 | |||
60 | /* | ||
61 | * AIC3X register cache | ||
62 | * We can't read the AIC3X register space when we are | ||
63 | * using 2 wire for device control, so we cache them instead. | ||
64 | * There is no point in caching the reset register | ||
65 | */ | ||
66 | static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = { | ||
67 | 0x00, 0x00, 0x00, 0x10, /* 0 */ | ||
68 | 0x04, 0x00, 0x00, 0x00, /* 4 */ | ||
69 | 0x00, 0x00, 0x00, 0x01, /* 8 */ | ||
70 | 0x00, 0x00, 0x00, 0x80, /* 12 */ | ||
71 | 0x80, 0xff, 0xff, 0x78, /* 16 */ | ||
72 | 0x78, 0x78, 0x78, 0x78, /* 20 */ | ||
73 | 0x78, 0x00, 0x00, 0xfe, /* 24 */ | ||
74 | 0x00, 0x00, 0xfe, 0x00, /* 28 */ | ||
75 | 0x18, 0x18, 0x00, 0x00, /* 32 */ | ||
76 | 0x00, 0x00, 0x00, 0x00, /* 36 */ | ||
77 | 0x00, 0x00, 0x00, 0x80, /* 40 */ | ||
78 | 0x80, 0x00, 0x00, 0x00, /* 44 */ | ||
79 | 0x00, 0x00, 0x00, 0x04, /* 48 */ | ||
80 | 0x00, 0x00, 0x00, 0x00, /* 52 */ | ||
81 | 0x00, 0x00, 0x04, 0x00, /* 56 */ | ||
82 | 0x00, 0x00, 0x00, 0x00, /* 60 */ | ||
83 | 0x00, 0x04, 0x00, 0x00, /* 64 */ | ||
84 | 0x00, 0x00, 0x00, 0x00, /* 68 */ | ||
85 | 0x04, 0x00, 0x00, 0x00, /* 72 */ | ||
86 | 0x00, 0x00, 0x00, 0x00, /* 76 */ | ||
87 | 0x00, 0x00, 0x00, 0x00, /* 80 */ | ||
88 | 0x00, 0x00, 0x00, 0x00, /* 84 */ | ||
89 | 0x00, 0x00, 0x00, 0x00, /* 88 */ | ||
90 | 0x00, 0x00, 0x00, 0x00, /* 92 */ | ||
91 | 0x00, 0x00, 0x00, 0x00, /* 96 */ | ||
92 | 0x00, 0x00, 0x02, /* 100 */ | ||
93 | }; | ||
94 | |||
95 | /* | ||
96 | * read aic3x register cache | ||
97 | */ | ||
98 | static inline unsigned int aic3x_read_reg_cache(struct snd_soc_codec *codec, | ||
99 | unsigned int reg) | ||
100 | { | ||
101 | u8 *cache = codec->reg_cache; | ||
102 | if (reg >= AIC3X_CACHEREGNUM) | ||
103 | return -1; | ||
104 | return cache[reg]; | ||
105 | } | ||
106 | |||
107 | /* | ||
108 | * write aic3x register cache | ||
109 | */ | ||
110 | static inline void aic3x_write_reg_cache(struct snd_soc_codec *codec, | ||
111 | u8 reg, u8 value) | ||
112 | { | ||
113 | u8 *cache = codec->reg_cache; | ||
114 | if (reg >= AIC3X_CACHEREGNUM) | ||
115 | return; | ||
116 | cache[reg] = value; | ||
117 | } | ||
118 | |||
119 | /* | ||
120 | * write to the aic3x register space | ||
121 | */ | ||
122 | static int aic3x_write(struct snd_soc_codec *codec, unsigned int reg, | ||
123 | unsigned int value) | ||
124 | { | ||
125 | u8 data[2]; | ||
126 | |||
127 | /* data is | ||
128 | * D15..D8 aic3x register offset | ||
129 | * D7...D0 register data | ||
130 | */ | ||
131 | data[0] = reg & 0xff; | ||
132 | data[1] = value & 0xff; | ||
133 | |||
134 | aic3x_write_reg_cache(codec, data[0], data[1]); | ||
135 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
136 | return 0; | ||
137 | else | ||
138 | return -EIO; | ||
139 | } | ||
140 | |||
141 | #define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \ | ||
142 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
143 | .info = snd_soc_info_volsw, \ | ||
144 | .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw_aic3x, \ | ||
145 | .private_value = SOC_SINGLE_VALUE(reg, shift, mask, invert) } | ||
146 | |||
147 | /* | ||
148 | * All input lines are connected when !0xf and disconnected with 0xf bit field, | ||
149 | * so we have to use specific dapm_put call for input mixer | ||
150 | */ | ||
151 | static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, | ||
152 | struct snd_ctl_elem_value *ucontrol) | ||
153 | { | ||
154 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | ||
155 | int reg = kcontrol->private_value & 0xff; | ||
156 | int shift = (kcontrol->private_value >> 8) & 0x0f; | ||
157 | int mask = (kcontrol->private_value >> 16) & 0xff; | ||
158 | int invert = (kcontrol->private_value >> 24) & 0x01; | ||
159 | unsigned short val, val_mask; | ||
160 | int ret; | ||
161 | struct snd_soc_dapm_path *path; | ||
162 | int found = 0; | ||
163 | |||
164 | val = (ucontrol->value.integer.value[0] & mask); | ||
165 | |||
166 | mask = 0xf; | ||
167 | if (val) | ||
168 | val = mask; | ||
169 | |||
170 | if (invert) | ||
171 | val = mask - val; | ||
172 | val_mask = mask << shift; | ||
173 | val = val << shift; | ||
174 | |||
175 | mutex_lock(&widget->codec->mutex); | ||
176 | |||
177 | if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) { | ||
178 | /* find dapm widget path assoc with kcontrol */ | ||
179 | list_for_each_entry(path, &widget->codec->dapm_paths, list) { | ||
180 | if (path->kcontrol != kcontrol) | ||
181 | continue; | ||
182 | |||
183 | /* found, now check type */ | ||
184 | found = 1; | ||
185 | if (val) | ||
186 | /* new connection */ | ||
187 | path->connect = invert ? 0 : 1; | ||
188 | else | ||
189 | /* old connection must be powered down */ | ||
190 | path->connect = invert ? 1 : 0; | ||
191 | break; | ||
192 | } | ||
193 | |||
194 | if (found) | ||
195 | snd_soc_dapm_sync_endpoints(widget->codec); | ||
196 | } | ||
197 | |||
198 | ret = snd_soc_update_bits(widget->codec, reg, val_mask, val); | ||
199 | |||
200 | mutex_unlock(&widget->codec->mutex); | ||
201 | return ret; | ||
202 | } | ||
203 | |||
204 | static const char *aic3x_left_dac_mux[] = { "DAC_L1", "DAC_L3", "DAC_L2" }; | ||
205 | static const char *aic3x_right_dac_mux[] = { "DAC_R1", "DAC_R3", "DAC_R2" }; | ||
206 | static const char *aic3x_left_hpcom_mux[] = | ||
207 | { "differential of HPLOUT", "constant VCM", "single-ended" }; | ||
208 | static const char *aic3x_right_hpcom_mux[] = | ||
209 | { "differential of HPROUT", "constant VCM", "single-ended", | ||
210 | "differential of HPLCOM", "external feedback" }; | ||
211 | static const char *aic3x_linein_mode_mux[] = { "single-ended", "differential" }; | ||
212 | |||
213 | #define LDAC_ENUM 0 | ||
214 | #define RDAC_ENUM 1 | ||
215 | #define LHPCOM_ENUM 2 | ||
216 | #define RHPCOM_ENUM 3 | ||
217 | #define LINE1L_ENUM 4 | ||
218 | #define LINE1R_ENUM 5 | ||
219 | #define LINE2L_ENUM 6 | ||
220 | #define LINE2R_ENUM 7 | ||
221 | |||
222 | static const struct soc_enum aic3x_enum[] = { | ||
223 | SOC_ENUM_SINGLE(DAC_LINE_MUX, 6, 3, aic3x_left_dac_mux), | ||
224 | SOC_ENUM_SINGLE(DAC_LINE_MUX, 4, 3, aic3x_right_dac_mux), | ||
225 | SOC_ENUM_SINGLE(HPLCOM_CFG, 4, 3, aic3x_left_hpcom_mux), | ||
226 | SOC_ENUM_SINGLE(HPRCOM_CFG, 3, 5, aic3x_right_hpcom_mux), | ||
227 | SOC_ENUM_SINGLE(LINE1L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), | ||
228 | SOC_ENUM_SINGLE(LINE1R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), | ||
229 | SOC_ENUM_SINGLE(LINE2L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), | ||
230 | SOC_ENUM_SINGLE(LINE2R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), | ||
231 | }; | ||
232 | |||
233 | static const struct snd_kcontrol_new aic3x_snd_controls[] = { | ||
234 | /* Output */ | ||
235 | SOC_DOUBLE_R("PCM Playback Volume", LDAC_VOL, RDAC_VOL, 0, 0x7f, 1), | ||
236 | |||
237 | SOC_DOUBLE_R("Line DAC Playback Volume", DACL1_2_LLOPM_VOL, | ||
238 | DACR1_2_RLOPM_VOL, 0, 0x7f, 1), | ||
239 | SOC_DOUBLE_R("Line DAC Playback Switch", LLOPM_CTRL, RLOPM_CTRL, 3, | ||
240 | 0x01, 0), | ||
241 | SOC_DOUBLE_R("Line PGA Bypass Playback Volume", PGAL_2_LLOPM_VOL, | ||
242 | PGAR_2_RLOPM_VOL, 0, 0x7f, 1), | ||
243 | SOC_DOUBLE_R("Line Line2 Bypass Playback Volume", LINE2L_2_LLOPM_VOL, | ||
244 | LINE2R_2_RLOPM_VOL, 0, 0x7f, 1), | ||
245 | |||
246 | SOC_DOUBLE_R("Mono DAC Playback Volume", DACL1_2_MONOLOPM_VOL, | ||
247 | DACR1_2_MONOLOPM_VOL, 0, 0x7f, 1), | ||
248 | SOC_SINGLE("Mono DAC Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0), | ||
249 | SOC_DOUBLE_R("Mono PGA Bypass Playback Volume", PGAL_2_MONOLOPM_VOL, | ||
250 | PGAR_2_MONOLOPM_VOL, 0, 0x7f, 1), | ||
251 | SOC_DOUBLE_R("Mono Line2 Bypass Playback Volume", LINE2L_2_MONOLOPM_VOL, | ||
252 | LINE2R_2_MONOLOPM_VOL, 0, 0x7f, 1), | ||
253 | |||
254 | SOC_DOUBLE_R("HP DAC Playback Volume", DACL1_2_HPLOUT_VOL, | ||
255 | DACR1_2_HPROUT_VOL, 0, 0x7f, 1), | ||
256 | SOC_DOUBLE_R("HP DAC Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3, | ||
257 | 0x01, 0), | ||
258 | SOC_DOUBLE_R("HP PGA Bypass Playback Volume", PGAL_2_HPLOUT_VOL, | ||
259 | PGAR_2_HPROUT_VOL, 0, 0x7f, 1), | ||
260 | SOC_DOUBLE_R("HP Line2 Bypass Playback Volume", LINE2L_2_HPLOUT_VOL, | ||
261 | LINE2R_2_HPROUT_VOL, 0, 0x7f, 1), | ||
262 | |||
263 | SOC_DOUBLE_R("HPCOM DAC Playback Volume", DACL1_2_HPLCOM_VOL, | ||
264 | DACR1_2_HPRCOM_VOL, 0, 0x7f, 1), | ||
265 | SOC_DOUBLE_R("HPCOM DAC Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3, | ||
266 | 0x01, 0), | ||
267 | SOC_DOUBLE_R("HPCOM PGA Bypass Playback Volume", PGAL_2_HPLCOM_VOL, | ||
268 | PGAR_2_HPRCOM_VOL, 0, 0x7f, 1), | ||
269 | SOC_DOUBLE_R("HPCOM Line2 Bypass Playback Volume", LINE2L_2_HPLCOM_VOL, | ||
270 | LINE2R_2_HPRCOM_VOL, 0, 0x7f, 1), | ||
271 | |||
272 | /* | ||
273 | * Note: enable Automatic input Gain Controller with care. It can | ||
274 | * adjust PGA to max value when ADC is on and will never go back. | ||
275 | */ | ||
276 | SOC_DOUBLE_R("AGC Switch", LAGC_CTRL_A, RAGC_CTRL_A, 7, 0x01, 0), | ||
277 | |||
278 | /* Input */ | ||
279 | SOC_DOUBLE_R("PGA Capture Volume", LADC_VOL, RADC_VOL, 0, 0x7f, 0), | ||
280 | SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1), | ||
281 | }; | ||
282 | |||
283 | /* add non dapm controls */ | ||
284 | static int aic3x_add_controls(struct snd_soc_codec *codec) | ||
285 | { | ||
286 | int err, i; | ||
287 | |||
288 | for (i = 0; i < ARRAY_SIZE(aic3x_snd_controls); i++) { | ||
289 | err = snd_ctl_add(codec->card, | ||
290 | snd_soc_cnew(&aic3x_snd_controls[i], | ||
291 | codec, NULL)); | ||
292 | if (err < 0) | ||
293 | return err; | ||
294 | } | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | /* Left DAC Mux */ | ||
300 | static const struct snd_kcontrol_new aic3x_left_dac_mux_controls = | ||
301 | SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]); | ||
302 | |||
303 | /* Right DAC Mux */ | ||
304 | static const struct snd_kcontrol_new aic3x_right_dac_mux_controls = | ||
305 | SOC_DAPM_ENUM("Route", aic3x_enum[RDAC_ENUM]); | ||
306 | |||
307 | /* Left HPCOM Mux */ | ||
308 | static const struct snd_kcontrol_new aic3x_left_hpcom_mux_controls = | ||
309 | SOC_DAPM_ENUM("Route", aic3x_enum[LHPCOM_ENUM]); | ||
310 | |||
311 | /* Right HPCOM Mux */ | ||
312 | static const struct snd_kcontrol_new aic3x_right_hpcom_mux_controls = | ||
313 | SOC_DAPM_ENUM("Route", aic3x_enum[RHPCOM_ENUM]); | ||
314 | |||
315 | /* Left DAC_L1 Mixer */ | ||
316 | static const struct snd_kcontrol_new aic3x_left_dac_mixer_controls[] = { | ||
317 | SOC_DAPM_SINGLE("Line Switch", DACL1_2_LLOPM_VOL, 7, 1, 0), | ||
318 | SOC_DAPM_SINGLE("Mono Switch", DACL1_2_MONOLOPM_VOL, 7, 1, 0), | ||
319 | SOC_DAPM_SINGLE("HP Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0), | ||
320 | SOC_DAPM_SINGLE("HPCOM Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0), | ||
321 | }; | ||
322 | |||
323 | /* Right DAC_R1 Mixer */ | ||
324 | static const struct snd_kcontrol_new aic3x_right_dac_mixer_controls[] = { | ||
325 | SOC_DAPM_SINGLE("Line Switch", DACR1_2_RLOPM_VOL, 7, 1, 0), | ||
326 | SOC_DAPM_SINGLE("Mono Switch", DACR1_2_MONOLOPM_VOL, 7, 1, 0), | ||
327 | SOC_DAPM_SINGLE("HP Switch", DACR1_2_HPROUT_VOL, 7, 1, 0), | ||
328 | SOC_DAPM_SINGLE("HPCOM Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0), | ||
329 | }; | ||
330 | |||
331 | /* Left PGA Mixer */ | ||
332 | static const struct snd_kcontrol_new aic3x_left_pga_mixer_controls[] = { | ||
333 | SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_LADC_CTRL, 3, 1, 1), | ||
334 | SOC_DAPM_SINGLE_AIC3X("Line2L Switch", LINE2L_2_LADC_CTRL, 3, 1, 1), | ||
335 | SOC_DAPM_SINGLE_AIC3X("Mic3L Switch", MIC3LR_2_LADC_CTRL, 4, 1, 1), | ||
336 | }; | ||
337 | |||
338 | /* Right PGA Mixer */ | ||
339 | static const struct snd_kcontrol_new aic3x_right_pga_mixer_controls[] = { | ||
340 | SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_RADC_CTRL, 3, 1, 1), | ||
341 | SOC_DAPM_SINGLE_AIC3X("Line2R Switch", LINE2R_2_RADC_CTRL, 3, 1, 1), | ||
342 | SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_RADC_CTRL, 0, 1, 1), | ||
343 | }; | ||
344 | |||
345 | /* Left Line1 Mux */ | ||
346 | static const struct snd_kcontrol_new aic3x_left_line1_mux_controls = | ||
347 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE1L_ENUM]); | ||
348 | |||
349 | /* Right Line1 Mux */ | ||
350 | static const struct snd_kcontrol_new aic3x_right_line1_mux_controls = | ||
351 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE1R_ENUM]); | ||
352 | |||
353 | /* Left Line2 Mux */ | ||
354 | static const struct snd_kcontrol_new aic3x_left_line2_mux_controls = | ||
355 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE2L_ENUM]); | ||
356 | |||
357 | /* Right Line2 Mux */ | ||
358 | static const struct snd_kcontrol_new aic3x_right_line2_mux_controls = | ||
359 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE2R_ENUM]); | ||
360 | |||
361 | /* Left PGA Bypass Mixer */ | ||
362 | static const struct snd_kcontrol_new aic3x_left_pga_bp_mixer_controls[] = { | ||
363 | SOC_DAPM_SINGLE("Line Switch", PGAL_2_LLOPM_VOL, 7, 1, 0), | ||
364 | SOC_DAPM_SINGLE("Mono Switch", PGAL_2_MONOLOPM_VOL, 7, 1, 0), | ||
365 | SOC_DAPM_SINGLE("HP Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0), | ||
366 | SOC_DAPM_SINGLE("HPCOM Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0), | ||
367 | }; | ||
368 | |||
369 | /* Right PGA Bypass Mixer */ | ||
370 | static const struct snd_kcontrol_new aic3x_right_pga_bp_mixer_controls[] = { | ||
371 | SOC_DAPM_SINGLE("Line Switch", PGAR_2_RLOPM_VOL, 7, 1, 0), | ||
372 | SOC_DAPM_SINGLE("Mono Switch", PGAR_2_MONOLOPM_VOL, 7, 1, 0), | ||
373 | SOC_DAPM_SINGLE("HP Switch", PGAR_2_HPROUT_VOL, 7, 1, 0), | ||
374 | SOC_DAPM_SINGLE("HPCOM Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0), | ||
375 | }; | ||
376 | |||
377 | /* Left Line2 Bypass Mixer */ | ||
378 | static const struct snd_kcontrol_new aic3x_left_line2_bp_mixer_controls[] = { | ||
379 | SOC_DAPM_SINGLE("Line Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0), | ||
380 | SOC_DAPM_SINGLE("Mono Switch", LINE2L_2_MONOLOPM_VOL, 7, 1, 0), | ||
381 | SOC_DAPM_SINGLE("HP Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0), | ||
382 | SOC_DAPM_SINGLE("HPCOM Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0), | ||
383 | }; | ||
384 | |||
385 | /* Right Line2 Bypass Mixer */ | ||
386 | static const struct snd_kcontrol_new aic3x_right_line2_bp_mixer_controls[] = { | ||
387 | SOC_DAPM_SINGLE("Line Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0), | ||
388 | SOC_DAPM_SINGLE("Mono Switch", LINE2R_2_MONOLOPM_VOL, 7, 1, 0), | ||
389 | SOC_DAPM_SINGLE("HP Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0), | ||
390 | SOC_DAPM_SINGLE("HPCOM Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0), | ||
391 | }; | ||
392 | |||
393 | static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { | ||
394 | /* Left DAC to Left Outputs */ | ||
395 | SND_SOC_DAPM_DAC("Left DAC", "Left Playback", DAC_PWR, 7, 0), | ||
396 | SND_SOC_DAPM_MUX("Left DAC Mux", SND_SOC_NOPM, 0, 0, | ||
397 | &aic3x_left_dac_mux_controls), | ||
398 | SND_SOC_DAPM_MIXER("Left DAC_L1 Mixer", SND_SOC_NOPM, 0, 0, | ||
399 | &aic3x_left_dac_mixer_controls[0], | ||
400 | ARRAY_SIZE(aic3x_left_dac_mixer_controls)), | ||
401 | SND_SOC_DAPM_MUX("Left HPCOM Mux", SND_SOC_NOPM, 0, 0, | ||
402 | &aic3x_left_hpcom_mux_controls), | ||
403 | SND_SOC_DAPM_PGA("Left Line Out", LLOPM_CTRL, 0, 0, NULL, 0), | ||
404 | SND_SOC_DAPM_PGA("Left HP Out", HPLOUT_CTRL, 0, 0, NULL, 0), | ||
405 | SND_SOC_DAPM_PGA("Left HP Com", HPLCOM_CTRL, 0, 0, NULL, 0), | ||
406 | |||
407 | /* Right DAC to Right Outputs */ | ||
408 | SND_SOC_DAPM_DAC("Right DAC", "Right Playback", DAC_PWR, 6, 0), | ||
409 | SND_SOC_DAPM_MUX("Right DAC Mux", SND_SOC_NOPM, 0, 0, | ||
410 | &aic3x_right_dac_mux_controls), | ||
411 | SND_SOC_DAPM_MIXER("Right DAC_R1 Mixer", SND_SOC_NOPM, 0, 0, | ||
412 | &aic3x_right_dac_mixer_controls[0], | ||
413 | ARRAY_SIZE(aic3x_right_dac_mixer_controls)), | ||
414 | SND_SOC_DAPM_MUX("Right HPCOM Mux", SND_SOC_NOPM, 0, 0, | ||
415 | &aic3x_right_hpcom_mux_controls), | ||
416 | SND_SOC_DAPM_PGA("Right Line Out", RLOPM_CTRL, 0, 0, NULL, 0), | ||
417 | SND_SOC_DAPM_PGA("Right HP Out", HPROUT_CTRL, 0, 0, NULL, 0), | ||
418 | SND_SOC_DAPM_PGA("Right HP Com", HPRCOM_CTRL, 0, 0, NULL, 0), | ||
419 | |||
420 | /* Mono Output */ | ||
421 | SND_SOC_DAPM_PGA("Mono Out", MONOLOPM_CTRL, 0, 0, NULL, 0), | ||
422 | |||
423 | /* Left Inputs to Left ADC */ | ||
424 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", LINE1L_2_LADC_CTRL, 2, 0), | ||
425 | SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0, | ||
426 | &aic3x_left_pga_mixer_controls[0], | ||
427 | ARRAY_SIZE(aic3x_left_pga_mixer_controls)), | ||
428 | SND_SOC_DAPM_MUX("Left Line1L Mux", SND_SOC_NOPM, 0, 0, | ||
429 | &aic3x_left_line1_mux_controls), | ||
430 | SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0, | ||
431 | &aic3x_left_line2_mux_controls), | ||
432 | |||
433 | /* Right Inputs to Right ADC */ | ||
434 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", | ||
435 | LINE1R_2_RADC_CTRL, 2, 0), | ||
436 | SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0, | ||
437 | &aic3x_right_pga_mixer_controls[0], | ||
438 | ARRAY_SIZE(aic3x_right_pga_mixer_controls)), | ||
439 | SND_SOC_DAPM_MUX("Right Line1R Mux", SND_SOC_NOPM, 0, 0, | ||
440 | &aic3x_right_line1_mux_controls), | ||
441 | SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0, | ||
442 | &aic3x_right_line2_mux_controls), | ||
443 | |||
444 | /* Mic Bias */ | ||
445 | SND_SOC_DAPM_MICBIAS("Mic Bias 2V", MICBIAS_CTRL, 6, 0), | ||
446 | SND_SOC_DAPM_MICBIAS("Mic Bias 2.5V", MICBIAS_CTRL, 7, 0), | ||
447 | SND_SOC_DAPM_MICBIAS("Mic Bias AVDD", MICBIAS_CTRL, 6, 0), | ||
448 | SND_SOC_DAPM_MICBIAS("Mic Bias AVDD", MICBIAS_CTRL, 7, 0), | ||
449 | |||
450 | /* Left PGA to Left Output bypass */ | ||
451 | SND_SOC_DAPM_MIXER("Left PGA Bypass Mixer", SND_SOC_NOPM, 0, 0, | ||
452 | &aic3x_left_pga_bp_mixer_controls[0], | ||
453 | ARRAY_SIZE(aic3x_left_pga_bp_mixer_controls)), | ||
454 | |||
455 | /* Right PGA to Right Output bypass */ | ||
456 | SND_SOC_DAPM_MIXER("Right PGA Bypass Mixer", SND_SOC_NOPM, 0, 0, | ||
457 | &aic3x_right_pga_bp_mixer_controls[0], | ||
458 | ARRAY_SIZE(aic3x_right_pga_bp_mixer_controls)), | ||
459 | |||
460 | /* Left Line2 to Left Output bypass */ | ||
461 | SND_SOC_DAPM_MIXER("Left Line2 Bypass Mixer", SND_SOC_NOPM, 0, 0, | ||
462 | &aic3x_left_line2_bp_mixer_controls[0], | ||
463 | ARRAY_SIZE(aic3x_left_line2_bp_mixer_controls)), | ||
464 | |||
465 | /* Right Line2 to Right Output bypass */ | ||
466 | SND_SOC_DAPM_MIXER("Right Line2 Bypass Mixer", SND_SOC_NOPM, 0, 0, | ||
467 | &aic3x_right_line2_bp_mixer_controls[0], | ||
468 | ARRAY_SIZE(aic3x_right_line2_bp_mixer_controls)), | ||
469 | |||
470 | SND_SOC_DAPM_OUTPUT("LLOUT"), | ||
471 | SND_SOC_DAPM_OUTPUT("RLOUT"), | ||
472 | SND_SOC_DAPM_OUTPUT("MONO_LOUT"), | ||
473 | SND_SOC_DAPM_OUTPUT("HPLOUT"), | ||
474 | SND_SOC_DAPM_OUTPUT("HPROUT"), | ||
475 | SND_SOC_DAPM_OUTPUT("HPLCOM"), | ||
476 | SND_SOC_DAPM_OUTPUT("HPRCOM"), | ||
477 | |||
478 | SND_SOC_DAPM_INPUT("MIC3L"), | ||
479 | SND_SOC_DAPM_INPUT("MIC3R"), | ||
480 | SND_SOC_DAPM_INPUT("LINE1L"), | ||
481 | SND_SOC_DAPM_INPUT("LINE1R"), | ||
482 | SND_SOC_DAPM_INPUT("LINE2L"), | ||
483 | SND_SOC_DAPM_INPUT("LINE2R"), | ||
484 | }; | ||
485 | |||
486 | static const char *intercon[][3] = { | ||
487 | /* Left Output */ | ||
488 | {"Left DAC Mux", "DAC_L1", "Left DAC"}, | ||
489 | {"Left DAC Mux", "DAC_L2", "Left DAC"}, | ||
490 | {"Left DAC Mux", "DAC_L3", "Left DAC"}, | ||
491 | |||
492 | {"Left DAC_L1 Mixer", "Line Switch", "Left DAC Mux"}, | ||
493 | {"Left DAC_L1 Mixer", "Mono Switch", "Left DAC Mux"}, | ||
494 | {"Left DAC_L1 Mixer", "HP Switch", "Left DAC Mux"}, | ||
495 | {"Left DAC_L1 Mixer", "HPCOM Switch", "Left DAC Mux"}, | ||
496 | {"Left Line Out", NULL, "Left DAC Mux"}, | ||
497 | {"Left HP Out", NULL, "Left DAC Mux"}, | ||
498 | |||
499 | {"Left HPCOM Mux", "differential of HPLOUT", "Left DAC_L1 Mixer"}, | ||
500 | {"Left HPCOM Mux", "constant VCM", "Left DAC_L1 Mixer"}, | ||
501 | {"Left HPCOM Mux", "single-ended", "Left DAC_L1 Mixer"}, | ||
502 | |||
503 | {"Left Line Out", NULL, "Left DAC_L1 Mixer"}, | ||
504 | {"Mono Out", NULL, "Left DAC_L1 Mixer"}, | ||
505 | {"Left HP Out", NULL, "Left DAC_L1 Mixer"}, | ||
506 | {"Left HP Com", NULL, "Left HPCOM Mux"}, | ||
507 | |||
508 | {"LLOUT", NULL, "Left Line Out"}, | ||
509 | {"LLOUT", NULL, "Left Line Out"}, | ||
510 | {"HPLOUT", NULL, "Left HP Out"}, | ||
511 | {"HPLCOM", NULL, "Left HP Com"}, | ||
512 | |||
513 | /* Right Output */ | ||
514 | {"Right DAC Mux", "DAC_R1", "Right DAC"}, | ||
515 | {"Right DAC Mux", "DAC_R2", "Right DAC"}, | ||
516 | {"Right DAC Mux", "DAC_R3", "Right DAC"}, | ||
517 | |||
518 | {"Right DAC_R1 Mixer", "Line Switch", "Right DAC Mux"}, | ||
519 | {"Right DAC_R1 Mixer", "Mono Switch", "Right DAC Mux"}, | ||
520 | {"Right DAC_R1 Mixer", "HP Switch", "Right DAC Mux"}, | ||
521 | {"Right DAC_R1 Mixer", "HPCOM Switch", "Right DAC Mux"}, | ||
522 | {"Right Line Out", NULL, "Right DAC Mux"}, | ||
523 | {"Right HP Out", NULL, "Right DAC Mux"}, | ||
524 | |||
525 | {"Right HPCOM Mux", "differential of HPROUT", "Right DAC_R1 Mixer"}, | ||
526 | {"Right HPCOM Mux", "constant VCM", "Right DAC_R1 Mixer"}, | ||
527 | {"Right HPCOM Mux", "single-ended", "Right DAC_R1 Mixer"}, | ||
528 | {"Right HPCOM Mux", "differential of HPLCOM", "Right DAC_R1 Mixer"}, | ||
529 | {"Right HPCOM Mux", "external feedback", "Right DAC_R1 Mixer"}, | ||
530 | |||
531 | {"Right Line Out", NULL, "Right DAC_R1 Mixer"}, | ||
532 | {"Mono Out", NULL, "Right DAC_R1 Mixer"}, | ||
533 | {"Right HP Out", NULL, "Right DAC_R1 Mixer"}, | ||
534 | {"Right HP Com", NULL, "Right HPCOM Mux"}, | ||
535 | |||
536 | {"RLOUT", NULL, "Right Line Out"}, | ||
537 | {"RLOUT", NULL, "Right Line Out"}, | ||
538 | {"HPROUT", NULL, "Right HP Out"}, | ||
539 | {"HPRCOM", NULL, "Right HP Com"}, | ||
540 | |||
541 | /* Mono Output */ | ||
542 | {"MONOLOUT", NULL, "Mono Out"}, | ||
543 | {"MONOLOUT", NULL, "Mono Out"}, | ||
544 | |||
545 | /* Left Input */ | ||
546 | {"Left Line1L Mux", "single-ended", "LINE1L"}, | ||
547 | {"Left Line1L Mux", "differential", "LINE1L"}, | ||
548 | |||
549 | {"Left Line2L Mux", "single-ended", "LINE2L"}, | ||
550 | {"Left Line2L Mux", "differential", "LINE2L"}, | ||
551 | |||
552 | {"Left PGA Mixer", "Line1L Switch", "Left Line1L Mux"}, | ||
553 | {"Left PGA Mixer", "Line2L Switch", "Left Line2L Mux"}, | ||
554 | {"Left PGA Mixer", "Mic3L Switch", "MIC3L"}, | ||
555 | |||
556 | {"Left ADC", NULL, "Left PGA Mixer"}, | ||
557 | |||
558 | /* Right Input */ | ||
559 | {"Right Line1R Mux", "single-ended", "LINE1R"}, | ||
560 | {"Right Line1R Mux", "differential", "LINE1R"}, | ||
561 | |||
562 | {"Right Line2R Mux", "single-ended", "LINE2R"}, | ||
563 | {"Right Line2R Mux", "differential", "LINE2R"}, | ||
564 | |||
565 | {"Right PGA Mixer", "Line1R Switch", "Right Line1R Mux"}, | ||
566 | {"Right PGA Mixer", "Line2R Switch", "Right Line2R Mux"}, | ||
567 | {"Right PGA Mixer", "Mic3R Switch", "MIC3R"}, | ||
568 | |||
569 | {"Right ADC", NULL, "Right PGA Mixer"}, | ||
570 | |||
571 | /* Left PGA Bypass */ | ||
572 | {"Left PGA Bypass Mixer", "Line Switch", "Left PGA Mixer"}, | ||
573 | {"Left PGA Bypass Mixer", "Mono Switch", "Left PGA Mixer"}, | ||
574 | {"Left PGA Bypass Mixer", "HP Switch", "Left PGA Mixer"}, | ||
575 | {"Left PGA Bypass Mixer", "HPCOM Switch", "Left PGA Mixer"}, | ||
576 | |||
577 | {"Left HPCOM Mux", "differential of HPLOUT", "Left PGA Bypass Mixer"}, | ||
578 | {"Left HPCOM Mux", "constant VCM", "Left PGA Bypass Mixer"}, | ||
579 | {"Left HPCOM Mux", "single-ended", "Left PGA Bypass Mixer"}, | ||
580 | |||
581 | {"Left Line Out", NULL, "Left PGA Bypass Mixer"}, | ||
582 | {"Mono Out", NULL, "Left PGA Bypass Mixer"}, | ||
583 | {"Left HP Out", NULL, "Left PGA Bypass Mixer"}, | ||
584 | |||
585 | /* Right PGA Bypass */ | ||
586 | {"Right PGA Bypass Mixer", "Line Switch", "Right PGA Mixer"}, | ||
587 | {"Right PGA Bypass Mixer", "Mono Switch", "Right PGA Mixer"}, | ||
588 | {"Right PGA Bypass Mixer", "HP Switch", "Right PGA Mixer"}, | ||
589 | {"Right PGA Bypass Mixer", "HPCOM Switch", "Right PGA Mixer"}, | ||
590 | |||
591 | {"Right HPCOM Mux", "differential of HPROUT", "Right PGA Bypass Mixer"}, | ||
592 | {"Right HPCOM Mux", "constant VCM", "Right PGA Bypass Mixer"}, | ||
593 | {"Right HPCOM Mux", "single-ended", "Right PGA Bypass Mixer"}, | ||
594 | {"Right HPCOM Mux", "differential of HPLCOM", "Right PGA Bypass Mixer"}, | ||
595 | {"Right HPCOM Mux", "external feedback", "Right PGA Bypass Mixer"}, | ||
596 | |||
597 | {"Right Line Out", NULL, "Right PGA Bypass Mixer"}, | ||
598 | {"Mono Out", NULL, "Right PGA Bypass Mixer"}, | ||
599 | {"Right HP Out", NULL, "Right PGA Bypass Mixer"}, | ||
600 | |||
601 | /* Left Line2 Bypass */ | ||
602 | {"Left Line2 Bypass Mixer", "Line Switch", "Left Line2L Mux"}, | ||
603 | {"Left Line2 Bypass Mixer", "Mono Switch", "Left Line2L Mux"}, | ||
604 | {"Left Line2 Bypass Mixer", "HP Switch", "Left Line2L Mux"}, | ||
605 | {"Left Line2 Bypass Mixer", "HPCOM Switch", "Left Line2L Mux"}, | ||
606 | |||
607 | {"Left HPCOM Mux", "differential of HPLOUT", "Left Line2 Bypass Mixer"}, | ||
608 | {"Left HPCOM Mux", "constant VCM", "Left Line2 Bypass Mixer"}, | ||
609 | {"Left HPCOM Mux", "single-ended", "Left Line2 Bypass Mixer"}, | ||
610 | |||
611 | {"Left Line Out", NULL, "Left Line2 Bypass Mixer"}, | ||
612 | {"Mono Out", NULL, "Left Line2 Bypass Mixer"}, | ||
613 | {"Left HP Out", NULL, "Left Line2 Bypass Mixer"}, | ||
614 | |||
615 | /* Right Line2 Bypass */ | ||
616 | {"Right Line2 Bypass Mixer", "Line Switch", "Right Line2R Mux"}, | ||
617 | {"Right Line2 Bypass Mixer", "Mono Switch", "Right Line2R Mux"}, | ||
618 | {"Right Line2 Bypass Mixer", "HP Switch", "Right Line2R Mux"}, | ||
619 | {"Right Line2 Bypass Mixer", "HPCOM Switch", "Right Line2R Mux"}, | ||
620 | |||
621 | {"Right HPCOM Mux", "differential of HPROUT", "Right Line2 Bypass Mixer"}, | ||
622 | {"Right HPCOM Mux", "constant VCM", "Right Line2 Bypass Mixer"}, | ||
623 | {"Right HPCOM Mux", "single-ended", "Right Line2 Bypass Mixer"}, | ||
624 | {"Right HPCOM Mux", "differential of HPLCOM", "Right Line2 Bypass Mixer"}, | ||
625 | {"Right HPCOM Mux", "external feedback", "Right Line2 Bypass Mixer"}, | ||
626 | |||
627 | {"Right Line Out", NULL, "Right Line2 Bypass Mixer"}, | ||
628 | {"Mono Out", NULL, "Right Line2 Bypass Mixer"}, | ||
629 | {"Right HP Out", NULL, "Right Line2 Bypass Mixer"}, | ||
630 | |||
631 | /* terminator */ | ||
632 | {NULL, NULL, NULL}, | ||
633 | }; | ||
634 | |||
635 | static int aic3x_add_widgets(struct snd_soc_codec *codec) | ||
636 | { | ||
637 | int i; | ||
638 | |||
639 | for (i = 0; i < ARRAY_SIZE(aic3x_dapm_widgets); i++) | ||
640 | snd_soc_dapm_new_control(codec, &aic3x_dapm_widgets[i]); | ||
641 | |||
642 | /* set up audio path interconnects */ | ||
643 | for (i = 0; intercon[i][0] != NULL; i++) | ||
644 | snd_soc_dapm_connect_input(codec, intercon[i][0], | ||
645 | intercon[i][1], intercon[i][2]); | ||
646 | |||
647 | snd_soc_dapm_new_widgets(codec); | ||
648 | return 0; | ||
649 | } | ||
650 | |||
651 | struct aic3x_rate_divs { | ||
652 | u32 mclk; | ||
653 | u32 rate; | ||
654 | u32 fsref_reg; | ||
655 | u8 sr_reg:4; | ||
656 | u8 pllj_reg; | ||
657 | u16 plld_reg; | ||
658 | }; | ||
659 | |||
660 | /* AIC3X codec mclk clock divider coefficients */ | ||
661 | static const struct aic3x_rate_divs aic3x_divs[] = { | ||
662 | /* 8k */ | ||
663 | {22579200, 8000, 48000, 0xa, 8, 7075}, | ||
664 | {33868800, 8000, 48000, 0xa, 5, 8049}, | ||
665 | /* 11.025k */ | ||
666 | {22579200, 11025, 44100, 0x6, 8, 0}, | ||
667 | {33868800, 11025, 44100, 0x6, 5, 3333}, | ||
668 | /* 16k */ | ||
669 | {22579200, 16000, 48000, 0x4, 8, 7075}, | ||
670 | {33868800, 16000, 48000, 0x4, 5, 8049}, | ||
671 | /* 22.05k */ | ||
672 | {22579200, 22050, 44100, 0x2, 8, 0}, | ||
673 | {33868800, 22050, 44100, 0x2, 5, 3333}, | ||
674 | /* 32k */ | ||
675 | {22579200, 32000, 48000, 0x1, 8, 7075}, | ||
676 | {33868800, 32000, 48000, 0x1, 5, 8049}, | ||
677 | /* 44.1k */ | ||
678 | {22579200, 44100, 44100, 0x0, 8, 0}, | ||
679 | {33868800, 44100, 44100, 0x0, 5, 3333}, | ||
680 | /* 48k */ | ||
681 | {22579200, 48000, 48000, 0x0, 8, 7075}, | ||
682 | {33868800, 48000, 48000, 0x0, 5, 8049}, | ||
683 | /* 64k */ | ||
684 | {22579200, 96000, 96000, 0x1, 8, 7075}, | ||
685 | {33868800, 96000, 96000, 0x1, 5, 8049}, | ||
686 | /* 88.2k */ | ||
687 | {22579200, 88200, 88200, 0x0, 8, 0}, | ||
688 | {33868800, 88200, 88200, 0x0, 5, 3333}, | ||
689 | /* 96k */ | ||
690 | {22579200, 96000, 96000, 0x0, 8, 7075}, | ||
691 | {33868800, 96000, 96000, 0x0, 5, 8049}, | ||
692 | }; | ||
693 | |||
694 | static inline int aic3x_get_divs(int mclk, int rate) | ||
695 | { | ||
696 | int i; | ||
697 | |||
698 | for (i = 0; i < ARRAY_SIZE(aic3x_divs); i++) { | ||
699 | if (aic3x_divs[i].rate == rate && aic3x_divs[i].mclk == mclk) | ||
700 | return i; | ||
701 | } | ||
702 | |||
703 | return 0; | ||
704 | } | ||
705 | |||
706 | static int aic3x_hw_params(struct snd_pcm_substream *substream, | ||
707 | struct snd_pcm_hw_params *params) | ||
708 | { | ||
709 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
710 | struct snd_soc_device *socdev = rtd->socdev; | ||
711 | struct snd_soc_codec *codec = socdev->codec; | ||
712 | struct aic3x_priv *aic3x = codec->private_data; | ||
713 | int i; | ||
714 | u8 data, pll_p, pll_r, pll_j; | ||
715 | u16 pll_d; | ||
716 | |||
717 | i = aic3x_get_divs(aic3x->sysclk, params_rate(params)); | ||
718 | |||
719 | /* Route Left DAC to left channel input and | ||
720 | * right DAC to right channel input */ | ||
721 | data = (LDAC2LCH | RDAC2RCH); | ||
722 | switch (aic3x_divs[i].fsref_reg) { | ||
723 | case 44100: | ||
724 | data |= FSREF_44100; | ||
725 | break; | ||
726 | case 48000: | ||
727 | data |= FSREF_48000; | ||
728 | break; | ||
729 | case 88200: | ||
730 | data |= FSREF_44100 | DUAL_RATE_MODE; | ||
731 | break; | ||
732 | case 96000: | ||
733 | data |= FSREF_48000 | DUAL_RATE_MODE; | ||
734 | break; | ||
735 | } | ||
736 | aic3x_write(codec, AIC3X_CODEC_DATAPATH_REG, data); | ||
737 | |||
738 | /* codec sample rate select */ | ||
739 | data = aic3x_divs[i].sr_reg; | ||
740 | data |= (data << 4); | ||
741 | aic3x_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data); | ||
742 | |||
743 | /* Use PLL for generation Fsref by equation: | ||
744 | * Fsref = (MCLK * K * R)/(2048 * P); | ||
745 | * Fix P = 2 and R = 1 and calculate K, if | ||
746 | * K = J.D, i.e. J - an interger portion of K and D is the fractional | ||
747 | * one with 4 digits of precision; | ||
748 | * Example: | ||
749 | * For MCLK = 22.5792 MHz and Fsref = 48kHz: | ||
750 | * Select P = 2, R= 1, K = 8.7074, which results in J = 8, D = 7074 | ||
751 | */ | ||
752 | pll_p = 2; | ||
753 | pll_r = 1; | ||
754 | pll_j = aic3x_divs[i].pllj_reg; | ||
755 | pll_d = aic3x_divs[i].plld_reg; | ||
756 | |||
757 | data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); | ||
758 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT)); | ||
759 | aic3x_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG, pll_r << PLLR_SHIFT); | ||
760 | aic3x_write(codec, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT); | ||
761 | aic3x_write(codec, AIC3X_PLL_PROGC_REG, (pll_d >> 6) << PLLD_MSB_SHIFT); | ||
762 | aic3x_write(codec, AIC3X_PLL_PROGD_REG, | ||
763 | (pll_d & 0x3F) << PLLD_LSB_SHIFT); | ||
764 | |||
765 | /* select data word length */ | ||
766 | data = | ||
767 | aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4)); | ||
768 | switch (params_format(params)) { | ||
769 | case SNDRV_PCM_FORMAT_S16_LE: | ||
770 | break; | ||
771 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
772 | data |= (0x01 << 4); | ||
773 | break; | ||
774 | case SNDRV_PCM_FORMAT_S24_LE: | ||
775 | data |= (0x02 << 4); | ||
776 | break; | ||
777 | case SNDRV_PCM_FORMAT_S32_LE: | ||
778 | data |= (0x03 << 4); | ||
779 | break; | ||
780 | } | ||
781 | aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data); | ||
782 | |||
783 | return 0; | ||
784 | } | ||
785 | |||
786 | static int aic3x_mute(struct snd_soc_codec_dai *dai, int mute) | ||
787 | { | ||
788 | struct snd_soc_codec *codec = dai->codec; | ||
789 | u8 ldac_reg = aic3x_read_reg_cache(codec, LDAC_VOL) & ~MUTE_ON; | ||
790 | u8 rdac_reg = aic3x_read_reg_cache(codec, RDAC_VOL) & ~MUTE_ON; | ||
791 | |||
792 | if (mute) { | ||
793 | aic3x_write(codec, LDAC_VOL, ldac_reg | MUTE_ON); | ||
794 | aic3x_write(codec, RDAC_VOL, rdac_reg | MUTE_ON); | ||
795 | } else { | ||
796 | aic3x_write(codec, LDAC_VOL, ldac_reg); | ||
797 | aic3x_write(codec, RDAC_VOL, rdac_reg); | ||
798 | } | ||
799 | |||
800 | return 0; | ||
801 | } | ||
802 | |||
803 | static int aic3x_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | ||
804 | int clk_id, unsigned int freq, int dir) | ||
805 | { | ||
806 | struct snd_soc_codec *codec = codec_dai->codec; | ||
807 | struct aic3x_priv *aic3x = codec->private_data; | ||
808 | |||
809 | switch (freq) { | ||
810 | case 22579200: | ||
811 | case 33868800: | ||
812 | aic3x->sysclk = freq; | ||
813 | return 0; | ||
814 | } | ||
815 | |||
816 | return -EINVAL; | ||
817 | } | ||
818 | |||
819 | static int aic3x_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | ||
820 | unsigned int fmt) | ||
821 | { | ||
822 | struct snd_soc_codec *codec = codec_dai->codec; | ||
823 | struct aic3x_priv *aic3x = codec->private_data; | ||
824 | u8 iface_areg = 0; | ||
825 | u8 iface_breg = 0; | ||
826 | |||
827 | /* set master/slave audio interface */ | ||
828 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
829 | case SND_SOC_DAIFMT_CBM_CFM: | ||
830 | aic3x->master = 1; | ||
831 | iface_areg |= BIT_CLK_MASTER | WORD_CLK_MASTER; | ||
832 | break; | ||
833 | case SND_SOC_DAIFMT_CBS_CFS: | ||
834 | aic3x->master = 0; | ||
835 | break; | ||
836 | default: | ||
837 | return -EINVAL; | ||
838 | } | ||
839 | |||
840 | /* interface format */ | ||
841 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
842 | case SND_SOC_DAIFMT_I2S: | ||
843 | break; | ||
844 | case SND_SOC_DAIFMT_DSP_A: | ||
845 | iface_breg |= (0x01 << 6); | ||
846 | break; | ||
847 | case SND_SOC_DAIFMT_RIGHT_J: | ||
848 | iface_breg |= (0x02 << 6); | ||
849 | break; | ||
850 | case SND_SOC_DAIFMT_LEFT_J: | ||
851 | iface_breg |= (0x03 << 6); | ||
852 | break; | ||
853 | default: | ||
854 | return -EINVAL; | ||
855 | } | ||
856 | |||
857 | /* set iface */ | ||
858 | aic3x_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg); | ||
859 | aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg); | ||
860 | |||
861 | return 0; | ||
862 | } | ||
863 | |||
864 | static int aic3x_dapm_event(struct snd_soc_codec *codec, int event) | ||
865 | { | ||
866 | struct aic3x_priv *aic3x = codec->private_data; | ||
867 | u8 reg; | ||
868 | |||
869 | switch (event) { | ||
870 | case SNDRV_CTL_POWER_D0: | ||
871 | /* all power is driven by DAPM system */ | ||
872 | if (aic3x->master) { | ||
873 | /* enable pll */ | ||
874 | reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); | ||
875 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, | ||
876 | reg | PLL_ENABLE); | ||
877 | } | ||
878 | break; | ||
879 | case SNDRV_CTL_POWER_D1: | ||
880 | case SNDRV_CTL_POWER_D2: | ||
881 | break; | ||
882 | case SNDRV_CTL_POWER_D3hot: | ||
883 | /* | ||
884 | * all power is driven by DAPM system, | ||
885 | * so output power is safe if bypass was set | ||
886 | */ | ||
887 | if (aic3x->master) { | ||
888 | /* disable pll */ | ||
889 | reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); | ||
890 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, | ||
891 | reg & ~PLL_ENABLE); | ||
892 | } | ||
893 | break; | ||
894 | case SNDRV_CTL_POWER_D3cold: | ||
895 | /* force all power off */ | ||
896 | reg = aic3x_read_reg_cache(codec, LINE1L_2_LADC_CTRL); | ||
897 | aic3x_write(codec, LINE1L_2_LADC_CTRL, reg & ~LADC_PWR_ON); | ||
898 | reg = aic3x_read_reg_cache(codec, LINE1R_2_RADC_CTRL); | ||
899 | aic3x_write(codec, LINE1R_2_RADC_CTRL, reg & ~RADC_PWR_ON); | ||
900 | |||
901 | reg = aic3x_read_reg_cache(codec, DAC_PWR); | ||
902 | aic3x_write(codec, DAC_PWR, reg & ~(LDAC_PWR_ON | RDAC_PWR_ON)); | ||
903 | |||
904 | reg = aic3x_read_reg_cache(codec, HPLOUT_CTRL); | ||
905 | aic3x_write(codec, HPLOUT_CTRL, reg & ~HPLOUT_PWR_ON); | ||
906 | reg = aic3x_read_reg_cache(codec, HPROUT_CTRL); | ||
907 | aic3x_write(codec, HPROUT_CTRL, reg & ~HPROUT_PWR_ON); | ||
908 | |||
909 | reg = aic3x_read_reg_cache(codec, HPLCOM_CTRL); | ||
910 | aic3x_write(codec, HPLCOM_CTRL, reg & ~HPLCOM_PWR_ON); | ||
911 | reg = aic3x_read_reg_cache(codec, HPRCOM_CTRL); | ||
912 | aic3x_write(codec, HPRCOM_CTRL, reg & ~HPRCOM_PWR_ON); | ||
913 | |||
914 | reg = aic3x_read_reg_cache(codec, MONOLOPM_CTRL); | ||
915 | aic3x_write(codec, MONOLOPM_CTRL, reg & ~MONOLOPM_PWR_ON); | ||
916 | |||
917 | reg = aic3x_read_reg_cache(codec, LLOPM_CTRL); | ||
918 | aic3x_write(codec, LLOPM_CTRL, reg & ~LLOPM_PWR_ON); | ||
919 | reg = aic3x_read_reg_cache(codec, RLOPM_CTRL); | ||
920 | aic3x_write(codec, RLOPM_CTRL, reg & ~RLOPM_PWR_ON); | ||
921 | |||
922 | if (aic3x->master) { | ||
923 | /* disable pll */ | ||
924 | reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); | ||
925 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, | ||
926 | reg & ~PLL_ENABLE); | ||
927 | } | ||
928 | break; | ||
929 | } | ||
930 | codec->dapm_state = event; | ||
931 | |||
932 | return 0; | ||
933 | } | ||
934 | |||
935 | #define AIC3X_RATES SNDRV_PCM_RATE_8000_96000 | ||
936 | #define AIC3X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ | ||
937 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) | ||
938 | |||
939 | struct snd_soc_codec_dai aic3x_dai = { | ||
940 | .name = "aic3x", | ||
941 | .playback = { | ||
942 | .stream_name = "Playback", | ||
943 | .channels_min = 1, | ||
944 | .channels_max = 2, | ||
945 | .rates = AIC3X_RATES, | ||
946 | .formats = AIC3X_FORMATS,}, | ||
947 | .capture = { | ||
948 | .stream_name = "Capture", | ||
949 | .channels_min = 1, | ||
950 | .channels_max = 2, | ||
951 | .rates = AIC3X_RATES, | ||
952 | .formats = AIC3X_FORMATS,}, | ||
953 | .ops = { | ||
954 | .hw_params = aic3x_hw_params, | ||
955 | }, | ||
956 | .dai_ops = { | ||
957 | .digital_mute = aic3x_mute, | ||
958 | .set_sysclk = aic3x_set_dai_sysclk, | ||
959 | .set_fmt = aic3x_set_dai_fmt, | ||
960 | } | ||
961 | }; | ||
962 | EXPORT_SYMBOL_GPL(aic3x_dai); | ||
963 | |||
964 | static int aic3x_suspend(struct platform_device *pdev, pm_message_t state) | ||
965 | { | ||
966 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
967 | struct snd_soc_codec *codec = socdev->codec; | ||
968 | |||
969 | aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | ||
970 | |||
971 | return 0; | ||
972 | } | ||
973 | |||
974 | static int aic3x_resume(struct platform_device *pdev) | ||
975 | { | ||
976 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
977 | struct snd_soc_codec *codec = socdev->codec; | ||
978 | int i; | ||
979 | u8 data[2]; | ||
980 | u8 *cache = codec->reg_cache; | ||
981 | |||
982 | /* Sync reg_cache with the hardware */ | ||
983 | for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++) { | ||
984 | data[0] = i; | ||
985 | data[1] = cache[i]; | ||
986 | codec->hw_write(codec->control_data, data, 2); | ||
987 | } | ||
988 | |||
989 | aic3x_dapm_event(codec, codec->suspend_dapm_state); | ||
990 | |||
991 | return 0; | ||
992 | } | ||
993 | |||
994 | /* | ||
995 | * initialise the AIC3X driver | ||
996 | * register the mixer and dsp interfaces with the kernel | ||
997 | */ | ||
998 | static int aic3x_init(struct snd_soc_device *socdev) | ||
999 | { | ||
1000 | struct snd_soc_codec *codec = socdev->codec; | ||
1001 | int reg, ret = 0; | ||
1002 | |||
1003 | codec->name = "aic3x"; | ||
1004 | codec->owner = THIS_MODULE; | ||
1005 | codec->read = aic3x_read_reg_cache; | ||
1006 | codec->write = aic3x_write; | ||
1007 | codec->dapm_event = aic3x_dapm_event; | ||
1008 | codec->dai = &aic3x_dai; | ||
1009 | codec->num_dai = 1; | ||
1010 | codec->reg_cache_size = sizeof(aic3x_reg); | ||
1011 | codec->reg_cache = kmemdup(aic3x_reg, sizeof(aic3x_reg), GFP_KERNEL); | ||
1012 | if (codec->reg_cache == NULL) | ||
1013 | return -ENOMEM; | ||
1014 | |||
1015 | aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT); | ||
1016 | aic3x_write(codec, AIC3X_RESET, SOFT_RESET); | ||
1017 | |||
1018 | /* register pcms */ | ||
1019 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
1020 | if (ret < 0) { | ||
1021 | printk(KERN_ERR "aic3x: failed to create pcms\n"); | ||
1022 | goto pcm_err; | ||
1023 | } | ||
1024 | |||
1025 | /* DAC default volume and mute */ | ||
1026 | aic3x_write(codec, LDAC_VOL, DEFAULT_VOL | MUTE_ON); | ||
1027 | aic3x_write(codec, RDAC_VOL, DEFAULT_VOL | MUTE_ON); | ||
1028 | |||
1029 | /* DAC to HP default volume and route to Output mixer */ | ||
1030 | aic3x_write(codec, DACL1_2_HPLOUT_VOL, DEFAULT_VOL | ROUTE_ON); | ||
1031 | aic3x_write(codec, DACR1_2_HPROUT_VOL, DEFAULT_VOL | ROUTE_ON); | ||
1032 | aic3x_write(codec, DACL1_2_HPLCOM_VOL, DEFAULT_VOL | ROUTE_ON); | ||
1033 | aic3x_write(codec, DACR1_2_HPRCOM_VOL, DEFAULT_VOL | ROUTE_ON); | ||
1034 | /* DAC to Line Out default volume and route to Output mixer */ | ||
1035 | aic3x_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON); | ||
1036 | aic3x_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON); | ||
1037 | /* DAC to Mono Line Out default volume and route to Output mixer */ | ||
1038 | aic3x_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON); | ||
1039 | aic3x_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON); | ||
1040 | |||
1041 | /* unmute all outputs */ | ||
1042 | reg = aic3x_read_reg_cache(codec, LLOPM_CTRL); | ||
1043 | aic3x_write(codec, LLOPM_CTRL, reg | UNMUTE); | ||
1044 | reg = aic3x_read_reg_cache(codec, RLOPM_CTRL); | ||
1045 | aic3x_write(codec, RLOPM_CTRL, reg | UNMUTE); | ||
1046 | reg = aic3x_read_reg_cache(codec, MONOLOPM_CTRL); | ||
1047 | aic3x_write(codec, MONOLOPM_CTRL, reg | UNMUTE); | ||
1048 | reg = aic3x_read_reg_cache(codec, HPLOUT_CTRL); | ||
1049 | aic3x_write(codec, HPLOUT_CTRL, reg | UNMUTE); | ||
1050 | reg = aic3x_read_reg_cache(codec, HPROUT_CTRL); | ||
1051 | aic3x_write(codec, HPROUT_CTRL, reg | UNMUTE); | ||
1052 | reg = aic3x_read_reg_cache(codec, HPLCOM_CTRL); | ||
1053 | aic3x_write(codec, HPLCOM_CTRL, reg | UNMUTE); | ||
1054 | reg = aic3x_read_reg_cache(codec, HPRCOM_CTRL); | ||
1055 | aic3x_write(codec, HPRCOM_CTRL, reg | UNMUTE); | ||
1056 | |||
1057 | /* ADC default volume and unmute */ | ||
1058 | aic3x_write(codec, LADC_VOL, DEFAULT_GAIN); | ||
1059 | aic3x_write(codec, RADC_VOL, DEFAULT_GAIN); | ||
1060 | /* By default route Line1 to ADC PGA mixer */ | ||
1061 | aic3x_write(codec, LINE1L_2_LADC_CTRL, 0x0); | ||
1062 | aic3x_write(codec, LINE1R_2_RADC_CTRL, 0x0); | ||
1063 | |||
1064 | /* PGA to HP Bypass default volume, disconnect from Output Mixer */ | ||
1065 | aic3x_write(codec, PGAL_2_HPLOUT_VOL, DEFAULT_VOL); | ||
1066 | aic3x_write(codec, PGAR_2_HPROUT_VOL, DEFAULT_VOL); | ||
1067 | aic3x_write(codec, PGAL_2_HPLCOM_VOL, DEFAULT_VOL); | ||
1068 | aic3x_write(codec, PGAR_2_HPRCOM_VOL, DEFAULT_VOL); | ||
1069 | /* PGA to Line Out default volume, disconnect from Output Mixer */ | ||
1070 | aic3x_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL); | ||
1071 | aic3x_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL); | ||
1072 | /* PGA to Mono Line Out default volume, disconnect from Output Mixer */ | ||
1073 | aic3x_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL); | ||
1074 | aic3x_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL); | ||
1075 | |||
1076 | /* Line2 to HP Bypass default volume, disconnect from Output Mixer */ | ||
1077 | aic3x_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL); | ||
1078 | aic3x_write(codec, LINE2R_2_HPROUT_VOL, DEFAULT_VOL); | ||
1079 | aic3x_write(codec, LINE2L_2_HPLCOM_VOL, DEFAULT_VOL); | ||
1080 | aic3x_write(codec, LINE2R_2_HPRCOM_VOL, DEFAULT_VOL); | ||
1081 | /* Line2 Line Out default volume, disconnect from Output Mixer */ | ||
1082 | aic3x_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL); | ||
1083 | aic3x_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL); | ||
1084 | /* Line2 to Mono Out default volume, disconnect from Output Mixer */ | ||
1085 | aic3x_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL); | ||
1086 | aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); | ||
1087 | |||
1088 | /* off, with power on */ | ||
1089 | aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | ||
1090 | |||
1091 | aic3x_add_controls(codec); | ||
1092 | aic3x_add_widgets(codec); | ||
1093 | ret = snd_soc_register_card(socdev); | ||
1094 | if (ret < 0) { | ||
1095 | printk(KERN_ERR "aic3x: failed to register card\n"); | ||
1096 | goto card_err; | ||
1097 | } | ||
1098 | |||
1099 | return ret; | ||
1100 | |||
1101 | card_err: | ||
1102 | snd_soc_free_pcms(socdev); | ||
1103 | snd_soc_dapm_free(socdev); | ||
1104 | pcm_err: | ||
1105 | kfree(codec->reg_cache); | ||
1106 | return ret; | ||
1107 | } | ||
1108 | |||
1109 | static struct snd_soc_device *aic3x_socdev; | ||
1110 | |||
1111 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1112 | /* | ||
1113 | * AIC3X 2 wire address can be up to 4 devices with device addresses | ||
1114 | * 0x18, 0x19, 0x1A, 0x1B | ||
1115 | */ | ||
1116 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
1117 | |||
1118 | /* Magic definition of all other variables and things */ | ||
1119 | I2C_CLIENT_INSMOD; | ||
1120 | |||
1121 | static struct i2c_driver aic3x_i2c_driver; | ||
1122 | static struct i2c_client client_template; | ||
1123 | |||
1124 | /* | ||
1125 | * If the i2c layer weren't so broken, we could pass this kind of data | ||
1126 | * around | ||
1127 | */ | ||
1128 | static int aic3x_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
1129 | { | ||
1130 | struct snd_soc_device *socdev = aic3x_socdev; | ||
1131 | struct aic3x_setup_data *setup = socdev->codec_data; | ||
1132 | struct snd_soc_codec *codec = socdev->codec; | ||
1133 | struct i2c_client *i2c; | ||
1134 | int ret; | ||
1135 | |||
1136 | if (addr != setup->i2c_address) | ||
1137 | return -ENODEV; | ||
1138 | |||
1139 | client_template.adapter = adap; | ||
1140 | client_template.addr = addr; | ||
1141 | |||
1142 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
1143 | if (i2c == NULL) { | ||
1144 | kfree(codec); | ||
1145 | return -ENOMEM; | ||
1146 | } | ||
1147 | i2c_set_clientdata(i2c, codec); | ||
1148 | codec->control_data = i2c; | ||
1149 | |||
1150 | ret = i2c_attach_client(i2c); | ||
1151 | if (ret < 0) { | ||
1152 | printk(KERN_ERR "aic3x: failed to attach codec at addr %x\n", | ||
1153 | addr); | ||
1154 | goto err; | ||
1155 | } | ||
1156 | |||
1157 | ret = aic3x_init(socdev); | ||
1158 | if (ret < 0) { | ||
1159 | printk(KERN_ERR "aic3x: failed to initialise AIC3X\n"); | ||
1160 | goto err; | ||
1161 | } | ||
1162 | return ret; | ||
1163 | |||
1164 | err: | ||
1165 | kfree(codec); | ||
1166 | kfree(i2c); | ||
1167 | return ret; | ||
1168 | } | ||
1169 | |||
1170 | static int aic3x_i2c_detach(struct i2c_client *client) | ||
1171 | { | ||
1172 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
1173 | i2c_detach_client(client); | ||
1174 | kfree(codec->reg_cache); | ||
1175 | kfree(client); | ||
1176 | return 0; | ||
1177 | } | ||
1178 | |||
1179 | static int aic3x_i2c_attach(struct i2c_adapter *adap) | ||
1180 | { | ||
1181 | return i2c_probe(adap, &addr_data, aic3x_codec_probe); | ||
1182 | } | ||
1183 | |||
1184 | /* machine i2c codec control layer */ | ||
1185 | static struct i2c_driver aic3x_i2c_driver = { | ||
1186 | .driver = { | ||
1187 | .name = "aic3x I2C Codec", | ||
1188 | .owner = THIS_MODULE, | ||
1189 | }, | ||
1190 | .id = I2C_DRIVERID_I2CDEV, | ||
1191 | .attach_adapter = aic3x_i2c_attach, | ||
1192 | .detach_client = aic3x_i2c_detach, | ||
1193 | .command = NULL, | ||
1194 | }; | ||
1195 | |||
1196 | static struct i2c_client client_template = { | ||
1197 | .name = "AIC3X", | ||
1198 | .driver = &aic3x_i2c_driver, | ||
1199 | }; | ||
1200 | #endif | ||
1201 | |||
1202 | static int aic3x_probe(struct platform_device *pdev) | ||
1203 | { | ||
1204 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1205 | struct aic3x_setup_data *setup; | ||
1206 | struct snd_soc_codec *codec; | ||
1207 | struct aic3x_priv *aic3x; | ||
1208 | int ret = 0; | ||
1209 | |||
1210 | printk(KERN_INFO "AIC3X Audio Codec %s\n", AIC3X_VERSION); | ||
1211 | |||
1212 | setup = socdev->codec_data; | ||
1213 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
1214 | if (codec == NULL) | ||
1215 | return -ENOMEM; | ||
1216 | |||
1217 | aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL); | ||
1218 | if (aic3x == NULL) { | ||
1219 | kfree(codec); | ||
1220 | return -ENOMEM; | ||
1221 | } | ||
1222 | |||
1223 | codec->private_data = aic3x; | ||
1224 | socdev->codec = codec; | ||
1225 | mutex_init(&codec->mutex); | ||
1226 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
1227 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
1228 | |||
1229 | aic3x_socdev = socdev; | ||
1230 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1231 | if (setup->i2c_address) { | ||
1232 | normal_i2c[0] = setup->i2c_address; | ||
1233 | codec->hw_write = (hw_write_t) i2c_master_send; | ||
1234 | ret = i2c_add_driver(&aic3x_i2c_driver); | ||
1235 | if (ret != 0) | ||
1236 | printk(KERN_ERR "can't add i2c driver"); | ||
1237 | } | ||
1238 | #else | ||
1239 | /* Add other interfaces here */ | ||
1240 | #endif | ||
1241 | return ret; | ||
1242 | } | ||
1243 | |||
1244 | static int aic3x_remove(struct platform_device *pdev) | ||
1245 | { | ||
1246 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1247 | struct snd_soc_codec *codec = socdev->codec; | ||
1248 | |||
1249 | /* power down chip */ | ||
1250 | if (codec->control_data) | ||
1251 | aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3); | ||
1252 | |||
1253 | snd_soc_free_pcms(socdev); | ||
1254 | snd_soc_dapm_free(socdev); | ||
1255 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1256 | i2c_del_driver(&aic3x_i2c_driver); | ||
1257 | #endif | ||
1258 | kfree(codec->private_data); | ||
1259 | kfree(codec); | ||
1260 | |||
1261 | return 0; | ||
1262 | } | ||
1263 | |||
1264 | struct snd_soc_codec_device soc_codec_dev_aic3x = { | ||
1265 | .probe = aic3x_probe, | ||
1266 | .remove = aic3x_remove, | ||
1267 | .suspend = aic3x_suspend, | ||
1268 | .resume = aic3x_resume, | ||
1269 | }; | ||
1270 | EXPORT_SYMBOL_GPL(soc_codec_dev_aic3x); | ||
1271 | |||
1272 | MODULE_DESCRIPTION("ASoC TLV320AIC3X codec driver"); | ||
1273 | MODULE_AUTHOR("Vladimir Barinov"); | ||
1274 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h new file mode 100644 index 000000000000..d0cdeeb629de --- /dev/null +++ b/sound/soc/codecs/tlv320aic3x.h | |||
@@ -0,0 +1,181 @@ | |||
1 | /* | ||
2 | * ALSA SoC TLV320AIC3X codec driver | ||
3 | * | ||
4 | * Author: Vladimir Barinov, <vbarinov@ru.mvista.com> | ||
5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef _AIC3X_H | ||
13 | #define _AIC3X_H | ||
14 | |||
15 | /* AIC3X register space */ | ||
16 | #define AIC3X_CACHEREGNUM 103 | ||
17 | |||
18 | /* Page select register */ | ||
19 | #define AIC3X_PAGE_SELECT 0 | ||
20 | /* Software reset register */ | ||
21 | #define AIC3X_RESET 1 | ||
22 | /* Codec Sample rate select register */ | ||
23 | #define AIC3X_SAMPLE_RATE_SEL_REG 2 | ||
24 | /* PLL progrramming register A */ | ||
25 | #define AIC3X_PLL_PROGA_REG 3 | ||
26 | /* PLL progrramming register B */ | ||
27 | #define AIC3X_PLL_PROGB_REG 4 | ||
28 | /* PLL progrramming register C */ | ||
29 | #define AIC3X_PLL_PROGC_REG 5 | ||
30 | /* PLL progrramming register D */ | ||
31 | #define AIC3X_PLL_PROGD_REG 6 | ||
32 | /* Codec datapath setup register */ | ||
33 | #define AIC3X_CODEC_DATAPATH_REG 7 | ||
34 | /* Audio serial data interface control register A */ | ||
35 | #define AIC3X_ASD_INTF_CTRLA 8 | ||
36 | /* Audio serial data interface control register B */ | ||
37 | #define AIC3X_ASD_INTF_CTRLB 9 | ||
38 | /* Audio overflow status and PLL R value programming register */ | ||
39 | #define AIC3X_OVRF_STATUS_AND_PLLR_REG 11 | ||
40 | |||
41 | /* ADC PGA Gain control registers */ | ||
42 | #define LADC_VOL 15 | ||
43 | #define RADC_VOL 16 | ||
44 | /* MIC3 control registers */ | ||
45 | #define MIC3LR_2_LADC_CTRL 17 | ||
46 | #define MIC3LR_2_RADC_CTRL 18 | ||
47 | /* Line1 Input control registers */ | ||
48 | #define LINE1L_2_LADC_CTRL 19 | ||
49 | #define LINE1R_2_RADC_CTRL 22 | ||
50 | /* Line2 Input control registers */ | ||
51 | #define LINE2L_2_LADC_CTRL 20 | ||
52 | #define LINE2R_2_RADC_CTRL 23 | ||
53 | /* MICBIAS Control Register */ | ||
54 | #define MICBIAS_CTRL 25 | ||
55 | |||
56 | /* AGC Control Registers A, B, C */ | ||
57 | #define LAGC_CTRL_A 26 | ||
58 | #define LAGC_CTRL_B 27 | ||
59 | #define LAGC_CTRL_C 28 | ||
60 | #define RAGC_CTRL_A 29 | ||
61 | #define RAGC_CTRL_B 30 | ||
62 | #define RAGC_CTRL_C 31 | ||
63 | |||
64 | /* DAC Power and Left High Power Output control registers */ | ||
65 | #define DAC_PWR 37 | ||
66 | #define HPLCOM_CFG 37 | ||
67 | /* Right High Power Output control registers */ | ||
68 | #define HPRCOM_CFG 38 | ||
69 | /* DAC Output Switching control registers */ | ||
70 | #define DAC_LINE_MUX 41 | ||
71 | /* High Power Output Driver Pop Reduction registers */ | ||
72 | #define HPOUT_POP_REDUCTION 42 | ||
73 | /* DAC Digital control registers */ | ||
74 | #define LDAC_VOL 43 | ||
75 | #define RDAC_VOL 44 | ||
76 | /* High Power Output control registers */ | ||
77 | #define LINE2L_2_HPLOUT_VOL 45 | ||
78 | #define LINE2R_2_HPROUT_VOL 62 | ||
79 | #define PGAL_2_HPLOUT_VOL 46 | ||
80 | #define PGAR_2_HPROUT_VOL 63 | ||
81 | #define DACL1_2_HPLOUT_VOL 47 | ||
82 | #define DACR1_2_HPROUT_VOL 64 | ||
83 | #define HPLOUT_CTRL 51 | ||
84 | #define HPROUT_CTRL 65 | ||
85 | /* High Power COM control registers */ | ||
86 | #define LINE2L_2_HPLCOM_VOL 52 | ||
87 | #define LINE2R_2_HPRCOM_VOL 69 | ||
88 | #define PGAL_2_HPLCOM_VOL 53 | ||
89 | #define PGAR_2_HPRCOM_VOL 70 | ||
90 | #define DACL1_2_HPLCOM_VOL 54 | ||
91 | #define DACR1_2_HPRCOM_VOL 71 | ||
92 | #define HPLCOM_CTRL 58 | ||
93 | #define HPRCOM_CTRL 72 | ||
94 | /* Mono Line Output Plus/Minus control registers */ | ||
95 | #define LINE2L_2_MONOLOPM_VOL 73 | ||
96 | #define LINE2R_2_MONOLOPM_VOL 76 | ||
97 | #define PGAL_2_MONOLOPM_VOL 74 | ||
98 | #define PGAR_2_MONOLOPM_VOL 77 | ||
99 | #define DACL1_2_MONOLOPM_VOL 75 | ||
100 | #define DACR1_2_MONOLOPM_VOL 78 | ||
101 | #define MONOLOPM_CTRL 79 | ||
102 | /* Line Output Plus/Minus control registers */ | ||
103 | #define LINE2L_2_LLOPM_VOL 80 | ||
104 | #define LINE2R_2_RLOPM_VOL 90 | ||
105 | #define PGAL_2_LLOPM_VOL 81 | ||
106 | #define PGAR_2_RLOPM_VOL 91 | ||
107 | #define DACL1_2_LLOPM_VOL 82 | ||
108 | #define DACR1_2_RLOPM_VOL 92 | ||
109 | #define LLOPM_CTRL 86 | ||
110 | #define RLOPM_CTRL 93 | ||
111 | /* Clock generation control register */ | ||
112 | #define AIC3X_CLKGEN_CTRL_REG 102 | ||
113 | |||
114 | /* Page select register bits */ | ||
115 | #define PAGE0_SELECT 0 | ||
116 | #define PAGE1_SELECT 1 | ||
117 | |||
118 | /* Audio serial data interface control register A bits */ | ||
119 | #define BIT_CLK_MASTER 0x80 | ||
120 | #define WORD_CLK_MASTER 0x40 | ||
121 | |||
122 | /* Codec Datapath setup register 7 */ | ||
123 | #define FSREF_44100 (1 << 7) | ||
124 | #define FSREF_48000 (0 << 7) | ||
125 | #define DUAL_RATE_MODE ((1 << 5) | (1 << 6)) | ||
126 | #define LDAC2LCH (0x1 << 3) | ||
127 | #define RDAC2RCH (0x1 << 1) | ||
128 | |||
129 | /* PLL registers bitfields */ | ||
130 | #define PLLP_SHIFT 0 | ||
131 | #define PLLR_SHIFT 0 | ||
132 | #define PLLJ_SHIFT 2 | ||
133 | #define PLLD_MSB_SHIFT 0 | ||
134 | #define PLLD_LSB_SHIFT 2 | ||
135 | |||
136 | /* Clock generation register bits */ | ||
137 | #define PLL_CLKIN_SHIFT 4 | ||
138 | #define MCLK_SOURCE 0x0 | ||
139 | #define PLL_CLKDIV_SHIFT 0 | ||
140 | |||
141 | /* Software reset register bits */ | ||
142 | #define SOFT_RESET 0x80 | ||
143 | |||
144 | /* PLL progrramming register A bits */ | ||
145 | #define PLL_ENABLE 0x80 | ||
146 | |||
147 | /* Route bits */ | ||
148 | #define ROUTE_ON 0x80 | ||
149 | |||
150 | /* Mute bits */ | ||
151 | #define UNMUTE 0x08 | ||
152 | #define MUTE_ON 0x80 | ||
153 | |||
154 | /* Power bits */ | ||
155 | #define LADC_PWR_ON 0x04 | ||
156 | #define RADC_PWR_ON 0x04 | ||
157 | #define LDAC_PWR_ON 0x80 | ||
158 | #define RDAC_PWR_ON 0x40 | ||
159 | #define HPLOUT_PWR_ON 0x01 | ||
160 | #define HPROUT_PWR_ON 0x01 | ||
161 | #define HPLCOM_PWR_ON 0x01 | ||
162 | #define HPRCOM_PWR_ON 0x01 | ||
163 | #define MONOLOPM_PWR_ON 0x01 | ||
164 | #define LLOPM_PWR_ON 0x01 | ||
165 | #define RLOPM_PWR_ON 0x01 | ||
166 | |||
167 | #define INVERT_VOL(val) (0x7f - val) | ||
168 | |||
169 | /* Default output volume (inverted) */ | ||
170 | #define DEFAULT_VOL INVERT_VOL(0x50) | ||
171 | /* Default input volume */ | ||
172 | #define DEFAULT_GAIN 0x20 | ||
173 | |||
174 | struct aic3x_setup_data { | ||
175 | unsigned short i2c_address; | ||
176 | }; | ||
177 | |||
178 | extern struct snd_soc_codec_dai aic3x_dai; | ||
179 | extern struct snd_soc_codec_device soc_codec_dev_aic3x; | ||
180 | |||
181 | #endif /* _AIC3X_H */ | ||
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 7ca0b5268289..9c33fe874928 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c | |||
@@ -19,7 +19,6 @@ | |||
19 | #include <linux/pm.h> | 19 | #include <linux/pm.h> |
20 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <sound/driver.h> | ||
23 | #include <sound/core.h> | 22 | #include <sound/core.h> |
24 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
25 | #include <sound/pcm_params.h> | 24 | #include <sound/pcm_params.h> |
@@ -562,13 +561,13 @@ static int wm8731_init(struct snd_soc_device *socdev) | |||
562 | 561 | ||
563 | /* set the update bits */ | 562 | /* set the update bits */ |
564 | reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V); | 563 | reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V); |
565 | wm8731_write(codec, WM8731_LOUT1V, reg | 0x0100); | 564 | wm8731_write(codec, WM8731_LOUT1V, reg & ~0x0100); |
566 | reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V); | 565 | reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V); |
567 | wm8731_write(codec, WM8731_ROUT1V, reg | 0x0100); | 566 | wm8731_write(codec, WM8731_ROUT1V, reg & ~0x0100); |
568 | reg = wm8731_read_reg_cache(codec, WM8731_LINVOL); | 567 | reg = wm8731_read_reg_cache(codec, WM8731_LINVOL); |
569 | wm8731_write(codec, WM8731_LINVOL, reg | 0x0100); | 568 | wm8731_write(codec, WM8731_LINVOL, reg & ~0x0100); |
570 | reg = wm8731_read_reg_cache(codec, WM8731_RINVOL); | 569 | reg = wm8731_read_reg_cache(codec, WM8731_RINVOL); |
571 | wm8731_write(codec, WM8731_RINVOL, reg | 0x0100); | 570 | wm8731_write(codec, WM8731_RINVOL, reg & ~0x0100); |
572 | 571 | ||
573 | wm8731_add_controls(codec); | 572 | wm8731_add_controls(codec); |
574 | wm8731_add_widgets(codec); | 573 | wm8731_add_widgets(codec); |
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 28684eeda738..77a857b997a2 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c | |||
@@ -19,7 +19,6 @@ | |||
19 | #include <linux/pm.h> | 19 | #include <linux/pm.h> |
20 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <sound/driver.h> | ||
23 | #include <sound/core.h> | 22 | #include <sound/core.h> |
24 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
25 | #include <sound/pcm_params.h> | 24 | #include <sound/pcm_params.h> |
@@ -189,7 +188,7 @@ SOC_ENUM("Bass Boost", wm8750_enum[0]), | |||
189 | SOC_ENUM("Bass Filter", wm8750_enum[1]), | 188 | SOC_ENUM("Bass Filter", wm8750_enum[1]), |
190 | SOC_SINGLE("Bass Volume", WM8750_BASS, 0, 15, 1), | 189 | SOC_SINGLE("Bass Volume", WM8750_BASS, 0, 15, 1), |
191 | 190 | ||
192 | SOC_SINGLE("Treble Volume", WM8750_TREBLE, 0, 15, 0), | 191 | SOC_SINGLE("Treble Volume", WM8750_TREBLE, 0, 15, 1), |
193 | SOC_ENUM("Treble Cut-off", wm8750_enum[2]), | 192 | SOC_ENUM("Treble Cut-off", wm8750_enum[2]), |
194 | 193 | ||
195 | SOC_SINGLE("3D Switch", WM8750_3D, 0, 1, 0), | 194 | SOC_SINGLE("3D Switch", WM8750_3D, 0, 1, 0), |
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index efced934566d..ddd9c71b3fde 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
@@ -41,13 +41,13 @@ | |||
41 | #include <linux/pm.h> | 41 | #include <linux/pm.h> |
42 | #include <linux/i2c.h> | 42 | #include <linux/i2c.h> |
43 | #include <linux/platform_device.h> | 43 | #include <linux/platform_device.h> |
44 | #include <sound/driver.h> | ||
45 | #include <sound/core.h> | 44 | #include <sound/core.h> |
46 | #include <sound/pcm.h> | 45 | #include <sound/pcm.h> |
47 | #include <sound/pcm_params.h> | 46 | #include <sound/pcm_params.h> |
48 | #include <sound/soc.h> | 47 | #include <sound/soc.h> |
49 | #include <sound/soc-dapm.h> | 48 | #include <sound/soc-dapm.h> |
50 | #include <sound/initval.h> | 49 | #include <sound/initval.h> |
50 | #include <sound/tlv.h> | ||
51 | #include <asm/div64.h> | 51 | #include <asm/div64.h> |
52 | 52 | ||
53 | #include "wm8753.h" | 53 | #include "wm8753.h" |
@@ -258,6 +258,8 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol, | |||
258 | return 1; | 258 | return 1; |
259 | } | 259 | } |
260 | 260 | ||
261 | static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600); | ||
262 | |||
261 | static const struct snd_kcontrol_new wm8753_snd_controls[] = { | 263 | static const struct snd_kcontrol_new wm8753_snd_controls[] = { |
262 | SOC_DOUBLE_R("PCM Volume", WM8753_LDAC, WM8753_RDAC, 0, 255, 0), | 264 | SOC_DOUBLE_R("PCM Volume", WM8753_LDAC, WM8753_RDAC, 0, 255, 0), |
263 | 265 | ||
@@ -287,8 +289,8 @@ SOC_SINGLE("Bass Volume", WM8753_BASS, 0, 15, 1), | |||
287 | SOC_SINGLE("Treble Volume", WM8753_TREBLE, 0, 15, 1), | 289 | SOC_SINGLE("Treble Volume", WM8753_TREBLE, 0, 15, 1), |
288 | SOC_ENUM("Treble Cut-off", wm8753_enum[2]), | 290 | SOC_ENUM("Treble Cut-off", wm8753_enum[2]), |
289 | 291 | ||
290 | SOC_DOUBLE("Sidetone Capture Volume", WM8753_RECMIX1, 0, 4, 7, 1), | 292 | SOC_DOUBLE_TLV("Sidetone Capture Volume", WM8753_RECMIX1, 0, 4, 7, 1, rec_mix_tlv), |
291 | SOC_SINGLE("Voice Sidetone Capture Volume", WM8753_RECMIX2, 0, 7, 1), | 293 | SOC_SINGLE_TLV("Voice Sidetone Capture Volume", WM8753_RECMIX2, 0, 7, 1, rec_mix_tlv), |
292 | 294 | ||
293 | SOC_DOUBLE_R("Capture Volume", WM8753_LINVOL, WM8753_RINVOL, 0, 63, 0), | 295 | SOC_DOUBLE_R("Capture Volume", WM8753_LINVOL, WM8753_RINVOL, 0, 63, 0), |
294 | SOC_DOUBLE_R("Capture ZC Switch", WM8753_LINVOL, WM8753_RINVOL, 6, 1, 0), | 296 | SOC_DOUBLE_R("Capture ZC Switch", WM8753_LINVOL, WM8753_RINVOL, 6, 1, 0), |
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 986b5d59cefa..590baea3c4c3 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c | |||
@@ -19,7 +19,6 @@ | |||
19 | #include <linux/version.h> | 19 | #include <linux/version.h> |
20 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
21 | #include <linux/device.h> | 21 | #include <linux/device.h> |
22 | #include <sound/driver.h> | ||
23 | #include <sound/core.h> | 22 | #include <sound/core.h> |
24 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
25 | #include <sound/ac97_codec.h> | 24 | #include <sound/ac97_codec.h> |
@@ -102,7 +101,8 @@ SOC_SINGLE("Speaker Playback ZC Switch", AC97_MASTER, 7, 1, 0), | |||
102 | SOC_SINGLE("Speaker Playback Invert Switch", AC97_MASTER, 6, 1, 0), | 101 | SOC_SINGLE("Speaker Playback Invert Switch", AC97_MASTER, 6, 1, 0), |
103 | SOC_SINGLE("Headphone Playback ZC Switch", AC97_HEADPHONE, 7, 1, 0), | 102 | SOC_SINGLE("Headphone Playback ZC Switch", AC97_HEADPHONE, 7, 1, 0), |
104 | SOC_SINGLE("Mono Playback ZC Switch", AC97_MASTER_MONO, 7, 1, 0), | 103 | SOC_SINGLE("Mono Playback ZC Switch", AC97_MASTER_MONO, 7, 1, 0), |
105 | SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 0), | 104 | SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 1), |
105 | SOC_SINGLE("Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1), | ||
106 | 106 | ||
107 | SOC_SINGLE("ALC Target Volume", AC97_CODEC_CLASS_REV, 12, 15, 0), | 107 | SOC_SINGLE("ALC Target Volume", AC97_CODEC_CLASS_REV, 12, 15, 0), |
108 | SOC_SINGLE("ALC Hold Time", AC97_CODEC_CLASS_REV, 8, 15, 0), | 108 | SOC_SINGLE("ALC Hold Time", AC97_CODEC_CLASS_REV, 8, 15, 0), |
@@ -131,7 +131,7 @@ SOC_SINGLE("Aux Playback Headphone Volume", AC97_CD, 12, 7, 1), | |||
131 | SOC_SINGLE("Aux Playback Speaker Volume", AC97_CD, 8, 7, 1), | 131 | SOC_SINGLE("Aux Playback Speaker Volume", AC97_CD, 8, 7, 1), |
132 | SOC_SINGLE("Aux Playback Phone Volume", AC97_CD, 4, 7, 1), | 132 | SOC_SINGLE("Aux Playback Phone Volume", AC97_CD, 4, 7, 1), |
133 | 133 | ||
134 | SOC_SINGLE("Phone Volume", AC97_PHONE, 0, 15, 0), | 134 | SOC_SINGLE("Phone Volume", AC97_PHONE, 0, 15, 1), |
135 | SOC_DOUBLE("Line Capture Volume", AC97_LINE, 8, 0, 31, 1), | 135 | SOC_DOUBLE("Line Capture Volume", AC97_LINE, 8, 0, 31, 1), |
136 | 136 | ||
137 | SOC_SINGLE("Capture 20dB Boost Switch", AC97_REC_SEL, 14, 1, 0), | 137 | SOC_SINGLE("Capture 20dB Boost Switch", AC97_REC_SEL, 14, 1, 0), |
@@ -145,8 +145,8 @@ SOC_ENUM("Bass Control", wm9712_enum[5]), | |||
145 | SOC_SINGLE("Bass Cut-off Switch", AC97_MASTER_TONE, 12, 1, 1), | 145 | SOC_SINGLE("Bass Cut-off Switch", AC97_MASTER_TONE, 12, 1, 1), |
146 | SOC_SINGLE("Tone Cut-off Switch", AC97_MASTER_TONE, 4, 1, 1), | 146 | SOC_SINGLE("Tone Cut-off Switch", AC97_MASTER_TONE, 4, 1, 1), |
147 | SOC_SINGLE("Playback Attenuate (-6dB) Switch", AC97_MASTER_TONE, 6, 1, 0), | 147 | SOC_SINGLE("Playback Attenuate (-6dB) Switch", AC97_MASTER_TONE, 6, 1, 0), |
148 | SOC_SINGLE("Bass Volume", AC97_MASTER_TONE, 8, 15, 0), | 148 | SOC_SINGLE("Bass Volume", AC97_MASTER_TONE, 8, 15, 1), |
149 | SOC_SINGLE("Treble Volume", AC97_MASTER_TONE, 0, 15, 0), | 149 | SOC_SINGLE("Treble Volume", AC97_MASTER_TONE, 0, 15, 1), |
150 | 150 | ||
151 | SOC_SINGLE("Capture ADC Switch", AC97_REC_GAIN, 15, 1, 1), | 151 | SOC_SINGLE("Capture ADC Switch", AC97_REC_GAIN, 15, 1, 1), |
152 | SOC_ENUM("Capture Volume Steps", wm9712_enum[6]), | 152 | SOC_ENUM("Capture Volume Steps", wm9712_enum[6]), |
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig new file mode 100644 index 000000000000..257101f44e9e --- /dev/null +++ b/sound/soc/fsl/Kconfig | |||
@@ -0,0 +1,20 @@ | |||
1 | menu "ALSA SoC audio for Freescale SOCs" | ||
2 | |||
3 | config SND_SOC_MPC8610 | ||
4 | bool "ALSA SoC support for the MPC8610 SOC" | ||
5 | depends on SND_SOC && MPC8610_HPCD | ||
6 | default y if MPC8610 | ||
7 | help | ||
8 | Say Y if you want to add support for codecs attached to the SSI | ||
9 | device on an MPC8610. | ||
10 | |||
11 | config SND_SOC_MPC8610_HPCD | ||
12 | bool "ALSA SoC support for the Freescale MPC8610 HPCD board" | ||
13 | depends on SND_SOC_MPC8610 | ||
14 | select SND_SOC_CS4270 | ||
15 | select SND_SOC_CS4270_VD33_ERRATA | ||
16 | default y if MPC8610_HPCD | ||
17 | help | ||
18 | Say Y if you want to enable audio on the Freescale MPC8610 HPCD. | ||
19 | |||
20 | endmenu | ||
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile new file mode 100644 index 000000000000..62f680a4a776 --- /dev/null +++ b/sound/soc/fsl/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # MPC8610 HPCD Machine Support | ||
2 | obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += mpc8610_hpcd.o | ||
3 | |||
4 | # MPC8610 Platform Support | ||
5 | obj-$(CONFIG_SND_SOC_MPC8610) += fsl_ssi.o fsl_dma.o | ||
6 | |||
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c new file mode 100644 index 000000000000..652514fc8142 --- /dev/null +++ b/sound/soc/fsl/fsl_dma.c | |||
@@ -0,0 +1,841 @@ | |||
1 | /* | ||
2 | * Freescale DMA ALSA SoC PCM driver | ||
3 | * | ||
4 | * Author: Timur Tabi <timur@freescale.com> | ||
5 | * | ||
6 | * Copyright 2007-2008 Freescale Semiconductor, Inc. This file is licensed | ||
7 | * under the terms of the GNU General Public License version 2. This | ||
8 | * program is licensed "as is" without any warranty of any kind, whether | ||
9 | * express or implied. | ||
10 | * | ||
11 | * This driver implements ASoC support for the Elo DMA controller, which is | ||
12 | * the DMA controller on Freescale 83xx, 85xx, and 86xx SOCs. In ALSA terms, | ||
13 | * the PCM driver is what handles the DMA buffer. | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/dma-mapping.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/delay.h> | ||
22 | |||
23 | #include <sound/driver.h> | ||
24 | #include <sound/core.h> | ||
25 | #include <sound/pcm.h> | ||
26 | #include <sound/pcm_params.h> | ||
27 | #include <sound/soc.h> | ||
28 | |||
29 | #include <asm/io.h> | ||
30 | |||
31 | #include "fsl_dma.h" | ||
32 | |||
33 | /* | ||
34 | * The formats that the DMA controller supports, which is anything | ||
35 | * that is 8, 16, or 32 bits. | ||
36 | */ | ||
37 | #define FSLDMA_PCM_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ | ||
38 | SNDRV_PCM_FMTBIT_U8 | \ | ||
39 | SNDRV_PCM_FMTBIT_S16_LE | \ | ||
40 | SNDRV_PCM_FMTBIT_S16_BE | \ | ||
41 | SNDRV_PCM_FMTBIT_U16_LE | \ | ||
42 | SNDRV_PCM_FMTBIT_U16_BE | \ | ||
43 | SNDRV_PCM_FMTBIT_S24_LE | \ | ||
44 | SNDRV_PCM_FMTBIT_S24_BE | \ | ||
45 | SNDRV_PCM_FMTBIT_U24_LE | \ | ||
46 | SNDRV_PCM_FMTBIT_U24_BE | \ | ||
47 | SNDRV_PCM_FMTBIT_S32_LE | \ | ||
48 | SNDRV_PCM_FMTBIT_S32_BE | \ | ||
49 | SNDRV_PCM_FMTBIT_U32_LE | \ | ||
50 | SNDRV_PCM_FMTBIT_U32_BE) | ||
51 | |||
52 | #define FSLDMA_PCM_RATES (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_192000 | \ | ||
53 | SNDRV_PCM_RATE_CONTINUOUS) | ||
54 | |||
55 | /* DMA global data. This structure is used by fsl_dma_open() to determine | ||
56 | * which DMA channels to assign to a substream. Unfortunately, ASoC V1 does | ||
57 | * not allow the machine driver to provide this information to the PCM | ||
58 | * driver in advance, and there's no way to differentiate between the two | ||
59 | * DMA controllers. So for now, this driver only supports one SSI device | ||
60 | * using two DMA channels. We cannot support multiple DMA devices. | ||
61 | * | ||
62 | * ssi_stx_phys: bus address of SSI STX register | ||
63 | * ssi_srx_phys: bus address of SSI SRX register | ||
64 | * dma_channel: pointer to the DMA channel's registers | ||
65 | * irq: IRQ for this DMA channel | ||
66 | * assigned: set to 1 if that DMA channel is assigned to a substream | ||
67 | */ | ||
68 | static struct { | ||
69 | dma_addr_t ssi_stx_phys; | ||
70 | dma_addr_t ssi_srx_phys; | ||
71 | struct ccsr_dma_channel __iomem *dma_channel[2]; | ||
72 | unsigned int irq[2]; | ||
73 | unsigned int assigned[2]; | ||
74 | } dma_global_data; | ||
75 | |||
76 | /* | ||
77 | * The number of DMA links to use. Two is the bare minimum, but if you | ||
78 | * have really small links you might need more. | ||
79 | */ | ||
80 | #define NUM_DMA_LINKS 2 | ||
81 | |||
82 | /** fsl_dma_private: p-substream DMA data | ||
83 | * | ||
84 | * Each substream has a 1-to-1 association with a DMA channel. | ||
85 | * | ||
86 | * The link[] array is first because it needs to be aligned on a 32-byte | ||
87 | * boundary, so putting it first will ensure alignment without padding the | ||
88 | * structure. | ||
89 | * | ||
90 | * @link[]: array of link descriptors | ||
91 | * @controller_id: which DMA controller (0, 1, ...) | ||
92 | * @channel_id: which DMA channel on the controller (0, 1, 2, ...) | ||
93 | * @dma_channel: pointer to the DMA channel's registers | ||
94 | * @irq: IRQ for this DMA channel | ||
95 | * @substream: pointer to the substream object, needed by the ISR | ||
96 | * @ssi_sxx_phys: bus address of the STX or SRX register to use | ||
97 | * @ld_buf_phys: physical address of the LD buffer | ||
98 | * @current_link: index into link[] of the link currently being processed | ||
99 | * @dma_buf_phys: physical address of the DMA buffer | ||
100 | * @dma_buf_next: physical address of the next period to process | ||
101 | * @dma_buf_end: physical address of the byte after the end of the DMA | ||
102 | * @buffer period_size: the size of a single period | ||
103 | * @num_periods: the number of periods in the DMA buffer | ||
104 | */ | ||
105 | struct fsl_dma_private { | ||
106 | struct fsl_dma_link_descriptor link[NUM_DMA_LINKS]; | ||
107 | unsigned int controller_id; | ||
108 | unsigned int channel_id; | ||
109 | struct ccsr_dma_channel __iomem *dma_channel; | ||
110 | unsigned int irq; | ||
111 | struct snd_pcm_substream *substream; | ||
112 | dma_addr_t ssi_sxx_phys; | ||
113 | dma_addr_t ld_buf_phys; | ||
114 | unsigned int current_link; | ||
115 | dma_addr_t dma_buf_phys; | ||
116 | dma_addr_t dma_buf_next; | ||
117 | dma_addr_t dma_buf_end; | ||
118 | size_t period_size; | ||
119 | unsigned int num_periods; | ||
120 | }; | ||
121 | |||
122 | /** | ||
123 | * fsl_dma_hardare: define characteristics of the PCM hardware. | ||
124 | * | ||
125 | * The PCM hardware is the Freescale DMA controller. This structure defines | ||
126 | * the capabilities of that hardware. | ||
127 | * | ||
128 | * Since the sampling rate and data format are not controlled by the DMA | ||
129 | * controller, we specify no limits for those values. The only exception is | ||
130 | * period_bytes_min, which is set to a reasonably low value to prevent the | ||
131 | * DMA controller from generating too many interrupts per second. | ||
132 | * | ||
133 | * Since each link descriptor has a 32-bit byte count field, we set | ||
134 | * period_bytes_max to the largest 32-bit number. We also have no maximum | ||
135 | * number of periods. | ||
136 | */ | ||
137 | static const struct snd_pcm_hardware fsl_dma_hardware = { | ||
138 | |||
139 | .info = SNDRV_PCM_INFO_INTERLEAVED | | ||
140 | SNDRV_PCM_INFO_MMAP | | ||
141 | SNDRV_PCM_INFO_MMAP_VALID, | ||
142 | .formats = FSLDMA_PCM_FORMATS, | ||
143 | .rates = FSLDMA_PCM_RATES, | ||
144 | .rate_min = 5512, | ||
145 | .rate_max = 192000, | ||
146 | .period_bytes_min = 512, /* A reasonable limit */ | ||
147 | .period_bytes_max = (u32) -1, | ||
148 | .periods_min = NUM_DMA_LINKS, | ||
149 | .periods_max = (unsigned int) -1, | ||
150 | .buffer_bytes_max = 128 * 1024, /* A reasonable limit */ | ||
151 | }; | ||
152 | |||
153 | /** | ||
154 | * fsl_dma_abort_stream: tell ALSA that the DMA transfer has aborted | ||
155 | * | ||
156 | * This function should be called by the ISR whenever the DMA controller | ||
157 | * halts data transfer. | ||
158 | */ | ||
159 | static void fsl_dma_abort_stream(struct snd_pcm_substream *substream) | ||
160 | { | ||
161 | unsigned long flags; | ||
162 | |||
163 | snd_pcm_stream_lock_irqsave(substream, flags); | ||
164 | |||
165 | if (snd_pcm_running(substream)) | ||
166 | snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); | ||
167 | |||
168 | snd_pcm_stream_unlock_irqrestore(substream, flags); | ||
169 | } | ||
170 | |||
171 | /** | ||
172 | * fsl_dma_update_pointers - update LD pointers to point to the next period | ||
173 | * | ||
174 | * As each period is completed, this function changes the the link | ||
175 | * descriptor pointers for that period to point to the next period. | ||
176 | */ | ||
177 | static void fsl_dma_update_pointers(struct fsl_dma_private *dma_private) | ||
178 | { | ||
179 | struct fsl_dma_link_descriptor *link = | ||
180 | &dma_private->link[dma_private->current_link]; | ||
181 | |||
182 | /* Update our link descriptors to point to the next period */ | ||
183 | if (dma_private->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
184 | link->source_addr = | ||
185 | cpu_to_be32(dma_private->dma_buf_next); | ||
186 | else | ||
187 | link->dest_addr = | ||
188 | cpu_to_be32(dma_private->dma_buf_next); | ||
189 | |||
190 | /* Update our variables for next time */ | ||
191 | dma_private->dma_buf_next += dma_private->period_size; | ||
192 | |||
193 | if (dma_private->dma_buf_next >= dma_private->dma_buf_end) | ||
194 | dma_private->dma_buf_next = dma_private->dma_buf_phys; | ||
195 | |||
196 | if (++dma_private->current_link >= NUM_DMA_LINKS) | ||
197 | dma_private->current_link = 0; | ||
198 | } | ||
199 | |||
200 | /** | ||
201 | * fsl_dma_isr: interrupt handler for the DMA controller | ||
202 | * | ||
203 | * @irq: IRQ of the DMA channel | ||
204 | * @dev_id: pointer to the dma_private structure for this DMA channel | ||
205 | */ | ||
206 | static irqreturn_t fsl_dma_isr(int irq, void *dev_id) | ||
207 | { | ||
208 | struct fsl_dma_private *dma_private = dev_id; | ||
209 | struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel; | ||
210 | irqreturn_t ret = IRQ_NONE; | ||
211 | u32 sr, sr2 = 0; | ||
212 | |||
213 | /* We got an interrupt, so read the status register to see what we | ||
214 | were interrupted for. | ||
215 | */ | ||
216 | sr = in_be32(&dma_channel->sr); | ||
217 | |||
218 | if (sr & CCSR_DMA_SR_TE) { | ||
219 | dev_err(dma_private->substream->pcm->card->dev, | ||
220 | "DMA transmit error (controller=%u channel=%u irq=%u\n", | ||
221 | dma_private->controller_id, | ||
222 | dma_private->channel_id, irq); | ||
223 | fsl_dma_abort_stream(dma_private->substream); | ||
224 | sr2 |= CCSR_DMA_SR_TE; | ||
225 | ret = IRQ_HANDLED; | ||
226 | } | ||
227 | |||
228 | if (sr & CCSR_DMA_SR_CH) | ||
229 | ret = IRQ_HANDLED; | ||
230 | |||
231 | if (sr & CCSR_DMA_SR_PE) { | ||
232 | dev_err(dma_private->substream->pcm->card->dev, | ||
233 | "DMA%u programming error (channel=%u irq=%u)\n", | ||
234 | dma_private->controller_id, | ||
235 | dma_private->channel_id, irq); | ||
236 | fsl_dma_abort_stream(dma_private->substream); | ||
237 | sr2 |= CCSR_DMA_SR_PE; | ||
238 | ret = IRQ_HANDLED; | ||
239 | } | ||
240 | |||
241 | if (sr & CCSR_DMA_SR_EOLNI) { | ||
242 | sr2 |= CCSR_DMA_SR_EOLNI; | ||
243 | ret = IRQ_HANDLED; | ||
244 | } | ||
245 | |||
246 | if (sr & CCSR_DMA_SR_CB) | ||
247 | ret = IRQ_HANDLED; | ||
248 | |||
249 | if (sr & CCSR_DMA_SR_EOSI) { | ||
250 | struct snd_pcm_substream *substream = dma_private->substream; | ||
251 | |||
252 | /* Tell ALSA we completed a period. */ | ||
253 | snd_pcm_period_elapsed(substream); | ||
254 | |||
255 | /* | ||
256 | * Update our link descriptors to point to the next period. We | ||
257 | * only need to do this if the number of periods is not equal to | ||
258 | * the number of links. | ||
259 | */ | ||
260 | if (dma_private->num_periods != NUM_DMA_LINKS) | ||
261 | fsl_dma_update_pointers(dma_private); | ||
262 | |||
263 | sr2 |= CCSR_DMA_SR_EOSI; | ||
264 | ret = IRQ_HANDLED; | ||
265 | } | ||
266 | |||
267 | if (sr & CCSR_DMA_SR_EOLSI) { | ||
268 | sr2 |= CCSR_DMA_SR_EOLSI; | ||
269 | ret = IRQ_HANDLED; | ||
270 | } | ||
271 | |||
272 | /* Clear the bits that we set */ | ||
273 | if (sr2) | ||
274 | out_be32(&dma_channel->sr, sr2); | ||
275 | |||
276 | return ret; | ||
277 | } | ||
278 | |||
279 | /** | ||
280 | * fsl_dma_new: initialize this PCM driver. | ||
281 | * | ||
282 | * This function is called when the codec driver calls snd_soc_new_pcms(), | ||
283 | * once for each .dai_link in the machine driver's snd_soc_machine | ||
284 | * structure. | ||
285 | */ | ||
286 | static int fsl_dma_new(struct snd_card *card, struct snd_soc_codec_dai *dai, | ||
287 | struct snd_pcm *pcm) | ||
288 | { | ||
289 | static u64 fsl_dma_dmamask = DMA_BIT_MASK(32); | ||
290 | int ret; | ||
291 | |||
292 | if (!card->dev->dma_mask) | ||
293 | card->dev->dma_mask = &fsl_dma_dmamask; | ||
294 | |||
295 | if (!card->dev->coherent_dma_mask) | ||
296 | card->dev->coherent_dma_mask = fsl_dma_dmamask; | ||
297 | |||
298 | ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, | ||
299 | fsl_dma_hardware.buffer_bytes_max, | ||
300 | &pcm->streams[0].substream->dma_buffer); | ||
301 | if (ret) { | ||
302 | dev_err(card->dev, | ||
303 | "Can't allocate playback DMA buffer (size=%u)\n", | ||
304 | fsl_dma_hardware.buffer_bytes_max); | ||
305 | return -ENOMEM; | ||
306 | } | ||
307 | |||
308 | ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, | ||
309 | fsl_dma_hardware.buffer_bytes_max, | ||
310 | &pcm->streams[1].substream->dma_buffer); | ||
311 | if (ret) { | ||
312 | snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer); | ||
313 | dev_err(card->dev, | ||
314 | "Can't allocate capture DMA buffer (size=%u)\n", | ||
315 | fsl_dma_hardware.buffer_bytes_max); | ||
316 | return -ENOMEM; | ||
317 | } | ||
318 | |||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | /** | ||
323 | * fsl_dma_open: open a new substream. | ||
324 | * | ||
325 | * Each substream has its own DMA buffer. | ||
326 | */ | ||
327 | static int fsl_dma_open(struct snd_pcm_substream *substream) | ||
328 | { | ||
329 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
330 | struct fsl_dma_private *dma_private; | ||
331 | dma_addr_t ld_buf_phys; | ||
332 | unsigned int channel; | ||
333 | int ret = 0; | ||
334 | |||
335 | /* | ||
336 | * Reject any DMA buffer whose size is not a multiple of the period | ||
337 | * size. We need to make sure that the DMA buffer can be evenly divided | ||
338 | * into periods. | ||
339 | */ | ||
340 | ret = snd_pcm_hw_constraint_integer(runtime, | ||
341 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
342 | if (ret < 0) { | ||
343 | dev_err(substream->pcm->card->dev, "invalid buffer size\n"); | ||
344 | return ret; | ||
345 | } | ||
346 | |||
347 | channel = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; | ||
348 | |||
349 | if (dma_global_data.assigned[channel]) { | ||
350 | dev_err(substream->pcm->card->dev, | ||
351 | "DMA channel already assigned\n"); | ||
352 | return -EBUSY; | ||
353 | } | ||
354 | |||
355 | dma_private = dma_alloc_coherent(substream->pcm->dev, | ||
356 | sizeof(struct fsl_dma_private), &ld_buf_phys, GFP_KERNEL); | ||
357 | if (!dma_private) { | ||
358 | dev_err(substream->pcm->card->dev, | ||
359 | "can't allocate DMA private data\n"); | ||
360 | return -ENOMEM; | ||
361 | } | ||
362 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
363 | dma_private->ssi_sxx_phys = dma_global_data.ssi_stx_phys; | ||
364 | else | ||
365 | dma_private->ssi_sxx_phys = dma_global_data.ssi_srx_phys; | ||
366 | |||
367 | dma_private->dma_channel = dma_global_data.dma_channel[channel]; | ||
368 | dma_private->irq = dma_global_data.irq[channel]; | ||
369 | dma_private->substream = substream; | ||
370 | dma_private->ld_buf_phys = ld_buf_phys; | ||
371 | dma_private->dma_buf_phys = substream->dma_buffer.addr; | ||
372 | |||
373 | /* We only support one DMA controller for now */ | ||
374 | dma_private->controller_id = 0; | ||
375 | dma_private->channel_id = channel; | ||
376 | |||
377 | ret = request_irq(dma_private->irq, fsl_dma_isr, 0, "DMA", dma_private); | ||
378 | if (ret) { | ||
379 | dev_err(substream->pcm->card->dev, | ||
380 | "can't register ISR for IRQ %u (ret=%i)\n", | ||
381 | dma_private->irq, ret); | ||
382 | dma_free_coherent(substream->pcm->dev, | ||
383 | sizeof(struct fsl_dma_private), | ||
384 | dma_private, dma_private->ld_buf_phys); | ||
385 | return ret; | ||
386 | } | ||
387 | |||
388 | dma_global_data.assigned[channel] = 1; | ||
389 | |||
390 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | ||
391 | snd_soc_set_runtime_hwparams(substream, &fsl_dma_hardware); | ||
392 | runtime->private_data = dma_private; | ||
393 | |||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | /** | ||
398 | * fsl_dma_hw_params: allocate the DMA buffer and the DMA link descriptors. | ||
399 | * | ||
400 | * ALSA divides the DMA buffer into N periods. We create NUM_DMA_LINKS link | ||
401 | * descriptors that ping-pong from one period to the next. For example, if | ||
402 | * there are six periods and two link descriptors, this is how they look | ||
403 | * before playback starts: | ||
404 | * | ||
405 | * The last link descriptor | ||
406 | * ____________ points back to the first | ||
407 | * | | | ||
408 | * V | | ||
409 | * ___ ___ | | ||
410 | * | |->| |->| | ||
411 | * |___| |___| | ||
412 | * | | | ||
413 | * | | | ||
414 | * V V | ||
415 | * _________________________________________ | ||
416 | * | | | | | | | The DMA buffer is | ||
417 | * | | | | | | | divided into 6 parts | ||
418 | * |______|______|______|______|______|______| | ||
419 | * | ||
420 | * and here's how they look after the first period is finished playing: | ||
421 | * | ||
422 | * ____________ | ||
423 | * | | | ||
424 | * V | | ||
425 | * ___ ___ | | ||
426 | * | |->| |->| | ||
427 | * |___| |___| | ||
428 | * | | | ||
429 | * |______________ | ||
430 | * | | | ||
431 | * V V | ||
432 | * _________________________________________ | ||
433 | * | | | | | | | | ||
434 | * | | | | | | | | ||
435 | * |______|______|______|______|______|______| | ||
436 | * | ||
437 | * The first link descriptor now points to the third period. The DMA | ||
438 | * controller is currently playing the second period. When it finishes, it | ||
439 | * will jump back to the first descriptor and play the third period. | ||
440 | * | ||
441 | * There are four reasons we do this: | ||
442 | * | ||
443 | * 1. The only way to get the DMA controller to automatically restart the | ||
444 | * transfer when it gets to the end of the buffer is to use chaining | ||
445 | * mode. Basic direct mode doesn't offer that feature. | ||
446 | * 2. We need to receive an interrupt at the end of every period. The DMA | ||
447 | * controller can generate an interrupt at the end of every link transfer | ||
448 | * (aka segment). Making each period into a DMA segment will give us the | ||
449 | * interrupts we need. | ||
450 | * 3. By creating only two link descriptors, regardless of the number of | ||
451 | * periods, we do not need to reallocate the link descriptors if the | ||
452 | * number of periods changes. | ||
453 | * 4. All of the audio data is still stored in a single, contiguous DMA | ||
454 | * buffer, which is what ALSA expects. We're just dividing it into | ||
455 | * contiguous parts, and creating a link descriptor for each one. | ||
456 | * | ||
457 | * Note that due to a quirk of the SSI's STX register, the target address | ||
458 | * for the DMA operations depends on the sample size. So we don't program | ||
459 | * the dest_addr (for playback -- source_addr for capture) fields in the | ||
460 | * link descriptors here. We do that in fsl_dma_prepare() | ||
461 | */ | ||
462 | static int fsl_dma_hw_params(struct snd_pcm_substream *substream, | ||
463 | struct snd_pcm_hw_params *hw_params) | ||
464 | { | ||
465 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
466 | struct fsl_dma_private *dma_private = runtime->private_data; | ||
467 | struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel; | ||
468 | |||
469 | dma_addr_t temp_addr; /* Pointer to next period */ | ||
470 | u64 temp_link; /* Pointer to next link descriptor */ | ||
471 | u32 mr; /* Temporary variable for MR register */ | ||
472 | |||
473 | unsigned int i; | ||
474 | |||
475 | /* Get all the parameters we need */ | ||
476 | size_t buffer_size = params_buffer_bytes(hw_params); | ||
477 | size_t period_size = params_period_bytes(hw_params); | ||
478 | |||
479 | /* Initialize our DMA tracking variables */ | ||
480 | dma_private->period_size = period_size; | ||
481 | dma_private->num_periods = params_periods(hw_params); | ||
482 | dma_private->dma_buf_end = dma_private->dma_buf_phys + buffer_size; | ||
483 | dma_private->dma_buf_next = dma_private->dma_buf_phys + | ||
484 | (NUM_DMA_LINKS * period_size); | ||
485 | if (dma_private->dma_buf_next >= dma_private->dma_buf_end) | ||
486 | dma_private->dma_buf_next = dma_private->dma_buf_phys; | ||
487 | |||
488 | /* | ||
489 | * Initialize each link descriptor. | ||
490 | * | ||
491 | * The actual address in STX0 (destination for playback, source for | ||
492 | * capture) is based on the sample size, but we don't know the sample | ||
493 | * size in this function, so we'll have to adjust that later. See | ||
494 | * comments in fsl_dma_prepare(). | ||
495 | * | ||
496 | * The DMA controller does not have a cache, so the CPU does not | ||
497 | * need to tell it to flush its cache. However, the DMA | ||
498 | * controller does need to tell the CPU to flush its cache. | ||
499 | * That's what the SNOOP bit does. | ||
500 | * | ||
501 | * Also, even though the DMA controller supports 36-bit addressing, for | ||
502 | * simplicity we currently support only 32-bit addresses for the audio | ||
503 | * buffer itself. | ||
504 | */ | ||
505 | temp_addr = substream->dma_buffer.addr; | ||
506 | temp_link = dma_private->ld_buf_phys + | ||
507 | sizeof(struct fsl_dma_link_descriptor); | ||
508 | |||
509 | for (i = 0; i < NUM_DMA_LINKS; i++) { | ||
510 | struct fsl_dma_link_descriptor *link = &dma_private->link[i]; | ||
511 | |||
512 | link->count = cpu_to_be32(period_size); | ||
513 | link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP); | ||
514 | link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP); | ||
515 | link->next = cpu_to_be64(temp_link); | ||
516 | |||
517 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
518 | link->source_addr = cpu_to_be32(temp_addr); | ||
519 | else | ||
520 | link->dest_addr = cpu_to_be32(temp_addr); | ||
521 | |||
522 | temp_addr += period_size; | ||
523 | temp_link += sizeof(struct fsl_dma_link_descriptor); | ||
524 | } | ||
525 | /* The last link descriptor points to the first */ | ||
526 | dma_private->link[i - 1].next = cpu_to_be64(dma_private->ld_buf_phys); | ||
527 | |||
528 | /* Tell the DMA controller where the first link descriptor is */ | ||
529 | out_be32(&dma_channel->clndar, | ||
530 | CCSR_DMA_CLNDAR_ADDR(dma_private->ld_buf_phys)); | ||
531 | out_be32(&dma_channel->eclndar, | ||
532 | CCSR_DMA_ECLNDAR_ADDR(dma_private->ld_buf_phys)); | ||
533 | |||
534 | /* The manual says the BCR must be clear before enabling EMP */ | ||
535 | out_be32(&dma_channel->bcr, 0); | ||
536 | |||
537 | /* | ||
538 | * Program the mode register for interrupts, external master control, | ||
539 | * and source/destination hold. Also clear the Channel Abort bit. | ||
540 | */ | ||
541 | mr = in_be32(&dma_channel->mr) & | ||
542 | ~(CCSR_DMA_MR_CA | CCSR_DMA_MR_DAHE | CCSR_DMA_MR_SAHE); | ||
543 | |||
544 | /* | ||
545 | * We want External Master Start and External Master Pause enabled, | ||
546 | * because the SSI is controlling the DMA controller. We want the DMA | ||
547 | * controller to be set up in advance, and then we signal only the SSI | ||
548 | * to start transfering. | ||
549 | * | ||
550 | * We want End-Of-Segment Interrupts enabled, because this will generate | ||
551 | * an interrupt at the end of each segment (each link descriptor | ||
552 | * represents one segment). Each DMA segment is the same thing as an | ||
553 | * ALSA period, so this is how we get an interrupt at the end of every | ||
554 | * period. | ||
555 | * | ||
556 | * We want Error Interrupt enabled, so that we can get an error if | ||
557 | * the DMA controller is mis-programmed somehow. | ||
558 | */ | ||
559 | mr |= CCSR_DMA_MR_EOSIE | CCSR_DMA_MR_EIE | CCSR_DMA_MR_EMP_EN | | ||
560 | CCSR_DMA_MR_EMS_EN; | ||
561 | |||
562 | /* For playback, we want the destination address to be held. For | ||
563 | capture, set the source address to be held. */ | ||
564 | mr |= (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? | ||
565 | CCSR_DMA_MR_DAHE : CCSR_DMA_MR_SAHE; | ||
566 | |||
567 | out_be32(&dma_channel->mr, mr); | ||
568 | |||
569 | return 0; | ||
570 | } | ||
571 | |||
572 | /** | ||
573 | * fsl_dma_prepare - prepare the DMA registers for playback. | ||
574 | * | ||
575 | * This function is called after the specifics of the audio data are known, | ||
576 | * i.e. snd_pcm_runtime is initialized. | ||
577 | * | ||
578 | * In this function, we finish programming the registers of the DMA | ||
579 | * controller that are dependent on the sample size. | ||
580 | * | ||
581 | * One of the drawbacks with big-endian is that when copying integers of | ||
582 | * different sizes to a fixed-sized register, the address to which the | ||
583 | * integer must be copied is dependent on the size of the integer. | ||
584 | * | ||
585 | * For example, if P is the address of a 32-bit register, and X is a 32-bit | ||
586 | * integer, then X should be copied to address P. However, if X is a 16-bit | ||
587 | * integer, then it should be copied to P+2. If X is an 8-bit register, | ||
588 | * then it should be copied to P+3. | ||
589 | * | ||
590 | * So for playback of 8-bit samples, the DMA controller must transfer single | ||
591 | * bytes from the DMA buffer to the last byte of the STX0 register, i.e. | ||
592 | * offset by 3 bytes. For 16-bit samples, the offset is two bytes. | ||
593 | * | ||
594 | * For 24-bit samples, the offset is 1 byte. However, the DMA controller | ||
595 | * does not support 3-byte copies (the DAHTS register supports only 1, 2, 4, | ||
596 | * and 8 bytes at a time). So we do not support packed 24-bit samples. | ||
597 | * 24-bit data must be padded to 32 bits. | ||
598 | */ | ||
599 | static int fsl_dma_prepare(struct snd_pcm_substream *substream) | ||
600 | { | ||
601 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
602 | struct fsl_dma_private *dma_private = runtime->private_data; | ||
603 | struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel; | ||
604 | u32 mr; | ||
605 | unsigned int i; | ||
606 | dma_addr_t ssi_sxx_phys; /* Bus address of SSI STX register */ | ||
607 | unsigned int frame_size; /* Number of bytes per frame */ | ||
608 | |||
609 | ssi_sxx_phys = dma_private->ssi_sxx_phys; | ||
610 | |||
611 | mr = in_be32(&dma_channel->mr) & ~(CCSR_DMA_MR_BWC_MASK | | ||
612 | CCSR_DMA_MR_SAHTS_MASK | CCSR_DMA_MR_DAHTS_MASK); | ||
613 | |||
614 | switch (runtime->sample_bits) { | ||
615 | case 8: | ||
616 | mr |= CCSR_DMA_MR_DAHTS_1 | CCSR_DMA_MR_SAHTS_1; | ||
617 | ssi_sxx_phys += 3; | ||
618 | break; | ||
619 | case 16: | ||
620 | mr |= CCSR_DMA_MR_DAHTS_2 | CCSR_DMA_MR_SAHTS_2; | ||
621 | ssi_sxx_phys += 2; | ||
622 | break; | ||
623 | case 32: | ||
624 | mr |= CCSR_DMA_MR_DAHTS_4 | CCSR_DMA_MR_SAHTS_4; | ||
625 | break; | ||
626 | default: | ||
627 | dev_err(substream->pcm->card->dev, | ||
628 | "unsupported sample size %u\n", runtime->sample_bits); | ||
629 | return -EINVAL; | ||
630 | } | ||
631 | |||
632 | frame_size = runtime->frame_bits / 8; | ||
633 | /* | ||
634 | * BWC should always be a multiple of the frame size. BWC determines | ||
635 | * how many bytes are sent/received before the DMA controller checks the | ||
636 | * SSI to see if it needs to stop. For playback, the transmit FIFO can | ||
637 | * hold three frames, so we want to send two frames at a time. For | ||
638 | * capture, the receive FIFO is triggered when it contains one frame, so | ||
639 | * we want to receive one frame at a time. | ||
640 | */ | ||
641 | |||
642 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
643 | mr |= CCSR_DMA_MR_BWC(2 * frame_size); | ||
644 | else | ||
645 | mr |= CCSR_DMA_MR_BWC(frame_size); | ||
646 | |||
647 | out_be32(&dma_channel->mr, mr); | ||
648 | |||
649 | /* | ||
650 | * Program the address of the DMA transfer to/from the SSI. | ||
651 | */ | ||
652 | for (i = 0; i < NUM_DMA_LINKS; i++) { | ||
653 | struct fsl_dma_link_descriptor *link = &dma_private->link[i]; | ||
654 | |||
655 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
656 | link->dest_addr = cpu_to_be32(ssi_sxx_phys); | ||
657 | else | ||
658 | link->source_addr = cpu_to_be32(ssi_sxx_phys); | ||
659 | } | ||
660 | |||
661 | return 0; | ||
662 | } | ||
663 | |||
664 | /** | ||
665 | * fsl_dma_pointer: determine the current position of the DMA transfer | ||
666 | * | ||
667 | * This function is called by ALSA when ALSA wants to know where in the | ||
668 | * stream buffer the hardware currently is. | ||
669 | * | ||
670 | * For playback, the SAR register contains the physical address of the most | ||
671 | * recent DMA transfer. For capture, the value is in the DAR register. | ||
672 | * | ||
673 | * The base address of the buffer is stored in the source_addr field of the | ||
674 | * first link descriptor. | ||
675 | */ | ||
676 | static snd_pcm_uframes_t fsl_dma_pointer(struct snd_pcm_substream *substream) | ||
677 | { | ||
678 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
679 | struct fsl_dma_private *dma_private = runtime->private_data; | ||
680 | struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel; | ||
681 | dma_addr_t position; | ||
682 | snd_pcm_uframes_t frames; | ||
683 | |||
684 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
685 | position = in_be32(&dma_channel->sar); | ||
686 | else | ||
687 | position = in_be32(&dma_channel->dar); | ||
688 | |||
689 | frames = bytes_to_frames(runtime, position - dma_private->dma_buf_phys); | ||
690 | |||
691 | /* | ||
692 | * If the current address is just past the end of the buffer, wrap it | ||
693 | * around. | ||
694 | */ | ||
695 | if (frames == runtime->buffer_size) | ||
696 | frames = 0; | ||
697 | |||
698 | return frames; | ||
699 | } | ||
700 | |||
701 | /** | ||
702 | * fsl_dma_hw_free: release resources allocated in fsl_dma_hw_params() | ||
703 | * | ||
704 | * Release the resources allocated in fsl_dma_hw_params() and de-program the | ||
705 | * registers. | ||
706 | * | ||
707 | * This function can be called multiple times. | ||
708 | */ | ||
709 | static int fsl_dma_hw_free(struct snd_pcm_substream *substream) | ||
710 | { | ||
711 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
712 | struct fsl_dma_private *dma_private = runtime->private_data; | ||
713 | |||
714 | if (dma_private) { | ||
715 | struct ccsr_dma_channel __iomem *dma_channel; | ||
716 | |||
717 | dma_channel = dma_private->dma_channel; | ||
718 | |||
719 | /* Stop the DMA */ | ||
720 | out_be32(&dma_channel->mr, CCSR_DMA_MR_CA); | ||
721 | out_be32(&dma_channel->mr, 0); | ||
722 | |||
723 | /* Reset all the other registers */ | ||
724 | out_be32(&dma_channel->sr, -1); | ||
725 | out_be32(&dma_channel->clndar, 0); | ||
726 | out_be32(&dma_channel->eclndar, 0); | ||
727 | out_be32(&dma_channel->satr, 0); | ||
728 | out_be32(&dma_channel->sar, 0); | ||
729 | out_be32(&dma_channel->datr, 0); | ||
730 | out_be32(&dma_channel->dar, 0); | ||
731 | out_be32(&dma_channel->bcr, 0); | ||
732 | out_be32(&dma_channel->nlndar, 0); | ||
733 | out_be32(&dma_channel->enlndar, 0); | ||
734 | } | ||
735 | |||
736 | return 0; | ||
737 | } | ||
738 | |||
739 | /** | ||
740 | * fsl_dma_close: close the stream. | ||
741 | */ | ||
742 | static int fsl_dma_close(struct snd_pcm_substream *substream) | ||
743 | { | ||
744 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
745 | struct fsl_dma_private *dma_private = runtime->private_data; | ||
746 | int dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; | ||
747 | |||
748 | if (dma_private) { | ||
749 | if (dma_private->irq) | ||
750 | free_irq(dma_private->irq, dma_private); | ||
751 | |||
752 | if (dma_private->ld_buf_phys) { | ||
753 | dma_unmap_single(substream->pcm->dev, | ||
754 | dma_private->ld_buf_phys, | ||
755 | sizeof(dma_private->link), DMA_TO_DEVICE); | ||
756 | } | ||
757 | |||
758 | /* Deallocate the fsl_dma_private structure */ | ||
759 | dma_free_coherent(substream->pcm->dev, | ||
760 | sizeof(struct fsl_dma_private), | ||
761 | dma_private, dma_private->ld_buf_phys); | ||
762 | substream->runtime->private_data = NULL; | ||
763 | } | ||
764 | |||
765 | dma_global_data.assigned[dir] = 0; | ||
766 | |||
767 | return 0; | ||
768 | } | ||
769 | |||
770 | /* | ||
771 | * Remove this PCM driver. | ||
772 | */ | ||
773 | static void fsl_dma_free_dma_buffers(struct snd_pcm *pcm) | ||
774 | { | ||
775 | struct snd_pcm_substream *substream; | ||
776 | unsigned int i; | ||
777 | |||
778 | for (i = 0; i < ARRAY_SIZE(pcm->streams); i++) { | ||
779 | substream = pcm->streams[i].substream; | ||
780 | if (substream) { | ||
781 | snd_dma_free_pages(&substream->dma_buffer); | ||
782 | substream->dma_buffer.area = NULL; | ||
783 | substream->dma_buffer.addr = 0; | ||
784 | } | ||
785 | } | ||
786 | } | ||
787 | |||
788 | static struct snd_pcm_ops fsl_dma_ops = { | ||
789 | .open = fsl_dma_open, | ||
790 | .close = fsl_dma_close, | ||
791 | .ioctl = snd_pcm_lib_ioctl, | ||
792 | .hw_params = fsl_dma_hw_params, | ||
793 | .hw_free = fsl_dma_hw_free, | ||
794 | .prepare = fsl_dma_prepare, | ||
795 | .pointer = fsl_dma_pointer, | ||
796 | }; | ||
797 | |||
798 | struct snd_soc_platform fsl_soc_platform = { | ||
799 | .name = "fsl-dma", | ||
800 | .pcm_ops = &fsl_dma_ops, | ||
801 | .pcm_new = fsl_dma_new, | ||
802 | .pcm_free = fsl_dma_free_dma_buffers, | ||
803 | }; | ||
804 | EXPORT_SYMBOL_GPL(fsl_soc_platform); | ||
805 | |||
806 | /** | ||
807 | * fsl_dma_configure: store the DMA parameters from the fabric driver. | ||
808 | * | ||
809 | * This function is called by the ASoC fabric driver to give us the DMA and | ||
810 | * SSI channel information. | ||
811 | * | ||
812 | * Unfortunately, ASoC V1 does make it possible to determine the DMA/SSI | ||
813 | * data when a substream is created, so for now we need to store this data | ||
814 | * into a global variable. This means that we can only support one DMA | ||
815 | * controller, and hence only one SSI. | ||
816 | */ | ||
817 | int fsl_dma_configure(struct fsl_dma_info *dma_info) | ||
818 | { | ||
819 | static int initialized; | ||
820 | |||
821 | /* We only support one DMA controller for now */ | ||
822 | if (initialized) | ||
823 | return 0; | ||
824 | |||
825 | dma_global_data.ssi_stx_phys = dma_info->ssi_stx_phys; | ||
826 | dma_global_data.ssi_srx_phys = dma_info->ssi_srx_phys; | ||
827 | dma_global_data.dma_channel[0] = dma_info->dma_channel[0]; | ||
828 | dma_global_data.dma_channel[1] = dma_info->dma_channel[1]; | ||
829 | dma_global_data.irq[0] = dma_info->dma_irq[0]; | ||
830 | dma_global_data.irq[1] = dma_info->dma_irq[1]; | ||
831 | dma_global_data.assigned[0] = 0; | ||
832 | dma_global_data.assigned[1] = 0; | ||
833 | |||
834 | initialized = 1; | ||
835 | return 1; | ||
836 | } | ||
837 | EXPORT_SYMBOL_GPL(fsl_dma_configure); | ||
838 | |||
839 | MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); | ||
840 | MODULE_DESCRIPTION("Freescale Elo DMA ASoC PCM module"); | ||
841 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/fsl/fsl_dma.h b/sound/soc/fsl/fsl_dma.h new file mode 100644 index 000000000000..430a6ce8b0d0 --- /dev/null +++ b/sound/soc/fsl/fsl_dma.h | |||
@@ -0,0 +1,149 @@ | |||
1 | /* | ||
2 | * mpc8610-pcm.h - ALSA PCM interface for the Freescale MPC8610 SoC | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #ifndef _MPC8610_PCM_H | ||
10 | #define _MPC8610_PCM_H | ||
11 | |||
12 | struct ccsr_dma { | ||
13 | u8 res0[0x100]; | ||
14 | struct ccsr_dma_channel { | ||
15 | __be32 mr; /* Mode register */ | ||
16 | __be32 sr; /* Status register */ | ||
17 | __be32 eclndar; /* Current link descriptor extended addr reg */ | ||
18 | __be32 clndar; /* Current link descriptor address register */ | ||
19 | __be32 satr; /* Source attributes register */ | ||
20 | __be32 sar; /* Source address register */ | ||
21 | __be32 datr; /* Destination attributes register */ | ||
22 | __be32 dar; /* Destination address register */ | ||
23 | __be32 bcr; /* Byte count register */ | ||
24 | __be32 enlndar; /* Next link descriptor extended address reg */ | ||
25 | __be32 nlndar; /* Next link descriptor address register */ | ||
26 | u8 res1[4]; | ||
27 | __be32 eclsdar; /* Current list descriptor extended addr reg */ | ||
28 | __be32 clsdar; /* Current list descriptor address register */ | ||
29 | __be32 enlsdar; /* Next list descriptor extended address reg */ | ||
30 | __be32 nlsdar; /* Next list descriptor address register */ | ||
31 | __be32 ssr; /* Source stride register */ | ||
32 | __be32 dsr; /* Destination stride register */ | ||
33 | u8 res2[0x38]; | ||
34 | } channel[4]; | ||
35 | __be32 dgsr; | ||
36 | }; | ||
37 | |||
38 | #define CCSR_DMA_MR_BWC_DISABLED 0x0F000000 | ||
39 | #define CCSR_DMA_MR_BWC_SHIFT 24 | ||
40 | #define CCSR_DMA_MR_BWC_MASK 0x0F000000 | ||
41 | #define CCSR_DMA_MR_BWC(x) \ | ||
42 | ((ilog2(x) << CCSR_DMA_MR_BWC_SHIFT) & CCSR_DMA_MR_BWC_MASK) | ||
43 | #define CCSR_DMA_MR_EMP_EN 0x00200000 | ||
44 | #define CCSR_DMA_MR_EMS_EN 0x00040000 | ||
45 | #define CCSR_DMA_MR_DAHTS_MASK 0x00030000 | ||
46 | #define CCSR_DMA_MR_DAHTS_1 0x00000000 | ||
47 | #define CCSR_DMA_MR_DAHTS_2 0x00010000 | ||
48 | #define CCSR_DMA_MR_DAHTS_4 0x00020000 | ||
49 | #define CCSR_DMA_MR_DAHTS_8 0x00030000 | ||
50 | #define CCSR_DMA_MR_SAHTS_MASK 0x0000C000 | ||
51 | #define CCSR_DMA_MR_SAHTS_1 0x00000000 | ||
52 | #define CCSR_DMA_MR_SAHTS_2 0x00004000 | ||
53 | #define CCSR_DMA_MR_SAHTS_4 0x00008000 | ||
54 | #define CCSR_DMA_MR_SAHTS_8 0x0000C000 | ||
55 | #define CCSR_DMA_MR_DAHE 0x00002000 | ||
56 | #define CCSR_DMA_MR_SAHE 0x00001000 | ||
57 | #define CCSR_DMA_MR_SRW 0x00000400 | ||
58 | #define CCSR_DMA_MR_EOSIE 0x00000200 | ||
59 | #define CCSR_DMA_MR_EOLNIE 0x00000100 | ||
60 | #define CCSR_DMA_MR_EOLSIE 0x00000080 | ||
61 | #define CCSR_DMA_MR_EIE 0x00000040 | ||
62 | #define CCSR_DMA_MR_XFE 0x00000020 | ||
63 | #define CCSR_DMA_MR_CDSM_SWSM 0x00000010 | ||
64 | #define CCSR_DMA_MR_CA 0x00000008 | ||
65 | #define CCSR_DMA_MR_CTM 0x00000004 | ||
66 | #define CCSR_DMA_MR_CC 0x00000002 | ||
67 | #define CCSR_DMA_MR_CS 0x00000001 | ||
68 | |||
69 | #define CCSR_DMA_SR_TE 0x00000080 | ||
70 | #define CCSR_DMA_SR_CH 0x00000020 | ||
71 | #define CCSR_DMA_SR_PE 0x00000010 | ||
72 | #define CCSR_DMA_SR_EOLNI 0x00000008 | ||
73 | #define CCSR_DMA_SR_CB 0x00000004 | ||
74 | #define CCSR_DMA_SR_EOSI 0x00000002 | ||
75 | #define CCSR_DMA_SR_EOLSI 0x00000001 | ||
76 | |||
77 | /* ECLNDAR takes bits 32-36 of the CLNDAR register */ | ||
78 | static inline u32 CCSR_DMA_ECLNDAR_ADDR(u64 x) | ||
79 | { | ||
80 | return (x >> 32) & 0xf; | ||
81 | } | ||
82 | |||
83 | #define CCSR_DMA_CLNDAR_ADDR(x) ((x) & 0xFFFFFFFE) | ||
84 | #define CCSR_DMA_CLNDAR_EOSIE 0x00000008 | ||
85 | |||
86 | /* SATR and DATR, combined */ | ||
87 | #define CCSR_DMA_ATR_PBATMU 0x20000000 | ||
88 | #define CCSR_DMA_ATR_TFLOWLVL_0 0x00000000 | ||
89 | #define CCSR_DMA_ATR_TFLOWLVL_1 0x06000000 | ||
90 | #define CCSR_DMA_ATR_TFLOWLVL_2 0x08000000 | ||
91 | #define CCSR_DMA_ATR_TFLOWLVL_3 0x0C000000 | ||
92 | #define CCSR_DMA_ATR_PCIORDER 0x02000000 | ||
93 | #define CCSR_DMA_ATR_SME 0x01000000 | ||
94 | #define CCSR_DMA_ATR_NOSNOOP 0x00040000 | ||
95 | #define CCSR_DMA_ATR_SNOOP 0x00050000 | ||
96 | #define CCSR_DMA_ATR_ESAD_MASK 0x0000000F | ||
97 | |||
98 | /** | ||
99 | * List Descriptor for extended chaining mode DMA operations. | ||
100 | * | ||
101 | * The CLSDAR register points to the first (in a linked-list) List | ||
102 | * Descriptor. Each object must be aligned on a 32-byte boundary. Each | ||
103 | * list descriptor points to a linked-list of link Descriptors. | ||
104 | */ | ||
105 | struct fsl_dma_list_descriptor { | ||
106 | __be64 next; /* Address of next list descriptor */ | ||
107 | __be64 first_link; /* Address of first link descriptor */ | ||
108 | __be32 source; /* Source stride */ | ||
109 | __be32 dest; /* Destination stride */ | ||
110 | u8 res[8]; /* Reserved */ | ||
111 | } __attribute__ ((aligned(32), packed)); | ||
112 | |||
113 | /** | ||
114 | * Link Descriptor for basic and extended chaining mode DMA operations. | ||
115 | * | ||
116 | * A Link Descriptor points to a single DMA buffer. Each link descriptor | ||
117 | * must be aligned on a 32-byte boundary. | ||
118 | */ | ||
119 | struct fsl_dma_link_descriptor { | ||
120 | __be32 source_attr; /* Programmed into SATR register */ | ||
121 | __be32 source_addr; /* Programmed into SAR register */ | ||
122 | __be32 dest_attr; /* Programmed into DATR register */ | ||
123 | __be32 dest_addr; /* Programmed into DAR register */ | ||
124 | __be64 next; /* Address of next link descriptor */ | ||
125 | __be32 count; /* Byte count */ | ||
126 | u8 res[4]; /* Reserved */ | ||
127 | } __attribute__ ((aligned(32), packed)); | ||
128 | |||
129 | /* DMA information needed to create a snd_soc_cpu_dai object | ||
130 | * | ||
131 | * ssi_stx_phys: bus address of SSI STX register to use | ||
132 | * ssi_srx_phys: bus address of SSI SRX register to use | ||
133 | * dma[0]: points to the DMA channel to use for playback | ||
134 | * dma[1]: points to the DMA channel to use for capture | ||
135 | * dma_irq[0]: IRQ of the DMA channel to use for playback | ||
136 | * dma_irq[1]: IRQ of the DMA channel to use for capture | ||
137 | */ | ||
138 | struct fsl_dma_info { | ||
139 | dma_addr_t ssi_stx_phys; | ||
140 | dma_addr_t ssi_srx_phys; | ||
141 | struct ccsr_dma_channel __iomem *dma_channel[2]; | ||
142 | unsigned int dma_irq[2]; | ||
143 | }; | ||
144 | |||
145 | extern struct snd_soc_platform fsl_soc_platform; | ||
146 | |||
147 | int fsl_dma_configure(struct fsl_dma_info *dma_info); | ||
148 | |||
149 | #endif | ||
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c new file mode 100644 index 000000000000..145ad13d52d1 --- /dev/null +++ b/sound/soc/fsl/fsl_ssi.c | |||
@@ -0,0 +1,644 @@ | |||
1 | /* | ||
2 | * Freescale SSI ALSA SoC Digital Audio Interface (DAI) driver | ||
3 | * | ||
4 | * Author: Timur Tabi <timur@freescale.com> | ||
5 | * | ||
6 | * Copyright 2007-2008 Freescale Semiconductor, Inc. This file is licensed | ||
7 | * under the terms of the GNU General Public License version 2. This | ||
8 | * program is licensed "as is" without any warranty of any kind, whether | ||
9 | * express or implied. | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/device.h> | ||
16 | #include <linux/delay.h> | ||
17 | |||
18 | #include <sound/driver.h> | ||
19 | #include <sound/core.h> | ||
20 | #include <sound/pcm.h> | ||
21 | #include <sound/pcm_params.h> | ||
22 | #include <sound/initval.h> | ||
23 | #include <sound/soc.h> | ||
24 | |||
25 | #include <asm/immap_86xx.h> | ||
26 | |||
27 | #include "fsl_ssi.h" | ||
28 | |||
29 | /** | ||
30 | * FSLSSI_I2S_RATES: sample rates supported by the I2S | ||
31 | * | ||
32 | * This driver currently only supports the SSI running in I2S slave mode, | ||
33 | * which means the codec determines the sample rate. Therefore, we tell | ||
34 | * ALSA that we support all rates and let the codec driver decide what rates | ||
35 | * are really supported. | ||
36 | */ | ||
37 | #define FSLSSI_I2S_RATES (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_192000 | \ | ||
38 | SNDRV_PCM_RATE_CONTINUOUS) | ||
39 | |||
40 | /** | ||
41 | * FSLSSI_I2S_FORMATS: audio formats supported by the SSI | ||
42 | * | ||
43 | * This driver currently only supports the SSI running in I2S slave mode. | ||
44 | * | ||
45 | * The SSI has a limitation in that the samples must be in the same byte | ||
46 | * order as the host CPU. This is because when multiple bytes are written | ||
47 | * to the STX register, the bytes and bits must be written in the same | ||
48 | * order. The STX is a shift register, so all the bits need to be aligned | ||
49 | * (bit-endianness must match byte-endianness). Processors typically write | ||
50 | * the bits within a byte in the same order that the bytes of a word are | ||
51 | * written in. So if the host CPU is big-endian, then only big-endian | ||
52 | * samples will be written to STX properly. | ||
53 | */ | ||
54 | #ifdef __BIG_ENDIAN | ||
55 | #define FSLSSI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \ | ||
56 | SNDRV_PCM_FMTBIT_S18_3BE | SNDRV_PCM_FMTBIT_S20_3BE | \ | ||
57 | SNDRV_PCM_FMTBIT_S24_3BE | SNDRV_PCM_FMTBIT_S24_BE) | ||
58 | #else | ||
59 | #define FSLSSI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \ | ||
60 | SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE | \ | ||
61 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE) | ||
62 | #endif | ||
63 | |||
64 | /** | ||
65 | * fsl_ssi_private: per-SSI private data | ||
66 | * | ||
67 | * @name: short name for this device ("SSI0", "SSI1", etc) | ||
68 | * @ssi: pointer to the SSI's registers | ||
69 | * @ssi_phys: physical address of the SSI registers | ||
70 | * @irq: IRQ of this SSI | ||
71 | * @dev: struct device pointer | ||
72 | * @playback: the number of playback streams opened | ||
73 | * @capture: the number of capture streams opened | ||
74 | * @cpu_dai: the CPU DAI for this device | ||
75 | * @dev_attr: the sysfs device attribute structure | ||
76 | * @stats: SSI statistics | ||
77 | */ | ||
78 | struct fsl_ssi_private { | ||
79 | char name[8]; | ||
80 | struct ccsr_ssi __iomem *ssi; | ||
81 | dma_addr_t ssi_phys; | ||
82 | unsigned int irq; | ||
83 | struct device *dev; | ||
84 | unsigned int playback; | ||
85 | unsigned int capture; | ||
86 | struct snd_soc_cpu_dai cpu_dai; | ||
87 | struct device_attribute dev_attr; | ||
88 | |||
89 | struct { | ||
90 | unsigned int rfrc; | ||
91 | unsigned int tfrc; | ||
92 | unsigned int cmdau; | ||
93 | unsigned int cmddu; | ||
94 | unsigned int rxt; | ||
95 | unsigned int rdr1; | ||
96 | unsigned int rdr0; | ||
97 | unsigned int tde1; | ||
98 | unsigned int tde0; | ||
99 | unsigned int roe1; | ||
100 | unsigned int roe0; | ||
101 | unsigned int tue1; | ||
102 | unsigned int tue0; | ||
103 | unsigned int tfs; | ||
104 | unsigned int rfs; | ||
105 | unsigned int tls; | ||
106 | unsigned int rls; | ||
107 | unsigned int rff1; | ||
108 | unsigned int rff0; | ||
109 | unsigned int tfe1; | ||
110 | unsigned int tfe0; | ||
111 | } stats; | ||
112 | }; | ||
113 | |||
114 | /** | ||
115 | * fsl_ssi_isr: SSI interrupt handler | ||
116 | * | ||
117 | * Although it's possible to use the interrupt handler to send and receive | ||
118 | * data to/from the SSI, we use the DMA instead. Programming is more | ||
119 | * complicated, but the performance is much better. | ||
120 | * | ||
121 | * This interrupt handler is used only to gather statistics. | ||
122 | * | ||
123 | * @irq: IRQ of the SSI device | ||
124 | * @dev_id: pointer to the ssi_private structure for this SSI device | ||
125 | */ | ||
126 | static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) | ||
127 | { | ||
128 | struct fsl_ssi_private *ssi_private = dev_id; | ||
129 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; | ||
130 | irqreturn_t ret = IRQ_NONE; | ||
131 | __be32 sisr; | ||
132 | __be32 sisr2 = 0; | ||
133 | |||
134 | /* We got an interrupt, so read the status register to see what we | ||
135 | were interrupted for. We mask it with the Interrupt Enable register | ||
136 | so that we only check for events that we're interested in. | ||
137 | */ | ||
138 | sisr = in_be32(&ssi->sisr) & in_be32(&ssi->sier); | ||
139 | |||
140 | if (sisr & CCSR_SSI_SISR_RFRC) { | ||
141 | ssi_private->stats.rfrc++; | ||
142 | sisr2 |= CCSR_SSI_SISR_RFRC; | ||
143 | ret = IRQ_HANDLED; | ||
144 | } | ||
145 | |||
146 | if (sisr & CCSR_SSI_SISR_TFRC) { | ||
147 | ssi_private->stats.tfrc++; | ||
148 | sisr2 |= CCSR_SSI_SISR_TFRC; | ||
149 | ret = IRQ_HANDLED; | ||
150 | } | ||
151 | |||
152 | if (sisr & CCSR_SSI_SISR_CMDAU) { | ||
153 | ssi_private->stats.cmdau++; | ||
154 | ret = IRQ_HANDLED; | ||
155 | } | ||
156 | |||
157 | if (sisr & CCSR_SSI_SISR_CMDDU) { | ||
158 | ssi_private->stats.cmddu++; | ||
159 | ret = IRQ_HANDLED; | ||
160 | } | ||
161 | |||
162 | if (sisr & CCSR_SSI_SISR_RXT) { | ||
163 | ssi_private->stats.rxt++; | ||
164 | ret = IRQ_HANDLED; | ||
165 | } | ||
166 | |||
167 | if (sisr & CCSR_SSI_SISR_RDR1) { | ||
168 | ssi_private->stats.rdr1++; | ||
169 | ret = IRQ_HANDLED; | ||
170 | } | ||
171 | |||
172 | if (sisr & CCSR_SSI_SISR_RDR0) { | ||
173 | ssi_private->stats.rdr0++; | ||
174 | ret = IRQ_HANDLED; | ||
175 | } | ||
176 | |||
177 | if (sisr & CCSR_SSI_SISR_TDE1) { | ||
178 | ssi_private->stats.tde1++; | ||
179 | ret = IRQ_HANDLED; | ||
180 | } | ||
181 | |||
182 | if (sisr & CCSR_SSI_SISR_TDE0) { | ||
183 | ssi_private->stats.tde0++; | ||
184 | ret = IRQ_HANDLED; | ||
185 | } | ||
186 | |||
187 | if (sisr & CCSR_SSI_SISR_ROE1) { | ||
188 | ssi_private->stats.roe1++; | ||
189 | sisr2 |= CCSR_SSI_SISR_ROE1; | ||
190 | ret = IRQ_HANDLED; | ||
191 | } | ||
192 | |||
193 | if (sisr & CCSR_SSI_SISR_ROE0) { | ||
194 | ssi_private->stats.roe0++; | ||
195 | sisr2 |= CCSR_SSI_SISR_ROE0; | ||
196 | ret = IRQ_HANDLED; | ||
197 | } | ||
198 | |||
199 | if (sisr & CCSR_SSI_SISR_TUE1) { | ||
200 | ssi_private->stats.tue1++; | ||
201 | sisr2 |= CCSR_SSI_SISR_TUE1; | ||
202 | ret = IRQ_HANDLED; | ||
203 | } | ||
204 | |||
205 | if (sisr & CCSR_SSI_SISR_TUE0) { | ||
206 | ssi_private->stats.tue0++; | ||
207 | sisr2 |= CCSR_SSI_SISR_TUE0; | ||
208 | ret = IRQ_HANDLED; | ||
209 | } | ||
210 | |||
211 | if (sisr & CCSR_SSI_SISR_TFS) { | ||
212 | ssi_private->stats.tfs++; | ||
213 | ret = IRQ_HANDLED; | ||
214 | } | ||
215 | |||
216 | if (sisr & CCSR_SSI_SISR_RFS) { | ||
217 | ssi_private->stats.rfs++; | ||
218 | ret = IRQ_HANDLED; | ||
219 | } | ||
220 | |||
221 | if (sisr & CCSR_SSI_SISR_TLS) { | ||
222 | ssi_private->stats.tls++; | ||
223 | ret = IRQ_HANDLED; | ||
224 | } | ||
225 | |||
226 | if (sisr & CCSR_SSI_SISR_RLS) { | ||
227 | ssi_private->stats.rls++; | ||
228 | ret = IRQ_HANDLED; | ||
229 | } | ||
230 | |||
231 | if (sisr & CCSR_SSI_SISR_RFF1) { | ||
232 | ssi_private->stats.rff1++; | ||
233 | ret = IRQ_HANDLED; | ||
234 | } | ||
235 | |||
236 | if (sisr & CCSR_SSI_SISR_RFF0) { | ||
237 | ssi_private->stats.rff0++; | ||
238 | ret = IRQ_HANDLED; | ||
239 | } | ||
240 | |||
241 | if (sisr & CCSR_SSI_SISR_TFE1) { | ||
242 | ssi_private->stats.tfe1++; | ||
243 | ret = IRQ_HANDLED; | ||
244 | } | ||
245 | |||
246 | if (sisr & CCSR_SSI_SISR_TFE0) { | ||
247 | ssi_private->stats.tfe0++; | ||
248 | ret = IRQ_HANDLED; | ||
249 | } | ||
250 | |||
251 | /* Clear the bits that we set */ | ||
252 | if (sisr2) | ||
253 | out_be32(&ssi->sisr, sisr2); | ||
254 | |||
255 | return ret; | ||
256 | } | ||
257 | |||
258 | /** | ||
259 | * fsl_ssi_startup: create a new substream | ||
260 | * | ||
261 | * This is the first function called when a stream is opened. | ||
262 | * | ||
263 | * If this is the first stream open, then grab the IRQ and program most of | ||
264 | * the SSI registers. | ||
265 | */ | ||
266 | static int fsl_ssi_startup(struct snd_pcm_substream *substream) | ||
267 | { | ||
268 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
269 | struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data; | ||
270 | |||
271 | /* | ||
272 | * If this is the first stream opened, then request the IRQ | ||
273 | * and initialize the SSI registers. | ||
274 | */ | ||
275 | if (!ssi_private->playback && !ssi_private->capture) { | ||
276 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; | ||
277 | int ret; | ||
278 | |||
279 | ret = request_irq(ssi_private->irq, fsl_ssi_isr, 0, | ||
280 | ssi_private->name, ssi_private); | ||
281 | if (ret < 0) { | ||
282 | dev_err(substream->pcm->card->dev, | ||
283 | "could not claim irq %u\n", ssi_private->irq); | ||
284 | return ret; | ||
285 | } | ||
286 | |||
287 | /* | ||
288 | * Section 16.5 of the MPC8610 reference manual says that the | ||
289 | * SSI needs to be disabled before updating the registers we set | ||
290 | * here. | ||
291 | */ | ||
292 | clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN); | ||
293 | |||
294 | /* | ||
295 | * Program the SSI into I2S Slave Non-Network Synchronous mode. | ||
296 | * Also enable the transmit and receive FIFO. | ||
297 | * | ||
298 | * FIXME: Little-endian samples require a different shift dir | ||
299 | */ | ||
300 | clrsetbits_be32(&ssi->scr, CCSR_SSI_SCR_I2S_MODE_MASK, | ||
301 | CCSR_SSI_SCR_TFR_CLK_DIS | | ||
302 | CCSR_SSI_SCR_I2S_MODE_SLAVE | CCSR_SSI_SCR_SYN); | ||
303 | |||
304 | out_be32(&ssi->stcr, | ||
305 | CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 | | ||
306 | CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TEFS | | ||
307 | CCSR_SSI_STCR_TSCKP); | ||
308 | |||
309 | out_be32(&ssi->srcr, | ||
310 | CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFEN0 | | ||
311 | CCSR_SSI_SRCR_RFSI | CCSR_SSI_SRCR_REFS | | ||
312 | CCSR_SSI_SRCR_RSCKP); | ||
313 | |||
314 | /* | ||
315 | * The DC and PM bits are only used if the SSI is the clock | ||
316 | * master. | ||
317 | */ | ||
318 | |||
319 | /* 4. Enable the interrupts and DMA requests */ | ||
320 | out_be32(&ssi->sier, | ||
321 | CCSR_SSI_SIER_TFRC_EN | CCSR_SSI_SIER_TDMAE | | ||
322 | CCSR_SSI_SIER_TIE | CCSR_SSI_SIER_TUE0_EN | | ||
323 | CCSR_SSI_SIER_TUE1_EN | CCSR_SSI_SIER_RFRC_EN | | ||
324 | CCSR_SSI_SIER_RDMAE | CCSR_SSI_SIER_RIE | | ||
325 | CCSR_SSI_SIER_ROE0_EN | CCSR_SSI_SIER_ROE1_EN); | ||
326 | |||
327 | /* | ||
328 | * Set the watermark for transmit FIFI 0 and receive FIFO 0. We | ||
329 | * don't use FIFO 1. Since the SSI only supports stereo, the | ||
330 | * watermark should never be an odd number. | ||
331 | */ | ||
332 | out_be32(&ssi->sfcsr, | ||
333 | CCSR_SSI_SFCSR_TFWM0(6) | CCSR_SSI_SFCSR_RFWM0(2)); | ||
334 | |||
335 | /* | ||
336 | * We keep the SSI disabled because if we enable it, then the | ||
337 | * DMA controller will start. It's not supposed to start until | ||
338 | * the SCR.TE (or SCR.RE) bit is set, but it does anyway. The | ||
339 | * DMA controller will transfer one "BWC" of data (i.e. the | ||
340 | * amount of data that the MR.BWC bits are set to). The reason | ||
341 | * this is bad is because at this point, the PCM driver has not | ||
342 | * finished initializing the DMA controller. | ||
343 | */ | ||
344 | } | ||
345 | |||
346 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
347 | ssi_private->playback++; | ||
348 | |||
349 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
350 | ssi_private->capture++; | ||
351 | |||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | /** | ||
356 | * fsl_ssi_prepare: prepare the SSI. | ||
357 | * | ||
358 | * Most of the SSI registers have been programmed in the startup function, | ||
359 | * but the word length must be programmed here. Unfortunately, programming | ||
360 | * the SxCCR.WL bits requires the SSI to be temporarily disabled. This can | ||
361 | * cause a problem with supporting simultaneous playback and capture. If | ||
362 | * the SSI is already playing a stream, then that stream may be temporarily | ||
363 | * stopped when you start capture. | ||
364 | * | ||
365 | * Note: The SxCCR.DC and SxCCR.PM bits are only used if the SSI is the | ||
366 | * clock master. | ||
367 | */ | ||
368 | static int fsl_ssi_prepare(struct snd_pcm_substream *substream) | ||
369 | { | ||
370 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
371 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
372 | struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data; | ||
373 | |||
374 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; | ||
375 | u32 wl; | ||
376 | |||
377 | wl = CCSR_SSI_SxCCR_WL(snd_pcm_format_width(runtime->format)); | ||
378 | |||
379 | clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN); | ||
380 | |||
381 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
382 | clrsetbits_be32(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl); | ||
383 | else | ||
384 | clrsetbits_be32(&ssi->srccr, CCSR_SSI_SxCCR_WL_MASK, wl); | ||
385 | |||
386 | setbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN); | ||
387 | |||
388 | return 0; | ||
389 | } | ||
390 | |||
391 | /** | ||
392 | * fsl_ssi_trigger: start and stop the DMA transfer. | ||
393 | * | ||
394 | * This function is called by ALSA to start, stop, pause, and resume the DMA | ||
395 | * transfer of data. | ||
396 | * | ||
397 | * The DMA channel is in external master start and pause mode, which | ||
398 | * means the SSI completely controls the flow of data. | ||
399 | */ | ||
400 | static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd) | ||
401 | { | ||
402 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
403 | struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data; | ||
404 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; | ||
405 | |||
406 | switch (cmd) { | ||
407 | case SNDRV_PCM_TRIGGER_START: | ||
408 | case SNDRV_PCM_TRIGGER_RESUME: | ||
409 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
410 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
411 | setbits32(&ssi->scr, CCSR_SSI_SCR_TE); | ||
412 | } else { | ||
413 | setbits32(&ssi->scr, CCSR_SSI_SCR_RE); | ||
414 | |||
415 | /* | ||
416 | * I think we need this delay to allow time for the SSI | ||
417 | * to put data into its FIFO. Without it, ALSA starts | ||
418 | * to complain about overruns. | ||
419 | */ | ||
420 | msleep(1); | ||
421 | } | ||
422 | break; | ||
423 | |||
424 | case SNDRV_PCM_TRIGGER_STOP: | ||
425 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
426 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
427 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
428 | clrbits32(&ssi->scr, CCSR_SSI_SCR_TE); | ||
429 | else | ||
430 | clrbits32(&ssi->scr, CCSR_SSI_SCR_RE); | ||
431 | break; | ||
432 | |||
433 | default: | ||
434 | return -EINVAL; | ||
435 | } | ||
436 | |||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | /** | ||
441 | * fsl_ssi_shutdown: shutdown the SSI | ||
442 | * | ||
443 | * Shutdown the SSI if there are no other substreams open. | ||
444 | */ | ||
445 | static void fsl_ssi_shutdown(struct snd_pcm_substream *substream) | ||
446 | { | ||
447 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
448 | struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data; | ||
449 | |||
450 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
451 | ssi_private->playback--; | ||
452 | |||
453 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
454 | ssi_private->capture--; | ||
455 | |||
456 | /* | ||
457 | * If this is the last active substream, disable the SSI and release | ||
458 | * the IRQ. | ||
459 | */ | ||
460 | if (!ssi_private->playback && !ssi_private->capture) { | ||
461 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; | ||
462 | |||
463 | clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN); | ||
464 | |||
465 | free_irq(ssi_private->irq, ssi_private); | ||
466 | } | ||
467 | } | ||
468 | |||
469 | /** | ||
470 | * fsl_ssi_set_sysclk: set the clock frequency and direction | ||
471 | * | ||
472 | * This function is called by the machine driver to tell us what the clock | ||
473 | * frequency and direction are. | ||
474 | * | ||
475 | * Currently, we only support operating as a clock slave (SND_SOC_CLOCK_IN), | ||
476 | * and we don't care about the frequency. Return an error if the direction | ||
477 | * is not SND_SOC_CLOCK_IN. | ||
478 | * | ||
479 | * @clk_id: reserved, should be zero | ||
480 | * @freq: the frequency of the given clock ID, currently ignored | ||
481 | * @dir: SND_SOC_CLOCK_IN (clock slave) or SND_SOC_CLOCK_OUT (clock master) | ||
482 | */ | ||
483 | static int fsl_ssi_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, | ||
484 | int clk_id, unsigned int freq, int dir) | ||
485 | { | ||
486 | |||
487 | return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL; | ||
488 | } | ||
489 | |||
490 | /** | ||
491 | * fsl_ssi_set_fmt: set the serial format. | ||
492 | * | ||
493 | * This function is called by the machine driver to tell us what serial | ||
494 | * format to use. | ||
495 | * | ||
496 | * Currently, we only support I2S mode. Return an error if the format is | ||
497 | * not SND_SOC_DAIFMT_I2S. | ||
498 | * | ||
499 | * @format: one of SND_SOC_DAIFMT_xxx | ||
500 | */ | ||
501 | static int fsl_ssi_set_fmt(struct snd_soc_cpu_dai *cpu_dai, unsigned int format) | ||
502 | { | ||
503 | return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL; | ||
504 | } | ||
505 | |||
506 | /** | ||
507 | * fsl_ssi_dai_template: template CPU DAI for the SSI | ||
508 | */ | ||
509 | static struct snd_soc_cpu_dai fsl_ssi_dai_template = { | ||
510 | .playback = { | ||
511 | /* The SSI does not support monaural audio. */ | ||
512 | .channels_min = 2, | ||
513 | .channels_max = 2, | ||
514 | .rates = FSLSSI_I2S_RATES, | ||
515 | .formats = FSLSSI_I2S_FORMATS, | ||
516 | }, | ||
517 | .capture = { | ||
518 | .channels_min = 2, | ||
519 | .channels_max = 2, | ||
520 | .rates = FSLSSI_I2S_RATES, | ||
521 | .formats = FSLSSI_I2S_FORMATS, | ||
522 | }, | ||
523 | .ops = { | ||
524 | .startup = fsl_ssi_startup, | ||
525 | .prepare = fsl_ssi_prepare, | ||
526 | .shutdown = fsl_ssi_shutdown, | ||
527 | .trigger = fsl_ssi_trigger, | ||
528 | }, | ||
529 | .dai_ops = { | ||
530 | .set_sysclk = fsl_ssi_set_sysclk, | ||
531 | .set_fmt = fsl_ssi_set_fmt, | ||
532 | }, | ||
533 | }; | ||
534 | |||
535 | /** | ||
536 | * fsl_sysfs_ssi_show: display SSI statistics | ||
537 | * | ||
538 | * Display the statistics for the current SSI device. | ||
539 | */ | ||
540 | static ssize_t fsl_sysfs_ssi_show(struct device *dev, | ||
541 | struct device_attribute *attr, char *buf) | ||
542 | { | ||
543 | struct fsl_ssi_private *ssi_private = | ||
544 | container_of(attr, struct fsl_ssi_private, dev_attr); | ||
545 | ssize_t length; | ||
546 | |||
547 | length = sprintf(buf, "rfrc=%u", ssi_private->stats.rfrc); | ||
548 | length += sprintf(buf + length, "\ttfrc=%u", ssi_private->stats.tfrc); | ||
549 | length += sprintf(buf + length, "\tcmdau=%u", ssi_private->stats.cmdau); | ||
550 | length += sprintf(buf + length, "\tcmddu=%u", ssi_private->stats.cmddu); | ||
551 | length += sprintf(buf + length, "\trxt=%u", ssi_private->stats.rxt); | ||
552 | length += sprintf(buf + length, "\trdr1=%u", ssi_private->stats.rdr1); | ||
553 | length += sprintf(buf + length, "\trdr0=%u", ssi_private->stats.rdr0); | ||
554 | length += sprintf(buf + length, "\ttde1=%u", ssi_private->stats.tde1); | ||
555 | length += sprintf(buf + length, "\ttde0=%u", ssi_private->stats.tde0); | ||
556 | length += sprintf(buf + length, "\troe1=%u", ssi_private->stats.roe1); | ||
557 | length += sprintf(buf + length, "\troe0=%u", ssi_private->stats.roe0); | ||
558 | length += sprintf(buf + length, "\ttue1=%u", ssi_private->stats.tue1); | ||
559 | length += sprintf(buf + length, "\ttue0=%u", ssi_private->stats.tue0); | ||
560 | length += sprintf(buf + length, "\ttfs=%u", ssi_private->stats.tfs); | ||
561 | length += sprintf(buf + length, "\trfs=%u", ssi_private->stats.rfs); | ||
562 | length += sprintf(buf + length, "\ttls=%u", ssi_private->stats.tls); | ||
563 | length += sprintf(buf + length, "\trls=%u", ssi_private->stats.rls); | ||
564 | length += sprintf(buf + length, "\trff1=%u", ssi_private->stats.rff1); | ||
565 | length += sprintf(buf + length, "\trff0=%u", ssi_private->stats.rff0); | ||
566 | length += sprintf(buf + length, "\ttfe1=%u", ssi_private->stats.tfe1); | ||
567 | length += sprintf(buf + length, "\ttfe0=%u\n", ssi_private->stats.tfe0); | ||
568 | |||
569 | return length; | ||
570 | } | ||
571 | |||
572 | /** | ||
573 | * fsl_ssi_create_dai: create a snd_soc_cpu_dai structure | ||
574 | * | ||
575 | * This function is called by the machine driver to create a snd_soc_cpu_dai | ||
576 | * structure. The function creates an ssi_private object, which contains | ||
577 | * the snd_soc_cpu_dai. It also creates the sysfs statistics device. | ||
578 | */ | ||
579 | struct snd_soc_cpu_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info) | ||
580 | { | ||
581 | struct snd_soc_cpu_dai *fsl_ssi_dai; | ||
582 | struct fsl_ssi_private *ssi_private; | ||
583 | int ret = 0; | ||
584 | struct device_attribute *dev_attr; | ||
585 | |||
586 | ssi_private = kzalloc(sizeof(struct fsl_ssi_private), GFP_KERNEL); | ||
587 | if (!ssi_private) { | ||
588 | dev_err(ssi_info->dev, "could not allocate DAI object\n"); | ||
589 | return NULL; | ||
590 | } | ||
591 | memcpy(&ssi_private->cpu_dai, &fsl_ssi_dai_template, | ||
592 | sizeof(struct snd_soc_cpu_dai)); | ||
593 | |||
594 | fsl_ssi_dai = &ssi_private->cpu_dai; | ||
595 | dev_attr = &ssi_private->dev_attr; | ||
596 | |||
597 | sprintf(ssi_private->name, "ssi%u", (u8) ssi_info->id); | ||
598 | ssi_private->ssi = ssi_info->ssi; | ||
599 | ssi_private->ssi_phys = ssi_info->ssi_phys; | ||
600 | ssi_private->irq = ssi_info->irq; | ||
601 | ssi_private->dev = ssi_info->dev; | ||
602 | |||
603 | ssi_private->dev->driver_data = fsl_ssi_dai; | ||
604 | |||
605 | /* Initialize the the device_attribute structure */ | ||
606 | dev_attr->attr.name = "ssi-stats"; | ||
607 | dev_attr->attr.mode = S_IRUGO; | ||
608 | dev_attr->show = fsl_sysfs_ssi_show; | ||
609 | |||
610 | ret = device_create_file(ssi_private->dev, dev_attr); | ||
611 | if (ret) { | ||
612 | dev_err(ssi_info->dev, "could not create sysfs %s file\n", | ||
613 | ssi_private->dev_attr.attr.name); | ||
614 | kfree(fsl_ssi_dai); | ||
615 | return NULL; | ||
616 | } | ||
617 | |||
618 | fsl_ssi_dai->private_data = ssi_private; | ||
619 | fsl_ssi_dai->name = ssi_private->name; | ||
620 | fsl_ssi_dai->id = ssi_info->id; | ||
621 | |||
622 | return fsl_ssi_dai; | ||
623 | } | ||
624 | EXPORT_SYMBOL_GPL(fsl_ssi_create_dai); | ||
625 | |||
626 | /** | ||
627 | * fsl_ssi_destroy_dai: destroy the snd_soc_cpu_dai object | ||
628 | * | ||
629 | * This function undoes the operations of fsl_ssi_create_dai() | ||
630 | */ | ||
631 | void fsl_ssi_destroy_dai(struct snd_soc_cpu_dai *fsl_ssi_dai) | ||
632 | { | ||
633 | struct fsl_ssi_private *ssi_private = | ||
634 | container_of(fsl_ssi_dai, struct fsl_ssi_private, cpu_dai); | ||
635 | |||
636 | device_remove_file(ssi_private->dev, &ssi_private->dev_attr); | ||
637 | |||
638 | kfree(ssi_private); | ||
639 | } | ||
640 | EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai); | ||
641 | |||
642 | MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); | ||
643 | MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver"); | ||
644 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h new file mode 100644 index 000000000000..c5ce88e15651 --- /dev/null +++ b/sound/soc/fsl/fsl_ssi.h | |||
@@ -0,0 +1,224 @@ | |||
1 | /* | ||
2 | * fsl_ssi.h - ALSA SSI interface for the Freescale MPC8610 SoC | ||
3 | * | ||
4 | * Author: Timur Tabi <timur@freescale.com> | ||
5 | * | ||
6 | * Copyright 2007-2008 Freescale Semiconductor, Inc. This file is licensed | ||
7 | * under the terms of the GNU General Public License version 2. This | ||
8 | * program is licensed "as is" without any warranty of any kind, whether | ||
9 | * express or implied. | ||
10 | */ | ||
11 | |||
12 | #ifndef _MPC8610_I2S_H | ||
13 | #define _MPC8610_I2S_H | ||
14 | |||
15 | /* SSI Register Map */ | ||
16 | struct ccsr_ssi { | ||
17 | __be32 stx0; /* 0x.0000 - SSI Transmit Data Register 0 */ | ||
18 | __be32 stx1; /* 0x.0004 - SSI Transmit Data Register 1 */ | ||
19 | __be32 srx0; /* 0x.0008 - SSI Receive Data Register 0 */ | ||
20 | __be32 srx1; /* 0x.000C - SSI Receive Data Register 1 */ | ||
21 | __be32 scr; /* 0x.0010 - SSI Control Register */ | ||
22 | __be32 sisr; /* 0x.0014 - SSI Interrupt Status Register Mixed */ | ||
23 | __be32 sier; /* 0x.0018 - SSI Interrupt Enable Register */ | ||
24 | __be32 stcr; /* 0x.001C - SSI Transmit Configuration Register */ | ||
25 | __be32 srcr; /* 0x.0020 - SSI Receive Configuration Register */ | ||
26 | __be32 stccr; /* 0x.0024 - SSI Transmit Clock Control Register */ | ||
27 | __be32 srccr; /* 0x.0028 - SSI Receive Clock Control Register */ | ||
28 | __be32 sfcsr; /* 0x.002C - SSI FIFO Control/Status Register */ | ||
29 | __be32 str; /* 0x.0030 - SSI Test Register */ | ||
30 | __be32 sor; /* 0x.0034 - SSI Option Register */ | ||
31 | __be32 sacnt; /* 0x.0038 - SSI AC97 Control Register */ | ||
32 | __be32 sacadd; /* 0x.003C - SSI AC97 Command Address Register */ | ||
33 | __be32 sacdat; /* 0x.0040 - SSI AC97 Command Data Register */ | ||
34 | __be32 satag; /* 0x.0044 - SSI AC97 Tag Register */ | ||
35 | __be32 stmsk; /* 0x.0048 - SSI Transmit Time Slot Mask Register */ | ||
36 | __be32 srmsk; /* 0x.004C - SSI Receive Time Slot Mask Register */ | ||
37 | __be32 saccst; /* 0x.0050 - SSI AC97 Channel Status Register */ | ||
38 | __be32 saccen; /* 0x.0054 - SSI AC97 Channel Enable Register */ | ||
39 | __be32 saccdis; /* 0x.0058 - SSI AC97 Channel Disable Register */ | ||
40 | }; | ||
41 | |||
42 | #define CCSR_SSI_SCR_RFR_CLK_DIS 0x00000800 | ||
43 | #define CCSR_SSI_SCR_TFR_CLK_DIS 0x00000400 | ||
44 | #define CCSR_SSI_SCR_TCH_EN 0x00000100 | ||
45 | #define CCSR_SSI_SCR_SYS_CLK_EN 0x00000080 | ||
46 | #define CCSR_SSI_SCR_I2S_MODE_MASK 0x00000060 | ||
47 | #define CCSR_SSI_SCR_I2S_MODE_NORMAL 0x00000000 | ||
48 | #define CCSR_SSI_SCR_I2S_MODE_MASTER 0x00000020 | ||
49 | #define CCSR_SSI_SCR_I2S_MODE_SLAVE 0x00000040 | ||
50 | #define CCSR_SSI_SCR_SYN 0x00000010 | ||
51 | #define CCSR_SSI_SCR_NET 0x00000008 | ||
52 | #define CCSR_SSI_SCR_RE 0x00000004 | ||
53 | #define CCSR_SSI_SCR_TE 0x00000002 | ||
54 | #define CCSR_SSI_SCR_SSIEN 0x00000001 | ||
55 | |||
56 | #define CCSR_SSI_SISR_RFRC 0x01000000 | ||
57 | #define CCSR_SSI_SISR_TFRC 0x00800000 | ||
58 | #define CCSR_SSI_SISR_CMDAU 0x00040000 | ||
59 | #define CCSR_SSI_SISR_CMDDU 0x00020000 | ||
60 | #define CCSR_SSI_SISR_RXT 0x00010000 | ||
61 | #define CCSR_SSI_SISR_RDR1 0x00008000 | ||
62 | #define CCSR_SSI_SISR_RDR0 0x00004000 | ||
63 | #define CCSR_SSI_SISR_TDE1 0x00002000 | ||
64 | #define CCSR_SSI_SISR_TDE0 0x00001000 | ||
65 | #define CCSR_SSI_SISR_ROE1 0x00000800 | ||
66 | #define CCSR_SSI_SISR_ROE0 0x00000400 | ||
67 | #define CCSR_SSI_SISR_TUE1 0x00000200 | ||
68 | #define CCSR_SSI_SISR_TUE0 0x00000100 | ||
69 | #define CCSR_SSI_SISR_TFS 0x00000080 | ||
70 | #define CCSR_SSI_SISR_RFS 0x00000040 | ||
71 | #define CCSR_SSI_SISR_TLS 0x00000020 | ||
72 | #define CCSR_SSI_SISR_RLS 0x00000010 | ||
73 | #define CCSR_SSI_SISR_RFF1 0x00000008 | ||
74 | #define CCSR_SSI_SISR_RFF0 0x00000004 | ||
75 | #define CCSR_SSI_SISR_TFE1 0x00000002 | ||
76 | #define CCSR_SSI_SISR_TFE0 0x00000001 | ||
77 | |||
78 | #define CCSR_SSI_SIER_RFRC_EN 0x01000000 | ||
79 | #define CCSR_SSI_SIER_TFRC_EN 0x00800000 | ||
80 | #define CCSR_SSI_SIER_RDMAE 0x00400000 | ||
81 | #define CCSR_SSI_SIER_RIE 0x00200000 | ||
82 | #define CCSR_SSI_SIER_TDMAE 0x00100000 | ||
83 | #define CCSR_SSI_SIER_TIE 0x00080000 | ||
84 | #define CCSR_SSI_SIER_CMDAU_EN 0x00040000 | ||
85 | #define CCSR_SSI_SIER_CMDDU_EN 0x00020000 | ||
86 | #define CCSR_SSI_SIER_RXT_EN 0x00010000 | ||
87 | #define CCSR_SSI_SIER_RDR1_EN 0x00008000 | ||
88 | #define CCSR_SSI_SIER_RDR0_EN 0x00004000 | ||
89 | #define CCSR_SSI_SIER_TDE1_EN 0x00002000 | ||
90 | #define CCSR_SSI_SIER_TDE0_EN 0x00001000 | ||
91 | #define CCSR_SSI_SIER_ROE1_EN 0x00000800 | ||
92 | #define CCSR_SSI_SIER_ROE0_EN 0x00000400 | ||
93 | #define CCSR_SSI_SIER_TUE1_EN 0x00000200 | ||
94 | #define CCSR_SSI_SIER_TUE0_EN 0x00000100 | ||
95 | #define CCSR_SSI_SIER_TFS_EN 0x00000080 | ||
96 | #define CCSR_SSI_SIER_RFS_EN 0x00000040 | ||
97 | #define CCSR_SSI_SIER_TLS_EN 0x00000020 | ||
98 | #define CCSR_SSI_SIER_RLS_EN 0x00000010 | ||
99 | #define CCSR_SSI_SIER_RFF1_EN 0x00000008 | ||
100 | #define CCSR_SSI_SIER_RFF0_EN 0x00000004 | ||
101 | #define CCSR_SSI_SIER_TFE1_EN 0x00000002 | ||
102 | #define CCSR_SSI_SIER_TFE0_EN 0x00000001 | ||
103 | |||
104 | #define CCSR_SSI_STCR_TXBIT0 0x00000200 | ||
105 | #define CCSR_SSI_STCR_TFEN1 0x00000100 | ||
106 | #define CCSR_SSI_STCR_TFEN0 0x00000080 | ||
107 | #define CCSR_SSI_STCR_TFDIR 0x00000040 | ||
108 | #define CCSR_SSI_STCR_TXDIR 0x00000020 | ||
109 | #define CCSR_SSI_STCR_TSHFD 0x00000010 | ||
110 | #define CCSR_SSI_STCR_TSCKP 0x00000008 | ||
111 | #define CCSR_SSI_STCR_TFSI 0x00000004 | ||
112 | #define CCSR_SSI_STCR_TFSL 0x00000002 | ||
113 | #define CCSR_SSI_STCR_TEFS 0x00000001 | ||
114 | |||
115 | #define CCSR_SSI_SRCR_RXEXT 0x00000400 | ||
116 | #define CCSR_SSI_SRCR_RXBIT0 0x00000200 | ||
117 | #define CCSR_SSI_SRCR_RFEN1 0x00000100 | ||
118 | #define CCSR_SSI_SRCR_RFEN0 0x00000080 | ||
119 | #define CCSR_SSI_SRCR_RFDIR 0x00000040 | ||
120 | #define CCSR_SSI_SRCR_RXDIR 0x00000020 | ||
121 | #define CCSR_SSI_SRCR_RSHFD 0x00000010 | ||
122 | #define CCSR_SSI_SRCR_RSCKP 0x00000008 | ||
123 | #define CCSR_SSI_SRCR_RFSI 0x00000004 | ||
124 | #define CCSR_SSI_SRCR_RFSL 0x00000002 | ||
125 | #define CCSR_SSI_SRCR_REFS 0x00000001 | ||
126 | |||
127 | /* STCCR and SRCCR */ | ||
128 | #define CCSR_SSI_SxCCR_DIV2 0x00040000 | ||
129 | #define CCSR_SSI_SxCCR_PSR 0x00020000 | ||
130 | #define CCSR_SSI_SxCCR_WL_SHIFT 13 | ||
131 | #define CCSR_SSI_SxCCR_WL_MASK 0x0001E000 | ||
132 | #define CCSR_SSI_SxCCR_WL(x) \ | ||
133 | (((((x) / 2) - 1) << CCSR_SSI_SxCCR_WL_SHIFT) & CCSR_SSI_SxCCR_WL_MASK) | ||
134 | #define CCSR_SSI_SxCCR_DC_SHIFT 8 | ||
135 | #define CCSR_SSI_SxCCR_DC_MASK 0x00001F00 | ||
136 | #define CCSR_SSI_SxCCR_DC(x) \ | ||
137 | ((((x) - 1) << CCSR_SSI_SxCCR_DC_SHIFT) & CCSR_SSI_SxCCR_DC_MASK) | ||
138 | #define CCSR_SSI_SxCCR_PM_SHIFT 0 | ||
139 | #define CCSR_SSI_SxCCR_PM_MASK 0x000000FF | ||
140 | #define CCSR_SSI_SxCCR_PM(x) \ | ||
141 | ((((x) - 1) << CCSR_SSI_SxCCR_PM_SHIFT) & CCSR_SSI_SxCCR_PM_MASK) | ||
142 | |||
143 | /* | ||
144 | * The xFCNT bits are read-only, and the xFWM bits are read/write. Use the | ||
145 | * CCSR_SSI_SFCSR_xFCNTy() macros to read the FIFO counters, and use the | ||
146 | * CCSR_SSI_SFCSR_xFWMy() macros to set the watermarks. | ||
147 | */ | ||
148 | #define CCSR_SSI_SFCSR_RFCNT1_SHIFT 28 | ||
149 | #define CCSR_SSI_SFCSR_RFCNT1_MASK 0xF0000000 | ||
150 | #define CCSR_SSI_SFCSR_RFCNT1(x) \ | ||
151 | (((x) & CCSR_SSI_SFCSR_RFCNT1_MASK) >> CCSR_SSI_SFCSR_RFCNT1_SHIFT) | ||
152 | #define CCSR_SSI_SFCSR_TFCNT1_SHIFT 24 | ||
153 | #define CCSR_SSI_SFCSR_TFCNT1_MASK 0x0F000000 | ||
154 | #define CCSR_SSI_SFCSR_TFCNT1(x) \ | ||
155 | (((x) & CCSR_SSI_SFCSR_TFCNT1_MASK) >> CCSR_SSI_SFCSR_TFCNT1_SHIFT) | ||
156 | #define CCSR_SSI_SFCSR_RFWM1_SHIFT 20 | ||
157 | #define CCSR_SSI_SFCSR_RFWM1_MASK 0x00F00000 | ||
158 | #define CCSR_SSI_SFCSR_RFWM1(x) \ | ||
159 | (((x) << CCSR_SSI_SFCSR_RFWM1_SHIFT) & CCSR_SSI_SFCSR_RFWM1_MASK) | ||
160 | #define CCSR_SSI_SFCSR_TFWM1_SHIFT 16 | ||
161 | #define CCSR_SSI_SFCSR_TFWM1_MASK 0x000F0000 | ||
162 | #define CCSR_SSI_SFCSR_TFWM1(x) \ | ||
163 | (((x) << CCSR_SSI_SFCSR_TFWM1_SHIFT) & CCSR_SSI_SFCSR_TFWM1_MASK) | ||
164 | #define CCSR_SSI_SFCSR_RFCNT0_SHIFT 12 | ||
165 | #define CCSR_SSI_SFCSR_RFCNT0_MASK 0x0000F000 | ||
166 | #define CCSR_SSI_SFCSR_RFCNT0(x) \ | ||
167 | (((x) & CCSR_SSI_SFCSR_RFCNT0_MASK) >> CCSR_SSI_SFCSR_RFCNT0_SHIFT) | ||
168 | #define CCSR_SSI_SFCSR_TFCNT0_SHIFT 8 | ||
169 | #define CCSR_SSI_SFCSR_TFCNT0_MASK 0x00000F00 | ||
170 | #define CCSR_SSI_SFCSR_TFCNT0(x) \ | ||
171 | (((x) & CCSR_SSI_SFCSR_TFCNT0_MASK) >> CCSR_SSI_SFCSR_TFCNT0_SHIFT) | ||
172 | #define CCSR_SSI_SFCSR_RFWM0_SHIFT 4 | ||
173 | #define CCSR_SSI_SFCSR_RFWM0_MASK 0x000000F0 | ||
174 | #define CCSR_SSI_SFCSR_RFWM0(x) \ | ||
175 | (((x) << CCSR_SSI_SFCSR_RFWM0_SHIFT) & CCSR_SSI_SFCSR_RFWM0_MASK) | ||
176 | #define CCSR_SSI_SFCSR_TFWM0_SHIFT 0 | ||
177 | #define CCSR_SSI_SFCSR_TFWM0_MASK 0x0000000F | ||
178 | #define CCSR_SSI_SFCSR_TFWM0(x) \ | ||
179 | (((x) << CCSR_SSI_SFCSR_TFWM0_SHIFT) & CCSR_SSI_SFCSR_TFWM0_MASK) | ||
180 | |||
181 | #define CCSR_SSI_STR_TEST 0x00008000 | ||
182 | #define CCSR_SSI_STR_RCK2TCK 0x00004000 | ||
183 | #define CCSR_SSI_STR_RFS2TFS 0x00002000 | ||
184 | #define CCSR_SSI_STR_RXSTATE(x) (((x) >> 8) & 0x1F) | ||
185 | #define CCSR_SSI_STR_TXD2RXD 0x00000080 | ||
186 | #define CCSR_SSI_STR_TCK2RCK 0x00000040 | ||
187 | #define CCSR_SSI_STR_TFS2RFS 0x00000020 | ||
188 | #define CCSR_SSI_STR_TXSTATE(x) ((x) & 0x1F) | ||
189 | |||
190 | #define CCSR_SSI_SOR_CLKOFF 0x00000040 | ||
191 | #define CCSR_SSI_SOR_RX_CLR 0x00000020 | ||
192 | #define CCSR_SSI_SOR_TX_CLR 0x00000010 | ||
193 | #define CCSR_SSI_SOR_INIT 0x00000008 | ||
194 | #define CCSR_SSI_SOR_WAIT_SHIFT 1 | ||
195 | #define CCSR_SSI_SOR_WAIT_MASK 0x00000006 | ||
196 | #define CCSR_SSI_SOR_WAIT(x) (((x) & 3) << CCSR_SSI_SOR_WAIT_SHIFT) | ||
197 | #define CCSR_SSI_SOR_SYNRST 0x00000001 | ||
198 | |||
199 | /* Instantiation data for an SSI interface | ||
200 | * | ||
201 | * This structure contains all the information that the the SSI driver needs | ||
202 | * to instantiate an SSI interface with ALSA. The machine driver should | ||
203 | * create this structure, fill it in, call fsl_ssi_create_dai(), and then | ||
204 | * delete the structure. | ||
205 | * | ||
206 | * id: which SSI this is (0, 1, etc. ) | ||
207 | * ssi: pointer to the SSI's registers | ||
208 | * ssi_phys: physical address of the SSI registers | ||
209 | * irq: IRQ of this SSI | ||
210 | * dev: struct device, used to create the sysfs statistics file | ||
211 | */ | ||
212 | struct fsl_ssi_info { | ||
213 | unsigned int id; | ||
214 | struct ccsr_ssi __iomem *ssi; | ||
215 | dma_addr_t ssi_phys; | ||
216 | unsigned int irq; | ||
217 | struct device *dev; | ||
218 | }; | ||
219 | |||
220 | struct snd_soc_cpu_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info); | ||
221 | void fsl_ssi_destroy_dai(struct snd_soc_cpu_dai *fsl_ssi_dai); | ||
222 | |||
223 | #endif | ||
224 | |||
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c new file mode 100644 index 000000000000..f26c4b2e8b6e --- /dev/null +++ b/sound/soc/fsl/mpc8610_hpcd.c | |||
@@ -0,0 +1,631 @@ | |||
1 | /** | ||
2 | * Freescale MPC8610HPCD ALSA SoC Fabric driver | ||
3 | * | ||
4 | * Author: Timur Tabi <timur@freescale.com> | ||
5 | * | ||
6 | * Copyright 2007-2008 Freescale Semiconductor, Inc. This file is licensed | ||
7 | * under the terms of the GNU General Public License version 2. This | ||
8 | * program is licensed "as is" without any warranty of any kind, whether | ||
9 | * express or implied. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/interrupt.h> | ||
14 | #include <linux/of_device.h> | ||
15 | #include <linux/of_platform.h> | ||
16 | #include <sound/soc.h> | ||
17 | #include <asm/immap_86xx.h> | ||
18 | |||
19 | #include "../codecs/cs4270.h" | ||
20 | #include "fsl_dma.h" | ||
21 | #include "fsl_ssi.h" | ||
22 | |||
23 | /** | ||
24 | * mpc8610_hpcd_data: fabric-specific ASoC device data | ||
25 | * | ||
26 | * This structure contains data for a single sound platform device on an | ||
27 | * MPC8610 HPCD. Some of the data is taken from the device tree. | ||
28 | */ | ||
29 | struct mpc8610_hpcd_data { | ||
30 | struct snd_soc_device sound_devdata; | ||
31 | struct snd_soc_dai_link dai; | ||
32 | struct snd_soc_machine machine; | ||
33 | unsigned int dai_format; | ||
34 | unsigned int codec_clk_direction; | ||
35 | unsigned int cpu_clk_direction; | ||
36 | unsigned int clk_frequency; | ||
37 | struct ccsr_guts __iomem *guts; | ||
38 | struct ccsr_ssi __iomem *ssi; | ||
39 | unsigned int ssi_id; /* 0 = SSI1, 1 = SSI2, etc */ | ||
40 | unsigned int ssi_irq; | ||
41 | unsigned int dma_id; /* 0 = DMA1, 1 = DMA2, etc */ | ||
42 | unsigned int dma_irq[2]; | ||
43 | struct ccsr_dma_channel __iomem *dma[2]; | ||
44 | unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/ | ||
45 | }; | ||
46 | |||
47 | /** | ||
48 | * mpc8610_hpcd_machine_probe: initalize the board | ||
49 | * | ||
50 | * This function is called when platform_device_add() is called. It is used | ||
51 | * to initialize the board-specific hardware. | ||
52 | * | ||
53 | * Here we program the DMACR and PMUXCR registers. | ||
54 | */ | ||
55 | static int mpc8610_hpcd_machine_probe(struct platform_device *sound_device) | ||
56 | { | ||
57 | struct mpc8610_hpcd_data *machine_data = | ||
58 | sound_device->dev.platform_data; | ||
59 | |||
60 | /* Program the signal routing between the SSI and the DMA */ | ||
61 | guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1, | ||
62 | machine_data->dma_channel_id[0], CCSR_GUTS_DMACR_DEV_SSI); | ||
63 | guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1, | ||
64 | machine_data->dma_channel_id[1], CCSR_GUTS_DMACR_DEV_SSI); | ||
65 | |||
66 | guts_set_pmuxcr_dma(machine_data->guts, machine_data->dma_id, | ||
67 | machine_data->dma_channel_id[0], 0); | ||
68 | guts_set_pmuxcr_dma(machine_data->guts, machine_data->dma_id, | ||
69 | machine_data->dma_channel_id[1], 0); | ||
70 | |||
71 | guts_set_pmuxcr_dma(machine_data->guts, 1, 0, 0); | ||
72 | guts_set_pmuxcr_dma(machine_data->guts, 1, 3, 0); | ||
73 | guts_set_pmuxcr_dma(machine_data->guts, 0, 3, 0); | ||
74 | |||
75 | switch (machine_data->ssi_id) { | ||
76 | case 0: | ||
77 | clrsetbits_be32(&machine_data->guts->pmuxcr, | ||
78 | CCSR_GUTS_PMUXCR_SSI1_MASK, CCSR_GUTS_PMUXCR_SSI1_SSI); | ||
79 | break; | ||
80 | case 1: | ||
81 | clrsetbits_be32(&machine_data->guts->pmuxcr, | ||
82 | CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI2_SSI); | ||
83 | break; | ||
84 | } | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | /** | ||
90 | * mpc8610_hpcd_startup: program the board with various hardware parameters | ||
91 | * | ||
92 | * This function takes board-specific information, like clock frequencies | ||
93 | * and serial data formats, and passes that information to the codec and | ||
94 | * transport drivers. | ||
95 | */ | ||
96 | static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream) | ||
97 | { | ||
98 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
99 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | ||
100 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | ||
101 | struct mpc8610_hpcd_data *machine_data = | ||
102 | rtd->socdev->dev->platform_data; | ||
103 | int ret = 0; | ||
104 | |||
105 | /* Tell the CPU driver what the serial protocol is. */ | ||
106 | if (cpu_dai->dai_ops.set_fmt) { | ||
107 | ret = cpu_dai->dai_ops.set_fmt(cpu_dai, | ||
108 | machine_data->dai_format); | ||
109 | if (ret < 0) { | ||
110 | dev_err(substream->pcm->card->dev, | ||
111 | "could not set CPU driver audio format\n"); | ||
112 | return ret; | ||
113 | } | ||
114 | } | ||
115 | |||
116 | /* Tell the codec driver what the serial protocol is. */ | ||
117 | if (codec_dai->dai_ops.set_fmt) { | ||
118 | ret = codec_dai->dai_ops.set_fmt(codec_dai, | ||
119 | machine_data->dai_format); | ||
120 | if (ret < 0) { | ||
121 | dev_err(substream->pcm->card->dev, | ||
122 | "could not set codec driver audio format\n"); | ||
123 | return ret; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | /* | ||
128 | * Tell the CPU driver what the clock frequency is, and whether it's a | ||
129 | * slave or master. | ||
130 | */ | ||
131 | if (cpu_dai->dai_ops.set_sysclk) { | ||
132 | ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, 0, | ||
133 | machine_data->clk_frequency, | ||
134 | machine_data->cpu_clk_direction); | ||
135 | if (ret < 0) { | ||
136 | dev_err(substream->pcm->card->dev, | ||
137 | "could not set CPU driver clock parameters\n"); | ||
138 | return ret; | ||
139 | } | ||
140 | } | ||
141 | |||
142 | /* | ||
143 | * Tell the codec driver what the MCLK frequency is, and whether it's | ||
144 | * a slave or master. | ||
145 | */ | ||
146 | if (codec_dai->dai_ops.set_sysclk) { | ||
147 | ret = codec_dai->dai_ops.set_sysclk(codec_dai, 0, | ||
148 | machine_data->clk_frequency, | ||
149 | machine_data->codec_clk_direction); | ||
150 | if (ret < 0) { | ||
151 | dev_err(substream->pcm->card->dev, | ||
152 | "could not set codec driver clock params\n"); | ||
153 | return ret; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | /** | ||
161 | * mpc8610_hpcd_machine_remove: Remove the sound device | ||
162 | * | ||
163 | * This function is called to remove the sound device for one SSI. We | ||
164 | * de-program the DMACR and PMUXCR register. | ||
165 | */ | ||
166 | int mpc8610_hpcd_machine_remove(struct platform_device *sound_device) | ||
167 | { | ||
168 | struct mpc8610_hpcd_data *machine_data = | ||
169 | sound_device->dev.platform_data; | ||
170 | |||
171 | /* Restore the signal routing */ | ||
172 | |||
173 | guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1, | ||
174 | machine_data->dma_channel_id[0], 0); | ||
175 | guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1, | ||
176 | machine_data->dma_channel_id[1], 0); | ||
177 | |||
178 | switch (machine_data->ssi_id) { | ||
179 | case 0: | ||
180 | clrsetbits_be32(&machine_data->guts->pmuxcr, | ||
181 | CCSR_GUTS_PMUXCR_SSI1_MASK, CCSR_GUTS_PMUXCR_SSI1_LA); | ||
182 | break; | ||
183 | case 1: | ||
184 | clrsetbits_be32(&machine_data->guts->pmuxcr, | ||
185 | CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI1_LA); | ||
186 | break; | ||
187 | } | ||
188 | |||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | /** | ||
193 | * mpc8610_hpcd_ops: ASoC fabric driver operations | ||
194 | */ | ||
195 | static struct snd_soc_ops mpc8610_hpcd_ops = { | ||
196 | .startup = mpc8610_hpcd_startup, | ||
197 | }; | ||
198 | |||
199 | /** | ||
200 | * mpc8610_hpcd_machine: ASoC machine data | ||
201 | */ | ||
202 | static struct snd_soc_machine mpc8610_hpcd_machine = { | ||
203 | .probe = mpc8610_hpcd_machine_probe, | ||
204 | .remove = mpc8610_hpcd_machine_remove, | ||
205 | .name = "MPC8610 HPCD", | ||
206 | .num_links = 1, | ||
207 | }; | ||
208 | |||
209 | /** | ||
210 | * mpc8610_hpcd_probe: OF probe function for the fabric driver | ||
211 | * | ||
212 | * This function gets called when an SSI node is found in the device tree. | ||
213 | * | ||
214 | * Although this is a fabric driver, the SSI node is the "master" node with | ||
215 | * respect to audio hardware connections. Therefore, we create a new ASoC | ||
216 | * device for each new SSI node that has a codec attached. | ||
217 | * | ||
218 | * FIXME: Currently, we only support one DMA controller, so if there are | ||
219 | * multiple SSI nodes with codecs, only the first will be supported. | ||
220 | * | ||
221 | * FIXME: Even if we did support multiple DMA controllers, we have no | ||
222 | * mechanism for assigning DMA controllers and channels to the individual | ||
223 | * SSI devices. We also probably aren't compatible with the generic Elo DMA | ||
224 | * device driver. | ||
225 | */ | ||
226 | static int mpc8610_hpcd_probe(struct of_device *ofdev, | ||
227 | const struct of_device_id *match) | ||
228 | { | ||
229 | struct device_node *np = ofdev->node; | ||
230 | struct device_node *codec_np = NULL; | ||
231 | struct device_node *guts_np = NULL; | ||
232 | struct device_node *dma_np = NULL; | ||
233 | struct device_node *dma_channel_np = NULL; | ||
234 | const phandle *codec_ph; | ||
235 | const char *sprop; | ||
236 | const u32 *iprop; | ||
237 | struct resource res; | ||
238 | struct platform_device *sound_device = NULL; | ||
239 | struct mpc8610_hpcd_data *machine_data; | ||
240 | struct fsl_ssi_info ssi_info; | ||
241 | struct fsl_dma_info dma_info; | ||
242 | int ret = -ENODEV; | ||
243 | |||
244 | machine_data = kzalloc(sizeof(struct mpc8610_hpcd_data), GFP_KERNEL); | ||
245 | if (!machine_data) | ||
246 | return -ENOMEM; | ||
247 | |||
248 | memset(&ssi_info, 0, sizeof(ssi_info)); | ||
249 | memset(&dma_info, 0, sizeof(dma_info)); | ||
250 | |||
251 | ssi_info.dev = &ofdev->dev; | ||
252 | |||
253 | /* | ||
254 | * We are only interested in SSIs with a codec phandle in them, so let's | ||
255 | * make sure this SSI has one. | ||
256 | */ | ||
257 | codec_ph = of_get_property(np, "codec-handle", NULL); | ||
258 | if (!codec_ph) | ||
259 | goto error; | ||
260 | |||
261 | codec_np = of_find_node_by_phandle(*codec_ph); | ||
262 | if (!codec_np) | ||
263 | goto error; | ||
264 | |||
265 | /* The MPC8610 HPCD only knows about the CS4270 codec, so reject | ||
266 | anything else. */ | ||
267 | if (!of_device_is_compatible(codec_np, "cirrus,cs4270")) | ||
268 | goto error; | ||
269 | |||
270 | /* Get the device ID */ | ||
271 | iprop = of_get_property(np, "cell-index", NULL); | ||
272 | if (!iprop) { | ||
273 | dev_err(&ofdev->dev, "cell-index property not found\n"); | ||
274 | ret = -EINVAL; | ||
275 | goto error; | ||
276 | } | ||
277 | machine_data->ssi_id = *iprop; | ||
278 | ssi_info.id = *iprop; | ||
279 | |||
280 | /* Get the serial format and clock direction. */ | ||
281 | sprop = of_get_property(np, "fsl,mode", NULL); | ||
282 | if (!sprop) { | ||
283 | dev_err(&ofdev->dev, "fsl,mode property not found\n"); | ||
284 | ret = -EINVAL; | ||
285 | goto error; | ||
286 | } | ||
287 | |||
288 | if (strcasecmp(sprop, "i2s-slave") == 0) { | ||
289 | machine_data->dai_format = SND_SOC_DAIFMT_I2S; | ||
290 | machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT; | ||
291 | machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN; | ||
292 | |||
293 | /* | ||
294 | * In i2s-slave mode, the codec has its own clock source, so we | ||
295 | * need to get the frequency from the device tree and pass it to | ||
296 | * the codec driver. | ||
297 | */ | ||
298 | iprop = of_get_property(codec_np, "clock-frequency", NULL); | ||
299 | if (!iprop || !*iprop) { | ||
300 | dev_err(&ofdev->dev, "codec bus-frequency property " | ||
301 | "is missing or invalid\n"); | ||
302 | ret = -EINVAL; | ||
303 | goto error; | ||
304 | } | ||
305 | machine_data->clk_frequency = *iprop; | ||
306 | } else if (strcasecmp(sprop, "i2s-master") == 0) { | ||
307 | machine_data->dai_format = SND_SOC_DAIFMT_I2S; | ||
308 | machine_data->codec_clk_direction = SND_SOC_CLOCK_IN; | ||
309 | machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT; | ||
310 | } else if (strcasecmp(sprop, "lj-slave") == 0) { | ||
311 | machine_data->dai_format = SND_SOC_DAIFMT_LEFT_J; | ||
312 | machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT; | ||
313 | machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN; | ||
314 | } else if (strcasecmp(sprop, "lj-master") == 0) { | ||
315 | machine_data->dai_format = SND_SOC_DAIFMT_LEFT_J; | ||
316 | machine_data->codec_clk_direction = SND_SOC_CLOCK_IN; | ||
317 | machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT; | ||
318 | } else if (strcasecmp(sprop, "rj-master") == 0) { | ||
319 | machine_data->dai_format = SND_SOC_DAIFMT_RIGHT_J; | ||
320 | machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT; | ||
321 | machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN; | ||
322 | } else if (strcasecmp(sprop, "rj-master") == 0) { | ||
323 | machine_data->dai_format = SND_SOC_DAIFMT_RIGHT_J; | ||
324 | machine_data->codec_clk_direction = SND_SOC_CLOCK_IN; | ||
325 | machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT; | ||
326 | } else if (strcasecmp(sprop, "ac97-slave") == 0) { | ||
327 | machine_data->dai_format = SND_SOC_DAIFMT_AC97; | ||
328 | machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT; | ||
329 | machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN; | ||
330 | } else if (strcasecmp(sprop, "ac97-master") == 0) { | ||
331 | machine_data->dai_format = SND_SOC_DAIFMT_AC97; | ||
332 | machine_data->codec_clk_direction = SND_SOC_CLOCK_IN; | ||
333 | machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT; | ||
334 | } else { | ||
335 | dev_err(&ofdev->dev, | ||
336 | "unrecognized fsl,mode property \"%s\"\n", sprop); | ||
337 | ret = -EINVAL; | ||
338 | goto error; | ||
339 | } | ||
340 | |||
341 | if (!machine_data->clk_frequency) { | ||
342 | dev_err(&ofdev->dev, "unknown clock frequency\n"); | ||
343 | ret = -EINVAL; | ||
344 | goto error; | ||
345 | } | ||
346 | |||
347 | /* Read the SSI information from the device tree */ | ||
348 | ret = of_address_to_resource(np, 0, &res); | ||
349 | if (ret) { | ||
350 | dev_err(&ofdev->dev, "could not obtain SSI address\n"); | ||
351 | goto error; | ||
352 | } | ||
353 | if (!res.start) { | ||
354 | dev_err(&ofdev->dev, "invalid SSI address\n"); | ||
355 | goto error; | ||
356 | } | ||
357 | ssi_info.ssi_phys = res.start; | ||
358 | |||
359 | machine_data->ssi = ioremap(ssi_info.ssi_phys, sizeof(struct ccsr_ssi)); | ||
360 | if (!machine_data->ssi) { | ||
361 | dev_err(&ofdev->dev, "could not map SSI address %x\n", | ||
362 | ssi_info.ssi_phys); | ||
363 | ret = -EINVAL; | ||
364 | goto error; | ||
365 | } | ||
366 | ssi_info.ssi = machine_data->ssi; | ||
367 | |||
368 | |||
369 | /* Get the IRQ of the SSI */ | ||
370 | machine_data->ssi_irq = irq_of_parse_and_map(np, 0); | ||
371 | if (!machine_data->ssi_irq) { | ||
372 | dev_err(&ofdev->dev, "could not get SSI IRQ\n"); | ||
373 | ret = -EINVAL; | ||
374 | goto error; | ||
375 | } | ||
376 | ssi_info.irq = machine_data->ssi_irq; | ||
377 | |||
378 | |||
379 | /* Map the global utilities registers. */ | ||
380 | guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts"); | ||
381 | if (!guts_np) { | ||
382 | dev_err(&ofdev->dev, "could not obtain address of GUTS\n"); | ||
383 | ret = -EINVAL; | ||
384 | goto error; | ||
385 | } | ||
386 | machine_data->guts = of_iomap(guts_np, 0); | ||
387 | of_node_put(guts_np); | ||
388 | if (!machine_data->guts) { | ||
389 | dev_err(&ofdev->dev, "could not map GUTS\n"); | ||
390 | ret = -EINVAL; | ||
391 | goto error; | ||
392 | } | ||
393 | |||
394 | /* Find the DMA channels to use. For now, we always use the first DMA | ||
395 | controller. */ | ||
396 | for_each_compatible_node(dma_np, NULL, "fsl,mpc8610-dma") { | ||
397 | iprop = of_get_property(dma_np, "cell-index", NULL); | ||
398 | if (iprop && (*iprop == 0)) { | ||
399 | of_node_put(dma_np); | ||
400 | break; | ||
401 | } | ||
402 | } | ||
403 | if (!dma_np) { | ||
404 | dev_err(&ofdev->dev, "could not find DMA node\n"); | ||
405 | ret = -EINVAL; | ||
406 | goto error; | ||
407 | } | ||
408 | machine_data->dma_id = *iprop; | ||
409 | |||
410 | /* | ||
411 | * Find the DMA channels to use. For now, we always use DMA channel 0 | ||
412 | * for playback, and DMA channel 1 for capture. | ||
413 | */ | ||
414 | while ((dma_channel_np = of_get_next_child(dma_np, dma_channel_np))) { | ||
415 | iprop = of_get_property(dma_channel_np, "cell-index", NULL); | ||
416 | /* Is it DMA channel 0? */ | ||
417 | if (iprop && (*iprop == 0)) { | ||
418 | /* dma_channel[0] and dma_irq[0] are for playback */ | ||
419 | dma_info.dma_channel[0] = of_iomap(dma_channel_np, 0); | ||
420 | dma_info.dma_irq[0] = | ||
421 | irq_of_parse_and_map(dma_channel_np, 0); | ||
422 | machine_data->dma_channel_id[0] = *iprop; | ||
423 | continue; | ||
424 | } | ||
425 | if (iprop && (*iprop == 1)) { | ||
426 | /* dma_channel[1] and dma_irq[1] are for capture */ | ||
427 | dma_info.dma_channel[1] = of_iomap(dma_channel_np, 0); | ||
428 | dma_info.dma_irq[1] = | ||
429 | irq_of_parse_and_map(dma_channel_np, 0); | ||
430 | machine_data->dma_channel_id[1] = *iprop; | ||
431 | continue; | ||
432 | } | ||
433 | } | ||
434 | if (!dma_info.dma_channel[0] || !dma_info.dma_channel[1] || | ||
435 | !dma_info.dma_irq[0] || !dma_info.dma_irq[1]) { | ||
436 | dev_err(&ofdev->dev, "could not find DMA channels\n"); | ||
437 | ret = -EINVAL; | ||
438 | goto error; | ||
439 | } | ||
440 | |||
441 | dma_info.ssi_stx_phys = ssi_info.ssi_phys + | ||
442 | offsetof(struct ccsr_ssi, stx0); | ||
443 | dma_info.ssi_srx_phys = ssi_info.ssi_phys + | ||
444 | offsetof(struct ccsr_ssi, srx0); | ||
445 | |||
446 | /* We have the DMA information, so tell the DMA driver what it is */ | ||
447 | if (!fsl_dma_configure(&dma_info)) { | ||
448 | dev_err(&ofdev->dev, "could not instantiate DMA device\n"); | ||
449 | ret = -EBUSY; | ||
450 | goto error; | ||
451 | } | ||
452 | |||
453 | /* | ||
454 | * Initialize our DAI data structure. We should probably get this | ||
455 | * information from the device tree. | ||
456 | */ | ||
457 | machine_data->dai.name = "CS4270"; | ||
458 | machine_data->dai.stream_name = "CS4270"; | ||
459 | |||
460 | machine_data->dai.cpu_dai = fsl_ssi_create_dai(&ssi_info); | ||
461 | machine_data->dai.codec_dai = &cs4270_dai; /* The codec_dai we want */ | ||
462 | machine_data->dai.ops = &mpc8610_hpcd_ops; | ||
463 | |||
464 | mpc8610_hpcd_machine.dai_link = &machine_data->dai; | ||
465 | |||
466 | /* Allocate a new audio platform device structure */ | ||
467 | sound_device = platform_device_alloc("soc-audio", -1); | ||
468 | if (!sound_device) { | ||
469 | dev_err(&ofdev->dev, "platform device allocation failed\n"); | ||
470 | ret = -ENOMEM; | ||
471 | goto error; | ||
472 | } | ||
473 | |||
474 | machine_data->sound_devdata.machine = &mpc8610_hpcd_machine; | ||
475 | machine_data->sound_devdata.codec_dev = &soc_codec_device_cs4270; | ||
476 | machine_data->sound_devdata.platform = &fsl_soc_platform; | ||
477 | |||
478 | sound_device->dev.platform_data = machine_data; | ||
479 | |||
480 | |||
481 | /* Set the platform device and ASoC device to point to each other */ | ||
482 | platform_set_drvdata(sound_device, &machine_data->sound_devdata); | ||
483 | |||
484 | machine_data->sound_devdata.dev = &sound_device->dev; | ||
485 | |||
486 | |||
487 | /* Tell ASoC to probe us. This will call mpc8610_hpcd_machine.probe(), | ||
488 | if it exists. */ | ||
489 | ret = platform_device_add(sound_device); | ||
490 | |||
491 | if (ret) { | ||
492 | dev_err(&ofdev->dev, "platform device add failed\n"); | ||
493 | goto error; | ||
494 | } | ||
495 | |||
496 | dev_set_drvdata(&ofdev->dev, sound_device); | ||
497 | |||
498 | return 0; | ||
499 | |||
500 | error: | ||
501 | of_node_put(codec_np); | ||
502 | of_node_put(guts_np); | ||
503 | of_node_put(dma_np); | ||
504 | of_node_put(dma_channel_np); | ||
505 | |||
506 | if (sound_device) | ||
507 | platform_device_unregister(sound_device); | ||
508 | |||
509 | if (machine_data->dai.cpu_dai) | ||
510 | fsl_ssi_destroy_dai(machine_data->dai.cpu_dai); | ||
511 | |||
512 | if (ssi_info.ssi) | ||
513 | iounmap(ssi_info.ssi); | ||
514 | |||
515 | if (ssi_info.irq) | ||
516 | irq_dispose_mapping(ssi_info.irq); | ||
517 | |||
518 | if (dma_info.dma_channel[0]) | ||
519 | iounmap(dma_info.dma_channel[0]); | ||
520 | |||
521 | if (dma_info.dma_channel[1]) | ||
522 | iounmap(dma_info.dma_channel[1]); | ||
523 | |||
524 | if (dma_info.dma_irq[0]) | ||
525 | irq_dispose_mapping(dma_info.dma_irq[0]); | ||
526 | |||
527 | if (dma_info.dma_irq[1]) | ||
528 | irq_dispose_mapping(dma_info.dma_irq[1]); | ||
529 | |||
530 | if (machine_data->guts) | ||
531 | iounmap(machine_data->guts); | ||
532 | |||
533 | kfree(machine_data); | ||
534 | |||
535 | return ret; | ||
536 | } | ||
537 | |||
538 | /** | ||
539 | * mpc8610_hpcd_remove: remove the OF device | ||
540 | * | ||
541 | * This function is called when the OF device is removed. | ||
542 | */ | ||
543 | static int mpc8610_hpcd_remove(struct of_device *ofdev) | ||
544 | { | ||
545 | struct platform_device *sound_device = dev_get_drvdata(&ofdev->dev); | ||
546 | struct mpc8610_hpcd_data *machine_data = | ||
547 | sound_device->dev.platform_data; | ||
548 | |||
549 | platform_device_unregister(sound_device); | ||
550 | |||
551 | if (machine_data->dai.cpu_dai) | ||
552 | fsl_ssi_destroy_dai(machine_data->dai.cpu_dai); | ||
553 | |||
554 | if (machine_data->ssi) | ||
555 | iounmap(machine_data->ssi); | ||
556 | |||
557 | if (machine_data->dma[0]) | ||
558 | iounmap(machine_data->dma[0]); | ||
559 | |||
560 | if (machine_data->dma[1]) | ||
561 | iounmap(machine_data->dma[1]); | ||
562 | |||
563 | if (machine_data->dma_irq[0]) | ||
564 | irq_dispose_mapping(machine_data->dma_irq[0]); | ||
565 | |||
566 | if (machine_data->dma_irq[1]) | ||
567 | irq_dispose_mapping(machine_data->dma_irq[1]); | ||
568 | |||
569 | if (machine_data->guts) | ||
570 | iounmap(machine_data->guts); | ||
571 | |||
572 | kfree(machine_data); | ||
573 | sound_device->dev.platform_data = NULL; | ||
574 | |||
575 | dev_set_drvdata(&ofdev->dev, NULL); | ||
576 | |||
577 | return 0; | ||
578 | } | ||
579 | |||
580 | static struct of_device_id mpc8610_hpcd_match[] = { | ||
581 | { | ||
582 | .compatible = "fsl,mpc8610-ssi", | ||
583 | }, | ||
584 | {} | ||
585 | }; | ||
586 | MODULE_DEVICE_TABLE(of, mpc8610_hpcd_match); | ||
587 | |||
588 | static struct of_platform_driver mpc8610_hpcd_of_driver = { | ||
589 | .owner = THIS_MODULE, | ||
590 | .name = "mpc8610_hpcd", | ||
591 | .match_table = mpc8610_hpcd_match, | ||
592 | .probe = mpc8610_hpcd_probe, | ||
593 | .remove = mpc8610_hpcd_remove, | ||
594 | }; | ||
595 | |||
596 | /** | ||
597 | * mpc8610_hpcd_init: fabric driver initialization. | ||
598 | * | ||
599 | * This function is called when this module is loaded. | ||
600 | */ | ||
601 | static int __init mpc8610_hpcd_init(void) | ||
602 | { | ||
603 | int ret; | ||
604 | |||
605 | printk(KERN_INFO "Freescale MPC8610 HPCD ALSA SoC fabric driver\n"); | ||
606 | |||
607 | ret = of_register_platform_driver(&mpc8610_hpcd_of_driver); | ||
608 | |||
609 | if (ret) | ||
610 | printk(KERN_ERR | ||
611 | "mpc8610-hpcd: failed to register platform driver\n"); | ||
612 | |||
613 | return ret; | ||
614 | } | ||
615 | |||
616 | /** | ||
617 | * mpc8610_hpcd_exit: fabric driver exit | ||
618 | * | ||
619 | * This function is called when this driver is unloaded. | ||
620 | */ | ||
621 | static void __exit mpc8610_hpcd_exit(void) | ||
622 | { | ||
623 | of_unregister_platform_driver(&mpc8610_hpcd_of_driver); | ||
624 | } | ||
625 | |||
626 | module_init(mpc8610_hpcd_init); | ||
627 | module_exit(mpc8610_hpcd_exit); | ||
628 | |||
629 | MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); | ||
630 | MODULE_DESCRIPTION("Freescale MPC8610 HPCD ALSA SoC fabric driver"); | ||
631 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index a83e22937c27..484f883459e0 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig | |||
@@ -53,3 +53,12 @@ config SND_PXA2XX_SOC_TOSA | |||
53 | help | 53 | help |
54 | Say Y if you want to add support for SoC audio on Sharp | 54 | Say Y if you want to add support for SoC audio on Sharp |
55 | Zaurus SL-C6000x models (Tosa). | 55 | Zaurus SL-C6000x models (Tosa). |
56 | |||
57 | config SND_PXA2XX_SOC_E800 | ||
58 | tristate "SoC AC97 Audio support for e800" | ||
59 | depends on SND_PXA2XX_SOC && MACH_E800 | ||
60 | select SND_SOC_WM9712 | ||
61 | select SND_PXA2XX_SOC_AC97 | ||
62 | help | ||
63 | Say Y if you want to add support for SoC audio on the | ||
64 | Toshiba e800 PDA | ||
diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile index 78e0d6b07d1d..04e5646f75ba 100644 --- a/sound/soc/pxa/Makefile +++ b/sound/soc/pxa/Makefile | |||
@@ -11,10 +11,12 @@ obj-$(CONFIG_SND_PXA2XX_SOC_I2S) += snd-soc-pxa2xx-i2s.o | |||
11 | snd-soc-corgi-objs := corgi.o | 11 | snd-soc-corgi-objs := corgi.o |
12 | snd-soc-poodle-objs := poodle.o | 12 | snd-soc-poodle-objs := poodle.o |
13 | snd-soc-tosa-objs := tosa.o | 13 | snd-soc-tosa-objs := tosa.o |
14 | snd-soc-e800-objs := e800_wm9712.o | ||
14 | snd-soc-spitz-objs := spitz.o | 15 | snd-soc-spitz-objs := spitz.o |
15 | 16 | ||
16 | obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o | 17 | obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o |
17 | obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o | 18 | obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o |
18 | obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o | 19 | obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o |
20 | obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o | ||
19 | obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o | 21 | obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o |
20 | 22 | ||
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index 5ee51a994ac3..3f34e531bebf 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #include <linux/timer.h> | 22 | #include <linux/timer.h> |
23 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
24 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
25 | #include <sound/driver.h> | ||
26 | #include <sound/core.h> | 25 | #include <sound/core.h> |
27 | #include <sound/pcm.h> | 26 | #include <sound/pcm.h> |
28 | #include <sound/soc.h> | 27 | #include <sound/soc.h> |
diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c new file mode 100644 index 000000000000..06e8afb25277 --- /dev/null +++ b/sound/soc/pxa/e800_wm9712.c | |||
@@ -0,0 +1,89 @@ | |||
1 | /* | ||
2 | * e800-wm9712.c -- SoC audio for e800 | ||
3 | * | ||
4 | * Based on tosa.c | ||
5 | * | ||
6 | * Copyright 2007 (c) Ian Molton <spyro@f2s.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; version 2 ONLY. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/moduleparam.h> | ||
16 | #include <linux/device.h> | ||
17 | |||
18 | #include <sound/core.h> | ||
19 | #include <sound/pcm.h> | ||
20 | #include <sound/soc.h> | ||
21 | #include <sound/soc-dapm.h> | ||
22 | |||
23 | #include <asm/mach-types.h> | ||
24 | #include <asm/arch/pxa-regs.h> | ||
25 | #include <asm/arch/hardware.h> | ||
26 | #include <asm/arch/audio.h> | ||
27 | |||
28 | #include "../codecs/wm9712.h" | ||
29 | #include "pxa2xx-pcm.h" | ||
30 | #include "pxa2xx-ac97.h" | ||
31 | |||
32 | static struct snd_soc_machine e800; | ||
33 | |||
34 | static struct snd_soc_dai_link e800_dai[] = { | ||
35 | { | ||
36 | .name = "AC97 Aux", | ||
37 | .stream_name = "AC97 Aux", | ||
38 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], | ||
39 | .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX], | ||
40 | }, | ||
41 | }; | ||
42 | |||
43 | static struct snd_soc_machine e800 = { | ||
44 | .name = "Toshiba e800", | ||
45 | .dai_link = e800_dai, | ||
46 | .num_links = ARRAY_SIZE(e800_dai), | ||
47 | }; | ||
48 | |||
49 | static struct snd_soc_device e800_snd_devdata = { | ||
50 | .machine = &e800, | ||
51 | .platform = &pxa2xx_soc_platform, | ||
52 | .codec_dev = &soc_codec_dev_wm9712, | ||
53 | }; | ||
54 | |||
55 | static struct platform_device *e800_snd_device; | ||
56 | |||
57 | static int __init e800_init(void) | ||
58 | { | ||
59 | int ret; | ||
60 | |||
61 | if (!machine_is_e800()) | ||
62 | return -ENODEV; | ||
63 | |||
64 | e800_snd_device = platform_device_alloc("soc-audio", -1); | ||
65 | if (!e800_snd_device) | ||
66 | return -ENOMEM; | ||
67 | |||
68 | platform_set_drvdata(e800_snd_device, &e800_snd_devdata); | ||
69 | e800_snd_devdata.dev = &e800_snd_device->dev; | ||
70 | ret = platform_device_add(e800_snd_device); | ||
71 | |||
72 | if (ret) | ||
73 | platform_device_put(e800_snd_device); | ||
74 | |||
75 | return ret; | ||
76 | } | ||
77 | |||
78 | static void __exit e800_exit(void) | ||
79 | { | ||
80 | platform_device_unregister(e800_snd_device); | ||
81 | } | ||
82 | |||
83 | module_init(e800_init); | ||
84 | module_exit(e800_exit); | ||
85 | |||
86 | /* Module information */ | ||
87 | MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); | ||
88 | MODULE_DESCRIPTION("ALSA SoC driver for e800"); | ||
89 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index 0915cf740421..5ae59bd309a3 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c | |||
@@ -19,7 +19,6 @@ | |||
19 | #include <linux/timer.h> | 19 | #include <linux/timer.h> |
20 | #include <linux/interrupt.h> | 20 | #include <linux/interrupt.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <sound/driver.h> | ||
23 | #include <sound/core.h> | 22 | #include <sound/core.h> |
24 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
25 | #include <sound/soc.h> | 24 | #include <sound/soc.h> |
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index 60e6f4677f93..815c15336255 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c | |||
@@ -17,7 +17,6 @@ | |||
17 | #include <linux/wait.h> | 17 | #include <linux/wait.h> |
18 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
19 | 19 | ||
20 | #include <sound/driver.h> | ||
21 | #include <sound/core.h> | 20 | #include <sound/core.h> |
22 | #include <sound/pcm.h> | 21 | #include <sound/pcm.h> |
23 | #include <sound/ac97_codec.h> | 22 | #include <sound/ac97_codec.h> |
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 50c5c83f67db..692b90002489 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c | |||
@@ -18,7 +18,6 @@ | |||
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/device.h> | 19 | #include <linux/device.h> |
20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
21 | #include <sound/driver.h> | ||
22 | #include <sound/core.h> | 21 | #include <sound/core.h> |
23 | #include <sound/pcm.h> | 22 | #include <sound/pcm.h> |
24 | #include <sound/initval.h> | 23 | #include <sound/initval.h> |
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index 35e8fa3a469c..daeaa4c8b876 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c | |||
@@ -16,7 +16,6 @@ | |||
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/dma-mapping.h> | 17 | #include <linux/dma-mapping.h> |
18 | 18 | ||
19 | #include <sound/driver.h> | ||
20 | #include <sound/core.h> | 19 | #include <sound/core.h> |
21 | #include <sound/pcm.h> | 20 | #include <sound/pcm.h> |
22 | #include <sound/pcm_params.h> | 21 | #include <sound/pcm_params.h> |
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index 4dd8f35312b3..d56709e15435 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #include <linux/timer.h> | 22 | #include <linux/timer.h> |
23 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
24 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
25 | #include <sound/driver.h> | ||
26 | #include <sound/core.h> | 25 | #include <sound/core.h> |
27 | #include <sound/pcm.h> | 26 | #include <sound/pcm.h> |
28 | #include <sound/soc.h> | 27 | #include <sound/soc.h> |
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index 5504e30acf14..e4d40b528ca4 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include <linux/moduleparam.h> | 25 | #include <linux/moduleparam.h> |
26 | #include <linux/device.h> | 26 | #include <linux/device.h> |
27 | 27 | ||
28 | #include <sound/driver.h> | ||
29 | #include <sound/core.h> | 28 | #include <sound/core.h> |
30 | #include <sound/pcm.h> | 29 | #include <sound/pcm.h> |
31 | #include <sound/soc.h> | 30 | #include <sound/soc.h> |
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index 5632a2e1518d..1f6dbfc4caa8 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig | |||
@@ -10,6 +10,9 @@ config SND_S3C24XX_SOC | |||
10 | config SND_S3C24XX_SOC_I2S | 10 | config SND_S3C24XX_SOC_I2S |
11 | tristate | 11 | tristate |
12 | 12 | ||
13 | config SND_S3C2412_SOC_I2S | ||
14 | tristate | ||
15 | |||
13 | config SND_S3C2443_SOC_AC97 | 16 | config SND_S3C2443_SOC_AC97 |
14 | tristate | 17 | tristate |
15 | select AC97_BUS | 18 | select AC97_BUS |
@@ -34,4 +37,12 @@ config SND_S3C24XX_SOC_SMDK2443_WM9710 | |||
34 | Say Y if you want to add support for SoC audio on smdk2443 | 37 | Say Y if you want to add support for SoC audio on smdk2443 |
35 | with the WM9710. | 38 | with the WM9710. |
36 | 39 | ||
40 | config SND_S3C24XX_SOC_LN2440SBC_ALC650 | ||
41 | tristate "SoC AC97 Audio support for LN2440SBC - ALC650" | ||
42 | depends on SND_S3C24XX_SOC | ||
43 | select SND_S3C2443_SOC_AC97 | ||
44 | select SND_SOC_AC97_CODEC | ||
45 | help | ||
46 | Say Y if you want to add support for SoC audio on ln2440sbc | ||
47 | with the ALC650. | ||
37 | 48 | ||
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile index 13c92f0fa1e4..0aa5fb0b9700 100644 --- a/sound/soc/s3c24xx/Makefile +++ b/sound/soc/s3c24xx/Makefile | |||
@@ -1,15 +1,19 @@ | |||
1 | # S3c24XX Platform Support | 1 | # S3c24XX Platform Support |
2 | snd-soc-s3c24xx-objs := s3c24xx-pcm.o | 2 | snd-soc-s3c24xx-objs := s3c24xx-pcm.o |
3 | snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o | 3 | snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o |
4 | snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o | ||
4 | snd-soc-s3c2443-ac97-objs := s3c2443-ac97.o | 5 | snd-soc-s3c2443-ac97-objs := s3c2443-ac97.o |
5 | 6 | ||
6 | obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o | 7 | obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o |
7 | obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o | 8 | obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o |
8 | obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o | 9 | obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o |
10 | obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o | ||
9 | 11 | ||
10 | # S3C24XX Machine Support | 12 | # S3C24XX Machine Support |
11 | snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o | 13 | snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o |
12 | snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o | 14 | snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o |
15 | snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o | ||
13 | 16 | ||
14 | obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o | 17 | obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o |
15 | obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o | 18 | obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o |
19 | obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o | ||
diff --git a/sound/soc/s3c24xx/ln2440sbc_alc650.c b/sound/soc/s3c24xx/ln2440sbc_alc650.c new file mode 100644 index 000000000000..9ed8f2e8da10 --- /dev/null +++ b/sound/soc/s3c24xx/ln2440sbc_alc650.c | |||
@@ -0,0 +1,85 @@ | |||
1 | /* | ||
2 | * SoC audio for ln2440sbc | ||
3 | * | ||
4 | * Copyright 2007 KonekTel, a.s. | ||
5 | * Author: Ivan Kuten | ||
6 | * ivan.kuten@promwad.com | ||
7 | * | ||
8 | * Heavily based on smdk2443_wm9710.c | ||
9 | * Copyright 2007 Wolfson Microelectronics PLC. | ||
10 | * Author: Graeme Gregory | ||
11 | * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License version 2 as | ||
15 | * published by the Free Software Foundation. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/device.h> | ||
21 | #include <sound/core.h> | ||
22 | #include <sound/pcm.h> | ||
23 | #include <sound/soc.h> | ||
24 | #include <sound/soc-dapm.h> | ||
25 | |||
26 | #include "../codecs/ac97.h" | ||
27 | #include "s3c24xx-pcm.h" | ||
28 | #include "s3c24xx-ac97.h" | ||
29 | |||
30 | static struct snd_soc_machine ln2440sbc; | ||
31 | |||
32 | static struct snd_soc_dai_link ln2440sbc_dai[] = { | ||
33 | { | ||
34 | .name = "AC97", | ||
35 | .stream_name = "AC97 HiFi", | ||
36 | .cpu_dai = &s3c2443_ac97_dai[0], | ||
37 | .codec_dai = &ac97_dai, | ||
38 | }, | ||
39 | }; | ||
40 | |||
41 | static struct snd_soc_machine ln2440sbc = { | ||
42 | .name = "LN2440SBC", | ||
43 | .dai_link = ln2440sbc_dai, | ||
44 | .num_links = ARRAY_SIZE(ln2440sbc_dai), | ||
45 | }; | ||
46 | |||
47 | static struct snd_soc_device ln2440sbc_snd_ac97_devdata = { | ||
48 | .machine = &ln2440sbc, | ||
49 | .platform = &s3c24xx_soc_platform, | ||
50 | .codec_dev = &soc_codec_dev_ac97, | ||
51 | }; | ||
52 | |||
53 | static struct platform_device *ln2440sbc_snd_ac97_device; | ||
54 | |||
55 | static int __init ln2440sbc_init(void) | ||
56 | { | ||
57 | int ret; | ||
58 | |||
59 | ln2440sbc_snd_ac97_device = platform_device_alloc("soc-audio", -1); | ||
60 | if (!ln2440sbc_snd_ac97_device) | ||
61 | return -ENOMEM; | ||
62 | |||
63 | platform_set_drvdata(ln2440sbc_snd_ac97_device, | ||
64 | &ln2440sbc_snd_ac97_devdata); | ||
65 | ln2440sbc_snd_ac97_devdata.dev = &ln2440sbc_snd_ac97_device->dev; | ||
66 | ret = platform_device_add(ln2440sbc_snd_ac97_device); | ||
67 | |||
68 | if (ret) | ||
69 | platform_device_put(ln2440sbc_snd_ac97_device); | ||
70 | |||
71 | return ret; | ||
72 | } | ||
73 | |||
74 | static void __exit ln2440sbc_exit(void) | ||
75 | { | ||
76 | platform_device_unregister(ln2440sbc_snd_ac97_device); | ||
77 | } | ||
78 | |||
79 | module_init(ln2440sbc_init); | ||
80 | module_exit(ln2440sbc_exit); | ||
81 | |||
82 | /* Module information */ | ||
83 | MODULE_AUTHOR("Ivan Kuten"); | ||
84 | MODULE_DESCRIPTION("ALSA SoC ALC650 LN2440SBC"); | ||
85 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index f1f6b9478af9..6ee115ceb011 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #include <linux/interrupt.h> | 22 | #include <linux/interrupt.h> |
23 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
24 | #include <linux/i2c.h> | 24 | #include <linux/i2c.h> |
25 | #include <sound/driver.h> | ||
26 | #include <sound/core.h> | 25 | #include <sound/core.h> |
27 | #include <sound/pcm.h> | 26 | #include <sound/pcm.h> |
28 | #include <sound/soc.h> | 27 | #include <sound/soc.h> |
@@ -30,13 +29,15 @@ | |||
30 | 29 | ||
31 | #include <asm/mach-types.h> | 30 | #include <asm/mach-types.h> |
32 | #include <asm/hardware/scoop.h> | 31 | #include <asm/hardware/scoop.h> |
33 | #include <asm/arch/regs-iis.h> | ||
34 | #include <asm/arch/regs-clock.h> | 32 | #include <asm/arch/regs-clock.h> |
35 | #include <asm/arch/regs-gpio.h> | 33 | #include <asm/arch/regs-gpio.h> |
36 | #include <asm/hardware.h> | 34 | #include <asm/hardware.h> |
37 | #include <asm/arch/audio.h> | 35 | #include <asm/arch/audio.h> |
38 | #include <asm/io.h> | 36 | #include <asm/io.h> |
39 | #include <asm/arch/spi-gpio.h> | 37 | #include <asm/arch/spi-gpio.h> |
38 | |||
39 | #include <asm/plat-s3c24xx/regs-iis.h> | ||
40 | |||
40 | #include "../codecs/wm8753.h" | 41 | #include "../codecs/wm8753.h" |
41 | #include "lm4857.h" | 42 | #include "lm4857.h" |
42 | #include "s3c24xx-pcm.h" | 43 | #include "s3c24xx-pcm.h" |
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c new file mode 100644 index 000000000000..c4a46dd589b3 --- /dev/null +++ b/sound/soc/s3c24xx/s3c2412-i2s.c | |||
@@ -0,0 +1,744 @@ | |||
1 | /* sound/soc/s3c24xx/s3c2412-i2s.c | ||
2 | * | ||
3 | * ALSA Soc Audio Layer - S3C2412 I2S driver | ||
4 | * | ||
5 | * Copyright (c) 2006 Wolfson Microelectronics PLC. | ||
6 | * Graeme Gregory graeme.gregory@wolfsonmicro.com | ||
7 | * linux@wolfsonmicro.com | ||
8 | * | ||
9 | * Copyright (c) 2007, 2004-2005 Simtec Electronics | ||
10 | * http://armlinux.simtec.co.uk/ | ||
11 | * Ben Dooks <ben@simtec.co.uk> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License as published by the | ||
15 | * Free Software Foundation; either version 2 of the License, or (at your | ||
16 | * option) any later version. | ||
17 | */ | ||
18 | |||
19 | #include <linux/init.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/device.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/clk.h> | ||
24 | #include <linux/kernel.h> | ||
25 | |||
26 | #include <sound/core.h> | ||
27 | #include <sound/pcm.h> | ||
28 | #include <sound/pcm_params.h> | ||
29 | #include <sound/initval.h> | ||
30 | #include <sound/soc.h> | ||
31 | #include <asm/hardware.h> | ||
32 | |||
33 | #include <linux/io.h> | ||
34 | #include <asm/dma.h> | ||
35 | |||
36 | #include <asm/plat-s3c24xx/regs-s3c2412-iis.h> | ||
37 | |||
38 | #include <asm/arch/regs-gpio.h> | ||
39 | #include <asm/arch/audio.h> | ||
40 | #include <asm/arch/dma.h> | ||
41 | |||
42 | #include "s3c24xx-pcm.h" | ||
43 | #include "s3c2412-i2s.h" | ||
44 | |||
45 | #define S3C2412_I2S_DEBUG 0 | ||
46 | #define S3C2412_I2S_DEBUG_CON 0 | ||
47 | |||
48 | #if S3C2412_I2S_DEBUG | ||
49 | #define DBG(x...) printk(KERN_INFO x) | ||
50 | #else | ||
51 | #define DBG(x...) do { } while (0) | ||
52 | #endif | ||
53 | |||
54 | static struct s3c2410_dma_client s3c2412_dma_client_out = { | ||
55 | .name = "I2S PCM Stereo out" | ||
56 | }; | ||
57 | |||
58 | static struct s3c2410_dma_client s3c2412_dma_client_in = { | ||
59 | .name = "I2S PCM Stereo in" | ||
60 | }; | ||
61 | |||
62 | static struct s3c24xx_pcm_dma_params s3c2412_i2s_pcm_stereo_out = { | ||
63 | .client = &s3c2412_dma_client_out, | ||
64 | .channel = DMACH_I2S_OUT, | ||
65 | .dma_addr = S3C2410_PA_IIS + S3C2412_IISTXD, | ||
66 | .dma_size = 4, | ||
67 | }; | ||
68 | |||
69 | static struct s3c24xx_pcm_dma_params s3c2412_i2s_pcm_stereo_in = { | ||
70 | .client = &s3c2412_dma_client_in, | ||
71 | .channel = DMACH_I2S_IN, | ||
72 | .dma_addr = S3C2410_PA_IIS + S3C2412_IISRXD, | ||
73 | .dma_size = 4, | ||
74 | }; | ||
75 | |||
76 | struct s3c2412_i2s_info { | ||
77 | struct device *dev; | ||
78 | void __iomem *regs; | ||
79 | struct clk *iis_clk; | ||
80 | struct clk *iis_pclk; | ||
81 | struct clk *iis_cclk; | ||
82 | |||
83 | u32 suspend_iismod; | ||
84 | u32 suspend_iiscon; | ||
85 | u32 suspend_iispsr; | ||
86 | }; | ||
87 | |||
88 | static struct s3c2412_i2s_info s3c2412_i2s; | ||
89 | |||
90 | #define bit_set(v, b) (((v) & (b)) ? 1 : 0) | ||
91 | |||
92 | #if S3C2412_I2S_DEBUG_CON | ||
93 | static void dbg_showcon(const char *fn, u32 con) | ||
94 | { | ||
95 | printk(KERN_DEBUG "%s: LRI=%d, TXFEMPT=%d, RXFEMPT=%d, TXFFULL=%d, RXFFULL=%d\n", fn, | ||
96 | bit_set(con, S3C2412_IISCON_LRINDEX), | ||
97 | bit_set(con, S3C2412_IISCON_TXFIFO_EMPTY), | ||
98 | bit_set(con, S3C2412_IISCON_RXFIFO_EMPTY), | ||
99 | bit_set(con, S3C2412_IISCON_TXFIFO_FULL), | ||
100 | bit_set(con, S3C2412_IISCON_RXFIFO_FULL)); | ||
101 | |||
102 | printk(KERN_DEBUG "%s: PAUSE: TXDMA=%d, RXDMA=%d, TXCH=%d, RXCH=%d\n", | ||
103 | fn, | ||
104 | bit_set(con, S3C2412_IISCON_TXDMA_PAUSE), | ||
105 | bit_set(con, S3C2412_IISCON_RXDMA_PAUSE), | ||
106 | bit_set(con, S3C2412_IISCON_TXCH_PAUSE), | ||
107 | bit_set(con, S3C2412_IISCON_RXCH_PAUSE)); | ||
108 | printk(KERN_DEBUG "%s: ACTIVE: TXDMA=%d, RXDMA=%d, IIS=%d\n", fn, | ||
109 | bit_set(con, S3C2412_IISCON_TXDMA_ACTIVE), | ||
110 | bit_set(con, S3C2412_IISCON_RXDMA_ACTIVE), | ||
111 | bit_set(con, S3C2412_IISCON_IIS_ACTIVE)); | ||
112 | } | ||
113 | #else | ||
114 | static inline void dbg_showcon(const char *fn, u32 con) | ||
115 | { | ||
116 | } | ||
117 | #endif | ||
118 | |||
119 | /* Turn on or off the transmission path. */ | ||
120 | static void s3c2412_snd_txctrl(int on) | ||
121 | { | ||
122 | struct s3c2412_i2s_info *i2s = &s3c2412_i2s; | ||
123 | void __iomem *regs = i2s->regs; | ||
124 | u32 fic, con, mod; | ||
125 | |||
126 | DBG("%s(%d)\n", __func__, on); | ||
127 | |||
128 | fic = readl(regs + S3C2412_IISFIC); | ||
129 | con = readl(regs + S3C2412_IISCON); | ||
130 | mod = readl(regs + S3C2412_IISMOD); | ||
131 | |||
132 | DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); | ||
133 | |||
134 | if (on) { | ||
135 | con |= S3C2412_IISCON_TXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE; | ||
136 | con &= ~S3C2412_IISCON_TXDMA_PAUSE; | ||
137 | con &= ~S3C2412_IISCON_TXCH_PAUSE; | ||
138 | |||
139 | switch (mod & S3C2412_IISMOD_MODE_MASK) { | ||
140 | case S3C2412_IISMOD_MODE_TXONLY: | ||
141 | case S3C2412_IISMOD_MODE_TXRX: | ||
142 | /* do nothing, we are in the right mode */ | ||
143 | break; | ||
144 | |||
145 | case S3C2412_IISMOD_MODE_RXONLY: | ||
146 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
147 | mod |= S3C2412_IISMOD_MODE_TXRX; | ||
148 | break; | ||
149 | |||
150 | default: | ||
151 | dev_err(i2s->dev, "TXEN: Invalid MODE in IISMOD\n"); | ||
152 | } | ||
153 | |||
154 | writel(con, regs + S3C2412_IISCON); | ||
155 | writel(mod, regs + S3C2412_IISMOD); | ||
156 | } else { | ||
157 | /* Note, we do not have any indication that the FIFO problems | ||
158 | * tha the S3C2410/2440 had apply here, so we should be able | ||
159 | * to disable the DMA and TX without resetting the FIFOS. | ||
160 | */ | ||
161 | |||
162 | con |= S3C2412_IISCON_TXDMA_PAUSE; | ||
163 | con |= S3C2412_IISCON_TXCH_PAUSE; | ||
164 | con &= ~S3C2412_IISCON_TXDMA_ACTIVE; | ||
165 | |||
166 | switch (mod & S3C2412_IISMOD_MODE_MASK) { | ||
167 | case S3C2412_IISMOD_MODE_TXRX: | ||
168 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
169 | mod |= S3C2412_IISMOD_MODE_RXONLY; | ||
170 | break; | ||
171 | |||
172 | case S3C2412_IISMOD_MODE_TXONLY: | ||
173 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
174 | con &= ~S3C2412_IISCON_IIS_ACTIVE; | ||
175 | break; | ||
176 | |||
177 | default: | ||
178 | dev_err(i2s->dev, "TXDIS: Invalid MODE in IISMOD\n"); | ||
179 | } | ||
180 | |||
181 | writel(mod, regs + S3C2412_IISMOD); | ||
182 | writel(con, regs + S3C2412_IISCON); | ||
183 | } | ||
184 | |||
185 | fic = readl(regs + S3C2412_IISFIC); | ||
186 | dbg_showcon(__func__, con); | ||
187 | DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); | ||
188 | } | ||
189 | |||
190 | static void s3c2412_snd_rxctrl(int on) | ||
191 | { | ||
192 | struct s3c2412_i2s_info *i2s = &s3c2412_i2s; | ||
193 | void __iomem *regs = i2s->regs; | ||
194 | u32 fic, con, mod; | ||
195 | |||
196 | DBG("%s(%d)\n", __func__, on); | ||
197 | |||
198 | fic = readl(regs + S3C2412_IISFIC); | ||
199 | con = readl(regs + S3C2412_IISCON); | ||
200 | mod = readl(regs + S3C2412_IISMOD); | ||
201 | |||
202 | DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); | ||
203 | |||
204 | if (on) { | ||
205 | con |= S3C2412_IISCON_RXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE; | ||
206 | con &= ~S3C2412_IISCON_RXDMA_PAUSE; | ||
207 | con &= ~S3C2412_IISCON_RXCH_PAUSE; | ||
208 | |||
209 | switch (mod & S3C2412_IISMOD_MODE_MASK) { | ||
210 | case S3C2412_IISMOD_MODE_TXRX: | ||
211 | case S3C2412_IISMOD_MODE_RXONLY: | ||
212 | /* do nothing, we are in the right mode */ | ||
213 | break; | ||
214 | |||
215 | case S3C2412_IISMOD_MODE_TXONLY: | ||
216 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
217 | mod |= S3C2412_IISMOD_MODE_TXRX; | ||
218 | break; | ||
219 | |||
220 | default: | ||
221 | dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n"); | ||
222 | } | ||
223 | |||
224 | writel(mod, regs + S3C2412_IISMOD); | ||
225 | writel(con, regs + S3C2412_IISCON); | ||
226 | } else { | ||
227 | /* See txctrl notes on FIFOs. */ | ||
228 | |||
229 | con &= ~S3C2412_IISCON_RXDMA_ACTIVE; | ||
230 | con |= S3C2412_IISCON_RXDMA_PAUSE; | ||
231 | con |= S3C2412_IISCON_RXCH_PAUSE; | ||
232 | |||
233 | switch (mod & S3C2412_IISMOD_MODE_MASK) { | ||
234 | case S3C2412_IISMOD_MODE_RXONLY: | ||
235 | con &= ~S3C2412_IISCON_IIS_ACTIVE; | ||
236 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
237 | break; | ||
238 | |||
239 | case S3C2412_IISMOD_MODE_TXRX: | ||
240 | mod &= ~S3C2412_IISMOD_MODE_MASK; | ||
241 | mod |= S3C2412_IISMOD_MODE_TXONLY; | ||
242 | break; | ||
243 | |||
244 | default: | ||
245 | dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n"); | ||
246 | } | ||
247 | |||
248 | writel(con, regs + S3C2412_IISCON); | ||
249 | writel(mod, regs + S3C2412_IISMOD); | ||
250 | } | ||
251 | |||
252 | fic = readl(regs + S3C2412_IISFIC); | ||
253 | DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); | ||
254 | } | ||
255 | |||
256 | |||
257 | /* | ||
258 | * Wait for the LR signal to allow synchronisation to the L/R clock | ||
259 | * from the codec. May only be needed for slave mode. | ||
260 | */ | ||
261 | static int s3c2412_snd_lrsync(void) | ||
262 | { | ||
263 | u32 iiscon; | ||
264 | unsigned long timeout = jiffies + msecs_to_jiffies(5); | ||
265 | |||
266 | DBG("Entered %s\n", __func__); | ||
267 | |||
268 | while (1) { | ||
269 | iiscon = readl(s3c2412_i2s.regs + S3C2412_IISCON); | ||
270 | if (iiscon & S3C2412_IISCON_LRINDEX) | ||
271 | break; | ||
272 | |||
273 | if (timeout < jiffies) { | ||
274 | printk(KERN_ERR "%s: timeout\n", __func__); | ||
275 | return -ETIMEDOUT; | ||
276 | } | ||
277 | } | ||
278 | |||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | /* | ||
283 | * Check whether CPU is the master or slave | ||
284 | */ | ||
285 | static inline int s3c2412_snd_is_clkmaster(void) | ||
286 | { | ||
287 | u32 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD); | ||
288 | |||
289 | DBG("Entered %s\n", __func__); | ||
290 | |||
291 | iismod &= S3C2412_IISMOD_MASTER_MASK; | ||
292 | return !(iismod == S3C2412_IISMOD_SLAVE); | ||
293 | } | ||
294 | |||
295 | /* | ||
296 | * Set S3C2412 I2S DAI format | ||
297 | */ | ||
298 | static int s3c2412_i2s_set_fmt(struct snd_soc_cpu_dai *cpu_dai, | ||
299 | unsigned int fmt) | ||
300 | { | ||
301 | u32 iismod; | ||
302 | |||
303 | |||
304 | DBG("Entered %s\n", __func__); | ||
305 | |||
306 | iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD); | ||
307 | DBG("hw_params r: IISMOD: %x \n", iismod); | ||
308 | |||
309 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
310 | case SND_SOC_DAIFMT_CBM_CFM: | ||
311 | iismod &= ~S3C2412_IISMOD_MASTER_MASK; | ||
312 | iismod |= S3C2412_IISMOD_SLAVE; | ||
313 | break; | ||
314 | case SND_SOC_DAIFMT_CBS_CFS: | ||
315 | iismod &= ~S3C2412_IISMOD_MASTER_MASK; | ||
316 | iismod |= S3C2412_IISMOD_MASTER_INTERNAL; | ||
317 | break; | ||
318 | default: | ||
319 | DBG("unknwon master/slave format\n"); | ||
320 | return -EINVAL; | ||
321 | } | ||
322 | |||
323 | iismod &= ~S3C2412_IISMOD_SDF_MASK; | ||
324 | |||
325 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
326 | case SND_SOC_DAIFMT_RIGHT_J: | ||
327 | iismod |= S3C2412_IISMOD_SDF_MSB; | ||
328 | break; | ||
329 | case SND_SOC_DAIFMT_LEFT_J: | ||
330 | iismod |= S3C2412_IISMOD_SDF_LSB; | ||
331 | break; | ||
332 | case SND_SOC_DAIFMT_I2S: | ||
333 | iismod |= S3C2412_IISMOD_SDF_IIS; | ||
334 | break; | ||
335 | default: | ||
336 | DBG("Unknown data format\n"); | ||
337 | return -EINVAL; | ||
338 | } | ||
339 | |||
340 | writel(iismod, s3c2412_i2s.regs + S3C2412_IISMOD); | ||
341 | DBG("hw_params w: IISMOD: %x \n", iismod); | ||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, | ||
346 | struct snd_pcm_hw_params *params) | ||
347 | { | ||
348 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
349 | u32 iismod; | ||
350 | |||
351 | DBG("Entered %s\n", __func__); | ||
352 | |||
353 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
354 | rtd->dai->cpu_dai->dma_data = &s3c2412_i2s_pcm_stereo_out; | ||
355 | else | ||
356 | rtd->dai->cpu_dai->dma_data = &s3c2412_i2s_pcm_stereo_in; | ||
357 | |||
358 | /* Working copies of register */ | ||
359 | iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD); | ||
360 | DBG("%s: r: IISMOD: %x\n", __func__, iismod); | ||
361 | |||
362 | switch (params_format(params)) { | ||
363 | case SNDRV_PCM_FORMAT_S8: | ||
364 | iismod |= S3C2412_IISMOD_8BIT; | ||
365 | break; | ||
366 | case SNDRV_PCM_FORMAT_S16_LE: | ||
367 | iismod &= ~S3C2412_IISMOD_8BIT; | ||
368 | break; | ||
369 | } | ||
370 | |||
371 | writel(iismod, s3c2412_i2s.regs + S3C2412_IISMOD); | ||
372 | DBG("%s: w: IISMOD: %x\n", __func__, iismod); | ||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd) | ||
377 | { | ||
378 | int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | ||
379 | unsigned long irqs; | ||
380 | int ret = 0; | ||
381 | |||
382 | DBG("Entered %s\n", __func__); | ||
383 | |||
384 | switch (cmd) { | ||
385 | case SNDRV_PCM_TRIGGER_START: | ||
386 | /* On start, ensure that the FIFOs are cleared and reset. */ | ||
387 | |||
388 | writel(capture ? S3C2412_IISFIC_RXFLUSH : S3C2412_IISFIC_TXFLUSH, | ||
389 | s3c2412_i2s.regs + S3C2412_IISFIC); | ||
390 | |||
391 | /* clear again, just in case */ | ||
392 | writel(0x0, s3c2412_i2s.regs + S3C2412_IISFIC); | ||
393 | |||
394 | case SNDRV_PCM_TRIGGER_RESUME: | ||
395 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
396 | if (!s3c2412_snd_is_clkmaster()) { | ||
397 | ret = s3c2412_snd_lrsync(); | ||
398 | if (ret) | ||
399 | goto exit_err; | ||
400 | } | ||
401 | |||
402 | local_irq_save(irqs); | ||
403 | |||
404 | if (capture) | ||
405 | s3c2412_snd_rxctrl(1); | ||
406 | else | ||
407 | s3c2412_snd_txctrl(1); | ||
408 | |||
409 | local_irq_restore(irqs); | ||
410 | break; | ||
411 | |||
412 | case SNDRV_PCM_TRIGGER_STOP: | ||
413 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
414 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
415 | local_irq_save(irqs); | ||
416 | |||
417 | if (capture) | ||
418 | s3c2412_snd_rxctrl(0); | ||
419 | else | ||
420 | s3c2412_snd_txctrl(0); | ||
421 | |||
422 | local_irq_restore(irqs); | ||
423 | break; | ||
424 | default: | ||
425 | ret = -EINVAL; | ||
426 | break; | ||
427 | } | ||
428 | |||
429 | exit_err: | ||
430 | return ret; | ||
431 | } | ||
432 | |||
433 | /* default table of all avaialable root fs divisors */ | ||
434 | static unsigned int s3c2412_iis_fs[] = { 256, 512, 384, 768, 0 }; | ||
435 | |||
436 | int s3c2412_iis_calc_rate(struct s3c2412_rate_calc *info, | ||
437 | unsigned int *fstab, | ||
438 | unsigned int rate, struct clk *clk) | ||
439 | { | ||
440 | unsigned long clkrate = clk_get_rate(clk); | ||
441 | unsigned int div; | ||
442 | unsigned int fsclk; | ||
443 | unsigned int actual; | ||
444 | unsigned int fs; | ||
445 | unsigned int fsdiv; | ||
446 | signed int deviation = 0; | ||
447 | unsigned int best_fs = 0; | ||
448 | unsigned int best_div = 0; | ||
449 | unsigned int best_rate = 0; | ||
450 | unsigned int best_deviation = INT_MAX; | ||
451 | |||
452 | |||
453 | if (fstab == NULL) | ||
454 | fstab = s3c2412_iis_fs; | ||
455 | |||
456 | for (fs = 0;; fs++) { | ||
457 | fsdiv = s3c2412_iis_fs[fs]; | ||
458 | |||
459 | if (fsdiv == 0) | ||
460 | break; | ||
461 | |||
462 | fsclk = clkrate / fsdiv; | ||
463 | div = fsclk / rate; | ||
464 | |||
465 | if ((fsclk % rate) > (rate / 2)) | ||
466 | div++; | ||
467 | |||
468 | if (div <= 1) | ||
469 | continue; | ||
470 | |||
471 | actual = clkrate / (fsdiv * div); | ||
472 | deviation = actual - rate; | ||
473 | |||
474 | printk(KERN_DEBUG "%dfs: div %d => result %d, deviation %d\n", | ||
475 | fsdiv, div, actual, deviation); | ||
476 | |||
477 | deviation = abs(deviation); | ||
478 | |||
479 | if (deviation < best_deviation) { | ||
480 | best_fs = fsdiv; | ||
481 | best_div = div; | ||
482 | best_rate = actual; | ||
483 | best_deviation = deviation; | ||
484 | } | ||
485 | |||
486 | if (deviation == 0) | ||
487 | break; | ||
488 | } | ||
489 | |||
490 | printk(KERN_DEBUG "best: fs=%d, div=%d, rate=%d\n", | ||
491 | best_fs, best_div, best_rate); | ||
492 | |||
493 | info->fs_div = best_fs; | ||
494 | info->clk_div = best_div; | ||
495 | |||
496 | return 0; | ||
497 | } | ||
498 | EXPORT_SYMBOL_GPL(s3c2412_iis_calc_rate); | ||
499 | |||
500 | /* | ||
501 | * Set S3C2412 Clock source | ||
502 | */ | ||
503 | static int s3c2412_i2s_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, | ||
504 | int clk_id, unsigned int freq, int dir) | ||
505 | { | ||
506 | u32 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD); | ||
507 | |||
508 | DBG("%s(%p, %d, %u, %d)\n", __func__, cpu_dai, clk_id, | ||
509 | freq, dir); | ||
510 | |||
511 | switch (clk_id) { | ||
512 | case S3C2412_CLKSRC_PCLK: | ||
513 | iismod &= ~S3C2412_IISMOD_MASTER_MASK; | ||
514 | iismod |= S3C2412_IISMOD_MASTER_INTERNAL; | ||
515 | break; | ||
516 | case S3C2412_CLKSRC_I2SCLK: | ||
517 | iismod &= ~S3C2412_IISMOD_MASTER_MASK; | ||
518 | iismod |= S3C2412_IISMOD_MASTER_EXTERNAL; | ||
519 | break; | ||
520 | default: | ||
521 | return -EINVAL; | ||
522 | } | ||
523 | |||
524 | writel(iismod, s3c2412_i2s.regs + S3C2412_IISMOD); | ||
525 | return 0; | ||
526 | } | ||
527 | |||
528 | /* | ||
529 | * Set S3C2412 Clock dividers | ||
530 | */ | ||
531 | static int s3c2412_i2s_set_clkdiv(struct snd_soc_cpu_dai *cpu_dai, | ||
532 | int div_id, int div) | ||
533 | { | ||
534 | struct s3c2412_i2s_info *i2s = &s3c2412_i2s; | ||
535 | u32 reg; | ||
536 | |||
537 | DBG("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div); | ||
538 | |||
539 | switch (div_id) { | ||
540 | case S3C2412_DIV_BCLK: | ||
541 | reg = readl(i2s->regs + S3C2412_IISMOD); | ||
542 | reg &= ~S3C2412_IISMOD_BCLK_MASK; | ||
543 | writel(reg | div, i2s->regs + S3C2412_IISMOD); | ||
544 | |||
545 | DBG("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD)); | ||
546 | break; | ||
547 | |||
548 | case S3C2412_DIV_RCLK: | ||
549 | if (div > 3) { | ||
550 | /* convert value to bit field */ | ||
551 | |||
552 | switch (div) { | ||
553 | case 256: | ||
554 | div = S3C2412_IISMOD_RCLK_256FS; | ||
555 | break; | ||
556 | |||
557 | case 384: | ||
558 | div = S3C2412_IISMOD_RCLK_384FS; | ||
559 | break; | ||
560 | |||
561 | case 512: | ||
562 | div = S3C2412_IISMOD_RCLK_512FS; | ||
563 | break; | ||
564 | |||
565 | case 768: | ||
566 | div = S3C2412_IISMOD_RCLK_768FS; | ||
567 | break; | ||
568 | |||
569 | default: | ||
570 | return -EINVAL; | ||
571 | } | ||
572 | } | ||
573 | |||
574 | reg = readl(s3c2412_i2s.regs + S3C2412_IISMOD); | ||
575 | reg &= ~S3C2412_IISMOD_RCLK_MASK; | ||
576 | writel(reg | div, i2s->regs + S3C2412_IISMOD); | ||
577 | DBG("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD)); | ||
578 | break; | ||
579 | |||
580 | case S3C2412_DIV_PRESCALER: | ||
581 | if (div >= 0) { | ||
582 | writel((div << 8) | S3C2412_IISPSR_PSREN, | ||
583 | i2s->regs + S3C2412_IISPSR); | ||
584 | } else { | ||
585 | writel(0x0, i2s->regs + S3C2412_IISPSR); | ||
586 | } | ||
587 | DBG("%s: PSR=%08x\n", __func__, readl(i2s->regs + S3C2412_IISPSR)); | ||
588 | break; | ||
589 | |||
590 | default: | ||
591 | return -EINVAL; | ||
592 | } | ||
593 | |||
594 | return 0; | ||
595 | } | ||
596 | |||
597 | struct clk *s3c2412_get_iisclk(void) | ||
598 | { | ||
599 | return s3c2412_i2s.iis_clk; | ||
600 | } | ||
601 | EXPORT_SYMBOL_GPL(s3c2412_get_iisclk); | ||
602 | |||
603 | |||
604 | static int s3c2412_i2s_probe(struct platform_device *pdev) | ||
605 | { | ||
606 | DBG("Entered %s\n", __func__); | ||
607 | |||
608 | s3c2412_i2s.dev = &pdev->dev; | ||
609 | |||
610 | s3c2412_i2s.regs = ioremap(S3C2410_PA_IIS, 0x100); | ||
611 | if (s3c2412_i2s.regs == NULL) | ||
612 | return -ENXIO; | ||
613 | |||
614 | s3c2412_i2s.iis_pclk = clk_get(&pdev->dev, "iis"); | ||
615 | if (s3c2412_i2s.iis_pclk == NULL) { | ||
616 | DBG("failed to get iis_clock\n"); | ||
617 | iounmap(s3c2412_i2s.regs); | ||
618 | return -ENODEV; | ||
619 | } | ||
620 | |||
621 | s3c2412_i2s.iis_cclk = clk_get(&pdev->dev, "i2sclk"); | ||
622 | if (s3c2412_i2s.iis_cclk == NULL) { | ||
623 | DBG("failed to get i2sclk clock\n"); | ||
624 | iounmap(s3c2412_i2s.regs); | ||
625 | return -ENODEV; | ||
626 | } | ||
627 | |||
628 | clk_set_parent(s3c2412_i2s.iis_cclk, clk_get(NULL, "mpll")); | ||
629 | |||
630 | clk_enable(s3c2412_i2s.iis_pclk); | ||
631 | clk_enable(s3c2412_i2s.iis_cclk); | ||
632 | |||
633 | s3c2412_i2s.iis_clk = s3c2412_i2s.iis_pclk; | ||
634 | |||
635 | /* Configure the I2S pins in correct mode */ | ||
636 | s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK); | ||
637 | s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2410_GPE1_I2SSCLK); | ||
638 | s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2410_GPE2_CDCLK); | ||
639 | s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI); | ||
640 | s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO); | ||
641 | |||
642 | s3c2412_snd_txctrl(0); | ||
643 | s3c2412_snd_rxctrl(0); | ||
644 | |||
645 | return 0; | ||
646 | } | ||
647 | |||
648 | #ifdef CONFIG_PM | ||
649 | static int s3c2412_i2s_suspend(struct platform_device *dev, | ||
650 | struct snd_soc_cpu_dai *dai) | ||
651 | { | ||
652 | struct s3c2412_i2s_info *i2s = &s3c2412_i2s; | ||
653 | u32 iismod; | ||
654 | |||
655 | if (dai->active) { | ||
656 | i2s->suspend_iismod = readl(i2s->regs + S3C2412_IISMOD); | ||
657 | i2s->suspend_iiscon = readl(i2s->regs + S3C2412_IISCON); | ||
658 | i2s->suspend_iispsr = readl(i2s->regs + S3C2412_IISPSR); | ||
659 | |||
660 | /* some basic suspend checks */ | ||
661 | |||
662 | iismod = readl(i2s->regs + S3C2412_IISMOD); | ||
663 | |||
664 | if (iismod & S3C2412_IISCON_RXDMA_ACTIVE) | ||
665 | dev_warn(&dev->dev, "%s: RXDMA active?\n", __func__); | ||
666 | |||
667 | if (iismod & S3C2412_IISCON_TXDMA_ACTIVE) | ||
668 | dev_warn(&dev->dev, "%s: TXDMA active?\n", __func__); | ||
669 | |||
670 | if (iismod & S3C2412_IISCON_IIS_ACTIVE) | ||
671 | dev_warn(&dev->dev, "%s: IIS active\n", __func__); | ||
672 | } | ||
673 | |||
674 | return 0; | ||
675 | } | ||
676 | |||
677 | static int s3c2412_i2s_resume(struct platform_device *pdev, | ||
678 | struct snd_soc_cpu_dai *dai) | ||
679 | { | ||
680 | struct s3c2412_i2s_info *i2s = &s3c2412_i2s; | ||
681 | |||
682 | dev_info(&pdev->dev, "dai_active %d, IISMOD %08x, IISCON %08x\n", | ||
683 | dai->active, i2s->suspend_iismod, i2s->suspend_iiscon); | ||
684 | |||
685 | if (dai->active) { | ||
686 | writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON); | ||
687 | writel(i2s->suspend_iismod, i2s->regs + S3C2412_IISMOD); | ||
688 | writel(i2s->suspend_iispsr, i2s->regs + S3C2412_IISPSR); | ||
689 | |||
690 | writel(S3C2412_IISFIC_RXFLUSH | S3C2412_IISFIC_TXFLUSH, | ||
691 | i2s->regs + S3C2412_IISFIC); | ||
692 | |||
693 | ndelay(250); | ||
694 | writel(0x0, i2s->regs + S3C2412_IISFIC); | ||
695 | |||
696 | } | ||
697 | |||
698 | return 0; | ||
699 | } | ||
700 | #else | ||
701 | #define s3c2412_i2s_suspend NULL | ||
702 | #define s3c2412_i2s_resume NULL | ||
703 | #endif /* CONFIG_PM */ | ||
704 | |||
705 | #define S3C2412_I2S_RATES \ | ||
706 | (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ | ||
707 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | ||
708 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | ||
709 | |||
710 | struct snd_soc_cpu_dai s3c2412_i2s_dai = { | ||
711 | .name = "s3c2412-i2s", | ||
712 | .id = 0, | ||
713 | .type = SND_SOC_DAI_I2S, | ||
714 | .probe = s3c2412_i2s_probe, | ||
715 | .suspend = s3c2412_i2s_suspend, | ||
716 | .resume = s3c2412_i2s_resume, | ||
717 | .playback = { | ||
718 | .channels_min = 2, | ||
719 | .channels_max = 2, | ||
720 | .rates = S3C2412_I2S_RATES, | ||
721 | .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE, | ||
722 | }, | ||
723 | .capture = { | ||
724 | .channels_min = 2, | ||
725 | .channels_max = 2, | ||
726 | .rates = S3C2412_I2S_RATES, | ||
727 | .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE, | ||
728 | }, | ||
729 | .ops = { | ||
730 | .trigger = s3c2412_i2s_trigger, | ||
731 | .hw_params = s3c2412_i2s_hw_params, | ||
732 | }, | ||
733 | .dai_ops = { | ||
734 | .set_fmt = s3c2412_i2s_set_fmt, | ||
735 | .set_clkdiv = s3c2412_i2s_set_clkdiv, | ||
736 | .set_sysclk = s3c2412_i2s_set_sysclk, | ||
737 | }, | ||
738 | }; | ||
739 | EXPORT_SYMBOL_GPL(s3c2412_i2s_dai); | ||
740 | |||
741 | /* Module information */ | ||
742 | MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); | ||
743 | MODULE_DESCRIPTION("S3C2412 I2S SoC Interface"); | ||
744 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.h b/sound/soc/s3c24xx/s3c2412-i2s.h new file mode 100644 index 000000000000..27f48e1ffa86 --- /dev/null +++ b/sound/soc/s3c24xx/s3c2412-i2s.h | |||
@@ -0,0 +1,38 @@ | |||
1 | /* sound/soc/s3c24xx/s3c2412-i2s.c | ||
2 | * | ||
3 | * ALSA Soc Audio Layer - S3C2412 I2S driver | ||
4 | * | ||
5 | * Copyright (c) 2007 Simtec Electronics | ||
6 | * http://armlinux.simtec.co.uk/ | ||
7 | * Ben Dooks <ben@simtec.co.uk> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | */ | ||
14 | |||
15 | #ifndef __SND_SOC_S3C24XX_S3C2412_I2S_H | ||
16 | #define __SND_SOC_S3C24XX_S3C2412_I2S_H __FILE__ | ||
17 | |||
18 | #define S3C2412_DIV_BCLK (1) | ||
19 | #define S3C2412_DIV_RCLK (2) | ||
20 | #define S3C2412_DIV_PRESCALER (3) | ||
21 | |||
22 | #define S3C2412_CLKSRC_PCLK (0) | ||
23 | #define S3C2412_CLKSRC_I2SCLK (1) | ||
24 | |||
25 | extern struct clk *s3c2412_get_iisclk(void); | ||
26 | |||
27 | extern struct snd_soc_cpu_dai s3c2412_i2s_dai; | ||
28 | |||
29 | struct s3c2412_rate_calc { | ||
30 | unsigned int clk_div; /* for prescaler */ | ||
31 | unsigned int fs_div; /* for root frame clock */ | ||
32 | }; | ||
33 | |||
34 | extern int s3c2412_iis_calc_rate(struct s3c2412_rate_calc *info, | ||
35 | unsigned int *fstab, | ||
36 | unsigned int rate, struct clk *clk); | ||
37 | |||
38 | #endif /* __SND_SOC_S3C24XX_S3C2412_I2S_H */ | ||
diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index 758a2637e7ac..1c1ddbf7f3c0 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
24 | #include <linux/clk.h> | 24 | #include <linux/clk.h> |
25 | 25 | ||
26 | #include <sound/driver.h> | ||
27 | #include <sound/core.h> | 26 | #include <sound/core.h> |
28 | #include <sound/pcm.h> | 27 | #include <sound/pcm.h> |
29 | #include <sound/ac97_codec.h> | 28 | #include <sound/ac97_codec.h> |
@@ -253,7 +252,7 @@ static int s3c2443_ac97_probe(struct platform_device *pdev) | |||
253 | ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE; | 252 | ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE; |
254 | writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | 253 | writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); |
255 | 254 | ||
256 | ret = request_irq(IRQ_S3C2443_AC97, s3c2443_ac97_irq, | 255 | ret = request_irq(IRQ_S3C244x_AC97, s3c2443_ac97_irq, |
257 | IRQF_DISABLED, "AC97", NULL); | 256 | IRQF_DISABLED, "AC97", NULL); |
258 | if (ret < 0) { | 257 | if (ret < 0) { |
259 | printk(KERN_ERR "s3c24xx-ac97: interrupt request failed.\n"); | 258 | printk(KERN_ERR "s3c24xx-ac97: interrupt request failed.\n"); |
@@ -266,7 +265,7 @@ static int s3c2443_ac97_probe(struct platform_device *pdev) | |||
266 | 265 | ||
267 | static void s3c2443_ac97_remove(struct platform_device *pdev) | 266 | static void s3c2443_ac97_remove(struct platform_device *pdev) |
268 | { | 267 | { |
269 | free_irq(IRQ_S3C2443_AC97, NULL); | 268 | free_irq(IRQ_S3C244x_AC97, NULL); |
270 | clk_disable(s3c24xx_ac97.ac97_clk); | 269 | clk_disable(s3c24xx_ac97.ac97_clk); |
271 | clk_put(s3c24xx_ac97.ac97_clk); | 270 | clk_put(s3c24xx_ac97.ac97_clk); |
272 | iounmap(s3c24xx_ac97.regs); | 271 | iounmap(s3c24xx_ac97.regs); |
diff --git a/sound/soc/s3c24xx/s3c24xx-ac97.h b/sound/soc/s3c24xx/s3c24xx-ac97.h index 2b835e8260fa..bf03e8ed16c3 100644 --- a/sound/soc/s3c24xx/s3c24xx-ac97.h +++ b/sound/soc/s3c24xx/s3c24xx-ac97.h | |||
@@ -20,6 +20,12 @@ | |||
20 | #define AC_CMD_ADDR(x) (x << 16) | 20 | #define AC_CMD_ADDR(x) (x << 16) |
21 | #define AC_CMD_DATA(x) (x & 0xffff) | 21 | #define AC_CMD_DATA(x) (x & 0xffff) |
22 | 22 | ||
23 | #ifdef CONFIG_CPU_S3C2440 | ||
24 | #define IRQ_S3C244x_AC97 IRQ_S3C2440_AC97 | ||
25 | #else | ||
26 | #define IRQ_S3C244x_AC97 IRQ_S3C2443_AC97 | ||
27 | #endif | ||
28 | |||
23 | extern struct snd_soc_cpu_dai s3c2443_ac97_dai[]; | 29 | extern struct snd_soc_cpu_dai s3c2443_ac97_dai[]; |
24 | 30 | ||
25 | #endif /*S3C24XXAC97_H_*/ | 31 | #endif /*S3C24XXAC97_H_*/ |
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index cd89c4105fcd..0a3c630951be 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c | |||
@@ -24,7 +24,7 @@ | |||
24 | #include <linux/device.h> | 24 | #include <linux/device.h> |
25 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
26 | #include <linux/clk.h> | 26 | #include <linux/clk.h> |
27 | #include <sound/driver.h> | 27 | #include <linux/jiffies.h> |
28 | #include <sound/core.h> | 28 | #include <sound/core.h> |
29 | #include <sound/pcm.h> | 29 | #include <sound/pcm.h> |
30 | #include <sound/pcm_params.h> | 30 | #include <sound/pcm_params.h> |
@@ -33,13 +33,14 @@ | |||
33 | 33 | ||
34 | #include <asm/hardware.h> | 34 | #include <asm/hardware.h> |
35 | #include <asm/io.h> | 35 | #include <asm/io.h> |
36 | #include <asm/arch/regs-iis.h> | ||
37 | #include <asm/arch/regs-gpio.h> | 36 | #include <asm/arch/regs-gpio.h> |
38 | #include <asm/arch/regs-clock.h> | 37 | #include <asm/arch/regs-clock.h> |
39 | #include <asm/arch/audio.h> | 38 | #include <asm/arch/audio.h> |
40 | #include <asm/dma.h> | 39 | #include <asm/dma.h> |
41 | #include <asm/arch/dma.h> | 40 | #include <asm/arch/dma.h> |
42 | 41 | ||
42 | #include <asm/plat-s3c24xx/regs-iis.h> | ||
43 | |||
43 | #include "s3c24xx-pcm.h" | 44 | #include "s3c24xx-pcm.h" |
44 | #include "s3c24xx-i2s.h" | 45 | #include "s3c24xx-i2s.h" |
45 | 46 | ||
@@ -75,6 +76,10 @@ static struct s3c24xx_pcm_dma_params s3c24xx_i2s_pcm_stereo_in = { | |||
75 | struct s3c24xx_i2s_info { | 76 | struct s3c24xx_i2s_info { |
76 | void __iomem *regs; | 77 | void __iomem *regs; |
77 | struct clk *iis_clk; | 78 | struct clk *iis_clk; |
79 | u32 iiscon; | ||
80 | u32 iismod; | ||
81 | u32 iisfcon; | ||
82 | u32 iispsr; | ||
78 | }; | 83 | }; |
79 | static struct s3c24xx_i2s_info s3c24xx_i2s; | 84 | static struct s3c24xx_i2s_info s3c24xx_i2s; |
80 | 85 | ||
@@ -184,7 +189,7 @@ static int s3c24xx_snd_lrsync(void) | |||
184 | if (iiscon & S3C2410_IISCON_LRINDEX) | 189 | if (iiscon & S3C2410_IISCON_LRINDEX) |
185 | break; | 190 | break; |
186 | 191 | ||
187 | if (timeout < jiffies) | 192 | if (time_after(jiffies, timeout)) |
188 | return -ETIMEDOUT; | 193 | return -ETIMEDOUT; |
189 | } | 194 | } |
190 | 195 | ||
@@ -405,6 +410,38 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev) | |||
405 | return 0; | 410 | return 0; |
406 | } | 411 | } |
407 | 412 | ||
413 | #ifdef CONFIG_PM | ||
414 | int s3c24xx_i2s_suspend(struct platform_device *pdev, | ||
415 | struct snd_soc_cpu_dai *cpu_dai) | ||
416 | { | ||
417 | s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); | ||
418 | s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); | ||
419 | s3c24xx_i2s.iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); | ||
420 | s3c24xx_i2s.iispsr = readl(s3c24xx_i2s.regs + S3C2410_IISPSR); | ||
421 | |||
422 | clk_disable(s3c24xx_i2s.iis_clk); | ||
423 | |||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | int s3c24xx_i2s_resume(struct platform_device *pdev, | ||
428 | struct snd_soc_cpu_dai *cpu_dai) | ||
429 | { | ||
430 | clk_enable(s3c24xx_i2s.iis_clk); | ||
431 | |||
432 | writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON); | ||
433 | writel(s3c24xx_i2s.iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); | ||
434 | writel(s3c24xx_i2s.iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON); | ||
435 | writel(s3c24xx_i2s.iispsr, s3c24xx_i2s.regs + S3C2410_IISPSR); | ||
436 | |||
437 | return 0; | ||
438 | } | ||
439 | #else | ||
440 | #define s3c24xx_i2s_suspend NULL | ||
441 | #define s3c24xx_i2s_resume NULL | ||
442 | #endif | ||
443 | |||
444 | |||
408 | #define S3C24XX_I2S_RATES \ | 445 | #define S3C24XX_I2S_RATES \ |
409 | (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ | 446 | (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ |
410 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | 447 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ |
@@ -415,6 +452,8 @@ struct snd_soc_cpu_dai s3c24xx_i2s_dai = { | |||
415 | .id = 0, | 452 | .id = 0, |
416 | .type = SND_SOC_DAI_I2S, | 453 | .type = SND_SOC_DAI_I2S, |
417 | .probe = s3c24xx_i2s_probe, | 454 | .probe = s3c24xx_i2s_probe, |
455 | .suspend = s3c24xx_i2s_suspend, | ||
456 | .resume = s3c24xx_i2s_resume, | ||
418 | .playback = { | 457 | .playback = { |
419 | .channels_min = 2, | 458 | .channels_min = 2, |
420 | .channels_max = 2, | 459 | .channels_max = 2, |
diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index 4107a87d4de3..29a6c82f873a 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c | |||
@@ -24,7 +24,6 @@ | |||
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <linux/dma-mapping.h> | 25 | #include <linux/dma-mapping.h> |
26 | 26 | ||
27 | #include <sound/driver.h> | ||
28 | #include <sound/core.h> | 27 | #include <sound/core.h> |
29 | #include <sound/pcm.h> | 28 | #include <sound/pcm.h> |
30 | #include <sound/pcm_params.h> | 29 | #include <sound/pcm_params.h> |
@@ -49,7 +48,9 @@ static const struct snd_pcm_hardware s3c24xx_pcm_hardware = { | |||
49 | .info = SNDRV_PCM_INFO_INTERLEAVED | | 48 | .info = SNDRV_PCM_INFO_INTERLEAVED | |
50 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 49 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
51 | SNDRV_PCM_INFO_MMAP | | 50 | SNDRV_PCM_INFO_MMAP | |
52 | SNDRV_PCM_INFO_MMAP_VALID, | 51 | SNDRV_PCM_INFO_MMAP_VALID | |
52 | SNDRV_PCM_INFO_PAUSE | | ||
53 | SNDRV_PCM_INFO_RESUME, | ||
53 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | 54 | .formats = SNDRV_PCM_FMTBIT_S16_LE | |
54 | SNDRV_PCM_FMTBIT_U16_LE | | 55 | SNDRV_PCM_FMTBIT_U16_LE | |
55 | SNDRV_PCM_FMTBIT_U8 | | 56 | SNDRV_PCM_FMTBIT_U8 | |
@@ -176,28 +177,6 @@ static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream, | |||
176 | } | 177 | } |
177 | } | 178 | } |
178 | 179 | ||
179 | /* channel needs configuring for mem=>device, increment memory addr, | ||
180 | * sync to pclk, half-word transfers to the IIS-FIFO. */ | ||
181 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
182 | s3c2410_dma_devconfig(prtd->params->channel, | ||
183 | S3C2410_DMASRC_MEM, S3C2410_DISRCC_INC | | ||
184 | S3C2410_DISRCC_APB, prtd->params->dma_addr); | ||
185 | |||
186 | s3c2410_dma_config(prtd->params->channel, | ||
187 | prtd->params->dma_size, | ||
188 | S3C2410_DCON_SYNC_PCLK | | ||
189 | S3C2410_DCON_HANDSHAKE); | ||
190 | } else { | ||
191 | s3c2410_dma_config(prtd->params->channel, | ||
192 | prtd->params->dma_size, | ||
193 | S3C2410_DCON_HANDSHAKE | | ||
194 | S3C2410_DCON_SYNC_PCLK); | ||
195 | |||
196 | s3c2410_dma_devconfig(prtd->params->channel, | ||
197 | S3C2410_DMASRC_HW, 0x3, | ||
198 | prtd->params->dma_addr); | ||
199 | } | ||
200 | |||
201 | s3c2410_dma_set_buffdone_fn(prtd->params->channel, | 180 | s3c2410_dma_set_buffdone_fn(prtd->params->channel, |
202 | s3c24xx_audio_buffdone); | 181 | s3c24xx_audio_buffdone); |
203 | 182 | ||
@@ -246,6 +225,28 @@ static int s3c24xx_pcm_prepare(struct snd_pcm_substream *substream) | |||
246 | if (!prtd->params) | 225 | if (!prtd->params) |
247 | return 0; | 226 | return 0; |
248 | 227 | ||
228 | /* channel needs configuring for mem=>device, increment memory addr, | ||
229 | * sync to pclk, half-word transfers to the IIS-FIFO. */ | ||
230 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
231 | s3c2410_dma_devconfig(prtd->params->channel, | ||
232 | S3C2410_DMASRC_MEM, S3C2410_DISRCC_INC | | ||
233 | S3C2410_DISRCC_APB, prtd->params->dma_addr); | ||
234 | |||
235 | s3c2410_dma_config(prtd->params->channel, | ||
236 | prtd->params->dma_size, | ||
237 | S3C2410_DCON_SYNC_PCLK | | ||
238 | S3C2410_DCON_HANDSHAKE); | ||
239 | } else { | ||
240 | s3c2410_dma_config(prtd->params->channel, | ||
241 | prtd->params->dma_size, | ||
242 | S3C2410_DCON_HANDSHAKE | | ||
243 | S3C2410_DCON_SYNC_PCLK); | ||
244 | |||
245 | s3c2410_dma_devconfig(prtd->params->channel, | ||
246 | S3C2410_DMASRC_HW, 0x3, | ||
247 | prtd->params->dma_addr); | ||
248 | } | ||
249 | |||
249 | /* flush the DMA channel */ | 250 | /* flush the DMA channel */ |
250 | s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH); | 251 | s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH); |
251 | prtd->dma_loaded = 0; | 252 | prtd->dma_loaded = 0; |
diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c index d46cd811ceb3..b4a56302b9ab 100644 --- a/sound/soc/s3c24xx/smdk2443_wm9710.c +++ b/sound/soc/s3c24xx/smdk2443_wm9710.c | |||
@@ -17,7 +17,6 @@ | |||
17 | 17 | ||
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/device.h> | 19 | #include <linux/device.h> |
20 | #include <sound/driver.h> | ||
21 | #include <sound/core.h> | 20 | #include <sound/core.h> |
22 | #include <sound/pcm.h> | 21 | #include <sound/pcm.h> |
23 | #include <sound/soc.h> | 22 | #include <sound/soc.h> |
diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c index cdee374b843e..7a3ce80d6727 100644 --- a/sound/soc/sh/dma-sh7760.c +++ b/sound/soc/sh/dma-sh7760.c | |||
@@ -16,7 +16,6 @@ | |||
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/dma-mapping.h> | 18 | #include <linux/dma-mapping.h> |
19 | #include <sound/driver.h> | ||
20 | #include <sound/core.h> | 19 | #include <sound/core.h> |
21 | #include <sound/pcm.h> | 20 | #include <sound/pcm.h> |
22 | #include <sound/pcm_params.h> | 21 | #include <sound/pcm_params.h> |
diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c index 8e3f03908cdb..b7b676b3d671 100644 --- a/sound/soc/sh/hac.c +++ b/sound/soc/sh/hac.c | |||
@@ -21,7 +21,6 @@ | |||
21 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
22 | #include <linux/wait.h> | 22 | #include <linux/wait.h> |
23 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
24 | #include <sound/driver.h> | ||
25 | #include <sound/core.h> | 24 | #include <sound/core.h> |
26 | #include <sound/pcm.h> | 25 | #include <sound/pcm.h> |
27 | #include <sound/ac97_codec.h> | 26 | #include <sound/ac97_codec.h> |
@@ -105,7 +104,7 @@ static int hac_get_codec_data(struct hac_priv *hac, unsigned short r, | |||
105 | unsigned int to1, to2, i; | 104 | unsigned int to1, to2, i; |
106 | unsigned short adr; | 105 | unsigned short adr; |
107 | 106 | ||
108 | for (i = 0; i < AC97_READ_RETRY; ++i) { | 107 | for (i = AC97_READ_RETRY; i; i--) { |
109 | *v = 0; | 108 | *v = 0; |
110 | /* wait for HAC to receive something from the codec */ | 109 | /* wait for HAC to receive something from the codec */ |
111 | for (to1 = TMO_E4; | 110 | for (to1 = TMO_E4; |
@@ -132,7 +131,7 @@ static int hac_get_codec_data(struct hac_priv *hac, unsigned short r, | |||
132 | udelay(21); | 131 | udelay(21); |
133 | } | 132 | } |
134 | HACREG(HACRSR) &= ~(RSR_STDRY | RSR_STARY); | 133 | HACREG(HACRSR) &= ~(RSR_STDRY | RSR_STARY); |
135 | return (i < AC97_READ_RETRY); | 134 | return i; |
136 | } | 135 | } |
137 | 136 | ||
138 | static unsigned short hac_read_codec_aux(struct hac_priv *hac, | 137 | static unsigned short hac_read_codec_aux(struct hac_priv *hac, |
@@ -141,7 +140,7 @@ static unsigned short hac_read_codec_aux(struct hac_priv *hac, | |||
141 | unsigned short val; | 140 | unsigned short val; |
142 | unsigned int i, to; | 141 | unsigned int i, to; |
143 | 142 | ||
144 | for (i = 0; i < AC97_READ_RETRY; i++) { | 143 | for (i = AC97_READ_RETRY; i; i--) { |
145 | /* send_read_request */ | 144 | /* send_read_request */ |
146 | local_irq_disable(); | 145 | local_irq_disable(); |
147 | HACREG(HACTSR) &= ~(TSR_CMDAMT); | 146 | HACREG(HACTSR) &= ~(TSR_CMDAMT); |
@@ -159,10 +158,7 @@ static unsigned short hac_read_codec_aux(struct hac_priv *hac, | |||
159 | break; | 158 | break; |
160 | } | 159 | } |
161 | 160 | ||
162 | if (i == AC97_READ_RETRY) | 161 | return i ? val : ~0; |
163 | return ~0; | ||
164 | |||
165 | return val; | ||
166 | } | 162 | } |
167 | 163 | ||
168 | static void hac_ac97_write(struct snd_ac97 *ac97, unsigned short reg, | 164 | static void hac_ac97_write(struct snd_ac97 *ac97, unsigned short reg, |
@@ -172,7 +168,7 @@ static void hac_ac97_write(struct snd_ac97 *ac97, unsigned short reg, | |||
172 | struct hac_priv *hac = &hac_cpu_data[unit_id]; | 168 | struct hac_priv *hac = &hac_cpu_data[unit_id]; |
173 | unsigned int i, to; | 169 | unsigned int i, to; |
174 | /* write_codec_aux */ | 170 | /* write_codec_aux */ |
175 | for (i = 0; i < AC97_WRITE_RETRY; i++) { | 171 | for (i = AC97_WRITE_RETRY; i; i--) { |
176 | /* send_write_request */ | 172 | /* send_write_request */ |
177 | local_irq_disable(); | 173 | local_irq_disable(); |
178 | HACREG(HACTSR) &= ~(TSR_CMDDMT | TSR_CMDAMT); | 174 | HACREG(HACTSR) &= ~(TSR_CMDDMT | TSR_CMDAMT); |
diff --git a/sound/soc/sh/sh7760-ac97.c b/sound/soc/sh/sh7760-ac97.c index 5563f14511fa..2f91de84c5c7 100644 --- a/sound/soc/sh/sh7760-ac97.c +++ b/sound/soc/sh/sh7760-ac97.c | |||
@@ -9,7 +9,6 @@ | |||
9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
10 | #include <linux/moduleparam.h> | 10 | #include <linux/moduleparam.h> |
11 | #include <linux/platform_device.h> | 11 | #include <linux/platform_device.h> |
12 | #include <sound/driver.h> | ||
13 | #include <sound/core.h> | 12 | #include <sound/core.h> |
14 | #include <sound/pcm.h> | 13 | #include <sound/pcm.h> |
15 | #include <sound/soc.h> | 14 | #include <sound/soc.h> |
diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c index b72bc316cb8e..3388bc3d62d1 100644 --- a/sound/soc/sh/ssi.c +++ b/sound/soc/sh/ssi.c | |||
@@ -30,7 +30,6 @@ | |||
30 | #include <linux/init.h> | 30 | #include <linux/init.h> |
31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
32 | #include <linux/platform_device.h> | 32 | #include <linux/platform_device.h> |
33 | #include <sound/driver.h> | ||
34 | #include <sound/core.h> | 33 | #include <sound/core.h> |
35 | #include <sound/pcm.h> | 34 | #include <sound/pcm.h> |
36 | #include <sound/initval.h> | 35 | #include <sound/initval.h> |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e6a67b58f296..9eb5479787c1 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -32,7 +32,6 @@ | |||
32 | #include <linux/pm.h> | 32 | #include <linux/pm.h> |
33 | #include <linux/bitops.h> | 33 | #include <linux/bitops.h> |
34 | #include <linux/platform_device.h> | 34 | #include <linux/platform_device.h> |
35 | #include <sound/driver.h> | ||
36 | #include <sound/core.h> | 35 | #include <sound/core.h> |
37 | #include <sound/pcm.h> | 36 | #include <sound/pcm.h> |
38 | #include <sound/pcm_params.h> | 37 | #include <sound/pcm_params.h> |
@@ -288,16 +287,25 @@ static void close_delayed_work(struct work_struct *work) | |||
288 | /* are we waiting on this codec DAI stream */ | 287 | /* are we waiting on this codec DAI stream */ |
289 | if (codec_dai->pop_wait == 1) { | 288 | if (codec_dai->pop_wait == 1) { |
290 | 289 | ||
290 | /* power down the codec to D1 if no longer active */ | ||
291 | if (codec->active == 0) { | ||
292 | dbg("pop wq D1 %s %s\n", codec->name, | ||
293 | codec_dai->playback.stream_name); | ||
294 | snd_soc_dapm_device_event(socdev, | ||
295 | SNDRV_CTL_POWER_D1); | ||
296 | } | ||
297 | |||
291 | codec_dai->pop_wait = 0; | 298 | codec_dai->pop_wait = 0; |
292 | snd_soc_dapm_stream_event(codec, codec_dai->playback.stream_name, | 299 | snd_soc_dapm_stream_event(codec, |
300 | codec_dai->playback.stream_name, | ||
293 | SND_SOC_DAPM_STREAM_STOP); | 301 | SND_SOC_DAPM_STREAM_STOP); |
294 | 302 | ||
295 | /* power down the codec power domain if no longer active */ | 303 | /* power down the codec power domain if no longer active */ |
296 | if (codec->active == 0) { | 304 | if (codec->active == 0) { |
297 | dbg("pop wq D3 %s %s\n", codec->name, | 305 | dbg("pop wq D3 %s %s\n", codec->name, |
298 | codec_dai->playback.stream_name); | 306 | codec_dai->playback.stream_name); |
299 | if (codec->dapm_event) | 307 | snd_soc_dapm_device_event(socdev, |
300 | codec->dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 308 | SNDRV_CTL_POWER_D3hot); |
301 | } | 309 | } |
302 | } | 310 | } |
303 | } | 311 | } |
@@ -353,12 +361,12 @@ static int soc_codec_close(struct snd_pcm_substream *substream) | |||
353 | } else { | 361 | } else { |
354 | /* capture streams can be powered down now */ | 362 | /* capture streams can be powered down now */ |
355 | snd_soc_dapm_stream_event(codec, | 363 | snd_soc_dapm_stream_event(codec, |
356 | codec_dai->capture.stream_name, SND_SOC_DAPM_STREAM_STOP); | 364 | codec_dai->capture.stream_name, |
365 | SND_SOC_DAPM_STREAM_STOP); | ||
357 | 366 | ||
358 | if (codec->active == 0 && codec_dai->pop_wait == 0){ | 367 | if (codec->active == 0 && codec_dai->pop_wait == 0) |
359 | if (codec->dapm_event) | 368 | snd_soc_dapm_device_event(socdev, |
360 | codec->dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 369 | SNDRV_CTL_POWER_D3hot); |
361 | } | ||
362 | } | 370 | } |
363 | 371 | ||
364 | mutex_unlock(&pcm_mutex); | 372 | mutex_unlock(&pcm_mutex); |
@@ -433,8 +441,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
433 | /* no delayed work - do we need to power up codec */ | 441 | /* no delayed work - do we need to power up codec */ |
434 | if (codec->dapm_state != SNDRV_CTL_POWER_D0) { | 442 | if (codec->dapm_state != SNDRV_CTL_POWER_D0) { |
435 | 443 | ||
436 | if (codec->dapm_event) | 444 | snd_soc_dapm_device_event(socdev, SNDRV_CTL_POWER_D1); |
437 | codec->dapm_event(codec, SNDRV_CTL_POWER_D1); | ||
438 | 445 | ||
439 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 446 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
440 | snd_soc_dapm_stream_event(codec, | 447 | snd_soc_dapm_stream_event(codec, |
@@ -445,8 +452,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
445 | codec_dai->capture.stream_name, | 452 | codec_dai->capture.stream_name, |
446 | SND_SOC_DAPM_STREAM_START); | 453 | SND_SOC_DAPM_STREAM_START); |
447 | 454 | ||
448 | if (codec->dapm_event) | 455 | snd_soc_dapm_device_event(socdev, SNDRV_CTL_POWER_D0); |
449 | codec->dapm_event(codec, SNDRV_CTL_POWER_D0); | ||
450 | if (codec_dai->dai_ops.digital_mute) | 456 | if (codec_dai->dai_ops.digital_mute) |
451 | codec_dai->dai_ops.digital_mute(codec_dai, 0); | 457 | codec_dai->dai_ops.digital_mute(codec_dai, 0); |
452 | 458 | ||
@@ -639,6 +645,10 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) | |||
639 | dai->dai_ops.digital_mute(dai, 1); | 645 | dai->dai_ops.digital_mute(dai, 1); |
640 | } | 646 | } |
641 | 647 | ||
648 | /* suspend all pcms */ | ||
649 | for (i = 0; i < machine->num_links; i++) | ||
650 | snd_pcm_suspend_all(machine->dai_link[i].pcm); | ||
651 | |||
642 | if (machine->suspend_pre) | 652 | if (machine->suspend_pre) |
643 | machine->suspend_pre(pdev, state); | 653 | machine->suspend_pre(pdev, state); |
644 | 654 | ||
@@ -873,6 +883,7 @@ static int soc_new_pcm(struct snd_soc_device *socdev, | |||
873 | return ret; | 883 | return ret; |
874 | } | 884 | } |
875 | 885 | ||
886 | dai_link->pcm = pcm; | ||
876 | pcm->private_data = rtd; | 887 | pcm->private_data = rtd; |
877 | soc_pcm_ops.mmap = socdev->platform->pcm_ops->mmap; | 888 | soc_pcm_ops.mmap = socdev->platform->pcm_ops->mmap; |
878 | soc_pcm_ops.pointer = socdev->platform->pcm_ops->pointer; | 889 | soc_pcm_ops.pointer = socdev->platform->pcm_ops->pointer; |
@@ -1090,7 +1101,6 @@ int snd_soc_register_card(struct snd_soc_device *socdev) | |||
1090 | struct snd_soc_machine *machine = socdev->machine; | 1101 | struct snd_soc_machine *machine = socdev->machine; |
1091 | int ret = 0, i, ac97 = 0, err = 0; | 1102 | int ret = 0, i, ac97 = 0, err = 0; |
1092 | 1103 | ||
1093 | mutex_lock(&codec->mutex); | ||
1094 | for(i = 0; i < machine->num_links; i++) { | 1104 | for(i = 0; i < machine->num_links; i++) { |
1095 | if (socdev->machine->dai_link[i].init) { | 1105 | if (socdev->machine->dai_link[i].init) { |
1096 | err = socdev->machine->dai_link[i].init(codec); | 1106 | err = socdev->machine->dai_link[i].init(codec); |
@@ -1116,12 +1126,14 @@ int snd_soc_register_card(struct snd_soc_device *socdev) | |||
1116 | goto out; | 1126 | goto out; |
1117 | } | 1127 | } |
1118 | 1128 | ||
1129 | mutex_lock(&codec->mutex); | ||
1119 | #ifdef CONFIG_SND_SOC_AC97_BUS | 1130 | #ifdef CONFIG_SND_SOC_AC97_BUS |
1120 | if (ac97) { | 1131 | if (ac97) { |
1121 | ret = soc_ac97_dev_register(codec); | 1132 | ret = soc_ac97_dev_register(codec); |
1122 | if (ret < 0) { | 1133 | if (ret < 0) { |
1123 | printk(KERN_ERR "asoc: AC97 device register failed\n"); | 1134 | printk(KERN_ERR "asoc: AC97 device register failed\n"); |
1124 | snd_card_free(codec->card); | 1135 | snd_card_free(codec->card); |
1136 | mutex_unlock(&codec->mutex); | ||
1125 | goto out; | 1137 | goto out; |
1126 | } | 1138 | } |
1127 | } | 1139 | } |
@@ -1134,8 +1146,10 @@ int snd_soc_register_card(struct snd_soc_device *socdev) | |||
1134 | err = device_create_file(socdev->dev, &dev_attr_codec_reg); | 1146 | err = device_create_file(socdev->dev, &dev_attr_codec_reg); |
1135 | if (err < 0) | 1147 | if (err < 0) |
1136 | printk(KERN_WARNING "asoc: failed to add codec sysfs entries\n"); | 1148 | printk(KERN_WARNING "asoc: failed to add codec sysfs entries\n"); |
1137 | out: | 1149 | |
1138 | mutex_unlock(&codec->mutex); | 1150 | mutex_unlock(&codec->mutex); |
1151 | |||
1152 | out: | ||
1139 | return ret; | 1153 | return ret; |
1140 | } | 1154 | } |
1141 | EXPORT_SYMBOL_GPL(snd_soc_register_card); | 1155 | EXPORT_SYMBOL_GPL(snd_soc_register_card); |
@@ -1215,7 +1229,6 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, | |||
1215 | memcpy(&template, _template, sizeof(template)); | 1229 | memcpy(&template, _template, sizeof(template)); |
1216 | if (long_name) | 1230 | if (long_name) |
1217 | template.name = long_name; | 1231 | template.name = long_name; |
1218 | template.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; | ||
1219 | template.index = 0; | 1232 | template.index = 0; |
1220 | 1233 | ||
1221 | return snd_ctl_new1(&template, data); | 1234 | return snd_ctl_new1(&template, data); |
@@ -1350,13 +1363,16 @@ EXPORT_SYMBOL_GPL(snd_soc_info_enum_ext); | |||
1350 | int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol, | 1363 | int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol, |
1351 | struct snd_ctl_elem_info *uinfo) | 1364 | struct snd_ctl_elem_info *uinfo) |
1352 | { | 1365 | { |
1353 | int mask = kcontrol->private_value; | 1366 | int max = kcontrol->private_value; |
1367 | |||
1368 | if (max == 1) | ||
1369 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
1370 | else | ||
1371 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1354 | 1372 | ||
1355 | uinfo->type = | ||
1356 | mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1357 | uinfo->count = 1; | 1373 | uinfo->count = 1; |
1358 | uinfo->value.integer.min = 0; | 1374 | uinfo->value.integer.min = 0; |
1359 | uinfo->value.integer.max = mask; | 1375 | uinfo->value.integer.max = max; |
1360 | return 0; | 1376 | return 0; |
1361 | } | 1377 | } |
1362 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext); | 1378 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext); |
@@ -1373,15 +1389,18 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext); | |||
1373 | int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, | 1389 | int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, |
1374 | struct snd_ctl_elem_info *uinfo) | 1390 | struct snd_ctl_elem_info *uinfo) |
1375 | { | 1391 | { |
1376 | int mask = (kcontrol->private_value >> 16) & 0xff; | 1392 | int max = (kcontrol->private_value >> 16) & 0xff; |
1377 | int shift = (kcontrol->private_value >> 8) & 0x0f; | 1393 | int shift = (kcontrol->private_value >> 8) & 0x0f; |
1378 | int rshift = (kcontrol->private_value >> 12) & 0x0f; | 1394 | int rshift = (kcontrol->private_value >> 12) & 0x0f; |
1379 | 1395 | ||
1380 | uinfo->type = | 1396 | if (max == 1) |
1381 | mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; | 1397 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; |
1398 | else | ||
1399 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1400 | |||
1382 | uinfo->count = shift == rshift ? 1 : 2; | 1401 | uinfo->count = shift == rshift ? 1 : 2; |
1383 | uinfo->value.integer.min = 0; | 1402 | uinfo->value.integer.min = 0; |
1384 | uinfo->value.integer.max = mask; | 1403 | uinfo->value.integer.max = max; |
1385 | return 0; | 1404 | return 0; |
1386 | } | 1405 | } |
1387 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw); | 1406 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw); |
@@ -1402,7 +1421,8 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, | |||
1402 | int reg = kcontrol->private_value & 0xff; | 1421 | int reg = kcontrol->private_value & 0xff; |
1403 | int shift = (kcontrol->private_value >> 8) & 0x0f; | 1422 | int shift = (kcontrol->private_value >> 8) & 0x0f; |
1404 | int rshift = (kcontrol->private_value >> 12) & 0x0f; | 1423 | int rshift = (kcontrol->private_value >> 12) & 0x0f; |
1405 | int mask = (kcontrol->private_value >> 16) & 0xff; | 1424 | int max = (kcontrol->private_value >> 16) & 0xff; |
1425 | int mask = (1 << fls(max)) - 1; | ||
1406 | int invert = (kcontrol->private_value >> 24) & 0x01; | 1426 | int invert = (kcontrol->private_value >> 24) & 0x01; |
1407 | 1427 | ||
1408 | ucontrol->value.integer.value[0] = | 1428 | ucontrol->value.integer.value[0] = |
@@ -1412,10 +1432,10 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, | |||
1412 | (snd_soc_read(codec, reg) >> rshift) & mask; | 1432 | (snd_soc_read(codec, reg) >> rshift) & mask; |
1413 | if (invert) { | 1433 | if (invert) { |
1414 | ucontrol->value.integer.value[0] = | 1434 | ucontrol->value.integer.value[0] = |
1415 | mask - ucontrol->value.integer.value[0]; | 1435 | max - ucontrol->value.integer.value[0]; |
1416 | if (shift != rshift) | 1436 | if (shift != rshift) |
1417 | ucontrol->value.integer.value[1] = | 1437 | ucontrol->value.integer.value[1] = |
1418 | mask - ucontrol->value.integer.value[1]; | 1438 | max - ucontrol->value.integer.value[1]; |
1419 | } | 1439 | } |
1420 | 1440 | ||
1421 | return 0; | 1441 | return 0; |
@@ -1438,25 +1458,24 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, | |||
1438 | int reg = kcontrol->private_value & 0xff; | 1458 | int reg = kcontrol->private_value & 0xff; |
1439 | int shift = (kcontrol->private_value >> 8) & 0x0f; | 1459 | int shift = (kcontrol->private_value >> 8) & 0x0f; |
1440 | int rshift = (kcontrol->private_value >> 12) & 0x0f; | 1460 | int rshift = (kcontrol->private_value >> 12) & 0x0f; |
1441 | int mask = (kcontrol->private_value >> 16) & 0xff; | 1461 | int max = (kcontrol->private_value >> 16) & 0xff; |
1462 | int mask = (1 << fls(max)) - 1; | ||
1442 | int invert = (kcontrol->private_value >> 24) & 0x01; | 1463 | int invert = (kcontrol->private_value >> 24) & 0x01; |
1443 | int err; | ||
1444 | unsigned short val, val2, val_mask; | 1464 | unsigned short val, val2, val_mask; |
1445 | 1465 | ||
1446 | val = (ucontrol->value.integer.value[0] & mask); | 1466 | val = (ucontrol->value.integer.value[0] & mask); |
1447 | if (invert) | 1467 | if (invert) |
1448 | val = mask - val; | 1468 | val = max - val; |
1449 | val_mask = mask << shift; | 1469 | val_mask = mask << shift; |
1450 | val = val << shift; | 1470 | val = val << shift; |
1451 | if (shift != rshift) { | 1471 | if (shift != rshift) { |
1452 | val2 = (ucontrol->value.integer.value[1] & mask); | 1472 | val2 = (ucontrol->value.integer.value[1] & mask); |
1453 | if (invert) | 1473 | if (invert) |
1454 | val2 = mask - val2; | 1474 | val2 = max - val2; |
1455 | val_mask |= mask << rshift; | 1475 | val_mask |= mask << rshift; |
1456 | val |= val2 << rshift; | 1476 | val |= val2 << rshift; |
1457 | } | 1477 | } |
1458 | err = snd_soc_update_bits(codec, reg, val_mask, val); | 1478 | return snd_soc_update_bits(codec, reg, val_mask, val); |
1459 | return err; | ||
1460 | } | 1479 | } |
1461 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw); | 1480 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw); |
1462 | 1481 | ||
@@ -1473,13 +1492,16 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw); | |||
1473 | int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol, | 1492 | int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol, |
1474 | struct snd_ctl_elem_info *uinfo) | 1493 | struct snd_ctl_elem_info *uinfo) |
1475 | { | 1494 | { |
1476 | int mask = (kcontrol->private_value >> 12) & 0xff; | 1495 | int max = (kcontrol->private_value >> 12) & 0xff; |
1496 | |||
1497 | if (max == 1) | ||
1498 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
1499 | else | ||
1500 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1477 | 1501 | ||
1478 | uinfo->type = | ||
1479 | mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1480 | uinfo->count = 2; | 1502 | uinfo->count = 2; |
1481 | uinfo->value.integer.min = 0; | 1503 | uinfo->value.integer.min = 0; |
1482 | uinfo->value.integer.max = mask; | 1504 | uinfo->value.integer.max = max; |
1483 | return 0; | 1505 | return 0; |
1484 | } | 1506 | } |
1485 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r); | 1507 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r); |
@@ -1500,7 +1522,8 @@ int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol, | |||
1500 | int reg = kcontrol->private_value & 0xff; | 1522 | int reg = kcontrol->private_value & 0xff; |
1501 | int reg2 = (kcontrol->private_value >> 24) & 0xff; | 1523 | int reg2 = (kcontrol->private_value >> 24) & 0xff; |
1502 | int shift = (kcontrol->private_value >> 8) & 0x0f; | 1524 | int shift = (kcontrol->private_value >> 8) & 0x0f; |
1503 | int mask = (kcontrol->private_value >> 12) & 0xff; | 1525 | int max = (kcontrol->private_value >> 12) & 0xff; |
1526 | int mask = (1<<fls(max))-1; | ||
1504 | int invert = (kcontrol->private_value >> 20) & 0x01; | 1527 | int invert = (kcontrol->private_value >> 20) & 0x01; |
1505 | 1528 | ||
1506 | ucontrol->value.integer.value[0] = | 1529 | ucontrol->value.integer.value[0] = |
@@ -1509,9 +1532,9 @@ int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol, | |||
1509 | (snd_soc_read(codec, reg2) >> shift) & mask; | 1532 | (snd_soc_read(codec, reg2) >> shift) & mask; |
1510 | if (invert) { | 1533 | if (invert) { |
1511 | ucontrol->value.integer.value[0] = | 1534 | ucontrol->value.integer.value[0] = |
1512 | mask - ucontrol->value.integer.value[0]; | 1535 | max - ucontrol->value.integer.value[0]; |
1513 | ucontrol->value.integer.value[1] = | 1536 | ucontrol->value.integer.value[1] = |
1514 | mask - ucontrol->value.integer.value[1]; | 1537 | max - ucontrol->value.integer.value[1]; |
1515 | } | 1538 | } |
1516 | 1539 | ||
1517 | return 0; | 1540 | return 0; |
@@ -1534,7 +1557,8 @@ int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol, | |||
1534 | int reg = kcontrol->private_value & 0xff; | 1557 | int reg = kcontrol->private_value & 0xff; |
1535 | int reg2 = (kcontrol->private_value >> 24) & 0xff; | 1558 | int reg2 = (kcontrol->private_value >> 24) & 0xff; |
1536 | int shift = (kcontrol->private_value >> 8) & 0x0f; | 1559 | int shift = (kcontrol->private_value >> 8) & 0x0f; |
1537 | int mask = (kcontrol->private_value >> 12) & 0xff; | 1560 | int max = (kcontrol->private_value >> 12) & 0xff; |
1561 | int mask = (1 << fls(max)) - 1; | ||
1538 | int invert = (kcontrol->private_value >> 20) & 0x01; | 1562 | int invert = (kcontrol->private_value >> 20) & 0x01; |
1539 | int err; | 1563 | int err; |
1540 | unsigned short val, val2, val_mask; | 1564 | unsigned short val, val2, val_mask; |
@@ -1544,8 +1568,8 @@ int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol, | |||
1544 | val2 = (ucontrol->value.integer.value[1] & mask); | 1568 | val2 = (ucontrol->value.integer.value[1] & mask); |
1545 | 1569 | ||
1546 | if (invert) { | 1570 | if (invert) { |
1547 | val = mask - val; | 1571 | val = max - val; |
1548 | val2 = mask - val2; | 1572 | val2 = max - val2; |
1549 | } | 1573 | } |
1550 | 1574 | ||
1551 | val = val << shift; | 1575 | val = val << shift; |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 29a546fecacf..620d7ea3c15f 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -43,7 +43,6 @@ | |||
43 | #include <linux/bitops.h> | 43 | #include <linux/bitops.h> |
44 | #include <linux/platform_device.h> | 44 | #include <linux/platform_device.h> |
45 | #include <linux/jiffies.h> | 45 | #include <linux/jiffies.h> |
46 | #include <sound/driver.h> | ||
47 | #include <sound/core.h> | 46 | #include <sound/core.h> |
48 | #include <sound/pcm.h> | 47 | #include <sound/pcm.h> |
49 | #include <sound/pcm_params.h> | 48 | #include <sound/pcm_params.h> |
@@ -524,11 +523,13 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | |||
524 | continue; | 523 | continue; |
525 | 524 | ||
526 | if (event == SND_SOC_DAPM_STREAM_START) { | 525 | if (event == SND_SOC_DAPM_STREAM_START) { |
527 | ret = w->event(w, SND_SOC_DAPM_PRE_PMU); | 526 | ret = w->event(w, |
527 | NULL, SND_SOC_DAPM_PRE_PMU); | ||
528 | if (ret < 0) | 528 | if (ret < 0) |
529 | return ret; | 529 | return ret; |
530 | } else if (event == SND_SOC_DAPM_STREAM_STOP) { | 530 | } else if (event == SND_SOC_DAPM_STREAM_STOP) { |
531 | ret = w->event(w, SND_SOC_DAPM_PRE_PMD); | 531 | ret = w->event(w, |
532 | NULL, SND_SOC_DAPM_PRE_PMD); | ||
532 | if (ret < 0) | 533 | if (ret < 0) |
533 | return ret; | 534 | return ret; |
534 | } | 535 | } |
@@ -539,11 +540,13 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | |||
539 | continue; | 540 | continue; |
540 | 541 | ||
541 | if (event == SND_SOC_DAPM_STREAM_START) { | 542 | if (event == SND_SOC_DAPM_STREAM_START) { |
542 | ret = w->event(w, SND_SOC_DAPM_POST_PMU); | 543 | ret = w->event(w, |
544 | NULL, SND_SOC_DAPM_POST_PMU); | ||
543 | if (ret < 0) | 545 | if (ret < 0) |
544 | return ret; | 546 | return ret; |
545 | } else if (event == SND_SOC_DAPM_STREAM_STOP) { | 547 | } else if (event == SND_SOC_DAPM_STREAM_STOP) { |
546 | ret = w->event(w, SND_SOC_DAPM_POST_PMD); | 548 | ret = w->event(w, |
549 | NULL, SND_SOC_DAPM_POST_PMD); | ||
547 | if (ret < 0) | 550 | if (ret < 0) |
548 | return ret; | 551 | return ret; |
549 | } | 552 | } |
@@ -567,26 +570,30 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | |||
567 | if (power) { | 570 | if (power) { |
568 | /* power up event */ | 571 | /* power up event */ |
569 | if (w->event_flags & SND_SOC_DAPM_PRE_PMU) { | 572 | if (w->event_flags & SND_SOC_DAPM_PRE_PMU) { |
570 | ret = w->event(w, SND_SOC_DAPM_PRE_PMU); | 573 | ret = w->event(w, |
574 | NULL, SND_SOC_DAPM_PRE_PMU); | ||
571 | if (ret < 0) | 575 | if (ret < 0) |
572 | return ret; | 576 | return ret; |
573 | } | 577 | } |
574 | dapm_update_bits(w); | 578 | dapm_update_bits(w); |
575 | if (w->event_flags & SND_SOC_DAPM_POST_PMU){ | 579 | if (w->event_flags & SND_SOC_DAPM_POST_PMU){ |
576 | ret = w->event(w, SND_SOC_DAPM_POST_PMU); | 580 | ret = w->event(w, |
581 | NULL, SND_SOC_DAPM_POST_PMU); | ||
577 | if (ret < 0) | 582 | if (ret < 0) |
578 | return ret; | 583 | return ret; |
579 | } | 584 | } |
580 | } else { | 585 | } else { |
581 | /* power down event */ | 586 | /* power down event */ |
582 | if (w->event_flags & SND_SOC_DAPM_PRE_PMD) { | 587 | if (w->event_flags & SND_SOC_DAPM_PRE_PMD) { |
583 | ret = w->event(w, SND_SOC_DAPM_PRE_PMD); | 588 | ret = w->event(w, |
589 | NULL, SND_SOC_DAPM_PRE_PMD); | ||
584 | if (ret < 0) | 590 | if (ret < 0) |
585 | return ret; | 591 | return ret; |
586 | } | 592 | } |
587 | dapm_update_bits(w); | 593 | dapm_update_bits(w); |
588 | if (w->event_flags & SND_SOC_DAPM_POST_PMD) { | 594 | if (w->event_flags & SND_SOC_DAPM_POST_PMD) { |
589 | ret = w->event(w, SND_SOC_DAPM_POST_PMD); | 595 | ret = w->event(w, |
596 | NULL, SND_SOC_DAPM_POST_PMD); | ||
590 | if (ret < 0) | 597 | if (ret < 0) |
591 | return ret; | 598 | return ret; |
592 | } | 599 | } |
@@ -692,7 +699,7 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | |||
692 | return 0; | 699 | return 0; |
693 | } | 700 | } |
694 | 701 | ||
695 | /* test and update the power status of a mixer widget */ | 702 | /* test and update the power status of a mixer or switch widget */ |
696 | static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | 703 | static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, |
697 | struct snd_kcontrol *kcontrol, int reg, | 704 | struct snd_kcontrol *kcontrol, int reg, |
698 | int val_mask, int val, int invert) | 705 | int val_mask, int val, int invert) |
@@ -700,7 +707,8 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | |||
700 | struct snd_soc_dapm_path *path; | 707 | struct snd_soc_dapm_path *path; |
701 | int found = 0; | 708 | int found = 0; |
702 | 709 | ||
703 | if (widget->id != snd_soc_dapm_mixer) | 710 | if (widget->id != snd_soc_dapm_mixer && |
711 | widget->id != snd_soc_dapm_switch) | ||
704 | return -ENODEV; | 712 | return -ENODEV; |
705 | 713 | ||
706 | if (!snd_soc_test_bits(widget->codec, reg, val_mask, val)) | 714 | if (!snd_soc_test_bits(widget->codec, reg, val_mask, val)) |
@@ -963,7 +971,6 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec) | |||
963 | { | 971 | { |
964 | struct snd_soc_dapm_widget *w; | 972 | struct snd_soc_dapm_widget *w; |
965 | 973 | ||
966 | mutex_lock(&codec->mutex); | ||
967 | list_for_each_entry(w, &codec->dapm_widgets, list) | 974 | list_for_each_entry(w, &codec->dapm_widgets, list) |
968 | { | 975 | { |
969 | if (w->new) | 976 | if (w->new) |
@@ -998,7 +1005,6 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec) | |||
998 | } | 1005 | } |
999 | 1006 | ||
1000 | dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); | 1007 | dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); |
1001 | mutex_unlock(&codec->mutex); | ||
1002 | return 0; | 1008 | return 0; |
1003 | } | 1009 | } |
1004 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); | 1010 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); |
@@ -1019,8 +1025,9 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, | |||
1019 | int reg = kcontrol->private_value & 0xff; | 1025 | int reg = kcontrol->private_value & 0xff; |
1020 | int shift = (kcontrol->private_value >> 8) & 0x0f; | 1026 | int shift = (kcontrol->private_value >> 8) & 0x0f; |
1021 | int rshift = (kcontrol->private_value >> 12) & 0x0f; | 1027 | int rshift = (kcontrol->private_value >> 12) & 0x0f; |
1022 | int mask = (kcontrol->private_value >> 16) & 0xff; | 1028 | int max = (kcontrol->private_value >> 16) & 0xff; |
1023 | int invert = (kcontrol->private_value >> 24) & 0x01; | 1029 | int invert = (kcontrol->private_value >> 24) & 0x01; |
1030 | int mask = (1 << fls(max)) - 1; | ||
1024 | 1031 | ||
1025 | /* return the saved value if we are powered down */ | 1032 | /* return the saved value if we are powered down */ |
1026 | if (widget->id == snd_soc_dapm_pga && !widget->power) { | 1033 | if (widget->id == snd_soc_dapm_pga && !widget->power) { |
@@ -1035,10 +1042,10 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, | |||
1035 | (snd_soc_read(widget->codec, reg) >> rshift) & mask; | 1042 | (snd_soc_read(widget->codec, reg) >> rshift) & mask; |
1036 | if (invert) { | 1043 | if (invert) { |
1037 | ucontrol->value.integer.value[0] = | 1044 | ucontrol->value.integer.value[0] = |
1038 | mask - ucontrol->value.integer.value[0]; | 1045 | max - ucontrol->value.integer.value[0]; |
1039 | if (shift != rshift) | 1046 | if (shift != rshift) |
1040 | ucontrol->value.integer.value[1] = | 1047 | ucontrol->value.integer.value[1] = |
1041 | mask - ucontrol->value.integer.value[1]; | 1048 | max - ucontrol->value.integer.value[1]; |
1042 | } | 1049 | } |
1043 | 1050 | ||
1044 | return 0; | 1051 | return 0; |
@@ -1061,7 +1068,8 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
1061 | int reg = kcontrol->private_value & 0xff; | 1068 | int reg = kcontrol->private_value & 0xff; |
1062 | int shift = (kcontrol->private_value >> 8) & 0x0f; | 1069 | int shift = (kcontrol->private_value >> 8) & 0x0f; |
1063 | int rshift = (kcontrol->private_value >> 12) & 0x0f; | 1070 | int rshift = (kcontrol->private_value >> 12) & 0x0f; |
1064 | int mask = (kcontrol->private_value >> 16) & 0xff; | 1071 | int max = (kcontrol->private_value >> 16) & 0xff; |
1072 | int mask = (1 << fls(max)) - 1; | ||
1065 | int invert = (kcontrol->private_value >> 24) & 0x01; | 1073 | int invert = (kcontrol->private_value >> 24) & 0x01; |
1066 | unsigned short val, val2, val_mask; | 1074 | unsigned short val, val2, val_mask; |
1067 | int ret; | 1075 | int ret; |
@@ -1069,13 +1077,13 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
1069 | val = (ucontrol->value.integer.value[0] & mask); | 1077 | val = (ucontrol->value.integer.value[0] & mask); |
1070 | 1078 | ||
1071 | if (invert) | 1079 | if (invert) |
1072 | val = mask - val; | 1080 | val = max - val; |
1073 | val_mask = mask << shift; | 1081 | val_mask = mask << shift; |
1074 | val = val << shift; | 1082 | val = val << shift; |
1075 | if (shift != rshift) { | 1083 | if (shift != rshift) { |
1076 | val2 = (ucontrol->value.integer.value[1] & mask); | 1084 | val2 = (ucontrol->value.integer.value[1] & mask); |
1077 | if (invert) | 1085 | if (invert) |
1078 | val2 = mask - val2; | 1086 | val2 = max - val2; |
1079 | val_mask |= mask << rshift; | 1087 | val_mask |= mask << rshift; |
1080 | val |= val2 << rshift; | 1088 | val |= val2 << rshift; |
1081 | } | 1089 | } |
@@ -1093,13 +1101,17 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
1093 | dapm_mixer_update_power(widget, kcontrol, reg, val_mask, val, invert); | 1101 | dapm_mixer_update_power(widget, kcontrol, reg, val_mask, val, invert); |
1094 | if (widget->event) { | 1102 | if (widget->event) { |
1095 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { | 1103 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { |
1096 | ret = widget->event(widget, SND_SOC_DAPM_PRE_REG); | 1104 | ret = widget->event(widget, kcontrol, |
1097 | if (ret < 0) | 1105 | SND_SOC_DAPM_PRE_REG); |
1106 | if (ret < 0) { | ||
1107 | ret = 1; | ||
1098 | goto out; | 1108 | goto out; |
1109 | } | ||
1099 | } | 1110 | } |
1100 | ret = snd_soc_update_bits(widget->codec, reg, val_mask, val); | 1111 | ret = snd_soc_update_bits(widget->codec, reg, val_mask, val); |
1101 | if (widget->event_flags & SND_SOC_DAPM_POST_REG) | 1112 | if (widget->event_flags & SND_SOC_DAPM_POST_REG) |
1102 | ret = widget->event(widget, SND_SOC_DAPM_POST_REG); | 1113 | ret = widget->event(widget, kcontrol, |
1114 | SND_SOC_DAPM_POST_REG); | ||
1103 | } else | 1115 | } else |
1104 | ret = snd_soc_update_bits(widget->codec, reg, val_mask, val); | 1116 | ret = snd_soc_update_bits(widget->codec, reg, val_mask, val); |
1105 | 1117 | ||
@@ -1174,13 +1186,15 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | |||
1174 | dapm_mux_update_power(widget, kcontrol, mask, mux, e); | 1186 | dapm_mux_update_power(widget, kcontrol, mask, mux, e); |
1175 | if (widget->event) { | 1187 | if (widget->event) { |
1176 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { | 1188 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { |
1177 | ret = widget->event(widget, SND_SOC_DAPM_PRE_REG); | 1189 | ret = widget->event(widget, |
1190 | kcontrol, SND_SOC_DAPM_PRE_REG); | ||
1178 | if (ret < 0) | 1191 | if (ret < 0) |
1179 | goto out; | 1192 | goto out; |
1180 | } | 1193 | } |
1181 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); | 1194 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); |
1182 | if (widget->event_flags & SND_SOC_DAPM_POST_REG) | 1195 | if (widget->event_flags & SND_SOC_DAPM_POST_REG) |
1183 | ret = widget->event(widget, SND_SOC_DAPM_POST_REG); | 1196 | ret = widget->event(widget, |
1197 | kcontrol, SND_SOC_DAPM_POST_REG); | ||
1184 | } else | 1198 | } else |
1185 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); | 1199 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); |
1186 | 1200 | ||
@@ -1280,6 +1294,29 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, | |||
1280 | EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); | 1294 | EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); |
1281 | 1295 | ||
1282 | /** | 1296 | /** |
1297 | * snd_soc_dapm_device_event - send a device event to the dapm core | ||
1298 | * @socdev: audio device | ||
1299 | * @event: device event | ||
1300 | * | ||
1301 | * Sends a device event to the dapm core. The core then makes any | ||
1302 | * necessary machine or codec power changes.. | ||
1303 | * | ||
1304 | * Returns 0 for success else error. | ||
1305 | */ | ||
1306 | int snd_soc_dapm_device_event(struct snd_soc_device *socdev, int event) | ||
1307 | { | ||
1308 | struct snd_soc_codec *codec = socdev->codec; | ||
1309 | struct snd_soc_machine *machine = socdev->machine; | ||
1310 | |||
1311 | if (machine->dapm_event) | ||
1312 | machine->dapm_event(machine, event); | ||
1313 | if (codec->dapm_event) | ||
1314 | codec->dapm_event(codec, event); | ||
1315 | return 0; | ||
1316 | } | ||
1317 | EXPORT_SYMBOL_GPL(snd_soc_dapm_device_event); | ||
1318 | |||
1319 | /** | ||
1283 | * snd_soc_dapm_set_endpoint - set audio endpoint status | 1320 | * snd_soc_dapm_set_endpoint - set audio endpoint status |
1284 | * @codec: audio codec | 1321 | * @codec: audio codec |
1285 | * @endpoint: audio signal endpoint (or start point) | 1322 | * @endpoint: audio signal endpoint (or start point) |
diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c index 07962a35f241..0c63e0585b15 100644 --- a/sound/sparc/amd7930.c +++ b/sound/sparc/amd7930.c | |||
@@ -36,7 +36,6 @@ | |||
36 | #include <linux/interrupt.h> | 36 | #include <linux/interrupt.h> |
37 | #include <linux/moduleparam.h> | 37 | #include <linux/moduleparam.h> |
38 | 38 | ||
39 | #include <sound/driver.h> | ||
40 | #include <sound/core.h> | 39 | #include <sound/core.h> |
41 | #include <sound/pcm.h> | 40 | #include <sound/pcm.h> |
42 | #include <sound/info.h> | 41 | #include <sound/info.h> |
@@ -859,7 +858,7 @@ static int snd_amd7930_put_volume(struct snd_kcontrol *kctl, struct snd_ctl_elem | |||
859 | spin_lock_irqsave(&amd->lock, flags); | 858 | spin_lock_irqsave(&amd->lock, flags); |
860 | 859 | ||
861 | if (*swval != ucontrol->value.integer.value[0]) { | 860 | if (*swval != ucontrol->value.integer.value[0]) { |
862 | *swval = ucontrol->value.integer.value[0]; | 861 | *swval = ucontrol->value.integer.value[0] & 0xff; |
863 | __amd7930_update_map(amd); | 862 | __amd7930_update_map(amd); |
864 | change = 1; | 863 | change = 1; |
865 | } else | 864 | } else |
diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c index f8c7a120ccbb..1c4797be72ee 100644 --- a/sound/sparc/cs4231.c +++ b/sound/sparc/cs4231.c | |||
@@ -19,7 +19,6 @@ | |||
19 | #include <linux/io.h> | 19 | #include <linux/io.h> |
20 | 20 | ||
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <sound/core.h> | 22 | #include <sound/core.h> |
24 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
25 | #include <sound/info.h> | 24 | #include <sound/info.h> |
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index 376b98691c96..3d00e0797b11 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c | |||
@@ -53,7 +53,6 @@ | |||
53 | * other DBRI low-level stuff | 53 | * other DBRI low-level stuff |
54 | */ | 54 | */ |
55 | 55 | ||
56 | #include <sound/driver.h> | ||
57 | #include <linux/interrupt.h> | 56 | #include <linux/interrupt.h> |
58 | #include <linux/delay.h> | 57 | #include <linux/delay.h> |
59 | #include <linux/irq.h> | 58 | #include <linux/irq.h> |
@@ -2279,14 +2278,25 @@ static int snd_cs4215_put_volume(struct snd_kcontrol *kcontrol, | |||
2279 | struct snd_dbri *dbri = snd_kcontrol_chip(kcontrol); | 2278 | struct snd_dbri *dbri = snd_kcontrol_chip(kcontrol); |
2280 | struct dbri_streaminfo *info = | 2279 | struct dbri_streaminfo *info = |
2281 | &dbri->stream_info[kcontrol->private_value]; | 2280 | &dbri->stream_info[kcontrol->private_value]; |
2281 | unsigned int vol[2]; | ||
2282 | int changed = 0; | 2282 | int changed = 0; |
2283 | 2283 | ||
2284 | if (info->left_gain != ucontrol->value.integer.value[0]) { | 2284 | vol[0] = ucontrol->value.integer.value[0]; |
2285 | info->left_gain = ucontrol->value.integer.value[0]; | 2285 | vol[1] = ucontrol->value.integer.value[1]; |
2286 | if (kcontrol->private_value == DBRI_PLAY) { | ||
2287 | if (vol[0] > DBRI_MAX_VOLUME || vol[1] > DBRI_MAX_VOLUME) | ||
2288 | return -EINVAL; | ||
2289 | } else { | ||
2290 | if (vol[0] > DBRI_MAX_GAIN || vol[1] > DBRI_MAX_GAIN) | ||
2291 | return -EINVAL; | ||
2292 | } | ||
2293 | |||
2294 | if (info->left_gain != vol[0]) { | ||
2295 | info->left_gain = vol[0]; | ||
2286 | changed = 1; | 2296 | changed = 1; |
2287 | } | 2297 | } |
2288 | if (info->right_gain != ucontrol->value.integer.value[1]) { | 2298 | if (info->right_gain != vol[1]) { |
2289 | info->right_gain = ucontrol->value.integer.value[1]; | 2299 | info->right_gain = vol[1]; |
2290 | changed = 1; | 2300 | changed = 1; |
2291 | } | 2301 | } |
2292 | if (changed) { | 2302 | if (changed) { |
diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c index fee869bcc959..89d6e9c35140 100644 --- a/sound/spi/at73c213.c +++ b/sound/spi/at73c213.c | |||
@@ -18,10 +18,10 @@ | |||
18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/mutex.h> | ||
21 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
22 | #include <linux/io.h> | 23 | #include <linux/io.h> |
23 | 24 | ||
24 | #include <sound/driver.h> | ||
25 | #include <sound/initval.h> | 25 | #include <sound/initval.h> |
26 | #include <sound/control.h> | 26 | #include <sound/control.h> |
27 | #include <sound/core.h> | 27 | #include <sound/core.h> |
@@ -76,8 +76,10 @@ struct snd_at73c213 { | |||
76 | u8 spi_rbuffer[2]; | 76 | u8 spi_rbuffer[2]; |
77 | /* Image of the SPI registers in AT73C213. */ | 77 | /* Image of the SPI registers in AT73C213. */ |
78 | u8 reg_image[18]; | 78 | u8 reg_image[18]; |
79 | /* Protect registers against concurrent access. */ | 79 | /* Protect SSC registers against concurrent access. */ |
80 | spinlock_t lock; | 80 | spinlock_t lock; |
81 | /* Protect mixer registers against concurrent access. */ | ||
82 | struct mutex mixer_lock; | ||
81 | }; | 83 | }; |
82 | 84 | ||
83 | #define get_chip(card) ((struct snd_at73c213 *)card->private_data) | 85 | #define get_chip(card) ((struct snd_at73c213 *)card->private_data) |
@@ -398,7 +400,7 @@ static int snd_at73c213_mono_get(struct snd_kcontrol *kcontrol, | |||
398 | int mask = (kcontrol->private_value >> 16) & 0xff; | 400 | int mask = (kcontrol->private_value >> 16) & 0xff; |
399 | int invert = (kcontrol->private_value >> 24) & 0xff; | 401 | int invert = (kcontrol->private_value >> 24) & 0xff; |
400 | 402 | ||
401 | spin_lock_irq(&chip->lock); | 403 | mutex_lock(&chip->mixer_lock); |
402 | 404 | ||
403 | ucontrol->value.integer.value[0] = | 405 | ucontrol->value.integer.value[0] = |
404 | (chip->reg_image[reg] >> shift) & mask; | 406 | (chip->reg_image[reg] >> shift) & mask; |
@@ -407,7 +409,7 @@ static int snd_at73c213_mono_get(struct snd_kcontrol *kcontrol, | |||
407 | ucontrol->value.integer.value[0] = | 409 | ucontrol->value.integer.value[0] = |
408 | mask - ucontrol->value.integer.value[0]; | 410 | mask - ucontrol->value.integer.value[0]; |
409 | 411 | ||
410 | spin_unlock_irq(&chip->lock); | 412 | mutex_unlock(&chip->mixer_lock); |
411 | 413 | ||
412 | return 0; | 414 | return 0; |
413 | } | 415 | } |
@@ -428,13 +430,13 @@ static int snd_at73c213_mono_put(struct snd_kcontrol *kcontrol, | |||
428 | val = mask - val; | 430 | val = mask - val; |
429 | val <<= shift; | 431 | val <<= shift; |
430 | 432 | ||
431 | spin_lock_irq(&chip->lock); | 433 | mutex_lock(&chip->mixer_lock); |
432 | 434 | ||
433 | val = (chip->reg_image[reg] & ~(mask << shift)) | val; | 435 | val = (chip->reg_image[reg] & ~(mask << shift)) | val; |
434 | change = val != chip->reg_image[reg]; | 436 | change = val != chip->reg_image[reg]; |
435 | retval = snd_at73c213_write_reg(chip, reg, val); | 437 | retval = snd_at73c213_write_reg(chip, reg, val); |
436 | 438 | ||
437 | spin_unlock_irq(&chip->lock); | 439 | mutex_unlock(&chip->mixer_lock); |
438 | 440 | ||
439 | if (retval) | 441 | if (retval) |
440 | return retval; | 442 | return retval; |
@@ -470,7 +472,7 @@ static int snd_at73c213_stereo_get(struct snd_kcontrol *kcontrol, | |||
470 | int mask = (kcontrol->private_value >> 24) & 0xff; | 472 | int mask = (kcontrol->private_value >> 24) & 0xff; |
471 | int invert = (kcontrol->private_value >> 22) & 1; | 473 | int invert = (kcontrol->private_value >> 22) & 1; |
472 | 474 | ||
473 | spin_lock_irq(&chip->lock); | 475 | mutex_lock(&chip->mixer_lock); |
474 | 476 | ||
475 | ucontrol->value.integer.value[0] = | 477 | ucontrol->value.integer.value[0] = |
476 | (chip->reg_image[left_reg] >> shift_left) & mask; | 478 | (chip->reg_image[left_reg] >> shift_left) & mask; |
@@ -484,7 +486,7 @@ static int snd_at73c213_stereo_get(struct snd_kcontrol *kcontrol, | |||
484 | mask - ucontrol->value.integer.value[1]; | 486 | mask - ucontrol->value.integer.value[1]; |
485 | } | 487 | } |
486 | 488 | ||
487 | spin_unlock_irq(&chip->lock); | 489 | mutex_unlock(&chip->mixer_lock); |
488 | 490 | ||
489 | return 0; | 491 | return 0; |
490 | } | 492 | } |
@@ -511,7 +513,7 @@ static int snd_at73c213_stereo_put(struct snd_kcontrol *kcontrol, | |||
511 | val1 <<= shift_left; | 513 | val1 <<= shift_left; |
512 | val2 <<= shift_right; | 514 | val2 <<= shift_right; |
513 | 515 | ||
514 | spin_lock_irq(&chip->lock); | 516 | mutex_lock(&chip->mixer_lock); |
515 | 517 | ||
516 | val1 = (chip->reg_image[left_reg] & ~(mask << shift_left)) | val1; | 518 | val1 = (chip->reg_image[left_reg] & ~(mask << shift_left)) | val1; |
517 | val2 = (chip->reg_image[right_reg] & ~(mask << shift_right)) | val2; | 519 | val2 = (chip->reg_image[right_reg] & ~(mask << shift_right)) | val2; |
@@ -519,16 +521,16 @@ static int snd_at73c213_stereo_put(struct snd_kcontrol *kcontrol, | |||
519 | || val2 != chip->reg_image[right_reg]; | 521 | || val2 != chip->reg_image[right_reg]; |
520 | retval = snd_at73c213_write_reg(chip, left_reg, val1); | 522 | retval = snd_at73c213_write_reg(chip, left_reg, val1); |
521 | if (retval) { | 523 | if (retval) { |
522 | spin_unlock_irq(&chip->lock); | 524 | mutex_unlock(&chip->mixer_lock); |
523 | goto out; | 525 | goto out; |
524 | } | 526 | } |
525 | retval = snd_at73c213_write_reg(chip, right_reg, val2); | 527 | retval = snd_at73c213_write_reg(chip, right_reg, val2); |
526 | if (retval) { | 528 | if (retval) { |
527 | spin_unlock_irq(&chip->lock); | 529 | mutex_unlock(&chip->mixer_lock); |
528 | goto out; | 530 | goto out; |
529 | } | 531 | } |
530 | 532 | ||
531 | spin_unlock_irq(&chip->lock); | 533 | mutex_unlock(&chip->mixer_lock); |
532 | 534 | ||
533 | return change; | 535 | return change; |
534 | 536 | ||
@@ -536,16 +538,7 @@ out: | |||
536 | return retval; | 538 | return retval; |
537 | } | 539 | } |
538 | 540 | ||
539 | static int snd_at73c213_mono_switch_info(struct snd_kcontrol *kcontrol, | 541 | #define snd_at73c213_mono_switch_info snd_ctl_boolean_mono_info |
540 | struct snd_ctl_elem_info *uinfo) | ||
541 | { | ||
542 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
543 | uinfo->count = 1; | ||
544 | uinfo->value.integer.min = 0; | ||
545 | uinfo->value.integer.max = 1; | ||
546 | |||
547 | return 0; | ||
548 | } | ||
549 | 542 | ||
550 | static int snd_at73c213_mono_switch_get(struct snd_kcontrol *kcontrol, | 543 | static int snd_at73c213_mono_switch_get(struct snd_kcontrol *kcontrol, |
551 | struct snd_ctl_elem_value *ucontrol) | 544 | struct snd_ctl_elem_value *ucontrol) |
@@ -555,7 +548,7 @@ static int snd_at73c213_mono_switch_get(struct snd_kcontrol *kcontrol, | |||
555 | int shift = (kcontrol->private_value >> 8) & 0xff; | 548 | int shift = (kcontrol->private_value >> 8) & 0xff; |
556 | int invert = (kcontrol->private_value >> 24) & 0xff; | 549 | int invert = (kcontrol->private_value >> 24) & 0xff; |
557 | 550 | ||
558 | spin_lock_irq(&chip->lock); | 551 | mutex_lock(&chip->mixer_lock); |
559 | 552 | ||
560 | ucontrol->value.integer.value[0] = | 553 | ucontrol->value.integer.value[0] = |
561 | (chip->reg_image[reg] >> shift) & 0x01; | 554 | (chip->reg_image[reg] >> shift) & 0x01; |
@@ -564,7 +557,7 @@ static int snd_at73c213_mono_switch_get(struct snd_kcontrol *kcontrol, | |||
564 | ucontrol->value.integer.value[0] = | 557 | ucontrol->value.integer.value[0] = |
565 | 0x01 - ucontrol->value.integer.value[0]; | 558 | 0x01 - ucontrol->value.integer.value[0]; |
566 | 559 | ||
567 | spin_unlock_irq(&chip->lock); | 560 | mutex_unlock(&chip->mixer_lock); |
568 | 561 | ||
569 | return 0; | 562 | return 0; |
570 | } | 563 | } |
@@ -589,14 +582,14 @@ static int snd_at73c213_mono_switch_put(struct snd_kcontrol *kcontrol, | |||
589 | val = mask - val; | 582 | val = mask - val; |
590 | val <<= shift; | 583 | val <<= shift; |
591 | 584 | ||
592 | spin_lock_irq(&chip->lock); | 585 | mutex_lock(&chip->mixer_lock); |
593 | 586 | ||
594 | val |= (chip->reg_image[reg] & ~(mask << shift)); | 587 | val |= (chip->reg_image[reg] & ~(mask << shift)); |
595 | change = val != chip->reg_image[reg]; | 588 | change = val != chip->reg_image[reg]; |
596 | 589 | ||
597 | retval = snd_at73c213_write_reg(chip, reg, val); | 590 | retval = snd_at73c213_write_reg(chip, reg, val); |
598 | 591 | ||
599 | spin_unlock_irq(&chip->lock); | 592 | mutex_unlock(&chip->mixer_lock); |
600 | 593 | ||
601 | if (retval) | 594 | if (retval) |
602 | return retval; | 595 | return retval; |
@@ -893,6 +886,7 @@ static int __devinit snd_at73c213_dev_init(struct snd_card *card, | |||
893 | return irq; | 886 | return irq; |
894 | 887 | ||
895 | spin_lock_init(&chip->lock); | 888 | spin_lock_init(&chip->lock); |
889 | mutex_init(&chip->mixer_lock); | ||
896 | chip->card = card; | 890 | chip->card = card; |
897 | chip->irq = -1; | 891 | chip->irq = -1; |
898 | 892 | ||
diff --git a/sound/synth/emux/emux.c b/sound/synth/emux/emux.c index ebcac13fd397..c89d2ea594b9 100644 --- a/sound/synth/emux/emux.c +++ b/sound/synth/emux/emux.c | |||
@@ -18,7 +18,6 @@ | |||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <sound/driver.h> | ||
22 | #include <linux/wait.h> | 21 | #include <linux/wait.h> |
23 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
24 | #include <linux/string.h> | 23 | #include <linux/string.h> |
diff --git a/sound/synth/emux/emux_hwdep.c b/sound/synth/emux/emux_hwdep.c index 9b63814c3f64..0a5391436add 100644 --- a/sound/synth/emux/emux_hwdep.c +++ b/sound/synth/emux/emux_hwdep.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <sound/core.h> | 22 | #include <sound/core.h> |
24 | #include <sound/hwdep.h> | 23 | #include <sound/hwdep.h> |
25 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
diff --git a/sound/synth/emux/emux_oss.c b/sound/synth/emux/emux_oss.c index 3436816727c8..f60a98ef7dec 100644 --- a/sound/synth/emux/emux_oss.c +++ b/sound/synth/emux/emux_oss.c | |||
@@ -22,7 +22,6 @@ | |||
22 | * midi emulation. | 22 | * midi emulation. |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <sound/driver.h> | ||
26 | 25 | ||
27 | #ifdef CONFIG_SND_SEQUENCER_OSS | 26 | #ifdef CONFIG_SND_SEQUENCER_OSS |
28 | 27 | ||
diff --git a/sound/synth/emux/emux_proc.c b/sound/synth/emux/emux_proc.c index 680f2b7fec20..687e6a13689e 100644 --- a/sound/synth/emux/emux_proc.c +++ b/sound/synth/emux/emux_proc.c | |||
@@ -18,7 +18,6 @@ | |||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <sound/driver.h> | ||
22 | #include <linux/wait.h> | 21 | #include <linux/wait.h> |
23 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
24 | #include <sound/core.h> | 23 | #include <sound/core.h> |
diff --git a/sound/synth/emux/emux_voice.h b/sound/synth/emux/emux_voice.h index 0a56ca18b165..09711f84ed30 100644 --- a/sound/synth/emux/emux_voice.h +++ b/sound/synth/emux/emux_voice.h | |||
@@ -22,7 +22,6 @@ | |||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <sound/driver.h> | ||
26 | #include <linux/wait.h> | 25 | #include <linux/wait.h> |
27 | #include <linux/sched.h> | 26 | #include <linux/sched.h> |
28 | #include <sound/core.h> | 27 | #include <sound/core.h> |
diff --git a/sound/synth/emux/soundfont.c b/sound/synth/emux/soundfont.c index 455e535933ec..36d53bd317ed 100644 --- a/sound/synth/emux/soundfont.c +++ b/sound/synth/emux/soundfont.c | |||
@@ -25,7 +25,6 @@ | |||
25 | * of doing things so that the old sfxload utility can be used. | 25 | * of doing things so that the old sfxload utility can be used. |
26 | * Everything may change when there is an alsa way of doing things. | 26 | * Everything may change when there is an alsa way of doing things. |
27 | */ | 27 | */ |
28 | #include <sound/driver.h> | ||
29 | #include <asm/uaccess.h> | 28 | #include <asm/uaccess.h> |
30 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
31 | #include <sound/core.h> | 30 | #include <sound/core.h> |
diff --git a/sound/synth/util_mem.c b/sound/synth/util_mem.c index 6fc3d2b2519f..deabe5f899c4 100644 --- a/sound/synth/util_mem.c +++ b/sound/synth/util_mem.c | |||
@@ -19,7 +19,6 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/mutex.h> | 21 | #include <linux/mutex.h> |
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
25 | #include <sound/core.h> | 24 | #include <sound/core.h> |
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 706143826aff..9351b8a765b9 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig | |||
@@ -31,17 +31,18 @@ config SND_USB_USX2Y | |||
31 | 31 | ||
32 | config SND_USB_CAIAQ | 32 | config SND_USB_CAIAQ |
33 | tristate "Native Instruments USB audio devices" | 33 | tristate "Native Instruments USB audio devices" |
34 | depends on SND && USB | 34 | depends on SND && USB |
35 | select SND_HWDEP | 35 | select SND_HWDEP |
36 | select SND_RAWMIDI | 36 | select SND_RAWMIDI |
37 | select SND_PCM | 37 | select SND_PCM |
38 | help | 38 | help |
39 | Say Y here to include support for caiaq USB audio interfaces, | 39 | Say Y here to include support for caiaq USB audio interfaces, |
40 | namely: | 40 | namely: |
41 | 41 | ||
42 | * Native Instruments RigKontrol2 | 42 | * Native Instruments RigKontrol2 |
43 | * Native Instruments RigKontrol3 | 43 | * Native Instruments RigKontrol3 |
44 | * Native Instruments Kore Controller | 44 | * Native Instruments Kore Controller |
45 | * Native Instruments Kore Controller 2 | ||
45 | * Native Instruments Audio Kontrol 1 | 46 | * Native Instruments Audio Kontrol 1 |
46 | * Native Instruments Audio 8 DJ | 47 | * Native Instruments Audio 8 DJ |
47 | 48 | ||
@@ -51,12 +52,15 @@ config SND_USB_CAIAQ | |||
51 | config SND_USB_CAIAQ_INPUT | 52 | config SND_USB_CAIAQ_INPUT |
52 | bool "enable input device for controllers" | 53 | bool "enable input device for controllers" |
53 | depends on SND_USB_CAIAQ | 54 | depends on SND_USB_CAIAQ |
55 | depends on INPUT=y || INPUT=SND_USB_CAIAQ | ||
54 | help | 56 | help |
55 | Say Y here to support input controllers like buttons, knobs, | 57 | Say Y here to support input controllers like buttons, knobs, |
56 | alpha dials and analog pedals on the following products: | 58 | alpha dials and analog pedals on the following products: |
57 | 59 | ||
58 | * Native Instruments RigKontrol2 | 60 | * Native Instruments RigKontrol2 |
59 | * Native Instruments RigKontrol3 | 61 | * Native Instruments RigKontrol3 |
62 | * Native Instruments Kore Controller | ||
63 | * Native Instruments Kore Controller 2 | ||
60 | * Native Instruments Audio Kontrol 1 | 64 | * Native Instruments Audio Kontrol 1 |
61 | 65 | ||
62 | endmenu | 66 | endmenu |
diff --git a/sound/usb/caiaq/Makefile b/sound/usb/caiaq/Makefile index 455c8c58a1bd..23dadd5a11cd 100644 --- a/sound/usb/caiaq/Makefile +++ b/sound/usb/caiaq/Makefile | |||
@@ -1,3 +1,4 @@ | |||
1 | snd-usb-caiaq-objs := caiaq-device.o caiaq-audio.o caiaq-midi.o caiaq-input.o | 1 | snd-usb-caiaq-y := caiaq-device.o caiaq-audio.o caiaq-midi.o caiaq-control.o |
2 | snd-usb-caiaq-$(CONFIG_SND_USB_CAIAQ_INPUT) += caiaq-input.o | ||
2 | 3 | ||
3 | obj-$(CONFIG_SND_USB_CAIAQ) += snd-usb-caiaq.o | 4 | obj-$(CONFIG_SND_USB_CAIAQ) += snd-usb-caiaq.o |
diff --git a/sound/usb/caiaq/caiaq-audio.c b/sound/usb/caiaq/caiaq-audio.c index 0666908a2361..9cc4cd8283f9 100644 --- a/sound/usb/caiaq/caiaq-audio.c +++ b/sound/usb/caiaq/caiaq-audio.c | |||
@@ -16,7 +16,6 @@ | |||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <sound/driver.h> | ||
20 | #include <linux/init.h> | 19 | #include <linux/init.h> |
21 | #include <linux/module.h> | 20 | #include <linux/module.h> |
22 | #include <linux/moduleparam.h> | 21 | #include <linux/moduleparam.h> |
@@ -27,9 +26,7 @@ | |||
27 | #include <sound/initval.h> | 26 | #include <sound/initval.h> |
28 | #include <sound/pcm.h> | 27 | #include <sound/pcm.h> |
29 | #include <sound/rawmidi.h> | 28 | #include <sound/rawmidi.h> |
30 | #ifdef CONFIG_SND_USB_CAIAQ_INPUT | ||
31 | #include <linux/input.h> | 29 | #include <linux/input.h> |
32 | #endif | ||
33 | 30 | ||
34 | #include "caiaq-device.h" | 31 | #include "caiaq-device.h" |
35 | #include "caiaq-audio.h" | 32 | #include "caiaq-audio.h" |
@@ -60,7 +57,7 @@ static struct snd_pcm_hardware snd_usb_caiaq_pcm_hardware = { | |||
60 | .channels_min = CHANNELS_PER_STREAM, | 57 | .channels_min = CHANNELS_PER_STREAM, |
61 | .channels_max = CHANNELS_PER_STREAM, | 58 | .channels_max = CHANNELS_PER_STREAM, |
62 | .buffer_bytes_max = MAX_BUFFER_SIZE, | 59 | .buffer_bytes_max = MAX_BUFFER_SIZE, |
63 | .period_bytes_min = 4096, | 60 | .period_bytes_min = 128, |
64 | .period_bytes_max = MAX_BUFFER_SIZE, | 61 | .period_bytes_max = MAX_BUFFER_SIZE, |
65 | .periods_min = 1, | 62 | .periods_min = 1, |
66 | .periods_max = 1024, | 63 | .periods_max = 1024, |
@@ -606,7 +603,7 @@ static void free_urbs(struct urb **urbs) | |||
606 | kfree(urbs); | 603 | kfree(urbs); |
607 | } | 604 | } |
608 | 605 | ||
609 | int __devinit snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) | 606 | int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) |
610 | { | 607 | { |
611 | int i, ret; | 608 | int i, ret; |
612 | 609 | ||
diff --git a/sound/usb/caiaq/caiaq-control.c b/sound/usb/caiaq/caiaq-control.c new file mode 100644 index 000000000000..798ca124da58 --- /dev/null +++ b/sound/usb/caiaq/caiaq-control.c | |||
@@ -0,0 +1,315 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2007 Daniel Mack | ||
3 | * friendly supported by NI. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include <linux/init.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/usb.h> | ||
23 | #include <sound/core.h> | ||
24 | #include <sound/initval.h> | ||
25 | #include <sound/pcm.h> | ||
26 | #include <sound/rawmidi.h> | ||
27 | #include <sound/control.h> | ||
28 | #include <linux/input.h> | ||
29 | |||
30 | #include "caiaq-device.h" | ||
31 | #include "caiaq-control.h" | ||
32 | |||
33 | #define CNT_INTVAL 0x10000 | ||
34 | |||
35 | static int control_info(struct snd_kcontrol *kcontrol, | ||
36 | struct snd_ctl_elem_info *uinfo) | ||
37 | { | ||
38 | struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol); | ||
39 | struct snd_usb_caiaqdev *dev = caiaqdev(chip->card); | ||
40 | int pos = kcontrol->private_value; | ||
41 | int is_intval = pos & CNT_INTVAL; | ||
42 | |||
43 | uinfo->count = 1; | ||
44 | pos &= ~CNT_INTVAL; | ||
45 | |||
46 | if (dev->chip.usb_id == | ||
47 | USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ) | ||
48 | && (pos == 0)) { | ||
49 | /* current input mode of A8DJ */ | ||
50 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
51 | uinfo->value.integer.min = 0; | ||
52 | uinfo->value.integer.max = 2; | ||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | if (is_intval) { | ||
57 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
58 | uinfo->value.integer.min = 0; | ||
59 | uinfo->value.integer.max = 64; | ||
60 | } else { | ||
61 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
62 | uinfo->value.integer.min = 0; | ||
63 | uinfo->value.integer.max = 1; | ||
64 | } | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static int control_get(struct snd_kcontrol *kcontrol, | ||
70 | struct snd_ctl_elem_value *ucontrol) | ||
71 | { | ||
72 | struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol); | ||
73 | struct snd_usb_caiaqdev *dev = caiaqdev(chip->card); | ||
74 | int pos = kcontrol->private_value; | ||
75 | |||
76 | if (pos & CNT_INTVAL) | ||
77 | ucontrol->value.integer.value[0] | ||
78 | = dev->control_state[pos & ~CNT_INTVAL]; | ||
79 | else | ||
80 | ucontrol->value.integer.value[0] | ||
81 | = !!(dev->control_state[pos / 8] & (1 << pos % 8)); | ||
82 | |||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static int control_put(struct snd_kcontrol *kcontrol, | ||
87 | struct snd_ctl_elem_value *ucontrol) | ||
88 | { | ||
89 | struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol); | ||
90 | struct snd_usb_caiaqdev *dev = caiaqdev(chip->card); | ||
91 | int pos = kcontrol->private_value; | ||
92 | |||
93 | if (pos & CNT_INTVAL) { | ||
94 | dev->control_state[pos & ~CNT_INTVAL] | ||
95 | = ucontrol->value.integer.value[0]; | ||
96 | snd_usb_caiaq_send_command(dev, EP1_CMD_DIMM_LEDS, | ||
97 | dev->control_state, sizeof(dev->control_state)); | ||
98 | } else { | ||
99 | if (ucontrol->value.integer.value[0]) | ||
100 | dev->control_state[pos / 8] |= 1 << (pos % 8); | ||
101 | else | ||
102 | dev->control_state[pos / 8] &= ~(1 << (pos % 8)); | ||
103 | |||
104 | snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, | ||
105 | dev->control_state, sizeof(dev->control_state)); | ||
106 | } | ||
107 | |||
108 | return 1; | ||
109 | } | ||
110 | |||
111 | static struct snd_kcontrol_new kcontrol_template __devinitdata = { | ||
112 | .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, | ||
113 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
114 | .index = 0, | ||
115 | .info = control_info, | ||
116 | .get = control_get, | ||
117 | .put = control_put, | ||
118 | /* name and private_value filled later */ | ||
119 | }; | ||
120 | |||
121 | struct caiaq_controller { | ||
122 | char *name; | ||
123 | int index; | ||
124 | }; | ||
125 | |||
126 | static struct caiaq_controller ak1_controller[] = { | ||
127 | { "LED left", 2 }, | ||
128 | { "LED middle", 1 }, | ||
129 | { "LED right", 0 }, | ||
130 | { "LED ring", 3 } | ||
131 | }; | ||
132 | |||
133 | static struct caiaq_controller rk2_controller[] = { | ||
134 | { "LED 1", 5 }, | ||
135 | { "LED 2", 4 }, | ||
136 | { "LED 3", 3 }, | ||
137 | { "LED 4", 2 }, | ||
138 | { "LED 5", 1 }, | ||
139 | { "LED 6", 0 }, | ||
140 | { "LED pedal", 6 }, | ||
141 | { "LED 7seg_1b", 8 }, | ||
142 | { "LED 7seg_1c", 9 }, | ||
143 | { "LED 7seg_2a", 10 }, | ||
144 | { "LED 7seg_2b", 11 }, | ||
145 | { "LED 7seg_2c", 12 }, | ||
146 | { "LED 7seg_2d", 13 }, | ||
147 | { "LED 7seg_2e", 14 }, | ||
148 | { "LED 7seg_2f", 15 }, | ||
149 | { "LED 7seg_2g", 16 }, | ||
150 | { "LED 7seg_3a", 17 }, | ||
151 | { "LED 7seg_3b", 18 }, | ||
152 | { "LED 7seg_3c", 19 }, | ||
153 | { "LED 7seg_3d", 20 }, | ||
154 | { "LED 7seg_3e", 21 }, | ||
155 | { "LED 7seg_3f", 22 }, | ||
156 | { "LED 7seg_3g", 23 } | ||
157 | }; | ||
158 | |||
159 | static struct caiaq_controller rk3_controller[] = { | ||
160 | { "LED 7seg_1a", 0 + 0 }, | ||
161 | { "LED 7seg_1b", 0 + 1 }, | ||
162 | { "LED 7seg_1c", 0 + 2 }, | ||
163 | { "LED 7seg_1d", 0 + 3 }, | ||
164 | { "LED 7seg_1e", 0 + 4 }, | ||
165 | { "LED 7seg_1f", 0 + 5 }, | ||
166 | { "LED 7seg_1g", 0 + 6 }, | ||
167 | { "LED 7seg_1p", 0 + 7 }, | ||
168 | |||
169 | { "LED 7seg_2a", 8 + 0 }, | ||
170 | { "LED 7seg_2b", 8 + 1 }, | ||
171 | { "LED 7seg_2c", 8 + 2 }, | ||
172 | { "LED 7seg_2d", 8 + 3 }, | ||
173 | { "LED 7seg_2e", 8 + 4 }, | ||
174 | { "LED 7seg_2f", 8 + 5 }, | ||
175 | { "LED 7seg_2g", 8 + 6 }, | ||
176 | { "LED 7seg_2p", 8 + 7 }, | ||
177 | |||
178 | { "LED 7seg_3a", 16 + 0 }, | ||
179 | { "LED 7seg_3b", 16 + 1 }, | ||
180 | { "LED 7seg_3c", 16 + 2 }, | ||
181 | { "LED 7seg_3d", 16 + 3 }, | ||
182 | { "LED 7seg_3e", 16 + 4 }, | ||
183 | { "LED 7seg_3f", 16 + 5 }, | ||
184 | { "LED 7seg_3g", 16 + 6 }, | ||
185 | { "LED 7seg_3p", 16 + 7 }, | ||
186 | |||
187 | { "LED 7seg_4a", 24 + 0 }, | ||
188 | { "LED 7seg_4b", 24 + 1 }, | ||
189 | { "LED 7seg_4c", 24 + 2 }, | ||
190 | { "LED 7seg_4d", 24 + 3 }, | ||
191 | { "LED 7seg_4e", 24 + 4 }, | ||
192 | { "LED 7seg_4f", 24 + 5 }, | ||
193 | { "LED 7seg_4g", 24 + 6 }, | ||
194 | { "LED 7seg_4p", 24 + 7 }, | ||
195 | |||
196 | { "LED 1", 32 + 0 }, | ||
197 | { "LED 2", 32 + 1 }, | ||
198 | { "LED 3", 32 + 2 }, | ||
199 | { "LED 4", 32 + 3 }, | ||
200 | { "LED 5", 32 + 4 }, | ||
201 | { "LED 6", 32 + 5 }, | ||
202 | { "LED 7", 32 + 6 }, | ||
203 | { "LED 8", 32 + 7 }, | ||
204 | { "LED pedal", 32 + 8 } | ||
205 | }; | ||
206 | |||
207 | static struct caiaq_controller kore_controller[] = { | ||
208 | { "LED F1", 8 | CNT_INTVAL }, | ||
209 | { "LED F2", 12 | CNT_INTVAL }, | ||
210 | { "LED F3", 0 | CNT_INTVAL }, | ||
211 | { "LED F4", 4 | CNT_INTVAL }, | ||
212 | { "LED F5", 11 | CNT_INTVAL }, | ||
213 | { "LED F6", 15 | CNT_INTVAL }, | ||
214 | { "LED F7", 3 | CNT_INTVAL }, | ||
215 | { "LED F8", 7 | CNT_INTVAL }, | ||
216 | { "LED touch1", 10 | CNT_INTVAL }, | ||
217 | { "LED touch2", 14 | CNT_INTVAL }, | ||
218 | { "LED touch3", 2 | CNT_INTVAL }, | ||
219 | { "LED touch4", 6 | CNT_INTVAL }, | ||
220 | { "LED touch5", 9 | CNT_INTVAL }, | ||
221 | { "LED touch6", 13 | CNT_INTVAL }, | ||
222 | { "LED touch7", 1 | CNT_INTVAL }, | ||
223 | { "LED touch8", 5 | CNT_INTVAL }, | ||
224 | { "LED left", 18 | CNT_INTVAL }, | ||
225 | { "LED right", 22 | CNT_INTVAL }, | ||
226 | { "LED up", 16 | CNT_INTVAL }, | ||
227 | { "LED down", 20 | CNT_INTVAL }, | ||
228 | { "LED stop", 23 | CNT_INTVAL }, | ||
229 | { "LED play", 21 | CNT_INTVAL }, | ||
230 | { "LED record", 19 | CNT_INTVAL }, | ||
231 | { "LED listen", 17 | CNT_INTVAL }, | ||
232 | { "LED lcd", 30 | CNT_INTVAL }, | ||
233 | { "LED menu", 28 | CNT_INTVAL }, | ||
234 | { "LED sound", 31 | CNT_INTVAL }, | ||
235 | { "LED esc", 29 | CNT_INTVAL }, | ||
236 | { "LED view", 27 | CNT_INTVAL }, | ||
237 | { "LED enter", 24 | CNT_INTVAL }, | ||
238 | { "LED control", 26 | CNT_INTVAL } | ||
239 | }; | ||
240 | |||
241 | static struct caiaq_controller a8dj_controller[] = { | ||
242 | { "Current input mode", 0 | CNT_INTVAL }, | ||
243 | { "GND lift for TC Vinyl mode", 24 + 0 }, | ||
244 | { "GND lift for TC CD/Line mode", 24 + 1 }, | ||
245 | { "GND lift for phono mode", 24 + 2 }, | ||
246 | { "GND lift for TC Vinyl mode", 24 + 3 }, | ||
247 | { "Software lock", 40 } | ||
248 | }; | ||
249 | |||
250 | int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev) | ||
251 | { | ||
252 | int i; | ||
253 | struct snd_kcontrol *kc; | ||
254 | |||
255 | switch (dev->chip.usb_id) { | ||
256 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): | ||
257 | for (i = 0; i < ARRAY_SIZE(ak1_controller); i++) { | ||
258 | struct caiaq_controller *c = ak1_controller + i; | ||
259 | kcontrol_template.name = c->name; | ||
260 | kcontrol_template.private_value = c->index; | ||
261 | kc = snd_ctl_new1(&kcontrol_template, dev); | ||
262 | snd_ctl_add(dev->chip.card, kc); | ||
263 | } | ||
264 | |||
265 | break; | ||
266 | |||
267 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): | ||
268 | for (i = 0; i < ARRAY_SIZE(rk2_controller); i++) { | ||
269 | struct caiaq_controller *c = rk2_controller + i; | ||
270 | kcontrol_template.name = c->name; | ||
271 | kcontrol_template.private_value = c->index; | ||
272 | kc = snd_ctl_new1(&kcontrol_template, dev); | ||
273 | snd_ctl_add(dev->chip.card, kc); | ||
274 | } | ||
275 | |||
276 | break; | ||
277 | |||
278 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): | ||
279 | for (i = 0; i < ARRAY_SIZE(rk3_controller); i++) { | ||
280 | struct caiaq_controller *c = rk3_controller + i; | ||
281 | kcontrol_template.name = c->name; | ||
282 | kcontrol_template.private_value = c->index; | ||
283 | kc = snd_ctl_new1(&kcontrol_template, dev); | ||
284 | snd_ctl_add(dev->chip.card, kc); | ||
285 | } | ||
286 | |||
287 | break; | ||
288 | |||
289 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER): | ||
290 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2): | ||
291 | for (i = 0; i < ARRAY_SIZE(kore_controller); i++) { | ||
292 | struct caiaq_controller *c = kore_controller + i; | ||
293 | kcontrol_template.name = c->name; | ||
294 | kcontrol_template.private_value = c->index; | ||
295 | kc = snd_ctl_new1(&kcontrol_template, dev); | ||
296 | snd_ctl_add(dev->chip.card, kc); | ||
297 | } | ||
298 | |||
299 | break; | ||
300 | |||
301 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ): | ||
302 | for (i = 0; i < ARRAY_SIZE(a8dj_controller); i++) { | ||
303 | struct caiaq_controller *c = a8dj_controller + i; | ||
304 | kcontrol_template.name = c->name; | ||
305 | kcontrol_template.private_value = c->index; | ||
306 | kc = snd_ctl_new1(&kcontrol_template, dev); | ||
307 | snd_ctl_add(dev->chip.card, kc); | ||
308 | } | ||
309 | |||
310 | break; | ||
311 | } | ||
312 | |||
313 | return 0; | ||
314 | } | ||
315 | |||
diff --git a/sound/usb/caiaq/caiaq-control.h b/sound/usb/caiaq/caiaq-control.h new file mode 100644 index 000000000000..2e7ab1aa4fb3 --- /dev/null +++ b/sound/usb/caiaq/caiaq-control.h | |||
@@ -0,0 +1,6 @@ | |||
1 | #ifndef CAIAQ_CONTROL_H | ||
2 | #define CAIAQ_CONTROL_H | ||
3 | |||
4 | int snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev); | ||
5 | |||
6 | #endif /* CAIAQ_CONTROL_H */ | ||
diff --git a/sound/usb/caiaq/caiaq-device.c b/sound/usb/caiaq/caiaq-device.c index 58af8142c571..58d25e4e7d6c 100644 --- a/sound/usb/caiaq/caiaq-device.c +++ b/sound/usb/caiaq/caiaq-device.c | |||
@@ -26,26 +26,28 @@ | |||
26 | #include <linux/usb.h> | 26 | #include <linux/usb.h> |
27 | #include <linux/input.h> | 27 | #include <linux/input.h> |
28 | #include <linux/spinlock.h> | 28 | #include <linux/spinlock.h> |
29 | #include <sound/driver.h> | ||
30 | #include <sound/core.h> | 29 | #include <sound/core.h> |
31 | #include <sound/initval.h> | 30 | #include <sound/initval.h> |
32 | #include <sound/pcm.h> | 31 | #include <sound/pcm.h> |
33 | #include <sound/rawmidi.h> | 32 | #include <sound/rawmidi.h> |
33 | #include <sound/control.h> | ||
34 | 34 | ||
35 | #include "caiaq-device.h" | 35 | #include "caiaq-device.h" |
36 | #include "caiaq-audio.h" | 36 | #include "caiaq-audio.h" |
37 | #include "caiaq-midi.h" | 37 | #include "caiaq-midi.h" |
38 | #include "caiaq-control.h" | ||
38 | 39 | ||
39 | #ifdef CONFIG_SND_USB_CAIAQ_INPUT | 40 | #ifdef CONFIG_SND_USB_CAIAQ_INPUT |
40 | #include "caiaq-input.h" | 41 | #include "caiaq-input.h" |
41 | #endif | 42 | #endif |
42 | 43 | ||
43 | MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); | 44 | MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); |
44 | MODULE_DESCRIPTION("caiaq USB audio, version 1.2.0"); | 45 | MODULE_DESCRIPTION("caiaq USB audio, version 1.3.2"); |
45 | MODULE_LICENSE("GPL"); | 46 | MODULE_LICENSE("GPL"); |
46 | MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," | 47 | MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," |
47 | "{Native Instruments, RigKontrol3}," | 48 | "{Native Instruments, RigKontrol3}," |
48 | "{Native Instruments, Kore Controller}," | 49 | "{Native Instruments, Kore Controller}," |
50 | "{Native Instruments, Kore Controller 2}," | ||
49 | "{Native Instruments, Audio Kontrol 1}" | 51 | "{Native Instruments, Audio Kontrol 1}" |
50 | "{Native Instruments, Audio 8 DJ}}"); | 52 | "{Native Instruments, Audio 8 DJ}}"); |
51 | 53 | ||
@@ -94,6 +96,11 @@ static struct usb_device_id snd_usb_id_table[] = { | |||
94 | .idProduct = USB_PID_KORECONTROLLER | 96 | .idProduct = USB_PID_KORECONTROLLER |
95 | }, | 97 | }, |
96 | { | 98 | { |
99 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE, | ||
100 | .idVendor = USB_VID_NATIVEINSTRUMENTS, | ||
101 | .idProduct = USB_PID_KORECONTROLLER2 | ||
102 | }, | ||
103 | { | ||
97 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE, | 104 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE, |
98 | .idVendor = USB_VID_NATIVEINSTRUMENTS, | 105 | .idVendor = USB_VID_NATIVEINSTRUMENTS, |
99 | .idProduct = USB_PID_AK1 | 106 | .idProduct = USB_PID_AK1 |
@@ -140,14 +147,21 @@ static void usb_ep1_command_reply_dispatch (struct urb* urb) | |||
140 | case EP1_CMD_MIDI_READ: | 147 | case EP1_CMD_MIDI_READ: |
141 | snd_usb_caiaq_midi_handle_input(dev, buf[1], buf + 3, buf[2]); | 148 | snd_usb_caiaq_midi_handle_input(dev, buf[1], buf + 3, buf[2]); |
142 | break; | 149 | break; |
143 | 150 | case EP1_CMD_READ_IO: | |
151 | if (dev->chip.usb_id == | ||
152 | USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ)) { | ||
153 | if (urb->actual_length > sizeof(dev->control_state)) | ||
154 | urb->actual_length = sizeof(dev->control_state); | ||
155 | memcpy(dev->control_state, buf + 1, urb->actual_length); | ||
156 | wake_up(&dev->ep1_wait_queue); | ||
157 | break; | ||
158 | } | ||
144 | #ifdef CONFIG_SND_USB_CAIAQ_INPUT | 159 | #ifdef CONFIG_SND_USB_CAIAQ_INPUT |
145 | case EP1_CMD_READ_ERP: | 160 | case EP1_CMD_READ_ERP: |
146 | case EP1_CMD_READ_ANALOG: | 161 | case EP1_CMD_READ_ANALOG: |
147 | case EP1_CMD_READ_IO: | ||
148 | snd_usb_caiaq_input_dispatch(dev, buf, urb->actual_length); | 162 | snd_usb_caiaq_input_dispatch(dev, buf, urb->actual_length); |
149 | break; | ||
150 | #endif | 163 | #endif |
164 | break; | ||
151 | } | 165 | } |
152 | 166 | ||
153 | dev->ep1_in_urb.actual_length = 0; | 167 | dev->ep1_in_urb.actual_length = 0; |
@@ -156,10 +170,10 @@ static void usb_ep1_command_reply_dispatch (struct urb* urb) | |||
156 | log("unable to submit urb. OOM!?\n"); | 170 | log("unable to submit urb. OOM!?\n"); |
157 | } | 171 | } |
158 | 172 | ||
159 | static int send_command (struct snd_usb_caiaqdev *dev, | 173 | int snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *dev, |
160 | unsigned char command, | 174 | unsigned char command, |
161 | const unsigned char *buffer, | 175 | const unsigned char *buffer, |
162 | int len) | 176 | int len) |
163 | { | 177 | { |
164 | int actual_len; | 178 | int actual_len; |
165 | struct usb_device *usb_dev = dev->chip.dev; | 179 | struct usb_device *usb_dev = dev->chip.dev; |
@@ -207,7 +221,8 @@ int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev, | |||
207 | rate, depth, bpp); | 221 | rate, depth, bpp); |
208 | 222 | ||
209 | dev->audio_parm_answer = -1; | 223 | dev->audio_parm_answer = -1; |
210 | ret = send_command(dev, EP1_CMD_AUDIO_PARAMS, tmp, sizeof(tmp)); | 224 | ret = snd_usb_caiaq_send_command(dev, EP1_CMD_AUDIO_PARAMS, |
225 | tmp, sizeof(tmp)); | ||
211 | 226 | ||
212 | if (ret) | 227 | if (ret) |
213 | return ret; | 228 | return ret; |
@@ -226,7 +241,8 @@ int snd_usb_caiaq_set_auto_msg (struct snd_usb_caiaqdev *dev, | |||
226 | int digital, int analog, int erp) | 241 | int digital, int analog, int erp) |
227 | { | 242 | { |
228 | char tmp[3] = { digital, analog, erp }; | 243 | char tmp[3] = { digital, analog, erp }; |
229 | return send_command(dev, EP1_CMD_AUTO_MSG, tmp, sizeof(tmp)); | 244 | return snd_usb_caiaq_send_command(dev, EP1_CMD_AUTO_MSG, |
245 | tmp, sizeof(tmp)); | ||
230 | } | 246 | } |
231 | 247 | ||
232 | static void setup_card(struct snd_usb_caiaqdev *dev) | 248 | static void setup_card(struct snd_usb_caiaqdev *dev) |
@@ -241,7 +257,7 @@ static void setup_card(struct snd_usb_caiaqdev *dev) | |||
241 | val[0] = 0x00; | 257 | val[0] = 0x00; |
242 | val[1] = 0x00; | 258 | val[1] = 0x00; |
243 | val[2] = 0x01; | 259 | val[2] = 0x01; |
244 | send_command(dev, EP1_CMD_WRITE_IO, val, 3); | 260 | snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, val, 3); |
245 | break; | 261 | break; |
246 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): | 262 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): |
247 | /* RigKontrol2 - display two centered dashes ('--') */ | 263 | /* RigKontrol2 - display two centered dashes ('--') */ |
@@ -249,22 +265,52 @@ static void setup_card(struct snd_usb_caiaqdev *dev) | |||
249 | val[1] = 0x40; | 265 | val[1] = 0x40; |
250 | val[2] = 0x40; | 266 | val[2] = 0x40; |
251 | val[3] = 0x00; | 267 | val[3] = 0x00; |
252 | send_command(dev, EP1_CMD_WRITE_IO, val, 4); | 268 | snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, val, 4); |
253 | break; | 269 | break; |
254 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): | 270 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): |
255 | /* Audio Kontrol 1 - make USB-LED stop blinking */ | 271 | /* Audio Kontrol 1 - make USB-LED stop blinking */ |
256 | val[0] = 0x00; | 272 | val[0] = 0x00; |
257 | send_command(dev, EP1_CMD_WRITE_IO, val, 1); | 273 | snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, val, 1); |
274 | break; | ||
275 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ): | ||
276 | /* Audio 8 DJ - trigger read of current settings */ | ||
277 | dev->control_state[0] = 0xff; | ||
278 | snd_usb_caiaq_set_auto_msg(dev, 1, 0, 0); | ||
279 | snd_usb_caiaq_send_command(dev, EP1_CMD_READ_IO, NULL, 0); | ||
280 | |||
281 | if (!wait_event_timeout(dev->ep1_wait_queue, | ||
282 | dev->control_state[0] != 0xff, HZ)) | ||
283 | return; | ||
284 | |||
285 | /* fix up some defaults */ | ||
286 | if ((dev->control_state[1] != 2) || | ||
287 | (dev->control_state[2] != 3) || | ||
288 | (dev->control_state[4] != 2)) { | ||
289 | dev->control_state[1] = 2; | ||
290 | dev->control_state[2] = 3; | ||
291 | dev->control_state[4] = 2; | ||
292 | snd_usb_caiaq_send_command(dev, | ||
293 | EP1_CMD_WRITE_IO, dev->control_state, 6); | ||
294 | } | ||
295 | |||
258 | break; | 296 | break; |
259 | } | 297 | } |
260 | 298 | ||
261 | ret = snd_usb_caiaq_audio_init(dev); | 299 | if (dev->spec.num_analog_audio_out + |
262 | if (ret < 0) | 300 | dev->spec.num_analog_audio_in + |
263 | log("Unable to set up audio system (ret=%d)\n", ret); | 301 | dev->spec.num_digital_audio_out + |
302 | dev->spec.num_digital_audio_in > 0) { | ||
303 | ret = snd_usb_caiaq_audio_init(dev); | ||
304 | if (ret < 0) | ||
305 | log("Unable to set up audio system (ret=%d)\n", ret); | ||
306 | } | ||
264 | 307 | ||
265 | ret = snd_usb_caiaq_midi_init(dev); | 308 | if (dev->spec.num_midi_in + |
266 | if (ret < 0) | 309 | dev->spec.num_midi_out > 0) { |
267 | log("Unable to set up MIDI system (ret=%d)\n", ret); | 310 | ret = snd_usb_caiaq_midi_init(dev); |
311 | if (ret < 0) | ||
312 | log("Unable to set up MIDI system (ret=%d)\n", ret); | ||
313 | } | ||
268 | 314 | ||
269 | #ifdef CONFIG_SND_USB_CAIAQ_INPUT | 315 | #ifdef CONFIG_SND_USB_CAIAQ_INPUT |
270 | ret = snd_usb_caiaq_input_init(dev); | 316 | ret = snd_usb_caiaq_input_init(dev); |
@@ -278,6 +324,10 @@ static void setup_card(struct snd_usb_caiaqdev *dev) | |||
278 | log("snd_card_register() returned %d\n", ret); | 324 | log("snd_card_register() returned %d\n", ret); |
279 | snd_card_free(dev->chip.card); | 325 | snd_card_free(dev->chip.card); |
280 | } | 326 | } |
327 | |||
328 | ret = snd_usb_caiaq_control_init(dev); | ||
329 | if (ret < 0) | ||
330 | log("Unable to set up control system (ret=%d)\n", ret); | ||
281 | } | 331 | } |
282 | 332 | ||
283 | static struct snd_card* create_card(struct usb_device* usb_dev) | 333 | static struct snd_card* create_card(struct usb_device* usb_dev) |
@@ -340,7 +390,7 @@ static int init_card(struct snd_usb_caiaqdev *dev) | |||
340 | if (usb_submit_urb(&dev->ep1_in_urb, GFP_KERNEL) != 0) | 390 | if (usb_submit_urb(&dev->ep1_in_urb, GFP_KERNEL) != 0) |
341 | return -EIO; | 391 | return -EIO; |
342 | 392 | ||
343 | err = send_command(dev, EP1_CMD_GET_DEVICE_INFO, NULL, 0); | 393 | err = snd_usb_caiaq_send_command(dev, EP1_CMD_GET_DEVICE_INFO, NULL, 0); |
344 | if (err) | 394 | if (err) |
345 | return err; | 395 | return err; |
346 | 396 | ||
diff --git a/sound/usb/caiaq/caiaq-device.h b/sound/usb/caiaq/caiaq-device.h index 79bc5be2df7a..96a491379c60 100644 --- a/sound/usb/caiaq/caiaq-device.h +++ b/sound/usb/caiaq/caiaq-device.h | |||
@@ -7,7 +7,8 @@ | |||
7 | 7 | ||
8 | #define USB_PID_RIGKONTROL2 0x1969 | 8 | #define USB_PID_RIGKONTROL2 0x1969 |
9 | #define USB_PID_RIGKONTROL3 0x1940 | 9 | #define USB_PID_RIGKONTROL3 0x1940 |
10 | #define USB_PID_KORECONTROLLER 0x4711 | 10 | #define USB_PID_KORECONTROLLER 0x4711 |
11 | #define USB_PID_KORECONTROLLER2 0x4712 | ||
11 | #define USB_PID_AK1 0x0815 | 12 | #define USB_PID_AK1 0x0815 |
12 | #define USB_PID_AUDIO8DJ 0x1978 | 13 | #define USB_PID_AUDIO8DJ 0x1978 |
13 | 14 | ||
@@ -35,6 +36,7 @@ | |||
35 | #define EP1_CMD_MIDI_WRITE 0x7 | 36 | #define EP1_CMD_MIDI_WRITE 0x7 |
36 | #define EP1_CMD_AUDIO_PARAMS 0x9 | 37 | #define EP1_CMD_AUDIO_PARAMS 0x9 |
37 | #define EP1_CMD_AUTO_MSG 0xb | 38 | #define EP1_CMD_AUTO_MSG 0xb |
39 | #define EP1_CMD_DIMM_LEDS 0xc | ||
38 | 40 | ||
39 | struct caiaq_device_spec { | 41 | struct caiaq_device_spec { |
40 | unsigned short fw_version; | 42 | unsigned short fw_version; |
@@ -62,7 +64,7 @@ struct snd_usb_caiaqdev { | |||
62 | struct urb **data_urbs_in; | 64 | struct urb **data_urbs_in; |
63 | struct urb **data_urbs_out; | 65 | struct urb **data_urbs_out; |
64 | struct snd_usb_caiaq_cb_info *data_cb_info; | 66 | struct snd_usb_caiaq_cb_info *data_cb_info; |
65 | 67 | ||
66 | unsigned char ep1_in_buf[EP1_BUFSIZE]; | 68 | unsigned char ep1_in_buf[EP1_BUFSIZE]; |
67 | unsigned char ep1_out_buf[EP1_BUFSIZE]; | 69 | unsigned char ep1_out_buf[EP1_BUFSIZE]; |
68 | unsigned char midi_out_buf[EP1_BUFSIZE]; | 70 | unsigned char midi_out_buf[EP1_BUFSIZE]; |
@@ -72,7 +74,7 @@ struct snd_usb_caiaqdev { | |||
72 | wait_queue_head_t ep1_wait_queue; | 74 | wait_queue_head_t ep1_wait_queue; |
73 | wait_queue_head_t prepare_wait_queue; | 75 | wait_queue_head_t prepare_wait_queue; |
74 | int spec_received, audio_parm_answer; | 76 | int spec_received, audio_parm_answer; |
75 | 77 | ||
76 | char vendor_name[CAIAQ_USB_STR_LEN]; | 78 | char vendor_name[CAIAQ_USB_STR_LEN]; |
77 | char product_name[CAIAQ_USB_STR_LEN]; | 79 | char product_name[CAIAQ_USB_STR_LEN]; |
78 | char serial[CAIAQ_USB_STR_LEN]; | 80 | char serial[CAIAQ_USB_STR_LEN]; |
@@ -90,11 +92,16 @@ struct snd_usb_caiaqdev { | |||
90 | struct snd_pcm_substream *sub_playback[MAX_STREAMS]; | 92 | struct snd_pcm_substream *sub_playback[MAX_STREAMS]; |
91 | struct snd_pcm_substream *sub_capture[MAX_STREAMS]; | 93 | struct snd_pcm_substream *sub_capture[MAX_STREAMS]; |
92 | 94 | ||
95 | /* Controls */ | ||
96 | unsigned char control_state[64]; | ||
97 | |||
93 | /* Linux input */ | 98 | /* Linux input */ |
94 | #ifdef CONFIG_SND_USB_CAIAQ_INPUT | 99 | #ifdef CONFIG_SND_USB_CAIAQ_INPUT |
95 | struct input_dev *input_dev; | 100 | struct input_dev *input_dev; |
101 | char phys[64]; /* physical device path */ | ||
102 | unsigned short keycode[64]; | ||
96 | #endif | 103 | #endif |
97 | 104 | ||
98 | /* ALSA */ | 105 | /* ALSA */ |
99 | struct snd_pcm *pcm; | 106 | struct snd_pcm *pcm; |
100 | struct snd_pcm_hardware pcm_info; | 107 | struct snd_pcm_hardware pcm_info; |
@@ -112,6 +119,9 @@ struct snd_usb_caiaq_cb_info { | |||
112 | 119 | ||
113 | int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev, int rate, int depth, int bbp); | 120 | int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev, int rate, int depth, int bbp); |
114 | int snd_usb_caiaq_set_auto_msg (struct snd_usb_caiaqdev *dev, int digital, int analog, int erp); | 121 | int snd_usb_caiaq_set_auto_msg (struct snd_usb_caiaqdev *dev, int digital, int analog, int erp); |
115 | 122 | int snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *dev, | |
123 | unsigned char command, | ||
124 | const unsigned char *buffer, | ||
125 | int len); | ||
116 | 126 | ||
117 | #endif /* CAIAQ_DEVICE_H */ | 127 | #endif /* CAIAQ_DEVICE_H */ |
diff --git a/sound/usb/caiaq/caiaq-input.c b/sound/usb/caiaq/caiaq-input.c index cd536ca20e56..f743847a5e5a 100644 --- a/sound/usb/caiaq/caiaq-input.c +++ b/sound/usb/caiaq/caiaq-input.c | |||
@@ -21,28 +21,61 @@ | |||
21 | #include <linux/moduleparam.h> | 21 | #include <linux/moduleparam.h> |
22 | #include <linux/input.h> | 22 | #include <linux/input.h> |
23 | #include <linux/usb.h> | 23 | #include <linux/usb.h> |
24 | #include <linux/usb/input.h> | ||
24 | #include <linux/spinlock.h> | 25 | #include <linux/spinlock.h> |
25 | #include <sound/driver.h> | ||
26 | #include <sound/core.h> | 26 | #include <sound/core.h> |
27 | #include <sound/rawmidi.h> | 27 | #include <sound/rawmidi.h> |
28 | #include <sound/pcm.h> | 28 | #include <sound/pcm.h> |
29 | #include "caiaq-device.h" | 29 | #include "caiaq-device.h" |
30 | #include "caiaq-input.h" | 30 | #include "caiaq-input.h" |
31 | 31 | ||
32 | #ifdef CONFIG_SND_USB_CAIAQ_INPUT | 32 | static unsigned short keycode_ak1[] = { KEY_C, KEY_B, KEY_A }; |
33 | 33 | static unsigned short keycode_rk2[] = { KEY_1, KEY_2, KEY_3, KEY_4, | |
34 | static unsigned char keycode_ak1[] = { KEY_C, KEY_B, KEY_A }; | 34 | KEY_5, KEY_6, KEY_7 }; |
35 | static unsigned char keycode_rk2[] = { KEY_1, KEY_2, KEY_3, KEY_4, | 35 | static unsigned short keycode_rk3[] = { KEY_1, KEY_2, KEY_3, KEY_4, |
36 | KEY_5, KEY_6, KEY_7 }; | 36 | KEY_5, KEY_6, KEY_7, KEY_5, KEY_6 }; |
37 | static unsigned char keycode_rk3[] = { KEY_1, KEY_2, KEY_3, KEY_4, | 37 | |
38 | KEY_5, KEY_6, KEY_7, KEY_5, KEY_6 }; | 38 | static unsigned short keycode_kore[] = { |
39 | 39 | KEY_FN_F1, /* "menu" */ | |
40 | #define DEG90 (range/2) | 40 | KEY_FN_F7, /* "lcd backlight */ |
41 | #define DEG180 (range) | 41 | KEY_FN_F2, /* "control" */ |
42 | #define DEG270 (DEG90 + DEG180) | 42 | KEY_FN_F3, /* "enter" */ |
43 | #define DEG360 (DEG180 * 2) | 43 | KEY_FN_F4, /* "view" */ |
44 | #define HIGH_PEAK (268) | 44 | KEY_FN_F5, /* "esc" */ |
45 | #define LOW_PEAK (-7) | 45 | KEY_FN_F6, /* "sound" */ |
46 | KEY_FN_F8, /* array spacer, never triggered. */ | ||
47 | KEY_RIGHT, | ||
48 | KEY_DOWN, | ||
49 | KEY_UP, | ||
50 | KEY_LEFT, | ||
51 | KEY_SOUND, /* "listen" */ | ||
52 | KEY_RECORD, | ||
53 | KEY_PLAYPAUSE, | ||
54 | KEY_STOP, | ||
55 | BTN_4, /* 8 softkeys */ | ||
56 | BTN_3, | ||
57 | BTN_2, | ||
58 | BTN_1, | ||
59 | BTN_8, | ||
60 | BTN_7, | ||
61 | BTN_6, | ||
62 | BTN_5, | ||
63 | KEY_BRL_DOT4, /* touch sensitive knobs */ | ||
64 | KEY_BRL_DOT3, | ||
65 | KEY_BRL_DOT2, | ||
66 | KEY_BRL_DOT1, | ||
67 | KEY_BRL_DOT8, | ||
68 | KEY_BRL_DOT7, | ||
69 | KEY_BRL_DOT6, | ||
70 | KEY_BRL_DOT5 | ||
71 | }; | ||
72 | |||
73 | #define DEG90 (range / 2) | ||
74 | #define DEG180 (range) | ||
75 | #define DEG270 (DEG90 + DEG180) | ||
76 | #define DEG360 (DEG180 * 2) | ||
77 | #define HIGH_PEAK (268) | ||
78 | #define LOW_PEAK (-7) | ||
46 | 79 | ||
47 | /* some of these devices have endless rotation potentiometers | 80 | /* some of these devices have endless rotation potentiometers |
48 | * built in which use two tapers, 90 degrees phase shifted. | 81 | * built in which use two tapers, 90 degrees phase shifted. |
@@ -56,8 +89,8 @@ static unsigned int decode_erp(unsigned char a, unsigned char b) | |||
56 | int range = HIGH_PEAK - LOW_PEAK; | 89 | int range = HIGH_PEAK - LOW_PEAK; |
57 | int mid_value = (HIGH_PEAK + LOW_PEAK) / 2; | 90 | int mid_value = (HIGH_PEAK + LOW_PEAK) / 2; |
58 | 91 | ||
59 | weight_b = abs(mid_value-a) - (range/2 - 100)/2; | 92 | weight_b = abs(mid_value - a) - (range / 2 - 100) / 2; |
60 | 93 | ||
61 | if (weight_b < 0) | 94 | if (weight_b < 0) |
62 | weight_b = 0; | 95 | weight_b = 0; |
63 | 96 | ||
@@ -93,7 +126,7 @@ static unsigned int decode_erp(unsigned char a, unsigned char b) | |||
93 | 126 | ||
94 | if (ret < 0) | 127 | if (ret < 0) |
95 | ret += 1000; | 128 | ret += 1000; |
96 | 129 | ||
97 | if (ret >= 1000) | 130 | if (ret >= 1000) |
98 | ret -= 1000; | 131 | ret -= 1000; |
99 | 132 | ||
@@ -108,76 +141,113 @@ static unsigned int decode_erp(unsigned char a, unsigned char b) | |||
108 | #undef LOW_PEAK | 141 | #undef LOW_PEAK |
109 | 142 | ||
110 | 143 | ||
111 | static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, | 144 | static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, |
112 | const unsigned char *buf, | 145 | const unsigned char *buf, |
113 | unsigned int len) | 146 | unsigned int len) |
114 | { | 147 | { |
115 | switch(dev->input_dev->id.product) { | 148 | struct input_dev *input_dev = dev->input_dev; |
116 | case USB_PID_RIGKONTROL2: | 149 | |
117 | input_report_abs(dev->input_dev, ABS_X, (buf[4] << 8) |buf[5]); | 150 | switch (dev->chip.usb_id) { |
118 | input_report_abs(dev->input_dev, ABS_Y, (buf[0] << 8) |buf[1]); | 151 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): |
119 | input_report_abs(dev->input_dev, ABS_Z, (buf[2] << 8) |buf[3]); | 152 | input_report_abs(input_dev, ABS_X, (buf[4] << 8) | buf[5]); |
120 | input_sync(dev->input_dev); | 153 | input_report_abs(input_dev, ABS_Y, (buf[0] << 8) | buf[1]); |
154 | input_report_abs(input_dev, ABS_Z, (buf[2] << 8) | buf[3]); | ||
155 | input_sync(input_dev); | ||
121 | break; | 156 | break; |
122 | case USB_PID_RIGKONTROL3: | 157 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): |
123 | input_report_abs(dev->input_dev, ABS_X, (buf[0] << 8) |buf[1]); | 158 | input_report_abs(input_dev, ABS_X, (buf[0] << 8) | buf[1]); |
124 | input_report_abs(dev->input_dev, ABS_Y, (buf[2] << 8) |buf[3]); | 159 | input_report_abs(input_dev, ABS_Y, (buf[2] << 8) | buf[3]); |
125 | input_report_abs(dev->input_dev, ABS_Z, (buf[4] << 8) |buf[5]); | 160 | input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]); |
126 | input_sync(dev->input_dev); | 161 | input_sync(input_dev); |
162 | break; | ||
163 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER): | ||
164 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2): | ||
165 | input_report_abs(input_dev, ABS_X, (buf[0] << 8) | buf[1]); | ||
166 | input_report_abs(input_dev, ABS_Y, (buf[2] << 8) | buf[3]); | ||
167 | input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]); | ||
168 | input_sync(input_dev); | ||
127 | break; | 169 | break; |
128 | } | 170 | } |
129 | } | 171 | } |
130 | 172 | ||
131 | static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev, | 173 | static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev, |
132 | const char *buf, unsigned int len) | 174 | const char *buf, unsigned int len) |
133 | { | 175 | { |
176 | struct input_dev *input_dev = dev->input_dev; | ||
134 | int i; | 177 | int i; |
135 | 178 | ||
136 | switch(dev->input_dev->id.product) { | 179 | switch (dev->chip.usb_id) { |
137 | case USB_PID_AK1: | 180 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): |
138 | i = decode_erp(buf[0], buf[1]); | 181 | i = decode_erp(buf[0], buf[1]); |
139 | input_report_abs(dev->input_dev, ABS_X, i); | 182 | input_report_abs(input_dev, ABS_X, i); |
140 | input_sync(dev->input_dev); | 183 | input_sync(input_dev); |
184 | break; | ||
185 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER): | ||
186 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2): | ||
187 | i = decode_erp(buf[7], buf[5]); | ||
188 | input_report_abs(input_dev, ABS_HAT0X, i); | ||
189 | i = decode_erp(buf[12], buf[14]); | ||
190 | input_report_abs(input_dev, ABS_HAT0Y, i); | ||
191 | i = decode_erp(buf[15], buf[13]); | ||
192 | input_report_abs(input_dev, ABS_HAT1X, i); | ||
193 | i = decode_erp(buf[0], buf[2]); | ||
194 | input_report_abs(input_dev, ABS_HAT1Y, i); | ||
195 | i = decode_erp(buf[3], buf[1]); | ||
196 | input_report_abs(input_dev, ABS_HAT2X, i); | ||
197 | i = decode_erp(buf[8], buf[10]); | ||
198 | input_report_abs(input_dev, ABS_HAT2Y, i); | ||
199 | i = decode_erp(buf[11], buf[9]); | ||
200 | input_report_abs(input_dev, ABS_HAT3X, i); | ||
201 | i = decode_erp(buf[4], buf[6]); | ||
202 | input_report_abs(input_dev, ABS_HAT3Y, i); | ||
203 | input_sync(input_dev); | ||
141 | break; | 204 | break; |
142 | } | 205 | } |
143 | } | 206 | } |
144 | 207 | ||
145 | static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev, | 208 | static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev, |
146 | char *buf, unsigned int len) | 209 | char *buf, unsigned int len) |
147 | { | 210 | { |
211 | struct input_dev *input_dev = dev->input_dev; | ||
212 | unsigned short *keycode = input_dev->keycode; | ||
148 | int i; | 213 | int i; |
149 | unsigned char *keycode = dev->input_dev->keycode; | ||
150 | 214 | ||
151 | if (!keycode) | 215 | if (!keycode) |
152 | return; | 216 | return; |
153 | 217 | ||
154 | if (dev->input_dev->id.product == USB_PID_RIGKONTROL2) | 218 | if (input_dev->id.product == USB_PID_RIGKONTROL2) |
155 | for (i=0; i<len; i++) | 219 | for (i = 0; i < len; i++) |
156 | buf[i] = ~buf[i]; | 220 | buf[i] = ~buf[i]; |
157 | 221 | ||
158 | for (i=0; (i<dev->input_dev->keycodemax) && (i < len); i++) | 222 | for (i = 0; i < input_dev->keycodemax && i < len * 8; i++) |
159 | input_report_key(dev->input_dev, keycode[i], | 223 | input_report_key(input_dev, keycode[i], |
160 | buf[i/8] & (1 << (i%8))); | 224 | buf[i / 8] & (1 << (i % 8))); |
161 | 225 | ||
162 | input_sync(dev->input_dev); | 226 | if (dev->chip.usb_id == |
227 | USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER) || | ||
228 | dev->chip.usb_id == | ||
229 | USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2)) | ||
230 | input_report_abs(dev->input_dev, ABS_MISC, 255 - buf[4]); | ||
231 | |||
232 | input_sync(input_dev); | ||
163 | } | 233 | } |
164 | 234 | ||
165 | void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *dev, | 235 | void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *dev, |
166 | char *buf, | 236 | char *buf, |
167 | unsigned int len) | 237 | unsigned int len) |
168 | { | 238 | { |
169 | if (!dev->input_dev || (len < 1)) | 239 | if (!dev->input_dev || len < 1) |
170 | return; | 240 | return; |
171 | 241 | ||
172 | switch (buf[0]) { | 242 | switch (buf[0]) { |
173 | case EP1_CMD_READ_ANALOG: | 243 | case EP1_CMD_READ_ANALOG: |
174 | snd_caiaq_input_read_analog(dev, buf+1, len-1); | 244 | snd_caiaq_input_read_analog(dev, buf + 1, len - 1); |
175 | break; | 245 | break; |
176 | case EP1_CMD_READ_ERP: | 246 | case EP1_CMD_READ_ERP: |
177 | snd_caiaq_input_read_erp(dev, buf+1, len-1); | 247 | snd_caiaq_input_read_erp(dev, buf + 1, len - 1); |
178 | break; | 248 | break; |
179 | case EP1_CMD_READ_IO: | 249 | case EP1_CMD_READ_IO: |
180 | snd_caiaq_input_read_io(dev, buf+1, len-1); | 250 | snd_caiaq_input_read_io(dev, buf + 1, len - 1); |
181 | break; | 251 | break; |
182 | } | 252 | } |
183 | } | 253 | } |
@@ -192,37 +262,34 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev) | |||
192 | if (!input) | 262 | if (!input) |
193 | return -ENOMEM; | 263 | return -ENOMEM; |
194 | 264 | ||
265 | usb_make_path(usb_dev, dev->phys, sizeof(dev->phys)); | ||
266 | strlcat(dev->phys, "/input0", sizeof(dev->phys)); | ||
267 | |||
195 | input->name = dev->product_name; | 268 | input->name = dev->product_name; |
196 | input->id.bustype = BUS_USB; | 269 | input->phys = dev->phys; |
197 | input->id.vendor = usb_dev->descriptor.idVendor; | 270 | usb_to_input_id(usb_dev, &input->id); |
198 | input->id.product = usb_dev->descriptor.idProduct; | 271 | input->dev.parent = &usb_dev->dev; |
199 | input->id.version = usb_dev->descriptor.bcdDevice; | ||
200 | 272 | ||
201 | switch (dev->chip.usb_id) { | 273 | switch (dev->chip.usb_id) { |
202 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): | 274 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): |
203 | input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | 275 | input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
204 | input->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) | | 276 | input->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) | |
205 | BIT_MASK(ABS_Z); | 277 | BIT_MASK(ABS_Z); |
206 | input->keycode = keycode_rk2; | 278 | BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_rk2)); |
207 | input->keycodesize = sizeof(char); | 279 | memcpy(dev->keycode, keycode_rk2, sizeof(keycode_rk2)); |
208 | input->keycodemax = ARRAY_SIZE(keycode_rk2); | 280 | input->keycodemax = ARRAY_SIZE(keycode_rk2); |
209 | for (i=0; i<ARRAY_SIZE(keycode_rk2); i++) | ||
210 | set_bit(keycode_rk2[i], input->keybit); | ||
211 | |||
212 | input_set_abs_params(input, ABS_X, 0, 4096, 0, 10); | 281 | input_set_abs_params(input, ABS_X, 0, 4096, 0, 10); |
213 | input_set_abs_params(input, ABS_Y, 0, 4096, 0, 10); | 282 | input_set_abs_params(input, ABS_Y, 0, 4096, 0, 10); |
214 | input_set_abs_params(input, ABS_Z, 0, 4096, 0, 10); | 283 | input_set_abs_params(input, ABS_Z, 0, 4096, 0, 10); |
215 | snd_usb_caiaq_set_auto_msg(dev, 1, 10, 0); | 284 | snd_usb_caiaq_set_auto_msg(dev, 1, 10, 0); |
216 | break; | 285 | break; |
217 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): | 286 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): |
218 | input->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | 287 | input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
219 | input->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_Z); | 288 | input->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) | |
220 | input->keycode = keycode_rk3; | 289 | BIT_MASK(ABS_Z); |
221 | input->keycodesize = sizeof(char); | 290 | BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_rk3)); |
291 | memcpy(dev->keycode, keycode_rk3, sizeof(keycode_rk3)); | ||
222 | input->keycodemax = ARRAY_SIZE(keycode_rk3); | 292 | input->keycodemax = ARRAY_SIZE(keycode_rk3); |
223 | for (i=0; i<ARRAY_SIZE(keycode_rk3); i++) | ||
224 | set_bit(keycode_rk3[i], input->keybit); | ||
225 | |||
226 | input_set_abs_params(input, ABS_X, 0, 1024, 0, 10); | 293 | input_set_abs_params(input, ABS_X, 0, 1024, 0, 10); |
227 | input_set_abs_params(input, ABS_Y, 0, 1024, 0, 10); | 294 | input_set_abs_params(input, ABS_Y, 0, 1024, 0, 10); |
228 | input_set_abs_params(input, ABS_Z, 0, 1024, 0, 10); | 295 | input_set_abs_params(input, ABS_Z, 0, 1024, 0, 10); |
@@ -231,21 +298,50 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev) | |||
231 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): | 298 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): |
232 | input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | 299 | input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
233 | input->absbit[0] = BIT_MASK(ABS_X); | 300 | input->absbit[0] = BIT_MASK(ABS_X); |
234 | input->keycode = keycode_ak1; | 301 | BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_ak1)); |
235 | input->keycodesize = sizeof(char); | 302 | memcpy(dev->keycode, keycode_ak1, sizeof(keycode_ak1)); |
236 | input->keycodemax = ARRAY_SIZE(keycode_ak1); | 303 | input->keycodemax = ARRAY_SIZE(keycode_ak1); |
237 | for (i=0; i<ARRAY_SIZE(keycode_ak1); i++) | ||
238 | set_bit(keycode_ak1[i], input->keybit); | ||
239 | |||
240 | input_set_abs_params(input, ABS_X, 0, 999, 0, 10); | 304 | input_set_abs_params(input, ABS_X, 0, 999, 0, 10); |
241 | snd_usb_caiaq_set_auto_msg(dev, 1, 0, 5); | 305 | snd_usb_caiaq_set_auto_msg(dev, 1, 0, 5); |
242 | break; | 306 | break; |
307 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER): | ||
308 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2): | ||
309 | input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | ||
310 | input->absbit[0] = BIT_MASK(ABS_HAT0X) | BIT_MASK(ABS_HAT0Y) | | ||
311 | BIT_MASK(ABS_HAT1X) | BIT_MASK(ABS_HAT1Y) | | ||
312 | BIT_MASK(ABS_HAT2X) | BIT_MASK(ABS_HAT2Y) | | ||
313 | BIT_MASK(ABS_HAT3X) | BIT_MASK(ABS_HAT3Y) | | ||
314 | BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) | | ||
315 | BIT_MASK(ABS_Z); | ||
316 | input->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC); | ||
317 | BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_kore)); | ||
318 | memcpy(dev->keycode, keycode_kore, sizeof(keycode_kore)); | ||
319 | input->keycodemax = ARRAY_SIZE(keycode_kore); | ||
320 | input_set_abs_params(input, ABS_HAT0X, 0, 999, 0, 10); | ||
321 | input_set_abs_params(input, ABS_HAT0Y, 0, 999, 0, 10); | ||
322 | input_set_abs_params(input, ABS_HAT1X, 0, 999, 0, 10); | ||
323 | input_set_abs_params(input, ABS_HAT1Y, 0, 999, 0, 10); | ||
324 | input_set_abs_params(input, ABS_HAT2X, 0, 999, 0, 10); | ||
325 | input_set_abs_params(input, ABS_HAT2Y, 0, 999, 0, 10); | ||
326 | input_set_abs_params(input, ABS_HAT3X, 0, 999, 0, 10); | ||
327 | input_set_abs_params(input, ABS_HAT3Y, 0, 999, 0, 10); | ||
328 | input_set_abs_params(input, ABS_X, 0, 4096, 0, 10); | ||
329 | input_set_abs_params(input, ABS_Y, 0, 4096, 0, 10); | ||
330 | input_set_abs_params(input, ABS_Z, 0, 4096, 0, 10); | ||
331 | input_set_abs_params(input, ABS_MISC, 0, 255, 0, 1); | ||
332 | snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5); | ||
333 | break; | ||
243 | default: | 334 | default: |
244 | /* no input methods supported on this device */ | 335 | /* no input methods supported on this device */ |
245 | input_free_device(input); | 336 | input_free_device(input); |
246 | return 0; | 337 | return 0; |
247 | } | 338 | } |
248 | 339 | ||
340 | input->keycode = dev->keycode; | ||
341 | input->keycodesize = sizeof(unsigned short); | ||
342 | for (i = 0; i < input->keycodemax; i++) | ||
343 | __set_bit(dev->keycode[i], input->keybit); | ||
344 | |||
249 | ret = input_register_device(input); | 345 | ret = input_register_device(input); |
250 | if (ret < 0) { | 346 | if (ret < 0) { |
251 | input_free_device(input); | 347 | input_free_device(input); |
@@ -265,5 +361,3 @@ void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev) | |||
265 | dev->input_dev = NULL; | 361 | dev->input_dev = NULL; |
266 | } | 362 | } |
267 | 363 | ||
268 | #endif /* CONFIG_SND_USB_CAIAQ_INPUT */ | ||
269 | |||
diff --git a/sound/usb/caiaq/caiaq-midi.c b/sound/usb/caiaq/caiaq-midi.c index 793ca20ce349..30b57f97c6e4 100644 --- a/sound/usb/caiaq/caiaq-midi.c +++ b/sound/usb/caiaq/caiaq-midi.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <linux/usb.h> | 23 | #include <linux/usb.h> |
24 | #include <linux/input.h> | 24 | #include <linux/input.h> |
25 | #include <linux/spinlock.h> | 25 | #include <linux/spinlock.h> |
26 | #include <sound/driver.h> | ||
27 | #include <sound/core.h> | 26 | #include <sound/core.h> |
28 | #include <sound/rawmidi.h> | 27 | #include <sound/rawmidi.h> |
29 | #include <sound/pcm.h> | 28 | #include <sound/pcm.h> |
@@ -124,7 +123,7 @@ void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *dev, | |||
124 | snd_rawmidi_receive(dev->midi_receive_substream, buf, len); | 123 | snd_rawmidi_receive(dev->midi_receive_substream, buf, len); |
125 | } | 124 | } |
126 | 125 | ||
127 | int __devinit snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device) | 126 | int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device) |
128 | { | 127 | { |
129 | int ret; | 128 | int ret; |
130 | struct snd_rawmidi *rmidi; | 129 | struct snd_rawmidi *rmidi; |
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 967b823eace0..8fa935665702 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c | |||
@@ -38,7 +38,6 @@ | |||
38 | */ | 38 | */ |
39 | 39 | ||
40 | 40 | ||
41 | #include <sound/driver.h> | ||
42 | #include <linux/bitops.h> | 41 | #include <linux/bitops.h> |
43 | #include <linux/init.h> | 42 | #include <linux/init.h> |
44 | #include <linux/list.h> | 43 | #include <linux/list.h> |
@@ -2078,6 +2077,14 @@ static int usb_audio_probe(struct usb_interface *intf, | |||
2078 | const struct usb_device_id *id); | 2077 | const struct usb_device_id *id); |
2079 | static void usb_audio_disconnect(struct usb_interface *intf); | 2078 | static void usb_audio_disconnect(struct usb_interface *intf); |
2080 | 2079 | ||
2080 | #ifdef CONFIG_PM | ||
2081 | static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message); | ||
2082 | static int usb_audio_resume(struct usb_interface *intf); | ||
2083 | #else | ||
2084 | #define usb_audio_suspend NULL | ||
2085 | #define usb_audio_resume NULL | ||
2086 | #endif | ||
2087 | |||
2081 | static struct usb_device_id usb_audio_ids [] = { | 2088 | static struct usb_device_id usb_audio_ids [] = { |
2082 | #include "usbquirks.h" | 2089 | #include "usbquirks.h" |
2083 | { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS), | 2090 | { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS), |
@@ -2092,6 +2099,8 @@ static struct usb_driver usb_audio_driver = { | |||
2092 | .name = "snd-usb-audio", | 2099 | .name = "snd-usb-audio", |
2093 | .probe = usb_audio_probe, | 2100 | .probe = usb_audio_probe, |
2094 | .disconnect = usb_audio_disconnect, | 2101 | .disconnect = usb_audio_disconnect, |
2102 | .suspend = usb_audio_suspend, | ||
2103 | .resume = usb_audio_resume, | ||
2095 | .id_table = usb_audio_ids, | 2104 | .id_table = usb_audio_ids, |
2096 | }; | 2105 | }; |
2097 | 2106 | ||
@@ -3654,6 +3663,45 @@ static void usb_audio_disconnect(struct usb_interface *intf) | |||
3654 | dev_get_drvdata(&intf->dev)); | 3663 | dev_get_drvdata(&intf->dev)); |
3655 | } | 3664 | } |
3656 | 3665 | ||
3666 | #ifdef CONFIG_PM | ||
3667 | static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) | ||
3668 | { | ||
3669 | struct snd_usb_audio *chip = dev_get_drvdata(&intf->dev); | ||
3670 | struct list_head *p; | ||
3671 | struct snd_usb_stream *as; | ||
3672 | |||
3673 | if (chip == (void *)-1L) | ||
3674 | return 0; | ||
3675 | |||
3676 | snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); | ||
3677 | if (!chip->num_suspended_intf++) { | ||
3678 | list_for_each(p, &chip->pcm_list) { | ||
3679 | as = list_entry(p, struct snd_usb_stream, list); | ||
3680 | snd_pcm_suspend_all(as->pcm); | ||
3681 | } | ||
3682 | } | ||
3683 | |||
3684 | return 0; | ||
3685 | } | ||
3686 | |||
3687 | static int usb_audio_resume(struct usb_interface *intf) | ||
3688 | { | ||
3689 | struct snd_usb_audio *chip = dev_get_drvdata(&intf->dev); | ||
3690 | |||
3691 | if (chip == (void *)-1L) | ||
3692 | return 0; | ||
3693 | if (--chip->num_suspended_intf) | ||
3694 | return 0; | ||
3695 | /* | ||
3696 | * ALSA leaves material resumption to user space | ||
3697 | * we just notify | ||
3698 | */ | ||
3699 | |||
3700 | snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0); | ||
3701 | |||
3702 | return 0; | ||
3703 | } | ||
3704 | #endif /* CONFIG_PM */ | ||
3657 | 3705 | ||
3658 | static int __init snd_usb_audio_init(void) | 3706 | static int __init snd_usb_audio_init(void) |
3659 | { | 3707 | { |
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 2272f45a1867..7cf18c38dc42 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h | |||
@@ -126,6 +126,7 @@ struct snd_usb_audio { | |||
126 | u32 usb_id; | 126 | u32 usb_id; |
127 | int shutdown; | 127 | int shutdown; |
128 | int num_interfaces; | 128 | int num_interfaces; |
129 | int num_suspended_intf; | ||
129 | 130 | ||
130 | struct list_head pcm_list; /* list of pcm streams */ | 131 | struct list_head pcm_list; /* list of pcm streams */ |
131 | int pcm_devs; | 132 | int pcm_devs; |
diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 6330788c1c2b..750e929d5870 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c | |||
@@ -35,7 +35,6 @@ | |||
35 | * SUCH DAMAGE. | 35 | * SUCH DAMAGE. |
36 | */ | 36 | */ |
37 | 37 | ||
38 | #include <sound/driver.h> | ||
39 | #include <linux/kernel.h> | 38 | #include <linux/kernel.h> |
40 | #include <linux/types.h> | 39 | #include <linux/types.h> |
41 | #include <linux/bitops.h> | 40 | #include <linux/bitops.h> |
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 5e329690cfb1..89c63d073cc6 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c | |||
@@ -26,7 +26,6 @@ | |||
26 | * | 26 | * |
27 | */ | 27 | */ |
28 | 28 | ||
29 | #include <sound/driver.h> | ||
30 | #include <linux/bitops.h> | 29 | #include <linux/bitops.h> |
31 | #include <linux/init.h> | 30 | #include <linux/init.h> |
32 | #include <linux/list.h> | 31 | #include <linux/list.h> |
@@ -1703,6 +1702,11 @@ static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer, | |||
1703 | case 19: /* speaker out jacks */ | 1702 | case 19: /* speaker out jacks */ |
1704 | case 20: /* headphones out jack */ | 1703 | case 20: /* headphones out jack */ |
1705 | break; | 1704 | break; |
1705 | /* live24ext: 4 = line-in jack */ | ||
1706 | case 3: /* hp-out jack (may actuate Mute) */ | ||
1707 | if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040)) | ||
1708 | snd_usb_mixer_notify_id(mixer, mixer->rc_cfg->mute_mixer_id); | ||
1709 | break; | ||
1706 | default: | 1710 | default: |
1707 | snd_printd(KERN_DEBUG "memory change in unknown unit %d\n", unitid); | 1711 | snd_printd(KERN_DEBUG "memory change in unknown unit %d\n", unitid); |
1708 | break; | 1712 | break; |
@@ -1951,6 +1955,9 @@ static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer) | |||
1951 | int i, err; | 1955 | int i, err; |
1952 | 1956 | ||
1953 | for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_controls); ++i) { | 1957 | for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_controls); ++i) { |
1958 | if (i > 1 && /* Live24ext has 2 LEDs only */ | ||
1959 | mixer->chip->usb_id == USB_ID(0x041e, 0x3040)) | ||
1960 | break; | ||
1954 | err = snd_ctl_add(mixer->chip->card, | 1961 | err = snd_ctl_add(mixer->chip->card, |
1955 | snd_ctl_new1(&snd_audigy2nx_controls[i], mixer)); | 1962 | snd_ctl_new1(&snd_audigy2nx_controls[i], mixer)); |
1956 | if (err < 0) | 1963 | if (err < 0) |
@@ -1963,28 +1970,42 @@ static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer) | |||
1963 | static void snd_audigy2nx_proc_read(struct snd_info_entry *entry, | 1970 | static void snd_audigy2nx_proc_read(struct snd_info_entry *entry, |
1964 | struct snd_info_buffer *buffer) | 1971 | struct snd_info_buffer *buffer) |
1965 | { | 1972 | { |
1966 | static const struct { | 1973 | static const struct sb_jack { |
1967 | int unitid; | 1974 | int unitid; |
1968 | const char *name; | 1975 | const char *name; |
1969 | } jacks[] = { | 1976 | } jacks_audigy2nx[] = { |
1970 | {4, "dig in "}, | 1977 | {4, "dig in "}, |
1971 | {7, "line in"}, | 1978 | {7, "line in"}, |
1972 | {19, "spk out"}, | 1979 | {19, "spk out"}, |
1973 | {20, "hph out"}, | 1980 | {20, "hph out"}, |
1981 | {-1, NULL} | ||
1982 | }, jacks_live24ext[] = { | ||
1983 | {4, "line in"}, /* &1=Line, &2=Mic*/ | ||
1984 | {3, "hph out"}, /* headphones */ | ||
1985 | {0, "RC "}, /* last command, 6 bytes see rc_config above */ | ||
1986 | {-1, NULL} | ||
1974 | }; | 1987 | }; |
1988 | const struct sb_jack *jacks; | ||
1975 | struct usb_mixer_interface *mixer = entry->private_data; | 1989 | struct usb_mixer_interface *mixer = entry->private_data; |
1976 | int i, err; | 1990 | int i, err; |
1977 | u8 buf[3]; | 1991 | u8 buf[3]; |
1978 | 1992 | ||
1979 | snd_iprintf(buffer, "%s jacks\n\n", mixer->chip->card->shortname); | 1993 | snd_iprintf(buffer, "%s jacks\n\n", mixer->chip->card->shortname); |
1980 | for (i = 0; i < ARRAY_SIZE(jacks); ++i) { | 1994 | if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020)) |
1995 | jacks = jacks_audigy2nx; | ||
1996 | else if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040)) | ||
1997 | jacks = jacks_live24ext; | ||
1998 | else | ||
1999 | return; | ||
2000 | |||
2001 | for (i = 0; jacks[i].name; ++i) { | ||
1981 | snd_iprintf(buffer, "%s: ", jacks[i].name); | 2002 | snd_iprintf(buffer, "%s: ", jacks[i].name); |
1982 | err = snd_usb_ctl_msg(mixer->chip->dev, | 2003 | err = snd_usb_ctl_msg(mixer->chip->dev, |
1983 | usb_rcvctrlpipe(mixer->chip->dev, 0), | 2004 | usb_rcvctrlpipe(mixer->chip->dev, 0), |
1984 | GET_MEM, USB_DIR_IN | USB_TYPE_CLASS | | 2005 | GET_MEM, USB_DIR_IN | USB_TYPE_CLASS | |
1985 | USB_RECIP_INTERFACE, 0, | 2006 | USB_RECIP_INTERFACE, 0, |
1986 | jacks[i].unitid << 8, buf, 3, 100); | 2007 | jacks[i].unitid << 8, buf, 3, 100); |
1987 | if (err == 3 && buf[0] == 3) | 2008 | if (err == 3 && (buf[0] == 3 || buf[0] == 6)) |
1988 | snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]); | 2009 | snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]); |
1989 | else | 2010 | else |
1990 | snd_iprintf(buffer, "?\n"); | 2011 | snd_iprintf(buffer, "?\n"); |
@@ -2022,7 +2043,8 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif) | |||
2022 | if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) | 2043 | if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) |
2023 | goto _error; | 2044 | goto _error; |
2024 | 2045 | ||
2025 | if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020)) { | 2046 | if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020) || |
2047 | mixer->chip->usb_id == USB_ID(0x041e, 0x3040)) { | ||
2026 | struct snd_info_entry *entry; | 2048 | struct snd_info_entry *entry; |
2027 | 2049 | ||
2028 | if ((err = snd_audigy2nx_controls_create(mixer)) < 0) | 2050 | if ((err = snd_audigy2nx_controls_create(mixer)) < 0) |
diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c index 7c4dcb3f436a..d755be0ad811 100644 --- a/sound/usb/usbmixer_maps.c +++ b/sound/usb/usbmixer_maps.c | |||
@@ -187,6 +187,13 @@ static struct usbmix_selector_map audigy2nx_selectors[] = { | |||
187 | { 0 } /* terminator */ | 187 | { 0 } /* terminator */ |
188 | }; | 188 | }; |
189 | 189 | ||
190 | /* Creative SoundBlaster Live! 24-bit External */ | ||
191 | static struct usbmix_name_map live24ext_map[] = { | ||
192 | /* 2: PCM Playback Volume */ | ||
193 | { 5, "Mic Capture" }, /* FU, default PCM Capture Volume */ | ||
194 | { 0 } /* terminator */ | ||
195 | }; | ||
196 | |||
190 | /* LineX FM Transmitter entry - needed to bypass controls bug */ | 197 | /* LineX FM Transmitter entry - needed to bypass controls bug */ |
191 | static struct usbmix_name_map linex_map[] = { | 198 | static struct usbmix_name_map linex_map[] = { |
192 | /* 1: IT pcm */ | 199 | /* 1: IT pcm */ |
@@ -273,6 +280,10 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = { | |||
273 | .map = audigy2nx_map, | 280 | .map = audigy2nx_map, |
274 | .selector_map = audigy2nx_selectors, | 281 | .selector_map = audigy2nx_selectors, |
275 | }, | 282 | }, |
283 | { | ||
284 | .id = USB_ID(0x041e, 0x3040), | ||
285 | .map = live24ext_map, | ||
286 | }, | ||
276 | { | 287 | { |
277 | /* Hercules DJ Console (Windows Edition) */ | 288 | /* Hercules DJ Console (Windows Edition) */ |
278 | .id = USB_ID(0x06f8, 0xb000), | 289 | .id = USB_ID(0x06f8, 0xb000), |
diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index 59410f437705..938dff5f9cef 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h | |||
@@ -1004,11 +1004,35 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
1004 | } | 1004 | } |
1005 | }, | 1005 | }, |
1006 | { | 1006 | { |
1007 | /* has ID 0x0049 when not in "Advanced Driver" mode */ | ||
1008 | USB_DEVICE(0x0582, 0x0047), | ||
1009 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | ||
1010 | /* .vendor_name = "EDIROL", */ | ||
1011 | /* .product_name = "UR-80", */ | ||
1012 | .ifnum = QUIRK_ANY_INTERFACE, | ||
1013 | .type = QUIRK_COMPOSITE, | ||
1014 | .data = (const struct snd_usb_audio_quirk[]) { | ||
1015 | /* in the 96 kHz modes, only interface 1 is there */ | ||
1016 | { | ||
1017 | .ifnum = 1, | ||
1018 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | ||
1019 | }, | ||
1020 | { | ||
1021 | .ifnum = 2, | ||
1022 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | ||
1023 | }, | ||
1024 | { | ||
1025 | .ifnum = -1 | ||
1026 | } | ||
1027 | } | ||
1028 | } | ||
1029 | }, | ||
1030 | { | ||
1007 | /* has ID 0x004a when not in "Advanced Driver" mode */ | 1031 | /* has ID 0x004a when not in "Advanced Driver" mode */ |
1008 | USB_DEVICE(0x0582, 0x0048), | 1032 | USB_DEVICE(0x0582, 0x0048), |
1009 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | 1033 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { |
1010 | .vendor_name = "EDIROL", | 1034 | /* .vendor_name = "EDIROL", */ |
1011 | .product_name = "UR-80", | 1035 | /* .product_name = "UR-80", */ |
1012 | .ifnum = 0, | 1036 | .ifnum = 0, |
1013 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | 1037 | .type = QUIRK_MIDI_FIXED_ENDPOINT, |
1014 | .data = & (const struct snd_usb_midi_endpoint_info) { | 1038 | .data = & (const struct snd_usb_midi_endpoint_info) { |
diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c index b76b3dd9df25..6495534e5bf6 100644 --- a/sound/usb/usx2y/usX2Yhwdep.c +++ b/sound/usb/usx2y/usX2Yhwdep.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
25 | #include <linux/usb.h> | 24 | #include <linux/usb.h> |
26 | #include <sound/core.h> | 25 | #include <sound/core.h> |
@@ -34,34 +33,31 @@ | |||
34 | int usX2Y_hwdep_pcm_new(struct snd_card *card); | 33 | int usX2Y_hwdep_pcm_new(struct snd_card *card); |
35 | 34 | ||
36 | 35 | ||
37 | static struct page * snd_us428ctls_vm_nopage(struct vm_area_struct *area, unsigned long address, int *type) | 36 | static int snd_us428ctls_vm_fault(struct vm_area_struct *area, |
37 | struct vm_fault *vmf) | ||
38 | { | 38 | { |
39 | unsigned long offset; | 39 | unsigned long offset; |
40 | struct page * page; | 40 | struct page * page; |
41 | void *vaddr; | 41 | void *vaddr; |
42 | 42 | ||
43 | snd_printdd("ENTER, start %lXh, ofs %lXh, pgoff %ld, addr %lXh\n", | 43 | snd_printdd("ENTER, start %lXh, pgoff %ld\n", |
44 | area->vm_start, | 44 | area->vm_start, |
45 | address - area->vm_start, | 45 | vmf->pgoff); |
46 | (address - area->vm_start) >> PAGE_SHIFT, | ||
47 | address); | ||
48 | 46 | ||
49 | offset = area->vm_pgoff << PAGE_SHIFT; | 47 | offset = vmf->pgoff << PAGE_SHIFT; |
50 | offset += address - area->vm_start; | ||
51 | snd_assert((offset % PAGE_SIZE) == 0, return NOPAGE_SIGBUS); | ||
52 | vaddr = (char*)((struct usX2Ydev *)area->vm_private_data)->us428ctls_sharedmem + offset; | 48 | vaddr = (char*)((struct usX2Ydev *)area->vm_private_data)->us428ctls_sharedmem + offset; |
53 | page = virt_to_page(vaddr); | 49 | page = virt_to_page(vaddr); |
54 | get_page(page); | 50 | get_page(page); |
55 | snd_printdd( "vaddr=%p made us428ctls_vm_nopage() return %p; offset=%lX\n", vaddr, page, offset); | 51 | vmf->page = page; |
56 | 52 | ||
57 | if (type) | 53 | snd_printdd("vaddr=%p made us428ctls_vm_fault() page %p\n", |
58 | *type = VM_FAULT_MINOR; | 54 | vaddr, page); |
59 | 55 | ||
60 | return page; | 56 | return 0; |
61 | } | 57 | } |
62 | 58 | ||
63 | static struct vm_operations_struct us428ctls_vm_ops = { | 59 | static struct vm_operations_struct us428ctls_vm_ops = { |
64 | .nopage = snd_us428ctls_vm_nopage, | 60 | .fault = snd_us428ctls_vm_fault, |
65 | }; | 61 | }; |
66 | 62 | ||
67 | static int snd_us428ctls_mmap(struct snd_hwdep * hw, struct file *filp, struct vm_area_struct *area) | 63 | static int snd_us428ctls_mmap(struct snd_hwdep * hw, struct file *filp, struct vm_area_struct *area) |
diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index e011fcacce92..e5981a630314 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c | |||
@@ -130,7 +130,6 @@ | |||
130 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 130 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
131 | */ | 131 | */ |
132 | 132 | ||
133 | #include <sound/driver.h> | ||
134 | #include <linux/init.h> | 133 | #include <linux/init.h> |
135 | #include <linux/module.h> | 134 | #include <linux/module.h> |
136 | #include <linux/moduleparam.h> | 135 | #include <linux/moduleparam.h> |
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index 48e9aa3f18c9..9a608fa85155 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c | |||
@@ -31,7 +31,6 @@ | |||
31 | */ | 31 | */ |
32 | 32 | ||
33 | 33 | ||
34 | #include <sound/driver.h> | ||
35 | #include <linux/interrupt.h> | 34 | #include <linux/interrupt.h> |
36 | #include <linux/usb.h> | 35 | #include <linux/usb.h> |
37 | #include <sound/core.h> | 36 | #include <sound/core.h> |
diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index a5e7bcd7ca2e..800b5cecfc80 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c | |||
@@ -683,30 +683,24 @@ static void snd_usX2Y_hwdep_pcm_vm_close(struct vm_area_struct *area) | |||
683 | } | 683 | } |
684 | 684 | ||
685 | 685 | ||
686 | static struct page * snd_usX2Y_hwdep_pcm_vm_nopage(struct vm_area_struct *area, unsigned long address, int *type) | 686 | static int snd_usX2Y_hwdep_pcm_vm_fault(struct vm_area_struct *area, |
687 | struct vm_fault *vmf) | ||
687 | { | 688 | { |
688 | unsigned long offset; | 689 | unsigned long offset; |
689 | struct page *page; | ||
690 | void *vaddr; | 690 | void *vaddr; |
691 | 691 | ||
692 | offset = area->vm_pgoff << PAGE_SHIFT; | 692 | offset = vmf->pgoff << PAGE_SHIFT; |
693 | offset += address - area->vm_start; | ||
694 | snd_assert((offset % PAGE_SIZE) == 0, return NOPAGE_OOM); | ||
695 | vaddr = (char*)((struct usX2Ydev *)area->vm_private_data)->hwdep_pcm_shm + offset; | 693 | vaddr = (char*)((struct usX2Ydev *)area->vm_private_data)->hwdep_pcm_shm + offset; |
696 | page = virt_to_page(vaddr); | 694 | vmf->page = virt_to_page(vaddr); |
697 | get_page(page); | 695 | get_page(vmf->page); |
698 | 696 | return 0; | |
699 | if (type) | ||
700 | *type = VM_FAULT_MINOR; | ||
701 | |||
702 | return page; | ||
703 | } | 697 | } |
704 | 698 | ||
705 | 699 | ||
706 | static struct vm_operations_struct snd_usX2Y_hwdep_pcm_vm_ops = { | 700 | static struct vm_operations_struct snd_usX2Y_hwdep_pcm_vm_ops = { |
707 | .open = snd_usX2Y_hwdep_pcm_vm_open, | 701 | .open = snd_usX2Y_hwdep_pcm_vm_open, |
708 | .close = snd_usX2Y_hwdep_pcm_vm_close, | 702 | .close = snd_usX2Y_hwdep_pcm_vm_close, |
709 | .nopage = snd_usX2Y_hwdep_pcm_vm_nopage, | 703 | .fault = snd_usX2Y_hwdep_pcm_vm_fault, |
710 | }; | 704 | }; |
711 | 705 | ||
712 | 706 | ||