summaryrefslogtreecommitdiff
path: root/kernel/OS/Linux/os_linux.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/OS/Linux/os_linux.c')
-rw-r--r--kernel/OS/Linux/os_linux.c1034
1 files changed, 1034 insertions, 0 deletions
diff --git a/kernel/OS/Linux/os_linux.c b/kernel/OS/Linux/os_linux.c
new file mode 100644
index 0000000..c47f3da
--- /dev/null
+++ b/kernel/OS/Linux/os_linux.c
@@ -0,0 +1,1034 @@
+/*
+ * Purpose: Operating system abstraction functions for Linux
+ */
+/*
+ *
+ * This file is part of Open Sound System.
+ *
+ * Copyright (C) 4Front Technologies 1996-2008.
+ *
+ * This this source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ */
+
+#include <oss_config.h>
+#include <midi_core.h>
+
+/*
+ * OSS has traditionally used fixed character device number (14). However
+ * current OSS uses fully dynamic major number allocation. The legacy
+ * character device 14 is left for ALSA.
+ */
+static int osscore_major = 0;
+static int oss_expired = 0;
+
+/*
+ * Number of cards supported in the same system. This should be largish
+ * because unplugging/replugging USB cards in wrong way may create
+ * large number of card instances.
+ */
+#define MAX_CARDS 32
+
+static oss_device_t *cards[MAX_CARDS];
+int oss_num_cards = 0;
+
+void
+oss_pci_byteswap (oss_device_t * osdev, int mode)
+{
+ // NOP
+}
+
+int
+oss_pci_read_config_byte (oss_device_t * osdev, offset_t where,
+ unsigned char *val)
+{
+ return osscore_pci_read_config_byte (osdev->dip, where, val);
+}
+
+int
+oss_pci_read_config_irq (oss_device_t * osdev, offset_t where,
+ unsigned char *val)
+{
+ return osscore_pci_read_config_irq (osdev->dip, where, val);
+}
+
+int
+oss_pci_read_config_word (oss_device_t * osdev, offset_t where,
+ unsigned short *val)
+{
+ if (osdev == NULL)
+ {
+ cmn_err (CE_CONT, "oss_pci_read_config_word: osdev==NULL\n");
+ return PCIBIOS_FAILED;
+ }
+
+ return osscore_pci_read_config_word (osdev->dip, where, val);
+}
+
+int
+oss_pci_read_config_dword (oss_device_t * osdev, offset_t where,
+ unsigned int *val)
+{
+ return osscore_pci_read_config_dword (osdev->dip, where, val);
+}
+
+int
+oss_pci_write_config_byte (oss_device_t * osdev, offset_t where,
+ unsigned char val)
+{
+ return osscore_pci_write_config_byte (osdev->dip, where, val);
+}
+
+int
+oss_pci_write_config_word (oss_device_t * osdev, offset_t where,
+ unsigned short val)
+{
+ return osscore_pci_write_config_word (osdev->dip, where, val);
+}
+
+int
+oss_pci_write_config_dword (oss_device_t * osdev, offset_t where,
+ unsigned int val)
+{
+ return osscore_pci_write_config_dword (osdev->dip, where, val);
+}
+
+int
+oss_pci_enable_msi (oss_device_t * osdev)
+{
+ return osscore_pci_enable_msi (osdev->dip);
+}
+
+int
+oss_find_minor (int dev_class, int instance)
+{
+ int i;
+
+ for (i = 0; i < oss_num_cdevs; i++)
+ {
+ if (oss_cdevs[i]->d != NULL && oss_cdevs[i]->dev_class == dev_class
+ && oss_cdevs[i]->instance == instance)
+ return i;
+ }
+
+ return OSS_ENXIO;
+}
+
+oss_device_t *
+osdev_create (dev_info_t * dip, int dev_type,
+ int instance, const char *nick, const char *handle)
+{
+ oss_device_t *osdev;
+
+ osdev = PMALLOC (NULL, sizeof (*osdev));
+ if (osdev == NULL)
+ {
+ cmn_err (CE_WARN, "osdev_create: Out of memory\n");
+ return NULL;
+ }
+
+ memset (osdev, 0, sizeof (*osdev));
+
+ sprintf (osdev->nick, "%s%d", nick, instance);
+ osdev->instance = instance;
+ osdev->dip = dip;
+ osdev->available = 1;
+ osdev->first_mixer = -1;
+
+ strcpy (osdev->modname, nick);
+
+ if (handle == NULL)
+ handle = nick;
+
+ if (oss_num_cards >= MAX_CARDS)
+ cmn_err (CE_WARN, "Too many OSS devices. At most %d permitted.\n",
+ MAX_CARDS);
+ else
+ {
+ osdev->cardnum = oss_num_cards;
+ cards[oss_num_cards++] = osdev;
+ }
+/*
+ * Create the device handle
+ */
+ switch (dev_type)
+ {
+ case DRV_PCI:
+ {
+ unsigned int subvendor;
+ char *devpath;
+ devpath = oss_pci_read_devpath (osdev->dip);
+ oss_pci_read_config_dword (osdev, 0x2c, &subvendor);
+
+ sprintf (osdev->handle, "PCI%08x-%s", subvendor, devpath);
+ }
+ break;
+
+ case DRV_USB:
+ // TODO: Get the vendor information
+ sprintf (osdev->handle, "USB-%s%d", handle, instance);
+ break;
+
+ default:
+ sprintf (osdev->handle, "%s%d", handle, instance);
+ }
+
+ return osdev;
+}
+
+oss_device_t *
+osdev_clone (oss_device_t * orig_osdev, int new_instance)
+{
+ oss_device_t *osdev;
+
+ osdev = PMALLOC (NULL, sizeof (*osdev));
+ if (osdev == NULL)
+ {
+ cmn_err (CE_WARN, "osdev_create: Out of memory\n");
+ return NULL;
+ }
+ memcpy (osdev, orig_osdev, sizeof (*osdev));
+ osdev->dev_type = DRV_CLONE;
+ osdev->instance = new_instance;
+ sprintf (osdev->nick, "%s%d", orig_osdev->modname, new_instance);
+ sprintf (osdev->handle, "%s%d", orig_osdev->modname, new_instance);
+
+ return osdev;
+}
+
+void
+osdev_delete (oss_device_t * osdev)
+{
+ int i;
+
+ if (osdev == NULL)
+ return;
+
+ osdev->available = 0;
+/*
+ * Mark all minor nodes for this module as invalid.
+ */
+ for (i = 0; i < oss_num_cdevs; i++)
+ if (oss_cdevs[i]->osdev == osdev)
+ {
+ oss_cdevs[i]->d = NULL;
+ oss_cdevs[i]->osdev = NULL;
+ strcpy (oss_cdevs[i]->name, "Removed device");
+ }
+}
+
+void
+osdev_set_owner (oss_device_t * osdev, struct module *owner)
+{
+ osdev->owner = owner;
+}
+
+void
+osdev_set_major (oss_device_t * osdev, int major)
+{
+ osdev->major = major;
+}
+
+void
+osdev_set_irqparms (oss_device_t * osdev, void *irqparms)
+{
+ osdev->irqparms = irqparms;
+}
+
+void *
+osdev_get_irqparms (oss_device_t * osdev)
+{
+ return osdev->irqparms;
+}
+
+char *
+osdev_get_nick (oss_device_t * osdev)
+{
+ return osdev->nick;
+}
+
+int
+osdev_get_instance (oss_device_t * osdev)
+{
+ return osdev->instance;
+}
+
+void
+oss_inc_intrcount (oss_device_t * osdev, int claimed)
+{
+ osdev->intrcount++;
+
+ if (claimed)
+ osdev->ackcount++;
+}
+
+struct module *
+osdev_get_owner (oss_device_t * osdev)
+{
+ return osdev->owner;
+}
+
+void *
+oss_get_osid (oss_device_t * osdev)
+{
+ return NULL; // TODO
+}
+
+int
+oss_get_procinfo(int what)
+{
+ switch (what)
+ {
+ case OSS_GET_PROCINFO_UID:
+ return oss_get_uid();
+ break;
+ }
+
+ return OSS_EINVAL;
+}
+
+int
+oss_disable_device (oss_device_t * osdev)
+{
+ int i;
+
+ if (osdev->major > 0)
+ oss_unregister_chrdev (osdev->major, osdev->nick);
+ osdev->major = 0;
+
+/*
+ * Now mark all devices unavailable (for the time being)
+ * TODO: Mobe this stuff to some common OSS module (also in Solaris)
+ */
+ if (osdev->refcount > 0)
+ {
+ return OSS_EBUSY;
+ }
+
+ for (i = 0; i < num_mixers; i++)
+ if (mixer_devs[i]->osdev == osdev)
+ {
+ mixer_devs[i]->unloaded = 1;
+ }
+
+ for (i = 0; i < num_mididevs; i++)
+ {
+ if (midi_devs[i]->osdev == osdev)
+ {
+ midi_devs[i]->unloaded = 1;
+ }
+ }
+
+ for (i = 0; i < num_audio_engines; i++)
+ if (audio_engines[i]->osdev == osdev)
+ {
+ audio_uninit_device (i);
+ }
+
+ return 0;
+}
+
+void
+oss_reserve_device (oss_device_t * osdev)
+{
+ osdev->refcount++;
+}
+
+void
+oss_unreserve_device (oss_device_t * osdev, int decrement)
+{
+ osdev->refcount--;
+ if (osdev->refcount < 0)
+ osdev->refcount = 0;
+}
+
+int
+oss_register_device (oss_device_t * osdev, const char *name)
+{
+ if (name == NULL)
+ {
+ cmn_err (CE_WARN, "oss_register_device: name==NULL\n");
+ osdev->name = "Undefined name";
+ return 0;
+ }
+
+ if ((osdev->name = PMALLOC (NULL, strlen (name) + 1)) == NULL)
+ {
+ cmn_err (CE_WARN, "Cannot allocate memory for device name\n");
+ osdev->name = "Unknown device";
+ }
+ strcpy (osdev->name, name);
+ return 0;
+}
+
+void
+oss_unregister_device (oss_device_t * osdev)
+{
+/*
+ * Notice! The driver calling this routine (the owner of the osdev parameter)
+ * has already uninitialized itself. Do not do any actions that may call this
+ * driver directly or indirectly.
+ */
+
+// TODO: Move this to some common OSS module (also under Solaris)
+}
+
+int
+oss_get_cardinfo (int cardnum, oss_card_info * ci)
+{
+/*
+ * Print information about a 'card' in a format suitable for /dev/sndstat
+ */
+
+ if (cardnum < 0 || cardnum >= oss_num_cards)
+ return OSS_ENXIO;
+
+ if (cards[cardnum]->name != NULL)
+ strncpy (ci->longname, cards[cardnum]->name, 128);
+ ci->longname[127] = 0;
+
+ if (cards[cardnum]->nick != NULL)
+ strncpy (ci->shortname, cards[cardnum]->nick, 16);
+ ci->shortname[15] = 0;
+
+ if (cards[cardnum]->hw_info != NULL)
+ strncpy (ci->hw_info, cards[cardnum]->hw_info, sizeof (ci->hw_info));
+ ci->hw_info[sizeof (ci->hw_info) - 1] = 0;
+ ci->intr_count = cards[cardnum]->intrcount;
+ ci->ack_count = cards[cardnum]->ackcount;
+
+ return 0;
+}
+
+int
+__oss_alloc_dmabuf (int dev, dmap_p dmap, unsigned int alloc_flags,
+ oss_uint64_t maxaddr, int direction)
+{
+ void *buf;
+ int err;
+ oss_native_word phaddr;
+ int size = 64 * 1024;
+ extern int dma_buffsize;
+
+ if (dma_buffsize > 16 && dma_buffsize <= 128)
+ size = dma_buffsize * 1024;
+
+ if (dmap->dmabuf != NULL)
+ return 0; /* Already done */
+
+ if (dmap == NULL)
+ {
+ cmn_err (CE_WARN, "oss_alloc_dmabuf: dmap==NULL\n");
+ return OSS_EIO;
+ }
+
+/*
+ * Some applications and virtual drivers need shorter buffer.
+ */
+ if (dmap->flags & DMAP_SMALLBUF)
+ {
+ size = SMALL_DMABUF_SIZE;
+ }
+ else if (dmap->flags & DMAP_MEDIUMBUF)
+ {
+ size = MEDIUM_DMABUF_SIZE;
+ }
+
+ if ((alloc_flags & DMABUF_SIZE_16BITS) && size > 32 * 1024)
+ size = 32 * 1024;
+
+ dmap->dmabuf = NULL;
+ dmap->buffsize = size;
+
+ err = -1;
+
+ while (err < 0 && dmap->dmabuf == NULL && dmap->buffsize >= 4 * 1024)
+ {
+ if ((buf =
+ oss_contig_malloc (dmap->osdev, dmap->buffsize, maxaddr,
+ &phaddr)) == NULL)
+ {
+ if ((dmap->buffsize = (dmap->buffsize / 2)) < 8 * 1024)
+ return OSS_ENOMEM;
+ cmn_err (CE_CONT, "Dropping DMA buffer size to %d bytes.\n",
+ dmap->buffsize);
+ continue;
+ }
+
+ dmap->dmabuf = buf;
+ dmap->dmabuf_phys = phaddr;
+
+ return 0;
+ }
+
+ return OSS_ENOMEM;
+}
+
+void
+oss_free_dmabuf (int dev, dmap_p dmap)
+{
+ void *buf = dmap->dmabuf;
+
+ if (dmap->dmabuf == NULL)
+ return;
+
+ dmap->dmabuf = NULL;
+ oss_contig_free (NULL, buf, dmap->buffsize);
+ dmap->dmabuf_phys = 0;
+}
+
+static inline int
+cpy_file (oss_file_handle_t * f, struct fileinfo *fi)
+{
+ // TODO: Handle acc_flags properly
+ fi->acc_flags = 0;
+ fi->mode = 0;
+ fi->acc_flags = oss_file_get_flags (f);
+
+ if ((fi->acc_flags & O_ACCMODE) == O_RDWR)
+ fi->mode = OPEN_READWRITE;
+ if ((fi->acc_flags & O_ACCMODE) == O_RDONLY)
+ fi->mode = OPEN_READ;
+ if ((fi->acc_flags & O_ACCMODE) == O_WRONLY)
+ fi->mode = OPEN_WRITE;
+
+ return fi->mode;
+}
+
+static int
+oss_cdev_open (oss_inode_handle_t * inode, oss_file_handle_t * file)
+{
+ int dev = oss_inode_get_minor (inode);
+ oss_native_word d;
+ int tmpdev, dev_class, retval;
+ struct fileinfo fi;
+ oss_cdev_t *cdev;
+
+ cpy_file (file, &fi);
+
+ if (dev > oss_num_cdevs)
+ return OSS_ENXIO;
+ if (oss_cdevs == NULL)
+ return OSS_ENXIO;
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d == NULL)
+ return OSS_ENXIO;
+
+ DDB (cmn_err
+ (CE_CONT, "oss_cdev_open(%d): %s, class=%d, instance=%d\n", dev,
+ cdev->name, cdev->dev_class, cdev->instance));
+
+ if (cdev->d->open == NULL)
+ {
+ return OSS_ENODEV;
+ }
+
+ dev_class = cdev->dev_class;
+
+ tmpdev = -1;
+ oss_inc_refcounts ();
+ retval =
+ cdev->d->open (cdev->instance, cdev->dev_class, &fi, 0, 0, &tmpdev);
+
+ if (retval < 0)
+ {
+ oss_dec_refcounts ();
+ return retval;
+ }
+
+ if (tmpdev != -1)
+ dev = tmpdev;
+
+ //open_devices++;
+ //open_count[dev]++;
+
+ d = dev;
+ oss_file_set_private (file, (void *) d);
+
+ return 0;
+}
+
+static int
+oss_cdev_release (oss_inode_handle_t * inode, oss_file_handle_t * file)
+{
+ oss_native_word d = (oss_native_word) oss_file_get_private (file);
+ int dev = d;
+ struct fileinfo fi;
+ oss_cdev_t *cdev;
+
+ cpy_file (file, &fi);
+
+ if (dev > oss_num_cdevs)
+ return 0;
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d->close == NULL)
+ {
+ return 0;
+ }
+
+ cdev->d->close (cdev->instance, &fi);
+ oss_dec_refcounts ();
+
+ return 0;
+}
+
+static ssize_t
+oss_cdev_read (oss_file_handle_t * file, char *buf, size_t count,
+ loff_t * offs)
+{
+ oss_native_word d = (oss_native_word) oss_file_get_private (file);
+ int dev = d;
+ oss_cdev_t *cdev;
+ int err;
+ uio_t uio;
+
+ struct fileinfo fi;
+ cpy_file (file, &fi);
+
+ if (dev > oss_num_cdevs)
+ return OSS_ENXIO;
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d->read == NULL)
+ {
+ return OSS_ENXIO;
+ }
+
+ if ((err = oss_create_uio (&uio, buf, count, UIO_READ, 0)) < 0)
+ {
+ return err;
+ }
+
+ err = cdev->d->read (cdev->instance, &fi, &uio, count);
+
+ return err;
+}
+
+static ssize_t
+oss_cdev_write (oss_file_handle_t * file, char *buf, size_t count,
+ loff_t * offs)
+{
+ oss_native_word d = (oss_native_word) oss_file_get_private (file);
+ int dev = d;
+ oss_cdev_t *cdev;
+ int err;
+ uio_t uio;
+
+ struct fileinfo fi;
+ cpy_file (file, &fi);
+
+ if (dev > oss_num_cdevs)
+ return OSS_ENXIO;
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d->write == NULL)
+ {
+ return OSS_ENXIO;
+ }
+
+ if ((err = oss_create_uio (&uio, buf, count, UIO_WRITE, 0)) < 0)
+ {
+ return err;
+ }
+
+ err = cdev->d->write (cdev->instance, &fi, &uio, count);
+
+ return err;
+}
+
+static int
+oss_cdev_ioctl (oss_inode_handle_t * inode, oss_file_handle_t * file,
+ unsigned int cmd, unsigned long arg)
+{
+ oss_native_word d = (oss_native_word) oss_file_get_private (file);
+ int dev = d;
+ oss_cdev_t *cdev;
+ int err;
+ int localbuf[64]; /* 256 bytes is the largest frequently used ioctl size */
+
+ int len = 0;
+ int alloced = 0;
+ int *ptr = (int *) arg;
+
+ struct fileinfo fi;
+ cpy_file (file, &fi);
+
+ if (dev > oss_num_cdevs)
+ return OSS_ENXIO;
+
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d->ioctl == NULL)
+ {
+ return OSS_ENXIO;
+ }
+
+ if (__SIOC_DIR (cmd) != __SIOC_NONE && __SIOC_DIR (cmd) != 0)
+ {
+ len = __SIOC_SIZE (cmd);
+ if (len < 1 || len > 65536 || arg == 0)
+ {
+ cmn_err (CE_WARN, "Bad ioctl command %x, %d, %x\n", cmd, len, arg);
+ return OSS_EFAULT;
+ }
+
+ /* Use statically allocated buffer for short arguments */
+ if (len > sizeof (localbuf))
+ {
+ ptr = KERNEL_MALLOC (len);
+ alloced = 1;
+ }
+ else
+ ptr = localbuf;
+
+ if (ptr == NULL || arg == 0)
+ {
+ return OSS_EFAULT;
+ }
+
+ if (__SIOC_DIR (cmd) & __SIOC_WRITE)
+ {
+ if (oss_copy_from_user (ptr, (char *) arg, len))
+ {
+ if (alloced)
+ KERNEL_FREE (ptr);
+ return OSS_EFAULT;
+ }
+ }
+ }
+
+ if ((err = cdev->d->ioctl (cdev->instance, &fi, cmd, (ioctl_arg) ptr)) < 0)
+ {
+ if (alloced)
+ KERNEL_FREE (ptr);
+ return err;
+ }
+
+ if (__SIOC_DIR (cmd) & __SIOC_READ)
+ {
+ if (oss_copy_to_user ((char *) arg, ptr, len))
+ {
+ if (alloced)
+ KERNEL_FREE (ptr);
+ return OSS_EFAULT;
+ }
+ }
+
+ /* Free the local buffer unless it was statically allocated */
+ if (ptr != NULL && alloced)
+ if (len > sizeof (localbuf))
+ KERNEL_FREE (ptr);
+
+ return ((err < 0) ? err : 0);
+
+}
+
+/* No BKL if this is used */
+static long
+oss_cdev_unlocked_ioctl (oss_file_handle_t * file, unsigned int cmd,
+ unsigned long arg)
+{
+ return oss_cdev_ioctl (NULL, file, cmd, arg);
+}
+
+/* Used for 32 bit clients on a 64 bit kernel. No BKL here either */
+static long
+oss_cdev_compat_ioctl (oss_file_handle_t * file, unsigned int cmd,
+ unsigned long arg)
+{
+ return oss_cdev_ioctl (NULL, file, cmd, arg);
+}
+
+static unsigned int
+oss_cdev_poll (oss_file_handle_t * file, oss_poll_table_handle_t * wait)
+{
+ oss_poll_event_t ev;
+ oss_native_word d = (oss_native_word) oss_file_get_private (file);
+ int dev = d;
+ oss_cdev_t *cdev;
+ int err;
+
+ struct fileinfo fi;
+ cpy_file (file, &fi);
+
+ if (dev > oss_num_cdevs)
+ return OSS_ENXIO;
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d->chpoll == NULL)
+ {
+ return OSS_ENXIO;
+ }
+
+ ev.wait = wait;
+ ev.file = file;
+ ev.events = POLLOUT | POLLWRNORM | POLLIN | POLLRDNORM;
+ ev.revents = 0;
+ err = cdev->d->chpoll (cdev->instance, &fi, &ev);
+ if (err < 0)
+ {
+ return err;
+ }
+
+ return ev.revents;
+}
+
+static int
+oss_cdev_mmap (oss_file_handle_t * file, oss_vm_area_handle_t * vma)
+{
+ oss_native_word d = (oss_native_word) oss_file_get_private (file);
+ int dev = d;
+ oss_cdev_t *cdev;
+ dmap_p dmap = NULL;
+ int err;
+
+ if (dev > oss_num_cdevs)
+ return OSS_ENXIO;
+
+ if ((cdev = oss_cdevs[dev]) == NULL)
+ {
+ return OSS_ENXIO;
+ }
+
+ if (cdev->dev_class != OSS_DEV_DSP && cdev->dev_class != OSS_DEV_DSP_ENGINE) /* Only mmap audio devices */
+ {
+ return OSS_ENXIO;
+ }
+
+ dev = cdev->instance;
+ if (dev < 0 || dev >= num_audio_engines)
+ return OSS_ENXIO;
+
+ if (audio_engines[dev]->flags & ADEV_NOMMAP)
+ return OSS_EIO;
+
+ if (oss_vma_get_flags (vma) & VM_WRITE) /* Map write and read/write to the output buf */
+ {
+ dmap = audio_engines[dev]->dmap_out;
+ }
+ else if (oss_vma_get_flags (vma) & VM_READ)
+ {
+ dmap = audio_engines[dev]->dmap_in;
+ }
+ else
+ {
+ cmn_err (CE_WARN, "Undefined mmap() access\n");
+ return OSS_EINVAL;
+ }
+
+ if (dmap == NULL)
+ {
+ cmn_err (CE_WARN, "mmap() error. dmap == NULL\n");
+ return OSS_EIO;
+ }
+
+ if (dmap->dmabuf == NULL)
+ {
+ cmn_err (CE_WARN, "mmap() called when raw_buf == NULL\n");
+ return OSS_EIO;
+ }
+
+ if (dmap->dmabuf_phys == 0)
+ {
+ cmn_err (CE_WARN, "mmap() not supported by device /dev/dsp%d.\n", dev);
+ return OSS_EIO;
+ }
+
+ if (dmap->mapping_flags)
+ {
+ cmn_err (CE_WARN, "mmap() called twice for the same DMA buffer\n");
+ return OSS_EIO;
+ }
+
+ if (dmap->flags & DMAP_COOKED)
+ {
+ cmn_err (CE_WARN,
+ "mmap() not possible with currently selected sample format.\n");
+ return OSS_EIO;
+ }
+
+ if ((err = oss_do_mmap (vma, dmap->dmabuf_phys, dmap->bytes_in_use)) < 0)
+ return err;
+
+ dmap->mapping_flags |= DMA_MAP_MAPPED;
+
+ memset (dmap->dmabuf, dmap->neutral_byte, dmap->bytes_in_use);
+ return 0;
+}
+
+oss_file_operation_handle_t oss_fops = {
+ oss_cdev_read,
+ oss_cdev_write,
+ NULL, /* oss_readdir */
+ oss_cdev_poll,
+ oss_cdev_ioctl,
+ oss_cdev_mmap,
+ oss_cdev_open,
+ oss_cdev_release,
+ oss_cdev_compat_ioctl,
+ oss_cdev_unlocked_ioctl
+};
+
+static int
+hookup_cdevsw (oss_device_t * osdev)
+{
+ return oss_register_chrdev (osdev, osscore_major, "osscore", &oss_fops);
+}
+
+int
+oss_request_major (oss_device_t * osdev, int major, char *module)
+{
+ int err;
+
+ err = oss_register_chrdev (osdev, major, module, &oss_fops);
+
+ return err;
+}
+
+static int
+grow_array(oss_device_t *osdev, oss_cdev_t ***arr, int *size, int increment)
+{
+ oss_cdev_t **old=*arr, **new = *arr;
+ int old_size = *size;
+ int new_size = *size;
+
+ new_size += increment;
+
+ if ((new=PMALLOC(osdev, new_size * sizeof (oss_cdev_t *)))==NULL)
+ return 0;
+
+ memset(new, 0, new_size * sizeof(oss_cdev_t *));
+ if (old != NULL)
+ memcpy(new, old, old_size * sizeof(oss_cdev_t *));
+
+ *size = new_size;
+ *arr = new;
+
+ if (old != NULL)
+ PMFREE(osdev, old);
+
+ return 1;
+}
+
+void
+oss_install_chrdev (oss_device_t * osdev, char *name, int dev_class,
+ int instance, oss_cdev_drv_t * drv, int flags)
+{
+/*
+ * oss_install_chrdev creates a character device (minor). However if
+ * name==NULL the device will not be exported (made visible to userland
+ * clients).
+ */
+
+ int num;
+ oss_cdev_t *cdev = NULL;
+
+ if (osdev->major == 0)
+ {
+ cmn_err (CE_WARN, "Module %s major=0\n", osdev->nick);
+ return;
+ }
+
+ if (osdev->major < 0)
+ {
+ cmn_err (CE_WARN, "Failed to allocate major device for %s\n",
+ osdev->nick);
+ }
+
+ if (dev_class != OSS_DEV_STATUS)
+ if (oss_expired && instance > 0)
+ return;
+/*
+ * Find if this dev_class&instance already exists (after previous module
+ * detach).
+ */
+
+ for (num = 0; num < oss_num_cdevs; num++)
+ if (oss_cdevs[num]->d == NULL) /* Unloaded driver */
+ if (oss_cdevs[num]->dev_class == dev_class
+ && oss_cdevs[num]->instance == instance)
+ {
+ cdev = oss_cdevs[num];
+ break;
+ }
+
+ if (cdev == NULL)
+ {
+ if (oss_num_cdevs >= OSS_MAX_CDEVS)
+ {
+ if (!grow_array(osdev, &oss_cdevs, &oss_max_cdevs, 100))
+ {
+ cmn_err (CE_WARN, "Out of minor numbers.\n");
+ return;
+ }
+ }
+
+ if ((cdev = PMALLOC (NULL, sizeof (*cdev))) == NULL)
+ {
+ cmn_err (CE_WARN, "Cannot allocate character device desc.\n");
+ return;
+ }
+
+ num = oss_num_cdevs++;
+ }
+
+ memset (cdev, 0, sizeof (*cdev));
+ cdev->dev_class = dev_class;
+ cdev->instance = instance;
+ cdev->d = drv;
+ cdev->osdev = osdev;
+ if (name != NULL)
+ strncpy (cdev->name, name, sizeof (cdev->name));
+ else
+ strcpy (cdev->name, "NONE");
+ cdev->name[sizeof (cdev->name) - 1] = 0;
+ oss_cdevs[num] = cdev;
+
+/*
+ * Export the device only if name != NULL
+ */
+ if (name != NULL)
+ {
+ strcpy (cdev->name, name);
+ oss_register_minor (osdev->major, num, name);
+ }
+}
+
+int
+oss_init_osscore (oss_device_t * osdev)
+{
+
+#ifdef LICENSED_VERSION
+ if (!oss_license_handle_time (oss_get_time ()))
+ {
+ cmn_err (CE_WARN, "This version of Open Sound System has expired\n");
+ cmn_err (CE_CONT,
+ "Please download the latest version from www.opensound.com\n");
+ oss_expired = 1;
+ }
+#endif
+
+ if ((osscore_major = hookup_cdevsw (osdev)) < 0)
+ {
+ cmn_err (CE_WARN, "Failed to allocate character major number %d\n",
+ osscore_major);
+ return OSS_EBUSY;
+ }
+
+ osdev->major = osscore_major;
+ oss_register_device (osdev, "OSS core services");
+
+ oss_common_init (osdev);
+
+ return 0;
+}
+
+void
+oss_uninit_osscore (oss_device_t * osdev)
+{
+ oss_unload_drivers ();
+
+ // free_all_irqs (); /* If something was left allocated by accident */
+ oss_unregister_chrdev (osscore_major, "osscore");
+}
+
+/*
+ * oss_pmalloc() is only used by usb_wraper.inc.
+ */
+void *
+oss_pmalloc (size_t sz)
+{
+ return oss_memblk_malloc(&oss_global_memblk, sz);
+}