Revision 29664923725a384dc7e0f74af7c66e5ab7bb2a26 authored by Marco Giunta on 18 October 2021, 16:25:52 UTC, committed by Takashi Iwai on 19 October 2021, 06:07:01 UTC
When a Jieli Technology USB Webcam is connected, the video part works
well, but the mic sound is speeded up. On dmesg there are messages
about different rates from the runtime rates, warnings about volume
resolution and lastly, the log is filled, every 5 seconds, with
retire_capture_urb error messages.

The mic works only when ep packet size is set to wMaxPacketSize (normal
sound and no more retire_capture_urb error messages). Skipping reading
sample rate, fixes the messages about different rates and forcing a volume
resolution, fixes warnings about volume range. I have arbitrarily choosed
the value (16): I read in a comment that there should be no more than 255
levels, so 4096 (max volume) / 16 = 0-255.

Signed-off-by: Marco Giunta <giun7a@gmail.com>
Link: https://lore.kernel.org/r/20211018162552.12082-1-giun7a@gmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
1 parent eadeb06
Raw File
mpi-mod.c
/* mpi-mod.c -  Modular reduction
 * Copyright (C) 1998, 1999, 2001, 2002, 2003,
 *               2007  Free Software Foundation, Inc.
 *
 * This file is part of Libgcrypt.
 */


#include "mpi-internal.h"
#include "longlong.h"

/* Context used with Barrett reduction.  */
struct barrett_ctx_s {
	MPI m;   /* The modulus - may not be modified. */
	int m_copied;   /* If true, M needs to be released.  */
	int k;
	MPI y;
	MPI r1;  /* Helper MPI. */
	MPI r2;  /* Helper MPI. */
	MPI r3;  /* Helper MPI allocated on demand. */
};



void mpi_mod(MPI rem, MPI dividend, MPI divisor)
{
	mpi_fdiv_r(rem, dividend, divisor);
}

/* This function returns a new context for Barrett based operations on
 * the modulus M.  This context needs to be released using
 * _gcry_mpi_barrett_free.  If COPY is true M will be transferred to
 * the context and the user may change M.  If COPY is false, M may not
 * be changed until gcry_mpi_barrett_free has been called.
 */
mpi_barrett_t mpi_barrett_init(MPI m, int copy)
{
	mpi_barrett_t ctx;
	MPI tmp;

	mpi_normalize(m);
	ctx = kcalloc(1, sizeof(*ctx), GFP_KERNEL);

	if (copy) {
		ctx->m = mpi_copy(m);
		ctx->m_copied = 1;
	} else
		ctx->m = m;

	ctx->k = mpi_get_nlimbs(m);
	tmp = mpi_alloc(ctx->k + 1);

	/* Barrett precalculation: y = floor(b^(2k) / m). */
	mpi_set_ui(tmp, 1);
	mpi_lshift_limbs(tmp, 2 * ctx->k);
	mpi_fdiv_q(tmp, tmp, m);

	ctx->y  = tmp;
	ctx->r1 = mpi_alloc(2 * ctx->k + 1);
	ctx->r2 = mpi_alloc(2 * ctx->k + 1);

	return ctx;
}

void mpi_barrett_free(mpi_barrett_t ctx)
{
	if (ctx) {
		mpi_free(ctx->y);
		mpi_free(ctx->r1);
		mpi_free(ctx->r2);
		if (ctx->r3)
			mpi_free(ctx->r3);
		if (ctx->m_copied)
			mpi_free(ctx->m);
		kfree(ctx);
	}
}


/* R = X mod M
 *
 * Using Barrett reduction.  Before using this function
 * _gcry_mpi_barrett_init must have been called to do the
 * precalculations.  CTX is the context created by this precalculation
 * and also conveys M.  If the Barret reduction could no be done a
 * straightforward reduction method is used.
 *
 * We assume that these conditions are met:
 * Input:  x =(x_2k-1 ...x_0)_b
 *     m =(m_k-1 ....m_0)_b	  with m_k-1 != 0
 * Output: r = x mod m
 */
void mpi_mod_barrett(MPI r, MPI x, mpi_barrett_t ctx)
{
	MPI m = ctx->m;
	int k = ctx->k;
	MPI y = ctx->y;
	MPI r1 = ctx->r1;
	MPI r2 = ctx->r2;
	int sign;

	mpi_normalize(x);
	if (mpi_get_nlimbs(x) > 2*k) {
		mpi_mod(r, x, m);
		return;
	}

	sign = x->sign;
	x->sign = 0;

	/* 1. q1 = floor( x / b^k-1)
	 *    q2 = q1 * y
	 *    q3 = floor( q2 / b^k+1 )
	 * Actually, we don't need qx, we can work direct on r2
	 */
	mpi_set(r2, x);
	mpi_rshift_limbs(r2, k-1);
	mpi_mul(r2, r2, y);
	mpi_rshift_limbs(r2, k+1);

	/* 2. r1 = x mod b^k+1
	 *	r2 = q3 * m mod b^k+1
	 *	r  = r1 - r2
	 * 3. if r < 0 then  r = r + b^k+1
	 */
	mpi_set(r1, x);
	if (r1->nlimbs > k+1) /* Quick modulo operation.  */
		r1->nlimbs = k+1;
	mpi_mul(r2, r2, m);
	if (r2->nlimbs > k+1) /* Quick modulo operation. */
		r2->nlimbs = k+1;
	mpi_sub(r, r1, r2);

	if (mpi_has_sign(r)) {
		if (!ctx->r3) {
			ctx->r3 = mpi_alloc(k + 2);
			mpi_set_ui(ctx->r3, 1);
			mpi_lshift_limbs(ctx->r3, k + 1);
		}
		mpi_add(r, r, ctx->r3);
	}

	/* 4. while r >= m do r = r - m */
	while (mpi_cmp(r, m) >= 0)
		mpi_sub(r, r, m);

	x->sign = sign;
}


void mpi_mul_barrett(MPI w, MPI u, MPI v, mpi_barrett_t ctx)
{
	mpi_mul(w, u, v);
	mpi_mod_barrett(w, w, ctx);
}
back to top