int snd_bcm2835_new_spdif_pcm(struct bcm2835_chip *chip) { struct snd_pcm *pcm; int err; audio_info(" .. IN\n"); if (mutex_lock_interruptible(&chip->audio_mutex)) { audio_error("Interrupted whilst waiting for lock\n"); return -EINTR; } err = snd_pcm_new(chip->card, "bcm2835 ALSA", 1, 1, 0, &pcm); if (err < 0) goto out; pcm->private_data = chip; strcpy(pcm->name, "bcm2835 IEC958/HDMI"); chip->pcm_spdif = pcm; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_bcm2835_playback_spdif_ops); /* pre-allocation of buffers */ /* NOTE: this may fail */ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL), snd_bcm2835_playback_spdif_hw.buffer_bytes_max, snd_bcm2835_playback_spdif_hw.buffer_bytes_max); out: mutex_unlock(&chip->audio_mutex); audio_info(" .. OUT\n"); return 0; }
/* create a pcm device */ int __devinit snd_bcm2835_new_pcm(bcm2835_chip_t * chip) { struct snd_pcm *pcm; int err; audio_info(" .. IN\n"); err = snd_pcm_new(chip->card, "bcm2835 ALSA", 0, MAX_SUBSTREAMS, 0, &pcm); if (err < 0) return err; pcm->private_data = chip; strcpy(pcm->name, "bcm2835 ALSA"); chip->pcm = pcm; chip->dest = AUDIO_DEST_AUTO; chip->volume = 100; /* set operators */ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_bcm2835_playback_ops); /* pre-allocation of buffers */ /* NOTE: this may fail */ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data (GFP_KERNEL), 64 * 1024, 64 * 1024); audio_info(" .. OUT\n"); return 0; }
/* hw_params callback */ static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { int err; struct snd_pcm_runtime *runtime = substream->runtime; bcm2835_alsa_stream_t *alsa_stream = (bcm2835_alsa_stream_t *) runtime->private_data; audio_info(" .. IN\n"); err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); if (err < 0) { audio_error (" pcm_lib_malloc failed to allocated pages for buffers\n"); return err; } err = bcm2835_audio_set_params(alsa_stream, params_channels(params), params_rate(params), snd_pcm_format_width(params_format (params))); if (err < 0) { audio_error(" error setting hw params\n"); } bcm2835_audio_setup(alsa_stream); audio_info(" .. OUT\n"); return err; }
/* close callback */ static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream) { /* the hardware-specific codes will be here */ struct bcm2835_chip *chip; struct snd_pcm_runtime *runtime; struct bcm2835_alsa_stream *alsa_stream; audio_info(" .. IN\n"); chip = snd_pcm_substream_chip(substream); if (mutex_lock_interruptible(&chip->audio_mutex)) { audio_error("Interrupted whilst waiting for lock\n"); return -EINTR; } runtime = substream->runtime; alsa_stream = runtime->private_data; audio_info("Alsa close\n"); /* * Call stop if it's still running. This happens when app * is force killed and we don't get a stop trigger. */ if (alsa_stream->running) { int err; err = bcm2835_audio_stop(alsa_stream); alsa_stream->running = 0; if (err) audio_error(" Failed to STOP alsa device\n"); } alsa_stream->period_size = 0; alsa_stream->buffer_size = 0; if (alsa_stream->open) { alsa_stream->open = 0; bcm2835_audio_close(alsa_stream); } if (alsa_stream->chip) alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL; /* * Do not free up alsa_stream here, it will be freed up by * runtime->private_free callback we registered in *_open above */ chip->opened &= ~(1 << substream->number); mutex_unlock(&chip->audio_mutex); audio_info(" .. OUT\n"); return 0; }
/* prepare callback */ static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream) { struct bcm2835_chip *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct bcm2835_alsa_stream *alsa_stream = runtime->private_data; int channels; int err; audio_info(" .. IN\n"); if (mutex_lock_interruptible(&chip->audio_mutex)) return -EINTR; /* notify the vchiq that it should enter spdif passthrough mode by * setting channels=0 (see * https://github.com/raspberrypi/linux/issues/528) */ if (chip->spdif_status & IEC958_AES0_NONAUDIO) channels = 0; else channels = alsa_stream->channels; err = bcm2835_audio_set_params(alsa_stream, channels, alsa_stream->params_rate, alsa_stream->pcm_format_width); if (err < 0) { audio_error(" error setting hw params\n"); } bcm2835_audio_setup(alsa_stream); /* in preparation of the stream, set the controls (volume level) of the stream */ bcm2835_audio_set_ctls(alsa_stream->chip); memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect)); alsa_stream->pcm_indirect.hw_buffer_size = alsa_stream->pcm_indirect.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream); alsa_stream->period_size = snd_pcm_lib_period_bytes(substream); alsa_stream->pos = 0; audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n", alsa_stream->buffer_size, alsa_stream->period_size, alsa_stream->pos, runtime->frame_bits); mutex_unlock(&chip->audio_mutex); audio_info(" .. OUT\n"); return 0; }
/* trigger callback */ static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_pcm_runtime *runtime = substream->runtime; struct bcm2835_alsa_stream *alsa_stream = runtime->private_data; int err = 0; audio_info(" .. IN\n"); switch (cmd) { case SNDRV_PCM_TRIGGER_START: audio_debug("bcm2835_AUDIO_TRIGGER_START running=%d\n", alsa_stream->running); if (!alsa_stream->running) { err = bcm2835_audio_start(alsa_stream); if (!err) { alsa_stream->pcm_indirect.hw_io = alsa_stream->pcm_indirect.hw_data = bytes_to_frames(runtime, alsa_stream->pos); substream->ops->ack(substream); alsa_stream->running = 1; alsa_stream->draining = 1; } else { audio_error(" Failed to START alsa device (%d)\n", err); } } break; case SNDRV_PCM_TRIGGER_STOP: audio_debug ("bcm2835_AUDIO_TRIGGER_STOP running=%d draining=%d\n", alsa_stream->running, runtime->status->state == SNDRV_PCM_STATE_DRAINING); if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) { audio_info("DRAINING\n"); alsa_stream->draining = 1; } else { audio_info("DROPPING\n"); alsa_stream->draining = 0; } if (alsa_stream->running) { err = bcm2835_audio_stop(alsa_stream); if (err != 0) audio_error(" Failed to STOP alsa device (%d)\n", err); alsa_stream->running = 0; } break; default: err = -EINVAL; } audio_info(" .. OUT\n"); return err; }
static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime) { audio_info("Freeing up alsa stream here ..\n"); if (runtime->private_data) kfree(runtime->private_data); runtime->private_data = NULL; }
/* pointer callback */ static snd_pcm_uframes_t snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; audio_info(" .. IN\n"); audio_debug("pcm_pointer... (%d) hwptr=%d appl=%d pos=%d\n", 0, frames_to_bytes(runtime, runtime->status->hw_ptr), frames_to_bytes(runtime, runtime->control->appl_ptr), alsa_stream->pos); audio_info(" .. OUT\n"); return bytes_to_frames(runtime, alsa_stream->pos); }
static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg) { int ret = snd_pcm_lib_ioctl(substream, cmd, arg); audio_info(" .. substream=%p, cmd=%d, arg=%p (%x) ret=%d\n", substream, cmd, arg, arg ? *(unsigned *)arg : 0, ret); return ret; }
static irqreturn_t bcm2835_playback_fifo_irq(int irq, void *dev_id) { bcm2835_alsa_stream_t *alsa_stream = (bcm2835_alsa_stream_t *) dev_id; uint32_t consumed = 0; int new_period = 0; audio_info(" .. IN\n"); audio_info("alsa_stream=%p substream=%p\n", alsa_stream, alsa_stream ? alsa_stream->substream : 0); if (alsa_stream->open) consumed = bcm2835_audio_retrieve_buffers(alsa_stream); /* We get called only if playback was triggered, So, the number of buffers we retrieve in * each iteration are the buffers that have been played out already */ if (alsa_stream->period_size) { if ((alsa_stream->pos / alsa_stream->period_size) != ((alsa_stream->pos + consumed) / alsa_stream->period_size)) new_period = 1; } audio_debug("updating pos cur: %d + %d max:%d period_bytes:%d, hw_ptr: %d new_period:%d\n", alsa_stream->pos, consumed, alsa_stream->buffer_size, (int)(alsa_stream->period_size*alsa_stream->substream->runtime->periods), frames_to_bytes(alsa_stream->substream->runtime, alsa_stream->substream->runtime->status->hw_ptr), new_period); if (alsa_stream->buffer_size) { alsa_stream->pos += consumed &~ (1<<30); alsa_stream->pos %= alsa_stream->buffer_size; } if (alsa_stream->substream) { if (new_period) snd_pcm_period_elapsed(alsa_stream->substream); } else { audio_warning(" unexpected NULL substream\n"); } audio_info(" .. OUT\n"); return IRQ_HANDLED; }
/* prepare callback */ static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; audio_info(" .. IN\n"); alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream); alsa_stream->period_size = snd_pcm_lib_period_bytes(substream); alsa_stream->pos = 0; audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n", alsa_stream->buffer_size, alsa_stream->period_size, alsa_stream->pos, runtime->frame_bits); audio_info(" .. OUT\n"); return 0; }
/* close callback */ static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream) { /* the hardware-specific codes will be here */ struct snd_pcm_runtime *runtime = substream->runtime; bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; audio_info(" .. IN\n"); audio_warning("Alsa close\n"); /* * Call stop if it's still running. This happens when app * is force killed and we don't get a stop trigger. */ if (alsa_stream->running) { int err; err = bcm2835_audio_stop(alsa_stream); alsa_stream->running = 0; if (err != 0) audio_error(" Failed to STOP alsa device\n"); } alsa_stream->period_size = 0; alsa_stream->buffer_size = 0; if (alsa_stream->open) { alsa_stream->open = 0; bcm2835_audio_close(alsa_stream); } if (alsa_stream->chip) alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL; /* * Do not free up alsa_stream here, it will be freed up by * runtime->private_free callback we registered in *_open above */ audio_info(" .. OUT\n"); return 0; }
static int snd_bcm2835_pcm_copy(struct snd_pcm_substream *substream, int channel, snd_pcm_uframes_t pos, void *src, snd_pcm_uframes_t count) { int ret; struct snd_pcm_runtime *runtime = substream->runtime; bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; audio_info(" .. IN\n"); audio_debug("copy.......... (%d) hwptr=%d appl=%d pos=%d\n", frames_to_bytes(runtime, count), frames_to_bytes(runtime, runtime-> status-> hw_ptr), frames_to_bytes(runtime, runtime->control->appl_ptr), alsa_stream->pos); ret = bcm2835_audio_write(alsa_stream, frames_to_bytes(runtime, count), src); audio_info(" .. OUT\n"); return ret; }
/* toggles mute on or off depending on the value of nmute, and returns * 1 if the mute value was changed, otherwise 0 */ static int toggle_mute(struct bcm2835_chip *chip, int nmute) { /* if settings are ok, just return 0 */ if(chip->mute == nmute) return 0; /* if the sound is muted then we need to unmute */ if(chip->mute == CTRL_VOL_MUTE) { chip->volume = chip->old_volume; /* copy the old volume back */ audio_info("Unmuting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume); } else /* otherwise we mute */ { chip->old_volume = chip->volume; chip->volume = 26214; /* set volume to minimum level AKA mute */ audio_info("Muting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume); } chip->mute = nmute; return 1; }
static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol); int changed = 0; if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) { audio_info("Volume change attempted.. volume = %d new_volume = %d\n", chip->volume, (int)ucontrol->value.integer.value[0]); if (chip->mute == CTRL_VOL_MUTE) { /* changed = toggle_mute(chip, CTRL_VOL_UNMUTE); */ return 1; /* should return 0 to signify no change but the mixer takes this as the opposite sign (no idea why) */ } if (changed || (ucontrol->value.integer.value[0] != chip2alsa(chip->volume))) { chip->volume = alsa2chip(ucontrol->value.integer.value[0]); changed = 1; } } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) { /* Now implemented */ audio_info(" Mute attempted\n"); changed = toggle_mute(chip, ucontrol->value.integer.value[0]); } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) { if (ucontrol->value.integer.value[0] != chip->dest) { chip->dest = ucontrol->value.integer.value[0]; changed = 1; } } if (changed) { if (bcm2835_audio_set_ctls(chip)) printk(KERN_ERR "Failed to set ALSA controls..\n"); } return changed; }
/* create a pcm device */ int snd_bcm2835_new_pcm(struct bcm2835_chip *chip) { struct snd_pcm *pcm; int err; audio_info(" .. IN\n"); mutex_init(&chip->audio_mutex); if (mutex_lock_interruptible(&chip->audio_mutex)) { audio_error("Interrupted whilst waiting for lock\n"); return -EINTR; } err = snd_pcm_new(chip->card, "bcm2835 ALSA", 0, MAX_SUBSTREAMS, 0, &pcm); if (err < 0) goto out; pcm->private_data = chip; strcpy(pcm->name, "bcm2835 ALSA"); chip->pcm = pcm; chip->dest = AUDIO_DEST_AUTO; chip->volume = alsa2chip(0); chip->mute = CTRL_VOL_UNMUTE; /*disable mute on startup */ /* set operators */ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_bcm2835_playback_ops); /* pre-allocation of buffers */ /* NOTE: this may fail */ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL), snd_bcm2835_playback_hw.buffer_bytes_max, snd_bcm2835_playback_hw.buffer_bytes_max); out: mutex_unlock(&chip->audio_mutex); audio_info(" .. OUT\n"); return 0; }
static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { audio_info(" ... IN\n"); if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; uinfo->value.integer.min = CTRL_VOL_MIN; uinfo->value.integer.max = CTRL_VOL_MAX; /* 2303 */ } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = 1; } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = AUDIO_DEST_MAX-1; } audio_info(" ... OUT\n"); return 0; }
/* hw_params callback */ static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime = substream->runtime; struct bcm2835_alsa_stream *alsa_stream = runtime->private_data; int err; audio_info(" .. IN\n"); err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); if (err < 0) { audio_error (" pcm_lib_malloc failed to allocated pages for buffers\n"); return err; } alsa_stream->channels = params_channels(params); alsa_stream->params_rate = params_rate(params); alsa_stream->pcm_format_width = snd_pcm_format_width(params_format(params)); audio_info(" .. OUT\n"); return err; }
static void audio_loop(t_mdxmini *data, int freq, int len) { int total; int sec; int sec_sample; if (len < 0) len = mdx_get_length(data); mdx_set_max_loop(data, 0); fade_init(); total = sec = sec_sample = 0; // put title info audio_disp_title(data); // put time audio_info(data, sec, len); do { // waiting for next block while(pcm.count >= (PCM_BUFFER_LEN - PCM_BLOCK_SIZE)) { if (audio_poll_event() < 0) { SDL_PauseAudio(1); return; } SDL_Delay(1); } // calculate samples mdx_calc_sample(data, pcm.buffer + pcm.write_pos, PCM_BLOCK); if (is_fade_run()) fade_stereo (pcm.buffer + pcm.write_pos, PCM_BLOCK); pcm.write_pos += PCM_BLOCK_SIZE; if (pcm.write_pos >= PCM_BUFFER_LEN) pcm.write_pos = 0; pcm.count += PCM_BLOCK_SIZE; total += PCM_BLOCK; sec_sample += PCM_BLOCK; // if sec_samples > 1sec while (sec_sample >= freq) { sec_sample -= freq; sec++; if (sec >= (len - 3)) { if (!is_fade_run()) fade_start(freq, 1); } if (!g_viewnote) audio_info(data, sec, len); } if (g_viewnote) audio_info(data, sec, len); }while(sec < len && !pcm.stop); printf("\n"); SDL_PauseAudio(1); }
static int snd_bcm2835_alsa_probe(struct platform_device *pdev) { static int dev; bcm2835_chip_t *chip; struct snd_card *card; int err; if (dev >= MAX_SUBSTREAMS) return -ENODEV; if (!enable[dev]) { dev++; return -ENOENT; } if (dev > 0) goto add_register_map; err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &g_card); if (err < 0) goto out; snd_card_set_dev(g_card, &pdev->dev); strcpy(g_card->driver, "bcm2835"); strcpy(g_card->shortname, "bcm2835 ALSA"); sprintf(g_card->longname, "%s", g_card->shortname); err = snd_bcm2835_create(g_card, pdev, &chip); if (err < 0) { dev_err(&pdev->dev, "Failed to create bcm2835 chip\n"); goto out_bcm2835_create; } g_chip = chip; err = snd_bcm2835_new_pcm(chip); if (err < 0) { dev_err(&pdev->dev, "Failed to create new BCM2835 pcm device\n"); goto out_bcm2835_new_pcm; } err = snd_bcm2835_new_spdif_pcm(chip); if (err < 0) { dev_err(&pdev->dev, "Failed to create new BCM2835 spdif pcm device\n"); goto out_bcm2835_new_spdif; } err = snd_bcm2835_new_ctl(chip); if (err < 0) { dev_err(&pdev->dev, "Failed to create new BCM2835 ctl\n"); goto out_bcm2835_new_ctl; } add_register_map: card = g_card; chip = g_chip; BUG_ON(!(card && chip)); chip->avail_substreams |= (1 << dev); chip->pdev[dev] = pdev; if (dev == 0) { err = snd_card_register(card); if (err < 0) { dev_err(&pdev->dev, "Failed to register bcm2835 ALSA card \n"); goto out_card_register; } platform_set_drvdata(pdev, card); audio_info("bcm2835 ALSA card created!\n"); } else { audio_info("bcm2835 ALSA chip created!\n"); platform_set_drvdata(pdev, (void *)dev); } dev++; return 0; out_card_register: out_bcm2835_new_ctl: out_bcm2835_new_spdif: out_bcm2835_new_pcm: out_bcm2835_create: BUG_ON(!g_card); if (snd_card_free(g_card)) dev_err(&pdev->dev, "Failed to free Registered alsa card\n"); g_card = NULL; out: dev = SNDRV_CARDS; /* stop more avail_substreams from being probed */ dev_err(&pdev->dev, "BCM2835 ALSA Probe failed !!\n"); return err; }
/* open callback */ static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream) { bcm2835_chip_t *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; bcm2835_alsa_stream_t *alsa_stream; int idx; int err; audio_info(" .. IN (%d)\n", substream->number); audio_warning("Alsa open (%d)\n", substream->number); idx = substream->number; if (idx > MAX_SUBSTREAMS) { audio_error ("substream(%d) device doesn't exist max(%d) substreams allowed\n", idx, MAX_SUBSTREAMS); err = -ENODEV; goto out; } /* Check if we are ready */ if (!(chip->avail_substreams & (1 << idx))) { /* We are not ready yet */ audio_error("substream(%d) device is not ready yet\n", idx); err = -EAGAIN; goto out; } alsa_stream = kzalloc(sizeof(bcm2835_alsa_stream_t), GFP_KERNEL); if (alsa_stream == NULL) { return -ENOMEM; } /* Initialise alsa_stream */ alsa_stream->chip = chip; alsa_stream->substream = substream; alsa_stream->idx = idx; chip->alsa_stream[idx] = alsa_stream; sema_init(&alsa_stream->buffers_update_sem, 0); sema_init(&alsa_stream->control_sem, 0); spin_lock_init(&alsa_stream->lock); /* Enabled in start trigger, called on each "fifo irq" after that */ alsa_stream->enable_fifo_irq = 0; alsa_stream->fifo_irq_handler = bcm2835_playback_fifo_irq; runtime->private_data = alsa_stream; runtime->private_free = snd_bcm2835_playback_free; runtime->hw = snd_bcm2835_playback_hw; /* minimum 16 bytes alignment (for vchiq bulk transfers) */ snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 16); err = bcm2835_audio_open(alsa_stream); if (err != 0) { kfree(alsa_stream); return err; } alsa_stream->open = 1; alsa_stream->draining = 1; out: audio_info(" .. OUT =%d\n", err); return err; }
static void audio_loop_file( t_mdxmini *data, const char *file, int freq , int len) { FILE *fp = NULL; int sec; int last_sec; int frames; int total_frames; short pcm_buffer[PCM_BLOCK_SIZE]; // put title info audio_disp_title(data); // get length if (len < 0) len = mdx_get_length(data); // len = 5; fade_init(); sec = frames = total_frames = 0; if (file) fp = fopen(file, "wb"); if (file && fp == NULL) { printf("Can't write a PCM file!\n"); return; } audio_write_wav_header(fp, freq, 0); audio_info(data, sec, len); do { // calculate samples if (fp) mdx_calc_sample(data, pcm_buffer, PCM_BLOCK); else mdx_calc_log(data, pcm_buffer, PCM_BLOCK); if (is_fade_run()) fade_stereo(pcm_buffer, PCM_BLOCK); if (fp) fwrite(pcm_buffer, PCM_BLOCK_BYTES, 1, fp); // increase pointer frames += PCM_BLOCK; total_frames += PCM_BLOCK; /* increase seconds */ while(frames >= freq) { frames -= freq; sec++; audio_info(data, sec, len); // start fader if (sec >= (len - 3)) { if (!is_fade_run()) fade_start(freq, 1); } } }while(sec < len && !pcm.stop); audio_write_wav_header( fp, freq, (total_frames * PCM_CH * PCM_BYTE_PER_SAMPLE)); printf("\n"); if (fp) fclose(fp); }
/* hw_free callback */ static int snd_bcm2835_pcm_hw_free(struct snd_pcm_substream *substream) { audio_info(" .. IN\n"); return snd_pcm_lib_free_pages(substream); }
static int snd_bcm2835_alsa_probe_dt(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct bcm2835_chip *chip; struct snd_card *card; u32 numchans; int err, i; err = of_property_read_u32(dev->of_node, "brcm,pwm-channels", &numchans); if (err) { dev_err(dev, "Failed to get DT property 'brcm,pwm-channels'"); return err; } if (numchans == 0 || numchans > MAX_SUBSTREAMS) { numchans = MAX_SUBSTREAMS; dev_warn(dev, "Illegal 'brcm,pwm-channels' value, will use %u\n", numchans); } err = snd_card_new(&pdev->dev, -1, NULL, THIS_MODULE, 0, &card); if (err) { dev_err(dev, "Failed to create soundcard structure\n"); return err; } snd_card_set_dev(card, dev); strcpy(card->driver, "bcm2835"); strcpy(card->shortname, "bcm2835 ALSA"); sprintf(card->longname, "%s", card->shortname); err = snd_bcm2835_create(card, pdev, &chip); if (err < 0) { dev_err(dev, "Failed to create bcm2835 chip\n"); goto err_free; } err = snd_bcm2835_new_pcm(chip); if (err < 0) { dev_err(dev, "Failed to create new bcm2835 pcm device\n"); goto err_free; } err = snd_bcm2835_new_spdif_pcm(chip); if (err < 0) { dev_err(dev, "Failed to create new bcm2835 spdif pcm device\n"); goto err_free; } err = snd_bcm2835_new_ctl(chip); if (err < 0) { dev_err(dev, "Failed to create new bcm2835 ctl\n"); goto err_free; } for (i = 0; i < numchans; i++) { chip->avail_substreams |= (1 << i); chip->pdev[i] = pdev; } err = snd_card_register(card); if (err) { dev_err(dev, "Failed to register bcm2835 ALSA card\n"); goto err_free; } g_card = card; g_chip = chip; platform_set_drvdata(pdev, card); audio_info("bcm2835 ALSA card created with %u channels\n", numchans); return 0; err_free: snd_card_free(card); return err; }
/* open callback */ static int snd_bcm2835_playback_open_generic( struct snd_pcm_substream *substream, int spdif) { struct bcm2835_chip *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct bcm2835_alsa_stream *alsa_stream; int idx; int err; audio_info(" .. IN (%d)\n", substream->number); if (mutex_lock_interruptible(&chip->audio_mutex)) { audio_error("Interrupted whilst waiting for lock\n"); return -EINTR; } audio_info("Alsa open (%d)\n", substream->number); idx = substream->number; if (spdif && chip->opened) { err = -EBUSY; goto out; } else if (!spdif && (chip->opened & (1 << idx))) { err = -EBUSY; goto out; } if (idx >= MAX_SUBSTREAMS) { audio_error ("substream(%d) device doesn't exist max(%d) substreams allowed\n", idx, MAX_SUBSTREAMS); err = -ENODEV; goto out; } /* Check if we are ready */ if (!(chip->avail_substreams & (1 << idx))) { /* We are not ready yet */ audio_error("substream(%d) device is not ready yet\n", idx); err = -EAGAIN; goto out; } alsa_stream = kzalloc(sizeof(*alsa_stream), GFP_KERNEL); if (!alsa_stream) { err = -ENOMEM; goto out; } /* Initialise alsa_stream */ alsa_stream->chip = chip; alsa_stream->substream = substream; alsa_stream->idx = idx; sema_init(&alsa_stream->buffers_update_sem, 0); sema_init(&alsa_stream->control_sem, 0); spin_lock_init(&alsa_stream->lock); err = bcm2835_audio_open(alsa_stream); if (err) { kfree(alsa_stream); goto out; } runtime->private_data = alsa_stream; runtime->private_free = snd_bcm2835_playback_free; if (spdif) { runtime->hw = snd_bcm2835_playback_spdif_hw; } else { /* clear spdif status, as we are not in spdif mode */ chip->spdif_status = 0; runtime->hw = snd_bcm2835_playback_hw; } /* minimum 16 bytes alignment (for vchiq bulk transfers) */ snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 16); chip->alsa_stream[idx] = alsa_stream; chip->opened |= (1 << idx); alsa_stream->open = 1; alsa_stream->draining = 1; out: mutex_unlock(&chip->audio_mutex); audio_info(" .. OUT =%d\n", err); return err; }