diff options
Diffstat (limited to 'sound')
76 files changed, 3535 insertions, 1107 deletions
diff --git a/sound/core/init.c b/sound/core/init.c index ec4a50ce5656..2de45fbd70fb 100644 --- a/sound/core/init.c +++ b/sound/core/init.c | |||
@@ -607,11 +607,16 @@ card_id_store_attr(struct device *dev, struct device_attribute *attr, | |||
607 | return -EEXIST; | 607 | return -EEXIST; |
608 | } | 608 | } |
609 | for (idx = 0; idx < snd_ecards_limit; idx++) { | 609 | for (idx = 0; idx < snd_ecards_limit; idx++) { |
610 | if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1)) | 610 | if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1)) { |
611 | goto __exist; | 611 | if (card == snd_cards[idx]) |
612 | goto __ok; | ||
613 | else | ||
614 | goto __exist; | ||
615 | } | ||
612 | } | 616 | } |
613 | strcpy(card->id, buf1); | 617 | strcpy(card->id, buf1); |
614 | snd_info_card_id_change(card); | 618 | snd_info_card_id_change(card); |
619 | __ok: | ||
615 | mutex_unlock(&snd_card_mutex); | 620 | mutex_unlock(&snd_card_mutex); |
616 | 621 | ||
617 | return count; | 622 | return count; |
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index f50ebf20df96..822dd56993ca 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c | |||
@@ -77,7 +77,7 @@ static int snd_mixer_oss_release(struct inode *inode, struct file *file) | |||
77 | struct snd_mixer_oss_file *fmixer; | 77 | struct snd_mixer_oss_file *fmixer; |
78 | 78 | ||
79 | if (file->private_data) { | 79 | if (file->private_data) { |
80 | fmixer = (struct snd_mixer_oss_file *) file->private_data; | 80 | fmixer = file->private_data; |
81 | module_put(fmixer->card->module); | 81 | module_put(fmixer->card->module); |
82 | snd_card_file_remove(fmixer->card, file); | 82 | snd_card_file_remove(fmixer->card, file); |
83 | kfree(fmixer); | 83 | kfree(fmixer); |
@@ -368,7 +368,7 @@ static int snd_mixer_oss_ioctl1(struct snd_mixer_oss_file *fmixer, unsigned int | |||
368 | 368 | ||
369 | static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 369 | static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
370 | { | 370 | { |
371 | return snd_mixer_oss_ioctl1((struct snd_mixer_oss_file *) file->private_data, cmd, arg); | 371 | return snd_mixer_oss_ioctl1(file->private_data, cmd, arg); |
372 | } | 372 | } |
373 | 373 | ||
374 | int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg) | 374 | int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg) |
@@ -582,7 +582,7 @@ static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer, | |||
582 | struct snd_mixer_oss_slot *pslot, | 582 | struct snd_mixer_oss_slot *pslot, |
583 | int *left, int *right) | 583 | int *left, int *right) |
584 | { | 584 | { |
585 | struct slot *slot = (struct slot *)pslot->private_data; | 585 | struct slot *slot = pslot->private_data; |
586 | 586 | ||
587 | *left = *right = 100; | 587 | *left = *right = 100; |
588 | if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) { | 588 | if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) { |
@@ -618,8 +618,10 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer, | |||
618 | if (numid == ID_UNKNOWN) | 618 | if (numid == ID_UNKNOWN) |
619 | return; | 619 | return; |
620 | down_read(&card->controls_rwsem); | 620 | down_read(&card->controls_rwsem); |
621 | if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) | 621 | if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { |
622 | up_read(&card->controls_rwsem); | ||
622 | return; | 623 | return; |
624 | } | ||
623 | uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); | 625 | uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); |
624 | uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); | 626 | uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); |
625 | if (uinfo == NULL || uctl == NULL) | 627 | if (uinfo == NULL || uctl == NULL) |
@@ -658,7 +660,7 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer, | |||
658 | return; | 660 | return; |
659 | down_read(&card->controls_rwsem); | 661 | down_read(&card->controls_rwsem); |
660 | if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { | 662 | if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { |
661 | up_read(&fmixer->card->controls_rwsem); | 663 | up_read(&card->controls_rwsem); |
662 | return; | 664 | return; |
663 | } | 665 | } |
664 | uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); | 666 | uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); |
@@ -691,7 +693,7 @@ static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer, | |||
691 | struct snd_mixer_oss_slot *pslot, | 693 | struct snd_mixer_oss_slot *pslot, |
692 | int left, int right) | 694 | int left, int right) |
693 | { | 695 | { |
694 | struct slot *slot = (struct slot *)pslot->private_data; | 696 | struct slot *slot = pslot->private_data; |
695 | 697 | ||
696 | if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) { | 698 | if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) { |
697 | snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right); | 699 | snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right); |
@@ -740,7 +742,7 @@ static int snd_mixer_oss_get_recsrc1_sw(struct snd_mixer_oss_file *fmixer, | |||
740 | struct snd_mixer_oss_slot *pslot, | 742 | struct snd_mixer_oss_slot *pslot, |
741 | int *active) | 743 | int *active) |
742 | { | 744 | { |
743 | struct slot *slot = (struct slot *)pslot->private_data; | 745 | struct slot *slot = pslot->private_data; |
744 | int left, right; | 746 | int left, right; |
745 | 747 | ||
746 | left = right = 1; | 748 | left = right = 1; |
@@ -753,7 +755,7 @@ static int snd_mixer_oss_get_recsrc1_route(struct snd_mixer_oss_file *fmixer, | |||
753 | struct snd_mixer_oss_slot *pslot, | 755 | struct snd_mixer_oss_slot *pslot, |
754 | int *active) | 756 | int *active) |
755 | { | 757 | { |
756 | struct slot *slot = (struct slot *)pslot->private_data; | 758 | struct slot *slot = pslot->private_data; |
757 | int left, right; | 759 | int left, right; |
758 | 760 | ||
759 | left = right = 1; | 761 | left = right = 1; |
@@ -766,7 +768,7 @@ static int snd_mixer_oss_put_recsrc1_sw(struct snd_mixer_oss_file *fmixer, | |||
766 | struct snd_mixer_oss_slot *pslot, | 768 | struct snd_mixer_oss_slot *pslot, |
767 | int active) | 769 | int active) |
768 | { | 770 | { |
769 | struct slot *slot = (struct slot *)pslot->private_data; | 771 | struct slot *slot = pslot->private_data; |
770 | 772 | ||
771 | snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0); | 773 | snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0); |
772 | return 0; | 774 | return 0; |
@@ -776,7 +778,7 @@ static int snd_mixer_oss_put_recsrc1_route(struct snd_mixer_oss_file *fmixer, | |||
776 | struct snd_mixer_oss_slot *pslot, | 778 | struct snd_mixer_oss_slot *pslot, |
777 | int active) | 779 | int active) |
778 | { | 780 | { |
779 | struct slot *slot = (struct slot *)pslot->private_data; | 781 | struct slot *slot = pslot->private_data; |
780 | 782 | ||
781 | snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1); | 783 | snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1); |
782 | return 0; | 784 | return 0; |
@@ -797,7 +799,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned | |||
797 | uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); | 799 | uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); |
798 | if (uinfo == NULL || uctl == NULL) { | 800 | if (uinfo == NULL || uctl == NULL) { |
799 | err = -ENOMEM; | 801 | err = -ENOMEM; |
800 | goto __unlock; | 802 | goto __free_only; |
801 | } | 803 | } |
802 | down_read(&card->controls_rwsem); | 804 | down_read(&card->controls_rwsem); |
803 | kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); | 805 | kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); |
@@ -813,7 +815,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned | |||
813 | if (!(mixer->mask_recsrc & (1 << idx))) | 815 | if (!(mixer->mask_recsrc & (1 << idx))) |
814 | continue; | 816 | continue; |
815 | pslot = &mixer->slots[idx]; | 817 | pslot = &mixer->slots[idx]; |
816 | slot = (struct slot *)pslot->private_data; | 818 | slot = pslot->private_data; |
817 | if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) | 819 | if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) |
818 | continue; | 820 | continue; |
819 | if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE)) | 821 | if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE)) |
@@ -826,6 +828,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned | |||
826 | err = 0; | 828 | err = 0; |
827 | __unlock: | 829 | __unlock: |
828 | up_read(&card->controls_rwsem); | 830 | up_read(&card->controls_rwsem); |
831 | __free_only: | ||
829 | kfree(uctl); | 832 | kfree(uctl); |
830 | kfree(uinfo); | 833 | kfree(uinfo); |
831 | return err; | 834 | return err; |
@@ -847,7 +850,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned | |||
847 | uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); | 850 | uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); |
848 | if (uinfo == NULL || uctl == NULL) { | 851 | if (uinfo == NULL || uctl == NULL) { |
849 | err = -ENOMEM; | 852 | err = -ENOMEM; |
850 | goto __unlock; | 853 | goto __free_only; |
851 | } | 854 | } |
852 | down_read(&card->controls_rwsem); | 855 | down_read(&card->controls_rwsem); |
853 | kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); | 856 | kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); |
@@ -861,7 +864,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned | |||
861 | if (!(mixer->mask_recsrc & (1 << idx))) | 864 | if (!(mixer->mask_recsrc & (1 << idx))) |
862 | continue; | 865 | continue; |
863 | pslot = &mixer->slots[idx]; | 866 | pslot = &mixer->slots[idx]; |
864 | slot = (struct slot *)pslot->private_data; | 867 | slot = pslot->private_data; |
865 | if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) | 868 | if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) |
866 | continue; | 869 | continue; |
867 | if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE)) | 870 | if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE)) |
@@ -880,6 +883,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned | |||
880 | err = 0; | 883 | err = 0; |
881 | __unlock: | 884 | __unlock: |
882 | up_read(&card->controls_rwsem); | 885 | up_read(&card->controls_rwsem); |
886 | __free_only: | ||
883 | kfree(uctl); | 887 | kfree(uctl); |
884 | kfree(uinfo); | 888 | kfree(uinfo); |
885 | return err; | 889 | return err; |
@@ -925,7 +929,7 @@ static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *sl | |||
925 | 929 | ||
926 | static void snd_mixer_oss_slot_free(struct snd_mixer_oss_slot *chn) | 930 | static void snd_mixer_oss_slot_free(struct snd_mixer_oss_slot *chn) |
927 | { | 931 | { |
928 | struct slot *p = (struct slot *)chn->private_data; | 932 | struct slot *p = chn->private_data; |
929 | if (p) { | 933 | if (p) { |
930 | if (p->allocated && p->assigned) { | 934 | if (p->allocated && p->assigned) { |
931 | kfree(p->assigned->name); | 935 | kfree(p->assigned->name); |
diff --git a/sound/core/pcm.c b/sound/core/pcm.c index ac242a377aea..6b4b1287b314 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c | |||
@@ -364,8 +364,7 @@ static void snd_pcm_stream_proc_info_read(struct snd_info_entry *entry, | |||
364 | static void snd_pcm_substream_proc_info_read(struct snd_info_entry *entry, | 364 | static void snd_pcm_substream_proc_info_read(struct snd_info_entry *entry, |
365 | struct snd_info_buffer *buffer) | 365 | struct snd_info_buffer *buffer) |
366 | { | 366 | { |
367 | snd_pcm_proc_info_read((struct snd_pcm_substream *)entry->private_data, | 367 | snd_pcm_proc_info_read(entry->private_data, buffer); |
368 | buffer); | ||
369 | } | 368 | } |
370 | 369 | ||
371 | static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry, | 370 | static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry, |
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index e23e0e7ab26f..a1707cca9c66 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c | |||
@@ -334,11 +334,15 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, | |||
334 | /* delta = "expected next hw_ptr" for in_interrupt != 0 */ | 334 | /* delta = "expected next hw_ptr" for in_interrupt != 0 */ |
335 | delta = runtime->hw_ptr_interrupt + runtime->period_size; | 335 | delta = runtime->hw_ptr_interrupt + runtime->period_size; |
336 | if (delta > new_hw_ptr) { | 336 | if (delta > new_hw_ptr) { |
337 | hw_base += runtime->buffer_size; | 337 | /* check for double acknowledged interrupts */ |
338 | if (hw_base >= runtime->boundary) | 338 | hdelta = jiffies - runtime->hw_ptr_jiffies; |
339 | hw_base = 0; | 339 | if (hdelta > runtime->hw_ptr_buffer_jiffies/2) { |
340 | new_hw_ptr = hw_base + pos; | 340 | hw_base += runtime->buffer_size; |
341 | goto __delta; | 341 | if (hw_base >= runtime->boundary) |
342 | hw_base = 0; | ||
343 | new_hw_ptr = hw_base + pos; | ||
344 | goto __delta; | ||
345 | } | ||
342 | } | 346 | } |
343 | } | 347 | } |
344 | /* new_hw_ptr might be lower than old_hw_ptr in case when */ | 348 | /* new_hw_ptr might be lower than old_hw_ptr in case when */ |
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index d4eb2ef80784..8bc7cb3db330 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c | |||
@@ -142,7 +142,7 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream, | |||
142 | 142 | ||
143 | #ifdef RULES_DEBUG | 143 | #ifdef RULES_DEBUG |
144 | #define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v | 144 | #define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v |
145 | char *snd_pcm_hw_param_names[] = { | 145 | static const char * const snd_pcm_hw_param_names[] = { |
146 | HW_PARAM(ACCESS), | 146 | HW_PARAM(ACCESS), |
147 | HW_PARAM(FORMAT), | 147 | HW_PARAM(FORMAT), |
148 | HW_PARAM(SUBFORMAT), | 148 | HW_PARAM(SUBFORMAT), |
@@ -864,6 +864,8 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state) | |||
864 | struct snd_pcm_runtime *runtime = substream->runtime; | 864 | struct snd_pcm_runtime *runtime = substream->runtime; |
865 | snd_pcm_trigger_tstamp(substream); | 865 | snd_pcm_trigger_tstamp(substream); |
866 | runtime->hw_ptr_jiffies = jiffies; | 866 | runtime->hw_ptr_jiffies = jiffies; |
867 | runtime->hw_ptr_buffer_jiffies = (runtime->buffer_size * HZ) / | ||
868 | runtime->rate; | ||
867 | runtime->status->state = state; | 869 | runtime->status->state = state; |
868 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && | 870 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && |
869 | runtime->silence_size > 0) | 871 | runtime->silence_size > 0) |
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index 480c38623da8..c8961165277c 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig | |||
@@ -74,6 +74,25 @@ config SND_DUMMY | |||
74 | To compile this driver as a module, choose M here: the module | 74 | To compile this driver as a module, choose M here: the module |
75 | will be called snd-dummy. | 75 | will be called snd-dummy. |
76 | 76 | ||
77 | config SND_ALOOP | ||
78 | tristate "Generic loopback driver (PCM)" | ||
79 | select SND_PCM | ||
80 | help | ||
81 | Say 'Y' or 'M' to include support for the PCM loopback device. | ||
82 | This module returns played samples back to the user space using | ||
83 | the standard ALSA PCM device. The devices are routed 0->1 and | ||
84 | 1->0, where first number is the playback PCM device and second | ||
85 | number is the capture device. Module creates two PCM devices and | ||
86 | configured number of substreams (see the pcm_substreams module | ||
87 | parameter). | ||
88 | |||
89 | The looback device allow time sychronization with an external | ||
90 | timing source using the time shift universal control (+-20% | ||
91 | of system time). | ||
92 | |||
93 | To compile this driver as a module, choose M here: the module | ||
94 | will be called snd-aloop. | ||
95 | |||
77 | config SND_VIRMIDI | 96 | config SND_VIRMIDI |
78 | tristate "Virtual MIDI soundcard" | 97 | tristate "Virtual MIDI soundcard" |
79 | depends on SND_SEQUENCER | 98 | depends on SND_SEQUENCER |
diff --git a/sound/drivers/Makefile b/sound/drivers/Makefile index d4a07f9ff2c7..1a8440c8b138 100644 --- a/sound/drivers/Makefile +++ b/sound/drivers/Makefile | |||
@@ -4,6 +4,7 @@ | |||
4 | # | 4 | # |
5 | 5 | ||
6 | snd-dummy-objs := dummy.o | 6 | snd-dummy-objs := dummy.o |
7 | snd-aloop-objs := aloop.o | ||
7 | snd-mtpav-objs := mtpav.o | 8 | snd-mtpav-objs := mtpav.o |
8 | snd-mts64-objs := mts64.o | 9 | snd-mts64-objs := mts64.o |
9 | snd-portman2x4-objs := portman2x4.o | 10 | snd-portman2x4-objs := portman2x4.o |
@@ -13,6 +14,7 @@ snd-ml403-ac97cr-objs := ml403-ac97cr.o pcm-indirect2.o | |||
13 | 14 | ||
14 | # Toplevel Module Dependency | 15 | # Toplevel Module Dependency |
15 | obj-$(CONFIG_SND_DUMMY) += snd-dummy.o | 16 | obj-$(CONFIG_SND_DUMMY) += snd-dummy.o |
17 | obj-$(CONFIG_SND_ALOOP) += snd-aloop.o | ||
16 | obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o | 18 | obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o |
17 | obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o | 19 | obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o |
18 | obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o | 20 | obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o |
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c new file mode 100644 index 000000000000..12b44b0b6777 --- /dev/null +++ b/sound/drivers/aloop.c | |||
@@ -0,0 +1,1258 @@ | |||
1 | /* | ||
2 | * Loopback soundcard | ||
3 | * | ||
4 | * Original code: | ||
5 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> | ||
6 | * | ||
7 | * More accurate positioning and full-duplex support: | ||
8 | * Copyright (c) Ahmet Ä°nan <ainan at mathematik.uni-freiburg.de> | ||
9 | * | ||
10 | * Major (almost complete) rewrite: | ||
11 | * Copyright (c) by Takashi Iwai <tiwai@suse.de> | ||
12 | * | ||
13 | * A next major update in 2010 (separate timers for playback and capture): | ||
14 | * Copyright (c) Jaroslav Kysela <perex@perex.cz> | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or modify | ||
17 | * it under the terms of the GNU General Public License as published by | ||
18 | * the Free Software Foundation; either version 2 of the License, or | ||
19 | * (at your option) any later version. | ||
20 | * | ||
21 | * This program is distributed in the hope that it will be useful, | ||
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
24 | * GNU General Public License for more details. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License | ||
27 | * along with this program; if not, write to the Free Software | ||
28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | #include <linux/init.h> | ||
33 | #include <linux/jiffies.h> | ||
34 | #include <linux/slab.h> | ||
35 | #include <linux/time.h> | ||
36 | #include <linux/wait.h> | ||
37 | #include <linux/moduleparam.h> | ||
38 | #include <linux/platform_device.h> | ||
39 | #include <sound/core.h> | ||
40 | #include <sound/control.h> | ||
41 | #include <sound/pcm.h> | ||
42 | #include <sound/info.h> | ||
43 | #include <sound/initval.h> | ||
44 | |||
45 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); | ||
46 | MODULE_DESCRIPTION("A loopback soundcard"); | ||
47 | MODULE_LICENSE("GPL"); | ||
48 | MODULE_SUPPORTED_DEVICE("{{ALSA,Loopback soundcard}}"); | ||
49 | |||
50 | #define MAX_PCM_SUBSTREAMS 8 | ||
51 | |||
52 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | ||
53 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | ||
54 | static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0}; | ||
55 | static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8}; | ||
56 | static int pcm_notify[SNDRV_CARDS]; | ||
57 | |||
58 | module_param_array(index, int, NULL, 0444); | ||
59 | MODULE_PARM_DESC(index, "Index value for loopback soundcard."); | ||
60 | module_param_array(id, charp, NULL, 0444); | ||
61 | MODULE_PARM_DESC(id, "ID string for loopback soundcard."); | ||
62 | module_param_array(enable, bool, NULL, 0444); | ||
63 | MODULE_PARM_DESC(enable, "Enable this loopback soundcard."); | ||
64 | module_param_array(pcm_substreams, int, NULL, 0444); | ||
65 | MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-8) for loopback driver."); | ||
66 | module_param_array(pcm_notify, int, NULL, 0444); | ||
67 | MODULE_PARM_DESC(pcm_notify, "Break capture when PCM format/rate/channels changes."); | ||
68 | |||
69 | #define NO_PITCH 100000 | ||
70 | |||
71 | struct loopback_pcm; | ||
72 | |||
73 | struct loopback_cable { | ||
74 | spinlock_t lock; | ||
75 | struct loopback_pcm *streams[2]; | ||
76 | struct snd_pcm_hardware hw; | ||
77 | /* flags */ | ||
78 | unsigned int valid; | ||
79 | unsigned int running; | ||
80 | unsigned int pause; | ||
81 | }; | ||
82 | |||
83 | struct loopback_setup { | ||
84 | unsigned int notify: 1; | ||
85 | unsigned int rate_shift; | ||
86 | unsigned int format; | ||
87 | unsigned int rate; | ||
88 | unsigned int channels; | ||
89 | struct snd_ctl_elem_id active_id; | ||
90 | struct snd_ctl_elem_id format_id; | ||
91 | struct snd_ctl_elem_id rate_id; | ||
92 | struct snd_ctl_elem_id channels_id; | ||
93 | }; | ||
94 | |||
95 | struct loopback { | ||
96 | struct snd_card *card; | ||
97 | struct mutex cable_lock; | ||
98 | struct loopback_cable *cables[MAX_PCM_SUBSTREAMS][2]; | ||
99 | struct snd_pcm *pcm[2]; | ||
100 | struct loopback_setup setup[MAX_PCM_SUBSTREAMS][2]; | ||
101 | }; | ||
102 | |||
103 | struct loopback_pcm { | ||
104 | struct loopback *loopback; | ||
105 | struct snd_pcm_substream *substream; | ||
106 | struct loopback_cable *cable; | ||
107 | unsigned int pcm_buffer_size; | ||
108 | unsigned int buf_pos; /* position in buffer */ | ||
109 | unsigned int silent_size; | ||
110 | /* PCM parameters */ | ||
111 | unsigned int pcm_period_size; | ||
112 | unsigned int pcm_bps; /* bytes per second */ | ||
113 | unsigned int pcm_salign; /* bytes per sample * channels */ | ||
114 | unsigned int pcm_rate_shift; /* rate shift value */ | ||
115 | /* flags */ | ||
116 | unsigned int period_update_pending :1; | ||
117 | /* timer stuff */ | ||
118 | unsigned int irq_pos; /* fractional IRQ position */ | ||
119 | unsigned int period_size_frac; | ||
120 | unsigned long last_jiffies; | ||
121 | struct timer_list timer; | ||
122 | }; | ||
123 | |||
124 | static struct platform_device *devices[SNDRV_CARDS]; | ||
125 | |||
126 | static inline unsigned int byte_pos(struct loopback_pcm *dpcm, unsigned int x) | ||
127 | { | ||
128 | if (dpcm->pcm_rate_shift == NO_PITCH) { | ||
129 | x /= HZ; | ||
130 | } else { | ||
131 | x = div_u64(NO_PITCH * (unsigned long long)x, | ||
132 | HZ * (unsigned long long)dpcm->pcm_rate_shift); | ||
133 | } | ||
134 | return x - (x % dpcm->pcm_salign); | ||
135 | } | ||
136 | |||
137 | static inline unsigned int frac_pos(struct loopback_pcm *dpcm, unsigned int x) | ||
138 | { | ||
139 | if (dpcm->pcm_rate_shift == NO_PITCH) { /* no pitch */ | ||
140 | return x * HZ; | ||
141 | } else { | ||
142 | x = div_u64(dpcm->pcm_rate_shift * (unsigned long long)x * HZ, | ||
143 | NO_PITCH); | ||
144 | } | ||
145 | return x; | ||
146 | } | ||
147 | |||
148 | static inline struct loopback_setup *get_setup(struct loopback_pcm *dpcm) | ||
149 | { | ||
150 | int device = dpcm->substream->pstr->pcm->device; | ||
151 | |||
152 | if (dpcm->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
153 | device ^= 1; | ||
154 | return &dpcm->loopback->setup[dpcm->substream->number][device]; | ||
155 | } | ||
156 | |||
157 | static inline unsigned int get_notify(struct loopback_pcm *dpcm) | ||
158 | { | ||
159 | return get_setup(dpcm)->notify; | ||
160 | } | ||
161 | |||
162 | static inline unsigned int get_rate_shift(struct loopback_pcm *dpcm) | ||
163 | { | ||
164 | return get_setup(dpcm)->rate_shift; | ||
165 | } | ||
166 | |||
167 | static void loopback_timer_start(struct loopback_pcm *dpcm) | ||
168 | { | ||
169 | unsigned long tick; | ||
170 | unsigned int rate_shift = get_rate_shift(dpcm); | ||
171 | |||
172 | if (rate_shift != dpcm->pcm_rate_shift) { | ||
173 | dpcm->pcm_rate_shift = rate_shift; | ||
174 | dpcm->period_size_frac = frac_pos(dpcm, dpcm->pcm_period_size); | ||
175 | } | ||
176 | if (dpcm->period_size_frac <= dpcm->irq_pos) { | ||
177 | dpcm->irq_pos %= dpcm->period_size_frac; | ||
178 | dpcm->period_update_pending = 1; | ||
179 | } | ||
180 | tick = dpcm->period_size_frac - dpcm->irq_pos; | ||
181 | tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps; | ||
182 | dpcm->timer.expires = jiffies + tick; | ||
183 | add_timer(&dpcm->timer); | ||
184 | } | ||
185 | |||
186 | static inline void loopback_timer_stop(struct loopback_pcm *dpcm) | ||
187 | { | ||
188 | del_timer(&dpcm->timer); | ||
189 | dpcm->timer.expires = 0; | ||
190 | } | ||
191 | |||
192 | #define CABLE_VALID_PLAYBACK (1 << SNDRV_PCM_STREAM_PLAYBACK) | ||
193 | #define CABLE_VALID_CAPTURE (1 << SNDRV_PCM_STREAM_CAPTURE) | ||
194 | #define CABLE_VALID_BOTH (CABLE_VALID_PLAYBACK|CABLE_VALID_CAPTURE) | ||
195 | |||
196 | static int loopback_check_format(struct loopback_cable *cable, int stream) | ||
197 | { | ||
198 | struct snd_pcm_runtime *runtime, *cruntime; | ||
199 | struct loopback_setup *setup; | ||
200 | struct snd_card *card; | ||
201 | int check; | ||
202 | |||
203 | if (cable->valid != CABLE_VALID_BOTH) { | ||
204 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
205 | goto __notify; | ||
206 | return 0; | ||
207 | } | ||
208 | runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]-> | ||
209 | substream->runtime; | ||
210 | cruntime = cable->streams[SNDRV_PCM_STREAM_CAPTURE]-> | ||
211 | substream->runtime; | ||
212 | check = runtime->format != cruntime->format || | ||
213 | runtime->rate != cruntime->rate || | ||
214 | runtime->channels != cruntime->channels; | ||
215 | if (!check) | ||
216 | return 0; | ||
217 | if (stream == SNDRV_PCM_STREAM_CAPTURE) { | ||
218 | return -EIO; | ||
219 | } else { | ||
220 | snd_pcm_stop(cable->streams[SNDRV_PCM_STREAM_CAPTURE]-> | ||
221 | substream, SNDRV_PCM_STATE_DRAINING); | ||
222 | __notify: | ||
223 | runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]-> | ||
224 | substream->runtime; | ||
225 | setup = get_setup(cable->streams[SNDRV_PCM_STREAM_PLAYBACK]); | ||
226 | card = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->loopback->card; | ||
227 | if (setup->format != runtime->format) { | ||
228 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
229 | &setup->format_id); | ||
230 | setup->format = runtime->format; | ||
231 | } | ||
232 | if (setup->rate != runtime->rate) { | ||
233 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
234 | &setup->rate_id); | ||
235 | setup->rate = runtime->rate; | ||
236 | } | ||
237 | if (setup->channels != runtime->channels) { | ||
238 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
239 | &setup->channels_id); | ||
240 | setup->channels = runtime->channels; | ||
241 | } | ||
242 | } | ||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | static void loopback_active_notify(struct loopback_pcm *dpcm) | ||
247 | { | ||
248 | snd_ctl_notify(dpcm->loopback->card, | ||
249 | SNDRV_CTL_EVENT_MASK_VALUE, | ||
250 | &get_setup(dpcm)->active_id); | ||
251 | } | ||
252 | |||
253 | static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) | ||
254 | { | ||
255 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
256 | struct loopback_pcm *dpcm = runtime->private_data; | ||
257 | struct loopback_cable *cable = dpcm->cable; | ||
258 | int err, stream = 1 << substream->stream; | ||
259 | |||
260 | switch (cmd) { | ||
261 | case SNDRV_PCM_TRIGGER_START: | ||
262 | err = loopback_check_format(cable, substream->stream); | ||
263 | if (err < 0) | ||
264 | return err; | ||
265 | dpcm->last_jiffies = jiffies; | ||
266 | dpcm->pcm_rate_shift = 0; | ||
267 | spin_lock(&cable->lock); | ||
268 | cable->running |= stream; | ||
269 | cable->pause &= ~stream; | ||
270 | spin_unlock(&cable->lock); | ||
271 | loopback_timer_start(dpcm); | ||
272 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
273 | loopback_active_notify(dpcm); | ||
274 | break; | ||
275 | case SNDRV_PCM_TRIGGER_STOP: | ||
276 | spin_lock(&cable->lock); | ||
277 | cable->running &= ~stream; | ||
278 | cable->pause &= ~stream; | ||
279 | spin_unlock(&cable->lock); | ||
280 | loopback_timer_stop(dpcm); | ||
281 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
282 | loopback_active_notify(dpcm); | ||
283 | break; | ||
284 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
285 | spin_lock(&cable->lock); | ||
286 | cable->pause |= stream; | ||
287 | spin_unlock(&cable->lock); | ||
288 | loopback_timer_stop(dpcm); | ||
289 | break; | ||
290 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
291 | spin_lock(&cable->lock); | ||
292 | dpcm->last_jiffies = jiffies; | ||
293 | cable->pause &= ~stream; | ||
294 | spin_unlock(&cable->lock); | ||
295 | loopback_timer_start(dpcm); | ||
296 | break; | ||
297 | default: | ||
298 | return -EINVAL; | ||
299 | } | ||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static void params_change_substream(struct loopback_pcm *dpcm, | ||
304 | struct snd_pcm_runtime *runtime) | ||
305 | { | ||
306 | struct snd_pcm_runtime *dst_runtime; | ||
307 | |||
308 | if (dpcm == NULL || dpcm->substream == NULL) | ||
309 | return; | ||
310 | dst_runtime = dpcm->substream->runtime; | ||
311 | if (dst_runtime == NULL) | ||
312 | return; | ||
313 | dst_runtime->hw = dpcm->cable->hw; | ||
314 | } | ||
315 | |||
316 | static void params_change(struct snd_pcm_substream *substream) | ||
317 | { | ||
318 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
319 | struct loopback_pcm *dpcm = runtime->private_data; | ||
320 | struct loopback_cable *cable = dpcm->cable; | ||
321 | |||
322 | cable->hw.formats = (1ULL << runtime->format); | ||
323 | cable->hw.rate_min = runtime->rate; | ||
324 | cable->hw.rate_max = runtime->rate; | ||
325 | cable->hw.channels_min = runtime->channels; | ||
326 | cable->hw.channels_max = runtime->channels; | ||
327 | params_change_substream(cable->streams[SNDRV_PCM_STREAM_PLAYBACK], | ||
328 | runtime); | ||
329 | params_change_substream(cable->streams[SNDRV_PCM_STREAM_CAPTURE], | ||
330 | runtime); | ||
331 | } | ||
332 | |||
333 | static int loopback_prepare(struct snd_pcm_substream *substream) | ||
334 | { | ||
335 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
336 | struct loopback_pcm *dpcm = runtime->private_data; | ||
337 | struct loopback_cable *cable = dpcm->cable; | ||
338 | int bps, salign; | ||
339 | |||
340 | salign = (snd_pcm_format_width(runtime->format) * | ||
341 | runtime->channels) / 8; | ||
342 | bps = salign * runtime->rate; | ||
343 | if (bps <= 0 || salign <= 0) | ||
344 | return -EINVAL; | ||
345 | |||
346 | dpcm->buf_pos = 0; | ||
347 | dpcm->pcm_buffer_size = frames_to_bytes(runtime, runtime->buffer_size); | ||
348 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { | ||
349 | /* clear capture buffer */ | ||
350 | dpcm->silent_size = dpcm->pcm_buffer_size; | ||
351 | snd_pcm_format_set_silence(runtime->format, runtime->dma_area, | ||
352 | runtime->buffer_size * runtime->channels); | ||
353 | } | ||
354 | |||
355 | dpcm->irq_pos = 0; | ||
356 | dpcm->period_update_pending = 0; | ||
357 | dpcm->pcm_bps = bps; | ||
358 | dpcm->pcm_salign = salign; | ||
359 | dpcm->pcm_period_size = frames_to_bytes(runtime, runtime->period_size); | ||
360 | |||
361 | mutex_lock(&dpcm->loopback->cable_lock); | ||
362 | if (!(cable->valid & ~(1 << substream->stream)) || | ||
363 | (get_setup(dpcm)->notify && | ||
364 | substream->stream == SNDRV_PCM_STREAM_PLAYBACK)) | ||
365 | params_change(substream); | ||
366 | cable->valid |= 1 << substream->stream; | ||
367 | mutex_unlock(&dpcm->loopback->cable_lock); | ||
368 | |||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | static void clear_capture_buf(struct loopback_pcm *dpcm, unsigned int bytes) | ||
373 | { | ||
374 | struct snd_pcm_runtime *runtime = dpcm->substream->runtime; | ||
375 | char *dst = runtime->dma_area; | ||
376 | unsigned int dst_off = dpcm->buf_pos; | ||
377 | |||
378 | if (dpcm->silent_size >= dpcm->pcm_buffer_size) | ||
379 | return; | ||
380 | if (dpcm->silent_size + bytes > dpcm->pcm_buffer_size) | ||
381 | bytes = dpcm->pcm_buffer_size - dpcm->silent_size; | ||
382 | |||
383 | for (;;) { | ||
384 | unsigned int size = bytes; | ||
385 | if (dst_off + size > dpcm->pcm_buffer_size) | ||
386 | size = dpcm->pcm_buffer_size - dst_off; | ||
387 | snd_pcm_format_set_silence(runtime->format, dst + dst_off, | ||
388 | bytes_to_frames(runtime, size) * | ||
389 | runtime->channels); | ||
390 | dpcm->silent_size += size; | ||
391 | bytes -= size; | ||
392 | if (!bytes) | ||
393 | break; | ||
394 | dst_off = 0; | ||
395 | } | ||
396 | } | ||
397 | |||
398 | static void copy_play_buf(struct loopback_pcm *play, | ||
399 | struct loopback_pcm *capt, | ||
400 | unsigned int bytes) | ||
401 | { | ||
402 | struct snd_pcm_runtime *runtime = play->substream->runtime; | ||
403 | char *src = runtime->dma_area; | ||
404 | char *dst = capt->substream->runtime->dma_area; | ||
405 | unsigned int src_off = play->buf_pos; | ||
406 | unsigned int dst_off = capt->buf_pos; | ||
407 | unsigned int clear_bytes = 0; | ||
408 | |||
409 | /* check if playback is draining, trim the capture copy size | ||
410 | * when our pointer is at the end of playback ring buffer */ | ||
411 | if (runtime->status->state == SNDRV_PCM_STATE_DRAINING && | ||
412 | snd_pcm_playback_hw_avail(runtime) < runtime->buffer_size) { | ||
413 | snd_pcm_uframes_t appl_ptr, appl_ptr1, diff; | ||
414 | appl_ptr = appl_ptr1 = runtime->control->appl_ptr; | ||
415 | appl_ptr1 -= appl_ptr1 % runtime->buffer_size; | ||
416 | appl_ptr1 += play->buf_pos / play->pcm_salign; | ||
417 | if (appl_ptr < appl_ptr1) | ||
418 | appl_ptr1 -= runtime->buffer_size; | ||
419 | diff = (appl_ptr - appl_ptr1) * play->pcm_salign; | ||
420 | if (diff < bytes) { | ||
421 | clear_bytes = bytes - diff; | ||
422 | bytes = diff; | ||
423 | } | ||
424 | } | ||
425 | |||
426 | for (;;) { | ||
427 | unsigned int size = bytes; | ||
428 | if (src_off + size > play->pcm_buffer_size) | ||
429 | size = play->pcm_buffer_size - src_off; | ||
430 | if (dst_off + size > capt->pcm_buffer_size) | ||
431 | size = capt->pcm_buffer_size - dst_off; | ||
432 | memcpy(dst + dst_off, src + src_off, size); | ||
433 | capt->silent_size = 0; | ||
434 | bytes -= size; | ||
435 | if (!bytes) | ||
436 | break; | ||
437 | src_off = (src_off + size) % play->pcm_buffer_size; | ||
438 | dst_off = (dst_off + size) % capt->pcm_buffer_size; | ||
439 | } | ||
440 | |||
441 | if (clear_bytes > 0) { | ||
442 | clear_capture_buf(capt, clear_bytes); | ||
443 | capt->silent_size = 0; | ||
444 | } | ||
445 | } | ||
446 | |||
447 | #define BYTEPOS_UPDATE_POSONLY 0 | ||
448 | #define BYTEPOS_UPDATE_CLEAR 1 | ||
449 | #define BYTEPOS_UPDATE_COPY 2 | ||
450 | |||
451 | static void loopback_bytepos_update(struct loopback_pcm *dpcm, | ||
452 | unsigned int delta, | ||
453 | unsigned int cmd) | ||
454 | { | ||
455 | unsigned int count; | ||
456 | unsigned long last_pos; | ||
457 | |||
458 | last_pos = byte_pos(dpcm, dpcm->irq_pos); | ||
459 | dpcm->irq_pos += delta * dpcm->pcm_bps; | ||
460 | count = byte_pos(dpcm, dpcm->irq_pos) - last_pos; | ||
461 | if (!count) | ||
462 | return; | ||
463 | if (cmd == BYTEPOS_UPDATE_CLEAR) | ||
464 | clear_capture_buf(dpcm, count); | ||
465 | else if (cmd == BYTEPOS_UPDATE_COPY) | ||
466 | copy_play_buf(dpcm->cable->streams[SNDRV_PCM_STREAM_PLAYBACK], | ||
467 | dpcm->cable->streams[SNDRV_PCM_STREAM_CAPTURE], | ||
468 | count); | ||
469 | dpcm->buf_pos += count; | ||
470 | dpcm->buf_pos %= dpcm->pcm_buffer_size; | ||
471 | if (dpcm->irq_pos >= dpcm->period_size_frac) { | ||
472 | dpcm->irq_pos %= dpcm->period_size_frac; | ||
473 | dpcm->period_update_pending = 1; | ||
474 | } | ||
475 | } | ||
476 | |||
477 | static unsigned int loopback_pos_update(struct loopback_cable *cable) | ||
478 | { | ||
479 | struct loopback_pcm *dpcm_play = | ||
480 | cable->streams[SNDRV_PCM_STREAM_PLAYBACK]; | ||
481 | struct loopback_pcm *dpcm_capt = | ||
482 | cable->streams[SNDRV_PCM_STREAM_CAPTURE]; | ||
483 | unsigned long delta_play = 0, delta_capt = 0; | ||
484 | unsigned int running; | ||
485 | |||
486 | spin_lock(&cable->lock); | ||
487 | running = cable->running ^ cable->pause; | ||
488 | if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) { | ||
489 | delta_play = jiffies - dpcm_play->last_jiffies; | ||
490 | dpcm_play->last_jiffies += delta_play; | ||
491 | } | ||
492 | |||
493 | if (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) { | ||
494 | delta_capt = jiffies - dpcm_capt->last_jiffies; | ||
495 | dpcm_capt->last_jiffies += delta_capt; | ||
496 | } | ||
497 | |||
498 | if (delta_play == 0 && delta_capt == 0) { | ||
499 | spin_unlock(&cable->lock); | ||
500 | return running; | ||
501 | } | ||
502 | |||
503 | if (delta_play > delta_capt) { | ||
504 | loopback_bytepos_update(dpcm_play, delta_play - delta_capt, | ||
505 | BYTEPOS_UPDATE_POSONLY); | ||
506 | delta_play = delta_capt; | ||
507 | } else if (delta_play < delta_capt) { | ||
508 | loopback_bytepos_update(dpcm_capt, delta_capt - delta_play, | ||
509 | BYTEPOS_UPDATE_CLEAR); | ||
510 | delta_capt = delta_play; | ||
511 | } | ||
512 | |||
513 | if (delta_play == 0 && delta_capt == 0) { | ||
514 | spin_unlock(&cable->lock); | ||
515 | return running; | ||
516 | } | ||
517 | /* note delta_capt == delta_play at this moment */ | ||
518 | loopback_bytepos_update(dpcm_capt, delta_capt, BYTEPOS_UPDATE_COPY); | ||
519 | loopback_bytepos_update(dpcm_play, delta_play, BYTEPOS_UPDATE_POSONLY); | ||
520 | spin_unlock(&cable->lock); | ||
521 | return running; | ||
522 | } | ||
523 | |||
524 | static void loopback_timer_function(unsigned long data) | ||
525 | { | ||
526 | struct loopback_pcm *dpcm = (struct loopback_pcm *)data; | ||
527 | unsigned int running; | ||
528 | |||
529 | running = loopback_pos_update(dpcm->cable); | ||
530 | if (running & (1 << dpcm->substream->stream)) { | ||
531 | loopback_timer_start(dpcm); | ||
532 | if (dpcm->period_update_pending) { | ||
533 | dpcm->period_update_pending = 0; | ||
534 | snd_pcm_period_elapsed(dpcm->substream); | ||
535 | } | ||
536 | } | ||
537 | } | ||
538 | |||
539 | static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream) | ||
540 | { | ||
541 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
542 | struct loopback_pcm *dpcm = runtime->private_data; | ||
543 | |||
544 | loopback_pos_update(dpcm->cable); | ||
545 | return bytes_to_frames(runtime, dpcm->buf_pos); | ||
546 | } | ||
547 | |||
548 | static struct snd_pcm_hardware loopback_pcm_hardware = | ||
549 | { | ||
550 | .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | | ||
551 | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE), | ||
552 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | | ||
553 | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE | | ||
554 | SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE), | ||
555 | .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000, | ||
556 | .rate_min = 8000, | ||
557 | .rate_max = 192000, | ||
558 | .channels_min = 1, | ||
559 | .channels_max = 32, | ||
560 | .buffer_bytes_max = 2 * 1024 * 1024, | ||
561 | .period_bytes_min = 64, | ||
562 | /* note check overflow in frac_pos() using pcm_rate_shift before | ||
563 | changing period_bytes_max value */ | ||
564 | .period_bytes_max = 1024 * 1024, | ||
565 | .periods_min = 1, | ||
566 | .periods_max = 1024, | ||
567 | .fifo_size = 0, | ||
568 | }; | ||
569 | |||
570 | static void loopback_runtime_free(struct snd_pcm_runtime *runtime) | ||
571 | { | ||
572 | struct loopback_pcm *dpcm = runtime->private_data; | ||
573 | kfree(dpcm); | ||
574 | } | ||
575 | |||
576 | static int loopback_hw_params(struct snd_pcm_substream *substream, | ||
577 | struct snd_pcm_hw_params *params) | ||
578 | { | ||
579 | return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | ||
580 | } | ||
581 | |||
582 | static int loopback_hw_free(struct snd_pcm_substream *substream) | ||
583 | { | ||
584 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
585 | struct loopback_pcm *dpcm = runtime->private_data; | ||
586 | struct loopback_cable *cable = dpcm->cable; | ||
587 | |||
588 | mutex_lock(&dpcm->loopback->cable_lock); | ||
589 | cable->valid &= ~(1 << substream->stream); | ||
590 | mutex_unlock(&dpcm->loopback->cable_lock); | ||
591 | return snd_pcm_lib_free_pages(substream); | ||
592 | } | ||
593 | |||
594 | static unsigned int get_cable_index(struct snd_pcm_substream *substream) | ||
595 | { | ||
596 | if (!substream->pcm->device) | ||
597 | return substream->stream; | ||
598 | else | ||
599 | return !substream->stream; | ||
600 | } | ||
601 | |||
602 | static int rule_format(struct snd_pcm_hw_params *params, | ||
603 | struct snd_pcm_hw_rule *rule) | ||
604 | { | ||
605 | |||
606 | struct snd_pcm_hardware *hw = rule->private; | ||
607 | struct snd_mask *maskp = hw_param_mask(params, rule->var); | ||
608 | |||
609 | maskp->bits[0] &= (u_int32_t)hw->formats; | ||
610 | maskp->bits[1] &= (u_int32_t)(hw->formats >> 32); | ||
611 | memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX-64) / 8); /* clear rest */ | ||
612 | if (! maskp->bits[0] && ! maskp->bits[1]) | ||
613 | return -EINVAL; | ||
614 | return 0; | ||
615 | } | ||
616 | |||
617 | static int rule_rate(struct snd_pcm_hw_params *params, | ||
618 | struct snd_pcm_hw_rule *rule) | ||
619 | { | ||
620 | struct snd_pcm_hardware *hw = rule->private; | ||
621 | struct snd_interval t; | ||
622 | |||
623 | t.min = hw->rate_min; | ||
624 | t.max = hw->rate_max; | ||
625 | t.openmin = t.openmax = 0; | ||
626 | t.integer = 0; | ||
627 | return snd_interval_refine(hw_param_interval(params, rule->var), &t); | ||
628 | } | ||
629 | |||
630 | static int rule_channels(struct snd_pcm_hw_params *params, | ||
631 | struct snd_pcm_hw_rule *rule) | ||
632 | { | ||
633 | struct snd_pcm_hardware *hw = rule->private; | ||
634 | struct snd_interval t; | ||
635 | |||
636 | t.min = hw->channels_min; | ||
637 | t.max = hw->channels_max; | ||
638 | t.openmin = t.openmax = 0; | ||
639 | t.integer = 0; | ||
640 | return snd_interval_refine(hw_param_interval(params, rule->var), &t); | ||
641 | } | ||
642 | |||
643 | static int loopback_open(struct snd_pcm_substream *substream) | ||
644 | { | ||
645 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
646 | struct loopback *loopback = substream->private_data; | ||
647 | struct loopback_pcm *dpcm; | ||
648 | struct loopback_cable *cable; | ||
649 | int err = 0; | ||
650 | int dev = get_cable_index(substream); | ||
651 | |||
652 | mutex_lock(&loopback->cable_lock); | ||
653 | dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL); | ||
654 | if (!dpcm) { | ||
655 | err = -ENOMEM; | ||
656 | goto unlock; | ||
657 | } | ||
658 | dpcm->loopback = loopback; | ||
659 | dpcm->substream = substream; | ||
660 | setup_timer(&dpcm->timer, loopback_timer_function, | ||
661 | (unsigned long)dpcm); | ||
662 | |||
663 | cable = loopback->cables[substream->number][dev]; | ||
664 | if (!cable) { | ||
665 | cable = kzalloc(sizeof(*cable), GFP_KERNEL); | ||
666 | if (!cable) { | ||
667 | kfree(dpcm); | ||
668 | err = -ENOMEM; | ||
669 | goto unlock; | ||
670 | } | ||
671 | spin_lock_init(&cable->lock); | ||
672 | cable->hw = loopback_pcm_hardware; | ||
673 | loopback->cables[substream->number][dev] = cable; | ||
674 | } | ||
675 | dpcm->cable = cable; | ||
676 | cable->streams[substream->stream] = dpcm; | ||
677 | |||
678 | snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); | ||
679 | |||
680 | /* use dynamic rules based on actual runtime->hw values */ | ||
681 | /* note that the default rules created in the PCM midlevel code */ | ||
682 | /* are cached -> they do not reflect the actual state */ | ||
683 | err = snd_pcm_hw_rule_add(runtime, 0, | ||
684 | SNDRV_PCM_HW_PARAM_FORMAT, | ||
685 | rule_format, &runtime->hw, | ||
686 | SNDRV_PCM_HW_PARAM_FORMAT, -1); | ||
687 | if (err < 0) | ||
688 | goto unlock; | ||
689 | err = snd_pcm_hw_rule_add(runtime, 0, | ||
690 | SNDRV_PCM_HW_PARAM_RATE, | ||
691 | rule_rate, &runtime->hw, | ||
692 | SNDRV_PCM_HW_PARAM_RATE, -1); | ||
693 | if (err < 0) | ||
694 | goto unlock; | ||
695 | err = snd_pcm_hw_rule_add(runtime, 0, | ||
696 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
697 | rule_channels, &runtime->hw, | ||
698 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); | ||
699 | if (err < 0) | ||
700 | goto unlock; | ||
701 | |||
702 | runtime->private_data = dpcm; | ||
703 | runtime->private_free = loopback_runtime_free; | ||
704 | if (get_notify(dpcm)) | ||
705 | runtime->hw = loopback_pcm_hardware; | ||
706 | else | ||
707 | runtime->hw = cable->hw; | ||
708 | unlock: | ||
709 | mutex_unlock(&loopback->cable_lock); | ||
710 | return err; | ||
711 | } | ||
712 | |||
713 | static int loopback_close(struct snd_pcm_substream *substream) | ||
714 | { | ||
715 | struct loopback *loopback = substream->private_data; | ||
716 | struct loopback_pcm *dpcm = substream->runtime->private_data; | ||
717 | struct loopback_cable *cable; | ||
718 | int dev = get_cable_index(substream); | ||
719 | |||
720 | loopback_timer_stop(dpcm); | ||
721 | mutex_lock(&loopback->cable_lock); | ||
722 | cable = loopback->cables[substream->number][dev]; | ||
723 | if (cable->streams[!substream->stream]) { | ||
724 | /* other stream is still alive */ | ||
725 | cable->streams[substream->stream] = NULL; | ||
726 | } else { | ||
727 | /* free the cable */ | ||
728 | loopback->cables[substream->number][dev] = NULL; | ||
729 | kfree(cable); | ||
730 | } | ||
731 | mutex_unlock(&loopback->cable_lock); | ||
732 | return 0; | ||
733 | } | ||
734 | |||
735 | static struct snd_pcm_ops loopback_playback_ops = { | ||
736 | .open = loopback_open, | ||
737 | .close = loopback_close, | ||
738 | .ioctl = snd_pcm_lib_ioctl, | ||
739 | .hw_params = loopback_hw_params, | ||
740 | .hw_free = loopback_hw_free, | ||
741 | .prepare = loopback_prepare, | ||
742 | .trigger = loopback_trigger, | ||
743 | .pointer = loopback_pointer, | ||
744 | }; | ||
745 | |||
746 | static struct snd_pcm_ops loopback_capture_ops = { | ||
747 | .open = loopback_open, | ||
748 | .close = loopback_close, | ||
749 | .ioctl = snd_pcm_lib_ioctl, | ||
750 | .hw_params = loopback_hw_params, | ||
751 | .hw_free = loopback_hw_free, | ||
752 | .prepare = loopback_prepare, | ||
753 | .trigger = loopback_trigger, | ||
754 | .pointer = loopback_pointer, | ||
755 | }; | ||
756 | |||
757 | static int __devinit loopback_pcm_new(struct loopback *loopback, | ||
758 | int device, int substreams) | ||
759 | { | ||
760 | struct snd_pcm *pcm; | ||
761 | int err; | ||
762 | |||
763 | err = snd_pcm_new(loopback->card, "Loopback PCM", device, | ||
764 | substreams, substreams, &pcm); | ||
765 | if (err < 0) | ||
766 | return err; | ||
767 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &loopback_playback_ops); | ||
768 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &loopback_capture_ops); | ||
769 | |||
770 | pcm->private_data = loopback; | ||
771 | pcm->info_flags = 0; | ||
772 | strcpy(pcm->name, "Loopback PCM"); | ||
773 | |||
774 | loopback->pcm[device] = pcm; | ||
775 | |||
776 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, | ||
777 | snd_dma_continuous_data(GFP_KERNEL), | ||
778 | 0, 2 * 1024 * 1024); | ||
779 | return 0; | ||
780 | } | ||
781 | |||
782 | static int loopback_rate_shift_info(struct snd_kcontrol *kcontrol, | ||
783 | struct snd_ctl_elem_info *uinfo) | ||
784 | { | ||
785 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
786 | uinfo->count = 1; | ||
787 | uinfo->value.integer.min = 80000; | ||
788 | uinfo->value.integer.max = 120000; | ||
789 | uinfo->value.integer.step = 1; | ||
790 | return 0; | ||
791 | } | ||
792 | |||
793 | static int loopback_rate_shift_get(struct snd_kcontrol *kcontrol, | ||
794 | struct snd_ctl_elem_value *ucontrol) | ||
795 | { | ||
796 | struct loopback *loopback = snd_kcontrol_chip(kcontrol); | ||
797 | |||
798 | ucontrol->value.integer.value[0] = | ||
799 | loopback->setup[kcontrol->id.subdevice] | ||
800 | [kcontrol->id.device].rate_shift; | ||
801 | return 0; | ||
802 | } | ||
803 | |||
804 | static int loopback_rate_shift_put(struct snd_kcontrol *kcontrol, | ||
805 | struct snd_ctl_elem_value *ucontrol) | ||
806 | { | ||
807 | struct loopback *loopback = snd_kcontrol_chip(kcontrol); | ||
808 | unsigned int val; | ||
809 | int change = 0; | ||
810 | |||
811 | val = ucontrol->value.integer.value[0]; | ||
812 | if (val < 80000) | ||
813 | val = 80000; | ||
814 | if (val > 120000) | ||
815 | val = 120000; | ||
816 | mutex_lock(&loopback->cable_lock); | ||
817 | if (val != loopback->setup[kcontrol->id.subdevice] | ||
818 | [kcontrol->id.device].rate_shift) { | ||
819 | loopback->setup[kcontrol->id.subdevice] | ||
820 | [kcontrol->id.device].rate_shift = val; | ||
821 | change = 1; | ||
822 | } | ||
823 | mutex_unlock(&loopback->cable_lock); | ||
824 | return change; | ||
825 | } | ||
826 | |||
827 | static int loopback_notify_get(struct snd_kcontrol *kcontrol, | ||
828 | struct snd_ctl_elem_value *ucontrol) | ||
829 | { | ||
830 | struct loopback *loopback = snd_kcontrol_chip(kcontrol); | ||
831 | |||
832 | ucontrol->value.integer.value[0] = | ||
833 | loopback->setup[kcontrol->id.subdevice] | ||
834 | [kcontrol->id.device].notify; | ||
835 | return 0; | ||
836 | } | ||
837 | |||
838 | static int loopback_notify_put(struct snd_kcontrol *kcontrol, | ||
839 | struct snd_ctl_elem_value *ucontrol) | ||
840 | { | ||
841 | struct loopback *loopback = snd_kcontrol_chip(kcontrol); | ||
842 | unsigned int val; | ||
843 | int change = 0; | ||
844 | |||
845 | val = ucontrol->value.integer.value[0] ? 1 : 0; | ||
846 | if (val != loopback->setup[kcontrol->id.subdevice] | ||
847 | [kcontrol->id.device].notify) { | ||
848 | loopback->setup[kcontrol->id.subdevice] | ||
849 | [kcontrol->id.device].notify = val; | ||
850 | change = 1; | ||
851 | } | ||
852 | return change; | ||
853 | } | ||
854 | |||
855 | static int loopback_active_get(struct snd_kcontrol *kcontrol, | ||
856 | struct snd_ctl_elem_value *ucontrol) | ||
857 | { | ||
858 | struct loopback *loopback = snd_kcontrol_chip(kcontrol); | ||
859 | struct loopback_cable *cable = loopback->cables | ||
860 | [kcontrol->id.subdevice][kcontrol->id.device ^ 1]; | ||
861 | unsigned int val = 0; | ||
862 | |||
863 | if (cable != NULL) | ||
864 | val = (cable->running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? | ||
865 | 1 : 0; | ||
866 | ucontrol->value.integer.value[0] = val; | ||
867 | return 0; | ||
868 | } | ||
869 | |||
870 | static int loopback_format_info(struct snd_kcontrol *kcontrol, | ||
871 | struct snd_ctl_elem_info *uinfo) | ||
872 | { | ||
873 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
874 | uinfo->count = 1; | ||
875 | uinfo->value.integer.min = 0; | ||
876 | uinfo->value.integer.max = SNDRV_PCM_FORMAT_LAST; | ||
877 | uinfo->value.integer.step = 1; | ||
878 | return 0; | ||
879 | } | ||
880 | |||
881 | static int loopback_format_get(struct snd_kcontrol *kcontrol, | ||
882 | struct snd_ctl_elem_value *ucontrol) | ||
883 | { | ||
884 | struct loopback *loopback = snd_kcontrol_chip(kcontrol); | ||
885 | |||
886 | ucontrol->value.integer.value[0] = | ||
887 | loopback->setup[kcontrol->id.subdevice] | ||
888 | [kcontrol->id.device].format; | ||
889 | return 0; | ||
890 | } | ||
891 | |||
892 | static int loopback_rate_info(struct snd_kcontrol *kcontrol, | ||
893 | struct snd_ctl_elem_info *uinfo) | ||
894 | { | ||
895 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
896 | uinfo->count = 1; | ||
897 | uinfo->value.integer.min = 0; | ||
898 | uinfo->value.integer.max = 192000; | ||
899 | uinfo->value.integer.step = 1; | ||
900 | return 0; | ||
901 | } | ||
902 | |||
903 | static int loopback_rate_get(struct snd_kcontrol *kcontrol, | ||
904 | struct snd_ctl_elem_value *ucontrol) | ||
905 | { | ||
906 | struct loopback *loopback = snd_kcontrol_chip(kcontrol); | ||
907 | |||
908 | ucontrol->value.integer.value[0] = | ||
909 | loopback->setup[kcontrol->id.subdevice] | ||
910 | [kcontrol->id.device].rate; | ||
911 | return 0; | ||
912 | } | ||
913 | |||
914 | static int loopback_channels_info(struct snd_kcontrol *kcontrol, | ||
915 | struct snd_ctl_elem_info *uinfo) | ||
916 | { | ||
917 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
918 | uinfo->count = 1; | ||
919 | uinfo->value.integer.min = 1; | ||
920 | uinfo->value.integer.max = 1024; | ||
921 | uinfo->value.integer.step = 1; | ||
922 | return 0; | ||
923 | } | ||
924 | |||
925 | static int loopback_channels_get(struct snd_kcontrol *kcontrol, | ||
926 | struct snd_ctl_elem_value *ucontrol) | ||
927 | { | ||
928 | struct loopback *loopback = snd_kcontrol_chip(kcontrol); | ||
929 | |||
930 | ucontrol->value.integer.value[0] = | ||
931 | loopback->setup[kcontrol->id.subdevice] | ||
932 | [kcontrol->id.device].channels; | ||
933 | return 0; | ||
934 | } | ||
935 | |||
936 | static struct snd_kcontrol_new loopback_controls[] __devinitdata = { | ||
937 | { | ||
938 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
939 | .name = "PCM Rate Shift 100000", | ||
940 | .info = loopback_rate_shift_info, | ||
941 | .get = loopback_rate_shift_get, | ||
942 | .put = loopback_rate_shift_put, | ||
943 | }, | ||
944 | { | ||
945 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
946 | .name = "PCM Notify", | ||
947 | .info = snd_ctl_boolean_mono_info, | ||
948 | .get = loopback_notify_get, | ||
949 | .put = loopback_notify_put, | ||
950 | }, | ||
951 | #define ACTIVE_IDX 2 | ||
952 | { | ||
953 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
954 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
955 | .name = "PCM Slave Active", | ||
956 | .info = snd_ctl_boolean_mono_info, | ||
957 | .get = loopback_active_get, | ||
958 | }, | ||
959 | #define FORMAT_IDX 3 | ||
960 | { | ||
961 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
962 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
963 | .name = "PCM Slave Format", | ||
964 | .info = loopback_format_info, | ||
965 | .get = loopback_format_get | ||
966 | }, | ||
967 | #define RATE_IDX 4 | ||
968 | { | ||
969 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
970 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
971 | .name = "PCM Slave Rate", | ||
972 | .info = loopback_rate_info, | ||
973 | .get = loopback_rate_get | ||
974 | }, | ||
975 | #define CHANNELS_IDX 5 | ||
976 | { | ||
977 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
978 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
979 | .name = "PCM Slave Channels", | ||
980 | .info = loopback_channels_info, | ||
981 | .get = loopback_channels_get | ||
982 | } | ||
983 | }; | ||
984 | |||
985 | static int __devinit loopback_mixer_new(struct loopback *loopback, int notify) | ||
986 | { | ||
987 | struct snd_card *card = loopback->card; | ||
988 | struct snd_pcm *pcm; | ||
989 | struct snd_kcontrol *kctl; | ||
990 | struct loopback_setup *setup; | ||
991 | int err, dev, substr, substr_count, idx; | ||
992 | |||
993 | strcpy(card->mixername, "Loopback Mixer"); | ||
994 | for (dev = 0; dev < 2; dev++) { | ||
995 | pcm = loopback->pcm[dev]; | ||
996 | substr_count = | ||
997 | pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count; | ||
998 | for (substr = 0; substr < substr_count; substr++) { | ||
999 | setup = &loopback->setup[substr][dev]; | ||
1000 | setup->notify = notify; | ||
1001 | setup->rate_shift = NO_PITCH; | ||
1002 | setup->format = SNDRV_PCM_FORMAT_S16_LE; | ||
1003 | setup->rate = 48000; | ||
1004 | setup->channels = 2; | ||
1005 | for (idx = 0; idx < ARRAY_SIZE(loopback_controls); | ||
1006 | idx++) { | ||
1007 | kctl = snd_ctl_new1(&loopback_controls[idx], | ||
1008 | loopback); | ||
1009 | if (!kctl) | ||
1010 | return -ENOMEM; | ||
1011 | kctl->id.device = dev; | ||
1012 | kctl->id.subdevice = substr; | ||
1013 | switch (idx) { | ||
1014 | case ACTIVE_IDX: | ||
1015 | setup->active_id = kctl->id; | ||
1016 | break; | ||
1017 | case FORMAT_IDX: | ||
1018 | setup->format_id = kctl->id; | ||
1019 | break; | ||
1020 | case RATE_IDX: | ||
1021 | setup->rate_id = kctl->id; | ||
1022 | break; | ||
1023 | case CHANNELS_IDX: | ||
1024 | setup->channels_id = kctl->id; | ||
1025 | break; | ||
1026 | default: | ||
1027 | break; | ||
1028 | } | ||
1029 | err = snd_ctl_add(card, kctl); | ||
1030 | if (err < 0) | ||
1031 | return err; | ||
1032 | } | ||
1033 | } | ||
1034 | } | ||
1035 | return 0; | ||
1036 | } | ||
1037 | |||
1038 | #ifdef CONFIG_PROC_FS | ||
1039 | |||
1040 | static void print_dpcm_info(struct snd_info_buffer *buffer, | ||
1041 | struct loopback_pcm *dpcm, | ||
1042 | const char *id) | ||
1043 | { | ||
1044 | snd_iprintf(buffer, " %s\n", id); | ||
1045 | if (dpcm == NULL) { | ||
1046 | snd_iprintf(buffer, " inactive\n"); | ||
1047 | return; | ||
1048 | } | ||
1049 | snd_iprintf(buffer, " buffer_size:\t%u\n", dpcm->pcm_buffer_size); | ||
1050 | snd_iprintf(buffer, " buffer_pos:\t\t%u\n", dpcm->buf_pos); | ||
1051 | snd_iprintf(buffer, " silent_size:\t%u\n", dpcm->silent_size); | ||
1052 | snd_iprintf(buffer, " period_size:\t%u\n", dpcm->pcm_period_size); | ||
1053 | snd_iprintf(buffer, " bytes_per_sec:\t%u\n", dpcm->pcm_bps); | ||
1054 | snd_iprintf(buffer, " sample_align:\t%u\n", dpcm->pcm_salign); | ||
1055 | snd_iprintf(buffer, " rate_shift:\t\t%u\n", dpcm->pcm_rate_shift); | ||
1056 | snd_iprintf(buffer, " update_pending:\t%u\n", | ||
1057 | dpcm->period_update_pending); | ||
1058 | snd_iprintf(buffer, " irq_pos:\t\t%u\n", dpcm->irq_pos); | ||
1059 | snd_iprintf(buffer, " period_frac:\t%u\n", dpcm->period_size_frac); | ||
1060 | snd_iprintf(buffer, " last_jiffies:\t%lu (%lu)\n", | ||
1061 | dpcm->last_jiffies, jiffies); | ||
1062 | snd_iprintf(buffer, " timer_expires:\t%lu\n", dpcm->timer.expires); | ||
1063 | } | ||
1064 | |||
1065 | static void print_substream_info(struct snd_info_buffer *buffer, | ||
1066 | struct loopback *loopback, | ||
1067 | int sub, | ||
1068 | int num) | ||
1069 | { | ||
1070 | struct loopback_cable *cable = loopback->cables[sub][num]; | ||
1071 | |||
1072 | snd_iprintf(buffer, "Cable %i substream %i:\n", num, sub); | ||
1073 | if (cable == NULL) { | ||
1074 | snd_iprintf(buffer, " inactive\n"); | ||
1075 | return; | ||
1076 | } | ||
1077 | snd_iprintf(buffer, " valid: %u\n", cable->valid); | ||
1078 | snd_iprintf(buffer, " running: %u\n", cable->running); | ||
1079 | snd_iprintf(buffer, " pause: %u\n", cable->pause); | ||
1080 | print_dpcm_info(buffer, cable->streams[0], "Playback"); | ||
1081 | print_dpcm_info(buffer, cable->streams[1], "Capture"); | ||
1082 | } | ||
1083 | |||
1084 | static void print_cable_info(struct snd_info_entry *entry, | ||
1085 | struct snd_info_buffer *buffer) | ||
1086 | { | ||
1087 | struct loopback *loopback = entry->private_data; | ||
1088 | int sub, num; | ||
1089 | |||
1090 | mutex_lock(&loopback->cable_lock); | ||
1091 | num = entry->name[strlen(entry->name)-1]; | ||
1092 | num = num == '0' ? 0 : 1; | ||
1093 | for (sub = 0; sub < MAX_PCM_SUBSTREAMS; sub++) | ||
1094 | print_substream_info(buffer, loopback, sub, num); | ||
1095 | mutex_unlock(&loopback->cable_lock); | ||
1096 | } | ||
1097 | |||
1098 | static int __devinit loopback_proc_new(struct loopback *loopback, int cidx) | ||
1099 | { | ||
1100 | char name[32]; | ||
1101 | struct snd_info_entry *entry; | ||
1102 | int err; | ||
1103 | |||
1104 | snprintf(name, sizeof(name), "cable#%d", cidx); | ||
1105 | err = snd_card_proc_new(loopback->card, name, &entry); | ||
1106 | if (err < 0) | ||
1107 | return err; | ||
1108 | |||
1109 | snd_info_set_text_ops(entry, loopback, print_cable_info); | ||
1110 | return 0; | ||
1111 | } | ||
1112 | |||
1113 | #else /* !CONFIG_PROC_FS */ | ||
1114 | |||
1115 | #define loopback_proc_new(loopback, cidx) do { } while (0) | ||
1116 | |||
1117 | #endif | ||
1118 | |||
1119 | static int __devinit loopback_probe(struct platform_device *devptr) | ||
1120 | { | ||
1121 | struct snd_card *card; | ||
1122 | struct loopback *loopback; | ||
1123 | int dev = devptr->id; | ||
1124 | int err; | ||
1125 | |||
1126 | err = snd_card_create(index[dev], id[dev], THIS_MODULE, | ||
1127 | sizeof(struct loopback), &card); | ||
1128 | if (err < 0) | ||
1129 | return err; | ||
1130 | loopback = card->private_data; | ||
1131 | |||
1132 | if (pcm_substreams[dev] < 1) | ||
1133 | pcm_substreams[dev] = 1; | ||
1134 | if (pcm_substreams[dev] > MAX_PCM_SUBSTREAMS) | ||
1135 | pcm_substreams[dev] = MAX_PCM_SUBSTREAMS; | ||
1136 | |||
1137 | loopback->card = card; | ||
1138 | mutex_init(&loopback->cable_lock); | ||
1139 | |||
1140 | err = loopback_pcm_new(loopback, 0, pcm_substreams[dev]); | ||
1141 | if (err < 0) | ||
1142 | goto __nodev; | ||
1143 | err = loopback_pcm_new(loopback, 1, pcm_substreams[dev]); | ||
1144 | if (err < 0) | ||
1145 | goto __nodev; | ||
1146 | err = loopback_mixer_new(loopback, pcm_notify[dev] ? 1 : 0); | ||
1147 | if (err < 0) | ||
1148 | goto __nodev; | ||
1149 | loopback_proc_new(loopback, 0); | ||
1150 | loopback_proc_new(loopback, 1); | ||
1151 | strcpy(card->driver, "Loopback"); | ||
1152 | strcpy(card->shortname, "Loopback"); | ||
1153 | sprintf(card->longname, "Loopback %i", dev + 1); | ||
1154 | err = snd_card_register(card); | ||
1155 | if (!err) { | ||
1156 | platform_set_drvdata(devptr, card); | ||
1157 | return 0; | ||
1158 | } | ||
1159 | __nodev: | ||
1160 | snd_card_free(card); | ||
1161 | return err; | ||
1162 | } | ||
1163 | |||
1164 | static int __devexit loopback_remove(struct platform_device *devptr) | ||
1165 | { | ||
1166 | snd_card_free(platform_get_drvdata(devptr)); | ||
1167 | platform_set_drvdata(devptr, NULL); | ||
1168 | return 0; | ||
1169 | } | ||
1170 | |||
1171 | #ifdef CONFIG_PM | ||
1172 | static int loopback_suspend(struct platform_device *pdev, | ||
1173 | pm_message_t state) | ||
1174 | { | ||
1175 | struct snd_card *card = platform_get_drvdata(pdev); | ||
1176 | struct loopback *loopback = card->private_data; | ||
1177 | |||
1178 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | ||
1179 | |||
1180 | snd_pcm_suspend_all(loopback->pcm[0]); | ||
1181 | snd_pcm_suspend_all(loopback->pcm[1]); | ||
1182 | return 0; | ||
1183 | } | ||
1184 | |||
1185 | static int loopback_resume(struct platform_device *pdev) | ||
1186 | { | ||
1187 | struct snd_card *card = platform_get_drvdata(pdev); | ||
1188 | |||
1189 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | ||
1190 | return 0; | ||
1191 | } | ||
1192 | #endif | ||
1193 | |||
1194 | #define SND_LOOPBACK_DRIVER "snd_aloop" | ||
1195 | |||
1196 | static struct platform_driver loopback_driver = { | ||
1197 | .probe = loopback_probe, | ||
1198 | .remove = __devexit_p(loopback_remove), | ||
1199 | #ifdef CONFIG_PM | ||
1200 | .suspend = loopback_suspend, | ||
1201 | .resume = loopback_resume, | ||
1202 | #endif | ||
1203 | .driver = { | ||
1204 | .name = SND_LOOPBACK_DRIVER | ||
1205 | }, | ||
1206 | }; | ||
1207 | |||
1208 | static void loopback_unregister_all(void) | ||
1209 | { | ||
1210 | int i; | ||
1211 | |||
1212 | for (i = 0; i < ARRAY_SIZE(devices); ++i) | ||
1213 | platform_device_unregister(devices[i]); | ||
1214 | platform_driver_unregister(&loopback_driver); | ||
1215 | } | ||
1216 | |||
1217 | static int __init alsa_card_loopback_init(void) | ||
1218 | { | ||
1219 | int i, err, cards; | ||
1220 | |||
1221 | err = platform_driver_register(&loopback_driver); | ||
1222 | if (err < 0) | ||
1223 | return err; | ||
1224 | |||
1225 | |||
1226 | cards = 0; | ||
1227 | for (i = 0; i < SNDRV_CARDS; i++) { | ||
1228 | struct platform_device *device; | ||
1229 | if (!enable[i]) | ||
1230 | continue; | ||
1231 | device = platform_device_register_simple(SND_LOOPBACK_DRIVER, | ||
1232 | i, NULL, 0); | ||
1233 | if (IS_ERR(device)) | ||
1234 | continue; | ||
1235 | if (!platform_get_drvdata(device)) { | ||
1236 | platform_device_unregister(device); | ||
1237 | continue; | ||
1238 | } | ||
1239 | devices[i] = device; | ||
1240 | cards++; | ||
1241 | } | ||
1242 | if (!cards) { | ||
1243 | #ifdef MODULE | ||
1244 | printk(KERN_ERR "aloop: No loopback enabled\n"); | ||
1245 | #endif | ||
1246 | loopback_unregister_all(); | ||
1247 | return -ENODEV; | ||
1248 | } | ||
1249 | return 0; | ||
1250 | } | ||
1251 | |||
1252 | static void __exit alsa_card_loopback_exit(void) | ||
1253 | { | ||
1254 | loopback_unregister_all(); | ||
1255 | } | ||
1256 | |||
1257 | module_init(alsa_card_loopback_init) | ||
1258 | module_exit(alsa_card_loopback_exit) | ||
diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c index 0e631c3221e3..f4cd49336f33 100644 --- a/sound/drivers/virmidi.c +++ b/sound/drivers/virmidi.c | |||
@@ -94,7 +94,7 @@ static int __devinit snd_virmidi_probe(struct platform_device *devptr) | |||
94 | sizeof(struct snd_card_virmidi), &card); | 94 | sizeof(struct snd_card_virmidi), &card); |
95 | if (err < 0) | 95 | if (err < 0) |
96 | return err; | 96 | return err; |
97 | vmidi = (struct snd_card_virmidi *)card->private_data; | 97 | vmidi = card->private_data; |
98 | vmidi->card = card; | 98 | vmidi->card = card; |
99 | 99 | ||
100 | if (midi_devs[dev] > MAX_MIDI_DEVICES) { | 100 | if (midi_devs[dev] > MAX_MIDI_DEVICES) { |
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c index 42d7844ecd0b..57ccba88700d 100644 --- a/sound/i2c/other/ak4xxx-adda.c +++ b/sound/i2c/other/ak4xxx-adda.c | |||
@@ -878,7 +878,7 @@ static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs) | |||
878 | static void proc_regs_read(struct snd_info_entry *entry, | 878 | static void proc_regs_read(struct snd_info_entry *entry, |
879 | struct snd_info_buffer *buffer) | 879 | struct snd_info_buffer *buffer) |
880 | { | 880 | { |
881 | struct snd_akm4xxx *ak = (struct snd_akm4xxx *)entry->private_data; | 881 | struct snd_akm4xxx *ak = entry->private_data; |
882 | int reg, val, chip; | 882 | int reg, val, chip; |
883 | for (chip = 0; chip < ak->num_chips; chip++) { | 883 | for (chip = 0; chip < ak->num_chips; chip++) { |
884 | for (reg = 0; reg < ak->total_regs; reg++) { | 884 | for (reg = 0; reg < ak->total_regs; reg++) { |
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index c6990c680796..52064cfa91f3 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig | |||
@@ -77,6 +77,32 @@ config SND_ALS100 | |||
77 | To compile this driver as a module, choose M here: the module | 77 | To compile this driver as a module, choose M here: the module |
78 | will be called snd-als100. | 78 | will be called snd-als100. |
79 | 79 | ||
80 | config SND_AZT1605 | ||
81 | tristate "Aztech AZT1605 Driver" | ||
82 | depends on SND | ||
83 | select SND_WSS_LIB | ||
84 | select SND_MPU401_UART | ||
85 | select SND_OPL3_LIB | ||
86 | help | ||
87 | Say Y here to include support for Aztech Sound Galaxy cards | ||
88 | based on the AZT1605 chipset. | ||
89 | |||
90 | To compile this driver as a module, choose M here: the module | ||
91 | will be called snd-azt1605. | ||
92 | |||
93 | config SND_AZT2316 | ||
94 | tristate "Aztech AZT2316 Driver" | ||
95 | depends on SND | ||
96 | select SND_WSS_LIB | ||
97 | select SND_MPU401_UART | ||
98 | select SND_OPL3_LIB | ||
99 | help | ||
100 | Say Y here to include support for Aztech Sound Galaxy cards | ||
101 | based on the AZT2316 chipset. | ||
102 | |||
103 | To compile this driver as a module, choose M here: the module | ||
104 | will be called snd-azt2316. | ||
105 | |||
80 | config SND_AZT2320 | 106 | config SND_AZT2320 |
81 | tristate "Aztech Systems AZT2320" | 107 | tristate "Aztech Systems AZT2320" |
82 | depends on PNP | 108 | depends on PNP |
@@ -351,16 +377,6 @@ config SND_SB16_CSP | |||
351 | coprocessor can do variable tasks like various compression and | 377 | coprocessor can do variable tasks like various compression and |
352 | decompression algorithms. | 378 | decompression algorithms. |
353 | 379 | ||
354 | config SND_SGALAXY | ||
355 | tristate "Aztech Sound Galaxy" | ||
356 | select SND_WSS_LIB | ||
357 | help | ||
358 | Say Y here to include support for Aztech Sound Galaxy | ||
359 | soundcards. | ||
360 | |||
361 | To compile this driver as a module, choose M here: the module | ||
362 | will be called snd-sgalaxy. | ||
363 | |||
364 | config SND_SSCAPE | 380 | config SND_SSCAPE |
365 | tristate "Ensoniq SoundScape driver" | 381 | tristate "Ensoniq SoundScape driver" |
366 | select SND_MPU401_UART | 382 | select SND_MPU401_UART |
diff --git a/sound/isa/Makefile b/sound/isa/Makefile index c73d30c4f462..8d781e419e2e 100644 --- a/sound/isa/Makefile +++ b/sound/isa/Makefile | |||
@@ -10,7 +10,6 @@ snd-cmi8330-objs := cmi8330.o | |||
10 | snd-es18xx-objs := es18xx.o | 10 | snd-es18xx-objs := es18xx.o |
11 | snd-opl3sa2-objs := opl3sa2.o | 11 | snd-opl3sa2-objs := opl3sa2.o |
12 | snd-sc6000-objs := sc6000.o | 12 | snd-sc6000-objs := sc6000.o |
13 | snd-sgalaxy-objs := sgalaxy.o | ||
14 | snd-sscape-objs := sscape.o | 13 | snd-sscape-objs := sscape.o |
15 | 14 | ||
16 | # Toplevel Module Dependency | 15 | # Toplevel Module Dependency |
@@ -21,8 +20,7 @@ obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o | |||
21 | obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o | 20 | obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o |
22 | obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o | 21 | obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o |
23 | obj-$(CONFIG_SND_SC6000) += snd-sc6000.o | 22 | obj-$(CONFIG_SND_SC6000) += snd-sc6000.o |
24 | obj-$(CONFIG_SND_SGALAXY) += snd-sgalaxy.o | ||
25 | obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o | 23 | obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o |
26 | 24 | ||
27 | obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ gus/ msnd/ opti9xx/ \ | 25 | obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ galaxy/ gus/ msnd/ opti9xx/ \ |
28 | sb/ wavefront/ wss/ | 26 | sb/ wavefront/ wss/ |
diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c index bbcbf92a8ebe..3cb75bc97699 100644 --- a/sound/isa/ad1816a/ad1816a.c +++ b/sound/isa/ad1816a/ad1816a.c | |||
@@ -162,7 +162,7 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard | |||
162 | sizeof(struct snd_card_ad1816a), &card); | 162 | sizeof(struct snd_card_ad1816a), &card); |
163 | if (error < 0) | 163 | if (error < 0) |
164 | return error; | 164 | return error; |
165 | acard = (struct snd_card_ad1816a *)card->private_data; | 165 | acard = card->private_data; |
166 | 166 | ||
167 | if ((error = snd_card_ad1816a_pnp(dev, acard, pcard, pid))) { | 167 | if ((error = snd_card_ad1816a_pnp(dev, acard, pcard, pid))) { |
168 | snd_card_free(card); | 168 | snd_card_free(card); |
diff --git a/sound/isa/azt2320.c b/sound/isa/azt2320.c index f7aa637b0d18..aac8dc15c2fe 100644 --- a/sound/isa/azt2320.c +++ b/sound/isa/azt2320.c | |||
@@ -188,7 +188,7 @@ static int __devinit snd_card_azt2320_probe(int dev, | |||
188 | sizeof(struct snd_card_azt2320), &card); | 188 | sizeof(struct snd_card_azt2320), &card); |
189 | if (error < 0) | 189 | if (error < 0) |
190 | return error; | 190 | return error; |
191 | acard = (struct snd_card_azt2320 *)card->private_data; | 191 | acard = card->private_data; |
192 | 192 | ||
193 | if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) { | 193 | if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) { |
194 | snd_card_free(card); | 194 | snd_card_free(card); |
diff --git a/sound/isa/galaxy/Makefile b/sound/isa/galaxy/Makefile new file mode 100644 index 000000000000..e307066d4315 --- /dev/null +++ b/sound/isa/galaxy/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | # | ||
2 | # Makefile for ALSA | ||
3 | # Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz> | ||
4 | # | ||
5 | |||
6 | snd-azt1605-objs := azt1605.o | ||
7 | snd-azt2316-objs := azt2316.o | ||
8 | |||
9 | obj-$(CONFIG_SND_AZT1605) += snd-azt1605.o | ||
10 | obj-$(CONFIG_SND_AZT2316) += snd-azt2316.o | ||
diff --git a/sound/isa/galaxy/azt1605.c b/sound/isa/galaxy/azt1605.c new file mode 100644 index 000000000000..9a97643cb713 --- /dev/null +++ b/sound/isa/galaxy/azt1605.c | |||
@@ -0,0 +1,91 @@ | |||
1 | /* | ||
2 | * Aztech AZT1605 Driver | ||
3 | * Copyright (C) 2007,2010 Rene Herman | ||
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, see <http://www.gnu.org/licenses/>. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #define AZT1605 | ||
21 | |||
22 | #define CRD_NAME "Aztech AZT1605" | ||
23 | #define DRV_NAME "AZT1605" | ||
24 | #define DEV_NAME "azt1605" | ||
25 | |||
26 | #define GALAXY_DSP_MAJOR 2 | ||
27 | #define GALAXY_DSP_MINOR 1 | ||
28 | |||
29 | #define GALAXY_CONFIG_SIZE 3 | ||
30 | |||
31 | /* | ||
32 | * 24-bit config register | ||
33 | */ | ||
34 | |||
35 | #define GALAXY_CONFIG_SBA_220 (0 << 0) | ||
36 | #define GALAXY_CONFIG_SBA_240 (1 << 0) | ||
37 | #define GALAXY_CONFIG_SBA_260 (2 << 0) | ||
38 | #define GALAXY_CONFIG_SBA_280 (3 << 0) | ||
39 | #define GALAXY_CONFIG_SBA_MASK GALAXY_CONFIG_SBA_280 | ||
40 | |||
41 | #define GALAXY_CONFIG_MPUA_300 (0 << 2) | ||
42 | #define GALAXY_CONFIG_MPUA_330 (1 << 2) | ||
43 | |||
44 | #define GALAXY_CONFIG_MPU_ENABLE (1 << 3) | ||
45 | |||
46 | #define GALAXY_CONFIG_GAME_ENABLE (1 << 4) | ||
47 | |||
48 | #define GALAXY_CONFIG_CD_PANASONIC (1 << 5) | ||
49 | #define GALAXY_CONFIG_CD_MITSUMI (1 << 6) | ||
50 | #define GALAXY_CONFIG_CD_MASK (\ | ||
51 | GALAXY_CONFIG_CD_PANASONIC | GALAXY_CONFIG_CD_MITSUMI) | ||
52 | |||
53 | #define GALAXY_CONFIG_UNUSED (1 << 7) | ||
54 | #define GALAXY_CONFIG_UNUSED_MASK GALAXY_CONFIG_UNUSED | ||
55 | |||
56 | #define GALAXY_CONFIG_SBIRQ_2 (1 << 8) | ||
57 | #define GALAXY_CONFIG_SBIRQ_3 (1 << 9) | ||
58 | #define GALAXY_CONFIG_SBIRQ_5 (1 << 10) | ||
59 | #define GALAXY_CONFIG_SBIRQ_7 (1 << 11) | ||
60 | |||
61 | #define GALAXY_CONFIG_MPUIRQ_2 (1 << 12) | ||
62 | #define GALAXY_CONFIG_MPUIRQ_3 (1 << 13) | ||
63 | #define GALAXY_CONFIG_MPUIRQ_5 (1 << 14) | ||
64 | #define GALAXY_CONFIG_MPUIRQ_7 (1 << 15) | ||
65 | |||
66 | #define GALAXY_CONFIG_WSSA_530 (0 << 16) | ||
67 | #define GALAXY_CONFIG_WSSA_604 (1 << 16) | ||
68 | #define GALAXY_CONFIG_WSSA_E80 (2 << 16) | ||
69 | #define GALAXY_CONFIG_WSSA_F40 (3 << 16) | ||
70 | |||
71 | #define GALAXY_CONFIG_WSS_ENABLE (1 << 18) | ||
72 | |||
73 | #define GALAXY_CONFIG_CDIRQ_11 (1 << 19) | ||
74 | #define GALAXY_CONFIG_CDIRQ_12 (1 << 20) | ||
75 | #define GALAXY_CONFIG_CDIRQ_15 (1 << 21) | ||
76 | #define GALAXY_CONFIG_CDIRQ_MASK (\ | ||
77 | GALAXY_CONFIG_CDIRQ_11 | GALAXY_CONFIG_CDIRQ_12 |\ | ||
78 | GALAXY_CONFIG_CDIRQ_15) | ||
79 | |||
80 | #define GALAXY_CONFIG_CDDMA_DISABLE (0 << 22) | ||
81 | #define GALAXY_CONFIG_CDDMA_0 (1 << 22) | ||
82 | #define GALAXY_CONFIG_CDDMA_1 (2 << 22) | ||
83 | #define GALAXY_CONFIG_CDDMA_3 (3 << 22) | ||
84 | #define GALAXY_CONFIG_CDDMA_MASK GALAXY_CONFIG_CDDMA_3 | ||
85 | |||
86 | #define GALAXY_CONFIG_MASK (\ | ||
87 | GALAXY_CONFIG_SBA_MASK | GALAXY_CONFIG_CD_MASK |\ | ||
88 | GALAXY_CONFIG_UNUSED_MASK | GALAXY_CONFIG_CDIRQ_MASK |\ | ||
89 | GALAXY_CONFIG_CDDMA_MASK) | ||
90 | |||
91 | #include "galaxy.c" | ||
diff --git a/sound/isa/galaxy/azt2316.c b/sound/isa/galaxy/azt2316.c new file mode 100644 index 000000000000..189441141df6 --- /dev/null +++ b/sound/isa/galaxy/azt2316.c | |||
@@ -0,0 +1,111 @@ | |||
1 | /* | ||
2 | * Aztech AZT2316 Driver | ||
3 | * Copyright (C) 2007,2010 Rene Herman | ||
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, see <http://www.gnu.org/licenses/>. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #define AZT2316 | ||
21 | |||
22 | #define CRD_NAME "Aztech AZT2316" | ||
23 | #define DRV_NAME "AZT2316" | ||
24 | #define DEV_NAME "azt2316" | ||
25 | |||
26 | #define GALAXY_DSP_MAJOR 3 | ||
27 | #define GALAXY_DSP_MINOR 1 | ||
28 | |||
29 | #define GALAXY_CONFIG_SIZE 4 | ||
30 | |||
31 | /* | ||
32 | * 32-bit config register | ||
33 | */ | ||
34 | |||
35 | #define GALAXY_CONFIG_SBA_220 (0 << 0) | ||
36 | #define GALAXY_CONFIG_SBA_240 (1 << 0) | ||
37 | #define GALAXY_CONFIG_SBA_260 (2 << 0) | ||
38 | #define GALAXY_CONFIG_SBA_280 (3 << 0) | ||
39 | #define GALAXY_CONFIG_SBA_MASK GALAXY_CONFIG_SBA_280 | ||
40 | |||
41 | #define GALAXY_CONFIG_SBIRQ_2 (1 << 2) | ||
42 | #define GALAXY_CONFIG_SBIRQ_5 (1 << 3) | ||
43 | #define GALAXY_CONFIG_SBIRQ_7 (1 << 4) | ||
44 | #define GALAXY_CONFIG_SBIRQ_10 (1 << 5) | ||
45 | |||
46 | #define GALAXY_CONFIG_SBDMA_DISABLE (0 << 6) | ||
47 | #define GALAXY_CONFIG_SBDMA_0 (1 << 6) | ||
48 | #define GALAXY_CONFIG_SBDMA_1 (2 << 6) | ||
49 | #define GALAXY_CONFIG_SBDMA_3 (3 << 6) | ||
50 | |||
51 | #define GALAXY_CONFIG_WSSA_530 (0 << 8) | ||
52 | #define GALAXY_CONFIG_WSSA_604 (1 << 8) | ||
53 | #define GALAXY_CONFIG_WSSA_E80 (2 << 8) | ||
54 | #define GALAXY_CONFIG_WSSA_F40 (3 << 8) | ||
55 | |||
56 | #define GALAXY_CONFIG_WSS_ENABLE (1 << 10) | ||
57 | |||
58 | #define GALAXY_CONFIG_GAME_ENABLE (1 << 11) | ||
59 | |||
60 | #define GALAXY_CONFIG_MPUA_300 (0 << 12) | ||
61 | #define GALAXY_CONFIG_MPUA_330 (1 << 12) | ||
62 | |||
63 | #define GALAXY_CONFIG_MPU_ENABLE (1 << 13) | ||
64 | |||
65 | #define GALAXY_CONFIG_CDA_310 (0 << 14) | ||
66 | #define GALAXY_CONFIG_CDA_320 (1 << 14) | ||
67 | #define GALAXY_CONFIG_CDA_340 (2 << 14) | ||
68 | #define GALAXY_CONFIG_CDA_350 (3 << 14) | ||
69 | #define GALAXY_CONFIG_CDA_MASK GALAXY_CONFIG_CDA_350 | ||
70 | |||
71 | #define GALAXY_CONFIG_CD_DISABLE (0 << 16) | ||
72 | #define GALAXY_CONFIG_CD_PANASONIC (1 << 16) | ||
73 | #define GALAXY_CONFIG_CD_SONY (2 << 16) | ||
74 | #define GALAXY_CONFIG_CD_MITSUMI (3 << 16) | ||
75 | #define GALAXY_CONFIG_CD_AZTECH (4 << 16) | ||
76 | #define GALAXY_CONFIG_CD_UNUSED_5 (5 << 16) | ||
77 | #define GALAXY_CONFIG_CD_UNUSED_6 (6 << 16) | ||
78 | #define GALAXY_CONFIG_CD_UNUSED_7 (7 << 16) | ||
79 | #define GALAXY_CONFIG_CD_MASK GALAXY_CONFIG_CD_UNUSED_7 | ||
80 | |||
81 | #define GALAXY_CONFIG_CDDMA8_DISABLE (0 << 20) | ||
82 | #define GALAXY_CONFIG_CDDMA8_0 (1 << 20) | ||
83 | #define GALAXY_CONFIG_CDDMA8_1 (2 << 20) | ||
84 | #define GALAXY_CONFIG_CDDMA8_3 (3 << 20) | ||
85 | #define GALAXY_CONFIG_CDDMA8_MASK GALAXY_CONFIG_CDDMA8_3 | ||
86 | |||
87 | #define GALAXY_CONFIG_CDDMA16_DISABLE (0 << 22) | ||
88 | #define GALAXY_CONFIG_CDDMA16_5 (1 << 22) | ||
89 | #define GALAXY_CONFIG_CDDMA16_6 (2 << 22) | ||
90 | #define GALAXY_CONFIG_CDDMA16_7 (3 << 22) | ||
91 | #define GALAXY_CONFIG_CDDMA16_MASK GALAXY_CONFIG_CDDMA16_7 | ||
92 | |||
93 | #define GALAXY_CONFIG_MPUIRQ_2 (1 << 24) | ||
94 | #define GALAXY_CONFIG_MPUIRQ_5 (1 << 25) | ||
95 | #define GALAXY_CONFIG_MPUIRQ_7 (1 << 26) | ||
96 | #define GALAXY_CONFIG_MPUIRQ_10 (1 << 27) | ||
97 | |||
98 | #define GALAXY_CONFIG_CDIRQ_5 (1 << 28) | ||
99 | #define GALAXY_CONFIG_CDIRQ_11 (1 << 29) | ||
100 | #define GALAXY_CONFIG_CDIRQ_12 (1 << 30) | ||
101 | #define GALAXY_CONFIG_CDIRQ_15 (1 << 31) | ||
102 | #define GALAXY_CONFIG_CDIRQ_MASK (\ | ||
103 | GALAXY_CONFIG_CDIRQ_5 | GALAXY_CONFIG_CDIRQ_11 |\ | ||
104 | GALAXY_CONFIG_CDIRQ_12 | GALAXY_CONFIG_CDIRQ_15) | ||
105 | |||
106 | #define GALAXY_CONFIG_MASK (\ | ||
107 | GALAXY_CONFIG_SBA_MASK | GALAXY_CONFIG_CDA_MASK |\ | ||
108 | GALAXY_CONFIG_CD_MASK | GALAXY_CONFIG_CDDMA16_MASK |\ | ||
109 | GALAXY_CONFIG_CDDMA8_MASK | GALAXY_CONFIG_CDIRQ_MASK) | ||
110 | |||
111 | #include "galaxy.c" | ||
diff --git a/sound/isa/galaxy/galaxy.c b/sound/isa/galaxy/galaxy.c new file mode 100644 index 000000000000..ee54df082b9c --- /dev/null +++ b/sound/isa/galaxy/galaxy.c | |||
@@ -0,0 +1,652 @@ | |||
1 | /* | ||
2 | * Aztech AZT1605/AZT2316 Driver | ||
3 | * Copyright (C) 2007,2010 Rene Herman | ||
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, see <http://www.gnu.org/licenses/>. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/isa.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/io.h> | ||
25 | #include <asm/processor.h> | ||
26 | #include <sound/core.h> | ||
27 | #include <sound/initval.h> | ||
28 | #include <sound/wss.h> | ||
29 | #include <sound/mpu401.h> | ||
30 | #include <sound/opl3.h> | ||
31 | |||
32 | MODULE_DESCRIPTION(CRD_NAME); | ||
33 | MODULE_AUTHOR("Rene Herman"); | ||
34 | MODULE_LICENSE("GPL"); | ||
35 | |||
36 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | ||
37 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | ||
38 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; | ||
39 | |||
40 | module_param_array(index, int, NULL, 0444); | ||
41 | MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard."); | ||
42 | module_param_array(id, charp, NULL, 0444); | ||
43 | MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard."); | ||
44 | module_param_array(enable, bool, NULL, 0444); | ||
45 | MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard."); | ||
46 | |||
47 | static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | ||
48 | static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | ||
49 | static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | ||
50 | static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | ||
51 | static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; | ||
52 | static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; | ||
53 | static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; | ||
54 | static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; | ||
55 | |||
56 | module_param_array(port, long, NULL, 0444); | ||
57 | MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver."); | ||
58 | module_param_array(wss_port, long, NULL, 0444); | ||
59 | MODULE_PARM_DESC(wss_port, "WSS port # for " CRD_NAME " driver."); | ||
60 | module_param_array(mpu_port, long, NULL, 0444); | ||
61 | MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver."); | ||
62 | module_param_array(fm_port, long, NULL, 0444); | ||
63 | MODULE_PARM_DESC(fm_port, "FM port # for " CRD_NAME " driver."); | ||
64 | module_param_array(irq, int, NULL, 0444); | ||
65 | MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver."); | ||
66 | module_param_array(mpu_irq, int, NULL, 0444); | ||
67 | MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver."); | ||
68 | module_param_array(dma1, int, NULL, 0444); | ||
69 | MODULE_PARM_DESC(dma1, "Playback DMA # for " CRD_NAME " driver."); | ||
70 | module_param_array(dma2, int, NULL, 0444); | ||
71 | MODULE_PARM_DESC(dma2, "Capture DMA # for " CRD_NAME " driver."); | ||
72 | |||
73 | /* | ||
74 | * Generic SB DSP support routines | ||
75 | */ | ||
76 | |||
77 | #define DSP_PORT_RESET 0x6 | ||
78 | #define DSP_PORT_READ 0xa | ||
79 | #define DSP_PORT_COMMAND 0xc | ||
80 | #define DSP_PORT_STATUS 0xc | ||
81 | #define DSP_PORT_DATA_AVAIL 0xe | ||
82 | |||
83 | #define DSP_SIGNATURE 0xaa | ||
84 | |||
85 | #define DSP_COMMAND_GET_VERSION 0xe1 | ||
86 | |||
87 | static int __devinit dsp_get_byte(void __iomem *port, u8 *val) | ||
88 | { | ||
89 | int loops = 1000; | ||
90 | |||
91 | while (!(ioread8(port + DSP_PORT_DATA_AVAIL) & 0x80)) { | ||
92 | if (!loops--) | ||
93 | return -EIO; | ||
94 | cpu_relax(); | ||
95 | } | ||
96 | *val = ioread8(port + DSP_PORT_READ); | ||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | static int __devinit dsp_reset(void __iomem *port) | ||
101 | { | ||
102 | u8 val; | ||
103 | |||
104 | iowrite8(1, port + DSP_PORT_RESET); | ||
105 | udelay(10); | ||
106 | iowrite8(0, port + DSP_PORT_RESET); | ||
107 | |||
108 | if (dsp_get_byte(port, &val) < 0 || val != DSP_SIGNATURE) | ||
109 | return -ENODEV; | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | static int __devinit dsp_command(void __iomem *port, u8 cmd) | ||
115 | { | ||
116 | int loops = 1000; | ||
117 | |||
118 | while (ioread8(port + DSP_PORT_STATUS) & 0x80) { | ||
119 | if (!loops--) | ||
120 | return -EIO; | ||
121 | cpu_relax(); | ||
122 | } | ||
123 | iowrite8(cmd, port + DSP_PORT_COMMAND); | ||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | static int __devinit dsp_get_version(void __iomem *port, u8 *major, u8 *minor) | ||
128 | { | ||
129 | int err; | ||
130 | |||
131 | err = dsp_command(port, DSP_COMMAND_GET_VERSION); | ||
132 | if (err < 0) | ||
133 | return err; | ||
134 | |||
135 | err = dsp_get_byte(port, major); | ||
136 | if (err < 0) | ||
137 | return err; | ||
138 | |||
139 | err = dsp_get_byte(port, minor); | ||
140 | if (err < 0) | ||
141 | return err; | ||
142 | |||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | /* | ||
147 | * Generic WSS support routines | ||
148 | */ | ||
149 | |||
150 | #define WSS_CONFIG_DMA_0 (1 << 0) | ||
151 | #define WSS_CONFIG_DMA_1 (2 << 0) | ||
152 | #define WSS_CONFIG_DMA_3 (3 << 0) | ||
153 | #define WSS_CONFIG_DUPLEX (1 << 2) | ||
154 | #define WSS_CONFIG_IRQ_7 (1 << 3) | ||
155 | #define WSS_CONFIG_IRQ_9 (2 << 3) | ||
156 | #define WSS_CONFIG_IRQ_10 (3 << 3) | ||
157 | #define WSS_CONFIG_IRQ_11 (4 << 3) | ||
158 | |||
159 | #define WSS_PORT_CONFIG 0 | ||
160 | #define WSS_PORT_SIGNATURE 3 | ||
161 | |||
162 | #define WSS_SIGNATURE 4 | ||
163 | |||
164 | static int __devinit wss_detect(void __iomem *wss_port) | ||
165 | { | ||
166 | if ((ioread8(wss_port + WSS_PORT_SIGNATURE) & 0x3f) != WSS_SIGNATURE) | ||
167 | return -ENODEV; | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static void wss_set_config(void __iomem *wss_port, u8 wss_config) | ||
173 | { | ||
174 | iowrite8(wss_config, wss_port + WSS_PORT_CONFIG); | ||
175 | } | ||
176 | |||
177 | /* | ||
178 | * Aztech Sound Galaxy specifics | ||
179 | */ | ||
180 | |||
181 | #define GALAXY_PORT_CONFIG 1024 | ||
182 | #define CONFIG_PORT_SET 4 | ||
183 | |||
184 | #define DSP_COMMAND_GALAXY_8 8 | ||
185 | #define GALAXY_COMMAND_GET_TYPE 5 | ||
186 | |||
187 | #define DSP_COMMAND_GALAXY_9 9 | ||
188 | #define GALAXY_COMMAND_WSSMODE 0 | ||
189 | #define GALAXY_COMMAND_SB8MODE 1 | ||
190 | |||
191 | #define GALAXY_MODE_WSS GALAXY_COMMAND_WSSMODE | ||
192 | #define GALAXY_MODE_SB8 GALAXY_COMMAND_SB8MODE | ||
193 | |||
194 | struct snd_galaxy { | ||
195 | void __iomem *port; | ||
196 | void __iomem *config_port; | ||
197 | void __iomem *wss_port; | ||
198 | u32 config; | ||
199 | struct resource *res_port; | ||
200 | struct resource *res_config_port; | ||
201 | struct resource *res_wss_port; | ||
202 | }; | ||
203 | |||
204 | static u32 config[SNDRV_CARDS]; | ||
205 | static u8 wss_config[SNDRV_CARDS]; | ||
206 | |||
207 | static int __devinit snd_galaxy_match(struct device *dev, unsigned int n) | ||
208 | { | ||
209 | if (!enable[n]) | ||
210 | return 0; | ||
211 | |||
212 | switch (port[n]) { | ||
213 | case SNDRV_AUTO_PORT: | ||
214 | dev_err(dev, "please specify port\n"); | ||
215 | return 0; | ||
216 | case 0x220: | ||
217 | config[n] |= GALAXY_CONFIG_SBA_220; | ||
218 | break; | ||
219 | case 0x240: | ||
220 | config[n] |= GALAXY_CONFIG_SBA_240; | ||
221 | break; | ||
222 | case 0x260: | ||
223 | config[n] |= GALAXY_CONFIG_SBA_260; | ||
224 | break; | ||
225 | case 0x280: | ||
226 | config[n] |= GALAXY_CONFIG_SBA_280; | ||
227 | break; | ||
228 | default: | ||
229 | dev_err(dev, "invalid port %#lx\n", port[n]); | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | switch (wss_port[n]) { | ||
234 | case SNDRV_AUTO_PORT: | ||
235 | dev_err(dev, "please specify wss_port\n"); | ||
236 | return 0; | ||
237 | case 0x530: | ||
238 | config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_530; | ||
239 | break; | ||
240 | case 0x604: | ||
241 | config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_604; | ||
242 | break; | ||
243 | case 0xe80: | ||
244 | config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_E80; | ||
245 | break; | ||
246 | case 0xf40: | ||
247 | config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_F40; | ||
248 | break; | ||
249 | default: | ||
250 | dev_err(dev, "invalid WSS port %#lx\n", wss_port[n]); | ||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | switch (irq[n]) { | ||
255 | case SNDRV_AUTO_IRQ: | ||
256 | dev_err(dev, "please specify irq\n"); | ||
257 | return 0; | ||
258 | case 7: | ||
259 | wss_config[n] |= WSS_CONFIG_IRQ_7; | ||
260 | break; | ||
261 | case 2: | ||
262 | irq[n] = 9; | ||
263 | case 9: | ||
264 | wss_config[n] |= WSS_CONFIG_IRQ_9; | ||
265 | break; | ||
266 | case 10: | ||
267 | wss_config[n] |= WSS_CONFIG_IRQ_10; | ||
268 | break; | ||
269 | case 11: | ||
270 | wss_config[n] |= WSS_CONFIG_IRQ_11; | ||
271 | break; | ||
272 | default: | ||
273 | dev_err(dev, "invalid IRQ %d\n", irq[n]); | ||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | switch (dma1[n]) { | ||
278 | case SNDRV_AUTO_DMA: | ||
279 | dev_err(dev, "please specify dma1\n"); | ||
280 | return 0; | ||
281 | case 0: | ||
282 | wss_config[n] |= WSS_CONFIG_DMA_0; | ||
283 | break; | ||
284 | case 1: | ||
285 | wss_config[n] |= WSS_CONFIG_DMA_1; | ||
286 | break; | ||
287 | case 3: | ||
288 | wss_config[n] |= WSS_CONFIG_DMA_3; | ||
289 | break; | ||
290 | default: | ||
291 | dev_err(dev, "invalid playback DMA %d\n", dma1[n]); | ||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | if (dma2[n] == SNDRV_AUTO_DMA || dma2[n] == dma1[n]) { | ||
296 | dma2[n] = -1; | ||
297 | goto mpu; | ||
298 | } | ||
299 | |||
300 | wss_config[n] |= WSS_CONFIG_DUPLEX; | ||
301 | switch (dma2[n]) { | ||
302 | case 0: | ||
303 | break; | ||
304 | case 1: | ||
305 | if (dma1[n] == 0) | ||
306 | break; | ||
307 | default: | ||
308 | dev_err(dev, "invalid capture DMA %d\n", dma2[n]); | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | mpu: | ||
313 | switch (mpu_port[n]) { | ||
314 | case SNDRV_AUTO_PORT: | ||
315 | dev_warn(dev, "mpu_port not specified; not using MPU-401\n"); | ||
316 | mpu_port[n] = -1; | ||
317 | goto fm; | ||
318 | case 0x300: | ||
319 | config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_300; | ||
320 | break; | ||
321 | case 0x330: | ||
322 | config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_330; | ||
323 | break; | ||
324 | default: | ||
325 | dev_err(dev, "invalid MPU port %#lx\n", mpu_port[n]); | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | switch (mpu_irq[n]) { | ||
330 | case SNDRV_AUTO_IRQ: | ||
331 | dev_warn(dev, "mpu_irq not specified: using polling mode\n"); | ||
332 | mpu_irq[n] = -1; | ||
333 | break; | ||
334 | case 2: | ||
335 | mpu_irq[n] = 9; | ||
336 | case 9: | ||
337 | config[n] |= GALAXY_CONFIG_MPUIRQ_2; | ||
338 | break; | ||
339 | #ifdef AZT1605 | ||
340 | case 3: | ||
341 | config[n] |= GALAXY_CONFIG_MPUIRQ_3; | ||
342 | break; | ||
343 | #endif | ||
344 | case 5: | ||
345 | config[n] |= GALAXY_CONFIG_MPUIRQ_5; | ||
346 | break; | ||
347 | case 7: | ||
348 | config[n] |= GALAXY_CONFIG_MPUIRQ_7; | ||
349 | break; | ||
350 | #ifdef AZT2316 | ||
351 | case 10: | ||
352 | config[n] |= GALAXY_CONFIG_MPUIRQ_10; | ||
353 | break; | ||
354 | #endif | ||
355 | default: | ||
356 | dev_err(dev, "invalid MPU IRQ %d\n", mpu_irq[n]); | ||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | if (mpu_irq[n] == irq[n]) { | ||
361 | dev_err(dev, "cannot share IRQ between WSS and MPU-401\n"); | ||
362 | return 0; | ||
363 | } | ||
364 | |||
365 | fm: | ||
366 | switch (fm_port[n]) { | ||
367 | case SNDRV_AUTO_PORT: | ||
368 | dev_warn(dev, "fm_port not specified: not using OPL3\n"); | ||
369 | fm_port[n] = -1; | ||
370 | break; | ||
371 | case 0x388: | ||
372 | break; | ||
373 | default: | ||
374 | dev_err(dev, "illegal FM port %#lx\n", fm_port[n]); | ||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | config[n] |= GALAXY_CONFIG_GAME_ENABLE; | ||
379 | return 1; | ||
380 | } | ||
381 | |||
382 | static int __devinit galaxy_init(struct snd_galaxy *galaxy, u8 *type) | ||
383 | { | ||
384 | u8 major; | ||
385 | u8 minor; | ||
386 | int err; | ||
387 | |||
388 | err = dsp_reset(galaxy->port); | ||
389 | if (err < 0) | ||
390 | return err; | ||
391 | |||
392 | err = dsp_get_version(galaxy->port, &major, &minor); | ||
393 | if (err < 0) | ||
394 | return err; | ||
395 | |||
396 | if (major != GALAXY_DSP_MAJOR || minor != GALAXY_DSP_MINOR) | ||
397 | return -ENODEV; | ||
398 | |||
399 | err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_8); | ||
400 | if (err < 0) | ||
401 | return err; | ||
402 | |||
403 | err = dsp_command(galaxy->port, GALAXY_COMMAND_GET_TYPE); | ||
404 | if (err < 0) | ||
405 | return err; | ||
406 | |||
407 | err = dsp_get_byte(galaxy->port, type); | ||
408 | if (err < 0) | ||
409 | return err; | ||
410 | |||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | static int __devinit galaxy_set_mode(struct snd_galaxy *galaxy, u8 mode) | ||
415 | { | ||
416 | int err; | ||
417 | |||
418 | err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_9); | ||
419 | if (err < 0) | ||
420 | return err; | ||
421 | |||
422 | err = dsp_command(galaxy->port, mode); | ||
423 | if (err < 0) | ||
424 | return err; | ||
425 | |||
426 | #ifdef AZT1605 | ||
427 | /* | ||
428 | * Needed for MPU IRQ on AZT1605, but AZT2316 loses WSS again | ||
429 | */ | ||
430 | err = dsp_reset(galaxy->port); | ||
431 | if (err < 0) | ||
432 | return err; | ||
433 | #endif | ||
434 | |||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | static void galaxy_set_config(struct snd_galaxy *galaxy, u32 config) | ||
439 | { | ||
440 | u8 tmp = ioread8(galaxy->config_port + CONFIG_PORT_SET); | ||
441 | int i; | ||
442 | |||
443 | iowrite8(tmp | 0x80, galaxy->config_port + CONFIG_PORT_SET); | ||
444 | for (i = 0; i < GALAXY_CONFIG_SIZE; i++) { | ||
445 | iowrite8(config, galaxy->config_port + i); | ||
446 | config >>= 8; | ||
447 | } | ||
448 | iowrite8(tmp & 0x7f, galaxy->config_port + CONFIG_PORT_SET); | ||
449 | msleep(10); | ||
450 | } | ||
451 | |||
452 | static void __devinit galaxy_config(struct snd_galaxy *galaxy, u32 config) | ||
453 | { | ||
454 | int i; | ||
455 | |||
456 | for (i = GALAXY_CONFIG_SIZE; i; i--) { | ||
457 | u8 tmp = ioread8(galaxy->config_port + i - 1); | ||
458 | galaxy->config = (galaxy->config << 8) | tmp; | ||
459 | } | ||
460 | config |= galaxy->config & GALAXY_CONFIG_MASK; | ||
461 | galaxy_set_config(galaxy, config); | ||
462 | } | ||
463 | |||
464 | static int __devinit galaxy_wss_config(struct snd_galaxy *galaxy, u8 wss_config) | ||
465 | { | ||
466 | int err; | ||
467 | |||
468 | err = wss_detect(galaxy->wss_port); | ||
469 | if (err < 0) | ||
470 | return err; | ||
471 | |||
472 | wss_set_config(galaxy->wss_port, wss_config); | ||
473 | |||
474 | err = galaxy_set_mode(galaxy, GALAXY_MODE_WSS); | ||
475 | if (err < 0) | ||
476 | return err; | ||
477 | |||
478 | return 0; | ||
479 | } | ||
480 | |||
481 | static void snd_galaxy_free(struct snd_card *card) | ||
482 | { | ||
483 | struct snd_galaxy *galaxy = card->private_data; | ||
484 | |||
485 | if (galaxy->wss_port) { | ||
486 | wss_set_config(galaxy->wss_port, 0); | ||
487 | ioport_unmap(galaxy->wss_port); | ||
488 | release_and_free_resource(galaxy->res_wss_port); | ||
489 | } | ||
490 | if (galaxy->config_port) { | ||
491 | galaxy_set_config(galaxy, galaxy->config); | ||
492 | ioport_unmap(galaxy->config_port); | ||
493 | release_and_free_resource(galaxy->res_config_port); | ||
494 | } | ||
495 | if (galaxy->port) { | ||
496 | ioport_unmap(galaxy->port); | ||
497 | release_and_free_resource(galaxy->res_port); | ||
498 | } | ||
499 | } | ||
500 | |||
501 | static int __devinit snd_galaxy_probe(struct device *dev, unsigned int n) | ||
502 | { | ||
503 | struct snd_galaxy *galaxy; | ||
504 | struct snd_wss *chip; | ||
505 | struct snd_card *card; | ||
506 | u8 type; | ||
507 | int err; | ||
508 | |||
509 | err = snd_card_create(index[n], id[n], THIS_MODULE, sizeof *galaxy, | ||
510 | &card); | ||
511 | if (err < 0) | ||
512 | return err; | ||
513 | |||
514 | snd_card_set_dev(card, dev); | ||
515 | |||
516 | card->private_free = snd_galaxy_free; | ||
517 | galaxy = card->private_data; | ||
518 | |||
519 | galaxy->res_port = request_region(port[n], 16, DRV_NAME); | ||
520 | if (!galaxy->res_port) { | ||
521 | dev_err(dev, "could not grab ports %#lx-%#lx\n", port[n], | ||
522 | port[n] + 15); | ||
523 | err = -EBUSY; | ||
524 | goto error; | ||
525 | } | ||
526 | galaxy->port = ioport_map(port[n], 16); | ||
527 | |||
528 | err = galaxy_init(galaxy, &type); | ||
529 | if (err < 0) { | ||
530 | dev_err(dev, "did not find a Sound Galaxy at %#lx\n", port[n]); | ||
531 | goto error; | ||
532 | } | ||
533 | dev_info(dev, "Sound Galaxy (type %d) found at %#lx\n", type, port[n]); | ||
534 | |||
535 | galaxy->res_config_port = request_region(port[n] + GALAXY_PORT_CONFIG, | ||
536 | 16, DRV_NAME); | ||
537 | if (!galaxy->res_config_port) { | ||
538 | dev_err(dev, "could not grab ports %#lx-%#lx\n", | ||
539 | port[n] + GALAXY_PORT_CONFIG, | ||
540 | port[n] + GALAXY_PORT_CONFIG + 15); | ||
541 | err = -EBUSY; | ||
542 | goto error; | ||
543 | } | ||
544 | galaxy->config_port = ioport_map(port[n] + GALAXY_PORT_CONFIG, 16); | ||
545 | |||
546 | galaxy_config(galaxy, config[n]); | ||
547 | |||
548 | galaxy->res_wss_port = request_region(wss_port[n], 4, DRV_NAME); | ||
549 | if (!galaxy->res_wss_port) { | ||
550 | dev_err(dev, "could not grab ports %#lx-%#lx\n", wss_port[n], | ||
551 | wss_port[n] + 3); | ||
552 | err = -EBUSY; | ||
553 | goto error; | ||
554 | } | ||
555 | galaxy->wss_port = ioport_map(wss_port[n], 4); | ||
556 | |||
557 | err = galaxy_wss_config(galaxy, wss_config[n]); | ||
558 | if (err < 0) { | ||
559 | dev_err(dev, "could not configure WSS\n"); | ||
560 | goto error; | ||
561 | } | ||
562 | |||
563 | strcpy(card->driver, DRV_NAME); | ||
564 | strcpy(card->shortname, DRV_NAME); | ||
565 | sprintf(card->longname, "%s at %#lx/%#lx, irq %d, dma %d/%d", | ||
566 | card->shortname, port[n], wss_port[n], irq[n], dma1[n], | ||
567 | dma2[n]); | ||
568 | |||
569 | err = snd_wss_create(card, wss_port[n] + 4, -1, irq[n], dma1[n], | ||
570 | dma2[n], WSS_HW_DETECT, 0, &chip); | ||
571 | if (err < 0) | ||
572 | goto error; | ||
573 | |||
574 | err = snd_wss_pcm(chip, 0, NULL); | ||
575 | if (err < 0) | ||
576 | goto error; | ||
577 | |||
578 | err = snd_wss_mixer(chip); | ||
579 | if (err < 0) | ||
580 | goto error; | ||
581 | |||
582 | err = snd_wss_timer(chip, 0, NULL); | ||
583 | if (err < 0) | ||
584 | goto error; | ||
585 | |||
586 | if (mpu_port[n] >= 0) { | ||
587 | err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, | ||
588 | mpu_port[n], 0, mpu_irq[n], | ||
589 | IRQF_DISABLED, NULL); | ||
590 | if (err < 0) | ||
591 | goto error; | ||
592 | } | ||
593 | |||
594 | if (fm_port[n] >= 0) { | ||
595 | struct snd_opl3 *opl3; | ||
596 | |||
597 | err = snd_opl3_create(card, fm_port[n], fm_port[n] + 2, | ||
598 | OPL3_HW_AUTO, 0, &opl3); | ||
599 | if (err < 0) { | ||
600 | dev_err(dev, "no OPL device at %#lx\n", fm_port[n]); | ||
601 | goto error; | ||
602 | } | ||
603 | err = snd_opl3_timer_new(opl3, 1, 2); | ||
604 | if (err < 0) | ||
605 | goto error; | ||
606 | |||
607 | err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); | ||
608 | if (err < 0) | ||
609 | goto error; | ||
610 | } | ||
611 | |||
612 | err = snd_card_register(card); | ||
613 | if (err < 0) | ||
614 | goto error; | ||
615 | |||
616 | dev_set_drvdata(dev, card); | ||
617 | return 0; | ||
618 | |||
619 | error: | ||
620 | snd_card_free(card); | ||
621 | return err; | ||
622 | } | ||
623 | |||
624 | static int __devexit snd_galaxy_remove(struct device *dev, unsigned int n) | ||
625 | { | ||
626 | snd_card_free(dev_get_drvdata(dev)); | ||
627 | dev_set_drvdata(dev, NULL); | ||
628 | return 0; | ||
629 | } | ||
630 | |||
631 | static struct isa_driver snd_galaxy_driver = { | ||
632 | .match = snd_galaxy_match, | ||
633 | .probe = snd_galaxy_probe, | ||
634 | .remove = __devexit_p(snd_galaxy_remove), | ||
635 | |||
636 | .driver = { | ||
637 | .name = DEV_NAME | ||
638 | } | ||
639 | }; | ||
640 | |||
641 | static int __init alsa_card_galaxy_init(void) | ||
642 | { | ||
643 | return isa_register_driver(&snd_galaxy_driver, SNDRV_CARDS); | ||
644 | } | ||
645 | |||
646 | static void __exit alsa_card_galaxy_exit(void) | ||
647 | { | ||
648 | isa_unregister_driver(&snd_galaxy_driver); | ||
649 | } | ||
650 | |||
651 | module_init(alsa_card_galaxy_init); | ||
652 | module_exit(alsa_card_galaxy_exit); | ||
diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c index f26eac8d8110..3e4a58b72913 100644 --- a/sound/isa/gus/gusmax.c +++ b/sound/isa/gus/gusmax.c | |||
@@ -191,7 +191,7 @@ static int __devinit snd_gusmax_mixer(struct snd_wss *chip) | |||
191 | 191 | ||
192 | static void snd_gusmax_free(struct snd_card *card) | 192 | static void snd_gusmax_free(struct snd_card *card) |
193 | { | 193 | { |
194 | struct snd_gusmax *maxcard = (struct snd_gusmax *)card->private_data; | 194 | struct snd_gusmax *maxcard = card->private_data; |
195 | 195 | ||
196 | if (maxcard == NULL) | 196 | if (maxcard == NULL) |
197 | return; | 197 | return; |
@@ -219,7 +219,7 @@ static int __devinit snd_gusmax_probe(struct device *pdev, unsigned int dev) | |||
219 | if (err < 0) | 219 | if (err < 0) |
220 | return err; | 220 | return err; |
221 | card->private_free = snd_gusmax_free; | 221 | card->private_free = snd_gusmax_free; |
222 | maxcard = (struct snd_gusmax *)card->private_data; | 222 | maxcard = card->private_data; |
223 | maxcard->card = card; | 223 | maxcard->card = card; |
224 | maxcard->irq = -1; | 224 | maxcard->irq = -1; |
225 | 225 | ||
diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c index 81284a8fa0ce..2259e3f726a7 100644 --- a/sound/isa/sb/sb8.c +++ b/sound/isa/sb/sb8.c | |||
@@ -72,7 +72,7 @@ static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id) | |||
72 | 72 | ||
73 | static void snd_sb8_free(struct snd_card *card) | 73 | static void snd_sb8_free(struct snd_card *card) |
74 | { | 74 | { |
75 | struct snd_sb8 *acard = (struct snd_sb8 *)card->private_data; | 75 | struct snd_sb8 *acard = card->private_data; |
76 | 76 | ||
77 | if (acard == NULL) | 77 | if (acard == NULL) |
78 | return; | 78 | return; |
diff --git a/sound/isa/sgalaxy.c b/sound/isa/sgalaxy.c deleted file mode 100644 index 6fe27b9d9440..000000000000 --- a/sound/isa/sgalaxy.c +++ /dev/null | |||
@@ -1,369 +0,0 @@ | |||
1 | /* | ||
2 | * Driver for Aztech Sound Galaxy cards | ||
3 | * Copyright (c) by Christopher Butler <chrisb@sandy.force9.co.uk. | ||
4 | * | ||
5 | * I don't have documentation for this card, I based this driver on the | ||
6 | * driver for OSS/Free included in the kernel source (drivers/sound/sgalaxy.c) | ||
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 | #include <linux/init.h> | ||
25 | #include <linux/err.h> | ||
26 | #include <linux/isa.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <linux/time.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/moduleparam.h> | ||
31 | #include <asm/dma.h> | ||
32 | #include <sound/core.h> | ||
33 | #include <sound/sb.h> | ||
34 | #include <sound/wss.h> | ||
35 | #include <sound/control.h> | ||
36 | #define SNDRV_LEGACY_FIND_FREE_IRQ | ||
37 | #define SNDRV_LEGACY_FIND_FREE_DMA | ||
38 | #include <sound/initval.h> | ||
39 | |||
40 | MODULE_AUTHOR("Christopher Butler <chrisb@sandy.force9.co.uk>"); | ||
41 | MODULE_DESCRIPTION("Aztech Sound Galaxy"); | ||
42 | MODULE_LICENSE("GPL"); | ||
43 | MODULE_SUPPORTED_DEVICE("{{Aztech Systems,Sound Galaxy}}"); | ||
44 | |||
45 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | ||
46 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | ||
47 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ | ||
48 | static long sbport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240 */ | ||
49 | static long wssport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x530,0xe80,0xf40,0x604 */ | ||
50 | static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 7,9,10,11 */ | ||
51 | static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3 */ | ||
52 | |||
53 | module_param_array(index, int, NULL, 0444); | ||
54 | MODULE_PARM_DESC(index, "Index value for Sound Galaxy soundcard."); | ||
55 | module_param_array(id, charp, NULL, 0444); | ||
56 | MODULE_PARM_DESC(id, "ID string for Sound Galaxy soundcard."); | ||
57 | module_param_array(sbport, long, NULL, 0444); | ||
58 | MODULE_PARM_DESC(sbport, "Port # for Sound Galaxy SB driver."); | ||
59 | module_param_array(wssport, long, NULL, 0444); | ||
60 | MODULE_PARM_DESC(wssport, "Port # for Sound Galaxy WSS driver."); | ||
61 | module_param_array(irq, int, NULL, 0444); | ||
62 | MODULE_PARM_DESC(irq, "IRQ # for Sound Galaxy driver."); | ||
63 | module_param_array(dma1, int, NULL, 0444); | ||
64 | MODULE_PARM_DESC(dma1, "DMA1 # for Sound Galaxy driver."); | ||
65 | |||
66 | #define SGALAXY_AUXC_LEFT 18 | ||
67 | #define SGALAXY_AUXC_RIGHT 19 | ||
68 | |||
69 | #define PFX "sgalaxy: " | ||
70 | |||
71 | /* | ||
72 | |||
73 | */ | ||
74 | |||
75 | #define AD1848P1( port, x ) ( port + c_d_c_AD1848##x ) | ||
76 | |||
77 | /* from lowlevel/sb/sb.c - to avoid having to allocate a struct snd_sb for the */ | ||
78 | /* short time we actually need it.. */ | ||
79 | |||
80 | static int snd_sgalaxy_sbdsp_reset(unsigned long port) | ||
81 | { | ||
82 | int i; | ||
83 | |||
84 | outb(1, SBP1(port, RESET)); | ||
85 | udelay(10); | ||
86 | outb(0, SBP1(port, RESET)); | ||
87 | udelay(30); | ||
88 | for (i = 0; i < 1000 && !(inb(SBP1(port, DATA_AVAIL)) & 0x80); i++); | ||
89 | if (inb(SBP1(port, READ)) != 0xaa) { | ||
90 | snd_printd("sb_reset: failed at 0x%lx!!!\n", port); | ||
91 | return -ENODEV; | ||
92 | } | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static int __devinit snd_sgalaxy_sbdsp_command(unsigned long port, | ||
97 | unsigned char val) | ||
98 | { | ||
99 | int i; | ||
100 | |||
101 | for (i = 10000; i; i--) | ||
102 | if ((inb(SBP1(port, STATUS)) & 0x80) == 0) { | ||
103 | outb(val, SBP1(port, COMMAND)); | ||
104 | return 1; | ||
105 | } | ||
106 | |||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static irqreturn_t snd_sgalaxy_dummy_interrupt(int irq, void *dev_id) | ||
111 | { | ||
112 | return IRQ_NONE; | ||
113 | } | ||
114 | |||
115 | static int __devinit snd_sgalaxy_setup_wss(unsigned long port, int irq, int dma) | ||
116 | { | ||
117 | static int interrupt_bits[] = {-1, -1, -1, -1, -1, -1, -1, 0x08, -1, | ||
118 | 0x10, 0x18, 0x20, -1, -1, -1, -1}; | ||
119 | static int dma_bits[] = {1, 2, 0, 3}; | ||
120 | int tmp, tmp1; | ||
121 | |||
122 | if ((tmp = inb(port + 3)) == 0xff) | ||
123 | { | ||
124 | snd_printdd("I/O address dead (0x%lx)\n", port); | ||
125 | return 0; | ||
126 | } | ||
127 | #if 0 | ||
128 | snd_printdd("WSS signature = 0x%x\n", tmp); | ||
129 | #endif | ||
130 | |||
131 | if ((tmp & 0x3f) != 0x04 && | ||
132 | (tmp & 0x3f) != 0x0f && | ||
133 | (tmp & 0x3f) != 0x00) { | ||
134 | snd_printdd("No WSS signature detected on port 0x%lx\n", | ||
135 | port + 3); | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | #if 0 | ||
140 | snd_printdd(PFX "setting up IRQ/DMA for WSS\n"); | ||
141 | #endif | ||
142 | |||
143 | /* initialize IRQ for WSS codec */ | ||
144 | tmp = interrupt_bits[irq % 16]; | ||
145 | if (tmp < 0) | ||
146 | return -EINVAL; | ||
147 | |||
148 | if (request_irq(irq, snd_sgalaxy_dummy_interrupt, IRQF_DISABLED, "sgalaxy", NULL)) { | ||
149 | snd_printk(KERN_ERR "sgalaxy: can't grab irq %d\n", irq); | ||
150 | return -EIO; | ||
151 | } | ||
152 | |||
153 | outb(tmp | 0x40, port); | ||
154 | tmp1 = dma_bits[dma % 4]; | ||
155 | outb(tmp | tmp1, port); | ||
156 | |||
157 | free_irq(irq, NULL); | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | static int __devinit snd_sgalaxy_detect(int dev, int irq, int dma) | ||
163 | { | ||
164 | #if 0 | ||
165 | snd_printdd(PFX "switching to WSS mode\n"); | ||
166 | #endif | ||
167 | |||
168 | /* switch to WSS mode */ | ||
169 | snd_sgalaxy_sbdsp_reset(sbport[dev]); | ||
170 | |||
171 | snd_sgalaxy_sbdsp_command(sbport[dev], 9); | ||
172 | snd_sgalaxy_sbdsp_command(sbport[dev], 0); | ||
173 | |||
174 | udelay(400); | ||
175 | return snd_sgalaxy_setup_wss(wssport[dev], irq, dma); | ||
176 | } | ||
177 | |||
178 | static struct snd_kcontrol_new snd_sgalaxy_controls[] = { | ||
179 | WSS_DOUBLE("Aux Playback Switch", 0, | ||
180 | SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 7, 7, 1, 1), | ||
181 | WSS_DOUBLE("Aux Playback Volume", 0, | ||
182 | SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 0, 0, 31, 0) | ||
183 | }; | ||
184 | |||
185 | static int __devinit snd_sgalaxy_mixer(struct snd_wss *chip) | ||
186 | { | ||
187 | struct snd_card *card = chip->card; | ||
188 | struct snd_ctl_elem_id id1, id2; | ||
189 | unsigned int idx; | ||
190 | int err; | ||
191 | |||
192 | memset(&id1, 0, sizeof(id1)); | ||
193 | memset(&id2, 0, sizeof(id2)); | ||
194 | id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
195 | /* reassign AUX0 to LINE */ | ||
196 | strcpy(id1.name, "Aux Playback Switch"); | ||
197 | strcpy(id2.name, "Line Playback Switch"); | ||
198 | if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) | ||
199 | return err; | ||
200 | strcpy(id1.name, "Aux Playback Volume"); | ||
201 | strcpy(id2.name, "Line Playback Volume"); | ||
202 | if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) | ||
203 | return err; | ||
204 | /* reassign AUX1 to FM */ | ||
205 | strcpy(id1.name, "Aux Playback Switch"); id1.index = 1; | ||
206 | strcpy(id2.name, "FM Playback Switch"); | ||
207 | if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) | ||
208 | return err; | ||
209 | strcpy(id1.name, "Aux Playback Volume"); | ||
210 | strcpy(id2.name, "FM Playback Volume"); | ||
211 | if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) | ||
212 | return err; | ||
213 | /* build AUX2 input */ | ||
214 | for (idx = 0; idx < ARRAY_SIZE(snd_sgalaxy_controls); idx++) { | ||
215 | err = snd_ctl_add(card, | ||
216 | snd_ctl_new1(&snd_sgalaxy_controls[idx], chip)); | ||
217 | if (err < 0) | ||
218 | return err; | ||
219 | } | ||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | static int __devinit snd_sgalaxy_match(struct device *devptr, unsigned int dev) | ||
224 | { | ||
225 | if (!enable[dev]) | ||
226 | return 0; | ||
227 | if (sbport[dev] == SNDRV_AUTO_PORT) { | ||
228 | snd_printk(KERN_ERR PFX "specify SB port\n"); | ||
229 | return 0; | ||
230 | } | ||
231 | if (wssport[dev] == SNDRV_AUTO_PORT) { | ||
232 | snd_printk(KERN_ERR PFX "specify WSS port\n"); | ||
233 | return 0; | ||
234 | } | ||
235 | return 1; | ||
236 | } | ||
237 | |||
238 | static int __devinit snd_sgalaxy_probe(struct device *devptr, unsigned int dev) | ||
239 | { | ||
240 | static int possible_irqs[] = {7, 9, 10, 11, -1}; | ||
241 | static int possible_dmas[] = {1, 3, 0, -1}; | ||
242 | int err, xirq, xdma1; | ||
243 | struct snd_card *card; | ||
244 | struct snd_wss *chip; | ||
245 | |||
246 | err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); | ||
247 | if (err < 0) | ||
248 | return err; | ||
249 | |||
250 | xirq = irq[dev]; | ||
251 | if (xirq == SNDRV_AUTO_IRQ) { | ||
252 | if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) { | ||
253 | snd_printk(KERN_ERR PFX "unable to find a free IRQ\n"); | ||
254 | err = -EBUSY; | ||
255 | goto _err; | ||
256 | } | ||
257 | } | ||
258 | xdma1 = dma1[dev]; | ||
259 | if (xdma1 == SNDRV_AUTO_DMA) { | ||
260 | if ((xdma1 = snd_legacy_find_free_dma(possible_dmas)) < 0) { | ||
261 | snd_printk(KERN_ERR PFX "unable to find a free DMA\n"); | ||
262 | err = -EBUSY; | ||
263 | goto _err; | ||
264 | } | ||
265 | } | ||
266 | |||
267 | if ((err = snd_sgalaxy_detect(dev, xirq, xdma1)) < 0) | ||
268 | goto _err; | ||
269 | |||
270 | err = snd_wss_create(card, wssport[dev] + 4, -1, | ||
271 | xirq, xdma1, -1, | ||
272 | WSS_HW_DETECT, 0, &chip); | ||
273 | if (err < 0) | ||
274 | goto _err; | ||
275 | card->private_data = chip; | ||
276 | |||
277 | err = snd_wss_pcm(chip, 0, NULL); | ||
278 | if (err < 0) { | ||
279 | snd_printdd(PFX "error creating new WSS PCM device\n"); | ||
280 | goto _err; | ||
281 | } | ||
282 | err = snd_wss_mixer(chip); | ||
283 | if (err < 0) { | ||
284 | snd_printdd(PFX "error creating new WSS mixer\n"); | ||
285 | goto _err; | ||
286 | } | ||
287 | if ((err = snd_sgalaxy_mixer(chip)) < 0) { | ||
288 | snd_printdd(PFX "the mixer rewrite failed\n"); | ||
289 | goto _err; | ||
290 | } | ||
291 | |||
292 | strcpy(card->driver, "Sound Galaxy"); | ||
293 | strcpy(card->shortname, "Sound Galaxy"); | ||
294 | sprintf(card->longname, "Sound Galaxy at 0x%lx, irq %d, dma %d", | ||
295 | wssport[dev], xirq, xdma1); | ||
296 | |||
297 | snd_card_set_dev(card, devptr); | ||
298 | |||
299 | if ((err = snd_card_register(card)) < 0) | ||
300 | goto _err; | ||
301 | |||
302 | dev_set_drvdata(devptr, card); | ||
303 | return 0; | ||
304 | |||
305 | _err: | ||
306 | snd_card_free(card); | ||
307 | return err; | ||
308 | } | ||
309 | |||
310 | static int __devexit snd_sgalaxy_remove(struct device *devptr, unsigned int dev) | ||
311 | { | ||
312 | snd_card_free(dev_get_drvdata(devptr)); | ||
313 | dev_set_drvdata(devptr, NULL); | ||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | #ifdef CONFIG_PM | ||
318 | static int snd_sgalaxy_suspend(struct device *pdev, unsigned int n, | ||
319 | pm_message_t state) | ||
320 | { | ||
321 | struct snd_card *card = dev_get_drvdata(pdev); | ||
322 | struct snd_wss *chip = card->private_data; | ||
323 | |||
324 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | ||
325 | chip->suspend(chip); | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | static int snd_sgalaxy_resume(struct device *pdev, unsigned int n) | ||
330 | { | ||
331 | struct snd_card *card = dev_get_drvdata(pdev); | ||
332 | struct snd_wss *chip = card->private_data; | ||
333 | |||
334 | chip->resume(chip); | ||
335 | snd_wss_out(chip, SGALAXY_AUXC_LEFT, chip->image[SGALAXY_AUXC_LEFT]); | ||
336 | snd_wss_out(chip, SGALAXY_AUXC_RIGHT, chip->image[SGALAXY_AUXC_RIGHT]); | ||
337 | |||
338 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | ||
339 | return 0; | ||
340 | } | ||
341 | #endif | ||
342 | |||
343 | #define DEV_NAME "sgalaxy" | ||
344 | |||
345 | static struct isa_driver snd_sgalaxy_driver = { | ||
346 | .match = snd_sgalaxy_match, | ||
347 | .probe = snd_sgalaxy_probe, | ||
348 | .remove = __devexit_p(snd_sgalaxy_remove), | ||
349 | #ifdef CONFIG_PM | ||
350 | .suspend = snd_sgalaxy_suspend, | ||
351 | .resume = snd_sgalaxy_resume, | ||
352 | #endif | ||
353 | .driver = { | ||
354 | .name = DEV_NAME | ||
355 | }, | ||
356 | }; | ||
357 | |||
358 | static int __init alsa_card_sgalaxy_init(void) | ||
359 | { | ||
360 | return isa_register_driver(&snd_sgalaxy_driver, SNDRV_CARDS); | ||
361 | } | ||
362 | |||
363 | static void __exit alsa_card_sgalaxy_exit(void) | ||
364 | { | ||
365 | isa_unregister_driver(&snd_sgalaxy_driver); | ||
366 | } | ||
367 | |||
368 | module_init(alsa_card_sgalaxy_init) | ||
369 | module_exit(alsa_card_sgalaxy_exit) | ||
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig index a513651fa149..76c090218073 100644 --- a/sound/oss/Kconfig +++ b/sound/oss/Kconfig | |||
@@ -545,11 +545,3 @@ config SOUND_KAHLUA | |||
545 | 545 | ||
546 | endif # SOUND_OSS | 546 | endif # SOUND_OSS |
547 | 547 | ||
548 | config SOUND_SH_DAC_AUDIO | ||
549 | tristate "SuperH DAC audio support" | ||
550 | depends on CPU_SH3 && HIGH_RES_TIMERS | ||
551 | |||
552 | config SOUND_SH_DAC_AUDIO_CHANNEL | ||
553 | int "DAC channel" | ||
554 | default "1" | ||
555 | depends on SOUND_SH_DAC_AUDIO | ||
diff --git a/sound/oss/Makefile b/sound/oss/Makefile index 567b8a74178a..96f14dcd0cd1 100644 --- a/sound/oss/Makefile +++ b/sound/oss/Makefile | |||
@@ -9,7 +9,6 @@ obj-$(CONFIG_SOUND_OSS) += sound.o | |||
9 | 9 | ||
10 | # Please leave it as is, cause the link order is significant ! | 10 | # Please leave it as is, cause the link order is significant ! |
11 | 11 | ||
12 | obj-$(CONFIG_SOUND_SH_DAC_AUDIO) += sh_dac_audio.o | ||
13 | obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o | 12 | obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o |
14 | obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o | 13 | obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o |
15 | obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o | 14 | obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o |
diff --git a/sound/oss/au1550_ac97.c b/sound/oss/au1550_ac97.c index c6f2621221ba..a8f626d99c5b 100644 --- a/sound/oss/au1550_ac97.c +++ b/sound/oss/au1550_ac97.c | |||
@@ -43,7 +43,6 @@ | |||
43 | #include <linux/sound.h> | 43 | #include <linux/sound.h> |
44 | #include <linux/slab.h> | 44 | #include <linux/slab.h> |
45 | #include <linux/soundcard.h> | 45 | #include <linux/soundcard.h> |
46 | #include <linux/smp_lock.h> | ||
47 | #include <linux/init.h> | 46 | #include <linux/init.h> |
48 | #include <linux/interrupt.h> | 47 | #include <linux/interrupt.h> |
49 | #include <linux/kernel.h> | 48 | #include <linux/kernel.h> |
@@ -77,6 +76,7 @@ | |||
77 | /* Boot options | 76 | /* Boot options |
78 | * 0 = no VRA, 1 = use VRA if codec supports it | 77 | * 0 = no VRA, 1 = use VRA if codec supports it |
79 | */ | 78 | */ |
79 | static DEFINE_MUTEX(au1550_ac97_mutex); | ||
80 | static int vra = 1; | 80 | static int vra = 1; |
81 | module_param(vra, bool, 0); | 81 | module_param(vra, bool, 0); |
82 | MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it"); | 82 | MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it"); |
@@ -171,7 +171,7 @@ au1550_delay(int msec) | |||
171 | static u16 | 171 | static u16 |
172 | rdcodec(struct ac97_codec *codec, u8 addr) | 172 | rdcodec(struct ac97_codec *codec, u8 addr) |
173 | { | 173 | { |
174 | struct au1550_state *s = (struct au1550_state *)codec->private_data; | 174 | struct au1550_state *s = codec->private_data; |
175 | unsigned long flags; | 175 | unsigned long flags; |
176 | u32 cmd, val; | 176 | u32 cmd, val; |
177 | u16 data; | 177 | u16 data; |
@@ -239,7 +239,7 @@ rdcodec(struct ac97_codec *codec, u8 addr) | |||
239 | static void | 239 | static void |
240 | wrcodec(struct ac97_codec *codec, u8 addr, u16 data) | 240 | wrcodec(struct ac97_codec *codec, u8 addr, u16 data) |
241 | { | 241 | { |
242 | struct au1550_state *s = (struct au1550_state *)codec->private_data; | 242 | struct au1550_state *s = codec->private_data; |
243 | unsigned long flags; | 243 | unsigned long flags; |
244 | u32 cmd, val; | 244 | u32 cmd, val; |
245 | int i; | 245 | int i; |
@@ -798,9 +798,9 @@ au1550_llseek(struct file *file, loff_t offset, int origin) | |||
798 | static int | 798 | static int |
799 | au1550_open_mixdev(struct inode *inode, struct file *file) | 799 | au1550_open_mixdev(struct inode *inode, struct file *file) |
800 | { | 800 | { |
801 | lock_kernel(); | 801 | mutex_lock(&au1550_ac97_mutex); |
802 | file->private_data = &au1550_state; | 802 | file->private_data = &au1550_state; |
803 | unlock_kernel(); | 803 | mutex_unlock(&au1550_ac97_mutex); |
804 | return 0; | 804 | return 0; |
805 | } | 805 | } |
806 | 806 | ||
@@ -820,13 +820,13 @@ mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd, | |||
820 | static long | 820 | static long |
821 | au1550_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg) | 821 | au1550_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg) |
822 | { | 822 | { |
823 | struct au1550_state *s = (struct au1550_state *)file->private_data; | 823 | struct au1550_state *s = file->private_data; |
824 | struct ac97_codec *codec = s->codec; | 824 | struct ac97_codec *codec = s->codec; |
825 | int ret; | 825 | int ret; |
826 | 826 | ||
827 | lock_kernel(); | 827 | mutex_lock(&au1550_ac97_mutex); |
828 | ret = mixdev_ioctl(codec, cmd, arg); | 828 | ret = mixdev_ioctl(codec, cmd, arg); |
829 | unlock_kernel(); | 829 | mutex_unlock(&au1550_ac97_mutex); |
830 | 830 | ||
831 | return ret; | 831 | return ret; |
832 | } | 832 | } |
@@ -1031,7 +1031,7 @@ copy_dmabuf_user(struct dmabuf *db, char* userbuf, int count, int to_user) | |||
1031 | static ssize_t | 1031 | static ssize_t |
1032 | au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos) | 1032 | au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos) |
1033 | { | 1033 | { |
1034 | struct au1550_state *s = (struct au1550_state *)file->private_data; | 1034 | struct au1550_state *s = file->private_data; |
1035 | struct dmabuf *db = &s->dma_adc; | 1035 | struct dmabuf *db = &s->dma_adc; |
1036 | DECLARE_WAITQUEUE(wait, current); | 1036 | DECLARE_WAITQUEUE(wait, current); |
1037 | ssize_t ret; | 1037 | ssize_t ret; |
@@ -1111,7 +1111,7 @@ out2: | |||
1111 | static ssize_t | 1111 | static ssize_t |
1112 | au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos) | 1112 | au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos) |
1113 | { | 1113 | { |
1114 | struct au1550_state *s = (struct au1550_state *)file->private_data; | 1114 | struct au1550_state *s = file->private_data; |
1115 | struct dmabuf *db = &s->dma_dac; | 1115 | struct dmabuf *db = &s->dma_dac; |
1116 | DECLARE_WAITQUEUE(wait, current); | 1116 | DECLARE_WAITQUEUE(wait, current); |
1117 | ssize_t ret = 0; | 1117 | ssize_t ret = 0; |
@@ -1211,7 +1211,7 @@ out2: | |||
1211 | static unsigned int | 1211 | static unsigned int |
1212 | au1550_poll(struct file *file, struct poll_table_struct *wait) | 1212 | au1550_poll(struct file *file, struct poll_table_struct *wait) |
1213 | { | 1213 | { |
1214 | struct au1550_state *s = (struct au1550_state *)file->private_data; | 1214 | struct au1550_state *s = file->private_data; |
1215 | unsigned long flags; | 1215 | unsigned long flags; |
1216 | unsigned int mask = 0; | 1216 | unsigned int mask = 0; |
1217 | 1217 | ||
@@ -1250,12 +1250,12 @@ au1550_poll(struct file *file, struct poll_table_struct *wait) | |||
1250 | static int | 1250 | static int |
1251 | au1550_mmap(struct file *file, struct vm_area_struct *vma) | 1251 | au1550_mmap(struct file *file, struct vm_area_struct *vma) |
1252 | { | 1252 | { |
1253 | struct au1550_state *s = (struct au1550_state *)file->private_data; | 1253 | struct au1550_state *s = file->private_data; |
1254 | struct dmabuf *db; | 1254 | struct dmabuf *db; |
1255 | unsigned long size; | 1255 | unsigned long size; |
1256 | int ret = 0; | 1256 | int ret = 0; |
1257 | 1257 | ||
1258 | lock_kernel(); | 1258 | mutex_lock(&au1550_ac97_mutex); |
1259 | mutex_lock(&s->sem); | 1259 | mutex_lock(&s->sem); |
1260 | if (vma->vm_flags & VM_WRITE) | 1260 | if (vma->vm_flags & VM_WRITE) |
1261 | db = &s->dma_dac; | 1261 | db = &s->dma_dac; |
@@ -1283,7 +1283,7 @@ au1550_mmap(struct file *file, struct vm_area_struct *vma) | |||
1283 | db->mapped = 1; | 1283 | db->mapped = 1; |
1284 | out: | 1284 | out: |
1285 | mutex_unlock(&s->sem); | 1285 | mutex_unlock(&s->sem); |
1286 | unlock_kernel(); | 1286 | mutex_unlock(&au1550_ac97_mutex); |
1287 | return ret; | 1287 | return ret; |
1288 | } | 1288 | } |
1289 | 1289 | ||
@@ -1342,7 +1342,7 @@ dma_count_done(struct dmabuf *db) | |||
1342 | static int | 1342 | static int |
1343 | au1550_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 1343 | au1550_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
1344 | { | 1344 | { |
1345 | struct au1550_state *s = (struct au1550_state *)file->private_data; | 1345 | struct au1550_state *s = file->private_data; |
1346 | unsigned long flags; | 1346 | unsigned long flags; |
1347 | audio_buf_info abinfo; | 1347 | audio_buf_info abinfo; |
1348 | count_info cinfo; | 1348 | count_info cinfo; |
@@ -1781,9 +1781,9 @@ au1550_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
1781 | { | 1781 | { |
1782 | int ret; | 1782 | int ret; |
1783 | 1783 | ||
1784 | lock_kernel(); | 1784 | mutex_lock(&au1550_ac97_mutex); |
1785 | ret = au1550_ioctl(file, cmd, arg); | 1785 | ret = au1550_ioctl(file, cmd, arg); |
1786 | unlock_kernel(); | 1786 | mutex_unlock(&au1550_ac97_mutex); |
1787 | 1787 | ||
1788 | return ret; | 1788 | return ret; |
1789 | } | 1789 | } |
@@ -1804,7 +1804,7 @@ au1550_open(struct inode *inode, struct file *file) | |||
1804 | #endif | 1804 | #endif |
1805 | 1805 | ||
1806 | file->private_data = s; | 1806 | file->private_data = s; |
1807 | lock_kernel(); | 1807 | mutex_lock(&au1550_ac97_mutex); |
1808 | /* wait for device to become free */ | 1808 | /* wait for device to become free */ |
1809 | mutex_lock(&s->open_mutex); | 1809 | mutex_lock(&s->open_mutex); |
1810 | while (s->open_mode & file->f_mode) { | 1810 | while (s->open_mode & file->f_mode) { |
@@ -1861,21 +1861,21 @@ au1550_open(struct inode *inode, struct file *file) | |||
1861 | out: | 1861 | out: |
1862 | mutex_unlock(&s->open_mutex); | 1862 | mutex_unlock(&s->open_mutex); |
1863 | out2: | 1863 | out2: |
1864 | unlock_kernel(); | 1864 | mutex_unlock(&au1550_ac97_mutex); |
1865 | return ret; | 1865 | return ret; |
1866 | } | 1866 | } |
1867 | 1867 | ||
1868 | static int | 1868 | static int |
1869 | au1550_release(struct inode *inode, struct file *file) | 1869 | au1550_release(struct inode *inode, struct file *file) |
1870 | { | 1870 | { |
1871 | struct au1550_state *s = (struct au1550_state *)file->private_data; | 1871 | struct au1550_state *s = file->private_data; |
1872 | 1872 | ||
1873 | lock_kernel(); | 1873 | mutex_lock(&au1550_ac97_mutex); |
1874 | 1874 | ||
1875 | if (file->f_mode & FMODE_WRITE) { | 1875 | if (file->f_mode & FMODE_WRITE) { |
1876 | unlock_kernel(); | 1876 | mutex_unlock(&au1550_ac97_mutex); |
1877 | drain_dac(s, file->f_flags & O_NONBLOCK); | 1877 | drain_dac(s, file->f_flags & O_NONBLOCK); |
1878 | lock_kernel(); | 1878 | mutex_lock(&au1550_ac97_mutex); |
1879 | } | 1879 | } |
1880 | 1880 | ||
1881 | mutex_lock(&s->open_mutex); | 1881 | mutex_lock(&s->open_mutex); |
@@ -1892,7 +1892,7 @@ au1550_release(struct inode *inode, struct file *file) | |||
1892 | s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE)); | 1892 | s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE)); |
1893 | mutex_unlock(&s->open_mutex); | 1893 | mutex_unlock(&s->open_mutex); |
1894 | wake_up(&s->open_wait); | 1894 | wake_up(&s->open_wait); |
1895 | unlock_kernel(); | 1895 | mutex_unlock(&au1550_ac97_mutex); |
1896 | return 0; | 1896 | return 0; |
1897 | } | 1897 | } |
1898 | 1898 | ||
diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c index 6ecd41abb066..87e2c72651f5 100644 --- a/sound/oss/dmasound/dmasound_core.c +++ b/sound/oss/dmasound/dmasound_core.c | |||
@@ -181,7 +181,7 @@ | |||
181 | #include <linux/init.h> | 181 | #include <linux/init.h> |
182 | #include <linux/soundcard.h> | 182 | #include <linux/soundcard.h> |
183 | #include <linux/poll.h> | 183 | #include <linux/poll.h> |
184 | #include <linux/smp_lock.h> | 184 | #include <linux/mutex.h> |
185 | 185 | ||
186 | #include <asm/uaccess.h> | 186 | #include <asm/uaccess.h> |
187 | 187 | ||
@@ -194,6 +194,7 @@ | |||
194 | * Declarations | 194 | * Declarations |
195 | */ | 195 | */ |
196 | 196 | ||
197 | static DEFINE_MUTEX(dmasound_core_mutex); | ||
197 | int dmasound_catchRadius = 0; | 198 | int dmasound_catchRadius = 0; |
198 | module_param(dmasound_catchRadius, int, 0); | 199 | module_param(dmasound_catchRadius, int, 0); |
199 | 200 | ||
@@ -323,22 +324,22 @@ static struct { | |||
323 | 324 | ||
324 | static int mixer_open(struct inode *inode, struct file *file) | 325 | static int mixer_open(struct inode *inode, struct file *file) |
325 | { | 326 | { |
326 | lock_kernel(); | 327 | mutex_lock(&dmasound_core_mutex); |
327 | if (!try_module_get(dmasound.mach.owner)) { | 328 | if (!try_module_get(dmasound.mach.owner)) { |
328 | unlock_kernel(); | 329 | mutex_unlock(&dmasound_core_mutex); |
329 | return -ENODEV; | 330 | return -ENODEV; |
330 | } | 331 | } |
331 | mixer.busy = 1; | 332 | mixer.busy = 1; |
332 | unlock_kernel(); | 333 | mutex_unlock(&dmasound_core_mutex); |
333 | return 0; | 334 | return 0; |
334 | } | 335 | } |
335 | 336 | ||
336 | static int mixer_release(struct inode *inode, struct file *file) | 337 | static int mixer_release(struct inode *inode, struct file *file) |
337 | { | 338 | { |
338 | lock_kernel(); | 339 | mutex_lock(&dmasound_core_mutex); |
339 | mixer.busy = 0; | 340 | mixer.busy = 0; |
340 | module_put(dmasound.mach.owner); | 341 | module_put(dmasound.mach.owner); |
341 | unlock_kernel(); | 342 | mutex_unlock(&dmasound_core_mutex); |
342 | return 0; | 343 | return 0; |
343 | } | 344 | } |
344 | 345 | ||
@@ -370,9 +371,9 @@ static long mixer_unlocked_ioctl(struct file *file, u_int cmd, u_long arg) | |||
370 | { | 371 | { |
371 | int ret; | 372 | int ret; |
372 | 373 | ||
373 | lock_kernel(); | 374 | mutex_lock(&dmasound_core_mutex); |
374 | ret = mixer_ioctl(file, cmd, arg); | 375 | ret = mixer_ioctl(file, cmd, arg); |
375 | unlock_kernel(); | 376 | mutex_unlock(&dmasound_core_mutex); |
376 | 377 | ||
377 | return ret; | 378 | return ret; |
378 | } | 379 | } |
@@ -752,9 +753,9 @@ static int sq_open(struct inode *inode, struct file *file) | |||
752 | { | 753 | { |
753 | int rc; | 754 | int rc; |
754 | 755 | ||
755 | lock_kernel(); | 756 | mutex_lock(&dmasound_core_mutex); |
756 | if (!try_module_get(dmasound.mach.owner)) { | 757 | if (!try_module_get(dmasound.mach.owner)) { |
757 | unlock_kernel(); | 758 | mutex_unlock(&dmasound_core_mutex); |
758 | return -ENODEV; | 759 | return -ENODEV; |
759 | } | 760 | } |
760 | 761 | ||
@@ -799,11 +800,11 @@ static int sq_open(struct inode *inode, struct file *file) | |||
799 | sound_set_format(AFMT_MU_LAW); | 800 | sound_set_format(AFMT_MU_LAW); |
800 | } | 801 | } |
801 | #endif | 802 | #endif |
802 | unlock_kernel(); | 803 | mutex_unlock(&dmasound_core_mutex); |
803 | return 0; | 804 | return 0; |
804 | out: | 805 | out: |
805 | module_put(dmasound.mach.owner); | 806 | module_put(dmasound.mach.owner); |
806 | unlock_kernel(); | 807 | mutex_unlock(&dmasound_core_mutex); |
807 | return rc; | 808 | return rc; |
808 | } | 809 | } |
809 | 810 | ||
@@ -869,7 +870,7 @@ static int sq_release(struct inode *inode, struct file *file) | |||
869 | { | 870 | { |
870 | int rc = 0; | 871 | int rc = 0; |
871 | 872 | ||
872 | lock_kernel(); | 873 | mutex_lock(&dmasound_core_mutex); |
873 | 874 | ||
874 | if (file->f_mode & FMODE_WRITE) { | 875 | if (file->f_mode & FMODE_WRITE) { |
875 | if (write_sq.busy) | 876 | if (write_sq.busy) |
@@ -900,7 +901,7 @@ static int sq_release(struct inode *inode, struct file *file) | |||
900 | write_sq_wake_up(file); /* checks f_mode */ | 901 | write_sq_wake_up(file); /* checks f_mode */ |
901 | #endif /* blocking open() */ | 902 | #endif /* blocking open() */ |
902 | 903 | ||
903 | unlock_kernel(); | 904 | mutex_unlock(&dmasound_core_mutex); |
904 | 905 | ||
905 | return rc; | 906 | return rc; |
906 | } | 907 | } |
@@ -1141,9 +1142,9 @@ static long sq_unlocked_ioctl(struct file *file, u_int cmd, u_long arg) | |||
1141 | { | 1142 | { |
1142 | int ret; | 1143 | int ret; |
1143 | 1144 | ||
1144 | lock_kernel(); | 1145 | mutex_lock(&dmasound_core_mutex); |
1145 | ret = sq_ioctl(file, cmd, arg); | 1146 | ret = sq_ioctl(file, cmd, arg); |
1146 | unlock_kernel(); | 1147 | mutex_unlock(&dmasound_core_mutex); |
1147 | 1148 | ||
1148 | return ret; | 1149 | return ret; |
1149 | } | 1150 | } |
@@ -1257,7 +1258,7 @@ static int state_open(struct inode *inode, struct file *file) | |||
1257 | int len = 0; | 1258 | int len = 0; |
1258 | int ret; | 1259 | int ret; |
1259 | 1260 | ||
1260 | lock_kernel(); | 1261 | mutex_lock(&dmasound_core_mutex); |
1261 | ret = -EBUSY; | 1262 | ret = -EBUSY; |
1262 | if (state.busy) | 1263 | if (state.busy) |
1263 | goto out; | 1264 | goto out; |
@@ -1329,16 +1330,16 @@ printk("dmasound: stat buffer used %d bytes\n", len) ; | |||
1329 | state.len = len; | 1330 | state.len = len; |
1330 | ret = 0; | 1331 | ret = 0; |
1331 | out: | 1332 | out: |
1332 | unlock_kernel(); | 1333 | mutex_unlock(&dmasound_core_mutex); |
1333 | return ret; | 1334 | return ret; |
1334 | } | 1335 | } |
1335 | 1336 | ||
1336 | static int state_release(struct inode *inode, struct file *file) | 1337 | static int state_release(struct inode *inode, struct file *file) |
1337 | { | 1338 | { |
1338 | lock_kernel(); | 1339 | mutex_lock(&dmasound_core_mutex); |
1339 | state.busy = 0; | 1340 | state.busy = 0; |
1340 | module_put(dmasound.mach.owner); | 1341 | module_put(dmasound.mach.owner); |
1341 | unlock_kernel(); | 1342 | mutex_unlock(&dmasound_core_mutex); |
1342 | return 0; | 1343 | return 0; |
1343 | } | 1344 | } |
1344 | 1345 | ||
diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c index 2e48b17667d0..b4c1eb504c22 100644 --- a/sound/oss/msnd_pinnacle.c +++ b/sound/oss/msnd_pinnacle.c | |||
@@ -39,7 +39,7 @@ | |||
39 | #include <linux/delay.h> | 39 | #include <linux/delay.h> |
40 | #include <linux/init.h> | 40 | #include <linux/init.h> |
41 | #include <linux/interrupt.h> | 41 | #include <linux/interrupt.h> |
42 | #include <linux/smp_lock.h> | 42 | #include <linux/mutex.h> |
43 | #include <linux/gfp.h> | 43 | #include <linux/gfp.h> |
44 | #include <asm/irq.h> | 44 | #include <asm/irq.h> |
45 | #include <asm/io.h> | 45 | #include <asm/io.h> |
@@ -79,6 +79,7 @@ | |||
79 | dev.rec_sample_rate / \ | 79 | dev.rec_sample_rate / \ |
80 | dev.rec_channels) | 80 | dev.rec_channels) |
81 | 81 | ||
82 | static DEFINE_MUTEX(msnd_pinnacle_mutex); | ||
82 | static multisound_dev_t dev; | 83 | static multisound_dev_t dev; |
83 | 84 | ||
84 | #ifndef HAVE_DSPCODEH | 85 | #ifndef HAVE_DSPCODEH |
@@ -651,12 +652,12 @@ static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
651 | 652 | ||
652 | ret = -EINVAL; | 653 | ret = -EINVAL; |
653 | 654 | ||
654 | lock_kernel(); | 655 | mutex_lock(&msnd_pinnacle_mutex); |
655 | if (minor == dev.dsp_minor) | 656 | if (minor == dev.dsp_minor) |
656 | ret = dsp_ioctl(file, cmd, arg); | 657 | ret = dsp_ioctl(file, cmd, arg); |
657 | else if (minor == dev.mixer_minor) | 658 | else if (minor == dev.mixer_minor) |
658 | ret = mixer_ioctl(cmd, arg); | 659 | ret = mixer_ioctl(cmd, arg); |
659 | unlock_kernel(); | 660 | mutex_unlock(&msnd_pinnacle_mutex); |
660 | 661 | ||
661 | return ret; | 662 | return ret; |
662 | } | 663 | } |
@@ -761,7 +762,7 @@ static int dev_open(struct inode *inode, struct file *file) | |||
761 | int minor = iminor(inode); | 762 | int minor = iminor(inode); |
762 | int err = 0; | 763 | int err = 0; |
763 | 764 | ||
764 | lock_kernel(); | 765 | mutex_lock(&msnd_pinnacle_mutex); |
765 | if (minor == dev.dsp_minor) { | 766 | if (minor == dev.dsp_minor) { |
766 | if ((file->f_mode & FMODE_WRITE && | 767 | if ((file->f_mode & FMODE_WRITE && |
767 | test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) || | 768 | test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) || |
@@ -791,7 +792,7 @@ static int dev_open(struct inode *inode, struct file *file) | |||
791 | } else | 792 | } else |
792 | err = -EINVAL; | 793 | err = -EINVAL; |
793 | out: | 794 | out: |
794 | unlock_kernel(); | 795 | mutex_unlock(&msnd_pinnacle_mutex); |
795 | return err; | 796 | return err; |
796 | } | 797 | } |
797 | 798 | ||
@@ -800,14 +801,14 @@ static int dev_release(struct inode *inode, struct file *file) | |||
800 | int minor = iminor(inode); | 801 | int minor = iminor(inode); |
801 | int err = 0; | 802 | int err = 0; |
802 | 803 | ||
803 | lock_kernel(); | 804 | mutex_lock(&msnd_pinnacle_mutex); |
804 | if (minor == dev.dsp_minor) | 805 | if (minor == dev.dsp_minor) |
805 | err = dsp_release(file); | 806 | err = dsp_release(file); |
806 | else if (minor == dev.mixer_minor) { | 807 | else if (minor == dev.mixer_minor) { |
807 | /* nothing */ | 808 | /* nothing */ |
808 | } else | 809 | } else |
809 | err = -EINVAL; | 810 | err = -EINVAL; |
810 | unlock_kernel(); | 811 | mutex_unlock(&msnd_pinnacle_mutex); |
811 | return err; | 812 | return err; |
812 | } | 813 | } |
813 | 814 | ||
diff --git a/sound/oss/sh_dac_audio.c b/sound/oss/sh_dac_audio.c deleted file mode 100644 index 479e3025a8a3..000000000000 --- a/sound/oss/sh_dac_audio.c +++ /dev/null | |||
@@ -1,325 +0,0 @@ | |||
1 | /* | ||
2 | * sound/oss/sh_dac_audio.c | ||
3 | * | ||
4 | * SH DAC based sound :( | ||
5 | * | ||
6 | * Copyright (C) 2004,2005 Andriy Skulysh | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file "COPYING" in the main directory of this archive | ||
10 | * for more details. | ||
11 | */ | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/sched.h> | ||
15 | #include <linux/linkage.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/fs.h> | ||
18 | #include <linux/sound.h> | ||
19 | #include <linux/smp_lock.h> | ||
20 | #include <linux/soundcard.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/hrtimer.h> | ||
23 | #include <asm/io.h> | ||
24 | #include <asm/uaccess.h> | ||
25 | #include <asm/irq.h> | ||
26 | #include <asm/delay.h> | ||
27 | #include <asm/clock.h> | ||
28 | #include <cpu/dac.h> | ||
29 | #include <asm/machvec.h> | ||
30 | #include <mach/hp6xx.h> | ||
31 | #include <asm/hd64461.h> | ||
32 | |||
33 | #define MODNAME "sh_dac_audio" | ||
34 | |||
35 | #define BUFFER_SIZE 48000 | ||
36 | |||
37 | static int rate; | ||
38 | static int empty; | ||
39 | static char *data_buffer, *buffer_begin, *buffer_end; | ||
40 | static int in_use, device_major; | ||
41 | static struct hrtimer hrtimer; | ||
42 | static ktime_t wakeups_per_second; | ||
43 | |||
44 | static void dac_audio_start_timer(void) | ||
45 | { | ||
46 | hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL); | ||
47 | } | ||
48 | |||
49 | static void dac_audio_stop_timer(void) | ||
50 | { | ||
51 | hrtimer_cancel(&hrtimer); | ||
52 | } | ||
53 | |||
54 | static void dac_audio_reset(void) | ||
55 | { | ||
56 | dac_audio_stop_timer(); | ||
57 | buffer_begin = buffer_end = data_buffer; | ||
58 | empty = 1; | ||
59 | } | ||
60 | |||
61 | static void dac_audio_sync(void) | ||
62 | { | ||
63 | while (!empty) | ||
64 | schedule(); | ||
65 | } | ||
66 | |||
67 | static void dac_audio_start(void) | ||
68 | { | ||
69 | if (mach_is_hp6xx()) { | ||
70 | u16 v = __raw_readw(HD64461_GPADR); | ||
71 | v &= ~HD64461_GPADR_SPEAKER; | ||
72 | __raw_writew(v, HD64461_GPADR); | ||
73 | } | ||
74 | |||
75 | sh_dac_enable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL); | ||
76 | } | ||
77 | static void dac_audio_stop(void) | ||
78 | { | ||
79 | dac_audio_stop_timer(); | ||
80 | |||
81 | if (mach_is_hp6xx()) { | ||
82 | u16 v = __raw_readw(HD64461_GPADR); | ||
83 | v |= HD64461_GPADR_SPEAKER; | ||
84 | __raw_writew(v, HD64461_GPADR); | ||
85 | } | ||
86 | |||
87 | sh_dac_output(0, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL); | ||
88 | sh_dac_disable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL); | ||
89 | } | ||
90 | |||
91 | static void dac_audio_set_rate(void) | ||
92 | { | ||
93 | wakeups_per_second = ktime_set(0, 1000000000 / rate); | ||
94 | } | ||
95 | |||
96 | static int dac_audio_ioctl(struct file *file, | ||
97 | unsigned int cmd, unsigned long arg) | ||
98 | { | ||
99 | int val; | ||
100 | |||
101 | switch (cmd) { | ||
102 | case OSS_GETVERSION: | ||
103 | return put_user(SOUND_VERSION, (int *)arg); | ||
104 | |||
105 | case SNDCTL_DSP_SYNC: | ||
106 | dac_audio_sync(); | ||
107 | return 0; | ||
108 | |||
109 | case SNDCTL_DSP_RESET: | ||
110 | dac_audio_reset(); | ||
111 | return 0; | ||
112 | |||
113 | case SNDCTL_DSP_GETFMTS: | ||
114 | return put_user(AFMT_U8, (int *)arg); | ||
115 | |||
116 | case SNDCTL_DSP_SETFMT: | ||
117 | return put_user(AFMT_U8, (int *)arg); | ||
118 | |||
119 | case SNDCTL_DSP_NONBLOCK: | ||
120 | spin_lock(&file->f_lock); | ||
121 | file->f_flags |= O_NONBLOCK; | ||
122 | spin_unlock(&file->f_lock); | ||
123 | return 0; | ||
124 | |||
125 | case SNDCTL_DSP_GETCAPS: | ||
126 | return 0; | ||
127 | |||
128 | case SOUND_PCM_WRITE_RATE: | ||
129 | val = *(int *)arg; | ||
130 | if (val > 0) { | ||
131 | rate = val; | ||
132 | dac_audio_set_rate(); | ||
133 | } | ||
134 | return put_user(rate, (int *)arg); | ||
135 | |||
136 | case SNDCTL_DSP_STEREO: | ||
137 | return put_user(0, (int *)arg); | ||
138 | |||
139 | case SOUND_PCM_WRITE_CHANNELS: | ||
140 | return put_user(1, (int *)arg); | ||
141 | |||
142 | case SNDCTL_DSP_SETDUPLEX: | ||
143 | return -EINVAL; | ||
144 | |||
145 | case SNDCTL_DSP_PROFILE: | ||
146 | return -EINVAL; | ||
147 | |||
148 | case SNDCTL_DSP_GETBLKSIZE: | ||
149 | return put_user(BUFFER_SIZE, (int *)arg); | ||
150 | |||
151 | case SNDCTL_DSP_SETFRAGMENT: | ||
152 | return 0; | ||
153 | |||
154 | default: | ||
155 | printk(KERN_ERR "sh_dac_audio: unimplemented ioctl=0x%x\n", | ||
156 | cmd); | ||
157 | return -EINVAL; | ||
158 | } | ||
159 | return -EINVAL; | ||
160 | } | ||
161 | |||
162 | static long dac_audio_unlocked_ioctl(struct file *file, u_int cmd, u_long arg) | ||
163 | { | ||
164 | int ret; | ||
165 | |||
166 | lock_kernel(); | ||
167 | ret = dac_audio_ioctl(file, cmd, arg); | ||
168 | unlock_kernel(); | ||
169 | |||
170 | return ret; | ||
171 | } | ||
172 | |||
173 | static ssize_t dac_audio_write(struct file *file, const char *buf, size_t count, | ||
174 | loff_t * ppos) | ||
175 | { | ||
176 | int free; | ||
177 | int nbytes; | ||
178 | |||
179 | if (!count) { | ||
180 | dac_audio_sync(); | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | free = buffer_begin - buffer_end; | ||
185 | |||
186 | if (free < 0) | ||
187 | free += BUFFER_SIZE; | ||
188 | if ((free == 0) && (empty)) | ||
189 | free = BUFFER_SIZE; | ||
190 | if (count > free) | ||
191 | count = free; | ||
192 | if (buffer_begin > buffer_end) { | ||
193 | if (copy_from_user((void *)buffer_end, buf, count)) | ||
194 | return -EFAULT; | ||
195 | |||
196 | buffer_end += count; | ||
197 | } else { | ||
198 | nbytes = data_buffer + BUFFER_SIZE - buffer_end; | ||
199 | if (nbytes > count) { | ||
200 | if (copy_from_user((void *)buffer_end, buf, count)) | ||
201 | return -EFAULT; | ||
202 | buffer_end += count; | ||
203 | } else { | ||
204 | if (copy_from_user((void *)buffer_end, buf, nbytes)) | ||
205 | return -EFAULT; | ||
206 | if (copy_from_user | ||
207 | ((void *)data_buffer, buf + nbytes, count - nbytes)) | ||
208 | return -EFAULT; | ||
209 | buffer_end = data_buffer + count - nbytes; | ||
210 | } | ||
211 | } | ||
212 | |||
213 | if (empty) { | ||
214 | empty = 0; | ||
215 | dac_audio_start_timer(); | ||
216 | } | ||
217 | |||
218 | return count; | ||
219 | } | ||
220 | |||
221 | static ssize_t dac_audio_read(struct file *file, char *buf, size_t count, | ||
222 | loff_t * ppos) | ||
223 | { | ||
224 | return -EINVAL; | ||
225 | } | ||
226 | |||
227 | static int dac_audio_open(struct inode *inode, struct file *file) | ||
228 | { | ||
229 | if (file->f_mode & FMODE_READ) | ||
230 | return -ENODEV; | ||
231 | |||
232 | lock_kernel(); | ||
233 | if (in_use) { | ||
234 | unlock_kernel(); | ||
235 | return -EBUSY; | ||
236 | } | ||
237 | |||
238 | in_use = 1; | ||
239 | |||
240 | dac_audio_start(); | ||
241 | unlock_kernel(); | ||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | static int dac_audio_release(struct inode *inode, struct file *file) | ||
246 | { | ||
247 | dac_audio_sync(); | ||
248 | dac_audio_stop(); | ||
249 | in_use = 0; | ||
250 | |||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | const struct file_operations dac_audio_fops = { | ||
255 | .read = dac_audio_read, | ||
256 | .write = dac_audio_write, | ||
257 | .unlocked_ioctl = dac_audio_unlocked_ioctl, | ||
258 | .open = dac_audio_open, | ||
259 | .release = dac_audio_release, | ||
260 | }; | ||
261 | |||
262 | static enum hrtimer_restart sh_dac_audio_timer(struct hrtimer *handle) | ||
263 | { | ||
264 | if (!empty) { | ||
265 | sh_dac_output(*buffer_begin, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL); | ||
266 | buffer_begin++; | ||
267 | |||
268 | if (buffer_begin == data_buffer + BUFFER_SIZE) | ||
269 | buffer_begin = data_buffer; | ||
270 | if (buffer_begin == buffer_end) | ||
271 | empty = 1; | ||
272 | } | ||
273 | |||
274 | if (!empty) | ||
275 | hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL); | ||
276 | |||
277 | return HRTIMER_NORESTART; | ||
278 | } | ||
279 | |||
280 | static int __init dac_audio_init(void) | ||
281 | { | ||
282 | if ((device_major = register_sound_dsp(&dac_audio_fops, -1)) < 0) { | ||
283 | printk(KERN_ERR "Cannot register dsp device"); | ||
284 | return device_major; | ||
285 | } | ||
286 | |||
287 | in_use = 0; | ||
288 | |||
289 | data_buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL); | ||
290 | if (data_buffer == NULL) | ||
291 | return -ENOMEM; | ||
292 | |||
293 | dac_audio_reset(); | ||
294 | rate = 8000; | ||
295 | dac_audio_set_rate(); | ||
296 | |||
297 | /* Today: High Resolution Timer driven DAC playback. | ||
298 | * The timer callback gets called once per sample. Ouch. | ||
299 | * | ||
300 | * Future: A much better approach would be to use the | ||
301 | * SH7720 CMT+DMAC+DAC hardware combination like this: | ||
302 | * - Program sample rate using CMT0 or CMT1 | ||
303 | * - Program DMAC to use CMT for timing and output to DAC | ||
304 | * - Play sound using DMAC, let CPU sleep. | ||
305 | * - While at it, rewrite this driver to use ALSA. | ||
306 | */ | ||
307 | |||
308 | hrtimer_init(&hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
309 | hrtimer.function = sh_dac_audio_timer; | ||
310 | |||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | static void __exit dac_audio_exit(void) | ||
315 | { | ||
316 | unregister_sound_dsp(device_major); | ||
317 | kfree((void *)data_buffer); | ||
318 | } | ||
319 | |||
320 | module_init(dac_audio_init); | ||
321 | module_exit(dac_audio_exit); | ||
322 | |||
323 | MODULE_AUTHOR("Andriy Skulysh, askulysh@image.kiev.ua"); | ||
324 | MODULE_DESCRIPTION("SH DAC sound driver"); | ||
325 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c index 07f803e6d203..46c0d03dbecc 100644 --- a/sound/oss/soundcard.c +++ b/sound/oss/soundcard.c | |||
@@ -40,7 +40,7 @@ | |||
40 | #include <linux/major.h> | 40 | #include <linux/major.h> |
41 | #include <linux/delay.h> | 41 | #include <linux/delay.h> |
42 | #include <linux/proc_fs.h> | 42 | #include <linux/proc_fs.h> |
43 | #include <linux/smp_lock.h> | 43 | #include <linux/mutex.h> |
44 | #include <linux/module.h> | 44 | #include <linux/module.h> |
45 | #include <linux/mm.h> | 45 | #include <linux/mm.h> |
46 | #include <linux/device.h> | 46 | #include <linux/device.h> |
@@ -56,6 +56,7 @@ | |||
56 | * Table for permanently allocated memory (used when unloading the module) | 56 | * Table for permanently allocated memory (used when unloading the module) |
57 | */ | 57 | */ |
58 | void * sound_mem_blocks[MAX_MEM_BLOCKS]; | 58 | void * sound_mem_blocks[MAX_MEM_BLOCKS]; |
59 | static DEFINE_MUTEX(soundcard_mutex); | ||
59 | int sound_nblocks = 0; | 60 | int sound_nblocks = 0; |
60 | 61 | ||
61 | /* Persistent DMA buffers */ | 62 | /* Persistent DMA buffers */ |
@@ -151,7 +152,7 @@ static ssize_t sound_read(struct file *file, char __user *buf, size_t count, lof | |||
151 | * big one anyway, we might as well bandage here.. | 152 | * big one anyway, we might as well bandage here.. |
152 | */ | 153 | */ |
153 | 154 | ||
154 | lock_kernel(); | 155 | mutex_lock(&soundcard_mutex); |
155 | 156 | ||
156 | DEB(printk("sound_read(dev=%d, count=%d)\n", dev, count)); | 157 | DEB(printk("sound_read(dev=%d, count=%d)\n", dev, count)); |
157 | switch (dev & 0x0f) { | 158 | switch (dev & 0x0f) { |
@@ -169,7 +170,7 @@ static ssize_t sound_read(struct file *file, char __user *buf, size_t count, lof | |||
169 | case SND_DEV_MIDIN: | 170 | case SND_DEV_MIDIN: |
170 | ret = MIDIbuf_read(dev, file, buf, count); | 171 | ret = MIDIbuf_read(dev, file, buf, count); |
171 | } | 172 | } |
172 | unlock_kernel(); | 173 | mutex_unlock(&soundcard_mutex); |
173 | return ret; | 174 | return ret; |
174 | } | 175 | } |
175 | 176 | ||
@@ -178,7 +179,7 @@ static ssize_t sound_write(struct file *file, const char __user *buf, size_t cou | |||
178 | int dev = iminor(file->f_path.dentry->d_inode); | 179 | int dev = iminor(file->f_path.dentry->d_inode); |
179 | int ret = -EINVAL; | 180 | int ret = -EINVAL; |
180 | 181 | ||
181 | lock_kernel(); | 182 | mutex_lock(&soundcard_mutex); |
182 | DEB(printk("sound_write(dev=%d, count=%d)\n", dev, count)); | 183 | DEB(printk("sound_write(dev=%d, count=%d)\n", dev, count)); |
183 | switch (dev & 0x0f) { | 184 | switch (dev & 0x0f) { |
184 | case SND_DEV_SEQ: | 185 | case SND_DEV_SEQ: |
@@ -196,7 +197,7 @@ static ssize_t sound_write(struct file *file, const char __user *buf, size_t cou | |||
196 | ret = MIDIbuf_write(dev, file, buf, count); | 197 | ret = MIDIbuf_write(dev, file, buf, count); |
197 | break; | 198 | break; |
198 | } | 199 | } |
199 | unlock_kernel(); | 200 | mutex_unlock(&soundcard_mutex); |
200 | return ret; | 201 | return ret; |
201 | } | 202 | } |
202 | 203 | ||
@@ -210,7 +211,7 @@ static int sound_open(struct inode *inode, struct file *file) | |||
210 | printk(KERN_ERR "Invalid minor device %d\n", dev); | 211 | printk(KERN_ERR "Invalid minor device %d\n", dev); |
211 | return -ENXIO; | 212 | return -ENXIO; |
212 | } | 213 | } |
213 | lock_kernel(); | 214 | mutex_lock(&soundcard_mutex); |
214 | switch (dev & 0x0f) { | 215 | switch (dev & 0x0f) { |
215 | case SND_DEV_CTL: | 216 | case SND_DEV_CTL: |
216 | dev >>= 4; | 217 | dev >>= 4; |
@@ -247,15 +248,15 @@ static int sound_open(struct inode *inode, struct file *file) | |||
247 | retval = -ENXIO; | 248 | retval = -ENXIO; |
248 | } | 249 | } |
249 | 250 | ||
250 | unlock_kernel(); | 251 | mutex_unlock(&soundcard_mutex); |
251 | return 0; | 252 | return retval; |
252 | } | 253 | } |
253 | 254 | ||
254 | static int sound_release(struct inode *inode, struct file *file) | 255 | static int sound_release(struct inode *inode, struct file *file) |
255 | { | 256 | { |
256 | int dev = iminor(inode); | 257 | int dev = iminor(inode); |
257 | 258 | ||
258 | lock_kernel(); | 259 | mutex_lock(&soundcard_mutex); |
259 | DEB(printk("sound_release(dev=%d)\n", dev)); | 260 | DEB(printk("sound_release(dev=%d)\n", dev)); |
260 | switch (dev & 0x0f) { | 261 | switch (dev & 0x0f) { |
261 | case SND_DEV_CTL: | 262 | case SND_DEV_CTL: |
@@ -280,7 +281,7 @@ static int sound_release(struct inode *inode, struct file *file) | |||
280 | default: | 281 | default: |
281 | printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev); | 282 | printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev); |
282 | } | 283 | } |
283 | unlock_kernel(); | 284 | mutex_unlock(&soundcard_mutex); |
284 | 285 | ||
285 | return 0; | 286 | return 0; |
286 | } | 287 | } |
@@ -354,7 +355,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
354 | if (cmd == OSS_GETVERSION) | 355 | if (cmd == OSS_GETVERSION) |
355 | return __put_user(SOUND_VERSION, (int __user *)p); | 356 | return __put_user(SOUND_VERSION, (int __user *)p); |
356 | 357 | ||
357 | lock_kernel(); | 358 | mutex_lock(&soundcard_mutex); |
358 | if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 && /* Mixer ioctl */ | 359 | if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 && /* Mixer ioctl */ |
359 | (dev & 0x0f) != SND_DEV_CTL) { | 360 | (dev & 0x0f) != SND_DEV_CTL) { |
360 | dtype = dev & 0x0f; | 361 | dtype = dev & 0x0f; |
@@ -369,7 +370,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
369 | ret = sound_mixer_ioctl(dev >> 4, cmd, p); | 370 | ret = sound_mixer_ioctl(dev >> 4, cmd, p); |
370 | break; | 371 | break; |
371 | } | 372 | } |
372 | unlock_kernel(); | 373 | mutex_unlock(&soundcard_mutex); |
373 | return ret; | 374 | return ret; |
374 | } | 375 | } |
375 | 376 | ||
@@ -399,7 +400,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
399 | break; | 400 | break; |
400 | 401 | ||
401 | } | 402 | } |
402 | unlock_kernel(); | 403 | mutex_unlock(&soundcard_mutex); |
403 | return ret; | 404 | return ret; |
404 | } | 405 | } |
405 | 406 | ||
@@ -439,35 +440,35 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma) | |||
439 | printk(KERN_ERR "Sound: mmap() not supported for other than audio devices\n"); | 440 | printk(KERN_ERR "Sound: mmap() not supported for other than audio devices\n"); |
440 | return -EINVAL; | 441 | return -EINVAL; |
441 | } | 442 | } |
442 | lock_kernel(); | 443 | mutex_lock(&soundcard_mutex); |
443 | if (vma->vm_flags & VM_WRITE) /* Map write and read/write to the output buf */ | 444 | if (vma->vm_flags & VM_WRITE) /* Map write and read/write to the output buf */ |
444 | dmap = audio_devs[dev]->dmap_out; | 445 | dmap = audio_devs[dev]->dmap_out; |
445 | else if (vma->vm_flags & VM_READ) | 446 | else if (vma->vm_flags & VM_READ) |
446 | dmap = audio_devs[dev]->dmap_in; | 447 | dmap = audio_devs[dev]->dmap_in; |
447 | else { | 448 | else { |
448 | printk(KERN_ERR "Sound: Undefined mmap() access\n"); | 449 | printk(KERN_ERR "Sound: Undefined mmap() access\n"); |
449 | unlock_kernel(); | 450 | mutex_unlock(&soundcard_mutex); |
450 | return -EINVAL; | 451 | return -EINVAL; |
451 | } | 452 | } |
452 | 453 | ||
453 | if (dmap == NULL) { | 454 | if (dmap == NULL) { |
454 | printk(KERN_ERR "Sound: mmap() error. dmap == NULL\n"); | 455 | printk(KERN_ERR "Sound: mmap() error. dmap == NULL\n"); |
455 | unlock_kernel(); | 456 | mutex_unlock(&soundcard_mutex); |
456 | return -EIO; | 457 | return -EIO; |
457 | } | 458 | } |
458 | if (dmap->raw_buf == NULL) { | 459 | if (dmap->raw_buf == NULL) { |
459 | printk(KERN_ERR "Sound: mmap() called when raw_buf == NULL\n"); | 460 | printk(KERN_ERR "Sound: mmap() called when raw_buf == NULL\n"); |
460 | unlock_kernel(); | 461 | mutex_unlock(&soundcard_mutex); |
461 | return -EIO; | 462 | return -EIO; |
462 | } | 463 | } |
463 | if (dmap->mapping_flags) { | 464 | if (dmap->mapping_flags) { |
464 | printk(KERN_ERR "Sound: mmap() called twice for the same DMA buffer\n"); | 465 | printk(KERN_ERR "Sound: mmap() called twice for the same DMA buffer\n"); |
465 | unlock_kernel(); | 466 | mutex_unlock(&soundcard_mutex); |
466 | return -EIO; | 467 | return -EIO; |
467 | } | 468 | } |
468 | if (vma->vm_pgoff != 0) { | 469 | if (vma->vm_pgoff != 0) { |
469 | printk(KERN_ERR "Sound: mmap() offset must be 0.\n"); | 470 | printk(KERN_ERR "Sound: mmap() offset must be 0.\n"); |
470 | unlock_kernel(); | 471 | mutex_unlock(&soundcard_mutex); |
471 | return -EINVAL; | 472 | return -EINVAL; |
472 | } | 473 | } |
473 | size = vma->vm_end - vma->vm_start; | 474 | size = vma->vm_end - vma->vm_start; |
@@ -478,7 +479,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma) | |||
478 | if (remap_pfn_range(vma, vma->vm_start, | 479 | if (remap_pfn_range(vma, vma->vm_start, |
479 | virt_to_phys(dmap->raw_buf) >> PAGE_SHIFT, | 480 | virt_to_phys(dmap->raw_buf) >> PAGE_SHIFT, |
480 | vma->vm_end - vma->vm_start, vma->vm_page_prot)) { | 481 | vma->vm_end - vma->vm_start, vma->vm_page_prot)) { |
481 | unlock_kernel(); | 482 | mutex_unlock(&soundcard_mutex); |
482 | return -EAGAIN; | 483 | return -EAGAIN; |
483 | } | 484 | } |
484 | 485 | ||
@@ -490,7 +491,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma) | |||
490 | memset(dmap->raw_buf, | 491 | memset(dmap->raw_buf, |
491 | dmap->neutral_byte, | 492 | dmap->neutral_byte, |
492 | dmap->bytes_in_use); | 493 | dmap->bytes_in_use); |
493 | unlock_kernel(); | 494 | mutex_unlock(&soundcard_mutex); |
494 | return 0; | 495 | return 0; |
495 | } | 496 | } |
496 | 497 | ||
diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c index b15840ad2527..44357d877a27 100644 --- a/sound/oss/swarm_cs4297a.c +++ b/sound/oss/swarm_cs4297a.c | |||
@@ -68,7 +68,6 @@ | |||
68 | #include <linux/delay.h> | 68 | #include <linux/delay.h> |
69 | #include <linux/sound.h> | 69 | #include <linux/sound.h> |
70 | #include <linux/slab.h> | 70 | #include <linux/slab.h> |
71 | #include <linux/smp_lock.h> | ||
72 | #include <linux/soundcard.h> | 71 | #include <linux/soundcard.h> |
73 | #include <linux/ac97_codec.h> | 72 | #include <linux/ac97_codec.h> |
74 | #include <linux/pci.h> | 73 | #include <linux/pci.h> |
@@ -94,6 +93,7 @@ | |||
94 | 93 | ||
95 | struct cs4297a_state; | 94 | struct cs4297a_state; |
96 | 95 | ||
96 | static DEFINE_MUTEX(swarm_cs4297a_mutex); | ||
97 | static void stop_dac(struct cs4297a_state *s); | 97 | static void stop_dac(struct cs4297a_state *s); |
98 | static void stop_adc(struct cs4297a_state *s); | 98 | static void stop_adc(struct cs4297a_state *s); |
99 | static void start_dac(struct cs4297a_state *s); | 99 | static void start_dac(struct cs4297a_state *s); |
@@ -1535,7 +1535,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file) | |||
1535 | CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, | 1535 | CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, |
1536 | printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()+\n")); | 1536 | printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()+\n")); |
1537 | 1537 | ||
1538 | lock_kernel(); | 1538 | mutex_lock(&swarm_cs4297a_mutex); |
1539 | list_for_each(entry, &cs4297a_devs) | 1539 | list_for_each(entry, &cs4297a_devs) |
1540 | { | 1540 | { |
1541 | s = list_entry(entry, struct cs4297a_state, list); | 1541 | s = list_entry(entry, struct cs4297a_state, list); |
@@ -1547,7 +1547,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file) | |||
1547 | CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2, | 1547 | CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2, |
1548 | printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- -ENODEV\n")); | 1548 | printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- -ENODEV\n")); |
1549 | 1549 | ||
1550 | unlock_kernel(); | 1550 | mutex_unlock(&swarm_cs4297a_mutex); |
1551 | return -ENODEV; | 1551 | return -ENODEV; |
1552 | } | 1552 | } |
1553 | VALIDATE_STATE(s); | 1553 | VALIDATE_STATE(s); |
@@ -1555,7 +1555,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file) | |||
1555 | 1555 | ||
1556 | CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, | 1556 | CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, |
1557 | printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- 0\n")); | 1557 | printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- 0\n")); |
1558 | unlock_kernel(); | 1558 | mutex_unlock(&swarm_cs4297a_mutex); |
1559 | 1559 | ||
1560 | return nonseekable_open(inode, file); | 1560 | return nonseekable_open(inode, file); |
1561 | } | 1561 | } |
@@ -1575,10 +1575,10 @@ static int cs4297a_ioctl_mixdev(struct file *file, | |||
1575 | unsigned int cmd, unsigned long arg) | 1575 | unsigned int cmd, unsigned long arg) |
1576 | { | 1576 | { |
1577 | int ret; | 1577 | int ret; |
1578 | lock_kernel(); | 1578 | mutex_lock(&swarm_cs4297a_mutex); |
1579 | ret = mixer_ioctl((struct cs4297a_state *) file->private_data, cmd, | 1579 | ret = mixer_ioctl((struct cs4297a_state *) file->private_data, cmd, |
1580 | arg); | 1580 | arg); |
1581 | unlock_kernel(); | 1581 | mutex_unlock(&swarm_cs4297a_mutex); |
1582 | return ret; | 1582 | return ret; |
1583 | } | 1583 | } |
1584 | 1584 | ||
@@ -2350,9 +2350,9 @@ static long cs4297a_unlocked_ioctl(struct file *file, u_int cmd, u_long arg) | |||
2350 | { | 2350 | { |
2351 | int ret; | 2351 | int ret; |
2352 | 2352 | ||
2353 | lock_kernel(); | 2353 | mutex_lock(&swarm_cs4297a_mutex); |
2354 | ret = cs4297a_ioctl(file, cmd, arg); | 2354 | ret = cs4297a_ioctl(file, cmd, arg); |
2355 | unlock_kernel(); | 2355 | mutex_unlock(&swarm_cs4297a_mutex); |
2356 | 2356 | ||
2357 | return ret; | 2357 | return ret; |
2358 | } | 2358 | } |
@@ -2509,9 +2509,9 @@ static int cs4297a_open(struct inode *inode, struct file *file) | |||
2509 | { | 2509 | { |
2510 | int ret; | 2510 | int ret; |
2511 | 2511 | ||
2512 | lock_kernel(); | 2512 | mutex_lock(&swarm_cs4297a_mutex); |
2513 | ret = cs4297a_open(inode, file); | 2513 | ret = cs4297a_open(inode, file); |
2514 | unlock_kernel(); | 2514 | mutex_unlock(&swarm_cs4297a_mutex); |
2515 | 2515 | ||
2516 | return ret; | 2516 | return ret; |
2517 | } | 2517 | } |
diff --git a/sound/oss/vwsnd.c b/sound/oss/vwsnd.c index 8cd73cdd88af..643f1113b1d8 100644 --- a/sound/oss/vwsnd.c +++ b/sound/oss/vwsnd.c | |||
@@ -145,7 +145,6 @@ | |||
145 | #include <linux/init.h> | 145 | #include <linux/init.h> |
146 | 146 | ||
147 | #include <linux/spinlock.h> | 147 | #include <linux/spinlock.h> |
148 | #include <linux/smp_lock.h> | ||
149 | #include <linux/wait.h> | 148 | #include <linux/wait.h> |
150 | #include <linux/interrupt.h> | 149 | #include <linux/interrupt.h> |
151 | #include <linux/mutex.h> | 150 | #include <linux/mutex.h> |
@@ -160,6 +159,7 @@ | |||
160 | 159 | ||
161 | #ifdef VWSND_DEBUG | 160 | #ifdef VWSND_DEBUG |
162 | 161 | ||
162 | static DEFINE_MUTEX(vwsnd_mutex); | ||
163 | static int shut_up = 1; | 163 | static int shut_up = 1; |
164 | 164 | ||
165 | /* | 165 | /* |
@@ -2891,11 +2891,11 @@ static long vwsnd_audio_ioctl(struct file *file, | |||
2891 | vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data; | 2891 | vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data; |
2892 | int ret; | 2892 | int ret; |
2893 | 2893 | ||
2894 | lock_kernel(); | 2894 | mutex_lock(&vwsnd_mutex); |
2895 | mutex_lock(&devc->io_mutex); | 2895 | mutex_lock(&devc->io_mutex); |
2896 | ret = vwsnd_audio_do_ioctl(file, cmd, arg); | 2896 | ret = vwsnd_audio_do_ioctl(file, cmd, arg); |
2897 | mutex_unlock(&devc->io_mutex); | 2897 | mutex_unlock(&devc->io_mutex); |
2898 | unlock_kernel(); | 2898 | mutex_unlock(&vwsnd_mutex); |
2899 | 2899 | ||
2900 | return ret; | 2900 | return ret; |
2901 | } | 2901 | } |
@@ -2922,7 +2922,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file) | |||
2922 | 2922 | ||
2923 | DBGE("(inode=0x%p, file=0x%p)\n", inode, file); | 2923 | DBGE("(inode=0x%p, file=0x%p)\n", inode, file); |
2924 | 2924 | ||
2925 | lock_kernel(); | 2925 | mutex_lock(&vwsnd_mutex); |
2926 | INC_USE_COUNT; | 2926 | INC_USE_COUNT; |
2927 | for (devc = vwsnd_dev_list; devc; devc = devc->next_dev) | 2927 | for (devc = vwsnd_dev_list; devc; devc = devc->next_dev) |
2928 | if ((devc->audio_minor & ~0x0F) == (minor & ~0x0F)) | 2928 | if ((devc->audio_minor & ~0x0F) == (minor & ~0x0F)) |
@@ -2930,7 +2930,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file) | |||
2930 | 2930 | ||
2931 | if (devc == NULL) { | 2931 | if (devc == NULL) { |
2932 | DEC_USE_COUNT; | 2932 | DEC_USE_COUNT; |
2933 | unlock_kernel(); | 2933 | mutex_unlock(&vwsnd_mutex); |
2934 | return -ENODEV; | 2934 | return -ENODEV; |
2935 | } | 2935 | } |
2936 | 2936 | ||
@@ -2939,13 +2939,13 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file) | |||
2939 | mutex_unlock(&devc->open_mutex); | 2939 | mutex_unlock(&devc->open_mutex); |
2940 | if (file->f_flags & O_NONBLOCK) { | 2940 | if (file->f_flags & O_NONBLOCK) { |
2941 | DEC_USE_COUNT; | 2941 | DEC_USE_COUNT; |
2942 | unlock_kernel(); | 2942 | mutex_unlock(&vwsnd_mutex); |
2943 | return -EBUSY; | 2943 | return -EBUSY; |
2944 | } | 2944 | } |
2945 | interruptible_sleep_on(&devc->open_wait); | 2945 | interruptible_sleep_on(&devc->open_wait); |
2946 | if (signal_pending(current)) { | 2946 | if (signal_pending(current)) { |
2947 | DEC_USE_COUNT; | 2947 | DEC_USE_COUNT; |
2948 | unlock_kernel(); | 2948 | mutex_unlock(&vwsnd_mutex); |
2949 | return -ERESTARTSYS; | 2949 | return -ERESTARTSYS; |
2950 | } | 2950 | } |
2951 | mutex_lock(&devc->open_mutex); | 2951 | mutex_lock(&devc->open_mutex); |
@@ -2998,7 +2998,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file) | |||
2998 | 2998 | ||
2999 | file->private_data = devc; | 2999 | file->private_data = devc; |
3000 | DBGRV(); | 3000 | DBGRV(); |
3001 | unlock_kernel(); | 3001 | mutex_unlock(&vwsnd_mutex); |
3002 | return 0; | 3002 | return 0; |
3003 | } | 3003 | } |
3004 | 3004 | ||
@@ -3012,7 +3012,7 @@ static int vwsnd_audio_release(struct inode *inode, struct file *file) | |||
3012 | vwsnd_port_t *wport = NULL, *rport = NULL; | 3012 | vwsnd_port_t *wport = NULL, *rport = NULL; |
3013 | int err = 0; | 3013 | int err = 0; |
3014 | 3014 | ||
3015 | lock_kernel(); | 3015 | mutex_lock(&vwsnd_mutex); |
3016 | mutex_lock(&devc->io_mutex); | 3016 | mutex_lock(&devc->io_mutex); |
3017 | { | 3017 | { |
3018 | DBGEV("(inode=0x%p, file=0x%p)\n", inode, file); | 3018 | DBGEV("(inode=0x%p, file=0x%p)\n", inode, file); |
@@ -3040,7 +3040,7 @@ static int vwsnd_audio_release(struct inode *inode, struct file *file) | |||
3040 | wake_up(&devc->open_wait); | 3040 | wake_up(&devc->open_wait); |
3041 | DEC_USE_COUNT; | 3041 | DEC_USE_COUNT; |
3042 | DBGR(); | 3042 | DBGR(); |
3043 | unlock_kernel(); | 3043 | mutex_unlock(&vwsnd_mutex); |
3044 | return err; | 3044 | return err; |
3045 | } | 3045 | } |
3046 | 3046 | ||
@@ -3068,18 +3068,18 @@ static int vwsnd_mixer_open(struct inode *inode, struct file *file) | |||
3068 | DBGEV("(inode=0x%p, file=0x%p)\n", inode, file); | 3068 | DBGEV("(inode=0x%p, file=0x%p)\n", inode, file); |
3069 | 3069 | ||
3070 | INC_USE_COUNT; | 3070 | INC_USE_COUNT; |
3071 | lock_kernel(); | 3071 | mutex_lock(&vwsnd_mutex); |
3072 | for (devc = vwsnd_dev_list; devc; devc = devc->next_dev) | 3072 | for (devc = vwsnd_dev_list; devc; devc = devc->next_dev) |
3073 | if (devc->mixer_minor == iminor(inode)) | 3073 | if (devc->mixer_minor == iminor(inode)) |
3074 | break; | 3074 | break; |
3075 | 3075 | ||
3076 | if (devc == NULL) { | 3076 | if (devc == NULL) { |
3077 | DEC_USE_COUNT; | 3077 | DEC_USE_COUNT; |
3078 | unlock_kernel(); | 3078 | mutex_unlock(&vwsnd_mutex); |
3079 | return -ENODEV; | 3079 | return -ENODEV; |
3080 | } | 3080 | } |
3081 | file->private_data = devc; | 3081 | file->private_data = devc; |
3082 | unlock_kernel(); | 3082 | mutex_unlock(&vwsnd_mutex); |
3083 | return 0; | 3083 | return 0; |
3084 | } | 3084 | } |
3085 | 3085 | ||
@@ -3223,7 +3223,7 @@ static long vwsnd_mixer_ioctl(struct file *file, | |||
3223 | 3223 | ||
3224 | DBGEV("(devc=0x%p, cmd=0x%x, arg=0x%lx)\n", devc, cmd, arg); | 3224 | DBGEV("(devc=0x%p, cmd=0x%x, arg=0x%lx)\n", devc, cmd, arg); |
3225 | 3225 | ||
3226 | lock_kernel(); | 3226 | mutex_lock(&vwsnd_mutex); |
3227 | mutex_lock(&devc->mix_mutex); | 3227 | mutex_lock(&devc->mix_mutex); |
3228 | { | 3228 | { |
3229 | if ((cmd & ~nrmask) == MIXER_READ(0)) | 3229 | if ((cmd & ~nrmask) == MIXER_READ(0)) |
@@ -3234,7 +3234,7 @@ static long vwsnd_mixer_ioctl(struct file *file, | |||
3234 | retval = -EINVAL; | 3234 | retval = -EINVAL; |
3235 | } | 3235 | } |
3236 | mutex_unlock(&devc->mix_mutex); | 3236 | mutex_unlock(&devc->mix_mutex); |
3237 | unlock_kernel(); | 3237 | mutex_unlock(&vwsnd_mutex); |
3238 | return retval; | 3238 | return retval; |
3239 | } | 3239 | } |
3240 | 3240 | ||
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index e7a8cd058efb..12e34653b8a8 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig | |||
@@ -207,12 +207,12 @@ config SND_CMIPCI | |||
207 | 207 | ||
208 | config SND_OXYGEN_LIB | 208 | config SND_OXYGEN_LIB |
209 | tristate | 209 | tristate |
210 | select SND_PCM | ||
211 | select SND_MPU401_UART | ||
212 | 210 | ||
213 | config SND_OXYGEN | 211 | config SND_OXYGEN |
214 | tristate "C-Media 8788 (Oxygen)" | 212 | tristate "C-Media 8788 (Oxygen)" |
215 | select SND_OXYGEN_LIB | 213 | select SND_OXYGEN_LIB |
214 | select SND_PCM | ||
215 | select SND_MPU401_UART | ||
216 | help | 216 | help |
217 | Say Y here to include support for sound cards based on the | 217 | Say Y here to include support for sound cards based on the |
218 | C-Media CMI8788 (Oxygen HD Audio) chip: | 218 | C-Media CMI8788 (Oxygen HD Audio) chip: |
@@ -581,6 +581,8 @@ config SND_HDSPM | |||
581 | config SND_HIFIER | 581 | config SND_HIFIER |
582 | tristate "TempoTec HiFier Fantasia" | 582 | tristate "TempoTec HiFier Fantasia" |
583 | select SND_OXYGEN_LIB | 583 | select SND_OXYGEN_LIB |
584 | select SND_PCM | ||
585 | select SND_MPU401_UART | ||
584 | help | 586 | help |
585 | Say Y here to include support for the MediaTek/TempoTec HiFier | 587 | Say Y here to include support for the MediaTek/TempoTec HiFier |
586 | Fantasia sound card. | 588 | Fantasia sound card. |
@@ -815,14 +817,17 @@ config SND_VIA82XX_MODEM | |||
815 | will be called snd-via82xx-modem. | 817 | will be called snd-via82xx-modem. |
816 | 818 | ||
817 | config SND_VIRTUOSO | 819 | config SND_VIRTUOSO |
818 | tristate "Asus Virtuoso 100/200 (Xonar)" | 820 | tristate "Asus Virtuoso 66/100/200 (Xonar)" |
819 | select SND_OXYGEN_LIB | 821 | select SND_OXYGEN_LIB |
822 | select SND_PCM | ||
823 | select SND_MPU401_UART | ||
824 | select SND_JACK if INPUT=y || INPUT=SND | ||
820 | help | 825 | help |
821 | Say Y here to include support for sound cards based on the | 826 | Say Y here to include support for sound cards based on the |
822 | Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, | 827 | Asus AV66/AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, DS, |
823 | Essence ST (Deluxe), and Essence STX. | 828 | Essence ST (Deluxe), and Essence STX. |
824 | Support for the DS is experimental. | 829 | Support for the HDAV1.3 (Deluxe) is incomplete; for the |
825 | Support for the HDAV1.3 (Deluxe) is very experimental. | 830 | HDAV1.3 Slim and Xense, missing. |
826 | 831 | ||
827 | To compile this driver as a module, choose M here: the module | 832 | To compile this driver as a module, choose M here: the module |
828 | will be called snd-virtuoso. | 833 | will be called snd-virtuoso. |
diff --git a/sound/pci/au88x0/au88x0_mixer.c b/sound/pci/au88x0/au88x0_mixer.c index c92f493d341e..557c782ae4fc 100644 --- a/sound/pci/au88x0/au88x0_mixer.c +++ b/sound/pci/au88x0/au88x0_mixer.c | |||
@@ -23,7 +23,7 @@ static int __devinit snd_vortex_mixer(vortex_t * vortex) | |||
23 | if ((err = snd_ac97_bus(vortex->card, 0, &ops, NULL, &pbus)) < 0) | 23 | if ((err = snd_ac97_bus(vortex->card, 0, &ops, NULL, &pbus)) < 0) |
24 | return err; | 24 | return err; |
25 | memset(&ac97, 0, sizeof(ac97)); | 25 | memset(&ac97, 0, sizeof(ac97)); |
26 | // Intialize AC97 codec stuff. | 26 | // Initialize AC97 codec stuff. |
27 | ac97.private_data = vortex; | 27 | ac97.private_data = vortex; |
28 | ac97.scaps = AC97_SCAP_NO_SPDIF; | 28 | ac97.scaps = AC97_SCAP_NO_SPDIF; |
29 | err = snd_ac97_mixer(pbus, &ac97, &vortex->codec); | 29 | err = snd_ac97_mixer(pbus, &ac97, &vortex->codec); |
diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index 14b8d9a91aae..f19c11077255 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h | |||
@@ -670,8 +670,9 @@ struct snd_ca0106_details { | |||
670 | gpio_type = 2 -> shared side-out/line-in. */ | 670 | gpio_type = 2 -> shared side-out/line-in. */ |
671 | int i2c_adc; /* with i2c_adc=1, the driver adds some capture volume | 671 | int i2c_adc; /* with i2c_adc=1, the driver adds some capture volume |
672 | controls, phone, mic, line-in and aux. */ | 672 | controls, phone, mic, line-in and aux. */ |
673 | int spi_dac; /* spi_dac=1 adds the mute switch for each analog | 673 | u16 spi_dac; /* spi_dac = 0 -> no spi interface for DACs |
674 | output, front, rear, etc. */ | 674 | spi_dac = 0x<front><rear><center-lfe><side> |
675 | -> specifies DAC id for each channel pair. */ | ||
675 | }; | 676 | }; |
676 | 677 | ||
677 | // definition of the chip-specific record | 678 | // definition of the chip-specific record |
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 0a3d3d6e77b4..d2d12c08f937 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c | |||
@@ -227,7 +227,7 @@ static struct snd_ca0106_details ca0106_chip_details[] = { | |||
227 | .name = "Audigy SE [SB0570]", | 227 | .name = "Audigy SE [SB0570]", |
228 | .gpio_type = 1, | 228 | .gpio_type = 1, |
229 | .i2c_adc = 1, | 229 | .i2c_adc = 1, |
230 | .spi_dac = 1 } , | 230 | .spi_dac = 0x4021 } , |
231 | /* New Audigy LS. Has a different DAC. */ | 231 | /* New Audigy LS. Has a different DAC. */ |
232 | /* SB0570: | 232 | /* SB0570: |
233 | * CTRL:CA0106-DAT | 233 | * CTRL:CA0106-DAT |
@@ -238,7 +238,17 @@ static struct snd_ca0106_details ca0106_chip_details[] = { | |||
238 | .name = "Audigy SE OEM [SB0570a]", | 238 | .name = "Audigy SE OEM [SB0570a]", |
239 | .gpio_type = 1, | 239 | .gpio_type = 1, |
240 | .i2c_adc = 1, | 240 | .i2c_adc = 1, |
241 | .spi_dac = 1 } , | 241 | .spi_dac = 0x4021 } , |
242 | /* Sound Blaster 5.1vx | ||
243 | * Tested: Playback on front, rear, center/lfe speakers | ||
244 | * Not-Tested: Capture | ||
245 | */ | ||
246 | { .serial = 0x10041102, | ||
247 | .name = "Sound Blaster 5.1vx [SB1070]", | ||
248 | .gpio_type = 1, | ||
249 | .i2c_adc = 0, | ||
250 | .spi_dac = 0x0124 | ||
251 | } , | ||
242 | /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */ | 252 | /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */ |
243 | /* SB0438 | 253 | /* SB0438 |
244 | * CTRL:CA0106-DAT | 254 | * CTRL:CA0106-DAT |
@@ -254,7 +264,7 @@ static struct snd_ca0106_details ca0106_chip_details[] = { | |||
254 | .name = "MSI K8N Diamond MB", | 264 | .name = "MSI K8N Diamond MB", |
255 | .gpio_type = 2, | 265 | .gpio_type = 2, |
256 | .i2c_adc = 1, | 266 | .i2c_adc = 1, |
257 | .spi_dac = 1 } , | 267 | .spi_dac = 0x4021 } , |
258 | /* Giga-byte GA-G1975X mobo | 268 | /* Giga-byte GA-G1975X mobo |
259 | * Novell bnc#395807 | 269 | * Novell bnc#395807 |
260 | */ | 270 | */ |
@@ -483,16 +493,18 @@ static void snd_ca0106_pcm_free_substream(struct snd_pcm_runtime *runtime) | |||
483 | } | 493 | } |
484 | 494 | ||
485 | static const int spi_dacd_reg[] = { | 495 | static const int spi_dacd_reg[] = { |
486 | [PCM_FRONT_CHANNEL] = SPI_DACD4_REG, | 496 | SPI_DACD0_REG, |
487 | [PCM_REAR_CHANNEL] = SPI_DACD0_REG, | 497 | SPI_DACD1_REG, |
488 | [PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_REG, | 498 | SPI_DACD2_REG, |
489 | [PCM_UNKNOWN_CHANNEL] = SPI_DACD1_REG, | 499 | 0, |
500 | SPI_DACD4_REG, | ||
490 | }; | 501 | }; |
491 | static const int spi_dacd_bit[] = { | 502 | static const int spi_dacd_bit[] = { |
492 | [PCM_FRONT_CHANNEL] = SPI_DACD4_BIT, | 503 | SPI_DACD0_BIT, |
493 | [PCM_REAR_CHANNEL] = SPI_DACD0_BIT, | 504 | SPI_DACD1_BIT, |
494 | [PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_BIT, | 505 | SPI_DACD2_BIT, |
495 | [PCM_UNKNOWN_CHANNEL] = SPI_DACD1_BIT, | 506 | 0, |
507 | SPI_DACD4_BIT, | ||
496 | }; | 508 | }; |
497 | 509 | ||
498 | static void restore_spdif_bits(struct snd_ca0106 *chip, int idx) | 510 | static void restore_spdif_bits(struct snd_ca0106 *chip, int idx) |
@@ -504,6 +516,45 @@ static void restore_spdif_bits(struct snd_ca0106 *chip, int idx) | |||
504 | } | 516 | } |
505 | } | 517 | } |
506 | 518 | ||
519 | static int snd_ca0106_channel_dac(struct snd_ca0106_details *details, | ||
520 | int channel_id) | ||
521 | { | ||
522 | switch (channel_id) { | ||
523 | case PCM_FRONT_CHANNEL: | ||
524 | return (details->spi_dac & 0xf000) >> (4 * 3); | ||
525 | case PCM_REAR_CHANNEL: | ||
526 | return (details->spi_dac & 0x0f00) >> (4 * 2); | ||
527 | case PCM_CENTER_LFE_CHANNEL: | ||
528 | return (details->spi_dac & 0x00f0) >> (4 * 1); | ||
529 | case PCM_UNKNOWN_CHANNEL: | ||
530 | return (details->spi_dac & 0x000f) >> (4 * 0); | ||
531 | default: | ||
532 | snd_printk(KERN_DEBUG "ca0106: unknown channel_id %d\n", | ||
533 | channel_id); | ||
534 | } | ||
535 | return 0; | ||
536 | } | ||
537 | |||
538 | static int snd_ca0106_pcm_power_dac(struct snd_ca0106 *chip, int channel_id, | ||
539 | int power) | ||
540 | { | ||
541 | if (chip->details->spi_dac) { | ||
542 | const int dac = snd_ca0106_channel_dac(chip->details, | ||
543 | channel_id); | ||
544 | const int reg = spi_dacd_reg[dac]; | ||
545 | const int bit = spi_dacd_bit[dac]; | ||
546 | |||
547 | if (power) | ||
548 | /* Power up */ | ||
549 | chip->spi_dac_reg[reg] &= ~bit; | ||
550 | else | ||
551 | /* Power down */ | ||
552 | chip->spi_dac_reg[reg] |= bit; | ||
553 | return snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]); | ||
554 | } | ||
555 | return 0; | ||
556 | } | ||
557 | |||
507 | /* open_playback callback */ | 558 | /* open_playback callback */ |
508 | static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream, | 559 | static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream, |
509 | int channel_id) | 560 | int channel_id) |
@@ -543,12 +594,9 @@ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substr | |||
543 | return err; | 594 | return err; |
544 | snd_pcm_set_sync(substream); | 595 | snd_pcm_set_sync(substream); |
545 | 596 | ||
546 | if (chip->details->spi_dac && channel_id != PCM_FRONT_CHANNEL) { | 597 | /* Front channel dac should already be on */ |
547 | const int reg = spi_dacd_reg[channel_id]; | 598 | if (channel_id != PCM_FRONT_CHANNEL) { |
548 | 599 | err = snd_ca0106_pcm_power_dac(chip, channel_id, 1); | |
549 | /* Power up dac */ | ||
550 | chip->spi_dac_reg[reg] &= ~spi_dacd_bit[channel_id]; | ||
551 | err = snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]); | ||
552 | if (err < 0) | 600 | if (err < 0) |
553 | return err; | 601 | return err; |
554 | } | 602 | } |
@@ -568,13 +616,14 @@ static int snd_ca0106_pcm_close_playback(struct snd_pcm_substream *substream) | |||
568 | 616 | ||
569 | restore_spdif_bits(chip, epcm->channel_id); | 617 | restore_spdif_bits(chip, epcm->channel_id); |
570 | 618 | ||
571 | if (chip->details->spi_dac && epcm->channel_id != PCM_FRONT_CHANNEL) { | 619 | /* Front channel dac should stay on */ |
572 | const int reg = spi_dacd_reg[epcm->channel_id]; | 620 | if (epcm->channel_id != PCM_FRONT_CHANNEL) { |
573 | 621 | int err; | |
574 | /* Power down DAC */ | 622 | err = snd_ca0106_pcm_power_dac(chip, epcm->channel_id, 0); |
575 | chip->spi_dac_reg[reg] |= spi_dacd_bit[epcm->channel_id]; | 623 | if (err < 0) |
576 | snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]); | 624 | return err; |
577 | } | 625 | } |
626 | |||
578 | /* FIXME: maybe zero others */ | 627 | /* FIXME: maybe zero others */ |
579 | return 0; | 628 | return 0; |
580 | } | 629 | } |
@@ -1002,29 +1051,27 @@ snd_ca0106_pcm_pointer_playback(struct snd_pcm_substream *substream) | |||
1002 | struct snd_ca0106 *emu = snd_pcm_substream_chip(substream); | 1051 | struct snd_ca0106 *emu = snd_pcm_substream_chip(substream); |
1003 | struct snd_pcm_runtime *runtime = substream->runtime; | 1052 | struct snd_pcm_runtime *runtime = substream->runtime; |
1004 | struct snd_ca0106_pcm *epcm = runtime->private_data; | 1053 | struct snd_ca0106_pcm *epcm = runtime->private_data; |
1005 | snd_pcm_uframes_t ptr, ptr1, ptr2,ptr3,ptr4 = 0; | 1054 | unsigned int ptr, prev_ptr; |
1006 | int channel = epcm->channel_id; | 1055 | int channel = epcm->channel_id; |
1056 | int timeout = 10; | ||
1007 | 1057 | ||
1008 | if (!epcm->running) | 1058 | if (!epcm->running) |
1009 | return 0; | 1059 | return 0; |
1010 | 1060 | ||
1011 | ptr3 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel); | 1061 | prev_ptr = -1; |
1012 | ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel); | 1062 | do { |
1013 | ptr4 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel); | 1063 | ptr = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel); |
1014 | if (ptr3 != ptr4) ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel); | 1064 | ptr = (ptr >> 3) * runtime->period_size; |
1015 | ptr2 = bytes_to_frames(runtime, ptr1); | 1065 | ptr += bytes_to_frames(runtime, |
1016 | ptr2+= (ptr4 >> 3) * runtime->period_size; | 1066 | snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel)); |
1017 | ptr=ptr2; | 1067 | if (ptr >= runtime->buffer_size) |
1018 | if (ptr >= runtime->buffer_size) | 1068 | ptr -= runtime->buffer_size; |
1019 | ptr -= runtime->buffer_size; | 1069 | if (prev_ptr == ptr) |
1020 | /* | 1070 | return ptr; |
1021 | printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, " | 1071 | prev_ptr = ptr; |
1022 | "buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", | 1072 | } while (--timeout); |
1023 | ptr1, ptr2, ptr, (int)runtime->buffer_size, | 1073 | snd_printk(KERN_WARNING "ca0106: unstable DMA pointer!\n"); |
1024 | (int)runtime->period_size, (int)runtime->frame_bits, | 1074 | return 0; |
1025 | (int)runtime->rate); | ||
1026 | */ | ||
1027 | return ptr; | ||
1028 | } | 1075 | } |
1029 | 1076 | ||
1030 | /* pointer_capture callback */ | 1077 | /* pointer_capture callback */ |
@@ -1362,7 +1409,7 @@ static unsigned int spi_dac_init[] = { | |||
1362 | SPI_REG(12, 0x00), | 1409 | SPI_REG(12, 0x00), |
1363 | SPI_REG(SPI_LDA4_REG, SPI_DA_BIT_0dB), | 1410 | SPI_REG(SPI_LDA4_REG, SPI_DA_BIT_0dB), |
1364 | SPI_REG(SPI_RDA4_REG, SPI_DA_BIT_0dB | SPI_DA_BIT_UPDATE), | 1411 | SPI_REG(SPI_RDA4_REG, SPI_DA_BIT_0dB | SPI_DA_BIT_UPDATE), |
1365 | SPI_REG(SPI_DACD4_REG, 0x00), | 1412 | SPI_REG(SPI_DACD4_REG, SPI_DACD4_BIT), |
1366 | }; | 1413 | }; |
1367 | 1414 | ||
1368 | static unsigned int i2c_adc_init[][2] = { | 1415 | static unsigned int i2c_adc_init[][2] = { |
@@ -1541,7 +1588,7 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume) | |||
1541 | /* snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); */ | 1588 | /* snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); */ |
1542 | } | 1589 | } |
1543 | 1590 | ||
1544 | if (chip->details->spi_dac == 1) { | 1591 | if (chip->details->spi_dac) { |
1545 | /* The SB0570 use SPI to control DAC. */ | 1592 | /* The SB0570 use SPI to control DAC. */ |
1546 | int size, n; | 1593 | int size, n; |
1547 | 1594 | ||
@@ -1553,6 +1600,9 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume) | |||
1553 | if (reg < ARRAY_SIZE(chip->spi_dac_reg)) | 1600 | if (reg < ARRAY_SIZE(chip->spi_dac_reg)) |
1554 | chip->spi_dac_reg[reg] = spi_dac_init[n]; | 1601 | chip->spi_dac_reg[reg] = spi_dac_init[n]; |
1555 | } | 1602 | } |
1603 | |||
1604 | /* Enable front dac only */ | ||
1605 | snd_ca0106_pcm_power_dac(chip, PCM_FRONT_CHANNEL, 1); | ||
1556 | } | 1606 | } |
1557 | } | 1607 | } |
1558 | 1608 | ||
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 85fd315d9999..630aa4998189 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c | |||
@@ -676,28 +676,65 @@ static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] __devinitdata = | |||
676 | I2C_VOLUME("Aux Capture Volume", 3), | 676 | I2C_VOLUME("Aux Capture Volume", 3), |
677 | }; | 677 | }; |
678 | 678 | ||
679 | #define SPI_SWITCH(xname,reg,bit) \ | 679 | static const int spi_dmute_reg[] = { |
680 | { \ | 680 | SPI_DMUTE0_REG, |
681 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 681 | SPI_DMUTE1_REG, |
682 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | 682 | SPI_DMUTE2_REG, |
683 | .info = spi_mute_info, \ | 683 | 0, |
684 | .get = spi_mute_get, \ | 684 | SPI_DMUTE4_REG, |
685 | .put = spi_mute_put, \ | 685 | }; |
686 | .private_value = (reg<<SPI_REG_SHIFT) | (bit) \ | 686 | static const int spi_dmute_bit[] = { |
687 | } | 687 | SPI_DMUTE0_BIT, |
688 | 688 | SPI_DMUTE1_BIT, | |
689 | static struct snd_kcontrol_new snd_ca0106_volume_spi_dac_ctls[] | 689 | SPI_DMUTE2_BIT, |
690 | __devinitdata = { | 690 | 0, |
691 | SPI_SWITCH("Analog Front Playback Switch", | 691 | SPI_DMUTE4_BIT, |
692 | SPI_DMUTE4_REG, SPI_DMUTE4_BIT), | ||
693 | SPI_SWITCH("Analog Rear Playback Switch", | ||
694 | SPI_DMUTE0_REG, SPI_DMUTE0_BIT), | ||
695 | SPI_SWITCH("Analog Center/LFE Playback Switch", | ||
696 | SPI_DMUTE2_REG, SPI_DMUTE2_BIT), | ||
697 | SPI_SWITCH("Analog Side Playback Switch", | ||
698 | SPI_DMUTE1_REG, SPI_DMUTE1_BIT), | ||
699 | }; | 692 | }; |
700 | 693 | ||
694 | static struct snd_kcontrol_new __devinit | ||
695 | snd_ca0106_volume_spi_dac_ctl(struct snd_ca0106_details *details, | ||
696 | int channel_id) | ||
697 | { | ||
698 | struct snd_kcontrol_new spi_switch = {0}; | ||
699 | int reg, bit; | ||
700 | int dac_id; | ||
701 | |||
702 | spi_switch.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
703 | spi_switch.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; | ||
704 | spi_switch.info = spi_mute_info; | ||
705 | spi_switch.get = spi_mute_get; | ||
706 | spi_switch.put = spi_mute_put; | ||
707 | |||
708 | switch (channel_id) { | ||
709 | case PCM_FRONT_CHANNEL: | ||
710 | spi_switch.name = "Analog Front Playback Switch"; | ||
711 | dac_id = (details->spi_dac & 0xf000) >> (4 * 3); | ||
712 | break; | ||
713 | case PCM_REAR_CHANNEL: | ||
714 | spi_switch.name = "Analog Rear Playback Switch"; | ||
715 | dac_id = (details->spi_dac & 0x0f00) >> (4 * 2); | ||
716 | break; | ||
717 | case PCM_CENTER_LFE_CHANNEL: | ||
718 | spi_switch.name = "Analog Center/LFE Playback Switch"; | ||
719 | dac_id = (details->spi_dac & 0x00f0) >> (4 * 1); | ||
720 | break; | ||
721 | case PCM_UNKNOWN_CHANNEL: | ||
722 | spi_switch.name = "Analog Side Playback Switch"; | ||
723 | dac_id = (details->spi_dac & 0x000f) >> (4 * 0); | ||
724 | break; | ||
725 | default: | ||
726 | /* Unused channel */ | ||
727 | spi_switch.name = NULL; | ||
728 | dac_id = 0; | ||
729 | } | ||
730 | reg = spi_dmute_reg[dac_id]; | ||
731 | bit = spi_dmute_bit[dac_id]; | ||
732 | |||
733 | spi_switch.private_value = (reg << SPI_REG_SHIFT) | bit; | ||
734 | |||
735 | return spi_switch; | ||
736 | } | ||
737 | |||
701 | static int __devinit remove_ctl(struct snd_card *card, const char *name) | 738 | static int __devinit remove_ctl(struct snd_card *card, const char *name) |
702 | { | 739 | { |
703 | struct snd_ctl_elem_id id; | 740 | struct snd_ctl_elem_id id; |
@@ -832,8 +869,18 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) | |||
832 | if (err < 0) | 869 | if (err < 0) |
833 | return err; | 870 | return err; |
834 | } | 871 | } |
835 | if (emu->details->spi_dac == 1) | 872 | if (emu->details->spi_dac) { |
836 | ADD_CTLS(emu, snd_ca0106_volume_spi_dac_ctls); | 873 | int i; |
874 | for (i = 0;; i++) { | ||
875 | struct snd_kcontrol_new ctl; | ||
876 | ctl = snd_ca0106_volume_spi_dac_ctl(emu->details, i); | ||
877 | if (!ctl.name) | ||
878 | break; | ||
879 | err = snd_ctl_add(card, snd_ctl_new1(&ctl, emu)); | ||
880 | if (err < 0) | ||
881 | return err; | ||
882 | } | ||
883 | } | ||
837 | 884 | ||
838 | /* Create virtual master controls */ | 885 | /* Create virtual master controls */ |
839 | vmaster = snd_ctl_make_virtual_master("Master Playback Volume", | 886 | vmaster = snd_ctl_make_virtual_master("Master Playback Volume", |
@@ -845,7 +892,7 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) | |||
845 | return err; | 892 | return err; |
846 | add_slaves(card, vmaster, slave_vols); | 893 | add_slaves(card, vmaster, slave_vols); |
847 | 894 | ||
848 | if (emu->details->spi_dac == 1) { | 895 | if (emu->details->spi_dac) { |
849 | vmaster = snd_ctl_make_virtual_master("Master Playback Switch", | 896 | vmaster = snd_ctl_make_virtual_master("Master Playback Switch", |
850 | NULL); | 897 | NULL); |
851 | if (!vmaster) | 898 | if (!vmaster) |
diff --git a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c index 8578c70c61f2..bab564824efe 100644 --- a/sound/pci/emu10k1/emumpu401.c +++ b/sound/pci/emu10k1/emumpu401.c | |||
@@ -321,7 +321,7 @@ static struct snd_rawmidi_ops snd_emu10k1_midi_input = | |||
321 | 321 | ||
322 | static void snd_emu10k1_midi_free(struct snd_rawmidi *rmidi) | 322 | static void snd_emu10k1_midi_free(struct snd_rawmidi *rmidi) |
323 | { | 323 | { |
324 | struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)rmidi->private_data; | 324 | struct snd_emu10k1_midi *midi = rmidi->private_data; |
325 | midi->interrupt = NULL; | 325 | midi->interrupt = NULL; |
326 | midi->rmidi = NULL; | 326 | midi->rmidi = NULL; |
327 | } | 327 | } |
diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c index d216362626d0..712c1710f9a2 100644 --- a/sound/pci/ice1712/delta.c +++ b/sound/pci/ice1712/delta.c | |||
@@ -563,6 +563,7 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice) | |||
563 | case ICE1712_SUBDEVICE_DELTA1010E: | 563 | case ICE1712_SUBDEVICE_DELTA1010E: |
564 | case ICE1712_SUBDEVICE_DELTA1010LT: | 564 | case ICE1712_SUBDEVICE_DELTA1010LT: |
565 | case ICE1712_SUBDEVICE_MEDIASTATION: | 565 | case ICE1712_SUBDEVICE_MEDIASTATION: |
566 | case ICE1712_SUBDEVICE_EDIROLDA2496: | ||
566 | ice->num_total_dacs = 8; | 567 | ice->num_total_dacs = 8; |
567 | ice->num_total_adcs = 8; | 568 | ice->num_total_adcs = 8; |
568 | break; | 569 | break; |
@@ -635,6 +636,7 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice) | |||
635 | err = snd_ice1712_akm4xxx_init(ak, &akm_delta410, &akm_delta410_priv, ice); | 636 | err = snd_ice1712_akm4xxx_init(ak, &akm_delta410, &akm_delta410_priv, ice); |
636 | break; | 637 | break; |
637 | case ICE1712_SUBDEVICE_DELTA1010LT: | 638 | case ICE1712_SUBDEVICE_DELTA1010LT: |
639 | case ICE1712_SUBDEVICE_EDIROLDA2496: | ||
638 | err = snd_ice1712_akm4xxx_init(ak, &akm_delta1010lt, &akm_delta1010lt_priv, ice); | 640 | err = snd_ice1712_akm4xxx_init(ak, &akm_delta1010lt, &akm_delta1010lt_priv, ice); |
639 | break; | 641 | break; |
640 | case ICE1712_SUBDEVICE_DELTA66: | 642 | case ICE1712_SUBDEVICE_DELTA66: |
@@ -734,6 +736,7 @@ static int __devinit snd_ice1712_delta_add_controls(struct snd_ice1712 *ice) | |||
734 | case ICE1712_SUBDEVICE_DELTA66: | 736 | case ICE1712_SUBDEVICE_DELTA66: |
735 | case ICE1712_SUBDEVICE_VX442: | 737 | case ICE1712_SUBDEVICE_VX442: |
736 | case ICE1712_SUBDEVICE_DELTA66E: | 738 | case ICE1712_SUBDEVICE_DELTA66E: |
739 | case ICE1712_SUBDEVICE_EDIROLDA2496: | ||
737 | err = snd_ice1712_akm4xxx_build_controls(ice); | 740 | err = snd_ice1712_akm4xxx_build_controls(ice); |
738 | if (err < 0) | 741 | if (err < 0) |
739 | return err; | 742 | return err; |
@@ -813,5 +816,12 @@ struct snd_ice1712_card_info snd_ice1712_delta_cards[] __devinitdata = { | |||
813 | .chip_init = snd_ice1712_delta_init, | 816 | .chip_init = snd_ice1712_delta_init, |
814 | .build_controls = snd_ice1712_delta_add_controls, | 817 | .build_controls = snd_ice1712_delta_add_controls, |
815 | }, | 818 | }, |
819 | { | ||
820 | .subvendor = ICE1712_SUBDEVICE_EDIROLDA2496, | ||
821 | .name = "Edirol DA2496", | ||
822 | .model = "da2496", | ||
823 | .chip_init = snd_ice1712_delta_init, | ||
824 | .build_controls = snd_ice1712_delta_add_controls, | ||
825 | }, | ||
816 | { } /* terminator */ | 826 | { } /* terminator */ |
817 | }; | 827 | }; |
diff --git a/sound/pci/ice1712/delta.h b/sound/pci/ice1712/delta.h index f7f14df81f26..1a0ac6cd6501 100644 --- a/sound/pci/ice1712/delta.h +++ b/sound/pci/ice1712/delta.h | |||
@@ -34,7 +34,8 @@ | |||
34 | "{MidiMan M Audio,Delta 410},"\ | 34 | "{MidiMan M Audio,Delta 410},"\ |
35 | "{MidiMan M Audio,Audiophile 24/96},"\ | 35 | "{MidiMan M Audio,Audiophile 24/96},"\ |
36 | "{Digigram,VX442},"\ | 36 | "{Digigram,VX442},"\ |
37 | "{Lionstracs,Mediastation}," | 37 | "{Lionstracs,Mediastation},"\ |
38 | "{Edirol,DA2496}," | ||
38 | 39 | ||
39 | #define ICE1712_SUBDEVICE_DELTA1010 0x121430d6 | 40 | #define ICE1712_SUBDEVICE_DELTA1010 0x121430d6 |
40 | #define ICE1712_SUBDEVICE_DELTA1010E 0xff1430d6 | 41 | #define ICE1712_SUBDEVICE_DELTA1010E 0xff1430d6 |
@@ -47,6 +48,7 @@ | |||
47 | #define ICE1712_SUBDEVICE_DELTA1010LT 0x12143bd6 | 48 | #define ICE1712_SUBDEVICE_DELTA1010LT 0x12143bd6 |
48 | #define ICE1712_SUBDEVICE_VX442 0x12143cd6 | 49 | #define ICE1712_SUBDEVICE_VX442 0x12143cd6 |
49 | #define ICE1712_SUBDEVICE_MEDIASTATION 0x694c0100 | 50 | #define ICE1712_SUBDEVICE_MEDIASTATION 0x694c0100 |
51 | #define ICE1712_SUBDEVICE_EDIROLDA2496 0xce164010 | ||
50 | 52 | ||
51 | /* entry point */ | 53 | /* entry point */ |
52 | extern struct snd_ice1712_card_info snd_ice1712_delta_cards[]; | 54 | extern struct snd_ice1712_card_info snd_ice1712_delta_cards[]; |
diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c index 6bc3f91b7281..cdb873f5da50 100644 --- a/sound/pci/ice1712/pontis.c +++ b/sound/pci/ice1712/pontis.c | |||
@@ -638,7 +638,7 @@ static struct snd_kcontrol_new pontis_controls[] __devinitdata = { | |||
638 | */ | 638 | */ |
639 | static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | 639 | static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buffer *buffer) |
640 | { | 640 | { |
641 | struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; | 641 | struct snd_ice1712 *ice = entry->private_data; |
642 | char line[64]; | 642 | char line[64]; |
643 | unsigned int reg, val; | 643 | unsigned int reg, val; |
644 | mutex_lock(&ice->gpio_mutex); | 644 | mutex_lock(&ice->gpio_mutex); |
@@ -653,7 +653,7 @@ static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buf | |||
653 | 653 | ||
654 | static void wm_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | 654 | static void wm_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) |
655 | { | 655 | { |
656 | struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; | 656 | struct snd_ice1712 *ice = entry->private_data; |
657 | int reg, val; | 657 | int reg, val; |
658 | 658 | ||
659 | mutex_lock(&ice->gpio_mutex); | 659 | mutex_lock(&ice->gpio_mutex); |
@@ -676,7 +676,7 @@ static void wm_proc_init(struct snd_ice1712 *ice) | |||
676 | 676 | ||
677 | static void cs_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | 677 | static void cs_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) |
678 | { | 678 | { |
679 | struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; | 679 | struct snd_ice1712 *ice = entry->private_data; |
680 | int reg, val; | 680 | int reg, val; |
681 | 681 | ||
682 | mutex_lock(&ice->gpio_mutex); | 682 | mutex_lock(&ice->gpio_mutex); |
diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c index 2a8e5cd8f2d8..e36ddb94c382 100644 --- a/sound/pci/ice1712/prodigy192.c +++ b/sound/pci/ice1712/prodigy192.c | |||
@@ -654,7 +654,7 @@ static int prodigy192_ak4114_init(struct snd_ice1712 *ice) | |||
654 | static void stac9460_proc_regs_read(struct snd_info_entry *entry, | 654 | static void stac9460_proc_regs_read(struct snd_info_entry *entry, |
655 | struct snd_info_buffer *buffer) | 655 | struct snd_info_buffer *buffer) |
656 | { | 656 | { |
657 | struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; | 657 | struct snd_ice1712 *ice = entry->private_data; |
658 | int reg, val; | 658 | int reg, val; |
659 | /* registers 0x0 - 0x14 */ | 659 | /* registers 0x0 - 0x14 */ |
660 | for (reg = 0; reg <= 0x15; reg++) { | 660 | for (reg = 0; reg <= 0x15; reg++) { |
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 6c0a11adb2a8..98a8eb3c92f7 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c | |||
@@ -79,6 +79,7 @@ static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { | |||
79 | { OXYGEN_PCI_SUBID(0x13f6, 0x0001), .driver_data = MODEL_CMEDIA_REF }, | 79 | { OXYGEN_PCI_SUBID(0x13f6, 0x0001), .driver_data = MODEL_CMEDIA_REF }, |
80 | { OXYGEN_PCI_SUBID(0x13f6, 0x0010), .driver_data = MODEL_CMEDIA_REF }, | 80 | { OXYGEN_PCI_SUBID(0x13f6, 0x0010), .driver_data = MODEL_CMEDIA_REF }, |
81 | { OXYGEN_PCI_SUBID(0x13f6, 0x8788), .driver_data = MODEL_CMEDIA_REF }, | 81 | { OXYGEN_PCI_SUBID(0x13f6, 0x8788), .driver_data = MODEL_CMEDIA_REF }, |
82 | { OXYGEN_PCI_SUBID(0x13f6, 0xffff), .driver_data = MODEL_CMEDIA_REF }, | ||
82 | { OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF }, | 83 | { OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF }, |
83 | { OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF }, | 84 | { OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF }, |
84 | { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN }, | 85 | { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN }, |
@@ -505,7 +506,8 @@ static const struct oxygen_model model_generic = { | |||
505 | PLAYBACK_2_TO_AC97_1 | | 506 | PLAYBACK_2_TO_AC97_1 | |
506 | CAPTURE_0_FROM_I2S_1 | | 507 | CAPTURE_0_FROM_I2S_1 | |
507 | CAPTURE_1_FROM_SPDIF | | 508 | CAPTURE_1_FROM_SPDIF | |
508 | CAPTURE_2_FROM_AC97_1, | 509 | CAPTURE_2_FROM_AC97_1 | |
510 | AC97_CD_INPUT, | ||
509 | .dac_channels = 8, | 511 | .dac_channels = 8, |
510 | .dac_volume_min = 0, | 512 | .dac_volume_min = 0, |
511 | .dac_volume_max = 255, | 513 | .dac_volume_max = 255, |
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index a3409edcfb50..7d5222caa0a9 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h | |||
@@ -34,6 +34,7 @@ | |||
34 | /* CAPTURE_3_FROM_I2S_3 not implemented */ | 34 | /* CAPTURE_3_FROM_I2S_3 not implemented */ |
35 | #define MIDI_OUTPUT 0x0800 | 35 | #define MIDI_OUTPUT 0x0800 |
36 | #define MIDI_INPUT 0x1000 | 36 | #define MIDI_INPUT 0x1000 |
37 | #define AC97_CD_INPUT 0x2000 | ||
37 | 38 | ||
38 | enum { | 39 | enum { |
39 | CONTROL_SPDIF_PCM, | 40 | CONTROL_SPDIF_PCM, |
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index 7e93cf884437..e5ebe56fb0c5 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c | |||
@@ -308,25 +308,46 @@ static void oxygen_restore_eeprom(struct oxygen *chip, | |||
308 | } | 308 | } |
309 | } | 309 | } |
310 | 310 | ||
311 | static void pci_bridge_magic(void) | 311 | static void configure_pcie_bridge(struct pci_dev *pci) |
312 | { | 312 | { |
313 | struct pci_dev *pci = NULL; | 313 | enum { PEX811X, PI7C9X110 }; |
314 | static const struct pci_device_id bridge_ids[] = { | ||
315 | { PCI_VDEVICE(PLX, 0x8111), .driver_data = PEX811X }, | ||
316 | { PCI_VDEVICE(PLX, 0x8112), .driver_data = PEX811X }, | ||
317 | { PCI_DEVICE(0x12d8, 0xe110), .driver_data = PI7C9X110 }, | ||
318 | { } | ||
319 | }; | ||
320 | struct pci_dev *bridge; | ||
321 | const struct pci_device_id *id; | ||
314 | u32 tmp; | 322 | u32 tmp; |
315 | 323 | ||
316 | for (;;) { | 324 | if (!pci->bus || !pci->bus->self) |
317 | /* If there is any Pericom PI7C9X110 PCI-E/PCI bridge ... */ | 325 | return; |
318 | pci = pci_get_device(0x12d8, 0xe110, pci); | 326 | bridge = pci->bus->self; |
319 | if (!pci) | 327 | |
320 | break; | 328 | id = pci_match_id(bridge_ids, bridge); |
321 | /* | 329 | if (!id) |
322 | * ... configure its secondary internal arbiter to park to | 330 | return; |
323 | * the secondary port, instead of to the last master. | 331 | |
324 | */ | 332 | switch (id->driver_data) { |
325 | if (!pci_read_config_dword(pci, 0x40, &tmp)) { | 333 | case PEX811X: /* PLX PEX8111/PEX8112 PCIe/PCI bridge */ |
326 | tmp |= 1; | 334 | pci_read_config_dword(bridge, 0x48, &tmp); |
327 | pci_write_config_dword(pci, 0x40, tmp); | 335 | tmp |= 1; /* enable blind prefetching */ |
328 | } | 336 | tmp |= 1 << 11; /* enable beacon generation */ |
329 | /* Why? Try asking C-Media. */ | 337 | pci_write_config_dword(bridge, 0x48, tmp); |
338 | |||
339 | pci_write_config_dword(bridge, 0x84, 0x0c); | ||
340 | pci_read_config_dword(bridge, 0x88, &tmp); | ||
341 | tmp &= ~(7 << 27); | ||
342 | tmp |= 2 << 27; /* set prefetch size to 128 bytes */ | ||
343 | pci_write_config_dword(bridge, 0x88, tmp); | ||
344 | break; | ||
345 | |||
346 | case PI7C9X110: /* Pericom PI7C9X110 PCIe/PCI bridge */ | ||
347 | pci_read_config_dword(bridge, 0x40, &tmp); | ||
348 | tmp |= 1; /* park the PCI arbiter to the sound chip */ | ||
349 | pci_write_config_dword(bridge, 0x40, tmp); | ||
350 | break; | ||
330 | } | 351 | } |
331 | } | 352 | } |
332 | 353 | ||
@@ -613,7 +634,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, | |||
613 | snd_card_set_dev(card, &pci->dev); | 634 | snd_card_set_dev(card, &pci->dev); |
614 | card->private_free = oxygen_card_free; | 635 | card->private_free = oxygen_card_free; |
615 | 636 | ||
616 | pci_bridge_magic(); | 637 | configure_pcie_bridge(pci); |
617 | oxygen_init(chip); | 638 | oxygen_init(chip); |
618 | chip->model.init(chip); | 639 | chip->model.init(chip); |
619 | 640 | ||
diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index f375b8a27862..2849b36f5f7e 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c | |||
@@ -708,7 +708,7 @@ static int ac97_fp_rec_volume_put(struct snd_kcontrol *ctl, | |||
708 | .private_value = ((codec) << 24) | ((stereo) << 16) | (index), \ | 708 | .private_value = ((codec) << 24) | ((stereo) << 16) | (index), \ |
709 | } | 709 | } |
710 | 710 | ||
711 | static DECLARE_TLV_DB_SCALE(monitor_db_scale, -1000, 1000, 0); | 711 | static DECLARE_TLV_DB_SCALE(monitor_db_scale, -600, 600, 0); |
712 | static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0); | 712 | static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0); |
713 | static DECLARE_TLV_DB_SCALE(ac97_rec_db_scale, 0, 150, 0); | 713 | static DECLARE_TLV_DB_SCALE(ac97_rec_db_scale, 0, 150, 0); |
714 | 714 | ||
@@ -972,6 +972,9 @@ static int add_controls(struct oxygen *chip, | |||
972 | if (!strcmp(template.name, "Stereo Upmixing") && | 972 | if (!strcmp(template.name, "Stereo Upmixing") && |
973 | chip->model.dac_channels == 2) | 973 | chip->model.dac_channels == 2) |
974 | continue; | 974 | continue; |
975 | if (!strncmp(template.name, "CD Capture ", 11) && | ||
976 | !(chip->model.device_config & AC97_CD_INPUT)) | ||
977 | continue; | ||
975 | if (!strcmp(template.name, "Master Playback Volume") && | 978 | if (!strcmp(template.name, "Master Playback Volume") && |
976 | chip->model.dac_tlv) { | 979 | chip->model.dac_tlv) { |
977 | template.tlv.p = chip->model.dac_tlv; | 980 | template.tlv.p = chip->model.dac_tlv; |
diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c index 9dff6954c397..814667442eb0 100644 --- a/sound/pci/oxygen/oxygen_pcm.c +++ b/sound/pci/oxygen/oxygen_pcm.c | |||
@@ -56,8 +56,8 @@ static const struct snd_pcm_hardware oxygen_stereo_hardware = { | |||
56 | .channels_max = 2, | 56 | .channels_max = 2, |
57 | .buffer_bytes_max = BUFFER_BYTES_MAX, | 57 | .buffer_bytes_max = BUFFER_BYTES_MAX, |
58 | .period_bytes_min = PERIOD_BYTES_MIN, | 58 | .period_bytes_min = PERIOD_BYTES_MIN, |
59 | .period_bytes_max = BUFFER_BYTES_MAX / 2, | 59 | .period_bytes_max = BUFFER_BYTES_MAX, |
60 | .periods_min = 2, | 60 | .periods_min = 1, |
61 | .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, | 61 | .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, |
62 | }; | 62 | }; |
63 | static const struct snd_pcm_hardware oxygen_multichannel_hardware = { | 63 | static const struct snd_pcm_hardware oxygen_multichannel_hardware = { |
@@ -82,8 +82,8 @@ static const struct snd_pcm_hardware oxygen_multichannel_hardware = { | |||
82 | .channels_max = 8, | 82 | .channels_max = 8, |
83 | .buffer_bytes_max = BUFFER_BYTES_MAX_MULTICH, | 83 | .buffer_bytes_max = BUFFER_BYTES_MAX_MULTICH, |
84 | .period_bytes_min = PERIOD_BYTES_MIN, | 84 | .period_bytes_min = PERIOD_BYTES_MIN, |
85 | .period_bytes_max = BUFFER_BYTES_MAX_MULTICH / 2, | 85 | .period_bytes_max = BUFFER_BYTES_MAX_MULTICH, |
86 | .periods_min = 2, | 86 | .periods_min = 1, |
87 | .periods_max = BUFFER_BYTES_MAX_MULTICH / PERIOD_BYTES_MIN, | 87 | .periods_max = BUFFER_BYTES_MAX_MULTICH / PERIOD_BYTES_MIN, |
88 | }; | 88 | }; |
89 | static const struct snd_pcm_hardware oxygen_ac97_hardware = { | 89 | static const struct snd_pcm_hardware oxygen_ac97_hardware = { |
@@ -100,8 +100,8 @@ static const struct snd_pcm_hardware oxygen_ac97_hardware = { | |||
100 | .channels_max = 2, | 100 | .channels_max = 2, |
101 | .buffer_bytes_max = BUFFER_BYTES_MAX, | 101 | .buffer_bytes_max = BUFFER_BYTES_MAX, |
102 | .period_bytes_min = PERIOD_BYTES_MIN, | 102 | .period_bytes_min = PERIOD_BYTES_MIN, |
103 | .period_bytes_max = BUFFER_BYTES_MAX / 2, | 103 | .period_bytes_max = BUFFER_BYTES_MAX, |
104 | .periods_min = 2, | 104 | .periods_min = 1, |
105 | .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, | 105 | .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, |
106 | }; | 106 | }; |
107 | 107 | ||
diff --git a/sound/pci/oxygen/oxygen_regs.h b/sound/pci/oxygen/oxygen_regs.h index 72de159d4567..4dcd41b78258 100644 --- a/sound/pci/oxygen/oxygen_regs.h +++ b/sound/pci/oxygen/oxygen_regs.h | |||
@@ -436,13 +436,15 @@ | |||
436 | /* OXYGEN_CHANNEL_* */ | 436 | /* OXYGEN_CHANNEL_* */ |
437 | 437 | ||
438 | #define OXYGEN_CODEC_VERSION 0xe4 | 438 | #define OXYGEN_CODEC_VERSION 0xe4 |
439 | #define OXYGEN_XCID_MASK 0x07 | 439 | #define OXYGEN_CODEC_ID_MASK 0x07 |
440 | 440 | ||
441 | #define OXYGEN_REVISION 0xe6 | 441 | #define OXYGEN_REVISION 0xe6 |
442 | #define OXYGEN_REVISION_XPKGID_MASK 0x0007 | 442 | #define OXYGEN_PACKAGE_ID_MASK 0x0007 |
443 | #define OXYGEN_PACKAGE_ID_8786 0x0004 | ||
444 | #define OXYGEN_PACKAGE_ID_8787 0x0006 | ||
445 | #define OXYGEN_PACKAGE_ID_8788 0x0007 | ||
443 | #define OXYGEN_REVISION_MASK 0xfff8 | 446 | #define OXYGEN_REVISION_MASK 0xfff8 |
444 | #define OXYGEN_REVISION_2 0x0008 /* bit flag */ | 447 | #define OXYGEN_REVISION_2 0x0008 |
445 | #define OXYGEN_REVISION_8787 0x0014 /* 8 bits */ | ||
446 | 448 | ||
447 | #define OXYGEN_OFFSIN_48K 0xe8 | 449 | #define OXYGEN_OFFSIN_48K 0xe8 |
448 | #define OXYGEN_OFFSBASE_48K 0xe9 | 450 | #define OXYGEN_OFFSBASE_48K 0xe9 |
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 06c863e86e3d..469010a8b849 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c | |||
@@ -25,9 +25,9 @@ | |||
25 | #include "xonar.h" | 25 | #include "xonar.h" |
26 | 26 | ||
27 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | 27 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); |
28 | MODULE_DESCRIPTION("Asus AVx00 driver"); | 28 | MODULE_DESCRIPTION("Asus Virtuoso driver"); |
29 | MODULE_LICENSE("GPL v2"); | 29 | MODULE_LICENSE("GPL v2"); |
30 | MODULE_SUPPORTED_DEVICE("{{Asus,AV100},{Asus,AV200}}"); | 30 | MODULE_SUPPORTED_DEVICE("{{Asus,AV66},{Asus,AV100},{Asus,AV200}}"); |
31 | 31 | ||
32 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | 32 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; |
33 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | 33 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; |
@@ -49,6 +49,7 @@ static DEFINE_PCI_DEVICE_TABLE(xonar_ids) = { | |||
49 | { OXYGEN_PCI_SUBID(0x1043, 0x834f) }, | 49 | { OXYGEN_PCI_SUBID(0x1043, 0x834f) }, |
50 | { OXYGEN_PCI_SUBID(0x1043, 0x835c) }, | 50 | { OXYGEN_PCI_SUBID(0x1043, 0x835c) }, |
51 | { OXYGEN_PCI_SUBID(0x1043, 0x835d) }, | 51 | { OXYGEN_PCI_SUBID(0x1043, 0x835d) }, |
52 | { OXYGEN_PCI_SUBID(0x1043, 0x835e) }, | ||
52 | { OXYGEN_PCI_SUBID(0x1043, 0x838e) }, | 53 | { OXYGEN_PCI_SUBID(0x1043, 0x838e) }, |
53 | { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, | 54 | { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, |
54 | { } | 55 | { } |
diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c index 7c4986b27f2b..aa27c31049af 100644 --- a/sound/pci/oxygen/xonar_cs43xx.c +++ b/sound/pci/oxygen/xonar_cs43xx.c | |||
@@ -367,13 +367,6 @@ static void xonar_d1_line_mic_ac97_switch(struct oxygen *chip, | |||
367 | 367 | ||
368 | static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -6000, 100, 0); | 368 | static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -6000, 100, 0); |
369 | 369 | ||
370 | static int xonar_d1_control_filter(struct snd_kcontrol_new *template) | ||
371 | { | ||
372 | if (!strncmp(template->name, "CD Capture ", 11)) | ||
373 | return 1; /* no CD input */ | ||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | static int xonar_d1_mixer_init(struct oxygen *chip) | 370 | static int xonar_d1_mixer_init(struct oxygen *chip) |
378 | { | 371 | { |
379 | int err; | 372 | int err; |
@@ -391,7 +384,6 @@ static const struct oxygen_model model_xonar_d1 = { | |||
391 | .longname = "Asus Virtuoso 100", | 384 | .longname = "Asus Virtuoso 100", |
392 | .chip = "AV200", | 385 | .chip = "AV200", |
393 | .init = xonar_d1_init, | 386 | .init = xonar_d1_init, |
394 | .control_filter = xonar_d1_control_filter, | ||
395 | .mixer_init = xonar_d1_mixer_init, | 387 | .mixer_init = xonar_d1_mixer_init, |
396 | .cleanup = xonar_d1_cleanup, | 388 | .cleanup = xonar_d1_cleanup, |
397 | .suspend = xonar_d1_suspend, | 389 | .suspend = xonar_d1_suspend, |
diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index ba18fb546b4f..d491fd6c0be2 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c | |||
@@ -132,6 +132,18 @@ | |||
132 | * GPIO 5 <- 0 | 132 | * GPIO 5 <- 0 |
133 | */ | 133 | */ |
134 | 134 | ||
135 | /* | ||
136 | * Xonar HDAV1.3 Slim | ||
137 | * ------------------ | ||
138 | * | ||
139 | * CMI8788: | ||
140 | * | ||
141 | * GPIO 1 -> enable output | ||
142 | * | ||
143 | * TXD -> HDMI controller | ||
144 | * RXD <- HDMI controller | ||
145 | */ | ||
146 | |||
135 | #include <linux/pci.h> | 147 | #include <linux/pci.h> |
136 | #include <linux/delay.h> | 148 | #include <linux/delay.h> |
137 | #include <linux/mutex.h> | 149 | #include <linux/mutex.h> |
@@ -362,7 +374,6 @@ static void xonar_st_init_common(struct oxygen *chip) | |||
362 | { | 374 | { |
363 | struct xonar_pcm179x *data = chip->model_data; | 375 | struct xonar_pcm179x *data = chip->model_data; |
364 | 376 | ||
365 | data->generic.anti_pop_delay = 100; | ||
366 | data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE; | 377 | data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE; |
367 | data->dacs = chip->model.private_data ? 4 : 1; | 378 | data->dacs = chip->model.private_data ? 4 : 1; |
368 | data->hp_gain_offset = 2*-18; | 379 | data->hp_gain_offset = 2*-18; |
@@ -408,6 +419,7 @@ static void xonar_st_init(struct oxygen *chip) | |||
408 | { | 419 | { |
409 | struct xonar_pcm179x *data = chip->model_data; | 420 | struct xonar_pcm179x *data = chip->model_data; |
410 | 421 | ||
422 | data->generic.anti_pop_delay = 100; | ||
411 | data->has_cs2000 = 1; | 423 | data->has_cs2000 = 1; |
412 | data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1; | 424 | data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1; |
413 | 425 | ||
@@ -428,6 +440,7 @@ static void xonar_stx_init(struct oxygen *chip) | |||
428 | struct xonar_pcm179x *data = chip->model_data; | 440 | struct xonar_pcm179x *data = chip->model_data; |
429 | 441 | ||
430 | xonar_st_init_i2c(chip); | 442 | xonar_st_init_i2c(chip); |
443 | data->generic.anti_pop_delay = 800; | ||
431 | data->generic.ext_power_reg = OXYGEN_GPI_DATA; | 444 | data->generic.ext_power_reg = OXYGEN_GPI_DATA; |
432 | data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; | 445 | data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; |
433 | data->generic.ext_power_bit = GPI_EXT_POWER; | 446 | data->generic.ext_power_bit = GPI_EXT_POWER; |
@@ -915,13 +928,6 @@ static int xonar_d2_control_filter(struct snd_kcontrol_new *template) | |||
915 | return 0; | 928 | return 0; |
916 | } | 929 | } |
917 | 930 | ||
918 | static int xonar_st_control_filter(struct snd_kcontrol_new *template) | ||
919 | { | ||
920 | if (!strncmp(template->name, "CD Capture ", 11)) | ||
921 | return 1; /* no CD input */ | ||
922 | return 0; | ||
923 | } | ||
924 | |||
925 | static int add_pcm1796_controls(struct oxygen *chip) | 931 | static int add_pcm1796_controls(struct oxygen *chip) |
926 | { | 932 | { |
927 | int err; | 933 | int err; |
@@ -991,7 +997,8 @@ static const struct oxygen_model model_xonar_d2 = { | |||
991 | CAPTURE_0_FROM_I2S_2 | | 997 | CAPTURE_0_FROM_I2S_2 | |
992 | CAPTURE_1_FROM_SPDIF | | 998 | CAPTURE_1_FROM_SPDIF | |
993 | MIDI_OUTPUT | | 999 | MIDI_OUTPUT | |
994 | MIDI_INPUT, | 1000 | MIDI_INPUT | |
1001 | AC97_CD_INPUT, | ||
995 | .dac_channels = 8, | 1002 | .dac_channels = 8, |
996 | .dac_volume_min = 255 - 2*60, | 1003 | .dac_volume_min = 255 - 2*60, |
997 | .dac_volume_max = 255, | 1004 | .dac_volume_max = 255, |
@@ -1037,7 +1044,6 @@ static const struct oxygen_model model_xonar_st = { | |||
1037 | .longname = "Asus Virtuoso 100", | 1044 | .longname = "Asus Virtuoso 100", |
1038 | .chip = "AV200", | 1045 | .chip = "AV200", |
1039 | .init = xonar_st_init, | 1046 | .init = xonar_st_init, |
1040 | .control_filter = xonar_st_control_filter, | ||
1041 | .mixer_init = xonar_st_mixer_init, | 1047 | .mixer_init = xonar_st_mixer_init, |
1042 | .cleanup = xonar_st_cleanup, | 1048 | .cleanup = xonar_st_cleanup, |
1043 | .suspend = xonar_st_suspend, | 1049 | .suspend = xonar_st_suspend, |
@@ -1108,6 +1114,9 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip, | |||
1108 | chip->model.resume = xonar_stx_resume; | 1114 | chip->model.resume = xonar_stx_resume; |
1109 | chip->model.set_dac_params = set_pcm1796_params; | 1115 | chip->model.set_dac_params = set_pcm1796_params; |
1110 | break; | 1116 | break; |
1117 | case 0x835e: | ||
1118 | snd_printk(KERN_ERR "the HDAV1.3 Slim is not supported\n"); | ||
1119 | return -ENODEV; | ||
1111 | default: | 1120 | default: |
1112 | return -EINVAL; | 1121 | return -EINVAL; |
1113 | } | 1122 | } |
diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index b82c1cfa96f5..200f7601276f 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c | |||
@@ -25,16 +25,24 @@ | |||
25 | * SPI 0 -> WM8766 (surround, center/LFE, back) | 25 | * SPI 0 -> WM8766 (surround, center/LFE, back) |
26 | * SPI 1 -> WM8776 (front, input) | 26 | * SPI 1 -> WM8776 (front, input) |
27 | * | 27 | * |
28 | * GPIO 4 <- headphone detect | 28 | * GPIO 4 <- headphone detect, 0 = plugged |
29 | * GPIO 6 -> route input jack to input 1/2 (1/0) | 29 | * GPIO 6 -> route input jack to mic-in (0) or line-in (1) |
30 | * GPIO 7 -> enable output to speakers | 30 | * GPIO 7 -> enable output to front L/R speaker channels |
31 | * GPIO 8 -> enable output to speakers | 31 | * GPIO 8 -> enable output to other speaker channels and front panel headphone |
32 | * | ||
33 | * WM8766: | ||
34 | * | ||
35 | * input 1 <- line | ||
36 | * input 2 <- mic | ||
37 | * input 3 <- front mic | ||
38 | * input 4 <- aux | ||
32 | */ | 39 | */ |
33 | 40 | ||
34 | #include <linux/pci.h> | 41 | #include <linux/pci.h> |
35 | #include <linux/delay.h> | 42 | #include <linux/delay.h> |
36 | #include <sound/control.h> | 43 | #include <sound/control.h> |
37 | #include <sound/core.h> | 44 | #include <sound/core.h> |
45 | #include <sound/jack.h> | ||
38 | #include <sound/pcm.h> | 46 | #include <sound/pcm.h> |
39 | #include <sound/pcm_params.h> | 47 | #include <sound/pcm_params.h> |
40 | #include <sound/tlv.h> | 48 | #include <sound/tlv.h> |
@@ -44,7 +52,8 @@ | |||
44 | 52 | ||
45 | #define GPIO_DS_HP_DETECT 0x0010 | 53 | #define GPIO_DS_HP_DETECT 0x0010 |
46 | #define GPIO_DS_INPUT_ROUTE 0x0040 | 54 | #define GPIO_DS_INPUT_ROUTE 0x0040 |
47 | #define GPIO_DS_OUTPUT_ENABLE 0x0180 | 55 | #define GPIO_DS_OUTPUT_FRONTLR 0x0080 |
56 | #define GPIO_DS_OUTPUT_ENABLE 0x0100 | ||
48 | 57 | ||
49 | #define LC_CONTROL_LIMITER 0x40000000 | 58 | #define LC_CONTROL_LIMITER 0x40000000 |
50 | #define LC_CONTROL_ALC 0x20000000 | 59 | #define LC_CONTROL_ALC 0x20000000 |
@@ -56,6 +65,7 @@ struct xonar_wm87x6 { | |||
56 | struct snd_kcontrol *line_adcmux_control; | 65 | struct snd_kcontrol *line_adcmux_control; |
57 | struct snd_kcontrol *mic_adcmux_control; | 66 | struct snd_kcontrol *mic_adcmux_control; |
58 | struct snd_kcontrol *lc_controls[13]; | 67 | struct snd_kcontrol *lc_controls[13]; |
68 | struct snd_jack *hp_jack; | ||
59 | }; | 69 | }; |
60 | 70 | ||
61 | static void wm8776_write(struct oxygen *chip, | 71 | static void wm8776_write(struct oxygen *chip, |
@@ -97,8 +107,12 @@ static void wm8766_write(struct oxygen *chip, | |||
97 | (0 << OXYGEN_SPI_CODEC_SHIFT) | | 107 | (0 << OXYGEN_SPI_CODEC_SHIFT) | |
98 | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, | 108 | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, |
99 | (reg << 9) | value); | 109 | (reg << 9) | value); |
100 | if (reg < ARRAY_SIZE(data->wm8766_regs)) | 110 | if (reg < ARRAY_SIZE(data->wm8766_regs)) { |
111 | if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) || | ||
112 | (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA)) | ||
113 | value &= ~WM8766_UPDATE; | ||
101 | data->wm8766_regs[reg] = value; | 114 | data->wm8766_regs[reg] = value; |
115 | } | ||
102 | } | 116 | } |
103 | 117 | ||
104 | static void wm8766_write_cached(struct oxygen *chip, | 118 | static void wm8766_write_cached(struct oxygen *chip, |
@@ -107,12 +121,8 @@ static void wm8766_write_cached(struct oxygen *chip, | |||
107 | struct xonar_wm87x6 *data = chip->model_data; | 121 | struct xonar_wm87x6 *data = chip->model_data; |
108 | 122 | ||
109 | if (reg >= ARRAY_SIZE(data->wm8766_regs) || | 123 | if (reg >= ARRAY_SIZE(data->wm8766_regs) || |
110 | value != data->wm8766_regs[reg]) { | 124 | value != data->wm8766_regs[reg]) |
111 | if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) || | ||
112 | (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA)) | ||
113 | value &= ~WM8766_UPDATE; | ||
114 | wm8766_write(chip, reg, value); | 125 | wm8766_write(chip, reg, value); |
115 | } | ||
116 | } | 126 | } |
117 | 127 | ||
118 | static void wm8776_registers_init(struct oxygen *chip) | 128 | static void wm8776_registers_init(struct oxygen *chip) |
@@ -141,7 +151,10 @@ static void wm8776_registers_init(struct oxygen *chip) | |||
141 | 151 | ||
142 | static void wm8766_registers_init(struct oxygen *chip) | 152 | static void wm8766_registers_init(struct oxygen *chip) |
143 | { | 153 | { |
154 | struct xonar_wm87x6 *data = chip->model_data; | ||
155 | |||
144 | wm8766_write(chip, WM8766_RESET, 0); | 156 | wm8766_write(chip, WM8766_RESET, 0); |
157 | wm8766_write(chip, WM8766_DAC_CTRL, data->wm8766_regs[WM8766_DAC_CTRL]); | ||
145 | wm8766_write(chip, WM8766_INT_CTRL, WM8766_FMT_LJUST | WM8766_IWL_24); | 158 | wm8766_write(chip, WM8766_INT_CTRL, WM8766_FMT_LJUST | WM8766_IWL_24); |
146 | wm8766_write(chip, WM8766_DAC_CTRL2, | 159 | wm8766_write(chip, WM8766_DAC_CTRL2, |
147 | WM8766_ZCD | (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); | 160 | WM8766_ZCD | (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); |
@@ -170,6 +183,40 @@ static void wm8776_init(struct oxygen *chip) | |||
170 | wm8776_registers_init(chip); | 183 | wm8776_registers_init(chip); |
171 | } | 184 | } |
172 | 185 | ||
186 | static void wm8766_init(struct oxygen *chip) | ||
187 | { | ||
188 | struct xonar_wm87x6 *data = chip->model_data; | ||
189 | |||
190 | data->wm8766_regs[WM8766_DAC_CTRL] = | ||
191 | WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT; | ||
192 | wm8766_registers_init(chip); | ||
193 | } | ||
194 | |||
195 | static void xonar_ds_handle_hp_jack(struct oxygen *chip) | ||
196 | { | ||
197 | struct xonar_wm87x6 *data = chip->model_data; | ||
198 | bool hp_plugged; | ||
199 | unsigned int reg; | ||
200 | |||
201 | mutex_lock(&chip->mutex); | ||
202 | |||
203 | hp_plugged = !(oxygen_read16(chip, OXYGEN_GPIO_DATA) & | ||
204 | GPIO_DS_HP_DETECT); | ||
205 | |||
206 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, | ||
207 | hp_plugged ? 0 : GPIO_DS_OUTPUT_FRONTLR, | ||
208 | GPIO_DS_OUTPUT_FRONTLR); | ||
209 | |||
210 | reg = data->wm8766_regs[WM8766_DAC_CTRL] & ~WM8766_MUTEALL; | ||
211 | if (hp_plugged) | ||
212 | reg |= WM8766_MUTEALL; | ||
213 | wm8766_write_cached(chip, WM8766_DAC_CTRL, reg); | ||
214 | |||
215 | snd_jack_report(data->hp_jack, hp_plugged ? SND_JACK_HEADPHONE : 0); | ||
216 | |||
217 | mutex_unlock(&chip->mutex); | ||
218 | } | ||
219 | |||
173 | static void xonar_ds_init(struct oxygen *chip) | 220 | static void xonar_ds_init(struct oxygen *chip) |
174 | { | 221 | { |
175 | struct xonar_wm87x6 *data = chip->model_data; | 222 | struct xonar_wm87x6 *data = chip->model_data; |
@@ -178,16 +225,22 @@ static void xonar_ds_init(struct oxygen *chip) | |||
178 | data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE; | 225 | data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE; |
179 | 226 | ||
180 | wm8776_init(chip); | 227 | wm8776_init(chip); |
181 | wm8766_registers_init(chip); | 228 | wm8766_init(chip); |
182 | 229 | ||
183 | oxygen_write16_masked(chip, OXYGEN_GPIO_CONTROL, GPIO_DS_INPUT_ROUTE, | 230 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, |
184 | GPIO_DS_HP_DETECT | GPIO_DS_INPUT_ROUTE); | 231 | GPIO_DS_INPUT_ROUTE | GPIO_DS_OUTPUT_FRONTLR); |
232 | oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, | ||
233 | GPIO_DS_HP_DETECT); | ||
185 | oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DS_INPUT_ROUTE); | 234 | oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DS_INPUT_ROUTE); |
186 | oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, GPIO_DS_HP_DETECT); | 235 | oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, GPIO_DS_HP_DETECT); |
187 | chip->interrupt_mask |= OXYGEN_INT_GPIO; | 236 | chip->interrupt_mask |= OXYGEN_INT_GPIO; |
188 | 237 | ||
189 | xonar_enable_output(chip); | 238 | xonar_enable_output(chip); |
190 | 239 | ||
240 | snd_jack_new(chip->card, "Headphone", | ||
241 | SND_JACK_HEADPHONE, &data->hp_jack); | ||
242 | xonar_ds_handle_hp_jack(chip); | ||
243 | |||
191 | snd_component_add(chip->card, "WM8776"); | 244 | snd_component_add(chip->card, "WM8776"); |
192 | snd_component_add(chip->card, "WM8766"); | 245 | snd_component_add(chip->card, "WM8766"); |
193 | } | 246 | } |
@@ -208,6 +261,7 @@ static void xonar_ds_resume(struct oxygen *chip) | |||
208 | wm8776_registers_init(chip); | 261 | wm8776_registers_init(chip); |
209 | wm8766_registers_init(chip); | 262 | wm8766_registers_init(chip); |
210 | xonar_enable_output(chip); | 263 | xonar_enable_output(chip); |
264 | xonar_ds_handle_hp_jack(chip); | ||
211 | } | 265 | } |
212 | 266 | ||
213 | static void wm8776_adc_hardware_filter(unsigned int channel, | 267 | static void wm8776_adc_hardware_filter(unsigned int channel, |
@@ -323,12 +377,27 @@ static void update_wm87x6_mute(struct oxygen *chip) | |||
323 | (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); | 377 | (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); |
324 | } | 378 | } |
325 | 379 | ||
326 | static void xonar_ds_gpio_changed(struct oxygen *chip) | 380 | static void update_wm8766_center_lfe_mix(struct oxygen *chip, bool mixed) |
327 | { | 381 | { |
328 | u16 bits; | 382 | struct xonar_wm87x6 *data = chip->model_data; |
383 | unsigned int reg; | ||
329 | 384 | ||
330 | bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); | 385 | /* |
331 | snd_printk(KERN_INFO "HP detect: %d\n", !!(bits & GPIO_DS_HP_DETECT)); | 386 | * The WM8766 can mix left and right channels, but this setting |
387 | * applies to all three stereo pairs. | ||
388 | */ | ||
389 | reg = data->wm8766_regs[WM8766_DAC_CTRL] & | ||
390 | ~(WM8766_PL_LEFT_MASK | WM8766_PL_RIGHT_MASK); | ||
391 | if (mixed) | ||
392 | reg |= WM8766_PL_LEFT_LRMIX | WM8766_PL_RIGHT_LRMIX; | ||
393 | else | ||
394 | reg |= WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT; | ||
395 | wm8766_write_cached(chip, WM8766_DAC_CTRL, reg); | ||
396 | } | ||
397 | |||
398 | static void xonar_ds_gpio_changed(struct oxygen *chip) | ||
399 | { | ||
400 | xonar_ds_handle_hp_jack(chip); | ||
332 | } | 401 | } |
333 | 402 | ||
334 | static int wm8776_bit_switch_get(struct snd_kcontrol *ctl, | 403 | static int wm8776_bit_switch_get(struct snd_kcontrol *ctl, |
@@ -896,7 +965,10 @@ static const struct snd_kcontrol_new ds_controls[] = { | |||
896 | .put = wm8776_input_mux_put, | 965 | .put = wm8776_input_mux_put, |
897 | .private_value = 1 << 1, | 966 | .private_value = 1 << 1, |
898 | }, | 967 | }, |
899 | WM8776_BIT_SWITCH("Aux", WM8776_ADCMUX, 1 << 2, 0, 0), | 968 | WM8776_BIT_SWITCH("Front Mic Capture Switch", |
969 | WM8776_ADCMUX, 1 << 2, 0, 0), | ||
970 | WM8776_BIT_SWITCH("Aux Capture Switch", | ||
971 | WM8776_ADCMUX, 1 << 3, 0, 0), | ||
900 | { | 972 | { |
901 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 973 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
902 | .name = "ADC Filter Capture Enum", | 974 | .name = "ADC Filter Capture Enum", |
@@ -956,13 +1028,6 @@ static const struct snd_kcontrol_new lc_controls[] = { | |||
956 | LC_CONTROL_ALC, wm8776_ngth_db_scale), | 1028 | LC_CONTROL_ALC, wm8776_ngth_db_scale), |
957 | }; | 1029 | }; |
958 | 1030 | ||
959 | static int xonar_ds_control_filter(struct snd_kcontrol_new *template) | ||
960 | { | ||
961 | if (!strncmp(template->name, "CD Capture ", 11)) | ||
962 | return 1; /* no CD input */ | ||
963 | return 0; | ||
964 | } | ||
965 | |||
966 | static int xonar_ds_mixer_init(struct oxygen *chip) | 1031 | static int xonar_ds_mixer_init(struct oxygen *chip) |
967 | { | 1032 | { |
968 | struct xonar_wm87x6 *data = chip->model_data; | 1033 | struct xonar_wm87x6 *data = chip->model_data; |
@@ -999,10 +1064,9 @@ static int xonar_ds_mixer_init(struct oxygen *chip) | |||
999 | 1064 | ||
1000 | static const struct oxygen_model model_xonar_ds = { | 1065 | static const struct oxygen_model model_xonar_ds = { |
1001 | .shortname = "Xonar DS", | 1066 | .shortname = "Xonar DS", |
1002 | .longname = "Asus Virtuoso 200", | 1067 | .longname = "Asus Virtuoso 66", |
1003 | .chip = "AV200", | 1068 | .chip = "AV200", |
1004 | .init = xonar_ds_init, | 1069 | .init = xonar_ds_init, |
1005 | .control_filter = xonar_ds_control_filter, | ||
1006 | .mixer_init = xonar_ds_mixer_init, | 1070 | .mixer_init = xonar_ds_mixer_init, |
1007 | .cleanup = xonar_ds_cleanup, | 1071 | .cleanup = xonar_ds_cleanup, |
1008 | .suspend = xonar_ds_suspend, | 1072 | .suspend = xonar_ds_suspend, |
@@ -1013,6 +1077,7 @@ static const struct oxygen_model model_xonar_ds = { | |||
1013 | .set_adc_params = set_wm8776_adc_params, | 1077 | .set_adc_params = set_wm8776_adc_params, |
1014 | .update_dac_volume = update_wm87x6_volume, | 1078 | .update_dac_volume = update_wm87x6_volume, |
1015 | .update_dac_mute = update_wm87x6_mute, | 1079 | .update_dac_mute = update_wm87x6_mute, |
1080 | .update_center_lfe_mix = update_wm8766_center_lfe_mix, | ||
1016 | .gpio_changed = xonar_ds_gpio_changed, | 1081 | .gpio_changed = xonar_ds_gpio_changed, |
1017 | .dac_tlv = wm87x6_dac_db_scale, | 1082 | .dac_tlv = wm87x6_dac_db_scale, |
1018 | .model_data_size = sizeof(struct xonar_wm87x6), | 1083 | .model_data_size = sizeof(struct xonar_wm87x6), |
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index d19dc052c391..d5f5b440fc40 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c | |||
@@ -1527,14 +1527,14 @@ snd_rme96_free(void *private_data) | |||
1527 | static void | 1527 | static void |
1528 | snd_rme96_free_spdif_pcm(struct snd_pcm *pcm) | 1528 | snd_rme96_free_spdif_pcm(struct snd_pcm *pcm) |
1529 | { | 1529 | { |
1530 | struct rme96 *rme96 = (struct rme96 *) pcm->private_data; | 1530 | struct rme96 *rme96 = pcm->private_data; |
1531 | rme96->spdif_pcm = NULL; | 1531 | rme96->spdif_pcm = NULL; |
1532 | } | 1532 | } |
1533 | 1533 | ||
1534 | static void | 1534 | static void |
1535 | snd_rme96_free_adat_pcm(struct snd_pcm *pcm) | 1535 | snd_rme96_free_adat_pcm(struct snd_pcm *pcm) |
1536 | { | 1536 | { |
1537 | struct rme96 *rme96 = (struct rme96 *) pcm->private_data; | 1537 | struct rme96 *rme96 = pcm->private_data; |
1538 | rme96->adat_pcm = NULL; | 1538 | rme96->adat_pcm = NULL; |
1539 | } | 1539 | } |
1540 | 1540 | ||
@@ -1661,7 +1661,7 @@ static void | |||
1661 | snd_rme96_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | 1661 | snd_rme96_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) |
1662 | { | 1662 | { |
1663 | int n; | 1663 | int n; |
1664 | struct rme96 *rme96 = (struct rme96 *)entry->private_data; | 1664 | struct rme96 *rme96 = entry->private_data; |
1665 | 1665 | ||
1666 | rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER); | 1666 | rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER); |
1667 | 1667 | ||
@@ -2348,7 +2348,7 @@ snd_rme96_probe(struct pci_dev *pci, | |||
2348 | if (err < 0) | 2348 | if (err < 0) |
2349 | return err; | 2349 | return err; |
2350 | card->private_free = snd_rme96_card_free; | 2350 | card->private_free = snd_rme96_card_free; |
2351 | rme96 = (struct rme96 *)card->private_data; | 2351 | rme96 = card->private_data; |
2352 | rme96->card = card; | 2352 | rme96->card = card; |
2353 | rme96->pci = pci; | 2353 | rme96->pci = pci; |
2354 | snd_card_set_dev(card, &pci->dev); | 2354 | snd_card_set_dev(card, &pci->dev); |
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index d6fa7bfd9aa1..0b720cf7783e 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c | |||
@@ -3284,7 +3284,7 @@ static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp) | |||
3284 | static void | 3284 | static void |
3285 | snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | 3285 | snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) |
3286 | { | 3286 | { |
3287 | struct hdsp *hdsp = (struct hdsp *) entry->private_data; | 3287 | struct hdsp *hdsp = entry->private_data; |
3288 | unsigned int status; | 3288 | unsigned int status; |
3289 | unsigned int status2; | 3289 | unsigned int status2; |
3290 | char *pref_sync_ref; | 3290 | char *pref_sync_ref; |
@@ -4566,7 +4566,7 @@ static int hdsp_get_peak(struct hdsp *hdsp, struct hdsp_peak_rms __user *peak_rm | |||
4566 | 4566 | ||
4567 | static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg) | 4567 | static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg) |
4568 | { | 4568 | { |
4569 | struct hdsp *hdsp = (struct hdsp *)hw->private_data; | 4569 | struct hdsp *hdsp = hw->private_data; |
4570 | void __user *argp = (void __user *)arg; | 4570 | void __user *argp = (void __user *)arg; |
4571 | int err; | 4571 | int err; |
4572 | 4572 | ||
@@ -5156,7 +5156,7 @@ static int snd_hdsp_free(struct hdsp *hdsp) | |||
5156 | 5156 | ||
5157 | static void snd_hdsp_card_free(struct snd_card *card) | 5157 | static void snd_hdsp_card_free(struct snd_card *card) |
5158 | { | 5158 | { |
5159 | struct hdsp *hdsp = (struct hdsp *) card->private_data; | 5159 | struct hdsp *hdsp = card->private_data; |
5160 | 5160 | ||
5161 | if (hdsp) | 5161 | if (hdsp) |
5162 | snd_hdsp_free(hdsp); | 5162 | snd_hdsp_free(hdsp); |
@@ -5182,7 +5182,7 @@ static int __devinit snd_hdsp_probe(struct pci_dev *pci, | |||
5182 | if (err < 0) | 5182 | if (err < 0) |
5183 | return err; | 5183 | return err; |
5184 | 5184 | ||
5185 | hdsp = (struct hdsp *) card->private_data; | 5185 | hdsp = card->private_data; |
5186 | card->private_free = snd_hdsp_card_free; | 5186 | card->private_free = snd_hdsp_card_free; |
5187 | hdsp->dev = dev; | 5187 | hdsp->dev = dev; |
5188 | hdsp->pci = pci; | 5188 | hdsp->pci = pci; |
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 20afdf9772ee..961d98297695 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c | |||
@@ -785,7 +785,7 @@ static int snapper_set_capture_source(struct pmac_tumbler *mix) | |||
785 | if (! mix->i2c.client) | 785 | if (! mix->i2c.client) |
786 | return -ENODEV; | 786 | return -ENODEV; |
787 | if (mix->capture_source) | 787 | if (mix->capture_source) |
788 | mix->acs = mix->acs |= 2; | 788 | mix->acs |= 2; |
789 | else | 789 | else |
790 | mix->acs &= ~2; | 790 | mix->acs &= ~2; |
791 | return i2c_smbus_write_byte_data(mix->i2c.client, TAS_REG_ACS, mix->acs); | 791 | return i2c_smbus_write_byte_data(mix->i2c.client, TAS_REG_ACS, mix->acs); |
diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c index 40eccfe9e358..4948a79f86a0 100644 --- a/sound/soc/davinci/davinci-sffsdr.c +++ b/sound/soc/davinci/davinci-sffsdr.c | |||
@@ -150,7 +150,7 @@ static int __init sffsdr_init(void) | |||
150 | sffsdr_snd_resources, | 150 | sffsdr_snd_resources, |
151 | ARRAY_SIZE(sffsdr_snd_resources)); | 151 | ARRAY_SIZE(sffsdr_snd_resources)); |
152 | if (ret) { | 152 | if (ret) { |
153 | printk(KERN_ERR "platform device add ressources failed\n"); | 153 | printk(KERN_ERR "platform device add resources failed\n"); |
154 | goto error; | 154 | goto error; |
155 | } | 155 | } |
156 | 156 | ||
diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c index 209c25994c7e..4719558289d4 100644 --- a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c | |||
@@ -182,7 +182,7 @@ static int neo1973_gta02_voice_hw_params( | |||
182 | if (ret < 0) | 182 | if (ret < 0) |
183 | return ret; | 183 | return ret; |
184 | 184 | ||
185 | /* configue and enable PLL for 12.288MHz output */ | 185 | /* configure and enable PLL for 12.288MHz output */ |
186 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, | 186 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, |
187 | iis_clkrate / 4, 12288000); | 187 | iis_clkrate / 4, 12288000); |
188 | if (ret < 0) | 188 | if (ret < 0) |
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 0cb4f86f6d1e..4ac620988e7c 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c | |||
@@ -201,7 +201,7 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream, | |||
201 | if (ret < 0) | 201 | if (ret < 0) |
202 | return ret; | 202 | return ret; |
203 | 203 | ||
204 | /* configue and enable PLL for 12.288MHz output */ | 204 | /* configure and enable PLL for 12.288MHz output */ |
205 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, | 205 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, |
206 | iis_clkrate / 4, 12288000); | 206 | iis_clkrate / 4, 12288000); |
207 | if (ret < 0) | 207 | if (ret < 0) |
diff --git a/sound/synth/emux/emux_hwdep.c b/sound/synth/emux/emux_hwdep.c index ff0b2a8fd25b..5ae1eae9f6db 100644 --- a/sound/synth/emux/emux_hwdep.c +++ b/sound/synth/emux/emux_hwdep.c | |||
@@ -128,6 +128,9 @@ snd_emux_init_hwdep(struct snd_emux *emu) | |||
128 | strcpy(hw->name, SNDRV_EMUX_HWDEP_NAME); | 128 | strcpy(hw->name, SNDRV_EMUX_HWDEP_NAME); |
129 | hw->iface = SNDRV_HWDEP_IFACE_EMUX_WAVETABLE; | 129 | hw->iface = SNDRV_HWDEP_IFACE_EMUX_WAVETABLE; |
130 | hw->ops.ioctl = snd_emux_hwdep_ioctl; | 130 | hw->ops.ioctl = snd_emux_hwdep_ioctl; |
131 | /* The ioctl parameter types are compatible between 32- and | ||
132 | * 64-bit architectures, so use the same function. */ | ||
133 | hw->ops.ioctl_compat = snd_emux_hwdep_ioctl; | ||
131 | hw->exclusive = 1; | 134 | hw->exclusive = 1; |
132 | hw->private_data = emu; | 135 | hw->private_data = emu; |
133 | if ((err = snd_card_register(emu->card)) < 0) | 136 | if ((err = snd_card_register(emu->card)) < 0) |
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 44d6d2ec964f..112984f4080f 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig | |||
@@ -65,6 +65,7 @@ config SND_USB_CAIAQ | |||
65 | * Native Instruments Guitar Rig Session I/O | 65 | * Native Instruments Guitar Rig Session I/O |
66 | * Native Instruments Guitar Rig mobile | 66 | * Native Instruments Guitar Rig mobile |
67 | * Native Instruments Traktor Kontrol X1 | 67 | * Native Instruments Traktor Kontrol X1 |
68 | * Native Instruments Traktor Kontrol S4 | ||
68 | 69 | ||
69 | To compile this driver as a module, choose M here: the module | 70 | To compile this driver as a module, choose M here: the module |
70 | will be called snd-usb-caiaq. | 71 | will be called snd-usb-caiaq. |
@@ -82,6 +83,7 @@ config SND_USB_CAIAQ_INPUT | |||
82 | * Native Instruments Kore Controller | 83 | * Native Instruments Kore Controller |
83 | * Native Instruments Kore Controller 2 | 84 | * Native Instruments Kore Controller 2 |
84 | * Native Instruments Audio Kontrol 1 | 85 | * Native Instruments Audio Kontrol 1 |
86 | * Native Instruments Traktor Kontrol S4 | ||
85 | 87 | ||
86 | config SND_USB_US122L | 88 | config SND_USB_US122L |
87 | tristate "Tascam US-122L USB driver" | 89 | tristate "Tascam US-122L USB driver" |
diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c index 4328cad6c3a2..68b97477577b 100644 --- a/sound/usb/caiaq/audio.c +++ b/sound/usb/caiaq/audio.c | |||
@@ -111,7 +111,7 @@ static int stream_start(struct snd_usb_caiaqdev *dev) | |||
111 | memset(dev->sub_capture, 0, sizeof(dev->sub_capture)); | 111 | memset(dev->sub_capture, 0, sizeof(dev->sub_capture)); |
112 | dev->input_panic = 0; | 112 | dev->input_panic = 0; |
113 | dev->output_panic = 0; | 113 | dev->output_panic = 0; |
114 | dev->first_packet = 1; | 114 | dev->first_packet = 4; |
115 | dev->streaming = 1; | 115 | dev->streaming = 1; |
116 | dev->warned = 0; | 116 | dev->warned = 0; |
117 | 117 | ||
@@ -169,7 +169,7 @@ static int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream) | |||
169 | } | 169 | } |
170 | 170 | ||
171 | static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub, | 171 | static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub, |
172 | struct snd_pcm_hw_params *hw_params) | 172 | struct snd_pcm_hw_params *hw_params) |
173 | { | 173 | { |
174 | debug("%s(%p)\n", __func__, sub); | 174 | debug("%s(%p)\n", __func__, sub); |
175 | return snd_pcm_lib_malloc_pages(sub, params_buffer_bytes(hw_params)); | 175 | return snd_pcm_lib_malloc_pages(sub, params_buffer_bytes(hw_params)); |
@@ -189,7 +189,7 @@ static int snd_usb_caiaq_pcm_hw_free(struct snd_pcm_substream *sub) | |||
189 | #endif | 189 | #endif |
190 | 190 | ||
191 | static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, | 191 | static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, |
192 | 48000, 64000, 88200, 96000, 176400, 192000 }; | 192 | 48000, 64000, 88200, 96000, 176400, 192000 }; |
193 | 193 | ||
194 | static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) | 194 | static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) |
195 | { | 195 | { |
@@ -201,12 +201,39 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) | |||
201 | debug("%s(%p)\n", __func__, substream); | 201 | debug("%s(%p)\n", __func__, substream); |
202 | 202 | ||
203 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 203 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
204 | dev->period_out_count[index] = BYTES_PER_SAMPLE + 1; | 204 | int out_pos; |
205 | dev->audio_out_buf_pos[index] = BYTES_PER_SAMPLE + 1; | 205 | |
206 | switch (dev->spec.data_alignment) { | ||
207 | case 0: | ||
208 | case 2: | ||
209 | out_pos = BYTES_PER_SAMPLE + 1; | ||
210 | break; | ||
211 | case 3: | ||
212 | default: | ||
213 | out_pos = 0; | ||
214 | break; | ||
215 | } | ||
216 | |||
217 | dev->period_out_count[index] = out_pos; | ||
218 | dev->audio_out_buf_pos[index] = out_pos; | ||
206 | } else { | 219 | } else { |
207 | int in_pos = (dev->spec.data_alignment == 2) ? 0 : 2; | 220 | int in_pos; |
208 | dev->period_in_count[index] = BYTES_PER_SAMPLE + in_pos; | 221 | |
209 | dev->audio_in_buf_pos[index] = BYTES_PER_SAMPLE + in_pos; | 222 | switch (dev->spec.data_alignment) { |
223 | case 0: | ||
224 | in_pos = BYTES_PER_SAMPLE + 2; | ||
225 | break; | ||
226 | case 2: | ||
227 | in_pos = BYTES_PER_SAMPLE; | ||
228 | break; | ||
229 | case 3: | ||
230 | default: | ||
231 | in_pos = 0; | ||
232 | break; | ||
233 | } | ||
234 | |||
235 | dev->period_in_count[index] = in_pos; | ||
236 | dev->audio_in_buf_pos[index] = in_pos; | ||
210 | } | 237 | } |
211 | 238 | ||
212 | if (dev->streaming) | 239 | if (dev->streaming) |
@@ -221,7 +248,7 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) | |||
221 | snd_pcm_limit_hw_rates(runtime); | 248 | snd_pcm_limit_hw_rates(runtime); |
222 | 249 | ||
223 | bytes_per_sample = BYTES_PER_SAMPLE; | 250 | bytes_per_sample = BYTES_PER_SAMPLE; |
224 | if (dev->spec.data_alignment == 2) | 251 | if (dev->spec.data_alignment >= 2) |
225 | bytes_per_sample++; | 252 | bytes_per_sample++; |
226 | 253 | ||
227 | bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE) | 254 | bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE) |
@@ -253,6 +280,8 @@ static int snd_usb_caiaq_pcm_trigger(struct snd_pcm_substream *sub, int cmd) | |||
253 | { | 280 | { |
254 | struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub); | 281 | struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub); |
255 | 282 | ||
283 | debug("%s(%p) cmd %d\n", __func__, sub, cmd); | ||
284 | |||
256 | switch (cmd) { | 285 | switch (cmd) { |
257 | case SNDRV_PCM_TRIGGER_START: | 286 | case SNDRV_PCM_TRIGGER_START: |
258 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 287 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
@@ -402,6 +431,61 @@ static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev, | |||
402 | } | 431 | } |
403 | } | 432 | } |
404 | 433 | ||
434 | static void read_in_urb_mode3(struct snd_usb_caiaqdev *dev, | ||
435 | const struct urb *urb, | ||
436 | const struct usb_iso_packet_descriptor *iso) | ||
437 | { | ||
438 | unsigned char *usb_buf = urb->transfer_buffer + iso->offset; | ||
439 | int stream, i; | ||
440 | |||
441 | /* paranoia check */ | ||
442 | if (iso->actual_length % (BYTES_PER_SAMPLE_USB * CHANNELS_PER_STREAM)) | ||
443 | return; | ||
444 | |||
445 | for (i = 0; i < iso->actual_length;) { | ||
446 | for (stream = 0; stream < dev->n_streams; stream++) { | ||
447 | struct snd_pcm_substream *sub = dev->sub_capture[stream]; | ||
448 | char *audio_buf = NULL; | ||
449 | int c, n, sz = 0; | ||
450 | |||
451 | if (sub && !dev->input_panic) { | ||
452 | struct snd_pcm_runtime *rt = sub->runtime; | ||
453 | audio_buf = rt->dma_area; | ||
454 | sz = frames_to_bytes(rt, rt->buffer_size); | ||
455 | } | ||
456 | |||
457 | for (c = 0; c < CHANNELS_PER_STREAM; c++) { | ||
458 | /* 3 audio data bytes, followed by 1 check byte */ | ||
459 | if (audio_buf) { | ||
460 | for (n = 0; n < BYTES_PER_SAMPLE; n++) { | ||
461 | audio_buf[dev->audio_in_buf_pos[stream]++] = usb_buf[i+n]; | ||
462 | |||
463 | if (dev->audio_in_buf_pos[stream] == sz) | ||
464 | dev->audio_in_buf_pos[stream] = 0; | ||
465 | } | ||
466 | |||
467 | dev->period_in_count[stream] += BYTES_PER_SAMPLE; | ||
468 | } | ||
469 | |||
470 | i += BYTES_PER_SAMPLE; | ||
471 | |||
472 | if (usb_buf[i] != ((stream << 1) | c) && | ||
473 | !dev->first_packet) { | ||
474 | if (!dev->input_panic) | ||
475 | printk(" EXPECTED: %02x got %02x, c %d, stream %d, i %d\n", | ||
476 | ((stream << 1) | c), usb_buf[i], c, stream, i); | ||
477 | dev->input_panic = 1; | ||
478 | } | ||
479 | |||
480 | i++; | ||
481 | } | ||
482 | } | ||
483 | } | ||
484 | |||
485 | if (dev->first_packet > 0) | ||
486 | dev->first_packet--; | ||
487 | } | ||
488 | |||
405 | static void read_in_urb(struct snd_usb_caiaqdev *dev, | 489 | static void read_in_urb(struct snd_usb_caiaqdev *dev, |
406 | const struct urb *urb, | 490 | const struct urb *urb, |
407 | const struct usb_iso_packet_descriptor *iso) | 491 | const struct usb_iso_packet_descriptor *iso) |
@@ -419,6 +503,9 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev, | |||
419 | case 2: | 503 | case 2: |
420 | read_in_urb_mode2(dev, urb, iso); | 504 | read_in_urb_mode2(dev, urb, iso); |
421 | break; | 505 | break; |
506 | case 3: | ||
507 | read_in_urb_mode3(dev, urb, iso); | ||
508 | break; | ||
422 | } | 509 | } |
423 | 510 | ||
424 | if ((dev->input_panic || dev->output_panic) && !dev->warned) { | 511 | if ((dev->input_panic || dev->output_panic) && !dev->warned) { |
@@ -429,9 +516,9 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev, | |||
429 | } | 516 | } |
430 | } | 517 | } |
431 | 518 | ||
432 | static void fill_out_urb(struct snd_usb_caiaqdev *dev, | 519 | static void fill_out_urb_mode_0(struct snd_usb_caiaqdev *dev, |
433 | struct urb *urb, | 520 | struct urb *urb, |
434 | const struct usb_iso_packet_descriptor *iso) | 521 | const struct usb_iso_packet_descriptor *iso) |
435 | { | 522 | { |
436 | unsigned char *usb_buf = urb->transfer_buffer + iso->offset; | 523 | unsigned char *usb_buf = urb->transfer_buffer + iso->offset; |
437 | struct snd_pcm_substream *sub; | 524 | struct snd_pcm_substream *sub; |
@@ -457,9 +544,67 @@ static void fill_out_urb(struct snd_usb_caiaqdev *dev, | |||
457 | /* fill in the check bytes */ | 544 | /* fill in the check bytes */ |
458 | if (dev->spec.data_alignment == 2 && | 545 | if (dev->spec.data_alignment == 2 && |
459 | i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == | 546 | i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == |
460 | (dev->n_streams * CHANNELS_PER_STREAM)) | 547 | (dev->n_streams * CHANNELS_PER_STREAM)) |
461 | for (stream = 0; stream < dev->n_streams; stream++, i++) | 548 | for (stream = 0; stream < dev->n_streams; stream++, i++) |
462 | usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i); | 549 | usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i); |
550 | } | ||
551 | } | ||
552 | |||
553 | static void fill_out_urb_mode_3(struct snd_usb_caiaqdev *dev, | ||
554 | struct urb *urb, | ||
555 | const struct usb_iso_packet_descriptor *iso) | ||
556 | { | ||
557 | unsigned char *usb_buf = urb->transfer_buffer + iso->offset; | ||
558 | int stream, i; | ||
559 | |||
560 | for (i = 0; i < iso->length;) { | ||
561 | for (stream = 0; stream < dev->n_streams; stream++) { | ||
562 | struct snd_pcm_substream *sub = dev->sub_playback[stream]; | ||
563 | char *audio_buf = NULL; | ||
564 | int c, n, sz = 0; | ||
565 | |||
566 | if (sub) { | ||
567 | struct snd_pcm_runtime *rt = sub->runtime; | ||
568 | audio_buf = rt->dma_area; | ||
569 | sz = frames_to_bytes(rt, rt->buffer_size); | ||
570 | } | ||
571 | |||
572 | for (c = 0; c < CHANNELS_PER_STREAM; c++) { | ||
573 | for (n = 0; n < BYTES_PER_SAMPLE; n++) { | ||
574 | if (audio_buf) { | ||
575 | usb_buf[i+n] = audio_buf[dev->audio_out_buf_pos[stream]++]; | ||
576 | |||
577 | if (dev->audio_out_buf_pos[stream] == sz) | ||
578 | dev->audio_out_buf_pos[stream] = 0; | ||
579 | } else { | ||
580 | usb_buf[i+n] = 0; | ||
581 | } | ||
582 | } | ||
583 | |||
584 | if (audio_buf) | ||
585 | dev->period_out_count[stream] += BYTES_PER_SAMPLE; | ||
586 | |||
587 | i += BYTES_PER_SAMPLE; | ||
588 | |||
589 | /* fill in the check byte pattern */ | ||
590 | usb_buf[i++] = (stream << 1) | c; | ||
591 | } | ||
592 | } | ||
593 | } | ||
594 | } | ||
595 | |||
596 | static inline void fill_out_urb(struct snd_usb_caiaqdev *dev, | ||
597 | struct urb *urb, | ||
598 | const struct usb_iso_packet_descriptor *iso) | ||
599 | { | ||
600 | switch (dev->spec.data_alignment) { | ||
601 | case 0: | ||
602 | case 2: | ||
603 | fill_out_urb_mode_0(dev, urb, iso); | ||
604 | break; | ||
605 | case 3: | ||
606 | fill_out_urb_mode_3(dev, urb, iso); | ||
607 | break; | ||
463 | } | 608 | } |
464 | } | 609 | } |
465 | 610 | ||
diff --git a/sound/usb/caiaq/control.c b/sound/usb/caiaq/control.c index 91c804cd2782..00e5d0a469e1 100644 --- a/sound/usb/caiaq/control.c +++ b/sound/usb/caiaq/control.c | |||
@@ -55,6 +55,10 @@ static int control_info(struct snd_kcontrol *kcontrol, | |||
55 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): | 55 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): |
56 | maxval = 127; | 56 | maxval = 127; |
57 | break; | 57 | break; |
58 | |||
59 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): | ||
60 | maxval = 31; | ||
61 | break; | ||
58 | } | 62 | } |
59 | 63 | ||
60 | if (is_intval) { | 64 | if (is_intval) { |
@@ -93,6 +97,7 @@ static int control_put(struct snd_kcontrol *kcontrol, | |||
93 | struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol); | 97 | struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol); |
94 | struct snd_usb_caiaqdev *dev = caiaqdev(chip->card); | 98 | struct snd_usb_caiaqdev *dev = caiaqdev(chip->card); |
95 | int pos = kcontrol->private_value; | 99 | int pos = kcontrol->private_value; |
100 | int v = ucontrol->value.integer.value[0]; | ||
96 | unsigned char cmd = EP1_CMD_WRITE_IO; | 101 | unsigned char cmd = EP1_CMD_WRITE_IO; |
97 | 102 | ||
98 | if (dev->chip.usb_id == | 103 | if (dev->chip.usb_id == |
@@ -100,12 +105,27 @@ static int control_put(struct snd_kcontrol *kcontrol, | |||
100 | cmd = EP1_CMD_DIMM_LEDS; | 105 | cmd = EP1_CMD_DIMM_LEDS; |
101 | 106 | ||
102 | if (pos & CNT_INTVAL) { | 107 | if (pos & CNT_INTVAL) { |
103 | dev->control_state[pos & ~CNT_INTVAL] | 108 | int i = pos & ~CNT_INTVAL; |
104 | = ucontrol->value.integer.value[0]; | 109 | |
105 | snd_usb_caiaq_send_command(dev, cmd, | 110 | dev->control_state[i] = v; |
106 | dev->control_state, sizeof(dev->control_state)); | 111 | |
112 | if (dev->chip.usb_id == | ||
113 | USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4)) { | ||
114 | int actual_len; | ||
115 | |||
116 | dev->ep8_out_buf[0] = i; | ||
117 | dev->ep8_out_buf[1] = v; | ||
118 | |||
119 | usb_bulk_msg(dev->chip.dev, | ||
120 | usb_sndbulkpipe(dev->chip.dev, 8), | ||
121 | dev->ep8_out_buf, sizeof(dev->ep8_out_buf), | ||
122 | &actual_len, 200); | ||
123 | } else { | ||
124 | snd_usb_caiaq_send_command(dev, cmd, | ||
125 | dev->control_state, sizeof(dev->control_state)); | ||
126 | } | ||
107 | } else { | 127 | } else { |
108 | if (ucontrol->value.integer.value[0]) | 128 | if (v) |
109 | dev->control_state[pos / 8] |= 1 << (pos % 8); | 129 | dev->control_state[pos / 8] |= 1 << (pos % 8); |
110 | else | 130 | else |
111 | dev->control_state[pos / 8] &= ~(1 << (pos % 8)); | 131 | dev->control_state[pos / 8] &= ~(1 << (pos % 8)); |
@@ -296,6 +316,179 @@ static struct caiaq_controller kontrolx1_controller[] = { | |||
296 | { "LED Deck B: SYNC", 8 | CNT_INTVAL }, | 316 | { "LED Deck B: SYNC", 8 | CNT_INTVAL }, |
297 | }; | 317 | }; |
298 | 318 | ||
319 | static struct caiaq_controller kontrols4_controller[] = { | ||
320 | { "LED: Master: Quant", 10 | CNT_INTVAL }, | ||
321 | { "LED: Master: Headphone", 11 | CNT_INTVAL }, | ||
322 | { "LED: Master: Master", 12 | CNT_INTVAL }, | ||
323 | { "LED: Master: Snap", 14 | CNT_INTVAL }, | ||
324 | { "LED: Master: Warning", 15 | CNT_INTVAL }, | ||
325 | { "LED: Master: Master button", 112 | CNT_INTVAL }, | ||
326 | { "LED: Master: Snap button", 113 | CNT_INTVAL }, | ||
327 | { "LED: Master: Rec", 118 | CNT_INTVAL }, | ||
328 | { "LED: Master: Size", 119 | CNT_INTVAL }, | ||
329 | { "LED: Master: Quant button", 120 | CNT_INTVAL }, | ||
330 | { "LED: Master: Browser button", 121 | CNT_INTVAL }, | ||
331 | { "LED: Master: Play button", 126 | CNT_INTVAL }, | ||
332 | { "LED: Master: Undo button", 127 | CNT_INTVAL }, | ||
333 | |||
334 | { "LED: Channel A: >", 4 | CNT_INTVAL }, | ||
335 | { "LED: Channel A: <", 5 | CNT_INTVAL }, | ||
336 | { "LED: Channel A: Meter 1", 97 | CNT_INTVAL }, | ||
337 | { "LED: Channel A: Meter 2", 98 | CNT_INTVAL }, | ||
338 | { "LED: Channel A: Meter 3", 99 | CNT_INTVAL }, | ||
339 | { "LED: Channel A: Meter 4", 100 | CNT_INTVAL }, | ||
340 | { "LED: Channel A: Meter 5", 101 | CNT_INTVAL }, | ||
341 | { "LED: Channel A: Meter 6", 102 | CNT_INTVAL }, | ||
342 | { "LED: Channel A: Meter clip", 103 | CNT_INTVAL }, | ||
343 | { "LED: Channel A: Active", 114 | CNT_INTVAL }, | ||
344 | { "LED: Channel A: Cue", 116 | CNT_INTVAL }, | ||
345 | { "LED: Channel A: FX1", 149 | CNT_INTVAL }, | ||
346 | { "LED: Channel A: FX2", 148 | CNT_INTVAL }, | ||
347 | |||
348 | { "LED: Channel B: >", 2 | CNT_INTVAL }, | ||
349 | { "LED: Channel B: <", 3 | CNT_INTVAL }, | ||
350 | { "LED: Channel B: Meter 1", 89 | CNT_INTVAL }, | ||
351 | { "LED: Channel B: Meter 2", 90 | CNT_INTVAL }, | ||
352 | { "LED: Channel B: Meter 3", 91 | CNT_INTVAL }, | ||
353 | { "LED: Channel B: Meter 4", 92 | CNT_INTVAL }, | ||
354 | { "LED: Channel B: Meter 5", 93 | CNT_INTVAL }, | ||
355 | { "LED: Channel B: Meter 6", 94 | CNT_INTVAL }, | ||
356 | { "LED: Channel B: Meter clip", 95 | CNT_INTVAL }, | ||
357 | { "LED: Channel B: Active", 122 | CNT_INTVAL }, | ||
358 | { "LED: Channel B: Cue", 125 | CNT_INTVAL }, | ||
359 | { "LED: Channel B: FX1", 147 | CNT_INTVAL }, | ||
360 | { "LED: Channel B: FX2", 146 | CNT_INTVAL }, | ||
361 | |||
362 | { "LED: Channel C: >", 6 | CNT_INTVAL }, | ||
363 | { "LED: Channel C: <", 7 | CNT_INTVAL }, | ||
364 | { "LED: Channel C: Meter 1", 105 | CNT_INTVAL }, | ||
365 | { "LED: Channel C: Meter 2", 106 | CNT_INTVAL }, | ||
366 | { "LED: Channel C: Meter 3", 107 | CNT_INTVAL }, | ||
367 | { "LED: Channel C: Meter 4", 108 | CNT_INTVAL }, | ||
368 | { "LED: Channel C: Meter 5", 109 | CNT_INTVAL }, | ||
369 | { "LED: Channel C: Meter 6", 110 | CNT_INTVAL }, | ||
370 | { "LED: Channel C: Meter clip", 111 | CNT_INTVAL }, | ||
371 | { "LED: Channel C: Active", 115 | CNT_INTVAL }, | ||
372 | { "LED: Channel C: Cue", 117 | CNT_INTVAL }, | ||
373 | { "LED: Channel C: FX1", 151 | CNT_INTVAL }, | ||
374 | { "LED: Channel C: FX2", 150 | CNT_INTVAL }, | ||
375 | |||
376 | { "LED: Channel D: >", 0 | CNT_INTVAL }, | ||
377 | { "LED: Channel D: <", 1 | CNT_INTVAL }, | ||
378 | { "LED: Channel D: Meter 1", 81 | CNT_INTVAL }, | ||
379 | { "LED: Channel D: Meter 2", 82 | CNT_INTVAL }, | ||
380 | { "LED: Channel D: Meter 3", 83 | CNT_INTVAL }, | ||
381 | { "LED: Channel D: Meter 4", 84 | CNT_INTVAL }, | ||
382 | { "LED: Channel D: Meter 5", 85 | CNT_INTVAL }, | ||
383 | { "LED: Channel D: Meter 6", 86 | CNT_INTVAL }, | ||
384 | { "LED: Channel D: Meter clip", 87 | CNT_INTVAL }, | ||
385 | { "LED: Channel D: Active", 123 | CNT_INTVAL }, | ||
386 | { "LED: Channel D: Cue", 124 | CNT_INTVAL }, | ||
387 | { "LED: Channel D: FX1", 145 | CNT_INTVAL }, | ||
388 | { "LED: Channel D: FX2", 144 | CNT_INTVAL }, | ||
389 | |||
390 | { "LED: Deck A: 1 (blue)", 22 | CNT_INTVAL }, | ||
391 | { "LED: Deck A: 1 (green)", 23 | CNT_INTVAL }, | ||
392 | { "LED: Deck A: 2 (blue)", 20 | CNT_INTVAL }, | ||
393 | { "LED: Deck A: 2 (green)", 21 | CNT_INTVAL }, | ||
394 | { "LED: Deck A: 3 (blue)", 18 | CNT_INTVAL }, | ||
395 | { "LED: Deck A: 3 (green)", 19 | CNT_INTVAL }, | ||
396 | { "LED: Deck A: 4 (blue)", 16 | CNT_INTVAL }, | ||
397 | { "LED: Deck A: 4 (green)", 17 | CNT_INTVAL }, | ||
398 | { "LED: Deck A: Load", 44 | CNT_INTVAL }, | ||
399 | { "LED: Deck A: Deck C button", 45 | CNT_INTVAL }, | ||
400 | { "LED: Deck A: In", 47 | CNT_INTVAL }, | ||
401 | { "LED: Deck A: Out", 46 | CNT_INTVAL }, | ||
402 | { "LED: Deck A: Shift", 24 | CNT_INTVAL }, | ||
403 | { "LED: Deck A: Sync", 27 | CNT_INTVAL }, | ||
404 | { "LED: Deck A: Cue", 26 | CNT_INTVAL }, | ||
405 | { "LED: Deck A: Play", 25 | CNT_INTVAL }, | ||
406 | { "LED: Deck A: Tempo up", 33 | CNT_INTVAL }, | ||
407 | { "LED: Deck A: Tempo down", 32 | CNT_INTVAL }, | ||
408 | { "LED: Deck A: Master", 34 | CNT_INTVAL }, | ||
409 | { "LED: Deck A: Keylock", 35 | CNT_INTVAL }, | ||
410 | { "LED: Deck A: Deck A", 37 | CNT_INTVAL }, | ||
411 | { "LED: Deck A: Deck C", 36 | CNT_INTVAL }, | ||
412 | { "LED: Deck A: Samples", 38 | CNT_INTVAL }, | ||
413 | { "LED: Deck A: On Air", 39 | CNT_INTVAL }, | ||
414 | { "LED: Deck A: Sample 1", 31 | CNT_INTVAL }, | ||
415 | { "LED: Deck A: Sample 2", 30 | CNT_INTVAL }, | ||
416 | { "LED: Deck A: Sample 3", 29 | CNT_INTVAL }, | ||
417 | { "LED: Deck A: Sample 4", 28 | CNT_INTVAL }, | ||
418 | { "LED: Deck A: Digit 1 - A", 55 | CNT_INTVAL }, | ||
419 | { "LED: Deck A: Digit 1 - B", 54 | CNT_INTVAL }, | ||
420 | { "LED: Deck A: Digit 1 - C", 53 | CNT_INTVAL }, | ||
421 | { "LED: Deck A: Digit 1 - D", 52 | CNT_INTVAL }, | ||
422 | { "LED: Deck A: Digit 1 - E", 51 | CNT_INTVAL }, | ||
423 | { "LED: Deck A: Digit 1 - F", 50 | CNT_INTVAL }, | ||
424 | { "LED: Deck A: Digit 1 - G", 49 | CNT_INTVAL }, | ||
425 | { "LED: Deck A: Digit 1 - dot", 48 | CNT_INTVAL }, | ||
426 | { "LED: Deck A: Digit 2 - A", 63 | CNT_INTVAL }, | ||
427 | { "LED: Deck A: Digit 2 - B", 62 | CNT_INTVAL }, | ||
428 | { "LED: Deck A: Digit 2 - C", 61 | CNT_INTVAL }, | ||
429 | { "LED: Deck A: Digit 2 - D", 60 | CNT_INTVAL }, | ||
430 | { "LED: Deck A: Digit 2 - E", 59 | CNT_INTVAL }, | ||
431 | { "LED: Deck A: Digit 2 - F", 58 | CNT_INTVAL }, | ||
432 | { "LED: Deck A: Digit 2 - G", 57 | CNT_INTVAL }, | ||
433 | { "LED: Deck A: Digit 2 - dot", 56 | CNT_INTVAL }, | ||
434 | |||
435 | { "LED: Deck B: 1 (blue)", 78 | CNT_INTVAL }, | ||
436 | { "LED: Deck B: 1 (green)", 79 | CNT_INTVAL }, | ||
437 | { "LED: Deck B: 2 (blue)", 76 | CNT_INTVAL }, | ||
438 | { "LED: Deck B: 2 (green)", 77 | CNT_INTVAL }, | ||
439 | { "LED: Deck B: 3 (blue)", 74 | CNT_INTVAL }, | ||
440 | { "LED: Deck B: 3 (green)", 75 | CNT_INTVAL }, | ||
441 | { "LED: Deck B: 4 (blue)", 72 | CNT_INTVAL }, | ||
442 | { "LED: Deck B: 4 (green)", 73 | CNT_INTVAL }, | ||
443 | { "LED: Deck B: Load", 180 | CNT_INTVAL }, | ||
444 | { "LED: Deck B: Deck D button", 181 | CNT_INTVAL }, | ||
445 | { "LED: Deck B: In", 183 | CNT_INTVAL }, | ||
446 | { "LED: Deck B: Out", 182 | CNT_INTVAL }, | ||
447 | { "LED: Deck B: Shift", 64 | CNT_INTVAL }, | ||
448 | { "LED: Deck B: Sync", 67 | CNT_INTVAL }, | ||
449 | { "LED: Deck B: Cue", 66 | CNT_INTVAL }, | ||
450 | { "LED: Deck B: Play", 65 | CNT_INTVAL }, | ||
451 | { "LED: Deck B: Tempo up", 185 | CNT_INTVAL }, | ||
452 | { "LED: Deck B: Tempo down", 184 | CNT_INTVAL }, | ||
453 | { "LED: Deck B: Master", 186 | CNT_INTVAL }, | ||
454 | { "LED: Deck B: Keylock", 187 | CNT_INTVAL }, | ||
455 | { "LED: Deck B: Deck B", 189 | CNT_INTVAL }, | ||
456 | { "LED: Deck B: Deck D", 188 | CNT_INTVAL }, | ||
457 | { "LED: Deck B: Samples", 190 | CNT_INTVAL }, | ||
458 | { "LED: Deck B: On Air", 191 | CNT_INTVAL }, | ||
459 | { "LED: Deck B: Sample 1", 71 | CNT_INTVAL }, | ||
460 | { "LED: Deck B: Sample 2", 70 | CNT_INTVAL }, | ||
461 | { "LED: Deck B: Sample 3", 69 | CNT_INTVAL }, | ||
462 | { "LED: Deck B: Sample 4", 68 | CNT_INTVAL }, | ||
463 | { "LED: Deck B: Digit 1 - A", 175 | CNT_INTVAL }, | ||
464 | { "LED: Deck B: Digit 1 - B", 174 | CNT_INTVAL }, | ||
465 | { "LED: Deck B: Digit 1 - C", 173 | CNT_INTVAL }, | ||
466 | { "LED: Deck B: Digit 1 - D", 172 | CNT_INTVAL }, | ||
467 | { "LED: Deck B: Digit 1 - E", 171 | CNT_INTVAL }, | ||
468 | { "LED: Deck B: Digit 1 - F", 170 | CNT_INTVAL }, | ||
469 | { "LED: Deck B: Digit 1 - G", 169 | CNT_INTVAL }, | ||
470 | { "LED: Deck B: Digit 1 - dot", 168 | CNT_INTVAL }, | ||
471 | { "LED: Deck B: Digit 2 - A", 167 | CNT_INTVAL }, | ||
472 | { "LED: Deck B: Digit 2 - B", 166 | CNT_INTVAL }, | ||
473 | { "LED: Deck B: Digit 2 - C", 165 | CNT_INTVAL }, | ||
474 | { "LED: Deck B: Digit 2 - D", 164 | CNT_INTVAL }, | ||
475 | { "LED: Deck B: Digit 2 - E", 163 | CNT_INTVAL }, | ||
476 | { "LED: Deck B: Digit 2 - F", 162 | CNT_INTVAL }, | ||
477 | { "LED: Deck B: Digit 2 - G", 161 | CNT_INTVAL }, | ||
478 | { "LED: Deck B: Digit 2 - dot", 160 | CNT_INTVAL }, | ||
479 | |||
480 | { "LED: FX1: dry/wet", 153 | CNT_INTVAL }, | ||
481 | { "LED: FX1: 1", 154 | CNT_INTVAL }, | ||
482 | { "LED: FX1: 2", 155 | CNT_INTVAL }, | ||
483 | { "LED: FX1: 3", 156 | CNT_INTVAL }, | ||
484 | { "LED: FX1: Mode", 157 | CNT_INTVAL }, | ||
485 | { "LED: FX2: dry/wet", 129 | CNT_INTVAL }, | ||
486 | { "LED: FX2: 1", 130 | CNT_INTVAL }, | ||
487 | { "LED: FX2: 2", 131 | CNT_INTVAL }, | ||
488 | { "LED: FX2: 3", 132 | CNT_INTVAL }, | ||
489 | { "LED: FX2: Mode", 133 | CNT_INTVAL }, | ||
490 | }; | ||
491 | |||
299 | static int __devinit add_controls(struct caiaq_controller *c, int num, | 492 | static int __devinit add_controls(struct caiaq_controller *c, int num, |
300 | struct snd_usb_caiaqdev *dev) | 493 | struct snd_usb_caiaqdev *dev) |
301 | { | 494 | { |
@@ -354,6 +547,11 @@ int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev) | |||
354 | ret = add_controls(kontrolx1_controller, | 547 | ret = add_controls(kontrolx1_controller, |
355 | ARRAY_SIZE(kontrolx1_controller), dev); | 548 | ARRAY_SIZE(kontrolx1_controller), dev); |
356 | break; | 549 | break; |
550 | |||
551 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): | ||
552 | ret = add_controls(kontrols4_controller, | ||
553 | ARRAY_SIZE(kontrols4_controller), dev); | ||
554 | break; | ||
357 | } | 555 | } |
358 | 556 | ||
359 | return ret; | 557 | return ret; |
diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c index cdfb856bddd2..6480c3283c05 100644 --- a/sound/usb/caiaq/device.c +++ b/sound/usb/caiaq/device.c | |||
@@ -36,7 +36,7 @@ | |||
36 | #include "input.h" | 36 | #include "input.h" |
37 | 37 | ||
38 | MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); | 38 | MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); |
39 | MODULE_DESCRIPTION("caiaq USB audio, version 1.3.21"); | 39 | MODULE_DESCRIPTION("caiaq USB audio"); |
40 | MODULE_LICENSE("GPL"); | 40 | MODULE_LICENSE("GPL"); |
41 | MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," | 41 | MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," |
42 | "{Native Instruments, RigKontrol3}," | 42 | "{Native Instruments, RigKontrol3}," |
@@ -48,7 +48,8 @@ MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," | |||
48 | "{Native Instruments, Audio 8 DJ}," | 48 | "{Native Instruments, Audio 8 DJ}," |
49 | "{Native Instruments, Session I/O}," | 49 | "{Native Instruments, Session I/O}," |
50 | "{Native Instruments, GuitarRig mobile}" | 50 | "{Native Instruments, GuitarRig mobile}" |
51 | "{Native Instruments, Traktor Kontrol X1}"); | 51 | "{Native Instruments, Traktor Kontrol X1}" |
52 | "{Native Instruments, Traktor Kontrol S4}"); | ||
52 | 53 | ||
53 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ | 54 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ |
54 | static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */ | 55 | static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */ |
@@ -134,6 +135,11 @@ static struct usb_device_id snd_usb_id_table[] = { | |||
134 | .idVendor = USB_VID_NATIVEINSTRUMENTS, | 135 | .idVendor = USB_VID_NATIVEINSTRUMENTS, |
135 | .idProduct = USB_PID_TRAKTORKONTROLX1 | 136 | .idProduct = USB_PID_TRAKTORKONTROLX1 |
136 | }, | 137 | }, |
138 | { | ||
139 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE, | ||
140 | .idVendor = USB_VID_NATIVEINSTRUMENTS, | ||
141 | .idProduct = USB_PID_TRAKTORKONTROLS4 | ||
142 | }, | ||
137 | { /* terminator */ } | 143 | { /* terminator */ } |
138 | }; | 144 | }; |
139 | 145 | ||
diff --git a/sound/usb/caiaq/device.h b/sound/usb/caiaq/device.h index f1117ecc84fd..e3d8a3efb35b 100644 --- a/sound/usb/caiaq/device.h +++ b/sound/usb/caiaq/device.h | |||
@@ -16,6 +16,7 @@ | |||
16 | #define USB_PID_SESSIONIO 0x1915 | 16 | #define USB_PID_SESSIONIO 0x1915 |
17 | #define USB_PID_GUITARRIGMOBILE 0x0d8d | 17 | #define USB_PID_GUITARRIGMOBILE 0x0d8d |
18 | #define USB_PID_TRAKTORKONTROLX1 0x2305 | 18 | #define USB_PID_TRAKTORKONTROLX1 0x2305 |
19 | #define USB_PID_TRAKTORKONTROLS4 0xbaff | ||
19 | 20 | ||
20 | #define EP1_BUFSIZE 64 | 21 | #define EP1_BUFSIZE 64 |
21 | #define EP4_BUFSIZE 512 | 22 | #define EP4_BUFSIZE 512 |
@@ -99,13 +100,14 @@ struct snd_usb_caiaqdev { | |||
99 | struct snd_pcm_substream *sub_capture[MAX_STREAMS]; | 100 | struct snd_pcm_substream *sub_capture[MAX_STREAMS]; |
100 | 101 | ||
101 | /* Controls */ | 102 | /* Controls */ |
102 | unsigned char control_state[64]; | 103 | unsigned char control_state[256]; |
104 | unsigned char ep8_out_buf[2]; | ||
103 | 105 | ||
104 | /* Linux input */ | 106 | /* Linux input */ |
105 | #ifdef CONFIG_SND_USB_CAIAQ_INPUT | 107 | #ifdef CONFIG_SND_USB_CAIAQ_INPUT |
106 | struct input_dev *input_dev; | 108 | struct input_dev *input_dev; |
107 | char phys[64]; /* physical device path */ | 109 | char phys[64]; /* physical device path */ |
108 | unsigned short keycode[64]; | 110 | unsigned short keycode[128]; |
109 | struct urb *ep4_in_urb; | 111 | struct urb *ep4_in_urb; |
110 | unsigned char ep4_in_buf[EP4_BUFSIZE]; | 112 | unsigned char ep4_in_buf[EP4_BUFSIZE]; |
111 | #endif | 113 | #endif |
diff --git a/sound/usb/caiaq/input.c b/sound/usb/caiaq/input.c index dcb620796d9e..4432ef7a70a9 100644 --- a/sound/usb/caiaq/input.c +++ b/sound/usb/caiaq/input.c | |||
@@ -67,7 +67,12 @@ static unsigned short keycode_kore[] = { | |||
67 | KEY_BRL_DOT5 | 67 | KEY_BRL_DOT5 |
68 | }; | 68 | }; |
69 | 69 | ||
70 | #define KONTROLX1_INPUTS 40 | 70 | #define KONTROLX1_INPUTS (40) |
71 | #define KONTROLS4_BUTTONS (12 * 8) | ||
72 | #define KONTROLS4_AXIS (46) | ||
73 | |||
74 | #define KONTROLS4_BUTTON(X) ((X) + BTN_MISC) | ||
75 | #define KONTROLS4_ABS(X) ((X) + ABS_HAT0X) | ||
71 | 76 | ||
72 | #define DEG90 (range / 2) | 77 | #define DEG90 (range / 2) |
73 | #define DEG180 (range) | 78 | #define DEG180 (range) |
@@ -139,6 +144,13 @@ static unsigned int decode_erp(unsigned char a, unsigned char b) | |||
139 | #undef HIGH_PEAK | 144 | #undef HIGH_PEAK |
140 | #undef LOW_PEAK | 145 | #undef LOW_PEAK |
141 | 146 | ||
147 | static inline void snd_caiaq_input_report_abs(struct snd_usb_caiaqdev *dev, | ||
148 | int axis, const unsigned char *buf, | ||
149 | int offset) | ||
150 | { | ||
151 | input_report_abs(dev->input_dev, axis, | ||
152 | (buf[offset * 2] << 8) | buf[offset * 2 + 1]); | ||
153 | } | ||
142 | 154 | ||
143 | static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, | 155 | static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, |
144 | const unsigned char *buf, | 156 | const unsigned char *buf, |
@@ -148,36 +160,30 @@ static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, | |||
148 | 160 | ||
149 | switch (dev->chip.usb_id) { | 161 | switch (dev->chip.usb_id) { |
150 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): | 162 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): |
151 | input_report_abs(input_dev, ABS_X, (buf[4] << 8) | buf[5]); | 163 | snd_caiaq_input_report_abs(dev, ABS_X, buf, 2); |
152 | input_report_abs(input_dev, ABS_Y, (buf[0] << 8) | buf[1]); | 164 | snd_caiaq_input_report_abs(dev, ABS_Y, buf, 0); |
153 | input_report_abs(input_dev, ABS_Z, (buf[2] << 8) | buf[3]); | 165 | snd_caiaq_input_report_abs(dev, ABS_Z, buf, 1); |
154 | input_sync(input_dev); | ||
155 | break; | 166 | break; |
156 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): | 167 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): |
157 | input_report_abs(input_dev, ABS_X, (buf[0] << 8) | buf[1]); | ||
158 | input_report_abs(input_dev, ABS_Y, (buf[2] << 8) | buf[3]); | ||
159 | input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]); | ||
160 | input_sync(input_dev); | ||
161 | break; | ||
162 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER): | 168 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER): |
163 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2): | 169 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2): |
164 | input_report_abs(input_dev, ABS_X, (buf[0] << 8) | buf[1]); | 170 | snd_caiaq_input_report_abs(dev, ABS_X, buf, 0); |
165 | input_report_abs(input_dev, ABS_Y, (buf[2] << 8) | buf[3]); | 171 | snd_caiaq_input_report_abs(dev, ABS_Y, buf, 1); |
166 | input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]); | 172 | snd_caiaq_input_report_abs(dev, ABS_Z, buf, 2); |
167 | input_sync(input_dev); | ||
168 | break; | 173 | break; |
169 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): | 174 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): |
170 | input_report_abs(input_dev, ABS_HAT0X, (buf[8] << 8) | buf[9]); | 175 | snd_caiaq_input_report_abs(dev, ABS_HAT0X, buf, 4); |
171 | input_report_abs(input_dev, ABS_HAT0Y, (buf[4] << 8) | buf[5]); | 176 | snd_caiaq_input_report_abs(dev, ABS_HAT0Y, buf, 2); |
172 | input_report_abs(input_dev, ABS_HAT1X, (buf[12] << 8) | buf[13]); | 177 | snd_caiaq_input_report_abs(dev, ABS_HAT1X, buf, 6); |
173 | input_report_abs(input_dev, ABS_HAT1Y, (buf[2] << 8) | buf[3]); | 178 | snd_caiaq_input_report_abs(dev, ABS_HAT1Y, buf, 1); |
174 | input_report_abs(input_dev, ABS_HAT2X, (buf[14] << 8) | buf[15]); | 179 | snd_caiaq_input_report_abs(dev, ABS_HAT2X, buf, 7); |
175 | input_report_abs(input_dev, ABS_HAT2Y, (buf[0] << 8) | buf[1]); | 180 | snd_caiaq_input_report_abs(dev, ABS_HAT2Y, buf, 0); |
176 | input_report_abs(input_dev, ABS_HAT3X, (buf[10] << 8) | buf[11]); | 181 | snd_caiaq_input_report_abs(dev, ABS_HAT3X, buf, 5); |
177 | input_report_abs(input_dev, ABS_HAT3Y, (buf[6] << 8) | buf[7]); | 182 | snd_caiaq_input_report_abs(dev, ABS_HAT3Y, buf, 3); |
178 | input_sync(input_dev); | ||
179 | break; | 183 | break; |
180 | } | 184 | } |
185 | |||
186 | input_sync(input_dev); | ||
181 | } | 187 | } |
182 | 188 | ||
183 | static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev, | 189 | static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev, |
@@ -250,6 +256,150 @@ static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev, | |||
250 | input_sync(input_dev); | 256 | input_sync(input_dev); |
251 | } | 257 | } |
252 | 258 | ||
259 | #define TKS4_MSGBLOCK_SIZE 16 | ||
260 | |||
261 | static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *dev, | ||
262 | const unsigned char *buf, | ||
263 | unsigned int len) | ||
264 | { | ||
265 | while (len) { | ||
266 | unsigned int i, block_id = (buf[0] << 8) | buf[1]; | ||
267 | |||
268 | switch (block_id) { | ||
269 | case 0: | ||
270 | /* buttons */ | ||
271 | for (i = 0; i < KONTROLS4_BUTTONS; i++) | ||
272 | input_report_key(dev->input_dev, KONTROLS4_BUTTON(i), | ||
273 | (buf[4 + (i / 8)] >> (i % 8)) & 1); | ||
274 | break; | ||
275 | |||
276 | case 1: | ||
277 | /* left wheel */ | ||
278 | input_report_abs(dev->input_dev, KONTROLS4_ABS(36), buf[9] | ((buf[8] & 0x3) << 8)); | ||
279 | /* right wheel */ | ||
280 | input_report_abs(dev->input_dev, KONTROLS4_ABS(37), buf[13] | ((buf[12] & 0x3) << 8)); | ||
281 | |||
282 | /* rotary encoders */ | ||
283 | input_report_abs(dev->input_dev, KONTROLS4_ABS(38), buf[3] & 0xf); | ||
284 | input_report_abs(dev->input_dev, KONTROLS4_ABS(39), buf[4] >> 4); | ||
285 | input_report_abs(dev->input_dev, KONTROLS4_ABS(40), buf[4] & 0xf); | ||
286 | input_report_abs(dev->input_dev, KONTROLS4_ABS(41), buf[5] >> 4); | ||
287 | input_report_abs(dev->input_dev, KONTROLS4_ABS(42), buf[5] & 0xf); | ||
288 | input_report_abs(dev->input_dev, KONTROLS4_ABS(43), buf[6] >> 4); | ||
289 | input_report_abs(dev->input_dev, KONTROLS4_ABS(44), buf[6] & 0xf); | ||
290 | input_report_abs(dev->input_dev, KONTROLS4_ABS(45), buf[7] >> 4); | ||
291 | input_report_abs(dev->input_dev, KONTROLS4_ABS(46), buf[7] & 0xf); | ||
292 | |||
293 | break; | ||
294 | case 2: | ||
295 | /* Volume Fader Channel D */ | ||
296 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(0), buf, 1); | ||
297 | /* Volume Fader Channel B */ | ||
298 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(1), buf, 2); | ||
299 | /* Volume Fader Channel A */ | ||
300 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(2), buf, 3); | ||
301 | /* Volume Fader Channel C */ | ||
302 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(3), buf, 4); | ||
303 | /* Loop Volume */ | ||
304 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(4), buf, 6); | ||
305 | /* Crossfader */ | ||
306 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(7), buf, 7); | ||
307 | |||
308 | break; | ||
309 | |||
310 | case 3: | ||
311 | /* Tempo Fader R */ | ||
312 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(6), buf, 3); | ||
313 | /* Tempo Fader L */ | ||
314 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(5), buf, 4); | ||
315 | /* Mic Volume */ | ||
316 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(8), buf, 6); | ||
317 | /* Cue Mix */ | ||
318 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(9), buf, 7); | ||
319 | |||
320 | break; | ||
321 | |||
322 | case 4: | ||
323 | /* Wheel distance sensor L */ | ||
324 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(10), buf, 1); | ||
325 | /* Wheel distance sensor R */ | ||
326 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(11), buf, 2); | ||
327 | /* Channel D EQ - Filter */ | ||
328 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(12), buf, 3); | ||
329 | /* Channel D EQ - Low */ | ||
330 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(13), buf, 4); | ||
331 | /* Channel D EQ - Mid */ | ||
332 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(14), buf, 5); | ||
333 | /* Channel D EQ - Hi */ | ||
334 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(15), buf, 6); | ||
335 | /* FX2 - dry/wet */ | ||
336 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(16), buf, 7); | ||
337 | |||
338 | break; | ||
339 | |||
340 | case 5: | ||
341 | /* FX2 - 1 */ | ||
342 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(17), buf, 1); | ||
343 | /* FX2 - 2 */ | ||
344 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(18), buf, 2); | ||
345 | /* FX2 - 3 */ | ||
346 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(19), buf, 3); | ||
347 | /* Channel B EQ - Filter */ | ||
348 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(20), buf, 4); | ||
349 | /* Channel B EQ - Low */ | ||
350 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(21), buf, 5); | ||
351 | /* Channel B EQ - Mid */ | ||
352 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(22), buf, 6); | ||
353 | /* Channel B EQ - Hi */ | ||
354 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(23), buf, 7); | ||
355 | |||
356 | break; | ||
357 | |||
358 | case 6: | ||
359 | /* Channel A EQ - Filter */ | ||
360 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(24), buf, 1); | ||
361 | /* Channel A EQ - Low */ | ||
362 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(25), buf, 2); | ||
363 | /* Channel A EQ - Mid */ | ||
364 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(26), buf, 3); | ||
365 | /* Channel A EQ - Hi */ | ||
366 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(27), buf, 4); | ||
367 | /* Channel C EQ - Filter */ | ||
368 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(28), buf, 5); | ||
369 | /* Channel C EQ - Low */ | ||
370 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(29), buf, 6); | ||
371 | /* Channel C EQ - Mid */ | ||
372 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(30), buf, 7); | ||
373 | |||
374 | break; | ||
375 | |||
376 | case 7: | ||
377 | /* Channel C EQ - Hi */ | ||
378 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(31), buf, 1); | ||
379 | /* FX1 - wet/dry */ | ||
380 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(32), buf, 2); | ||
381 | /* FX1 - 1 */ | ||
382 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(33), buf, 3); | ||
383 | /* FX1 - 2 */ | ||
384 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(34), buf, 4); | ||
385 | /* FX1 - 3 */ | ||
386 | snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(35), buf, 5); | ||
387 | |||
388 | break; | ||
389 | |||
390 | default: | ||
391 | debug("%s(): bogus block (id %d)\n", | ||
392 | __func__, block_id); | ||
393 | return; | ||
394 | } | ||
395 | |||
396 | len -= TKS4_MSGBLOCK_SIZE; | ||
397 | buf += TKS4_MSGBLOCK_SIZE; | ||
398 | } | ||
399 | |||
400 | input_sync(dev->input_dev); | ||
401 | } | ||
402 | |||
253 | static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb) | 403 | static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb) |
254 | { | 404 | { |
255 | struct snd_usb_caiaqdev *dev = urb->context; | 405 | struct snd_usb_caiaqdev *dev = urb->context; |
@@ -259,11 +409,11 @@ static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb) | |||
259 | if (urb->status || !dev || urb != dev->ep4_in_urb) | 409 | if (urb->status || !dev || urb != dev->ep4_in_urb) |
260 | return; | 410 | return; |
261 | 411 | ||
262 | if (urb->actual_length < 24) | ||
263 | goto requeue; | ||
264 | |||
265 | switch (dev->chip.usb_id) { | 412 | switch (dev->chip.usb_id) { |
266 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): | 413 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): |
414 | if (urb->actual_length < 24) | ||
415 | goto requeue; | ||
416 | |||
267 | if (buf[0] & 0x3) | 417 | if (buf[0] & 0x3) |
268 | snd_caiaq_input_read_io(dev, buf + 1, 7); | 418 | snd_caiaq_input_read_io(dev, buf + 1, 7); |
269 | 419 | ||
@@ -271,6 +421,10 @@ static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb) | |||
271 | snd_caiaq_input_read_analog(dev, buf + 8, 16); | 421 | snd_caiaq_input_read_analog(dev, buf + 8, 16); |
272 | 422 | ||
273 | break; | 423 | break; |
424 | |||
425 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): | ||
426 | snd_usb_caiaq_tks4_dispatch(dev, buf, urb->actual_length); | ||
427 | break; | ||
274 | } | 428 | } |
275 | 429 | ||
276 | requeue: | 430 | requeue: |
@@ -289,6 +443,7 @@ static int snd_usb_caiaq_input_open(struct input_dev *idev) | |||
289 | 443 | ||
290 | switch (dev->chip.usb_id) { | 444 | switch (dev->chip.usb_id) { |
291 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): | 445 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): |
446 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): | ||
292 | if (usb_submit_urb(dev->ep4_in_urb, GFP_KERNEL) != 0) | 447 | if (usb_submit_urb(dev->ep4_in_urb, GFP_KERNEL) != 0) |
293 | return -EIO; | 448 | return -EIO; |
294 | break; | 449 | break; |
@@ -306,6 +461,7 @@ static void snd_usb_caiaq_input_close(struct input_dev *idev) | |||
306 | 461 | ||
307 | switch (dev->chip.usb_id) { | 462 | switch (dev->chip.usb_id) { |
308 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): | 463 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): |
464 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): | ||
309 | usb_kill_urb(dev->ep4_in_urb); | 465 | usb_kill_urb(dev->ep4_in_urb); |
310 | break; | 466 | break; |
311 | } | 467 | } |
@@ -456,6 +612,46 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev) | |||
456 | snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5); | 612 | snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5); |
457 | 613 | ||
458 | break; | 614 | break; |
615 | |||
616 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): | ||
617 | input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | ||
618 | BUILD_BUG_ON(sizeof(dev->keycode) < KONTROLS4_BUTTONS); | ||
619 | for (i = 0; i < KONTROLS4_BUTTONS; i++) | ||
620 | dev->keycode[i] = KONTROLS4_BUTTON(i); | ||
621 | input->keycodemax = KONTROLS4_BUTTONS; | ||
622 | |||
623 | for (i = 0; i < KONTROLS4_AXIS; i++) { | ||
624 | int axis = KONTROLS4_ABS(i); | ||
625 | input->absbit[BIT_WORD(axis)] |= BIT_MASK(axis); | ||
626 | } | ||
627 | |||
628 | /* 36 analog potentiometers and faders */ | ||
629 | for (i = 0; i < 36; i++) | ||
630 | input_set_abs_params(input, KONTROLS4_ABS(i), 0, 0xfff, 0, 10); | ||
631 | |||
632 | /* 2 encoder wheels */ | ||
633 | input_set_abs_params(input, KONTROLS4_ABS(36), 0, 0x3ff, 0, 1); | ||
634 | input_set_abs_params(input, KONTROLS4_ABS(37), 0, 0x3ff, 0, 1); | ||
635 | |||
636 | /* 9 rotary encoders */ | ||
637 | for (i = 0; i < 9; i++) | ||
638 | input_set_abs_params(input, KONTROLS4_ABS(38+i), 0, 0xf, 0, 1); | ||
639 | |||
640 | dev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
641 | if (!dev->ep4_in_urb) { | ||
642 | ret = -ENOMEM; | ||
643 | goto exit_free_idev; | ||
644 | } | ||
645 | |||
646 | usb_fill_bulk_urb(dev->ep4_in_urb, usb_dev, | ||
647 | usb_rcvbulkpipe(usb_dev, 0x4), | ||
648 | dev->ep4_in_buf, EP4_BUFSIZE, | ||
649 | snd_usb_caiaq_ep4_reply_dispatch, dev); | ||
650 | |||
651 | snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5); | ||
652 | |||
653 | break; | ||
654 | |||
459 | default: | 655 | default: |
460 | /* no input methods supported on this device */ | 656 | /* no input methods supported on this device */ |
461 | goto exit_free_idev; | 657 | goto exit_free_idev; |
diff --git a/sound/usb/card.c b/sound/usb/card.c index 4eabafa5b037..800f7cb4f251 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c | |||
@@ -300,9 +300,13 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, | |||
300 | 300 | ||
301 | *rchip = NULL; | 301 | *rchip = NULL; |
302 | 302 | ||
303 | if (snd_usb_get_speed(dev) != USB_SPEED_LOW && | 303 | switch (snd_usb_get_speed(dev)) { |
304 | snd_usb_get_speed(dev) != USB_SPEED_FULL && | 304 | case USB_SPEED_LOW: |
305 | snd_usb_get_speed(dev) != USB_SPEED_HIGH) { | 305 | case USB_SPEED_FULL: |
306 | case USB_SPEED_HIGH: | ||
307 | case USB_SPEED_SUPER: | ||
308 | break; | ||
309 | default: | ||
306 | snd_printk(KERN_ERR "unknown device speed %d\n", snd_usb_get_speed(dev)); | 310 | snd_printk(KERN_ERR "unknown device speed %d\n", snd_usb_get_speed(dev)); |
307 | return -ENXIO; | 311 | return -ENXIO; |
308 | } | 312 | } |
@@ -378,11 +382,22 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, | |||
378 | if (len < sizeof(card->longname)) | 382 | if (len < sizeof(card->longname)) |
379 | usb_make_path(dev, card->longname + len, sizeof(card->longname) - len); | 383 | usb_make_path(dev, card->longname + len, sizeof(card->longname) - len); |
380 | 384 | ||
381 | strlcat(card->longname, | 385 | switch (snd_usb_get_speed(dev)) { |
382 | snd_usb_get_speed(dev) == USB_SPEED_LOW ? ", low speed" : | 386 | case USB_SPEED_LOW: |
383 | snd_usb_get_speed(dev) == USB_SPEED_FULL ? ", full speed" : | 387 | strlcat(card->longname, ", low speed", sizeof(card->longname)); |
384 | ", high speed", | 388 | break; |
385 | sizeof(card->longname)); | 389 | case USB_SPEED_FULL: |
390 | strlcat(card->longname, ", full speed", sizeof(card->longname)); | ||
391 | break; | ||
392 | case USB_SPEED_HIGH: | ||
393 | strlcat(card->longname, ", high speed", sizeof(card->longname)); | ||
394 | break; | ||
395 | case USB_SPEED_SUPER: | ||
396 | strlcat(card->longname, ", super speed", sizeof(card->longname)); | ||
397 | break; | ||
398 | default: | ||
399 | break; | ||
400 | } | ||
386 | 401 | ||
387 | snd_usb_audio_create_proc(chip); | 402 | snd_usb_audio_create_proc(chip); |
388 | 403 | ||
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index ef0a07e34844..b0ef9f501896 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c | |||
@@ -405,8 +405,6 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
405 | break; | 405 | break; |
406 | case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */ | 406 | case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */ |
407 | case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ | 407 | case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ |
408 | case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra 8 */ | ||
409 | case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */ | ||
410 | /* doesn't set the sample rate attribute, but supports it */ | 408 | /* doesn't set the sample rate attribute, but supports it */ |
411 | fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE; | 409 | fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE; |
412 | break; | 410 | break; |
diff --git a/sound/usb/helper.c b/sound/usb/helper.c index d48d6f8f6ac9..f280c1903c25 100644 --- a/sound/usb/helper.c +++ b/sound/usb/helper.c | |||
@@ -103,11 +103,16 @@ int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request, | |||
103 | unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip, | 103 | unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip, |
104 | struct usb_host_interface *alts) | 104 | struct usb_host_interface *alts) |
105 | { | 105 | { |
106 | if (snd_usb_get_speed(chip->dev) == USB_SPEED_HIGH && | 106 | switch (snd_usb_get_speed(chip->dev)) { |
107 | get_endpoint(alts, 0)->bInterval >= 1 && | 107 | case USB_SPEED_HIGH: |
108 | get_endpoint(alts, 0)->bInterval <= 4) | 108 | case USB_SPEED_SUPER: |
109 | return get_endpoint(alts, 0)->bInterval - 1; | 109 | if (get_endpoint(alts, 0)->bInterval >= 1 && |
110 | else | 110 | get_endpoint(alts, 0)->bInterval <= 4) |
111 | return 0; | 111 | return get_endpoint(alts, 0)->bInterval - 1; |
112 | break; | ||
113 | default: | ||
114 | break; | ||
115 | } | ||
116 | return 0; | ||
112 | } | 117 | } |
113 | 118 | ||
diff --git a/sound/usb/midi.c b/sound/usb/midi.c index b9c2bc65f51a..25bce7e5b1af 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c | |||
@@ -784,7 +784,7 @@ static struct usb_protocol_ops snd_usbmidi_novation_ops = { | |||
784 | }; | 784 | }; |
785 | 785 | ||
786 | /* | 786 | /* |
787 | * "raw" protocol: used by the MOTU FastLane. | 787 | * "raw" protocol: just move raw MIDI bytes from/to the endpoint |
788 | */ | 788 | */ |
789 | 789 | ||
790 | static void snd_usbmidi_raw_input(struct snd_usb_midi_in_endpoint* ep, | 790 | static void snd_usbmidi_raw_input(struct snd_usb_midi_in_endpoint* ep, |
@@ -834,7 +834,14 @@ static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep, | |||
834 | 834 | ||
835 | if (!ep->ports[0].active) | 835 | if (!ep->ports[0].active) |
836 | return; | 836 | return; |
837 | count = snd_usb_get_speed(ep->umidi->dev) == USB_SPEED_HIGH ? 1 : 2; | 837 | switch (snd_usb_get_speed(ep->umidi->dev)) { |
838 | case USB_SPEED_HIGH: | ||
839 | case USB_SPEED_SUPER: | ||
840 | count = 1; | ||
841 | break; | ||
842 | default: | ||
843 | count = 2; | ||
844 | } | ||
838 | count = snd_rawmidi_transmit(ep->ports[0].substream, | 845 | count = snd_rawmidi_transmit(ep->ports[0].substream, |
839 | urb->transfer_buffer, | 846 | urb->transfer_buffer, |
840 | count); | 847 | count); |
@@ -2115,7 +2122,7 @@ int snd_usbmidi_create(struct snd_card *card, | |||
2115 | umidi->usb_protocol_ops = &snd_usbmidi_novation_ops; | 2122 | umidi->usb_protocol_ops = &snd_usbmidi_novation_ops; |
2116 | err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); | 2123 | err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); |
2117 | break; | 2124 | break; |
2118 | case QUIRK_MIDI_FASTLANE: | 2125 | case QUIRK_MIDI_RAW_BYTES: |
2119 | umidi->usb_protocol_ops = &snd_usbmidi_raw_ops; | 2126 | umidi->usb_protocol_ops = &snd_usbmidi_raw_ops; |
2120 | /* | 2127 | /* |
2121 | * Interface 1 contains isochronous endpoints, but with the same | 2128 | * Interface 1 contains isochronous endpoints, but with the same |
@@ -2126,7 +2133,8 @@ int snd_usbmidi_create(struct snd_card *card, | |||
2126 | * interface 0, so we have to make sure that the USB core looks | 2133 | * interface 0, so we have to make sure that the USB core looks |
2127 | * again at interface 0 by calling usb_set_interface() on it. | 2134 | * again at interface 0 by calling usb_set_interface() on it. |
2128 | */ | 2135 | */ |
2129 | usb_set_interface(umidi->dev, 0, 0); | 2136 | if (umidi->usb_id == USB_ID(0x07fd, 0x0001)) /* MOTU Fastlane */ |
2137 | usb_set_interface(umidi->dev, 0, 0); | ||
2130 | err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); | 2138 | err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); |
2131 | break; | 2139 | break; |
2132 | case QUIRK_MIDI_EMAGIC: | 2140 | case QUIRK_MIDI_EMAGIC: |
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 3ed3901369ce..f2d74d654b3c 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c | |||
@@ -759,8 +759,6 @@ static void usb_mixer_elem_free(struct snd_kcontrol *kctl) | |||
759 | */ | 759 | */ |
760 | static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) | 760 | static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) |
761 | { | 761 | { |
762 | struct snd_usb_audio *chip = cval->mixer->chip; | ||
763 | |||
764 | /* for failsafe */ | 762 | /* for failsafe */ |
765 | cval->min = default_min; | 763 | cval->min = default_min; |
766 | cval->max = cval->min + 1; | 764 | cval->max = cval->min + 1; |
@@ -783,7 +781,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) | |||
783 | if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 || | 781 | if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 || |
784 | get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) { | 782 | get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) { |
785 | snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n", | 783 | snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n", |
786 | cval->id, snd_usb_ctrl_intf(chip), cval->control, cval->id); | 784 | cval->id, snd_usb_ctrl_intf(cval->mixer->chip), cval->control, cval->id); |
787 | return -EINVAL; | 785 | return -EINVAL; |
788 | } | 786 | } |
789 | if (get_ctl_value(cval, UAC_GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) { | 787 | if (get_ctl_value(cval, UAC_GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) { |
@@ -1642,9 +1640,10 @@ static int mixer_ctl_selector_info(struct snd_kcontrol *kcontrol, struct snd_ctl | |||
1642 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 1640 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
1643 | uinfo->count = 1; | 1641 | uinfo->count = 1; |
1644 | uinfo->value.enumerated.items = cval->max; | 1642 | uinfo->value.enumerated.items = cval->max; |
1645 | if ((int)uinfo->value.enumerated.item >= cval->max) | 1643 | if (uinfo->value.enumerated.item >= cval->max) |
1646 | uinfo->value.enumerated.item = cval->max - 1; | 1644 | uinfo->value.enumerated.item = cval->max - 1; |
1647 | strcpy(uinfo->value.enumerated.name, itemlist[uinfo->value.enumerated.item]); | 1645 | strlcpy(uinfo->value.enumerated.name, itemlist[uinfo->value.enumerated.item], |
1646 | sizeof(uinfo->value.enumerated.name)); | ||
1648 | return 0; | 1647 | return 0; |
1649 | } | 1648 | } |
1650 | 1649 | ||
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index e7df1e5e3f2e..7dae05d8783e 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c | |||
@@ -60,6 +60,7 @@ static const struct rc_config { | |||
60 | { USB_ID(0x041e, 0x3000), 0, 1, 2, 1, 18, 0x0013 }, /* Extigy */ | 60 | { USB_ID(0x041e, 0x3000), 0, 1, 2, 1, 18, 0x0013 }, /* Extigy */ |
61 | { USB_ID(0x041e, 0x3020), 2, 1, 6, 6, 18, 0x0013 }, /* Audigy 2 NX */ | 61 | { USB_ID(0x041e, 0x3020), 2, 1, 6, 6, 18, 0x0013 }, /* Audigy 2 NX */ |
62 | { USB_ID(0x041e, 0x3040), 2, 2, 6, 6, 2, 0x6e91 }, /* Live! 24-bit */ | 62 | { USB_ID(0x041e, 0x3040), 2, 2, 6, 6, 2, 0x6e91 }, /* Live! 24-bit */ |
63 | { USB_ID(0x041e, 0x3042), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi */ | ||
63 | { USB_ID(0x041e, 0x3048), 2, 2, 6, 6, 2, 0x6e91 }, /* Toshiba SB0500 */ | 64 | { USB_ID(0x041e, 0x3048), 2, 2, 6, 6, 2, 0x6e91 }, /* Toshiba SB0500 */ |
64 | }; | 65 | }; |
65 | 66 | ||
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 3b5135c93062..f49756c1b837 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c | |||
@@ -466,7 +466,7 @@ static int hw_check_valid_format(struct snd_usb_substream *subs, | |||
466 | return 0; | 466 | return 0; |
467 | } | 467 | } |
468 | /* check whether the period time is >= the data packet interval */ | 468 | /* check whether the period time is >= the data packet interval */ |
469 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) { | 469 | if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) { |
470 | ptime = 125 * (1 << fp->datainterval); | 470 | ptime = 125 * (1 << fp->datainterval); |
471 | if (ptime > pt->max || (ptime == pt->max && pt->openmax)) { | 471 | if (ptime > pt->max || (ptime == pt->max && pt->openmax)) { |
472 | hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max); | 472 | hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max); |
@@ -734,7 +734,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre | |||
734 | } | 734 | } |
735 | 735 | ||
736 | param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; | 736 | param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; |
737 | if (snd_usb_get_speed(subs->dev) != USB_SPEED_HIGH) | 737 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) |
738 | /* full speed devices have fixed data packet interval */ | 738 | /* full speed devices have fixed data packet interval */ |
739 | ptmin = 1000; | 739 | ptmin = 1000; |
740 | if (ptmin == 1000) | 740 | if (ptmin == 1000) |
diff --git a/sound/usb/proc.c b/sound/usb/proc.c index f5e3f356b95f..3c650ab3c91d 100644 --- a/sound/usb/proc.c +++ b/sound/usb/proc.c | |||
@@ -107,7 +107,7 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s | |||
107 | } | 107 | } |
108 | snd_iprintf(buffer, "\n"); | 108 | snd_iprintf(buffer, "\n"); |
109 | } | 109 | } |
110 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) | 110 | if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) |
111 | snd_iprintf(buffer, " Data packet interval: %d us\n", | 111 | snd_iprintf(buffer, " Data packet interval: %d us\n", |
112 | 125 * (1 << fp->datainterval)); | 112 | 125 * (1 << fp->datainterval)); |
113 | // snd_iprintf(buffer, " Max Packet Size = %d\n", fp->maxpacksize); | 113 | // snd_iprintf(buffer, " Max Packet Size = %d\n", fp->maxpacksize); |
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 2e8003f98fca..ad7079d1676c 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h | |||
@@ -240,9 +240,21 @@ YAMAHA_DEVICE(0x104f, NULL), | |||
240 | YAMAHA_DEVICE(0x1050, NULL), | 240 | YAMAHA_DEVICE(0x1050, NULL), |
241 | YAMAHA_DEVICE(0x1051, NULL), | 241 | YAMAHA_DEVICE(0x1051, NULL), |
242 | YAMAHA_DEVICE(0x1052, NULL), | 242 | YAMAHA_DEVICE(0x1052, NULL), |
243 | YAMAHA_INTERFACE(0x1053, 0, NULL), | ||
244 | YAMAHA_INTERFACE(0x1054, 0, NULL), | ||
245 | YAMAHA_DEVICE(0x1055, NULL), | ||
246 | YAMAHA_DEVICE(0x1056, NULL), | ||
247 | YAMAHA_DEVICE(0x1057, NULL), | ||
248 | YAMAHA_DEVICE(0x1058, NULL), | ||
249 | YAMAHA_DEVICE(0x1059, NULL), | ||
250 | YAMAHA_DEVICE(0x105a, NULL), | ||
251 | YAMAHA_DEVICE(0x105b, NULL), | ||
252 | YAMAHA_DEVICE(0x105c, NULL), | ||
253 | YAMAHA_DEVICE(0x105d, NULL), | ||
243 | YAMAHA_DEVICE(0x2000, "DGP-7"), | 254 | YAMAHA_DEVICE(0x2000, "DGP-7"), |
244 | YAMAHA_DEVICE(0x2001, "DGP-5"), | 255 | YAMAHA_DEVICE(0x2001, "DGP-5"), |
245 | YAMAHA_DEVICE(0x2002, NULL), | 256 | YAMAHA_DEVICE(0x2002, NULL), |
257 | YAMAHA_DEVICE(0x2003, NULL), | ||
246 | YAMAHA_DEVICE(0x5000, "CS1D"), | 258 | YAMAHA_DEVICE(0x5000, "CS1D"), |
247 | YAMAHA_DEVICE(0x5001, "DSP1D"), | 259 | YAMAHA_DEVICE(0x5001, "DSP1D"), |
248 | YAMAHA_DEVICE(0x5002, "DME32"), | 260 | YAMAHA_DEVICE(0x5002, "DME32"), |
@@ -1136,11 +1148,34 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
1136 | } | 1148 | } |
1137 | }, | 1149 | }, |
1138 | { | 1150 | { |
1151 | /* has ID 0x0066 when not in "Advanced Driver" mode */ | ||
1152 | USB_DEVICE(0x0582, 0x0064), | ||
1153 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | ||
1154 | /* .vendor_name = "EDIROL", */ | ||
1155 | /* .product_name = "PCR-1", */ | ||
1156 | .ifnum = QUIRK_ANY_INTERFACE, | ||
1157 | .type = QUIRK_COMPOSITE, | ||
1158 | .data = (const struct snd_usb_audio_quirk[]) { | ||
1159 | { | ||
1160 | .ifnum = 1, | ||
1161 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | ||
1162 | }, | ||
1163 | { | ||
1164 | .ifnum = 2, | ||
1165 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | ||
1166 | }, | ||
1167 | { | ||
1168 | .ifnum = -1 | ||
1169 | } | ||
1170 | } | ||
1171 | } | ||
1172 | }, | ||
1173 | { | ||
1139 | /* has ID 0x0067 when not in "Advanced Driver" mode */ | 1174 | /* has ID 0x0067 when not in "Advanced Driver" mode */ |
1140 | USB_DEVICE(0x0582, 0x0065), | 1175 | USB_DEVICE(0x0582, 0x0065), |
1141 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | 1176 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { |
1142 | .vendor_name = "EDIROL", | 1177 | /* .vendor_name = "EDIROL", */ |
1143 | .product_name = "PCR-1", | 1178 | /* .product_name = "PCR-1", */ |
1144 | .ifnum = 0, | 1179 | .ifnum = 0, |
1145 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | 1180 | .type = QUIRK_MIDI_FIXED_ENDPOINT, |
1146 | .data = & (const struct snd_usb_midi_endpoint_info) { | 1181 | .data = & (const struct snd_usb_midi_endpoint_info) { |
@@ -1525,6 +1560,50 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
1525 | } | 1560 | } |
1526 | } | 1561 | } |
1527 | }, | 1562 | }, |
1563 | { | ||
1564 | /* has ID 0x0110 when not in Advanced Driver mode */ | ||
1565 | USB_DEVICE_VENDOR_SPEC(0x0582, 0x010f), | ||
1566 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | ||
1567 | /* .vendor_name = "Roland", */ | ||
1568 | /* .product_name = "A-PRO", */ | ||
1569 | .ifnum = 1, | ||
1570 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | ||
1571 | .data = & (const struct snd_usb_midi_endpoint_info) { | ||
1572 | .out_cables = 0x0003, | ||
1573 | .in_cables = 0x0007 | ||
1574 | } | ||
1575 | } | ||
1576 | }, | ||
1577 | { | ||
1578 | USB_DEVICE(0x0582, 0x0113), | ||
1579 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | ||
1580 | /* .vendor_name = "BOSS", */ | ||
1581 | /* .product_name = "ME-25", */ | ||
1582 | .ifnum = QUIRK_ANY_INTERFACE, | ||
1583 | .type = QUIRK_COMPOSITE, | ||
1584 | .data = (const struct snd_usb_audio_quirk[]) { | ||
1585 | { | ||
1586 | .ifnum = 0, | ||
1587 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | ||
1588 | }, | ||
1589 | { | ||
1590 | .ifnum = 1, | ||
1591 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | ||
1592 | }, | ||
1593 | { | ||
1594 | .ifnum = 2, | ||
1595 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | ||
1596 | .data = & (const struct snd_usb_midi_endpoint_info) { | ||
1597 | .out_cables = 0x0001, | ||
1598 | .in_cables = 0x0001 | ||
1599 | } | ||
1600 | }, | ||
1601 | { | ||
1602 | .ifnum = -1 | ||
1603 | } | ||
1604 | } | ||
1605 | } | ||
1606 | }, | ||
1528 | 1607 | ||
1529 | /* Guillemot devices */ | 1608 | /* Guillemot devices */ |
1530 | { | 1609 | { |
@@ -1830,7 +1909,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
1830 | USB_DEVICE(0x0763, 0x2080), | 1909 | USB_DEVICE(0x0763, 0x2080), |
1831 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | 1910 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { |
1832 | /* .vendor_name = "M-Audio", */ | 1911 | /* .vendor_name = "M-Audio", */ |
1833 | /* .product_name = "Fast Track Ultra 8", */ | 1912 | /* .product_name = "Fast Track Ultra", */ |
1834 | .ifnum = QUIRK_ANY_INTERFACE, | 1913 | .ifnum = QUIRK_ANY_INTERFACE, |
1835 | .type = QUIRK_COMPOSITE, | 1914 | .type = QUIRK_COMPOSITE, |
1836 | .data = & (const struct snd_usb_audio_quirk[]) { | 1915 | .data = & (const struct snd_usb_audio_quirk[]) { |
@@ -1840,11 +1919,51 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
1840 | }, | 1919 | }, |
1841 | { | 1920 | { |
1842 | .ifnum = 1, | 1921 | .ifnum = 1, |
1843 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | 1922 | .type = QUIRK_AUDIO_FIXED_ENDPOINT, |
1923 | .data = & (const struct audioformat) { | ||
1924 | .formats = SNDRV_PCM_FMTBIT_S24_3LE, | ||
1925 | .channels = 8, | ||
1926 | .iface = 1, | ||
1927 | .altsetting = 1, | ||
1928 | .altset_idx = 1, | ||
1929 | .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, | ||
1930 | .endpoint = 0x01, | ||
1931 | .ep_attr = 0x09, | ||
1932 | .rates = SNDRV_PCM_RATE_44100 | | ||
1933 | SNDRV_PCM_RATE_48000 | | ||
1934 | SNDRV_PCM_RATE_88200 | | ||
1935 | SNDRV_PCM_RATE_96000, | ||
1936 | .rate_min = 44100, | ||
1937 | .rate_max = 96000, | ||
1938 | .nr_rates = 4, | ||
1939 | .rate_table = (unsigned int[]) { | ||
1940 | 44100, 48000, 88200, 96000 | ||
1941 | } | ||
1942 | } | ||
1844 | }, | 1943 | }, |
1845 | { | 1944 | { |
1846 | .ifnum = 2, | 1945 | .ifnum = 2, |
1847 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | 1946 | .type = QUIRK_AUDIO_FIXED_ENDPOINT, |
1947 | .data = & (const struct audioformat) { | ||
1948 | .formats = SNDRV_PCM_FMTBIT_S24_3LE, | ||
1949 | .channels = 8, | ||
1950 | .iface = 2, | ||
1951 | .altsetting = 1, | ||
1952 | .altset_idx = 1, | ||
1953 | .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, | ||
1954 | .endpoint = 0x81, | ||
1955 | .ep_attr = 0x05, | ||
1956 | .rates = SNDRV_PCM_RATE_44100 | | ||
1957 | SNDRV_PCM_RATE_48000 | | ||
1958 | SNDRV_PCM_RATE_88200 | | ||
1959 | SNDRV_PCM_RATE_96000, | ||
1960 | .rate_min = 44100, | ||
1961 | .rate_max = 96000, | ||
1962 | .nr_rates = 4, | ||
1963 | .rate_table = (unsigned int[]) { | ||
1964 | 44100, 48000, 88200, 96000 | ||
1965 | } | ||
1966 | } | ||
1848 | }, | 1967 | }, |
1849 | /* interface 3 (MIDI) is standard compliant */ | 1968 | /* interface 3 (MIDI) is standard compliant */ |
1850 | { | 1969 | { |
@@ -1867,11 +1986,51 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
1867 | }, | 1986 | }, |
1868 | { | 1987 | { |
1869 | .ifnum = 1, | 1988 | .ifnum = 1, |
1870 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | 1989 | .type = QUIRK_AUDIO_FIXED_ENDPOINT, |
1990 | .data = & (const struct audioformat) { | ||
1991 | .formats = SNDRV_PCM_FMTBIT_S24_3LE, | ||
1992 | .channels = 8, | ||
1993 | .iface = 1, | ||
1994 | .altsetting = 1, | ||
1995 | .altset_idx = 1, | ||
1996 | .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, | ||
1997 | .endpoint = 0x01, | ||
1998 | .ep_attr = 0x09, | ||
1999 | .rates = SNDRV_PCM_RATE_44100 | | ||
2000 | SNDRV_PCM_RATE_48000 | | ||
2001 | SNDRV_PCM_RATE_88200 | | ||
2002 | SNDRV_PCM_RATE_96000, | ||
2003 | .rate_min = 44100, | ||
2004 | .rate_max = 96000, | ||
2005 | .nr_rates = 4, | ||
2006 | .rate_table = (unsigned int[]) { | ||
2007 | 44100, 48000, 88200, 96000 | ||
2008 | } | ||
2009 | } | ||
1871 | }, | 2010 | }, |
1872 | { | 2011 | { |
1873 | .ifnum = 2, | 2012 | .ifnum = 2, |
1874 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | 2013 | .type = QUIRK_AUDIO_FIXED_ENDPOINT, |
2014 | .data = & (const struct audioformat) { | ||
2015 | .formats = SNDRV_PCM_FMTBIT_S24_3LE, | ||
2016 | .channels = 8, | ||
2017 | .iface = 2, | ||
2018 | .altsetting = 1, | ||
2019 | .altset_idx = 1, | ||
2020 | .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, | ||
2021 | .endpoint = 0x81, | ||
2022 | .ep_attr = 0x05, | ||
2023 | .rates = SNDRV_PCM_RATE_44100 | | ||
2024 | SNDRV_PCM_RATE_48000 | | ||
2025 | SNDRV_PCM_RATE_88200 | | ||
2026 | SNDRV_PCM_RATE_96000, | ||
2027 | .rate_min = 44100, | ||
2028 | .rate_max = 96000, | ||
2029 | .nr_rates = 4, | ||
2030 | .rate_table = (unsigned int[]) { | ||
2031 | 44100, 48000, 88200, 96000 | ||
2032 | } | ||
2033 | } | ||
1875 | }, | 2034 | }, |
1876 | /* interface 3 (MIDI) is standard compliant */ | 2035 | /* interface 3 (MIDI) is standard compliant */ |
1877 | { | 2036 | { |
@@ -1919,7 +2078,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
1919 | .data = & (const struct snd_usb_audio_quirk[]) { | 2078 | .data = & (const struct snd_usb_audio_quirk[]) { |
1920 | { | 2079 | { |
1921 | .ifnum = 0, | 2080 | .ifnum = 0, |
1922 | .type = QUIRK_MIDI_FASTLANE | 2081 | .type = QUIRK_MIDI_RAW_BYTES |
1923 | }, | 2082 | }, |
1924 | { | 2083 | { |
1925 | .ifnum = 1, | 2084 | .ifnum = 1, |
@@ -2068,6 +2227,15 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
2068 | } | 2227 | } |
2069 | }, | 2228 | }, |
2070 | { | 2229 | { |
2230 | USB_DEVICE(0x1235, 0x000e), | ||
2231 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | ||
2232 | /* .vendor_name = "Novation", */ | ||
2233 | /* .product_name = "Launchpad", */ | ||
2234 | .ifnum = 0, | ||
2235 | .type = QUIRK_MIDI_RAW_BYTES | ||
2236 | } | ||
2237 | }, | ||
2238 | { | ||
2071 | USB_DEVICE_VENDOR_SPEC(0x1235, 0x4661), | 2239 | USB_DEVICE_VENDOR_SPEC(0x1235, 0x4661), |
2072 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | 2240 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { |
2073 | .vendor_name = "Novation", | 2241 | .vendor_name = "Novation", |
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 9a9da09586a5..cf8bf088394b 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c | |||
@@ -287,7 +287,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip, | |||
287 | [QUIRK_MIDI_YAMAHA] = create_any_midi_quirk, | 287 | [QUIRK_MIDI_YAMAHA] = create_any_midi_quirk, |
288 | [QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk, | 288 | [QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk, |
289 | [QUIRK_MIDI_NOVATION] = create_any_midi_quirk, | 289 | [QUIRK_MIDI_NOVATION] = create_any_midi_quirk, |
290 | [QUIRK_MIDI_FASTLANE] = create_any_midi_quirk, | 290 | [QUIRK_MIDI_RAW_BYTES] = create_any_midi_quirk, |
291 | [QUIRK_MIDI_EMAGIC] = create_any_midi_quirk, | 291 | [QUIRK_MIDI_EMAGIC] = create_any_midi_quirk, |
292 | [QUIRK_MIDI_CME] = create_any_midi_quirk, | 292 | [QUIRK_MIDI_CME] = create_any_midi_quirk, |
293 | [QUIRK_MIDI_AKAI] = create_any_midi_quirk, | 293 | [QUIRK_MIDI_AKAI] = create_any_midi_quirk, |
diff --git a/sound/usb/urb.c b/sound/usb/urb.c index de607d4411ac..8deeaad10f10 100644 --- a/sound/usb/urb.c +++ b/sound/usb/urb.c | |||
@@ -244,7 +244,7 @@ int snd_usb_init_substream_urbs(struct snd_usb_substream *subs, | |||
244 | else | 244 | else |
245 | subs->curpacksize = maxsize; | 245 | subs->curpacksize = maxsize; |
246 | 246 | ||
247 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) | 247 | if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) |
248 | packs_per_ms = 8 >> subs->datainterval; | 248 | packs_per_ms = 8 >> subs->datainterval; |
249 | else | 249 | else |
250 | packs_per_ms = 1; | 250 | packs_per_ms = 1; |
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 24d3319cc34d..db3eb21627ee 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h | |||
@@ -70,7 +70,7 @@ enum quirk_type { | |||
70 | QUIRK_MIDI_YAMAHA, | 70 | QUIRK_MIDI_YAMAHA, |
71 | QUIRK_MIDI_MIDIMAN, | 71 | QUIRK_MIDI_MIDIMAN, |
72 | QUIRK_MIDI_NOVATION, | 72 | QUIRK_MIDI_NOVATION, |
73 | QUIRK_MIDI_FASTLANE, | 73 | QUIRK_MIDI_RAW_BYTES, |
74 | QUIRK_MIDI_EMAGIC, | 74 | QUIRK_MIDI_EMAGIC, |
75 | QUIRK_MIDI_CME, | 75 | QUIRK_MIDI_CME, |
76 | QUIRK_MIDI_AKAI, | 76 | QUIRK_MIDI_AKAI, |
diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index 2a528e56afd5..287ef73b1237 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c | |||
@@ -36,9 +36,9 @@ | |||
36 | plain usx2y alsa mode is able to achieve 64frames, 4periods, but only at the | 36 | plain usx2y alsa mode is able to achieve 64frames, 4periods, but only at the |
37 | cost of easier triggered i.e. aeolus xruns (128 or 256frames, | 37 | cost of easier triggered i.e. aeolus xruns (128 or 256frames, |
38 | 2periods works but is useless cause of crackling). | 38 | 2periods works but is useless cause of crackling). |
39 | 39 | ||
40 | This is a first "proof of concept" implementation. | 40 | This is a first "proof of concept" implementation. |
41 | Later, funcionalities should migrate to more apropriate places: | 41 | Later, functionalities should migrate to more apropriate places: |
42 | Userland: | 42 | Userland: |
43 | - The jackd could mmap its float-pcm buffers directly from alsa-lib. | 43 | - The jackd could mmap its float-pcm buffers directly from alsa-lib. |
44 | - alsa-lib could provide power of 2 period sized shaping combined with int/float | 44 | - alsa-lib could provide power of 2 period sized shaping combined with int/float |
@@ -54,7 +54,7 @@ | |||
54 | #include <linux/gfp.h> | 54 | #include <linux/gfp.h> |
55 | #include "usbusx2yaudio.c" | 55 | #include "usbusx2yaudio.c" |
56 | 56 | ||
57 | #if defined(USX2Y_NRPACKS_VARIABLE) || (!defined(USX2Y_NRPACKS_VARIABLE) && USX2Y_NRPACKS == 1) | 57 | #if defined(USX2Y_NRPACKS_VARIABLE) || USX2Y_NRPACKS == 1 |
58 | 58 | ||
59 | #include <sound/hwdep.h> | 59 | #include <sound/hwdep.h> |
60 | 60 | ||