Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * MMM soundcard
- * Copyright (c) by Jon Pry <[email protected]>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
- #include <linux/init.h>
- #include <linux/err.h>
- #include <linux/platform_device.h>
- #include <linux/jiffies.h>
- #include <linux/slab.h>
- #include <linux/time.h>
- #include <linux/wait.h>
- #include <linux/hrtimer.h>
- #include <linux/math64.h>
- #include <linux/moduleparam.h>
- #include <linux/gpio.h>
- #include <sound/core.h>
- #include <sound/control.h>
- #include <sound/tlv.h>
- #include <sound/pcm.h>
- #include <sound/rawmidi.h>
- #include <sound/info.h>
- #include <sound/initval.h>
- #define SND_MMM_DRIVER "snd_mmm"
- struct mmm_snd {
- struct snd_card *card;
- struct snd_pcm *pcm;
- struct snd_pcm_substream *substream;
- volatile unsigned int current_ptr;
- volatile unsigned int running;
- spinlock_t lock;
- };
- static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
- static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
- /* hardware definition */
- static struct snd_pcm_hardware snd_mmm_playback_hw = {
- .info = (SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER),
- .formats = SNDRV_PCM_FMTBIT_S32_LE,
- .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
- .rate_min = 44100,
- .rate_max = 48000,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = 16384,
- .period_bytes_min = 8096,
- .period_bytes_max = 8096,
- .periods_min = 2,
- .periods_max = 2,
- };
- /* hardware definition */
- static struct snd_pcm_hardware snd_mmm_capture_hw = {
- .info = (SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP_VALID),
- .formats = SNDRV_PCM_FMTBIT_S32_LE,
- .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100,
- .rate_min = 44100,
- .rate_max = 48000,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = 16384,
- .period_bytes_min = 8096,
- .period_bytes_max = 8096,
- .periods_min = 2,
- .periods_max = 2,
- };
- /* open callback */
- static int snd_mmm_playback_open(struct snd_pcm_substream *substream)
- {
- struct mmm_snd *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- chip->substream = substream;
- chip->current_ptr = 0;
- chip->running = 0;
- runtime->hw = snd_mmm_playback_hw;
- /* more hardware-initialization will be done here */
- //....
- printk("%s\n",__func__);
- return 0;
- }
- /* close callback */
- static int snd_mmm_playback_close(struct snd_pcm_substream *substream)
- {
- struct mmm_snd *chip = snd_pcm_substream_chip(substream);
- /* the hardware-specific codes will be here */
- //....
- printk("%s\n",__func__);
- chip->running = 0;
- chip->substream = 0;
- return 0;
- }
- /* open callback */
- static int snd_mmm_capture_open(struct snd_pcm_substream *substream)
- {
- struct mmm_snd *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- int ret=0;
- printk("%s\n",__func__);
- runtime->hw = snd_mmm_capture_hw;
- /* more hardware-initialization will be done here */
- //....
- ret = snd_pcm_hw_constraint_integer(runtime,
- SNDRV_PCM_HW_PARAM_PERIODS);
- if(ret < 0)
- return ret;
- ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
- return ret;
- }
- /* close callback */
- static int snd_mmm_capture_close(struct snd_pcm_substream *substream)
- {
- struct mmm_snd *chip = snd_pcm_substream_chip(substream);
- /* the hardware-specific codes will be here */
- //....
- printk("%s\n",__func__);
- return 0;
- }
- /* hw_params callback */
- static int snd_mmm_pcm_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
- {
- printk("%s\n",__func__);
- return snd_pcm_lib_malloc_pages(substream,
- params_buffer_bytes(hw_params));
- }
- /* hw_free callback */
- static int snd_mmm_pcm_hw_free(struct snd_pcm_substream *substream)
- {
- printk("%s\n",__func__);
- return snd_pcm_lib_free_pages(substream);
- }
- /* prepare callback */
- static int snd_mmm_pcm_prepare(struct snd_pcm_substream *substream)
- {
- struct mmm_snd *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- chip->current_ptr = 0;
- printk("%s\n",__func__);
- return 0;
- }
- /* trigger callback */
- static int snd_mmm_pcm_trigger(struct snd_pcm_substream *substream,
- int cmd)
- {
- struct mmm_snd *chip = snd_pcm_substream_chip(substream);
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- /* do something to start the PCM engine */
- //....
- chip->running = 1;
- printk("%s PCM Trigger start\n", __func__);
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- chip->running = 0;
- printk("%s PCM Trigger stop\n", __func__);
- /* do something to stop the PCM engine */
- //....
- break;
- default:
- printk("Unknown pcm trigger\n");
- return -EINVAL;
- }
- return 0;
- }
- /* pointer callback */
- static snd_pcm_uframes_t
- snd_mmm_pcm_pointer(struct snd_pcm_substream *substream)
- {
- struct mmm_snd *chip = snd_pcm_substream_chip(substream);
- unsigned int current_ptr;
- printk("%s\n", __func__);
- /* get the current hardware pointer */
- current_ptr = chip->current_ptr*1024;
- return current_ptr;
- }
- /* operators */
- static struct snd_pcm_ops snd_mmm_playback_ops = {
- .open = snd_mmm_playback_open,
- .close = snd_mmm_playback_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_mmm_pcm_hw_params,
- .hw_free = snd_mmm_pcm_hw_free,
- .prepare = snd_mmm_pcm_prepare,
- .trigger = snd_mmm_pcm_trigger,
- .pointer = snd_mmm_pcm_pointer,
- };
- /* operators */
- static struct snd_pcm_ops snd_mmm_capture_ops = {
- .open = snd_mmm_capture_open,
- .close = snd_mmm_capture_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_mmm_pcm_hw_params,
- .hw_free = snd_mmm_pcm_hw_free,
- .prepare = snd_mmm_pcm_prepare,
- .trigger = snd_mmm_pcm_trigger,
- .pointer = snd_mmm_pcm_pointer,
- };
- /*
- * definitions of capture are omitted here...
- */
- static irqreturn_t snd_mmm_interrupt(int irq, void *dev_id)
- {
- struct mmm_snd *chip = dev_id;
- spin_lock(&chip->lock);
- if (chip->running)
- {
- chip->current_ptr=!chip->current_ptr;
- /* call updater, unlock before it */
- printk("PCM period elapsed\n");
- spin_unlock(&chip->lock);
- snd_pcm_period_elapsed(chip->substream);
- spin_lock(&chip->lock);
- /* acknowledge the interrupt if necessary */
- }
- spin_unlock(&chip->lock);
- return IRQ_HANDLED;
- }
- /* create a pcm device */
- static int __devinit snd_mmm_new_pcm(struct mmm_snd *chip)
- {
- struct snd_pcm *pcm;
- int err;
- err = snd_pcm_new(chip->card, "MMM PCM", 0, 1, 1, &pcm);
- if (err < 0)
- return err;
- pcm->private_data = chip;
- spin_lock_init(&chip->lock);
- chip->substream = 0;
- strcpy(pcm->name, "MMM PCM");
- chip->pcm = pcm;
- /* set operators */
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
- &snd_mmm_playback_ops);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
- &snd_mmm_capture_ops);
- /* pre-allocation of buffers */
- /* NOTE: this may fail */
- //What does it do i wonder?
- snd_pcm_lib_preallocate_pages_for_all(pcm,
- SNDRV_DMA_TYPE_CONTINUOUS,
- snd_dma_continuous_data(GFP_KERNEL),
- 0, 16*1024);
- return 0;
- }
- static int __devinit snd_mmm_probe(struct platform_device *devptr)
- {
- int err;
- struct snd_card *card;
- struct mmm_snd *chip;
- int dev = devptr->id;
- err = snd_card_create(index[dev], id[dev], THIS_MODULE,
- sizeof(struct mmm_snd), &card);
- if (err < 0)
- return err;
- chip = card->private_data;
- chip->card = card;
- err = snd_mmm_new_pcm(chip);
- if (err < 0)
- goto __nodev;
- strcpy(card->driver, "MMM");
- strcpy(card->shortname, "MMM");
- strcpy(card->longname, "MMM 0");
- snd_card_set_dev(card, &devptr->dev);
- err = snd_card_register(card);
- if (err<0)
- {
- printk("Failed to register sound card\n");
- goto __nodev;
- }
- platform_set_drvdata(devptr, card);
- err = gpio_request(96,"FPGA_DBUF");
- if(err < 0)
- {
- printk("Failed to get gpio FPGA_DBUF\n");
- goto __nodev;
- }
- gpio_direction_input(96);
- err = request_irq(gpio_to_irq(96), snd_mmm_interrupt,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
- "fpga_dbuf", chip);
- if(err < 0)
- {
- printk("Failed to request irq\n");
- goto __nodev;
- }
- return 0;
- __nodev:
- snd_card_free(card);
- return err;
- }
- static struct platform_driver snd_mmm_driver = {
- .probe = snd_mmm_probe,
- .driver = {
- .name = SND_MMM_DRIVER
- },
- };
- static int __init alsa_card_mmm_init(void)
- {
- int err;
- err = platform_driver_register(&snd_mmm_driver);
- if (err < 0)
- return err;
- struct platform_device *device;
- device = platform_device_register_simple(SND_MMM_DRIVER,
- 0, NULL, 0);
- return 0;
- }
- module_init(alsa_card_mmm_init)
- MODULE_AUTHOR("Jon Pry <[email protected]>");
- MODULE_DESCRIPTION("MMM soundcard");
- MODULE_LICENSE("GPL");
- MODULE_SUPPORTED_DEVICE("{{ALSA,MMM soundcard}}");
Add Comment
Please, Sign In to add comment