[PATCH v4 36/43] usb: gadget: f_uac2: conversion to new API

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Generate descriptors in new format and attach them to USB function in
prep_descs(). Implement prep_vendor_descs() to supply class specific
descriptors. Change set_alt() implementation and implement clear_alt()
operation. Remove boilerplate code.

Signed-off-by: Robert Baldyga <r.baldyga@xxxxxxxxxxx>
---
 drivers/usb/gadget/function/f_uac2.c | 360 ++++++++++++-----------------------
 1 file changed, 121 insertions(+), 239 deletions(-)

diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c
index 044ca79..f5a184d 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -63,7 +63,6 @@ struct uac2_req {
 
 struct uac2_rtd_params {
 	struct snd_uac2_chip *uac2; /* parent chip */
-	bool ep_enabled; /* if the ep is enabled */
 	/* Size of the ring buffer */
 	size_t dma_bytes;
 	unsigned char *dma_area;
@@ -119,10 +118,6 @@ static struct snd_pcm_hardware uac2_pcm_hardware = {
 };
 
 struct audio_dev {
-	u8 ac_intf, ac_alt;
-	u8 as_out_intf, as_out_alt;
-	u8 as_in_intf, as_in_alt;
-
 	struct usb_ep *in_ep, *out_ep;
 	struct usb_function func;
 
@@ -180,10 +175,6 @@ agdev_iso_complete(struct usb_ep *ep, struct usb_request *req)
 	struct uac2_rtd_params *prm = ur->pp;
 	struct snd_uac2_chip *uac2 = prm->uac2;
 
-	/* i/f shutting down */
-	if (!prm->ep_enabled || req->status == -ESHUTDOWN)
-		return;
-
 	/*
 	 * We can't really do much about bad xfers.
 	 * Afterall, the ISOCH xfers could fail legitimately.
@@ -880,65 +871,20 @@ static struct uac2_iso_endpoint_descriptor as_iso_in_desc = {
 	.wLockDelay = 0,
 };
 
-static struct usb_descriptor_header *fs_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 *)&out_clk_src_desc,
-	(struct usb_descriptor_header *)&usb_out_it_desc,
-	(struct usb_descriptor_header *)&io_in_it_desc,
-	(struct usb_descriptor_header *)&usb_in_ot_desc,
-	(struct usb_descriptor_header *)&io_out_ot_desc,
-
-	(struct usb_descriptor_header *)&std_as_out_if0_desc,
-	(struct usb_descriptor_header *)&std_as_out_if1_desc,
-
-	(struct usb_descriptor_header *)&as_out_hdr_desc,
-	(struct usb_descriptor_header *)&as_out_fmt1_desc,
-	(struct usb_descriptor_header *)&fs_epout_desc,
-	(struct usb_descriptor_header *)&as_iso_out_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,
-};
+USB_COMPOSITE_ENDPOINT(ep_out, &fs_epout_desc, &hs_epout_desc, NULL, NULL);
+USB_COMPOSITE_ENDPOINT(ep_in, &fs_epin_desc, &hs_epin_desc, NULL, NULL);
 
-static struct usb_descriptor_header *hs_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 *)&out_clk_src_desc,
-	(struct usb_descriptor_header *)&usb_out_it_desc,
-	(struct usb_descriptor_header *)&io_in_it_desc,
-	(struct usb_descriptor_header *)&usb_in_ot_desc,
-	(struct usb_descriptor_header *)&io_out_ot_desc,
-
-	(struct usb_descriptor_header *)&std_as_out_if0_desc,
-	(struct usb_descriptor_header *)&std_as_out_if1_desc,
-
-	(struct usb_descriptor_header *)&as_out_hdr_desc,
-	(struct usb_descriptor_header *)&as_out_fmt1_desc,
-	(struct usb_descriptor_header *)&hs_epout_desc,
-	(struct usb_descriptor_header *)&as_iso_out_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,
-};
+USB_COMPOSITE_ALTSETTING(intf0alt0, &std_ac_if_desc);
+USB_COMPOSITE_ALTSETTING(intf1alt0, &std_as_out_if0_desc);
+USB_COMPOSITE_ALTSETTING(intf1alt1, &std_as_out_if1_desc, &ep_out);
+USB_COMPOSITE_ALTSETTING(intf2alt0, &std_as_in_if0_desc);
+USB_COMPOSITE_ALTSETTING(intf2alt1, &std_as_in_if1_desc, &ep_in);
+
+USB_COMPOSITE_INTERFACE(intf0, &intf0alt0);
+USB_COMPOSITE_INTERFACE(intf1, &intf1alt0, &intf1alt1);
+USB_COMPOSITE_INTERFACE(intf2, &intf2alt0, &intf2alt1);
+
+USB_COMPOSITE_DESCRIPTORS(uac2_descs, &intf0, &intf1, &intf2);
 
 struct cntrl_cur_lay3 {
 	__u32	dCUR;
@@ -957,11 +903,6 @@ free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep)
 	struct snd_uac2_chip *uac2 = prm->uac2;
 	int i;
 
-	if (!prm->ep_enabled)
-		return;
-
-	prm->ep_enabled = false;
-
 	for (i = 0; i < USB_XFERS; i++) {
 		if (prm->ureq[i].req) {
 			usb_ep_dequeue(ep, prm->ureq[i].req);
@@ -969,10 +910,6 @@ free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep)
 			prm->ureq[i].req = NULL;
 		}
 	}
-
-	if (usb_ep_disable(ep))
-		dev_err(&uac2->pdev.dev,
-			"%s:%d Error!\n", __func__, __LINE__);
 }
 
 static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
@@ -998,18 +935,13 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
 				le16_to_cpu(ep_desc->wMaxPacketSize)));
 }
 
-static int
-afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
+static int afunc_prep_descs(struct usb_function *fn)
 {
 	struct audio_dev *agdev = func_to_agdev(fn);
-	struct snd_uac2_chip *uac2 = &agdev->uac2;
-	struct usb_composite_dev *cdev = cfg->cdev;
-	struct usb_gadget *gadget = cdev->gadget;
-	struct device *dev = &uac2->pdev.dev;
+	struct usb_composite_dev *cdev = fn->config->cdev;
 	struct uac2_rtd_params *prm;
 	struct f_uac2_opts *uac2_opts;
 	struct usb_string *us;
-	int ret;
 
 	uac2_opts = container_of(fn->fi, struct f_uac2_opts, func_inst);
 
@@ -1029,6 +961,28 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
 	std_as_in_if0_desc.iInterface = us[STR_AS_IN_ALT0].id;
 	std_as_in_if1_desc.iInterface = us[STR_AS_IN_ALT1].id;
 
+	/* Calculate wMaxPacketSize according to audio bandwidth */
+	set_ep_max_packet_size(uac2_opts, &fs_epin_desc, 1000, true);
+	set_ep_max_packet_size(uac2_opts, &fs_epout_desc, 1000, false);
+	set_ep_max_packet_size(uac2_opts, &hs_epin_desc, 8000, true);
+	set_ep_max_packet_size(uac2_opts, &hs_epout_desc, 8000, false);
+
+	prm = &agdev->uac2.c_prm;
+	prm->max_psize = hs_epout_desc.wMaxPacketSize;
+
+	prm = &agdev->uac2.p_prm;
+	prm->max_psize = hs_epin_desc.wMaxPacketSize;
+
+	return usb_function_set_descs(fn, &uac2_descs);
+}
+
+static int afunc_prep_vendor_descs(struct usb_function *fn)
+{
+	struct audio_dev *agdev = func_to_agdev(fn);
+	struct f_uac2_opts *uac2_opts;
+	int ret;
+
+	uac2_opts = container_of(fn->fi, struct f_uac2_opts, func_inst);
 
 	/* Initialize the configurable parameters */
 	usb_out_it_desc.bNrChannels = num_channels(uac2_opts->c_chmask);
@@ -1047,135 +1001,78 @@ 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);
 
-	ret = usb_interface_id(cfg, fn);
-	if (ret < 0) {
-		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
-		return ret;
-	}
-	std_ac_if_desc.bInterfaceNumber = ret;
-	agdev->ac_intf = ret;
-	agdev->ac_alt = 0;
-
-	ret = usb_interface_id(cfg, fn);
-	if (ret < 0) {
-		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
-		return ret;
-	}
-	std_as_out_if0_desc.bInterfaceNumber = ret;
-	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) {
-		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
-		return ret;
-	}
-	std_as_in_if0_desc.bInterfaceNumber = ret;
-	std_as_in_if1_desc.bInterfaceNumber = ret;
-	agdev->as_in_intf = ret;
-	agdev->as_in_alt = 0;
-
-	agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc);
-	if (!agdev->out_ep) {
-		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
-		goto err;
-	}
-
-	agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc);
-	if (!agdev->in_ep) {
-		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
-		goto err;
-	}
-
-	uac2->p_prm.uac2 = uac2;
-	uac2->c_prm.uac2 = uac2;
-
-	/* Calculate wMaxPacketSize according to audio bandwidth */
-	set_ep_max_packet_size(uac2_opts, &fs_epin_desc, 1000, true);
-	set_ep_max_packet_size(uac2_opts, &fs_epout_desc, 1000, false);
-	set_ep_max_packet_size(uac2_opts, &hs_epin_desc, 8000, true);
-	set_ep_max_packet_size(uac2_opts, &hs_epout_desc, 8000, false);
-
-	hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress;
-	hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;
-
-	ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL);
-	if (ret)
-		goto err;
-
-	prm = &agdev->uac2.c_prm;
-	prm->max_psize = hs_epout_desc.wMaxPacketSize;
-	prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);
-	if (!prm->rbuf) {
-		prm->max_psize = 0;
-		goto err_free_descs;
-	}
-
-	prm = &agdev->uac2.p_prm;
-	prm->max_psize = hs_epin_desc.wMaxPacketSize;
-	prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);
-	if (!prm->rbuf) {
-		prm->max_psize = 0;
-		goto err_free_descs;
-	}
+	usb_function_add_vendor_desc(fn,
+			(struct usb_descriptor_header *)&iad_desc);
+
+	usb_altset_add_vendor_desc(fn, 0, 0,
+			(struct usb_descriptor_header *)&ac_hdr_desc);
+	usb_altset_add_vendor_desc(fn, 0, 0,
+			(struct usb_descriptor_header *)&in_clk_src_desc);
+	usb_altset_add_vendor_desc(fn, 0, 0,
+			(struct usb_descriptor_header *)&out_clk_src_desc);
+	usb_altset_add_vendor_desc(fn, 0, 0,
+			(struct usb_descriptor_header *)&usb_out_it_desc);
+	usb_altset_add_vendor_desc(fn, 0, 0,
+			(struct usb_descriptor_header *)&io_in_it_desc);
+	usb_altset_add_vendor_desc(fn, 0, 0,
+			(struct usb_descriptor_header *)&usb_in_ot_desc);
+	usb_altset_add_vendor_desc(fn, 0, 0,
+			(struct usb_descriptor_header *)&io_out_ot_desc);
+
+	usb_altset_add_vendor_desc(fn, 1, 1,
+			(struct usb_descriptor_header *)&as_out_hdr_desc);
+	usb_altset_add_vendor_desc(fn, 1, 1,
+			(struct usb_descriptor_header *)&as_out_fmt1_desc);
+	usb_ep_add_vendor_desc(fn, 1, 1, 0,
+			(struct usb_descriptor_header *)&as_iso_out_desc);
+
+	usb_altset_add_vendor_desc(fn, 2, 1,
+			(struct usb_descriptor_header *)&as_in_hdr_desc);
+	usb_altset_add_vendor_desc(fn, 2, 1,
+			(struct usb_descriptor_header *)&as_in_fmt1_desc);
+	usb_ep_add_vendor_desc(fn, 2, 1, 0,
+			(struct usb_descriptor_header *)&as_iso_in_desc);
 
 	ret = alsa_uac2_init(agdev);
 	if (ret)
-		goto err_free_descs;
-	return 0;
+		return ret;
 
-err_free_descs:
-	usb_free_all_descriptors(fn);
-err:
-	kfree(agdev->uac2.p_prm.rbuf);
-	kfree(agdev->uac2.c_prm.rbuf);
-	return -EINVAL;
+	return 0;
 }
 
-static int
-afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
+static int afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
 {
 	struct usb_composite_dev *cdev = fn->config->cdev;
 	struct audio_dev *agdev = func_to_agdev(fn);
 	struct snd_uac2_chip *uac2 = &agdev->uac2;
 	struct usb_gadget *gadget = cdev->gadget;
 	struct device *dev = &uac2->pdev.dev;
+	struct f_uac2_opts *opts = agdev_to_uac2_opts(agdev);
+	struct usb_endpoint_descriptor *ep_desc;
 	struct usb_request *req;
 	struct usb_ep *ep;
 	struct uac2_rtd_params *prm;
-	int req_len, i;
+	unsigned int factor, rate;
+	int ret, req_len, i;
 
-	/* No i/f has more than 2 alt settings */
-	if (alt > 1) {
-		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
-		return -EINVAL;
-	}
-
-	if (intf == agdev->ac_intf) {
-		/* Control I/f has only 1 AltSetting - 0 */
-		if (alt) {
-			dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
-			return -EINVAL;
-		}
+	if (alt == 0)
 		return 0;
-	}
 
-	if (intf == agdev->as_out_intf) {
-		ep = agdev->out_ep;
+	switch (intf) {
+	case 1:
+		ep = agdev->out_ep = usb_function_get_ep(fn, intf, 0);
 		prm = &uac2->c_prm;
-		config_ep_by_speed(gadget, fn, ep);
-		agdev->as_out_alt = alt;
+		prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);
+		if (!prm->rbuf)
+			return -ENOMEM;
 		req_len = prm->max_psize;
-	} else if (intf == agdev->as_in_intf) {
-		struct f_uac2_opts *opts = agdev_to_uac2_opts(agdev);
-		unsigned int factor, rate;
-		struct usb_endpoint_descriptor *ep_desc;
-
-		ep = agdev->in_ep;
+		break;
+	case 2:
+		ep = agdev->in_ep = usb_function_get_ep(fn, intf, 0);
 		prm = &uac2->p_prm;
-		config_ep_by_speed(gadget, fn, ep);
-		agdev->as_in_alt = alt;
+		prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);
+		if (!prm->rbuf)
+			return -ENOMEM;
 
 		/* pre-calculate the playback endpoint's interval */
 		if (gadget->speed == USB_SPEED_FULL) {
@@ -1201,24 +1098,18 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
 
 		req_len = uac2->p_pktsize;
 		uac2->p_residue = 0;
-	} else {
-		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
-		return -EINVAL;
-	}
-
-	if (alt == 0) {
-		free_ep(prm, ep);
+		break;
+	default:
 		return 0;
 	}
 
-	prm->ep_enabled = true;
-	usb_ep_enable(ep);
-
 	for (i = 0; i < USB_XFERS; i++) {
 		if (!prm->ureq[i].req) {
 			req = usb_ep_alloc_request(ep, GFP_ATOMIC);
-			if (req == NULL)
-				return -ENOMEM;
+			if (req == NULL) {
+				ret = -ENOMEM;
+				goto err;
+			}
 
 			prm->ureq[i].req = req;
 			prm->ureq[i].pp = prm;
@@ -1235,39 +1126,31 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
 	}
 
 	return 0;
-}
-
-static int
-afunc_get_alt(struct usb_function *fn, unsigned intf)
-{
-	struct audio_dev *agdev = func_to_agdev(fn);
-	struct snd_uac2_chip *uac2 = &agdev->uac2;
 
-	if (intf == agdev->ac_intf)
-		return agdev->ac_alt;
-	else if (intf == agdev->as_out_intf)
-		return agdev->as_out_alt;
-	else if (intf == agdev->as_in_intf)
-		return agdev->as_in_alt;
-	else
-		dev_err(&uac2->pdev.dev,
-			"%s:%d Invalid Interface %d!\n",
-			__func__, __LINE__, intf);
-
-	return -EINVAL;
+err:
+	kfree(prm->rbuf);
+	return ret;
 }
 
 static void
-afunc_disable(struct usb_function *fn)
+afunc_clear_alt(struct usb_function *fn, unsigned intf, unsigned alt)
 {
 	struct audio_dev *agdev = func_to_agdev(fn);
 	struct snd_uac2_chip *uac2 = &agdev->uac2;
 
-	free_ep(&uac2->p_prm, agdev->in_ep);
-	agdev->as_in_alt = 0;
+	if (alt == 0)
+		return;
 
-	free_ep(&uac2->c_prm, agdev->out_ep);
-	agdev->as_out_alt = 0;
+	switch (intf) {
+	case 1:
+		free_ep(&uac2->c_prm, agdev->out_ep);
+		kfree(agdev->uac2.c_prm.rbuf);
+		break;
+	case 2:
+		free_ep(&uac2->p_prm, agdev->in_ep);
+		kfree(agdev->uac2.p_prm.rbuf);
+		break;
+	}
 }
 
 static int
@@ -1386,7 +1269,7 @@ setup_rq_inf(struct usb_function *fn, const struct usb_ctrlrequest *cr)
 	u16 w_index = le16_to_cpu(cr->wIndex);
 	u8 intf = w_index & 0xff;
 
-	if (intf != agdev->ac_intf) {
+	if (intf != usb_get_interface_id(fn, 0)) {
 		dev_err(&uac2->pdev.dev,
 			"%s:%d Error!\n", __func__, __LINE__);
 		return -EOPNOTSUPP;
@@ -1552,6 +1435,8 @@ static void afunc_free(struct usb_function *f)
 
 	agdev = func_to_agdev(f);
 	opts = container_of(f->fi, struct f_uac2_opts, func_inst);
+
+	alsa_uac2_exit(agdev);
 	kfree(agdev);
 	mutex_lock(&opts->lock);
 	--opts->refcnt;
@@ -1561,21 +1446,14 @@ static void afunc_free(struct usb_function *f)
 static void afunc_unbind(struct usb_configuration *c, struct usb_function *f)
 {
 	struct audio_dev *agdev = func_to_agdev(f);
-	struct uac2_rtd_params *prm;
 
 	alsa_uac2_exit(agdev);
-
-	prm = &agdev->uac2.p_prm;
-	kfree(prm->rbuf);
-
-	prm = &agdev->uac2.c_prm;
-	kfree(prm->rbuf);
-	usb_free_all_descriptors(f);
 }
 
 static struct usb_function *afunc_alloc(struct usb_function_instance *fi)
 {
 	struct audio_dev *agdev;
+	struct snd_uac2_chip *uac2;
 	struct f_uac2_opts *opts;
 
 	agdev = kzalloc(sizeof(*agdev), GFP_KERNEL);
@@ -1588,14 +1466,18 @@ static struct usb_function *afunc_alloc(struct usb_function_instance *fi)
 	mutex_unlock(&opts->lock);
 
 	agdev->func.name = "uac2_func";
-	agdev->func.bind = afunc_bind;
+	agdev->func.prep_descs = afunc_prep_descs;
+	agdev->func.prep_vendor_descs = afunc_prep_vendor_descs;
 	agdev->func.unbind = afunc_unbind;
 	agdev->func.set_alt = afunc_set_alt;
-	agdev->func.get_alt = afunc_get_alt;
-	agdev->func.disable = afunc_disable;
+	agdev->func.clear_alt = afunc_clear_alt;
 	agdev->func.setup = afunc_setup;
 	agdev->func.free_func = afunc_free;
 
+	uac2 = &agdev->uac2;
+	uac2->p_prm.uac2 = uac2;
+	uac2->c_prm.uac2 = uac2;
+
 	return &agdev->func;
 }
 
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux