LCOV - code coverage report
Current view: top level - sound/core - hrtimer.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 16 77 20.8 %
Date: 2022-04-01 14:58:12 Functions: 1 7 14.3 %
Branches: 2 24 8.3 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-or-later
       2                 :            : /*
       3                 :            :  * ALSA timer back-end using hrtimer
       4                 :            :  * Copyright (C) 2008 Takashi Iwai
       5                 :            :  */
       6                 :            : 
       7                 :            : #include <linux/init.h>
       8                 :            : #include <linux/slab.h>
       9                 :            : #include <linux/module.h>
      10                 :            : #include <linux/moduleparam.h>
      11                 :            : #include <linux/hrtimer.h>
      12                 :            : #include <sound/core.h>
      13                 :            : #include <sound/timer.h>
      14                 :            : 
      15                 :            : MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
      16                 :            : MODULE_DESCRIPTION("ALSA hrtimer backend");
      17                 :            : MODULE_LICENSE("GPL");
      18                 :            : 
      19                 :            : MODULE_ALIAS("snd-timer-" __stringify(SNDRV_TIMER_GLOBAL_HRTIMER));
      20                 :            : 
      21                 :            : #define NANO_SEC        1000000000UL    /* 10^9 in sec */
      22                 :            : static unsigned int resolution;
      23                 :            : 
      24                 :            : struct snd_hrtimer {
      25                 :            :         struct snd_timer *timer;
      26                 :            :         struct hrtimer hrt;
      27                 :            :         bool in_callback;
      28                 :            : };
      29                 :            : 
      30                 :          0 : static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)
      31                 :            : {
      32                 :          0 :         struct snd_hrtimer *stime = container_of(hrt, struct snd_hrtimer, hrt);
      33                 :          0 :         struct snd_timer *t = stime->timer;
      34                 :          0 :         ktime_t delta;
      35                 :          0 :         unsigned long ticks;
      36                 :          0 :         enum hrtimer_restart ret = HRTIMER_NORESTART;
      37                 :            : 
      38                 :          0 :         spin_lock(&t->lock);
      39         [ #  # ]:          0 :         if (!t->running)
      40                 :          0 :                 goto out; /* fast path */
      41                 :          0 :         stime->in_callback = true;
      42                 :          0 :         ticks = t->sticks;
      43                 :          0 :         spin_unlock(&t->lock);
      44                 :            : 
      45                 :            :         /* calculate the drift */
      46         [ #  # ]:          0 :         delta = ktime_sub(hrt->base->get_time(), hrtimer_get_expires(hrt));
      47         [ #  # ]:          0 :         if (delta > 0)
      48         [ #  # ]:          0 :                 ticks += ktime_divns(delta, ticks * resolution);
      49                 :            : 
      50                 :          0 :         snd_timer_interrupt(stime->timer, ticks);
      51                 :            : 
      52                 :          0 :         spin_lock(&t->lock);
      53         [ #  # ]:          0 :         if (t->running) {
      54                 :          0 :                 hrtimer_add_expires_ns(hrt, t->sticks * resolution);
      55                 :          0 :                 ret = HRTIMER_RESTART;
      56                 :            :         }
      57                 :            : 
      58                 :          0 :         stime->in_callback = false;
      59                 :          0 :  out:
      60                 :          0 :         spin_unlock(&t->lock);
      61                 :          0 :         return ret;
      62                 :            : }
      63                 :            : 
      64                 :          0 : static int snd_hrtimer_open(struct snd_timer *t)
      65                 :            : {
      66                 :          0 :         struct snd_hrtimer *stime;
      67                 :            : 
      68                 :          0 :         stime = kzalloc(sizeof(*stime), GFP_KERNEL);
      69         [ #  # ]:          0 :         if (!stime)
      70                 :            :                 return -ENOMEM;
      71                 :          0 :         hrtimer_init(&stime->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
      72                 :          0 :         stime->timer = t;
      73                 :          0 :         stime->hrt.function = snd_hrtimer_callback;
      74                 :          0 :         t->private_data = stime;
      75                 :          0 :         return 0;
      76                 :            : }
      77                 :            : 
      78                 :          0 : static int snd_hrtimer_close(struct snd_timer *t)
      79                 :            : {
      80                 :          0 :         struct snd_hrtimer *stime = t->private_data;
      81                 :            : 
      82         [ #  # ]:          0 :         if (stime) {
      83                 :          0 :                 spin_lock_irq(&t->lock);
      84                 :          0 :                 t->running = 0; /* just to be sure */
      85                 :          0 :                 stime->in_callback = 1; /* skip start/stop */
      86                 :          0 :                 spin_unlock_irq(&t->lock);
      87                 :            : 
      88                 :          0 :                 hrtimer_cancel(&stime->hrt);
      89                 :          0 :                 kfree(stime);
      90                 :          0 :                 t->private_data = NULL;
      91                 :            :         }
      92                 :          0 :         return 0;
      93                 :            : }
      94                 :            : 
      95                 :          0 : static int snd_hrtimer_start(struct snd_timer *t)
      96                 :            : {
      97                 :          0 :         struct snd_hrtimer *stime = t->private_data;
      98                 :            : 
      99         [ #  # ]:          0 :         if (stime->in_callback)
     100                 :            :                 return 0;
     101                 :          0 :         hrtimer_start(&stime->hrt, ns_to_ktime(t->sticks * resolution),
     102                 :            :                       HRTIMER_MODE_REL);
     103                 :          0 :         return 0;
     104                 :            : }
     105                 :            : 
     106                 :          0 : static int snd_hrtimer_stop(struct snd_timer *t)
     107                 :            : {
     108                 :          0 :         struct snd_hrtimer *stime = t->private_data;
     109                 :            : 
     110         [ #  # ]:          0 :         if (stime->in_callback)
     111                 :            :                 return 0;
     112                 :          0 :         hrtimer_try_to_cancel(&stime->hrt);
     113                 :          0 :         return 0;
     114                 :            : }
     115                 :            : 
     116                 :            : static const struct snd_timer_hardware hrtimer_hw __initconst = {
     117                 :            :         .flags =        SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_TASKLET,
     118                 :            :         .open =         snd_hrtimer_open,
     119                 :            :         .close =        snd_hrtimer_close,
     120                 :            :         .start =        snd_hrtimer_start,
     121                 :            :         .stop =         snd_hrtimer_stop,
     122                 :            : };
     123                 :            : 
     124                 :            : /*
     125                 :            :  * entry functions
     126                 :            :  */
     127                 :            : 
     128                 :            : static struct snd_timer *mytimer;
     129                 :            : 
     130                 :          3 : static int __init snd_hrtimer_init(void)
     131                 :            : {
     132                 :          3 :         struct snd_timer *timer;
     133                 :          3 :         int err;
     134                 :            : 
     135                 :          3 :         resolution = hrtimer_resolution;
     136                 :            : 
     137                 :            :         /* Create a new timer and set up the fields */
     138                 :          3 :         err = snd_timer_global_new("hrtimer", SNDRV_TIMER_GLOBAL_HRTIMER,
     139                 :            :                                    &timer);
     140         [ +  - ]:          3 :         if (err < 0)
     141                 :            :                 return err;
     142                 :            : 
     143                 :          3 :         timer->module = THIS_MODULE;
     144                 :          3 :         strcpy(timer->name, "HR timer");
     145                 :          3 :         timer->hw = hrtimer_hw;
     146                 :          3 :         timer->hw.resolution = resolution;
     147                 :          3 :         timer->hw.ticks = NANO_SEC / resolution;
     148                 :          3 :         timer->max_instances = 100; /* lower the limit */
     149                 :            : 
     150                 :          3 :         err = snd_timer_global_register(timer);
     151         [ -  + ]:          3 :         if (err < 0) {
     152                 :          0 :                 snd_timer_global_free(timer);
     153                 :          0 :                 return err;
     154                 :            :         }
     155                 :          3 :         mytimer = timer; /* remember this */
     156                 :            : 
     157                 :          3 :         return 0;
     158                 :            : }
     159                 :            : 
     160                 :          0 : static void __exit snd_hrtimer_exit(void)
     161                 :            : {
     162         [ #  # ]:          0 :         if (mytimer) {
     163                 :          0 :                 snd_timer_global_free(mytimer);
     164                 :          0 :                 mytimer = NULL;
     165                 :            :         }
     166                 :          0 : }
     167                 :            : 
     168                 :            : module_init(snd_hrtimer_init);
     169                 :            : module_exit(snd_hrtimer_exit);

Generated by: LCOV version 1.14