Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  *  PCM Interface - misc routines
0003  *  Copyright (c) 1998 by Jaroslav Kysela <perex@perex.cz>
0004  *
0005  *
0006  *   This library is free software; you can redistribute it and/or modify
0007  *   it under the terms of the GNU Library General Public License as
0008  *   published by the Free Software Foundation; either version 2 of
0009  *   the License, or (at your option) any later version.
0010  *
0011  *   This program is distributed in the hope that it will be useful,
0012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014  *   GNU Library General Public License for more details.
0015  *
0016  *   You should have received a copy of the GNU Library General Public
0017  *   License along with this library; if not, write to the Free Software
0018  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
0019  *
0020  */
0021   
0022 #include <linux/time.h>
0023 #include <linux/export.h>
0024 #include <sound/core.h>
0025 #include <sound/pcm.h>
0026 
0027 #include "pcm_local.h"
0028 
0029 #define SND_PCM_FORMAT_UNKNOWN (-1)
0030 
0031 /* NOTE: "signed" prefix must be given below since the default char is
0032  *       unsigned on some architectures!
0033  */
0034 struct pcm_format_data {
0035     unsigned char width;    /* bit width */
0036     unsigned char phys; /* physical bit width */
0037     signed char le; /* 0 = big-endian, 1 = little-endian, -1 = others */
0038     signed char signd;  /* 0 = unsigned, 1 = signed, -1 = others */
0039     unsigned char silence[8];   /* silence data to fill */
0040 };
0041 
0042 /* we do lots of calculations on snd_pcm_format_t; shut up sparse */
0043 #define INT __force int
0044 
0045 static bool valid_format(snd_pcm_format_t format)
0046 {
0047     return (INT)format >= 0 && (INT)format <= (INT)SNDRV_PCM_FORMAT_LAST;
0048 }
0049 
0050 static const struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = {
0051     [SNDRV_PCM_FORMAT_S8] = {
0052         .width = 8, .phys = 8, .le = -1, .signd = 1,
0053         .silence = {},
0054     },
0055     [SNDRV_PCM_FORMAT_U8] = {
0056         .width = 8, .phys = 8, .le = -1, .signd = 0,
0057         .silence = { 0x80 },
0058     },
0059     [SNDRV_PCM_FORMAT_S16_LE] = {
0060         .width = 16, .phys = 16, .le = 1, .signd = 1,
0061         .silence = {},
0062     },
0063     [SNDRV_PCM_FORMAT_S16_BE] = {
0064         .width = 16, .phys = 16, .le = 0, .signd = 1,
0065         .silence = {},
0066     },
0067     [SNDRV_PCM_FORMAT_U16_LE] = {
0068         .width = 16, .phys = 16, .le = 1, .signd = 0,
0069         .silence = { 0x00, 0x80 },
0070     },
0071     [SNDRV_PCM_FORMAT_U16_BE] = {
0072         .width = 16, .phys = 16, .le = 0, .signd = 0,
0073         .silence = { 0x80, 0x00 },
0074     },
0075     [SNDRV_PCM_FORMAT_S24_LE] = {
0076         .width = 24, .phys = 32, .le = 1, .signd = 1,
0077         .silence = {},
0078     },
0079     [SNDRV_PCM_FORMAT_S24_BE] = {
0080         .width = 24, .phys = 32, .le = 0, .signd = 1,
0081         .silence = {},
0082     },
0083     [SNDRV_PCM_FORMAT_U24_LE] = {
0084         .width = 24, .phys = 32, .le = 1, .signd = 0,
0085         .silence = { 0x00, 0x00, 0x80 },
0086     },
0087     [SNDRV_PCM_FORMAT_U24_BE] = {
0088         .width = 24, .phys = 32, .le = 0, .signd = 0,
0089         .silence = { 0x00, 0x80, 0x00, 0x00 },
0090     },
0091     [SNDRV_PCM_FORMAT_S32_LE] = {
0092         .width = 32, .phys = 32, .le = 1, .signd = 1,
0093         .silence = {},
0094     },
0095     [SNDRV_PCM_FORMAT_S32_BE] = {
0096         .width = 32, .phys = 32, .le = 0, .signd = 1,
0097         .silence = {},
0098     },
0099     [SNDRV_PCM_FORMAT_U32_LE] = {
0100         .width = 32, .phys = 32, .le = 1, .signd = 0,
0101         .silence = { 0x00, 0x00, 0x00, 0x80 },
0102     },
0103     [SNDRV_PCM_FORMAT_U32_BE] = {
0104         .width = 32, .phys = 32, .le = 0, .signd = 0,
0105         .silence = { 0x80, 0x00, 0x00, 0x00 },
0106     },
0107     [SNDRV_PCM_FORMAT_FLOAT_LE] = {
0108         .width = 32, .phys = 32, .le = 1, .signd = -1,
0109         .silence = {},
0110     },
0111     [SNDRV_PCM_FORMAT_FLOAT_BE] = {
0112         .width = 32, .phys = 32, .le = 0, .signd = -1,
0113         .silence = {},
0114     },
0115     [SNDRV_PCM_FORMAT_FLOAT64_LE] = {
0116         .width = 64, .phys = 64, .le = 1, .signd = -1,
0117         .silence = {},
0118     },
0119     [SNDRV_PCM_FORMAT_FLOAT64_BE] = {
0120         .width = 64, .phys = 64, .le = 0, .signd = -1,
0121         .silence = {},
0122     },
0123     [SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE] = {
0124         .width = 32, .phys = 32, .le = 1, .signd = -1,
0125         .silence = {},
0126     },
0127     [SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE] = {
0128         .width = 32, .phys = 32, .le = 0, .signd = -1,
0129         .silence = {},
0130     },
0131     [SNDRV_PCM_FORMAT_MU_LAW] = {
0132         .width = 8, .phys = 8, .le = -1, .signd = -1,
0133         .silence = { 0x7f },
0134     },
0135     [SNDRV_PCM_FORMAT_A_LAW] = {
0136         .width = 8, .phys = 8, .le = -1, .signd = -1,
0137         .silence = { 0x55 },
0138     },
0139     [SNDRV_PCM_FORMAT_IMA_ADPCM] = {
0140         .width = 4, .phys = 4, .le = -1, .signd = -1,
0141         .silence = {},
0142     },
0143     [SNDRV_PCM_FORMAT_G723_24] = {
0144         .width = 3, .phys = 3, .le = -1, .signd = -1,
0145         .silence = {},
0146     },
0147     [SNDRV_PCM_FORMAT_G723_40] = {
0148         .width = 5, .phys = 5, .le = -1, .signd = -1,
0149         .silence = {},
0150     },
0151     [SNDRV_PCM_FORMAT_DSD_U8] = {
0152         .width = 8, .phys = 8, .le = 1, .signd = 0,
0153         .silence = { 0x69 },
0154     },
0155     [SNDRV_PCM_FORMAT_DSD_U16_LE] = {
0156         .width = 16, .phys = 16, .le = 1, .signd = 0,
0157         .silence = { 0x69, 0x69 },
0158     },
0159     [SNDRV_PCM_FORMAT_DSD_U32_LE] = {
0160         .width = 32, .phys = 32, .le = 1, .signd = 0,
0161         .silence = { 0x69, 0x69, 0x69, 0x69 },
0162     },
0163     [SNDRV_PCM_FORMAT_DSD_U16_BE] = {
0164         .width = 16, .phys = 16, .le = 0, .signd = 0,
0165         .silence = { 0x69, 0x69 },
0166     },
0167     [SNDRV_PCM_FORMAT_DSD_U32_BE] = {
0168         .width = 32, .phys = 32, .le = 0, .signd = 0,
0169         .silence = { 0x69, 0x69, 0x69, 0x69 },
0170     },
0171     /* FIXME: the following two formats are not defined properly yet */
0172     [SNDRV_PCM_FORMAT_MPEG] = {
0173         .le = -1, .signd = -1,
0174     },
0175     [SNDRV_PCM_FORMAT_GSM] = {
0176         .le = -1, .signd = -1,
0177     },
0178     [SNDRV_PCM_FORMAT_S20_LE] = {
0179         .width = 20, .phys = 32, .le = 1, .signd = 1,
0180         .silence = {},
0181     },
0182     [SNDRV_PCM_FORMAT_S20_BE] = {
0183         .width = 20, .phys = 32, .le = 0, .signd = 1,
0184         .silence = {},
0185     },
0186     [SNDRV_PCM_FORMAT_U20_LE] = {
0187         .width = 20, .phys = 32, .le = 1, .signd = 0,
0188         .silence = { 0x00, 0x00, 0x08, 0x00 },
0189     },
0190     [SNDRV_PCM_FORMAT_U20_BE] = {
0191         .width = 20, .phys = 32, .le = 0, .signd = 0,
0192         .silence = { 0x00, 0x08, 0x00, 0x00 },
0193     },
0194     /* FIXME: the following format is not defined properly yet */
0195     [SNDRV_PCM_FORMAT_SPECIAL] = {
0196         .le = -1, .signd = -1,
0197     },
0198     [SNDRV_PCM_FORMAT_S24_3LE] = {
0199         .width = 24, .phys = 24, .le = 1, .signd = 1,
0200         .silence = {},
0201     },
0202     [SNDRV_PCM_FORMAT_S24_3BE] = {
0203         .width = 24, .phys = 24, .le = 0, .signd = 1,
0204         .silence = {},
0205     },
0206     [SNDRV_PCM_FORMAT_U24_3LE] = {
0207         .width = 24, .phys = 24, .le = 1, .signd = 0,
0208         .silence = { 0x00, 0x00, 0x80 },
0209     },
0210     [SNDRV_PCM_FORMAT_U24_3BE] = {
0211         .width = 24, .phys = 24, .le = 0, .signd = 0,
0212         .silence = { 0x80, 0x00, 0x00 },
0213     },
0214     [SNDRV_PCM_FORMAT_S20_3LE] = {
0215         .width = 20, .phys = 24, .le = 1, .signd = 1,
0216         .silence = {},
0217     },
0218     [SNDRV_PCM_FORMAT_S20_3BE] = {
0219         .width = 20, .phys = 24, .le = 0, .signd = 1,
0220         .silence = {},
0221     },
0222     [SNDRV_PCM_FORMAT_U20_3LE] = {
0223         .width = 20, .phys = 24, .le = 1, .signd = 0,
0224         .silence = { 0x00, 0x00, 0x08 },
0225     },
0226     [SNDRV_PCM_FORMAT_U20_3BE] = {
0227         .width = 20, .phys = 24, .le = 0, .signd = 0,
0228         .silence = { 0x08, 0x00, 0x00 },
0229     },
0230     [SNDRV_PCM_FORMAT_S18_3LE] = {
0231         .width = 18, .phys = 24, .le = 1, .signd = 1,
0232         .silence = {},
0233     },
0234     [SNDRV_PCM_FORMAT_S18_3BE] = {
0235         .width = 18, .phys = 24, .le = 0, .signd = 1,
0236         .silence = {},
0237     },
0238     [SNDRV_PCM_FORMAT_U18_3LE] = {
0239         .width = 18, .phys = 24, .le = 1, .signd = 0,
0240         .silence = { 0x00, 0x00, 0x02 },
0241     },
0242     [SNDRV_PCM_FORMAT_U18_3BE] = {
0243         .width = 18, .phys = 24, .le = 0, .signd = 0,
0244         .silence = { 0x02, 0x00, 0x00 },
0245     },
0246     [SNDRV_PCM_FORMAT_G723_24_1B] = {
0247         .width = 3, .phys = 8, .le = -1, .signd = -1,
0248         .silence = {},
0249     },
0250     [SNDRV_PCM_FORMAT_G723_40_1B] = {
0251         .width = 5, .phys = 8, .le = -1, .signd = -1,
0252         .silence = {},
0253     },
0254 };
0255 
0256 
0257 /**
0258  * snd_pcm_format_signed - Check the PCM format is signed linear
0259  * @format: the format to check
0260  *
0261  * Return: 1 if the given PCM format is signed linear, 0 if unsigned
0262  * linear, and a negative error code for non-linear formats.
0263  */
0264 int snd_pcm_format_signed(snd_pcm_format_t format)
0265 {
0266     int val;
0267     if (!valid_format(format))
0268         return -EINVAL;
0269     val = pcm_formats[(INT)format].signd;
0270     if (val < 0)
0271         return -EINVAL;
0272     return val;
0273 }
0274 EXPORT_SYMBOL(snd_pcm_format_signed);
0275 
0276 /**
0277  * snd_pcm_format_unsigned - Check the PCM format is unsigned linear
0278  * @format: the format to check
0279  *
0280  * Return: 1 if the given PCM format is unsigned linear, 0 if signed
0281  * linear, and a negative error code for non-linear formats.
0282  */
0283 int snd_pcm_format_unsigned(snd_pcm_format_t format)
0284 {
0285     int val;
0286 
0287     val = snd_pcm_format_signed(format);
0288     if (val < 0)
0289         return val;
0290     return !val;
0291 }
0292 EXPORT_SYMBOL(snd_pcm_format_unsigned);
0293 
0294 /**
0295  * snd_pcm_format_linear - Check the PCM format is linear
0296  * @format: the format to check
0297  *
0298  * Return: 1 if the given PCM format is linear, 0 if not.
0299  */
0300 int snd_pcm_format_linear(snd_pcm_format_t format)
0301 {
0302     return snd_pcm_format_signed(format) >= 0;
0303 }
0304 EXPORT_SYMBOL(snd_pcm_format_linear);
0305 
0306 /**
0307  * snd_pcm_format_little_endian - Check the PCM format is little-endian
0308  * @format: the format to check
0309  *
0310  * Return: 1 if the given PCM format is little-endian, 0 if
0311  * big-endian, or a negative error code if endian not specified.
0312  */
0313 int snd_pcm_format_little_endian(snd_pcm_format_t format)
0314 {
0315     int val;
0316     if (!valid_format(format))
0317         return -EINVAL;
0318     val = pcm_formats[(INT)format].le;
0319     if (val < 0)
0320         return -EINVAL;
0321     return val;
0322 }
0323 EXPORT_SYMBOL(snd_pcm_format_little_endian);
0324 
0325 /**
0326  * snd_pcm_format_big_endian - Check the PCM format is big-endian
0327  * @format: the format to check
0328  *
0329  * Return: 1 if the given PCM format is big-endian, 0 if
0330  * little-endian, or a negative error code if endian not specified.
0331  */
0332 int snd_pcm_format_big_endian(snd_pcm_format_t format)
0333 {
0334     int val;
0335 
0336     val = snd_pcm_format_little_endian(format);
0337     if (val < 0)
0338         return val;
0339     return !val;
0340 }
0341 EXPORT_SYMBOL(snd_pcm_format_big_endian);
0342 
0343 /**
0344  * snd_pcm_format_width - return the bit-width of the format
0345  * @format: the format to check
0346  *
0347  * Return: The bit-width of the format, or a negative error code
0348  * if unknown format.
0349  */
0350 int snd_pcm_format_width(snd_pcm_format_t format)
0351 {
0352     int val;
0353     if (!valid_format(format))
0354         return -EINVAL;
0355     val = pcm_formats[(INT)format].width;
0356     if (!val)
0357         return -EINVAL;
0358     return val;
0359 }
0360 EXPORT_SYMBOL(snd_pcm_format_width);
0361 
0362 /**
0363  * snd_pcm_format_physical_width - return the physical bit-width of the format
0364  * @format: the format to check
0365  *
0366  * Return: The physical bit-width of the format, or a negative error code
0367  * if unknown format.
0368  */
0369 int snd_pcm_format_physical_width(snd_pcm_format_t format)
0370 {
0371     int val;
0372     if (!valid_format(format))
0373         return -EINVAL;
0374     val = pcm_formats[(INT)format].phys;
0375     if (!val)
0376         return -EINVAL;
0377     return val;
0378 }
0379 EXPORT_SYMBOL(snd_pcm_format_physical_width);
0380 
0381 /**
0382  * snd_pcm_format_size - return the byte size of samples on the given format
0383  * @format: the format to check
0384  * @samples: sampling rate
0385  *
0386  * Return: The byte size of the given samples for the format, or a
0387  * negative error code if unknown format.
0388  */
0389 ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples)
0390 {
0391     int phys_width = snd_pcm_format_physical_width(format);
0392     if (phys_width < 0)
0393         return -EINVAL;
0394     return samples * phys_width / 8;
0395 }
0396 EXPORT_SYMBOL(snd_pcm_format_size);
0397 
0398 /**
0399  * snd_pcm_format_silence_64 - return the silent data in 8 bytes array
0400  * @format: the format to check
0401  *
0402  * Return: The format pattern to fill or %NULL if error.
0403  */
0404 const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format)
0405 {
0406     if (!valid_format(format))
0407         return NULL;
0408     if (! pcm_formats[(INT)format].phys)
0409         return NULL;
0410     return pcm_formats[(INT)format].silence;
0411 }
0412 EXPORT_SYMBOL(snd_pcm_format_silence_64);
0413 
0414 /**
0415  * snd_pcm_format_set_silence - set the silence data on the buffer
0416  * @format: the PCM format
0417  * @data: the buffer pointer
0418  * @samples: the number of samples to set silence
0419  *
0420  * Sets the silence data on the buffer for the given samples.
0421  *
0422  * Return: Zero if successful, or a negative error code on failure.
0423  */
0424 int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples)
0425 {
0426     int width;
0427     unsigned char *dst;
0428     const unsigned char *pat;
0429 
0430     if (!valid_format(format))
0431         return -EINVAL;
0432     if (samples == 0)
0433         return 0;
0434     width = pcm_formats[(INT)format].phys; /* physical width */
0435     pat = pcm_formats[(INT)format].silence;
0436     if (!width || !pat)
0437         return -EINVAL;
0438     /* signed or 1 byte data */
0439     if (pcm_formats[(INT)format].signd == 1 || width <= 8) {
0440         unsigned int bytes = samples * width / 8;
0441         memset(data, *pat, bytes);
0442         return 0;
0443     }
0444     /* non-zero samples, fill using a loop */
0445     width /= 8;
0446     dst = data;
0447 #if 0
0448     while (samples--) {
0449         memcpy(dst, pat, width);
0450         dst += width;
0451     }
0452 #else
0453     /* a bit optimization for constant width */
0454     switch (width) {
0455     case 2:
0456         while (samples--) {
0457             memcpy(dst, pat, 2);
0458             dst += 2;
0459         }
0460         break;
0461     case 3:
0462         while (samples--) {
0463             memcpy(dst, pat, 3);
0464             dst += 3;
0465         }
0466         break;
0467     case 4:
0468         while (samples--) {
0469             memcpy(dst, pat, 4);
0470             dst += 4;
0471         }
0472         break;
0473     case 8:
0474         while (samples--) {
0475             memcpy(dst, pat, 8);
0476             dst += 8;
0477         }
0478         break;
0479     }
0480 #endif
0481     return 0;
0482 }
0483 EXPORT_SYMBOL(snd_pcm_format_set_silence);
0484 
0485 /**
0486  * snd_pcm_hw_limit_rates - determine rate_min/rate_max fields
0487  * @hw: the pcm hw instance
0488  *
0489  * Determines the rate_min and rate_max fields from the rates bits of
0490  * the given hw.
0491  *
0492  * Return: Zero if successful.
0493  */
0494 int snd_pcm_hw_limit_rates(struct snd_pcm_hardware *hw)
0495 {
0496     int i;
0497     for (i = 0; i < (int)snd_pcm_known_rates.count; i++) {
0498         if (hw->rates & (1 << i)) {
0499             hw->rate_min = snd_pcm_known_rates.list[i];
0500             break;
0501         }
0502     }
0503     for (i = (int)snd_pcm_known_rates.count - 1; i >= 0; i--) {
0504         if (hw->rates & (1 << i)) {
0505             hw->rate_max = snd_pcm_known_rates.list[i];
0506             break;
0507         }
0508     }
0509     return 0;
0510 }
0511 EXPORT_SYMBOL(snd_pcm_hw_limit_rates);
0512 
0513 /**
0514  * snd_pcm_rate_to_rate_bit - converts sample rate to SNDRV_PCM_RATE_xxx bit
0515  * @rate: the sample rate to convert
0516  *
0517  * Return: The SNDRV_PCM_RATE_xxx flag that corresponds to the given rate, or
0518  * SNDRV_PCM_RATE_KNOT for an unknown rate.
0519  */
0520 unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate)
0521 {
0522     unsigned int i;
0523 
0524     for (i = 0; i < snd_pcm_known_rates.count; i++)
0525         if (snd_pcm_known_rates.list[i] == rate)
0526             return 1u << i;
0527     return SNDRV_PCM_RATE_KNOT;
0528 }
0529 EXPORT_SYMBOL(snd_pcm_rate_to_rate_bit);
0530 
0531 /**
0532  * snd_pcm_rate_bit_to_rate - converts SNDRV_PCM_RATE_xxx bit to sample rate
0533  * @rate_bit: the rate bit to convert
0534  *
0535  * Return: The sample rate that corresponds to the given SNDRV_PCM_RATE_xxx flag
0536  * or 0 for an unknown rate bit.
0537  */
0538 unsigned int snd_pcm_rate_bit_to_rate(unsigned int rate_bit)
0539 {
0540     unsigned int i;
0541 
0542     for (i = 0; i < snd_pcm_known_rates.count; i++)
0543         if ((1u << i) == rate_bit)
0544             return snd_pcm_known_rates.list[i];
0545     return 0;
0546 }
0547 EXPORT_SYMBOL(snd_pcm_rate_bit_to_rate);
0548 
0549 static unsigned int snd_pcm_rate_mask_sanitize(unsigned int rates)
0550 {
0551     if (rates & SNDRV_PCM_RATE_CONTINUOUS)
0552         return SNDRV_PCM_RATE_CONTINUOUS;
0553     else if (rates & SNDRV_PCM_RATE_KNOT)
0554         return SNDRV_PCM_RATE_KNOT;
0555     return rates;
0556 }
0557 
0558 /**
0559  * snd_pcm_rate_mask_intersect - computes the intersection between two rate masks
0560  * @rates_a: The first rate mask
0561  * @rates_b: The second rate mask
0562  *
0563  * This function computes the rates that are supported by both rate masks passed
0564  * to the function. It will take care of the special handling of
0565  * SNDRV_PCM_RATE_CONTINUOUS and SNDRV_PCM_RATE_KNOT.
0566  *
0567  * Return: A rate mask containing the rates that are supported by both rates_a
0568  * and rates_b.
0569  */
0570 unsigned int snd_pcm_rate_mask_intersect(unsigned int rates_a,
0571     unsigned int rates_b)
0572 {
0573     rates_a = snd_pcm_rate_mask_sanitize(rates_a);
0574     rates_b = snd_pcm_rate_mask_sanitize(rates_b);
0575 
0576     if (rates_a & SNDRV_PCM_RATE_CONTINUOUS)
0577         return rates_b;
0578     else if (rates_b & SNDRV_PCM_RATE_CONTINUOUS)
0579         return rates_a;
0580     else if (rates_a & SNDRV_PCM_RATE_KNOT)
0581         return rates_b;
0582     else if (rates_b & SNDRV_PCM_RATE_KNOT)
0583         return rates_a;
0584     return rates_a & rates_b;
0585 }
0586 EXPORT_SYMBOL_GPL(snd_pcm_rate_mask_intersect);
0587 
0588 /**
0589  * snd_pcm_rate_range_to_bits - converts rate range to SNDRV_PCM_RATE_xxx bit
0590  * @rate_min: the minimum sample rate
0591  * @rate_max: the maximum sample rate
0592  *
0593  * This function has an implicit assumption: the rates in the given range have
0594  * only the pre-defined rates like 44100 or 16000.
0595  *
0596  * Return: The SNDRV_PCM_RATE_xxx flag that corresponds to the given rate range,
0597  * or SNDRV_PCM_RATE_KNOT for an unknown range.
0598  */
0599 unsigned int snd_pcm_rate_range_to_bits(unsigned int rate_min,
0600     unsigned int rate_max)
0601 {
0602     unsigned int rates = 0;
0603     int i;
0604 
0605     for (i = 0; i < snd_pcm_known_rates.count; i++) {
0606         if (snd_pcm_known_rates.list[i] >= rate_min
0607             && snd_pcm_known_rates.list[i] <= rate_max)
0608             rates |= 1 << i;
0609     }
0610 
0611     if (!rates)
0612         rates = SNDRV_PCM_RATE_KNOT;
0613 
0614     return rates;
0615 }
0616 EXPORT_SYMBOL_GPL(snd_pcm_rate_range_to_bits);