patch-1.3.9 linux/drivers/sound/soundcard.c
Next file: linux/drivers/sound/soundvers.h
Previous file: linux/drivers/sound/sound_timer.c
Back to the patch index
Back to the overall index
- Lines: 474
- Date:
Mon Jul 10 01:45:22 1995
- Orig file:
v1.3.8/linux/drivers/sound/soundcard.c
- Orig date:
Mon Jan 23 23:04:09 1995
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c
@@ -26,13 +26,15 @@
* SUCH DAMAGE.
*
*/
+/*
+ * Created modular version by Peter Trattler (peter@sbox.tu-graz.ac.at)
+ */
#include "sound_config.h"
#ifdef CONFIGURE_SOUNDCARD
#include <linux/major.h>
-#include <linux/mm.h>
static int soundcards_installed = 0; /* Number of installed
@@ -44,15 +46,9 @@
int
snd_ioctl_return (int *addr, int value)
{
- int error;
-
if (value < 0)
return value;
- error = verify_area(VERIFY_WRITE, addr, sizeof(int));
- if (error)
- return error;
-
PUT_WORD_TO_USER (addr, 0, value);
return 0;
}
@@ -73,6 +69,11 @@
{
int dev;
+#ifdef MODULE
+ int err;
+
+#endif
+
dev = inode->i_rdev;
dev = MINOR (dev);
@@ -88,7 +89,8 @@
static int
sound_open (struct inode *inode, struct file *file)
{
- int dev;
+ int dev, retval;
+ struct fileinfo tmp_file;
dev = inode->i_rdev;
dev = MINOR (dev);
@@ -99,16 +101,25 @@
return RET_ERROR (ENXIO);
}
- files[dev].mode = 0;
+ tmp_file.mode = 0;
+ tmp_file.filp = file;
if ((file->f_flags & O_ACCMODE) == O_RDWR)
- files[dev].mode = OPEN_READWRITE;
+ tmp_file.mode = OPEN_READWRITE;
if ((file->f_flags & O_ACCMODE) == O_RDONLY)
- files[dev].mode = OPEN_READ;
+ tmp_file.mode = OPEN_READ;
if ((file->f_flags & O_ACCMODE) == O_WRONLY)
- files[dev].mode = OPEN_WRITE;
+ tmp_file.mode = OPEN_WRITE;
- return sound_open_sw (dev, &files[dev]);
+ if ((retval = sound_open_sw (dev, &tmp_file)) < 0)
+ return retval;
+
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+
+ memcpy ((char *) &files[dev], (char *) &tmp_file, sizeof (tmp_file));
+ return retval;
}
static void
@@ -120,6 +131,9 @@
dev = MINOR (dev);
sound_release_sw (dev, &files[dev]);
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
}
static int
@@ -131,6 +145,29 @@
dev = inode->i_rdev;
dev = MINOR (dev);
+ if (cmd & IOC_INOUT)
+ {
+ /*
+ * Have to validate the address given by the process.
+ */
+ int len, err;
+
+ len = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
+
+ if (cmd & IOC_IN)
+ {
+ if ((err = verify_area (VERIFY_READ, (void *) arg, len)) < 0)
+ return err;
+ }
+
+ if (cmd & IOC_OUT)
+ {
+ if ((err = verify_area (VERIFY_WRITE, (void *) arg, len)) < 0)
+ return err;
+ }
+
+ }
+
return sound_ioctl_sw (dev, &files[dev], cmd, arg);
}
@@ -148,6 +185,7 @@
{
#ifndef EXCLUDE_SEQUENCER
case SND_DEV_SEQ:
+ case SND_DEV_SEQ2:
return sequencer_select (dev, &files[dev], sel_type, wait);
break;
#endif
@@ -158,6 +196,14 @@
break;
#endif
+#ifndef EXCLUDE_AUDIO
+ case SND_DEV_DSP:
+ case SND_DEV_DSP16:
+ case SND_DEV_AUDIO:
+ return audio_select (dev, &files[dev], sel_type, wait);
+ break;
+#endif
+
default:
return 0;
}
@@ -181,7 +227,9 @@
long
soundcard_init (long mem_start)
{
+#ifndef MODULE
register_chrdev (SOUND_MAJOR, "sound", &sound_fops);
+#endif
soundcard_configured = 1;
@@ -212,6 +260,89 @@
return mem_start;
}
+#ifdef MODULE
+static unsigned long irqs = 0;
+void snd_release_irq (int);
+static int module_sound_mem_init (void);
+static void module_sound_mem_release (void);
+
+static void
+free_all_irqs (void)
+{
+ int i;
+
+ for (i = 0; i < 31; i++)
+ if (irqs & (1ul << i))
+ snd_release_irq (i);
+ irqs = 0;
+}
+
+char kernel_version[] = UTS_RELEASE;
+
+static long memory_pool = 0;
+static int memsize = 70 * 1024;
+static int debugmem = 0; /* switched off by default */
+
+int
+init_module (void)
+{
+ long lastbyte;
+ int err;
+
+ printk ("sound: made modular by Peter Trattler (peter@sbox.tu-graz.ac.at)\n");
+ err = register_chrdev (SOUND_MAJOR, "sound", &sound_fops);
+ if (err)
+ {
+ printk ("sound: driver already loaded/included in kernel\n");
+ return err;
+ }
+ memory_pool = (long) kmalloc (memsize, GFP_KERNEL);
+ if (memory_pool == 0l)
+ {
+ unregister_chrdev (SOUND_MAJOR, "sound");
+ return -ENOMEM;
+ }
+ lastbyte = soundcard_init (memory_pool);
+ if (lastbyte > memory_pool + memsize)
+ {
+ printk ("sound: Not enough memory; use : 'insmod sound.o memsize=%ld'\n",
+ lastbyte - memory_pool);
+ kfree ((void *) memory_pool);
+ unregister_chrdev (SOUND_MAJOR, "sound");
+ free_all_irqs ();
+ return -ENOMEM;
+ }
+ err = module_sound_mem_init ();
+ if (err)
+ {
+ module_sound_mem_release ();
+ kfree ((void *) memory_pool);
+ unregister_chrdev (SOUND_MAJOR, "sound");
+ free_all_irqs ();
+ return err;
+ }
+ if (lastbyte < memory_pool + memsize)
+ printk ("sound: (Suggestion) too much memory; use : 'insmod sound.o memsize=%ld'\n",
+ lastbyte - memory_pool);
+ return 0;
+}
+
+void
+cleanup_module (void)
+{
+ if (MOD_IN_USE)
+ printk ("sound: module busy -- remove delayed\n");
+ else
+ {
+ kfree ((void *) memory_pool);
+ unregister_chrdev (SOUND_MAJOR, "sound");
+ free_all_irqs ();
+ module_sound_mem_release ();
+ }
+}
+
+#endif
+
void
tenmicrosec (void)
{
@@ -222,22 +353,19 @@
}
int
-snd_set_irq_handler (int interrupt_level, void (*hndlr) (int, struct pt_regs *))
+snd_set_irq_handler (int interrupt_level, INT_HANDLER_PROTO (), char *name)
{
int retcode;
- retcode = request_irq(interrupt_level, hndlr,
-#ifdef SND_SA_INTERRUPT
- SA_INTERRUPT,
-#else
- 0,
-#endif
- "sound");
-
+ retcode = request_irq (interrupt_level, hndlr, SA_INTERRUPT, name);
if (retcode < 0)
{
printk ("Sound: IRQ%d already in use\n", interrupt_level);
}
+#ifdef MODULE
+ else
+ irqs |= (1ul << interrupt_level);
+#endif
return retcode;
}
@@ -245,6 +373,9 @@
void
snd_release_irq (int vect)
{
+#ifdef MODULE
+ irqs &= ~(1ul << vect);
+#endif
free_irq (vect);
}
@@ -286,6 +417,152 @@
return 0;
}
+#ifdef MODULE
+
+#ifdef KMALLOC_DMA_BROKEN
+#define KMALLOC_MEM_REGIONS 20
+
+static char *dma_list[KMALLOC_MEM_REGIONS];
+static int dma_last = 0;
+inline void
+add_to_dma_list (char *adr)
+{
+ dma_list[dma_last++] = adr;
+}
+
+#endif
+
+static int
+module_sound_mem_init (void)
+{
+ int dev, ret = 0;
+ unsigned long dma_pagesize;
+ char *start_addr, *end_addr;
+ struct dma_buffparms *dmap;
+
+ for (dev = 0; dev < num_audiodevs; dev++)
+ if (audio_devs[dev]->buffcount > 0 && audio_devs[dev]->dmachan >= 0)
+ {
+ dmap = audio_devs[dev]->dmap;
+ if (audio_devs[dev]->flags & DMA_AUTOMODE)
+ audio_devs[dev]->buffcount = 1;
+
+ if (audio_devs[dev]->dmachan > 3)
+ dma_pagesize = 131072; /* 16bit dma: 128k */
+ else
+ dma_pagesize = 65536; /* 8bit dma: 64k */
+ if (debugmem)
+ printk ("sound: dma-page-size %lu\n", dma_pagesize);
+ /* More sanity checks */
+
+ if (audio_devs[dev]->buffsize > dma_pagesize)
+ audio_devs[dev]->buffsize = dma_pagesize;
+ audio_devs[dev]->buffsize &= 0xfffff000; /* Truncate to n*4k */
+ if (audio_devs[dev]->buffsize < 4096)
+ audio_devs[dev]->buffsize = 4096;
+ if (debugmem)
+ printk ("sound: buffsize %lu\n", audio_devs[dev]->buffsize);
+ /* Now allocate the buffers */
+ for (dmap->raw_count = 0; dmap->raw_count < audio_devs[dev]->buffcount;
+ dmap->raw_count++)
+ {
+#ifdef KMALLOC_DMA_BROKEN
+ start_addr = kmalloc (audio_devs[dev]->buffsize, GFP_KERNEL);
+ if (start_addr)
+ {
+ if (debugmem)
+ printk ("sound: trying 0x%lx for DMA\n", (long) start_addr);
+ if (valid_dma_page ((unsigned long) start_addr,
+ audio_devs[dev]->buffsize,
+ dma_pagesize))
+ add_to_dma_list (start_addr);
+ else
+ {
+ kfree (start_addr);
+ start_addr = kmalloc (audio_devs[dev]->buffsize * 2,
+ GFP_KERNEL); /* what a waste :-( */
+ if (start_addr)
+ {
+ if (debugmem)
+ printk ("sound: failed; trying 0x%lx aligned to",
+ (long) start_addr);
+ add_to_dma_list (start_addr);
+ /* now align it to the next dma-page boundary */
+ start_addr = (char *) (((long) start_addr
+ + dma_pagesize - 1)
+ & ~(dma_pagesize - 1));
+ if (debugmem)
+ printk (" 0x%lx\n", (long) start_addr);
+ }
+ }
+ }
+#else
+ start_addr = kmalloc (audio_devs[dev]->buffsize,
+ GFP_DMA | GFP_KERNEL);
+#endif
+ if (start_addr == NULL)
+ ret = -ENOMEM; /* Can't stop the loop in this case, because
+ * ...->raw_buf [...] must be initilized
+ * to valid values (at least to NULL)
+ */
+ else
+ {
+ /* make some checks */
+ end_addr = start_addr + audio_devs[dev]->buffsize - 1;
+ if (debugmem)
+ printk ("sound: start 0x%lx, end 0x%lx\n",
+ (long) start_addr, (long) end_addr);
+ /* now check if it fits into the same dma-pagesize */
+ if (((long) start_addr & ~(dma_pagesize - 1))
+ != ((long) end_addr & ~(dma_pagesize - 1))
+ || end_addr >= (char *) (16 * 1024 * 1024))
+ {
+ printk (
+ "sound: kmalloc returned invalid address 0x%lx for %ld Bytes DMA-buffer\n",
+ (long) start_addr,
+ audio_devs[dev]->buffsize);
+ ret = -EFAULT;
+ }
+ }
+ dmap->raw_buf[dmap->raw_count] = start_addr;
+ dmap->raw_buf_phys[dmap->raw_count] = (unsigned long) start_addr;
+ }
+ }
+ return ret;
+}
+
+static void
+module_sound_mem_release (void)
+{
+#ifdef KMALLOC_DMA_BROKEN
+ int i;
+
+ for (i = 0; i < dma_last; i++)
+ {
+ if (debugmem)
+ printk ("sound: freeing 0x%lx\n", (long) dma_list[i]);
+ kfree (dma_list[i]);
+ }
+#else
+ int dev, i;
+
+ for (dev = 0; dev < num_audiodevs; dev++)
+ if (audio_devs[dev]->buffcount > 0 && audio_devs[dev]->dmachan >= 0)
+ {
+ for (i = 0; i < audio_devs[dev]->buffcount; i++)
+ if (audio_devs[dev]->dmap->raw_buf[i])
+ {
+ if (debugmem)
+ printk ("sound: freeing 0x%lx\n",
+ (long) (audio_devs[dev]->dmap->raw_buf[i]));
+ kfree (audio_devs[dev]->dmap->raw_buf[i]);
+ }
+ }
+#endif
+}
+
+#else /* !MODULE */
+
void
sound_mem_init (void)
{
@@ -309,7 +586,7 @@
audio_devs[dev]->buffcount = 1;
if (audio_devs[dev]->dmachan > 3 && audio_devs[dev]->buffsize > 65536)
- dma_pagesize = 131072;/* 128k */
+ dma_pagesize = 131072; /* 128k */
else
dma_pagesize = 65536;
@@ -347,6 +624,8 @@
} /* for dev */
}
+#endif /* !MODULE */
+
#endif
#else
@@ -365,5 +644,14 @@
{
/* Dummy version */
}
+
+#ifdef MODULE
+static int
+module_sound_mem_init (void)
+{
+ return 0; /* no error */
+}
+
+#endif
#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this