1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* 3 * Helper functions for indirect PCM data transfer to a simple FIFO in 4 * hardware (small, no possibility to read "hardware io position", 5 * updating position done by interrupt, ...) 6 * 7 * Copyright (c) by 2007 Joachim Foerster <JOFT@gmx.de> 8 * 9 * Based on "pcm-indirect.h" (alsa-driver-1.0.13) by 10 * 11 * Copyright (c) by Takashi Iwai <tiwai@suse.de> 12 * Jaroslav Kysela <perex@suse.cz> 13 */ 14 15 #ifndef __SOUND_PCM_INDIRECT2_H 16 #define __SOUND_PCM_INDIRECT2_H 17 18 /* struct snd_pcm_substream, struct snd_pcm_runtime, snd_pcm_uframes_t */ 19 #include <sound/pcm.h> 20 21 /* Debug options for code which may be removed completely in a final version */ 22 #ifdef CONFIG_SND_DEBUG 23 #define SND_PCM_INDIRECT2_STAT /* turn on some "statistics" about the 24 * process of copying bytes from the 25 * intermediate buffer to the hardware 26 * fifo and the other way round 27 */ 28 #endif 29 30 struct snd_pcm_indirect2 { 31 unsigned int hw_buffer_size; /* Byte size of hardware buffer */ 32 int hw_ready; /* playback: 1 = hw fifo has room left, 33 * 0 = hw fifo is full 34 */ 35 unsigned int min_multiple; 36 int min_periods; /* counts number of min. periods until 37 * min_multiple is reached 38 */ 39 int min_period_count; /* counts bytes to count number of 40 * min. periods 41 */ 42 43 unsigned int sw_buffer_size; /* Byte size of software buffer */ 44 45 /* sw_data: position in intermediate buffer, where we will read (or 46 * write) from/to next time (to transfer data to/from HW) 47 */ 48 unsigned int sw_data; /* Offset to next dst (or src) in sw 49 * ring buffer 50 */ 51 /* easiest case (playback): 52 * sw_data is nearly the same as ~ runtime->control->appl_ptr, with the 53 * exception that sw_data is "behind" by the number if bytes ALSA wrote 54 * to the intermediate buffer last time. 55 * A call to ack() callback synchronizes both indirectly. 56 */ 57 58 /* We have no real sw_io pointer here. Usually sw_io is pointing to the 59 * current playback/capture position _inside_ the hardware. Devices 60 * with plain FIFOs often have no possibility to publish this position. 61 * So we say: if sw_data is updated, that means bytes were copied to 62 * the hardware, we increase sw_io by that amount, because there have 63 * to be as much bytes which were played. So sw_io will stay behind 64 * sw_data all the time and has to converge to sw_data at the end of 65 * playback. 66 */ 67 unsigned int sw_io; /* Current software pointer in bytes */ 68 69 /* sw_ready: number of bytes ALSA copied to the intermediate buffer, so 70 * it represents the number of bytes which wait for transfer to the HW 71 */ 72 int sw_ready; /* Bytes ready to be transferred to/from hw */ 73 74 /* appl_ptr: last known position of ALSA (where ALSA is going to write 75 * next time into the intermediate buffer 76 */ 77 snd_pcm_uframes_t appl_ptr; /* Last seen appl_ptr */ 78 79 unsigned int bytes2hw; 80 int check_alignment; 81 82 #ifdef SND_PCM_INDIRECT2_STAT 83 unsigned int zeros2hw; 84 unsigned int mul_elapsed; 85 unsigned int mul_elapsed_real; 86 unsigned long firstbytetime; 87 unsigned long lastbytetime; 88 unsigned long firstzerotime; 89 unsigned int byte_sizes[64]; 90 unsigned int zero_sizes[64]; 91 unsigned int min_adds[8]; 92 unsigned int mul_adds[8]; 93 unsigned int zero_times[3750]; /* = 15s */ 94 unsigned int zero_times_saved; 95 unsigned int zero_times_notsaved; 96 unsigned int irq_occured; 97 unsigned int pointer_calls; 98 unsigned int lastdifftime; 99 #endif 100 }; 101 102 typedef size_t (*snd_pcm_indirect2_copy_t) (struct snd_pcm_substream *substream, 103 struct snd_pcm_indirect2 *rec, 104 size_t bytes); 105 typedef size_t (*snd_pcm_indirect2_zero_t) (struct snd_pcm_substream *substream, 106 struct snd_pcm_indirect2 *rec); 107 108 #ifdef SND_PCM_INDIRECT2_STAT 109 void snd_pcm_indirect2_stat(struct snd_pcm_substream *substream, 110 struct snd_pcm_indirect2 *rec); 111 #endif 112 113 snd_pcm_uframes_t 114 snd_pcm_indirect2_pointer(struct snd_pcm_substream *substream, 115 struct snd_pcm_indirect2 *rec); 116 void 117 snd_pcm_indirect2_playback_interrupt(struct snd_pcm_substream *substream, 118 struct snd_pcm_indirect2 *rec, 119 snd_pcm_indirect2_copy_t copy, 120 snd_pcm_indirect2_zero_t zero); 121 void 122 snd_pcm_indirect2_capture_interrupt(struct snd_pcm_substream *substream, 123 struct snd_pcm_indirect2 *rec, 124 snd_pcm_indirect2_copy_t copy, 125 snd_pcm_indirect2_zero_t null); 126 127 #endif /* __SOUND_PCM_INDIRECT2_H */