1 /* 2 * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 3 * GUS's memory access via proc filesystem 4 * 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 */ 21 22 #include <linux/slab.h> 23 #include <sound/core.h> 24 #include <sound/gus.h> 25 #include <sound/info.h> 26 27 struct gus_proc_private { 28 int rom; /* data are in ROM */ 29 unsigned int address; 30 unsigned int size; 31 struct snd_gus_card * gus; 32 }; 33 34 static long snd_gf1_mem_proc_dump(struct snd_info_entry *entry, void *file_private_data, 35 struct file *file, char __user *buf, 36 unsigned long count, unsigned long pos) 37 { 38 long size; 39 struct gus_proc_private *priv = entry->private_data; 40 struct snd_gus_card *gus = priv->gus; 41 int err; 42 43 size = count; 44 if (pos + size > priv->size) 45 size = (long)priv->size - pos; 46 if (size > 0) { 47 if ((err = snd_gus_dram_read(gus, buf, pos, size, priv->rom)) < 0) 48 return err; 49 return size; 50 } 51 return 0; 52 } 53 54 static long long snd_gf1_mem_proc_llseek(struct snd_info_entry *entry, 55 void *private_file_data, 56 struct file *file, 57 long long offset, 58 int orig) 59 { 60 struct gus_proc_private *priv = entry->private_data; 61 62 switch (orig) { 63 case SEEK_SET: 64 file->f_pos = offset; 65 break; 66 case SEEK_CUR: 67 file->f_pos += offset; 68 break; 69 case SEEK_END: /* offset is negative */ 70 file->f_pos = priv->size + offset; 71 break; 72 default: 73 return -EINVAL; 74 } 75 if (file->f_pos > priv->size) 76 file->f_pos = priv->size; 77 return file->f_pos; 78 } 79 80 static void snd_gf1_mem_proc_free(struct snd_info_entry *entry) 81 { 82 struct gus_proc_private *priv = entry->private_data; 83 kfree(priv); 84 } 85 86 static struct snd_info_entry_ops snd_gf1_mem_proc_ops = { 87 .read = snd_gf1_mem_proc_dump, 88 .llseek = snd_gf1_mem_proc_llseek, 89 }; 90 91 int snd_gf1_mem_proc_init(struct snd_gus_card * gus) 92 { 93 int idx; 94 char name[16]; 95 struct gus_proc_private *priv; 96 struct snd_info_entry *entry; 97 98 for (idx = 0; idx < 4; idx++) { 99 if (gus->gf1.mem_alloc.banks_8[idx].size > 0) { 100 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 101 if (priv == NULL) 102 return -ENOMEM; 103 priv->gus = gus; 104 sprintf(name, "gus-ram-%i", idx); 105 if (! snd_card_proc_new(gus->card, name, &entry)) { 106 entry->content = SNDRV_INFO_CONTENT_DATA; 107 entry->private_data = priv; 108 entry->private_free = snd_gf1_mem_proc_free; 109 entry->c.ops = &snd_gf1_mem_proc_ops; 110 priv->address = gus->gf1.mem_alloc.banks_8[idx].address; 111 priv->size = entry->size = gus->gf1.mem_alloc.banks_8[idx].size; 112 } 113 } 114 } 115 for (idx = 0; idx < 4; idx++) { 116 if (gus->gf1.rom_present & (1 << idx)) { 117 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 118 if (priv == NULL) 119 return -ENOMEM; 120 priv->rom = 1; 121 priv->gus = gus; 122 sprintf(name, "gus-rom-%i", idx); 123 if (! snd_card_proc_new(gus->card, name, &entry)) { 124 entry->content = SNDRV_INFO_CONTENT_DATA; 125 entry->private_data = priv; 126 entry->private_free = snd_gf1_mem_proc_free; 127 entry->c.ops = &snd_gf1_mem_proc_ops; 128 priv->address = idx * 4096 * 1024; 129 priv->size = entry->size = gus->gf1.rom_memory; 130 } 131 } 132 } 133 return 0; 134 } 135