diff options
Diffstat (limited to 'sound/pci/asihpi/asihpi.c')
-rw-r--r-- | sound/pci/asihpi/asihpi.c | 294 |
1 files changed, 152 insertions, 142 deletions
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index f4b9e2b7ae87..e8de831f98bc 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c | |||
@@ -23,8 +23,11 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include "hpi_internal.h" | 25 | #include "hpi_internal.h" |
26 | #include "hpi_version.h" | ||
26 | #include "hpimsginit.h" | 27 | #include "hpimsginit.h" |
27 | #include "hpioctl.h" | 28 | #include "hpioctl.h" |
29 | #include "hpicmn.h" | ||
30 | |||
28 | 31 | ||
29 | #include <linux/pci.h> | 32 | #include <linux/pci.h> |
30 | #include <linux/init.h> | 33 | #include <linux/init.h> |
@@ -44,7 +47,8 @@ | |||
44 | 47 | ||
45 | MODULE_LICENSE("GPL"); | 48 | MODULE_LICENSE("GPL"); |
46 | MODULE_AUTHOR("AudioScience inc. <support@audioscience.com>"); | 49 | MODULE_AUTHOR("AudioScience inc. <support@audioscience.com>"); |
47 | MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx"); | 50 | MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx " |
51 | HPI_VER_STRING); | ||
48 | 52 | ||
49 | #if defined CONFIG_SND_DEBUG_VERBOSE | 53 | #if defined CONFIG_SND_DEBUG_VERBOSE |
50 | /** | 54 | /** |
@@ -63,8 +67,8 @@ MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx"); | |||
63 | 67 | ||
64 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* index 0-MAX */ | 68 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* index 0-MAX */ |
65 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | 69 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ |
66 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | 70 | static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; |
67 | static int enable_hpi_hwdep = 1; | 71 | static bool enable_hpi_hwdep = 1; |
68 | 72 | ||
69 | module_param_array(index, int, NULL, S_IRUGO); | 73 | module_param_array(index, int, NULL, S_IRUGO); |
70 | MODULE_PARM_DESC(index, "ALSA index value for AudioScience soundcard."); | 74 | MODULE_PARM_DESC(index, "ALSA index value for AudioScience soundcard."); |
@@ -119,12 +123,7 @@ struct clk_cache { | |||
119 | struct snd_card_asihpi { | 123 | struct snd_card_asihpi { |
120 | struct snd_card *card; | 124 | struct snd_card *card; |
121 | struct pci_dev *pci; | 125 | struct pci_dev *pci; |
122 | u16 adapter_index; | 126 | struct hpi_adapter *hpi; |
123 | u32 serial_number; | ||
124 | u16 type; | ||
125 | u16 version; | ||
126 | u16 num_outstreams; | ||
127 | u16 num_instreams; | ||
128 | 127 | ||
129 | u32 h_mixer; | 128 | u32 h_mixer; |
130 | struct clk_cache cc; | 129 | struct clk_cache cc; |
@@ -135,6 +134,8 @@ struct snd_card_asihpi { | |||
135 | u16 update_interval_frames; | 134 | u16 update_interval_frames; |
136 | u16 in_max_chans; | 135 | u16 in_max_chans; |
137 | u16 out_max_chans; | 136 | u16 out_max_chans; |
137 | u16 in_min_chans; | ||
138 | u16 out_min_chans; | ||
138 | }; | 139 | }; |
139 | 140 | ||
140 | /* Per stream data */ | 141 | /* Per stream data */ |
@@ -495,6 +496,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, | |||
495 | 496 | ||
496 | snd_printdd("stream_host_buffer_attach status 0x%x\n", | 497 | snd_printdd("stream_host_buffer_attach status 0x%x\n", |
497 | dpcm->hpi_buffer_attached); | 498 | dpcm->hpi_buffer_attached); |
499 | |||
498 | } | 500 | } |
499 | bytes_per_sec = params_rate(params) * params_channels(params); | 501 | bytes_per_sec = params_rate(params) * params_channels(params); |
500 | width = snd_pcm_format_width(params_format(params)); | 502 | width = snd_pcm_format_width(params_format(params)); |
@@ -757,8 +759,7 @@ static void snd_card_asihpi_timer_function(unsigned long data) | |||
757 | if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 759 | if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
758 | pcm_buf_dma_ofs = ds->pcm_buf_host_rw_ofs - bytes_avail; | 760 | pcm_buf_dma_ofs = ds->pcm_buf_host_rw_ofs - bytes_avail; |
759 | if (state == HPI_STATE_STOPPED) { | 761 | if (state == HPI_STATE_STOPPED) { |
760 | if ((bytes_avail == 0) && | 762 | if (bytes_avail == 0) { |
761 | (on_card_bytes < ds->pcm_buf_host_rw_ofs)) { | ||
762 | hpi_handle_error(hpi_stream_start(ds->h_stream)); | 763 | hpi_handle_error(hpi_stream_start(ds->h_stream)); |
763 | snd_printdd("P%d start\n", s->number); | 764 | snd_printdd("P%d start\n", s->number); |
764 | ds->drained_count = 0; | 765 | ds->drained_count = 0; |
@@ -767,7 +768,7 @@ static void snd_card_asihpi_timer_function(unsigned long data) | |||
767 | snd_printd(KERN_WARNING "P%d drained\n", | 768 | snd_printd(KERN_WARNING "P%d drained\n", |
768 | s->number); | 769 | s->number); |
769 | ds->drained_count++; | 770 | ds->drained_count++; |
770 | if (ds->drained_count > 2) { | 771 | if (ds->drained_count > 20) { |
771 | snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN); | 772 | snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN); |
772 | continue; | 773 | continue; |
773 | } | 774 | } |
@@ -888,8 +889,8 @@ static void snd_card_asihpi_timer_function(unsigned long data) | |||
888 | pd, xfer2)); | 889 | pd, xfer2)); |
889 | } | 890 | } |
890 | } | 891 | } |
891 | ds->pcm_buf_host_rw_ofs = ds->pcm_buf_host_rw_ofs + xfercount; | 892 | ds->pcm_buf_host_rw_ofs += xfercount; |
892 | ds->pcm_buf_elapsed_dma_ofs = pcm_buf_dma_ofs; | 893 | ds->pcm_buf_elapsed_dma_ofs += xfercount; |
893 | snd_pcm_period_elapsed(s); | 894 | snd_pcm_period_elapsed(s); |
894 | } | 895 | } |
895 | } | 896 | } |
@@ -902,7 +903,9 @@ static void snd_card_asihpi_timer_function(unsigned long data) | |||
902 | static int snd_card_asihpi_playback_ioctl(struct snd_pcm_substream *substream, | 903 | static int snd_card_asihpi_playback_ioctl(struct snd_pcm_substream *substream, |
903 | unsigned int cmd, void *arg) | 904 | unsigned int cmd, void *arg) |
904 | { | 905 | { |
905 | snd_printddd(KERN_INFO "P%d ioctl %d\n", substream->number, cmd); | 906 | char name[16]; |
907 | snd_pcm_debug_name(substream, name, sizeof(name)); | ||
908 | snd_printddd(KERN_INFO "%s ioctl %d\n", name, cmd); | ||
906 | return snd_pcm_lib_ioctl(substream, cmd, arg); | 909 | return snd_pcm_lib_ioctl(substream, cmd, arg); |
907 | } | 910 | } |
908 | 911 | ||
@@ -927,21 +930,23 @@ snd_card_asihpi_playback_pointer(struct snd_pcm_substream *substream) | |||
927 | struct snd_pcm_runtime *runtime = substream->runtime; | 930 | struct snd_pcm_runtime *runtime = substream->runtime; |
928 | struct snd_card_asihpi_pcm *dpcm = runtime->private_data; | 931 | struct snd_card_asihpi_pcm *dpcm = runtime->private_data; |
929 | snd_pcm_uframes_t ptr; | 932 | snd_pcm_uframes_t ptr; |
933 | char name[16]; | ||
934 | snd_pcm_debug_name(substream, name, sizeof(name)); | ||
930 | 935 | ||
931 | ptr = bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs % dpcm->buffer_bytes); | 936 | ptr = bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs % dpcm->buffer_bytes); |
932 | snd_printddd("P%d pointer = 0x%04lx\n", substream->number, (unsigned long)ptr); | 937 | snd_printddd("%s pointer = 0x%04lx\n", name, (unsigned long)ptr); |
933 | return ptr; | 938 | return ptr; |
934 | } | 939 | } |
935 | 940 | ||
936 | static void snd_card_asihpi_playback_format(struct snd_card_asihpi *asihpi, | 941 | static u64 snd_card_asihpi_playback_formats(struct snd_card_asihpi *asihpi, |
937 | u32 h_stream, | 942 | u32 h_stream) |
938 | struct snd_pcm_hardware *pcmhw) | ||
939 | { | 943 | { |
940 | struct hpi_format hpi_format; | 944 | struct hpi_format hpi_format; |
941 | u16 format; | 945 | u16 format; |
942 | u16 err; | 946 | u16 err; |
943 | u32 h_control; | 947 | u32 h_control; |
944 | u32 sample_rate = 48000; | 948 | u32 sample_rate = 48000; |
949 | u64 formats = 0; | ||
945 | 950 | ||
946 | /* on cards without SRC, must query at valid rate, | 951 | /* on cards without SRC, must query at valid rate, |
947 | * maybe set by external sync | 952 | * maybe set by external sync |
@@ -956,41 +961,29 @@ static void snd_card_asihpi_playback_format(struct snd_card_asihpi *asihpi, | |||
956 | 961 | ||
957 | for (format = HPI_FORMAT_PCM8_UNSIGNED; | 962 | for (format = HPI_FORMAT_PCM8_UNSIGNED; |
958 | format <= HPI_FORMAT_PCM24_SIGNED; format++) { | 963 | format <= HPI_FORMAT_PCM24_SIGNED; format++) { |
959 | err = hpi_format_create(&hpi_format, | 964 | err = hpi_format_create(&hpi_format, asihpi->out_max_chans, |
960 | 2, format, sample_rate, 128000, 0); | 965 | format, sample_rate, 128000, 0); |
961 | if (!err) | 966 | if (!err) |
962 | err = hpi_outstream_query_format(h_stream, | 967 | err = hpi_outstream_query_format(h_stream, &hpi_format); |
963 | &hpi_format); | ||
964 | if (!err && (hpi_to_alsa_formats[format] != -1)) | 968 | if (!err && (hpi_to_alsa_formats[format] != -1)) |
965 | pcmhw->formats |= | 969 | formats |= (1ULL << hpi_to_alsa_formats[format]); |
966 | (1ULL << hpi_to_alsa_formats[format]); | ||
967 | } | 970 | } |
971 | return formats; | ||
968 | } | 972 | } |
969 | 973 | ||
970 | static struct snd_pcm_hardware snd_card_asihpi_playback = { | ||
971 | .channels_min = 1, | ||
972 | .channels_max = 2, | ||
973 | .buffer_bytes_max = BUFFER_BYTES_MAX, | ||
974 | .period_bytes_min = PERIOD_BYTES_MIN, | ||
975 | .period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN, | ||
976 | .periods_min = PERIODS_MIN, | ||
977 | .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, | ||
978 | .fifo_size = 0, | ||
979 | }; | ||
980 | |||
981 | static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream) | 974 | static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream) |
982 | { | 975 | { |
983 | struct snd_pcm_runtime *runtime = substream->runtime; | 976 | struct snd_pcm_runtime *runtime = substream->runtime; |
984 | struct snd_card_asihpi_pcm *dpcm; | 977 | struct snd_card_asihpi_pcm *dpcm; |
985 | struct snd_card_asihpi *card = snd_pcm_substream_chip(substream); | 978 | struct snd_card_asihpi *card = snd_pcm_substream_chip(substream); |
979 | struct snd_pcm_hardware snd_card_asihpi_playback; | ||
986 | int err; | 980 | int err; |
987 | 981 | ||
988 | dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL); | 982 | dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL); |
989 | if (dpcm == NULL) | 983 | if (dpcm == NULL) |
990 | return -ENOMEM; | 984 | return -ENOMEM; |
991 | 985 | ||
992 | err = | 986 | err = hpi_outstream_open(card->hpi->adapter->index, |
993 | hpi_outstream_open(card->adapter_index, | ||
994 | substream->number, &dpcm->h_stream); | 987 | substream->number, &dpcm->h_stream); |
995 | hpi_handle_error(err); | 988 | hpi_handle_error(err); |
996 | if (err) | 989 | if (err) |
@@ -1012,12 +1005,19 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream) | |||
1012 | runtime->private_data = dpcm; | 1005 | runtime->private_data = dpcm; |
1013 | runtime->private_free = snd_card_asihpi_runtime_free; | 1006 | runtime->private_free = snd_card_asihpi_runtime_free; |
1014 | 1007 | ||
1015 | snd_card_asihpi_playback.channels_max = card->out_max_chans; | 1008 | memset(&snd_card_asihpi_playback, 0, sizeof(snd_card_asihpi_playback)); |
1009 | snd_card_asihpi_playback.buffer_bytes_max = BUFFER_BYTES_MAX; | ||
1010 | snd_card_asihpi_playback.period_bytes_min = PERIOD_BYTES_MIN; | ||
1016 | /*?snd_card_asihpi_playback.period_bytes_min = | 1011 | /*?snd_card_asihpi_playback.period_bytes_min = |
1017 | card->out_max_chans * 4096; */ | 1012 | card->out_max_chans * 4096; */ |
1018 | 1013 | snd_card_asihpi_playback.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN; | |
1019 | snd_card_asihpi_playback_format(card, dpcm->h_stream, | 1014 | snd_card_asihpi_playback.periods_min = PERIODS_MIN; |
1020 | &snd_card_asihpi_playback); | 1015 | snd_card_asihpi_playback.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN; |
1016 | /* snd_card_asihpi_playback.fifo_size = 0; */ | ||
1017 | snd_card_asihpi_playback.channels_max = card->out_max_chans; | ||
1018 | snd_card_asihpi_playback.channels_min = card->out_min_chans; | ||
1019 | snd_card_asihpi_playback.formats = | ||
1020 | snd_card_asihpi_playback_formats(card, dpcm->h_stream); | ||
1021 | 1021 | ||
1022 | snd_card_asihpi_pcm_samplerates(card, &snd_card_asihpi_playback); | 1022 | snd_card_asihpi_pcm_samplerates(card, &snd_card_asihpi_playback); |
1023 | 1023 | ||
@@ -1029,8 +1029,10 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream) | |||
1029 | SNDRV_PCM_INFO_MMAP | | 1029 | SNDRV_PCM_INFO_MMAP | |
1030 | SNDRV_PCM_INFO_MMAP_VALID; | 1030 | SNDRV_PCM_INFO_MMAP_VALID; |
1031 | 1031 | ||
1032 | if (card->support_grouping) | 1032 | if (card->support_grouping) { |
1033 | snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_SYNC_START; | 1033 | snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_SYNC_START; |
1034 | snd_pcm_set_sync(substream); | ||
1035 | } | ||
1034 | 1036 | ||
1035 | /* struct is copied, so can create initializer dynamically */ | 1037 | /* struct is copied, so can create initializer dynamically */ |
1036 | runtime->hw = snd_card_asihpi_playback; | 1038 | runtime->hw = snd_card_asihpi_playback; |
@@ -1047,8 +1049,6 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream) | |||
1047 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, | 1049 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, |
1048 | card->update_interval_frames * 2, UINT_MAX); | 1050 | card->update_interval_frames * 2, UINT_MAX); |
1049 | 1051 | ||
1050 | snd_pcm_set_sync(substream); | ||
1051 | |||
1052 | snd_printdd("playback open\n"); | 1052 | snd_printdd("playback open\n"); |
1053 | 1053 | ||
1054 | return 0; | 1054 | return 0; |
@@ -1114,15 +1114,15 @@ static int snd_card_asihpi_capture_prepare(struct snd_pcm_substream *substream) | |||
1114 | 1114 | ||
1115 | 1115 | ||
1116 | 1116 | ||
1117 | static void snd_card_asihpi_capture_format(struct snd_card_asihpi *asihpi, | 1117 | static u64 snd_card_asihpi_capture_formats(struct snd_card_asihpi *asihpi, |
1118 | u32 h_stream, | 1118 | u32 h_stream) |
1119 | struct snd_pcm_hardware *pcmhw) | ||
1120 | { | 1119 | { |
1121 | struct hpi_format hpi_format; | 1120 | struct hpi_format hpi_format; |
1122 | u16 format; | 1121 | u16 format; |
1123 | u16 err; | 1122 | u16 err; |
1124 | u32 h_control; | 1123 | u32 h_control; |
1125 | u32 sample_rate = 48000; | 1124 | u32 sample_rate = 48000; |
1125 | u64 formats = 0; | ||
1126 | 1126 | ||
1127 | /* on cards without SRC, must query at valid rate, | 1127 | /* on cards without SRC, must query at valid rate, |
1128 | maybe set by external sync */ | 1128 | maybe set by external sync */ |
@@ -1137,34 +1137,22 @@ static void snd_card_asihpi_capture_format(struct snd_card_asihpi *asihpi, | |||
1137 | for (format = HPI_FORMAT_PCM8_UNSIGNED; | 1137 | for (format = HPI_FORMAT_PCM8_UNSIGNED; |
1138 | format <= HPI_FORMAT_PCM24_SIGNED; format++) { | 1138 | format <= HPI_FORMAT_PCM24_SIGNED; format++) { |
1139 | 1139 | ||
1140 | err = hpi_format_create(&hpi_format, 2, format, | 1140 | err = hpi_format_create(&hpi_format, asihpi->in_max_chans, |
1141 | sample_rate, 128000, 0); | 1141 | format, sample_rate, 128000, 0); |
1142 | if (!err) | 1142 | if (!err) |
1143 | err = hpi_instream_query_format(h_stream, | 1143 | err = hpi_instream_query_format(h_stream, &hpi_format); |
1144 | &hpi_format); | ||
1145 | if (!err) | 1144 | if (!err) |
1146 | pcmhw->formats |= | 1145 | formats |= (1ULL << hpi_to_alsa_formats[format]); |
1147 | (1ULL << hpi_to_alsa_formats[format]); | ||
1148 | } | 1146 | } |
1147 | return formats; | ||
1149 | } | 1148 | } |
1150 | 1149 | ||
1151 | |||
1152 | static struct snd_pcm_hardware snd_card_asihpi_capture = { | ||
1153 | .channels_min = 1, | ||
1154 | .channels_max = 2, | ||
1155 | .buffer_bytes_max = BUFFER_BYTES_MAX, | ||
1156 | .period_bytes_min = PERIOD_BYTES_MIN, | ||
1157 | .period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN, | ||
1158 | .periods_min = PERIODS_MIN, | ||
1159 | .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, | ||
1160 | .fifo_size = 0, | ||
1161 | }; | ||
1162 | |||
1163 | static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream) | 1150 | static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream) |
1164 | { | 1151 | { |
1165 | struct snd_pcm_runtime *runtime = substream->runtime; | 1152 | struct snd_pcm_runtime *runtime = substream->runtime; |
1166 | struct snd_card_asihpi *card = snd_pcm_substream_chip(substream); | 1153 | struct snd_card_asihpi *card = snd_pcm_substream_chip(substream); |
1167 | struct snd_card_asihpi_pcm *dpcm; | 1154 | struct snd_card_asihpi_pcm *dpcm; |
1155 | struct snd_pcm_hardware snd_card_asihpi_capture; | ||
1168 | int err; | 1156 | int err; |
1169 | 1157 | ||
1170 | dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL); | 1158 | dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL); |
@@ -1172,10 +1160,10 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream) | |||
1172 | return -ENOMEM; | 1160 | return -ENOMEM; |
1173 | 1161 | ||
1174 | snd_printdd("capture open adapter %d stream %d\n", | 1162 | snd_printdd("capture open adapter %d stream %d\n", |
1175 | card->adapter_index, substream->number); | 1163 | card->hpi->adapter->index, substream->number); |
1176 | 1164 | ||
1177 | err = hpi_handle_error( | 1165 | err = hpi_handle_error( |
1178 | hpi_instream_open(card->adapter_index, | 1166 | hpi_instream_open(card->hpi->adapter->index, |
1179 | substream->number, &dpcm->h_stream)); | 1167 | substream->number, &dpcm->h_stream)); |
1180 | if (err) | 1168 | if (err) |
1181 | kfree(dpcm); | 1169 | kfree(dpcm); |
@@ -1184,7 +1172,6 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream) | |||
1184 | if (err) | 1172 | if (err) |
1185 | return -EIO; | 1173 | return -EIO; |
1186 | 1174 | ||
1187 | |||
1188 | init_timer(&dpcm->timer); | 1175 | init_timer(&dpcm->timer); |
1189 | dpcm->timer.data = (unsigned long) dpcm; | 1176 | dpcm->timer.data = (unsigned long) dpcm; |
1190 | dpcm->timer.function = snd_card_asihpi_timer_function; | 1177 | dpcm->timer.function = snd_card_asihpi_timer_function; |
@@ -1192,9 +1179,17 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream) | |||
1192 | runtime->private_data = dpcm; | 1179 | runtime->private_data = dpcm; |
1193 | runtime->private_free = snd_card_asihpi_runtime_free; | 1180 | runtime->private_free = snd_card_asihpi_runtime_free; |
1194 | 1181 | ||
1182 | memset(&snd_card_asihpi_capture, 0, sizeof(snd_card_asihpi_capture)); | ||
1183 | snd_card_asihpi_capture.buffer_bytes_max = BUFFER_BYTES_MAX; | ||
1184 | snd_card_asihpi_capture.period_bytes_min = PERIOD_BYTES_MIN; | ||
1185 | snd_card_asihpi_capture.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN; | ||
1186 | snd_card_asihpi_capture.periods_min = PERIODS_MIN; | ||
1187 | snd_card_asihpi_capture.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN; | ||
1188 | /* snd_card_asihpi_capture.fifo_size = 0; */ | ||
1195 | snd_card_asihpi_capture.channels_max = card->in_max_chans; | 1189 | snd_card_asihpi_capture.channels_max = card->in_max_chans; |
1196 | snd_card_asihpi_capture_format(card, dpcm->h_stream, | 1190 | snd_card_asihpi_capture.channels_min = card->in_min_chans; |
1197 | &snd_card_asihpi_capture); | 1191 | snd_card_asihpi_capture.formats = |
1192 | snd_card_asihpi_capture_formats(card, dpcm->h_stream); | ||
1198 | snd_card_asihpi_pcm_samplerates(card, &snd_card_asihpi_capture); | 1193 | snd_card_asihpi_pcm_samplerates(card, &snd_card_asihpi_capture); |
1199 | snd_card_asihpi_capture.info = SNDRV_PCM_INFO_INTERLEAVED | | 1194 | snd_card_asihpi_capture.info = SNDRV_PCM_INFO_INTERLEAVED | |
1200 | SNDRV_PCM_INFO_MMAP | | 1195 | SNDRV_PCM_INFO_MMAP | |
@@ -1240,15 +1235,20 @@ static struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = { | |||
1240 | .pointer = snd_card_asihpi_capture_pointer, | 1235 | .pointer = snd_card_asihpi_capture_pointer, |
1241 | }; | 1236 | }; |
1242 | 1237 | ||
1243 | static int __devinit snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi, | 1238 | static int __devinit snd_card_asihpi_pcm_new( |
1244 | int device, int substreams) | 1239 | struct snd_card_asihpi *asihpi, int device) |
1245 | { | 1240 | { |
1246 | struct snd_pcm *pcm; | 1241 | struct snd_pcm *pcm; |
1247 | int err; | 1242 | int err; |
1243 | u16 num_instreams, num_outstreams, x16; | ||
1244 | u32 x32; | ||
1245 | |||
1246 | err = hpi_adapter_get_info(asihpi->hpi->adapter->index, | ||
1247 | &num_outstreams, &num_instreams, | ||
1248 | &x16, &x32, &x16); | ||
1248 | 1249 | ||
1249 | err = snd_pcm_new(asihpi->card, "Asihpi PCM", device, | 1250 | err = snd_pcm_new(asihpi->card, "Asihpi PCM", device, |
1250 | asihpi->num_outstreams, asihpi->num_instreams, | 1251 | num_outstreams, num_instreams, &pcm); |
1251 | &pcm); | ||
1252 | if (err < 0) | 1252 | if (err < 0) |
1253 | return err; | 1253 | return err; |
1254 | /* pointer to ops struct is stored, dont change ops afterwards! */ | 1254 | /* pointer to ops struct is stored, dont change ops afterwards! */ |
@@ -1314,7 +1314,7 @@ static const char * const asihpi_src_names[] = { | |||
1314 | "Analog", | 1314 | "Analog", |
1315 | "Adapter", | 1315 | "Adapter", |
1316 | "RTP", | 1316 | "RTP", |
1317 | "GPI", | 1317 | "Internal" |
1318 | }; | 1318 | }; |
1319 | 1319 | ||
1320 | compile_time_assert( | 1320 | compile_time_assert( |
@@ -1332,7 +1332,6 @@ static const char * const asihpi_dst_names[] = { | |||
1332 | "Net", | 1332 | "Net", |
1333 | "Analog", | 1333 | "Analog", |
1334 | "RTP", | 1334 | "RTP", |
1335 | "GPO", | ||
1336 | }; | 1335 | }; |
1337 | 1336 | ||
1338 | compile_time_assert( | 1337 | compile_time_assert( |
@@ -1410,6 +1409,7 @@ static int snd_asihpi_volume_info(struct snd_kcontrol *kcontrol, | |||
1410 | struct snd_ctl_elem_info *uinfo) | 1409 | struct snd_ctl_elem_info *uinfo) |
1411 | { | 1410 | { |
1412 | u32 h_control = kcontrol->private_value; | 1411 | u32 h_control = kcontrol->private_value; |
1412 | u32 count; | ||
1413 | u16 err; | 1413 | u16 err; |
1414 | /* native gains are in millibels */ | 1414 | /* native gains are in millibels */ |
1415 | short min_gain_mB; | 1415 | short min_gain_mB; |
@@ -1424,8 +1424,12 @@ static int snd_asihpi_volume_info(struct snd_kcontrol *kcontrol, | |||
1424 | step_gain_mB = VOL_STEP_mB; | 1424 | step_gain_mB = VOL_STEP_mB; |
1425 | } | 1425 | } |
1426 | 1426 | ||
1427 | err = hpi_meter_query_channels(h_control, &count); | ||
1428 | if (err) | ||
1429 | count = HPI_MAX_CHANNELS; | ||
1430 | |||
1427 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 1431 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
1428 | uinfo->count = 2; | 1432 | uinfo->count = count; |
1429 | uinfo->value.integer.min = min_gain_mB / VOL_STEP_mB; | 1433 | uinfo->value.integer.min = min_gain_mB / VOL_STEP_mB; |
1430 | uinfo->value.integer.max = max_gain_mB / VOL_STEP_mB; | 1434 | uinfo->value.integer.max = max_gain_mB / VOL_STEP_mB; |
1431 | uinfo->value.integer.step = step_gain_mB / VOL_STEP_mB; | 1435 | uinfo->value.integer.step = step_gain_mB / VOL_STEP_mB; |
@@ -2033,8 +2037,15 @@ static int __devinit snd_asihpi_tuner_add(struct snd_card_asihpi *asihpi, | |||
2033 | static int snd_asihpi_meter_info(struct snd_kcontrol *kcontrol, | 2037 | static int snd_asihpi_meter_info(struct snd_kcontrol *kcontrol, |
2034 | struct snd_ctl_elem_info *uinfo) | 2038 | struct snd_ctl_elem_info *uinfo) |
2035 | { | 2039 | { |
2040 | u32 h_control = kcontrol->private_value; | ||
2041 | u32 count; | ||
2042 | u16 err; | ||
2043 | err = hpi_meter_query_channels(h_control, &count); | ||
2044 | if (err) | ||
2045 | count = HPI_MAX_CHANNELS; | ||
2046 | |||
2036 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 2047 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
2037 | uinfo->count = HPI_MAX_CHANNELS; | 2048 | uinfo->count = count; |
2038 | uinfo->value.integer.min = 0; | 2049 | uinfo->value.integer.min = 0; |
2039 | uinfo->value.integer.max = 0x7FFFFFFF; | 2050 | uinfo->value.integer.max = 0x7FFFFFFF; |
2040 | return 0; | 2051 | return 0; |
@@ -2248,6 +2259,9 @@ static int snd_asihpi_cmode_info(struct snd_kcontrol *kcontrol, | |||
2248 | valid_modes++; | 2259 | valid_modes++; |
2249 | } | 2260 | } |
2250 | 2261 | ||
2262 | if (!valid_modes) | ||
2263 | return -EINVAL; | ||
2264 | |||
2251 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 2265 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
2252 | uinfo->count = 1; | 2266 | uinfo->count = 1; |
2253 | uinfo->value.enumerated.items = valid_modes; | 2267 | uinfo->value.enumerated.items = valid_modes; |
@@ -2547,7 +2561,7 @@ static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi) | |||
2547 | strcpy(card->mixername, "Asihpi Mixer"); | 2561 | strcpy(card->mixername, "Asihpi Mixer"); |
2548 | 2562 | ||
2549 | err = | 2563 | err = |
2550 | hpi_mixer_open(asihpi->adapter_index, | 2564 | hpi_mixer_open(asihpi->hpi->adapter->index, |
2551 | &asihpi->h_mixer); | 2565 | &asihpi->h_mixer); |
2552 | hpi_handle_error(err); | 2566 | hpi_handle_error(err); |
2553 | if (err) | 2567 | if (err) |
@@ -2665,24 +2679,33 @@ snd_asihpi_proc_read(struct snd_info_entry *entry, | |||
2665 | struct snd_info_buffer *buffer) | 2679 | struct snd_info_buffer *buffer) |
2666 | { | 2680 | { |
2667 | struct snd_card_asihpi *asihpi = entry->private_data; | 2681 | struct snd_card_asihpi *asihpi = entry->private_data; |
2668 | u16 version; | ||
2669 | u32 h_control; | 2682 | u32 h_control; |
2670 | u32 rate = 0; | 2683 | u32 rate = 0; |
2671 | u16 source = 0; | 2684 | u16 source = 0; |
2685 | |||
2686 | u16 num_outstreams; | ||
2687 | u16 num_instreams; | ||
2688 | u16 version; | ||
2689 | u32 serial_number; | ||
2690 | u16 type; | ||
2691 | |||
2672 | int err; | 2692 | int err; |
2673 | 2693 | ||
2674 | snd_iprintf(buffer, "ASIHPI driver proc file\n"); | 2694 | snd_iprintf(buffer, "ASIHPI driver proc file\n"); |
2695 | |||
2696 | hpi_handle_error(hpi_adapter_get_info(asihpi->hpi->adapter->index, | ||
2697 | &num_outstreams, &num_instreams, | ||
2698 | &version, &serial_number, &type)); | ||
2699 | |||
2675 | snd_iprintf(buffer, | 2700 | snd_iprintf(buffer, |
2676 | "adapter ID=%4X\n_index=%d\n" | 2701 | "Adapter type ASI%4X\nHardware Index %d\n" |
2677 | "num_outstreams=%d\n_num_instreams=%d\n", | 2702 | "%d outstreams\n%d instreams\n", |
2678 | asihpi->type, asihpi->adapter_index, | 2703 | type, asihpi->hpi->adapter->index, |
2679 | asihpi->num_outstreams, asihpi->num_instreams); | 2704 | num_outstreams, num_instreams); |
2680 | 2705 | ||
2681 | version = asihpi->version; | ||
2682 | snd_iprintf(buffer, | 2706 | snd_iprintf(buffer, |
2683 | "serial#=%d\n_hw version %c%d\nDSP code version %03d\n", | 2707 | "Serial#%d\nHardware version %c%d\nDSP code version %03d\n", |
2684 | asihpi->serial_number, ((version >> 3) & 0xf) + 'A', | 2708 | serial_number, ((version >> 3) & 0xf) + 'A', version & 0x7, |
2685 | version & 0x7, | ||
2686 | ((version >> 13) * 100) + ((version >> 7) & 0x3f)); | 2709 | ((version >> 13) * 100) + ((version >> 7) & 0x3f)); |
2687 | 2710 | ||
2688 | err = hpi_mixer_get_control(asihpi->h_mixer, | 2711 | err = hpi_mixer_get_control(asihpi->h_mixer, |
@@ -2690,18 +2713,15 @@ snd_asihpi_proc_read(struct snd_info_entry *entry, | |||
2690 | HPI_CONTROL_SAMPLECLOCK, &h_control); | 2713 | HPI_CONTROL_SAMPLECLOCK, &h_control); |
2691 | 2714 | ||
2692 | if (!err) { | 2715 | if (!err) { |
2693 | err = hpi_sample_clock_get_sample_rate( | 2716 | err = hpi_sample_clock_get_sample_rate(h_control, &rate); |
2694 | h_control, &rate); | ||
2695 | err += hpi_sample_clock_get_source(h_control, &source); | 2717 | err += hpi_sample_clock_get_source(h_control, &source); |
2696 | 2718 | ||
2697 | if (!err) | 2719 | if (!err) |
2698 | snd_iprintf(buffer, "sample_clock=%d_hz, source %s\n", | 2720 | snd_iprintf(buffer, "Sample Clock %dHz, source %s\n", |
2699 | rate, sampleclock_sources[source]); | 2721 | rate, sampleclock_sources[source]); |
2700 | } | 2722 | } |
2701 | |||
2702 | } | 2723 | } |
2703 | 2724 | ||
2704 | |||
2705 | static void __devinit snd_asihpi_proc_init(struct snd_card_asihpi *asihpi) | 2725 | static void __devinit snd_asihpi_proc_init(struct snd_card_asihpi *asihpi) |
2706 | { | 2726 | { |
2707 | struct snd_info_entry *entry; | 2727 | struct snd_info_entry *entry; |
@@ -2773,35 +2793,34 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev, | |||
2773 | const struct pci_device_id *pci_id) | 2793 | const struct pci_device_id *pci_id) |
2774 | { | 2794 | { |
2775 | int err; | 2795 | int err; |
2776 | 2796 | struct hpi_adapter *hpi; | |
2777 | u16 version; | ||
2778 | int pcm_substreams; | ||
2779 | |||
2780 | struct hpi_adapter *hpi_card; | ||
2781 | struct snd_card *card; | 2797 | struct snd_card *card; |
2782 | struct snd_card_asihpi *asihpi; | 2798 | struct snd_card_asihpi *asihpi; |
2783 | 2799 | ||
2784 | u32 h_control; | 2800 | u32 h_control; |
2785 | u32 h_stream; | 2801 | u32 h_stream; |
2802 | u32 adapter_index; | ||
2786 | 2803 | ||
2787 | static int dev; | 2804 | static int dev; |
2788 | if (dev >= SNDRV_CARDS) | 2805 | if (dev >= SNDRV_CARDS) |
2789 | return -ENODEV; | 2806 | return -ENODEV; |
2790 | 2807 | ||
2791 | /* Should this be enable[hpi_card->index] ? */ | 2808 | /* Should this be enable[hpi->index] ? */ |
2792 | if (!enable[dev]) { | 2809 | if (!enable[dev]) { |
2793 | dev++; | 2810 | dev++; |
2794 | return -ENOENT; | 2811 | return -ENOENT; |
2795 | } | 2812 | } |
2796 | 2813 | ||
2814 | /* Initialise low-level HPI driver */ | ||
2797 | err = asihpi_adapter_probe(pci_dev, pci_id); | 2815 | err = asihpi_adapter_probe(pci_dev, pci_id); |
2798 | if (err < 0) | 2816 | if (err < 0) |
2799 | return err; | 2817 | return err; |
2800 | 2818 | ||
2801 | hpi_card = pci_get_drvdata(pci_dev); | 2819 | hpi = pci_get_drvdata(pci_dev); |
2820 | adapter_index = hpi->adapter->index; | ||
2802 | /* first try to give the card the same index as its hardware index */ | 2821 | /* first try to give the card the same index as its hardware index */ |
2803 | err = snd_card_create(hpi_card->index, | 2822 | err = snd_card_create(adapter_index, |
2804 | id[hpi_card->index], THIS_MODULE, | 2823 | id[adapter_index], THIS_MODULE, |
2805 | sizeof(struct snd_card_asihpi), | 2824 | sizeof(struct snd_card_asihpi), |
2806 | &card); | 2825 | &card); |
2807 | if (err < 0) { | 2826 | if (err < 0) { |
@@ -2815,50 +2834,32 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev, | |||
2815 | return err; | 2834 | return err; |
2816 | snd_printk(KERN_WARNING | 2835 | snd_printk(KERN_WARNING |
2817 | "**** WARNING **** Adapter index %d->ALSA index %d\n", | 2836 | "**** WARNING **** Adapter index %d->ALSA index %d\n", |
2818 | hpi_card->index, card->number); | 2837 | adapter_index, card->number); |
2819 | } | 2838 | } |
2820 | 2839 | ||
2821 | snd_card_set_dev(card, &pci_dev->dev); | 2840 | snd_card_set_dev(card, &pci_dev->dev); |
2822 | 2841 | ||
2823 | asihpi = (struct snd_card_asihpi *) card->private_data; | 2842 | asihpi = card->private_data; |
2824 | asihpi->card = card; | 2843 | asihpi->card = card; |
2825 | asihpi->pci = pci_dev; | 2844 | asihpi->pci = pci_dev; |
2826 | asihpi->adapter_index = hpi_card->index; | 2845 | asihpi->hpi = hpi; |
2827 | hpi_handle_error(hpi_adapter_get_info( | 2846 | |
2828 | asihpi->adapter_index, | 2847 | snd_printk(KERN_INFO "adapter ID=%4X index=%d\n", |
2829 | &asihpi->num_outstreams, | 2848 | asihpi->hpi->adapter->type, adapter_index); |
2830 | &asihpi->num_instreams, | 2849 | |
2831 | &asihpi->version, | 2850 | err = hpi_adapter_get_property(adapter_index, |
2832 | &asihpi->serial_number, &asihpi->type)); | ||
2833 | |||
2834 | version = asihpi->version; | ||
2835 | snd_printk(KERN_INFO "adapter ID=%4X index=%d num_outstreams=%d " | ||
2836 | "num_instreams=%d S/N=%d\n" | ||
2837 | "Hw Version %c%d DSP code version %03d\n", | ||
2838 | asihpi->type, asihpi->adapter_index, | ||
2839 | asihpi->num_outstreams, | ||
2840 | asihpi->num_instreams, asihpi->serial_number, | ||
2841 | ((version >> 3) & 0xf) + 'A', | ||
2842 | version & 0x7, | ||
2843 | ((version >> 13) * 100) + ((version >> 7) & 0x3f)); | ||
2844 | |||
2845 | pcm_substreams = asihpi->num_outstreams; | ||
2846 | if (pcm_substreams < asihpi->num_instreams) | ||
2847 | pcm_substreams = asihpi->num_instreams; | ||
2848 | |||
2849 | err = hpi_adapter_get_property(asihpi->adapter_index, | ||
2850 | HPI_ADAPTER_PROPERTY_CAPS1, | 2851 | HPI_ADAPTER_PROPERTY_CAPS1, |
2851 | NULL, &asihpi->support_grouping); | 2852 | NULL, &asihpi->support_grouping); |
2852 | if (err) | 2853 | if (err) |
2853 | asihpi->support_grouping = 0; | 2854 | asihpi->support_grouping = 0; |
2854 | 2855 | ||
2855 | err = hpi_adapter_get_property(asihpi->adapter_index, | 2856 | err = hpi_adapter_get_property(adapter_index, |
2856 | HPI_ADAPTER_PROPERTY_CAPS2, | 2857 | HPI_ADAPTER_PROPERTY_CAPS2, |
2857 | &asihpi->support_mrx, NULL); | 2858 | &asihpi->support_mrx, NULL); |
2858 | if (err) | 2859 | if (err) |
2859 | asihpi->support_mrx = 0; | 2860 | asihpi->support_mrx = 0; |
2860 | 2861 | ||
2861 | err = hpi_adapter_get_property(asihpi->adapter_index, | 2862 | err = hpi_adapter_get_property(adapter_index, |
2862 | HPI_ADAPTER_PROPERTY_INTERVAL, | 2863 | HPI_ADAPTER_PROPERTY_INTERVAL, |
2863 | NULL, &asihpi->update_interval_frames); | 2864 | NULL, &asihpi->update_interval_frames); |
2864 | if (err) | 2865 | if (err) |
@@ -2867,7 +2868,7 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev, | |||
2867 | if (!asihpi->can_dma) | 2868 | if (!asihpi->can_dma) |
2868 | asihpi->update_interval_frames *= 2; | 2869 | asihpi->update_interval_frames *= 2; |
2869 | 2870 | ||
2870 | hpi_handle_error(hpi_instream_open(asihpi->adapter_index, | 2871 | hpi_handle_error(hpi_instream_open(adapter_index, |
2871 | 0, &h_stream)); | 2872 | 0, &h_stream)); |
2872 | 2873 | ||
2873 | err = hpi_instream_host_buffer_free(h_stream); | 2874 | err = hpi_instream_host_buffer_free(h_stream); |
@@ -2875,7 +2876,7 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev, | |||
2875 | 2876 | ||
2876 | hpi_handle_error(hpi_instream_close(h_stream)); | 2877 | hpi_handle_error(hpi_instream_close(h_stream)); |
2877 | 2878 | ||
2878 | err = hpi_adapter_get_property(asihpi->adapter_index, | 2879 | err = hpi_adapter_get_property(adapter_index, |
2879 | HPI_ADAPTER_PROPERTY_CURCHANNELS, | 2880 | HPI_ADAPTER_PROPERTY_CURCHANNELS, |
2880 | &asihpi->in_max_chans, &asihpi->out_max_chans); | 2881 | &asihpi->in_max_chans, &asihpi->out_max_chans); |
2881 | if (err) { | 2882 | if (err) { |
@@ -2883,13 +2884,22 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev, | |||
2883 | asihpi->out_max_chans = 2; | 2884 | asihpi->out_max_chans = 2; |
2884 | } | 2885 | } |
2885 | 2886 | ||
2886 | snd_printk(KERN_INFO "has dma:%d, grouping:%d, mrx:%d\n", | 2887 | if (asihpi->out_max_chans > 2) { /* assume LL mode */ |
2888 | asihpi->out_min_chans = asihpi->out_max_chans; | ||
2889 | asihpi->in_min_chans = asihpi->in_max_chans; | ||
2890 | asihpi->support_grouping = 0; | ||
2891 | } else { | ||
2892 | asihpi->out_min_chans = 1; | ||
2893 | asihpi->in_min_chans = 1; | ||
2894 | } | ||
2895 | |||
2896 | snd_printk(KERN_INFO "Has dma:%d, grouping:%d, mrx:%d\n", | ||
2887 | asihpi->can_dma, | 2897 | asihpi->can_dma, |
2888 | asihpi->support_grouping, | 2898 | asihpi->support_grouping, |
2889 | asihpi->support_mrx | 2899 | asihpi->support_mrx |
2890 | ); | 2900 | ); |
2891 | 2901 | ||
2892 | err = snd_card_asihpi_pcm_new(asihpi, 0, pcm_substreams); | 2902 | err = snd_card_asihpi_pcm_new(asihpi, 0); |
2893 | if (err < 0) { | 2903 | if (err < 0) { |
2894 | snd_printk(KERN_ERR "pcm_new failed\n"); | 2904 | snd_printk(KERN_ERR "pcm_new failed\n"); |
2895 | goto __nodev; | 2905 | goto __nodev; |
@@ -2916,13 +2926,14 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev, | |||
2916 | 2926 | ||
2917 | strcpy(card->driver, "ASIHPI"); | 2927 | strcpy(card->driver, "ASIHPI"); |
2918 | 2928 | ||
2919 | sprintf(card->shortname, "AudioScience ASI%4X", asihpi->type); | 2929 | sprintf(card->shortname, "AudioScience ASI%4X", |
2930 | asihpi->hpi->adapter->type); | ||
2920 | sprintf(card->longname, "%s %i", | 2931 | sprintf(card->longname, "%s %i", |
2921 | card->shortname, asihpi->adapter_index); | 2932 | card->shortname, adapter_index); |
2922 | err = snd_card_register(card); | 2933 | err = snd_card_register(card); |
2923 | 2934 | ||
2924 | if (!err) { | 2935 | if (!err) { |
2925 | hpi_card->snd_card_asihpi = card; | 2936 | hpi->snd_card = card; |
2926 | dev++; | 2937 | dev++; |
2927 | return 0; | 2938 | return 0; |
2928 | } | 2939 | } |
@@ -2935,10 +2946,9 @@ __nodev: | |||
2935 | 2946 | ||
2936 | static void __devexit snd_asihpi_remove(struct pci_dev *pci_dev) | 2947 | static void __devexit snd_asihpi_remove(struct pci_dev *pci_dev) |
2937 | { | 2948 | { |
2938 | struct hpi_adapter *hpi_card = pci_get_drvdata(pci_dev); | 2949 | struct hpi_adapter *hpi = pci_get_drvdata(pci_dev); |
2939 | 2950 | snd_card_free(hpi->snd_card); | |
2940 | snd_card_free(hpi_card->snd_card_asihpi); | 2951 | hpi->snd_card = NULL; |
2941 | hpi_card->snd_card_asihpi = NULL; | ||
2942 | asihpi_adapter_remove(pci_dev); | 2952 | asihpi_adapter_remove(pci_dev); |
2943 | } | 2953 | } |
2944 | 2954 | ||