/*
   forward-alsa.h - ALSA driver for SoftLab-NSK Forward boards

   Copyright (C) 2017 - 2024 SoftLab-NSK <forward@softlab.tv>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; either version 2
   of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#ifndef FORWARD_ALSA_H
#define FORWARD_ALSA_H

#include "forward.h"

#include <sound/pcm.h>

#define FORWARD_ALSA_MODULE_NAME "forward-alsa"

#define FORWARD_ALSA_MAX_SDI_GROUPS (4)
#define FORWARD_ALSA_IRQ_PRIORITY -1
#define FORWARD_ALSA_MAX_RESYNC_FRAMES 48 * 10
#define FORWARD_ALSA_RFC3190_TAG 0x1F

struct forward_alsa_io;
struct forward_alsa_dev_ops;

enum forward_alsa_stream_type {
	FORWARD_ALSA_RAW,
	FORWARD_ALSA_SMPTE_272,
	FORWARD_ALSA_SMPTE_299,
	FORWARD_ALSA_HDMI,
	FORWARD_ALSA_RFC3190,
	FORWARD_ALSA_RAW_24BE,
	FORWARD_ALSA_RAW_20BE,
	FORWARD_ALSA_RAW_16BE
};

struct forward_alsa {
	struct forward_dev *dev;
	struct snd_card *card;

	struct forward_alsa_io *io;
	const struct forward_alsa_dev_ops *ops;
};

struct forward_alsa_dev_ops {
	int (*init_io)(struct forward_alsa_io *io);
	void (*fini_io)(struct forward_alsa_io *io);

	forward_irq_t (*irq_mask)(const struct forward_alsa_io *io);

	bool (*irq_info)(const struct forward_alsa_io *io, const forward_irq_t *irq, int *offset,
			 size_t *size, bool *field);

	void (*buffer_info)(const struct forward_alsa_io *io, u32 *address, size_t *size);

	void (*fill_hw)(struct forward_alsa_io *io, struct snd_pcm_hardware *hw);

	void (*update_format)(struct forward_alsa_io *io);

	int (*start)(struct forward_alsa_io *io);
	void (*stop)(struct forward_alsa_io *io);
};

int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t size);
void snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs);
struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, unsigned long offset);

#define forward_alsa_ptr_add(x, v, runtime)                                     \
	{                                                                       \
		snd_pcm_sframes_t tmp = (x) + (v);                              \
		if (unlikely(tmp >= (snd_pcm_sframes_t)(runtime)->buffer_size)) \
			tmp %= (runtime)->buffer_size;                          \
		(x) = tmp;                                                      \
	}

#define forward_alsa_ptr_inc(x, runtime) forward_alsa_ptr_add(x, 1, runtime)

#endif
