forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-10-22 8ac6c7a54ed1b98d142dce24b11c6de6a1e239a5
kernel/sound/firewire/tascam/tascam-hwdep.c
....@@ -1,9 +1,8 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * tascam-hwdep.c - a part of driver for TASCAM FireWire series
34 *
45 * Copyright (c) 2015 Takashi Sakamoto
5
- *
6
- * Licensed under the terms of the GNU General Public License, version 2.
76 */
87
98 /*
....@@ -16,18 +15,95 @@
1615
1716 #include "tascam.h"
1817
18
+static long tscm_hwdep_read_locked(struct snd_tscm *tscm, char __user *buf,
19
+ long count, loff_t *offset)
20
+ __releases(&tscm->lock)
21
+{
22
+ struct snd_firewire_event_lock_status event = {
23
+ .type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS,
24
+ };
25
+
26
+ event.status = (tscm->dev_lock_count > 0);
27
+ tscm->dev_lock_changed = false;
28
+ count = min_t(long, count, sizeof(event));
29
+
30
+ spin_unlock_irq(&tscm->lock);
31
+
32
+ if (copy_to_user(buf, &event, count))
33
+ return -EFAULT;
34
+
35
+ return count;
36
+}
37
+
38
+static long tscm_hwdep_read_queue(struct snd_tscm *tscm, char __user *buf,
39
+ long remained, loff_t *offset)
40
+ __releases(&tscm->lock)
41
+{
42
+ char __user *pos = buf;
43
+ unsigned int type = SNDRV_FIREWIRE_EVENT_TASCAM_CONTROL;
44
+ struct snd_firewire_tascam_change *entries = tscm->queue;
45
+ long count;
46
+
47
+ // At least, one control event can be copied.
48
+ if (remained < sizeof(type) + sizeof(*entries)) {
49
+ spin_unlock_irq(&tscm->lock);
50
+ return -EINVAL;
51
+ }
52
+
53
+ // Copy the type field later.
54
+ count = sizeof(type);
55
+ remained -= sizeof(type);
56
+ pos += sizeof(type);
57
+
58
+ while (true) {
59
+ unsigned int head_pos;
60
+ unsigned int tail_pos;
61
+ unsigned int length;
62
+
63
+ if (tscm->pull_pos == tscm->push_pos)
64
+ break;
65
+ else if (tscm->pull_pos < tscm->push_pos)
66
+ tail_pos = tscm->push_pos;
67
+ else
68
+ tail_pos = SND_TSCM_QUEUE_COUNT;
69
+ head_pos = tscm->pull_pos;
70
+
71
+ length = (tail_pos - head_pos) * sizeof(*entries);
72
+ if (remained < length)
73
+ length = rounddown(remained, sizeof(*entries));
74
+ if (length == 0)
75
+ break;
76
+
77
+ spin_unlock_irq(&tscm->lock);
78
+ if (copy_to_user(pos, &entries[head_pos], length))
79
+ return -EFAULT;
80
+
81
+ spin_lock_irq(&tscm->lock);
82
+
83
+ tscm->pull_pos = tail_pos % SND_TSCM_QUEUE_COUNT;
84
+
85
+ count += length;
86
+ remained -= length;
87
+ pos += length;
88
+ }
89
+
90
+ spin_unlock_irq(&tscm->lock);
91
+
92
+ if (copy_to_user(buf, &type, sizeof(type)))
93
+ return -EFAULT;
94
+
95
+ return count;
96
+}
97
+
1998 static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
2099 loff_t *offset)
21100 {
22101 struct snd_tscm *tscm = hwdep->private_data;
23102 DEFINE_WAIT(wait);
24
- union snd_firewire_event event = {
25
- .lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS,
26
- };
27103
28104 spin_lock_irq(&tscm->lock);
29105
30
- while (!tscm->dev_lock_changed) {
106
+ while (!tscm->dev_lock_changed && tscm->push_pos == tscm->pull_pos) {
31107 prepare_to_wait(&tscm->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
32108 spin_unlock_irq(&tscm->lock);
33109 schedule();
....@@ -37,15 +113,15 @@
37113 spin_lock_irq(&tscm->lock);
38114 }
39115
40
- event.lock_status.status = (tscm->dev_lock_count > 0);
41
- tscm->dev_lock_changed = false;
42
-
43
- spin_unlock_irq(&tscm->lock);
44
-
45
- count = min_t(long, count, sizeof(event.lock_status));
46
-
47
- if (copy_to_user(buf, &event, count))
48
- return -EFAULT;
116
+ // NOTE: The acquired lock should be released in callee side.
117
+ if (tscm->dev_lock_changed) {
118
+ count = tscm_hwdep_read_locked(tscm, buf, count, offset);
119
+ } else if (tscm->push_pos != tscm->pull_pos) {
120
+ count = tscm_hwdep_read_queue(tscm, buf, count, offset);
121
+ } else {
122
+ spin_unlock_irq(&tscm->lock);
123
+ count = 0;
124
+ }
49125
50126 return count;
51127 }
....@@ -59,7 +135,7 @@
59135 poll_wait(file, &tscm->hwdep_wait, wait);
60136
61137 spin_lock_irq(&tscm->lock);
62
- if (tscm->dev_lock_changed)
138
+ if (tscm->dev_lock_changed || tscm->push_pos != tscm->pull_pos)
63139 events = EPOLLIN | EPOLLRDNORM;
64140 else
65141 events = 0;
....@@ -123,6 +199,14 @@
123199 return err;
124200 }
125201
202
+static int tscm_hwdep_state(struct snd_tscm *tscm, void __user *arg)
203
+{
204
+ if (copy_to_user(arg, tscm->state, sizeof(tscm->state)))
205
+ return -EFAULT;
206
+
207
+ return 0;
208
+}
209
+
126210 static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
127211 {
128212 struct snd_tscm *tscm = hwdep->private_data;
....@@ -147,6 +231,8 @@
147231 return hwdep_lock(tscm);
148232 case SNDRV_FIREWIRE_IOCTL_UNLOCK:
149233 return hwdep_unlock(tscm);
234
+ case SNDRV_FIREWIRE_IOCTL_TASCAM_STATE:
235
+ return tscm_hwdep_state(tscm, (void __user *)arg);
150236 default:
151237 return -ENOIOCTLCMD;
152238 }
....@@ -185,5 +271,7 @@
185271 hwdep->private_data = tscm;
186272 hwdep->exclusive = true;
187273
274
+ tscm->hwdep = hwdep;
275
+
188276 return err;
189277 }