2 * digi00x-hwdep.c - a part of driver for Digidesign Digi 002/003 family
4 * Copyright (c) 2014-2015 Takashi Sakamoto
6 * Licensed under the terms of the GNU General Public License, version 2.
10 * This codes give three functionality.
12 * 1.get firewire node information
13 * 2.get notification about starting/stopping stream
14 * 3.lock/unlock stream
15 * 4.get asynchronous messaging
20 static long hwdep_read(struct snd_hwdep
*hwdep
, char __user
*buf
, long count
,
23 struct snd_dg00x
*dg00x
= hwdep
->private_data
;
25 union snd_firewire_event event
;
27 spin_lock_irq(&dg00x
->lock
);
29 while (!dg00x
->dev_lock_changed
&& dg00x
->msg
== 0) {
30 prepare_to_wait(&dg00x
->hwdep_wait
, &wait
, TASK_INTERRUPTIBLE
);
31 spin_unlock_irq(&dg00x
->lock
);
33 finish_wait(&dg00x
->hwdep_wait
, &wait
);
34 if (signal_pending(current
))
36 spin_lock_irq(&dg00x
->lock
);
39 memset(&event
, 0, sizeof(event
));
40 if (dg00x
->dev_lock_changed
) {
41 event
.lock_status
.type
= SNDRV_FIREWIRE_EVENT_LOCK_STATUS
;
42 event
.lock_status
.status
= (dg00x
->dev_lock_count
> 0);
43 dg00x
->dev_lock_changed
= false;
45 count
= min_t(long, count
, sizeof(event
.lock_status
));
47 event
.digi00x_message
.type
=
48 SNDRV_FIREWIRE_EVENT_DIGI00X_MESSAGE
;
49 event
.digi00x_message
.message
= dg00x
->msg
;
52 count
= min_t(long, count
, sizeof(event
.digi00x_message
));
55 spin_unlock_irq(&dg00x
->lock
);
57 if (copy_to_user(buf
, &event
, count
))
63 static unsigned int hwdep_poll(struct snd_hwdep
*hwdep
, struct file
*file
,
66 struct snd_dg00x
*dg00x
= hwdep
->private_data
;
69 poll_wait(file
, &dg00x
->hwdep_wait
, wait
);
71 spin_lock_irq(&dg00x
->lock
);
72 if (dg00x
->dev_lock_changed
|| dg00x
->msg
)
73 events
= POLLIN
| POLLRDNORM
;
76 spin_unlock_irq(&dg00x
->lock
);
81 static int hwdep_get_info(struct snd_dg00x
*dg00x
, void __user
*arg
)
83 struct fw_device
*dev
= fw_parent_device(dg00x
->unit
);
84 struct snd_firewire_get_info info
;
86 memset(&info
, 0, sizeof(info
));
87 info
.type
= SNDRV_FIREWIRE_TYPE_DIGI00X
;
88 info
.card
= dev
->card
->index
;
89 *(__be32
*)&info
.guid
[0] = cpu_to_be32(dev
->config_rom
[3]);
90 *(__be32
*)&info
.guid
[4] = cpu_to_be32(dev
->config_rom
[4]);
91 strlcpy(info
.device_name
, dev_name(&dev
->device
),
92 sizeof(info
.device_name
));
94 if (copy_to_user(arg
, &info
, sizeof(info
)))
100 static int hwdep_lock(struct snd_dg00x
*dg00x
)
104 spin_lock_irq(&dg00x
->lock
);
106 if (dg00x
->dev_lock_count
== 0) {
107 dg00x
->dev_lock_count
= -1;
113 spin_unlock_irq(&dg00x
->lock
);
118 static int hwdep_unlock(struct snd_dg00x
*dg00x
)
122 spin_lock_irq(&dg00x
->lock
);
124 if (dg00x
->dev_lock_count
== -1) {
125 dg00x
->dev_lock_count
= 0;
131 spin_unlock_irq(&dg00x
->lock
);
136 static int hwdep_release(struct snd_hwdep
*hwdep
, struct file
*file
)
138 struct snd_dg00x
*dg00x
= hwdep
->private_data
;
140 spin_lock_irq(&dg00x
->lock
);
141 if (dg00x
->dev_lock_count
== -1)
142 dg00x
->dev_lock_count
= 0;
143 spin_unlock_irq(&dg00x
->lock
);
148 static int hwdep_ioctl(struct snd_hwdep
*hwdep
, struct file
*file
,
149 unsigned int cmd
, unsigned long arg
)
151 struct snd_dg00x
*dg00x
= hwdep
->private_data
;
154 case SNDRV_FIREWIRE_IOCTL_GET_INFO
:
155 return hwdep_get_info(dg00x
, (void __user
*)arg
);
156 case SNDRV_FIREWIRE_IOCTL_LOCK
:
157 return hwdep_lock(dg00x
);
158 case SNDRV_FIREWIRE_IOCTL_UNLOCK
:
159 return hwdep_unlock(dg00x
);
166 static int hwdep_compat_ioctl(struct snd_hwdep
*hwdep
, struct file
*file
,
167 unsigned int cmd
, unsigned long arg
)
169 return hwdep_ioctl(hwdep
, file
, cmd
,
170 (unsigned long)compat_ptr(arg
));
173 #define hwdep_compat_ioctl NULL
176 static const struct snd_hwdep_ops hwdep_ops
= {
178 .release
= hwdep_release
,
180 .ioctl
= hwdep_ioctl
,
181 .ioctl_compat
= hwdep_compat_ioctl
,
184 int snd_dg00x_create_hwdep_device(struct snd_dg00x
*dg00x
)
186 struct snd_hwdep
*hwdep
;
189 err
= snd_hwdep_new(dg00x
->card
, "Digi00x", 0, &hwdep
);
193 strcpy(hwdep
->name
, "Digi00x");
194 hwdep
->iface
= SNDRV_HWDEP_IFACE_FW_DIGI00X
;
195 hwdep
->ops
= hwdep_ops
;
196 hwdep
->private_data
= dg00x
;
197 hwdep
->exclusive
= true;