This adds interface between userspace and feedback endpoint to report real feedback frequency to the Host. Current implementation adds new userspace interface ALSA mixer control "Capture Pitch 1000000" (similar to aloop driver's "PCM Rate Shift 100000" mixer control) Value in PPM is chosen to have correction value agnostic of the actual HW rate, which the application is not necessarily dealing with, while still retaining a good enough precision to allow smooth clock correction on the playback side, if necessary. Similar to sound/usb/endpoint.c, a slow down is allowed up to 25%. This has no impact on the required bandwidth. Speedup correction has an impact on the bandwidth reserved for the isochronous endpoint. The default allowed speedup is 500ppm. This seems to be more than enough but, if necessary, this is configurable through a module parameter. The reserved bandwidth is rounded up to the next packet size. Usage of this new control is easy to implement in existing userspace tools like alsaloop from alsa-utils. Signed-off-by: Ruslan Bilovol <ruslan.bilovol@gmail.com> Signed-off-by: Jerome Brunet <jbrunet@baylibre.com> Link: https://lore.kernel.org/r/20210603220104.1216001-4-jbrunet@baylibre.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
97 lines
2.5 KiB
C
97 lines
2.5 KiB
C
/* SPDX-License-Identifier: GPL-2.0+ */
|
|
/*
|
|
* u_audio.h -- interface to USB gadget "ALSA sound card" utilities
|
|
*
|
|
* Copyright (C) 2016
|
|
* Author: Ruslan Bilovol <ruslan.bilovol@gmail.com>
|
|
*/
|
|
|
|
#ifndef __U_AUDIO_H
|
|
#define __U_AUDIO_H
|
|
|
|
#include <linux/usb/composite.h>
|
|
|
|
/*
|
|
* Same maximum frequency deviation on the slower side as in
|
|
* sound/usb/endpoint.c. Value is expressed in per-mil deviation.
|
|
* The maximum deviation on the faster side will be provided as
|
|
* parameter, as it impacts the endpoint required bandwidth.
|
|
*/
|
|
#define FBACK_SLOW_MAX 250
|
|
|
|
struct uac_params {
|
|
/* playback */
|
|
int p_chmask; /* channel mask */
|
|
int p_srate; /* rate in Hz */
|
|
int p_ssize; /* sample size */
|
|
|
|
/* capture */
|
|
int c_chmask; /* channel mask */
|
|
int c_srate; /* rate in Hz */
|
|
int c_ssize; /* sample size */
|
|
|
|
int req_number; /* number of preallocated requests */
|
|
int fb_max; /* upper frequency drift feedback limit per-mil */
|
|
};
|
|
|
|
struct g_audio {
|
|
struct usb_function func;
|
|
struct usb_gadget *gadget;
|
|
|
|
struct usb_ep *in_ep;
|
|
|
|
struct usb_ep *out_ep;
|
|
/* feedback IN endpoint corresponding to out_ep */
|
|
struct usb_ep *in_ep_fback;
|
|
|
|
/* Max packet size for all in_ep possible speeds */
|
|
unsigned int in_ep_maxpsize;
|
|
/* Max packet size for all out_ep possible speeds */
|
|
unsigned int out_ep_maxpsize;
|
|
|
|
/* The ALSA Sound Card it represents on the USB-Client side */
|
|
struct snd_uac_chip *uac;
|
|
|
|
struct uac_params params;
|
|
};
|
|
|
|
static inline struct g_audio *func_to_g_audio(struct usb_function *f)
|
|
{
|
|
return container_of(f, struct g_audio, func);
|
|
}
|
|
|
|
static inline uint num_channels(uint chanmask)
|
|
{
|
|
uint num = 0;
|
|
|
|
while (chanmask) {
|
|
num += (chanmask & 1);
|
|
chanmask >>= 1;
|
|
}
|
|
|
|
return num;
|
|
}
|
|
|
|
/*
|
|
* g_audio_setup - initialize one virtual ALSA sound card
|
|
* @g_audio: struct with filled params, in_ep_maxpsize, out_ep_maxpsize
|
|
* @pcm_name: the id string for a PCM instance of this sound card
|
|
* @card_name: name of this soundcard
|
|
*
|
|
* This sets up the single virtual ALSA sound card that may be exported by a
|
|
* gadget driver using this framework.
|
|
*
|
|
* Context: may sleep
|
|
*
|
|
* Returns zero on success, or a negative error on failure.
|
|
*/
|
|
int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
|
|
const char *card_name);
|
|
void g_audio_cleanup(struct g_audio *g_audio);
|
|
|
|
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);
|
|
|
|
#endif /* __U_AUDIO_H */
|