[alsa-devel] [RFC][PATCH 26/37] ALSA: firewire-tascam: add MMAP support to show status and control message
Takashi Iwai
tiwai at suse.de
Mon Jul 20 16:23:40 CEST 2015
On Sat, 11 Jul 2015 16:12:37 +0200,
Takashi Sakamoto wrote:
>
> TASCAM FireWire series transfers status and control messages in
> isochronous packets. One packet includes one message, and the
> message is periodic every 64 packets. As a result, the messages
> construct image with 64 quadlets. For example:
>
> 00 00000000, 32 00000000
> 01 00000000, 33 00000000
> 02 00000000, 34 00000000
> 03 00020000, 35 00000000
> 04 00000000, 36 25ea0000
> 05 ffff0000, 37 27dfff00
> 06 ffffffff, 38 1d9d0000
> 07 ffffffff, 39 00000000
> 08 ffffffff, 40 25ea0000
> 09 ffffffff, 41 27dfff00
> 10 00000000, 42 00000000
> 11 00000000, 43 00000000
> 12 00000000, 44 00000000
> 13 00000000, 45 00000000
> 14 00000000, 46 00000000
> 15 00010000, 47 00000000
> 16 00012e00, 48 00000000
> 17 00010400, 49 00000000
> 18 00011e00, 50 00000000
> 19 00011200, 51 00000000
> 20 00014900, 52 01010101
> 21 00011e00, 53 00000000
> 22 00010c00, 54 25ea0000
> 23 00013000, 55 27dfff00
> 24 00000000, 56 00000000
> 25 00000000, 57 00000000
> 26 00000000, 58 00000000
> 27 00000000, 59 00000001
> 28 00000000, 60 00000000
> 29 00000000, 61 00000000
> 30 00000000, 62 00000000
> 31 00000000, 63 00000000
>
> Quadlet 00-15 show control messages. Quadlet 16-23 show analog input
> level. Quadlet 24-31 shows digital ADAT input level. Quadlet 32-33
> shows digital S/PDIF input level. Quadlet 34-35 is unknown. Quadlet
> 36-43 shows analog output level. The other quadlets are unknown.
>
> This image is updated every 1 msec or less, depending on current
> sampling transfer frequency.
>
> This commit adds MMAP support to show this image via hwdep interface.
> An userspace application can map a page frame to its virtual address
> space with read-only flag. This driver write every control and status
> messages into the page frame, and the userspace application can parse
> them.
>
> The control messages are both of edge-triggered/level-trigerred,
> according to physical implementation. For example, the control message
> corresponding to toggle switch acts as edge-trigger, while the control
> message corresponding to level fader acts as level-trigger. These control
> messages are updated every 1 msec or less, alghough the scheduling
> granuality in Linux operating system is not always so small. This may
> cause the userspace parser misses some messages when many tasks are
> running without voluntary programs.
>
> Typically, such messages should be converted to MIDI control change
> messages for userspace applications. Thus, this driver should have
> a converter with appropriate MIDI map. Currently I have no good idea
> for the map and it is not implemented yet. Developers helps are
> required.
>
> Cc: Yoshifuji Hideaki <yoshfuji at linux-ipv6.org>
> Signed-off-by: Takashi Sakamoto <o-takashi at sakamocchi.jp>
Using mmap for accessing this kind of message isn't good for various
reasons. First off, it's volatile, and your implementation keeps only
a single record, thus it will be overridden at each input.
Second, the access is racy.
Third, the mmap implementation can be complex if a cache coherency
plays a role. It's easy on x86, but for others...
And the rest... there must be something else I overlooked obviously
(I don't count a bug here, e.g. the lack of offset value check in vm
fault handler :)
thanks,
Takashi
> ---
> include/uapi/sound/firewire.h | 4 ++++
> sound/firewire/tascam/amdtp-tascam.c | 4 +++-
> sound/firewire/tascam/tascam-hwdep.c | 30 ++++++++++++++++++++++++++++++
> sound/firewire/tascam/tascam-stream.c | 15 +++++++++++++++
> sound/firewire/tascam/tascam.h | 3 +++
> 5 files changed, 55 insertions(+), 1 deletion(-)
>
> diff --git a/include/uapi/sound/firewire.h b/include/uapi/sound/firewire.h
> index db79a12..c5cb86d 100644
> --- a/include/uapi/sound/firewire.h
> +++ b/include/uapi/sound/firewire.h
> @@ -79,4 +79,8 @@ struct snd_firewire_get_info {
> * Returns -EBUSY if the driver is already streaming.
> */
>
> +struct snd_firewire_tascam_status {
> + __u32 status[64];
> +};
> +
> #endif /* _UAPI_SOUND_FIREWIRE_H_INCLUDED */
> diff --git a/sound/firewire/tascam/amdtp-tascam.c b/sound/firewire/tascam/amdtp-tascam.c
> index 22c2eaf..ca54b85 100644
> --- a/sound/firewire/tascam/amdtp-tascam.c
> +++ b/sound/firewire/tascam/amdtp-tascam.c
> @@ -155,14 +155,16 @@ void amdtp_tscm_set_pcm_format(struct amdtp_stream *s, snd_pcm_format_t format)
> static void read_control_messages(struct amdtp_stream *s,
> __be32 *buffer, unsigned int data_blocks)
> {
> + struct snd_tscm *tscm = container_of(s, struct snd_tscm, tx_stream);
> unsigned int first, index = 0;
> unsigned int i;
>
> first = (buffer[0] >> 15) % 64;
>
> - /* TODO */
> for (i = 0; i < data_blocks; i++) {
> index = be32_to_cpu(buffer[0]) % 64;
> + tscm->status->status[index] =
> + be32_to_cpu(buffer[s->data_block_quadlets - 1]);
> buffer += s->data_block_quadlets;
> }
> }
> diff --git a/sound/firewire/tascam/tascam-hwdep.c b/sound/firewire/tascam/tascam-hwdep.c
> index 4b539f5..fe51fee 100644
> --- a/sound/firewire/tascam/tascam-hwdep.c
> +++ b/sound/firewire/tascam/tascam-hwdep.c
> @@ -175,12 +175,42 @@ static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
> #define hwdep_compat_ioctl NULL
> #endif
>
> +static int hwdep_vm_fault(struct vm_area_struct *area, struct vm_fault *vmf)
> +{
> + struct snd_tscm *tscm = area->vm_private_data;
> + void *virt_addr;
> + struct page *page;
> +
> + /* The page is already allocated by streaming layer. */
> + virt_addr = (char *)(tscm->status) + (vmf->pgoff << PAGE_SHIFT);
> + page = virt_to_page(virt_addr);
> + get_page(page);
> + vmf->page = page;
> +
> + return 0;
> +}
> +
> +static const struct vm_operations_struct hwdep_vm_ops = {
> + .fault = hwdep_vm_fault,
> +};
> +
> +static int hwdep_mmap(struct snd_hwdep *hwdep, struct file *filp,
> + struct vm_area_struct *area)
> +{
> + area->vm_ops = &hwdep_vm_ops;
> + area->vm_flags = VM_READ | VM_RAND_READ | VM_DONTEXPAND;
> + area->vm_private_data = hwdep->private_data;
> +
> + return 0;
> +}
> +
> static const struct snd_hwdep_ops hwdep_ops = {
> .read = hwdep_read,
> .release = hwdep_release,
> .poll = hwdep_poll,
> .ioctl = hwdep_ioctl,
> .ioctl_compat = hwdep_compat_ioctl,
> + .mmap = hwdep_mmap,
> };
>
> int snd_tscm_create_hwdep_device(struct snd_tscm *tscm)
> diff --git a/sound/firewire/tascam/tascam-stream.c b/sound/firewire/tascam/tascam-stream.c
> index 23124fb..83f437e 100644
> --- a/sound/firewire/tascam/tascam-stream.c
> +++ b/sound/firewire/tascam/tascam-stream.c
> @@ -314,6 +314,7 @@ error:
> int snd_tscm_stream_init_duplex(struct snd_tscm *tscm)
> {
> unsigned int pcm_channels;
> + unsigned int size;
> int err;
>
> /* For out-stream. */
> @@ -344,6 +345,15 @@ int snd_tscm_stream_init_duplex(struct snd_tscm *tscm)
> if (err < 0)
> amdtp_stream_destroy(&tscm->rx_stream);
>
> + /* For control messages. */
> + size = sizeof(struct snd_firewire_tascam_status);
> + tscm->status = snd_malloc_pages(size, GFP_KERNEL);
> + if (tscm->status == NULL) {
> + amdtp_stream_destroy(&tscm->tx_stream);
> + amdtp_stream_destroy(&tscm->rx_stream);
> + return -ENOMEM;
> + }
> +
> return 0;
> }
>
> @@ -363,11 +373,16 @@ void snd_tscm_stream_update_duplex(struct snd_tscm *tscm)
> */
> void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm)
> {
> + unsigned int size;
> +
> amdtp_stream_destroy(&tscm->rx_stream);
> amdtp_stream_destroy(&tscm->tx_stream);
>
> fw_iso_resources_destroy(&tscm->rx_resources);
> fw_iso_resources_destroy(&tscm->tx_resources);
> +
> + size = sizeof(struct snd_firewire_tascam_status);
> + snd_free_pages(tscm->status, size);
> }
>
> int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
> diff --git a/sound/firewire/tascam/tascam.h b/sound/firewire/tascam/tascam.h
> index 053a8bf..0340693 100644
> --- a/sound/firewire/tascam/tascam.h
> +++ b/sound/firewire/tascam/tascam.h
> @@ -70,6 +70,9 @@ struct snd_tscm {
> int dev_lock_count;
> bool dev_lock_changed;
> wait_queue_head_t hwdep_wait;
> +
> + /* For control messages. */
> + struct snd_firewire_tascam_status *status;
> };
>
> #define TSCM_ADDR_BASE 0xffff00000000ull
> --
> 2.1.4
>
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel at alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
>
More information about the Alsa-devel
mailing list