[alsa-devel] [PATCH 5/5] asihpi: add hwdep (experimental)
Add hpi ioctl via hwdep (experimental, disabled by default). Adjust sampleclock control to use new hpi apis.
Signed-off-by: Eliot Blennerhassett <linux@audioscience.com --- diff -r 6def4892d3f5 pci/Kconfig --- a/pci/Kconfig Mon Mar 03 11:05:48 2008 +0100 +++ b/pci/Kconfig Sat Feb 23 20:24:59 2008 +1300 @@ -17,6 +17,7 @@ config SND_ASIHPI depends on SND && X86 select FW_LOADER select SND_PCM + select SND_HWDEP help Say 'Y' or 'M' to include support for AudioScience ASIxxxx soundcards.
diff -r 6def4892d3f5 pci/asihpi/asihpi.c --- a/pci/asihpi/asihpi.c Mon Mar 03 11:05:48 2008 +0100 +++ b/pci/asihpi/asihpi.c Wed Mar 05 21:59:31 2008 +1300 @@ -23,6 +23,9 @@ */ /* >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 @@ -66,19 +69,28 @@ #include <sound/info.h> #include <sound/initval.h> #include <sound/tlv.h> +#include <sound/hwdep.h>
#include "hpi.h"
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; - -module_param_array(index, int, NULL, 0444); +static int enable_hpi_hwdep; + +module_param_array(index, int, NULL, S_IRUGO); MODULE_PARM_DESC(index, "ALSA Index value for AudioScience soundcard."); -module_param_array(id, charp, NULL, 0444); + +module_param_array(id, charp, NULL, S_IRUGO); MODULE_PARM_DESC(id, "ALSA ID string for AudioScience soundcard."); -module_param_array(enable, bool, NULL, 0444); + +module_param_array(enable, bool, NULL, S_IRUGO); 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); @@ -114,6 +126,7 @@ struct clk_source {
struct clk_cache { int count; + int has_local; struct clk_source s[MAX_CLOCKSOURCES]; };
@@ -1602,7 +1615,6 @@ static int __devinit snd_asihpi_aesebu_t snd_control->info = snd_asihpi_aesebu_format_info; snd_control->get = snd_asihpi_aesebu_tx_format_get; snd_control->put = snd_asihpi_aesebu_tx_format_put; - snd_control->index = asihpi_control->wDstNodeIndex + ixb;
asihpi_ctl_name(snd_control, asihpi_control, "Format");
@@ -1909,9 +1921,9 @@ static int log2lin[] = { 6790940, 2147484, /* -60dB */ 679094, - 214748, + 214748, /* -80 */ 67909, - 21475, + 21475, /* -100 */ 6791, 2147, 679, @@ -2153,8 +2165,9 @@ static void __devinit snd_asihpi_cmode_n ------------------------------------------------------------*/
static char *sampleclock_sources[MAX_CLOCKSOURCES] = - { "N/A", "Adapter", "AES/EBU Sync", "Word External", "Word Header", - "SMPTE", "AES/EBU In1", "Auto", "Cobranet", + { "N/A", "Local PLL", "AES/EBU Sync", "Word External", "Word Header", + "SMPTE", "AES/EBU In1", "Auto", "Network", "Invalid", + "Prev Module", "AES/EBU In2", "AES/EBU In3", "AES/EBU In4", "AES/EBU In5", "AES/EBU In6", "AES/EBU In7", "AES/EBU In8"};
@@ -2239,7 +2252,9 @@ static void __devinit snd_asihpi_clksrc_ snd_control->info = snd_asihpi_clksrc_info; snd_control->get = snd_asihpi_clksrc_get; snd_control->put = snd_asihpi_clksrc_put; - asihpi_ctl_name(snd_control, asihpi_control, "ClockSource"); + asihpi_ctl_name(snd_control, asihpi_control, "Source"); + + clkcache->has_local = 0;
for (i = 0; i <= HPI_SAMPLECLOCK_SOURCE_LAST; i++) { if (HPI_ControlQuery(phSubSys, hSC, @@ -2250,6 +2265,8 @@ static void __devinit snd_asihpi_clksrc_ clkcache->s[i].name = sampleclock_sources[wSource]; if (wSource == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT) hasAesIn = 1; + if (wSource == HPI_SAMPLECLOCK_SOURCE_LOCAL) + clkcache->has_local = 1; } if (hasAesIn) /* already will have picked up index 0 above */ @@ -2271,7 +2288,7 @@ static void __devinit snd_asihpi_clksrc_ /*------------------------------------------------------------ Clkrate controls ------------------------------------------------------------*/ -static int snd_asihpi_clkrate_info(struct snd_kcontrol *kcontrol, +static int snd_asihpi_clklocal_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; @@ -2283,18 +2300,18 @@ static int snd_asihpi_clkrate_info(struc return 0; }
-static int snd_asihpi_clkrate_get(struct snd_kcontrol *kcontrol, +static int snd_asihpi_clklocal_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { u32 hControl = kcontrol->private_value; u32 dwRate;
- HPI_SampleClock_GetSampleRate(phSubSys, hControl, &dwRate); + HPI_SampleClock_GetLocalRate(phSubSys, hControl, &dwRate); ucontrol->value.integer.value[0] = dwRate; return 0; }
-static int snd_asihpi_clkrate_put(struct snd_kcontrol *kcontrol, +static int snd_asihpi_clklocal_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int change; @@ -2304,21 +2321,55 @@ static int snd_asihpi_clkrate_put(struct asihpi->mixer_clkrate[addr][1] != right; */ change = 1; - HPI_SampleClock_SetSampleRate(phSubSys, hControl, + HPI_SampleClock_SetLocalRate(phSubSys, hControl, ucontrol->value.integer.value[0]); return change; }
+static void __devinit snd_asihpi_clklocal_new( + struct hpi_control *asihpi_control, + struct snd_kcontrol_new *snd_control) +{ + snd_control->info = snd_asihpi_clklocal_info; + snd_control->get = snd_asihpi_clklocal_get; + snd_control->put = snd_asihpi_clklocal_put; + + asihpi_ctl_name(snd_control, asihpi_control, "LocalRate"); +} + +static int snd_asihpi_clkrate_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 8000; + uinfo->value.integer.max = 192000; + uinfo->value.integer.step = 100; + + return 0; +} + +static int snd_asihpi_clkrate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u32 hControl = kcontrol->private_value; + u32 dwRate; + + HPI_SampleClock_GetSampleRate(phSubSys, hControl, &dwRate); + ucontrol->value.integer.value[0] = dwRate; + return 0; +} + static void __devinit snd_asihpi_clkrate_new(struct hpi_control *asihpi_control, struct snd_kcontrol_new *snd_control) { snd_control->info = snd_asihpi_clkrate_info; snd_control->get = snd_asihpi_clkrate_get; - snd_control->put = snd_asihpi_clkrate_put; + snd_control->access = + SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;
asihpi_ctl_name(snd_control, asihpi_control, "Rate"); } - /*------------------------------------------------------------ Mixer ------------------------------------------------------------*/ @@ -2404,6 +2455,14 @@ static int __devinit snd_card_asihpi_mix return err; snd_asihpi_clkrate_new(&asihpi_control, &snd_control); + err = snd_ctl_add(card, + snd_ctl_new1(&snd_control, asihpi)); + if (err < 0) + return err; + if (asihpi->cc.has_local) + snd_asihpi_clklocal_new(&asihpi_control, + &snd_control); + break; case HPI_CONTROL_CONNECTION: /* ignore these */ continue; @@ -2510,6 +2569,55 @@ static void __devinit snd_asihpi_proc_in }
/*------------------------------------------------------------ + HWDEP + ------------------------------------------------------------*/ + +static int snd_asihpi_hpi_open(struct snd_hwdep * hw, struct file *file) +{ + return 0; +} + +static int snd_asihpi_hpi_release(struct snd_hwdep * hw, struct file *file) +{ + return 0; +} + +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); +} + + +/* 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) +{ + struct snd_hwdep *hw; + int err; + + if (rhwdep) + *rhwdep = NULL; + err = snd_hwdep_new(asihpi->card, "HPI", device, &hw); + if (err < 0) + return err; + strcpy(hw->name, "asihpi (HPI)"); + hw->iface = SNDRV_HWDEP_IFACE_LAST; + hw->ops.open = snd_asihpi_hpi_open; + hw->ops.ioctl = snd_asihpi_hpi_ioctl; + hw->ops.release = snd_asihpi_hpi_release; + hw->private_data = asihpi; + if (rhwdep) + *rhwdep = hw; + return 0; +} + +/*------------------------------------------------------------ CARD ------------------------------------------------------------*/ int __devinit snd_asihpi_bind(struct hpi_adapter *hpi_card) @@ -2602,10 +2710,13 @@ int __devinit snd_asihpi_bind(struct hpi HPI_CONTROL_SAMPLECLOCK, &hControl);
if (!err) - err = HPI_SampleClock_SetSampleRate(phSubSys, + err = HPI_SampleClock_SetLocalRate(phSubSys, hControl, adapter_fs);
snd_asihpi_proc_init(asihpi); + + if (enable_hpi_hwdep) + snd_asihpi_hpi_new(asihpi, 0, NULL);
if (asihpi->support_mmap) strcpy(card->driver, "ASIHPI-MMAP"); diff -r 6def4892d3f5 pci/asihpi/hpimod.c --- a/pci/asihpi/hpimod.c Mon Mar 03 11:05:48 2008 +0100 +++ b/pci/asihpi/hpimod.c Wed Mar 05 21:59:31 2008 +1300 @@ -24,14 +24,10 @@ Linux HPI driver module #include "hpi.h" #include "hpidebug.h" #include "hpimsgx.h" + #include <linux/fs.h> #include <linux/slab.h> #include <linux/moduleparam.h> -#include <linux/pci.h> -#include <linux/device.h> -#include <linux/interrupt.h> -#include <linux/mutex.h> -#include <linux/version.h> #include <asm/uaccess.h> #include <linux/stringify.h>
@@ -167,13 +163,13 @@ static int hpi_release( }
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 11) -static long hpi_ioctl( +long asihpi_hpi_ioctl( struct file *file, unsigned int cmd, unsigned long arg ) #else -static int hpi_ioctl( +static int asihpi_hpi_ioctl( struct inode *inode, struct file *file, unsigned int cmd, @@ -225,8 +221,18 @@ static int hpi_ioctl(
/* -1=no data 0=read from user mem, 1=write to user mem */ int wrflag = -1; - int nAdapter = hm.wAdapterIndex; + u32 nAdapter = hm.wAdapterIndex; switch (hm.wFunction) { + case HPI_SUBSYS_CREATE_ADAPTER: + case HPI_SUBSYS_DELETE_ADAPTER: + /* Application must not use these functions! */ + hr.wSize = sizeof(struct hpi_response_header); + hr.wError = HPI_ERROR_INVALID_OPERATION; + hr.wFunction = hm.wFunction; + uncopied_bytes = copy_to_user(phr, &hr, hr.wSize); + if (uncopied_bytes) + return -EFAULT; + return 0; case HPI_OSTREAM_WRITE: case HPI_ISTREAM_READ: /* Yes, sparse, this is correct. */ @@ -252,60 +258,49 @@ static int hpi_ioctl( break; }
- if ((nAdapter >= HPI_MAX_ADAPTERS || nAdapter < 0) && - (hm.wObject != HPI_OBJ_SUBSYSTEM)) - hr.wError = HPI_ERROR_INVALID_OBJ_INDEX; - else { - if (mutex_lock_interruptible(&adapters[nAdapter]. - mutex)) - return -EINTR; - - if (wrflag == 0) { - if (size > bufsize) { - mutex_unlock(&adapters[nAdapter]. - mutex); - HPI_DEBUG_LOG(ERROR, - "Requested transfer of %d " - "bytes, max buffer size " - "is %d bytes.\n", size, - bufsize); - return -EINVAL; - } - - uncopied_bytes = - copy_from_user(pa->pBuffer, ptr, - size); - if (uncopied_bytes) - HPI_DEBUG_LOG(WARNING, - "Missed %d of %d " - "bytes from user\n", - uncopied_bytes, size); + if (mutex_lock_interruptible(&adapters[nAdapter].mutex)) + return -EINTR; + + if (wrflag == 0) { + if (size > bufsize) { + mutex_unlock(&adapters[nAdapter].mutex); + HPI_DEBUG_LOG(ERROR, + "Requested transfer of %d " + "bytes, max buffer size " + "is %d bytes.\n", size, bufsize); + return -EINVAL; }
- HPI_MessageF(&hm, &hr, file); - - if (wrflag == 1) { - if (size > bufsize) { - mutex_unlock(&adapters[nAdapter]. - mutex); - HPI_DEBUG_LOG(ERROR, - "Requested transfer of %d " - "bytes, max buffer size is " - "%d bytes.\n", size, bufsize); - return -EINVAL; - } - - uncopied_bytes = - copy_to_user(ptr, pa->pBuffer, size); - if (uncopied_bytes) - HPI_DEBUG_LOG(WARNING, - "Missed %d of %d " - "bytes to user\n", - uncopied_bytes, size); + uncopied_bytes = + copy_from_user(pa->pBuffer, ptr, size); + if (uncopied_bytes) + HPI_DEBUG_LOG(WARNING, + "Missed %d of %d " + "bytes from user\n", + uncopied_bytes, size); + } + + HPI_MessageF(&hm, &hr, file); + + if (wrflag == 1) { + if (size > bufsize) { + mutex_unlock(&adapters[nAdapter].mutex); + HPI_DEBUG_LOG(ERROR, + "Requested transfer of %d " + "bytes, max buffer size is " + "%d bytes.\n", size, bufsize); + return -EINVAL; }
- mutex_unlock(&adapters[nAdapter].mutex); + uncopied_bytes = copy_to_user(ptr, pa->pBuffer, size); + if (uncopied_bytes) + HPI_DEBUG_LOG(WARNING, + "Missed %d of %d " + "bytes to user\n", + uncopied_bytes, size); } + + mutex_unlock(&adapters[nAdapter].mutex); }
/* on return response size must be set */ @@ -322,9 +317,9 @@ static struct file_operations hpi_fops = static struct file_operations hpi_fops = { .owner = THIS_MODULE, #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 11) - .unlocked_ioctl = hpi_ioctl, + .unlocked_ioctl = asihpi_hpi_ioctl, #else - .ioctl = hpi_ioctl, + .ioctl = asihpi_hpi_ioctl, #endif .open = hpi_open, .release = hpi_release @@ -399,6 +394,9 @@ static int __devinit adapter_probe(
/* call CreateAdapterObject on the relevant hpi module */ HPI_MessageEx(&hm, &hr, HOWNER_KERNEL); + if (hr.wError) + goto err; + adapter.pBuffer = vmalloc(bufsize); if (adapter.pBuffer == NULL) { HPI_DEBUG_LOG(ERROR, @@ -407,39 +405,37 @@ static int __devinit adapter_probe( goto err; }
- if (hr.wError == 0) { - adapter.index = hr.u.s.wAdapterIndex; - adapter.type = hr.u.s.awAdapterList[adapter.index]; + adapter.index = hr.u.s.wAdapterIndex; + adapter.type = hr.u.s.awAdapterList[adapter.index]; + hm.wAdapterIndex = adapter.index; + + err = HPI_AdapterOpen(NULL, adapter.index); + if (err) + goto err; + + adapter.snd_card_asihpi = NULL; + /* WARNING can't init sem in 'adapter' + * and then copy it to adapters[] ?!?! + */ + adapters[hr.u.s.wAdapterIndex] = adapter; + mutex_init(&adapters[adapter.index].mutex); +#ifdef ALSA_BUILD + if (snd_asihpi_bind(&adapters[adapter.index])) { + HPI_InitMessage(&hm, HPI_OBJ_SUBSYSTEM, + HPI_SUBSYS_DELETE_ADAPTER); hm.wAdapterIndex = adapter.index; - - err = HPI_AdapterOpen(NULL, adapter.index); - if (err) - goto err; - - adapter.snd_card_asihpi = NULL; - /* WARNING can't init sem in 'adapter' - * and then copy it to adapters[] ?!?! - */ - adapters[hr.u.s.wAdapterIndex] = adapter; - mutex_init(&adapters[adapter.index].mutex); -#ifdef ALSA_BUILD - if (snd_asihpi_bind(&adapters[adapter.index])) { - HPI_InitMessage(&hm, HPI_OBJ_SUBSYSTEM, - HPI_SUBSYS_DELETE_ADAPTER); - hm.wAdapterIndex = adapter.index; - HPI_MessageEx(&hm, &hr, HOWNER_KERNEL); - goto err; - } -#endif - - pci_set_drvdata(pci_dev, &adapters[adapter.index]); - adapter_count++; - - printk(KERN_INFO - "Probe found adapter ASI%04X HPI index #%d.\n", - adapter.type, adapter.index); - return 0; - } + HPI_MessageEx(&hm, &hr, HOWNER_KERNEL); + goto err; + } +#endif + + pci_set_drvdata(pci_dev, &adapters[adapter.index]); + adapter_count++; + + printk(KERN_INFO + "Probe found adapter ASI%04X HPI index #%d.\n", + adapter.type, adapter.index); + return 0;
err: for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; idx++) {
Patch 2/5 is waiting moderator approval (its 90K)
At Thu, 06 Mar 2008 15:07:54 +1300, Eliot Blennerhassett wrote:
Patch 2/5 is waiting moderator approval (its 90K)
Add my address to Cc at the next time so that I get patches directly.
thanks,
Takashi
On 06-03-08 10:50, Takashi Iwai wrote:
At Thu, 06 Mar 2008 15:07:54 +1300, Eliot Blennerhassett wrote:
Patch 2/5 is waiting moderator approval (its 90K)
Add my address to Cc at the next time so that I get patches directly.
I've emailed Jaroslav a number of times asking to up the limit but have as usual seen them disappear into the great perex email blackhole. By now I'm simply rejecting them, asking posters to contact Jaroslav themselves...
The limit's at 60K right now which has been too little for quite a few valid patches. I believe that upto now 200K should mostly do but haven't in fact seen anything being size-moderated which _wasn't_ valid list content -- the size moderation category seems fairly useless to start with therefore.
Rene.
At Thu, 06 Mar 2008 11:05:40 +0100, Rene Herman wrote:
On 06-03-08 10:50, Takashi Iwai wrote:
At Thu, 06 Mar 2008 15:07:54 +1300, Eliot Blennerhassett wrote:
Patch 2/5 is waiting moderator approval (its 90K)
Add my address to Cc at the next time so that I get patches directly.
I've emailed Jaroslav a number of times asking to up the limit but have as usual seen them disappear into the great perex email blackhole. By now I'm simply rejecting them, asking posters to contact Jaroslav themselves...
The limit's at 60K right now which has been too little for quite a few valid patches. I believe that upto now 200K should mostly do but haven't in fact seen anything being size-moderated which _wasn't_ valid list content -- the size moderation category seems fairly useless to start with therefore.
Besides that, in general it's recommended to add relevent developers to Cc's if you post patches. Then patches reach directly to the developers and have more chances to get in more quickly and certainly.
Takashi
On Thu, Mar 06, 2008 at 11:12:58AM +0100, Takashi Iwai wrote:
Besides that, in general it's recommended to add relevent developers to Cc's if you post patches. Then patches reach directly to the developers and have more chances to get in more quickly and certainly.
But note that there are a few subsystem maintainers who don't like this so it's worth looking at what other people submitting patches for the subsystem are doing.
At Thu, 6 Mar 2008 10:17:04 +0000, Mark Brown wrote:
On Thu, Mar 06, 2008 at 11:12:58AM +0100, Takashi Iwai wrote:
Besides that, in general it's recommended to add relevent developers to Cc's if you post patches. Then patches reach directly to the developers and have more chances to get in more quickly and certainly.
But note that there are a few subsystem maintainers who don't like this so it's worth looking at what other people submitting patches for the subsystem are doing.
Yeah there are always exceptions :) But, *in general*, Cc to developers is a good thing.
BTW, this doesn't mean that you don't send patches to ML. The patches should be sent to ML, and Cc to maintainers/developers.
Takashi
participants (4)
-
Eliot Blennerhassett
-
Mark Brown
-
Rene Herman
-
Takashi Iwai