clk: imx: correct i.MX7D AV PLL num/denom offset
[sfrench/cifs-2.6.git] / sound / firewire / fireworks / fireworks_hwdep.c
1 /*
2  * fireworks_hwdep.c - a part of driver for Fireworks based devices
3  *
4  * Copyright (c) 2013-2014 Takashi Sakamoto
5  *
6  * Licensed under the terms of the GNU General Public License, version 2.
7  */
8
9 /*
10  * This codes have five functionalities.
11  *
12  * 1.get information about firewire node
13  * 2.get notification about starting/stopping stream
14  * 3.lock/unlock streaming
15  * 4.transmit command of EFW transaction
16  * 5.receive response of EFW transaction
17  *
18  */
19
20 #include "fireworks.h"
21
22 static long
23 hwdep_read_resp_buf(struct snd_efw *efw, char __user *buf, long remained,
24                     loff_t *offset)
25 {
26         unsigned int length, till_end, type;
27         struct snd_efw_transaction *t;
28         u8 *pull_ptr;
29         long count = 0;
30
31         if (remained < sizeof(type) + sizeof(struct snd_efw_transaction))
32                 return -ENOSPC;
33
34         /* data type is SNDRV_FIREWIRE_EVENT_EFW_RESPONSE */
35         type = SNDRV_FIREWIRE_EVENT_EFW_RESPONSE;
36         if (copy_to_user(buf, &type, sizeof(type)))
37                 return -EFAULT;
38         remained -= sizeof(type);
39         buf += sizeof(type);
40
41         /* write into buffer as many responses as possible */
42         spin_lock_irq(&efw->lock);
43
44         /*
45          * When another task reaches here during this task's access to user
46          * space, it picks up current position in buffer and can read the same
47          * series of responses.
48          */
49         pull_ptr = efw->pull_ptr;
50
51         while (efw->push_ptr != pull_ptr) {
52                 t = (struct snd_efw_transaction *)(pull_ptr);
53                 length = be32_to_cpu(t->length) * sizeof(__be32);
54
55                 /* confirm enough space for this response */
56                 if (remained < length)
57                         break;
58
59                 /* copy from ring buffer to user buffer */
60                 while (length > 0) {
61                         till_end = snd_efw_resp_buf_size -
62                                 (unsigned int)(pull_ptr - efw->resp_buf);
63                         till_end = min_t(unsigned int, length, till_end);
64
65                         spin_unlock_irq(&efw->lock);
66
67                         if (copy_to_user(buf, pull_ptr, till_end))
68                                 return -EFAULT;
69
70                         spin_lock_irq(&efw->lock);
71
72                         pull_ptr += till_end;
73                         if (pull_ptr >= efw->resp_buf + snd_efw_resp_buf_size)
74                                 pull_ptr -= snd_efw_resp_buf_size;
75
76                         length -= till_end;
77                         buf += till_end;
78                         count += till_end;
79                         remained -= till_end;
80                 }
81         }
82
83         /*
84          * All of tasks can read from the buffer nearly simultaneously, but the
85          * last position for each task is different depending on the length of
86          * given buffer. Here, for simplicity, a position of buffer is set by
87          * the latest task. It's better for a listening application to allow one
88          * thread to read from the buffer. Unless, each task can read different
89          * sequence of responses depending on variation of buffer length.
90          */
91         efw->pull_ptr = pull_ptr;
92
93         spin_unlock_irq(&efw->lock);
94
95         return count;
96 }
97
98 static long
99 hwdep_read_locked(struct snd_efw *efw, char __user *buf, long count,
100                   loff_t *offset)
101 {
102         union snd_firewire_event event = {
103                 .lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS,
104         };
105
106         spin_lock_irq(&efw->lock);
107
108         event.lock_status.status = (efw->dev_lock_count > 0);
109         efw->dev_lock_changed = false;
110
111         spin_unlock_irq(&efw->lock);
112
113         count = min_t(long, count, sizeof(event.lock_status));
114
115         if (copy_to_user(buf, &event, count))
116                 return -EFAULT;
117
118         return count;
119 }
120
121 static long
122 hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
123            loff_t *offset)
124 {
125         struct snd_efw *efw = hwdep->private_data;
126         DEFINE_WAIT(wait);
127         bool dev_lock_changed;
128         bool queued;
129
130         spin_lock_irq(&efw->lock);
131
132         dev_lock_changed = efw->dev_lock_changed;
133         queued = efw->push_ptr != efw->pull_ptr;
134
135         while (!dev_lock_changed && !queued) {
136                 prepare_to_wait(&efw->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
137                 spin_unlock_irq(&efw->lock);
138                 schedule();
139                 finish_wait(&efw->hwdep_wait, &wait);
140                 if (signal_pending(current))
141                         return -ERESTARTSYS;
142                 spin_lock_irq(&efw->lock);
143                 dev_lock_changed = efw->dev_lock_changed;
144                 queued = efw->push_ptr != efw->pull_ptr;
145         }
146
147         spin_unlock_irq(&efw->lock);
148
149         if (dev_lock_changed)
150                 count = hwdep_read_locked(efw, buf, count, offset);
151         else if (queued)
152                 count = hwdep_read_resp_buf(efw, buf, count, offset);
153
154         return count;
155 }
156
157 static long
158 hwdep_write(struct snd_hwdep *hwdep, const char __user *data, long count,
159             loff_t *offset)
160 {
161         struct snd_efw *efw = hwdep->private_data;
162         u32 seqnum;
163         u8 *buf;
164
165         if (count < sizeof(struct snd_efw_transaction) ||
166             SND_EFW_RESPONSE_MAXIMUM_BYTES < count)
167                 return -EINVAL;
168
169         buf = memdup_user(data, count);
170         if (IS_ERR(buf))
171                 return PTR_ERR(buf);
172
173         /* check seqnum is not for kernel-land */
174         seqnum = be32_to_cpu(((struct snd_efw_transaction *)buf)->seqnum);
175         if (seqnum > SND_EFW_TRANSACTION_USER_SEQNUM_MAX) {
176                 count = -EINVAL;
177                 goto end;
178         }
179
180         if (snd_efw_transaction_cmd(efw->unit, buf, count) < 0)
181                 count = -EIO;
182 end:
183         kfree(buf);
184         return count;
185 }
186
187 static __poll_t
188 hwdep_poll(struct snd_hwdep *hwdep, struct file *file, poll_table *wait)
189 {
190         struct snd_efw *efw = hwdep->private_data;
191         __poll_t events;
192
193         poll_wait(file, &efw->hwdep_wait, wait);
194
195         spin_lock_irq(&efw->lock);
196         if (efw->dev_lock_changed || efw->pull_ptr != efw->push_ptr)
197                 events = EPOLLIN | EPOLLRDNORM;
198         else
199                 events = 0;
200         spin_unlock_irq(&efw->lock);
201
202         return events | EPOLLOUT;
203 }
204
205 static int
206 hwdep_get_info(struct snd_efw *efw, void __user *arg)
207 {
208         struct fw_device *dev = fw_parent_device(efw->unit);
209         struct snd_firewire_get_info info;
210
211         memset(&info, 0, sizeof(info));
212         info.type = SNDRV_FIREWIRE_TYPE_FIREWORKS;
213         info.card = dev->card->index;
214         *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
215         *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
216         strlcpy(info.device_name, dev_name(&dev->device),
217                 sizeof(info.device_name));
218
219         if (copy_to_user(arg, &info, sizeof(info)))
220                 return -EFAULT;
221
222         return 0;
223 }
224
225 static int
226 hwdep_lock(struct snd_efw *efw)
227 {
228         int err;
229
230         spin_lock_irq(&efw->lock);
231
232         if (efw->dev_lock_count == 0) {
233                 efw->dev_lock_count = -1;
234                 err = 0;
235         } else {
236                 err = -EBUSY;
237         }
238
239         spin_unlock_irq(&efw->lock);
240
241         return err;
242 }
243
244 static int
245 hwdep_unlock(struct snd_efw *efw)
246 {
247         int err;
248
249         spin_lock_irq(&efw->lock);
250
251         if (efw->dev_lock_count == -1) {
252                 efw->dev_lock_count = 0;
253                 err = 0;
254         } else {
255                 err = -EBADFD;
256         }
257
258         spin_unlock_irq(&efw->lock);
259
260         return err;
261 }
262
263 static int
264 hwdep_release(struct snd_hwdep *hwdep, struct file *file)
265 {
266         struct snd_efw *efw = hwdep->private_data;
267
268         spin_lock_irq(&efw->lock);
269         if (efw->dev_lock_count == -1)
270                 efw->dev_lock_count = 0;
271         spin_unlock_irq(&efw->lock);
272
273         return 0;
274 }
275
276 static int
277 hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
278             unsigned int cmd, unsigned long arg)
279 {
280         struct snd_efw *efw = hwdep->private_data;
281
282         switch (cmd) {
283         case SNDRV_FIREWIRE_IOCTL_GET_INFO:
284                 return hwdep_get_info(efw, (void __user *)arg);
285         case SNDRV_FIREWIRE_IOCTL_LOCK:
286                 return hwdep_lock(efw);
287         case SNDRV_FIREWIRE_IOCTL_UNLOCK:
288                 return hwdep_unlock(efw);
289         default:
290                 return -ENOIOCTLCMD;
291         }
292 }
293
294 #ifdef CONFIG_COMPAT
295 static int
296 hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
297                    unsigned int cmd, unsigned long arg)
298 {
299         return hwdep_ioctl(hwdep, file, cmd,
300                            (unsigned long)compat_ptr(arg));
301 }
302 #else
303 #define hwdep_compat_ioctl NULL
304 #endif
305
306 int snd_efw_create_hwdep_device(struct snd_efw *efw)
307 {
308         static const struct snd_hwdep_ops ops = {
309                 .read           = hwdep_read,
310                 .write          = hwdep_write,
311                 .release        = hwdep_release,
312                 .poll           = hwdep_poll,
313                 .ioctl          = hwdep_ioctl,
314                 .ioctl_compat   = hwdep_compat_ioctl,
315         };
316         struct snd_hwdep *hwdep;
317         int err;
318
319         err = snd_hwdep_new(efw->card, "Fireworks", 0, &hwdep);
320         if (err < 0)
321                 goto end;
322         strcpy(hwdep->name, "Fireworks");
323         hwdep->iface = SNDRV_HWDEP_IFACE_FW_FIREWORKS;
324         hwdep->ops = ops;
325         hwdep->private_data = efw;
326         hwdep->exclusive = true;
327 end:
328         return err;
329 }
330