On Tue, May 30, 2017 at 5:13 AM, Ruslan Bilovol <ruslan.bilovol@xxxxxxxxx> wrote: > On Mon, May 22, 2017 at 6:58 PM, Jassi Brar <jassisinghbrar@xxxxxxxxx> wrote: >> On Thu, May 18, 2017 at 4:07 AM, Ruslan Bilovol >> <ruslan.bilovol@xxxxxxxxx> wrote: >>> Abstract the peripheral side ALSA sound card code from >>> the f_uac2 function into a component that can be called >>> by various functions, so the various flavors can be split >>> apart and selectively reused. >>> >>> Visible changes: >>> - add uac_params structure to pass audio paramteres for >>> g_audio_setup >>> - make ALSA sound card's name configurable >>> - add [in/out]_ep_maxpsize >>> - allocate snd_uac_chip structure during g_audio_setup >>> - add u_audio_[start/stop]_[capture/playback] functions >>> >>> Signed-off-by: Ruslan Bilovol <ruslan.bilovol@xxxxxxxxx> >>> --- >>> drivers/usb/gadget/Kconfig | 4 + >>> drivers/usb/gadget/function/Makefile | 1 + >>> drivers/usb/gadget/function/f_uac2.c | 721 ++++------------------------------ >>> drivers/usb/gadget/function/u_audio.c | 661 +++++++++++++++++++++++++++++++ >>> drivers/usb/gadget/function/u_audio.h | 95 +++++ >>> drivers/usb/gadget/legacy/Kconfig | 1 + >>> 6 files changed, 846 insertions(+), 637 deletions(-) >>> create mode 100644 drivers/usb/gadget/function/u_audio.c >>> create mode 100644 drivers/usb/gadget/function/u_audio.h >>> >>> diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig >>> index c164d6b..2ba0ace 100644 >>> --- a/drivers/usb/gadget/Kconfig >>> +++ b/drivers/usb/gadget/Kconfig >>> @@ -158,6 +158,9 @@ config USB_U_SERIAL >>> config USB_U_ETHER >>> tristate >>> >>> +config USB_U_AUDIO >>> + tristate >>> + >>> config USB_F_SERIAL >>> tristate >>> >>> @@ -381,6 +384,7 @@ config USB_CONFIGFS_F_UAC2 >>> depends on SND >>> select USB_LIBCOMPOSITE >>> select SND_PCM >>> + select USB_U_AUDIO >>> select USB_F_UAC2 >>> help >>> This Audio function is compatible with USB Audio Class >>> diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile >>> index cb8c225..b29f2ae 100644 >>> --- a/drivers/usb/gadget/function/Makefile >>> +++ b/drivers/usb/gadget/function/Makefile >>> @@ -32,6 +32,7 @@ usb_f_mass_storage-y := f_mass_storage.o storage_common.o >>> obj-$(CONFIG_USB_F_MASS_STORAGE)+= usb_f_mass_storage.o >>> usb_f_fs-y := f_fs.o >>> obj-$(CONFIG_USB_F_FS) += usb_f_fs.o >>> +obj-$(CONFIG_USB_U_AUDIO) += u_audio.o >>> usb_f_uac1-y := f_uac1.o u_uac1.o >>> obj-$(CONFIG_USB_F_UAC1) += usb_f_uac1.o >>> usb_f_uac2-y := f_uac2.o >>> diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c >>> index d4565b5..059a14a 100644 >>> --- a/drivers/usb/gadget/function/f_uac2.c >>> +++ b/drivers/usb/gadget/function/f_uac2.c >>> @@ -15,10 +15,7 @@ >>> #include <linux/usb/audio-v2.h> >>> #include <linux/module.h> >>> >>> -#include <sound/core.h> >>> -#include <sound/pcm.h> >>> -#include <sound/pcm_params.h> >>> - >>> +#include "u_audio.h" >>> #include "u_uac2.h" >>> >>> /* >>> @@ -50,455 +47,23 @@ >>> #define UNFLW_CTRL 8 >>> #define OVFLW_CTRL 10 >>> >>> -struct uac2_req { >>> - struct uac2_rtd_params *pp; /* parent param */ >>> - struct usb_request *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; >>> - >>> - struct snd_pcm_substream *ss; >>> - >>> - /* Ring buffer */ >>> - ssize_t hw_ptr; >>> - >>> - void *rbuf; >>> - >>> - size_t period_size; >>> - >>> - unsigned max_psize; >>> - struct uac2_req *ureq; >>> - >>> - spinlock_t lock; >>> -}; >>> - >>> -struct snd_uac2_chip { >>> - struct uac2_rtd_params p_prm; >>> - struct uac2_rtd_params c_prm; >>> - >>> - struct snd_card *card; >>> - struct snd_pcm *pcm; >>> - >>> - /* timekeeping for the playback endpoint */ >>> - unsigned int p_interval; >>> - unsigned int p_residue; >>> - >>> - /* pre-calculated values for playback iso completion */ >>> - unsigned int p_pktsize; >>> - unsigned int p_pktsize_residue; >>> - unsigned int p_framesize; >>> +struct f_uac2 { >>> + 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() */ >>> }; >>> >>> -#define BUFF_SIZE_MAX (PAGE_SIZE * 16) >>> -#define PRD_SIZE_MAX PAGE_SIZE >>> -#define MIN_PERIODS 4 >>> - >>> -static struct snd_pcm_hardware uac2_pcm_hardware = { >>> - .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER >>> - | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID >>> - | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, >>> - .rates = SNDRV_PCM_RATE_CONTINUOUS, >>> - .periods_max = BUFF_SIZE_MAX / PRD_SIZE_MAX, >>> - .buffer_bytes_max = BUFF_SIZE_MAX, >>> - .period_bytes_max = PRD_SIZE_MAX, >>> - .periods_min = MIN_PERIODS, >>> -}; >>> - >>> -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; >>> - struct usb_gadget *gadget; >>> - >>> - /* The ALSA Sound Card it represents on the USB-Client side */ >>> - struct snd_uac2_chip uac2; >>> -}; >>> - >>> -static inline >>> -struct audio_dev *func_to_agdev(struct usb_function *f) >>> +static inline struct f_uac2 *func_to_uac2(struct usb_function *f) >>> { >>> - return container_of(f, struct audio_dev, func); >>> + return container_of(f, struct f_uac2, g_audio.func); >>> } >>> >>> static inline >>> -struct audio_dev *uac2_to_agdev(struct snd_uac2_chip *u) >>> -{ >>> - return container_of(u, struct audio_dev, uac2); >>> -} >>> - >>> -static inline >>> -struct f_uac2_opts *agdev_to_uac2_opts(struct audio_dev *agdev) >>> +struct f_uac2_opts *g_audio_to_uac2_opts(struct g_audio *agdev) >>> { >>> return container_of(agdev->func.fi, struct f_uac2_opts, func_inst); >>> } >>> >>> -static inline >>> -uint num_channels(uint chanmask) >>> -{ >>> - uint num = 0; >>> - >>> - while (chanmask) { >>> - num += (chanmask & 1); >>> - chanmask >>= 1; >>> - } >>> - >>> - return num; >>> -} >>> - >>> -static void >>> -agdev_iso_complete(struct usb_ep *ep, struct usb_request *req) >>> -{ >>> - unsigned pending; >>> - unsigned long flags; >>> - unsigned int hw_ptr; >>> - bool update_alsa = false; >>> - int status = req->status; >>> - struct uac2_req *ur = req->context; >>> - struct snd_pcm_substream *substream; >>> - 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. >>> - */ >>> - if (status) >>> - pr_debug("%s: iso_complete status(%d) %d/%d\n", >>> - __func__, status, req->actual, req->length); >>> - >>> - substream = prm->ss; >>> - >>> - /* Do nothing if ALSA isn't active */ >>> - if (!substream) >>> - goto exit; >>> - >>> - spin_lock_irqsave(&prm->lock, flags); >>> - >>> - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { >>> - /* >>> - * For each IN packet, take the quotient of the current data >>> - * rate and the endpoint's interval as the base packet size. >>> - * If there is a residue from this division, add it to the >>> - * residue accumulator. >>> - */ >>> - req->length = uac2->p_pktsize; >>> - uac2->p_residue += uac2->p_pktsize_residue; >>> - >>> - /* >>> - * Whenever there are more bytes in the accumulator than we >>> - * need to add one more sample frame, increase this packet's >>> - * size and decrease the accumulator. >>> - */ >>> - if (uac2->p_residue / uac2->p_interval >= uac2->p_framesize) { >>> - req->length += uac2->p_framesize; >>> - uac2->p_residue -= uac2->p_framesize * >>> - uac2->p_interval; >>> - } >>> - >>> - req->actual = req->length; >>> - } >>> - >>> - pending = prm->hw_ptr % prm->period_size; >>> - pending += req->actual; >>> - if (pending >= prm->period_size) >>> - update_alsa = true; >>> - >>> - hw_ptr = prm->hw_ptr; >>> - prm->hw_ptr = (prm->hw_ptr + req->actual) % prm->dma_bytes; >>> - >>> - spin_unlock_irqrestore(&prm->lock, flags); >>> - >>> - /* Pack USB load in ALSA ring buffer */ >>> - pending = prm->dma_bytes - hw_ptr; >>> - >>> - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { >>> - if (unlikely(pending < req->actual)) { >>> - memcpy(req->buf, prm->dma_area + hw_ptr, pending); >>> - memcpy(req->buf + pending, prm->dma_area, >>> - req->actual - pending); >>> - } else { >>> - memcpy(req->buf, prm->dma_area + hw_ptr, req->actual); >>> - } >>> - } else { >>> - if (unlikely(pending < req->actual)) { >>> - memcpy(prm->dma_area + hw_ptr, req->buf, pending); >>> - memcpy(prm->dma_area, req->buf + pending, >>> - req->actual - pending); >>> - } else { >>> - memcpy(prm->dma_area + hw_ptr, req->buf, req->actual); >>> - } >>> - } >>> - >>> -exit: >>> - if (usb_ep_queue(ep, req, GFP_ATOMIC)) >>> - dev_err(uac2->card->dev, "%d Error!\n", __LINE__); >>> - >>> - if (update_alsa) >>> - snd_pcm_period_elapsed(substream); >>> - >>> - return; >>> -} >>> - >>> -static int >>> -uac2_pcm_trigger(struct snd_pcm_substream *substream, int cmd) >>> -{ >>> - struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream); >>> - struct audio_dev *agdev = uac2_to_agdev(uac2); >>> - struct f_uac2_opts *uac2_opts = agdev_to_uac2_opts(agdev); >>> - struct uac2_rtd_params *prm; >>> - unsigned long flags; >>> - int err = 0; >>> - >>> - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) >>> - prm = &uac2->p_prm; >>> - else >>> - prm = &uac2->c_prm; >>> - >>> - spin_lock_irqsave(&prm->lock, flags); >>> - >>> - /* Reset */ >>> - prm->hw_ptr = 0; >>> - >>> - switch (cmd) { >>> - case SNDRV_PCM_TRIGGER_START: >>> - case SNDRV_PCM_TRIGGER_RESUME: >>> - prm->ss = substream; >>> - break; >>> - case SNDRV_PCM_TRIGGER_STOP: >>> - case SNDRV_PCM_TRIGGER_SUSPEND: >>> - prm->ss = NULL; >>> - break; >>> - default: >>> - err = -EINVAL; >>> - } >>> - >>> - spin_unlock_irqrestore(&prm->lock, flags); >>> - >>> - /* Clear buffer after Play stops */ >>> - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && !prm->ss) >>> - memset(prm->rbuf, 0, prm->max_psize * uac2_opts->req_number); >>> - >>> - return err; >>> -} >>> - >>> -static snd_pcm_uframes_t uac2_pcm_pointer(struct snd_pcm_substream *substream) >>> -{ >>> - struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream); >>> - struct uac2_rtd_params *prm; >>> - >>> - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) >>> - prm = &uac2->p_prm; >>> - else >>> - prm = &uac2->c_prm; >>> - >>> - return bytes_to_frames(substream->runtime, prm->hw_ptr); >>> -} >>> - >>> -static int uac2_pcm_hw_params(struct snd_pcm_substream *substream, >>> - struct snd_pcm_hw_params *hw_params) >>> -{ >>> - struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream); >>> - struct uac2_rtd_params *prm; >>> - int err; >>> - >>> - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) >>> - prm = &uac2->p_prm; >>> - else >>> - prm = &uac2->c_prm; >>> - >>> - err = snd_pcm_lib_malloc_pages(substream, >>> - params_buffer_bytes(hw_params)); >>> - if (err >= 0) { >>> - prm->dma_bytes = substream->runtime->dma_bytes; >>> - prm->dma_area = substream->runtime->dma_area; >>> - prm->period_size = params_period_bytes(hw_params); >>> - } >>> - >>> - return err; >>> -} >>> - >>> -static int uac2_pcm_hw_free(struct snd_pcm_substream *substream) >>> -{ >>> - struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream); >>> - struct uac2_rtd_params *prm; >>> - >>> - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) >>> - prm = &uac2->p_prm; >>> - else >>> - prm = &uac2->c_prm; >>> - >>> - prm->dma_area = NULL; >>> - prm->dma_bytes = 0; >>> - prm->period_size = 0; >>> - >>> - return snd_pcm_lib_free_pages(substream); >>> -} >>> - >>> -static int uac2_pcm_open(struct snd_pcm_substream *substream) >>> -{ >>> - struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream); >>> - struct snd_pcm_runtime *runtime = substream->runtime; >>> - struct audio_dev *audio_dev; >>> - struct f_uac2_opts *opts; >>> - int p_ssize, c_ssize; >>> - int p_srate, c_srate; >>> - int p_chmask, c_chmask; >>> - >>> - audio_dev = uac2_to_agdev(uac2); >>> - opts = container_of(audio_dev->func.fi, struct f_uac2_opts, func_inst); >>> - p_ssize = opts->p_ssize; >>> - c_ssize = opts->c_ssize; >>> - p_srate = opts->p_srate; >>> - c_srate = opts->c_srate; >>> - p_chmask = opts->p_chmask; >>> - c_chmask = opts->c_chmask; >>> - uac2->p_residue = 0; >>> - >>> - runtime->hw = uac2_pcm_hardware; >>> - >>> - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { >>> - spin_lock_init(&uac2->p_prm.lock); >>> - runtime->hw.rate_min = p_srate; >>> - switch (p_ssize) { >>> - case 3: >>> - runtime->hw.formats = SNDRV_PCM_FMTBIT_S24_3LE; >>> - break; >>> - case 4: >>> - runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE; >>> - break; >>> - default: >>> - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; >>> - break; >>> - } >>> - runtime->hw.channels_min = num_channels(p_chmask); >>> - runtime->hw.period_bytes_min = 2 * uac2->p_prm.max_psize >>> - / runtime->hw.periods_min; >>> - } else { >>> - spin_lock_init(&uac2->c_prm.lock); >>> - runtime->hw.rate_min = c_srate; >>> - switch (c_ssize) { >>> - case 3: >>> - runtime->hw.formats = SNDRV_PCM_FMTBIT_S24_3LE; >>> - break; >>> - case 4: >>> - runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE; >>> - break; >>> - default: >>> - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; >>> - break; >>> - } >>> - runtime->hw.channels_min = num_channels(c_chmask); >>> - runtime->hw.period_bytes_min = 2 * uac2->c_prm.max_psize >>> - / runtime->hw.periods_min; >>> - } >>> - >>> - runtime->hw.rate_max = runtime->hw.rate_min; >>> - runtime->hw.channels_max = runtime->hw.channels_min; >>> - >>> - snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); >>> - >>> - return 0; >>> -} >>> - >>> -/* ALSA cries without these function pointers */ >>> -static int uac2_pcm_null(struct snd_pcm_substream *substream) >>> -{ >>> - return 0; >>> -} >>> - >>> -static struct snd_pcm_ops uac2_pcm_ops = { >>> - .open = uac2_pcm_open, >>> - .close = uac2_pcm_null, >>> - .ioctl = snd_pcm_lib_ioctl, >>> - .hw_params = uac2_pcm_hw_params, >>> - .hw_free = uac2_pcm_hw_free, >>> - .trigger = uac2_pcm_trigger, >>> - .pointer = uac2_pcm_pointer, >>> - .prepare = uac2_pcm_null, >>> -}; >>> - >>> -static int snd_uac2_probe(struct audio_dev *audio_dev) >>> -{ >>> - struct snd_uac2_chip *uac2 = &audio_dev->uac2; >>> - struct snd_card *card; >>> - struct snd_pcm *pcm; >>> - struct f_uac2_opts *opts; >>> - int err; >>> - int p_chmask, c_chmask; >>> - >>> - opts = container_of(audio_dev->func.fi, struct f_uac2_opts, func_inst); >>> - p_chmask = opts->p_chmask; >>> - c_chmask = opts->c_chmask; >>> - >>> - /* Choose any slot, with no id */ >>> - err = snd_card_new(&audio_dev->gadget->dev, >>> - -1, NULL, THIS_MODULE, 0, &card); >>> - if (err < 0) >>> - return err; >>> - >>> - uac2->card = card; >>> - >>> - /* >>> - * Create first PCM device >>> - * 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); >>> - if (err < 0) >>> - goto snd_fail; >>> - >>> - strcpy(pcm->name, "UAC2 PCM"); >>> - pcm->private_data = uac2; >>> - >>> - uac2->pcm = pcm; >>> - >>> - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &uac2_pcm_ops); >>> - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &uac2_pcm_ops); >>> - >>> - strcpy(card->driver, "UAC2_Gadget"); >>> - strcpy(card->shortname, "UAC2_Gadget"); >>> - sprintf(card->longname, "UAC2_Gadget %i", card->dev->id); >>> - >>> - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, >>> - snd_dma_continuous_data(GFP_KERNEL), 0, BUFF_SIZE_MAX); >>> - >>> - err = snd_card_register(card); >>> - >>> - if (!err) >>> - return 0; >>> - >>> -snd_fail: >>> - snd_card_free(card); >>> - >>> - uac2->pcm = NULL; >>> - uac2->card = NULL; >>> - >>> - return err; >>> -} >>> - >>> -static int snd_uac2_remove(struct audio_dev *audio_dev) >>> -{ >>> - struct snd_card *card = audio_dev->uac2.card; >>> - >>> - if (card) >>> - return snd_card_free(card); >>> - >>> - return 0; >>> -} >>> - >>> - >>> /* --------- USB Function Interface ------------- */ >>> >>> enum { >>> @@ -886,32 +451,6 @@ struct cntrl_range_lay3 { >>> __u32 dRES; >>> } __packed; >>> >>> -static inline void >>> -free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep) >>> -{ >>> - struct snd_uac2_chip *uac2 = prm->uac2; >>> - struct audio_dev *agdev = uac2_to_agdev(uac2); >>> - struct f_uac2_opts *uac2_opts = agdev_to_uac2_opts(agdev); >>> - int i; >>> - >>> - if (!prm->ep_enabled) >>> - return; >>> - >>> - prm->ep_enabled = false; >>> - >>> - for (i = 0; i < uac2_opts->req_number; i++) { >>> - if (prm->ureq[i].req) { >>> - usb_ep_dequeue(ep, prm->ureq[i].req); >>> - usb_ep_free_request(ep, prm->ureq[i].req); >>> - prm->ureq[i].req = NULL; >>> - } >>> - } >>> - >>> - if (usb_ep_disable(ep)) >>> - dev_err(uac2->card->dev, >>> - "%s:%d Error!\n", __func__, __LINE__); >>> -} >>> - >>> static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, >>> struct usb_endpoint_descriptor *ep_desc, >>> unsigned int factor, bool is_playback) >>> @@ -938,12 +477,11 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, >>> static int >>> afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) >>> { >>> - struct audio_dev *agdev = func_to_agdev(fn); >>> - struct snd_uac2_chip *uac2 = &agdev->uac2; >>> + struct f_uac2 *uac2 = func_to_uac2(fn); >>> + struct g_audio *agdev = func_to_g_audio(fn); >>> struct usb_composite_dev *cdev = cfg->cdev; >>> struct usb_gadget *gadget = cdev->gadget; >>> struct device *dev = &gadget->dev; >>> - struct uac2_rtd_params *prm; >>> struct f_uac2_opts *uac2_opts; >>> struct usb_string *us; >>> int ret; >>> @@ -990,8 +528,8 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, >>> return ret; >>> } >>> std_ac_if_desc.bInterfaceNumber = ret; >>> - agdev->ac_intf = ret; >>> - agdev->ac_alt = 0; >>> + uac2->ac_intf = ret; >>> + uac2->ac_alt = 0; >>> >>> ret = usb_interface_id(cfg, fn); >>> if (ret < 0) { >>> @@ -1000,8 +538,8 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, >>> } >>> std_as_out_if0_desc.bInterfaceNumber = ret; >>> std_as_out_if1_desc.bInterfaceNumber = ret; >>> - agdev->as_out_intf = ret; >>> - agdev->as_out_alt = 0; >>> + uac2->as_out_intf = ret; >>> + uac2->as_out_alt = 0; >>> >>> ret = usb_interface_id(cfg, fn); >>> if (ret < 0) { >>> @@ -1010,8 +548,8 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, >>> } >>> std_as_in_if0_desc.bInterfaceNumber = ret; >>> std_as_in_if1_desc.bInterfaceNumber = ret; >>> - agdev->as_in_intf = ret; >>> - agdev->as_in_alt = 0; >>> + uac2->as_in_intf = ret; >>> + uac2->as_in_alt = 0; >>> >>> agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc); >>> if (!agdev->out_ep) { >>> @@ -1025,15 +563,17 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, >>> return ret; >>> } >>> >>> - 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); >>> >>> + agdev->in_ep_maxpsize = max(fs_epin_desc.wMaxPacketSize, >>> + hs_epin_desc.wMaxPacketSize); >>> + agdev->out_ep_maxpsize = max(fs_epout_desc.wMaxPacketSize, >>> + hs_epout_desc.wMaxPacketSize); >>> + >>> hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress; >>> hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress; >>> >>> @@ -1044,46 +584,18 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, >>> >>> agdev->gadget = gadget; >>> >>> - prm = &agdev->uac2.c_prm; >>> - prm->max_psize = hs_epout_desc.wMaxPacketSize; >>> - prm->ureq = kcalloc(uac2_opts->req_number, sizeof(struct uac2_req), >>> - GFP_KERNEL); >>> - if (!prm->ureq) { >>> - ret = -ENOMEM; >>> - goto err_free_descs; >>> - } >>> - prm->rbuf = kcalloc(uac2_opts->req_number, prm->max_psize, GFP_KERNEL); >>> - if (!prm->rbuf) { >>> - prm->max_psize = 0; >>> - ret = -ENOMEM; >>> - goto err_free_descs; >>> - } >>> - >>> - prm = &agdev->uac2.p_prm; >>> - prm->max_psize = hs_epin_desc.wMaxPacketSize; >>> - prm->ureq = kcalloc(uac2_opts->req_number, sizeof(struct uac2_req), >>> - GFP_KERNEL); >>> - if (!prm->ureq) { >>> - ret = -ENOMEM; >>> - goto err_free_descs; >>> - } >>> - prm->rbuf = kcalloc(uac2_opts->req_number, prm->max_psize, GFP_KERNEL); >>> - if (!prm->rbuf) { >>> - prm->max_psize = 0; >>> - ret = -ENOMEM; >>> - goto err_no_memory; >>> - } >>> - >>> - ret = snd_uac2_probe(agdev); >>> + agdev->params.p_chmask = uac2_opts->p_chmask; >>> + agdev->params.p_srate = uac2_opts->p_srate; >>> + agdev->params.p_ssize = uac2_opts->p_ssize; >>> + agdev->params.c_chmask = uac2_opts->c_chmask; >>> + 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"); >>> if (ret) >>> - goto err_no_memory; >>> + goto err_free_descs; >>> return 0; >>> >>> -err_no_memory: >>> - kfree(agdev->uac2.p_prm.ureq); >>> - kfree(agdev->uac2.c_prm.ureq); >>> - kfree(agdev->uac2.p_prm.rbuf); >>> - kfree(agdev->uac2.c_prm.rbuf); >>> err_free_descs: >>> usb_free_all_descriptors(fn); >>> agdev->gadget = NULL; >>> @@ -1094,15 +606,10 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, >>> 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 f_uac2_opts *opts = agdev_to_uac2_opts(agdev); >>> - struct snd_uac2_chip *uac2 = &agdev->uac2; >>> + struct f_uac2 *uac2 = func_to_uac2(fn); >>> struct usb_gadget *gadget = cdev->gadget; >>> struct device *dev = &gadget->dev; >>> - struct usb_request *req; >>> - struct usb_ep *ep; >>> - struct uac2_rtd_params *prm; >>> - int req_len, i; >>> + int ret = 0; >>> >>> /* No i/f has more than 2 alt settings */ >>> if (alt > 1) { >>> @@ -1110,7 +617,7 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, >>> return -EINVAL; >>> } >>> >>> - if (intf == agdev->ac_intf) { >>> + if (intf == uac2->ac_intf) { >>> /* Control I/f has only 1 AltSetting - 0 */ >>> if (alt) { >>> dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); >>> @@ -1119,92 +626,40 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, >>> return 0; >>> } >>> >>> - if (intf == agdev->as_out_intf) { >>> - ep = agdev->out_ep; >>> - prm = &uac2->c_prm; >>> - config_ep_by_speed(gadget, fn, ep); >>> - agdev->as_out_alt = alt; >>> - req_len = prm->max_psize; >>> - } else if (intf == agdev->as_in_intf) { >>> - unsigned int factor, rate; >>> - struct usb_endpoint_descriptor *ep_desc; >>> - >>> - ep = agdev->in_ep; >>> - prm = &uac2->p_prm; >>> - config_ep_by_speed(gadget, fn, ep); >>> - agdev->as_in_alt = alt; >>> - >>> - /* pre-calculate the playback endpoint's interval */ >>> - if (gadget->speed == USB_SPEED_FULL) { >>> - ep_desc = &fs_epin_desc; >>> - factor = 1000; >>> - } else { >>> - ep_desc = &hs_epin_desc; >>> - factor = 8000; >>> - } >>> - >>> - /* pre-compute some values for iso_complete() */ >>> - uac2->p_framesize = opts->p_ssize * >>> - num_channels(opts->p_chmask); >>> - rate = opts->p_srate * uac2->p_framesize; >>> - uac2->p_interval = factor / (1 << (ep_desc->bInterval - 1)); >>> - uac2->p_pktsize = min_t(unsigned int, rate / uac2->p_interval, >>> - prm->max_psize); >>> + if (intf == uac2->as_out_intf) { >>> + uac2->as_out_alt = alt; >>> >>> - if (uac2->p_pktsize < prm->max_psize) >>> - uac2->p_pktsize_residue = rate % uac2->p_interval; >>> + if (alt) >>> + ret = u_audio_start_capture(&uac2->g_audio); >>> else >>> - uac2->p_pktsize_residue = 0; >>> + u_audio_stop_capture(&uac2->g_audio); >>> + } else if (intf == uac2->as_in_intf) { >>> + uac2->as_in_alt = alt; >>> >>> - req_len = uac2->p_pktsize; >>> - uac2->p_residue = 0; >>> + if (alt) >>> + ret = u_audio_start_playback(&uac2->g_audio); >>> + else >>> + u_audio_stop_playback(&uac2->g_audio); >>> } else { >>> dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); >>> return -EINVAL; >>> } >>> >>> - if (alt == 0) { >>> - free_ep(prm, ep); >>> - return 0; >>> - } >>> - >>> - prm->ep_enabled = true; >>> - usb_ep_enable(ep); >>> - >>> - for (i = 0; i < opts->req_number; i++) { >>> - if (!prm->ureq[i].req) { >>> - req = usb_ep_alloc_request(ep, GFP_ATOMIC); >>> - if (req == NULL) >>> - return -ENOMEM; >>> - >>> - prm->ureq[i].req = req; >>> - prm->ureq[i].pp = prm; >>> - >>> - req->zero = 0; >>> - req->context = &prm->ureq[i]; >>> - req->length = req_len; >>> - req->complete = agdev_iso_complete; >>> - req->buf = prm->rbuf + i * prm->max_psize; >>> - } >>> - >>> - if (usb_ep_queue(ep, prm->ureq[i].req, GFP_ATOMIC)) >>> - dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); >>> - } >>> - >>> - return 0; >>> + return ret; >>> } >>> >>> static int >>> afunc_get_alt(struct usb_function *fn, unsigned intf) >>> { >>> - struct audio_dev *agdev = func_to_agdev(fn); >>> - >>> - 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; >>> + struct f_uac2 *uac2 = func_to_uac2(fn); >>> + struct g_audio *agdev = func_to_g_audio(fn); >>> + >>> + if (intf == uac2->ac_intf) >>> + return uac2->ac_alt; >>> + else if (intf == uac2->as_out_intf) >>> + return uac2->as_out_alt; >>> + else if (intf == uac2->as_in_intf) >>> + return uac2->as_in_alt; >>> else >>> dev_err(&agdev->gadget->dev, >>> "%s:%d Invalid Interface %d!\n", >>> @@ -1216,21 +671,19 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, >>> static void >>> afunc_disable(struct usb_function *fn) >>> { >>> - 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; >>> + struct f_uac2 *uac2 = func_to_uac2(fn); >>> >>> - free_ep(&uac2->c_prm, agdev->out_ep); >>> - agdev->as_out_alt = 0; >>> + uac2->as_in_alt = 0; >>> + uac2->as_out_alt = 0; >>> + u_audio_stop_capture(&uac2->g_audio); >>> + u_audio_stop_playback(&uac2->g_audio); >>> } >>> >>> static int >>> in_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr) >>> { >>> struct usb_request *req = fn->config->cdev->req; >>> - struct audio_dev *agdev = func_to_agdev(fn); >>> + struct g_audio *agdev = func_to_g_audio(fn); >>> struct f_uac2_opts *opts; >>> u16 w_length = le16_to_cpu(cr->wLength); >>> u16 w_index = le16_to_cpu(cr->wIndex); >>> @@ -1240,7 +693,7 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, >>> int value = -EOPNOTSUPP; >>> int p_srate, c_srate; >>> >>> - opts = agdev_to_uac2_opts(agdev); >>> + opts = g_audio_to_uac2_opts(agdev); >>> p_srate = opts->p_srate; >>> c_srate = opts->c_srate; >>> >>> @@ -1271,7 +724,7 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, >>> in_rq_range(struct usb_function *fn, const struct usb_ctrlrequest *cr) >>> { >>> struct usb_request *req = fn->config->cdev->req; >>> - struct audio_dev *agdev = func_to_agdev(fn); >>> + struct g_audio *agdev = func_to_g_audio(fn); >>> struct f_uac2_opts *opts; >>> u16 w_length = le16_to_cpu(cr->wLength); >>> u16 w_index = le16_to_cpu(cr->wIndex); >>> @@ -1282,7 +735,7 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, >>> int value = -EOPNOTSUPP; >>> int p_srate, c_srate; >>> >>> - opts = agdev_to_uac2_opts(agdev); >>> + opts = g_audio_to_uac2_opts(agdev); >>> p_srate = opts->p_srate; >>> c_srate = opts->c_srate; >>> >>> @@ -1336,11 +789,12 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, >>> static int >>> setup_rq_inf(struct usb_function *fn, const struct usb_ctrlrequest *cr) >>> { >>> - struct audio_dev *agdev = func_to_agdev(fn); >>> + struct f_uac2 *uac2 = func_to_uac2(fn); >>> + struct g_audio *agdev = func_to_g_audio(fn); >>> u16 w_index = le16_to_cpu(cr->wIndex); >>> u8 intf = w_index & 0xff; >>> >>> - if (intf != agdev->ac_intf) { >>> + if (intf != uac2->ac_intf) { >>> dev_err(&agdev->gadget->dev, >>> "%s:%d Error!\n", __func__, __LINE__); >>> return -EOPNOTSUPP; >>> @@ -1358,7 +812,7 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, >>> afunc_setup(struct usb_function *fn, const struct usb_ctrlrequest *cr) >>> { >>> struct usb_composite_dev *cdev = fn->config->cdev; >>> - struct audio_dev *agdev = func_to_agdev(fn); >>> + struct g_audio *agdev = func_to_g_audio(fn); >>> struct usb_request *req = cdev->req; >>> u16 w_length = le16_to_cpu(cr->wLength); >>> int value = -EOPNOTSUPP; >>> @@ -1504,10 +958,10 @@ static struct usb_function_instance *afunc_alloc_inst(void) >>> >>> static void afunc_free(struct usb_function *f) >>> { >>> - struct audio_dev *agdev; >>> + struct g_audio *agdev; >>> struct f_uac2_opts *opts; >>> >>> - agdev = func_to_agdev(f); >>> + agdev = func_to_g_audio(f); >>> opts = container_of(f->fi, struct f_uac2_opts, func_inst); >>> kfree(agdev); >>> mutex_lock(&opts->lock); >>> @@ -1517,17 +971,9 @@ 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; >>> - >>> - snd_uac2_remove(agdev); >>> - >>> - prm = &agdev->uac2.p_prm; >>> - kfree(prm->rbuf); >>> + struct g_audio *agdev = func_to_g_audio(f); >>> >>> - prm = &agdev->uac2.c_prm; >>> - kfree(prm->rbuf); >>> - kfree(prm->ureq); >>> + g_audio_cleanup(agdev); >>> usb_free_all_descriptors(f); >>> >>> agdev->gadget = NULL; >>> @@ -1535,11 +981,11 @@ static void afunc_unbind(struct usb_configuration *c, struct usb_function *f) >>> >>> static struct usb_function *afunc_alloc(struct usb_function_instance *fi) >>> { >>> - struct audio_dev *agdev; >>> + struct f_uac2 *uac2; >>> struct f_uac2_opts *opts; >>> >>> - agdev = kzalloc(sizeof(*agdev), GFP_KERNEL); >>> - if (agdev == NULL) >>> + uac2 = kzalloc(sizeof(*uac2), GFP_KERNEL); >>> + if (uac2 == NULL) >>> return ERR_PTR(-ENOMEM); >>> >>> opts = container_of(fi, struct f_uac2_opts, func_inst); >>> @@ -1547,19 +993,20 @@ static struct usb_function *afunc_alloc(struct usb_function_instance *fi) >>> ++opts->refcnt; >>> mutex_unlock(&opts->lock); >>> >>> - agdev->func.name = "uac2_func"; >>> - agdev->func.bind = afunc_bind; >>> - 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.setup = afunc_setup; >>> - agdev->func.free_func = afunc_free; >>> + uac2->g_audio.func.name = "uac2_func"; >>> + uac2->g_audio.func.bind = afunc_bind; >>> + uac2->g_audio.func.unbind = afunc_unbind; >>> + uac2->g_audio.func.set_alt = afunc_set_alt; >>> + uac2->g_audio.func.get_alt = afunc_get_alt; >>> + uac2->g_audio.func.disable = afunc_disable; >>> + uac2->g_audio.func.setup = afunc_setup; >>> + uac2->g_audio.func.free_func = afunc_free; >>> >>> - return &agdev->func; >>> + return &uac2->g_audio.func; >>> } >>> >>> DECLARE_USB_FUNCTION_INIT(uac2, afunc_alloc_inst, afunc_alloc); >>> MODULE_LICENSE("GPL"); >>> MODULE_AUTHOR("Yadwinder Singh"); >>> MODULE_AUTHOR("Jaswinder Singh"); >>> +MODULE_AUTHOR("Ruslan Bilovol"); >>> >> drivers/usb/gadget/function/f_uac2.c | 721 ++++------------------------------ >> >> Basically you move out ALSA sound card implementation and %s/agdev/uac2/ >> I am not sure churn warrants a MODULE_AUTHOR. People have made far >> more important contribution to the UAC2, > > Yes, I added it after cumulative effect of this patch and patch 1/3 > where I removed platform driver/device creation from f_uac2. > I haven't find any rules on this and just counted changed lines, > however in this particular case it's better to use something > like MODULE_CLEANER(). Just joking :) > > I'll remove this line then. > Thanks, that will be fair to all. >> >> >>> diff --git a/drivers/usb/gadget/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c >>> new file mode 100644 >>> index 0000000..8ee65b8 >>> --- /dev/null >>> +++ b/drivers/usb/gadget/function/u_audio.c >>> @@ -0,0 +1,661 @@ >>> +/* >>> + * u_audio.c -- interface to USB gadget "ALSA sound card" utilities >>> + * >>> + * Copyright (C) 2016 >>> + * Author: Ruslan Bilovol <ruslan.bilovol@xxxxxxxxx> >>> + * >>> + * Based on f_uac2.c which is: >>> + * Copyright (C) 2011 >>> + * Yadwinder Singh (yadi.brar01@xxxxxxxxx) >>> + * Jaswinder Singh (jaswinder.singh@xxxxxxxxxx) >>> + * >> Again this is not "based on", rather where you paste the code you cut >> from f_uac2.c >> Of course you also pad it with minor changes to make it useful to your >> uac1 code. I am not happy with losing copyright on the sound card >> implementation for the UAC drivers. > > I don't remember why I wrote it as "based on" back in 2016, > probably looking into another patches as example. As per my > understanding, "based on" + your name in Copyright means > that you still continue to hold copyright on the sound card > implementation (otherwise why mention it?). > I don't think copyright spreads by inspiration :) But seriously, we have to be careful if we set a precedence here. You write some important piece of code and assert copyright over it. Sometime later someone finds a reason to move that code to a new file and adds his/her copyright while relegating you to just "inspiration". You can contest the code was your copyright originally but is surely tougher than having the code clearly state that fact. > However I'm not a lawyer so can't say for sure. > Will change this description in next patchset to make it clear, > so you won't loose your copyright. > Thank you. -- 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