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