xref: /kernel/linux/linux-5.10/sound/isa/gus/gus_dram.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
48c2ecf20Sopenharmony_ci *  DRAM access routines
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/time.h>
88c2ecf20Sopenharmony_ci#include <sound/core.h>
98c2ecf20Sopenharmony_ci#include <sound/gus.h>
108c2ecf20Sopenharmony_ci#include <sound/info.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cistatic int snd_gus_dram_poke(struct snd_gus_card *gus, char __user *_buffer,
148c2ecf20Sopenharmony_ci			     unsigned int address, unsigned int size)
158c2ecf20Sopenharmony_ci{
168c2ecf20Sopenharmony_ci	unsigned long flags;
178c2ecf20Sopenharmony_ci	unsigned int size1, size2;
188c2ecf20Sopenharmony_ci	char buffer[256], *pbuffer;
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci	while (size > 0) {
218c2ecf20Sopenharmony_ci		size1 = size > sizeof(buffer) ? sizeof(buffer) : size;
228c2ecf20Sopenharmony_ci		if (copy_from_user(buffer, _buffer, size1))
238c2ecf20Sopenharmony_ci			return -EFAULT;
248c2ecf20Sopenharmony_ci		if (gus->interwave) {
258c2ecf20Sopenharmony_ci			spin_lock_irqsave(&gus->reg_lock, flags);
268c2ecf20Sopenharmony_ci			snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x01);
278c2ecf20Sopenharmony_ci			snd_gf1_dram_addr(gus, address);
288c2ecf20Sopenharmony_ci			outsb(GUSP(gus, DRAM), buffer, size1);
298c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&gus->reg_lock, flags);
308c2ecf20Sopenharmony_ci			address += size1;
318c2ecf20Sopenharmony_ci		} else {
328c2ecf20Sopenharmony_ci			pbuffer = buffer;
338c2ecf20Sopenharmony_ci			size2 = size1;
348c2ecf20Sopenharmony_ci			while (size2--)
358c2ecf20Sopenharmony_ci				snd_gf1_poke(gus, address++, *pbuffer++);
368c2ecf20Sopenharmony_ci		}
378c2ecf20Sopenharmony_ci		size -= size1;
388c2ecf20Sopenharmony_ci		_buffer += size1;
398c2ecf20Sopenharmony_ci	}
408c2ecf20Sopenharmony_ci	return 0;
418c2ecf20Sopenharmony_ci}
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ciint snd_gus_dram_write(struct snd_gus_card *gus, char __user *buffer,
458c2ecf20Sopenharmony_ci		       unsigned int address, unsigned int size)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	return snd_gus_dram_poke(gus, buffer, address, size);
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic int snd_gus_dram_peek(struct snd_gus_card *gus, char __user *_buffer,
518c2ecf20Sopenharmony_ci			     unsigned int address, unsigned int size,
528c2ecf20Sopenharmony_ci			     int rom)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	unsigned long flags;
558c2ecf20Sopenharmony_ci	unsigned int size1, size2;
568c2ecf20Sopenharmony_ci	char buffer[256], *pbuffer;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	while (size > 0) {
598c2ecf20Sopenharmony_ci		size1 = size > sizeof(buffer) ? sizeof(buffer) : size;
608c2ecf20Sopenharmony_ci		if (gus->interwave) {
618c2ecf20Sopenharmony_ci			spin_lock_irqsave(&gus->reg_lock, flags);
628c2ecf20Sopenharmony_ci			snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, rom ? 0x03 : 0x01);
638c2ecf20Sopenharmony_ci			snd_gf1_dram_addr(gus, address);
648c2ecf20Sopenharmony_ci			insb(GUSP(gus, DRAM), buffer, size1);
658c2ecf20Sopenharmony_ci			snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x01);
668c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&gus->reg_lock, flags);
678c2ecf20Sopenharmony_ci			address += size1;
688c2ecf20Sopenharmony_ci		} else {
698c2ecf20Sopenharmony_ci			pbuffer = buffer;
708c2ecf20Sopenharmony_ci			size2 = size1;
718c2ecf20Sopenharmony_ci			while (size2--)
728c2ecf20Sopenharmony_ci				*pbuffer++ = snd_gf1_peek(gus, address++);
738c2ecf20Sopenharmony_ci		}
748c2ecf20Sopenharmony_ci		if (copy_to_user(_buffer, buffer, size1))
758c2ecf20Sopenharmony_ci			return -EFAULT;
768c2ecf20Sopenharmony_ci		size -= size1;
778c2ecf20Sopenharmony_ci		_buffer += size1;
788c2ecf20Sopenharmony_ci	}
798c2ecf20Sopenharmony_ci	return 0;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ciint snd_gus_dram_read(struct snd_gus_card *gus, char __user *buffer,
838c2ecf20Sopenharmony_ci		      unsigned int address, unsigned int size,
848c2ecf20Sopenharmony_ci		      int rom)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	return snd_gus_dram_peek(gus, buffer, address, size, rom);
878c2ecf20Sopenharmony_ci}
88