18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
48c2ecf20Sopenharmony_ci *  GUS's memory access via proc filesystem
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/slab.h>
88c2ecf20Sopenharmony_ci#include <sound/core.h>
98c2ecf20Sopenharmony_ci#include <sound/gus.h>
108c2ecf20Sopenharmony_ci#include <sound/info.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_cistruct gus_proc_private {
138c2ecf20Sopenharmony_ci	int rom;		/* data are in ROM */
148c2ecf20Sopenharmony_ci	unsigned int address;
158c2ecf20Sopenharmony_ci	unsigned int size;
168c2ecf20Sopenharmony_ci	struct snd_gus_card * gus;
178c2ecf20Sopenharmony_ci};
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistatic ssize_t snd_gf1_mem_proc_dump(struct snd_info_entry *entry,
208c2ecf20Sopenharmony_ci				     void *file_private_data,
218c2ecf20Sopenharmony_ci				     struct file *file, char __user *buf,
228c2ecf20Sopenharmony_ci				     size_t count, loff_t pos)
238c2ecf20Sopenharmony_ci{
248c2ecf20Sopenharmony_ci	struct gus_proc_private *priv = entry->private_data;
258c2ecf20Sopenharmony_ci	struct snd_gus_card *gus = priv->gus;
268c2ecf20Sopenharmony_ci	int err;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	err = snd_gus_dram_read(gus, buf, pos, count, priv->rom);
298c2ecf20Sopenharmony_ci	if (err < 0)
308c2ecf20Sopenharmony_ci		return err;
318c2ecf20Sopenharmony_ci	return count;
328c2ecf20Sopenharmony_ci}
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic void snd_gf1_mem_proc_free(struct snd_info_entry *entry)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	struct gus_proc_private *priv = entry->private_data;
378c2ecf20Sopenharmony_ci	kfree(priv);
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic const struct snd_info_entry_ops snd_gf1_mem_proc_ops = {
418c2ecf20Sopenharmony_ci	.read = snd_gf1_mem_proc_dump,
428c2ecf20Sopenharmony_ci};
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ciint snd_gf1_mem_proc_init(struct snd_gus_card * gus)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	int idx;
478c2ecf20Sopenharmony_ci	char name[16];
488c2ecf20Sopenharmony_ci	struct gus_proc_private *priv;
498c2ecf20Sopenharmony_ci	struct snd_info_entry *entry;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	for (idx = 0; idx < 4; idx++) {
528c2ecf20Sopenharmony_ci		if (gus->gf1.mem_alloc.banks_8[idx].size > 0) {
538c2ecf20Sopenharmony_ci			priv = kzalloc(sizeof(*priv), GFP_KERNEL);
548c2ecf20Sopenharmony_ci			if (priv == NULL)
558c2ecf20Sopenharmony_ci				return -ENOMEM;
568c2ecf20Sopenharmony_ci			priv->gus = gus;
578c2ecf20Sopenharmony_ci			sprintf(name, "gus-ram-%i", idx);
588c2ecf20Sopenharmony_ci			if (! snd_card_proc_new(gus->card, name, &entry)) {
598c2ecf20Sopenharmony_ci				entry->content = SNDRV_INFO_CONTENT_DATA;
608c2ecf20Sopenharmony_ci				entry->private_data = priv;
618c2ecf20Sopenharmony_ci				entry->private_free = snd_gf1_mem_proc_free;
628c2ecf20Sopenharmony_ci				entry->c.ops = &snd_gf1_mem_proc_ops;
638c2ecf20Sopenharmony_ci				priv->address = gus->gf1.mem_alloc.banks_8[idx].address;
648c2ecf20Sopenharmony_ci				priv->size = entry->size = gus->gf1.mem_alloc.banks_8[idx].size;
658c2ecf20Sopenharmony_ci			}
668c2ecf20Sopenharmony_ci		}
678c2ecf20Sopenharmony_ci	}
688c2ecf20Sopenharmony_ci	for (idx = 0; idx < 4; idx++) {
698c2ecf20Sopenharmony_ci		if (gus->gf1.rom_present & (1 << idx)) {
708c2ecf20Sopenharmony_ci			priv = kzalloc(sizeof(*priv), GFP_KERNEL);
718c2ecf20Sopenharmony_ci			if (priv == NULL)
728c2ecf20Sopenharmony_ci				return -ENOMEM;
738c2ecf20Sopenharmony_ci			priv->rom = 1;
748c2ecf20Sopenharmony_ci			priv->gus = gus;
758c2ecf20Sopenharmony_ci			sprintf(name, "gus-rom-%i", idx);
768c2ecf20Sopenharmony_ci			if (! snd_card_proc_new(gus->card, name, &entry)) {
778c2ecf20Sopenharmony_ci				entry->content = SNDRV_INFO_CONTENT_DATA;
788c2ecf20Sopenharmony_ci				entry->private_data = priv;
798c2ecf20Sopenharmony_ci				entry->private_free = snd_gf1_mem_proc_free;
808c2ecf20Sopenharmony_ci				entry->c.ops = &snd_gf1_mem_proc_ops;
818c2ecf20Sopenharmony_ci				priv->address = idx * 4096 * 1024;
828c2ecf20Sopenharmony_ci				priv->size = entry->size = gus->gf1.rom_memory;
838c2ecf20Sopenharmony_ci			}
848c2ecf20Sopenharmony_ci		}
858c2ecf20Sopenharmony_ci	}
868c2ecf20Sopenharmony_ci	return 0;
878c2ecf20Sopenharmony_ci}
88