Revert "FROMLIST: usb: gadget: f_uac*: Support multiple sampling rates"

This reverts commit 37ed8f4607.

Signed-off-by: Tao Huang <huangtao@rock-chips.com>
Change-Id: Id61128a4036dbc8384bc60da8f8a586b9b697800
This commit is contained in:
Tao Huang
2021-12-01 19:50:18 +08:00
parent 1b310c9a83
commit 1e50aec536
5 changed files with 76 additions and 392 deletions

View File

@@ -3,7 +3,6 @@
* f_uac1.c -- USB Audio Class 1.0 Function (using u_audio API)
*
* Copyright (C) 2016 Ruslan Bilovol <ruslan.bilovol@gmail.com>
* Copyright (C) 2017 Julian Scheel <julian@jusst.de>
*
* This driver doesn't expect any real Audio codec to be present
* on the device - the audio streams are simply sinked to and
@@ -183,18 +182,16 @@ static struct uac1_as_header_descriptor as_in_header_desc = {
.wFormatTag = cpu_to_le16(UAC_FORMAT_TYPE_I_PCM),
};
DECLARE_UAC_FORMAT_TYPE_I_DISCRETE_DESC(UAC_MAX_RATES);
#define uac_format_type_i_discrete_descriptor \
uac_format_type_i_discrete_descriptor_##UAC_MAX_RATES
DECLARE_UAC_FORMAT_TYPE_I_DISCRETE_DESC(1);
static struct uac_format_type_i_discrete_descriptor as_out_type_i_desc = {
.bLength = 0, /* filled on rate setup */
static struct uac_format_type_i_discrete_descriptor_1 as_out_type_i_desc = {
.bLength = UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_FORMAT_TYPE,
.bFormatType = UAC_FORMAT_TYPE_I,
.bSubframeSize = 2,
.bBitResolution = 16,
.bSamFreqType = 0, /* filled on rate setup */
.bSamFreqType = 1,
};
/* Standard ISO OUT Endpoint Descriptor */
@@ -218,14 +215,14 @@ static struct uac_iso_endpoint_descriptor as_iso_out_desc = {
.wLockDelay = cpu_to_le16(1),
};
static struct uac_format_type_i_discrete_descriptor as_in_type_i_desc = {
.bLength = 0, /* filled on rate setup */
static struct uac_format_type_i_discrete_descriptor_1 as_in_type_i_desc = {
.bLength = UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_FORMAT_TYPE,
.bFormatType = UAC_FORMAT_TYPE_I,
.bSubframeSize = 2,
.bBitResolution = 16,
.bSamFreqType = 0, /* filled on rate setup */
.bSamFreqType = 1,
};
/* Standard ISO OUT Endpoint Descriptor */
@@ -324,57 +321,23 @@ static struct usb_gadget_strings *uac1_strings[] = {
* This function is an ALSA sound card following USB Audio Class Spec 1.0.
*/
static void uac_cs_attr_sample_rate(struct usb_ep *ep, struct usb_request *req)
{
struct usb_function *fn = ep->driver_data;
struct usb_composite_dev *cdev = fn->config->cdev;
struct g_audio *agdev = func_to_g_audio(fn);
struct f_uac *uac1 = func_to_uac(fn);
struct f_uac_opts *opts = g_audio_to_uac_opts(agdev);
u8 *buf = (u8 *)req->buf;
u32 val = 0;
if (req->actual != 3) {
WARN(cdev, "Invalid data size for UAC_EP_CS_ATTR_SAMPLE_RATE.\n");
return;
}
val = buf[0] | (buf[1] << 8) | (buf[2] << 16);
if (uac1->ctl_id == agdev->in_ep->address) {
opts->p_srate_active = val;
u_audio_set_playback_srate(agdev, opts->p_srate_active);
} else if (uac1->ctl_id == agdev->out_ep->address) {
opts->c_srate_active = val;
u_audio_set_capture_srate(agdev, opts->c_srate_active);
}
}
static int audio_set_endpoint_req(struct usb_function *f,
const struct usb_ctrlrequest *ctrl)
{
struct usb_composite_dev *cdev = f->config->cdev;
struct usb_request *req = f->config->cdev->req;
struct f_uac *uac1 = func_to_uac(f);
int value = -EOPNOTSUPP;
u8 ep = le16_to_cpu(ctrl->wIndex) & 0xff;
u16 len = le16_to_cpu(ctrl->wLength);
u16 w_value = le16_to_cpu(ctrl->wValue);
u8 cs = w_value >> 8;
DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
ctrl->bRequest, w_value, len, ep);
switch (ctrl->bRequest) {
case UAC_SET_CUR: {
if (cs == UAC_EP_CS_ATTR_SAMPLE_RATE) {
cdev->gadget->ep0->driver_data = f;
uac1->ctl_id = ep;
req->complete = uac_cs_attr_sample_rate;
}
case UAC_SET_CUR:
value = len;
break;
}
case UAC_SET_MIN:
break;
@@ -398,34 +361,16 @@ static int audio_get_endpoint_req(struct usb_function *f,
const struct usb_ctrlrequest *ctrl)
{
struct usb_composite_dev *cdev = f->config->cdev;
struct usb_request *req = f->config->cdev->req;
struct g_audio *agdev = func_to_g_audio(f);
struct f_uac_opts *opts = g_audio_to_uac_opts(agdev);
u8 *buf = (u8 *)req->buf;
int value = -EOPNOTSUPP;
u8 ep = le16_to_cpu(ctrl->wIndex) & 0xff;
u16 len = le16_to_cpu(ctrl->wLength);
u16 w_value = le16_to_cpu(ctrl->wValue);
u8 cs = w_value >> 8;
u32 val = 0;
DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
ctrl->bRequest, w_value, len, ep);
switch (ctrl->bRequest) {
case UAC_GET_CUR: {
if (cs == UAC_EP_CS_ATTR_SAMPLE_RATE) {
if (ep == agdev->in_ep->address)
val = opts->p_srate_active;
else if (ep == agdev->out_ep->address)
val = opts->c_srate_active;
buf[2] = (val >> 16) & 0xff;
buf[1] = (val >> 8) & 0xff;
buf[0] = val & 0xff;
}
value = len;
break;
}
case UAC_GET_CUR:
case UAC_GET_MIN:
case UAC_GET_MAX:
case UAC_GET_RES:
@@ -573,8 +518,9 @@ 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;
u8 *sam_freq;
int rate;
int status;
int idx, i;
audio_opts = container_of(f->fi, struct f_uac_opts, func_inst);
@@ -608,23 +554,12 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f)
as_in_type_i_desc.bBitResolution = audio_opts->p_ssize * 8;
/* Set sample rates */
for (i = 0, idx = 0; i < UAC_MAX_RATES; i++) {
if (audio_opts->c_srate[i] == 0)
break;
memcpy(as_out_type_i_desc.tSamFreq[idx++],
&audio_opts->c_srate[i], 3);
}
as_out_type_i_desc.bLength = UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(idx);
as_out_type_i_desc.bSamFreqType = idx;
for (i = 0, idx = 0; i < UAC_MAX_RATES; i++) {
if (audio_opts->p_srate[i] == 0)
break;
memcpy(as_in_type_i_desc.tSamFreq[idx++],
&audio_opts->p_srate[i], 3);
}
as_in_type_i_desc.bLength = UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(idx);
as_in_type_i_desc.bSamFreqType = idx;
rate = audio_opts->c_srate;
sam_freq = as_out_type_i_desc.tSamFreq[0];
memcpy(sam_freq, &rate, 3);
rate = audio_opts->p_srate;
sam_freq = as_in_type_i_desc.tSamFreq[0];
memcpy(sam_freq, &rate, 3);
/* allocate instance-specific interface IDs, and patch descriptors */
status = usb_interface_id(c, f);
@@ -679,14 +614,10 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f)
audio->out_ep_maxpsize = le16_to_cpu(as_out_ep_desc.wMaxPacketSize);
audio->in_ep_maxpsize = le16_to_cpu(as_in_ep_desc.wMaxPacketSize);
audio->params.c_chmask = audio_opts->c_chmask;
memcpy(audio->params.c_srate, audio_opts->c_srate,
sizeof(audio->params.c_srate));
audio->params.c_srate_active = audio_opts->c_srate_active;
audio->params.c_srate = audio_opts->c_srate;
audio->params.c_ssize = audio_opts->c_ssize;
audio->params.p_chmask = audio_opts->p_chmask;
memcpy(audio->params.p_srate, audio_opts->p_srate,
sizeof(audio->params.p_srate));
audio->params.p_srate_active = audio_opts->p_srate_active;
audio->params.p_srate = audio_opts->p_srate;
audio->params.p_ssize = audio_opts->p_ssize;
audio->params.req_number = audio_opts->req_number;
@@ -709,14 +640,13 @@ static struct configfs_item_operations f_uac1_item_ops = {
};
UAC_ATTRIBUTE(c_chmask);
UAC_ATTRIBUTE(c_srate);
UAC_ATTRIBUTE(c_ssize);
UAC_ATTRIBUTE(p_chmask);
UAC_ATTRIBUTE(p_srate);
UAC_ATTRIBUTE(p_ssize);
UAC_ATTRIBUTE(req_number);
UAC_RATE_ATTRIBUTE(p_srate);
UAC_RATE_ATTRIBUTE(c_srate);
static struct configfs_attribute *f_uac1_attrs[] = {
&f_uac_opts_attr_c_chmask,
&f_uac_opts_attr_c_srate,
@@ -757,12 +687,10 @@ static struct usb_function_instance *f_audio_alloc_inst(void)
&f_uac1_func_type);
opts->c_chmask = UAC_DEF_CCHMASK;
opts->c_srate[0] = UAC_DEF_CSRATE;
opts->c_srate_active = UAC_DEF_CSRATE;
opts->c_srate = UAC_DEF_CSRATE;
opts->c_ssize = UAC_DEF_CSSIZE;
opts->p_chmask = UAC_DEF_PCHMASK;
opts->p_srate[0] = UAC_DEF_PSRATE;
opts->p_srate_active = UAC_DEF_PSRATE;
opts->p_srate = UAC_DEF_PSRATE;
opts->p_ssize = UAC_DEF_PSSIZE;
opts->req_number = UAC_DEF_REQ_NUM;
return &opts->func_inst;

View File

@@ -5,7 +5,6 @@
* Copyright (C) 2011
* Yadwinder Singh (yadi.brar01@gmail.com)
* Jaswinder Singh (jaswinder.singh@linaro.org)
* Copyright (C) 2017 Julian Scheel <julian@jusst.de>
*/
#include <linux/usb/audio.h>
@@ -60,11 +59,14 @@ enum {
STR_AS_IN_ALT1,
};
static char clksrc_in[8];
static char clksrc_out[8];
static struct usb_string strings_fn[] = {
[STR_ASSOC].s = "Source/Sink",
[STR_IF_CTRL].s = "Topology Control",
[STR_CLKSRC_IN].s = "Input clock",
[STR_CLKSRC_OUT].s = "Output clock",
[STR_CLKSRC_IN].s = clksrc_in,
[STR_CLKSRC_OUT].s = clksrc_out,
[STR_USB_IT].s = "USBH Out",
[STR_IO_IT].s = "USBD Out",
[STR_USB_OT].s = "USBH In",
@@ -117,7 +119,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_RDWR << CLK_FREQ_CTRL),
.bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL),
.bAssocTerminal = 0,
};
@@ -129,7 +131,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_RDWR << CLK_FREQ_CTRL),
.bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL),
.bAssocTerminal = 0,
};
@@ -422,26 +424,19 @@ 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;
static int set_ep_max_packet_size(const struct f_uac_opts *uac2_opts,
struct usb_endpoint_descriptor *ep_desc,
enum usb_device_speed speed, bool is_playback)
{
int chmask, srate = 0, ssize;
int chmask, srate, ssize;
u16 max_size_bw, max_size_ep;
unsigned int factor;
int i;
switch (speed) {
case USB_SPEED_FULL:
@@ -460,21 +455,11 @@ static int set_ep_max_packet_size(const struct f_uac_opts *uac2_opts,
if (is_playback) {
chmask = uac2_opts->p_chmask;
for (i = 0; i < UAC_MAX_RATES; i++) {
if (uac2_opts->p_srate[i] == 0)
break;
if (uac2_opts->p_srate[i] > srate)
srate = uac2_opts->p_srate[i];
}
srate = uac2_opts->p_srate;
ssize = uac2_opts->p_ssize;
} else {
chmask = uac2_opts->c_chmask;
for (i = 0; i < UAC_MAX_RATES; i++) {
if (uac2_opts->c_srate[i] == 0)
break;
if (uac2_opts->c_srate[i] > srate)
srate = uac2_opts->c_srate[i];
}
srate = uac2_opts->c_srate;
ssize = uac2_opts->c_ssize;
}
@@ -650,6 +635,9 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
as_in_fmt1_desc.bSubslotSize = uac2_opts->p_ssize;
as_in_fmt1_desc.bBitResolution = uac2_opts->p_ssize * 8;
snprintf(clksrc_in, sizeof(clksrc_in), "%uHz", uac2_opts->p_srate);
snprintf(clksrc_out, sizeof(clksrc_out), "%uHz", uac2_opts->c_srate);
ret = usb_interface_id(cfg, fn);
if (ret < 0) {
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
@@ -750,14 +738,10 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
agdev->gadget = gadget;
agdev->params.p_chmask = uac2_opts->p_chmask;
memcpy(agdev->params.p_srate, uac2_opts->p_srate,
sizeof(agdev->params.p_srate));
agdev->params.p_srate_active = uac2_opts->p_srate_active;
agdev->params.p_srate = uac2_opts->p_srate;
agdev->params.p_ssize = uac2_opts->p_ssize;
agdev->params.c_chmask = uac2_opts->c_chmask;
memcpy(agdev->params.c_srate, uac2_opts->c_srate,
sizeof(agdev->params.c_srate));
agdev->params.c_srate_active = uac2_opts->c_srate_active;
agdev->params.c_srate = uac2_opts->c_srate;
agdev->params.c_ssize = uac2_opts->c_ssize;
agdev->params.req_number = uac2_opts->req_number;
ret = g_audio_setup(agdev, "UAC2 PCM", "UAC2_Gadget");
@@ -863,8 +847,8 @@ in_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr)
int p_srate, c_srate;
opts = g_audio_to_uac_opts(agdev);
p_srate = opts->p_srate_active;
c_srate = opts->c_srate_active;
p_srate = opts->p_srate;
c_srate = opts->c_srate;
if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) {
struct cntrl_cur_lay3 c;
@@ -875,7 +859,6 @@ in_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr)
else if (entity_id == USB_OUT_CLK_ID)
c.dCUR = cpu_to_le32(c_srate);
DBG(fn->config->cdev, "%s(): %d\n", __func__, c.dCUR);
value = min_t(unsigned, w_length, sizeof c);
memcpy(req->buf, &c, value);
} else if (control_selector == UAC2_CS_CONTROL_CLOCK_VALID) {
@@ -901,40 +884,28 @@ in_rq_range(struct usb_function *fn, const struct usb_ctrlrequest *cr)
u16 w_value = le16_to_cpu(cr->wValue);
u8 entity_id = (w_index >> 8) & 0xff;
u8 control_selector = w_value >> 8;
struct cntrl_ranges_lay3 rs;
struct cntrl_range_lay3 r;
int value = -EOPNOTSUPP;
int srate = 0;
int i;
int p_srate, c_srate;
opts = g_audio_to_uac_opts(agdev);
p_srate = opts->p_srate;
c_srate = opts->c_srate;
if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) {
rs.wNumSubRanges = 0;
for (i = 0; i < UAC_MAX_RATES; i++) {
if (entity_id == USB_IN_CLK_ID)
srate = opts->p_srate[i];
else if (entity_id == USB_OUT_CLK_ID)
srate = opts->c_srate[i];
else
return -EOPNOTSUPP;
if (entity_id == USB_IN_CLK_ID)
r.dMIN = cpu_to_le32(p_srate);
else if (entity_id == USB_OUT_CLK_ID)
r.dMIN = cpu_to_le32(c_srate);
else
return -EOPNOTSUPP;
if (srate == 0)
break;
r.dMAX = r.dMIN;
r.dRES = 0;
r.wNumSubRanges = cpu_to_le16(1);
rs.r[rs.wNumSubRanges].dMIN = srate;
rs.r[rs.wNumSubRanges].dMAX = srate;
rs.r[rs.wNumSubRanges].dRES = 0;
rs.wNumSubRanges++;
DBG(fn->config->cdev,
"%s(): clk %d: report rate %d. %d\n",
__func__, entity_id, rs.wNumSubRanges,
srate);
}
value = min_t(unsigned int, w_length, ranges_size(rs));
DBG(fn->config->cdev, "%s(): send %d rates, size %d\n",
__func__, rs.wNumSubRanges, value);
memcpy(req->buf, &rs, value);
value = min_t(unsigned, w_length, sizeof r);
memcpy(req->buf, &r, value);
} else {
dev_err(&agdev->gadget->dev,
"%s:%d control_selector=%d TODO!\n",
@@ -947,7 +918,6 @@ in_rq_range(struct usb_function *fn, const struct usb_ctrlrequest *cr)
static int
ac_rq_in(struct usb_function *fn, const struct usb_ctrlrequest *cr)
{
DBG(fn->config->cdev, "%s(): %d\n", __func__, cr->bRequest);
if (cr->bRequest == UAC2_CS_CUR)
return in_rq_cur(fn, cr);
else if (cr->bRequest == UAC2_CS_RANGE)
@@ -956,50 +926,15 @@ 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 usb_composite_dev *cdev = fn->config->cdev;
struct g_audio *agdev = func_to_g_audio(fn);
struct f_uac *uac2 = func_to_uac(fn);
struct f_uac_opts *opts = g_audio_to_uac_opts(agdev);
u32 val;
if (req->actual != 4) {
WARN(cdev, "Invalid data size for UAC2_CS_CONTROL_SAM_FREQ.\n");
return;
}
val = le32_to_cpu(*((u32 *)req->buf));
if (uac2->ctl_id == USB_IN_CLK_ID) {
opts->p_srate_active = val;
u_audio_set_playback_srate(agdev, opts->p_srate_active);
} else if (uac2->ctl_id == USB_OUT_CLK_ID) {
opts->c_srate_active = val;
u_audio_set_capture_srate(agdev, opts->c_srate_active);
}
}
static int
out_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr)
{
struct usb_composite_dev *cdev = fn->config->cdev;
struct usb_request *req = cdev->req;
u16 w_length = le16_to_cpu(cr->wLength);
struct f_uac *uac2 = func_to_uac(fn);
u16 w_value = le16_to_cpu(cr->wValue);
u16 w_index = le16_to_cpu(cr->wIndex);
u8 control_selector = w_value >> 8;
u8 clock_id = w_index >> 8;
if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) {
DBG(cdev, "control_selector UAC2_CS_CONTROL_SAM_FREQ, clock: %d\n",
clock_id);
cdev->gadget->ep0->driver_data = fn;
uac2->ctl_id = clock_id;
req->complete = uac2_cs_control_sam_freq;
if (control_selector == UAC2_CS_CONTROL_SAM_FREQ)
return w_length;
}
return -EOPNOTSUPP;
}
@@ -1064,14 +999,13 @@ static struct configfs_item_operations f_uac2_item_ops = {
};
UAC_ATTRIBUTE(p_chmask);
UAC_ATTRIBUTE(p_srate);
UAC_ATTRIBUTE(p_ssize);
UAC_ATTRIBUTE(c_chmask);
UAC_ATTRIBUTE(c_srate);
UAC_ATTRIBUTE(c_ssize);
UAC_ATTRIBUTE(req_number);
UAC_RATE_ATTRIBUTE(p_srate);
UAC_RATE_ATTRIBUTE(c_srate);
static struct configfs_attribute *f_uac2_attrs[] = {
&f_uac_opts_attr_p_chmask,
&f_uac_opts_attr_p_srate,
@@ -1112,12 +1046,10 @@ static struct usb_function_instance *afunc_alloc_inst(void)
&f_uac2_func_type);
opts->p_chmask = UAC_DEF_PCHMASK;
opts->p_srate[0] = UAC_DEF_PSRATE;
opts->p_srate_active = UAC_DEF_PSRATE;
opts->p_srate = UAC_DEF_PSRATE;
opts->p_ssize = UAC_DEF_PSSIZE;
opts->c_chmask = UAC_DEF_CCHMASK;
opts->c_srate[0] = UAC_DEF_CSRATE;
opts->c_srate_active = UAC_DEF_CSRATE;
opts->c_srate = UAC_DEF_CSRATE;
opts->c_ssize = UAC_DEF_CSSIZE;
opts->req_number = UAC_DEF_REQ_NUM;
return &opts->func_inst;

View File

@@ -13,7 +13,6 @@
*/
#include <linux/module.h>
#include <sound/control.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -249,17 +248,18 @@ static int uac_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_uac_chip *uac = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct g_audio *audio_dev = uac->audio_dev;
struct g_audio *audio_dev;
struct uac_params *params;
int p_ssize, c_ssize;
int p_srate, c_srate;
int p_chmask, c_chmask;
audio_dev = uac->audio_dev;
params = &audio_dev->params;
p_ssize = params->p_ssize;
c_ssize = params->c_ssize;
p_srate = params->p_srate_active;
c_srate = params->c_srate_active;
p_srate = params->p_srate;
c_srate = params->c_srate;
p_chmask = params->p_chmask;
c_chmask = params->c_chmask;
uac->p_residue = 0;
@@ -288,52 +288,6 @@ static int uac_pcm_open(struct snd_pcm_substream *substream)
return 0;
}
static int uac_pcm_rate_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 324000;
return 0;
}
static int uac_pcm_rate_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_uac_chip *uac = snd_kcontrol_chip(kcontrol);
struct g_audio *audio_dev = uac->audio_dev;
struct uac_params *params = &audio_dev->params;
if (kcontrol->private_value == SNDRV_PCM_STREAM_CAPTURE)
ucontrol->value.integer.value[0] = params->c_srate_active;
else if (kcontrol->private_value == SNDRV_PCM_STREAM_PLAYBACK)
ucontrol->value.integer.value[0] = params->p_srate_active;
else
return -EINVAL;
return 0;
}
static struct snd_kcontrol_new uac_pcm_controls[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "Capture Rate",
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
.info = uac_pcm_rate_info,
.get = uac_pcm_rate_get,
.private_value = SNDRV_PCM_STREAM_CAPTURE,
},
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "Playback Rate",
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
.info = uac_pcm_rate_info,
.get = uac_pcm_rate_get,
.private_value = SNDRV_PCM_STREAM_PLAYBACK,
},
};
/* ALSA cries without these function pointers */
static int uac_pcm_null(struct snd_pcm_substream *substream)
{
@@ -381,59 +335,6 @@ static inline void free_ep(struct uac_rtd_params *prm, struct usb_ep *ep)
dev_err(uac->card->dev, "%s:%d Error!\n", __func__, __LINE__);
}
static struct snd_kcontrol *u_audio_get_ctl(struct g_audio *audio_dev,
const char *name)
{
struct snd_ctl_elem_id elem_id;
memset(&elem_id, 0, sizeof(elem_id));
elem_id.iface = SNDRV_CTL_ELEM_IFACE_PCM;
strlcpy(elem_id.name, name, sizeof(elem_id.name));
return snd_ctl_find_id(audio_dev->uac->card, &elem_id);
}
int u_audio_set_capture_srate(struct g_audio *audio_dev, int srate)
{
struct snd_kcontrol *ctl = u_audio_get_ctl(audio_dev, "Capture Rate");
struct uac_params *params = &audio_dev->params;
int i;
for (i = 0; i < UAC_MAX_RATES; i++) {
if (params->c_srate[i] == srate) {
params->c_srate_active = srate;
snd_ctl_notify(audio_dev->uac->card,
SNDRV_CTL_EVENT_MASK_VALUE, &ctl->id);
return 0;
}
if (params->c_srate[i] == 0)
break;
}
return -EINVAL;
}
EXPORT_SYMBOL_GPL(u_audio_set_capture_srate);
int u_audio_set_playback_srate(struct g_audio *audio_dev, int srate)
{
struct snd_kcontrol *ctl = u_audio_get_ctl(audio_dev, "Playback Rate");
struct uac_params *params = &audio_dev->params;
int i;
for (i = 0; i < UAC_MAX_RATES; i++) {
if (params->p_srate[i] == srate) {
params->p_srate_active = srate;
snd_ctl_notify(audio_dev->uac->card,
SNDRV_CTL_EVENT_MASK_VALUE, &ctl->id);
return 0;
}
if (params->p_srate[i] == 0)
break;
}
return -EINVAL;
}
EXPORT_SYMBOL_GPL(u_audio_set_playback_srate);
int u_audio_start_capture(struct g_audio *audio_dev)
{
struct snd_uac_chip *uac = audio_dev->uac;
@@ -493,11 +394,10 @@ int u_audio_start_playback(struct g_audio *audio_dev)
struct usb_ep *ep;
struct uac_rtd_params *prm;
struct uac_params *params = &audio_dev->params;
unsigned int factor, rate;
unsigned int factor;
const struct usb_endpoint_descriptor *ep_desc;
int req_len, i;
dev_dbg(dev, "start playback with rate %d\n", params->p_srate_active);
ep = audio_dev->in_ep;
prm = &uac->p_prm;
config_ep_by_speed(gadget, &audio_dev->func, ep);
@@ -513,13 +413,15 @@ int u_audio_start_playback(struct g_audio *audio_dev)
/* pre-compute some values for iso_complete() */
uac->p_framesize = params->p_ssize *
num_channels(params->p_chmask);
rate = params->p_srate_active * uac->p_framesize;
uac->p_interval = factor / (1 << (ep_desc->bInterval - 1));
uac->p_pktsize = min_t(unsigned int, rate / uac->p_interval,
uac->p_pktsize = min_t(unsigned int,
uac->p_framesize *
(params->p_srate / uac->p_interval),
ep->maxpacket);
if (uac->p_pktsize < ep->maxpacket)
uac->p_pktsize_residue = rate % uac->p_interval;
uac->p_pktsize_residue = uac->p_framesize *
(params->p_srate % uac->p_interval);
else
uac->p_pktsize_residue = 0;
@@ -569,7 +471,6 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
struct uac_params *params;
int p_chmask, c_chmask;
int err;
int i;
if (!g_audio)
return -EINVAL;
@@ -661,14 +562,6 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
NULL, 0, BUFF_SIZE_MAX);
/* Add controls */
for (i = 0; i < ARRAY_SIZE(uac_pcm_controls); i++) {
err = snd_ctl_add(card,
snd_ctl_new1(&uac_pcm_controls[i], uac));
if (err < 0)
goto snd_fail;
}
err = snd_card_register(card);
if (!err)

View File

@@ -11,18 +11,15 @@
#include <linux/usb/composite.h>
#define UAC_MAX_RATES 10
struct uac_params {
/* playback */
int p_chmask; /* channel mask */
int p_srate[UAC_MAX_RATES]; /* rate in Hz */
int p_srate_active; /* selected rate in Hz */
int p_srate; /* rate in Hz */
int p_ssize; /* sample size */
/* capture */
int c_chmask; /* channel mask */
int c_srate[UAC_MAX_RATES]; /* rate in Hz */
int c_srate_active; /* selected rate in Hz */
int c_srate; /* rate in Hz */
int c_ssize; /* sample size */
int req_number; /* number of preallocated requests */
@@ -84,7 +81,5 @@ int u_audio_start_capture(struct g_audio *g_audio);
void u_audio_stop_capture(struct g_audio *g_audio);
int u_audio_start_playback(struct g_audio *g_audio);
void u_audio_stop_playback(struct g_audio *g_audio);
int u_audio_set_capture_srate(struct g_audio *audio_dev, int srate);
int u_audio_set_playback_srate(struct g_audio *audio_dev, int srate);
#endif /* __U_AUDIO_H */

View File

@@ -13,7 +13,6 @@
#define __U_UAC_H
#include <linux/usb/composite.h>
#include "u_audio.h"
#define UAC_DEF_CCHMASK 0x3
#define UAC_DEF_CSRATE 48000
@@ -28,12 +27,10 @@
struct f_uac_opts {
struct usb_function_instance func_inst;
int c_chmask;
int c_srate[UAC_MAX_RATES];
int c_srate_active;
int c_srate;
int c_ssize;
int p_chmask;
int p_srate[UAC_MAX_RATES];
int p_srate_active;
int p_srate;
int p_ssize;
int req_number;
unsigned bound:1;
@@ -85,71 +82,10 @@ end: \
\
CONFIGFS_ATTR(f_uac_opts_, name)
#define UAC_RATE_ATTRIBUTE(name) \
static ssize_t f_uac_opts_##name##_show(struct config_item *item, \
char *page) \
{ \
struct f_uac_opts *opts = to_f_uac_opts(item); \
int result = 0; \
int i; \
\
mutex_lock(&opts->lock); \
page[0] = '\0'; \
for (i = 0; i < UAC_MAX_RATES; i++) { \
if (opts->name[i] == 0) \
continue; \
result += sprintf(page + strlen(page), "%u,", \
opts->name[i]); \
} \
if (strlen(page) > 0) \
page[strlen(page) - 1] = '\n'; \
mutex_unlock(&opts->lock); \
\
return result; \
} \
\
static ssize_t f_uac_opts_##name##_store(struct config_item *item, \
const char *page, size_t len) \
{ \
struct f_uac_opts *opts = to_f_uac_opts(item); \
char *split_page = NULL; \
int ret = -EINVAL; \
char *token; \
u32 num; \
int i; \
\
mutex_lock(&opts->lock); \
if (opts->refcnt) { \
ret = -EBUSY; \
goto end; \
} \
\
i = 0; \
memset(opts->name, 0x00, sizeof(opts->name)); \
split_page = kstrdup(page, GFP_KERNEL); \
while ((token = strsep(&split_page, ",")) != NULL) { \
ret = kstrtou32(token, 0, &num); \
if (ret) \
goto end; \
\
opts->name[i++] = num; \
opts->name##_active = num; \
ret = len; \
}; \
\
end: \
kfree(split_page); \
mutex_unlock(&opts->lock); \
return ret; \
} \
\
CONFIGFS_ATTR(f_uac_opts_, name)
struct f_uac {
struct g_audio g_audio;
u8 ac_intf, as_in_intf, as_out_intf;
u8 ac_alt, as_in_alt, as_out_alt; /* needed for get_alt() */
int ctl_id;
};
static inline struct f_uac *func_to_uac(struct usb_function *f)