2 * fireworks_hwdep.c - a part of driver for Fireworks based devices
4 * Copyright (c) 2013-2014 Takashi Sakamoto
6 * Licensed under the terms of the GNU General Public License, version 2.
10 * This codes have five functionalities.
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
20 #include "fireworks.h"
23 hwdep_read_resp_buf(struct snd_efw
*efw
, char __user
*buf
, long remained
,
26 unsigned int length
, till_end
, type
;
27 struct snd_efw_transaction
*t
;
30 if (remained
< sizeof(type
) + sizeof(struct snd_efw_transaction
))
33 /* data type is SNDRV_FIREWIRE_EVENT_EFW_RESPONSE */
34 type
= SNDRV_FIREWIRE_EVENT_EFW_RESPONSE
;
35 if (copy_to_user(buf
, &type
, sizeof(type
)))
37 remained
-= sizeof(type
);
40 /* write into buffer as many responses as possible */
41 while (efw
->resp_queues
> 0) {
42 t
= (struct snd_efw_transaction
*)(efw
->pull_ptr
);
43 length
= be32_to_cpu(t
->length
) * sizeof(__be32
);
45 /* confirm enough space for this response */
46 if (remained
< length
)
49 /* copy from ring buffer to user buffer */
51 till_end
= snd_efw_resp_buf_size
-
52 (unsigned int)(efw
->pull_ptr
- efw
->resp_buf
);
53 till_end
= min_t(unsigned int, length
, till_end
);
55 if (copy_to_user(buf
, efw
->pull_ptr
, till_end
))
58 efw
->pull_ptr
+= till_end
;
59 if (efw
->pull_ptr
>= efw
->resp_buf
+
60 snd_efw_resp_buf_size
)
61 efw
->pull_ptr
-= snd_efw_resp_buf_size
;
76 hwdep_read_locked(struct snd_efw
*efw
, char __user
*buf
, long count
,
79 union snd_firewire_event event
;
81 memset(&event
, 0, sizeof(event
));
83 event
.lock_status
.type
= SNDRV_FIREWIRE_EVENT_LOCK_STATUS
;
84 event
.lock_status
.status
= (efw
->dev_lock_count
> 0);
85 efw
->dev_lock_changed
= false;
87 count
= min_t(long, count
, sizeof(event
.lock_status
));
89 if (copy_to_user(buf
, &event
, count
))
96 hwdep_read(struct snd_hwdep
*hwdep
, char __user
*buf
, long count
,
99 struct snd_efw
*efw
= hwdep
->private_data
;
102 spin_lock_irq(&efw
->lock
);
104 while ((!efw
->dev_lock_changed
) && (efw
->resp_queues
== 0)) {
105 prepare_to_wait(&efw
->hwdep_wait
, &wait
, TASK_INTERRUPTIBLE
);
106 spin_unlock_irq(&efw
->lock
);
108 finish_wait(&efw
->hwdep_wait
, &wait
);
109 if (signal_pending(current
))
111 spin_lock_irq(&efw
->lock
);
114 if (efw
->dev_lock_changed
)
115 count
= hwdep_read_locked(efw
, buf
, count
, offset
);
116 else if (efw
->resp_queues
> 0)
117 count
= hwdep_read_resp_buf(efw
, buf
, count
, offset
);
119 spin_unlock_irq(&efw
->lock
);
125 hwdep_write(struct snd_hwdep
*hwdep
, const char __user
*data
, long count
,
128 struct snd_efw
*efw
= hwdep
->private_data
;
132 if (count
< sizeof(struct snd_efw_transaction
) ||
133 SND_EFW_RESPONSE_MAXIMUM_BYTES
< count
)
136 buf
= memdup_user(data
, count
);
140 /* check seqnum is not for kernel-land */
141 seqnum
= be32_to_cpu(((struct snd_efw_transaction
*)buf
)->seqnum
);
142 if (seqnum
> SND_EFW_TRANSACTION_USER_SEQNUM_MAX
) {
147 if (snd_efw_transaction_cmd(efw
->unit
, buf
, count
) < 0)
155 hwdep_poll(struct snd_hwdep
*hwdep
, struct file
*file
, poll_table
*wait
)
157 struct snd_efw
*efw
= hwdep
->private_data
;
160 poll_wait(file
, &efw
->hwdep_wait
, wait
);
162 spin_lock_irq(&efw
->lock
);
163 if (efw
->dev_lock_changed
|| (efw
->resp_queues
> 0))
164 events
= POLLIN
| POLLRDNORM
;
167 spin_unlock_irq(&efw
->lock
);
169 return events
| POLLOUT
;
173 hwdep_get_info(struct snd_efw
*efw
, void __user
*arg
)
175 struct fw_device
*dev
= fw_parent_device(efw
->unit
);
176 struct snd_firewire_get_info info
;
178 memset(&info
, 0, sizeof(info
));
179 info
.type
= SNDRV_FIREWIRE_TYPE_FIREWORKS
;
180 info
.card
= dev
->card
->index
;
181 *(__be32
*)&info
.guid
[0] = cpu_to_be32(dev
->config_rom
[3]);
182 *(__be32
*)&info
.guid
[4] = cpu_to_be32(dev
->config_rom
[4]);
183 strlcpy(info
.device_name
, dev_name(&dev
->device
),
184 sizeof(info
.device_name
));
186 if (copy_to_user(arg
, &info
, sizeof(info
)))
193 hwdep_lock(struct snd_efw
*efw
)
197 spin_lock_irq(&efw
->lock
);
199 if (efw
->dev_lock_count
== 0) {
200 efw
->dev_lock_count
= -1;
206 spin_unlock_irq(&efw
->lock
);
212 hwdep_unlock(struct snd_efw
*efw
)
216 spin_lock_irq(&efw
->lock
);
218 if (efw
->dev_lock_count
== -1) {
219 efw
->dev_lock_count
= 0;
225 spin_unlock_irq(&efw
->lock
);
231 hwdep_release(struct snd_hwdep
*hwdep
, struct file
*file
)
233 struct snd_efw
*efw
= hwdep
->private_data
;
235 spin_lock_irq(&efw
->lock
);
236 if (efw
->dev_lock_count
== -1)
237 efw
->dev_lock_count
= 0;
238 spin_unlock_irq(&efw
->lock
);
244 hwdep_ioctl(struct snd_hwdep
*hwdep
, struct file
*file
,
245 unsigned int cmd
, unsigned long arg
)
247 struct snd_efw
*efw
= hwdep
->private_data
;
250 case SNDRV_FIREWIRE_IOCTL_GET_INFO
:
251 return hwdep_get_info(efw
, (void __user
*)arg
);
252 case SNDRV_FIREWIRE_IOCTL_LOCK
:
253 return hwdep_lock(efw
);
254 case SNDRV_FIREWIRE_IOCTL_UNLOCK
:
255 return hwdep_unlock(efw
);
263 hwdep_compat_ioctl(struct snd_hwdep
*hwdep
, struct file
*file
,
264 unsigned int cmd
, unsigned long arg
)
266 return hwdep_ioctl(hwdep
, file
, cmd
,
267 (unsigned long)compat_ptr(arg
));
270 #define hwdep_compat_ioctl NULL
273 static const struct snd_hwdep_ops hwdep_ops
= {
275 .write
= hwdep_write
,
276 .release
= hwdep_release
,
278 .ioctl
= hwdep_ioctl
,
279 .ioctl_compat
= hwdep_compat_ioctl
,
282 int snd_efw_create_hwdep_device(struct snd_efw
*efw
)
284 struct snd_hwdep
*hwdep
;
287 err
= snd_hwdep_new(efw
->card
, "Fireworks", 0, &hwdep
);
290 strcpy(hwdep
->name
, "Fireworks");
291 hwdep
->iface
= SNDRV_HWDEP_IFACE_FW_FIREWORKS
;
292 hwdep
->ops
= hwdep_ops
;
293 hwdep
->private_data
= efw
;
294 hwdep
->exclusive
= true;