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
next prev parent 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).