--- sys/dev/sound/pcm/ac97.c.orig (revision 200510) +++ sys/dev/sound/pcm/ac97.c (working copy) @@ -715,8 +715,27 @@ ac97_initmixer(struct ac97_info *codec) * (ac97 2.3). */ bit = codec->mix[i].bits; - if (bit == 5) - bit++; + if (bit == 5) { + /* + * Test for possible 6bit control by + * turning on 5th (or 13th) and detect + * possible clamped values on the lower + * bits, which might be possible for + * 5bit control. + * + * XXX Emulators (QEMU, Virtualbox, + * etc..) does not reset the + * high bit, making it looks like + * a 6bit control. Consider that + * as "buggy codec". + */ + j = 1 << (5 + codec->mix[i].ofs); + ac97_wrcd(codec, reg, j); + k = ac97_rdcd(codec, reg); + k >>= codec->mix[i].ofs; + if ((k & 0x1f) != 0x1f) + bit++; + } j = ((1 << bit) - 1) << codec->mix[i].ofs; ac97_wrcd(codec, reg, j | (codec->mix[i].mute ? 0x8000 : 0)); --- sys/dev/sound/pcm/ac97_patch.c.orig 2009-04-15 03:14:26.000000000 +0000 +++ sys/dev/sound/pcm/ac97_patch.c 2009-11-15 16:10:10.000000000 +0000 @@ -48,9 +48,46 @@ void ad198x_patch(struct ac97_info* codec) { + /* + * AD198x series have 2 pairs of analog output: + * SURR_OUT/HP_OUT(surround or headphone) and LINE_OUT. + * + * Since SURR_OUT/HP_OUT output pins are equipped with power amps, + * retail machines often wire these to headphones jacks and/or + * internal speakers. + * This also means "mixer phout" will adjust speaker volume + * and "mixer vol" adjust lineout level, _independently_. + * + * (Linux has flags to swap vol/phout, and FreeBSD can do similar + * by mix_setrealdev() and gang them with mix_setparentchild()) + * + * AD198x register 0x76 + * 0x0400: select mixer for SURR_OUT/HP_OUT output pins (default surround DAC) + * 0x0020: select surround DAC for LINE_OUT output pins (default mixer) + * + * Selecting surround DAC for any output will yield "no sound", + * until FreeBSD supports surround DAC handling. + * + * Previous ad198x_patch() had set 0x0420, but 0x0400 seems to be + * better for all instances. At least you have mixer output + * for all output pins. + * The value is valid for all AD1888, AD1980, AD1985 and AD1986. + * (AD1986, having independent SURR_OUT and HP_OUT, will select + * mixer output for SURR_OUT by setting 0x0400 bit.) + * + * Fujitsu C610 seems to wire SURR_OUT/HP_OUT for + * internal speaker, and LINE_OUT for lineout AND headphone jacks; + * by setting previous 0x0420, internal speaker works but + * no output for either jacks. + * ASUS A9T may had been working by not setting the register because + * it only wired LINE_OUT. + */ switch (ac97_getsubvendor(codec)) { case 0x11931043: /* Not for ASUS A9T (probably else too). */ break; + case 0x122f10cf: /* Fujitsu C610 (perhaps for others) */ + ac97_wrcd(codec, 0x76, ac97_rdcd(codec, 0x76) | 0x0400); + break; default: ac97_wrcd(codec, 0x76, ac97_rdcd(codec, 0x76) | 0x0420); break; --- sys/dev/sound/pcm/dsp.c.orig (revision 222087) +++ sys/dev/sound/pcm/dsp.c (working copy) @@ -1969,7 +1969,9 @@ oc->fifo_samples = (sndbuf_getready(b) - tmp) / sndbuf_getalign(b); #else oc->samples = sndbuf_gettotal(bs) / sndbuf_getalign(bs); - oc->fifo_samples = sndbuf_getready(bs) / sndbuf_getalign(bs); + oc->fifo_samples = + ((chn == wrch) ? sndbuf_getready(bs) : + sndbuf_getfree(bs)) / sndbuf_getalign(bs); #endif CHN_UNLOCK(chn); } --- sys/tools/sound/feeder_rate_mkfilter.awk.orig (revision 197114) +++ sys/tools/sound/feeder_rate_mkfilter.awk (working copy) @@ -228,26 +228,34 @@ function lpf(imp, n, rolloff, beta, num, i, j, x, imp[0] = rolloff; # - # Generate ideal sinc impulses, locate the last zero-crossing and pad - # the remaining with 0. + # Generate ideal sinc impulses. # + for (i = 1; i < n; i++) { + x = (M_PI * i) / (1.0 * num); + imp[i] = sin(x * rolloff) / x; + } + + # + # Locate the last zero-crossing and pad the remaining with 0. + # # Note that there are other (faster) ways of calculating this without # the misery of traversing the entire sinc given the fact that the # distance between each zero crossings is actually the bandwidth of # the impulses, but it seems having 0.0001% chances of failure due to # limited precision. # + # Avoid zero padding if number of taps is too small ( < 6 ). + # + j = n; - for (i = 1; i < n; i++) { - x = (M_PI * i) / (1.0 * num); - imp[i] = sin(x * rolloff) / x; - if (i != 1 && (imp[i] * imp[i - 1]) <= 0.0) + x = floor(((n - 1) * 2) / num); + + for (i = n - 1; x > 5 && j == n && i > 1; i--) { + if ((imp[i] * imp[i - 1]) <= 0.0) j = i; + imp[i] = 0.0; } - for (i = j; i < n; i++) - imp[i] = 0.0; - nm = 1.0 * (j - 1); if (beta >= Z_WINDOW_KAISER) @@ -482,50 +490,19 @@ function genscale(bit, s1, s2, scale) else if (s1 < 0) scale = sprintf("(v) << %d", abs(s1)); else - scale = sprintf("(v) >> %d", s1); + scale = sprintf("Z_OUT_SHIFT%s(v, %d)", \ + (s1 > 31) ? "_L" : "", s1); scale = sprintf("(%s) * Z_SCALE_CAST(s)", scale); if (s2 != 0) - scale = sprintf("(%s) >> %d", scale, s2); + scale = sprintf("Z_OUT_SHIFT%s(%s, %d)", \ + (s2 > 31) ? "_L" : "", scale, s2); - printf("#define Z_SCALE_%d(v, s)\t%s(%s)\n", \ + printf("#define Z_SCALE_%d(v, s)\t\t\t\t\t\t%s\\\n\t(%s)\n", \ bit, (bit < 10) ? "\t" : "", scale); } -function genlerp(bit, use64, lerp) -{ - if ((bit + Z_LINEAR_SHIFT) <= 32) { - lerp = sprintf("(((y) - (x)) * (z)) >> %d", Z_LINEAR_SHIFT); - } else if (use64 != 0) { - if ((bit + Z_LINEAR_SHIFT) <= 64) { - lerp = sprintf( \ - "(((int64_t)(y) - (x)) * (z)) " \ - ">> %d", \ - Z_LINEAR_SHIFT); - } else { - lerp = sprintf( \ - "((int64_t)((y) >> %d) - ((x) >> %d)) * ", \ - "(z)" \ - bit + Z_LINEAR_SHIFT - 64, \ - bit + Z_LINEAR_SHIFT - 64); - if ((64 - bit) != 0) - lerp = sprintf("(%s) >> %d", lerp, 64 - bit); - } - } else { - lerp = sprintf( \ - "(((y) >> %d) - ((x) >> %d)) * (z)", \ - bit + Z_LINEAR_SHIFT - 32, \ - bit + Z_LINEAR_SHIFT - 32); - if ((32 - bit) != 0) - lerp = sprintf("(%s) >> %d", lerp, 32 - bit); - } - - printf("#define Z_LINEAR_INTERPOLATE_%d(z, x, y)" \ - "\t\t\t\t%s\\\n\t((x) + (%s))\n", \ - bit, (bit < 10) ? "\t" : "", lerp); -} - function init_drift(drift, xdrift) { xdrift = floor(drift); @@ -586,7 +563,9 @@ function init_accum_bit(accbit, xaccbit) } # - # Initialize dynamic range of accumulator. + # Initialize dynamic range of accumulator. Less than 39 produce + # quite noticable quantization errors but can be compensated by + # enabling SND_FEEDER_RATE_HP (slower execution). # if (xaccbit > 64) xaccbit = 64; @@ -603,7 +582,8 @@ function init_coeff_interpolator(interp) # if (interp == "ZOH" || interp == "LINEAR" || \ interp == "QUADRATIC" || interp == "HERMITE" || \ - interp == "BSPLINE" || interp == "OPT32X" || \ + interp == "BSPLINE" || interp == "BSPLINE_3" || \ + interp == "BSPLINE_5" || interp == "OPT32X" || \ interp == "OPT16X" || interp == "OPT8X" || \ interp == "OPT4X" || interp == "OPT2X") Z_COEFF_INTERPOLATOR = interp; @@ -633,12 +613,6 @@ BEGIN { Z_INTERP_COEFF_SHIFT = 24; Z_INTERP_COEFF_ONE = shl(1, Z_INTERP_COEFF_SHIFT); - Z_LINEAR_FULL_SHIFT = Z_FULL_SHIFT; - Z_LINEAR_FULL_ONE = shl(1, Z_LINEAR_FULL_SHIFT); - Z_LINEAR_SHIFT = 8; - Z_LINEAR_UNSHIFT = Z_LINEAR_FULL_SHIFT - Z_LINEAR_SHIFT; - Z_LINEAR_ONE = shl(1, Z_LINEAR_SHIFT) - Z_DRIFT_SHIFT_DEFAULT = 5; Z_DRIFT_SHIFT = -1; # meehhhh... let it overflow... @@ -789,6 +763,17 @@ BEGIN { "(1 << ((y) - 1))) >> (y))\n"); printf("#define Z_RSHIFT_L(x, y)\t(((x) + " \ "(1LL << ((y) - 1))) >> (y))\n\n"); + printf("#define Z_TSHIFT(x, y)\t\t((x) >> (y))\n"); + printf("#define Z_TSHIFT_L(x, y)\t((x) >> (y))\n\n"); + printf("#define Z_OUT_SHIFT(...)\tZ_TSHIFT(__VA_ARGS__)\n"); + printf("#define Z_OUT_SHIFT_L(...)\tZ_TSHIFT_L(__VA_ARGS__)\n\n"); + printf("#ifdef SND_FEEDER_RATE_HP\n"); + printf("#define Z_NORM_SHIFT(...)\tZ_RSHIFT(__VA_ARGS__)\n"); + printf("#define Z_NORM_SHIFT_L(...)\tZ_RSHIFT_L(__VA_ARGS__)\n"); + printf("#else\n"); + printf("#define Z_NORM_SHIFT(...)\tZ_TSHIFT(__VA_ARGS__)\n"); + printf("#define Z_NORM_SHIFT_L(...)\tZ_TSHIFT(__VA_ARGS__)\n"); + printf("#endif\n\n"); printf("#define Z_FULL_SHIFT\t\t%d\n", Z_FULL_SHIFT); printf("#define Z_FULL_ONE\t\t0x%08x%s\n", Z_FULL_ONE, \ (Z_FULL_ONE > INT32_MAX) ? "U" : ""); @@ -807,7 +792,9 @@ BEGIN { v = (Z_ONE - 1) * abs(largest_interp); if (v < INT32_MIN || v > INT32_MAX) zinterphp = sprintf("(int64_t)%s", zinterphp); - zinterphp = sprintf("(%s) >> %d", zinterphp, zinterpunshift); + zinterphp = sprintf("Z_RSHIFT%s(%s, %d)", \ + (zinterpunshift > 31) ? "_L" : "", zinterphp, \ + zinterpunshift); } else if (zinterpunshift < 0) zinterphp = sprintf("(%s) << %d", zinterphp, \ abs(zinterpunshift)); @@ -821,7 +808,7 @@ BEGIN { abs(Z_INTERP_UNSHIFT)); else if (Z_INTERP_UNSHIFT > 0) zinterp = sprintf("(%s) >> %d", zinterp, Z_INTERP_UNSHIFT); - if (zinterphp != zinterp) { + #if (zinterphp != zinterp) { printf("\n#ifdef SND_FEEDER_RATE_HP\n"); printf("#define Z_COEFF_INTERPOLATE(z, c, d)" \ "\t\t\t\t\t\\\n\t((c) + (%s))\n", zinterphp); @@ -829,15 +816,19 @@ BEGIN { printf("#define Z_COEFF_INTERPOLATE(z, c, d)" \ "\t\t\t\t\t\\\n\t((c) + (%s))\n", zinterp); printf("#endif\n"); - } else - printf("#define Z_COEFF_INTERPOLATE(z, c, d)" \ - "\t\t\t\t\t\\\n\t((c) + (%s))\n", zinterp); + #} else + # printf("#define Z_COEFF_INTERPOLATE(z, c, d)" \ + # "\t\t\t\t\t\\\n\t((c) + (%s))\n", zinterp); #printf("\n"); #printf("#define Z_SCALE_SHIFT\t\t%d\n", Z_SCALE_SHIFT); #printf("#define Z_SCALE_ONE\t\t0x%08x%s\n", Z_SCALE_ONE, \ # (Z_SCALE_ONE > INT32_MAX) ? "U" : ""); printf("\n"); + printf("#ifdef Z_SCALE_UINT\n"); printf("#define Z_SCALE_CAST(s)\t\t((uint32_t)(s))\n"); + printf("#else\n"); + printf("#define Z_SCALE_CAST(s)\t\t(s)\n"); + printf("#endif\n"); genscale(8); genscale(16); genscale(24); @@ -849,29 +840,101 @@ BEGIN { (i - (Z_ACCUMULATOR_BIT - Z_COEFF_SHIFT)) : 0; printf("#define Z_GUARD_BIT_%d\t\t%d\n", i, gbit); if (gbit == 0) - printf("#define Z_NORM_%d(v)\t\t(v)\n\n", i); + printf("#define Z_NORM_%d(v)\t\t(v)\n", i); else printf("#define Z_NORM_%d(v)\t\t" \ - "((v) >> Z_GUARD_BIT_%d)\n\n", i, i); + "Z_NORM_SHIFT%s(v, Z_GUARD_BIT_%d)\n", \ + i, (gbit > 31) ? "_L" : "", i); + printf("#define Z_OUT_%d(v, s)\t\t\t\t\t\t\t\\\n\t" \ + "(((s) != Z_ONE) ? Z_SCALE_%d(v, s) :\t\t\t\t\\" \ + "\n\t", i, i); + if (Z_COEFF_SHIFT - gbit > 0) + printf("Z_OUT_SHIFT(v, Z_COEFF_SHIFT - " \ + "Z_GUARD_BIT_%d)", i); + else + printf("(v)"); + printf(")\n\n"); } + + printf("#define Z_LINEAR_SHIFT\t\t31\n"); + printf("#define Z_LINEAR_ONE\t\t(1U << Z_LINEAR_SHIFT)\n"); printf("\n"); - printf("#define Z_LINEAR_FULL_ONE\t0x%08xU\n", Z_LINEAR_FULL_ONE); - printf("#define Z_LINEAR_SHIFT\t\t%d\n", Z_LINEAR_SHIFT); - printf("#define Z_LINEAR_UNSHIFT\t%d\n", Z_LINEAR_UNSHIFT); - printf("#define Z_LINEAR_ONE\t\t0x%08x\n", Z_LINEAR_ONE); + printf("#define _Z_LINEAR_INTERPOLATE_INT32(z, x, y, xs, ys, " \ + "s)\t\t\t\\\n\t((x) + (((((y) >> (ys)) - ((x) >> (xs))) * " \ + "(z)) >> (s)))\n"); printf("\n"); - printf("#ifdef SND_PCM_64\n"); - genlerp(8, 1); - genlerp(16, 1); - genlerp(24, 1); - genlerp(32, 1); - printf("#else\t/* !SND_PCM_64 */\n"); - genlerp(8, 0); - genlerp(16, 0); - genlerp(24, 0); - genlerp(32, 0); - printf("#endif\t/* SND_PCM_64 */\n"); + printf("#define _Z_LINEAR_INTERPOLATE_INT64(z, x, y)" \ + "\t\t\t\t\\\n\t_Z_LINEAR_INTERPOLATE_INT32(z, x, " \ + "(int64_t)(y), 0, 0, Z_LINEAR_SHIFT)\n"); printf("\n"); + printf("#define Z_LINEAR_FRACTION_8_INT32(x)\t\t" \ + "((x) >> (Z_LINEAR_SHIFT - 24))\n"); + printf("#define Z_LINEAR_FRACTION_16_INT32(x)\t\t" \ + "((x) >> (Z_LINEAR_SHIFT - 16))\n"); + printf("#define Z_LINEAR_FRACTION_24_INT32(x)\t\t" \ + "((x) >> (Z_LINEAR_SHIFT - 8))\n"); + printf("#define Z_LINEAR_FRACTION_32_INT32(x)\t\t" \ + "((x) >> (Z_LINEAR_SHIFT - 8))\n"); + printf("\n"); + printf("#define Z_LINEAR_FRACTION_8_INT64(x)\t\t(x)\n"); + printf("#define Z_LINEAR_FRACTION_16_INT64(x)\t\t(x)\n"); + printf("#define Z_LINEAR_FRACTION_24_INT64(x)\t\t(x)\n"); + printf("#define Z_LINEAR_FRACTION_32_INT64(x)\t\t(x)\n"); + printf("\n"); + printf("#define Z_LINEAR_INTERPOLATE_8_INT32(...)\t\t\t\t\\\n"); + printf("\t_Z_LINEAR_INTERPOLATE_INT32(__VA_ARGS__, 0, 0, 24)\n"); + printf("#define Z_LINEAR_INTERPOLATE_16_INT32(...)\t\t\t\t\\\n"); + printf("\t_Z_LINEAR_INTERPOLATE_INT32(__VA_ARGS__, 0, 0, 16)\n"); + printf("#define Z_LINEAR_INTERPOLATE_24_INT32(...)\t\t\t\t\\\n"); + printf("\t_Z_LINEAR_INTERPOLATE_INT32(__VA_ARGS__, 0, 0, 8)\n"); + printf("#define Z_LINEAR_INTERPOLATE_32_INT32(...)\t\t\t\t\\\n"); + printf("\t_Z_LINEAR_INTERPOLATE_INT32(__VA_ARGS__, 8, 8, 0)\n"); + printf("\n"); + printf("#define Z_LINEAR_INTERPOLATE_8_INT64(...)\t\t\t\t\\\n"); + printf("\t_Z_LINEAR_INTERPOLATE_INT64(__VA_ARGS__)\n"); + printf("#define Z_LINEAR_INTERPOLATE_16_INT64(...)\t\t\t\t\\\n"); + printf("\t_Z_LINEAR_INTERPOLATE_INT64(__VA_ARGS__)\n"); + printf("#define Z_LINEAR_INTERPOLATE_24_INT64(...)\t\t\t\t\\\n"); + printf("\t_Z_LINEAR_INTERPOLATE_INT64(__VA_ARGS__)\n"); + printf("#define Z_LINEAR_INTERPOLATE_32_INT64(...)\t\t\t\t\\\n"); + printf("\t_Z_LINEAR_INTERPOLATE_INT64(__VA_ARGS__)\n"); + printf("\n"); + printf("#if defined(SND_PCM_64) || defined(SND_FEEDER_RATE_HP)\n"); + printf("#define Z_LINEAR_FRACTION_8(...)\t" \ + "Z_LINEAR_FRACTION_8_INT64(__VA_ARGS__)\n"); + printf("#define Z_LINEAR_FRACTION_16(...)\t" \ + "Z_LINEAR_FRACTION_16_INT64(__VA_ARGS__)\n"); + printf("#define Z_LINEAR_FRACTION_24(...)\t" \ + "Z_LINEAR_FRACTION_24_INT64(__VA_ARGS__)\n"); + printf("#define Z_LINEAR_FRACTION_32(...)\t" \ + "Z_LINEAR_FRACTION_32_INT64(__VA_ARGS__)\n"); + printf("#define Z_LINEAR_INTERPOLATE_8(...)\t\t\t\t\t\\\n"); + printf("\tZ_LINEAR_INTERPOLATE_8_INT64(__VA_ARGS__)\n"); + printf("#define Z_LINEAR_INTERPOLATE_16(...)\t\t\t\t\t\\\n"); + printf("\tZ_LINEAR_INTERPOLATE_16_INT64(__VA_ARGS__)\n"); + printf("#define Z_LINEAR_INTERPOLATE_24(...)\t\t\t\t\t\\\n"); + printf("\tZ_LINEAR_INTERPOLATE_24_INT64(__VA_ARGS__)\n"); + printf("#define Z_LINEAR_INTERPOLATE_32(...)\t\t\t\t\t\\\n"); + printf("\tZ_LINEAR_INTERPOLATE_32_INT64(__VA_ARGS__)\n"); + printf("#else\n"); + printf("#define Z_LINEAR_FRACTION_8(...)\t" \ + "Z_LINEAR_FRACTION_8_INT32(__VA_ARGS__)\n"); + printf("#define Z_LINEAR_FRACTION_16(...)\t" \ + "Z_LINEAR_FRACTION_16_INT32(__VA_ARGS__)\n"); + printf("#define Z_LINEAR_FRACTION_24(...)\t" \ + "Z_LINEAR_FRACTION_24_INT32(__VA_ARGS__)\n"); + printf("#define Z_LINEAR_FRACTION_32(...)\t" \ + "Z_LINEAR_FRACTION_32_INT32(__VA_ARGS__)\n"); + printf("#define Z_LINEAR_INTERPOLATE_8(...)\t\t\t\t\t\\\n"); + printf("\tZ_LINEAR_INTERPOLATE_8_INT32(__VA_ARGS__)\n"); + printf("#define Z_LINEAR_INTERPOLATE_16(...)\t\t\t\t\t\\\n"); + printf("\tZ_LINEAR_INTERPOLATE_16_INT32(__VA_ARGS__)\n"); + printf("#define Z_LINEAR_INTERPOLATE_24(...)\t\t\t\t\t\\\n"); + printf("\tZ_LINEAR_INTERPOLATE_24_INT32(__VA_ARGS__)\n"); + printf("#define Z_LINEAR_INTERPOLATE_32(...)\t\t\t\t\t\\\n"); + printf("\tZ_LINEAR_INTERPOLATE_32_INT32(__VA_ARGS__)\n"); + printf("#endif\n\n"); + printf("#define Z_QUALITY_ZOH\t\t0\n"); printf("#define Z_QUALITY_LINEAR\t1\n"); printf("#define Z_QUALITY_SINC\t\t%d\n", \ @@ -879,9 +942,23 @@ BEGIN { printf("\n"); printf("#define Z_QUALITY_MIN\t\t0\n"); printf("#define Z_QUALITY_MAX\t\t%d\n", length(ztab) + 1); - if (Z_COEFF_INTERPOLATOR != 0) - printf("\n#define Z_COEFF_INTERP_%s\t1\n", \ + if (Z_COEFF_INTERPOLATOR != 0) { + printf("\n#if !(defined(Z_COEFF_INTERP_ZOH) || " \ + "defined(Z_COEFF_INTERP_LINEAR) ||\t\t\\\n" \ + " defined(Z_COEFF_INTERP_QUADRATIC) || " \ + "defined(Z_COEFF_INTERP_HERMITE) ||\t\\\n" \ + " defined(Z_COEFF_INTERP_BSPLINE) || " \ + "defined(Z_COEFF_INTERP_BSPLINE_3) ||\t\\\n" \ + " defined(Z_COEFF_INTERP_BSPLINE_5) || " \ + "defined(Z_COEFF_INTERP_OPT32X) ||\t\\\n" \ + " defined(Z_COEFF_INTERP_OPT16X) || " \ + "defined(Z_COEFF_INTERP_OPT8X) ||\t\t\\\n" \ + " defined(Z_COEFF_INTERP_OPT4X) || " \ + "defined(Z_COEFF_INTERP_OPT2X))\n"); + printf("#define Z_COEFF_INTERP_%s\t1\n", \ Z_COEFF_INTERPOLATOR); + printf("#endif\n"); + } printf("\n/*\n * smallest: %.32f\n * largest: %.32f\n *\n", \ smallest, largest); printf(" * z_unshift=%d, z_interp_shift=%d\n *\n", \ --- sys/dev/sound/pcm/feeder_rate.c.orig (revision 217079) +++ sys/dev/sound/pcm/feeder_rate.c (working copy) @@ -54,6 +54,7 @@ #endif #include #include +#include #include "feeder_if.h" #define SND_USE_FXDIV @@ -69,6 +70,7 @@ #define Z_DIAGNOSTIC 1 #elif defined(_KERNEL) #undef Z_DIAGNOSTIC +#undef Z_STRESS_TEST #endif #ifndef Z_QUALITY_DEFAULT @@ -78,8 +80,10 @@ #define Z_RESERVOIR 2048 #define Z_RESERVOIR_MAX 131072 +#define Z_DOWNMAX 48 /* 384000 / 8000 */ + #define Z_SINC_MAX 0x3fffff -#define Z_SINC_DOWNMAX 48 /* 384000 / 8000 */ +#define Z_SINC_DOWNMAX Z_DOWNMAX #ifdef _KERNEL #define Z_POLYPHASE_MAX 183040 /* 286 taps, 640 phases */ @@ -137,7 +141,6 @@ int32_t z_alphadrift; /* alpha drift rate */ int32_t z_startdrift; /* buffer start position drift rate */ #endif - int32_t z_mask; /* delay line full length mask */ int32_t z_size; /* half width of FIR taps */ int32_t z_full; /* full size of delay line */ int32_t z_alloc; /* largest allocated full size of delay line */ @@ -273,11 +276,8 @@ CHN_FOREACH(c, d, channels.pcm) { CHN_LOCK(c); f = chn_findfeeder(c, FEEDER_RATE); - if (f == NULL || f->data == NULL || CHN_STARTED(c)) { - CHN_UNLOCK(c); - continue; - } - (void)FEEDER_SET(f, FEEDRATE_QUALITY, val); + if (f != NULL && f->data != NULL) + (void)FEEDER_SET(f, FEEDRATE_QUALITY, val); CHN_UNLOCK(c); } PCM_RELEASE(d); @@ -301,6 +301,11 @@ #define Z_IS_SINC(i) ((i)->quality > Z_QUALITY_LINEAR) /* + * Linear interpolation with downsampling ratio of 1 is practically zoh. + */ +#define Z_IS_LINEAR_ZOH(i) (Z_IS_LINEAR(i) && (i)->z_gy == 1) + +/* * Macroses for accurate sample time drift calculations. * * gy2gx : given the amount of output, return the _exact_ required amount of @@ -360,32 +365,39 @@ #define z_gx2gy(i, v) _Z_GX2GY(i, (i)->z_alpha, v) #define z_drift(i, x, y) _Z_DRIFT(i, x, y) +#define Z_SRC_DOWN(i) ((i)->z_gx > (i)->z_gy) +#define Z_SRC_UP(i) (!Z_SRC_DOWN(i)) + +#define Z_FACTOR_DOWN(i) (Z_SRC_DOWN(i) ? _Z_GY2GX(i, 0, 1) : 0) +#define Z_FACTOR_UP(i) (Z_SRC_UP(i) ? _Z_GX2GY(i, 0, 1) : 0) + /* * Macroses for SINC coefficients table manipulations.. whatever. */ #define Z_SINC_COEFF_IDX(i) ((i)->quality - Z_QUALITY_LINEAR - 1) #define Z_SINC_LEN(i) \ - ((int32_t)(((uint64_t)z_coeff_tab[Z_SINC_COEFF_IDX(i)].len << \ - Z_SHIFT) / (i)->z_dy)) + ((int32_t)((((uint64_t)z_coeff_tab[Z_SINC_COEFF_IDX(i)].len << \ + Z_SHIFT) - 1) / (i)->z_dy)) #define Z_SINC_BASE_LEN(i) \ ((z_coeff_tab[Z_SINC_COEFF_IDX(i)].len - 1) >> (Z_DRIFT_SHIFT - 1)) /* - * Macroses for linear delay buffer operations. Alignment is not - * really necessary since we're not using true circular buffer, but it - * will help us guard against possible trespasser. To be honest, - * the linear block operations does not need guarding at all due to - * accurate drifting! + * Macroses for linear delay buffer operations. */ -#define z_align(i, v) ((v) & (i)->z_mask) -#define z_next(i, o, v) z_align(i, (o) + (v)) -#define z_prev(i, o, v) z_align(i, (o) - (v)) -#define z_fetched(i) (z_align(i, (i)->z_pos - (i)->z_start) - 1) +#define z_fetched(i) ((i)->z_pos - (i)->z_start - 1) #define z_free(i) ((i)->z_full - (i)->z_pos) /* + * For !sinc, z_size represents full history. + */ +#define z_history(i) (Z_IS_SINC(i) ? ((i)->z_size << 1) : \ + (i)->z_size) + +#define z_start_drift(i) _Z_GY2GX(i, 0, 1) + +/* * Macroses for Bla Bla .. :) */ #define z_copy(src, dst, sz) (void)memcpy(dst, src, sz) @@ -398,6 +410,31 @@ return ((x < y) ? x : y); } +static void +z_zero(uint8_t *buf, uint32_t format, uint32_t count) +{ + intpcm_write_t *wr_op; + uint8_t *b; + uint32_t bps; + + if (count < 1) + return; + + if ((format & AFMT_SIGNED) || + (wr_op = feeder_format_write_op(format)) == NULL) { + memset(buf, sndbuf_zerodata(format), count * AFMT_BPS(format)); + return; + } + + bps = AFMT_BPS(format); + b = buf + (count * bps); + + do { + b -= bps; + wr_op(b, 0); + } while (b != buf); +} + static int32_t z_gcd(int32_t x, int32_t y) { @@ -412,6 +449,7 @@ return (x); } +#ifndef Z_STRESS_TEST static int32_t z_roundpow2(int32_t v) { @@ -427,6 +465,7 @@ return (i); } +#endif /* * Zero Order Hold, the worst of the worst, an insult against quality, @@ -461,7 +500,18 @@ * but without any proper filtering which means aliasing still exist and * could become worst with a right sample. Interpolation centered within * Z_LINEAR_ONE between the present and previous sample and everything is - * done with simple 32bit scaling arithmetic. + * done with simple 64bit or 32bit scaling arithmetic. + * + * 64bit linear interpolation - Full dynamic range, slower on 32bit arch + * (though still quite fast). + * + * 32bit linear interpolation - Fraction and interpolation reduced to make + * room for 32bit arithmetic at the cost + * of conversion accuracy but lightning fast. + * + * Whether it is 64bit or 32bit, these are only interesting from analysis + * point of view. Draging it further for the sake of quality is fighting + * a losing cause. */ #define Z_DECLARE_LINEAR(SIGN, BIT, ENDIAN) \ static void \ @@ -472,7 +522,7 @@ uint32_t ch; \ uint8_t *sx, *sy; \ \ - z = ((uint32_t)info->z_alpha * info->z_dx) >> Z_LINEAR_UNSHIFT; \ + z = Z_LINEAR_FRACTION_##BIT(info->z_alpha * info->z_dx); \ \ sx = info->z_delay + (info->z_start * info->channels * \ PCM_##BIT##_BPS); \ @@ -522,15 +572,25 @@ * shifted to a full 32 bit, scaled and restored during write for * maximum dynamic range (only for downsampling). */ -#define _Z_SINC_ACCUMULATE(SIGN, BIT, ENDIAN, adv) \ - c += z >> Z_SHIFT; \ +#define _Z_SINC_ACCUMULATE(SIGN, BIT, ENDIAN, adv, acc) \ + c = z >> Z_SHIFT; \ z &= Z_MASK; \ - coeff = Z_COEFF_INTERPOLATE(z, z_coeff[c], z_dcoeff[c]); \ + z_coeff += c; \ + z_dcoeff += c; \ + coeff = Z_COEFF_INTERPOLATE(z, *z_coeff, *z_dcoeff); \ x = _PCM_READ_##SIGN##BIT##_##ENDIAN(p); \ - v += Z_NORM_##BIT((intpcm64_t)x * coeff); \ + acc += Z_NORM_##BIT((intpcm64_t)x * coeff); \ z += info->z_dy; \ p adv##= info->channels * PCM_##BIT##_BPS +#define _Z_SINC_FAST_ACCUMULATE(SIGN, BIT, ENDIAN, adv, acc) \ + z_coeff += z >> Z_SHIFT; \ + z &= Z_MASK; \ + x = _PCM_READ_##SIGN##BIT##_##ENDIAN(p); \ + acc += Z_NORM_##BIT((intpcm64_t)x * *z_coeff); \ + z += info->z_dy; \ + p adv##= info->channels * PCM_##BIT##_BPS + /* * XXX GCC4 optimization is such a !@#$%, need manual unrolling. */ @@ -539,11 +599,18 @@ _Z_SINC_ACCUMULATE(__VA_ARGS__); \ _Z_SINC_ACCUMULATE(__VA_ARGS__); \ } while (0) +#define Z_SINC_FAST_ACCUMULATE(...) do { \ + _Z_SINC_FAST_ACCUMULATE(__VA_ARGS__); \ + _Z_SINC_FAST_ACCUMULATE(__VA_ARGS__); \ +} while (0) #define Z_SINC_ACCUMULATE_DECR 2 #else #define Z_SINC_ACCUMULATE(...) do { \ _Z_SINC_ACCUMULATE(__VA_ARGS__); \ } while (0) +#define Z_SINC_FAST_ACCUMULATE(...) do { \ + _Z_SINC_FAST_ACCUMULATE(__VA_ARGS__); \ +} while (0) #define Z_SINC_ACCUMULATE_DECR 1 #endif @@ -551,60 +618,94 @@ static void \ z_feed_sinc_##SIGN##BIT##ENDIAN(struct z_info *info, uint8_t *dst) \ { \ - intpcm64_t v; \ + intpcm64_t v, v0; \ intpcm_t x; \ uint8_t *p; \ int32_t coeff, z, *z_coeff, *z_dcoeff; \ - uint32_t c, center, ch, i; \ + uint32_t c, ch, i; \ \ - z_coeff = info->z_coeff; \ - z_dcoeff = info->z_dcoeff; \ - center = z_prev(info, info->z_start, info->z_size); \ ch = info->channels * PCM_##BIT##_BPS; \ dst += ch; \ \ do { \ + v = v0 = 0; \ dst -= PCM_##BIT##_BPS; \ ch -= PCM_##BIT##_BPS; \ - v = 0; \ z = info->z_alpha * info->z_dx; \ - c = 0; \ - p = info->z_delay + (z_next(info, center, 1) * \ + p = info->z_delay + ((info->z_start - info->z_size + 1) * \ info->channels * PCM_##BIT##_BPS) + ch; \ + z_coeff = info->z_coeff; \ + z_dcoeff = info->z_dcoeff; \ for (i = info->z_size; i != 0; i -= Z_SINC_ACCUMULATE_DECR) \ - Z_SINC_ACCUMULATE(SIGN, BIT, ENDIAN, +); \ + Z_SINC_ACCUMULATE(SIGN, BIT, ENDIAN, +, v); \ z = info->z_dy - (info->z_alpha * info->z_dx); \ - c = 0; \ - p = info->z_delay + (center * info->channels * \ - PCM_##BIT##_BPS) + ch; \ + p = info->z_delay + ((info->z_start - info->z_size) * \ + info->channels * PCM_##BIT##_BPS) + ch; \ + z_coeff = info->z_coeff; \ + z_dcoeff = info->z_dcoeff; \ for (i = info->z_size; i != 0; i -= Z_SINC_ACCUMULATE_DECR) \ - Z_SINC_ACCUMULATE(SIGN, BIT, ENDIAN, -); \ - if (info->z_scale != Z_ONE) \ - v = Z_SCALE_##BIT(v, info->z_scale); \ - else \ - v >>= Z_COEFF_SHIFT - Z_GUARD_BIT_##BIT; \ + Z_SINC_ACCUMULATE(SIGN, BIT, ENDIAN, -, v0); \ + v += v0; \ + v = Z_OUT_##BIT(v, info->z_scale); \ Z_CLIP_CHECK(v, BIT); \ _PCM_WRITE_##SIGN##BIT##_##ENDIAN(dst, Z_CLAMP(v, BIT)); \ } while (ch != 0); \ } +#define Z_DECLARE_SINC_FAST(SIGN, BIT, ENDIAN) \ +static void \ +z_feed_sinc_fast_##SIGN##BIT##ENDIAN(struct z_info *info, uint8_t *dst) \ +{ \ + intpcm64_t v, v0; \ + intpcm_t x; \ + uint8_t *p; \ + int32_t z, *z_coeff; \ + uint32_t ch, i; \ + \ + ch = info->channels * PCM_##BIT##_BPS; \ + dst += ch; \ + \ + do { \ + v = v0 = 0; \ + dst -= PCM_##BIT##_BPS; \ + ch -= PCM_##BIT##_BPS; \ + z = info->z_alpha * info->z_dx; \ + p = info->z_delay + ((info->z_start - info->z_size + 1) * \ + info->channels * PCM_##BIT##_BPS) + ch; \ + z_coeff = info->z_coeff; \ + for (i = info->z_size; i != 0; i -= Z_SINC_ACCUMULATE_DECR) \ + Z_SINC_FAST_ACCUMULATE(SIGN, BIT, ENDIAN, +, v); \ + z = info->z_dy - (info->z_alpha * info->z_dx); \ + p = info->z_delay + ((info->z_start - info->z_size) * \ + info->channels * PCM_##BIT##_BPS) + ch; \ + z_coeff = info->z_coeff; \ + for (i = info->z_size; i != 0; i -= Z_SINC_ACCUMULATE_DECR) \ + Z_SINC_FAST_ACCUMULATE(SIGN, BIT, ENDIAN, -, v0); \ + v += v0; \ + v = Z_OUT_##BIT(v, info->z_scale); \ + Z_CLIP_CHECK(v, BIT); \ + _PCM_WRITE_##SIGN##BIT##_##ENDIAN(dst, Z_CLAMP(v, BIT)); \ + } while (ch != 0); \ +} + #define Z_DECLARE_SINC_POLYPHASE(SIGN, BIT, ENDIAN) \ static void \ z_feed_sinc_polyphase_##SIGN##BIT##ENDIAN(struct z_info *info, uint8_t *dst) \ { \ - intpcm64_t v; \ + intpcm64_t v, v0; \ intpcm_t x; \ uint8_t *p; \ - int32_t ch, i, start, *z_pcoeff; \ + int32_t *z_pcoeff; \ + uint32_t ch, i, start; \ \ ch = info->channels * PCM_##BIT##_BPS; \ dst += ch; \ - start = z_prev(info, info->z_start, (info->z_size << 1) - 1) * ch; \ + start = (info->z_start - (info->z_size << 1) + 1) * ch; \ \ do { \ + v = v0 = 0; \ dst -= PCM_##BIT##_BPS; \ ch -= PCM_##BIT##_BPS; \ - v = 0; \ p = info->z_delay + start + ch; \ z_pcoeff = info->z_pcoeff + \ ((info->z_alpha * info->z_size) << 1); \ @@ -614,14 +715,12 @@ z_pcoeff++; \ p += info->channels * PCM_##BIT##_BPS; \ x = _PCM_READ_##SIGN##BIT##_##ENDIAN(p); \ - v += Z_NORM_##BIT((intpcm64_t)x * *z_pcoeff); \ + v0 += Z_NORM_##BIT((intpcm64_t)x * *z_pcoeff); \ z_pcoeff++; \ p += info->channels * PCM_##BIT##_BPS; \ } \ - if (info->z_scale != Z_ONE) \ - v = Z_SCALE_##BIT(v, info->z_scale); \ - else \ - v >>= Z_COEFF_SHIFT - Z_GUARD_BIT_##BIT; \ + v += v0; \ + v = Z_OUT_##BIT(v, info->z_scale); \ Z_CLIP_CHECK(v, BIT); \ _PCM_WRITE_##SIGN##BIT##_##ENDIAN(dst, Z_CLAMP(v, BIT)); \ } while (ch != 0); \ @@ -630,6 +729,7 @@ #define Z_DECLARE(SIGN, BIT, ENDIAN) \ Z_DECLARE_LINEAR(SIGN, BIT, ENDIAN) \ Z_DECLARE_SINC(SIGN, BIT, ENDIAN) \ + Z_DECLARE_SINC_FAST(SIGN, BIT, ENDIAN) \ Z_DECLARE_SINC_POLYPHASE(SIGN, BIT, ENDIAN) #if BYTE_ORDER == LITTLE_ENDIAN || defined(SND_FEEDER_MULTIFORMAT) @@ -657,6 +757,7 @@ Z_RESAMPLER_ZOH, Z_RESAMPLER_LINEAR, Z_RESAMPLER_SINC, + Z_RESAMPLER_SINC_FAST, Z_RESAMPLER_SINC_POLYPHASE, Z_RESAMPLER_LAST }; @@ -671,6 +772,8 @@ [Z_RESAMPLER_ZOH] = z_feed_zoh, \ [Z_RESAMPLER_LINEAR] = z_feed_linear_##SIGN##BIT##ENDIAN, \ [Z_RESAMPLER_SINC] = z_feed_sinc_##SIGN##BIT##ENDIAN, \ + [Z_RESAMPLER_SINC_FAST] = \ + z_feed_sinc_fast_##SIGN##BIT##ENDIAN, \ [Z_RESAMPLER_SINC_POLYPHASE] = \ z_feed_sinc_polyphase_##SIGN##BIT##ENDIAN \ } \ @@ -768,7 +871,6 @@ #else fprintf(stderr, "%s(): sinc l=%d != Z_SINC_LEN=%d\n", __func__, len, Z_SINC_LEN(info)); - return (-1); #endif } @@ -786,12 +888,15 @@ */ #if !(defined(Z_COEFF_INTERP_ZOH) || defined(Z_COEFF_INTERP_LINEAR) || \ defined(Z_COEFF_INTERP_QUADRATIC) || defined(Z_COEFF_INTERP_HERMITE) || \ - defined(Z_COEFF_INTER_BSPLINE) || defined(Z_COEFF_INTERP_OPT32X) || \ + defined(Z_COEFF_INTERP_BSPLINE) || defined(Z_COEFF_INTERP_BSPLINE_3) || \ + defined(Z_COEFF_INTERP_BSPLINE_5) || defined(Z_COEFF_INTERP_OPT32X) || \ defined(Z_COEFF_INTERP_OPT16X) || defined(Z_COEFF_INTERP_OPT8X) || \ defined(Z_COEFF_INTERP_OPT4X) || defined(Z_COEFF_INTERP_OPT2X)) -#if Z_DRIFT_SHIFT >= 6 -#define Z_COEFF_INTERP_BSPLINE 1 -#elif Z_DRIFT_SHIFT >= 5 +#if Z_DRIFT_SHIFT >= 7 +#define Z_COEFF_INTERP_BSPLINE_3 1 +#elif Z_DRIFT_SHIFT == 6 +#define Z_COEFF_INTERP_BSPLINE_5 1 +#elif Z_DRIFT_SHIFT == 5 #define Z_COEFF_INTERP_OPT32X 1 #elif Z_DRIFT_SHIFT == 4 #define Z_COEFF_INTERP_OPT16X 1 @@ -804,7 +909,14 @@ #else #error "Z_DRIFT_SHIFT screwed!" #endif +#elif defined(Z_COEFF_INTERP_BSPLINE) && !(defined(Z_COEFF_INTERP_BSPLINE_3) || \ + defined(Z_COEFF_INTERP_BSPLINE_5)) +#if Z_DRIFT_SHIFT >= 7 +#define Z_COEFF_INTERP_BSPLINE_3 1 +#else +#define Z_COEFF_INTERP_BSPLINE_5 1 #endif +#endif /* * In classic polyphase mode, the actual coefficients for each phases need to @@ -850,13 +962,14 @@ /* 4-point, 3rd-order Hermite */ zh0 = z_coeff[0]; zh1 = z_coeff[1] - z_coeff[-1]; - zh2 = (z_coeff[-1] << 1) - (z_coeff[0] * 5) + (z_coeff[1] << 2) - - z_coeff[2]; - zh3 = z_coeff[2] - z_coeff[-1] + ((z_coeff[0] - z_coeff[1]) * 3); + zh2 = ((int64_t)z_coeff[1] << 2) - ((int64_t)z_coeff[0] * 5) + + (z_coeff[-1] << 1) - z_coeff[2]; + zh3 = ((int64_t)(z_coeff[0] - z_coeff[1]) * 3) + z_coeff[2] - + z_coeff[-1]; coeff = Z_RSHIFT((Z_RSHIFT((Z_RSHIFT((int64_t)zh3 * z, Z_SHIFT) + zh2) * z, Z_SHIFT) + zh1) * z, Z_SHIFT + 1) + zh0; -#elif defined(Z_COEFF_INTERP_BSPLINE) +#elif defined(Z_COEFF_INTERP_BSPLINE_3) int32_t zb0, zb1, zb2, zb3; /* 4-point, 3rd-order B-Spline */ @@ -864,11 +977,38 @@ z_coeff[-1] + z_coeff[1]), 30); zb1 = z_coeff[1] - z_coeff[-1]; zb2 = z_coeff[-1] + z_coeff[1] - (z_coeff[0] << 1); - zb3 = Z_RSHIFT(0x15555555LL * (((z_coeff[0] - z_coeff[1]) * 3) + - z_coeff[2] - z_coeff[-1]), 30); + zb3 = Z_RSHIFT(0x15555555LL * + (((int64_t)(z_coeff[0] - z_coeff[1]) * 3) + z_coeff[2] - + z_coeff[-1]), 30); - coeff = (Z_RSHIFT((Z_RSHIFT((Z_RSHIFT((int64_t)zb3 * z, Z_SHIFT) + - zb2) * z, Z_SHIFT) + zb1) * z, Z_SHIFT) + zb0 + 1) >> 1; + coeff = Z_RSHIFT(Z_RSHIFT((Z_RSHIFT((Z_RSHIFT( + (int64_t)zb3 * z, Z_SHIFT) + zb2) * z, Z_SHIFT) + + zb1) * z, Z_SHIFT) + zb0, 1); +#elif defined(Z_COEFF_INTERP_BSPLINE_5) + int32_t zb0, zb1, zb2, zb3, zb4, zb5; + + /* 6-point, 5th-order B-Spline */ + zb0 = Z_RSHIFT((0x01111111LL * (z_coeff[-2] + z_coeff[2])) + + (0x1bbbbbbcLL * (z_coeff[-1] + z_coeff[1])) + + (0x46666666LL * z_coeff[0]), 30); + zb1 = Z_RSHIFT((0x05555555LL * (z_coeff[2] - z_coeff[-2])) + + (0x35555555LL * (z_coeff[1] - z_coeff[-1])), 30); + zb2 = Z_RSHIFT((0x0aaaaaabLL * (z_coeff[-2] + z_coeff[2])) + + (0x15555555LL * (z_coeff[-1] + z_coeff[1])) - + (0x40000000LL * z_coeff[0]), 30); + zb3 = Z_RSHIFT((0x0aaaaaabLL * (z_coeff[2] - z_coeff[-2])) - + (0x15555555LL * (z_coeff[1] - z_coeff[-1])), 30); + zb4 = Z_RSHIFT((0x05555555LL * (z_coeff[-2] + z_coeff[2])) - + (0x15555555LL * (z_coeff[-1] + z_coeff[1])) + + (0x20000000LL * z_coeff[0]), 30); + zb5 = Z_RSHIFT((0x01111111LL * (z_coeff[3] - z_coeff[-2])) + + (0x05555555LL * (z_coeff[-1] - z_coeff[2])) + + (0x0aaaaaabLL * (z_coeff[1] - z_coeff[0])), 30); + + coeff = Z_RSHIFT(Z_RSHIFT((Z_RSHIFT((Z_RSHIFT((Z_RSHIFT((Z_RSHIFT( + (int64_t)zb5 * z, Z_SHIFT) + zb4) * z, Z_SHIFT) + + zb3) * z, Z_SHIFT) + zb2) * z, Z_SHIFT) + zb1) * z, Z_SHIFT) + + zb0, 1); #elif defined(Z_COEFF_INTERP_OPT32X) int32_t zoz, zoe1, zoe2, zoe3, zoo1, zoo2, zoo3; int32_t zoc0, zoc1, zoc2, zoc3, zoc4, zoc5; @@ -882,23 +1022,23 @@ zoo2 = z_coeff[2] - z_coeff[-1]; zoo3 = z_coeff[3] - z_coeff[-2]; - zoc0 = Z_RSHIFT((0x1ac2260dLL * zoe1) + (0x0526cdcaLL * zoe2) + - (0x00170c29LL * zoe3), 30); - zoc1 = Z_RSHIFT((0x14f8a49aLL * zoo1) + (0x0d6d1109LL * zoo2) + - (0x008cd4dcLL * zoo3), 30); - zoc2 = Z_RSHIFT((-0x0d3e94a4LL * zoe1) + (0x0bddded4LL * zoe2) + - (0x0160b5d0LL * zoe3), 30); - zoc3 = Z_RSHIFT((-0x0de10cc4LL * zoo1) + (0x019b2a7dLL * zoo2) + - (0x01cfe914LL * zoo3), 30); - zoc4 = Z_RSHIFT((0x02aa12d7LL * zoe1) + (-0x03ff1bb3LL * zoe2) + - (0x015508ddLL * zoe3), 30); - zoc5 = Z_RSHIFT((0x051d29e5LL * zoo1) + (-0x028e7647LL * zoo2) + - (0x0082d81aLL * zoo3), 30); + zoc0 = Z_RSHIFT((0x36a357d2LL * zoe1) + (0x0943c9cfLL * zoe2) + + (0x0018de5fLL * zoe3), 30); + zoc1 = Z_RSHIFT((0x2ddd5aecLL * zoo1) + (0x1a2d984bLL * zoo2) + + (0x00b85f3eLL * zoo3), 30); + zoc2 = Z_RSHIFT((-0x1bc6f4ecLL * zoe1) + (0x19aa6f62LL * zoe2) + + (0x021c858aLL * zoe3), 30); + zoc3 = Z_RSHIFT((-0x2024ef40LL * zoo1) + (0x0567cd19LL * zoo2) + + (0x032f8198LL * zoo3), 30); + zoc4 = Z_RSHIFT((0x05556cd2LL * zoe1) + (-0x0800233eLL * zoe2) + + (0x02aab66bLL * zoe3), 30); + zoc5 = Z_RSHIFT((0x0ab00fedLL * zoo1) + (-0x05580913LL * zoo2) + + (0x01119bdcLL * zoo3), 30); - coeff = Z_RSHIFT((Z_RSHIFT((Z_RSHIFT((Z_RSHIFT((Z_RSHIFT( + coeff = Z_RSHIFT(Z_RSHIFT((Z_RSHIFT((Z_RSHIFT((Z_RSHIFT((Z_RSHIFT( (int64_t)zoc5 * zoz, Z_SHIFT) + zoc4) * zoz, Z_SHIFT) + zoc3) * zoz, Z_SHIFT) + - zoc2) * zoz, Z_SHIFT) + zoc1) * zoz, Z_SHIFT) + zoc0; + zoc2) * zoz, Z_SHIFT) + zoc1) * zoz, Z_SHIFT) + zoc0, 1); #elif defined(Z_COEFF_INTERP_OPT16X) int32_t zoz, zoe1, zoe2, zoe3, zoo1, zoo2, zoo3; int32_t zoc0, zoc1, zoc2, zoc3, zoc4, zoc5; @@ -912,23 +1052,23 @@ zoo2 = z_coeff[2] - z_coeff[-1]; zoo3 = z_coeff[3] - z_coeff[-2]; - zoc0 = Z_RSHIFT((0x1ac2260dLL * zoe1) + (0x0526cdcaLL * zoe2) + - (0x00170c29LL * zoe3), 30); - zoc1 = Z_RSHIFT((0x14f8a49aLL * zoo1) + (0x0d6d1109LL * zoo2) + - (0x008cd4dcLL * zoo3), 30); - zoc2 = Z_RSHIFT((-0x0d3e94a4LL * zoe1) + (0x0bddded4LL * zoe2) + - (0x0160b5d0LL * zoe3), 30); - zoc3 = Z_RSHIFT((-0x0de10cc4LL * zoo1) + (0x019b2a7dLL * zoo2) + - (0x01cfe914LL * zoo3), 30); - zoc4 = Z_RSHIFT((0x02aa12d7LL * zoe1) + (-0x03ff1bb3LL * zoe2) + - (0x015508ddLL * zoe3), 30); - zoc5 = Z_RSHIFT((0x051d29e5LL * zoo1) + (-0x028e7647LL * zoo2) + - (0x0082d81aLL * zoo3), 30); + zoc0 = Z_RSHIFT((0x35844c1aLL * zoe1) + (0x0a4d9b93LL * zoe2) + + (0x002e1852LL * zoe3), 30); + zoc1 = Z_RSHIFT((0x29f14933LL * zoo1) + (0x1ada2213LL * zoo2) + + (0x0119a9b7LL * zoo3), 30); + zoc2 = Z_RSHIFT((-0x1a7d2947LL * zoe1) + (0x17bbbda7LL * zoe2) + + (0x02c16ba0LL * zoe3), 30); + zoc3 = Z_RSHIFT((-0x1bc21989LL * zoo1) + (0x033654faLL * zoo2) + + (0x039fd228LL * zoo3), 30); + zoc4 = Z_RSHIFT((0x055425aeLL * zoe1) + (-0x07fe3767LL * zoe2) + + (0x02aa11b9LL * zoe3), 30); + zoc5 = Z_RSHIFT((0x0a3a53caLL * zoo1) + (-0x051cec8eLL * zoo2) + + (0x0105b035LL * zoo3), 30); - coeff = Z_RSHIFT((Z_RSHIFT((Z_RSHIFT((Z_RSHIFT((Z_RSHIFT( + coeff = Z_RSHIFT(Z_RSHIFT((Z_RSHIFT((Z_RSHIFT((Z_RSHIFT((Z_RSHIFT( (int64_t)zoc5 * zoz, Z_SHIFT) + zoc4) * zoz, Z_SHIFT) + zoc3) * zoz, Z_SHIFT) + - zoc2) * zoz, Z_SHIFT) + zoc1) * zoz, Z_SHIFT) + zoc0; + zoc2) * zoz, Z_SHIFT) + zoc1) * zoz, Z_SHIFT) + zoc0, 1); #elif defined(Z_COEFF_INTERP_OPT8X) int32_t zoz, zoe1, zoe2, zoe3, zoo1, zoo2, zoo3; int32_t zoc0, zoc1, zoc2, zoc3, zoc4, zoc5; @@ -942,23 +1082,23 @@ zoo2 = z_coeff[2] - z_coeff[-1]; zoo3 = z_coeff[3] - z_coeff[-2]; - zoc0 = Z_RSHIFT((0x1aa9b47dLL * zoe1) + (0x053d9944LL * zoe2) + - (0x0018b23fLL * zoe3), 30); - zoc1 = Z_RSHIFT((0x14a104d1LL * zoo1) + (0x0d7d2504LL * zoo2) + - (0x0094b599LL * zoo3), 30); - zoc2 = Z_RSHIFT((-0x0d22530bLL * zoe1) + (0x0bb37a2cLL * zoe2) + - (0x016ed8e0LL * zoe3), 30); - zoc3 = Z_RSHIFT((-0x0d744b1cLL * zoo1) + (0x01649591LL * zoo2) + - (0x01dae93aLL * zoo3), 30); - zoc4 = Z_RSHIFT((0x02a7ee1bLL * zoe1) + (-0x03fbdb24LL * zoe2) + - (0x0153ed07LL * zoe3), 30); - zoc5 = Z_RSHIFT((0x04cf9b6cLL * zoo1) + (-0x0266b378LL * zoo2) + - (0x007a7c26LL * zoo3), 30); + zoc0 = Z_RSHIFT((0x355368f9LL * zoe1) + (0x0a7b3288LL * zoe2) + + (0x0031647fLL * zoe3), 30); + zoc1 = Z_RSHIFT((0x294209a1LL * zoo1) + (0x1afa4a08LL * zoo2) + + (0x01296b33LL * zoo3), 30); + zoc2 = Z_RSHIFT((-0x1a44a615LL * zoe1) + (0x1766f457LL * zoe2) + + (0x02ddb1bfLL * zoe3), 30); + zoc3 = Z_RSHIFT((-0x1ae89637LL * zoo1) + (0x02c92b21LL * zoo2) + + (0x03b5d273LL * zoo3), 30); + zoc4 = Z_RSHIFT((0x054fdc36LL * zoe1) + (-0x07f7b647LL * zoe2) + + (0x02a7da0eLL * zoe3), 30); + zoc5 = Z_RSHIFT((0x099f36d8LL * zoo1) + (-0x04cd66efLL * zoo2) + + (0x00f4f84dLL * zoo3), 30); - coeff = Z_RSHIFT((Z_RSHIFT((Z_RSHIFT((Z_RSHIFT((Z_RSHIFT( + coeff = Z_RSHIFT(Z_RSHIFT((Z_RSHIFT((Z_RSHIFT((Z_RSHIFT((Z_RSHIFT( (int64_t)zoc5 * zoz, Z_SHIFT) + zoc4) * zoz, Z_SHIFT) + zoc3) * zoz, Z_SHIFT) + - zoc2) * zoz, Z_SHIFT) + zoc1) * zoz, Z_SHIFT) + zoc0; + zoc2) * zoz, Z_SHIFT) + zoc1) * zoz, Z_SHIFT) + zoc0, 1); #elif defined(Z_COEFF_INTERP_OPT4X) int32_t zoz, zoe1, zoe2, zoe3, zoo1, zoo2, zoo3; int32_t zoc0, zoc1, zoc2, zoc3, zoc4, zoc5; @@ -972,23 +1112,23 @@ zoo2 = z_coeff[2] - z_coeff[-1]; zoo3 = z_coeff[3] - z_coeff[-2]; - zoc0 = Z_RSHIFT((0x1a8eda43LL * zoe1) + (0x0556ee38LL * zoe2) + - (0x001a3784LL * zoe3), 30); - zoc1 = Z_RSHIFT((0x143d863eLL * zoo1) + (0x0d910e36LL * zoo2) + - (0x009ca889LL * zoo3), 30); - zoc2 = Z_RSHIFT((-0x0d026821LL * zoe1) + (0x0b837773LL * zoe2) + - (0x017ef0c6LL * zoe3), 30); - zoc3 = Z_RSHIFT((-0x0cef1502LL * zoo1) + (0x01207a8eLL * zoo2) + - (0x01e936dbLL * zoo3), 30); - zoc4 = Z_RSHIFT((0x029fe643LL * zoe1) + (-0x03ef3fc8LL * zoe2) + - (0x014f5923LL * zoe3), 30); - zoc5 = Z_RSHIFT((0x043a9d08LL * zoo1) + (-0x02154febLL * zoo2) + - (0x00670dbdLL * zoo3), 30); + zoc0 = Z_RSHIFT((0x351db485LL * zoe1) + (0x0aaddc70LL * zoe2) + + (0x00346f09LL * zoe3), 30); + zoc1 = Z_RSHIFT((0x287b0c7bLL * zoo1) + (0x1b221c6cLL * zoo2) + + (0x01395113LL * zoo3), 30); + zoc2 = Z_RSHIFT((-0x1a04d042LL * zoe1) + (0x1706eee6LL * zoe2) + + (0x02fde18bLL * zoe3), 30); + zoc3 = Z_RSHIFT((-0x19de2a03LL * zoo1) + (0x0240f51cLL * zoo2) + + (0x03d26db6LL * zoo3), 30); + zoc4 = Z_RSHIFT((0x053fcc86LL * zoe1) + (-0x07de7f90LL * zoe2) + + (0x029eb247LL * zoe3), 30); + zoc5 = Z_RSHIFT((0x08753a11LL * zoo1) + (-0x042a9fd6LL * zoo2) + + (0x00ce1b7aLL * zoo3), 30); - coeff = Z_RSHIFT((Z_RSHIFT((Z_RSHIFT((Z_RSHIFT((Z_RSHIFT( + coeff = Z_RSHIFT(Z_RSHIFT((Z_RSHIFT((Z_RSHIFT((Z_RSHIFT((Z_RSHIFT( (int64_t)zoc5 * zoz, Z_SHIFT) + zoc4) * zoz, Z_SHIFT) + zoc3) * zoz, Z_SHIFT) + - zoc2) * zoz, Z_SHIFT) + zoc1) * zoz, Z_SHIFT) + zoc0; + zoc2) * zoz, Z_SHIFT) + zoc1) * zoz, Z_SHIFT) + zoc0, 1); #elif defined(Z_COEFF_INTERP_OPT2X) int32_t zoz, zoe1, zoe2, zoe3, zoo1, zoo2, zoo3; int32_t zoc0, zoc1, zoc2, zoc3, zoc4, zoc5; @@ -1002,23 +1142,23 @@ zoo2 = z_coeff[2] - z_coeff[-1]; zoo3 = z_coeff[3] - z_coeff[-2]; - zoc0 = Z_RSHIFT((0x19edb6fdLL * zoe1) + (0x05ebd062LL * zoe2) + - (0x00267881LL * zoe3), 30); - zoc1 = Z_RSHIFT((0x1223af76LL * zoo1) + (0x0de3dd6bLL * zoo2) + - (0x00d683cdLL * zoo3), 30); - zoc2 = Z_RSHIFT((-0x0c3ee068LL * zoe1) + (0x0a5c3769LL * zoe2) + - (0x01e2aceaLL * zoe3), 30); - zoc3 = Z_RSHIFT((-0x0a8ab614LL * zoo1) + (-0x0019522eLL * zoo2) + - (0x022cefc7LL * zoo3), 30); - zoc4 = Z_RSHIFT((0x0276187dLL * zoe1) + (-0x03a801e8LL * zoe2) + - (0x0131d935LL * zoe3), 30); - zoc5 = Z_RSHIFT((0x02c373f5LL * zoo1) + (-0x01275f83LL * zoo2) + - (0x0018ee79LL * zoo3), 30); + zoc0 = Z_RSHIFT((0x33db6dfbLL * zoe1) + (0x0bd7a0c5LL * zoe2) + + (0x004cf101LL * zoe3), 30); + zoc1 = Z_RSHIFT((0x24475eecLL * zoo1) + (0x1bc7bad5LL * zoo2) + + (0x01ad079bLL * zoo3), 30); + zoc2 = Z_RSHIFT((-0x187dc0d1LL * zoe1) + (0x14b86ed1LL * zoe2) + + (0x03c559d4LL * zoe3), 30); + zoc3 = Z_RSHIFT((-0x15156c27LL * zoo1) + (-0x0032a45cLL * zoo2) + + (0x0459df8eLL * zoo3), 30); + zoc4 = Z_RSHIFT((0x04ec30fbLL * zoe1) + (-0x075003d1LL * zoe2) + + (0x0263b26bLL * zoe3), 30); + zoc5 = Z_RSHIFT((0x0586e7eaLL * zoo1) + (-0x024ebf05LL * zoo2) + + (0x0031dcf2LL * zoo3), 30); - coeff = Z_RSHIFT((Z_RSHIFT((Z_RSHIFT((Z_RSHIFT((Z_RSHIFT( + coeff = Z_RSHIFT(Z_RSHIFT((Z_RSHIFT((Z_RSHIFT((Z_RSHIFT((Z_RSHIFT( (int64_t)zoc5 * zoz, Z_SHIFT) + zoc4) * zoz, Z_SHIFT) + zoc3) * zoz, Z_SHIFT) + - zoc2) * zoz, Z_SHIFT) + zoc1) * zoz, Z_SHIFT) + zoc0; + zoc2) * zoz, Z_SHIFT) + zoc1) * zoz, Z_SHIFT) + zoc0, 1); #else #error "Interpolation type screwed!" #endif @@ -1032,7 +1172,7 @@ static int z_resampler_build_polyphase(struct z_info *info) { - int32_t alpha, c, i, z, idx; + int32_t *z_coeff, *z_pcoeff, alpha, i, z; /* Let this be here first. */ if (info->z_pcoeff != NULL) { @@ -1061,24 +1201,23 @@ for (alpha = 0; alpha < info->z_gy; alpha++) { z = alpha * info->z_dx; - c = 0; + z_coeff = info->z_coeff; + z_pcoeff = info->z_pcoeff + (alpha * info->z_size * 2) + + info->z_size; for (i = info->z_size; i != 0; i--) { - c += z >> Z_SHIFT; + z_coeff += z >> Z_SHIFT; z &= Z_MASK; - idx = (alpha * info->z_size * 2) + - (info->z_size * 2) - i; - info->z_pcoeff[idx] = - z_coeff_interpolate(z, info->z_coeff + c); + *z_pcoeff++ = z_coeff_interpolate(z, z_coeff); z += info->z_dy; } z = info->z_dy - (alpha * info->z_dx); - c = 0; + z_coeff = info->z_coeff; + z_pcoeff = info->z_pcoeff + (alpha * info->z_size * 2) + + info->z_size - 1; for (i = info->z_size; i != 0; i--) { - c += z >> Z_SHIFT; + z_coeff += z >> Z_SHIFT; z &= Z_MASK; - idx = (alpha * info->z_size * 2) + i - 1; - info->z_pcoeff[idx] = - z_coeff_interpolate(z, info->z_coeff + c); + *z_pcoeff-- = z_coeff_interpolate(z, z_coeff); z += info->z_dy; } } @@ -1097,7 +1236,7 @@ struct z_info *info; int64_t gy2gx_max, gx2gy_max; uint32_t format; - int32_t align, i, z_scale; + int32_t align, bufsz, i, startdrift, z_scale; int adaptive; info = f->data; @@ -1129,7 +1268,7 @@ * we're pretty much in business. Scaling is not needed for * upsampling, so we just slap Z_ONE there. */ - if (info->z_gx > info->z_gy) + if (Z_SRC_DOWN(info)) { /* * If the downsampling ratio is beyond sanity, * enable semi-adaptive mode. Although handling @@ -1137,12 +1276,12 @@ * conversion is just pointless, unworthy, * nonsensical noises, etc. */ - if ((info->z_gx / info->z_gy) > Z_SINC_DOWNMAX) + if (Z_FACTOR_DOWN(info) > Z_SINC_DOWNMAX) z_scale = Z_ONE / Z_SINC_DOWNMAX; else z_scale = ((uint64_t)info->z_gy << Z_SHIFT) / info->z_gx; - else + } else z_scale = Z_ONE; /* @@ -1234,13 +1373,14 @@ if (info->z_coeff == NULL || info->z_dcoeff == NULL) return (EINVAL); - } else if (Z_IS_LINEAR(info)) { + } else if (Z_IS_LINEAR(info) && !Z_IS_LINEAR_ZOH(info)) { /* * Don't put much effort if we're doing linear interpolation. * Just center the interpolation distance within Z_LINEAR_ONE, * and be happy about it. */ - info->z_dx = Z_LINEAR_FULL_ONE / info->z_gy; + info->z_dx = Z_LINEAR_ONE / info->z_gy; + info->z_size = 2; } /* @@ -1255,6 +1395,10 @@ if (Z_IS_SINC(info) && adaptive == 0 && z_resampler_build_polyphase(info) == 0) ridx = Z_RESAMPLER_SINC_POLYPHASE; + else if (Z_IS_SINC(info) && feeder_rate_polyphase_max < 0) + ridx = Z_RESAMPLER_SINC_FAST; + else if (Z_IS_LINEAR_ZOH(info)) + ridx = Z_RESAMPLER_ZOH; else ridx = Z_RESAMPLER_IDX(info); info->z_resample = z_resampler_tab[i].resampler[ridx]; @@ -1306,14 +1450,45 @@ info->z_maxfeed = gy2gx_max * align; + startdrift = z_start_drift(info); #ifdef Z_USE_ALPHADRIFT - info->z_startdrift = z_gy2gx(info, 1); - info->z_alphadrift = z_drift(info, info->z_startdrift, 1); + info->z_startdrift = startdrift; + info->z_alphadrift = z_drift(info, startdrift, 1); #endif - i = z_gy2gx(info, 1); - info->z_full = z_roundpow2((info->z_size << 1) + i); +#ifdef Z_STRESS_TEST + info->z_full = z_history(info); +#else + /* + * Extreme downsampling does not deserve buffering optimization + * since startdrift might become too large. + */ + if (Z_FACTOR_DOWN(info) > Z_DOWNMAX) + info->z_full = 0; + else { + /* + * First, optimize delay buffer size by allocating enough + * samples so that at least it can accomodate multiple + * passes of resampling routine in a single feed. + */ + info->z_full = z_roundpow2(z_history(info) + startdrift); + /* Test against multi-pass without ^2 rounding. */ + bufsz = z_history(info) + startdrift; + if ((bufsz * align) > (info->z_full * align)) + info->z_full = bufsz; + } + + /* Test against single-pass with ^2 rounding. */ + bufsz = z_roundpow2(z_history(info)); + if ((bufsz * align) > (info->z_full * align)) + info->z_full = bufsz; + + /* Test against single-pass without ^2 rounding */ + bufsz = z_history(info); + if ((bufsz * align) > (info->z_full * align)) + info->z_full = bufsz; + /* * Too big to be true, and overflowing left and right like mad .. */ @@ -1330,36 +1505,33 @@ * buffer shifting in main conversion/feeder loop. */ while (info->z_full < Z_RESERVOIR_MAX && - (info->z_full - (info->z_size << 1)) < Z_RESERVOIR) + (info->z_full - z_history(info)) < Z_RESERVOIR) info->z_full <<= 1; +#endif /* Initialize buffer position. */ - info->z_mask = info->z_full - 1; - info->z_start = z_prev(info, info->z_size << 1, 1); - info->z_pos = z_next(info, info->z_start, 1); + info->z_pos = z_history(info) - 1; + info->z_start = info->z_pos - startdrift; /* * Allocate or reuse delay line buffer, whichever makes sense. */ - i = info->z_full * align; - if (i < 1) - return (E2BIG); + bufsz = info->z_full * align; - if (info->z_delay == NULL || info->z_alloc < i || - i <= (info->z_alloc >> 1)) { + if (info->z_delay == NULL || info->z_alloc < bufsz || + bufsz <= (info->z_alloc >> 1)) { if (info->z_delay != NULL) free(info->z_delay, M_DEVBUF); - info->z_delay = malloc(i, M_DEVBUF, M_NOWAIT | M_ZERO); + info->z_delay = malloc(bufsz, M_DEVBUF, M_NOWAIT | M_ZERO); if (info->z_delay == NULL) return (ENOMEM); - info->z_alloc = i; + info->z_alloc = bufsz; } /* * Zero out head of buffer to avoid pops and clicks. */ - memset(info->z_delay, sndbuf_zerodata(f->desc->out), - info->z_pos * align); + z_zero(info->z_delay, format, info->z_pos * info->channels); #ifdef Z_DIAGNOSTIC /* @@ -1397,11 +1569,10 @@ "", info->z_alloc >> 30); fprintf(stderr, "\t%12s %10d (min output samples)\n", "", - (int32_t)z_gx2gy(info, info->z_full - (info->z_size << 1))); + (int32_t)z_gx2gy(info, info->z_full - z_history(info))); fprintf(stderr, "\t%12s %10d (min allocated output samples)\n", "", - (int32_t)z_gx2gy(info, (info->z_alloc / align) - - (info->z_size << 1))); + (int32_t)z_gx2gy(info, (info->z_alloc / align) - z_history(info))); fprintf(stderr, "\t%12s = %10d\n", "z_gy2gx()", (int32_t)z_gy2gx(info, 1)); fprintf(stderr, "\t%12s = %10d -> z_gy2gx() -> %d\n", @@ -1414,6 +1585,10 @@ dumpz(full); dumpz(start); dumpz(pos); +#ifdef Z_USE_ALPHADRIFT + dumpz(alphadrift); + dumpz(startdrift); +#endif dumpz(scale); fprintf(stderr, "\t%12s %10f\n", "", (double)info->z_scale / Z_ONE); @@ -1568,13 +1743,34 @@ return (0); } +/* + * The math, though pretty much elementary, looks scary enough. But just + * how accurate is this entire conversion and buffering routine? + * + * 1) It is accurate to the point that you don't need more than the total + * number of history samples that need to be kept, which means at least: + * + * sinc = total number of taps (z_size * 2, including 1 current sample) + * linear = current and previous sample (1 + 1 = 2) + * zoh = current sample (1) + * + * However, small buffer means that a lot of buffer shifting need to be + * done and will effect the entire conversion performance. It is also the + * best way to stress things out. + * + * 2) For zero-order-hold (ZOH), symmetric conversion of up and down is + * lossless. Up followed by down symmetrically, not the other way round. + * Regardless of whatever ratios involved. Lossless. No kidding. + * + * ...and thus, it is the very definition of accurate. + */ static uint32_t z_resampler_feed_internal(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, uint32_t count, void *source) { struct z_info *info; int32_t alphadrift, startdrift, reqout, ocount, reqin, align; - int32_t fetch, fetched, start, cp; + int32_t fetch, fetched; uint8_t *dst; info = f->data; @@ -1601,7 +1797,7 @@ startdrift = info->z_startdrift; alphadrift = info->z_alphadrift; #else - startdrift = _Z_GY2GX(info, 0, 1); + startdrift = z_start_drift(info); alphadrift = z_drift(info, startdrift, 1); #endif @@ -1611,22 +1807,88 @@ if (reqin != 0) { fetch = z_min(z_free(info), reqin); if (fetch == 0) { +#define z_future_startdrift() (((info->z_alpha + alphadrift) < info->z_gy) ? \ + startdrift : (startdrift - 1)) +#define z_future_start() (info->z_start + z_future_startdrift()) +#define z_future_begin() (z_future_start() - z_history(info) + 1) /* - * No more free spaces, so wind enough + * No more free spaces, so wind required * samples back to the head of delay line - * in byte domain. + * in byte domain. The winding process is + * done in a such way that the future begin + * offset will fall exactly at index 0 of + * delay/history buffer. + * + * zfb = future z_start begin offset + * (constant = 0) + * zfs = future z_start + * zfp = future z_pos + * zfsd = future startdrift + * zh = z_history + * f = current fetched buffer (constant) + * zs = current z_start + * + * zfb = 0 + * zfs - zh + 1 = 0 + * zfs = zh - 1 + * zs + zfsd = zh - 1 + * zs = zh - zfsd - 1 + * zfp - f - 1 = zh - zfsd - 1 + * zfp = zh - zfsd - 1 + f + 1 + * zfp = zh - zfsd + f */ + + /* Get the amount of fetched samples. */ fetched = z_fetched(info); - start = z_prev(info, info->z_start, - (info->z_size << 1) - 1); - cp = (info->z_size << 1) + fetched; - z_copy(info->z_delay + (start * align), - info->z_delay, cp * align); - info->z_start = - z_prev(info, info->z_size << 1, 1); - info->z_pos = - z_next(info, info->z_start, fetched + 1); - fetch = z_min(z_free(info), reqin); + + /* Calculate future z_pos. */ + info->z_pos = z_history(info) - + z_future_startdrift() + fetched; + + /* + * z_pos <= 0 : The current fetched + * samples will fall far + * behind the delay buffer. + * Dispose it entirely. + * Set z_pos to 0. + * + * z_pos < z_full : Early part of fetched + * samples will fall behind + * the delay buffer. Move + * remaining to the head. + * + * z_pos == z_full : Do nothing. The entire + * fetched samples might be + * reused. + * + * z_pos > z_full : Mathematically impossible. + * + * It is obvious that z_start might become + * negative at certain point, but the drift + * process will reposition it within z_full + * boundary just before the resampling routine + * begin. + */ + if (info->z_pos != info->z_full) { +#if defined(Z_DIAGNOSTIC) || defined(Z_STRESS_TEST) + /* Mathematically impossible. */ + if (info->z_pos > info->z_full) + fprintf(stderr, "OVERFLOW: " + "z_pos=%d >= z_full\n", + info->z_pos, info->z_full); +#endif + if (info->z_pos > 0) + z_copy(info->z_delay + + ((info->z_full - + info->z_pos) * align), + info->z_delay, + info->z_pos * align); + else + info->z_pos = 0; + info->z_start = info->z_pos - + fetched - 1; + fetch = z_min(z_free(info), reqin); + } #ifdef Z_DIAGNOSTIC if (1) { static uint32_t kk = 0; @@ -1634,8 +1896,9 @@ "Buffer Move: " "start=%d fetched=%d cp=%d " "cycle=%u [%u]\r", - start, fetched, cp, info->z_cycle, - ++kk); + info->z_full - info->z_pos, + fetched, info->z_pos, + info->z_cycle, ++kk); } info->z_cycle = 0; #endif @@ -1645,6 +1908,20 @@ * Fetch in byte domain and jump back * to sample domain. */ +#if defined(Z_DIAGNOSTIC) || defined(Z_STRESS_TEST) + /* Mathematically impossible. */ + if (fetch < 0) + fprintf(stderr, "NEGATIVE FETCH: %d\n", + fetch); + if (info->z_pos >= info->z_full) + fprintf(stderr, "OVERFLOW: " + "z_pos=%d >= z_full=%d\n", + info->z_pos, info->z_full); + if ((info->z_full - info->z_pos) < fetch) + fprintf(stderr, "IMPOSSIBLE FETCH: " + "fetch=%d, z_pos=%d, z_full=%d\n", + fetch, info->z_pos, info->z_full); +#endif fetched = SND_FXDIV(z_feed(f->source, c, info->z_delay + (info->z_pos * align), fetch * align, source), align); @@ -1662,6 +1939,9 @@ reqout = z_min(z_gx2gy(info, z_fetched(info)), ocount); if (reqout != 0) { +#ifdef Z_DIAGNOSTIC + info->z_cycle += reqout; +#endif ocount -= reqout; /* @@ -1673,27 +1953,33 @@ * due to integer division in z_gy2gx(). Nevertheless, * both should give the same exact accurate drifting * results, so the later is favourable. + * + * startdrift = z_gy2gx(info, 1); + * alphadrift = z_drift(info, startdrift, 1); + * info->z_start += startdrift; + * info->z_alpha += alphadrift; */ do { - info->z_resample(info, dst); -#if 0 - startdrift = z_gy2gx(info, 1); - alphadrift = z_drift(info, startdrift, 1); + info->z_alpha += alphadrift; info->z_start += startdrift; - info->z_alpha += alphadrift; -#else - info->z_alpha += alphadrift; - if (info->z_alpha < info->z_gy) - info->z_start += startdrift; - else { - info->z_start += startdrift - 1; + if (info->z_alpha >= info->z_gy) { info->z_alpha -= info->z_gy; + info->z_start -= 1; } +#if defined(Z_DIAGNOSTIC) || defined(Z_STRESS_TEST) + /* Mathematically impossible. */ + if (info->z_start >= info->z_full) + fprintf(stderr, "OVERFLOW: " + "z_start=%d >= z_full=%d\n", + info->z_start, info->z_full); + if ((info->z_start - z_history(info) + 1) < 0) + fprintf(stderr, "UNDERFLOW: " + "z_start_begin=%d\n", + info->z_start - + z_history(info) + 1); #endif + info->z_resample(info, dst); dst += align; -#ifdef Z_DIAGNOSTIC - info->z_cycle++; -#endif } while (--reqout != 0); } } while (reqin != 0 && ocount != 0); --- sys/dev/sound/pcm/pcm.h.orig (revision 196041) +++ sys/dev/sound/pcm/pcm.h (working copy) @@ -167,14 +167,14 @@ typedef uint64_t uintpcm64_t; b8[0] = (val >> 24) ^ 0x80; \ } while (0) -#define _PCM_READ_S16_NE(b8) _PCM_READ_S16_LE(b8) -#define _PCM_READ_U16_NE(b8) _PCM_READ_U16_LE(b8) -#define _PCM_READ_S32_NE(b8) _PCM_READ_S32_LE(b8) -#define _PCM_READ_U32_NE(b8) _PCM_READ_U32_LE(b8) -#define _PCM_WRITE_S16_NE(b6) _PCM_WRITE_S16_LE(b8) -#define _PCM_WRITE_U16_NE(b6) _PCM_WRITE_U16_LE(b8) -#define _PCM_WRITE_S32_NE(b6) _PCM_WRITE_S32_LE(b8) -#define _PCM_WRITE_U32_NE(b6) _PCM_WRITE_U32_LE(b8) +#define _PCM_READ_S16_NE(b8) _PCM_READ_S16_LE(b8) +#define _PCM_READ_U16_NE(b8) _PCM_READ_U16_LE(b8) +#define _PCM_READ_S32_NE(b8) _PCM_READ_S32_LE(b8) +#define _PCM_READ_U32_NE(b8) _PCM_READ_U32_LE(b8) +#define _PCM_WRITE_S16_NE(b8, val) _PCM_WRITE_S16_LE(b8, val) +#define _PCM_WRITE_U16_NE(b8, val) _PCM_WRITE_U16_LE(b8, val) +#define _PCM_WRITE_S32_NE(b8, val) _PCM_WRITE_S32_LE(b8, val) +#define _PCM_WRITE_U32_NE(b8, val) _PCM_WRITE_U32_LE(b8, val) #else /* !LITTLE_ENDIAN */ #define _PCM_READ_S16_LE(b8) \ INTPCM_T((b8)[0] | (((int8_t)((b8)[1])) << 8)) @@ -236,14 +236,14 @@ typedef uint64_t uintpcm64_t; *((uint32_t *)(b8)) = (val) ^ 0x80000000; \ } while (0) -#define _PCM_READ_S16_NE(b8) _PCM_READ_S16_BE(b8) -#define _PCM_READ_U16_NE(b8) _PCM_READ_U16_BE(b8) -#define _PCM_READ_S32_NE(b8) _PCM_READ_S32_BE(b8) -#define _PCM_READ_U32_NE(b8) _PCM_READ_U32_BE(b8) -#define _PCM_WRITE_S16_NE(b6) _PCM_WRITE_S16_BE(b8) -#define _PCM_WRITE_U16_NE(b6) _PCM_WRITE_U16_BE(b8) -#define _PCM_WRITE_S32_NE(b6) _PCM_WRITE_S32_BE(b8) -#define _PCM_WRITE_U32_NE(b6) _PCM_WRITE_U32_BE(b8) +#define _PCM_READ_S16_NE(b8) _PCM_READ_S16_BE(b8) +#define _PCM_READ_U16_NE(b8) _PCM_READ_U16_BE(b8) +#define _PCM_READ_S32_NE(b8) _PCM_READ_S32_BE(b8) +#define _PCM_READ_U32_NE(b8) _PCM_READ_U32_BE(b8) +#define _PCM_WRITE_S16_NE(b8, val) _PCM_WRITE_S16_BE(b8, val) +#define _PCM_WRITE_U16_NE(b8, val) _PCM_WRITE_U16_BE(b8, val) +#define _PCM_WRITE_S32_NE(b8, val) _PCM_WRITE_S32_BE(b8, val) +#define _PCM_WRITE_U32_NE(b8, val) _PCM_WRITE_U32_BE(b8, val) #endif /* LITTLE_ENDIAN */ #define _PCM_READ_S24_LE(b8) \ @@ -289,15 +289,15 @@ typedef uint64_t uintpcm64_t; } while (0) #if BYTE_ORDER == LITTLE_ENDIAN -#define _PCM_READ_S24_NE(b8) _PCM_READ_S24_LE(b8) -#define _PCM_READ_U24_NE(b8) _PCM_READ_U24_LE(b8) -#define _PCM_WRITE_S24_NE(b6) _PCM_WRITE_S24_LE(b8) -#define _PCM_WRITE_U24_NE(b6) _PCM_WRITE_U24_LE(b8) +#define _PCM_READ_S24_NE(b8) _PCM_READ_S24_LE(b8) +#define _PCM_READ_U24_NE(b8) _PCM_READ_U24_LE(b8) +#define _PCM_WRITE_S24_NE(b8, val) _PCM_WRITE_S24_LE(b8, val) +#define _PCM_WRITE_U24_NE(b8, val) _PCM_WRITE_U24_LE(b8, val) #else /* !LITTLE_ENDIAN */ -#define _PCM_READ_S24_NE(b8) _PCM_READ_S24_BE(b8) -#define _PCM_READ_U24_NE(b8) _PCM_READ_U24_BE(b8) -#define _PCM_WRITE_S24_NE(b6) _PCM_WRITE_S24_BE(b8) -#define _PCM_WRITE_U24_NE(b6) _PCM_WRITE_U24_BE(b8) +#define _PCM_READ_S24_NE(b8) _PCM_READ_S24_BE(b8) +#define _PCM_READ_U24_NE(b8) _PCM_READ_U24_BE(b8) +#define _PCM_WRITE_S24_NE(b8, val) _PCM_WRITE_S24_BE(b8, val) +#define _PCM_WRITE_U24_NE(b8, val) _PCM_WRITE_U24_BE(b8, val) #endif /* LITTLE_ENDIAN */ /* * 8bit sample is pretty much useless since it doesn't provide @@ -339,8 +339,8 @@ typedef uint64_t uintpcm64_t; #define PCM_READ_S16_NE(b8) _PCM_READ_S16_NE(b8) #define PCM_READ_U16_NE(b8) _PCM_READ_U16_NE(b8) -#define PCM_WRITE_S16_NE(b8) _PCM_WRITE_S16_NE(b8) -#define PCM_WRITE_U16_NE(b8) _PCM_WRITE_U16_NE(b8) +#define PCM_WRITE_S16_NE(b8, val) _PCM_WRITE_S16_NE(b8, val) +#define PCM_WRITE_U16_NE(b8, val) _PCM_WRITE_U16_NE(b8, val) /* 24bit */ #define PCM_READ_S24_LE(b8) _PCM_READ_S24_LE(b8) @@ -355,8 +355,8 @@ typedef uint64_t uintpcm64_t; #define PCM_READ_S24_NE(b8) _PCM_READ_S24_NE(b8) #define PCM_READ_U24_NE(b8) _PCM_READ_U24_NE(b8) -#define PCM_WRITE_S24_NE(b8) _PCM_WRITE_S24_NE(b8) -#define PCM_WRITE_U24_NE(b8) _PCM_WRITE_U24_NE(b8) +#define PCM_WRITE_S24_NE(b8, val) _PCM_WRITE_S24_NE(b8, val) +#define PCM_WRITE_U24_NE(b8, val) _PCM_WRITE_U24_NE(b8, val) /* 32bit */ #ifdef SND_PCM_64 @@ -372,8 +372,8 @@ typedef uint64_t uintpcm64_t; #define PCM_READ_S32_NE(b8) _PCM_READ_S32_NE(b8) #define PCM_READ_U32_NE(b8) _PCM_READ_U32_NE(b8) -#define PCM_WRITE_S32_NE(b8) _PCM_WRITE_S32_NE(b8) -#define PCM_WRITE_U32_NE(b8) _PCM_WRITE_U32_NE(b8) +#define PCM_WRITE_S32_NE(b8, val) _PCM_WRITE_S32_NE(b8, val) +#define PCM_WRITE_U32_NE(b8, val) _PCM_WRITE_U32_NE(b8, val) #else /* !SND_PCM_64 */ /* * 24bit integer ?!? This is quite unfortunate, eh? Get the fact straight: --- sys/dev/sound/null.c.orig 1970-01-01 07:30:00.000000000 +0730 +++ sys/dev/sound/null.c 2009-09-23 03:38:06.000000000 +0800 @@ -0,0 +1,620 @@ +/*- + * Copyright (c) 2007-2009 Ariff Abdullah + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_KERNEL_OPTION_HEADERS +#include "opt_snd.h" +#endif + +#include +#include +#include "mixer_if.h" + +SND_DECLARE_FILE("$FreeBSD$"); + +#define SNDNULL_DESC "NULL Audio" + +#define SNDNULL_RATE_MIN 8000 +#define SNDNULL_RATE_MAX 192000 + +#define SNDNULL_RATE_DEFAULT 48000 +#define SNDNULL_FMT_DEFAULT SND_FORMAT(AFMT_S16_LE, 2, 0) +#define SNDNULL_FMTSTR_DEFAULT "s16le:2.0" + +#define SNDNULL_NPCHAN 1 +#define SNDNULL_NRCHAN 1 +#define SNDNULL_MAXCHAN (SNDNULL_NPCHAN + SNDNULL_NRCHAN) + +#define SNDNULL_BUFSZ_MIN 4096 +#define SNDNULL_BUFSZ_MAX 65536 +#define SNDNULL_BUFSZ_DEFAULT 4096 + +#define SNDNULL_BLKCNT_MIN 2 +#define SNDNULL_BLKCNT_MAX 512 +#define SNDNULL_BLKCNT_DEFAULT SNDNULL_BLKCNT_MIN + +#define SNDNULL_LOCK(sc) snd_mtxlock((sc)->lock) +#define SNDNULL_UNLOCK(sc) snd_mtxunlock((sc)->lock) + +struct sndnull_info; + +struct sndnull_chinfo { + struct snd_dbuf *buffer; + struct pcm_channel *channel; + struct pcmchan_caps *caps; + struct sndnull_info *parent; + uint32_t ptr, intrcnt; + int dir, active; +}; + +struct sndnull_info { + device_t dev; + struct sndnull_chinfo ch[SNDNULL_MAXCHAN]; + struct pcmchan_caps caps; + uint32_t bufsz; + uint32_t blkcnt; + uint32_t fmtlist[2]; + struct mtx *lock; + uint8_t *ringbuffer; + int chnum; + + struct callout poll_timer; + int poll_ticks, polling; +}; + +static void * +sndnull_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, + struct pcm_channel *c, int dir) +{ + struct sndnull_info *sc = devinfo; + struct sndnull_chinfo *ch; + + SNDNULL_LOCK(sc); + + ch = &sc->ch[sc->chnum++]; + ch->buffer = b; + ch->parent = sc; + ch->channel = c; + ch->dir = dir; + ch->caps = &sc->caps; + + SNDNULL_UNLOCK(sc); + + if (sndbuf_setup(ch->buffer, sc->ringbuffer, sc->bufsz) == -1) + return (NULL); + + return (ch); +} + +static int +sndnull_chan_setformat(kobj_t obj, void *data, uint32_t format) +{ + struct sndnull_chinfo *ch = data; + + if (ch->caps->fmtlist[0] != format) + return (EINVAL); + + return (0); +} + +static uint32_t +sndnull_chan_setspeed(kobj_t obj, void *data, uint32_t spd) +{ + struct sndnull_chinfo *ch = data; + + if (spd < ch->caps->minspeed) + spd = ch->caps->minspeed; + if (spd > ch->caps->maxspeed) + spd = ch->caps->maxspeed; + + return (spd); +} + +static int +sndnull_chan_setfragments(kobj_t obj, void *data, uint32_t blksz, + uint32_t blkcnt) +{ + struct sndnull_chinfo *ch = data; + struct sndnull_info *sc = ch->parent; + + blkcnt = sc->blkcnt; + blksz = sndbuf_getmaxsize(ch->buffer) / blkcnt; + blksz -= blksz % sndbuf_getalign(ch->buffer); + + if ((sndbuf_getblksz(ch->buffer) != blksz || + sndbuf_getblkcnt(ch->buffer) != blkcnt) && + sndbuf_resize(ch->buffer, blkcnt, blksz) != 0) + device_printf(sc->dev, "%s: failed blksz=%u blkcnt=%u\n", + __func__, blksz, blkcnt); + + return (0); +} + +static uint32_t +sndnull_chan_setblocksize(kobj_t obj, void *data, uint32_t blksz) +{ + struct sndnull_chinfo *ch = data; + struct sndnull_info *sc = ch->parent; + + sndnull_chan_setfragments(obj, data, blksz, sc->blkcnt); + + return (sndbuf_getblksz(ch->buffer)); +} + +#define SNDNULL_CHAN_ACTIVE(ch) ((ch)->active != 0) + +static __inline int +sndnull_anychan_active(struct sndnull_info *sc) +{ + int i; + + for (i = 0; i < sc->chnum; i++) { + if (SNDNULL_CHAN_ACTIVE(&sc->ch[i])) + return (1); + } + + return (0); +} + +static void +sndnull_poll_callback(void *arg) +{ + struct sndnull_info *sc = arg; + struct sndnull_chinfo *ch; + int i; + + if (sc == NULL) + return; + + SNDNULL_LOCK(sc); + + if (!sndnull_anychan_active(sc)) { + SNDNULL_UNLOCK(sc); + return; + } + + for (i = 0; i < sc->chnum; i++) { + ch = &sc->ch[i]; + if (SNDNULL_CHAN_ACTIVE(ch)) { + ch->ptr += sndbuf_getblksz(ch->buffer); + ch->ptr %= sndbuf_getsize(ch->buffer); + ch->intrcnt += 1; + SNDNULL_UNLOCK(sc); + chn_intr(ch->channel); + SNDNULL_LOCK(sc); + } + } + + callout_reset(&sc->poll_timer, sc->poll_ticks, + sndnull_poll_callback, sc); + + SNDNULL_UNLOCK(sc); +} + +static int +sndnull_chan_trigger(kobj_t obj, void *data, int go) +{ + struct sndnull_chinfo *ch = data; + struct sndnull_info *sc = ch->parent; + int pollticks; + + if (!PCMTRIG_COMMON(go)) + return (0); + + SNDNULL_LOCK(sc); + + switch (go) { + case PCMTRIG_START: + if (!sndnull_anychan_active(sc)) { + pollticks = ((uint64_t)hz * + sndbuf_getblksz(ch->buffer)) / + ((uint64_t)sndbuf_getalign(ch->buffer) * + sndbuf_getspd(ch->buffer)); + if (pollticks < 1) + pollticks = 1; + sc->poll_ticks = pollticks; + callout_reset(&sc->poll_timer, 1, + sndnull_poll_callback, sc); + if (bootverbose) + device_printf(sc->dev, + "PCMTRIG_START: pollticks=%d\n", + pollticks); + } + if (ch->dir == PCMDIR_REC) + memset(sc->ringbuffer, sndbuf_zerodata( + sndbuf_getfmt(ch->buffer)), + sndbuf_getmaxsize(ch->buffer)); + ch->ptr = 0; + ch->intrcnt = 0; + ch->active = 1; + break; + case PCMTRIG_STOP: + case PCMTRIG_ABORT: + ch->active = 0; + if (!sndnull_anychan_active(sc)) + callout_stop(&sc->poll_timer); + if (ch->dir == PCMDIR_PLAY) + memset(sc->ringbuffer, sndbuf_zerodata( + sndbuf_getfmt(ch->buffer)), + sndbuf_getmaxsize(ch->buffer)); + break; + default: + break; + } + + SNDNULL_UNLOCK(sc); + + return (0); +} + +static uint32_t +sndnull_chan_getptr(kobj_t obj, void *data) +{ + struct sndnull_chinfo *ch = data; + struct sndnull_info *sc = ch->parent; + uint32_t ptr; + + SNDNULL_LOCK(sc); + ptr = (SNDNULL_CHAN_ACTIVE(ch)) ? ch->ptr : 0; + SNDNULL_UNLOCK(sc); + + return (ptr); +} + +static struct pcmchan_caps * +sndnull_chan_getcaps(kobj_t obj, void *data) +{ + + return (((struct sndnull_chinfo *)data)->caps); +} + +static kobj_method_t sndnull_chan_methods[] = { + KOBJMETHOD(channel_init, sndnull_chan_init), + KOBJMETHOD(channel_setformat, sndnull_chan_setformat), + KOBJMETHOD(channel_setspeed, sndnull_chan_setspeed), + KOBJMETHOD(channel_setblocksize, sndnull_chan_setblocksize), + KOBJMETHOD(channel_setfragments, sndnull_chan_setfragments), + KOBJMETHOD(channel_trigger, sndnull_chan_trigger), + KOBJMETHOD(channel_getptr, sndnull_chan_getptr), + KOBJMETHOD(channel_getcaps, sndnull_chan_getcaps), + KOBJMETHOD_END +}; +CHANNEL_DECLARE(sndnull_chan); + +static const struct { + int ctl; + int rec; +} sndnull_mixer_ctls[SOUND_MIXER_NRDEVICES] = { + [SOUND_MIXER_VOLUME] = { 1, 0 }, + [SOUND_MIXER_BASS] = { 1, 0 }, + [SOUND_MIXER_TREBLE] = { 1, 0 }, + [SOUND_MIXER_SYNTH] = { 1, 1 }, + [SOUND_MIXER_PCM] = { 1, 1 }, + [SOUND_MIXER_SPEAKER] = { 1, 0 }, + [SOUND_MIXER_LINE] = { 1, 1 }, + [SOUND_MIXER_MIC] = { 1, 1 }, + [SOUND_MIXER_CD] = { 1, 1 }, + [SOUND_MIXER_IMIX] = { 1, 1 }, + [SOUND_MIXER_RECLEV] = { 1, 0 }, +}; + +static int +sndnull_mixer_init(struct snd_mixer *m) +{ + uint32_t mask, recmask; + int i; + + mask = 0; + recmask = 0; + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { + if (sndnull_mixer_ctls[i].ctl != 0) + mask |= 1 << i; + if (sndnull_mixer_ctls[i].rec != 0) + recmask |= 1 << i; + } + + mix_setdevs(m, mask); + mix_setrecdevs(m, recmask); + + return (0); +} + +static int +sndnull_mixer_set(struct snd_mixer *m, unsigned dev, unsigned left, + unsigned right) +{ + + if (!(dev < SOUND_MIXER_NRDEVICES && sndnull_mixer_ctls[dev].ctl != 0)) + return (-1); + + return (left | (right << 8)); +} + +static uint32_t +sndnull_mixer_setrecsrc(struct snd_mixer *m, uint32_t src) +{ + uint32_t recsrc; + int i; + + recsrc = src; + + if (recsrc & SOUND_MASK_IMIX) + recsrc &= SOUND_MASK_IMIX; + else { + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { + if (sndnull_mixer_ctls[i].rec == 0) + recsrc &= ~(1 << i); + } + } + + return (recsrc); +} + +static kobj_method_t sndnull_mixer_methods[] = { + KOBJMETHOD(mixer_init, sndnull_mixer_init), + KOBJMETHOD(mixer_set, sndnull_mixer_set), + KOBJMETHOD(mixer_setrecsrc, sndnull_mixer_setrecsrc), + KOBJMETHOD_END +}; +MIXER_DECLARE(sndnull_mixer); + +static int +sysctl_sndnull_rate(SYSCTL_HANDLER_ARGS) +{ + struct sndnull_info *sc; + device_t dev; + int err, val; + + dev = oidp->oid_arg1; + + sc = pcm_getdevinfo(dev); + if (sc == NULL) + return (EINVAL); + + SNDNULL_LOCK(sc); + val = sc->caps.maxspeed; + SNDNULL_UNLOCK(sc); + + err = sysctl_handle_int(oidp, &val, 0, req); + + if (err != 0 || req->newptr == NULL) + return (err); + + if (val < SNDNULL_RATE_MIN) + val = SNDNULL_RATE_MIN; + if (val > SNDNULL_RATE_MAX) + val = SNDNULL_RATE_MAX; + + SNDNULL_LOCK(sc); + if (sndnull_anychan_active(sc)) + err = EBUSY; + else { + sc->caps.minspeed = (uint32_t)val; + sc->caps.maxspeed = sc->caps.minspeed; + } + SNDNULL_UNLOCK(sc); + + return (err); +} + +static int +sysctl_sndnull_format(SYSCTL_HANDLER_ARGS) +{ + struct sndnull_info *sc; + device_t dev; + int err; + char fmtstr[AFMTSTR_LEN]; + uint32_t fmt; + + dev = oidp->oid_arg1; + + sc = pcm_getdevinfo(dev); + if (sc == NULL) + return (EINVAL); + + SNDNULL_LOCK(sc); + fmt = sc->fmtlist[0]; + if (snd_afmt2str(fmt, fmtstr, sizeof(fmtstr)) != fmt) + strlcpy(fmtstr, SNDNULL_FMTSTR_DEFAULT, sizeof(fmtstr)); + SNDNULL_UNLOCK(sc); + + err = sysctl_handle_string(oidp, fmtstr, sizeof(fmtstr), req); + + if (err != 0 || req->newptr == NULL) + return (err); + + fmt = snd_str2afmt(fmtstr); + if (fmt == 0) + return (EINVAL); + + SNDNULL_LOCK(sc); + if (fmt != sc->fmtlist[0]) { + if (sndnull_anychan_active(sc)) + err = EBUSY; + else + sc->fmtlist[0] = fmt; + } + SNDNULL_UNLOCK(sc); + + return (err); +} + +static device_t sndnull_dev = NULL; + +static void +sndnull_dev_identify(driver_t *driver, device_t parent) +{ + + if (sndnull_dev == NULL) + sndnull_dev = BUS_ADD_CHILD(parent, 0, "pcm", -1); +} + +static int +sndnull_dev_probe(device_t dev) +{ + + if (dev != NULL && dev == sndnull_dev) { + device_set_desc(dev, SNDNULL_DESC); + return (BUS_PROBE_DEFAULT); + } + + return (ENXIO); +} + +static int +sndnull_dev_attach(device_t dev) +{ + struct sndnull_info *sc; + char status[SND_STATUSLEN]; + int i; + + sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); + + sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_null softc"); + sc->dev = dev; + + callout_init(&sc->poll_timer, CALLOUT_MPSAFE); + sc->poll_ticks = 1; + + sc->caps.minspeed = SNDNULL_RATE_DEFAULT; + sc->caps.maxspeed = SNDNULL_RATE_DEFAULT; + sc->fmtlist[0] = SNDNULL_FMT_DEFAULT; + sc->fmtlist[1] = 0; + sc->caps.fmtlist = sc->fmtlist; + + sc->bufsz = pcm_getbuffersize(dev, SNDNULL_BUFSZ_MIN, + SNDNULL_BUFSZ_DEFAULT, SNDNULL_BUFSZ_MAX); + sc->blkcnt = SNDNULL_BLKCNT_DEFAULT; + + sc->ringbuffer = malloc(sc->bufsz, M_DEVBUF, M_WAITOK | M_ZERO); + + if (mixer_init(dev, &sndnull_mixer_class, sc) != 0) + device_printf(dev, "mixer_init() failed\n"); + + if (pcm_register(dev, sc, SNDNULL_NPCHAN, SNDNULL_NRCHAN)) + return (ENXIO); + + for (i = 0; i < SNDNULL_NPCHAN; i++) + pcm_addchan(dev, PCMDIR_PLAY, &sndnull_chan_class, sc); + for (i = 0; i < SNDNULL_NRCHAN; i++) + pcm_addchan(dev, PCMDIR_REC, &sndnull_chan_class, sc); + + snprintf(status, SND_STATUSLEN, "at %s %s", + device_get_nameunit(device_get_parent(dev)), + PCM_KLDSTRING(snd_null)); + + pcm_setflags(dev, pcm_getflags(dev) | SD_F_MPSAFE); + pcm_setstatus(dev, status); + + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, + "rate", CTLTYPE_INT | CTLFLAG_RW, dev, sizeof(dev), + sysctl_sndnull_rate, "I", "runtime rate"); + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, + "format", CTLTYPE_STRING | CTLFLAG_RW, dev, sizeof(dev), + sysctl_sndnull_format, "A", "runtime format"); + + return (0); +} + +static void +sndnull_release_resources(struct sndnull_info *sc) +{ + + if (sc == NULL) + return; + if (sc->chnum != 0) { + SNDNULL_LOCK(sc); + callout_stop(&sc->poll_timer); + SNDNULL_UNLOCK(sc); + callout_drain(&sc->poll_timer); + } + if (sc->ringbuffer != NULL) { + free(sc->ringbuffer, M_DEVBUF); + sc->ringbuffer = NULL; + } + if (sc->lock != NULL) { + snd_mtxfree(sc->lock); + sc->lock = NULL; + } + free(sc, M_DEVBUF); +} + +static int +sndnull_dev_detach(device_t dev) +{ + struct sndnull_info *sc; + int err; + + sc = pcm_getdevinfo(dev); + if (sc != NULL) { + err = pcm_unregister(dev); + if (err != 0) + return (err); + sndnull_release_resources(sc); + } + + return (0); +} + +static device_method_t sndnull_methods[] = { + DEVMETHOD(device_identify, sndnull_dev_identify), + DEVMETHOD(device_probe, sndnull_dev_probe), + DEVMETHOD(device_attach, sndnull_dev_attach), + DEVMETHOD(device_detach, sndnull_dev_detach), + { 0, 0 } +}; + +static driver_t sndnull_driver = { + "pcm", + sndnull_methods, + PCM_SOFTC_SIZE, +}; + +static int +sndnull_modevent(module_t mod, int type, void *data) +{ + + switch (type) { + case MOD_UNLOAD: + if (sndnull_dev != NULL) + device_delete_child(device_get_parent(sndnull_dev), + sndnull_dev); + sndnull_dev = NULL; + case MOD_LOAD: + return (0); + break; + default: + break; + } + + return (ENOTSUP); +} + +DRIVER_MODULE(snd_null, nexus, sndnull_driver, pcm_devclass, sndnull_modevent, + 0); +MODULE_DEPEND(snd_null, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); +MODULE_VERSION(snd_null, 1); --- sys/dev/sound/usb/uaudio.c.orig 2009-06-08 07:45:46.000000000 +0800 +++ sys/dev/sound/usb/uaudio.c 2009-06-08 08:57:15.000000000 +0800 @@ -264,6 +264,7 @@ uint8_t sc_pcm_registered:1; uint8_t sc_mixer_init:1; uint8_t sc_uq_audio_swap_lr:1; + uint8_t sc_uq_audio_softpcm:1; uint8_t sc_uq_au_inp_async:1; uint8_t sc_uq_au_no_xu:1; uint8_t sc_uq_bad_adc:1; @@ -593,6 +594,9 @@ if (usb_test_quirk(uaa, UQ_AUDIO_SWAP_LR)) sc->sc_uq_audio_swap_lr = 1; + if (usb_test_quirk(uaa, UQ_AUDIO_SOFTPCM)) + sc->sc_uq_audio_softpcm = 1; + if (usb_test_quirk(uaa, UQ_AU_INP_ASYNC)) sc->sc_uq_au_inp_async = 1; @@ -1956,6 +1960,9 @@ case VOLUME_CONTROL: mix.type = MIX_SIGNED_16; + if (mixernumber == SOUND_MIXER_PCM && + sc->sc_uq_audio_softpcm) + mixernumber = SOUND_MIXER_OGAIN; mix.ctl = mixernumber; break; --- sys/modules/sound/driver/Makefile.orig 2009-01-26 02:20:15.000000000 +0800 +++ sys/modules/sound/driver/Makefile 2009-06-08 08:57:15.000000000 +0800 @@ -6,7 +6,7 @@ SUBDIR+= via82c686 vibes driver uaudio .if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64" -SUBDIR+= cmi mss +SUBDIR+= cmi mss null .endif .if ${MACHINE_CPUARCH} == "sparc64" --- sys/modules/sound/driver/null/Makefile.orig 1970-01-01 07:30:00.000000000 +0730 +++ sys/modules/sound/driver/null/Makefile 2009-06-08 08:57:15.000000000 +0800 @@ -0,0 +1,9 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../../dev/sound + +KMOD= snd_null +SRCS= device_if.h bus_if.h +SRCS+= null.c + +.include --- sys/kern/kern_conf.c.orig 2007-11-01 21:10:02.000000000 +0800 +++ sys/kern/kern_conf.c 2007-11-01 21:10:27.000000000 +0800 @@ -1144,7 +1144,7 @@ u *= 10; u += name[i++] - '0'; } - if (u > 0xffffff) + if (u > CLONE_UNITMASK) return (0); *unit = u; if (namep) --- usr.sbin/powerd/powerd.c.orig 2007-11-01 21:12:16.000000000 +0800 +++ usr.sbin/powerd/powerd.c 2007-11-01 21:25:40.000000000 +0800 @@ -57,6 +57,12 @@ #define DEFAULT_ACTIVE_PERCENT 75 #define DEFAULT_IDLE_PERCENT 50 #define DEFAULT_POLL_INTERVAL 250 /* Poll interval in milliseconds */ +#define DEFAULT_TZ_SUSPEND 10 /* TZ suspend in seconds */ + +#define TZ_ZEROC 2732 +#define TZ_MAXC 12732 +#define TZ_KELVTOC(x) (((x) - TZ_ZEROC) / 10), abs(((x) - TZ_ZEROC) % 10) +#define TZ_CTOKELV(x) ((int)((x) * 10 + TZ_ZEROC)) typedef enum { MODE_MIN, @@ -89,6 +95,8 @@ static int set_freq(int freq); static void acline_init(void); static void acline_read(void); +static void tz_init(void); +static int tz_read(void); static int devd_init(void); static void devd_close(void); static void handle_sigs(int sig); @@ -101,6 +109,9 @@ static int levels_mib[4]; static int acline_mib[4]; static size_t acline_mib_len; +static int tz_psv_mib[5]; +static int tz_cur_mib[5]; +static u_int tz_namelen; /* Configuration */ static int cpu_running_mark; @@ -109,6 +120,7 @@ static int vflag; static volatile sig_atomic_t exit_requested; +static int tz_psv; static power_src_t acline_status; static enum { ac_none, @@ -407,6 +419,69 @@ } static void +tz_init(void) +{ + size_t len; + + if (tz_psv == 0) { + len = 5; + if (sysctlnametomib("hw.acpi.thermal.tz0._PSV", tz_psv_mib, + &len)) { + tz_psv = -1; + return; + } + + len = 0; + if (sysctl(tz_psv_mib, 5, NULL, &len, NULL, 0) || + len != sizeof(tz_psv)) { + tz_psv = -1; + return; + } + + if (sysctl(tz_psv_mib, 5, &tz_psv, &len, NULL, 0)) { + tz_psv = -1; + return; + } + } + + len = 5; + if (sysctlnametomib("hw.acpi.thermal.tz0.temperature", + tz_cur_mib, &len)) { + len = 4; + if (sysctlnametomib("dev.cpu.0.temperature", + tz_cur_mib, &len)) { + tz_psv = -1; + return; + } + } + + tz_namelen = len; + len = 0; + + if (sysctl(tz_cur_mib, tz_namelen, NULL, &len, NULL, 0) || + len != sizeof(int)) { + tz_psv = -1; + return; + } +} + +static int +tz_read(void) +{ + int tz_cur; + size_t len; + + if (tz_psv == -1) + return (-1); + + len = sizeof(tz_cur); + if (sysctl(tz_cur_mib, tz_namelen, &tz_cur, &len, NULL, 0)) + return (-1); + + return (tz_cur); +} + +static void parse_mode(char *arg, int *mode, int ch) { @@ -434,7 +509,7 @@ { fprintf(stderr, -"usage: powerd [-v] [-a mode] [-b mode] [-i %%] [-m freq] [-M freq] [-n mode] [-p ival] [-r %%] [-P pidfile]\n"); +"usage: powerd [-v] [-a mode] [-b mode] [-i %%] [-m freq] [-M freq] [-n mode] [-p ival] [-r %%] [-P pidfile] [-z C] [-Z sec]\n"); exit(1); } @@ -449,6 +524,7 @@ int freq, curfreq, initfreq, *freqs, i, j, *mwatts, numfreqs, load; int minfreq = -1, maxfreq = -1; int ch, mode, mode_ac, mode_battery, mode_none, idle, to; + int curtz, curtzsuspend, tz_suspend; uint64_t mjoules_used; size_t len; @@ -460,12 +536,16 @@ poll_ival = DEFAULT_POLL_INTERVAL; mjoules_used = 0; vflag = 0; + tz_psv = -1; + curtz = -1; + tz_suspend = DEFAULT_TZ_SUSPEND * 1000000; + curtzsuspend = 0; /* User must be root to control frequencies. */ if (geteuid() != 0) errx(1, "must be root to run"); - while ((ch = getopt(argc, argv, "a:b:i:m:M:n:p:P:r:v")) != -1) + while ((ch = getopt(argc, argv, "a:b:i:m:M:n:p:P:r:vz:Z:")) != -1) switch (ch) { case 'a': parse_mode(optarg, &mode_ac, ch); @@ -518,9 +598,27 @@ usage(); } break; + case 't': + tz_psv = 0; + break; case 'v': vflag = 1; break; + case 'z': + tz_psv = TZ_CTOKELV(strtod(optarg, NULL)); + if (tz_psv < TZ_ZEROC || tz_psv > TZ_MAXC) { + warnx("%s is out of temperature range", optarg); + usage(); + } + break; + case 'Z': + tz_suspend = atoi(optarg); + if (tz_suspend < 0 || tz_suspend > 1800) { + warnx("%s is out of tz suspend range", optarg); + usage(); + } + tz_suspend *= 1000000; + break; default: usage(); } @@ -541,6 +639,20 @@ if (sysctlnametomib("dev.cpu.0.freq_levels", levels_mib, &len)) err(1, "lookup freq_levels"); + /* Thermal Zone throttling */ + if (tz_psv != -1) { + tz_init(); + curtz = tz_read(); + } + if (curtz == -1) + tz_psv = -1; + if (vflag && tz_psv != -1 && curtz != -1) { + printf("tz throttling: %d.%dC (current: %d.%dC) " + "suspend: %d seconds\n", + TZ_KELVTOC(tz_psv), TZ_KELVTOC(curtz), + tz_suspend / 1000000); + } + /* Check if we can read the load and supported freqs. */ if (read_usage_times(NULL)) err(1, "read_usage_times"); @@ -685,6 +797,38 @@ (mwatts[i] * (poll_ival / 1000)) / 1000; } + if (tz_psv != -1 && (curtz = tz_read()) != -1 && + curtz > tz_psv) { + for (i = 0; i < numfreqs; i++) { + if (freqs[i] == curfreq) + break; + } + i++; + if (i < numfreqs) { + if (vflag) { + printf("tz %d.%dC > %d.%dC, " + "decreasing clock speed from " + "%d MHz to %d MHz\n", + TZ_KELVTOC(curtz), + TZ_KELVTOC(tz_psv), curfreq, + freqs[i]); + } + if (set_freq(freqs[i]) != 0) + warn("error setting CPU frequency %d", + freqs[i]); + } + curtzsuspend = tz_suspend; + continue; + } + + if (curtzsuspend > 0) { + if (vflag) + printf("tz suspend: %d seconds left\n", + curtzsuspend / 1000000); + curtzsuspend -= poll_ival; + continue; + } + /* Always switch to the lowest frequency in min mode. */ if (mode == MODE_MIN) { freq = freqs[numfreqs - 1]; --- sys/modules/ata/Makefile.orig 2007-11-01 21:28:21.000000000 +0800 +++ sys/modules/ata/Makefile 2007-11-01 21:28:33.000000000 +0800 @@ -8,6 +8,6 @@ SUBDIR += ataisa .endif SUBDIR += atapci -SUBDIR += atadisk atapicd atapifd atapist ataraid atapicam #atacam +SUBDIR += atadisk atapicd atapifd atapist ataraid atapicam #atacam .include --- usr.sbin/cdcontrol/cdcontrol.c.orig 2007-11-01 21:34:25.000000000 +0800 +++ usr.sbin/cdcontrol/cdcontrol.c 2007-11-01 21:35:37.000000000 +0800 @@ -86,6 +86,7 @@ #define STATUS_AUDIO 0x1 #define STATUS_MEDIA 0x2 #define STATUS_VOLUME 0x4 +#define SESSION_SECTORS (152 * 75) struct cmdtab { int command; @@ -1028,6 +1029,12 @@ e[1].addr.msf.frame); else next = ntohl(e[1].addr.lba); + if (e[1].track < 100) { + if (!(e->control & 4) && (e[1].control & 4)) + next -= SESSION_SECTORS; + else if ((e->control & 4) != (e[1].control & 4)) + next -= 150; + } len = next - block; /* Take into account a start offset time. */ lba2msf (len - 150, &m, &s, &f); --- sys/cam/scsi/scsi_da.c.orig 2007-11-01 21:37:14.000000000 +0800 +++ sys/cam/scsi/scsi_da.c 2007-11-01 21:38:18.000000000 +0800 @@ -147,6 +147,13 @@ /* SPI, FC devices */ { /* + * Apacer Audio Steno AV220 USB MP3 Player + */ + {T_DIRECT, SIP_MEDIA_REMOVABLE, "" , "MP3 Flash Drive 1.02", "*"}, + /*quirks*/ DA_Q_NO_SYNC_CACHE|DA_Q_NO_PREVENT + }, + { + /* * Fujitsu M2513A MO drives. * Tested devices: M2513A2 firmware versions 1200 & 1300. * (dip switch selects whether T_DIRECT or T_OPTICAL device) --- usr.sbin/acpi/acpiconf/acpiconf.c.orig 2007-11-02 20:42:12.000000000 +0800 +++ usr.sbin/acpi/acpiconf/acpiconf.c 2007-11-02 20:42:22.000000000 +0800 @@ -77,14 +77,13 @@ err(EX_IOERR, "ack sleep type failed"); } -/* should be a acpi define, but doesn't appear to be */ -#define UNKNOWN_CAP 0xffffffff -#define UNKNOWN_VOLTAGE 0xffffffff - static int acpi_battinfo(int num) { union acpi_battery_ioctl_arg battio; + struct acpi_battinfo battinfo; + struct acpi_bif bif; + struct acpi_bst bst; const char *pwr_units; int hours, min, amp; uint32_t volt; @@ -96,86 +95,118 @@ battio.unit = num; if (ioctl(acpifd, ACPIIO_BATT_GET_BIF, &battio) == -1) err(EX_IOERR, "get battery info (%d) failed", num); + bif = battio.bif; amp = battio.bif.units; pwr_units = amp ? "mA" : "mW"; - if (battio.bif.dcap == UNKNOWN_CAP) + if (bif.dcap == ACPI_BATT_UNKNOWN) printf("Design capacity:\tunknown\n"); else - printf("Design capacity:\t%d %sh\n", battio.bif.dcap, + printf("Design capacity:\t%d %sh\n", bif.dcap, pwr_units); - if (battio.bif.lfcap == UNKNOWN_CAP) + if (bif.lfcap == ACPI_BATT_UNKNOWN) printf("Last full capacity:\tunknown\n"); else - printf("Last full capacity:\t%d %sh\n", battio.bif.lfcap, + printf("Last full capacity:\t%d %sh\n", bif.lfcap, pwr_units); - printf("Technology:\t\t%s\n", battio.bif.btech == 0 ? + printf("Technology:\t\t%s\n", bif.btech == 0 ? "primary (non-rechargeable)" : "secondary (rechargeable)"); - if (battio.bif.dvol == UNKNOWN_CAP) + if (bif.dvol == ACPI_BATT_UNKNOWN) printf("Design voltage:\t\tunknown\n"); else - printf("Design voltage:\t\t%d mV\n", battio.bif.dvol); - printf("Capacity (warn):\t%d %sh\n", battio.bif.wcap, pwr_units); - printf("Capacity (low):\t\t%d %sh\n", battio.bif.lcap, pwr_units); - printf("Low/warn granularity:\t%d %sh\n", battio.bif.gra1, pwr_units); - printf("Warn/full granularity:\t%d %sh\n", battio.bif.gra2, pwr_units); - printf("Model number:\t\t%s\n", battio.bif.model); - printf("Serial number:\t\t%s\n", battio.bif.serial); - printf("Type:\t\t\t%s\n", battio.bif.type); - printf("OEM info:\t\t%s\n", battio.bif.oeminfo); + printf("Design voltage:\t\t%d mV\n", bif.dvol); + printf("Capacity (warn):\t%d %sh\n", bif.wcap, pwr_units); + printf("Capacity (low):\t\t%d %sh\n", bif.lcap, pwr_units); + printf("Low/warn granularity:\t%d %sh\n", bif.gra1, pwr_units); + printf("Warn/full granularity:\t%d %sh\n", bif.gra2, pwr_units); + printf("Model number:\t\t%s\n", bif.model); + printf("Serial number:\t\t%s\n", bif.serial); + printf("Type:\t\t\t%s\n", bif.type); + printf("OEM info:\t\t%s\n", bif.oeminfo); /* Fetch battery voltage information. */ - volt = UNKNOWN_VOLTAGE; + volt = ACPI_BATT_UNKNOWN; battio.unit = num; if (ioctl(acpifd, ACPIIO_BATT_GET_BST, &battio) == -1) err(EX_IOERR, "get battery status (%d) failed", num); + bst = battio.bst; if (battio.bst.state != ACPI_BATT_STAT_NOT_PRESENT) - volt = battio.bst.volt; + volt = bst.volt; /* Print current battery state information. */ battio.unit = num; if (ioctl(acpifd, ACPIIO_BATT_GET_BATTINFO, &battio) == -1) err(EX_IOERR, "get battery user info (%d) failed", num); - if (battio.battinfo.state != ACPI_BATT_STAT_NOT_PRESENT) { + battinfo = battio.battinfo; + if (battinfo.state != ACPI_BATT_STAT_NOT_PRESENT) { printf("State:\t\t\t"); - if (battio.battinfo.state == 0) + if (battinfo.state == 0) printf("high "); - if (battio.battinfo.state & ACPI_BATT_STAT_CRITICAL) + if (battinfo.state & ACPI_BATT_STAT_CRITICAL) printf("critical "); - if (battio.battinfo.state & ACPI_BATT_STAT_DISCHARG) + if (battinfo.state & ACPI_BATT_STAT_DISCHARG) printf("discharging "); - if (battio.battinfo.state & ACPI_BATT_STAT_CHARGING) + if (battinfo.state & ACPI_BATT_STAT_CHARGING) printf("charging "); printf("\n"); - if (battio.battinfo.cap == -1) + if (battinfo.cap == -1) printf("Remaining capacity:\tunknown\n"); else printf("Remaining capacity:\t%d%%\n", - battio.battinfo.cap); - if (battio.battinfo.min == -1) + battinfo.cap); + if (battinfo.min == -1) printf("Remaining time:\t\tunknown\n"); else { - hours = battio.battinfo.min / 60; - min = battio.battinfo.min % 60; + hours = battinfo.min / 60; + min = battinfo.min % 60; printf("Remaining time:\t\t%d:%02d\n", hours, min); } - if (battio.battinfo.rate == -1) + if (battinfo.rate == -1) printf("Present rate:\t\tunknown\n"); - else if (amp && volt != UNKNOWN_VOLTAGE) { + else if (amp && volt != ACPI_BATT_UNKNOWN) { printf("Present rate:\t\t%d mA (%d mW)\n", - battio.battinfo.rate, - battio.battinfo.rate * volt / 1000); + battinfo.rate, + battinfo.rate * volt / 1000); } else printf("Present rate:\t\t%d %s\n", - battio.battinfo.rate, pwr_units); + battinfo.rate, pwr_units); } else printf("State:\t\t\tnot present\n"); /* Print battery voltage information. */ - if (volt == UNKNOWN_VOLTAGE) - printf("Present voltage:\tunknown\n"); - else - printf("Present voltage:\t%d mV\n", volt); + bst = battio.bst; + if (bst.state != ACPI_BATT_STAT_NOT_PRESENT) { + if (battinfo.state == ACPI_BATT_STAT_NOT_PRESENT) { + printf("State:\t\t\t"); + if (bst.state == 0) + printf("high "); + if (bst.state & ACPI_BATT_STAT_CRITICAL) + printf("critical "); + if (bst.state & ACPI_BATT_STAT_DISCHARG) + printf("discharging "); + if (bst.state & ACPI_BATT_STAT_CHARGING) + printf("charging "); + printf("\n"); + if (bst.rate == ACPI_BATT_UNKNOWN) + printf("Present rate:\t\tunknown\n"); + else + printf("Present rate:\t\t%d %s\n", + bst.rate, pwr_units); + if (bst.cap == ACPI_BATT_UNKNOWN || + bif.lfcap == ACPI_BATT_UNKNOWN) + printf("Remaining capacity:\tunknown\n"); + else + printf("Remaining capacity:\t%d%%\n", + (100 * bst.cap) / bif.lfcap); + } + if (bst.volt == ACPI_BATT_UNKNOWN) + printf("Voltage:\t\t%d mV\n", bst.volt); + } + if (battinfo.state == ACPI_BATT_STAT_NOT_PRESENT && + bst.state == ACPI_BATT_STAT_NOT_PRESENT) + printf("State:\t\t\tnot present\n"); + + return (0); } @@ -190,7 +221,7 @@ main(int argc, char *argv[]) { char c, *prog; - int sleep_type; + int sleep_type, acline; prog = argv[0]; if (argc < 2) @@ -227,6 +258,18 @@ if (sleep_type != -1) acpi_sleep(sleep_type); + else { + if (ioctl(acpifd, ACPIIO_ACAD_GET_STATUS, &acline) == -1) + err(EX_IOERR, "get ac status failed"); + printf("AC line:\t\t"); + if (acline == 0) + printf("off-line"); + else if (acline == 1) + printf("on-line"); + else + printf("unknown"); + printf("\n"); + } close(acpifd); exit (0); --- sys/dev/usb/usbdevs.orig 2008-02-14 09:35:08.000000000 +0800 +++ sys/dev/usb/usbdevs 2008-02-14 09:37:26.000000000 +0800 @@ -634,6 +634,7 @@ vendor SOHOWARE 0x15e8 SOHOware vendor UMAX 0x1606 UMAX Data Systems vendor INSIDEOUT 0x1608 Inside Out Networks +vendor QUALCOMM3 0x1614 Qualcomm vendor AMOI 0x1614 Amoi Electronics vendor GOODWAY 0x1631 Good Way Technology vendor ENTREGA 0x1645 Entrega @@ -2660,7 +2661,9 @@ product QUALCOMM2 RWT_FCT 0x3100 RWT FCT-CDMA 2000 1xRTT modem product QUALCOMM2 CDMA_MSM 0x3196 CDMA Technologies MSM modem product QUALCOMM2 AC8700 0x6000 AC8700 +product QUALCOMM3 BLUE_CUBE 0x0800 Blue Cube HSDPA USB Modem product QUALCOMMINC CDMA_MSM 0x0001 CDMA Technologies MSM modem +product QUALCOMMINC CDMA_MSM2 0x0051 CDMA Technologies MSM modem product QUALCOMMINC E0002 0x0002 3G modem product QUALCOMMINC E0003 0x0003 3G modem product QUALCOMMINC E0004 0x0004 3G modem product QUALCOMMINC E0005 0x0005 3G modem --- sys/dev/usb/quirk/usb_quirk.h.orig 2009-02-24 02:31:00.000000000 +0800 +++ sys/dev/usb/quirk/usb_quirk.h 2009-04-11 14:57:20.000000000 +0800 @@ -39,6 +39,7 @@ /* Various quirks */ UQ_AUDIO_SWAP_LR, /* left and right sound channels are swapped */ + UQ_AUDIO_SOFTPCM, /* "pcm" mixer as "ogain", forcing softpcm */ UQ_AU_INP_ASYNC, /* input is async despite claim of adaptive */ UQ_AU_NO_FRAC, /* don't adjust for fractional samples */ UQ_AU_NO_XU, /* audio device has broken extension unit */ --- sys/dev/usb/quirk/usb_quirk.c.orig (revision 200399) +++ sys/dev/usb/quirk/usb_quirk.c (working copy) @@ -121,7 +121,7 @@ USB_QUIRK(METAGEEK, WISPY1B, 0x0000, 0xffff, UQ_KBD_IGNORE, UQ_HID_IGNORE), USB_QUIRK(METAGEEK, WISPY24X, 0x0000, 0xffff, UQ_KBD_IGNORE, UQ_HID_IGNORE), USB_QUIRK(METAGEEK2, WISPYDBX, 0x0000, 0xffff, UQ_KBD_IGNORE, UQ_HID_IGNORE), - USB_QUIRK(TENX, UAUDIO0, 0x0101, 0x0101, UQ_AUDIO_SWAP_LR), + USB_QUIRK(TENX, UAUDIO0, 0x0101, 0x0101, UQ_AUDIO_SWAP_LR, UQ_AUDIO_SOFTPCM), /* MS keyboards do weird things */ USB_QUIRK(MICROSOFT, WLINTELLIMOUSE, 0x0000, 0xffff, UQ_MS_LEADING_BYTE), /* umodem(4) device quirks */ @@ -465,6 +465,7 @@ [UQ_NONE] = "UQ_NONE", [UQ_MATCH_VENDOR_ONLY] = "UQ_MATCH_VENDOR_ONLY", [UQ_AUDIO_SWAP_LR] = "UQ_AUDIO_SWAP_LR", + [UQ_AUDIO_SOFTPCM] = "UQ_AUDIO_SOFTPCM", [UQ_AU_INP_ASYNC] = "UQ_AU_INP_ASYNC", [UQ_AU_NO_FRAC] = "UQ_AU_NO_FRAC", [UQ_AU_NO_XU] = "UQ_AU_NO_XU", --- sys/i386/conf/MIKI.orig 1970-01-01 07:30:00.000000000 +0730 +++ sys/i386/conf/MIKI 2009-08-15 12:09:03.000000000 +0800 @@ -0,0 +1,67 @@ +cpu I686_CPU +ident MIKI +options SCHED_ULE +options PREEMPTION +options INET +options INET6 +options SCTP +options FFS +options SOFTUPDATES +options UFS_ACL +options UFS_DIRHASH +options UFS_GJOURNAL +#options COMPAT_43TTY +options COMPAT_FREEBSD4 +options COMPAT_FREEBSD5 +options COMPAT_FREEBSD6 +options COMPAT_FREEBSD7 +options _KPOSIX_PRIORITY_SCHEDULING +options PRINTF_BUFR_SIZE=128 +options KBD_INSTALL_CDEV +options INCLUDE_CONFIG_FILE +options DEVICE_POLLING +options HZ=1000 +options SC_KERNEL_CONS_ATTR=(FG_WHITE|BG_BLACK) +options AUDIT +options MAC +options FLOWTABLE +options SMP +device apic +device pci +device ata +device atadisk +options ATA_STATIC_ID +device scbus +device da +device cd +device pass +device atkbdc +device atkbd +device psm +device kbdmux +device vga +device splash +device sc +device pmtimer +device uart +device ppc +device ppbus +device loop +device ether +device pty +device bpf +device carp + +options IEEE80211_AMPDU_AGE +options IEEE80211_SUPPORT_MESH +options IEEE80211_AMPDU_AGE +options AH_SUPPORT_AR5416 + +options SND_DEBUG +options SND_FEEDER_MULTIFORMAT +options SND_FEEDER_FULL_MULTIFORMAT +options SND_PCM_64 + +options IPSEC +device crypto +device enc --- sys/i386/conf/MIKI_ZFS.orig 1970-01-01 07:30:00.000000000 +0730 +++ sys/i386/conf/MIKI_ZFS 2009-07-20 22:20:24.000000000 +0800 @@ -0,0 +1,3 @@ +include MIKI +ident MIKI_ZFS +options KVA_PAGES=512 --- sys/i386/conf/MIKI_DEBUG.orig 1970-01-01 07:30:00.000000000 +0730 +++ sys/i386/conf/MIKI_DEBUG 2009-04-26 11:35:35.000000000 +0800 @@ -0,0 +1,10 @@ +include MIKI +ident MIKI_DEBUG +makeoptions DEBUG=-g +options KDB +options DDB +options GDB +options INVARIANTS +options INVARIANT_SUPPORT +options WITNESS +options WITNESS_SKIPSPIN --- sys/amd64/conf/FUU.orig 1970-01-01 07:30:00.000000000 +0730 +++ sys/amd64/conf/FUU 2011-04-18 23:13:13.000000000 +0800 @@ -0,0 +1,360 @@ +# +# GENERIC -- Generic kernel configuration file for FreeBSD/amd64 +# +# For more information on this file, please read the config(5) manual page, +# and/or the handbook section on Kernel Configuration Files: +# +# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html +# +# The handbook is also available locally in /usr/share/doc/handbook +# if you've installed the doc distribution, otherwise always see the +# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the +# latest information. +# +# An exhaustive list of options and more detailed explanations of the +# device lines is also present in the ../../conf/NOTES and NOTES files. +# If you are in doubt as to the purpose or necessity of a line, check first +# in NOTES. +# +# $FreeBSD: head/sys/amd64/conf/GENERIC 225482 2011-09-11 17:39:51Z brueffer $ + +cpu HAMMER +ident FUU + +#makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols + +options SCHED_ULE # ULE scheduler +options PREEMPTION # Enable kernel thread preemption +options INET # InterNETworking +options INET6 # IPv6 communications protocols +options SCTP # Stream Control Transmission Protocol +options FFS # Berkeley Fast Filesystem +options SOFTUPDATES # Enable FFS soft updates support +options UFS_ACL # Support for access control lists +options UFS_DIRHASH # Improve performance on big directories +options UFS_GJOURNAL # Enable gjournal-based UFS journaling +options MD_ROOT # MD is a potential root device +options NFSCL # New Network Filesystem Client +options NFSD # New Network Filesystem Server +options NFSLOCKD # Network Lock Manager +options NFS_ROOT # NFS usable as /, requires NFSCL +options MSDOSFS # MSDOS Filesystem +options CD9660 # ISO 9660 Filesystem +options PROCFS # Process filesystem (requires PSEUDOFS) +options PSEUDOFS # Pseudo-filesystem framework +options GEOM_PART_GPT # GUID Partition Tables. +options GEOM_LABEL # Provides labelization +options COMPAT_FREEBSD32 # Compatible with i386 binaries +options COMPAT_FREEBSD4 # Compatible with FreeBSD4 +options COMPAT_FREEBSD5 # Compatible with FreeBSD5 +options COMPAT_FREEBSD6 # Compatible with FreeBSD6 +options COMPAT_FREEBSD7 # Compatible with FreeBSD7 +options SCSI_DELAY=5000 # Delay (in ms) before probing SCSI +options KTRACE # ktrace(1) support +options STACK # stack(9) support +options SYSVSHM # SYSV-style shared memory +options SYSVMSG # SYSV-style message queues +options SYSVSEM # SYSV-style semaphores +options _KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions +options PRINTF_BUFR_SIZE=128 # Prevent printf output being interspersed. +options KBD_INSTALL_CDEV # install a CDEV entry in /dev +options HWPMC_HOOKS # Necessary kernel hooks for hwpmc(4) +options AUDIT # Security event auditing +options MAC # TrustedBSD MAC Framework +#options KDTRACE_FRAME # Ensure frames are compiled in +#options KDTRACE_HOOKS # Kernel DTrace hooks +options INCLUDE_CONFIG_FILE # Include this file in kernel + +# Debugging for use in -current +#options KDB # Enable kernel debugger support. +#options DDB # Support DDB. +#options GDB # Support remote GDB. +#options DEADLKRES # Enable the deadlock resolver +#options INVARIANTS # Enable calls of extra sanity checking +#options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS +#options WITNESS # Enable checks to detect deadlocks and cycles +#options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed +#options MALLOC_DEBUG_MAXZONES=8 # Separate malloc(9) zones + +# Make an SMP-capable kernel by default +options SMP # Symmetric MultiProcessor Kernel + +# CPU frequency control +device cpufreq + +# Bus support. +device acpi +device pci + +# Floppy drives +device fdc + +# ATA controllers +device ahci # AHCI-compatible SATA controllers +device ata # Legacy ATA/SATA controllers +options ATA_CAM # Handle legacy controllers with CAM +options ATA_STATIC_ID # Static device numbering +device mvs # Marvell 88SX50XX/88SX60XX/88SX70XX/SoC SATA +device siis # SiliconImage SiI3124/SiI3132/SiI3531 SATA + +# SCSI Controllers +device ahc # AHA2940 and onboard AIC7xxx devices +options AHC_REG_PRETTY_PRINT # Print register bitfields in debug + # output. Adds ~128k to driver. +#device ahd # AHA39320/29320 and onboard AIC79xx devices +#options AHD_REG_PRETTY_PRINT # Print register bitfields in debug + # output. Adds ~215k to driver. +device amd # AMD 53C974 (Tekram DC-390(T)) +device hptiop # Highpoint RocketRaid 3xxx series +device isp # Qlogic family +#device ispfw # Firmware for QLogic HBAs- normally a module +device mpt # LSI-Logic MPT-Fusion +device mps # LSI-Logic MPT-Fusion 2 +#device ncr # NCR/Symbios Logic +device sym # NCR/Symbios Logic (newer chipsets + those of `ncr') +device trm # Tekram DC395U/UW/F DC315U adapters + +device adv # Advansys SCSI adapters +device adw # Advansys wide SCSI adapters +device aic # Adaptec 15[012]x SCSI adapters, AIC-6[23]60. +device bt # Buslogic/Mylex MultiMaster SCSI adapters + +# ATA/SCSI peripherals +device scbus # SCSI bus (required for ATA/SCSI) +device ch # SCSI media changers +device da # Direct Access (disks) +device sa # Sequential Access (tape etc) +device cd # CD +device pass # Passthrough device (direct ATA/SCSI access) +device ses # SCSI Environmental Services (and SAF-TE) + +# RAID controllers interfaced to the SCSI subsystem +device amr # AMI MegaRAID +device arcmsr # Areca SATA II RAID +#XXX it is not 64-bit clean, -scottl +#device asr # DPT SmartRAID V, VI and Adaptec SCSI RAID +device ciss # Compaq Smart RAID 5* +device dpt # DPT Smartcache III, IV - See NOTES for options +device hptmv # Highpoint RocketRAID 182x +device hptrr # Highpoint RocketRAID 17xx, 22xx, 23xx, 25xx +device iir # Intel Integrated RAID +device ips # IBM (Adaptec) ServeRAID +device mly # Mylex AcceleRAID/eXtremeRAID +device twa # 3ware 9000 series PATA/SATA RAID + +# RAID controllers +device aac # Adaptec FSA RAID +device aacp # SCSI passthrough for aac (requires CAM) +device ida # Compaq Smart RAID +device mfi # LSI MegaRAID SAS +device mlx # Mylex DAC960 family +#XXX pointer/int warnings +#device pst # Promise Supertrak SX6000 +device twe # 3ware ATA RAID + +# atkbdc0 controls both the keyboard and the PS/2 mouse +device atkbdc # AT keyboard controller +device atkbd # AT keyboard +device psm # PS/2 mouse + +device kbdmux # keyboard multiplexer + +device vga # VGA video card driver + +device splash # Splash screen and screen saver support + +# syscons is the default console driver, resembling an SCO console +device sc +options SC_PIXEL_MODE # add support for the raster text mode + +device agp # support several AGP chipsets + +# PCCARD (PCMCIA) support +# PCMCIA and cardbus bridge support +device cbb # cardbus (yenta) bridge +device pccard # PC Card (16-bit) bus +device cardbus # CardBus (32-bit) bus + +# Serial (COM) ports +device uart # Generic UART driver + +# Parallel port +device ppc +device ppbus # Parallel port bus (required) +device lpt # Printer +device plip # TCP/IP over parallel +device ppi # Parallel port interface device +#device vpo # Requires scbus and da + +device puc # Multi I/O cards and multi-channel UARTs + +# PCI Ethernet NICs. +device bxe # Broadcom BCM57710/BCM57711/BCM57711E 10Gb Ethernet +device de # DEC/Intel DC21x4x (``Tulip'') +device em # Intel PRO/1000 Gigabit Ethernet Family +device igb # Intel PRO/1000 PCIE Server Gigabit Family +device ixgbe # Intel PRO/10GbE PCIE Ethernet Family +device le # AMD Am7900 LANCE and Am79C9xx PCnet +device ti # Alteon Networks Tigon I/II gigabit Ethernet +device txp # 3Com 3cR990 (``Typhoon'') +device vx # 3Com 3c590, 3c595 (``Vortex'') + +# PCI Ethernet NICs that use the common MII bus controller code. +# NOTE: Be sure to keep the 'device miibus' line in order to use these NICs! +device miibus # MII bus support +device ae # Attansic/Atheros L2 FastEthernet +device age # Attansic/Atheros L1 Gigabit Ethernet +device alc # Atheros AR8131/AR8132 Ethernet +device ale # Atheros AR8121/AR8113/AR8114 Ethernet +device bce # Broadcom BCM5706/BCM5708 Gigabit Ethernet +device bfe # Broadcom BCM440x 10/100 Ethernet +device bge # Broadcom BCM570xx Gigabit Ethernet +device dc # DEC/Intel 21143 and various workalikes +device et # Agere ET1310 10/100/Gigabit Ethernet +device fxp # Intel EtherExpress PRO/100B (82557, 82558) +device jme # JMicron JMC250 Gigabit/JMC260 Fast Ethernet +device lge # Level 1 LXT1001 gigabit Ethernet +device msk # Marvell/SysKonnect Yukon II Gigabit Ethernet +device nfe # nVidia nForce MCP on-board Ethernet +device nge # NatSemi DP83820 gigabit Ethernet +#device nve # nVidia nForce MCP on-board Ethernet Networking +device pcn # AMD Am79C97x PCI 10/100 (precedence over 'le') +device re # RealTek 8139C+/8169/8169S/8110S +device rl # RealTek 8129/8139 +device sf # Adaptec AIC-6915 (``Starfire'') +device sge # Silicon Integrated Systems SiS190/191 +device sis # Silicon Integrated Systems SiS 900/SiS 7016 +device sk # SysKonnect SK-984x & SK-982x gigabit Ethernet +device ste # Sundance ST201 (D-Link DFE-550TX) +device stge # Sundance/Tamarack TC9021 gigabit Ethernet +device tl # Texas Instruments ThunderLAN +device tx # SMC EtherPower II (83c170 ``EPIC'') +device vge # VIA VT612x gigabit Ethernet +device vr # VIA Rhine, Rhine II +device wb # Winbond W89C840F +device xl # 3Com 3c90x (``Boomerang'', ``Cyclone'') + +# ISA Ethernet NICs. pccard NICs included. +device cs # Crystal Semiconductor CS89x0 NIC +# 'device ed' requires 'device miibus' +device ed # NE[12]000, SMC Ultra, 3c503, DS8390 cards +device ex # Intel EtherExpress Pro/10 and Pro/10+ +device ep # Etherlink III based cards +device fe # Fujitsu MB8696x based cards +device sn # SMC's 9000 series of Ethernet chips +device xe # Xircom pccard Ethernet + +# Wireless NIC cards +device wlan # 802.11 support +options IEEE80211_DEBUG # enable debug msgs +options IEEE80211_AMPDU_AGE # age frames in AMPDU reorder q's +options IEEE80211_SUPPORT_MESH # enable 802.11s draft support +device wlan_wep # 802.11 WEP support +device wlan_ccmp # 802.11 CCMP support +device wlan_tkip # 802.11 TKIP support +device wlan_amrr # AMRR transmit rate control algorithm +device an # Aironet 4500/4800 802.11 wireless NICs. +device ath # Atheros NIC's +device ath_pci # Atheros pci/cardbus glue +device ath_hal # pci/cardbus chip support +options AH_SUPPORT_AR5416 # enable AR5416 tx/rx descriptors +device ath_rate_sample # SampleRate tx rate control for ath +#device bwi # Broadcom BCM430x/BCM431x wireless NICs. +#device bwn # Broadcom BCM43xx wireless NICs. +device ipw # Intel 2100 wireless NICs. +device iwi # Intel 2200BG/2225BG/2915ABG wireless NICs. +device iwn # Intel 4965/1000/5000/6000 wireless NICs. +device malo # Marvell Libertas wireless NICs. +device mwl # Marvell 88W8363 802.11n wireless NICs. +device ral # Ralink Technology RT2500 wireless NICs. +device wi # WaveLAN/Intersil/Symbol 802.11 wireless NICs. +device wpi # Intel 3945ABG wireless NICs. + +# Pseudo devices. +device loop # Network loopback +device random # Entropy device +device ether # Ethernet support +device vlan # 802.1Q VLAN support +device tun # Packet tunnel. +device pty # BSD-style compatibility pseudo ttys +device md # Memory "disks" +device gif # IPv6 and IPv4 tunneling +device faith # IPv6-to-IPv4 relaying (translation) +device firmware # firmware assist module + +# The `bpf' device enables the Berkeley Packet Filter. +# Be aware of the administrative consequences of enabling this! +# Note that 'bpf' is required for DHCP. +device bpf # Berkeley packet filter + +# USB support +#options USB_DEBUG # enable debug msgs +device uhci # UHCI PCI->USB interface +device ohci # OHCI PCI->USB interface +device ehci # EHCI PCI->USB interface (USB 2.0) +device xhci # XHCI PCI->USB interface (USB 3.0) +device usb # USB Bus (required) +#device udbp # USB Double Bulk Pipe devices (needs netgraph) +device uhid # "Human Interface Devices" +device ukbd # Keyboard +device ulpt # Printer +device umass # Disks/Mass storage - Requires scbus and da +device ums # Mouse +device urio # Diamond Rio 500 MP3 player +# USB Serial devices +device u3g # USB-based 3G modems (Option, Huawei, Sierra) +device uark # Technologies ARK3116 based serial adapters +device ubsa # Belkin F5U103 and compatible serial adapters +device uftdi # For FTDI usb serial adapters +device uipaq # Some WinCE based devices +device uplcom # Prolific PL-2303 serial adapters +device uslcom # SI Labs CP2101/CP2102 serial adapters +device uvisor # Visor and Palm devices +device uvscom # USB serial support for DDI pocket's PHS +# USB Ethernet, requires miibus +device aue # ADMtek USB Ethernet +device axe # ASIX Electronics USB Ethernet +device cdce # Generic USB over Ethernet +device cue # CATC USB Ethernet +device kue # Kawasaki LSI USB Ethernet +device rue # RealTek RTL8150 USB Ethernet +device udav # Davicom DM9601E USB +# USB Wireless +device rum # Ralink Technology RT2501USB wireless NICs +device run # Ralink Technology RT2700/RT2800/RT3000 NICs. +device uath # Atheros AR5523 wireless NICs +device upgt # Conexant/Intersil PrismGT wireless NICs. +device ural # Ralink Technology RT2500USB wireless NICs +device urtw # Realtek RTL8187B/L wireless NICs +device zyd # ZyDAS zd1211/zd1211b wireless NICs + +# FireWire support +device firewire # FireWire bus code +device sbp # SCSI over FireWire (Requires scbus and da) +device fwe # Ethernet over FireWire (non-standard!) +device fwip # IP over FireWire (RFC 2734,3146) +device dcons # Dumb console driver +device dcons_crom # Configuration ROM for dcons + +# Sound support +options SND_DEBUG +options SND_FEEDER_MULTIFORMAT +options SND_FEEDER_FULL_MULTIFORMAT +options SND_PCM_64 + +# IPSec +options IPSEC +options IPSEC_NAT_T +device crypto +device enc + +device carp + +options ALTQ +options ALTQ_CBQ # Class Based Queueing +options ALTQ_RED # Random Early Detection +options ALTQ_RIO # RED In/Out +options ALTQ_HFSC # Hierarchical Packet Scheduler +options ALTQ_CDNR # Traffic conditioner +options ALTQ_PRIQ # Priority Queueing +options ALTQ_NOPCC # Required if the TSC is unusable --- sys/amd64/conf/FUU_DEBUG.orig 1970-01-01 07:30:00.000000000 +0730 +++ sys/amd64/conf/FUU_DEBUG 2010-08-01 17:25:01.807978170 +0800 @@ -0,0 +1,13 @@ +include FUU +ident FUU_DEBUG +makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols +options KDB # Enable kernel debugger support. +options DDB # Support DDB. +options GDB # Support remote GDB. +options DEADLKRES # Enable the deadlock resolver +options INVARIANTS # Enable calls of extra sanity checking +options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS +options WITNESS # Enable checks to detect deadlocks and cycles +options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed +options MALLOC_DEBUG_MAXZONES=8 # Separate malloc(9) zones +options USB_DEBUG # enable debug msgs --- sys/dev/usb/wlan/if_zyd.c.orig (revision 210522) +++ sys/dev/usb/wlan/if_zyd.c (working copy) @@ -2353,7 +2353,9 @@ return (0x3); } - device_printf(sc->sc_dev, "unsupported rate %d\n", rate); + if (bootverbose) + device_printf(sc->sc_dev, "unsupported rate %d\n", rate); + return (0x0); } --- sys/compat/ndis/subr_hal.c.orig (revision 217079) +++ sys/compat/ndis/subr_hal.c (working copy) @@ -437,7 +437,7 @@ static void dummy() { - printf("hal dummy called...\n"); + /* printf("hal dummy called...\n"); */ } image_patch_table hal_functbl[] = { --- sys/compat/ndis/subr_ntoskrnl.c.orig (revision 217079) +++ sys/compat/ndis/subr_ntoskrnl.c (working copy) @@ -4251,7 +4251,7 @@ static void dummy() { - printf("ntoskrnl dummy called...\n"); + /* printf("ntoskrnl dummy called...\n"); */ } --- sys/compat/ndis/subr_ndis.c.orig (revision 217079) +++ sys/compat/ndis/subr_ndis.c (working copy) @@ -136,7 +136,7 @@ static void NdisOpenConfigurationKeyByName(ndis_status *, ndis_handle, unicode_string *, ndis_handle *); static ndis_status ndis_encode_parm(ndis_miniport_block *, - struct sysctl_oid *, ndis_parm_type, ndis_config_parm **); + struct sysctl_oid *, ndis_parm_type, ndis_config_parm **, int); static ndis_status ndis_decode_parm(ndis_miniport_block *, ndis_config_parm *, char *); static void NdisReadConfiguration(ndis_status *, ndis_config_parm **, @@ -540,11 +540,12 @@ } static ndis_status -ndis_encode_parm(block, oid, type, parm) +ndis_encode_parm(block, oid, type, parm, literal) ndis_miniport_block *block; struct sysctl_oid *oid; ndis_parm_type type; ndis_config_parm **parm; + int literal; { ndis_config_parm *p; ndis_parmlist_entry *np; @@ -567,7 +568,7 @@ val = strtoul((char *)oid->oid_arg1, NULL, 10); us = &p->ncp_parmdata.ncp_stringdata; p->ncp_type = ndis_parm_string; - if (val) { + if (!literal && val) { snprintf(tmp, 32, "%x", val); RtlInitAnsiString(&as, tmp); } else { @@ -651,7 +652,8 @@ return; } - *status = ndis_encode_parm(block, oidp, type, parm); + *status = ndis_encode_parm(block, oidp, type, parm, + strcasecmp(keystr, "NetworkAddress") == 0); RtlFreeAnsiString(&as); return; } @@ -3221,7 +3223,7 @@ static void dummy() { - printf("NDIS dummy called...\n"); + /* printf("NDIS dummy called...\n"); */ } /* --- sys/compat/ndis/subr_usbd.c.orig (revision 217079) +++ sys/compat/ndis/subr_usbd.c (working copy) @@ -1427,7 +1427,7 @@ static void dummy(void) { - printf("USBD dummy called\n"); + /* printf("USBD dummy called\n"); */ } image_patch_table usbd_functbl[] = { --- sys/dev/if_ndis/if_ndis.c.orig (revision 217079) +++ sys/dev/if_ndis/if_ndis.c (working copy) @@ -989,6 +989,7 @@ return NULL; vap = &nvp->vap; ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); + IEEE80211_ADDR_COPY(vap->iv_myaddr, mac); /* override with driver methods */ nvp->newstate = vap->iv_newstate; vap->iv_newstate = ndis_newstate; @@ -1942,6 +1943,11 @@ struct ifnet *ifp = sc->ifp; struct ieee80211com *ic = ifp->if_l2com; int i, len, error; + struct ieee80211vap *vap; + struct sysctl_ctx_entry *e; + struct sysctl_oid *oidp; + uint8_t *eaddr; + char eaddr_str[(IEEE80211_ADDR_LEN * 2) + 1]; /* * Avoid reintializing the link unnecessarily. @@ -1968,6 +1974,30 @@ /* Init our MAC address */ + /* + * "NetworkAddress" value should be 12 bytes HEX. + */ + vap = TAILQ_FIRST(&ic->ic_vaps); + eaddr = vap->iv_myaddr; + snprintf(eaddr_str, sizeof(eaddr_str), "%02x%02x%02x%02x%02x%02x", + eaddr[0], eaddr[1], eaddr[2], + eaddr[3], eaddr[4], eaddr[5]); + TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) { + oidp = e->entry; + if (strcasecmp(oidp->oid_name, "NetworkAddress") == 0) { + /* + * Copy the value, so NdisReadConfiguration() + * will find and use this configured value. + */ + strcpy((char *)oidp->oid_arg1, eaddr_str); + goto mac_addr_save_out; + } + } + /* Add sysctl entry for "NetworkAdress", in case it doesn't exist */ + ndis_add_sysctl(sc, "NetworkAddress", "(dynamically set key)", + eaddr_str, CTLFLAG_RW); +mac_addr_save_out: + /* Program the packet filter */ sc->ndis_filter = NDIS_PACKET_TYPE_DIRECTED; --- sys/dev/sound/pcm/feeder.h.orig (revision 217915) +++ sys/dev/sound/pcm/feeder.h (working copy) @@ -53,9 +53,6 @@ void feeder_register(void *p); struct feeder_class *feeder_getclass(struct pcm_feederdesc *desc); -u_int32_t snd_fmtscore(u_int32_t fmt); -u_int32_t snd_fmtbestbit(u_int32_t fmt, u_int32_t *fmts); -u_int32_t snd_fmtbestchannel(u_int32_t fmt, u_int32_t *fmts); u_int32_t snd_fmtbest(u_int32_t fmt, u_int32_t *fmts); int chn_addfeeder(struct pcm_channel *c, struct feeder_class *fc, --- sys/dev/sound/pcm/feeder.c.orig (revision 217915) +++ sys/dev/sound/pcm/feeder.c (working copy) @@ -279,161 +279,84 @@ return NULL; } -/* - * 14bit format scoring - * -------------------- - * - * 13 12 11 10 9 8 2 1 0 offset - * +---+---+---+---+---+---+-------------+---+---+ - * | X | X | X | X | X | X | X X X X X X | X | X | - * +---+---+---+---+---+---+-------------+---+---+ - * | | | | | | | | | - * | | | | | | | | +--> signed? - * | | | | | | | | - * | | | | | | | +------> bigendian? - * | | | | | | | - * | | | | | | +---------------> total channels - * | | | | | | - * | | | | | +------------------------> AFMT_A_LAW - * | | | | | - * | | | | +----------------------------> AFMT_MU_LAW - * | | | | - * | | | +--------------------------------> AFMT_8BIT - * | | | - * | | +------------------------------------> AFMT_16BIT - * | | - * | +----------------------------------------> AFMT_24BIT - * | - * +--------------------------------------------> AFMT_32BIT - */ -#define score_signeq(s1, s2) (((s1) & 0x1) == ((s2) & 0x1)) -#define score_endianeq(s1, s2) (((s1) & 0x2) == ((s2) & 0x2)) -#define score_cheq(s1, s2) (((s1) & 0xfc) == ((s2) & 0xfc)) -#define score_chgt(s1, s2) (((s1) & 0xfc) > ((s2) & 0xfc)) -#define score_chlt(s1, s2) (((s1) & 0xfc) < ((s2) & 0xfc)) -#define score_val(s1) ((s1) & 0x3f00) -#define score_cse(s1) ((s1) & 0x7f) - -u_int32_t -snd_fmtscore(u_int32_t fmt) +static u_int32_t +snd_fmtscore(u_int32_t base, u_int32_t fmt) { u_int32_t ret; ret = 0; - if (fmt & AFMT_SIGNED) - ret |= 1 << 0; - if (fmt & AFMT_BIGENDIAN) - ret |= 1 << 1; - /*if (fmt & AFMT_STEREO) - ret |= (2 & 0x3f) << 2; + + /* + * 1st priority: 1:1 channel mapping. + * Larger + nearest channel will get higher metric. + * Largest supported range: 128 vs 1 channel. + */ + if (AFMT_CHANNEL(fmt) == AFMT_CHANNEL(base)) + ret |= 0xff << 24; + else if (AFMT_CHANNEL(fmt) > AFMT_CHANNEL(base)) + ret |= (0xff - AFMT_CHANNEL(fmt) + AFMT_CHANNEL(base)) << 24; else - ret |= (1 & 0x3f) << 2;*/ - ret |= (AFMT_CHANNEL(fmt) & 0x3f) << 2; - if (fmt & AFMT_A_LAW) - ret |= 1 << 8; - else if (fmt & AFMT_MU_LAW) - ret |= 1 << 9; - else if (fmt & AFMT_8BIT) - ret |= 1 << 10; - else if (fmt & AFMT_16BIT) - ret |= 1 << 11; - else if (fmt & AFMT_24BIT) - ret |= 1 << 12; - else if (fmt & AFMT_32BIT) - ret |= 1 << 13; + ret |= (0x80 + AFMT_CHANNEL(fmt) - AFMT_CHANNEL(base)) << 24; + + /* + * 2nd priority: bitdepth for dynamic range. + * Larger + nearest bitdepth will get higher metric. + * Largest supported range: 128 vs 8 bit. + */ + if (AFMT_BIT(fmt) == AFMT_BIT(base)) + ret |= 0xff << 16; + else if (AFMT_BIT(fmt) > AFMT_BIT(base)) + ret |= (0xff - AFMT_BIT(fmt) + AFMT_BIT(base)) << 16; + else + ret |= (0x80 + AFMT_BIT(fmt) - AFMT_BIT(base)) << 16; - return ret; -} + /* 3rd priority: encoding match. */ + if (AFMT_ENCODING(fmt) == AFMT_ENCODING(base)) + ret |= 0x3 << 14; + else if (!(AFMT_G711 & fmt) == !(AFMT_G711 & base)) + ret |= 0x2 << 14; -static u_int32_t -snd_fmtbestfunc(u_int32_t fmt, u_int32_t *fmts, int cheq) -{ - u_int32_t best, score, score2, oldscore; - int i; + /* Bail out if any of these is a non-convertible (AC3, etc). */ + if (!(AFMT_CONVERTIBLE & fmt) || !(AFMT_CONVERTIBLE & base)) + return ret; - if (fmt == 0 || fmts == NULL || fmts[0] == 0) - return 0; + /* 4th priority: endianness match. */ + if ((AFMT_BIT(fmt) > 8 && AFMT_BIT(base) > 8 && + !(AFMT_BIGENDIAN & fmt) == !(AFMT_BIGENDIAN & base)) || + (AFMT_BIT(fmt) == 8 && AFMT_BIT(base) == 8)) + ret |= 1 << 13; - if (snd_fmtvalid(fmt, fmts)) - return fmt; + /* 5th priority: signedness match .*/ + if (!(AFMT_SIGNED & fmt) == !(AFMT_SIGNED & base)) + ret |= 1 << 12; - best = 0; - score = snd_fmtscore(fmt); - oldscore = 0; - for (i = 0; fmts[i] != 0; i++) { - score2 = snd_fmtscore(fmts[i]); - if (cheq && !score_cheq(score, score2) && - (score_chlt(score2, score) || - (oldscore != 0 && score_chgt(score2, oldscore)))) - continue; - if (oldscore == 0 || - (score_val(score2) == score_val(score)) || - (score_val(score2) == score_val(oldscore)) || - (score_val(score2) > score_val(oldscore) && - score_val(score2) < score_val(score)) || - (score_val(score2) < score_val(oldscore) && - score_val(score2) > score_val(score)) || - (score_val(oldscore) < score_val(score) && - score_val(score2) > score_val(oldscore))) { - if (score_val(oldscore) != score_val(score2) || - score_cse(score) == score_cse(score2) || - ((score_cse(oldscore) != score_cse(score) && - !score_endianeq(score, oldscore) && - (score_endianeq(score, score2) || - (!score_signeq(score, oldscore) && - score_signeq(score, score2)))))) { - best = fmts[i]; - oldscore = score2; - } - } - } - return best; + return ret; } u_int32_t -snd_fmtbestbit(u_int32_t fmt, u_int32_t *fmts) -{ - return snd_fmtbestfunc(fmt, fmts, 0); -} - -u_int32_t -snd_fmtbestchannel(u_int32_t fmt, u_int32_t *fmts) -{ - return snd_fmtbestfunc(fmt, fmts, 1); -} - -u_int32_t snd_fmtbest(u_int32_t fmt, u_int32_t *fmts) { - u_int32_t best1, best2; - u_int32_t score, score1, score2; + u_int32_t curscore, score, bestfmt; + int i; + /* Requested format supported. */ if (snd_fmtvalid(fmt, fmts)) return fmt; - best1 = snd_fmtbestchannel(fmt, fmts); - best2 = snd_fmtbestbit(fmt, fmts); + /* Begin with first format, do metric comparison later. */ + curscore = snd_fmtscore(fmt, fmts[0]); + bestfmt = fmts[0]; - if (best1 != 0 && best2 != 0 && best1 != best2) { - /*if (fmt & AFMT_STEREO)*/ - if (AFMT_CHANNEL(fmt) > 1) - return best1; - else { - score = score_val(snd_fmtscore(fmt)); - score1 = score_val(snd_fmtscore(best1)); - score2 = score_val(snd_fmtscore(best2)); - if (score1 == score2 || score1 == score) - return best1; - else if (score2 == score) - return best2; - else if (score1 > score2) - return best1; - return best2; + /* Iterate, calculate metric score and choose the highest. */ + for (i = 1; fmts[i] != 0; i++) { + score = snd_fmtscore(fmt, fmts[i]); + if (score > curscore) { + curscore = score; + bestfmt = fmts[i]; } - } else if (best2 == 0) - return best1; - else - return best2; + } + + return bestfmt; } void --- sys/dev/sound/pcm/feeder_matrix.c.orig (revision 217915) +++ sys/dev/sound/pcm/feeder_matrix.c (working copy) @@ -107,7 +107,13 @@ [8] = SND_CHN_MATRIX_8 }; +static int feeder_matrix_attenuation = 1; #ifdef _KERNEL +TUNABLE_INT("hw.snd.feeder_matrix_attenuation", &feeder_matrix_attenuation); +SYSCTL_INT(_hw_snd, OID_AUTO, feeder_matrix_attenuation, CTLFLAG_RW, + &feeder_matrix_attenuation, 1, + "perform channel attenuation on down-mixing"); + #define FEEDMATRIX_CLIP_CHECK(...) #else #define FEEDMATRIX_CLIP_CHECK(v, BIT) do { \ @@ -353,7 +359,7 @@ #define FEEDMATRIX_ATTN_SHIFT 16 - if (j > 1) { + if (feeder_matrix_attenuation > 0 && j > 1) { /* * XXX For channel that require accumulation from * multiple channels, apply a slight attenuation to --- sys/dev/sound/pcm/feeder_format.c.orig (revision 217915) +++ sys/dev/sound/pcm/feeder_format.c (working copy) @@ -72,7 +72,7 @@ intpcm_write_null(uint8_t *dst, intpcm_t v __unused) { - _PCM_WRITE_S16_LE(dst, 0); + PCM_WRITE_S16_NE(dst, 0); } #define FEEDFORMAT_ENTRY(SIGN, BIT, ENDIAN) \