From: John Keeping <john@metanate.com>
To: Pavel Hofman <pavel.hofman@ivitera.com>
Cc: linux-usb@vger.kernel.org,
Ruslan Bilovol <ruslan.bilovol@gmail.com>,
Felipe Balbi <balbi@kernel.org>,
Jerome Brunet <jbrunet@baylibre.com>,
Julian Scheel <julian@jusst.de>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Subject: Re: [PATCH v2 03/11] usb: gadget: f_uac2: Support multiple sampling rates
Date: Tue, 4 Jan 2022 15:33:12 +0000 [thread overview]
Message-ID: <YdRouHVKWDjea6D3@donbot> (raw)
In-Reply-To: <71a8efe9-e515-fe14-c4ec-34c97a16395e@ivitera.com>
On Wed, Dec 22, 2021 at 11:01:16AM +0100, Pavel Hofman wrote:
>
> Dne 21. 12. 21 v 12:59 John Keeping napsal(a):
> > On Mon, Dec 20, 2021 at 10:11:22PM +0100, Pavel Hofman wrote:
> > > From: Julian Scheel <julian@jusst.de>
> > >
> > > A list of sampling rates can be specified via configfs. All enabled
> > > sampling rates are sent to the USB host on request. When the host
> > > selects a sampling rate the internal active rate is updated.
> > >
> > > Config strings with single value stay compatible with the previous version.
> > >
> > > Multiple samplerates passed as configuration arrays to g_audio module
> > > when built for f_uac2.
> > >
> > > Signed-off-by: Julian Scheel <julian@jusst.de>
> > > Signed-off-by: Pavel Hofman <pavel.hofman@ivitera.com>
> > > ---
[snip]
> > > };
> > > static inline struct f_uac2 *func_to_uac2(struct usb_function *f)
> > > @@ -166,7 +167,7 @@ static struct uac_clock_source_descriptor in_clk_src_desc = {
> > > .bDescriptorSubtype = UAC2_CLOCK_SOURCE,
> > > /* .bClockID = DYNAMIC */
> > > .bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED,
> > > - .bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL),
> > > + .bmControls = (CONTROL_RDWR << CLK_FREQ_CTRL),
> > > .bAssocTerminal = 0,
> > > };
> > > @@ -178,7 +179,7 @@ static struct uac_clock_source_descriptor out_clk_src_desc = {
> > > .bDescriptorSubtype = UAC2_CLOCK_SOURCE,
> > > /* .bClockID = DYNAMIC */
> > > .bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED,
> > > - .bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL),
> > > + .bmControls = (CONTROL_RDWR << CLK_FREQ_CTRL),
> > > .bAssocTerminal = 0,
> > > };
> > > @@ -635,12 +636,32 @@ struct cntrl_cur_lay3 {
> > > };
> > > struct cntrl_range_lay3 {
> > > - __le16 wNumSubRanges;
> > > __le32 dMIN;
> > > __le32 dMAX;
> > > __le32 dRES;
> > > } __packed;
> > > +#define ranges_size(c) (sizeof(c.wNumSubRanges) + c.wNumSubRanges \
> > > + * sizeof(struct cntrl_ranges_lay3))
> > > +
> > > +struct cntrl_ranges_lay3 {
> > > + __u16 wNumSubRanges;
> > > + struct cntrl_range_lay3 r[UAC_MAX_RATES];
> > > +} __packed;
> >
> > These structures are now inconsistent between cntrl_range_lay2 and
> > cntrl_range_lay3. Would it be better to make these flex arrays? I
> > guess that will make the code that uses it more complicated, but at the
> > moment it looks like these are trying to be generic while in reality
> > being quite specific to the one place that uses them at the moment.
>
> I am afraid I do not know exactly how to do that. Please can you post an
> example? The rate control requires u32 (u16 is too small). Thanks a lot.
After the change in this patch, we end up with:
struct cntrl_range_lay2 {
__le16 wNumSubRanges;
__le16 wMIN;
__le16 wMAX;
__le16 wRES;
} __packed;
struct cntrl_range_lay3 {
__le32 dMIN;
__le32 dMAX;
__le32 dRES;
} __packed;
so there are two structures with similar names but totally different
structure, which I think risks confusion in the future.
I wonder if DECLARE_UAC2_FEATURE_UNIT_DESCRIPTOR in linux/usb/audio-v2.h
provides inspiration here, so potentially something like:
#define DECLARE_UAC2_CNTRL_RANGE_LAY3(n) \
struct uac2_cntrl_range_lay3_##n { \
__le16 wNumSubRanges; \
struct cntrl_range_le32 r[n]; \
} __packed;
DECLARE_UAC2_CNTRL_RANGE_LAY3(UAC_MAX_RATES);
> > > +static int get_max_srate(const int *srates)
> > > +{
> > > + int i, max_srate = 0;
> > > +
> > > + for (i = 0; i < UAC_MAX_RATES; i++) {
> > > + if (srates[i] == 0)
> > > + break;
> > > + if (srates[i] > max_srate)
> > > + max_srate = srates[i];
> > > + }
> > > + return max_srate;
> > > +}
> > > +
> > > static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
> > > struct usb_endpoint_descriptor *ep_desc,
> > > enum usb_device_speed speed, bool is_playback)
> > > @@ -667,11 +688,11 @@ static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
> > > if (is_playback) {
> > > chmask = uac2_opts->p_chmask;
> > > - srate = uac2_opts->p_srate;
> > > + srate = get_max_srate(uac2_opts->p_srates);
> > > ssize = uac2_opts->p_ssize;
> > > } else {
> > > chmask = uac2_opts->c_chmask;
> > > - srate = uac2_opts->c_srate;
> > > + srate = get_max_srate(uac2_opts->c_srates);
> > > ssize = uac2_opts->c_ssize;
> > > }
> > > @@ -912,10 +933,10 @@ static int afunc_validate_opts(struct g_audio *agdev, struct device *dev)
> > > } else if ((opts->c_ssize < 1) || (opts->c_ssize > 4)) {
> > > dev_err(dev, "Error: incorrect capture sample size\n");
> > > return -EINVAL;
> > > - } else if (!opts->p_srate) {
> > > + } else if (!opts->p_srates[0]) {
> > > dev_err(dev, "Error: incorrect playback sampling rate\n");
> > > return -EINVAL;
> > > - } else if (!opts->c_srate) {
> > > + } else if (!opts->c_srates[0]) {
> > > dev_err(dev, "Error: incorrect capture sampling rate\n");
> > > return -EINVAL;
> > > }
> > > @@ -1210,7 +1231,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
> > > agdev->params.p_chmask = uac2_opts->p_chmask;
> > > agdev->params.p_srate = uac2_opts->p_srate;
> > > - agdev->params.p_srates[0] = uac2_opts->p_srate;
> > > + memcpy(agdev->params.p_srates, uac2_opts->p_srates,
> > > + sizeof(agdev->params.p_srates));
> > > agdev->params.p_ssize = uac2_opts->p_ssize;
> > > if (FUIN_EN(uac2_opts)) {
> > > agdev->params.p_fu.id = USB_IN_FU_ID;
> > > @@ -1222,7 +1244,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
> > > }
> > > agdev->params.c_chmask = uac2_opts->c_chmask;
> > > agdev->params.c_srate = uac2_opts->c_srate;
> > > - agdev->params.c_srates[0] = uac2_opts->c_srate;
> > > + memcpy(agdev->params.c_srates, uac2_opts->c_srates,
> > > + sizeof(agdev->params.c_srates));
> > > agdev->params.c_ssize = uac2_opts->c_ssize;
> > > if (FUOUT_EN(uac2_opts)) {
> > > agdev->params.c_fu.id = USB_OUT_FU_ID;
> > > @@ -1502,28 +1525,39 @@ in_rq_range(struct usb_function *fn, const struct usb_ctrlrequest *cr)
> > > u8 entity_id = (w_index >> 8) & 0xff;
> > > u8 control_selector = w_value >> 8;
> > > int value = -EOPNOTSUPP;
> > > - int p_srate, c_srate;
> > > -
> > > - p_srate = opts->p_srate;
> > > - c_srate = opts->c_srate;
> > > if ((entity_id == USB_IN_CLK_ID) || (entity_id == USB_OUT_CLK_ID)) {
> > > if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) {
> > > - struct cntrl_range_lay3 r;
> > > + struct cntrl_ranges_lay3 rs;
> > > + int i;
> > > + int wNumSubRanges = 0;
> > > + int srate;
> > > + int *srates;
> > > if (entity_id == USB_IN_CLK_ID)
> > > - r.dMIN = cpu_to_le32(p_srate);
> > > + srates = opts->p_srates;
> > > else if (entity_id == USB_OUT_CLK_ID)
> > > - r.dMIN = cpu_to_le32(c_srate);
> > > + srates = opts->c_srates;
> > > else
> > > return -EOPNOTSUPP;
> > > -
> > > - r.dMAX = r.dMIN;
> > > - r.dRES = 0;
> > > - r.wNumSubRanges = cpu_to_le16(1);
> > > -
> > > - value = min_t(unsigned int, w_length, sizeof(r));
> > > - memcpy(req->buf, &r, value);
> > > + for (i = 0; i < UAC_MAX_RATES; i++) {
> > > + srate = srates[i];
> > > + if (srate == 0)
> > > + break;
> > > +
> > > + rs.r[wNumSubRanges].dMIN = cpu_to_le32(srate);
> > > + rs.r[wNumSubRanges].dMAX = cpu_to_le32(srate);
> > > + rs.r[wNumSubRanges].dRES = 0;
> > > + wNumSubRanges++;
> > > + dev_dbg(&agdev->gadget->dev,
> > > + "%s(): clk %d: rate ID %d: %d\n",
> > > + __func__, entity_id, wNumSubRanges, srate);
> > > + }
> > > + rs.wNumSubRanges = cpu_to_le16(wNumSubRanges);
> > > + value = min_t(unsigned int, w_length, ranges_size(rs));
> > > + dev_dbg(&agdev->gadget->dev, "%s(): sending %d rates, size %d\n",
> > > + __func__, rs.wNumSubRanges, value);
> > > + memcpy(req->buf, &rs, value);
> > > } else {
> > > dev_err(&agdev->gadget->dev,
> > > "%s:%d control_selector=%d TODO!\n",
> > > @@ -1582,6 +1616,28 @@ ac_rq_in(struct usb_function *fn, const struct usb_ctrlrequest *cr)
> > > return -EOPNOTSUPP;
> > > }
> > > +static void uac2_cs_control_sam_freq(struct usb_ep *ep, struct usb_request *req)
> > > +{
> > > + struct usb_function *fn = ep->driver_data;
> > > + struct g_audio *agdev = func_to_g_audio(fn);
> > > + struct f_uac2 *uac2 = func_to_uac2(fn);
> > > + struct f_uac2_opts *opts = g_audio_to_uac2_opts(agdev);
> > > + u32 val;
> > > +
> > > + if (req->actual != 4)
> > > + return;
> > > +
> > > + val = le32_to_cpu(*((u32 *)req->buf));
> > > + dev_dbg(&agdev->gadget->dev, "%s val: %d.\n", __func__, val);
> > > + if (uac2->ctl_id == USB_IN_CLK_ID) {
> > > + opts->p_srate = val;
> >
> > Don't you need to hold opts->lock to change this?
> > I'm not sure opts should be changed here though - that's the setup phase
> > and this is "current state", so shouldn't it move to struct f_uac2?
>
> OK. I moved the current p_srate/c_srate from struct opts to f_uac2,
> initialized with first value of opts->p_srates/c_srates[0] in afunc_bind.
> The struct f_uac2 has no lock yet. Should I add the lock mutex to f_uac2 and
> be locking f_uac2 access here in uac2_cs_control_sam_freq?
Could we move this into struct uac_rtd_params and use the existing lock
there to guard it?
It would need accessor functions as that structure's local to u_audio.c,
but there's already u_audio_set_playback_srate() so that isn't a big
change.
John
next prev parent reply other threads:[~2022-01-04 15:33 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-12-20 21:11 [PATCH v2 00/11] usb: gadget: audio: Multiple rates, dyn. bInterval Pavel Hofman
2021-12-20 21:11 ` [PATCH v2 01/11] usb: gadget: u_audio: Subdevice 0 for capture ctls Pavel Hofman
2021-12-20 21:11 ` [PATCH v2 02/11] usb: gadget: u_audio: Support multiple sampling rates Pavel Hofman
2021-12-21 11:35 ` John Keeping
2021-12-22 7:13 ` Pavel Hofman
2022-01-04 15:32 ` John Keeping
2022-01-05 10:55 ` Pavel Hofman
2021-12-20 21:11 ` [PATCH v2 03/11] usb: gadget: f_uac2: " Pavel Hofman
2021-12-21 11:59 ` John Keeping
2021-12-22 10:01 ` Pavel Hofman
2022-01-04 15:33 ` John Keeping [this message]
2022-01-05 12:20 ` Pavel Hofman
2022-01-05 12:44 ` John Keeping
2022-01-05 14:05 ` Pavel Hofman
2022-01-06 8:45 ` Pavel Hofman
2021-12-20 21:11 ` [PATCH v2 04/11] usb: gadget: f_uac1: " Pavel Hofman
2021-12-20 21:11 ` [PATCH v2 05/11] usb: gadget: f_uac2: Renaming Clock Sources to fixed names Pavel Hofman
2021-12-21 12:02 ` John Keeping
2021-12-22 10:11 ` Pavel Hofman
2021-12-20 21:11 ` [PATCH v2 06/11] usb: gadget: u_audio: Rate ctl notifies about current srate (0=stopped) Pavel Hofman
2021-12-21 12:07 ` John Keeping
2021-12-22 10:41 ` Pavel Hofman
2021-12-20 21:11 ` [PATCH v2 07/11] usb: gadget: u_audio: Stopping PCM substream at capture/playback stop Pavel Hofman
2021-12-21 12:18 ` John Keeping
2021-12-22 12:26 ` Pavel Hofman
2021-12-28 9:04 ` [RFC: PATCH " Pavel Hofman
2021-12-20 21:11 ` [PATCH v2 08/11] usb: gadget: u_audio: Adding suspend call Pavel Hofman
2021-12-20 21:11 ` [PATCH v2 09/11] usb: gadget: f_uac2: Adding suspend callback Pavel Hofman
2021-12-20 21:11 ` [PATCH v2 10/11] usb: gadget: f_uac1: " Pavel Hofman
2021-12-20 21:11 ` [PATCH v2 11/11] usb: gadget: f_uac2: Determining bInterval for HS and SS Pavel Hofman
2021-12-21 12:29 ` John Keeping
2021-12-22 13:35 ` Pavel Hofman
2021-12-22 19:50 ` John Keeping
2021-12-23 7:09 ` Pavel Hofman
2022-01-04 15:33 ` John Keeping
2022-01-05 11:31 ` Pavel Hofman
2022-01-06 14:32 ` John Keeping
2022-01-07 10:30 ` Pavel Hofman
2021-12-21 7:59 ` [PATCH v2 00/11] usb: gadget: audio: Multiple rates, dyn. bInterval Greg Kroah-Hartman
2021-12-22 13:38 ` Pavel Hofman
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=YdRouHVKWDjea6D3@donbot \
--to=john@metanate.com \
--cc=balbi@kernel.org \
--cc=gregkh@linuxfoundation.org \
--cc=jbrunet@baylibre.com \
--cc=julian@jusst.de \
--cc=linux-usb@vger.kernel.org \
--cc=pavel.hofman@ivitera.com \
--cc=ruslan.bilovol@gmail.com \
/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).