--- zzzz-none-000/linux-3.10.107/sound/core/timer.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/sound/core/timer.c 2021-02-04 17:41:59.000000000 +0000 @@ -35,9 +35,9 @@ #include #include -#if defined(CONFIG_SND_HRTIMER) || defined(CONFIG_SND_HRTIMER_MODULE) +#if IS_ENABLED(CONFIG_SND_HRTIMER) #define DEFAULT_TIMER_LIMIT 4 -#elif defined(CONFIG_SND_RTCTIMER) || defined(CONFIG_SND_RTCTIMER_MODULE) +#elif IS_ENABLED(CONFIG_SND_RTCTIMER) #define DEFAULT_TIMER_LIMIT 2 #else #define DEFAULT_TIMER_LIMIT 1 @@ -65,6 +65,7 @@ int qtail; int qused; int queue_size; + bool disconnected; struct snd_timer_read *queue; struct snd_timer_tread *tqueue; spinlock_t qlock; @@ -242,7 +243,8 @@ /* open a slave instance */ if (tid->dev_sclass <= SNDRV_TIMER_SCLASS_NONE || tid->dev_sclass > SNDRV_TIMER_SCLASS_OSS_SEQUENCER) { - snd_printd("invalid slave class %i\n", tid->dev_sclass); + pr_debug("ALSA: timer: invalid slave class %i\n", + tid->dev_sclass); return -EINVAL; } mutex_lock(®ister_mutex); @@ -289,6 +291,9 @@ mutex_unlock(®ister_mutex); return -ENOMEM; } + /* take a card refcount for safe disconnection */ + if (timer->card) + get_device(&timer->card->card_dev); timeri->slave_class = tid->dev_sclass; timeri->slave_id = slave_id; @@ -298,6 +303,8 @@ kfree(timeri->owner); kfree(timeri); + if (timer->card) + put_device(&timer->card->card_dev); module_put(timer->module); mutex_unlock(®ister_mutex); return err; @@ -369,6 +376,9 @@ } spin_unlock(&timer->lock); spin_unlock_irq(&slave_active_lock); + /* release a card refcount for safe disconnection */ + if (timer->card) + put_device(&timer->card->card_dev); mutex_unlock(®ister_mutex); } out: @@ -404,7 +414,7 @@ struct timespec tstamp; if (timer_tstamp_monotonic) - do_posix_clock_monotonic_gettime(&tstamp); + ktime_get_ts(&tstamp); else getnstimeofday(&tstamp); if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_START || @@ -489,6 +499,8 @@ timer = timeri->timer; if (timer == NULL) return -EINVAL; + if (timer->card && timer->card->shutdown) + return -ENODEV; spin_lock_irqsave(&timer->lock, flags); if (timeri->flags & (SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START)) { @@ -540,6 +552,10 @@ } list_del_init(&timeri->ack_list); list_del_init(&timeri->active_list); + if (timer->card && timer->card->shutdown) { + spin_unlock_irqrestore(&timer->lock, flags); + return 0; + } if ((timeri->flags & SNDRV_TIMER_IFLG_RUNNING) && !(--timer->running)) { timer->hw.stop(timer); @@ -600,6 +616,8 @@ timer = timeri->timer; if (! timer) return -EINVAL; + if (timer->card && timer->card->shutdown) + return -ENODEV; spin_lock_irqsave(&timer->lock, flags); if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) { result = -EBUSY; @@ -668,6 +686,9 @@ unsigned long resolution, ticks; unsigned long flags; + if (timer->card && timer->card->shutdown) + return; + spin_lock_irqsave(&timer->lock, flags); /* now process all callbacks */ while (!list_empty(&timer->sack_list_head)) { @@ -708,6 +729,9 @@ if (timer == NULL) return; + if (timer->card && timer->card->shutdown) + return; + spin_lock_irqsave(&timer->lock, flags); /* remember the current resolution */ @@ -818,10 +842,8 @@ if (rtimer) *rtimer = NULL; timer = kzalloc(sizeof(*timer), GFP_KERNEL); - if (timer == NULL) { - snd_printk(KERN_ERR "timer: cannot allocate\n"); + if (!timer) return -ENOMEM; - } timer->tmr_class = tid->dev_class; timer->card = card; timer->tmr_device = tid->device; @@ -859,7 +881,7 @@ if (! list_empty(&timer->open_list_head)) { struct list_head *p, *n; struct snd_timer_instance *ti; - snd_printk(KERN_WARNING "timer %p is busy?\n", timer); + pr_warn("ALSA: timer %p is busy?\n", timer); list_for_each_safe(p, n, &timer->open_list_head) { list_del_init(p); ti = list_entry(p, struct snd_timer_instance, open_list); @@ -921,11 +943,28 @@ return 0; } +/* just for reference in snd_timer_dev_disconnect() below */ +static void snd_timer_user_ccallback(struct snd_timer_instance *timeri, + int event, struct timespec *tstamp, + unsigned long resolution); + static int snd_timer_dev_disconnect(struct snd_device *device) { struct snd_timer *timer = device->device_data; + struct snd_timer_instance *ti; + mutex_lock(®ister_mutex); list_del_init(&timer->device_list); + /* wake up pending sleepers */ + list_for_each_entry(ti, &timer->open_list_head, open_list) { + /* FIXME: better to have a ti.disconnect() op */ + if (ti->ccallback == snd_timer_user_ccallback) { + struct snd_timer_user *tu = ti->callback_data; + + tu->disconnected = true; + wake_up(&tu->qchange_sleep); + } + } mutex_unlock(®ister_mutex); return 0; } @@ -936,6 +975,8 @@ unsigned long resolution = 0; struct snd_timer_instance *ti, *ts; + if (timer->card && timer->card->shutdown) + return; if (! (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)) return; if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_MSTART || @@ -1075,15 +1116,13 @@ snd_timer_free(timer); return -ENOMEM; } - init_timer(&priv->tlist); - priv->tlist.function = snd_timer_s_function; - priv->tlist.data = (unsigned long) timer; + setup_timer(&priv->tlist, snd_timer_s_function, (unsigned long) timer); timer->private_data = priv; timer->private_free = snd_timer_free_system; return snd_timer_global_register(timer); } -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_SND_PROC_FS /* * Info interface */ @@ -1096,6 +1135,8 @@ mutex_lock(®ister_mutex); list_for_each_entry(timer, &snd_timer_list, device_list) { + if (timer->card && timer->card->shutdown) + continue; switch (timer->tmr_class) { case SNDRV_TIMER_CLASS_GLOBAL: snd_iprintf(buffer, "G%i: ", timer->tmr_device); @@ -1153,7 +1194,7 @@ { snd_info_free_entry(snd_timer_proc_entry); } -#else /* !CONFIG_PROC_FS */ +#else /* !CONFIG_SND_PROC_FS */ #define snd_timer_proc_init() #define snd_timer_proc_done() #endif @@ -1249,7 +1290,7 @@ } if (tu->last_resolution != resolution || ticks > 0) { if (timer_tstamp_monotonic) - do_posix_clock_monotonic_gettime(&tstamp); + ktime_get_ts(&tstamp); else getnstimeofday(&tstamp); } @@ -1912,6 +1953,7 @@ { struct snd_timer_user *tu; long result = 0, unit; + int qhead; int err = 0; tu = file->private_data; @@ -1923,7 +1965,7 @@ if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) { err = -EAGAIN; - break; + goto _error; } set_current_state(TASK_INTERRUPTIBLE); @@ -1936,44 +1978,41 @@ remove_wait_queue(&tu->qchange_sleep, &wait); + if (tu->disconnected) { + err = -ENODEV; + goto _error; + } if (signal_pending(current)) { err = -ERESTARTSYS; - break; + goto _error; } } + qhead = tu->qhead++; + tu->qhead %= tu->queue_size; + tu->qused--; spin_unlock_irq(&tu->qlock); - if (err < 0) - goto _error; mutex_lock(&tu->ioctl_lock); if (tu->tread) { - if (copy_to_user(buffer, &tu->tqueue[tu->qhead++], - sizeof(struct snd_timer_tread))) { - mutex_unlock(&tu->ioctl_lock); + if (copy_to_user(buffer, &tu->tqueue[qhead], + sizeof(struct snd_timer_tread))) err = -EFAULT; - goto _error; - } } else { - if (copy_to_user(buffer, &tu->queue[tu->qhead++], - sizeof(struct snd_timer_read))) { - mutex_unlock(&tu->ioctl_lock); + if (copy_to_user(buffer, &tu->queue[qhead], + sizeof(struct snd_timer_read))) err = -EFAULT; - goto _error; - } } mutex_unlock(&tu->ioctl_lock); - tu->qhead %= tu->queue_size; - + spin_lock_irq(&tu->qlock); + if (err < 0) + goto _error; result += unit; buffer += unit; - - spin_lock_irq(&tu->qlock); - tu->qused--; } - spin_unlock_irq(&tu->qlock); _error: + spin_unlock_irq(&tu->qlock); return result > 0 ? result : err; } @@ -1989,6 +2028,8 @@ mask = 0; if (tu->qused) mask |= POLLIN | POLLRDNORM; + if (tu->disconnected) + mask |= POLLERR; return mask; } @@ -2012,6 +2053,17 @@ .fasync = snd_timer_user_fasync, }; +/* unregister the system timer */ +static void snd_timer_free_all(void) +{ + struct snd_timer *timer, *n; + + list_for_each_entry_safe(timer, n, &snd_timer_list, device_list) + snd_timer_free(timer); +} + +static struct device timer_dev; + /* * ENTRY functions */ @@ -2020,32 +2072,39 @@ { int err; + snd_device_initialize(&timer_dev, NULL); + dev_set_name(&timer_dev, "timer"); + #ifdef SNDRV_OSS_INFO_DEV_TIMERS snd_oss_info_register(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1, "system timer"); #endif - if ((err = snd_timer_register_system()) < 0) - snd_printk(KERN_ERR "unable to register system timer (%i)\n", - err); - if ((err = snd_register_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0, - &snd_timer_f_ops, NULL, "timer")) < 0) - snd_printk(KERN_ERR "unable to register timer device (%i)\n", - err); + err = snd_timer_register_system(); + if (err < 0) { + pr_err("ALSA: unable to register system timer (%i)\n", err); + put_device(&timer_dev); + return err; + } + + err = snd_register_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0, + &snd_timer_f_ops, NULL, &timer_dev); + if (err < 0) { + pr_err("ALSA: unable to register timer device (%i)\n", err); + snd_timer_free_all(); + put_device(&timer_dev); + return err; + } + snd_timer_proc_init(); return 0; } static void __exit alsa_timer_exit(void) { - struct list_head *p, *n; - - snd_unregister_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0); - /* unregister the system timer */ - list_for_each_safe(p, n, &snd_timer_list) { - struct snd_timer *timer = list_entry(p, struct snd_timer, device_list); - snd_timer_free(timer); - } + snd_unregister_device(&timer_dev); + snd_timer_free_all(); + put_device(&timer_dev); snd_timer_proc_done(); #ifdef SNDRV_OSS_INFO_DEV_TIMERS snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1);