alsa-devel.alsa-project.org archive mirror
 help / color / mirror / Atom feed
From: Ben Hutchings <ben.hutchings@codethink.co.uk>
To: Jorge Sanjuan <jorge.sanjuan@codethink.co.uk>,
	alsa-devel@alsa-project.org
Cc: linux-kernel@lists.codethink.co.uk
Subject: Re: [Linux-kernel] [PATCH 1/6] ALSA: usb: ADC3: Add initial BADD spec support
Date: Wed, 13 Dec 2017 22:48:53 +0000	[thread overview]
Message-ID: <1513205333.18523.270.camel@codethink.co.uk> (raw)
In-Reply-To: <20171129105532.15420-2-jorge.sanjuan@codethink.co.uk>

On Wed, 2017-11-29 at 10:55 +0000, Jorge Sanjuan wrote:
> The Basic Audio Device 3 (BADD) spec requires the host to
> have "inferred" descriptors when a BADD profile ID is specified.
> This descriptor generator creates a buffer with known descriptors
> for each profile that can be then read to create the alsa audio
> device(s). The UAC3 compliant devices should have one configuration
> that is BADD compliant.
> 
> The USB request from host are bypassed and these buffers are read
> instead.
> 
> This patch series covers (for now) the following topologies:
> 
>  - HEADPHONE.
>  - HEADSET.
> 
> For more information refer to the spec at:
> 
>  http://www.usb.org/developers/docs/devclass_docs/
> 
> Signed-off-by: Jorge Sanjuan <jorge.sanjuan@codethink.co.uk>
> ---
[...]
> --- /dev/null
> +++ b/sound/usb/badd.c
> @@ -0,0 +1,495 @@
> +/*
> + *   USB: Audio Class 3: support for BASIC AUDIO DEVICE v.3
> + *
> + *   Author: Jorge Sanjuan <jorge.sanjuan@codethink.co.uk>
> + *   Copyright (C) 2017 Codethink Ltd.
> + *
> + *   This program is free software; you can redistribute it and/or modify

Drop the GPL boilerplate and add an SPDX licence identifier instead
(see commit b24413180f56).

[...]
> +struct uac3_feature_unit_descriptor inf_feat_unit_id2 = {
> +	.bLength = 0x0F, /* 0x13 if stereo */
> +	.bDescriptorType = USB_DT_CS_INTERFACE,
> +	.bDescriptorSubtype = UAC3_FEATURE_UNIT,
> +
> +	.bUnitID = 0x02,
> +	/* bSourceID -> Profile dependent */
> +	.bmaControls[0] = 0x03, /* Mute */
> +	.bmaControls[1] = 0x0C, /* Chn1 Vol */
> +	/* If stereo */
> +	//.bmaControls[2] = 0x0C, /* Chn2 Vol */

Kernel style is to use only /* */ comments, not // comments.

[...]
> +/**
> + * badd_gen_cluster_desc - This is to bypass the GET_HIGH_CAPABILITY
> + * UAC3 requests for getting cluster descriptors and, instead, generate
> + * the cluster on the host side as per BADD specification.
> + */

A kernel-doc comment mst have a one-line summary and then a description
of each parameter.  This function probably doesn't need that kind of
documentation, so you could drop the extra * from the comment opener.

> +void * badd_gen_cluster_desc(unsigned int m_s)

No space after the *.  Use checkpatch.pl to check for trivial style
issues like this.

> +{
> +	struct uac3_cluster_header_descriptor cluster;
> +	struct uac3_cluster_information_segment_descriptor segment;
> +	struct uac3_cluster_end_segment_descriptor end;
> +	void *buffer;
> +	int pos = 0;
> +	int length;
> +
> +	end.wLength = 0x03;

I think this needs to be a little-endian, in which case you need to use
cpu_to_le16(0x03).

Similarly for all the other 16/32-bit fields in descriptors.

> +	end.bSegmentType = UAC3_END_SEGMENT;
> +
> +	if (m_s == 0x01) { /* Mono */

Rather than commenting that this constant means Mono, you should name
it with an enum or macro.  (Or if the variable is actually a number of
channels, then you should rename it.)

> +		length = 0x10;

Where does this number come from?  Shouldn't it be written as
sizeof(cluster) + sizeof(segment) + sizeof(end)?

[...]
> +/**
> + * badd_gen_csint_desc - generates a buffer with the inferred
> + * descriptors that are predefined in the BADD specfication.

A kernel-doc summary has to be a single line.  This is not just a
recommendation, it's a hard constraint of the script.

There are a lot more magic numbers in here that ought to be replaced by
either named constants or an expression using sizeof().

[...]
> --- a/sound/usb/stream.c
> +++ b/sound/usb/stream.c
> @@ -37,6 +37,7 @@
>  #include "format.h"
>  #include "clock.h"
>  #include "stream.h"
> +#include "badd.h"
>  
>  /*
>   * free a substream
> @@ -485,7 +486,11 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
>  	struct usb_interface_descriptor *altsd = get_iface_desc(alts);
>  	int attributes = 0;
>  
> -	csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT);
> +	if (protocol == UAC_VERSION_3 &&
> +			chip->badd_profile > UAC3_FUNCTION_SUBCLASS_FULL_ADC_3_0)

This looks excessively indented.

> +		csep = badd_get_ep_dec();
> +	else
> +		csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT);
>  
>  	/* Creamware Noah has this descriptor after the 2nd endpoint */
>  	if (!csep && altsd->bNumEndpoints >= 2)
[...]
> @@ -715,11 +723,33 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
>  			struct uac3_as_header_descriptor *as;
>  			struct uac3_cluster_header_descriptor *cluster;
>  			struct uac3_hc_descriptor_header hc_header;
> +			struct usb_host_interface *badd_ctrl_intf;
> +			void *badd_extra;
> +			int badd_extralen;
>  			u16 cluster_id, wLength;
>  
> -			as = snd_usb_find_csint_desc(alts->extra,
> -							alts->extralen,
> -							NULL, UAC_AS_GENERAL);
> +			badd_ctrl_intf = kzalloc(sizeof(*badd_ctrl_intf), GFP_KERNEL);

Missing an error check here.

> +			memcpy(badd_ctrl_intf, chip->ctrl_intf, sizeof(*badd_ctrl_intf));
> +
> +			if (chip->badd_profile > UAC3_FUNCTION_SUBCLASS_FULL_ADC_3_0) {
> +
> +				as = badd_get_as_iface(stream, ep_packsize);
> +
> +				err = badd_gen_csint_desc(&badd_extra, chip->badd_profile, as->wClusterDescrID);
> +				if (err <= 0 || !badd_extra) {
> +					dev_err(&dev->dev,
> +						"%u:%d : Cannot set BADD profile 0x%x. err=%d. badd_extra %p\n",
> +						iface_no, altno, chip->badd_profile, err, badd_extra);
> +					return err;
> +				}
> +
> +				badd_extralen = err;
> +				badd_ctrl_intf->extra = badd_extra;
> +				badd_ctrl_intf->extralen = badd_extralen;

I don't think the badd_extra or badd_extralen variables are really
needed here - they just seem to complicate this.

> +			} else
> +				as = snd_usb_find_csint_desc(alts->extra,
> +								alts->extralen,
> +								NULL, UAC_AS_GENERAL);
>  
>  			if (!as) {
>  				dev_err(&dev->dev,
> @@ -743,53 +773,64 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
>  				continue;
>  			}
>  
> -			/*
> -			 * Get number of channels and channel map through
> -			 * High Capability Cluster Descriptor
> -			 *
> -			 * First step: get High Capability header and
> -			 * read size of Cluster Descriptor
> -			 */
> -			err = snd_usb_ctl_msg(chip->dev,
> -					usb_rcvctrlpipe(chip->dev, 0),
> -					UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
> -					USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
> -					cluster_id,
> -					snd_usb_ctrl_intf(chip),
> -					&hc_header, sizeof(hc_header));
> -			if (err < 0)
> -				return err;
> -			else if (err != sizeof(hc_header)) {
> -				dev_err(&dev->dev,
> -					"%u:%d : can't get High Capability descriptor\n",
> -					iface_no, altno);
> -				return -EIO;
> -			}
> -
> -			/*
> -			 * Second step: allocate needed amount of memory
> -			 * and request Cluster Descriptor
> -			 */
> -			wLength = le16_to_cpu(hc_header.wLength);
> -			cluster = kzalloc(wLength, GFP_KERNEL);
> -			if (!cluster)
> -				return -ENOMEM;
> -			err = snd_usb_ctl_msg(chip->dev,
> -					usb_rcvctrlpipe(chip->dev, 0),
> -					UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
> -					USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
> -					cluster_id,
> -					snd_usb_ctrl_intf(chip),
> -					cluster, wLength);
> -			if (err < 0) {
> -				kfree(cluster);
> -				return err;
> -			} else if (err != wLength) {
> -				dev_err(&dev->dev,
> -					"%u:%d : can't get Cluster Descriptor\n",
> -					iface_no, altno);
> -				kfree(cluster);
> -				return -EIO;
> +			if (chip->badd_profile > UAC3_FUNCTION_SUBCLASS_FULL_ADC_3_0) {
> +
> +				cluster = badd_gen_cluster_desc(cluster_id);
> +				if (!cluster) {
> +					dev_err(&dev->dev, 
> +						"%u:%d : can't get Cluster Descriptor\n",
> +						iface_no, altno);
> +					return -ENOMEM;
> +				}
> +			} else {
> +				/*
> +				 * Get number of channels and channel map through
> +				 * High Capability Cluster Descriptor
> +				 *
> +				 * First step: get High Capability header and
> +				 * read size of Cluster Descriptor
> +				 */
> +				err = snd_usb_ctl_msg(chip->dev,
> +						usb_rcvctrlpipe(chip->dev, 0),
> +						UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
> +						USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
> +						cluster_id,
> +						snd_usb_ctrl_intf(chip),
> +						&hc_header, sizeof(hc_header));
> +				if (err < 0)
> +					return err;
> +				else if (err != sizeof(hc_header)) {
> +					dev_err(&dev->dev,
> +						"%u:%d : can't get High Capability descriptor\n",
> +						iface_no, altno);
> +					return -EIO;
> +				}
> +
> +				/*
> +				 * Second step: allocate needed amount of memory
> +				 * and request Cluster Descriptor
> +				 */
> +				wLength = le16_to_cpu(hc_header.wLength);
> +				cluster = kzalloc(wLength, GFP_KERNEL);
> +				if (!cluster)
> +					return -ENOMEM;
> +				err = snd_usb_ctl_msg(chip->dev,
> +						usb_rcvctrlpipe(chip->dev, 0),
> +						UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
> +						USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
> +						cluster_id,
> +						snd_usb_ctrl_intf(chip),
> +						cluster, wLength);
> +				if (err < 0) {
> +					kfree(cluster);
> +					return err;
> +				} else if (err != wLength) {
> +					dev_err(&dev->dev,
> +						"%u:%d : can't get Cluster Descriptor\n",
> +						iface_no, altno);
> +					kfree(cluster);
> +					return -EIO;
> +				}

This is a large block of code getting indented many levels deep.  I
can't help thinking that it also ought to be turned into a separate
function.

All the error cases in this block will now leak badd_ctrl_inf, and it
would be easier to avoid that if it's turned into a separate function.


>  			}
>  
>  			num_channels = cluster->bNrChannels;
> @@ -802,7 +843,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
>  			/* lookup the terminal associated to this interface
>  			 * to extract the clock */
>  			input_term = snd_usb_find_input_terminal_descriptor(
> -							chip->ctrl_intf,
> +							badd_ctrl_intf,
>  							as->bTerminalLink);
>  
>  			if (input_term) {
> @@ -810,7 +851,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
>  				break;
>  			}
>  
> -			output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
> +			output_term = snd_usb_find_output_terminal_descriptor(badd_ctrl_intf,
>  									      as->bTerminalLink);
>  			if (output_term) {
>  				clock = output_term->bCSourceID;
[...]

It looks like badd_ctrl_inf *always* gets leaked.

Ben.

-- 
Ben Hutchings
Software Developer, Codethink Ltd.

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

  reply	other threads:[~2017-12-13 22:48 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-11-29 10:55 [PATCH 0/6] ALSA: usb: UAC3. Add support for Basic Audio Device (BADD) Jorge Sanjuan
2017-11-29 10:55 ` [PATCH 1/6] ALSA: usb: ADC3: Add initial BADD spec support Jorge Sanjuan
2017-12-13 22:48   ` Ben Hutchings [this message]
2017-11-29 10:55 ` [PATCH 2/6] ALSA: usb: ADC3. BADD specification: fixed 48KHz sample rate Jorge Sanjuan
2017-11-29 10:55 ` [PATCH 3/6] ALSA: usb: ADC3. Do not set sample rate for BADD configuration Jorge Sanjuan
2017-11-29 10:55 ` [PATCH 4/6] usb: audio: Fix variable length field to be variable Jorge Sanjuan
2017-11-29 11:33   ` Clemens Ladisch
2017-11-29 10:55 ` [PATCH 5/6] ALSA: usb: Use Class Specific EP for UAC3 devices Jorge Sanjuan
2017-12-13 22:55   ` [Linux-kernel] " Ben Hutchings
2017-11-29 10:55 ` [PATCH 6/6] ALSA: usb: Only get control header for UAC1 class Jorge Sanjuan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1513205333.18523.270.camel@codethink.co.uk \
    --to=ben.hutchings@codethink.co.uk \
    --cc=alsa-devel@alsa-project.org \
    --cc=jorge.sanjuan@codethink.co.uk \
    --cc=linux-kernel@lists.codethink.co.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).