···35struct imx_pcm_runtime_data {36 int period;37 int periods;38- unsigned long dma_addr;39- int dma;40 unsigned long offset;041 unsigned long size;42- unsigned long period_cnt;43- void *buf;44 struct timer_list timer;45- int period_time;46};000004748static void imx_ssi_timer_callback(unsigned long data)49{···53 struct snd_pcm_runtime *runtime = substream->runtime;54 struct imx_pcm_runtime_data *iprtd = runtime->private_data;55 struct pt_regs regs;05657 get_fiq_regs(®s);58···62 else63 iprtd->offset = regs.ARM_r9 & 0xffff;6465- iprtd->timer.expires = jiffies + iprtd->period_time;000000000000000066 add_timer(&iprtd->timer);67- snd_pcm_period_elapsed(substream);68}6970static struct fiq_handler fh = {···9596 iprtd->size = params_buffer_bytes(params);97 iprtd->periods = params_periods(params);98- iprtd->period = params_period_bytes(params);99 iprtd->offset = 0;100- iprtd->period_time = HZ / (params_rate(params) / params_period_size(params));0101102 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);103···134 case SNDRV_PCM_TRIGGER_START:135 case SNDRV_PCM_TRIGGER_RESUME:136 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:137- iprtd->timer.expires = jiffies + iprtd->period_time;138 add_timer(&iprtd->timer);139 if (++fiq_enable == 1)140 enable_fiq(imx_pcm_fiq);
···35struct imx_pcm_runtime_data {36 int period;37 int periods;0038 unsigned long offset;39+ unsigned long last_offset;40 unsigned long size;0041 struct timer_list timer;42+ int poll_time;43};44+45+static inline void imx_ssi_set_next_poll(struct imx_pcm_runtime_data *iprtd)46+{47+ iprtd->timer.expires = jiffies + iprtd->poll_time;48+}4950static void imx_ssi_timer_callback(unsigned long data)51{···51 struct snd_pcm_runtime *runtime = substream->runtime;52 struct imx_pcm_runtime_data *iprtd = runtime->private_data;53 struct pt_regs regs;54+ unsigned long delta;5556 get_fiq_regs(®s);57···59 else60 iprtd->offset = regs.ARM_r9 & 0xffff;6162+ /* How much data have we transferred since the last period report? */63+ if (iprtd->offset >= iprtd->last_offset)64+ delta = iprtd->offset - iprtd->last_offset;65+ else66+ delta = runtime->buffer_size + iprtd->offset67+ - iprtd->last_offset;68+69+ /* If we've transferred at least a period then report it and70+ * reset our poll time */71+ if (delta >= runtime->period_size) {72+ snd_pcm_period_elapsed(substream);73+ iprtd->last_offset = iprtd->offset;74+75+ imx_ssi_set_next_poll(iprtd);76+ }77+78+ /* Restart the timer; if we didn't report we'll run on the next tick */79 add_timer(&iprtd->timer);80+81}8283static struct fiq_handler fh = {···7677 iprtd->size = params_buffer_bytes(params);78 iprtd->periods = params_periods(params);79+ iprtd->period = params_period_bytes(params) ;80 iprtd->offset = 0;81+ iprtd->last_offset = 0;82+ iprtd->poll_time = HZ / (params_rate(params) / params_period_size(params));8384 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);85···114 case SNDRV_PCM_TRIGGER_START:115 case SNDRV_PCM_TRIGGER_RESUME:116 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:117+ imx_ssi_set_next_poll(iprtd);118 add_timer(&iprtd->timer);119 if (++fiq_enable == 1)120 enable_fiq(imx_pcm_fiq);