Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Dummy soundcard
0004  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
0005  */
0006 
0007 #include <linux/init.h>
0008 #include <linux/err.h>
0009 #include <linux/platform_device.h>
0010 #include <linux/jiffies.h>
0011 #include <linux/slab.h>
0012 #include <linux/time.h>
0013 #include <linux/wait.h>
0014 #include <linux/hrtimer.h>
0015 #include <linux/math64.h>
0016 #include <linux/module.h>
0017 #include <sound/core.h>
0018 #include <sound/control.h>
0019 #include <sound/tlv.h>
0020 #include <sound/pcm.h>
0021 #include <sound/rawmidi.h>
0022 #include <sound/info.h>
0023 #include <sound/initval.h>
0024 
0025 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
0026 MODULE_DESCRIPTION("Dummy soundcard (/dev/null)");
0027 MODULE_LICENSE("GPL");
0028 
0029 #define MAX_PCM_DEVICES     4
0030 #define MAX_PCM_SUBSTREAMS  128
0031 #define MAX_MIDI_DEVICES    2
0032 
0033 /* defaults */
0034 #define MAX_BUFFER_SIZE     (64*1024)
0035 #define MIN_PERIOD_SIZE     64
0036 #define MAX_PERIOD_SIZE     MAX_BUFFER_SIZE
0037 #define USE_FORMATS         (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE)
0038 #define USE_RATE        SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000
0039 #define USE_RATE_MIN        5500
0040 #define USE_RATE_MAX        48000
0041 #define USE_CHANNELS_MIN    1
0042 #define USE_CHANNELS_MAX    2
0043 #define USE_PERIODS_MIN     1
0044 #define USE_PERIODS_MAX     1024
0045 
0046 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;  /* Index 0-MAX */
0047 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;   /* ID for this card */
0048 static bool enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
0049 static char *model[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = NULL};
0050 static int pcm_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
0051 static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8};
0052 //static int midi_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
0053 #ifdef CONFIG_HIGH_RES_TIMERS
0054 static bool hrtimer = 1;
0055 #endif
0056 static bool fake_buffer = 1;
0057 
0058 module_param_array(index, int, NULL, 0444);
0059 MODULE_PARM_DESC(index, "Index value for dummy soundcard.");
0060 module_param_array(id, charp, NULL, 0444);
0061 MODULE_PARM_DESC(id, "ID string for dummy soundcard.");
0062 module_param_array(enable, bool, NULL, 0444);
0063 MODULE_PARM_DESC(enable, "Enable this dummy soundcard.");
0064 module_param_array(model, charp, NULL, 0444);
0065 MODULE_PARM_DESC(model, "Soundcard model.");
0066 module_param_array(pcm_devs, int, NULL, 0444);
0067 MODULE_PARM_DESC(pcm_devs, "PCM devices # (0-4) for dummy driver.");
0068 module_param_array(pcm_substreams, int, NULL, 0444);
0069 MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-128) for dummy driver.");
0070 //module_param_array(midi_devs, int, NULL, 0444);
0071 //MODULE_PARM_DESC(midi_devs, "MIDI devices # (0-2) for dummy driver.");
0072 module_param(fake_buffer, bool, 0444);
0073 MODULE_PARM_DESC(fake_buffer, "Fake buffer allocations.");
0074 #ifdef CONFIG_HIGH_RES_TIMERS
0075 module_param(hrtimer, bool, 0644);
0076 MODULE_PARM_DESC(hrtimer, "Use hrtimer as the timer source.");
0077 #endif
0078 
0079 static struct platform_device *devices[SNDRV_CARDS];
0080 
0081 #define MIXER_ADDR_MASTER   0
0082 #define MIXER_ADDR_LINE     1
0083 #define MIXER_ADDR_MIC      2
0084 #define MIXER_ADDR_SYNTH    3
0085 #define MIXER_ADDR_CD       4
0086 #define MIXER_ADDR_LAST     4
0087 
0088 struct dummy_timer_ops {
0089     int (*create)(struct snd_pcm_substream *);
0090     void (*free)(struct snd_pcm_substream *);
0091     int (*prepare)(struct snd_pcm_substream *);
0092     int (*start)(struct snd_pcm_substream *);
0093     int (*stop)(struct snd_pcm_substream *);
0094     snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *);
0095 };
0096 
0097 #define get_dummy_ops(substream) \
0098     (*(const struct dummy_timer_ops **)(substream)->runtime->private_data)
0099 
0100 struct dummy_model {
0101     const char *name;
0102     int (*playback_constraints)(struct snd_pcm_runtime *runtime);
0103     int (*capture_constraints)(struct snd_pcm_runtime *runtime);
0104     u64 formats;
0105     size_t buffer_bytes_max;
0106     size_t period_bytes_min;
0107     size_t period_bytes_max;
0108     unsigned int periods_min;
0109     unsigned int periods_max;
0110     unsigned int rates;
0111     unsigned int rate_min;
0112     unsigned int rate_max;
0113     unsigned int channels_min;
0114     unsigned int channels_max;
0115 };
0116 
0117 struct snd_dummy {
0118     struct snd_card *card;
0119     const struct dummy_model *model;
0120     struct snd_pcm *pcm;
0121     struct snd_pcm_hardware pcm_hw;
0122     spinlock_t mixer_lock;
0123     int mixer_volume[MIXER_ADDR_LAST+1][2];
0124     int capture_source[MIXER_ADDR_LAST+1][2];
0125     int iobox;
0126     struct snd_kcontrol *cd_volume_ctl;
0127     struct snd_kcontrol *cd_switch_ctl;
0128 };
0129 
0130 /*
0131  * card models
0132  */
0133 
0134 static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime)
0135 {
0136     int err;
0137     err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
0138     if (err < 0)
0139         return err;
0140     err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX);
0141     if (err < 0)
0142         return err;
0143     return 0;
0144 }
0145 
0146 static const struct dummy_model model_emu10k1 = {
0147     .name = "emu10k1",
0148     .playback_constraints = emu10k1_playback_constraints,
0149     .buffer_bytes_max = 128 * 1024,
0150 };
0151 
0152 static const struct dummy_model model_rme9652 = {
0153     .name = "rme9652",
0154     .buffer_bytes_max = 26 * 64 * 1024,
0155     .formats = SNDRV_PCM_FMTBIT_S32_LE,
0156     .channels_min = 26,
0157     .channels_max = 26,
0158     .periods_min = 2,
0159     .periods_max = 2,
0160 };
0161 
0162 static const struct dummy_model model_ice1712 = {
0163     .name = "ice1712",
0164     .buffer_bytes_max = 256 * 1024,
0165     .formats = SNDRV_PCM_FMTBIT_S32_LE,
0166     .channels_min = 10,
0167     .channels_max = 10,
0168     .periods_min = 1,
0169     .periods_max = 1024,
0170 };
0171 
0172 static const struct dummy_model model_uda1341 = {
0173     .name = "uda1341",
0174     .buffer_bytes_max = 16380,
0175     .formats = SNDRV_PCM_FMTBIT_S16_LE,
0176     .channels_min = 2,
0177     .channels_max = 2,
0178     .periods_min = 2,
0179     .periods_max = 255,
0180 };
0181 
0182 static const struct dummy_model model_ac97 = {
0183     .name = "ac97",
0184     .formats = SNDRV_PCM_FMTBIT_S16_LE,
0185     .channels_min = 2,
0186     .channels_max = 2,
0187     .rates = SNDRV_PCM_RATE_48000,
0188     .rate_min = 48000,
0189     .rate_max = 48000,
0190 };
0191 
0192 static const struct dummy_model model_ca0106 = {
0193     .name = "ca0106",
0194     .formats = SNDRV_PCM_FMTBIT_S16_LE,
0195     .buffer_bytes_max = ((65536-64)*8),
0196     .period_bytes_max = (65536-64),
0197     .periods_min = 2,
0198     .periods_max = 8,
0199     .channels_min = 2,
0200     .channels_max = 2,
0201     .rates = SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_96000|SNDRV_PCM_RATE_192000,
0202     .rate_min = 48000,
0203     .rate_max = 192000,
0204 };
0205 
0206 static const struct dummy_model *dummy_models[] = {
0207     &model_emu10k1,
0208     &model_rme9652,
0209     &model_ice1712,
0210     &model_uda1341,
0211     &model_ac97,
0212     &model_ca0106,
0213     NULL
0214 };
0215 
0216 /*
0217  * system timer interface
0218  */
0219 
0220 struct dummy_systimer_pcm {
0221     /* ops must be the first item */
0222     const struct dummy_timer_ops *timer_ops;
0223     spinlock_t lock;
0224     struct timer_list timer;
0225     unsigned long base_time;
0226     unsigned int frac_pos;  /* fractional sample position (based HZ) */
0227     unsigned int frac_period_rest;
0228     unsigned int frac_buffer_size;  /* buffer_size * HZ */
0229     unsigned int frac_period_size;  /* period_size * HZ */
0230     unsigned int rate;
0231     int elapsed;
0232     struct snd_pcm_substream *substream;
0233 };
0234 
0235 static void dummy_systimer_rearm(struct dummy_systimer_pcm *dpcm)
0236 {
0237     mod_timer(&dpcm->timer, jiffies +
0238         DIV_ROUND_UP(dpcm->frac_period_rest, dpcm->rate));
0239 }
0240 
0241 static void dummy_systimer_update(struct dummy_systimer_pcm *dpcm)
0242 {
0243     unsigned long delta;
0244 
0245     delta = jiffies - dpcm->base_time;
0246     if (!delta)
0247         return;
0248     dpcm->base_time += delta;
0249     delta *= dpcm->rate;
0250     dpcm->frac_pos += delta;
0251     while (dpcm->frac_pos >= dpcm->frac_buffer_size)
0252         dpcm->frac_pos -= dpcm->frac_buffer_size;
0253     while (dpcm->frac_period_rest <= delta) {
0254         dpcm->elapsed++;
0255         dpcm->frac_period_rest += dpcm->frac_period_size;
0256     }
0257     dpcm->frac_period_rest -= delta;
0258 }
0259 
0260 static int dummy_systimer_start(struct snd_pcm_substream *substream)
0261 {
0262     struct dummy_systimer_pcm *dpcm = substream->runtime->private_data;
0263     spin_lock(&dpcm->lock);
0264     dpcm->base_time = jiffies;
0265     dummy_systimer_rearm(dpcm);
0266     spin_unlock(&dpcm->lock);
0267     return 0;
0268 }
0269 
0270 static int dummy_systimer_stop(struct snd_pcm_substream *substream)
0271 {
0272     struct dummy_systimer_pcm *dpcm = substream->runtime->private_data;
0273     spin_lock(&dpcm->lock);
0274     del_timer(&dpcm->timer);
0275     spin_unlock(&dpcm->lock);
0276     return 0;
0277 }
0278 
0279 static int dummy_systimer_prepare(struct snd_pcm_substream *substream)
0280 {
0281     struct snd_pcm_runtime *runtime = substream->runtime;
0282     struct dummy_systimer_pcm *dpcm = runtime->private_data;
0283 
0284     dpcm->frac_pos = 0;
0285     dpcm->rate = runtime->rate;
0286     dpcm->frac_buffer_size = runtime->buffer_size * HZ;
0287     dpcm->frac_period_size = runtime->period_size * HZ;
0288     dpcm->frac_period_rest = dpcm->frac_period_size;
0289     dpcm->elapsed = 0;
0290 
0291     return 0;
0292 }
0293 
0294 static void dummy_systimer_callback(struct timer_list *t)
0295 {
0296     struct dummy_systimer_pcm *dpcm = from_timer(dpcm, t, timer);
0297     unsigned long flags;
0298     int elapsed = 0;
0299     
0300     spin_lock_irqsave(&dpcm->lock, flags);
0301     dummy_systimer_update(dpcm);
0302     dummy_systimer_rearm(dpcm);
0303     elapsed = dpcm->elapsed;
0304     dpcm->elapsed = 0;
0305     spin_unlock_irqrestore(&dpcm->lock, flags);
0306     if (elapsed)
0307         snd_pcm_period_elapsed(dpcm->substream);
0308 }
0309 
0310 static snd_pcm_uframes_t
0311 dummy_systimer_pointer(struct snd_pcm_substream *substream)
0312 {
0313     struct dummy_systimer_pcm *dpcm = substream->runtime->private_data;
0314     snd_pcm_uframes_t pos;
0315 
0316     spin_lock(&dpcm->lock);
0317     dummy_systimer_update(dpcm);
0318     pos = dpcm->frac_pos / HZ;
0319     spin_unlock(&dpcm->lock);
0320     return pos;
0321 }
0322 
0323 static int dummy_systimer_create(struct snd_pcm_substream *substream)
0324 {
0325     struct dummy_systimer_pcm *dpcm;
0326 
0327     dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
0328     if (!dpcm)
0329         return -ENOMEM;
0330     substream->runtime->private_data = dpcm;
0331     timer_setup(&dpcm->timer, dummy_systimer_callback, 0);
0332     spin_lock_init(&dpcm->lock);
0333     dpcm->substream = substream;
0334     return 0;
0335 }
0336 
0337 static void dummy_systimer_free(struct snd_pcm_substream *substream)
0338 {
0339     kfree(substream->runtime->private_data);
0340 }
0341 
0342 static const struct dummy_timer_ops dummy_systimer_ops = {
0343     .create =   dummy_systimer_create,
0344     .free =     dummy_systimer_free,
0345     .prepare =  dummy_systimer_prepare,
0346     .start =    dummy_systimer_start,
0347     .stop =     dummy_systimer_stop,
0348     .pointer =  dummy_systimer_pointer,
0349 };
0350 
0351 #ifdef CONFIG_HIGH_RES_TIMERS
0352 /*
0353  * hrtimer interface
0354  */
0355 
0356 struct dummy_hrtimer_pcm {
0357     /* ops must be the first item */
0358     const struct dummy_timer_ops *timer_ops;
0359     ktime_t base_time;
0360     ktime_t period_time;
0361     atomic_t running;
0362     struct hrtimer timer;
0363     struct snd_pcm_substream *substream;
0364 };
0365 
0366 static enum hrtimer_restart dummy_hrtimer_callback(struct hrtimer *timer)
0367 {
0368     struct dummy_hrtimer_pcm *dpcm;
0369 
0370     dpcm = container_of(timer, struct dummy_hrtimer_pcm, timer);
0371     if (!atomic_read(&dpcm->running))
0372         return HRTIMER_NORESTART;
0373     /*
0374      * In cases of XRUN and draining, this calls .trigger to stop PCM
0375      * substream.
0376      */
0377     snd_pcm_period_elapsed(dpcm->substream);
0378     if (!atomic_read(&dpcm->running))
0379         return HRTIMER_NORESTART;
0380 
0381     hrtimer_forward_now(timer, dpcm->period_time);
0382     return HRTIMER_RESTART;
0383 }
0384 
0385 static int dummy_hrtimer_start(struct snd_pcm_substream *substream)
0386 {
0387     struct dummy_hrtimer_pcm *dpcm = substream->runtime->private_data;
0388 
0389     dpcm->base_time = hrtimer_cb_get_time(&dpcm->timer);
0390     hrtimer_start(&dpcm->timer, dpcm->period_time, HRTIMER_MODE_REL_SOFT);
0391     atomic_set(&dpcm->running, 1);
0392     return 0;
0393 }
0394 
0395 static int dummy_hrtimer_stop(struct snd_pcm_substream *substream)
0396 {
0397     struct dummy_hrtimer_pcm *dpcm = substream->runtime->private_data;
0398 
0399     atomic_set(&dpcm->running, 0);
0400     if (!hrtimer_callback_running(&dpcm->timer))
0401         hrtimer_cancel(&dpcm->timer);
0402     return 0;
0403 }
0404 
0405 static inline void dummy_hrtimer_sync(struct dummy_hrtimer_pcm *dpcm)
0406 {
0407     hrtimer_cancel(&dpcm->timer);
0408 }
0409 
0410 static snd_pcm_uframes_t
0411 dummy_hrtimer_pointer(struct snd_pcm_substream *substream)
0412 {
0413     struct snd_pcm_runtime *runtime = substream->runtime;
0414     struct dummy_hrtimer_pcm *dpcm = runtime->private_data;
0415     u64 delta;
0416     u32 pos;
0417 
0418     delta = ktime_us_delta(hrtimer_cb_get_time(&dpcm->timer),
0419                    dpcm->base_time);
0420     delta = div_u64(delta * runtime->rate + 999999, 1000000);
0421     div_u64_rem(delta, runtime->buffer_size, &pos);
0422     return pos;
0423 }
0424 
0425 static int dummy_hrtimer_prepare(struct snd_pcm_substream *substream)
0426 {
0427     struct snd_pcm_runtime *runtime = substream->runtime;
0428     struct dummy_hrtimer_pcm *dpcm = runtime->private_data;
0429     unsigned int period, rate;
0430     long sec;
0431     unsigned long nsecs;
0432 
0433     dummy_hrtimer_sync(dpcm);
0434     period = runtime->period_size;
0435     rate = runtime->rate;
0436     sec = period / rate;
0437     period %= rate;
0438     nsecs = div_u64((u64)period * 1000000000UL + rate - 1, rate);
0439     dpcm->period_time = ktime_set(sec, nsecs);
0440 
0441     return 0;
0442 }
0443 
0444 static int dummy_hrtimer_create(struct snd_pcm_substream *substream)
0445 {
0446     struct dummy_hrtimer_pcm *dpcm;
0447 
0448     dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
0449     if (!dpcm)
0450         return -ENOMEM;
0451     substream->runtime->private_data = dpcm;
0452     hrtimer_init(&dpcm->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
0453     dpcm->timer.function = dummy_hrtimer_callback;
0454     dpcm->substream = substream;
0455     atomic_set(&dpcm->running, 0);
0456     return 0;
0457 }
0458 
0459 static void dummy_hrtimer_free(struct snd_pcm_substream *substream)
0460 {
0461     struct dummy_hrtimer_pcm *dpcm = substream->runtime->private_data;
0462     dummy_hrtimer_sync(dpcm);
0463     kfree(dpcm);
0464 }
0465 
0466 static const struct dummy_timer_ops dummy_hrtimer_ops = {
0467     .create =   dummy_hrtimer_create,
0468     .free =     dummy_hrtimer_free,
0469     .prepare =  dummy_hrtimer_prepare,
0470     .start =    dummy_hrtimer_start,
0471     .stop =     dummy_hrtimer_stop,
0472     .pointer =  dummy_hrtimer_pointer,
0473 };
0474 
0475 #endif /* CONFIG_HIGH_RES_TIMERS */
0476 
0477 /*
0478  * PCM interface
0479  */
0480 
0481 static int dummy_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
0482 {
0483     switch (cmd) {
0484     case SNDRV_PCM_TRIGGER_START:
0485     case SNDRV_PCM_TRIGGER_RESUME:
0486         return get_dummy_ops(substream)->start(substream);
0487     case SNDRV_PCM_TRIGGER_STOP:
0488     case SNDRV_PCM_TRIGGER_SUSPEND:
0489         return get_dummy_ops(substream)->stop(substream);
0490     }
0491     return -EINVAL;
0492 }
0493 
0494 static int dummy_pcm_prepare(struct snd_pcm_substream *substream)
0495 {
0496     return get_dummy_ops(substream)->prepare(substream);
0497 }
0498 
0499 static snd_pcm_uframes_t dummy_pcm_pointer(struct snd_pcm_substream *substream)
0500 {
0501     return get_dummy_ops(substream)->pointer(substream);
0502 }
0503 
0504 static const struct snd_pcm_hardware dummy_pcm_hardware = {
0505     .info =         (SNDRV_PCM_INFO_MMAP |
0506                  SNDRV_PCM_INFO_INTERLEAVED |
0507                  SNDRV_PCM_INFO_RESUME |
0508                  SNDRV_PCM_INFO_MMAP_VALID),
0509     .formats =      USE_FORMATS,
0510     .rates =        USE_RATE,
0511     .rate_min =     USE_RATE_MIN,
0512     .rate_max =     USE_RATE_MAX,
0513     .channels_min =     USE_CHANNELS_MIN,
0514     .channels_max =     USE_CHANNELS_MAX,
0515     .buffer_bytes_max = MAX_BUFFER_SIZE,
0516     .period_bytes_min = MIN_PERIOD_SIZE,
0517     .period_bytes_max = MAX_PERIOD_SIZE,
0518     .periods_min =      USE_PERIODS_MIN,
0519     .periods_max =      USE_PERIODS_MAX,
0520     .fifo_size =        0,
0521 };
0522 
0523 static int dummy_pcm_hw_params(struct snd_pcm_substream *substream,
0524                    struct snd_pcm_hw_params *hw_params)
0525 {
0526     if (fake_buffer) {
0527         /* runtime->dma_bytes has to be set manually to allow mmap */
0528         substream->runtime->dma_bytes = params_buffer_bytes(hw_params);
0529         return 0;
0530     }
0531     return 0;
0532 }
0533 
0534 static int dummy_pcm_open(struct snd_pcm_substream *substream)
0535 {
0536     struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
0537     const struct dummy_model *model = dummy->model;
0538     struct snd_pcm_runtime *runtime = substream->runtime;
0539     const struct dummy_timer_ops *ops;
0540     int err;
0541 
0542     ops = &dummy_systimer_ops;
0543 #ifdef CONFIG_HIGH_RES_TIMERS
0544     if (hrtimer)
0545         ops = &dummy_hrtimer_ops;
0546 #endif
0547 
0548     err = ops->create(substream);
0549     if (err < 0)
0550         return err;
0551     get_dummy_ops(substream) = ops;
0552 
0553     runtime->hw = dummy->pcm_hw;
0554     if (substream->pcm->device & 1) {
0555         runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
0556         runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
0557     }
0558     if (substream->pcm->device & 2)
0559         runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP |
0560                       SNDRV_PCM_INFO_MMAP_VALID);
0561 
0562     if (model == NULL)
0563         return 0;
0564 
0565     if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0566         if (model->playback_constraints)
0567             err = model->playback_constraints(substream->runtime);
0568     } else {
0569         if (model->capture_constraints)
0570             err = model->capture_constraints(substream->runtime);
0571     }
0572     if (err < 0) {
0573         get_dummy_ops(substream)->free(substream);
0574         return err;
0575     }
0576     return 0;
0577 }
0578 
0579 static int dummy_pcm_close(struct snd_pcm_substream *substream)
0580 {
0581     get_dummy_ops(substream)->free(substream);
0582     return 0;
0583 }
0584 
0585 /*
0586  * dummy buffer handling
0587  */
0588 
0589 static void *dummy_page[2];
0590 
0591 static void free_fake_buffer(void)
0592 {
0593     if (fake_buffer) {
0594         int i;
0595         for (i = 0; i < 2; i++)
0596             if (dummy_page[i]) {
0597                 free_page((unsigned long)dummy_page[i]);
0598                 dummy_page[i] = NULL;
0599             }
0600     }
0601 }
0602 
0603 static int alloc_fake_buffer(void)
0604 {
0605     int i;
0606 
0607     if (!fake_buffer)
0608         return 0;
0609     for (i = 0; i < 2; i++) {
0610         dummy_page[i] = (void *)get_zeroed_page(GFP_KERNEL);
0611         if (!dummy_page[i]) {
0612             free_fake_buffer();
0613             return -ENOMEM;
0614         }
0615     }
0616     return 0;
0617 }
0618 
0619 static int dummy_pcm_copy(struct snd_pcm_substream *substream,
0620               int channel, unsigned long pos,
0621               void __user *dst, unsigned long bytes)
0622 {
0623     return 0; /* do nothing */
0624 }
0625 
0626 static int dummy_pcm_copy_kernel(struct snd_pcm_substream *substream,
0627                  int channel, unsigned long pos,
0628                  void *dst, unsigned long bytes)
0629 {
0630     return 0; /* do nothing */
0631 }
0632 
0633 static int dummy_pcm_silence(struct snd_pcm_substream *substream,
0634                  int channel, unsigned long pos,
0635                  unsigned long bytes)
0636 {
0637     return 0; /* do nothing */
0638 }
0639 
0640 static struct page *dummy_pcm_page(struct snd_pcm_substream *substream,
0641                    unsigned long offset)
0642 {
0643     return virt_to_page(dummy_page[substream->stream]); /* the same page */
0644 }
0645 
0646 static const struct snd_pcm_ops dummy_pcm_ops = {
0647     .open =     dummy_pcm_open,
0648     .close =    dummy_pcm_close,
0649     .hw_params =    dummy_pcm_hw_params,
0650     .prepare =  dummy_pcm_prepare,
0651     .trigger =  dummy_pcm_trigger,
0652     .pointer =  dummy_pcm_pointer,
0653 };
0654 
0655 static const struct snd_pcm_ops dummy_pcm_ops_no_buf = {
0656     .open =     dummy_pcm_open,
0657     .close =    dummy_pcm_close,
0658     .hw_params =    dummy_pcm_hw_params,
0659     .prepare =  dummy_pcm_prepare,
0660     .trigger =  dummy_pcm_trigger,
0661     .pointer =  dummy_pcm_pointer,
0662     .copy_user =    dummy_pcm_copy,
0663     .copy_kernel =  dummy_pcm_copy_kernel,
0664     .fill_silence = dummy_pcm_silence,
0665     .page =     dummy_pcm_page,
0666 };
0667 
0668 static int snd_card_dummy_pcm(struct snd_dummy *dummy, int device,
0669                   int substreams)
0670 {
0671     struct snd_pcm *pcm;
0672     const struct snd_pcm_ops *ops;
0673     int err;
0674 
0675     err = snd_pcm_new(dummy->card, "Dummy PCM", device,
0676                    substreams, substreams, &pcm);
0677     if (err < 0)
0678         return err;
0679     dummy->pcm = pcm;
0680     if (fake_buffer)
0681         ops = &dummy_pcm_ops_no_buf;
0682     else
0683         ops = &dummy_pcm_ops;
0684     snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, ops);
0685     snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, ops);
0686     pcm->private_data = dummy;
0687     pcm->info_flags = 0;
0688     strcpy(pcm->name, "Dummy PCM");
0689     if (!fake_buffer) {
0690         snd_pcm_set_managed_buffer_all(pcm,
0691             SNDRV_DMA_TYPE_CONTINUOUS,
0692             NULL,
0693             0, 64*1024);
0694     }
0695     return 0;
0696 }
0697 
0698 /*
0699  * mixer interface
0700  */
0701 
0702 #define DUMMY_VOLUME(xname, xindex, addr) \
0703 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
0704   .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
0705   .name = xname, .index = xindex, \
0706   .info = snd_dummy_volume_info, \
0707   .get = snd_dummy_volume_get, .put = snd_dummy_volume_put, \
0708   .private_value = addr, \
0709   .tlv = { .p = db_scale_dummy } }
0710 
0711 static int snd_dummy_volume_info(struct snd_kcontrol *kcontrol,
0712                  struct snd_ctl_elem_info *uinfo)
0713 {
0714     uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
0715     uinfo->count = 2;
0716     uinfo->value.integer.min = -50;
0717     uinfo->value.integer.max = 100;
0718     return 0;
0719 }
0720  
0721 static int snd_dummy_volume_get(struct snd_kcontrol *kcontrol,
0722                 struct snd_ctl_elem_value *ucontrol)
0723 {
0724     struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);
0725     int addr = kcontrol->private_value;
0726 
0727     spin_lock_irq(&dummy->mixer_lock);
0728     ucontrol->value.integer.value[0] = dummy->mixer_volume[addr][0];
0729     ucontrol->value.integer.value[1] = dummy->mixer_volume[addr][1];
0730     spin_unlock_irq(&dummy->mixer_lock);
0731     return 0;
0732 }
0733 
0734 static int snd_dummy_volume_put(struct snd_kcontrol *kcontrol,
0735                 struct snd_ctl_elem_value *ucontrol)
0736 {
0737     struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);
0738     int change, addr = kcontrol->private_value;
0739     int left, right;
0740 
0741     left = ucontrol->value.integer.value[0];
0742     if (left < -50)
0743         left = -50;
0744     if (left > 100)
0745         left = 100;
0746     right = ucontrol->value.integer.value[1];
0747     if (right < -50)
0748         right = -50;
0749     if (right > 100)
0750         right = 100;
0751     spin_lock_irq(&dummy->mixer_lock);
0752     change = dummy->mixer_volume[addr][0] != left ||
0753              dummy->mixer_volume[addr][1] != right;
0754     dummy->mixer_volume[addr][0] = left;
0755     dummy->mixer_volume[addr][1] = right;
0756     spin_unlock_irq(&dummy->mixer_lock);
0757     return change;
0758 }
0759 
0760 static const DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0);
0761 
0762 #define DUMMY_CAPSRC(xname, xindex, addr) \
0763 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
0764   .info = snd_dummy_capsrc_info, \
0765   .get = snd_dummy_capsrc_get, .put = snd_dummy_capsrc_put, \
0766   .private_value = addr }
0767 
0768 #define snd_dummy_capsrc_info   snd_ctl_boolean_stereo_info
0769  
0770 static int snd_dummy_capsrc_get(struct snd_kcontrol *kcontrol,
0771                 struct snd_ctl_elem_value *ucontrol)
0772 {
0773     struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);
0774     int addr = kcontrol->private_value;
0775 
0776     spin_lock_irq(&dummy->mixer_lock);
0777     ucontrol->value.integer.value[0] = dummy->capture_source[addr][0];
0778     ucontrol->value.integer.value[1] = dummy->capture_source[addr][1];
0779     spin_unlock_irq(&dummy->mixer_lock);
0780     return 0;
0781 }
0782 
0783 static int snd_dummy_capsrc_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
0784 {
0785     struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);
0786     int change, addr = kcontrol->private_value;
0787     int left, right;
0788 
0789     left = ucontrol->value.integer.value[0] & 1;
0790     right = ucontrol->value.integer.value[1] & 1;
0791     spin_lock_irq(&dummy->mixer_lock);
0792     change = dummy->capture_source[addr][0] != left &&
0793              dummy->capture_source[addr][1] != right;
0794     dummy->capture_source[addr][0] = left;
0795     dummy->capture_source[addr][1] = right;
0796     spin_unlock_irq(&dummy->mixer_lock);
0797     return change;
0798 }
0799 
0800 static int snd_dummy_iobox_info(struct snd_kcontrol *kcontrol,
0801                 struct snd_ctl_elem_info *info)
0802 {
0803     static const char *const names[] = { "None", "CD Player" };
0804 
0805     return snd_ctl_enum_info(info, 1, 2, names);
0806 }
0807 
0808 static int snd_dummy_iobox_get(struct snd_kcontrol *kcontrol,
0809                    struct snd_ctl_elem_value *value)
0810 {
0811     struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);
0812 
0813     value->value.enumerated.item[0] = dummy->iobox;
0814     return 0;
0815 }
0816 
0817 static int snd_dummy_iobox_put(struct snd_kcontrol *kcontrol,
0818                    struct snd_ctl_elem_value *value)
0819 {
0820     struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);
0821     int changed;
0822 
0823     if (value->value.enumerated.item[0] > 1)
0824         return -EINVAL;
0825 
0826     changed = value->value.enumerated.item[0] != dummy->iobox;
0827     if (changed) {
0828         dummy->iobox = value->value.enumerated.item[0];
0829 
0830         if (dummy->iobox) {
0831             dummy->cd_volume_ctl->vd[0].access &=
0832                 ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
0833             dummy->cd_switch_ctl->vd[0].access &=
0834                 ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
0835         } else {
0836             dummy->cd_volume_ctl->vd[0].access |=
0837                 SNDRV_CTL_ELEM_ACCESS_INACTIVE;
0838             dummy->cd_switch_ctl->vd[0].access |=
0839                 SNDRV_CTL_ELEM_ACCESS_INACTIVE;
0840         }
0841 
0842         snd_ctl_notify(dummy->card, SNDRV_CTL_EVENT_MASK_INFO,
0843                    &dummy->cd_volume_ctl->id);
0844         snd_ctl_notify(dummy->card, SNDRV_CTL_EVENT_MASK_INFO,
0845                    &dummy->cd_switch_ctl->id);
0846     }
0847 
0848     return changed;
0849 }
0850 
0851 static const struct snd_kcontrol_new snd_dummy_controls[] = {
0852 DUMMY_VOLUME("Master Volume", 0, MIXER_ADDR_MASTER),
0853 DUMMY_CAPSRC("Master Capture Switch", 0, MIXER_ADDR_MASTER),
0854 DUMMY_VOLUME("Synth Volume", 0, MIXER_ADDR_SYNTH),
0855 DUMMY_CAPSRC("Synth Capture Switch", 0, MIXER_ADDR_SYNTH),
0856 DUMMY_VOLUME("Line Volume", 0, MIXER_ADDR_LINE),
0857 DUMMY_CAPSRC("Line Capture Switch", 0, MIXER_ADDR_LINE),
0858 DUMMY_VOLUME("Mic Volume", 0, MIXER_ADDR_MIC),
0859 DUMMY_CAPSRC("Mic Capture Switch", 0, MIXER_ADDR_MIC),
0860 DUMMY_VOLUME("CD Volume", 0, MIXER_ADDR_CD),
0861 DUMMY_CAPSRC("CD Capture Switch", 0, MIXER_ADDR_CD),
0862 {
0863     .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0864     .name  = "External I/O Box",
0865     .info  = snd_dummy_iobox_info,
0866     .get   = snd_dummy_iobox_get,
0867     .put   = snd_dummy_iobox_put,
0868 },
0869 };
0870 
0871 static int snd_card_dummy_new_mixer(struct snd_dummy *dummy)
0872 {
0873     struct snd_card *card = dummy->card;
0874     struct snd_kcontrol *kcontrol;
0875     unsigned int idx;
0876     int err;
0877 
0878     spin_lock_init(&dummy->mixer_lock);
0879     strcpy(card->mixername, "Dummy Mixer");
0880     dummy->iobox = 1;
0881 
0882     for (idx = 0; idx < ARRAY_SIZE(snd_dummy_controls); idx++) {
0883         kcontrol = snd_ctl_new1(&snd_dummy_controls[idx], dummy);
0884         err = snd_ctl_add(card, kcontrol);
0885         if (err < 0)
0886             return err;
0887         if (!strcmp(kcontrol->id.name, "CD Volume"))
0888             dummy->cd_volume_ctl = kcontrol;
0889         else if (!strcmp(kcontrol->id.name, "CD Capture Switch"))
0890             dummy->cd_switch_ctl = kcontrol;
0891 
0892     }
0893     return 0;
0894 }
0895 
0896 #if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_PROC_FS)
0897 /*
0898  * proc interface
0899  */
0900 static void print_formats(struct snd_dummy *dummy,
0901               struct snd_info_buffer *buffer)
0902 {
0903     snd_pcm_format_t i;
0904 
0905     pcm_for_each_format(i) {
0906         if (dummy->pcm_hw.formats & pcm_format_to_bits(i))
0907             snd_iprintf(buffer, " %s", snd_pcm_format_name(i));
0908     }
0909 }
0910 
0911 static void print_rates(struct snd_dummy *dummy,
0912             struct snd_info_buffer *buffer)
0913 {
0914     static const int rates[] = {
0915         5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000,
0916         64000, 88200, 96000, 176400, 192000,
0917     };
0918     int i;
0919 
0920     if (dummy->pcm_hw.rates & SNDRV_PCM_RATE_CONTINUOUS)
0921         snd_iprintf(buffer, " continuous");
0922     if (dummy->pcm_hw.rates & SNDRV_PCM_RATE_KNOT)
0923         snd_iprintf(buffer, " knot");
0924     for (i = 0; i < ARRAY_SIZE(rates); i++)
0925         if (dummy->pcm_hw.rates & (1 << i))
0926             snd_iprintf(buffer, " %d", rates[i]);
0927 }
0928 
0929 #define get_dummy_int_ptr(dummy, ofs) \
0930     (unsigned int *)((char *)&((dummy)->pcm_hw) + (ofs))
0931 #define get_dummy_ll_ptr(dummy, ofs) \
0932     (unsigned long long *)((char *)&((dummy)->pcm_hw) + (ofs))
0933 
0934 struct dummy_hw_field {
0935     const char *name;
0936     const char *format;
0937     unsigned int offset;
0938     unsigned int size;
0939 };
0940 #define FIELD_ENTRY(item, fmt) {           \
0941     .name = #item,                 \
0942     .format = fmt,                 \
0943     .offset = offsetof(struct snd_pcm_hardware, item), \
0944     .size = sizeof(dummy_pcm_hardware.item) }
0945 
0946 static const struct dummy_hw_field fields[] = {
0947     FIELD_ENTRY(formats, "%#llx"),
0948     FIELD_ENTRY(rates, "%#x"),
0949     FIELD_ENTRY(rate_min, "%d"),
0950     FIELD_ENTRY(rate_max, "%d"),
0951     FIELD_ENTRY(channels_min, "%d"),
0952     FIELD_ENTRY(channels_max, "%d"),
0953     FIELD_ENTRY(buffer_bytes_max, "%ld"),
0954     FIELD_ENTRY(period_bytes_min, "%ld"),
0955     FIELD_ENTRY(period_bytes_max, "%ld"),
0956     FIELD_ENTRY(periods_min, "%d"),
0957     FIELD_ENTRY(periods_max, "%d"),
0958 };
0959 
0960 static void dummy_proc_read(struct snd_info_entry *entry,
0961                 struct snd_info_buffer *buffer)
0962 {
0963     struct snd_dummy *dummy = entry->private_data;
0964     int i;
0965 
0966     for (i = 0; i < ARRAY_SIZE(fields); i++) {
0967         snd_iprintf(buffer, "%s ", fields[i].name);
0968         if (fields[i].size == sizeof(int))
0969             snd_iprintf(buffer, fields[i].format,
0970                 *get_dummy_int_ptr(dummy, fields[i].offset));
0971         else
0972             snd_iprintf(buffer, fields[i].format,
0973                 *get_dummy_ll_ptr(dummy, fields[i].offset));
0974         if (!strcmp(fields[i].name, "formats"))
0975             print_formats(dummy, buffer);
0976         else if (!strcmp(fields[i].name, "rates"))
0977             print_rates(dummy, buffer);
0978         snd_iprintf(buffer, "\n");
0979     }
0980 }
0981 
0982 static void dummy_proc_write(struct snd_info_entry *entry,
0983                  struct snd_info_buffer *buffer)
0984 {
0985     struct snd_dummy *dummy = entry->private_data;
0986     char line[64];
0987 
0988     while (!snd_info_get_line(buffer, line, sizeof(line))) {
0989         char item[20];
0990         const char *ptr;
0991         unsigned long long val;
0992         int i;
0993 
0994         ptr = snd_info_get_str(item, line, sizeof(item));
0995         for (i = 0; i < ARRAY_SIZE(fields); i++) {
0996             if (!strcmp(item, fields[i].name))
0997                 break;
0998         }
0999         if (i >= ARRAY_SIZE(fields))
1000             continue;
1001         snd_info_get_str(item, ptr, sizeof(item));
1002         if (kstrtoull(item, 0, &val))
1003             continue;
1004         if (fields[i].size == sizeof(int))
1005             *get_dummy_int_ptr(dummy, fields[i].offset) = val;
1006         else
1007             *get_dummy_ll_ptr(dummy, fields[i].offset) = val;
1008     }
1009 }
1010 
1011 static void dummy_proc_init(struct snd_dummy *chip)
1012 {
1013     snd_card_rw_proc_new(chip->card, "dummy_pcm", chip,
1014                  dummy_proc_read, dummy_proc_write);
1015 }
1016 #else
1017 #define dummy_proc_init(x)
1018 #endif /* CONFIG_SND_DEBUG && CONFIG_SND_PROC_FS */
1019 
1020 static int snd_dummy_probe(struct platform_device *devptr)
1021 {
1022     struct snd_card *card;
1023     struct snd_dummy *dummy;
1024     const struct dummy_model *m = NULL, **mdl;
1025     int idx, err;
1026     int dev = devptr->id;
1027 
1028     err = snd_devm_card_new(&devptr->dev, index[dev], id[dev], THIS_MODULE,
1029                 sizeof(struct snd_dummy), &card);
1030     if (err < 0)
1031         return err;
1032     dummy = card->private_data;
1033     dummy->card = card;
1034     for (mdl = dummy_models; *mdl && model[dev]; mdl++) {
1035         if (strcmp(model[dev], (*mdl)->name) == 0) {
1036             printk(KERN_INFO
1037                 "snd-dummy: Using model '%s' for card %i\n",
1038                 (*mdl)->name, card->number);
1039             m = dummy->model = *mdl;
1040             break;
1041         }
1042     }
1043     for (idx = 0; idx < MAX_PCM_DEVICES && idx < pcm_devs[dev]; idx++) {
1044         if (pcm_substreams[dev] < 1)
1045             pcm_substreams[dev] = 1;
1046         if (pcm_substreams[dev] > MAX_PCM_SUBSTREAMS)
1047             pcm_substreams[dev] = MAX_PCM_SUBSTREAMS;
1048         err = snd_card_dummy_pcm(dummy, idx, pcm_substreams[dev]);
1049         if (err < 0)
1050             return err;
1051     }
1052 
1053     dummy->pcm_hw = dummy_pcm_hardware;
1054     if (m) {
1055         if (m->formats)
1056             dummy->pcm_hw.formats = m->formats;
1057         if (m->buffer_bytes_max)
1058             dummy->pcm_hw.buffer_bytes_max = m->buffer_bytes_max;
1059         if (m->period_bytes_min)
1060             dummy->pcm_hw.period_bytes_min = m->period_bytes_min;
1061         if (m->period_bytes_max)
1062             dummy->pcm_hw.period_bytes_max = m->period_bytes_max;
1063         if (m->periods_min)
1064             dummy->pcm_hw.periods_min = m->periods_min;
1065         if (m->periods_max)
1066             dummy->pcm_hw.periods_max = m->periods_max;
1067         if (m->rates)
1068             dummy->pcm_hw.rates = m->rates;
1069         if (m->rate_min)
1070             dummy->pcm_hw.rate_min = m->rate_min;
1071         if (m->rate_max)
1072             dummy->pcm_hw.rate_max = m->rate_max;
1073         if (m->channels_min)
1074             dummy->pcm_hw.channels_min = m->channels_min;
1075         if (m->channels_max)
1076             dummy->pcm_hw.channels_max = m->channels_max;
1077     }
1078 
1079     err = snd_card_dummy_new_mixer(dummy);
1080     if (err < 0)
1081         return err;
1082     strcpy(card->driver, "Dummy");
1083     strcpy(card->shortname, "Dummy");
1084     sprintf(card->longname, "Dummy %i", dev + 1);
1085 
1086     dummy_proc_init(dummy);
1087 
1088     err = snd_card_register(card);
1089     if (err < 0)
1090         return err;
1091     platform_set_drvdata(devptr, card);
1092     return 0;
1093 }
1094 
1095 #ifdef CONFIG_PM_SLEEP
1096 static int snd_dummy_suspend(struct device *pdev)
1097 {
1098     struct snd_card *card = dev_get_drvdata(pdev);
1099 
1100     snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
1101     return 0;
1102 }
1103     
1104 static int snd_dummy_resume(struct device *pdev)
1105 {
1106     struct snd_card *card = dev_get_drvdata(pdev);
1107 
1108     snd_power_change_state(card, SNDRV_CTL_POWER_D0);
1109     return 0;
1110 }
1111 
1112 static SIMPLE_DEV_PM_OPS(snd_dummy_pm, snd_dummy_suspend, snd_dummy_resume);
1113 #define SND_DUMMY_PM_OPS    &snd_dummy_pm
1114 #else
1115 #define SND_DUMMY_PM_OPS    NULL
1116 #endif
1117 
1118 #define SND_DUMMY_DRIVER    "snd_dummy"
1119 
1120 static struct platform_driver snd_dummy_driver = {
1121     .probe      = snd_dummy_probe,
1122     .driver     = {
1123         .name   = SND_DUMMY_DRIVER,
1124         .pm = SND_DUMMY_PM_OPS,
1125     },
1126 };
1127 
1128 static void snd_dummy_unregister_all(void)
1129 {
1130     int i;
1131 
1132     for (i = 0; i < ARRAY_SIZE(devices); ++i)
1133         platform_device_unregister(devices[i]);
1134     platform_driver_unregister(&snd_dummy_driver);
1135     free_fake_buffer();
1136 }
1137 
1138 static int __init alsa_card_dummy_init(void)
1139 {
1140     int i, cards, err;
1141 
1142     err = platform_driver_register(&snd_dummy_driver);
1143     if (err < 0)
1144         return err;
1145 
1146     err = alloc_fake_buffer();
1147     if (err < 0) {
1148         platform_driver_unregister(&snd_dummy_driver);
1149         return err;
1150     }
1151 
1152     cards = 0;
1153     for (i = 0; i < SNDRV_CARDS; i++) {
1154         struct platform_device *device;
1155         if (! enable[i])
1156             continue;
1157         device = platform_device_register_simple(SND_DUMMY_DRIVER,
1158                              i, NULL, 0);
1159         if (IS_ERR(device))
1160             continue;
1161         if (!platform_get_drvdata(device)) {
1162             platform_device_unregister(device);
1163             continue;
1164         }
1165         devices[i] = device;
1166         cards++;
1167     }
1168     if (!cards) {
1169 #ifdef MODULE
1170         printk(KERN_ERR "Dummy soundcard not found or device busy\n");
1171 #endif
1172         snd_dummy_unregister_all();
1173         return -ENODEV;
1174     }
1175     return 0;
1176 }
1177 
1178 static void __exit alsa_card_dummy_exit(void)
1179 {
1180     snd_dummy_unregister_all();
1181 }
1182 
1183 module_init(alsa_card_dummy_init)
1184 module_exit(alsa_card_dummy_exit)