diff options
author | Eliot Blennerhassett <eliot@blennerhassett.gen.nz> | 2014-11-19 22:22:53 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2014-11-22 16:33:13 -0500 |
commit | f9a376c3f6d77e59d41350901b2bafbaf8791df0 (patch) | |
tree | b97b1b78966dba5ac3194558d779ca1840f10304 /sound/pci/asihpi | |
parent | c1464a885444dd7e9c4491177ee102b64adc46c5 (diff) |
ALSA: asihpi: Add support for stream interrupt.
Some cards have a so-called low-latency mode, in which they present
a single multichannel stream with no mixing or samplerate conversion.
In this mode the card can generate an interrupt per internal processing
block (typically 32 or 64 frames)
Signed-off-by: Eliot Blennerhassett <eliot@blennerhassett.gen.nz>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/asihpi')
-rw-r--r-- | sound/pci/asihpi/asihpi.c | 177 | ||||
-rw-r--r-- | sound/pci/asihpi/hpi6205.c | 43 | ||||
-rw-r--r-- | sound/pci/asihpi/hpi_internal.h | 4 | ||||
-rw-r--r-- | sound/pci/asihpi/hpicmn.h | 19 | ||||
-rw-r--r-- | sound/pci/asihpi/hpioctl.c | 124 | ||||
-rw-r--r-- | sound/pci/asihpi/hpios.h | 4 |
6 files changed, 321 insertions, 50 deletions
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index c06903304e12..ae29f30547cc 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Asihpi soundcard | 2 | * Asihpi soundcard |
3 | * Copyright (c) by AudioScience Inc <alsa@audioscience.com> | 3 | * Copyright (c) by AudioScience Inc <support@audioscience.com> |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of version 2 of the GNU General Public License as | 6 | * it under the terms of version 2 of the GNU General Public License as |
@@ -124,6 +124,16 @@ struct snd_card_asihpi { | |||
124 | struct pci_dev *pci; | 124 | struct pci_dev *pci; |
125 | struct hpi_adapter *hpi; | 125 | struct hpi_adapter *hpi; |
126 | 126 | ||
127 | /* In low latency mode there is only one stream, a pointer to its | ||
128 | * private data is stored here on trigger and cleared on stop. | ||
129 | * The interrupt handler uses it as a parameter when calling | ||
130 | * snd_card_asihpi_timer_function(). | ||
131 | */ | ||
132 | struct snd_card_asihpi_pcm *llmode_streampriv; | ||
133 | struct tasklet_struct t; | ||
134 | void (*pcm_start)(struct snd_pcm_substream *substream); | ||
135 | void (*pcm_stop)(struct snd_pcm_substream *substream); | ||
136 | |||
127 | u32 h_mixer; | 137 | u32 h_mixer; |
128 | struct clk_cache cc; | 138 | struct clk_cache cc; |
129 | 139 | ||
@@ -544,6 +554,48 @@ static void snd_card_asihpi_pcm_timer_stop(struct snd_pcm_substream *substream) | |||
544 | del_timer(&dpcm->timer); | 554 | del_timer(&dpcm->timer); |
545 | } | 555 | } |
546 | 556 | ||
557 | static void snd_card_asihpi_pcm_int_start(struct snd_pcm_substream *substream) | ||
558 | { | ||
559 | struct snd_card_asihpi_pcm *dpcm; | ||
560 | struct snd_card_asihpi *card; | ||
561 | |||
562 | BUG_ON(!substream); | ||
563 | |||
564 | dpcm = (struct snd_card_asihpi_pcm *)substream->runtime->private_data; | ||
565 | card = snd_pcm_substream_chip(substream); | ||
566 | |||
567 | BUG_ON(in_interrupt()); | ||
568 | tasklet_disable(&card->t); | ||
569 | card->llmode_streampriv = dpcm; | ||
570 | tasklet_enable(&card->t); | ||
571 | |||
572 | hpi_handle_error(hpi_adapter_set_property(card->hpi->adapter->index, | ||
573 | HPI_ADAPTER_PROPERTY_IRQ_RATE, | ||
574 | card->update_interval_frames, 0)); | ||
575 | } | ||
576 | |||
577 | static void snd_card_asihpi_pcm_int_stop(struct snd_pcm_substream *substream) | ||
578 | { | ||
579 | struct snd_card_asihpi_pcm *dpcm; | ||
580 | struct snd_card_asihpi *card; | ||
581 | |||
582 | BUG_ON(!substream); | ||
583 | |||
584 | dpcm = (struct snd_card_asihpi_pcm *)substream->runtime->private_data; | ||
585 | card = snd_pcm_substream_chip(substream); | ||
586 | |||
587 | hpi_handle_error(hpi_adapter_set_property(card->hpi->adapter->index, | ||
588 | HPI_ADAPTER_PROPERTY_IRQ_RATE, 0, 0)); | ||
589 | |||
590 | if (in_interrupt()) | ||
591 | card->llmode_streampriv = NULL; | ||
592 | else { | ||
593 | tasklet_disable(&card->t); | ||
594 | card->llmode_streampriv = NULL; | ||
595 | tasklet_enable(&card->t); | ||
596 | } | ||
597 | } | ||
598 | |||
547 | static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, | 599 | static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, |
548 | int cmd) | 600 | int cmd) |
549 | { | 601 | { |
@@ -602,7 +654,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, | |||
602 | break; | 654 | break; |
603 | } | 655 | } |
604 | /* start the master stream */ | 656 | /* start the master stream */ |
605 | snd_card_asihpi_pcm_timer_start(substream); | 657 | card->pcm_start(substream); |
606 | if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) || | 658 | if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) || |
607 | !card->can_dma) | 659 | !card->can_dma) |
608 | hpi_handle_error(hpi_stream_start(dpcm->h_stream)); | 660 | hpi_handle_error(hpi_stream_start(dpcm->h_stream)); |
@@ -610,7 +662,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, | |||
610 | 662 | ||
611 | case SNDRV_PCM_TRIGGER_STOP: | 663 | case SNDRV_PCM_TRIGGER_STOP: |
612 | snd_printdd("%s trigger stop\n", name); | 664 | snd_printdd("%s trigger stop\n", name); |
613 | snd_card_asihpi_pcm_timer_stop(substream); | 665 | card->pcm_stop(substream); |
614 | snd_pcm_group_for_each_entry(s, substream) { | 666 | snd_pcm_group_for_each_entry(s, substream) { |
615 | if (snd_pcm_substream_chip(s) != card) | 667 | if (snd_pcm_substream_chip(s) != card) |
616 | continue; | 668 | continue; |
@@ -641,12 +693,12 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, | |||
641 | 693 | ||
642 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 694 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
643 | snd_printdd("%s trigger pause release\n", name); | 695 | snd_printdd("%s trigger pause release\n", name); |
696 | card->pcm_start(substream); | ||
644 | hpi_handle_error(hpi_stream_start(dpcm->h_stream)); | 697 | hpi_handle_error(hpi_stream_start(dpcm->h_stream)); |
645 | snd_card_asihpi_pcm_timer_start(substream); | ||
646 | break; | 698 | break; |
647 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 699 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
648 | snd_printdd("%s trigger pause push\n", name); | 700 | snd_printdd("%s trigger pause push\n", name); |
649 | snd_card_asihpi_pcm_timer_stop(substream); | 701 | card->pcm_stop(substream); |
650 | hpi_handle_error(hpi_stream_stop(dpcm->h_stream)); | 702 | hpi_handle_error(hpi_stream_stop(dpcm->h_stream)); |
651 | break; | 703 | break; |
652 | default: | 704 | default: |
@@ -718,8 +770,8 @@ static void snd_card_asihpi_timer_function(unsigned long data) | |||
718 | u32 buffer_size, bytes_avail, samples_played, on_card_bytes; | 770 | u32 buffer_size, bytes_avail, samples_played, on_card_bytes; |
719 | char name[16]; | 771 | char name[16]; |
720 | 772 | ||
721 | snd_pcm_debug_name(substream, name, sizeof(name)); | ||
722 | 773 | ||
774 | snd_pcm_debug_name(substream, name, sizeof(name)); | ||
723 | 775 | ||
724 | /* find minimum newdata and buffer pos in group */ | 776 | /* find minimum newdata and buffer pos in group */ |
725 | snd_pcm_group_for_each_entry(s, substream) { | 777 | snd_pcm_group_for_each_entry(s, substream) { |
@@ -779,7 +831,8 @@ static void snd_card_asihpi_timer_function(unsigned long data) | |||
779 | newdata); | 831 | newdata); |
780 | } | 832 | } |
781 | 833 | ||
782 | snd_printddd("timer1, %s, %d, S=%d, elap=%d, rw=%d, dsp=%d, left=%d, aux=%d, space=%d, hw_ptr=%ld, appl_ptr=%ld\n", | 834 | snd_printddd( |
835 | "timer1, %s, %d, S=%d, elap=%d, rw=%d, dsp=%d, left=%d, aux=%d, space=%d, hw_ptr=%ld, appl_ptr=%ld\n", | ||
783 | name, s->number, state, | 836 | name, s->number, state, |
784 | ds->pcm_buf_elapsed_dma_ofs, | 837 | ds->pcm_buf_elapsed_dma_ofs, |
785 | ds->pcm_buf_host_rw_ofs, | 838 | ds->pcm_buf_host_rw_ofs, |
@@ -815,11 +868,13 @@ static void snd_card_asihpi_timer_function(unsigned long data) | |||
815 | 868 | ||
816 | snd_pcm_group_for_each_entry(s, substream) { | 869 | snd_pcm_group_for_each_entry(s, substream) { |
817 | struct snd_card_asihpi_pcm *ds = s->runtime->private_data; | 870 | struct snd_card_asihpi_pcm *ds = s->runtime->private_data; |
871 | runtime = s->runtime; | ||
818 | 872 | ||
819 | /* don't link Cap and Play */ | 873 | /* don't link Cap and Play */ |
820 | if (substream->stream != s->stream) | 874 | if (substream->stream != s->stream) |
821 | continue; | 875 | continue; |
822 | 876 | ||
877 | /* Store dma offset for use by pointer callback */ | ||
823 | ds->pcm_buf_dma_ofs = pcm_buf_dma_ofs; | 878 | ds->pcm_buf_dma_ofs = pcm_buf_dma_ofs; |
824 | 879 | ||
825 | if (xfercount && | 880 | if (xfercount && |
@@ -878,16 +933,38 @@ static void snd_card_asihpi_timer_function(unsigned long data) | |||
878 | pd, xfer2)); | 933 | pd, xfer2)); |
879 | } | 934 | } |
880 | } | 935 | } |
936 | /* ? host_rw_ofs always ahead of elapsed_dma_ofs by preload size? */ | ||
881 | ds->pcm_buf_host_rw_ofs += xfercount; | 937 | ds->pcm_buf_host_rw_ofs += xfercount; |
882 | ds->pcm_buf_elapsed_dma_ofs += xfercount; | 938 | ds->pcm_buf_elapsed_dma_ofs += xfercount; |
883 | snd_pcm_period_elapsed(s); | 939 | snd_pcm_period_elapsed(s); |
884 | } | 940 | } |
885 | } | 941 | } |
886 | 942 | ||
887 | if (dpcm->respawn_timer) | 943 | if (!card->hpi->interrupt_mode && dpcm->respawn_timer) |
888 | add_timer(&dpcm->timer); | 944 | add_timer(&dpcm->timer); |
889 | } | 945 | } |
890 | 946 | ||
947 | static void snd_card_asihpi_int_task(unsigned long data) | ||
948 | { | ||
949 | struct hpi_adapter *a = (struct hpi_adapter *)data; | ||
950 | struct snd_card_asihpi *asihpi; | ||
951 | |||
952 | WARN_ON(!a || !a->snd_card || !a->snd_card->private_data); | ||
953 | asihpi = (struct snd_card_asihpi *)a->snd_card->private_data; | ||
954 | if (asihpi->llmode_streampriv) | ||
955 | snd_card_asihpi_timer_function( | ||
956 | (unsigned long)asihpi->llmode_streampriv); | ||
957 | } | ||
958 | |||
959 | static void snd_card_asihpi_isr(struct hpi_adapter *a) | ||
960 | { | ||
961 | struct snd_card_asihpi *asihpi; | ||
962 | |||
963 | WARN_ON(!a || !a->snd_card || !a->snd_card->private_data); | ||
964 | asihpi = (struct snd_card_asihpi *)a->snd_card->private_data; | ||
965 | tasklet_schedule(&asihpi->t); | ||
966 | } | ||
967 | |||
891 | /***************************** PLAYBACK OPS ****************/ | 968 | /***************************** PLAYBACK OPS ****************/ |
892 | static int snd_card_asihpi_playback_ioctl(struct snd_pcm_substream *substream, | 969 | static int snd_card_asihpi_playback_ioctl(struct snd_pcm_substream *substream, |
893 | unsigned int cmd, void *arg) | 970 | unsigned int cmd, void *arg) |
@@ -995,13 +1072,22 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream) | |||
995 | runtime->private_free = snd_card_asihpi_runtime_free; | 1072 | runtime->private_free = snd_card_asihpi_runtime_free; |
996 | 1073 | ||
997 | memset(&snd_card_asihpi_playback, 0, sizeof(snd_card_asihpi_playback)); | 1074 | memset(&snd_card_asihpi_playback, 0, sizeof(snd_card_asihpi_playback)); |
998 | snd_card_asihpi_playback.buffer_bytes_max = BUFFER_BYTES_MAX; | 1075 | if (!card->hpi->interrupt_mode) { |
999 | snd_card_asihpi_playback.period_bytes_min = PERIOD_BYTES_MIN; | 1076 | snd_card_asihpi_playback.buffer_bytes_max = BUFFER_BYTES_MAX; |
1000 | /*?snd_card_asihpi_playback.period_bytes_min = | 1077 | snd_card_asihpi_playback.period_bytes_min = PERIOD_BYTES_MIN; |
1001 | card->out_max_chans * 4096; */ | 1078 | snd_card_asihpi_playback.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN; |
1002 | snd_card_asihpi_playback.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN; | 1079 | snd_card_asihpi_playback.periods_min = PERIODS_MIN; |
1003 | snd_card_asihpi_playback.periods_min = PERIODS_MIN; | 1080 | snd_card_asihpi_playback.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN; |
1004 | snd_card_asihpi_playback.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN; | 1081 | } else { |
1082 | size_t pbmin = card->update_interval_frames * | ||
1083 | card->out_max_chans; | ||
1084 | snd_card_asihpi_playback.buffer_bytes_max = BUFFER_BYTES_MAX; | ||
1085 | snd_card_asihpi_playback.period_bytes_min = pbmin; | ||
1086 | snd_card_asihpi_playback.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN; | ||
1087 | snd_card_asihpi_playback.periods_min = PERIODS_MIN; | ||
1088 | snd_card_asihpi_playback.periods_max = BUFFER_BYTES_MAX / pbmin; | ||
1089 | } | ||
1090 | |||
1005 | /* snd_card_asihpi_playback.fifo_size = 0; */ | 1091 | /* snd_card_asihpi_playback.fifo_size = 0; */ |
1006 | snd_card_asihpi_playback.channels_max = card->out_max_chans; | 1092 | snd_card_asihpi_playback.channels_max = card->out_max_chans; |
1007 | snd_card_asihpi_playback.channels_min = card->out_min_chans; | 1093 | snd_card_asihpi_playback.channels_min = card->out_min_chans; |
@@ -1036,7 +1122,7 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream) | |||
1036 | card->update_interval_frames); | 1122 | card->update_interval_frames); |
1037 | 1123 | ||
1038 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, | 1124 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, |
1039 | card->update_interval_frames * 2, UINT_MAX); | 1125 | card->update_interval_frames, UINT_MAX); |
1040 | 1126 | ||
1041 | snd_printdd("playback open\n"); | 1127 | snd_printdd("playback open\n"); |
1042 | 1128 | ||
@@ -1102,8 +1188,6 @@ static int snd_card_asihpi_capture_prepare(struct snd_pcm_substream *substream) | |||
1102 | return 0; | 1188 | return 0; |
1103 | } | 1189 | } |
1104 | 1190 | ||
1105 | |||
1106 | |||
1107 | static u64 snd_card_asihpi_capture_formats(struct snd_card_asihpi *asihpi, | 1191 | static u64 snd_card_asihpi_capture_formats(struct snd_card_asihpi *asihpi, |
1108 | u32 h_stream) | 1192 | u32 h_stream) |
1109 | { | 1193 | { |
@@ -1170,11 +1254,21 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream) | |||
1170 | runtime->private_free = snd_card_asihpi_runtime_free; | 1254 | runtime->private_free = snd_card_asihpi_runtime_free; |
1171 | 1255 | ||
1172 | memset(&snd_card_asihpi_capture, 0, sizeof(snd_card_asihpi_capture)); | 1256 | memset(&snd_card_asihpi_capture, 0, sizeof(snd_card_asihpi_capture)); |
1173 | snd_card_asihpi_capture.buffer_bytes_max = BUFFER_BYTES_MAX; | 1257 | if (!card->hpi->interrupt_mode) { |
1174 | snd_card_asihpi_capture.period_bytes_min = PERIOD_BYTES_MIN; | 1258 | snd_card_asihpi_capture.buffer_bytes_max = BUFFER_BYTES_MAX; |
1175 | snd_card_asihpi_capture.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN; | 1259 | snd_card_asihpi_capture.period_bytes_min = PERIOD_BYTES_MIN; |
1176 | snd_card_asihpi_capture.periods_min = PERIODS_MIN; | 1260 | snd_card_asihpi_capture.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN; |
1177 | snd_card_asihpi_capture.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN; | 1261 | snd_card_asihpi_capture.periods_min = PERIODS_MIN; |
1262 | snd_card_asihpi_capture.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN; | ||
1263 | } else { | ||
1264 | size_t pbmin = card->update_interval_frames * | ||
1265 | card->out_max_chans; | ||
1266 | snd_card_asihpi_capture.buffer_bytes_max = BUFFER_BYTES_MAX; | ||
1267 | snd_card_asihpi_capture.period_bytes_min = pbmin; | ||
1268 | snd_card_asihpi_capture.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN; | ||
1269 | snd_card_asihpi_capture.periods_min = PERIODS_MIN; | ||
1270 | snd_card_asihpi_capture.periods_max = BUFFER_BYTES_MAX / pbmin; | ||
1271 | } | ||
1178 | /* snd_card_asihpi_capture.fifo_size = 0; */ | 1272 | /* snd_card_asihpi_capture.fifo_size = 0; */ |
1179 | snd_card_asihpi_capture.channels_max = card->in_max_chans; | 1273 | snd_card_asihpi_capture.channels_max = card->in_max_chans; |
1180 | snd_card_asihpi_capture.channels_min = card->in_min_chans; | 1274 | snd_card_asihpi_capture.channels_min = card->in_min_chans; |
@@ -1199,7 +1293,7 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream) | |||
1199 | snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, | 1293 | snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, |
1200 | card->update_interval_frames); | 1294 | card->update_interval_frames); |
1201 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, | 1295 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, |
1202 | card->update_interval_frames * 2, UINT_MAX); | 1296 | card->update_interval_frames, UINT_MAX); |
1203 | 1297 | ||
1204 | snd_pcm_set_sync(substream); | 1298 | snd_pcm_set_sync(substream); |
1205 | 1299 | ||
@@ -2444,15 +2538,19 @@ static int snd_asihpi_clkrate_get(struct snd_kcontrol *kcontrol, | |||
2444 | static int snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi, | 2538 | static int snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi, |
2445 | struct hpi_control *hpi_ctl) | 2539 | struct hpi_control *hpi_ctl) |
2446 | { | 2540 | { |
2447 | struct snd_card *card = asihpi->card; | 2541 | struct snd_card *card; |
2448 | struct snd_kcontrol_new snd_control; | 2542 | struct snd_kcontrol_new snd_control; |
2449 | 2543 | ||
2450 | struct clk_cache *clkcache = &asihpi->cc; | 2544 | struct clk_cache *clkcache; |
2451 | u32 hSC = hpi_ctl->h_control; | 2545 | u32 hSC = hpi_ctl->h_control; |
2452 | int has_aes_in = 0; | 2546 | int has_aes_in = 0; |
2453 | int i, j; | 2547 | int i, j; |
2454 | u16 source; | 2548 | u16 source; |
2455 | 2549 | ||
2550 | if (snd_BUG_ON(!asihpi)) | ||
2551 | return -EINVAL; | ||
2552 | card = asihpi->card; | ||
2553 | clkcache = &asihpi->cc; | ||
2456 | snd_control.private_value = hpi_ctl->h_control; | 2554 | snd_control.private_value = hpi_ctl->h_control; |
2457 | 2555 | ||
2458 | clkcache->has_local = 0; | 2556 | clkcache->has_local = 0; |
@@ -2808,6 +2906,7 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev, | |||
2808 | asihpi->card = card; | 2906 | asihpi->card = card; |
2809 | asihpi->pci = pci_dev; | 2907 | asihpi->pci = pci_dev; |
2810 | asihpi->hpi = hpi; | 2908 | asihpi->hpi = hpi; |
2909 | hpi->snd_card = card; | ||
2811 | 2910 | ||
2812 | snd_printk(KERN_INFO "adapter ID=%4X index=%d\n", | 2911 | snd_printk(KERN_INFO "adapter ID=%4X index=%d\n", |
2813 | asihpi->hpi->adapter->type, adapter_index); | 2912 | asihpi->hpi->adapter->type, adapter_index); |
@@ -2830,8 +2929,16 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev, | |||
2830 | if (err) | 2929 | if (err) |
2831 | asihpi->update_interval_frames = 512; | 2930 | asihpi->update_interval_frames = 512; |
2832 | 2931 | ||
2833 | if (!asihpi->can_dma) | 2932 | if (hpi->interrupt_mode) { |
2834 | asihpi->update_interval_frames *= 2; | 2933 | asihpi->pcm_start = snd_card_asihpi_pcm_int_start; |
2934 | asihpi->pcm_stop = snd_card_asihpi_pcm_int_stop; | ||
2935 | tasklet_init(&asihpi->t, snd_card_asihpi_int_task, | ||
2936 | (unsigned long)hpi); | ||
2937 | hpi->interrupt_callback = snd_card_asihpi_isr; | ||
2938 | } else { | ||
2939 | asihpi->pcm_start = snd_card_asihpi_pcm_timer_start; | ||
2940 | asihpi->pcm_stop = snd_card_asihpi_pcm_timer_stop; | ||
2941 | } | ||
2835 | 2942 | ||
2836 | hpi_handle_error(hpi_instream_open(adapter_index, | 2943 | hpi_handle_error(hpi_instream_open(adapter_index, |
2837 | 0, &h_stream)); | 2944 | 0, &h_stream)); |
@@ -2841,6 +2948,9 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev, | |||
2841 | 2948 | ||
2842 | hpi_handle_error(hpi_instream_close(h_stream)); | 2949 | hpi_handle_error(hpi_instream_close(h_stream)); |
2843 | 2950 | ||
2951 | if (!asihpi->can_dma) | ||
2952 | asihpi->update_interval_frames *= 2; | ||
2953 | |||
2844 | err = hpi_adapter_get_property(adapter_index, | 2954 | err = hpi_adapter_get_property(adapter_index, |
2845 | HPI_ADAPTER_PROPERTY_CURCHANNELS, | 2955 | HPI_ADAPTER_PROPERTY_CURCHANNELS, |
2846 | &asihpi->in_max_chans, &asihpi->out_max_chans); | 2956 | &asihpi->in_max_chans, &asihpi->out_max_chans); |
@@ -2900,7 +3010,6 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev, | |||
2900 | err = snd_card_register(card); | 3010 | err = snd_card_register(card); |
2901 | 3011 | ||
2902 | if (!err) { | 3012 | if (!err) { |
2903 | hpi->snd_card = card; | ||
2904 | dev++; | 3013 | dev++; |
2905 | return 0; | 3014 | return 0; |
2906 | } | 3015 | } |
@@ -2914,6 +3023,16 @@ __nodev: | |||
2914 | static void snd_asihpi_remove(struct pci_dev *pci_dev) | 3023 | static void snd_asihpi_remove(struct pci_dev *pci_dev) |
2915 | { | 3024 | { |
2916 | struct hpi_adapter *hpi = pci_get_drvdata(pci_dev); | 3025 | struct hpi_adapter *hpi = pci_get_drvdata(pci_dev); |
3026 | struct snd_card_asihpi *asihpi = hpi->snd_card->private_data; | ||
3027 | |||
3028 | /* Stop interrupts */ | ||
3029 | if (hpi->interrupt_mode) { | ||
3030 | hpi->interrupt_callback = NULL; | ||
3031 | hpi_handle_error(hpi_adapter_set_property(hpi->adapter->index, | ||
3032 | HPI_ADAPTER_PROPERTY_IRQ_RATE, 0, 0)); | ||
3033 | tasklet_kill(&asihpi->t); | ||
3034 | } | ||
3035 | |||
2917 | snd_card_free(hpi->snd_card); | 3036 | snd_card_free(hpi->snd_card); |
2918 | hpi->snd_card = NULL; | 3037 | hpi->snd_card = NULL; |
2919 | asihpi_adapter_remove(pci_dev); | 3038 | asihpi_adapter_remove(pci_dev); |
diff --git a/sound/pci/asihpi/hpi6205.c b/sound/pci/asihpi/hpi6205.c index 4f2873880b16..8d5abfa4e24b 100644 --- a/sound/pci/asihpi/hpi6205.c +++ b/sound/pci/asihpi/hpi6205.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | 2 | ||
3 | AudioScience HPI driver | 3 | AudioScience HPI driver |
4 | Copyright (C) 1997-2011 AudioScience Inc. <support@audioscience.com> | 4 | Copyright (C) 1997-2014 AudioScience Inc. <support@audioscience.com> |
5 | 5 | ||
6 | This program is free software; you can redistribute it and/or modify | 6 | This program is free software; you can redistribute it and/or modify |
7 | it under the terms of version 2 of the GNU General Public License as | 7 | it under the terms of version 2 of the GNU General Public License as |
@@ -163,6 +163,9 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao, | |||
163 | 163 | ||
164 | static void delete_adapter_obj(struct hpi_adapter_obj *pao); | 164 | static void delete_adapter_obj(struct hpi_adapter_obj *pao); |
165 | 165 | ||
166 | static int adapter_irq_query_and_clear(struct hpi_adapter_obj *pao, | ||
167 | u32 message); | ||
168 | |||
166 | static void outstream_host_buffer_allocate(struct hpi_adapter_obj *pao, | 169 | static void outstream_host_buffer_allocate(struct hpi_adapter_obj *pao, |
167 | struct hpi_message *phm, struct hpi_response *phr); | 170 | struct hpi_message *phm, struct hpi_response *phr); |
168 | 171 | ||
@@ -283,7 +286,6 @@ static void adapter_message(struct hpi_adapter_obj *pao, | |||
283 | case HPI_ADAPTER_DELETE: | 286 | case HPI_ADAPTER_DELETE: |
284 | adapter_delete(pao, phm, phr); | 287 | adapter_delete(pao, phm, phr); |
285 | break; | 288 | break; |
286 | |||
287 | default: | 289 | default: |
288 | hw_message(pao, phm, phr); | 290 | hw_message(pao, phm, phr); |
289 | break; | 291 | break; |
@@ -673,6 +675,12 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao, | |||
673 | 675 | ||
674 | HPI_DEBUG_LOG(INFO, "bootload DSP OK\n"); | 676 | HPI_DEBUG_LOG(INFO, "bootload DSP OK\n"); |
675 | 677 | ||
678 | pao->irq_query_and_clear = adapter_irq_query_and_clear; | ||
679 | pao->instream_host_buffer_status = | ||
680 | phw->p_interface_buffer->instream_host_buffer_status; | ||
681 | pao->outstream_host_buffer_status = | ||
682 | phw->p_interface_buffer->outstream_host_buffer_status; | ||
683 | |||
676 | return hpi_add_adapter(pao); | 684 | return hpi_add_adapter(pao); |
677 | } | 685 | } |
678 | 686 | ||
@@ -713,6 +721,21 @@ static void delete_adapter_obj(struct hpi_adapter_obj *pao) | |||
713 | 721 | ||
714 | /*****************************************************************************/ | 722 | /*****************************************************************************/ |
715 | /* Adapter functions */ | 723 | /* Adapter functions */ |
724 | static int adapter_irq_query_and_clear(struct hpi_adapter_obj *pao, | ||
725 | u32 message) | ||
726 | { | ||
727 | struct hpi_hw_obj *phw = pao->priv; | ||
728 | u32 hsr = 0; | ||
729 | |||
730 | hsr = ioread32(phw->prHSR); | ||
731 | if (hsr & C6205_HSR_INTSRC) { | ||
732 | /* reset the interrupt from the DSP */ | ||
733 | iowrite32(C6205_HSR_INTSRC, phw->prHSR); | ||
734 | return HPI_IRQ_MIXER; | ||
735 | } | ||
736 | |||
737 | return HPI_IRQ_NONE; | ||
738 | } | ||
716 | 739 | ||
717 | /*****************************************************************************/ | 740 | /*****************************************************************************/ |
718 | /* OutStream Host buffer functions */ | 741 | /* OutStream Host buffer functions */ |
@@ -1331,17 +1354,21 @@ static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao, | |||
1331 | if (boot_code_id[1] != 0) { | 1354 | if (boot_code_id[1] != 0) { |
1332 | /* DSP 1 is a C6713 */ | 1355 | /* DSP 1 is a C6713 */ |
1333 | /* CLKX0 <- '1' release the C6205 bootmode pulldowns */ | 1356 | /* CLKX0 <- '1' release the C6205 bootmode pulldowns */ |
1334 | boot_loader_write_mem32(pao, 0, (0x018C0024L), 0x00002202); | 1357 | boot_loader_write_mem32(pao, 0, 0x018C0024, 0x00002202); |
1335 | hpios_delay_micro_seconds(100); | 1358 | hpios_delay_micro_seconds(100); |
1336 | /* Reset the 6713 #1 - revB */ | 1359 | /* Reset the 6713 #1 - revB */ |
1337 | boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 0); | 1360 | boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 0); |
1338 | 1361 | /* value of bit 3 is unknown after DSP reset, other bits shoudl be 0 */ | |
1339 | /* dummy read every 4 words for 6205 advisory 1.4.4 */ | 1362 | if (0 != (boot_loader_read_mem32(pao, 0, |
1340 | boot_loader_read_mem32(pao, 0, 0); | 1363 | (C6205_BAR0_TIMER1_CTL)) & ~8)) |
1341 | 1364 | return HPI6205_ERROR_6205_REG; | |
1342 | hpios_delay_micro_seconds(100); | 1365 | hpios_delay_micro_seconds(100); |
1366 | |||
1343 | /* Release C6713 from reset - revB */ | 1367 | /* Release C6713 from reset - revB */ |
1344 | boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 4); | 1368 | boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 4); |
1369 | if (4 != (boot_loader_read_mem32(pao, 0, | ||
1370 | (C6205_BAR0_TIMER1_CTL)) & ~8)) | ||
1371 | return HPI6205_ERROR_6205_REG; | ||
1345 | hpios_delay_micro_seconds(100); | 1372 | hpios_delay_micro_seconds(100); |
1346 | } | 1373 | } |
1347 | 1374 | ||
@@ -2089,7 +2116,7 @@ static u16 message_response_sequence(struct hpi_adapter_obj *pao, | |||
2089 | return 0; | 2116 | return 0; |
2090 | } | 2117 | } |
2091 | 2118 | ||
2092 | /* Assume buffer of type struct bus_master_interface | 2119 | /* Assume buffer of type struct bus_master_interface_62 |
2093 | is allocated "noncacheable" */ | 2120 | is allocated "noncacheable" */ |
2094 | 2121 | ||
2095 | if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT)) { | 2122 | if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT)) { |
diff --git a/sound/pci/asihpi/hpi_internal.h b/sound/pci/asihpi/hpi_internal.h index c9bdc284cdaf..48380ce2c81b 100644 --- a/sound/pci/asihpi/hpi_internal.h +++ b/sound/pci/asihpi/hpi_internal.h | |||
@@ -686,8 +686,8 @@ union hpi_adapterx_msg { | |||
686 | u16 value; | 686 | u16 value; |
687 | } test_assert; | 687 | } test_assert; |
688 | struct { | 688 | struct { |
689 | u32 yes; | 689 | u32 message; |
690 | } irq_query; | 690 | } irq; |
691 | u32 pad[3]; | 691 | u32 pad[3]; |
692 | }; | 692 | }; |
693 | 693 | ||
diff --git a/sound/pci/asihpi/hpicmn.h b/sound/pci/asihpi/hpicmn.h index e44121283047..46629c2d101b 100644 --- a/sound/pci/asihpi/hpicmn.h +++ b/sound/pci/asihpi/hpicmn.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /** | 1 | /** |
2 | 2 | ||
3 | AudioScience HPI driver | 3 | AudioScience HPI driver |
4 | Copyright (C) 1997-2011 AudioScience Inc. <support@audioscience.com> | 4 | Copyright (C) 1997-2014 AudioScience Inc. <support@audioscience.com> |
5 | 5 | ||
6 | This program is free software; you can redistribute it and/or modify | 6 | This program is free software; you can redistribute it and/or modify |
7 | it under the terms of version 2 of the GNU General Public License as | 7 | it under the terms of version 2 of the GNU General Public License as |
@@ -21,7 +21,11 @@ | |||
21 | struct hpi_adapter_obj; | 21 | struct hpi_adapter_obj; |
22 | 22 | ||
23 | /* a function that takes an adapter obj and returns an int */ | 23 | /* a function that takes an adapter obj and returns an int */ |
24 | typedef int adapter_int_func(struct hpi_adapter_obj *pao); | 24 | typedef int adapter_int_func(struct hpi_adapter_obj *pao, u32 message); |
25 | |||
26 | #define HPI_IRQ_NONE (0) | ||
27 | #define HPI_IRQ_MESSAGE (1) | ||
28 | #define HPI_IRQ_MIXER (2) | ||
25 | 29 | ||
26 | struct hpi_adapter_obj { | 30 | struct hpi_adapter_obj { |
27 | struct hpi_pci pci; /* PCI info - bus#,dev#,address etc */ | 31 | struct hpi_pci pci; /* PCI info - bus#,dev#,address etc */ |
@@ -33,6 +37,9 @@ struct hpi_adapter_obj { | |||
33 | u16 dsp_crashed; | 37 | u16 dsp_crashed; |
34 | u16 has_control_cache; | 38 | u16 has_control_cache; |
35 | void *priv; | 39 | void *priv; |
40 | adapter_int_func *irq_query_and_clear; | ||
41 | struct hpi_hostbuffer_status *instream_host_buffer_status; | ||
42 | struct hpi_hostbuffer_status *outstream_host_buffer_status; | ||
36 | }; | 43 | }; |
37 | 44 | ||
38 | struct hpi_control_cache { | 45 | struct hpi_control_cache { |
@@ -55,13 +62,21 @@ void hpi_delete_adapter(struct hpi_adapter_obj *pao); | |||
55 | 62 | ||
56 | short hpi_check_control_cache(struct hpi_control_cache *pC, | 63 | short hpi_check_control_cache(struct hpi_control_cache *pC, |
57 | struct hpi_message *phm, struct hpi_response *phr); | 64 | struct hpi_message *phm, struct hpi_response *phr); |
65 | |||
66 | short hpi_check_control_cache_single(struct hpi_control_cache_single *pC, | ||
67 | struct hpi_message *phm, struct hpi_response *phr); | ||
68 | |||
58 | struct hpi_control_cache *hpi_alloc_control_cache(const u32 | 69 | struct hpi_control_cache *hpi_alloc_control_cache(const u32 |
59 | number_of_controls, const u32 size_in_bytes, u8 *pDSP_control_buffer); | 70 | number_of_controls, const u32 size_in_bytes, u8 *pDSP_control_buffer); |
71 | |||
60 | void hpi_free_control_cache(struct hpi_control_cache *p_cache); | 72 | void hpi_free_control_cache(struct hpi_control_cache *p_cache); |
61 | 73 | ||
62 | void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *pC, | 74 | void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *pC, |
63 | struct hpi_message *phm, struct hpi_response *phr); | 75 | struct hpi_message *phm, struct hpi_response *phr); |
64 | 76 | ||
77 | void hpi_cmn_control_cache_sync_to_msg_single(struct hpi_control_cache_single | ||
78 | *pC, struct hpi_message *phm, struct hpi_response *phr); | ||
79 | |||
65 | u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr); | 80 | u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr); |
66 | 81 | ||
67 | hpi_handler_func HPI_COMMON; | 82 | hpi_handler_func HPI_COMMON; |
diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c index 7f0272032fbb..9454932fc9c0 100644 --- a/sound/pci/asihpi/hpioctl.c +++ b/sound/pci/asihpi/hpioctl.c | |||
@@ -1,7 +1,8 @@ | |||
1 | /******************************************************************************* | 1 | /******************************************************************************* |
2 | |||
3 | AudioScience HPI driver | 2 | AudioScience HPI driver |
4 | Copyright (C) 1997-2011 AudioScience Inc. <support@audioscience.com> | 3 | Common Linux HPI ioctl and module probe/remove functions |
4 | |||
5 | Copyright (C) 1997-2014 AudioScience Inc. <support@audioscience.com> | ||
5 | 6 | ||
6 | This program is free software; you can redistribute it and/or modify | 7 | This program is free software; you can redistribute it and/or modify |
7 | it under the terms of version 2 of the GNU General Public License as | 8 | it under the terms of version 2 of the GNU General Public License as |
@@ -12,11 +13,6 @@ | |||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | GNU General Public License for more details. | 14 | GNU General Public License for more details. |
14 | 15 | ||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Common Linux HPI ioctl and module probe/remove functions | ||
20 | *******************************************************************************/ | 16 | *******************************************************************************/ |
21 | #define SOURCEFILE_NAME "hpioctl.c" | 17 | #define SOURCEFILE_NAME "hpioctl.c" |
22 | 18 | ||
@@ -29,6 +25,7 @@ Common Linux HPI ioctl and module probe/remove functions | |||
29 | #include "hpicmn.h" | 25 | #include "hpicmn.h" |
30 | 26 | ||
31 | #include <linux/fs.h> | 27 | #include <linux/fs.h> |
28 | #include <linux/interrupt.h> | ||
32 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
33 | #include <linux/moduleparam.h> | 30 | #include <linux/moduleparam.h> |
34 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
@@ -307,10 +304,38 @@ out: | |||
307 | return err; | 304 | return err; |
308 | } | 305 | } |
309 | 306 | ||
307 | static int asihpi_irq_count; | ||
308 | |||
309 | static irqreturn_t asihpi_isr(int irq, void *dev_id) | ||
310 | { | ||
311 | struct hpi_adapter *a = dev_id; | ||
312 | int handled; | ||
313 | |||
314 | if (!a->adapter->irq_query_and_clear) { | ||
315 | pr_err("asihpi_isr ASI%04X:%d no handler\n", a->adapter->type, | ||
316 | a->adapter->index); | ||
317 | return IRQ_NONE; | ||
318 | } | ||
319 | |||
320 | handled = a->adapter->irq_query_and_clear(a->adapter, 0); | ||
321 | |||
322 | if (!handled) | ||
323 | return IRQ_NONE; | ||
324 | |||
325 | asihpi_irq_count++; | ||
326 | /* printk(KERN_INFO "asihpi_isr %d ASI%04X:%d irq handled\n", | ||
327 | asihpi_irq_count, a->adapter->type, a->adapter->index); */ | ||
328 | |||
329 | if (a->interrupt_callback) | ||
330 | a->interrupt_callback(a); | ||
331 | |||
332 | return IRQ_HANDLED; | ||
333 | } | ||
334 | |||
310 | int asihpi_adapter_probe(struct pci_dev *pci_dev, | 335 | int asihpi_adapter_probe(struct pci_dev *pci_dev, |
311 | const struct pci_device_id *pci_id) | 336 | const struct pci_device_id *pci_id) |
312 | { | 337 | { |
313 | int idx, nm; | 338 | int idx, nm, low_latency_mode = 0, irq_supported = 0; |
314 | int adapter_index; | 339 | int adapter_index; |
315 | unsigned int memlen; | 340 | unsigned int memlen; |
316 | struct hpi_message hm; | 341 | struct hpi_message hm; |
@@ -388,8 +413,39 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev, | |||
388 | hm.adapter_index = adapter.adapter->index; | 413 | hm.adapter_index = adapter.adapter->index; |
389 | hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); | 414 | hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); |
390 | 415 | ||
391 | if (hr.error) | 416 | if (hr.error) { |
417 | HPI_DEBUG_LOG(ERROR, "HPI_ADAPTER_OPEN failed, aborting\n"); | ||
418 | goto err; | ||
419 | } | ||
420 | |||
421 | /* Check if current mode == Low Latency mode */ | ||
422 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | ||
423 | HPI_ADAPTER_GET_MODE); | ||
424 | hm.adapter_index = adapter.adapter->index; | ||
425 | hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); | ||
426 | |||
427 | if (hr.error) { | ||
428 | HPI_DEBUG_LOG(ERROR, | ||
429 | "HPI_ADAPTER_GET_MODE failed, aborting\n"); | ||
392 | goto err; | 430 | goto err; |
431 | } | ||
432 | |||
433 | if (hr.u.ax.mode.adapter_mode == HPI_ADAPTER_MODE_LOW_LATENCY) | ||
434 | low_latency_mode = 1; | ||
435 | |||
436 | /* Check if IRQs are supported */ | ||
437 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | ||
438 | HPI_ADAPTER_GET_PROPERTY); | ||
439 | hm.adapter_index = adapter.adapter->index; | ||
440 | hm.u.ax.property_set.property = HPI_ADAPTER_PROPERTY_SUPPORTS_IRQ; | ||
441 | hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); | ||
442 | if (hr.error || !hr.u.ax.property_get.parameter1) { | ||
443 | dev_info(&pci_dev->dev, | ||
444 | "IRQs not supported by adapter at index %d\n", | ||
445 | adapter.adapter->index); | ||
446 | } else { | ||
447 | irq_supported = 1; | ||
448 | } | ||
393 | 449 | ||
394 | /* WARNING can't init mutex in 'adapter' | 450 | /* WARNING can't init mutex in 'adapter' |
395 | * and then copy it to adapters[] ?!?! | 451 | * and then copy it to adapters[] ?!?! |
@@ -398,6 +454,44 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev, | |||
398 | mutex_init(&adapters[adapter_index].mutex); | 454 | mutex_init(&adapters[adapter_index].mutex); |
399 | pci_set_drvdata(pci_dev, &adapters[adapter_index]); | 455 | pci_set_drvdata(pci_dev, &adapters[adapter_index]); |
400 | 456 | ||
457 | if (low_latency_mode && irq_supported) { | ||
458 | if (!adapter.adapter->irq_query_and_clear) { | ||
459 | dev_err(&pci_dev->dev, | ||
460 | "no IRQ handler for adapter %d, aborting\n", | ||
461 | adapter.adapter->index); | ||
462 | goto err; | ||
463 | } | ||
464 | |||
465 | /* Disable IRQ generation on DSP side by setting the rate to 0 */ | ||
466 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | ||
467 | HPI_ADAPTER_SET_PROPERTY); | ||
468 | hm.adapter_index = adapter.adapter->index; | ||
469 | hm.u.ax.property_set.property = HPI_ADAPTER_PROPERTY_IRQ_RATE; | ||
470 | hm.u.ax.property_set.parameter1 = 0; | ||
471 | hm.u.ax.property_set.parameter2 = 0; | ||
472 | hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); | ||
473 | if (hr.error) { | ||
474 | HPI_DEBUG_LOG(ERROR, | ||
475 | "HPI_ADAPTER_GET_MODE failed, aborting\n"); | ||
476 | goto err; | ||
477 | } | ||
478 | |||
479 | /* Note: request_irq calls asihpi_isr here */ | ||
480 | if (request_irq(pci_dev->irq, asihpi_isr, IRQF_SHARED, | ||
481 | "asihpi", &adapters[adapter_index])) { | ||
482 | dev_err(&pci_dev->dev, "request_irq(%d) failed\n", | ||
483 | pci_dev->irq); | ||
484 | goto err; | ||
485 | } | ||
486 | |||
487 | adapters[adapter_index].interrupt_mode = 1; | ||
488 | |||
489 | dev_info(&pci_dev->dev, "using irq %d\n", pci_dev->irq); | ||
490 | adapters[adapter_index].irq = pci_dev->irq; | ||
491 | } else { | ||
492 | dev_info(&pci_dev->dev, "using polled mode\n"); | ||
493 | } | ||
494 | |||
401 | dev_info(&pci_dev->dev, "probe succeeded for ASI%04X HPI index %d\n", | 495 | dev_info(&pci_dev->dev, "probe succeeded for ASI%04X HPI index %d\n", |
402 | adapter.adapter->type, adapter_index); | 496 | adapter.adapter->type, adapter_index); |
403 | 497 | ||
@@ -431,6 +525,15 @@ void asihpi_adapter_remove(struct pci_dev *pci_dev) | |||
431 | pa = pci_get_drvdata(pci_dev); | 525 | pa = pci_get_drvdata(pci_dev); |
432 | pci = pa->adapter->pci; | 526 | pci = pa->adapter->pci; |
433 | 527 | ||
528 | /* Disable IRQ generation on DSP side */ | ||
529 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | ||
530 | HPI_ADAPTER_SET_PROPERTY); | ||
531 | hm.adapter_index = pa->adapter->index; | ||
532 | hm.u.ax.property_set.property = HPI_ADAPTER_PROPERTY_IRQ_RATE; | ||
533 | hm.u.ax.property_set.parameter1 = 0; | ||
534 | hm.u.ax.property_set.parameter2 = 0; | ||
535 | hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); | ||
536 | |||
434 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | 537 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, |
435 | HPI_ADAPTER_DELETE); | 538 | HPI_ADAPTER_DELETE); |
436 | hm.adapter_index = pa->adapter->index; | 539 | hm.adapter_index = pa->adapter->index; |
@@ -442,6 +545,9 @@ void asihpi_adapter_remove(struct pci_dev *pci_dev) | |||
442 | iounmap(pci.ap_mem_base[idx]); | 545 | iounmap(pci.ap_mem_base[idx]); |
443 | } | 546 | } |
444 | 547 | ||
548 | if (pa->irq) | ||
549 | free_irq(pa->irq, pa); | ||
550 | |||
445 | if (pa->p_buffer) | 551 | if (pa->p_buffer) |
446 | vfree(pa->p_buffer); | 552 | vfree(pa->p_buffer); |
447 | 553 | ||
diff --git a/sound/pci/asihpi/hpios.h b/sound/pci/asihpi/hpios.h index d17d017940d8..4e383601b9cf 100644 --- a/sound/pci/asihpi/hpios.h +++ b/sound/pci/asihpi/hpios.h | |||
@@ -151,6 +151,10 @@ struct hpi_adapter { | |||
151 | struct hpi_adapter_obj *adapter; | 151 | struct hpi_adapter_obj *adapter; |
152 | struct snd_card *snd_card; | 152 | struct snd_card *snd_card; |
153 | 153 | ||
154 | int irq; | ||
155 | int interrupt_mode; | ||
156 | void (*interrupt_callback) (struct hpi_adapter *); | ||
157 | |||
154 | /* mutex prevents contention for one card | 158 | /* mutex prevents contention for one card |
155 | between multiple user programs (via ioctl) */ | 159 | between multiple user programs (via ioctl) */ |
156 | struct mutex mutex; | 160 | struct mutex mutex; |