Something went wrong. Try again.
(I'm so sorry!) Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204// SPDX-License-Identifier: GPL-2.0-or-later/* * Misc and compatibility things * Copyright (c) by Jaroslav Kysela <perex@perex.cz> */
#include <linux/init.h>#include <linux/export.h>#include <linux/moduleparam.h>#include <linux/time.h>#include <linux/slab.h>#include <linux/ioport.h>#include <linux/fs.h>#include <sound/core.h>
void release_and_free_resource(struct resource *res){ if (res) { release_resource(res); kfree(res); }}EXPORT_SYMBOL(release_and_free_resource);
#ifdef CONFIG_PCI#include <linux/pci.h>/** * snd_pci_quirk_lookup_id - look up a PCI SSID quirk list * @vendor: PCI SSV id * @device: PCI SSD id * @list: quirk list, terminated by a null entry * * Look through the given quirk list and finds a matching entry * with the same PCI SSID. When subdevice is 0, all subdevice * values may match. * * Returns the matched entry pointer, or NULL if nothing matched. */const struct snd_pci_quirk *snd_pci_quirk_lookup_id(u16 vendor, u16 device, const struct snd_pci_quirk *list){ const struct snd_pci_quirk *q;
for (q = list; q->subvendor || q->subdevice; q++) { if (q->subvendor != vendor) continue; if (!q->subdevice || (device & q->subdevice_mask) == q->subdevice) return q; } return NULL;}EXPORT_SYMBOL(snd_pci_quirk_lookup_id);
/** * snd_pci_quirk_lookup - look up a PCI SSID quirk list * @pci: pci_dev handle * @list: quirk list, terminated by a null entry * * Look through the given quirk list and finds a matching entry * with the same PCI SSID. When subdevice is 0, all subdevice * values may match. * * Returns the matched entry pointer, or NULL if nothing matched. */const struct snd_pci_quirk *snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list){ if (!pci) return NULL; return snd_pci_quirk_lookup_id(pci->subsystem_vendor, pci->subsystem_device, list);}EXPORT_SYMBOL(snd_pci_quirk_lookup);#endif
/* * Deferred async signal helpers * * Below are a few helper functions to wrap the async signal handling * in the deferred work. The main purpose is to avoid the messy deadlock * around tasklist_lock and co at the kill_fasync() invocation. * fasync_helper() and kill_fasync() are replaced with snd_fasync_helper() * and snd_kill_fasync(), respectively. In addition, snd_fasync_free() has * to be called at releasing the relevant file object. */struct snd_fasync { struct fasync_struct *fasync; int signal; int poll; int on; struct list_head list;};
static DEFINE_SPINLOCK(snd_fasync_lock);static LIST_HEAD(snd_fasync_list);
static void snd_fasync_work_fn(struct work_struct *work){ struct snd_fasync *fasync; int signal, poll;
spin_lock_irq(&snd_fasync_lock); while (!list_empty(&snd_fasync_list)) { fasync = list_first_entry(&snd_fasync_list, struct snd_fasync, list); list_del_init(&fasync->list); if (!fasync->on) continue; signal = fasync->signal; poll = fasync->poll; spin_unlock_irq(&snd_fasync_lock); kill_fasync(&fasync->fasync, signal, poll); spin_lock_irq(&snd_fasync_lock); } spin_unlock_irq(&snd_fasync_lock);}
static DECLARE_WORK(snd_fasync_work, snd_fasync_work_fn);
int snd_fasync_helper(int fd, struct file *file, int on, struct snd_fasync **fasyncp){ struct snd_fasync *fasync = NULL;
if (on) { fasync = kzalloc_obj(*fasync); if (!fasync) return -ENOMEM; INIT_LIST_HEAD(&fasync->list); }
scoped_guard(spinlock_irq, &snd_fasync_lock) { if (*fasyncp) { kfree(fasync); fasync = *fasyncp; } else { if (!fasync) return 0; *fasyncp = fasync; } fasync->on = on; } return fasync_helper(fd, file, on, &fasync->fasync);}EXPORT_SYMBOL_GPL(snd_fasync_helper);
void snd_kill_fasync(struct snd_fasync *fasync, int signal, int poll){ if (!fasync) return; guard(spinlock_irqsave)(&snd_fasync_lock); if (!fasync->on) return; fasync->signal = signal; fasync->poll = poll; list_move(&fasync->list, &snd_fasync_list); schedule_work(&snd_fasync_work);}EXPORT_SYMBOL_GPL(snd_kill_fasync);
void snd_fasync_free(struct snd_fasync *fasync){ if (!fasync) return;
scoped_guard(spinlock_irq, &snd_fasync_lock) { fasync->on = 0; list_del_init(&fasync->list); }
flush_work(&snd_fasync_work); kfree(fasync);}EXPORT_SYMBOL_GPL(snd_fasync_free);
/* * generic refcount helper */
void snd_refcount_init(struct snd_refcount *ref){ atomic_set(&ref->count, 0); init_waitqueue_head(&ref->waiter); spin_lock_init(&ref->lock);}EXPORT_SYMBOL_GPL(snd_refcount_init);
void snd_refcount_put(struct snd_refcount *ref){ guard(spinlock_irqsave)(&ref->lock); if (atomic_dec_and_test(&ref->count)) wake_up(&ref->waiter);}EXPORT_SYMBOL_GPL(snd_refcount_put);
void snd_refcount_sync(struct snd_refcount *ref){ guard(spinlock_irq)(&ref->lock); wait_event_lock_irq(ref->waiter, !atomic_read(&ref->count), ref->lock);}EXPORT_SYMBOL_GPL(snd_refcount_sync);