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 | |
13 | static 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(to: buffer, from: _buffer, n: 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, data: 0x01); |
27 | snd_gf1_dram_addr(gus, addr: address); |
28 | outsb(GUSP(gus, DRAM), addr: buffer, count: size1); |
29 | spin_unlock_irqrestore(lock: &gus->reg_lock, flags); |
30 | address += size1; |
31 | } else { |
32 | pbuffer = buffer; |
33 | size2 = size1; |
34 | while (size2--) |
35 | snd_gf1_poke(gus, addr: address++, data: *pbuffer++); |
36 | } |
37 | size -= size1; |
38 | _buffer += size1; |
39 | } |
40 | return 0; |
41 | } |
42 | |
43 | |
44 | int 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: buffer, address, size); |
48 | } |
49 | |
50 | static 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, data: rom ? 0x03 : 0x01); |
63 | snd_gf1_dram_addr(gus, addr: address); |
64 | insb(GUSP(gus, DRAM), addr: buffer, count: size1); |
65 | snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, data: 0x01); |
66 | spin_unlock_irqrestore(lock: &gus->reg_lock, flags); |
67 | address += size1; |
68 | } else { |
69 | pbuffer = buffer; |
70 | size2 = size1; |
71 | while (size2--) |
72 | *pbuffer++ = snd_gf1_peek(gus, addr: address++); |
73 | } |
74 | if (copy_to_user(to: _buffer, from: buffer, n: size1)) |
75 | return -EFAULT; |
76 | size -= size1; |
77 | _buffer += size1; |
78 | } |
79 | return 0; |
80 | } |
81 | |
82 | int 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: buffer, address, size, rom); |
87 | } |
88 | |