From: Eliot Blennerhassett linux@audioscience.com
Signed-off-by: Eliot Blennerhassett eblennerhassett@audioscience.com
diff --git a/pci/asihpi/asihpi.c b/pci/asihpi/asihpi.c index 538c771..3ffc47b 100644 --- a/pci/asihpi/asihpi.c +++ b/pci/asihpi/asihpi.c @@ -24,9 +24,6 @@ /* >0: print Hw params, timer vars. >1: print stream write/copy sizes */ #define REALLY_VERBOSE_LOGGING 0
-/* Experimental HPI hwdep interface */ -#define EXPERIMENTAL_HWDEP 0 - #if REALLY_VERBOSE_LOGGING #define VPRINTK1 printk #else @@ -50,7 +47,14 @@ #define ASI_STYLE_NAMES 1 #endif
+#ifndef KERNEL_ALSA_BUILD +/* building in ALSA source tree */ #include "adriver.h" +#else +/* building in kernel tree */ +#include <sound/driver.h> +#endif + #include <linux/pci.h> #include <linux/version.h> #include <linux/init.h> @@ -68,11 +72,16 @@ #include <sound/hwdep.h>
#include "hpi.h" +#include "hpioctl.h" + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("AudioScience Inc. support@audioscience.com"); +MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; -static int enable_hpi_hwdep; +static int enable_hpi_hwdep = 1;
module_param_array(index, int, NULL, S_IRUGO); MODULE_PARM_DESC(index, "ALSA Index value for AudioScience soundcard."); @@ -85,15 +94,18 @@ MODULE_PARM_DESC(enable, "ALSA Enable AudioScience soundcard.");
module_param(enable_hpi_hwdep, bool, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(enable_hpi_hwdep, - "ALSA Enable HPI hwdep for AudioScience soundcard " - "(experimental)"); - -/* used by hpimod.c, stop sparse from complaining */ -int snd_asihpi_bind(struct hpi_adapter *hpi_card); -void snd_asihpi_unbind(struct hpi_adapter *hpi_card); + "ALSA Enable HPI hwdep for AudioScience soundcard ");
-/* index base 0 or 1 for control names or indices */ -static const int ixb; +/* identify driver */ +#ifdef KERNEL_ALSA_BUILD +static char * build_info = "Built using headers from kernel source"; +module_param(build_info, charp, S_IRUGO); +MODULE_PARM_DESC(build_info, "Built using headers from kernel source"); +#else +static char * build_info = "Built within ALSA source"; +module_param(build_info, charp, S_IRUGO); +MODULE_PARM_DESC(build_info, "Built within ALSA source"); +#endif
/* set to 1 to dump every control from adapter to log */ static const int mixer_dump; @@ -142,6 +154,7 @@ struct snd_card_asihpi {
int support_mmap; int support_grouping; + int support_mrx; };
/* Per stream data */ @@ -352,6 +365,89 @@ static int snd_card_asihpi_format_alsa2hpi(snd_pcm_format_t alsaFormat, return -EINVAL; }
+static void snd_card_asihpi_pcm_samplerates(struct snd_card_asihpi *asihpi, + struct snd_pcm_hardware *pcmhw) +{ + u16 err; + u32 hControl; + u32 sampleRate; + int idx; + unsigned int rate_min = 200000; + unsigned int rate_max = 0; + unsigned int rates = 0; + + if (asihpi->support_mrx) { + rates |= SNDRV_PCM_RATE_CONTINUOUS; + rates |= SNDRV_PCM_RATE_8000_96000; + rate_min = 8000; + rate_max = 100000; + } else { + /* on cards without SRC, valid rates are determined by sampleclock */ + err = HPI_MixerGetControl(phSubSys, asihpi->hMixer, + HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0, + HPI_CONTROL_SAMPLECLOCK, &hControl); + + for (idx=0; idx<100; idx++) { + if (HPI_ControlQuery(phSubSys, hControl, HPI_SAMPLECLOCK_SAMPLERATE, + idx, 0, &sampleRate)) + break; + + rate_min = min(rate_min, sampleRate); + rate_max = max(rate_max, sampleRate); + + switch (sampleRate) { + case 5512: + rates |= SNDRV_PCM_RATE_5512; + break; + case 8000: + rates |= SNDRV_PCM_RATE_8000; + break; + case 11025: + rates |= SNDRV_PCM_RATE_11025; + break; + case 16000: + rates |= SNDRV_PCM_RATE_16000; + break; + case 22050: + rates |= SNDRV_PCM_RATE_22050; + break; + case 32000: + rates |= SNDRV_PCM_RATE_32000; + break; + case 44100: + rates |= SNDRV_PCM_RATE_44100; + break; + case 48000: + rates |= SNDRV_PCM_RATE_48000; + break; + case 64000: + rates |= SNDRV_PCM_RATE_64000; + break; + case 88200: + rates |= SNDRV_PCM_RATE_88200; + break; + case 96000: + rates |= SNDRV_PCM_RATE_96000; + break; + case 176400: + rates |= SNDRV_PCM_RATE_176400; + break; + case 192000: + rates |= SNDRV_PCM_RATE_192000; + break; + default: /* some other rate */ + rates |= SNDRV_PCM_RATE_KNOT; + } + } + } + + /*printk(KERN_INFO "Supported rates %X %d %d\n", rates, rate_min, rate_max); */ + pcmhw->rates = rates; + pcmhw->rate_min = rate_min; + pcmhw->rate_max = rate_max; + +} + static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -784,7 +880,7 @@ snd_card_asihpi_playback_pointer(struct snd_pcm_substream *substream)
static void snd_card_asihpi_playback_format(struct snd_card_asihpi *asihpi, u32 hStream, - u64 *formats) + struct snd_pcm_hardware * pcmhw) { struct hpi_format hpi_format; u16 wFormat; @@ -810,7 +906,7 @@ static void snd_card_asihpi_playback_format(struct snd_card_asihpi *asihpi, err = HPI_OutStreamQueryFormat(phSubSys, hStream, &hpi_format); if (!err && (hpi_to_alsa_formats[wFormat] != -1)) - *formats |= (1ULL << hpi_to_alsa_formats[wFormat]); + pcmhw->formats |= (1ULL << hpi_to_alsa_formats[wFormat]); } }
@@ -860,11 +956,10 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream) runtime->private_free = snd_card_asihpi_runtime_free;
snd_card_asihpi_playback_format(card, dpcm->hStream, - &snd_card_asihpi_playback.formats); - snd_card_asihpi_playback.rates = SNDRV_PCM_RATE_CONTINUOUS | - SNDRV_PCM_RATE_8000_192000; - snd_card_asihpi_playback.rate_min = 5500; - snd_card_asihpi_playback.rate_max = 192000; + &snd_card_asihpi_playback); + + snd_card_asihpi_pcm_samplerates(card, &snd_card_asihpi_playback); + snd_card_asihpi_playback.info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE;
@@ -1006,12 +1101,13 @@ static int snd_card_asihpi_capture_prepare(struct snd_pcm_substream *substream)
static void snd_card_asihpi_capture_format(struct snd_card_asihpi *asihpi, u32 hStream, - u64 *formats) + struct snd_pcm_hardware *pcmhw) { struct hpi_format hpi_format; u16 wFormat; u16 err; u32 hControl; + u32 dwSampleRate = 48000;
/* on cards without SRC, must query at valid rate, maybe set by external sync */ @@ -1021,20 +1117,21 @@ static void snd_card_asihpi_capture_format(struct snd_card_asihpi *asihpi,
if (!err) err = HPI_SampleClock_GetSampleRate(phSubSys, hControl, - &hpi_format.dwSampleRate); + &dwSampleRate);
for (wFormat = HPI_FORMAT_PCM8_UNSIGNED; wFormat <= HPI_FORMAT_PCM24_SIGNED; wFormat++) {
- HPI_FormatCreate(&hpi_format, 2, wFormat, 48000, 128000, 0); + HPI_FormatCreate(&hpi_format, 2, wFormat, dwSampleRate, 128000, 0); err = HPI_InStreamQueryFormat(phSubSys, hStream, &hpi_format); if (!err) - *formats |= (1ULL << hpi_to_alsa_formats[wFormat]); + pcmhw->formats |= (1ULL << hpi_to_alsa_formats[wFormat]); } }
+ static struct snd_pcm_hardware snd_card_asihpi_capture = { .channels_min = 1, .channels_max = 2, @@ -1079,12 +1176,11 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream) runtime->private_free = snd_card_asihpi_runtime_free;
snd_card_asihpi_capture_format(card, dpcm->hStream, - &snd_card_asihpi_capture.formats); - snd_card_asihpi_capture.rates = SNDRV_PCM_RATE_CONTINUOUS | - SNDRV_PCM_RATE_8000_192000; - snd_card_asihpi_capture.rate_min = 5500; - snd_card_asihpi_capture.rate_max = 192000; + &snd_card_asihpi_capture); + + snd_card_asihpi_pcm_samplerates(card, &snd_card_asihpi_capture); snd_card_asihpi_capture.info = SNDRV_PCM_INFO_INTERLEAVED; + if (card->support_mmap) snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID; @@ -1300,50 +1396,29 @@ static inline int ctl_add(struct snd_card *card, struct snd_kcontrol_new *ctl, return 0; }
+/* Convert HPI control name and location into ALSA control name */ static void asihpi_ctl_name(struct snd_kcontrol_new *snd_control, struct hpi_control *asihpi_control, char *name) { -#if 1 -/* entire control ID is a string */ if (asihpi_control->wSrcNodeType && asihpi_control->wDstNodeType) sprintf(snd_control->name, "%s%d to %s%d %s", asihpi_src_names[asihpi_control->wSrcNodeType], - asihpi_control->wSrcNodeIndex + ixb, + asihpi_control->wSrcNodeIndex, asihpi_dst_names[asihpi_control->wDstNodeType], - asihpi_control->wDstNodeIndex + ixb, + asihpi_control->wDstNodeIndex, name); else if (asihpi_control->wDstNodeType) { sprintf(snd_control->name, "%s%d %s", asihpi_dst_names[asihpi_control->wDstNodeType], - asihpi_control->wDstNodeIndex + ixb, + asihpi_control->wDstNodeIndex, name); } else { sprintf(snd_control->name, "%s%d %s", asihpi_src_names[asihpi_control->wSrcNodeType], - asihpi_control->wSrcNodeIndex + ixb, + asihpi_control->wSrcNodeIndex, name); } -#else -/* use string plus index of destination or only node */ - snd_control->index = asihpi_control->wDstNodeIndex + ixb; - if (asihpi_control->wSrcNodeType && asihpi_control->wDstNodeType) - sprintf(snd_control->name, "%s%d to %s %s", - asihpi_src_names[asihpi_control->wSrcNodeType], - asihpi_control->wSrcNodeIndex + ixb, - asihpi_dst_names[asihpi_control->wDstNodeType], - name); - else if (asihpi_control->wDstNodeType) - sprintf(snd_control->name, "%s %s", - asihpi_dst_names[asihpi_control->wDstNodeType], - name); - else { - sprintf(snd_control->name, "%s %s", - asihpi_src_names[asihpi_control->wSrcNodeType], - name); - snd_control->index = asihpi_control->wSrcNodeIndex + ixb; - } -#endif }
/*------------------------------------------------------------ @@ -2041,7 +2116,7 @@ static int snd_asihpi_mux_info(struct snd_kcontrol *kcontrol,
sprintf(uinfo->value.enumerated.name, "%s %d", asihpi_src_names[wSrcNodeType - HPI_SOURCENODE_BASE], - wSrcNodeIndex + ixb); + wSrcNodeIndex); return 0; }
@@ -2201,15 +2276,16 @@ static int snd_asihpi_clksrc_get(struct snd_kcontrol *kcontrol, (struct snd_card_asihpi *)(kcontrol->private_data); struct clk_cache *clkcache = &asihpi->cc; u32 hControl = kcontrol->private_value; - u16 wSource, wIndex; + u16 wSource, wIndex = 0; int i;
ucontrol->value.enumerated.item[0] = 0; - /*Get current clock source, return "N/A" if an error occurs*/ if (HPI_SampleClock_GetSource(phSubSys, hControl, &wSource)) wSource = 0; - if (HPI_SampleClock_GetSourceIndex(phSubSys, hControl, &wIndex)) - wIndex = 0; + + if (wSource == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT) + if (HPI_SampleClock_GetSourceIndex(phSubSys, hControl, &wIndex)) + wIndex = 0;
for (i = 0; i < clkcache->count; i++) if ((clkcache->s[i].source == wSource) && @@ -2290,6 +2366,7 @@ static void __devinit snd_asihpi_clksrc_new(struct snd_card_asihpi *asihpi, /*------------------------------------------------------------ Clkrate controls ------------------------------------------------------------*/ +/* Need to change this to enumerated control with list of rates */ static int snd_asihpi_clklocal_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -2335,6 +2412,8 @@ static void __devinit snd_asihpi_clklocal_new( snd_control->info = snd_asihpi_clklocal_info; snd_control->get = snd_asihpi_clklocal_get; snd_control->put = snd_asihpi_clklocal_put; + snd_control->access = SNDRV_CTL_ELEM_ACCESS_READWRITE ; +
asihpi_ctl_name(snd_control, asihpi_control, "LocalRate"); } @@ -2425,9 +2504,7 @@ static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi) asihpi_control.wDstNodeType -= HPI_DESTNODE_BASE; snd_control.index = 0; snd_control.private_value = hControl; - snd_control.access = - SNDRV_CTL_ELEM_ACCESS_WRITE | - SNDRV_CTL_ELEM_ACCESS_READ; + snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE ; switch (asihpi_control.wControlType) { case HPI_CONTROL_VOLUME: snd_asihpi_volume_new(&asihpi_control, @@ -2576,29 +2653,36 @@ static void __devinit snd_asihpi_proc_init(struct snd_card_asihpi *asihpi)
static int snd_asihpi_hpi_open(struct snd_hwdep *hw, struct file *file) { - return 0; + if (enable_hpi_hwdep) + return 0; + else + return -ENODEV; + }
static int snd_asihpi_hpi_release(struct snd_hwdep *hw, struct file *file) { - return 0; + if (enable_hpi_hwdep) + return asihpi_hpi_release(file); + else + return -ENODEV; }
-long asihpi_hpi_ioctl(struct file *file, - unsigned int cmd, unsigned long arg); - static int snd_asihpi_hpi_ioctl(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg) { - return asihpi_hpi_ioctl(file, cmd, arg); + if (enable_hpi_hwdep) + return asihpi_hpi_ioctl(file, cmd, arg); + else + return -ENODEV; }
/* results in /dev/snd/hwC#D0 file for each card with index # also /proc/asound/hwdep will contain '#-00: asihpi (HPI) for each card' */ -int __devinit snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi, int device, - struct snd_hwdep **rhwdep) +static int __devinit snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi, + int device, struct snd_hwdep **rhwdep) { struct snd_hwdep *hw; int err; @@ -2622,13 +2706,15 @@ int __devinit snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi, int device, /*------------------------------------------------------------ CARD ------------------------------------------------------------*/ -int __devinit snd_asihpi_bind(struct hpi_adapter *hpi_card) +int __devinit snd_asihpi_probe(struct pci_dev *pci_dev, + const struct pci_device_id *pci_id) { int err;
u16 wVersion; int pcm_substreams;
+ struct hpi_adapter *hpi_card; struct snd_card *card; struct snd_card_asihpi *asihpi;
@@ -2645,6 +2731,12 @@ int __devinit snd_asihpi_bind(struct hpi_adapter *hpi_card) return -ENOENT; }
+ err = asihpi_adapter_probe(pci_dev, pci_id); + if (err < 0) + return err; + + hpi_card = pci_get_drvdata(pci_dev); + /* first try to give the card the same index as its hardware index */ card = snd_card_new(hpi_card->index, id[hpi_card->index], THIS_MODULE, @@ -2672,8 +2764,9 @@ int __devinit snd_asihpi_bind(struct hpi_adapter *hpi_card) &asihpi->wNumInStreams, &asihpi->wVersion, &asihpi->dwSerialNumber, &asihpi->wType)); + wVersion = asihpi->wVersion; - snd_printk(KERN_INFO "Adapter ID=%4X Index=%d NumOutStreams=%d" + snd_printk(KERN_INFO "Adapter ID=%4X Index=%d NumOutStreams=%d " "NumInStreams=%d S/N=%d\n" "Hw Version %c%d DSP code version %03d\n", asihpi->wType, asihpi->wAdapterIndex, @@ -2695,6 +2788,11 @@ int __devinit snd_asihpi_bind(struct hpi_adapter *hpi_card)
err = HPI_InStreamHostBufferFree(phSubSys, hStream); asihpi->support_mmap = (!err); + + asihpi->support_mrx = (((asihpi->wType & 0xFF00) == 0x8900) || + ((asihpi->wType & 0xF000) == 0x6000)); + + printk(KERN_INFO "Supports mmap:%d grouping:%d\n", asihpi->support_mmap, asihpi->support_grouping);
@@ -2717,8 +2815,9 @@ int __devinit snd_asihpi_bind(struct hpi_adapter *hpi_card)
snd_asihpi_proc_init(asihpi);
- if (enable_hpi_hwdep) - snd_asihpi_hpi_new(asihpi, 0, NULL); + /* always create, can be enabled or disabled dynamically + by enable_hwdep module param*/ + snd_asihpi_hpi_new(asihpi, 0, NULL);
if (asihpi->support_mmap) strcpy(card->driver, "ASIHPI-MMAP"); @@ -2727,7 +2826,7 @@ int __devinit snd_asihpi_bind(struct hpi_adapter *hpi_card)
sprintf(card->shortname, "AudioScience ASI%4X", asihpi->wType); sprintf(card->longname, "%s %i", - card->shortname, asihpi->wAdapterIndex + ixb); + card->shortname, asihpi->wAdapterIndex); err = snd_card_register(card); if (!err) { hpi_card->snd_card_asihpi = card; @@ -2740,8 +2839,50 @@ __nodev:
}
-void snd_asihpi_unbind(struct hpi_adapter *hpi_card) +static void __devexit snd_asihpi_remove(struct pci_dev *pci_dev) { + struct hpi_adapter *hpi_card = pci_get_drvdata(pci_dev); + snd_card_free(hpi_card->snd_card_asihpi); hpi_card->snd_card_asihpi = NULL; + asihpi_adapter_remove(pci_dev); +} + +struct pci_device_id asihpi_pci_tbl[] = { + {HPI_PCI_VENDOR_ID_TI, HPI_ADAPTER_DSP6205, + HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0, + (kernel_ulong_t)HPI_6205}, + {HPI_PCI_VENDOR_ID_TI, HPI_ADAPTER_PCI2040, + HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0, + (kernel_ulong_t)HPI_6000}, + {0,} +}; +MODULE_DEVICE_TABLE(pci, asihpi_pci_tbl); + +static struct pci_driver driver = { + .name = "asihpi", + .id_table = asihpi_pci_tbl, + .probe = snd_asihpi_probe, + .remove = __devexit_p(snd_asihpi_remove), +#ifdef CONFIG_PM +/* .suspend = snd_asihpi_suspend, + .resume = snd_asihpi_resume, */ +#endif +}; + +static int __init snd_asihpi_init(void) +{ + asihpi_init(); + return pci_register_driver(&driver); } + +static void __exit snd_asihpi_exit(void) +{ + + pci_unregister_driver(&driver); + asihpi_exit(); +} + +module_init(snd_asihpi_init) +module_exit(snd_asihpi_exit) +