From 071106ecf68c401173c58808b1cf5f68cc50d390 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Fri, 05 Jan 2024 08:39:27 +0000 Subject: [PATCH] change wifi driver to cypress --- kernel/sound/firewire/tascam/tascam-hwdep.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 files changed, 104 insertions(+), 16 deletions(-) diff --git a/kernel/sound/firewire/tascam/tascam-hwdep.c b/kernel/sound/firewire/tascam/tascam-hwdep.c index 4e4c1e9..6f38335 100644 --- a/kernel/sound/firewire/tascam/tascam-hwdep.c +++ b/kernel/sound/firewire/tascam/tascam-hwdep.c @@ -1,9 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * tascam-hwdep.c - a part of driver for TASCAM FireWire series * * Copyright (c) 2015 Takashi Sakamoto - * - * Licensed under the terms of the GNU General Public License, version 2. */ /* @@ -16,18 +15,95 @@ #include "tascam.h" +static long tscm_hwdep_read_locked(struct snd_tscm *tscm, char __user *buf, + long count, loff_t *offset) + __releases(&tscm->lock) +{ + struct snd_firewire_event_lock_status event = { + .type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS, + }; + + event.status = (tscm->dev_lock_count > 0); + tscm->dev_lock_changed = false; + count = min_t(long, count, sizeof(event)); + + spin_unlock_irq(&tscm->lock); + + if (copy_to_user(buf, &event, count)) + return -EFAULT; + + return count; +} + +static long tscm_hwdep_read_queue(struct snd_tscm *tscm, char __user *buf, + long remained, loff_t *offset) + __releases(&tscm->lock) +{ + char __user *pos = buf; + unsigned int type = SNDRV_FIREWIRE_EVENT_TASCAM_CONTROL; + struct snd_firewire_tascam_change *entries = tscm->queue; + long count; + + // At least, one control event can be copied. + if (remained < sizeof(type) + sizeof(*entries)) { + spin_unlock_irq(&tscm->lock); + return -EINVAL; + } + + // Copy the type field later. + count = sizeof(type); + remained -= sizeof(type); + pos += sizeof(type); + + while (true) { + unsigned int head_pos; + unsigned int tail_pos; + unsigned int length; + + if (tscm->pull_pos == tscm->push_pos) + break; + else if (tscm->pull_pos < tscm->push_pos) + tail_pos = tscm->push_pos; + else + tail_pos = SND_TSCM_QUEUE_COUNT; + head_pos = tscm->pull_pos; + + length = (tail_pos - head_pos) * sizeof(*entries); + if (remained < length) + length = rounddown(remained, sizeof(*entries)); + if (length == 0) + break; + + spin_unlock_irq(&tscm->lock); + if (copy_to_user(pos, &entries[head_pos], length)) + return -EFAULT; + + spin_lock_irq(&tscm->lock); + + tscm->pull_pos = tail_pos % SND_TSCM_QUEUE_COUNT; + + count += length; + remained -= length; + pos += length; + } + + spin_unlock_irq(&tscm->lock); + + if (copy_to_user(buf, &type, sizeof(type))) + return -EFAULT; + + return count; +} + static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, loff_t *offset) { struct snd_tscm *tscm = hwdep->private_data; DEFINE_WAIT(wait); - union snd_firewire_event event = { - .lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS, - }; spin_lock_irq(&tscm->lock); - while (!tscm->dev_lock_changed) { + while (!tscm->dev_lock_changed && tscm->push_pos == tscm->pull_pos) { prepare_to_wait(&tscm->hwdep_wait, &wait, TASK_INTERRUPTIBLE); spin_unlock_irq(&tscm->lock); schedule(); @@ -37,15 +113,15 @@ spin_lock_irq(&tscm->lock); } - event.lock_status.status = (tscm->dev_lock_count > 0); - tscm->dev_lock_changed = false; - - spin_unlock_irq(&tscm->lock); - - count = min_t(long, count, sizeof(event.lock_status)); - - if (copy_to_user(buf, &event, count)) - return -EFAULT; + // NOTE: The acquired lock should be released in callee side. + if (tscm->dev_lock_changed) { + count = tscm_hwdep_read_locked(tscm, buf, count, offset); + } else if (tscm->push_pos != tscm->pull_pos) { + count = tscm_hwdep_read_queue(tscm, buf, count, offset); + } else { + spin_unlock_irq(&tscm->lock); + count = 0; + } return count; } @@ -59,7 +135,7 @@ poll_wait(file, &tscm->hwdep_wait, wait); spin_lock_irq(&tscm->lock); - if (tscm->dev_lock_changed) + if (tscm->dev_lock_changed || tscm->push_pos != tscm->pull_pos) events = EPOLLIN | EPOLLRDNORM; else events = 0; @@ -123,6 +199,14 @@ return err; } +static int tscm_hwdep_state(struct snd_tscm *tscm, void __user *arg) +{ + if (copy_to_user(arg, tscm->state, sizeof(tscm->state))) + return -EFAULT; + + return 0; +} + static int hwdep_release(struct snd_hwdep *hwdep, struct file *file) { struct snd_tscm *tscm = hwdep->private_data; @@ -147,6 +231,8 @@ return hwdep_lock(tscm); case SNDRV_FIREWIRE_IOCTL_UNLOCK: return hwdep_unlock(tscm); + case SNDRV_FIREWIRE_IOCTL_TASCAM_STATE: + return tscm_hwdep_state(tscm, (void __user *)arg); default: return -ENOIOCTLCMD; } @@ -185,5 +271,7 @@ hwdep->private_data = tscm; hwdep->exclusive = true; + tscm->hwdep = hwdep; + return err; } -- Gitblit v1.6.2