summaryrefslogtreecommitdiffstats
path: root/drivers/sound/soundcard.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-01-07 02:33:00 +0000
committer <ralf@linux-mips.org>1997-01-07 02:33:00 +0000
commitbeb116954b9b7f3bb56412b2494b562f02b864b1 (patch)
tree120e997879884e1b9d93b265221b939d2ef1ade1 /drivers/sound/soundcard.c
parent908d4681a1dc3792ecafbe64265783a86c4cccb6 (diff)
Import of Linux/MIPS 2.1.14
Diffstat (limited to 'drivers/sound/soundcard.c')
-rw-r--r--drivers/sound/soundcard.c782
1 files changed, 610 insertions, 172 deletions
diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c
index ab90bf5da..43b0c7a8b 100644
--- a/drivers/sound/soundcard.c
+++ b/drivers/sound/soundcard.c
@@ -2,113 +2,141 @@
* linux/kernel/chr_drv/sound/soundcard.c
*
* Soundcard driver for Linux
+ */
+/*
+ * Copyright (C) by Hannu Savolainen 1993-1996
*
- * Copyright by Hannu Savolainen 1993
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
*/
+#include <linux/config.h>
-#include "sound_config.h"
-#ifdef CONFIGURE_SOUNDCARD
+#include "sound_config.h"
#include <linux/major.h>
-#include <linux/mm.h>
-static int soundcards_installed = 0; /* Number of installed
- * soundcards */
+int *sound_osp = NULL;
+static int chrdev_registered = 0;
+static int sound_major = SOUND_MAJOR;
+
+static int is_unloading = 0;
+
+/*
+ * Table for permanently allocated memory (used when unloading the module)
+ */
+caddr_t sound_mem_blocks[1024];
+int sound_nblocks = 0;
+
static int soundcard_configured = 0;
static struct fileinfo files[SND_NDEVS];
+static char dma_alloc_map[8] =
+{0};
+
+#define DMA_MAP_UNAVAIL 0
+#define DMA_MAP_FREE 1
+#define DMA_MAP_BUSY 2
+
+
int
-snd_ioctl_return (int *addr, int value)
+ioctl_in (caddr_t arg)
+{
+ int xx;
+
+ get_user (xx, (int *) arg);
+ return xx;
+}
+
+int
+ioctl_out (caddr_t arg, int result)
{
- int error;
+ put_user (result, (int *) arg);
+ return 0;
+}
+int
+snd_ioctl_return (int *addr, int value)
+{
if (value < 0)
return value;
- error = verify_area(VERIFY_WRITE, addr, sizeof(int));
- if (error)
- return error;
-
- PUT_WORD_TO_USER (addr, 0, value);
+ put_user (value, (int *) &((addr)[0]));
return 0;
}
-static int
-sound_read (struct inode *inode, struct file *file, char *buf, int count)
+static long
+sound_read (struct inode *inode, struct file *file, char *buf, unsigned long count)
{
int dev;
- dev = inode->i_rdev;
- dev = MINOR (dev);
+ dev = MINOR (inode->i_rdev);
+
+ files[dev].flags = file->f_flags;
return sound_read_sw (dev, &files[dev], buf, count);
}
-static int
-sound_write (struct inode *inode, struct file *file, char *buf, int count)
+static long
+sound_write (struct inode *inode, struct file *file, const char *buf, unsigned long count)
{
int dev;
- dev = inode->i_rdev;
- dev = MINOR (dev);
+ dev = MINOR (inode->i_rdev);
+
+ files[dev].flags = file->f_flags;
return sound_write_sw (dev, &files[dev], buf, count);
}
-static int
-sound_lseek (struct inode *inode, struct file *file, off_t offset, int orig)
+static long long
+sound_lseek (struct inode *inode, struct file *file, long long offset, int orig)
{
- return RET_ERROR (EPERM);
+ return -EPERM;
}
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);
+ if (is_unloading)
+ {
+ printk ("Sound: Driver partially removed. Can't open device\n");
+ return -EBUSY;
+ }
+
+ dev = MINOR (inode->i_rdev);
if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS)
{
printk ("SoundCard Error: The soundcard system has not been configured\n");
- return RET_ERROR (ENXIO);
+ return -ENXIO;
}
- files[dev].mode = 0;
+ tmp_file.mode = 0;
+ tmp_file.flags = file->f_flags;
+
+ if ((tmp_file.flags & O_ACCMODE) == O_RDWR)
+ tmp_file.mode = OPEN_READWRITE;
+ if ((tmp_file.flags & O_ACCMODE) == O_RDONLY)
+ tmp_file.mode = OPEN_READ;
+ if ((tmp_file.flags & O_ACCMODE) == O_WRONLY)
+ tmp_file.mode = OPEN_WRITE;
- if ((file->f_flags & O_ACCMODE) == O_RDWR)
- files[dev].mode = OPEN_READWRITE;
- if ((file->f_flags & O_ACCMODE) == O_RDONLY)
- files[dev].mode = OPEN_READ;
- if ((file->f_flags & O_ACCMODE) == O_WRONLY)
- files[dev].mode = OPEN_WRITE;
+ if ((retval = sound_open_sw (dev, &tmp_file)) < 0)
+ return retval;
+
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
- return sound_open_sw (dev, &files[dev]);
+ memcpy ((char *) &files[dev], (char *) &tmp_file, sizeof (tmp_file));
+ return retval;
}
static void
@@ -116,22 +144,52 @@ sound_release (struct inode *inode, struct file *file)
{
int dev;
- dev = inode->i_rdev;
- dev = MINOR (dev);
+ dev = MINOR (inode->i_rdev);
+
+ files[dev].flags = file->f_flags;
sound_release_sw (dev, &files[dev]);
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
}
static int
sound_ioctl (struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
- int dev;
+ int dev, err;
+
+ dev = MINOR (inode->i_rdev);
+
+ files[dev].flags = file->f_flags;
+
+ if (_IOC_DIR (cmd) != _IOC_NONE)
+ {
+ /*
+ * Have to validate the address given by the process.
+ */
+ int len;
+
+ len = _IOC_SIZE (cmd);
+
+ if (_IOC_DIR (cmd) & _IOC_WRITE)
+ {
+ if ((err = verify_area (VERIFY_READ, (void *) arg, len)) < 0)
+ return err;
+ }
+
+ if (_IOC_DIR (cmd) & _IOC_READ)
+ {
+ if ((err = verify_area (VERIFY_WRITE, (void *) arg, len)) < 0)
+ return err;
+ }
+
+ }
- dev = inode->i_rdev;
- dev = MINOR (dev);
+ err = sound_ioctl_sw (dev, &files[dev], cmd, (caddr_t) arg);
- return sound_ioctl_sw (dev, &files[dev], cmd, arg);
+ return err;
}
static int
@@ -139,25 +197,35 @@ sound_select (struct inode *inode, struct file *file, int sel_type, select_table
{
int dev;
- dev = inode->i_rdev;
- dev = MINOR (dev);
+ dev = MINOR (inode->i_rdev);
+
+ files[dev].flags = file->f_flags;
DEB (printk ("sound_select(dev=%d, type=0x%x)\n", dev, sel_type));
switch (dev & 0x0f)
{
-#ifndef EXCLUDE_SEQUENCER
+#ifdef CONFIG_SEQUENCER
case SND_DEV_SEQ:
+ case SND_DEV_SEQ2:
return sequencer_select (dev, &files[dev], sel_type, wait);
break;
#endif
-#ifndef EXCLUDE_MIDI
+#ifdef CONFIG_MIDI
case SND_DEV_MIDIN:
return MIDIbuf_select (dev, &files[dev], sel_type, wait);
break;
#endif
+#ifdef CONFIG_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;
}
@@ -165,6 +233,94 @@ sound_select (struct inode *inode, struct file *file, int sel_type, select_table
return 0;
}
+static int
+sound_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma)
+{
+ int dev, dev_class;
+ unsigned long size;
+ struct dma_buffparms *dmap = NULL;
+
+ dev = MINOR (inode->i_rdev);
+
+ files[dev].flags = file->f_flags;
+
+ dev_class = dev & 0x0f;
+ dev >>= 4;
+
+ if (dev_class != SND_DEV_DSP && dev_class != SND_DEV_DSP16 && dev_class != SND_DEV_AUDIO)
+ {
+ printk ("Sound: mmap() not supported for other than audio devices\n");
+ return -EINVAL;
+ }
+
+ if ((vma->vm_flags & (VM_READ | VM_WRITE)) == (VM_READ | VM_WRITE))
+ {
+ printk ("Sound: Cannot do read/write mmap()\n");
+ return -EINVAL;
+ }
+
+ if (vma->vm_flags & VM_READ)
+ {
+ dmap = audio_devs[dev]->dmap_in;
+ }
+ else if (vma->vm_flags & VM_WRITE)
+ {
+ dmap = audio_devs[dev]->dmap_out;
+ }
+ else
+ {
+ printk ("Sound: Undefined mmap() access\n");
+ return -EINVAL;
+ }
+
+ if (dmap == NULL)
+ {
+ printk ("Sound: mmap() error. dmap == NULL\n");
+ return -EIO;
+ }
+
+ if (dmap->raw_buf == NULL)
+ {
+ printk ("Sound: mmap() called when raw_buf == NULL\n");
+ return -EIO;
+ }
+
+ if (dmap->mapping_flags)
+ {
+ printk ("Sound: mmap() called twice for the same DMA buffer\n");
+ return -EIO;
+ }
+
+ if (vma->vm_offset != 0)
+ {
+ printk ("Sound: mmap() offset must be 0.\n");
+ return -EINVAL;
+ }
+
+ size = vma->vm_end - vma->vm_start;
+
+ if (size != dmap->bytes_in_use)
+ {
+ printk ("Sound: mmap() size = %ld. Should be %d\n",
+ size, dmap->bytes_in_use);
+ }
+
+ if (remap_page_range (vma->vm_start, virt_to_phys (dmap->raw_buf),
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot))
+ return -EAGAIN;
+
+ vma->vm_inode = inode;
+ inode->i_count++;
+
+ dmap->mapping_flags |= DMA_MAP_MAPPED;
+
+ memset (dmap->raw_buf,
+ dmap->neutral_byte,
+ dmap->bytes_in_use);
+ return 0;
+}
+
static struct file_operations sound_fops =
{
sound_lseek,
@@ -173,47 +329,160 @@ static struct file_operations sound_fops =
NULL, /* sound_readdir */
sound_select,
sound_ioctl,
- NULL,
+ sound_mmap,
sound_open,
sound_release
};
-long
-soundcard_init (long mem_start)
+void
+soundcard_init (void)
{
- register_chrdev (SOUND_MAJOR, "sound", &sound_fops);
+#ifndef MODULE
+ register_chrdev (sound_major, "sound", &sound_fops);
+ chrdev_registered = 1;
+#endif
soundcard_configured = 1;
- mem_start = sndtable_init (mem_start); /* Initialize call tables and
- * detect cards */
+ sndtable_init (); /* Initialize call tables and detect cards */
+
- if (!(soundcards_installed = sndtable_get_cardcount ()))
- return mem_start; /* No cards detected */
+ if (sndtable_get_cardcount () == 0)
+ return; /* No cards detected */
-#ifndef EXCLUDE_AUDIO
+#ifdef CONFIG_AUDIO
if (num_audiodevs) /* Audio devices present */
{
- mem_start = DMAbuf_init (mem_start);
- mem_start = audio_init (mem_start);
+ DMAbuf_init ();
+ audio_init_devices ();
}
#endif
-#ifndef EXCLUDE_MIDI
+#ifdef CONFIG_MIDI
if (num_midis)
- mem_start = MIDIbuf_init (mem_start);
+ MIDIbuf_init ();
#endif
-#ifndef EXCLUDE_SEQUENCER
+#ifdef CONFIG_SEQUENCER
if (num_midis + num_synths)
- mem_start = sequencer_init (mem_start);
+ sequencer_init ();
#endif
- return mem_start;
}
+static unsigned int irqs = 0;
+
+#ifdef MODULE
+static void
+free_all_irqs (void)
+{
+ int i;
+
+ for (i = 0; i < 31; i++)
+ if (irqs & (1ul << i))
+ {
+ printk ("Sound warning: IRQ%d was left allocated - fixed.\n", i);
+ snd_release_irq (i);
+ }
+ irqs = 0;
+}
+
+char kernel_version[] = UTS_RELEASE;
+
+#endif
+
+static int debugmem = 0; /* switched off by default */
+
+static int sound[20] =
+{0};
+
+int
+init_module (void)
+{
+ int err;
+ int ints[21];
+ int i;
+
+ if (0 < 0)
+ {
+ printk ("Sound: Incompatible kernel (wrapper) version\n");
+ return -EINVAL;
+ }
+
+ /*
+ * "sound=" command line handling by Harald Milz.
+ */
+ i = 0;
+ while (i < 20 && sound[i])
+ ints[i + 1] = sound[i++];
+ ints[0] = i;
+
+ if (i)
+ sound_setup ("sound=", ints);
+
+ err = register_chrdev (sound_major, "sound", &sound_fops);
+ if (err)
+ {
+ printk ("sound: driver already loaded/included in kernel\n");
+ return err;
+ }
+
+ chrdev_registered = 1;
+ soundcard_init ();
+
+ if (sound_nblocks >= 1024)
+ printk ("Sound warning: Deallocation table was too small.\n");
+
+ return 0;
+}
+
+#ifdef MODULE
+
+
void
-tenmicrosec (void)
+cleanup_module (void)
+{
+ int i;
+
+ if (MOD_IN_USE)
+ {
+ return;
+ }
+
+ if (chrdev_registered)
+ unregister_chrdev (sound_major, "sound");
+
+#ifdef CONFIG_SEQUENCER
+ sound_stop_timer ();
+#endif
+
+#ifdef CONFIG_LOWLEVEL_SOUND
+ {
+ extern void sound_unload_lowlevel_drivers (void);
+
+ sound_unload_lowlevel_drivers ();
+ }
+#endif
+ sound_unload_drivers ();
+
+ for (i = 0; i < sound_nblocks; i++)
+ vfree (sound_mem_blocks[i]);
+
+ free_all_irqs (); /* If something was left allocated by accident */
+
+ for (i = 0; i < 8; i++)
+ if (dma_alloc_map[i] != DMA_MAP_UNAVAIL)
+ {
+ printk ("Sound: Hmm, DMA%d was left allocated - fixed\n", i);
+ sound_free_dma (i);
+ }
+
+
+}
+#endif
+
+void
+tenmicrosec (int *osp)
{
int i;
@@ -222,148 +491,317 @@ tenmicrosec (void)
}
int
-snd_set_irq_handler (int interrupt_level, void (*hndlr) (int, struct pt_regs *))
+snd_set_irq_handler (int interrupt_level, void (*iproc) (int, void *, struct pt_regs *), char *name, int *osp)
{
int retcode;
+ unsigned long flags;
- retcode = request_irq(interrupt_level, hndlr,
-#ifdef SND_SA_INTERRUPT
- SA_INTERRUPT,
-#else
- 0,
-#endif
- "sound");
-
+ save_flags (flags);
+ cli ();
+ retcode = request_irq (interrupt_level, iproc, 0 /* SA_INTERRUPT */ , name, NULL);
if (retcode < 0)
{
printk ("Sound: IRQ%d already in use\n", interrupt_level);
}
+ else
+ irqs |= (1ul << interrupt_level);
+ restore_flags (flags);
return retcode;
}
void
snd_release_irq (int vect)
{
- free_irq (vect);
+ if (!(irqs & (1ul << vect)))
+ return;
+
+ irqs &= ~(1ul << vect);
+ free_irq (vect, NULL);
+}
+
+int
+sound_alloc_dma (int chn, char *deviceID)
+{
+ int err;
+
+ if ((err = request_dma (chn, deviceID)) != 0)
+ return err;
+
+ dma_alloc_map[chn] = DMA_MAP_FREE;
+
+ return 0;
+}
+
+int
+sound_open_dma (int chn, char *deviceID)
+{
+ unsigned long flags;
+
+ if (chn < 0 || chn > 7 || chn == 4)
+ {
+ printk ("sound_open_dma: Invalid DMA channel %d\n", chn);
+ return 1;
+ }
+
+ save_flags (flags);
+ cli ();
+
+ if (dma_alloc_map[chn] != DMA_MAP_FREE)
+ {
+ printk ("sound_open_dma: DMA channel %d busy or not allocated\n", chn);
+ restore_flags (flags);
+ return 1;
+ }
+
+ dma_alloc_map[chn] = DMA_MAP_BUSY;
+ restore_flags (flags);
+ return 0;
}
-#ifndef EXCLUDE_SEQUENCER
+void
+sound_free_dma (int chn)
+{
+ if (dma_alloc_map[chn] != DMA_MAP_FREE)
+ {
+ /* printk ("sound_free_dma: Bad access to DMA channel %d\n", chn); */
+ return;
+ }
+ free_dma (chn);
+ dma_alloc_map[chn] = DMA_MAP_UNAVAIL;
+}
+
+void
+sound_close_dma (int chn)
+{
+ unsigned long flags;
+
+ save_flags (flags);
+ cli ();
+
+ if (dma_alloc_map[chn] != DMA_MAP_BUSY)
+ {
+ printk ("sound_close_dma: Bad access to DMA channel %d\n", chn);
+ restore_flags (flags);
+ return;
+ }
+ dma_alloc_map[chn] = DMA_MAP_FREE;
+ restore_flags (flags);
+}
+
+#ifdef CONFIG_SEQUENCER
+
+
+static struct timer_list seq_timer =
+{NULL, NULL, 0, 0, sequencer_timer};
+
void
request_sound_timer (int count)
{
extern unsigned long seq_time;
-#if 1
if (count < 0)
- count = jiffies + (-count);
- else
- count += seq_time;
- timer_table[SOUND_TIMER].fn = sequencer_timer;
- timer_table[SOUND_TIMER].expires = count;
- timer_active |= 1 << SOUND_TIMER;
-#endif
-}
+ {
-#endif
+ {
+ seq_timer.expires = (-count) + jiffies;
+ add_timer (&seq_timer);
+ };
+ return;
+ }
+
+ count += seq_time;
+
+ count -= jiffies;
+
+ if (count < 1)
+ count = 1;
+
+
+ {
+ seq_timer.expires = (count) + jiffies;
+ add_timer (&seq_timer);
+ };
+}
void
sound_stop_timer (void)
{
-#if 1
- timer_table[SOUND_TIMER].expires = 0;
- timer_active &= ~(1 << SOUND_TIMER);
-#endif
+ del_timer (&seq_timer);;
}
+#endif
-#ifndef EXCLUDE_AUDIO
-static int
-valid_dma_page (unsigned long addr, unsigned long dev_buffsize, unsigned long dma_pagesize)
-{
- if (((addr & (dma_pagesize - 1)) + dev_buffsize) <= dma_pagesize)
- return 1;
- else
- return 0;
-}
+#ifdef CONFIG_AUDIO
-void
-sound_mem_init (void)
+#ifdef KMALLOC_DMA_BROKEN
+fatal_error__This_version_is_not_compatible_with_this_kernel;
+#endif
+
+static int dma_buffsize = DSP_BUFFSIZE;
+
+int
+sound_alloc_dmap (int dev, struct dma_buffparms *dmap, int chan)
{
- int i, dev;
- unsigned long start_addr, end_addr, mem_ptr, dma_pagesize;
- struct dma_buffparms *dmap;
+ char *start_addr, *end_addr;
+ int i, dma_pagesize;
- mem_ptr = high_memory;
+ dmap->mapping_flags &= ~DMA_MAP_MAPPED;
- /* Some sanity checks */
+ if (dmap->raw_buf != NULL)
+ return 0; /* Already done */
- if (mem_ptr > (16 * 1024 * 1024))
- mem_ptr = 16 * 1024 * 1024; /* Limit to 16M */
+ if (dma_buffsize < 4096)
+ dma_buffsize = 4096;
- for (dev = 0; dev < num_audiodevs; dev++) /* Enumerate devices */
- if (audio_devs[dev]->buffcount > 0 && audio_devs[dev]->dmachan >= 0)
- {
- dmap = audio_devs[dev]->dmap;
+ if (chan < 4)
+ dma_pagesize = 64 * 1024;
+ else
+ dma_pagesize = 128 * 1024;
- if (audio_devs[dev]->flags & DMA_AUTOMODE)
- audio_devs[dev]->buffcount = 1;
+ dmap->raw_buf = NULL;
- if (audio_devs[dev]->dmachan > 3 && audio_devs[dev]->buffsize > 65536)
- dma_pagesize = 131072;/* 128k */
- else
- dma_pagesize = 65536;
+ if (debugmem)
+ printk ("sound: buffsize[%d] = %lu\n", dev, audio_devs[dev]->buffsize);
- /* More sanity checks */
+ audio_devs[dev]->buffsize = dma_buffsize;
- 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 (audio_devs[dev]->buffsize > dma_pagesize)
+ audio_devs[dev]->buffsize = dma_pagesize;
- /* Now allocate the buffers */
+ start_addr = NULL;
- for (dmap->raw_count = 0; dmap->raw_count < audio_devs[dev]->buffcount; dmap->raw_count++)
- {
- start_addr = mem_ptr - audio_devs[dev]->buffsize;
- if (!valid_dma_page (start_addr, audio_devs[dev]->buffsize, dma_pagesize))
- start_addr &= ~(dma_pagesize - 1); /* Align address to
- * dma_pagesize */
+/*
+ * Now loop until we get a free buffer. Try to get smaller buffer if
+ * it fails.
+ */
- end_addr = start_addr + audio_devs[dev]->buffsize - 1;
+ while (start_addr == NULL && audio_devs[dev]->buffsize > PAGE_SIZE)
+ {
+ int sz, size;
- dmap->raw_buf[dmap->raw_count] = (char *) start_addr;
- dmap->raw_buf_phys[dmap->raw_count] = start_addr;
- mem_ptr = start_addr;
+ for (sz = 0, size = PAGE_SIZE;
+ size < audio_devs[dev]->buffsize;
+ sz++, size <<= 1);
- for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++)
- {
- if (mem_map[i])
- panic ("sound_mem_init: Page not free (driver incompatible with kernel).\n");
+ audio_devs[dev]->buffsize = PAGE_SIZE * (1 << sz);
- mem_map[i] = MAP_PAGE_RESERVED;
- }
- }
- } /* for dev */
-}
+ if ((start_addr = (char *) __get_free_pages (GFP_ATOMIC, sz, MAX_DMA_ADDRESS)) == NULL)
+ audio_devs[dev]->buffsize /= 2;
+ }
-#endif
+ if (start_addr == NULL)
+ {
+ printk ("Sound error: Couldn't allocate DMA buffer\n");
+ return -ENOMEM;
+ }
+ 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 *) (MAX_DMA_ADDRESS))
+ {
+ printk (
+ "sound: Got invalid address 0x%lx for %ldb DMA-buffer\n",
+ (long) start_addr,
+ audio_devs[dev]->buffsize);
+ return -EFAULT;
+ }
+ }
+ dmap->raw_buf = start_addr;
+ dmap->raw_buf_phys = virt_to_bus (start_addr);
-#else
+ for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++)
+ {
+ set_bit (PG_reserved, &mem_map[i].flags);;
+ }
+
+ return 0;
+}
-long
-soundcard_init (long mem_start) /* Dummy version */
+void
+sound_free_dmap (int dev, struct dma_buffparms *dmap, int chan)
{
- return mem_start;
+ int sz, size, i;
+ unsigned long start_addr, end_addr;
+
+ if (dmap->raw_buf == NULL)
+ return;
+
+ if (dmap->mapping_flags & DMA_MAP_MAPPED)
+ return; /* Don't free mmapped buffer. Will use it next time */
+
+ for (sz = 0, size = PAGE_SIZE;
+ size < audio_devs[dev]->buffsize;
+ sz++, size <<= 1);
+
+ start_addr = (unsigned long) dmap->raw_buf;
+ end_addr = start_addr + audio_devs[dev]->buffsize;
+
+ for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++)
+ {
+ clear_bit (PG_reserved, &mem_map[i].flags);;
+ }
+
+ free_pages ((unsigned long) dmap->raw_buf, sz);
+ dmap->raw_buf = NULL;
}
+int
+sound_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc * info)
+{
+ printk ("Entered sound_map_buffer()\n");
+ printk ("Exited sound_map_buffer()\n");
+ return -EINVAL;
+}
#endif
-#if !defined(CONFIGURE_SOUNDCARD) || defined(EXCLUDE_AUDIO)
void
-sound_mem_init (void)
+conf_printf (char *name, struct address_info *hw_config)
{
- /* Dummy version */
+ if (!trace_init)
+ return;
+
+ printk ("<%s> at 0x%03x", name, hw_config->io_base);
+
+ if (hw_config->irq)
+ printk (" irq %d", (hw_config->irq > 0) ? hw_config->irq : -hw_config->irq);
+
+ if (hw_config->dma != -1 || hw_config->dma2 != -1)
+ {
+ printk (" dma %d", hw_config->dma);
+ if (hw_config->dma2 != -1)
+ printk (",%d", hw_config->dma2);
+ }
+
+ printk ("\n");
}
-#endif
+void
+conf_printf2 (char *name, int base, int irq, int dma, int dma2)
+{
+ if (!trace_init)
+ return;
+
+ printk ("<%s> at 0x%03x", name, base);
+
+ if (irq)
+ printk (" irq %d", (irq > 0) ? irq : -irq);
+
+ if (dma != -1 || dma2 != -1)
+ {
+ printk (" dma %d", dma);
+ if (dma2 != -1)
+ printk (",%d", dma2);
+ }
+
+ printk ("\n");
+}