1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
4 *  DRAM access routines
5 */
6
7#include <linux/time.h>
8#include <sound/core.h>
9#include <sound/gus.h>
10#include <sound/info.h>
11
12
13static int snd_gus_dram_poke(struct snd_gus_card *gus, char __user *_buffer,
14			     unsigned int address, unsigned int size)
15{
16	unsigned long flags;
17	unsigned int size1, size2;
18	char buffer[256], *pbuffer;
19
20	while (size > 0) {
21		size1 = size > sizeof(buffer) ? sizeof(buffer) : size;
22		if (copy_from_user(buffer, _buffer, size1))
23			return -EFAULT;
24		if (gus->interwave) {
25			spin_lock_irqsave(&gus->reg_lock, flags);
26			snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x01);
27			snd_gf1_dram_addr(gus, address);
28			outsb(GUSP(gus, DRAM), buffer, size1);
29			spin_unlock_irqrestore(&gus->reg_lock, flags);
30			address += size1;
31		} else {
32			pbuffer = buffer;
33			size2 = size1;
34			while (size2--)
35				snd_gf1_poke(gus, address++, *pbuffer++);
36		}
37		size -= size1;
38		_buffer += size1;
39	}
40	return 0;
41}
42
43
44int snd_gus_dram_write(struct snd_gus_card *gus, char __user *buffer,
45		       unsigned int address, unsigned int size)
46{
47	return snd_gus_dram_poke(gus, buffer, address, size);
48}
49
50static int snd_gus_dram_peek(struct snd_gus_card *gus, char __user *_buffer,
51			     unsigned int address, unsigned int size,
52			     int rom)
53{
54	unsigned long flags;
55	unsigned int size1, size2;
56	char buffer[256], *pbuffer;
57
58	while (size > 0) {
59		size1 = size > sizeof(buffer) ? sizeof(buffer) : size;
60		if (gus->interwave) {
61			spin_lock_irqsave(&gus->reg_lock, flags);
62			snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, rom ? 0x03 : 0x01);
63			snd_gf1_dram_addr(gus, address);
64			insb(GUSP(gus, DRAM), buffer, size1);
65			snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x01);
66			spin_unlock_irqrestore(&gus->reg_lock, flags);
67			address += size1;
68		} else {
69			pbuffer = buffer;
70			size2 = size1;
71			while (size2--)
72				*pbuffer++ = snd_gf1_peek(gus, address++);
73		}
74		if (copy_to_user(_buffer, buffer, size1))
75			return -EFAULT;
76		size -= size1;
77		_buffer += size1;
78	}
79	return 0;
80}
81
82int snd_gus_dram_read(struct snd_gus_card *gus, char __user *buffer,
83		      unsigned int address, unsigned int size,
84		      int rom)
85{
86	return snd_gus_dram_peek(gus, buffer, address, size, rom);
87}
88