[linux-audio-dev] Sending USB msgs to sound card through snd_usb_audio driver - how ?

Clemens Ladisch clemens at ladisch.de
Thu Jun 9 08:33:53 UTC 2005


Jan Holst Jensen wrote:
> --- Clemens Ladisch <clemens at ladisch.de> wrote:
> > > Are there any standard ioctl() calls in the
> >
> > No, but this would be a very good idea for testing
> > purposes.  I'll add a hwdep device for this.
>
> Great. Looking forward to that. But until then, my
> best shot is hacking the driver I guess... ?

This _is_ hacking the driver.  :-)

> Any idea what happens in Windows ? Doesn't seem like
> the device is locked by the driver in that OS (?).

It is, but usually the driver provides ioctls to allow applications to
change some settings.


The patch adds an hwdep device that provides a USBDEVFS_CONTROL ioctl
that should work identical to that from <linux/usbdevice_fs.h>, except
that you need root privileges to use it.

The patch is against the CVS version of ALSA.  Both the driver and
alsa-lib need to be recompiled.

To access the device, use snd_hwdep_open() and snd_hwdep_ioctl(). The
device name is "hw:X,1" where X is the card number.


HTH
Clemens
-------------- next part --------------


Index: alsa/alsa-kernel/include/asound.h
===================================================================
--- alsa.orig/alsa-kernel/include/asound.h	2005-05-17 10:04:16.000000000 +0200
+++ alsa/alsa-kernel/include/asound.h	2005-06-08 22:30:47.000000000 +0200
@@ -114,9 +114,10 @@ enum sndrv_hwdep_iface {
 	SNDRV_HWDEP_IFACE_USX2Y_PCM,	/* Tascam US122, US224 & US428 rawusb pcm */
 	SNDRV_HWDEP_IFACE_PCXHR,	/* Digigram PCXHR */
 	SNDRV_HWDEP_IFACE_SB_RC,	/* SB Extigy/Audigy2NX remote control */
+	SNDRV_HWDEP_IFACE_USB_CTRL,	/* USB control transfers */
 
 	/* Don't forget to change the following: */
-	SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_SB_RC
+	SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_USB_CTRL,
 };
 
 struct sndrv_hwdep_info {
Index: alsa/alsa-lib/include/sound/asound.h
===================================================================
--- alsa.orig/alsa-lib/include/sound/asound.h	2005-05-20 17:15:54.000000000 +0200
+++ alsa/alsa-lib/include/sound/asound.h	2005-06-08 22:34:12.000000000 +0200
@@ -112,9 +112,10 @@ enum sndrv_hwdep_iface {
 	SNDRV_HWDEP_IFACE_USX2Y_PCM,	/* Tascam US122, US224 & US428 rawusb pcm */
 	SNDRV_HWDEP_IFACE_PCXHR,	/* Digigram PCXHR */
 	SNDRV_HWDEP_IFACE_SB_RC,	/* SB Extigy/Audigy2NX remote control */
+	SNDRV_HWDEP_IFACE_USB_CTRL,	/* USB control transfers */
 
 	/* Don't forget to change the following: */
-	SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_SB_RC
+	SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_USB_CTRL
 };
 
 struct sndrv_hwdep_info {
Index: alsa/alsa-lib/include/hwdep.h
===================================================================
--- alsa.orig/alsa-lib/include/hwdep.h	2005-04-29 17:26:40.000000000 +0200
+++ alsa/alsa-lib/include/hwdep.h	2005-06-08 22:37:08.000000000 +0200
@@ -68,8 +68,9 @@ typedef enum _snd_hwdep_iface {
 	SND_HWDEP_IFACE_USX2Y_PCM,	/**< Tascam US122, US224 & US428 raw USB PCM */
 	SND_HWDEP_IFACE_PCXHR,		/**< Digigram PCXHR */
 	SND_HWDEP_IFACE_SB_RC,		/**< SB Extigy/Audigy2NX remote control */
+	SND_HWDEP_IFACE_USB_CTRL,	/**< USB control transfers */
                 
-	SND_HWDEP_IFACE_LAST = SND_HWDEP_IFACE_SB_RC  /**< last known hwdep interface */
+	SND_HWDEP_IFACE_LAST = SND_HWDEP_IFACE_USB_CTRL	/**< last known hwdep interface */
 } snd_hwdep_iface_t;
 
 /** open for reading */
Index: alsa/alsa-kernel/usb/usbaudio.c
===================================================================
--- alsa.orig/alsa-kernel/usb/usbaudio.c	2005-05-31 18:13:22.000000000 +0200
+++ alsa/alsa-kernel/usb/usbaudio.c	2005-06-08 23:31:31.000000000 +0200
@@ -45,11 +45,13 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
 #include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
+#include <sound/hwdep.h>
 #include <sound/initval.h>
 
 #include "usbaudio.h"
@@ -3012,6 +3014,69 @@ static void snd_usb_audio_create_proc(sn
 		snd_info_set_text_ops(entry, chip, 1024, proc_audio_usbid_read);
 }
 
+/* hwdep interface */
+static int snd_usb_audio_hwdep_open(snd_hwdep_t *hwdep, struct file *file)
+{
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	return 0;
+}
+
+static int snd_usb_audio_hwdep_ioctl(snd_hwdep_t *hwdep, struct file *file,
+				     unsigned int cmd, unsigned long arg)
+{
+	snd_usb_audio_t *chip = hwdep->private_data;
+	struct usbdevfs_ctrltransfer ctrl;
+	void *buffer;
+	int ret;
+
+	if (cmd != USBDEVFS_CONTROL)
+		return -ENOTTY;
+	if (copy_from_user(&ctrl, (void __user *)arg, sizeof(ctrl)))
+		return -EFAULT;
+	if (ctrl.wLength > PAGE_SIZE)
+		return -EINVAL;
+	if (!(buffer = (void *)__get_free_page(GFP_KERNEL)))
+		return -ENOMEM;
+	if (ctrl.bRequestType & USB_DIR_IN) {
+		ret = usb_control_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
+				      ctrl.bRequest, ctrl.bRequestType,
+				      ctrl.wValue, ctrl.wIndex,
+				      buffer, ctrl.wLength, ctrl.timeout);
+		if (ret > 0 && ctrl.wLength &&
+		    copy_to_user(ctrl.data, buffer, ctrl.wLength)) {
+			ret = -EFAULT;
+			goto _error;
+		}
+	} else {
+		if (ctrl.wLength &&
+		    copy_from_user(buffer, ctrl.data, ctrl.wLength)) {
+			ret = -EFAULT;
+			goto _error;
+		}
+		ret = usb_control_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0),
+				      ctrl.bRequest, ctrl.bRequestType,
+				      ctrl.wValue, ctrl.wIndex,
+				      buffer, ctrl.wLength, ctrl.timeout);
+	}
+_error:
+	free_page((unsigned long)buffer);
+	return ret;
+}
+
+static void snd_usb_audio_create_hwdep(snd_usb_audio_t *chip)
+{
+	snd_hwdep_t *hwdep;
+
+	if (snd_hwdep_new(chip->card, "USB Control", 1, &hwdep) >= 0) {
+		strcpy(hwdep->name, "USB Control");
+		hwdep->iface = SNDRV_HWDEP_IFACE_USB_CTRL;
+		hwdep->private_data = chip;
+		hwdep->ops.open = snd_usb_audio_hwdep_open;
+		hwdep->ops.ioctl = snd_usb_audio_hwdep_ioctl;
+	}
+}
+
 /*
  * free the chip instance
  *
@@ -3127,6 +3192,7 @@ static int snd_usb_audio_create(struct u
 		sizeof(card->longname));
 
 	snd_usb_audio_create_proc(chip);
+	snd_usb_audio_create_hwdep(chip);
 
 	*rchip = chip;
 	return 0;
Index: alsa/alsa-driver/usb/usbaudio.patch
===================================================================
--- alsa.orig/alsa-driver/usb/usbaudio.patch	2005-05-02 09:43:49.000000000 +0200
+++ alsa/alsa-driver/usb/usbaudio.patch	2005-06-08 23:31:50.000000000 +0200
@@ -1,11 +1,11 @@
---- ../alsa-kernel/usb/usbaudio.c	2005-04-29 23:54:04.000000000 +0200
-+++ usbaudio.c	2005-04-29 23:56:20.000000000 +0200
+--- ../alsa-kernel/usb/usbaudio.c	2005-06-08 23:31:31.000000000 +0200
++++ usbaudio.c	2005-06-08 23:31:38.000000000 +0200
 @@ -1,3 +1,4 @@
 +#include "usbaudio.inc"
  /*
   *   (Tentative) USB Audio Driver for ALSA
   *
-@@ -67,7 +68,12 @@
+@@ -69,7 +70,12 @@
  static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Vendor ID for this card */
  static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Product ID for this card */
  static int nrpacks = 4;		/* max. number of packets per urb */
@@ -19,7 +19,7 @@
  
  module_param_array(index, int, NULL, 0444);
  MODULE_PARM_DESC(index, "Index value for the USB audio adapter.");
-@@ -1902,8 +1908,13 @@
+@@ -1874,8 +1880,13 @@
  			return -ENOMEM;
  		memcpy(buf, data, size);
  	}
@@ -33,7 +33,7 @@
  	if (size > 0) {
  		memcpy(data, buf, size);
  		kfree(buf);
-@@ -1916,9 +1927,11 @@
+@@ -1888,9 +1899,11 @@
   * entry point for linux usb interface
   */
  
@@ -45,7 +45,7 @@
  
  static struct usb_device_id usb_audio_ids [] = {
  #include "usbquirks.h"
-@@ -1931,10 +1944,15 @@
+@@ -1903,10 +1916,15 @@
  MODULE_DEVICE_TABLE (usb, usb_audio_ids);
  
  static struct usb_driver usb_audio_driver = {
@@ -61,7 +61,7 @@
  	.id_table =	usb_audio_ids,
  };
  
-@@ -2460,7 +2478,11 @@
+@@ -2432,7 +2450,11 @@
  		    (altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING &&
  		     altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC) ||
  		    altsd->bNumEndpoints < 1 ||
@@ -73,7 +73,7 @@
  			continue;
  		/* must be isochronous */
  		if ((get_endpoint(alts, 0)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
-@@ -2523,7 +2545,11 @@
+@@ -2495,7 +2517,11 @@
  		fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
  		fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
  		/* FIXME: decode wMaxPacketSize of high bandwith endpoints */
@@ -85,7 +85,7 @@
  		fp->attributes = csep[3];
  
  		/* some quirks for attributes here */
-@@ -2811,7 +2837,11 @@
+@@ -2782,7 +2808,11 @@
  	fp->iface = altsd->bInterfaceNumber;
  	fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
  	fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
@@ -97,7 +97,7 @@
  
  	switch (fp->maxpacksize) {
  	case 0x120:
-@@ -2877,7 +2907,11 @@
+@@ -2848,7 +2878,11 @@
  	fp->iface = altsd->bInterfaceNumber;
  	fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
  	fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
@@ -109,7 +109,7 @@
  	fp->rate_max = fp->rate_min = combine_triple(&alts->extra[8]);
  
  	stream = (fp->endpoint & USB_DIR_IN)
-@@ -2935,8 +2969,13 @@
+@@ -2906,8 +2940,13 @@
  	struct usb_host_config *config = dev->actconfig;
  	int err;
  
@@ -123,7 +123,7 @@
  		snd_printdd("sending Extigy boot sequence...\n");
  		/* Send message to force it to reconnect with full interface. */
  		err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev,0),
-@@ -2948,8 +2987,13 @@
+@@ -2919,8 +2958,13 @@
  		if (err < 0) snd_printdd("error usb_get_descriptor: %d\n", err);
  		err = usb_reset_configuration(dev);
  		if (err < 0) snd_printdd("error usb_reset_configuration: %d\n", err);
@@ -137,7 +137,17 @@
  		return -ENODEV; /* quit this anyway */
  	}
  	return 0;
-@@ -3082,8 +3126,13 @@
+@@ -3038,6 +3082,9 @@
+ 		return -EINVAL;
+ 	if (!(buffer = (void *)__get_free_page(GFP_KERNEL)))
+ 		return -ENOMEM;
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
++	ctrl.timeout = (ctrl.timeout * HZ + 999) / 1000;
++#endif
+ 	if (ctrl.bRequestType & USB_DIR_IN) {
+ 		ret = usb_control_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
+ 				      ctrl.bRequest, ctrl.bRequestType,
+@@ -3135,8 +3182,13 @@
  	chip->index = idx;
  	chip->dev = dev;
  	chip->card = card;
@@ -151,7 +161,7 @@
  	INIT_LIST_HEAD(&chip->pcm_list);
  	INIT_LIST_HEAD(&chip->midi_list);
  	INIT_LIST_HEAD(&chip->mixer_list);
-@@ -3171,8 +3220,12 @@
+@@ -3223,8 +3275,12 @@
  
  	alts = &intf->altsetting[0];
  	ifnum = get_iface_desc(alts)->bInterfaceNumber;
@@ -164,7 +174,7 @@
  
  	if (quirk && quirk->ifnum >= 0 && ifnum != quirk->ifnum)
  		goto __err_val;
-@@ -3293,12 +3346,17 @@
+@@ -3351,12 +3407,17 @@
  		}
  		usb_chip[chip->index] = NULL;
  		up(&register_mutex);
@@ -182,7 +192,7 @@
  /*
   * new 2.5 USB kernel API
   */
-@@ -3319,6 +3377,8 @@
+@@ -3377,6 +3438,8 @@
  	snd_usb_audio_disconnect(interface_to_usbdev(intf),
  				 dev_get_drvdata(&intf->dev));
  }
@@ -191,7 +201,7 @@
  
  
  static int __init snd_usb_audio_init(void)
-@@ -3339,3 +3399,5 @@
+@@ -3397,3 +3460,5 @@
  
  module_init(snd_usb_audio_init);
  module_exit(snd_usb_audio_cleanup);


More information about the Linux-audio-dev mailing list