aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/asihpi
diff options
context:
space:
mode:
authorEliot Blennerhassett <eblennerhassett@audioscience.com>2011-04-05 04:55:44 -0400
committerTakashi Iwai <tiwai@suse.de>2011-04-05 05:47:25 -0400
commitf3d145aac913b318e96e5c2763d8908805a5e30a (patch)
tree5a65d135ca0d282e91abffc4f516df494ced118f /sound/pci/asihpi
parent0b7ce9e2bd2d9dbc8f4797b0cd5e0d138cb529e1 (diff)
ALSA: asihpi: MMAP for non-busmaster cards
Allow older non DMA capable cards to use MMAP by emulating the DMA using read and write functions, and getting rid of copy & silence callbacks that were used only by older cards. Signed-off-by: Eliot Blennerhassett <eblennerhassett@audioscience.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/asihpi')
-rw-r--r--sound/pci/asihpi/asihpi.c205
1 files changed, 70 insertions, 135 deletions
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c
index a5226e3af3d7..d5258aa738a1 100644
--- a/sound/pci/asihpi/asihpi.c
+++ b/sound/pci/asihpi/asihpi.c
@@ -42,6 +42,7 @@
42#include <sound/tlv.h> 42#include <sound/tlv.h>
43#include <sound/hwdep.h> 43#include <sound/hwdep.h>
44 44
45
45MODULE_LICENSE("GPL"); 46MODULE_LICENSE("GPL");
46MODULE_AUTHOR("AudioScience inc. <support@audioscience.com>"); 47MODULE_AUTHOR("AudioScience inc. <support@audioscience.com>");
47MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx"); 48MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx");
@@ -146,7 +147,7 @@ struct snd_card_asihpi {
146 u32 h_mixer; 147 u32 h_mixer;
147 struct clk_cache cc; 148 struct clk_cache cc;
148 149
149 u16 support_mmap; 150 u16 can_dma;
150 u16 support_grouping; 151 u16 support_grouping;
151 u16 support_mrx; 152 u16 support_mrx;
152 u16 update_interval_frames; 153 u16 update_interval_frames;
@@ -491,8 +492,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
491 } 492 }
492 493
493 dpcm->hpi_buffer_attached = 0; 494 dpcm->hpi_buffer_attached = 0;
494 if (card->support_mmap) { 495 if (card->can_dma) {
495
496 err = hpi_stream_host_buffer_attach(dpcm->h_stream, 496 err = hpi_stream_host_buffer_attach(dpcm->h_stream,
497 params_buffer_bytes(params), runtime->dma_addr); 497 params_buffer_bytes(params), runtime->dma_addr);
498 if (err == 0) { 498 if (err == 0) {
@@ -594,8 +594,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
594 continue; 594 continue;
595 595
596 ds->drained_count = 0; 596 ds->drained_count = 0;
597 if ((s->stream == SNDRV_PCM_STREAM_PLAYBACK) && 597 if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
598 (card->support_mmap)) {
599 /* How do I know how much valid data is present 598 /* How do I know how much valid data is present
600 * in buffer? Must be at least one period! 599 * in buffer? Must be at least one period!
601 * Guessing 2 periods, but if 600 * Guessing 2 periods, but if
@@ -630,7 +629,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
630 /* start the master stream */ 629 /* start the master stream */
631 snd_card_asihpi_pcm_timer_start(substream); 630 snd_card_asihpi_pcm_timer_start(substream);
632 if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) || 631 if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) ||
633 !card->support_mmap) 632 !card->can_dma)
634 hpi_handle_error(hpi_stream_start(dpcm->h_stream)); 633 hpi_handle_error(hpi_stream_start(dpcm->h_stream));
635 break; 634 break;
636 635
@@ -766,6 +765,9 @@ static void snd_card_asihpi_timer_function(unsigned long data)
766 /* number of bytes in on-card buffer */ 765 /* number of bytes in on-card buffer */
767 runtime->delay = on_card_bytes; 766 runtime->delay = on_card_bytes;
768 767
768 if (!card->can_dma)
769 on_card_bytes = bytes_avail;
770
769 if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) { 771 if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
770 pcm_buf_dma_ofs = ds->pcm_buf_host_rw_ofs - bytes_avail; 772 pcm_buf_dma_ofs = ds->pcm_buf_host_rw_ofs - bytes_avail;
771 if (state == HPI_STATE_STOPPED) { 773 if (state == HPI_STATE_STOPPED) {
@@ -844,30 +846,63 @@ static void snd_card_asihpi_timer_function(unsigned long data)
844 846
845 ds->pcm_buf_dma_ofs = pcm_buf_dma_ofs; 847 ds->pcm_buf_dma_ofs = pcm_buf_dma_ofs;
846 848
847 if (xfercount && (on_card_bytes <= ds->period_bytes)) { 849 if (xfercount &&
848 if (card->support_mmap) { 850 /* Limit use of on card fifo for playback */
849 if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) { 851 ((on_card_bytes <= ds->period_bytes) ||
850 snd_printddd("P%d write x%04x\n", 852 (s->stream == SNDRV_PCM_STREAM_CAPTURE)))
853
854 {
855
856 unsigned int buf_ofs = ds->pcm_buf_host_rw_ofs % ds->buffer_bytes;
857 unsigned int xfer1, xfer2;
858 char *pd = &s->runtime->dma_area[buf_ofs];
859
860 if (card->can_dma) {
861 xfer1 = xfercount;
862 xfer2 = 0;
863 } else {
864 xfer1 = min(xfercount, ds->buffer_bytes - buf_ofs);
865 xfer2 = xfercount - xfer1;
866 }
867
868 if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
869 snd_printddd("P%d write1 0x%04X 0x%04X\n",
870 s->number, xfer1, buf_ofs);
871 hpi_handle_error(
872 hpi_outstream_write_buf(
873 ds->h_stream, pd, xfer1,
874 &ds->format));
875
876 if (xfer2) {
877 pd = s->runtime->dma_area;
878
879 snd_printddd("P%d write2 0x%04X 0x%04X\n",
851 s->number, 880 s->number,
852 ds->period_bytes); 881 xfercount - xfer1, buf_ofs);
853 hpi_handle_error( 882 hpi_handle_error(
854 hpi_outstream_write_buf( 883 hpi_outstream_write_buf(
855 ds->h_stream, 884 ds->h_stream, pd,
856 &s->runtime-> 885 xfercount - xfer1,
857 dma_area[0],
858 xfercount,
859 &ds->format)); 886 &ds->format));
860 } else { 887 }
861 snd_printddd("C%d read x%04x\n", 888 } else {
862 s->number, 889 snd_printddd("C%d read1 0x%04x\n",
863 xfercount); 890 s->number, xfer1);
891 hpi_handle_error(
892 hpi_instream_read_buf(
893 ds->h_stream,
894 pd, xfer1));
895 if (xfer2) {
896 pd = s->runtime->dma_area;
897 snd_printddd("C%d read2 0x%04x\n",
898 s->number, xfer2);
864 hpi_handle_error( 899 hpi_handle_error(
865 hpi_instream_read_buf( 900 hpi_instream_read_buf(
866 ds->h_stream, 901 ds->h_stream,
867 NULL, xfercount)); 902 pd, xfer2));
868 } 903 }
869 ds->pcm_buf_host_rw_ofs = ds->pcm_buf_host_rw_ofs + xfercount; 904 }
870 } /* else R/W will be handled by read/write callbacks */ 905 ds->pcm_buf_host_rw_ofs = ds->pcm_buf_host_rw_ofs + xfercount;
871 ds->pcm_buf_elapsed_dma_ofs = pcm_buf_dma_ofs; 906 ds->pcm_buf_elapsed_dma_ofs = pcm_buf_dma_ofs;
872 snd_pcm_period_elapsed(s); 907 snd_pcm_period_elapsed(s);
873 } 908 }
@@ -1004,11 +1039,9 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
1004 SNDRV_PCM_INFO_DOUBLE | 1039 SNDRV_PCM_INFO_DOUBLE |
1005 SNDRV_PCM_INFO_BATCH | 1040 SNDRV_PCM_INFO_BATCH |
1006 SNDRV_PCM_INFO_BLOCK_TRANSFER | 1041 SNDRV_PCM_INFO_BLOCK_TRANSFER |
1007 SNDRV_PCM_INFO_PAUSE; 1042 SNDRV_PCM_INFO_PAUSE |
1008 1043 SNDRV_PCM_INFO_MMAP |
1009 if (card->support_mmap) 1044 SNDRV_PCM_INFO_MMAP_VALID;
1010 snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_MMAP |
1011 SNDRV_PCM_INFO_MMAP_VALID;
1012 1045
1013 if (card->support_grouping) 1046 if (card->support_grouping)
1014 snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_SYNC_START; 1047 snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_SYNC_START;
@@ -1016,7 +1049,7 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
1016 /* struct is copied, so can create initializer dynamically */ 1049 /* struct is copied, so can create initializer dynamically */
1017 runtime->hw = snd_card_asihpi_playback; 1050 runtime->hw = snd_card_asihpi_playback;
1018 1051
1019 if (card->support_mmap) 1052 if (card->can_dma)
1020 err = snd_pcm_hw_constraint_pow2(runtime, 0, 1053 err = snd_pcm_hw_constraint_pow2(runtime, 0,
1021 SNDRV_PCM_HW_PARAM_BUFFER_BYTES); 1054 SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
1022 if (err < 0) 1055 if (err < 0)
@@ -1046,58 +1079,6 @@ static int snd_card_asihpi_playback_close(struct snd_pcm_substream *substream)
1046 return 0; 1079 return 0;
1047} 1080}
1048 1081
1049static int snd_card_asihpi_playback_copy(struct snd_pcm_substream *substream,
1050 int channel,
1051 snd_pcm_uframes_t pos,
1052 void __user *src,
1053 snd_pcm_uframes_t count)
1054{
1055 struct snd_pcm_runtime *runtime = substream->runtime;
1056 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
1057 unsigned int len;
1058
1059 len = frames_to_bytes(runtime, count);
1060
1061 if (copy_from_user(runtime->dma_area, src, len))
1062 return -EFAULT;
1063
1064 snd_printddd("playback copy%d %u bytes\n",
1065 substream->number, len);
1066
1067 hpi_handle_error(hpi_outstream_write_buf(dpcm->h_stream,
1068 runtime->dma_area, len, &dpcm->format));
1069
1070 dpcm->pcm_buf_host_rw_ofs += len;
1071
1072 return 0;
1073}
1074
1075static int snd_card_asihpi_playback_silence(struct snd_pcm_substream *
1076 substream, int channel,
1077 snd_pcm_uframes_t pos,
1078 snd_pcm_uframes_t count)
1079{
1080 /* Usually writes silence to DMA buffer, which should be overwritten
1081 by real audio later. Our fifos cannot be overwritten, and are not
1082 free-running DMAs. Silence is output on fifo underflow.
1083 This callback is still required to allow the copy callback to be used.
1084 */
1085 return 0;
1086}
1087
1088static struct snd_pcm_ops snd_card_asihpi_playback_ops = {
1089 .open = snd_card_asihpi_playback_open,
1090 .close = snd_card_asihpi_playback_close,
1091 .ioctl = snd_card_asihpi_playback_ioctl,
1092 .hw_params = snd_card_asihpi_pcm_hw_params,
1093 .hw_free = snd_card_asihpi_hw_free,
1094 .prepare = snd_card_asihpi_playback_prepare,
1095 .trigger = snd_card_asihpi_trigger,
1096 .pointer = snd_card_asihpi_playback_pointer,
1097 .copy = snd_card_asihpi_playback_copy,
1098 .silence = snd_card_asihpi_playback_silence,
1099};
1100
1101static struct snd_pcm_ops snd_card_asihpi_playback_mmap_ops = { 1082static struct snd_pcm_ops snd_card_asihpi_playback_mmap_ops = {
1102 .open = snd_card_asihpi_playback_open, 1083 .open = snd_card_asihpi_playback_open,
1103 .close = snd_card_asihpi_playback_close, 1084 .close = snd_card_asihpi_playback_close,
@@ -1229,18 +1210,16 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream)
1229 snd_card_asihpi_capture_format(card, dpcm->h_stream, 1210 snd_card_asihpi_capture_format(card, dpcm->h_stream,
1230 &snd_card_asihpi_capture); 1211 &snd_card_asihpi_capture);
1231 snd_card_asihpi_pcm_samplerates(card, &snd_card_asihpi_capture); 1212 snd_card_asihpi_pcm_samplerates(card, &snd_card_asihpi_capture);
1232 snd_card_asihpi_capture.info = SNDRV_PCM_INFO_INTERLEAVED; 1213 snd_card_asihpi_capture.info = SNDRV_PCM_INFO_INTERLEAVED |
1233 1214 SNDRV_PCM_INFO_MMAP |
1234 if (card->support_mmap) 1215 SNDRV_PCM_INFO_MMAP_VALID;
1235 snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_MMAP |
1236 SNDRV_PCM_INFO_MMAP_VALID;
1237 1216
1238 if (card->support_grouping) 1217 if (card->support_grouping)
1239 snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_SYNC_START; 1218 snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_SYNC_START;
1240 1219
1241 runtime->hw = snd_card_asihpi_capture; 1220 runtime->hw = snd_card_asihpi_capture;
1242 1221
1243 if (card->support_mmap) 1222 if (card->can_dma)
1244 err = snd_pcm_hw_constraint_pow2(runtime, 0, 1223 err = snd_pcm_hw_constraint_pow2(runtime, 0,
1245 SNDRV_PCM_HW_PARAM_BUFFER_BYTES); 1224 SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
1246 if (err < 0) 1225 if (err < 0)
@@ -1264,28 +1243,6 @@ static int snd_card_asihpi_capture_close(struct snd_pcm_substream *substream)
1264 return 0; 1243 return 0;
1265} 1244}
1266 1245
1267static int snd_card_asihpi_capture_copy(struct snd_pcm_substream *substream,
1268 int channel, snd_pcm_uframes_t pos,
1269 void __user *dst, snd_pcm_uframes_t count)
1270{
1271 struct snd_pcm_runtime *runtime = substream->runtime;
1272 struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
1273 u32 len;
1274
1275 len = frames_to_bytes(runtime, count);
1276
1277 snd_printddd("capture copy%d %d bytes\n", substream->number, len);
1278 hpi_handle_error(hpi_instream_read_buf(dpcm->h_stream,
1279 runtime->dma_area, len));
1280
1281 dpcm->pcm_buf_host_rw_ofs = dpcm->pcm_buf_host_rw_ofs + len;
1282
1283 if (copy_to_user(dst, runtime->dma_area, len))
1284 return -EFAULT;
1285
1286 return 0;
1287}
1288
1289static struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = { 1246static struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = {
1290 .open = snd_card_asihpi_capture_open, 1247 .open = snd_card_asihpi_capture_open,
1291 .close = snd_card_asihpi_capture_close, 1248 .close = snd_card_asihpi_capture_close,
@@ -1297,18 +1254,6 @@ static struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = {
1297 .pointer = snd_card_asihpi_capture_pointer, 1254 .pointer = snd_card_asihpi_capture_pointer,
1298}; 1255};
1299 1256
1300static struct snd_pcm_ops snd_card_asihpi_capture_ops = {
1301 .open = snd_card_asihpi_capture_open,
1302 .close = snd_card_asihpi_capture_close,
1303 .ioctl = snd_card_asihpi_capture_ioctl,
1304 .hw_params = snd_card_asihpi_pcm_hw_params,
1305 .hw_free = snd_card_asihpi_hw_free,
1306 .prepare = snd_card_asihpi_capture_prepare,
1307 .trigger = snd_card_asihpi_trigger,
1308 .pointer = snd_card_asihpi_capture_pointer,
1309 .copy = snd_card_asihpi_capture_copy
1310};
1311
1312static int __devinit snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi, 1257static int __devinit snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi,
1313 int device, int substreams) 1258 int device, int substreams)
1314{ 1259{
@@ -1321,17 +1266,10 @@ static int __devinit snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi,
1321 if (err < 0) 1266 if (err < 0)
1322 return err; 1267 return err;
1323 /* pointer to ops struct is stored, dont change ops afterwards! */ 1268 /* pointer to ops struct is stored, dont change ops afterwards! */
1324 if (asihpi->support_mmap) {
1325 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, 1269 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1326 &snd_card_asihpi_playback_mmap_ops); 1270 &snd_card_asihpi_playback_mmap_ops);
1327 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, 1271 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
1328 &snd_card_asihpi_capture_mmap_ops); 1272 &snd_card_asihpi_capture_mmap_ops);
1329 } else {
1330 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1331 &snd_card_asihpi_playback_ops);
1332 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
1333 &snd_card_asihpi_capture_ops);
1334 }
1335 1273
1336 pcm->private_data = asihpi; 1274 pcm->private_data = asihpi;
1337 pcm->info_flags = 0; 1275 pcm->info_flags = 0;
@@ -2895,14 +2833,14 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
2895 if (err) 2833 if (err)
2896 asihpi->update_interval_frames = 512; 2834 asihpi->update_interval_frames = 512;
2897 2835
2898 if (!asihpi->support_mmap) 2836 if (!asihpi->can_dma)
2899 asihpi->update_interval_frames *= 2; 2837 asihpi->update_interval_frames *= 2;
2900 2838
2901 hpi_handle_error(hpi_instream_open(asihpi->adapter_index, 2839 hpi_handle_error(hpi_instream_open(asihpi->adapter_index,
2902 0, &h_stream)); 2840 0, &h_stream));
2903 2841
2904 err = hpi_instream_host_buffer_free(h_stream); 2842 err = hpi_instream_host_buffer_free(h_stream);
2905 asihpi->support_mmap = (!err); 2843 asihpi->can_dma = (!err);
2906 2844
2907 hpi_handle_error(hpi_instream_close(h_stream)); 2845 hpi_handle_error(hpi_instream_close(h_stream));
2908 2846
@@ -2914,8 +2852,8 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
2914 asihpi->out_max_chans = 2; 2852 asihpi->out_max_chans = 2;
2915 } 2853 }
2916 2854
2917 snd_printk(KERN_INFO "supports mmap:%d grouping:%d mrx:%d\n", 2855 snd_printk(KERN_INFO "has dma:%d, grouping:%d, mrx:%d\n",
2918 asihpi->support_mmap, 2856 asihpi->can_dma,
2919 asihpi->support_grouping, 2857 asihpi->support_grouping,
2920 asihpi->support_mrx 2858 asihpi->support_mrx
2921 ); 2859 );
@@ -2945,10 +2883,7 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
2945 by enable_hwdep module param*/ 2883 by enable_hwdep module param*/
2946 snd_asihpi_hpi_new(asihpi, 0, NULL); 2884 snd_asihpi_hpi_new(asihpi, 0, NULL);
2947 2885
2948 if (asihpi->support_mmap) 2886 strcpy(card->driver, "ASIHPI");
2949 strcpy(card->driver, "ASIHPI-MMAP");
2950 else
2951 strcpy(card->driver, "ASIHPI");
2952 2887
2953 sprintf(card->shortname, "AudioScience ASI%4X", asihpi->type); 2888 sprintf(card->shortname, "AudioScience ASI%4X", asihpi->type);
2954 sprintf(card->longname, "%s %i", 2889 sprintf(card->longname, "%s %i",