usb: gadget: f_uac1: finalize wMaxPacketSize according to bandwidth

According to USB Audio Device 1.0 Spec, Ch4.6.1.1:
The wMaxPacketSize of endpoint is defined as follows:
Maximum packet size of endpoint is capable of sending
or receiving when this configuration is selected. This
is determined by the audio bandwidth constraints of
the endpoint.

In current code, the wMaxPacketSize is limited to 200,
and the bInterval is set to 4 (1ms). That is, the maximum
bandwidth over USB bus is 200 * 1000 = 200000 bytes.

We find an issue about bandwidth limitation when we try to
support UAC1 with 8ch * 16bit * 16KHz on RK3308 platform,
which needs more bandwidth than it can support.

This patch sets the wMaxPacketSize dynamically according
to the parameters of UAC1. It is similar to the same thing
done earlier for f_uac2.

Change-Id: I9af3fd7665a80b5eb0cfb5dc91ebe2c20df1dd46
Signed-off-by: William Wu <william.wu@rock-chips.com>
This commit is contained in:
William Wu
2021-05-13 11:59:21 +08:00
committed by Tao Huang
parent 3a54d14600
commit 573d2e1e2e

View File

@@ -246,7 +246,7 @@ static struct usb_endpoint_descriptor as_out_ep_desc = {
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_SYNC_ADAPTIVE
| USB_ENDPOINT_XFER_ISOC,
.wMaxPacketSize = cpu_to_le16(UAC1_OUT_EP_MAX_PACKET_SIZE),
/* .wMaxPacketSize = DYNAMIC */
.bInterval = 4,
};
@@ -277,7 +277,7 @@ static struct usb_endpoint_descriptor as_in_ep_desc = {
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_SYNC_ASYNC
| USB_ENDPOINT_XFER_ISOC,
.wMaxPacketSize = cpu_to_le16(UAC1_OUT_EP_MAX_PACKET_SIZE),
/* .wMaxPacketSize = DYNAMIC */
.bInterval = 4,
};
@@ -808,6 +808,57 @@ static void setup_descriptor(struct f_uac_opts *opts)
f_audio_desc[i++] = NULL;
}
static int set_ep_max_packet_size(const struct f_uac_opts *opts,
struct usb_endpoint_descriptor *ep_desc,
enum usb_device_speed speed, bool is_playback)
{
int chmask, srate = 0, ssize;
u16 max_size_bw, max_size_ep;
unsigned int factor;
int i;
switch (speed) {
case USB_SPEED_FULL:
max_size_ep = 1023;
factor = 1000;
break;
case USB_SPEED_HIGH:
max_size_ep = 1024;
factor = 8000;
break;
default:
return -EINVAL;
}
if (is_playback) {
chmask = opts->p_chmask;
for (i = 0; i < UAC_MAX_RATES; i++) {
if (opts->p_srate[i] == 0)
break;
if (opts->p_srate[i] > srate)
srate = opts->p_srate[i];
}
ssize = opts->p_ssize;
} else {
chmask = opts->c_chmask;
for (i = 0; i < UAC_MAX_RATES; i++) {
if (opts->c_srate[i] == 0)
break;
if (opts->c_srate[i] > srate)
srate = opts->c_srate[i];
}
ssize = opts->c_ssize;
}
max_size_bw = num_channels(chmask) * ssize *
((srate / (factor / (1 << (ep_desc->bInterval - 1)))) + 1);
ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw,
max_size_ep));
return 0;
}
/* audio function driver setup/binding */
static int f_audio_bind(struct usb_configuration *c, struct usb_function *f)
@@ -819,6 +870,7 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f)
struct f_uac_opts *audio_opts;
struct usb_ep *ep = NULL;
struct usb_string *us;
struct device *dev = &gadget->dev;
int status;
int idx, i;
@@ -862,6 +914,27 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f)
memcpy(as_out_type_i_desc.tSamFreq[idx++],
&audio_opts->c_srate[i], 3);
}
/*
* Calculate wMaxPacketSize according to audio bandwidth.
* Set the max packet with USB_SPEED_HIGH by default to
* be compatible with larger bandwidth requirements for
* high speed mode.
*/
status = set_ep_max_packet_size(audio_opts, &as_out_ep_desc,
USB_SPEED_HIGH, false);
if (status < 0) {
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
goto fail;
}
status = set_ep_max_packet_size(audio_opts, &as_in_ep_desc,
USB_SPEED_HIGH, true);
if (status < 0) {
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
goto fail;
}
as_out_type_i_desc.bLength = UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(idx);
as_out_type_i_desc.bSamFreqType = idx;