Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d91394bf authored by Sriharsha Allenki's avatar Sriharsha Allenki Committed by Gerrit - the friendly Code Review server
Browse files

usb: gadget: f_uac2: Support for mic only use case



Add support for dynamic switch between mic only and
mic, speaker use case for the existing f_uac2 driver.
Mic will be enabled always, user can choose to
disable/enable the speaker usecase using the module
parameter enable_capture.
To enable speaker
echo Y > /sys/module/usb_f_uac2/parameters/enable_capture
setprop sys.usb.config diag,adb,uac2
To disable speaker
echo N > /sys/module/usb_f_uac2/parameters/enable_capture
setprop sys.usb.config diag,adb,uac2

Change-Id: Ic58bac474c6854dfb89c0568b887e9fb4fc6d937
Signed-off-by: default avatarSriharsha Allenki <sallenki@codeaurora.org>
parent a650fa2d
Loading
Loading
Loading
Loading
+135 −46
Original line number Diff line number Diff line
@@ -54,6 +54,10 @@
#define UNFLW_CTRL	8
#define OVFLW_CTRL	10

static bool enable_capture;
module_param(enable_capture, bool, 0644);
MODULE_PARM_DESC(enable_capture, "Enable USB Peripheral speaker function");

static const char *uac2_name = "snd_uac2";

struct uac2_req {
@@ -126,6 +130,8 @@ struct audio_dev {
	struct usb_ep *in_ep, *out_ep;
	struct usb_function func;

	bool enable_capture;

	/* The ALSA Sound Card it represents on the USB-Client side */
	struct snd_uac2_chip uac2;
};
@@ -468,7 +474,9 @@ static int snd_uac2_probe(struct platform_device *pdev)
	 * Create a substream only for non-zero channel streams
	 */
	err = snd_pcm_new(uac2->card, "UAC2 PCM", 0,
			       p_chmask ? 1 : 0, c_chmask ? 1 : 0, &pcm);
			       p_chmask ? 1 : 0,
			       (c_chmask && audio_dev->enable_capture) ? 1 : 0,
			       &pcm);
	if (err < 0)
		goto snd_fail;

@@ -912,6 +920,25 @@ static struct usb_descriptor_header *fs_audio_desc[] = {
	NULL,
};

static struct usb_descriptor_header *fs_playback_audio_desc[] = {
	(struct usb_descriptor_header *)&iad_desc,
	(struct usb_descriptor_header *)&std_ac_if_desc,

	(struct usb_descriptor_header *)&ac_hdr_desc,
	(struct usb_descriptor_header *)&in_clk_src_desc,
	(struct usb_descriptor_header *)&io_in_it_desc,
	(struct usb_descriptor_header *)&usb_in_ot_desc,

	(struct usb_descriptor_header *)&std_as_in_if0_desc,
	(struct usb_descriptor_header *)&std_as_in_if1_desc,

	(struct usb_descriptor_header *)&as_in_hdr_desc,
	(struct usb_descriptor_header *)&as_in_fmt1_desc,
	(struct usb_descriptor_header *)&fs_epin_desc,
	(struct usb_descriptor_header *)&as_iso_in_desc,
	NULL,
};

static struct usb_descriptor_header *hs_audio_desc[] = {
	(struct usb_descriptor_header *)&iad_desc,
	(struct usb_descriptor_header *)&std_ac_if_desc,
@@ -942,6 +969,25 @@ static struct usb_descriptor_header *hs_audio_desc[] = {
	NULL,
};

static struct usb_descriptor_header *hs_playback_audio_desc[] = {
	(struct usb_descriptor_header *)&iad_desc,
	(struct usb_descriptor_header *)&std_ac_if_desc,

	(struct usb_descriptor_header *)&ac_hdr_desc,
	(struct usb_descriptor_header *)&in_clk_src_desc,
	(struct usb_descriptor_header *)&io_in_it_desc,
	(struct usb_descriptor_header *)&usb_in_ot_desc,

	(struct usb_descriptor_header *)&std_as_in_if0_desc,
	(struct usb_descriptor_header *)&std_as_in_if1_desc,

	(struct usb_descriptor_header *)&as_in_hdr_desc,
	(struct usb_descriptor_header *)&as_in_fmt1_desc,
	(struct usb_descriptor_header *)&hs_epin_desc,
	(struct usb_descriptor_header *)&as_iso_in_desc,
	NULL,
};

static struct usb_descriptor_header *ss_audio_desc[] = {
	(struct usb_descriptor_header *)&iad_desc,
	(struct usb_descriptor_header *)&std_ac_if_desc,
@@ -974,6 +1020,26 @@ static struct usb_descriptor_header *ss_audio_desc[] = {
	NULL,
};

static struct usb_descriptor_header *ss_playback_audio_desc[] = {
	(struct usb_descriptor_header *)&iad_desc,
	(struct usb_descriptor_header *)&std_ac_if_desc,

	(struct usb_descriptor_header *)&ac_hdr_desc,
	(struct usb_descriptor_header *)&in_clk_src_desc,
	(struct usb_descriptor_header *)&io_in_it_desc,
	(struct usb_descriptor_header *)&usb_in_ot_desc,

	(struct usb_descriptor_header *)&std_as_in_if0_desc,
	(struct usb_descriptor_header *)&std_as_in_if1_desc,

	(struct usb_descriptor_header *)&as_in_hdr_desc,
	(struct usb_descriptor_header *)&as_in_fmt1_desc,
	(struct usb_descriptor_header *)&hs_epin_desc,
	(struct usb_descriptor_header *)&ss_epin_comp_desc,
	(struct usb_descriptor_header *)&as_iso_in_desc,
	NULL,
};

struct cntrl_cur_lay3 {
	__u32	dCUR;
};
@@ -1081,6 +1147,9 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
	snprintf(clksrc_in, sizeof(clksrc_in), "%uHz", uac2_opts->p_srate);
	snprintf(clksrc_out, sizeof(clksrc_out), "%uHz", uac2_opts->c_srate);

	pr_debug("%s bind with capture enabled(%d)\n", __func__,
							enable_capture);
	agdev->enable_capture = enable_capture;
	ret = usb_interface_id(cfg, fn);
	if (ret < 0) {
		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
@@ -1091,6 +1160,7 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
	agdev->ac_intf = ret;
	agdev->ac_alt = 0;

	if (agdev->enable_capture) {
		ret = usb_interface_id(cfg, fn);
		if (ret < 0) {
			dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
@@ -1100,6 +1170,7 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
		std_as_out_if1_desc.bInterfaceNumber = ret;
		agdev->as_out_intf = ret;
		agdev->as_out_alt = 0;
	}

	ret = usb_interface_id(cfg, fn);
	if (ret < 0) {
@@ -1111,11 +1182,13 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
	agdev->as_in_intf = ret;
	agdev->as_in_alt = 0;

	if (agdev->enable_capture) {
		agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc);
		if (!agdev->out_ep) {
			dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
			return ret;
		}
	}

	agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc);
	if (!agdev->in_ep) {
@@ -1135,11 +1208,18 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
	hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress;
	hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;

	if (agdev->enable_capture) {
		ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc,
					ss_audio_desc, NULL);
	} else {
		ret = usb_assign_descriptors(fn, fs_playback_audio_desc,
						hs_playback_audio_desc,
						ss_playback_audio_desc, NULL);
	}
	if (ret)
		return ret;

	if (agdev->enable_capture) {
		prm = &agdev->uac2.c_prm;
		prm->max_psize = hs_epout_desc.wMaxPacketSize;
		prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);
@@ -1147,6 +1227,7 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
			prm->max_psize = 0;
			goto err_free_descs;
		}
	}

	prm = &agdev->uac2.p_prm;
	prm->max_psize = hs_epin_desc.wMaxPacketSize;
@@ -1197,7 +1278,7 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
		return 0;
	}

	if (intf == agdev->as_out_intf) {
	if (intf == agdev->as_out_intf && agdev->enable_capture) {
		ep = agdev->out_ep;
		prm = &uac2->c_prm;
		config_ep_by_speed(gadget, fn, ep);
@@ -1247,6 +1328,8 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
		return 0;
	}

	if (intf == agdev->as_in_intf ||
		(intf == agdev->as_out_intf && agdev->enable_capture)) {
		prm->ep_enabled = true;
		usb_ep_enable(ep);

@@ -1267,7 +1350,9 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
			}

			if (usb_ep_queue(ep, prm->ureq[i].req, GFP_ATOMIC))
			dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
				dev_err(dev, "%s:%d Error!\n", __func__,
						__LINE__);
		}
	}

	return 0;
@@ -1281,7 +1366,7 @@ afunc_get_alt(struct usb_function *fn, unsigned intf)

	if (intf == agdev->ac_intf)
		return agdev->ac_alt;
	else if (intf == agdev->as_out_intf)
	else if (intf == agdev->as_out_intf && agdev->enable_capture)
		return agdev->as_out_alt;
	else if (intf == agdev->as_in_intf)
		return agdev->as_in_alt;
@@ -1302,9 +1387,11 @@ afunc_disable(struct usb_function *fn)
	free_ep(&uac2->p_prm, agdev->in_ep);
	agdev->as_in_alt = 0;

	if (agdev->enable_capture) {
		free_ep(&uac2->c_prm, agdev->out_ep);
		agdev->as_out_alt = 0;
	}
}

static int
in_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr)
@@ -1605,8 +1692,10 @@ static void afunc_unbind(struct usb_configuration *c, struct usb_function *f)
	prm = &agdev->uac2.p_prm;
	kfree(prm->rbuf);

	if (agdev->enable_capture) {
		prm = &agdev->uac2.c_prm;
		kfree(prm->rbuf);
	}
	usb_free_all_descriptors(f);
}