aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/asihpi
diff options
context:
space:
mode:
authorEliot Blennerhassett <eliot@blennerhassett.gen.nz>2014-11-19 22:22:53 -0500
committerTakashi Iwai <tiwai@suse.de>2014-11-22 16:33:13 -0500
commitf9a376c3f6d77e59d41350901b2bafbaf8791df0 (patch)
treeb97b1b78966dba5ac3194558d779ca1840f10304 /sound/pci/asihpi
parentc1464a885444dd7e9c4491177ee102b64adc46c5 (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.c177
-rw-r--r--sound/pci/asihpi/hpi6205.c43
-rw-r--r--sound/pci/asihpi/hpi_internal.h4
-rw-r--r--sound/pci/asihpi/hpicmn.h19
-rw-r--r--sound/pci/asihpi/hpioctl.c124
-rw-r--r--sound/pci/asihpi/hpios.h4
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
557static 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
577static 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
547static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, 599static 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
947static 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
959static 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 ****************/
892static int snd_card_asihpi_playback_ioctl(struct snd_pcm_substream *substream, 969static 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
1107static u64 snd_card_asihpi_capture_formats(struct snd_card_asihpi *asihpi, 1191static 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,
2444static int snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi, 2538static 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:
2914static void snd_asihpi_remove(struct pci_dev *pci_dev) 3023static 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
164static void delete_adapter_obj(struct hpi_adapter_obj *pao); 164static void delete_adapter_obj(struct hpi_adapter_obj *pao);
165 165
166static int adapter_irq_query_and_clear(struct hpi_adapter_obj *pao,
167 u32 message);
168
166static void outstream_host_buffer_allocate(struct hpi_adapter_obj *pao, 169static 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 */
724static 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 @@
21struct hpi_adapter_obj; 21struct 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 */
24typedef int adapter_int_func(struct hpi_adapter_obj *pao); 24typedef 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
26struct hpi_adapter_obj { 30struct 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
38struct hpi_control_cache { 45struct hpi_control_cache {
@@ -55,13 +62,21 @@ void hpi_delete_adapter(struct hpi_adapter_obj *pao);
55 62
56short hpi_check_control_cache(struct hpi_control_cache *pC, 63short 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
66short hpi_check_control_cache_single(struct hpi_control_cache_single *pC,
67 struct hpi_message *phm, struct hpi_response *phr);
68
58struct hpi_control_cache *hpi_alloc_control_cache(const u32 69struct 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
60void hpi_free_control_cache(struct hpi_control_cache *p_cache); 72void hpi_free_control_cache(struct hpi_control_cache *p_cache);
61 73
62void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *pC, 74void 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
77void hpi_cmn_control_cache_sync_to_msg_single(struct hpi_control_cache_single
78 *pC, struct hpi_message *phm, struct hpi_response *phr);
79
65u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr); 80u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr);
66 81
67hpi_handler_func HPI_COMMON; 82hpi_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
19Common 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
307static int asihpi_irq_count;
308
309static 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
310int asihpi_adapter_probe(struct pci_dev *pci_dev, 335int 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;