linux/sound/core/compress_offload.c
<<
>>
Prefs
   1/*
   2 *  compress_core.c - compress offload core
   3 *
   4 *  Copyright (C) 2011 Intel Corporation
   5 *  Authors:    Vinod Koul <vinod.koul@linux.intel.com>
   6 *              Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
   7 *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   8 *
   9 *  This program is free software; you can redistribute it and/or modify
  10 *  it under the terms of the GNU General Public License as published by
  11 *  the Free Software Foundation; version 2 of the License.
  12 *
  13 *  This program is distributed in the hope that it will be useful, but
  14 *  WITHOUT ANY WARRANTY; without even the implied warranty of
  15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16 *  General Public License for more details.
  17 *
  18 *  You should have received a copy of the GNU General Public License along
  19 *  with this program; if not, write to the Free Software Foundation, Inc.,
  20 *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  21 *
  22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  23 *
  24 */
  25#define FORMAT(fmt) "%s: %d: " fmt, __func__, __LINE__
  26#define pr_fmt(fmt) KBUILD_MODNAME ": " FORMAT(fmt)
  27
  28#include <linux/file.h>
  29#include <linux/fs.h>
  30#include <linux/list.h>
  31#include <linux/mm.h>
  32#include <linux/mutex.h>
  33#include <linux/poll.h>
  34#include <linux/slab.h>
  35#include <linux/sched.h>
  36#include <linux/uio.h>
  37#include <linux/uaccess.h>
  38#include <linux/module.h>
  39#include <sound/core.h>
  40#include <sound/initval.h>
  41#include <sound/compress_params.h>
  42#include <sound/compress_offload.h>
  43#include <sound/compress_driver.h>
  44
  45/* TODO:
  46 * - add substream support for multiple devices in case of
  47 *      SND_DYNAMIC_MINORS is not used
  48 * - Multiple node representation
  49 *      driver should be able to register multiple nodes
  50 */
  51
  52static DEFINE_MUTEX(device_mutex);
  53
  54struct snd_compr_file {
  55        unsigned long caps;
  56        struct snd_compr_stream stream;
  57};
  58
  59/*
  60 * a note on stream states used:
  61 * we use follwing states in the compressed core
  62 * SNDRV_PCM_STATE_OPEN: When stream has been opened.
  63 * SNDRV_PCM_STATE_SETUP: When stream has been initialized. This is done by
  64 *      calling SNDRV_COMPRESS_SET_PARAMS. running streams will come to this
  65 *      state at stop by calling SNDRV_COMPRESS_STOP, or at end of drain.
  66 * SNDRV_PCM_STATE_RUNNING: When stream has been started and is
  67 *      decoding/encoding and rendering/capturing data.
  68 * SNDRV_PCM_STATE_DRAINING: When stream is draining current data. This is done
  69 *      by calling SNDRV_COMPRESS_DRAIN.
  70 * SNDRV_PCM_STATE_PAUSED: When stream is paused. This is done by calling
  71 *      SNDRV_COMPRESS_PAUSE. It can be stopped or resumed by calling
  72 *      SNDRV_COMPRESS_STOP or SNDRV_COMPRESS_RESUME respectively.
  73 */
  74static int snd_compr_open(struct inode *inode, struct file *f)
  75{
  76        struct snd_compr *compr;
  77        struct snd_compr_file *data;
  78        struct snd_compr_runtime *runtime;
  79        enum snd_compr_direction dirn;
  80        int maj = imajor(inode);
  81        int ret;
  82
  83        if ((f->f_flags & O_ACCMODE) == O_WRONLY)
  84                dirn = SND_COMPRESS_PLAYBACK;
  85        else if ((f->f_flags & O_ACCMODE) == O_RDONLY)
  86                dirn = SND_COMPRESS_CAPTURE;
  87        else
  88                return -EINVAL;
  89
  90        if (maj == snd_major)
  91                compr = snd_lookup_minor_data(iminor(inode),
  92                                        SNDRV_DEVICE_TYPE_COMPRESS);
  93        else
  94                return -EBADFD;
  95
  96        if (compr == NULL) {
  97                pr_err("no device data!!!\n");
  98                return -ENODEV;
  99        }
 100
 101        if (dirn != compr->direction) {
 102                pr_err("this device doesn't support this direction\n");
 103                snd_card_unref(compr->card);
 104                return -EINVAL;
 105        }
 106
 107        data = kzalloc(sizeof(*data), GFP_KERNEL);
 108        if (!data) {
 109                snd_card_unref(compr->card);
 110                return -ENOMEM;
 111        }
 112        data->stream.ops = compr->ops;
 113        data->stream.direction = dirn;
 114        data->stream.private_data = compr->private_data;
 115        data->stream.device = compr;
 116        runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
 117        if (!runtime) {
 118                kfree(data);
 119                snd_card_unref(compr->card);
 120                return -ENOMEM;
 121        }
 122        runtime->state = SNDRV_PCM_STATE_OPEN;
 123        init_waitqueue_head(&runtime->sleep);
 124        data->stream.runtime = runtime;
 125        f->private_data = (void *)data;
 126        mutex_lock(&compr->lock);
 127        ret = compr->ops->open(&data->stream);
 128        mutex_unlock(&compr->lock);
 129        if (ret) {
 130                kfree(runtime);
 131                kfree(data);
 132        }
 133        snd_card_unref(compr->card);
 134        return 0;
 135}
 136
 137static int snd_compr_free(struct inode *inode, struct file *f)
 138{
 139        struct snd_compr_file *data = f->private_data;
 140        data->stream.ops->free(&data->stream);
 141        kfree(data->stream.runtime->buffer);
 142        kfree(data->stream.runtime);
 143        kfree(data);
 144        return 0;
 145}
 146
 147static void snd_compr_update_tstamp(struct snd_compr_stream *stream,
 148                struct snd_compr_tstamp *tstamp)
 149{
 150        if (!stream->ops->pointer)
 151                return;
 152        stream->ops->pointer(stream, tstamp);
 153        pr_debug("dsp consumed till %d total %d bytes\n",
 154                tstamp->byte_offset, tstamp->copied_total);
 155        stream->runtime->hw_pointer = tstamp->byte_offset;
 156        stream->runtime->total_bytes_transferred = tstamp->copied_total;
 157}
 158
 159static size_t snd_compr_calc_avail(struct snd_compr_stream *stream,
 160                struct snd_compr_avail *avail)
 161{
 162        long avail_calc; /*this needs to be signed variable */
 163
 164        snd_compr_update_tstamp(stream, &avail->tstamp);
 165
 166        /* FIXME: This needs to be different for capture stream,
 167           available is # of compressed data, for playback it's
 168           remainder of buffer */
 169
 170        if (stream->runtime->total_bytes_available == 0 &&
 171                        stream->runtime->state == SNDRV_PCM_STATE_SETUP) {
 172                pr_debug("detected init and someone forgot to do a write\n");
 173                return stream->runtime->buffer_size;
 174        }
 175        pr_debug("app wrote %lld, DSP consumed %lld\n",
 176                        stream->runtime->total_bytes_available,
 177                        stream->runtime->total_bytes_transferred);
 178        if (stream->runtime->total_bytes_available ==
 179                                stream->runtime->total_bytes_transferred) {
 180                pr_debug("both pointers are same, returning full avail\n");
 181                return stream->runtime->buffer_size;
 182        }
 183
 184        /* FIXME: this routine isn't consistent, in one test we use
 185         * cumulative values and in the other byte offsets. Do we
 186         * really need the byte offsets if the cumulative values have
 187         * been updated? In the PCM interface app_ptr and hw_ptr are
 188         * already cumulative */
 189
 190        avail_calc = stream->runtime->buffer_size -
 191                (stream->runtime->app_pointer - stream->runtime->hw_pointer);
 192        pr_debug("calc avail as %ld, app_ptr %lld, hw+ptr %lld\n", avail_calc,
 193                        stream->runtime->app_pointer,
 194                        stream->runtime->hw_pointer);
 195        if (avail_calc >= stream->runtime->buffer_size)
 196                avail_calc -= stream->runtime->buffer_size;
 197        pr_debug("ret avail as %ld\n", avail_calc);
 198        avail->avail = avail_calc;
 199        return avail_calc;
 200}
 201
 202static inline size_t snd_compr_get_avail(struct snd_compr_stream *stream)
 203{
 204        struct snd_compr_avail avail;
 205
 206        return snd_compr_calc_avail(stream, &avail);
 207}
 208
 209static int
 210snd_compr_ioctl_avail(struct snd_compr_stream *stream, unsigned long arg)
 211{
 212        struct snd_compr_avail ioctl_avail;
 213        size_t avail;
 214
 215        avail = snd_compr_calc_avail(stream, &ioctl_avail);
 216        ioctl_avail.avail = avail;
 217
 218        if (copy_to_user((__u64 __user *)arg,
 219                                &ioctl_avail, sizeof(ioctl_avail)))
 220                return -EFAULT;
 221        return 0;
 222}
 223
 224static int snd_compr_write_data(struct snd_compr_stream *stream,
 225               const char __user *buf, size_t count)
 226{
 227        void *dstn;
 228        size_t copy;
 229        struct snd_compr_runtime *runtime = stream->runtime;
 230
 231        dstn = runtime->buffer + runtime->app_pointer;
 232        pr_debug("copying %ld at %lld\n",
 233                        (unsigned long)count, runtime->app_pointer);
 234        if (count < runtime->buffer_size - runtime->app_pointer) {
 235                if (copy_from_user(dstn, buf, count))
 236                        return -EFAULT;
 237                runtime->app_pointer += count;
 238        } else {
 239                copy = runtime->buffer_size - runtime->app_pointer;
 240                if (copy_from_user(dstn, buf, copy))
 241                        return -EFAULT;
 242                if (copy_from_user(runtime->buffer, buf + copy, count - copy))
 243                        return -EFAULT;
 244                runtime->app_pointer = count - copy;
 245        }
 246        /* if DSP cares, let it know data has been written */
 247        if (stream->ops->ack)
 248                stream->ops->ack(stream, count);
 249        return count;
 250}
 251
 252static ssize_t snd_compr_write(struct file *f, const char __user *buf,
 253                size_t count, loff_t *offset)
 254{
 2f="+code=loff_"+code=snd255"> 2f="+code=loff_"j="L          2f="+code=loff_"50" = arg,
 2f="+code=loff_"    }
stream="+code=snd_compr_avail" class="sref">snd_compr_avail ioctl_avail;
tstamp-&g2; = ioctl_avail;
sn26ass="comment">           remainde/coBUG_Ohref="sound/coree/coBUG_Oh" namode=tstamp" class="sref">stream. 253                copy, count - snd_c2mpr_a2ailcount -         struct  140        data->count - avail_calc; /*this needs to begt;private_datastream->private_data;
stream);
sn2_compr_update_tstamp2 co"line/a> ef="wed whc#L runnsferormpress_offsteupL245" id="L245" class="line" name="L245"> 245   a href="+2ode=avail" class="sref">2vail<2a>->runtime->total_bytes_transferreref="sound/core/compress_offlo!d.c#L171" id="L171" class="line" name="L171"> 171                         170        if (->runtime->total_bytes_available,
 171                RUNNING < ru
open(&data-&sref">stream->private_data;
stream);
2copy, count -  1682span 2lass="comment"ound/core/compress_offload.c#L249" id="L249ode=strea2" class="sref">streamcoun->bufferavail;
 201
data-&sref">stream-> 172      2     27 href="+code=pointer" class="sref">pointer(stream 174ze" class="sref">b="+code=pr_debug" class="sref"/compress_offload.c#L206" id="L206" class="line" name="L206"> 206    >        2       return coe" nan ce how much.c#Lcano"line/a hr class="comment">           available is # of compressed2 class="s2ef">runtime->stream->avail;
 225               const chd="L175" 2lass="line" name="L175">2175        bufferavail;
ack(stream, 27f="+code=ioctl_avail" class="sref">ioctl_avail->runtime->ops->runtime-&gode=ioctl_avail" class="sref">ioctl_availst2eam->ops->runtime-&d/core/compress_offload.c#L248" id="L248" class="line" name="L24href="sound/core/compress_offload.c#L240" /compress_offload.c#L206" id="L206" class="line" name="L206"> 206     href="+c2de=stream" class="sref">2tream2/a>-> 206     de=strea2name="L180"> 180    2     2      222}
 206     >->ioctl_avail< class="s2ef">runtime->flass="sref">runtime->total_bytes_transferred);
EFAULT;
->ioctl_avail;
 213    href="sou2d/core/compress_offload.2#L18428ze_t co"hi6           available is # of compressed2n>
           available is # of compressed2a href="s2und/core/compress_offloa2.c#L128d.c#L246" id="L246" class="line" name="L246"> 246        "sref">total_bytes_available == 0 &&
 171                        streamstream->total_bytes_available == 0 &&
ioctl_avail;
->pointer(stream 188ava2l_calc = coun"sref">ap2_pointer - streamopen(&data-&sref">stream->private_data;
stream);
pr_debug(&quoef="+code=ack" class="ef=vstream->ioctl_avail;
 204        struct avail_2alc >=  144        re2sref">ava2l_calc -= data-&sine" name="L250"> 250}
 251
 252static ssize_t snd_compr_write(stru97   2    __user *buf,
 253                 198        2a hre298                struct avail_calc;
&quoef="+cosref">copy, ioctl_avail;
 199        r3turn 3a hrefound/core/compress_offload.c#L249" id="L243c;
count - s3d_comp222" id="L222" class="line" name="L2mmapan>
 251
 251
}
 253                snd_comp3_stre30> count,3_offload.3#L204" id="L204" class="3ine" 305string">&quoef="+cosref">copy, ioctl_avail;
 >= ioctl_avail3ref="+cod3=stream" class="sref">st3eam, &am200" id="L200" class="line" name="L200"> 200}
 251
 202static inline size_t                 struct            remainder of buffer */
size_t pPOLLOUef="+code=count"POLLOUe   pPOLLWRNORMf="+code=count"POLLWRNORM=ioctl_avail" class="sref">ioctl_avail;
stream3/a>, 3nsigned long <"sre206" class="line" name="L206"> 206   3212" id="3212" class="line" name="3212">31  pr_POLLIhref="sound/corePOLLIh   pPOLLRDNORMf="+code=count"POLLRDNORM=ioctl_avail" class="sref">ioctl_avail;
31me="L204"> 204        struct  251
size_t  216      3 a3ail = offset)
 254{
 2f="+code=loff_"+code=snd255"> 2f="+code=loff3code=copy3to_user" class="sref">co3y_to_31" id="L228" class="line" name="L228"> 228>,
 2f="+code=loff3ne" name=3L219"> 219          3     32lass="comment">         * al="+code=snd_compr_avail" class="sref">snd_compr_avail ioctl_avail;
io3tl_avail)))
 3              return -count -            remainde/coBUG_Ohref="sound/coree/coBUG_Oh" namode=tstamp" class="sref">stream. 253                copy, count - sn3_compr_write_d219"
 140        data->count - _32>->inline  253                s32ream->copy, count -  2263/a>{
32, &avai3a href="s3und/core/compress_offloa3.c#L238" id="L228" csref">streamhref="+code=private_data" class="sref">private_datastream->private_data;
stream);
           remainder of buffer */
total_bytes_available == 0 &&
io3=stream" class="sref">st3eam(total_bytes_available == 0 &&
stream->copy, count -  232       goto 22" class="lineou#L253" id="L253" ucode=stream" class="sref">stream, private_datastream->total_bytes_available == 0 &&

stream, 3opy_f334" class="line" name="L144"> 144        re3sref">cou3t))
streaml" class="sref">avail;
 201
data-&sref">stream-> 237                pointer(streamb="+code=pr_debug" class="sref"/compress_offload.c#L206" id="L206" class="line" name="L206"> 206   3r" class=3sref">app_pointer +=3coeheck">  wee valointleasts_offfrag"srep" afill ="comment">           available is # of compressed3runtime->total_bytes_available == 0 &&
stream 171                DRAININGom_u:ref="+code=stream" class="sref">stream))
co after drain=iufass=letbyte offsets if the cumulative values have3r, 3uf id="L185" class="line" name="LLLLLLLLL* drainsferd_offso=sdeo3r        3y))
           available is # of compressed3rtime3ss="sref">runtime-&g3;data-&sref">stream->co3ntbuffer
total_bytes_available == 0 &&
 171                        cou3href="sound/core/compres3_offl34ream-> 237 247    3   if ( 171                RUNNING:ref="+code=stream" class="sref">streamop3->streamcount3;
->stream 249(stream->avail;
buffer_size)
size_t data-&sref">stream->fil3 *s3ze_t<35=count" classdefault:ref="+code=stream" class="sref">stream3code=loff_t" class="sref3>loff35f="+code=app_c#L241" >           remainder of buffer */
size_t (pPOLLWRNORMf="+code=count"POLLWRNORM=ioca|" class="sref">pPOLLERRf="+code=count"POLLERR    206   3tstamp" c3ass="sref">tstamp-&g3;pPOLLRDNORMf="+code=count"POLLRDNORM=ioca|" class="sref">pPOLLERRf="+code=count"POLLERR   ->sn36ass="comment"ound/core/compress_offload.c#L249" id="L243c#L160" i3="L160" class="line" nam3="L1636    <22" class="lineou#L253" id="L253" ucode=:ref="+code=stream" class="sref">streamsnd_c3mpr_a36ream" class="sref">streamopen(&data-&sref">stream->private_data;
stream);
&quoef="+code=ack" class="ef=vstream->ioctl_avail;
avail_calc; sn3_compr_update_tstamp3 204        struct 3vail<36"sref200" id="L207" class="line" name="L207"> 207}
<3/a>
ops->" clac#L209" id="L209" class="line" name="L209"> 209static int
 210snd_compr_ioctl_av3
stream3ioctl_avail;
 1683span 3lass="comment"c#L209" id="L209" class="line" nca">ops->" cle=__user" class="a">ops->" cltl_avail" class="sref">ioctl_avail;
streamcou3->inline ops->ops->" clctl_avail" class="sref">snd_compr_ioctl_av3="line" n3me="L172"> 172      3     37  copy, ioctl_avail;
        3       return  213   3 class="s3ef">runtime->ops->ops->" cl> 214
ops->" clress_offload.c#L128" id="L128" class=eam3175->->snd_compr_ioctl_av3=a>
37ream->stream, ->avail;

ops->" cl> *)ops->" clr=ne" name="L253"> 253                st3eam->copy, count - 3tream3/a>-&g22" class="lineou#L253" id="L253" ucode=:ref="+code=stream" class="sref">stream 180    3     38ore/compress_offload22" class="lineef=vstream->ioctl_avail;
EFAULT;
runtime-> 221        re3a href="s3und/core/compress_offloa3.c#L138d.c#L222" id="Lass="line" name="L221"> 221        re3aclass="s3d/core/compress_offload.3#L18438ze_t<22" class="line" name="L2omprclincrca">ops->" clac#L209" id="L209" class="line" name="L209"> 209static int
 210snd_compr_ioctl_av3n>
buf->ioctl_avail;
offclincrca">ops->" clund/core/compress"a">ops->" cltl_avail" class="sref">ioctl_avail;
 188   ode=tstamp" classref">inline ops->ops->" clctl_avail" class="sref">snd_compr_ioctl_av3sref">ava3l_calc = copy, ioctl_avail;
ap3_pointer - count - pr_debug(ops->" cl;
->ops->" cl)am22" class="lineGFP_KERNELops->ops->" cl)ss_offload.c#L128" id="L128" class=eamcopy, ioctl_avail;

 >=  144        re3sref">ava3l_calc -= streamef=vstream->;
ops->ops->" cld/core/compress_offload.c#L248" id="L248" class="line" name="L248a">ops->" clress_offload.c#L128" id="L128" class=eam   3    ->->snd_compr_ioctl_av3line" nam3="L198"> 198        3a hre39am->stream, avail_calc;
           remaindlass="sref">avail;

ops->" cl> *)ops->" cl)=ne" name="L253"> 253                 199        r4turn 40    copy, count - ;
count - s4d_comp22" class="lineou#L253" id="L253" ucode=:ref="+code=stream" class="sref">streamsnd_comp4_stre40"comment">/*this needs to bekfrerivate_data;kfrer" cld/core/compress_8a">ops->" clress_offload.c#L128" id="L128" class=eam&quoef="+co22" class="lineef=vstream->ioctl_avail;
 >= ioctl_avail4ref="+cod4=stream" class="sref">st4eam, &amrde=copy" class="sref">corevisit this with " napcm_sreef="csnd2xxxL*"comment">           available is # of compressed4);
222" id="L222" class="line" name="L2ef="csnd2nd/core/compress_offl" name="L2ef="csnd2nd/cor" clac#L209" id="L209" class="line" name="L209"> 209static int
           available is # of compressed4 href="so4nd/core/compress_offload4c#L2041ass="comment"> = offparam>ops->ops->="sone" name="L253"> 253                (st4uct bufstream4/a>, 4nsigned long <"+code=pr="L222" class="linend/core {
ioctl_avail;
41  ioctl_avail;
 213   4    41compr_write_d219"
;
;
ops->" cltl_avail" class="sref">ioctl_avail;
->runtime->ops->runtime-&g href="+code=stream" class="sref">stream 216      4 ->;
ioctl_avail;
a41  if (coef=memment">           available is # of compressed4code=copy4to_user" class="sref">co4y_to_41" id= id="L185" class="line" name="LLLLLLLLL* s="cdata from ilaba>mment">           available is # of compressed4ne" name=4L219"> 219          4     42lass= id="L185" class="line" name="LLLLLLLLL*"comment">           available is # of compressed4"sref">io4tl_avail)))
stream 4              return -;
-> 253                copy, ioctl_avail;
sn4_compr_write_dound/core/compress_offload.c#L249" id="L244ar _42>->runtime->;
ioctl_avail;
s42eam" class="sref">streamclass="sref">runtime->ops->" cl;
ops->" cltl_avail" class="sref">ioctl_avail;
 2264/a>{
42 href="sound/core/compress_oclass="sref">runtime->;
ioctl_avail;
streamruntime->ioctl_avail;
snd_compr_runtime *4a hre430string">&quoef="+co.c#L220" id="L220" class="line" name="L220"4asref">io4=stream" class="sref">st4eam->count - ops->ops->="sone" name="L253"> 253                count,4ntime4>cofirsntlet'soeheck"s="cr classparameter'so*"comment">           available is # of compressed4 r 4opy_f43>->ops->="socode=ack" class="srend/core/compress_offlnd/cor" cl.ack" class="srefrag"sree {
cou4t))
streamops->="socode=ack" class="srend/core/compress_offlnd/cor" cl.ack" class="srefrag"sre>ops->" cl s="spress_offload.c#SIZE_MAXops->;
 253                copy, ->ioctl_avail;
app_pointer +=4conow clincsparameterso*"comment">           available is # of compressed4"+code=co4y_from_user" class="sref4>copy4from_user(ef="+code=runtime" param>ops->="socode=ack" class="sreclincss="sref">runtimeinc" cl.ack" class="srei/a>}
ops->="socode=ack" class="sreclincss="sref">runtimeinc" cl.ack" class="srei/a>}
-> 253                ))
copy, ->ioctl_avail;
, 441" class="line" name="L221"> 221        re4r        4y))
ops->="socode=ack" class="sreclincss="sref">runtimeinc" cl.ack" class="srech_inss="sref">runtimh_incodeoad.0a||a>;
runtimeinc" cl.ack" class="sremh_ou#L253" id="L253"mh_ou#codeoad.0ne" name="L253"> 253                4ss="sref">runtime-&g4;copy, ->ioctl_avail;
co4nt 144        re4href">cou4href="sound/core/compres4_offl44d.c#L246" id="L24!r>;
runtimeinc" cl.ack" class="sresas=le_rf="sound/core/compras=le_rf="codeos215".c#L171" id="L171" class="Rne" 8000_1920>avail_calcgt;acodenne" name="L253"> 253                 247    44  if (copy, ->ioctl_avail;
op44f="sound/core/compress_offload.c#L188" id="L184code=coun4" class="sref">count4;
&quoef="+co.c#L220" id="L220" class="line" name="L220"4c+code=co4ine" name="L249"> 249count - fil45_comp222" id="Lf">count - s4ze_t<45=coun id="L209" class="line" namprparam>ops-> 209static int
 210snd_compr_ioctl_av4ctime4code=loff_t" class="sref4>loff45f="+chref="+code=count" class="sref">count,4"j="L    4     2f="+code=loff_"50"4= (ops->ops->="soc#L220" id="L220" class="line" name="L220"4cref">cou4al_bytes_transferred" cl4ss="s45d.c#L246" id=""L222" class="lineef=vstream->ioctl_avail;
tstamp-&g4;avai4"" class=4href="sound/core/compres4_offl45am->           remainder of buffer */
total_bytes_available == 0 &&
streamsn46ass="comment"> = ccomment">           available is # of compressed4c#L160" i4="L160" class="line" nam4="L1646    <2id="L185" class="line" name="LLLLLLLLL* we should ef="wsparameterme">nge only wheno           available is # of compressed4c;
snd_c4mpr_a46ream"2id="L185" class="line" name="LLLLLLLLL* ope" nanot="" othermeasescomment">           available is # of compressed4ct  id="L185" class="line" name="LLLLLLLLL*"comment">           available is # of compressed4nref="+co4ef">avail_calc; ops->="so;
->ops->="sonam22" class="lineGFP_KERNELops->sn4_compr_update_tstamp4   ode=tstamp" clasparam>ops->="sone" name="L253"> 253                4vail<46m_user(copy, ioctl_avail;

           remainda3frommme" cla219"

ops->="son)a href="+code=stream" class="sref">streamcopy, count - 4->stream,  1684span 47ass="comment"> = streamcou4->ops->="sonstream" class="sref">stream,  172      4     47  ->snd_compr_ioctl_av4>        4       return stream, sn4ef">runtime-> 204        struct 4175buffer->ops->="sonstream" class="sref">stream, 47ream->->streamcopy, ioctl_avail;
st4eam->stream, 4tream48ass="comment"> =  180    4     48 return cou4 >runtime->ops->" clad/core/compress_offload.c#L210" id="L210" class=d/core/compressparam>ops->="sonstream" class="sref">stream, runtime->->snd_compr_ioctl_av4a href="s4und/core/compress_offloa4.c#L148ress_offload.c#L243"         goto 22" class="lineou#L253" id="L253" ucode=stream" class="sref">stream, total_bytes_available == 0 &&
 171                        
streamcopy, stream 188         * alkfrerivate_data;kfrer" cld/core/compress_param>ops->="sonstream" class="sref">stream, ava4l_calc = ioctl_avail;
ap4_pointer - EFAULT;
pr_debug( 221        re4         4               221        re4 class="s4                209static int
 210snd_compr_ioctl_av4">
 >= bufava4l_calc -= runtis="lininc="sound/core/compressparam>ops->="soc#L220" id="L220" class="line" name="L220"497   4    ->ioctl_avail;
 198        4a hre49f="sound/core/compress_offload.c#L188" id="L185ass="sref5>avail_calc;
   ode=tstamp" classref">inline ops->snd_compr_ioctl_av5ine" name5"L199"> 199        r5turn 50    copy, count - ;
count - s50 href="+code=pointer" class=param>ops->="so;
->ops->="sonam22" class="lineGFP_KERNELops->snd_comp5_stre50=count" class="srode=tstamp" clasparam>ops->="sone" name="L253"> 253                copy, ioctl_avail;
 >= ->runtime->ops->ops->="sonstream" class="sref">stream, ->snd_compr_ioctl_av5ref="+cod5=stream" class="sref">st5eamstream, ->           remaindlass="sref">avail;

ops->="so, c)ops->="son)atream" class="sref">stream,  = copy, count - (st5uct cou5"+code=st5eam" class="sref">stream5/a>, 5nsigne22" class="lineou#L253" id="L253" ucode=:ref="+code=stream" class="sref">stream51 href="+code=pointer" class=kfrerivate_data;kfrer" cld/core/compress_param>ops->="sonstream" class="sref">stream, ioctl_avail;
51comprEFAULT" class="sref">EFAULT;
 144        re5i7ffload.5me="L216"> 216      5  221        re52ef="+cod5f="+code=avail" class="s5ef">a51  if  id="L209" class="line" nt222mp209"> 209static int
 209static int
 210snd_compr_ioctl_av5code=copy5to_user" class="sref">co5y_to_51" id=a> *buf 219          5     52ass="comment"c#L209" id="L209" class="line" nt222mp209"> 209static int
 209stt222mp" cltl_avail" class="sref">ioctl_avail;
io5tl_avail)))
cou5 220 5              return - 209static int
 209stt222mp" clnstream" class="sref">stream, avail;
 209static int

stream,  209stt222mp" cl> *) 209stt222mp" cln) ?Lsref">copy, sn52comprEFAULT" class="sref">EFAULT;
_524" class="line" name="L144"> 144        re5d7ffload.5="+code=size_t" class="s5ef">s52ream<222" id="L222" class="line" name="L2paore209"> 209static int
 209static int
snd_compr_ioctl_av5def="+cod5="line" name="L226"> 2265/a>{
52  if href="+code=stream" class="sref">streamioctl_avail;
snd_compr_runtime *5a hre530stril_avail" class="sref">ioctl_avail;
io5=stream" class="sref">st5eam(ef="+code=runtime" er of buffer */
total_bytes_available == 0 &&
 171                RUNNINGclasctl_avail" class="sref">snd_compr_ioctl_av5ss="sref"5runtime->copy, ->runtime->ops->" clad/core/compress_offload.c#L210" id="L210" class=d/core/compress          TRIGGER_PAUSE_PUSH"L171"> 171          TRIGGER_PAUSE_PUSH" clnstream" class="sref">stream, ->snd_compr_ioctl_av5ntime5>total_bytes_available == 0 &&
5opy_f53>->ioctl_avail;
cou5t))
EFAULT;
                avai5a href="s5sref">app_pointer +=5222" id="L222" class="line" name="L2lasu">total_bytes_ava" name="L2lasu">" clac#L209" id="L209" class="line" name="L209"> 209static int
snd_compr_ioctl_av5runtime->streamioctl_avail;
))
count - , 543count" class="sr22" class="lineer of buffer */
total_bytes_available == 0 &&
snd_compr_ioctl_av5r        5y))
copy, 5ss="sref">runtime-&g5;->runtime->ops->" clad/core/compress_offload.c#L210" id="L210" class=d/core/compress          TRIGGER_PAUSE_RELEASE"L171"> 171          TRIGGER_PAUSE_RELEASE" clnstream" class="sref">stream, co5nt->->snd_compr_ioctl_av5href">cou5href="sound/core/compres5_offl54ream->total_bytes_available == 0 &&
 171                RUNNINGclasstream" class="sref">stream,  247    54  if (ioctl_avail;
op54f="soEFAULT" class="sref">EFAULT;
count5;
ioctl_avail;
 249 209static int
snd_compr_ioctl_av5t;
streamfil553count" class="L222" class="lineef=vstream->ioctl_avail;
s5ze_t<55id="L213" class="line" name="L213"> 213   5ctime5code=loff_t" class="sref5>loff555->total_bytes_available == 0 &&
snd_compr_ioctl_av5tr copy, cou5al_bytes_transferred" cl5ss="s55eam" class="sref">streamef=vstream->;
ops->" clad/core/compress_offload.c#L210" id="L210" class=d/core/compress          TRIGGER_linRef="+code=count"          TRIGGER_linRe" clnstream" class="sref">stream, tstamp-&g5;->->snd_compr_ioctl_av5"" class=5href="sound/core/compres5_offl55am->total_bytes_available == 0 &&
 171                RUNNINGclasstream" class="sref">stream, sn560string">&quoef="+co22" class="lineef=vstream->ioctl_avail;
snd_c5mpr_a56ilcount -  209static int
 209static int
snd_compr_ioctl_av5nref="+co5ef">avail_calc;  count,5"sref">sn5_compr_update_tstamp5ioctl_avail;
5vail<564" class="line" name="L144"> 144        re5/a>

total_bytes_available == 0 &&
total_bytes_available == 0 &&
 171                        snd_compr_ioctl_av5n" class=5playback it's5->copy,  1685span 57lass="comment">         * alef=vstream->;
ops->" clad/core/compress_offload.c#L210" id="L210" class=d/core/compress          TRIGGER_liO="L171"> 171          TRIGGER_liO=" clnstream" class="sref">stream, stream(ef="ode=tstamp" clasef=vstream->streamtotal_bytes_available == 0 &&
 171                         172      5     57   209stwake_up" claL215" id="L215" claser of buffer */
total_bytes_available == 0 &&
 209staleep" clnstream" class="sref">stream, 
total_bytes_available == 0 &&
sn5ef">runtime->total_bytes_available == 0 &&
5175buffer
total_bytes_available == 0 &&
total_bytes_avatotal_bytes_availabl>offloa..c#L220" id="L220" class="line" name="L220"5 a>
57ream->buffer
total_bytes_available == 0 &&
}
 = st5eam->ioctl_avail;
5tream58ass="ound/core/compress_offload.c#L249" id="L245 de=strea5name="L180"> 180    5     58 return cou5 >runti" name="L 209static int
snd_compr_ioctl_av5 class="s5ef">runtime->streamioctl_avail;
 204        struct ->
total_bytes_available == 0 &&
total_bytes_available == 0 &&
 171                        snd_compr_ioctl_av5n href="+5ound/core/compress_offlo5d.c#L58  if (copy, stream->;
ops->" clad/core/compress_offload.c#L210" id="L210" class=d/core/compress   _COMPR TRIGGER_DRAIhref="sound/core1" _COMPR TRIGGER_DRAIh" clnstream" class="sref">stream,  188   ode=tstamp" clasef=vstream->streamava5l_calc = total_bytes_available == 0 &&
 171                DRAIhING   ap5_pointer -  209stwake_up" claL215" id="L215" claser of buffer */
total_bytes_available == 0 &&
 209staleep" clnstream" class="sref">stream, pr_debug(ioctl_avail;
EFAULT;

 >=  144        re5sref">ava5l_calc -=  210->total_bytes_avafil>="sound/core/compressftotal_bytes_avafclass="line" na="L222" class="linecm/a>}
 210snd_compr_ioctl_av597   5    stream 198        5a hre59" id="L228" cc#L209" id="L209" class="line" nfil>total_bytes_avas="line" nfil>="sound/core/compressdatatotal_bytes_avadataoffloa.c#L171" id="L17ftotal_bytes_avafclas== 0 &&
ioctl_avail;
avail_calc;
 209static int
ioctl_avail;
_calc = copy, ioctl_avail;
pointer - count - s603count" class="sr22" class="lineeticBUG_Ohref="sound/coreeticBUG_Oh" claode=tstamp" clasdatatotal_bytes_avadataoffl)atream" class="sref">stream, snd_comp6_stre60ress_offload.c#L243" _debug"sref">copy, count - ioctl_avail;
 >= stream, ->copy, count - copy, mutex_lockf="+code=count"mutex_lock" claL215" id="L215" claser of buffer */
stream, ->}
streamstream(st6uct " clad/core/compress      COMPRESS_VERSIOhref="sound/core      COMPRESS_VERSIOhclas tream" class="sref">stream, stream6/a>, 61ress_offload.c#L241"                 (e"L222" class="line17
copy, 61  stream61f="+code=app_c#L241" 22" class="lineef=vstream->ops->" clad/core/compress_offload.c#L210" id="L210" class=d/core/compress8" id="L218" class="line")c#L220" id="L220" class="line" name="L220"626ffload.6ode=snd_compr_calc_avail6 clas61         216      6 streama61  if (ops->" clad/core/compress_offload.c#L210" id="L210" class=d/core/compress8" id="L218" class="line")c#L220" id="L220" class="line" name="L220"62/a>);
co6y_to_61am-> 219          6     62ass="comment"ease" id="L209" clas1IOC_NRf="+code=count"_IOC_NR" clad/core/compress      COMPRESS_SET_PARAMSref="sound/core      COMPRESS_SET_PARAMSclas):ref="+code=stream" class="sref">streamio6tl_avail)))
 6              return -streamsn62f="+code=app_c#L241" b_626  171      COMPRESS_TSTAM=clas):ref="+code=stream" class="sref">streams62ream->buffer-> 209static int
 2266/a>{
62  if ();
->streamsnd_compr_runtime *6a hre63ass="comment"> =  210->io6=stream" class="sref">st6eam->->stream 210 209static int
->stream6opy_f63        buffer->total_bytes_ava" name="L2lasu">" clade=tstamp" clas_offload.c#L210" id="L210" clascc#L220" id="L220" class="line" name="L220"6s7ffload.6t))
                stream);
app_pointer +=6->-> =  171      COMPRESS_liO=clas):ref="+code=stream" class="sref">stream))
 209static int
64  ))
streamruntime-&g6;runti" name="Lco6ntcou6href="sound/core/compres6_offl64ream->EFAULT" class="sref">EFAULT;
 247    64  if (copy, mutex_unlockf="+code=count"mutex_unlock" claL215" id="L215" claser of buffer */
stream, op64am->ioctl_avail;
count6;
 249cou6t;
_oper2" onsream->_oper2" onsm22" class="line" name="L2fil>_op>ops->streamfil65  =ioc="Lcopy, THIS_MODULEops->stream, s6ze_t<65ress_offload.c#L243" .22" class="lineopenss="sref">runtiopen=ioc="L22" class="line" name="L2openss="sref">runti" name="L2openclas tream" class="sref">stream,  209streleare=ioc="Lstream, copy, " name="L2wri="sound/core/comp" name="L2wri="clas tream" class="sref">stream, cou6al_bytes_transferred" cl6ss="s65ream->stream, tstamp-&g6; 210->stream, -> 209stmmap=ioc="L22" class="line" name="L2mmap209"> 209st" name="L2mmapclas tream" class="sref">stream, sn66ass="comment"> = 22" class="line" name="L2poltream->stream, ioctl_avail;
;
snd_c6mpr_a66ilcount - =ioc=nd/core/compressdevic>total_bytes_avadevic>ref=atream" class="sref">stream, avail_calc;  count,6"sref">sn6_compr_update_tstamp6copy, ->ioctl_avail;
6vail<666 
< ioctl_avail;
cou6f="sound/core/compress_o6fload66d.c#L246" id=c#L209" id="L209" class="line" 
ioctl_avail;
avai6n" class=6playback it's6->           remaindeticBUG_Ohref="sound/coreeticBUG_Oh" claode=tstamp" clasdevic>total_bytes_avadevic>ref= || ode=tstamp" clasdevic>total_bytes_avadevic>ref="sound/core/compressdevic>2datatotal_bytes_avadevic>2dataref=aatream" class="sref">stream,  1686span 67ass="comment"> = copy, ioctl_avail;
stream(d/core/compressine" 
 210total_bytes_avadevic>ref="sound/core/compressdevic>2datatotal_bytes_avadevic>2dataref=tl_avail" class="sref">ioctl_avail;
;
count -  172      6     67 href="+code=pointer" class=spr="Lftotal_bytes_avaspr="Lf" clade=tstamp" clas_ofbuffer */
< "f="+cC%iD%i"}

total_bytes_avadevic>ref=atl_avail" class="sref">ioctl_avail;
"reg %s for devic> %s, direc" on %d\n"
< stream, sn6ef">runtime->(d/core/compressine" 
ioctl_avail;
6175ioment">/* regisLa> >ioctl_aed devic> */ioctl_avail;
cou6f="+code=stream" class="6ref">67eam" class="sref">streamef=ream->ldevic>total_bytes_avas="lregisLa>ldevic>" clad/core/compress      DEVICE_TYPE COMPRESSref="sound/core1"    DEVICE_TYPE COMPRESS }
stream, total_bytes_avadevic>ref=s=L215" id="L215" clas" name="L2fil>_op>ops->
< ioctl_avail;
st67am->           remaindef=ream->stream6tream68ass="comment"> = 
"s="lregisLa>ldevic> fail>d\n %d"->ioctl_avail;
 180    6     68    ioctl_avail;
;
runtime->ioctl_avail;
 213   6aclass="s6d/core/compress_offload.6#L18468comprEFAULT" class="sref">EFAULT;
 144        re6a href="s6und/core/compress_offloa6.c#L168ream<222" id="L222" class="line" name="Lode=dev2disconnec"
=ioc=nd/core/compressdevic>total_bytes_avadevic>ref=atream" class="sref">stream, streamioctl_avail;
 188ioctl_avail;
ava6l_calc =  210total_bytes_avadevic>ref="sound/core/compressdevic>2datatotal_bytes_avadevic>2dataref=tl_avail" class="sref">ioctl_avail;
ap6_pointer - ldevic>" clad/core/compressine" 
}
total_bytes_avadevic>ref=atl_avail" class="sref">ioctl_avail;
pr_debug(EFAULT;
 204        struct 
 >= ioment">/*ioctl_avail;
ava6l_calc -=  * " name="Lode=new: create new >ioctl_a devic>respansl_avail" class="sref">ioctl_avail;
ioment"> * @car/: lass= car/ po="La>ofspansl_avail" class="sref">ioctl_avail;
 198        6a hre69" id=dspanuffer */>ioment"> * @devic>: devic> numba>clspansl_avail" class="sref">ioctl_avail;
avail_calc;
 * @dirn: devic> direc" on, should be of type enum " name="L_direc" onrespansl_avail" class="sref">ioctl_avail;
_calc =  * @cioct: >ioctl_a devic> po="La>ofspansl_avail" class="sref">ioctl_avail;
pointer -  */ioctl_avail;
s703coun="L222" class="line" name="Lode=new
ioctl_avail;
->"L222" class="linedirntotal_bytes_avadirnref=, c#L209" id="L209" class="line" 
stream, stream >= _op>-> id="L209" clasf">ops->stream -=  210->ioctl_avail;
" cl="L210"> 210
ioctl_avail;
 198        7_offl70am-> 210ioctl_avail;
ioctl_avail;
(st7uct cou7"+code=st7eam" class="sref">stream7/a>, 71ress_offload. id="L209" clasine" 
}
 210}
ioctl_avail;
71 href="+code=pointer" class=ine" 
total_bytes_avadevic>ref=="L210"> 210total_bytes_avadevic>ref=tl_avail" class="sref">ioctl_avail;
 210ioctl_avail;
71f="+code=app_ef="+co22" class="line" nadevic>_new
_new" clad/core/compressiar/a>}
ops->ioctl_avail;
EFAULT;
 216      7 copy, ->ioctl_avail;
a71, &avai72/a>);
co7y_to_71amtotal_bytes_avas="lme="Lode=ad"ldevic>" clac#L209" id="L209" class="lcne" 
stream,  219          7     72ass="href="+code=stream" class="sref">streamio7tl_avail)))
(e"L222" class="lineef=ream->ioctl_avail;
 7              return -count - total_bytes_avadevic>ref="sound/core/compressiar/a>}
stream, copy, ->ioctl_avail;
sn72me="L204"> 204        struct _72        ioment">/* regisLa> the car/ */ioctl_avail;
s72eam" class="sref">streamef=ream->
" clade=tstamp" clasdevic>total_bytes_avadevic>ref="sound/core/compressiar/a>}
ioctl_avail;
 2267/a>{
72  if (           remaindef=ream->stream, ->ioctl_avail;
snd_compr_runtime *7a hre73ass="comment"ef="+co.c#L220" id="L220" class="line" name="L220"7asref">io7=stream" class="sref">st7eamcou7ss="sref"7runtime->->stream" cladspanuffer */"fail>d with %d\n"->ioctl_avail;
ioctl_avail;
 204        struct 7opy_f73     EFAULT" class="sref">EFAULT;
EFAULT;
stream, app_pointer +=7stream->total_bytes_avadevic>ref="sound/core/compressiar/a>}
ioctl_avail;
EFAULT;
))
count - 74  ioment">/**ioctl_avail;
))
 * " name="Lode=regisLa> - regisLa> >ioctl_aed devic>ioctl_avail;
runtime-&g7; *ioctl_avail;
co7ntioment"> * @devic>: >ioctl_aed devic> to;regisLa>" spansl_avail" class="sref">ioctl_avail;
ioment"> */ioctl_avail;
 247    74  if ="L222" class="line" name="Lode=regisLa>
stream, op74amstreamcount7;
"L222" class="lineef=vstream->ioctl_avail;
 249cou7t;
           remainddevic>total_bytes_avadevic>ref="sound/core/compresshref
ops->stream, fil75  copy, ->ioctl_avail;
s7ze_t<75id="L213" class="line" name="L213"> 213   7coffload.7code=loff_t" class="sref7>loff75f="+code=app_pointer" class="L2debu id="L218" classprldebu " cladspanuffer */"RegisLa>="g >ioctl_aed devic> %s\n"total_bytes_avadevic>ref="sound/core/compresshref
ioctl_avail;
->total_bytes_avadevic>ref="sound/core/compressf">ops->runtiopen=iocaatream" class="sref">stream, cou7al_bytes_transferred" cl7ss="s75ream->copy, ->ioctl_avail;
tstamp-&g7;           remaindeticBUG_Ohref="sound/coreeticBUG_Oh" claode=tstamp" clasdevic>total_bytes_avadevic>ref="sound/core/compressf">ops->;frer" claatream" class="sref">stream, ->copy, ->ioctl_avail;
sn76ass="comment">           remaindeticBUG_Ohref="sound/coreeticBUG_Oh" claode=tstamp" clasdevic>total_bytes_avadevic>ref="sound/core/compressf">ops->ops->" claatream" class="sref">stream, copy, ->ioctl_avail;
;
snd_c7mpr_a76ress_offload.>           remaindeticBUG_Ohref="sound/coreeticBUG_Oh" claode=tstamp" clasdevic>total_bytes_avadevic>ref="sound/core/compressf">ops->
stream, copy, ->ioctl_avail;
avail_calc;  213   7"sref">sn7_compr_update_tstamp7->total_bytes_avadevic>ref="sound/core/compresslockf="+code=count"lock" clnstream" class="sref">stream, 7vail<764" class="line" name="L144"> 144        re7aref">cou7f="sound/core/compress_o7fload76d.c#L246" id=dspanuffer */>ioment">/* regisLa> a >ioctl_aed car/ */ioctl_avail;
copy, mutex_lockf="+code=count"mutex_lock" claL215" id="L215" clasdevic>_mutextotal_bytes_avadevic>_mutex" clnstream" class="sref">stream, 7-> 210total_bytes_avas="lme="Lode=ad"ldevic>" clad/core/compressdevic>total_bytes_avadevic>ref=astream" class="sref">stream,  1687span 77ass="comment"ref">copy, mutex_unlockf="+code=count"mutex_unlock" claL215" id="L215" clasdevic>_mutextotal_bytes_avadevic>_mutex" clnstream" class="sref">stream, stream(ef="+co22" class="lineef=vstream->ioctl_avail;
;
EFAULT;
 172      7     77 hrefref">copy, ->stream,  213   7 sref">sn7ef">runtime->stream, 7175streamcou7f="+code=stream" class="7ref">77eam" class="sref">stream"L2debu id="L218" classprldebu " cladspanuffer */"Remov="g >ioctl_aed devic> %s\n"total_bytes_avadevic>ref="sound/core/compresshref
ioctl_avail;
copy, mutex_lockf="+code=count"mutex_lock" claL215" id="L215" clasdevic>_mutextotal_bytes_avadevic>_mutex" clnstream" class="sref">stream, st77am->total_bytes_avadevic>ref=astream" class="sref">stream, 7tream78ass="comment"ref">copy, mutex_unlockf="+code=count"mutex_unlock" claL215" id="L215" clasdevic>_mutextotal_bytes_avadevic>_mutex" clnstream" class="sref">stream,  180    7     78rom_user(ef="+co.c#L220" id="L220" class="line" name="L220"7 ;
EFAULT;
runtime->copy, ->stream,  213   7aclass="s7d/core/compress_offload.7#L18478compr222" id="L222" class="line__ini=ream->stream, streamEFAULT;
EFAULT;
 188stream, ava7l_calc = streamap7_pointer - EFAULT;
pr_debug(EFAULT;
copy, module_ini=ream->stream, copy, module_exi=ream->stream,  144        re7sref">ava7l_calc -= copy, MODULE_DESCRIPTIOhref="sound/coreMODULE_DESCRIPTIOh" cladspanuffer */"ALSA Cioctl_aed >       frrefwork"stream, copy, MODULE_AUTHORf="+code=count"MODULE_AUTHOR" cladspanuffer */"Vinod Koul=<vinod.koul@="+ux.="Lal.tresoun"stream,  198        7a hre79" id=def">copy, MODULE_LICENSEops->"GPL v2"stream, avail_calc;



d/div>


>
The original LXR software by the ream" clahttp://ss=rceforge.net/amojects/lx>
>LXR >iomuni=yss=", this experimental vers on by ream" clamailto:lx>@="+ux.no">lx>@="+ux.noss=".
d/div>

>
lx>.="+ux.no kindly hosLad by ream" clahttp://www.redpill-="+amo.no">Redpill L"+amo AS s sinc> 1995.
d/div>