[PATCH] g_audio fixes: driver bind/unbind, audio structs packing, configuration layout

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch applies to the USB Gadget Audio driver, g_audio.ko.

The fixes include --
* driver bind and unbind processing
* several configuration structs were incomplete or not packed.

The additions include ...
* Endpoint ControlSelector support added: handles Sample_Freq.
* USB_DT_AC_FEATURE_UNIT_SIZE() macro handles different element sizes.


With these changes I was able to get the USB Gadget Audio driver to pass 
audio playback (speaker) from a WindowXP laptop running WMP-11 to a set 
of USB-speakers on a Linux (ubuntu) system via the g_audio + net2280 udc driver.

Below shows a simple line diagram of this test configuration.

   [WMP-11] --usb--> [g_audio + net2280] --/dev/snd/pcmC0D0p--> [ALSA] --usb--> USB-speakers
[--WindowsXP---][--------------------- Ubuntu (9.04) Linux ---------------][----hw device---]


Signed-off-by: Robin Callender <robin_callender@xxxxxxxxxxx>


diff -uprN linux-2.6.30.4.orig/drivers/usb/gadget/audio.c linux-2.6.30.4/drivers/usb/gadget/audio.c
--- linux-2.6.30.4.orig/drivers/usb/gadget/audio.c	2009-08-15 14:23:40.000000000 -0700
+++ linux-2.6.30.4/drivers/usb/gadget/audio.c	2009-08-15 15:17:25.000000000 -0700
@@ -89,6 +89,21 @@ static const struct usb_descriptor_heade
 
 /*-------------------------------------------------------------------------*/
 
+static void audio_set_endpoint_complete(struct usb_ep *ep, 
+					struct usb_request *req)
+{
+	struct f_audio *audio = req->context;
+	u32 data = 0;
+
+	if (req->status == 0 && audio->set_con) {
+		memcpy(&data, req->buf, req->length);
+		audio->set_con->set(audio->set_con, audio->set_cmd,
+				    le32_to_cpu(data));
+		//printk("%s(%d)\n", audio->set_con->name, le32_to_cpu(data));
+		audio->set_con = NULL;
+	}
+}
+
 /**
  * Handle USB audio endpoint set/get command in setup class request
  */
@@ -97,31 +112,45 @@ static int audio_set_endpoint_req(struct
 		const struct usb_ctrlrequest *ctrl)
 {
 	struct usb_composite_dev *cdev = c->cdev;
-	int			value = -EOPNOTSUPP;
-	u16			ep = le16_to_cpu(ctrl->wIndex);
-	u16			len = le16_to_cpu(ctrl->wLength);
-	u16			w_value = le16_to_cpu(ctrl->wValue);
+	struct usb_request *req = cdev->req;
+	struct f_audio *audio = req->context;
+	struct usb_audio_control_selector *cs;
+	struct usb_audio_control *con;
+
+	int	value   = -EOPNOTSUPP;
+	u8	id      = le16_to_cpu(ctrl->wIndex) & 0xFF;
+	u16	len     = le16_to_cpu(ctrl->wLength);
+	u16	w_value = le16_to_cpu(ctrl->wValue);
+	u8	con_sel = (w_value >> 8) & 0xFF;
+	u8	cmd     = (ctrl->bRequest & 0x0F);
 
 	DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
-			ctrl->bRequest, w_value, len, ep);
+			ctrl->bRequest, w_value, len, id);
+
+	list_for_each_entry(cs, &audio->ep_cs, list) {
+		if (cs->id == id) {
+			list_for_each_entry(con, &cs->control, list) {
+				if (con->type == con_sel) {
+					audio->set_con = con;
+					break;
+				}
+			}
+			break;
+		}
+	}
 
 	switch (ctrl->bRequest) {
 	case SET_CUR:
-		value = 0;
-		break;
-
 	case SET_MIN:
-		break;
-
 	case SET_MAX:
-		break;
-
 	case SET_RES:
+		audio->set_cmd = cmd;
+		req->context  = audio;
+		req->complete = audio_set_endpoint_complete;
+		value = len;
 		break;
-
 	case SET_MEM:
 		break;
-
 	default:
 		break;
 	}
@@ -146,7 +175,7 @@ static int audio_get_endpoint_req(struct
 	case GET_MIN:
 	case GET_MAX:
 	case GET_RES:
-		value = 3;
+		value = len;
 		break;
 	case GET_MEM:
 		break;
diff -uprN linux-2.6.30.4.orig/drivers/usb/gadget/f_audio.c linux-2.6.30.4/drivers/usb/gadget/f_audio.c
--- linux-2.6.30.4.orig/drivers/usb/gadget/f_audio.c	2009-08-15 14:23:40.000000000 -0700
+++ linux-2.6.30.4/drivers/usb/gadget/f_audio.c	2009-08-15 15:10:59.000000000 -0700
@@ -39,7 +39,7 @@ MODULE_PARM_DESC(audio_buf_size, "Audio 
  */
 #define F_AUDIO_AC_INTERFACE	0
 #define F_AUDIO_AS_INTERFACE	1
-#define F_AUDIO_NUM_INTERFACES	2
+#define F_AUDIO_NUM_INTERFACES	1
 
 /* B.3.1  Standard AC Interface Descriptor */
 static struct usb_interface_descriptor ac_interface_desc __initdata = {
@@ -50,20 +50,24 @@ static struct usb_interface_descriptor a
 	.bInterfaceSubClass =	USB_SUBCLASS_AUDIOCONTROL,
 };
 
-DECLARE_USB_AC_HEADER_DESCRIPTOR(2);
+DECLARE_USB_AC_HEADER_DESCRIPTOR(1);
+
+#define USB_DT_AC_HEADER_LENGTH	USB_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES)
 
-#define USB_DT_AC_HEADER_LENGH	USB_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES)
 /* B.3.2  Class-Specific AC Interface Descriptor */
-static struct usb_ac_header_descriptor_2 ac_header_desc = {
-	.bLength =		USB_DT_AC_HEADER_LENGH,
+static struct usb_ac_header_descriptor_1 ac_header_desc = {
+	.bLength =		USB_DT_AC_HEADER_LENGTH,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorSubtype =	HEADER,
 	.bcdADC =		__constant_cpu_to_le16(0x0100),
-	.wTotalLength =		__constant_cpu_to_le16(USB_DT_AC_HEADER_LENGH),
+	.wTotalLength =		__constant_cpu_to_le16(
+					USB_DT_AC_HEADER_SIZE(1)         +
+					USB_DT_AC_INPUT_TERMINAL_SIZE    +
+					USB_DT_AC_FEATURE_UNIT_SIZE(1,1) +
+					USB_DT_AC_OUTPUT_TERMINAL_SIZE),
 	.bInCollection =	F_AUDIO_NUM_INTERFACES,
 	.baInterfaceNr = {
-		[0] =		F_AUDIO_AC_INTERFACE,
-		[1] =		F_AUDIO_AS_INTERFACE,
+		[0] =		F_AUDIO_AS_INTERFACE,
 	}
 };
 
@@ -82,7 +86,7 @@ DECLARE_USB_AC_FEATURE_UNIT_DESCRIPTOR(0
 
 #define FEATURE_UNIT_ID		2
 static struct usb_ac_feature_unit_descriptor_0 feature_unit_desc = {
-	.bLength		= USB_DT_AC_FEATURE_UNIT_SIZE(0),
+	.bLength		= USB_DT_AC_FEATURE_UNIT_SIZE(1,1),
 	.bDescriptorType	= USB_DT_CS_INTERFACE,
 	.bDescriptorSubtype	= FEATURE_UNIT,
 	.bUnitID		= FEATURE_UNIT_ID,
@@ -181,22 +185,38 @@ static struct usb_endpoint_descriptor as
 };
 
 /* Class-specific AS ISO OUT Endpoint Descriptor */
-static struct usb_as_iso_endpoint_descriptor as_iso_out_desc __initdata = {
+static struct usb_as_iso_endpoint_descriptor as_iso_out_desc  = {
 	.bLength =		USB_AS_ISO_ENDPOINT_DESC_SIZE,
 	.bDescriptorType =	USB_DT_CS_ENDPOINT,
 	.bDescriptorSubtype =	EP_GENERAL,
-	.bmAttributes = 	1,
+	.bmAttributes = 	SAMPLE_FREQ,
 	.bLockDelayUnits =	1,
 	.wLockDelay =		__constant_cpu_to_le16(1),
 };
 
+static struct usb_audio_control sample_freq_control = {
+	.list = LIST_HEAD_INIT(sample_freq_control.list),
+	.name = "Sampling Frequency Control",
+	.type = EP_ISO_SAMPLE_FREQ,
+	.set = generic_set_cmd,
+	.get = generic_get_cmd,
+};
+
+static struct usb_audio_control_selector as_iso_out = {
+	.list = LIST_HEAD_INIT(as_iso_out.list),
+	.id   = EP_GENERAL,
+	.name = "Iso-out Endpoint Control",
+	.type = EP_GENERAL,
+	.desc = (struct usb_descriptor_header *)&as_iso_out_desc,
+};
+
 static struct usb_descriptor_header *f_audio_desc[] __initdata = {
 	(struct usb_descriptor_header *)&ac_interface_desc,
 	(struct usb_descriptor_header *)&ac_header_desc,
 
 	(struct usb_descriptor_header *)&input_terminal_desc,
-	(struct usb_descriptor_header *)&output_terminal_desc,
 	(struct usb_descriptor_header *)&feature_unit_desc,
+	(struct usb_descriptor_header *)&output_terminal_desc,
 
 	(struct usb_descriptor_header *)&as_interface_alt_0_desc,
 	(struct usb_descriptor_header *)&as_interface_alt_1_desc,
@@ -280,7 +300,8 @@ struct f_audio {
 	struct list_head play_queue;
 
 	/* Control Set command */
-	struct list_head cs;
+	struct list_head fu_cs;
+	struct list_head ep_cs;
 	u8 set_cmd;
 	struct usb_audio_control *set_con;
 };
@@ -386,7 +407,7 @@ static int audio_set_intf_req(struct usb
 	DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, entity %d\n",
 			ctrl->bRequest, w_value, len, id);
 
-	list_for_each_entry(cs, &audio->cs, list) {
+	list_for_each_entry(cs, &audio->fu_cs, list) {
 		if (cs->id == id) {
 			list_for_each_entry(con, &cs->control, list) {
 				if (con->type == con_sel) {
@@ -423,7 +444,7 @@ static int audio_get_intf_req(struct usb
 	DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, entity %d\n",
 			ctrl->bRequest, w_value, len, id);
 
-	list_for_each_entry(cs, &audio->cs, list) {
+	list_for_each_entry(cs, &audio->fu_cs, list) {
 		if (cs->id == id) {
 			list_for_each_entry(con, &cs->control, list) {
 				if (con->type == con_sel && con->get) {
@@ -626,17 +647,19 @@ f_audio_unbind(struct usb_configuration 
 {
 	struct f_audio		*audio = func_to_audio(f);
 
+	gaudio_cleanup(&audio->card);
+
 	usb_free_descriptors(f->descriptors);
 	kfree(audio);
 }
 
 /*-------------------------------------------------------------------------*/
 
-/* Todo: add more control selecotor dynamically */
+/* Todo: add more control selector dynamically */
 int __init control_selector_init(struct f_audio *audio)
 {
-	INIT_LIST_HEAD(&audio->cs);
-	list_add(&feature_unit.list, &audio->cs);
+	INIT_LIST_HEAD(&audio->fu_cs);
+	list_add(&feature_unit.list, &audio->fu_cs);
 
 	INIT_LIST_HEAD(&feature_unit.control);
 	list_add(&mute_control.list, &feature_unit.control);
@@ -647,6 +670,12 @@ int __init control_selector_init(struct 
 	volume_control.data[_MAX] = 0xfff0;
 	volume_control.data[_RES] = 0x0030;
 
+	INIT_LIST_HEAD(&audio->ep_cs);
+	list_add(&as_iso_out.list, &audio->ep_cs);
+
+	INIT_LIST_HEAD(&as_iso_out.control);
+	list_add(&sample_freq_control.list, &as_iso_out.control);
+
 	return 0;
 }
 
diff -uprN linux-2.6.30.4.orig/drivers/usb/gadget/u_audio.c linux-2.6.30.4/drivers/usb/gadget/u_audio.c
--- linux-2.6.30.4.orig/drivers/usb/gadget/u_audio.c	2009-08-15 14:57:15.000000000 -0700
+++ linux-2.6.30.4/drivers/usb/gadget/u_audio.c	2009-08-15 14:59:59.000000000 -0700
@@ -231,7 +231,6 @@ static int gaudio_open_snd_dev(struct ga
 		int ret = PTR_ERR(snd->filp);
 		ERROR(card, "unable to open sound control device file: %s\n",
 				fn_cntl);
-		snd->filp = NULL;
 		return ret;
 	}
 	snd->card = card;
@@ -241,20 +240,18 @@ static int gaudio_open_snd_dev(struct ga
 	snd->filp = filp_open(fn_play, O_WRONLY, 0);
 	if (IS_ERR(snd->filp)) {
 		ERROR(card, "No such PCM playback device: %s\n", fn_play);
-		snd->filp = NULL;
+	} else {
+		pcm_file = snd->filp->private_data;
+		snd->substream = pcm_file->substream;
+		snd->card = card;
+		playback_default_hw_params(snd);
 	}
-	pcm_file = snd->filp->private_data;
-	snd->substream = pcm_file->substream;
-	snd->card = card;
-	playback_default_hw_params(snd);
 
 	/* Open PCM capture device and setup substream */
 	snd = &card->capture;
 	snd->filp = filp_open(fn_cap, O_RDONLY, 0);
 	if (IS_ERR(snd->filp)) {
 		ERROR(card, "No such PCM capture device: %s\n", fn_cap);
-		snd->substream = NULL;
-		snd->card = NULL;
 	} else {
 		pcm_file = snd->filp->private_data;
 		snd->substream = pcm_file->substream;
diff -uprN linux-2.6.30.4.orig/include/linux/usb/audio.h linux-2.6.30.4/include/linux/usb/audio.h
--- linux-2.6.30.4.orig/include/linux/usb/audio.h	2009-08-15 14:23:56.000000000 -0700
+++ linux-2.6.30.4/include/linux/usb/audio.h	2009-08-15 15:25:57.000000000 -0700
@@ -162,8 +162,8 @@ struct usb_output_terminal_descriptor {
 #define USB_AC_OUTPUT_TERMINAL_COMMUNICATION_SPEAKER		0x306
 #define USB_AC_OUTPUT_TERMINAL_LOW_FREQ_EFFECTS_SPEAKER		0x307
 
-/* Set bControlSize = 2 as default setting */
-#define USB_DT_AC_FEATURE_UNIT_SIZE(ch)		(7 + ((ch) + 1) * 2)
+
+#define USB_DT_AC_FEATURE_UNIT_SIZE(ch,n)	(7 + (((ch) + 1) * n))
 
 /* As above, but more useful for defining your own descriptors: */
 #define DECLARE_USB_AC_FEATURE_UNIT_DESCRIPTOR(ch) 		\
@@ -255,7 +255,7 @@ struct usb_as_iso_endpoint_descriptor {
 	__u8  bmAttributes;
 	__u8  bLockDelayUnits;
 	__le16 wLockDelay;
-};
+} __attribute__ ((packed));
 #define USB_AS_ISO_ENDPOINT_DESC_SIZE	7
 
 #define FU_CONTROL_UNDEFINED		0x00
@@ -281,6 +281,13 @@ struct usb_as_iso_endpoint_descriptor {
 #define FU_BASS_BOOST	(1 << (BASS_BOOST_CONTROL - 1))
 #define FU_LOUDNESS	(1 << (LOUDNESS_CONTROL - 1))
 
+#define EP_ISO_UNDEFINED		0x00
+#define EP_ISO_SAMPLE_FREQ		0x01
+#define EP_ISO_PITCH_CONTROL		0x02
+
+#define SAMPLE_FREQ	(1 << (EP_ISO_SAMPLE_FREQ - 1))
+#define PITCH_CONTROL	(1 << (EP_ISO_PITCH_CONTROL - 1))
+
 struct usb_audio_control {
 	struct list_head list;
 	const char *name;


--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux