/* Very simple dummy ALSA driver. Copyright (C) 2007 Trent Piepho */ #include #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) #include #endif #include #include #include #include #include #include #include #include #include MODULE_LICENSE("GPL"); #include #define MHZ 1544.426 #define INT (unsigned int)(MHZ * (1<<12) + 0.5) #define FRAC (unsigned int)(MHZ * (1<<21) / 1000.0 + 0.5) #define timestamp(str, args...) { u64 _time; u32 _rem; rdtscll(_time); \ _time = (_time - chip->starttime)<<12; \ _rem = do_div(_time, INT); \ printk("%s - %u.%03u us " str "\n", __FUNCTION__, \ (unsigned int)_time, (_rem << 9) / FRAC , ## args); } struct snd_as { u64 starttime; }; static struct snd_pcm_hardware as_hw = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_INTERLEAVED, .formats = SNDRV_PCM_FMTBIT_U8, .rates = SNDRV_PCM_RATE_8000_48000, .rate_min = 8000, .rate_max = 48000, .channels_min = 1, .channels_max = 1, .buffer_bytes_max = (128 * 1024), .period_bytes_min = 1024, .period_bytes_max = (128 * 1024), .periods_min = 1, .periods_max = 128, }; static int as_open(struct snd_pcm_substream *substream) { struct snd_as *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int err; runtime->hw = as_hw; rdtscll(chip->starttime); err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); timestamp(""); return err; } static int as_close(struct snd_pcm_substream *substream) { struct snd_as *chip = snd_pcm_substream_chip(substream); timestamp(""); return 0; } static int as_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct snd_as *chip = snd_pcm_substream_chip(substream); timestamp("periods %d, period size %d", params_periods(hw_params), params_period_size(hw_params)); return 0; } static int as_prepare(struct snd_pcm_substream *substream) { struct snd_as *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; timestamp("periods %d, period size %lu", runtime->periods, runtime->period_size); return 0; } static int as_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_as *chip = snd_pcm_substream_chip(substream); timestamp("cmd %d", cmd); return 0; } static snd_pcm_uframes_t as_pointer(struct snd_pcm_substream *substream) { struct snd_as *chip = snd_pcm_substream_chip(substream); timestamp(""); return 0; } static struct snd_pcm_ops as_pcm_ops = { .open = as_open, .close = as_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = as_hw_params, .prepare = as_prepare, .trigger = as_trigger, .pointer = as_pointer, }; static struct snd_card *card; static int __init init(void) { struct snd_as *chip; struct snd_pcm *pcm; int err; card = snd_card_new(-1, SNDRV_DEFAULT_STR1, THIS_MODULE, sizeof(*chip)); chip = card->private_data; snd_pcm_new(card, "Test", 0, 1, 1, &pcm); pcm->private_data = chip; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &as_pcm_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &as_pcm_ops); err = snd_card_register(card); return err; } module_init(init); static void __exit exit(void) { snd_card_free(card); return; } module_exit(exit);