summaryrefslogtreecommitdiff
path: root/kernel/OS
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2013-05-03 21:08:42 +0400
committerIgor Pashev <pashev.igor@gmail.com>2013-05-03 21:08:42 +0400
commit1058def8e7827e56ce4a70afb4aeacb5dc44148f (patch)
tree4495d23e7b54ab5700e3839081e797c1eafe0db9 /kernel/OS
downloadoss4-upstream/4.2-build2006.tar.gz
Imported Upstream version 4.2-build2006upstream/4.2-build2006upstream
Diffstat (limited to 'kernel/OS')
-rw-r--r--kernel/OS/.nomake0
-rw-r--r--kernel/OS/BeOS/.config1
-rw-r--r--kernel/OS/BeOS/driver_beos.c104
-rw-r--r--kernel/OS/BeOS/module.inc186
-rw-r--r--kernel/OS/BeOS/os_beos.c2222
-rw-r--r--kernel/OS/BeOS/os_beos.h471
-rw-r--r--kernel/OS/FreeBSD/.config1
-rw-r--r--kernel/OS/FreeBSD/os_freebsd.c1107
-rw-r--r--kernel/OS/FreeBSD/os_freebsd.h263
-rw-r--r--kernel/OS/FreeBSD/wrapper/bsddefs.h150
-rw-r--r--kernel/OS/Linux/.config1
-rw-r--r--kernel/OS/Linux/os_linux.c1034
-rw-r--r--kernel/OS/Linux/os_linux.h287
-rw-r--r--kernel/OS/Linux/oss_ddi.h46
-rw-r--r--kernel/OS/Linux/wrapper/.nomake0
-rw-r--r--kernel/OS/Linux/wrapper/wrap.h288
-rw-r--r--kernel/OS/SCO_SV/.config1
-rw-r--r--kernel/OS/SCO_SV/module.inc277
-rw-r--r--kernel/OS/SCO_SV/os_sco.c1679
-rw-r--r--kernel/OS/SCO_SV/os_sco.h408
-rw-r--r--kernel/OS/SunOS/.config1
-rw-r--r--kernel/OS/SunOS/module.inc389
-rw-r--r--kernel/OS/SunOS/os_solaris.c2401
-rw-r--r--kernel/OS/SunOS/os_solaris.h518
-rw-r--r--kernel/OS/SunOS/udi.c1365
-rw-r--r--kernel/OS/VxWorks/.config1
-rw-r--r--kernel/OS/VxWorks/linux/ioctl.h5
-rw-r--r--kernel/OS/VxWorks/module.inc127
-rw-r--r--kernel/OS/VxWorks/os_vxworks.c1133
-rw-r--r--kernel/OS/VxWorks/os_vxworks.h297
30 files changed, 14763 insertions, 0 deletions
diff --git a/kernel/OS/.nomake b/kernel/OS/.nomake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/kernel/OS/.nomake
diff --git a/kernel/OS/BeOS/.config b/kernel/OS/BeOS/.config
new file mode 100644
index 0000000..816ac62
--- /dev/null
+++ b/kernel/OS/BeOS/.config
@@ -0,0 +1 @@
+mode=kernel
diff --git a/kernel/OS/BeOS/driver_beos.c b/kernel/OS/BeOS/driver_beos.c
new file mode 100644
index 0000000..61f4bf9
--- /dev/null
+++ b/kernel/OS/BeOS/driver_beos.c
@@ -0,0 +1,104 @@
+/*
+ * Purpose: devfs interface for BeOS/Haiku
+ */
+/*
+ *
+ * This file is part of Open Sound System.
+ *
+ * Copyright (C) 4Front Technologies 1996-2007.
+ *
+ * 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. Please contact sales@opensound.com for further info.
+ *
+ */
+
+#include "oss_config.h"
+#include "midi_core.h"
+#include <oss_pci.h>
+#include <KernelExport.h>
+#include <Drivers.h>
+
+#define DRIVER_NAME "ossdrv"
+
+int32 api_version = B_CUR_DRIVER_API_VERSION;
+
+oss_core_module_info *gOSSCore = NULL;
+
+// #pragma mark -
+
+// XXX: malloc it + update it from device list
+
+const char **
+publish_devices(void)
+{
+ return gOSSCore->oss_publish_devices();
+}
+
+
+device_hooks *
+find_device(const char *name)
+{
+ FENTRYA("%s", name);
+
+ FEXIT();
+ return gOSSCore->oss_get_driver_hooks();
+}
+
+// #pragma mark -
+
+status_t
+init_hardware(void)
+{
+ status_t err;
+ FENTRY();
+
+ err = get_module(OSS_CORE_MODULE_NAME, (module_info **)&gOSSCore);
+ if (err < B_OK) {
+ FEXIT();
+ return err;
+ }
+
+ put_module(OSS_CORE_MODULE_NAME);
+
+ FEXIT();
+ return B_OK;
+}
+
+status_t
+init_driver(void)
+{
+ status_t err = ENOMEM;
+ FENTRY();
+
+ err = get_module(OSS_CORE_MODULE_NAME, (module_info **)&gOSSCore);
+ if (err < B_OK)
+ goto err1;
+ err = gOSSCore->init_osscore();
+ dprintf("oss:init_osscore: 0x%08lx\n", err);
+ if (err < B_OK)
+ goto err2;
+ err = gOSSCore->oss_load_drivers();
+ err = B_OK;
+ FEXITR(err);
+ return err;
+
+err2:
+ put_module(OSS_CORE_MODULE_NAME);
+err1:
+ FEXITR(err);
+ return err;
+}
+
+void
+uninit_driver(void)
+{
+ status_t err;
+ FENTRY();
+
+ err = gOSSCore->oss_unload_all_drivers();
+ err = gOSSCore->uninit_osscore();
+ dprintf("oss:uninit_osscore: 0x%08lx\n", err);
+ put_module(OSS_CORE_MODULE_NAME);
+ FEXIT();
+}
diff --git a/kernel/OS/BeOS/module.inc b/kernel/OS/BeOS/module.inc
new file mode 100644
index 0000000..be7ab1b
--- /dev/null
+++ b/kernel/OS/BeOS/module.inc
@@ -0,0 +1,186 @@
+/* -*- c -*-
+ * Purpose: OSS module wrapper for BeOS/Haiku
+ *
+ * This file will be included from the auto-generated drv_cfg.c files. Under
+ * UnixWare and OpenServer this will will be compiled during the initial build
+ * of OSS (in the development system).
+ */
+/*
+ *
+ * This file is part of Open Sound System.
+ *
+ * Copyright (C) 4Front Technologies 1996-2007.
+ *
+ * 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. Please contact sales@opensound.com for further info.
+ *
+ */
+
+#include <PCI.h>
+
+//pci_module_info *gPCI = NULL;
+extern pci_module_info *gPCI;
+
+#if DRIVER_TYPE==DRV_VIRTUAL
+static oss_device_t *osdev = NULL;
+#endif
+
+#if DRIVER_TYPE==DRV_PCI
+int DRIVER_PROBE()
+{
+ oss_device_t *osdev;
+ pci_info pcii;
+ uint32 pci_index = 0;
+ uint32 count = 0;
+ int err = ENOENT;
+ static int instance = 0;
+ FENTRY();
+
+ /* while there are more pci devices */
+ while ((*gPCI->get_nth_pci_info)(pci_index, &pcii) == B_NO_ERROR)
+ {
+ int vendor;
+ bool match = false;
+ bool sub = true;
+
+ /* we first loop through all subsystem entries, then loop again */
+rescan:
+ vendor = 0;
+ /* if we match a supported vendor */
+ while (id_table[vendor].vendor)
+ {
+
+ /* check for function vendor & device id */
+ if (!sub &&
+ id_table[vendor].subsystem == false &&
+ id_table[vendor].vendor == pcii.vendor_id &&
+ id_table[vendor].product == pcii.device_id)
+ {
+ dprintf("oss: matching pci %04x,%04x\n", id_table[vendor].vendor, id_table[vendor].product);
+ match = true;
+ }
+
+ /* check for subsystem vendor & device id */
+ if (sub &&
+ id_table[vendor].subsystem == true &&
+ pcii.header_type == 0 &&
+ id_table[vendor].vendor == pcii.u.h0.subsystem_vendor_id &&
+ id_table[vendor].product == pcii.u.h0.subsystem_id)
+ {
+ dprintf("oss: matching pci subsystem %04x,%04x\n", id_table[vendor].vendor, id_table[vendor].product);
+ match = true;
+ }
+
+ if (match)
+ {
+ dev_info_t *di;
+ di = PMALLOC(NULL, sizeof(dev_info_t));
+ if (!di)
+ break;
+ memcpy(di, &pcii, sizeof(pcii));
+ if ((osdev =
+ osdev_create (di, DRIVER_TYPE, instance, DRIVER_NICK, NULL)) == NULL)
+ {
+ break;
+ }
+
+ /* should be called once, but we need an osdev */
+ oss_load_options (osdev, local_driver_options);
+
+ if (!DRIVER_ATTACH (osdev))
+ {
+ cmn_err (CE_WARN, "Attach failed\n");
+ osdev_delete (osdev);
+ break;
+ }
+
+ instance++;
+ count++;
+ break;
+ }
+ vendor++;
+ }
+ /* we've checked for subsystem IDs, now rescan for IDs */
+ if (!match && sub) {
+ sub = false;
+ goto rescan;
+ }
+ /* next pci_info struct, please */
+ pci_index++;
+ }
+
+ oss_audio_delayed_attach ();
+
+ if (count)
+ err = 0;
+err:
+ FEXITR(err);
+ return err;
+}
+#endif
+
+#if DRIVER_TYPE==DRV_VIRTUAL
+int DRIVER_PROBE()
+{
+ int err = EIO;
+ FENTRY();
+ if ((osdev =
+ osdev_create (NULL, DRIVER_TYPE, 0, DRIVER_NICK, NULL)) == NULL)
+ {
+ goto err;
+ }
+
+ oss_load_options (osdev, local_driver_options);
+
+ if (!DRIVER_ATTACH (osdev))
+ {
+ cmn_err (CE_WARN, "Attach failed\n");
+ osdev_delete (osdev);
+ goto err;
+ }
+
+ err = 0;
+err:
+ FEXITR(err);
+ return err;
+}
+#endif
+
+
+
+
+
+
+static status_t
+stdops(int32 op, ...)
+{
+ status_t err;
+ switch (op)
+ {
+ case B_MODULE_INIT:
+ err = get_module(B_PCI_MODULE_NAME, (module_info **)&gPCI);
+ return err;
+
+ case B_MODULE_UNINIT:
+ //err = unload_driver(DRIVER_NICK);
+ //if (err < B_OK)
+ // return err;
+ put_module(B_PCI_MODULE_NAME);
+ return B_OK;
+
+ }
+ return B_ERROR;
+}
+
+oss_drv_module_info DRIVER_MODULE_OBJECT = {
+ {
+ OSS_MAKE_DRV_MOD_NAME(DRIVER_NICK),
+ 0,
+ stdops,
+ },
+ DRIVER_PROBE,
+ DRIVER_ATTACH,
+ DRIVER_DETACH
+};
+
diff --git a/kernel/OS/BeOS/os_beos.c b/kernel/OS/BeOS/os_beos.c
new file mode 100644
index 0000000..08587c5
--- /dev/null
+++ b/kernel/OS/BeOS/os_beos.c
@@ -0,0 +1,2222 @@
+/*
+ * Purpose: Operating system abstraction functions for BeOS/Haiku
+ */
+/*
+ *
+ * This file is part of Open Sound System.
+ *
+ * Copyright (C) 4Front Technologies 1996-2007.
+ *
+ * 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. Please contact sales@opensound.com for further info.
+ *
+ */
+
+#include "oss_config.h"
+#include "midi_core.h"
+#include <oss_pci.h>
+#include <Drivers.h>
+#include <KernelExport.h>
+#include <driver_settings.h>
+
+/*
+ * The BeOS and Haiku kernels are preemptible,
+ * therefore we must ensure safe access to global variables.
+ * Such variables are marked by GM.
+ * Other protected variables:
+ * - oss_cdevs
+ * - mixer_devs
+ * XXX: use a benaphore ??
+ */
+#if 0
+// spinlock
+static oss_mutex_t osscore_mutex;
+#define CORE_LOCK_VAR \
+ oss_native_word osscore_mutex_flags
+#define CORE_LOCK_INIT() \
+ MUTEX_INIT (osdev, osscore_mutex, MH_TOP)
+#define CORE_LOCK_CLEANUP() \
+ MUTEX_CLEANUP (osscore_mutex)
+#define LOCK_CORE() \
+ MUTEX_ENTER_IRQDISABLE (osscore_mutex, osscore_mutex_flags)
+#define UNLOCK_CORE() \
+ MUTEX_EXIT_IRQRESTORE (osscore_mutex, osscore_mutex_flags)
+#else
+// benaphore
+typedef struct benaphore {
+ sem_id sem;
+ int32 count;
+} benaphore;
+benaphore osscore_benaphore;
+#define CORE_LOCK_VAR \
+ int dummy_ocl
+#define CORE_LOCK_INIT() \
+ osscore_benaphore.count = 1; \
+ osscore_benaphore.sem = create_sem(0, "OSS CORE LOCK")
+#define CORE_LOCK_CLEANUP() \
+ delete_sem(osscore_benaphore.sem)
+#define LOCK_CORE() \
+ { \
+ if (atomic_add(&osscore_benaphore.count, -1) <= 0) \
+ acquire_sem(osscore_benaphore.sem); \
+ }
+#define UNLOCK_CORE() \
+ { \
+ if (atomic_add(&osscore_benaphore.count, 1) < 0) \
+ release_sem(osscore_benaphore.sem); \
+ }
+#endif
+
+#define DEBUG_IRQ 1
+#if DEBUG_IRQ
+vint32 irq_count = 0;
+#endif
+
+volatile int oss_open_devices = 0;
+#define MAX_CARDS 16
+int oss_num_cards = 0; /* GM */
+static oss_device_t *cards[MAX_CARDS]; /* GM */
+static int oss_expired = 0;
+extern int vmix_disabled;
+
+//static struct fileinfo files[OSS_MAX_CDEVS];
+//static volatile int open_count[OSS_MAX_CDEVS] = { 0 };
+//static volatile int open_devices = 0; /* GM */
+
+pci_module_info *gPCI = NULL;
+
+static char **gDeviceNames = NULL; // buffer for all names
+
+device_hooks oss_driver_hooks;
+
+/*
+ * Table for permanently allocated memory (to be freed by std_op(UNLOAD))
+ */
+#define MAX_MEMBLOCKS 4096
+static void *memblocks[MAX_MEMBLOCKS]; /* GM */
+static int nmemblocks = 0; /* GM */
+
+void *
+oss_contig_malloc (oss_device_t * osdev, int size, oss_uint64_t memlimit,
+ oss_native_word * phaddr)
+{
+ status_t err;
+ area_id id;
+ void *p = NULL;
+ uint32 lock = B_CONTIGUOUS;
+ physical_entry pent[1];
+
+ *phaddr = 0;
+
+ switch (memlimit)
+ {
+ case MEMLIMIT_ISA:
+ case MEMLIMIT_28BITS:
+ case MEMLIMIT_30BITS:
+ case MEMLIMIT_31BITS:
+ /* no known way to force a physical address limit other than <16M */
+ lock = B_LOMEM;
+ break;
+ case MEMLIMIT_32BITS:
+ lock = B_CONTIGUOUS;
+ break;
+
+ default:
+ cmn_err (CE_WARN, "Bad DMA memlimit for %s\n", osdev->nick);
+ }
+
+ /* round up to page size */
+ size += B_PAGE_SIZE - 1;
+ size &= ~(B_PAGE_SIZE - 1);
+
+ if ((err = id = create_area(OSS_CONTIG_AREA_NAME, &p, B_ANY_KERNEL_ADDRESS,
+ size, lock, 0)) < B_OK)
+ {
+ cmn_err (CE_WARN, "create_area() failed\n");
+ return NULL;
+ }
+
+ if ((err = get_memory_map(p, size, pent, 1)) < B_OK)
+ {
+ cmn_err (CE_WARN, "get_memory_map() failed\n");
+ delete_area(id);
+ return NULL;
+ }
+ //XXX:DEBUG
+ *phaddr = (oss_native_word)pent[0].address;
+ dprintf("oss_contig_malloc: area %d @ va %p, pa %p, sz %d\n", id, p, (void *)(*phaddr), size);
+ return p;
+}
+
+void
+oss_contig_free (oss_device_t * osdev, void *p, int sz)
+{
+ area_id id;
+ if (p == NULL)
+ return;
+ id = area_for(p);
+ if (id < B_OK)
+ return;
+#ifdef MEMDEBUG
+ {
+ area_info ai;
+ if ((get_area_info(id, &ai) < B_OK) || strncmp(ai.name, OSS_CONTIG_AREA_NAME))
+ {
+ cmn_err (CE_NOTE, "oss_contig_free: bad area (%ld)!\n", id);
+ return;
+ }
+ }
+#endif
+ delete_area(id);
+}
+
+int
+__oss_alloc_dmabuf (int dev, dmap_p dmap, unsigned int alloc_flags,
+ oss_uint64_t maxaddr, int direction)
+{
+ void *tmpbuf;
+ 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;
+
+/*
+ * 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;
+
+ tmpbuf = CONTIG_MALLOC (dmap->osdev, size, maxaddr, &phaddr, NULL);
+ if (tmpbuf == NULL)
+ return OSS_ENOMEM;
+ dmap->dmabuf = tmpbuf;
+ dmap->buffsize = size;
+ dmap->dmabuf_phys = phaddr;
+
+ return 0;
+}
+
+void
+oss_free_dmabuf (int dev, dmap_p dmap)
+{
+ if (dmap->dmabuf == NULL)
+ return;
+
+ CONTIG_FREE (dmap->osdev, dmap->dmabuf, dmap->buffsize, NULL);
+ dmap->dmabuf = NULL;
+ dmap->buffsize = 0;
+ dmap->dmabuf_phys = 0;
+}
+
+
+oss_native_word
+oss_virt_to_bus (void *addr)
+{
+ physical_entry pent[2];
+ status_t err;
+
+ if (addr == NULL)
+ return 0;
+
+ /* XXX: ROUNDUP(B_PAGE_SIZE) ? */
+ if ((err = get_memory_map(addr, 1, pent, 2)) < 1)
+ {
+ cmn_err (CE_WARN, "Virtual address %x not mapped\n", (int) addr);
+ return 0;
+ }
+ //XXX:which???
+ //return (oss_native_word)pent[0].address;
+ return (oss_native_word)(gPCI->ram_address(pent[0].address));
+}
+
+
+void *
+oss_pmalloc (size_t sz)
+{
+ void *tmp;
+
+ tmp = KERNEL_MALLOC (sz);
+
+ if (nmemblocks < MAX_MEMBLOCKS)
+ memblocks[nmemblocks++] = tmp;
+
+ return tmp;
+}
+
+int
+oss_create_uio (uio_t * uio, char *buf, size_t count, uio_rw_t rw,
+ int is_kernel)
+{
+ memset (uio, 0, sizeof (*uio));
+
+ if (is_kernel)
+ {
+ oss_cmn_err (CE_CONT,
+ "oss_create_uio: Kernel space buffers not supported\n");
+ return OSS_EIO;
+ }
+
+ uio->ptr = buf;
+ uio->resid = count;
+ uio->kernel_space = is_kernel;
+ uio->rw = rw;
+
+ return 0;
+}
+
+int
+oss_uiomove (void *address, size_t nbytes, enum uio_rw rwflag, uio_t * uio)
+{
+ int err = EFAULT;
+ FENTRY();
+
+ if (rwflag != uio->rw)
+ {
+ oss_cmn_err (CE_WARN, "uiomove: Bad direction\n");
+ goto err;
+ }
+
+ if (uio->resid < nbytes)
+ {
+ oss_cmn_err (CE_WARN, "uiomove: Bad count %d (%d)\n", nbytes,
+ uio->resid);
+ goto err;
+ }
+
+ if (uio->kernel_space)
+ goto err;
+
+ switch (rwflag)
+ {
+ case UIO_READ:
+ //XXX:user_memcpy...
+ memcpy (uio->ptr, address, nbytes);
+ break;
+
+ case UIO_WRITE:
+ //XXX:user_memcpy...
+ memcpy (address, uio->ptr, nbytes);
+ break;
+ }
+
+ uio->resid -= nbytes;
+ uio->ptr += nbytes;
+
+ err = B_OK;
+err:
+ FEXITR(err);
+ return err;
+}
+
+
+void
+oss_cmn_err (int level, char *s, ...)
+{
+ char tmp[1024], *a[6];
+ va_list ap;
+ int i, n = 0;
+
+ va_start (ap, s);
+
+ for (i = 0; i < strlen (s); i++)
+ if (s[i] == '%')
+ n++;
+
+ for (i = 0; i < n && i < 6; i++)
+ a[i] = va_arg (ap, char *);
+
+ for (i = n; i < 6; i++)
+ a[i] = NULL;
+
+ if (level == CE_CONT)
+ {
+ sprintf (tmp, s, a[0], a[1], a[2], a[3], a[4], a[5], NULL,
+ NULL, NULL, NULL);
+ dprintf ("%s", tmp);
+ }
+ else
+ {
+ strcpy (tmp, "osscore: ");
+ sprintf (tmp + strlen (tmp), s, a[0], a[1], a[2], a[3], a[4], a[5],
+ NULL, NULL, NULL, NULL);
+ if (level == CE_PANIC)
+ panic (tmp);
+
+ dprintf ("%s", tmp);
+ }
+ va_end (ap);
+}
+
+
+/*
+ * Sleep/wakeup
+ */
+
+struct oss_wait_queue *
+oss_create_wait_queue (oss_device_t * osdev, const char *name)
+{
+ struct oss_wait_queue *wq;
+ status_t err;
+ FENTRYA(", %s", name);
+
+ if ((wq = malloc (sizeof (*wq))) == NULL)
+ {
+ oss_cmn_err (CE_WARN, "malloc(%d) failed (wq)\n", sizeof (*wq));
+ return NULL;
+ }
+ sprintf(wq->name, OSS_WQ_SEM_NAME "%-20s", name);
+ err = wq->sem = create_sem(0, wq->name);
+ if (err < B_OK)
+ {
+ free(wq);
+ oss_cmn_err (CE_WARN, "create_sem() failed (wq)\n");
+ return NULL;
+ }
+
+ return wq;
+}
+
+void
+oss_reset_wait_queue (struct oss_wait_queue *wq)
+{
+ sem_info si;
+ status_t err;
+ FENTRY();
+
+ wq->flags = 0;
+ err = create_sem(0, wq->name);
+ if (err >= 0) {
+ /* replace with the new one */
+ delete_sem(wq->sem);
+ wq->sem = err;
+ }
+
+ FEXIT();
+}
+
+void
+oss_remove_wait_queue (struct oss_wait_queue *wq)
+{
+ FENTRY();
+ delete_sem(wq->sem);
+ free (wq);
+}
+
+int
+oss_sleep (struct oss_wait_queue *wq, oss_mutex_t * mutex, int ticks,
+ oss_native_word * flags, unsigned int *status)
+{
+ bigtime_t timeout = B_INFINITE_TIMEOUT;
+ uint32 semflags = B_CAN_INTERRUPT | B_RELATIVE_TIMEOUT;
+ int result = 0;
+ FENTRYA("(%s), , %d, , ", wq->name, ticks);
+ *status = 0;
+
+ if (wq == NULL)
+ return 0;
+
+#ifdef B_WAKE_ON_TIMEOUT
+ // Dano only; sure it's what we want ?
+ if (wq->flags & WK_WAKEUP)
+ semflags |= B_WAKE_ON_TIMEOUT;
+#endif
+
+ wq->flags = 0;
+ MUTEX_EXIT_IRQRESTORE(*mutex, *flags);
+
+ if (ticks > 0)
+ timeout = ticks * 1000000LL / OSS_HZ;
+ result = acquire_sem_etc (wq->sem, 1, semflags, timeout);
+ //dprintf("oss_sleep:acquire_sem(s:%ld, 1, %x, %Ld): 0x%08lx\n", wq->sem, semflags, timeout, result);
+
+ MUTEX_ENTER_IRQDISABLE (*mutex, *flags);
+
+ if (result == EINTR) /* Signal received */
+ {
+ *status |= WK_SIGNAL;
+ return 1;
+ }
+
+ if (result == B_TIMED_OUT)
+ //if (!(wq->flags & WK_WAKEUP)) /* Timeout */
+ {
+ return 0;
+ }
+
+ return 1;
+}
+
+int
+oss_register_poll (struct oss_wait_queue *wq, oss_mutex_t * mutex,
+ oss_native_word * flags, oss_poll_event_t * ev)
+{
+ FENTRYA("(%s), , , , ", wq->name);
+ dprintf("oss:UNIMPLEMENTED:%s\n", __FUNCTION__);
+ MUTEX_EXIT_IRQRESTORE(*mutex, *flags);
+ //poll_wait ((struct file *) ev->file, &wq->wq, (struct wait *) ev->wait);
+ MUTEX_ENTER_IRQDISABLE (*mutex, *flags);
+ return 0;
+}
+
+void
+oss_wakeup (struct oss_wait_queue *wq, oss_mutex_t * mutex,
+ oss_native_word * flags, short events)
+{
+ FENTRYA("(%s), , %x, , ", wq->name, events);
+ if (wq == NULL)
+ return;
+
+ wq->flags |= WK_WAKEUP;
+ MUTEX_EXIT_IRQRESTORE(*mutex, *flags);
+
+ //dprintf("oss_wakeup:release_sem(s:%ld)\n", wq->sem);
+ release_sem_etc (wq->sem, 1, B_DO_NOT_RESCHEDULE);
+ //XXX:handle select here
+
+ MUTEX_ENTER_IRQDISABLE (*mutex, *flags);
+}
+
+unsigned long
+oss_get_time (void)
+{
+ return (unsigned long) (system_time() / (1000000 / OSS_HZ));
+}
+
+typedef struct tmout_desc
+{
+ struct timer timer; /* MUST be first */
+
+ volatile int active;
+ int timestamp;
+ void (*func) (void *);
+ void *arg;
+} tmout_desc_t;
+
+static volatile int next_id = 0;
+#define MAX_TMOUTS 128
+
+tmout_desc_t tmouts[MAX_TMOUTS] = { {0} };
+
+int timeout_random = 0x12123400;
+
+int32
+oss_timer_callback (struct timer *timer)
+{
+ tmout_desc_t *tmout = (tmout_desc_t *)timer;
+ int ix;
+ void *arg;
+
+ timeout_random++;
+
+ if (!tmout->active)
+ return;
+
+ arg = tmout->arg;
+ tmout->active = 0;
+ tmout->timestamp = 0;
+
+ tmout->func (arg);
+ return B_HANDLED_INTERRUPT;//B_INVOKE_SCHEDULER ?;
+}
+
+timeout_id_t
+oss_timeout (void (*func) (void *), void *arg, unsigned long long ticks)
+{
+ tmout_desc_t *tmout = NULL;
+ bigtime_t period;
+ int id, n;
+
+ timeout_random++;
+
+ n = 0;
+ id = -1;
+
+ while (id == -1 && n < MAX_TMOUTS)
+ {
+ if (!tmouts[next_id].active)
+ {
+ tmouts[next_id].active = 1;
+ id = next_id++;
+ tmout = &tmouts[id];
+ break;
+ }
+
+ next_id = (next_id + 1) % MAX_TMOUTS;
+ }
+
+ if (id == -1) /* No timer slots available */
+ {
+ oss_cmn_err (CE_WARN, "Timeout table full\n");
+ return 0;
+ }
+
+ tmout->func = func;
+ tmout->arg = arg;
+ tmout->timestamp = id | (timeout_random & ~0xff);
+
+ period = ticks * 1000000LL / OSS_HZ;
+ add_timer (&tmout->timer, oss_timer_callback, period, B_ONE_SHOT_RELATIVE_TIMER);
+
+ return id | (timeout_random & ~0xff);
+}
+
+void
+oss_untimeout (timeout_id_t id)
+{
+ tmout_desc_t *tmout;
+ int ix;
+
+ ix = id & 0xff;
+ if (ix < 0 || ix >= MAX_TMOUTS)
+ return;
+
+ timeout_random++;
+ tmout = &tmouts[ix];
+
+ if (tmout->timestamp != id) /* Expired timer */
+ return;
+ if (tmout->active)
+ cancel_timer (&tmout->timer);
+ tmout->active = 0;
+ tmout->timestamp = 0;
+}
+
+
+caddr_t
+oss_map_pci_mem (oss_device_t * osdev, int nr, int phaddr, int size)
+{
+ status_t err;
+ void *va = NULL;
+ FENTRYA("%p,%d,%u,%d", osdev, nr, phaddr, size);
+ //XXX:align phaddr ?
+ /* round up to page size */
+ size += B_PAGE_SIZE - 1;
+ size &= ~(B_PAGE_SIZE - 1);
+
+ err = map_physical_memory(OSS_PCI_AREA_NAME, (void *)phaddr, size,
+ B_ANY_KERNEL_BLOCK_ADDRESS, 0, &va);
+ if (err < B_OK)
+ va = NULL;
+ FEXITR((uint32)va);
+ return (caddr_t)va;
+}
+
+void
+oss_unmap_pci_mem (void *addr)
+{
+ area_id id;
+ if (addr == NULL)
+ return;
+ id = area_for(addr);
+ if (id < B_OK)
+ return;
+#ifdef MEMDEBUG
+ {
+ area_info ai;
+ if ((get_area_info(id, &ai) < B_OK) || strncmp(ai.name, OSS_PCI_AREA_NAME))
+ {
+ cmn_err (CE_NOTE, "oss_unmap_pci_mem: bad area (%ld)!\n", id);
+ return;
+ }
+ }
+#endif
+ delete_area(id);
+}
+
+void
+oss_pci_byteswap (oss_device_t * osdev, int mode)
+{
+ // NOP
+}
+
+void
+oss_pcie_init (oss_device_t * osdev, int flags)
+{
+ /* TODO: Should we do something? */
+}
+
+int
+pci_read_config_byte (oss_device_t * osdev, offset_t where,
+ unsigned char *val)
+{
+ if (osdev->dev_type != DRV_PCI || osdev->dip == NULL)
+ return PCIBIOS_FAILED;
+ *val = (unsigned char)gPCI->read_pci_config (osdev->dip->pciinfo.bus,
+ osdev->dip->pciinfo.device,
+ osdev->dip->pciinfo.function,
+ (uchar)where, 1);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+pci_read_config_irq (oss_device_t * osdev, offset_t where, unsigned char *val)
+{
+ int ret;
+
+ if (osdev->dev_type != DRV_PCI)
+ return PCIBIOS_FAILED;
+ ret = pci_read_config_byte (osdev, where, val);
+ return ret;
+}
+
+
+int
+pci_read_config_word (oss_device_t * osdev, offset_t where,
+ unsigned short *val)
+{
+ if (osdev->dev_type != DRV_PCI || osdev->dip == NULL)
+ return PCIBIOS_FAILED;
+ *val = (unsigned short)gPCI->read_pci_config (osdev->dip->pciinfo.bus,
+ osdev->dip->pciinfo.device,
+ osdev->dip->pciinfo.function,
+ (uchar)where, 2);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+pci_read_config_dword (oss_device_t * osdev, offset_t where,
+ unsigned int *val)
+{
+ if (osdev->dev_type != DRV_PCI || osdev->dip == NULL)
+ return PCIBIOS_FAILED;
+ *val = (unsigned int)gPCI->read_pci_config (osdev->dip->pciinfo.bus,
+ osdev->dip->pciinfo.device,
+ osdev->dip->pciinfo.function,
+ (uchar)where, 4);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+pci_write_config_byte (oss_device_t * osdev, offset_t where,
+ unsigned char val)
+{
+ if (osdev->dev_type != DRV_PCI || osdev->dip == NULL)
+ return PCIBIOS_FAILED;
+ gPCI->write_pci_config (osdev->dip->pciinfo.bus,
+ osdev->dip->pciinfo.device,
+ osdev->dip->pciinfo.function,
+ (uchar)where, 1, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+pci_write_config_word (oss_device_t * osdev, offset_t where,
+ unsigned short val)
+{
+ if (osdev->dev_type != DRV_PCI || osdev->dip == NULL)
+ return PCIBIOS_FAILED;
+ gPCI->write_pci_config (osdev->dip->pciinfo.bus,
+ osdev->dip->pciinfo.device,
+ osdev->dip->pciinfo.function,
+ (uchar)where, 2, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+pci_write_config_dword (oss_device_t * osdev, offset_t where,
+ unsigned int val)
+{
+ if (osdev->dev_type != DRV_PCI || osdev->dip == NULL)
+ return PCIBIOS_FAILED;
+ gPCI->write_pci_config (osdev->dip->pciinfo.bus,
+ osdev->dip->pciinfo.device,
+ osdev->dip->pciinfo.function,
+ (uchar)where, 4, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+
+#ifdef MUTEX_CHECKS
+static int oss_context = 0; /* 0=user context, 1=interrupt context */
+#endif
+
+static int32
+ossintr (void *idata)
+{
+ oss_device_t *osdev = idata;
+ oss_native_word flags;
+ //dprintf("oss:intr(%ld)!\n", osdev->irq);
+#ifdef MUTEX_CHECKS
+ int saved_context;
+ saved_context = oss_context;
+ if (oss_context == 1)
+ cmn_err (CE_WARN, "Recursive interrupt\n");
+ oss_context = 1;
+#endif
+
+ MUTEX_ENTER_IRQDISABLE (osdev->mutex, flags);
+
+ if (!osdev->tophalf_handler (osdev))
+ {
+ MUTEX_EXIT_IRQRESTORE (osdev->mutex, flags);
+#ifdef MUTEX_CHECKS
+ oss_context = saved_context;
+#endif
+ return B_UNHANDLED_INTERRUPT;
+ }
+
+ if (osdev->bottomhalf_handler != NULL)
+ osdev->bottomhalf_handler (osdev);
+
+ MUTEX_EXIT_IRQRESTORE (osdev->mutex, flags);
+#ifdef MUTEX_CHECKS
+ oss_context = saved_context;
+#endif
+
+ return B_HANDLED_INTERRUPT;
+}
+
+int
+oss_register_interrupts (oss_device_t * osdev, int intrnum,
+ oss_tophalf_handler_t top,
+ oss_bottomhalf_handler_t bottom)
+{
+ unsigned char pci_irq_line;
+ int err;
+ FENTRYA(", %d, , ", intrnum);
+
+ if (intrnum != 0)
+ {
+ cmn_err (CE_WARN, "Bad interrupt index (%d) for %s\n", intrnum,
+ osdev->name);
+ return OSS_EINVAL;
+ }
+
+ if (osdev == NULL)
+ {
+ cmn_err (CE_WARN, "oss_register_interrupts: Bad osdev\n");
+ return OSS_EINVAL;
+ }
+
+ if (osdev->tophalf_handler != NULL || osdev->bottomhalf_handler != NULL)
+ {
+ cmn_err (CE_WARN, "Interrupts already registered for %s\n",
+ osdev->name);
+ return OSS_EINVAL;
+ }
+
+ if (top == NULL)
+ {
+ cmn_err (CE_WARN, "Bad interrupt handler for %s\n", osdev->name);
+ return OSS_EINVAL;
+ }
+
+ // could probably use osdev->dip->pciinfo...
+ if (pci_read_config_irq (osdev, PCI_INTERRUPT_LINE, &pci_irq_line) > 0)
+ return OSS_EIO;
+
+ osdev->irq = pci_irq_line;
+ osdev->tophalf_handler = top;
+ osdev->bottomhalf_handler = bottom;
+ err = install_io_interrupt_handler (pci_irq_line, ossintr, osdev, 0);
+ dprintf("install_io_interrupt_handler (%d, %p, %p, 0) = 0x%08lx\n", pci_irq_line, ossintr, osdev, err);
+ if (err < B_OK)
+ {
+ cmn_err (CE_WARN, "install_io_interrupt_handler failed for %s\n", osdev->nick);
+ osdev->irq = -1;
+ osdev->tophalf_handler = NULL;
+ osdev->bottomhalf_handler = NULL;
+ return err;
+ }
+
+#if DEBUG_IRQ
+ atomic_add(&irq_count, 1);
+#endif
+
+ return 0;
+}
+
+void
+oss_unregister_interrupts (oss_device_t * osdev)
+{
+ status_t err = B_OK;
+ FENTRY();
+ dprintf("remove_io_interrupt_handler (%d, %p, %p)\n", osdev->irq, ossintr, osdev);
+ if (osdev->irq >= 0)
+ err = remove_io_interrupt_handler (osdev->irq, ossintr, osdev);
+ if (err < B_OK)
+ cmn_err (CE_WARN, "Error removing interrupt index (%d) for %s: %s\n",
+ osdev->irq, osdev->name, strerror(err));
+#if DEBUG_IRQ
+ atomic_add(&irq_count, -1);
+#endif
+ osdev->irq = -1;
+}
+
+int
+oss_register_device (oss_device_t * osdev, const char *name)
+{
+ static int dev_instance = 0;
+ FENTRYA(", %s", name);
+
+ DDB (cmn_err (CE_CONT, "OSS device %d is %s\n", dev_instance++, name));
+
+ 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);
+ FEXITR(0);
+ return 0;
+}
+
+int
+oss_disable_device (oss_device_t * osdev)
+{
+ int i;
+ CORE_LOCK_VAR;
+ FENTRY();
+/*
+ * This routine should check if the device is ready to be unloaded (no devices are in use).
+ * If the device cannot be unloaded this routine must return OSS_EBUSY.
+ *
+ * If the device can be unloaded then disable any timers or other features that may cause the
+ * device to be called. Also mark the audio/midi/mixer/etc devices of this device to be disabled.
+ * However the interrupt handler should still stay enabled. The low level driver will call
+ * oss_unregister_interrupts() after it has cleared the interrupt enable register.
+ */
+ LOCK_CORE();
+ if (osdev->refcount > 0 || oss_open_devices > 0)
+ {
+ UNLOCK_CORE();
+ cmn_err (CE_CONT, "Refcount %d, open_devices %d\n", osdev->refcount,
+ oss_open_devices);
+ return OSS_EBUSY;
+ }
+
+/*
+ * Now mark all devices unavailable (for the time being)
+ */
+
+ 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)
+ {
+ UNLOCK_CORE(); //needed until a benaphore is used.
+ audio_uninit_device (i);
+ LOCK_CORE();
+ }
+
+ UNLOCK_CORE();
+
+ FEXIT();
+ return 0;
+}
+
+void
+oss_unregister_device (oss_device_t * osdev)
+{
+ FENTRY();
+/*
+ * 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.
+ */
+
+/*
+ * Force reload of all drivers if any application tries to open any
+ * of the devices.
+ */
+ //do_forceload = 1;
+ FEXIT();
+}
+
+void
+oss_reserve_device (oss_device_t * osdev)
+{
+ CORE_LOCK_VAR;
+
+ //XXX:use atomic_add() ?
+ LOCK_CORE();
+ osdev->refcount++;
+ UNLOCK_CORE();
+}
+
+void
+oss_unreserve_device (oss_device_t * osdev, int decrement)
+{
+ CORE_LOCK_VAR;
+
+ //XXX:use atomic_add() ?
+ LOCK_CORE();
+ osdev->refcount--;
+ if (osdev->refcount < 0)
+ osdev->refcount = 0;
+ UNLOCK_CORE();
+}
+
+void *
+oss_get_osid (oss_device_t * osdev)
+{
+// return osdev->osid;
+ return osdev->dip;
+ return NULL; // XXX:TODO
+}
+
+int
+oss_get_procinfo(int what)
+{
+ switch (what)
+ {
+ case OSS_GET_PROCINFO_UID:
+ return getuid();
+ break;
+ }
+
+ return OSS_EINVAL;
+}
+
+oss_device_t *
+osdev_create (dev_info_t * dip, int dev_type, int instance, const char *nick,
+ const char *handle)
+{
+ oss_device_t *osdev = NULL;
+ int i, err;
+ caddr_t addr;
+ off_t region_size;
+ CORE_LOCK_VAR;
+ FENTRYA(", %d, %d, %s, %s", dev_type, instance, nick, handle);
+
+ if (handle == NULL)
+ handle = nick;
+
+ /*
+ * Don't accept any more drivers if expired
+ */
+ if (oss_expired && oss_num_cards > 0)
+ return NULL;
+
+ LOCK_CORE();
+ for (i = 0; dip && (i < oss_num_cards); i++)
+ {
+ if (cards[i] == NULL)
+ continue;
+ if (cards[i]->available)
+ continue;
+ if (cards[i]->dip == dip)
+ {
+ osdev = cards[i];
+ break;
+ }
+ }
+ UNLOCK_CORE();
+
+ if (osdev == NULL)
+ {
+ if ((osdev = PMALLOC (NULL, sizeof (*osdev))) == NULL)
+ {
+ cmn_err (CE_WARN, "osdev_create: Out of memory\n");
+ return NULL;
+ }
+
+ LOCK_CORE();
+ if (oss_num_cards >= MAX_CARDS)
+ {
+ UNLOCK_CORE();
+ cmn_err (CE_PANIC, "Too many OSS devices. At most %d permitted.\n",
+ MAX_CARDS);
+ return NULL;
+ }
+ memset (osdev, 0, sizeof (*osdev));
+
+ osdev->cardnum = oss_num_cards;
+ cards[oss_num_cards++] = osdev;
+ UNLOCK_CORE();
+ }
+
+ osdev->dip = dip;
+ //osdev->osid = dip;
+ osdev->unloaded = 0;
+ osdev->available = 1;
+ osdev->first_mixer = -1;
+ osdev->instance = instance;
+ osdev->dev_type = dev_type;
+ osdev->devc = NULL;
+ MUTEX_INIT (osdev, osdev->mutex, MH_GLOBAL);
+ sprintf (osdev->nick, "%s%d", nick, instance);
+ strcpy (osdev->modname, nick);
+
+ switch (dev_type)
+ {
+ case DRV_PCI:
+ /* NOP */
+#ifdef __HAIKU__
+ if (gPCI->reserve_device(osdev->dip->pciinfo.bus,
+ osdev->dip->pciinfo.device,
+ osdev->dip->pciinfo.function,
+ "oss", osdev) != B_OK) {
+ cmn_err (CE_WARN, "Could not reserve PCI device\n");
+ /* XXX: CLEANUP! */
+ return NULL;
+ }
+#endif
+ break;
+
+ case DRV_VIRTUAL:
+ case DRV_STREAMS:
+ /* NOP */
+ break;
+
+ case DRV_USB:
+ /* NOP */
+ break;
+
+ default:
+ cmn_err (CE_WARN, "Bad device type\n");
+ return NULL;
+ }
+
+/*
+ * Create the device handle
+ */
+ switch (dev_type)
+ {
+ case DRV_PCI:
+ {
+ unsigned int subvendor;
+ pci_read_config_dword (osdev, 0x2c, &subvendor);
+
+ sprintf (osdev->handle, "PCI%08x-%d", subvendor, instance);
+ }
+ 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);
+ }
+
+ FEXIT();
+ return osdev;
+}
+
+oss_device_t *
+osdev_clone (oss_device_t * orig_osdev, int new_instance)
+{
+ oss_device_t *osdev;
+ FENTRYA(", %d", new_instance);
+
+ 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);
+
+ FEXIT();
+ return osdev;
+}
+
+void
+osdev_delete (oss_device_t * osdev)
+{
+ int i;
+ CORE_LOCK_VAR;
+
+ FENTRY();
+ if (osdev == NULL)
+ return;
+ osdev->available=0;
+
+ switch (osdev->dev_type)
+ {
+ case DRV_PCI:
+ /* NOP */
+ //pci_config_teardown (&osdev->pci_config_handle);
+ //osdev->pci_config_handle = NULL;
+#ifdef __HAIKU__
+ gPCI->unreserve_device(osdev->dip->pciinfo.bus,
+ osdev->dip->pciinfo.device,
+ osdev->dip->pciinfo.function,
+ "oss", osdev);
+#endif
+ break;
+ }
+
+/*
+ * Mark all minor nodes for this module as invalid.
+ */
+ LOCK_CORE();
+ 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");
+ }
+ UNLOCK_CORE();
+
+ MUTEX_CLEANUP (osdev->mutex);
+ osdev->unloaded = 1;
+ FEXIT();
+}
+
+static int
+grow_array(oss_device_t *osdev, oss_cdev_t ***arr, int *size, int element_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 * element_size))==NULL)
+ return 0;
+
+ memset(new, 0, new_size * element_size);
+ if (old != NULL)
+ memcpy(new, old, old_size * element_size);
+
+ *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 i, num;
+ oss_cdev_t *cdev = NULL;
+ CORE_LOCK_VAR;
+ FENTRYA(", %s, %d, %d, , %d", name, dev_class, instance, flags);
+
+ if (dev_class != OSS_DEV_STATUS)
+ if (oss_expired && instance > 0)
+ return;
+/*
+ * Find if this dev_class&instance already exists (after previous module
+ * detach).
+ */
+
+ LOCK_CORE();
+ 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];
+ //dprintf("oss:reusing cdev[%d]\n", num);
+ 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) - 1);
+ else
+ strcpy (cdev->name, "NONE");
+ cdev->name[sizeof (cdev->name) - 1] = 0;
+ oss_cdevs[num] = cdev;
+ break;
+ }
+ UNLOCK_CORE();
+
+ if (cdev == NULL)
+ {
+ /* must alloc before locking, the rest must be atomic */
+ if ((cdev = PMALLOC (NULL, sizeof (*cdev))) == NULL)
+ {
+ cmn_err (CE_WARN, "Cannot allocate character device desc.\n");
+ return;
+ }
+
+ LOCK_CORE();
+ if (oss_num_cdevs >= OSS_MAX_CDEVS)
+ {
+ if (!grow_array(osdev, &oss_cdevs, &oss_max_cdevs, sizeof(oss_cdev_t*), 100))
+ {
+ cmn_err (CE_WARN, "Cannot allocate new minor numbers.\n");
+ UNLOCK_CORE();
+ 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) - 1);
+ else
+ strcpy (cdev->name, "NONE");
+ cdev->name[sizeof (cdev->name) - 1] = 0;
+ oss_cdevs[num] = cdev;
+ //dprintf("oss:reusing cdev[%d]: @%p\n", num, cdev);
+ UNLOCK_CORE();
+ }
+
+/*
+ * Export the device only if name != NULL
+ */
+#if 0
+ if (name != NULL)
+ {
+ char tmp[64], *s;
+ char *dev_type = "oss_sysdev";
+
+//XXX: maybe do something ??
+ }
+#endif
+ FEXIT();
+}
+
+int
+oss_get_cardinfo (int cardnum, oss_card_info * ci)
+{
+ CORE_LOCK_VAR;
+/*
+ * Print information about a 'card' in a format suitable for /dev/sndstat
+ */
+
+ LOCK_CORE();
+ if (cardnum < 0 || cardnum >= oss_num_cards)
+ {
+ UNLOCK_CORE();
+ return OSS_ENXIO;
+ }
+
+ if (cards[cardnum]->name != NULL)
+ strncpy (ci->longname, cards[cardnum]->name, 128);
+ ci->shortname[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)-1);
+ ci->hw_info[sizeof(ci->hw_info)-1]=0;
+
+ UNLOCK_CORE();
+
+ return 0;
+}
+
+/* XXX: major/minors don't exist in BeOS, WTF */
+int
+oss_find_minor (int dev_class, int instance)
+{
+ int i, minor = -1;
+ CORE_LOCK_VAR;
+
+ LOCK_CORE();
+ 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)
+ {
+ minor = i;
+ break;
+ }
+ UNLOCK_CORE();
+
+ return minor;
+}
+
+
+#ifdef MUTEX_CHECKS
+void
+debug_mutex_init (oss_mutex_t * mutex, char *file, int line)
+{
+ memset (mutex, 0, sizeof (mutex));
+ mutex->lock = 0;
+ mutex->owner = -1;
+}
+
+void
+debug_mutex_destroy (oss_mutex_t * mutex, char *file, int line)
+{
+ if (find_thread(NULL) == mutex->owner)
+ {
+ cmn_err (CE_NOTE, "%s:%d: mutex still owned (%d)\n", file, line, mutex->owner);
+ }
+ if (mutex->lock)
+ {
+ cmn_err (CE_NOTE, "%s:%d: mutex still locked (%d)\n", file, line, mutex->lock);
+ }
+}
+
+void
+debug_mutex_enter (oss_mutex_t * mutex, char *file, int line, oss_native_word *flags)
+{
+ if (find_thread(NULL) == mutex->owner)
+ {
+ cmn_err (CE_NOTE, "%s:%d: Re-entrant mutex (%s:%d %d)\n", file, line,
+ mutex->file, mutex->line, mutex->busy_flags);
+ return;
+ }
+
+ mutex->file = file;
+ mutex->line = line;
+ mutex->busy_flags = flags ? CNTX_INTR : CNTX_USER;
+ if (flags)
+ *flags = (oss_native_word) disable_interrupts();
+ acquire_spinlock (&mutex->lock);
+
+}
+
+void
+debug_mutex_exit (oss_mutex_t * mutex, char *file, int line, oss_native_word *flags)
+{
+ if (find_thread(NULL) != mutex->owner)
+ {
+ cmn_err (CE_NOTE, "Mutex not owned %s:%d\n", file, line);
+ }
+ else
+ {
+ release_spinlock(&mutex->lock);
+ if (flags)
+ restore_interrupts((cpu_status)*flags);
+ }
+
+ mutex->owner = -1;
+ mutex->file = NULL;
+ mutex->line = 0;
+ mutex->busy_flags = 0;
+}
+#endif
+
+
+void
+oss_load_options (oss_device_t * osdev, oss_option_map_t map[])
+{
+ char name[32] = OSS_CONFIG_FILE_PREFIX "core";
+ void *handle;
+ const char *valstr;
+ int i;
+
+ if (osdev == NULL)
+ return;
+
+ /* if not core module, take the module name */
+ if (strcmp(osdev->modname, "oss"))
+ strncpy (name, osdev->modname, 16);
+
+ dprintf("oss_load_options(): %s\n", name);
+ handle = load_driver_settings (name);
+ /* not there */
+ if (handle == NULL)
+ return;
+
+ for (i = 0; map[i].name != NULL; i++)
+ {
+ /* discard given without value */
+ if ((valstr =
+ get_driver_parameter (handle,
+ map[i].name, NULL, NULL)) != NULL)
+ {
+ int base = 10;
+ if (!strncmp (valstr, "0x", 2))
+ {
+ base = 16;
+ valstr += 2;
+ }
+ *map[i].ptr = (int)strtol (valstr, NULL, base);
+ }
+ }
+ unload_driver_settings (handle);
+}
+
+#ifdef DEBUG_KDLCMD
+static int
+kdl_oss_dump_cards(int argc, char **argv)
+{
+ int i;
+ kprintf("oss_num_cards = %d\n", oss_num_cards);
+ for (i = 0; i < oss_num_cards; i++)
+ {
+ if (cards[i] == NULL)
+ continue;
+ kprintf("oss_cards[%d] = {\n", i);
+ kprintf(" cardnum= %d\n", cards[i]->cardnum);
+ kprintf(" dev_type= %d\n", cards[i]->dev_type);
+ kprintf(" instance= %d\n", cards[i]->instance);
+
+ kprintf(" unloaded= %d\n", cards[i]->unloaded);
+
+ kprintf(" name= %s\n", cards[i]->name);
+ kprintf(" nick= %-16s\n", cards[i]->nick);
+ kprintf(" modname= %-32s\n", cards[i]->modname);
+ kprintf(" handle= %-32s\n", cards[i]->handle);
+ kprintf(" num_audio_engines= %d\n", cards[i]->num_audio_engines);
+ kprintf(" num_audioplay= %d\n", cards[i]->num_audioplay);
+ kprintf(" num_audiorec= %d\n", cards[i]->num_audiorec);
+ kprintf(" num_audioduplex= %d\n", cards[i]->num_audioduplex);
+ kprintf(" num_mididevs= %d\n", cards[i]->num_mididevs);
+ kprintf(" num_mixerdevs= %d\n", cards[i]->num_mixerdevs);
+
+ kprintf(" refcount= %d\n", cards[i]->refcount);
+
+ kprintf(" irq= %d\n", cards[i]->irq);
+ kprintf("}\n");
+ }
+ return 0;
+}
+
+static int
+kdl_oss_dump_cdevs(int argc, char **argv)
+{
+ int i;
+ kprintf("oss_num_cdevs = %d\n", oss_num_cdevs);
+ for (i = 0; i < oss_num_cdevs; i++)
+ {
+ if (oss_cdevs[i] == NULL)
+ continue;
+ kprintf("oss_cdevs[%d] = {\n", i);
+ kprintf(" dev_class= %d\n", oss_cdevs[i]->dev_class);
+ kprintf(" instance= %d\n", oss_cdevs[i]->instance);
+ kprintf(" name= %-32s\n", oss_cdevs[i]->name);
+ kprintf(" osdev= %p\n", oss_cdevs[i]->osdev);
+ //kprintf(" opencount= %d\n", open_count[i]);
+ kprintf("}\n");
+ }
+ return 0;
+}
+#endif
+
+/*
+ * Driver entry point routines
+ */
+
+status_t
+init_osscore (void)
+{
+ int err = 0;
+ oss_device_t *osdev;
+ FENTRY();
+
+#ifdef LICENSED_VERSION
+/*WRITEME*/
+#endif
+
+ add_debugger_command("oss_dump_cards", &kdl_oss_dump_cards, "Dump the OSS cards[] array.");
+ add_debugger_command("oss_dump_cdevs", &kdl_oss_dump_cdevs, "Dump the OSS cdevs[] array.");
+
+ //MUTEX_INIT (osdev, osscore_mutex, MH_TOP);
+ CORE_LOCK_INIT();
+
+ if ((osdev = osdev_create (NULL, DRV_VIRTUAL, 0, "oss", NULL)) == NULL)
+ {
+ cmn_err (CE_WARN, "Creating osdev failed\n");
+ FEXITR(ENOMEM);
+ return OSS_ENOMEM;
+ }
+
+
+ oss_load_options (osdev, oss_global_options);
+
+ oss_common_init (osdev);
+
+ oss_register_device (osdev, "OSS core services");
+
+ FEXIT();
+ return 0;
+}
+
+status_t
+uninit_osscore (void)
+{
+ int i;
+ static int already_unloaded = 0;
+ FENTRY();
+
+ if (oss_open_devices > 0)
+ return EBUSY;
+
+ if (already_unloaded)
+ return 0;
+ already_unloaded = 1;
+
+ oss_unload_drivers ();
+
+ //LOCK_CORE();
+ for (i = 0; i < nmemblocks; i++)
+ KERNEL_FREE (memblocks[i]);
+ nmemblocks = 0;
+
+ CORE_LOCK_CLEANUP();
+ //MUTEX_CLEANUP (osscore_mutex);
+
+ remove_debugger_command("oss_dump_cdevs", &kdl_oss_dump_cdevs);
+ remove_debugger_command("oss_dump_cards", &kdl_oss_dump_cards);
+
+#if DEBUG_IRQ
+ dprintf("oss: %ld irq handlers left\n", irq_count);
+#endif
+
+
+ return 0;
+}
+
+const char **
+oss_publish_devices(void)
+{
+ int i, j;
+ char *name;
+ CORE_LOCK_VAR;
+
+ FENTRY();
+
+ LOCK_CORE();
+ gDeviceNames = realloc(gDeviceNames, (oss_num_cdevs + 1) * sizeof(char *)
+ + (oss_num_cdevs * DEVICE_NAME_LEN));
+ if (gDeviceNames == NULL) {
+ UNLOCK_CORE();
+ FEXIT();
+ return NULL;
+ }
+ name = (char *)(&gDeviceNames[oss_num_cdevs + 1]);
+ for (i = 0; i < oss_num_cdevs+1; i++)
+ gDeviceNames[i] = NULL;
+ //dprintf("oss_num_cdevs = %d\n", oss_num_cdevs);
+ for (i = 0, j = 0; i < oss_num_cdevs; i++)
+ {
+ oss_cdev_t *cdev = oss_cdevs[i];
+ if (cdev && cdev->d)
+ {
+ strcpy(name, DEVICE_PREFIX);
+ strncat(name, cdev->name, 32-1);
+ //dprintf("oss: publishing %s\n", name);
+ gDeviceNames[j++] = name;
+ name += DEVICE_NAME_LEN;
+ }
+ }
+ UNLOCK_CORE();
+
+ FEXIT();
+ return (const char**)gDeviceNames;
+}
+
+device_hooks *oss_get_driver_hooks (void)
+{
+ return &oss_driver_hooks;
+}
+
+status_t
+oss_load_drivers (void)
+{
+ oss_drv_module_info *drv;
+ char module[256];
+ size_t modulesz = sizeof(module);
+ void *cookie;
+ status_t err = ENOENT;
+ FENTRY();
+ cookie = open_module_list(OSS_MODULES_PREFIX);
+ if (cookie == NULL)
+ goto err1;
+ while (read_next_module_name(cookie, module, &modulesz) >= B_OK)
+ {
+ err = get_module(module, (module_info **)&drv);
+ if (err >= B_OK)
+ {
+ if (drv->driver_probe() < B_OK)
+ put_module(module);
+ }
+ modulesz = sizeof(module);
+ }
+ err = B_OK;
+err2:
+ close_module_list(cookie);
+err1:
+ FEXITR(err);
+ return B_OK;
+}
+
+status_t
+oss_probe_pci (void)
+{
+ FENTRY();
+ //XXX:TODO:remove me
+ //ali5455_probe();
+ //atiaudio_probe();
+ FEXIT();
+ return B_OK;
+}
+
+
+static status_t
+unload_driver (const char *nick)
+{
+ oss_drv_module_info *drv;
+ char module[256];
+ status_t err = B_OK;
+ int i;
+ CORE_LOCK_VAR;
+ FENTRYA("%s", nick);
+
+ /* skip ourselves */
+ if (!strcmp(nick, "oss"))
+ goto err1;
+
+ sprintf(module, "%s%s%s", OSS_MODULES_PREFIX, nick, OSS_MODULES_SUFFIX);
+ err = get_module(module, (module_info **)&drv);
+ if (err < B_OK)
+ goto err1;
+
+ err = EBUSY;
+
+ LOCK_CORE();
+ /* detach all osdevs for this driver */
+ for (i = 0; i < oss_num_cards; i++)
+ {
+ oss_device_t *osdev = cards[i];
+ if (!osdev)
+ continue;
+ if (strncmp(osdev->modname, nick, 32))
+ continue;
+ UNLOCK_CORE();
+ err = drv->driver_detach(osdev);
+ if (err < B_OK)
+ goto err2;
+ LOCK_CORE();
+ //cards[i] = NULL; // XXX: not sure...
+ }
+ UNLOCK_CORE();
+ err = B_OK;
+ put_module(module);
+ /* twice */
+err2:
+ put_module(module);
+err1:
+ FEXITR(err);
+ return err;
+}
+
+status_t
+oss_unload_all_drivers(void)
+{
+ char module[256];
+ status_t err = B_OK;
+ int i;
+ CORE_LOCK_VAR;
+ FENTRY();
+
+ /* for each osdev still around, unload the module it came from,
+ * which should delete them.
+ */
+ LOCK_CORE();
+ for (i = 0; i < oss_num_cards; i++)
+ {
+ if (!cards[i])
+ continue;
+ if (cards[i]->unloaded)
+ continue;
+ UNLOCK_CORE();
+ err = unload_driver(cards[i]->modname);
+ if (err < B_OK)
+ break;
+ LOCK_CORE();
+ }
+ UNLOCK_CORE();
+
+ FEXITR(err);
+ return err;
+}
+
+
+static status_t
+oss_stdops(int32 op, ...)
+{
+ status_t err;
+ switch (op)
+ {
+ case B_MODULE_INIT:
+ //vmix_disabled = 1; /* disable vmix */
+ err = get_module(B_PCI_MODULE_NAME, (module_info **)&gPCI);
+ if (err >= B_OK)
+ {
+ //XXX:call init_osscore() here
+ return err;
+ put_module(B_PCI_MODULE_NAME);
+ }
+ return err;
+ case B_MODULE_UNINIT:
+ free(gDeviceNames);
+ put_module(B_PCI_MODULE_NAME);
+ return B_OK;
+
+ }
+ return B_ERROR;
+}
+
+oss_core_module_info gOSSCoreModule = {
+ {
+ OSS_CORE_MODULE_NAME,
+ /*B_KEEP_LOADED*/0,
+ oss_stdops,
+ },
+ init_osscore,
+ uninit_osscore,
+ oss_publish_devices,
+ oss_get_driver_hooks,
+ oss_probe_pci,
+ oss_load_drivers,
+ oss_unload_all_drivers,
+};
+
+// for f in kernel/drv/*; do echo "extern oss_drv_module_info gModule_$(basename $f);"; done
+extern oss_drv_module_info gModule_oss_ali5455;
+extern oss_drv_module_info gModule_oss_atiaudio;
+extern oss_drv_module_info gModule_oss_audigyls;
+//extern oss_drv_module_info gModule_oss_audiocs;
+extern oss_drv_module_info gModule_oss_audioloop;
+extern oss_drv_module_info gModule_oss_audiopci;
+extern oss_drv_module_info gModule_oss_cmi878x;
+extern oss_drv_module_info gModule_oss_cmpci;
+extern oss_drv_module_info gModule_oss_cs4281;
+extern oss_drv_module_info gModule_oss_cs461x;
+extern oss_drv_module_info gModule_oss_digi96;
+extern oss_drv_module_info gModule_oss_emu10k1x;
+extern oss_drv_module_info gModule_oss_envy24;
+extern oss_drv_module_info gModule_oss_envy24ht;
+extern oss_drv_module_info gModule_oss_fmedia;
+extern oss_drv_module_info gModule_oss_geode;
+extern oss_drv_module_info gModule_oss_hdaudio;
+extern oss_drv_module_info gModule_oss_ich;
+//extern oss_drv_module_info gModule_oss_imux;
+//extern oss_drv_module_info gModule_oss_midiloop;
+//extern oss_drv_module_info gModule_oss_midimix;
+//extern oss_drv_module_info gModule_oss_sadasupport;
+extern oss_drv_module_info gModule_oss_sblive;
+extern oss_drv_module_info gModule_oss_sbpci;
+extern oss_drv_module_info gModule_oss_sbxfi;
+extern oss_drv_module_info gModule_oss_solo;
+extern oss_drv_module_info gModule_oss_trident;
+//extern oss_drv_module_info gModule_oss_usb;
+//extern oss_drv_module_info gModule_oss_userdev;
+extern oss_drv_module_info gModule_oss_via823x;
+extern oss_drv_module_info gModule_oss_via97;
+extern oss_drv_module_info gModule_oss_ymf7xx;
+//extern oss_drv_module_info gModule_osscore;
+
+module_info *modules[] = {
+ (module_info *)&gOSSCoreModule,
+//for f in kernel/drv/*; do echo " (module_info *)&gModule_$(basename $f),"; done >> kernel/OS/BeOS/os_beos.c (module_info *)&gModule_oss_ali5455,
+ (module_info *)&gModule_oss_atiaudio,
+ (module_info *)&gModule_oss_audigyls,
+ //(module_info *)&gModule_oss_audiocs,
+ //(module_info *)&gModule_oss_audioloop,
+ (module_info *)&gModule_oss_audiopci,
+ (module_info *)&gModule_oss_cmi878x,
+ (module_info *)&gModule_oss_cmpci,
+ (module_info *)&gModule_oss_cs4281,
+ (module_info *)&gModule_oss_cs461x,
+ (module_info *)&gModule_oss_digi96,
+ (module_info *)&gModule_oss_emu10k1x,
+ (module_info *)&gModule_oss_envy24,
+ (module_info *)&gModule_oss_envy24ht,
+ (module_info *)&gModule_oss_fmedia,
+ (module_info *)&gModule_oss_geode,
+ (module_info *)&gModule_oss_hdaudio,
+ (module_info *)&gModule_oss_ich,
+ //(module_info *)&gModule_oss_imux,
+ //(module_info *)&gModule_oss_midiloop,
+ //(module_info *)&gModule_oss_midimix,
+ //(module_info *)&gModule_oss_sadasupport,
+ (module_info *)&gModule_oss_sblive,
+ (module_info *)&gModule_oss_sbpci,
+ (module_info *)&gModule_oss_sbxfi,
+ (module_info *)&gModule_oss_solo,
+ (module_info *)&gModule_oss_trident,
+ //(module_info *)&gModule_oss_usb,
+ //(module_info *)&gModule_oss_userdev,
+ (module_info *)&gModule_oss_via823x,
+ (module_info *)&gModule_oss_via97,
+ (module_info *)&gModule_oss_ymf7xx,
+// (module_info *)&gModule_osscore,
+
+#if 0 /* OLD */
+
+
+ (module_info *)&gModule_oss_ali5455,
+
+ (module_info *)&gModule_oss_allegro,
+ (module_info *)&gModule_oss_als300,
+ (module_info *)&gModule_oss_als4000,
+ (module_info *)&gModule_oss_apci97,
+
+ (module_info *)&gModule_oss_atiaudio,
+
+ (module_info *)&gModule_oss_audigyls,
+ //(module_info *)&gModule_oss_audioloop,
+ (module_info *)&gModule_oss_audiopci,
+ (module_info *)&gModule_oss_cmi8788,
+ (module_info *)&gModule_oss_cmpci,
+ (module_info *)&gModule_oss_cs4280,
+ (module_info *)&gModule_oss_cs4281,
+ (module_info *)&gModule_oss_digi32,
+ (module_info *)&gModule_oss_digi96,
+ (module_info *)&gModule_oss_emu10k1x,
+ (module_info *)&gModule_oss_envy24,
+ (module_info *)&gModule_oss_envy24ht,
+ (module_info *)&gModule_oss_fm801,
+ (module_info *)&gModule_oss_geode,
+ (module_info *)&gModule_oss_hdaudio,
+
+ (module_info *)&gModule_oss_ich,
+
+#ifdef ENABLE_IMUX
+ (module_info *)&gModule_oss_imux,
+#endif
+ (module_info *)&gModule_oss_maestro,
+ (module_info *)&gModule_oss_neomagic,
+ (module_info *)&gModule_oss_s3vibes,
+ (module_info *)&gModule_oss_sblive,
+#ifdef ENABLE_SOFTOSS
+ //(module_info *)&gModule_oss_softoss,
+#endif
+ (module_info *)&gModule_oss_solo,
+ (module_info *)&gModule_oss_trident,
+ (module_info *)&gModule_oss_via8233,
+ (module_info *)&gModule_oss_via97,
+ (module_info *)&gModule_oss_vortex,
+ (module_info *)&gModule_oss_ymf7xx,
+#endif
+
+ NULL
+};
+
+/*
+ * Driver hooks
+ */
+
+
+typedef struct ossdev_cookie {
+ int minor; /* index into cdevs[] */
+ oss_cdev_t *cdev;
+ struct fileinfo file;
+} ossdev_cookie_t;
+
+static int find_cdev(const char *name)
+{
+ int i, which = -1;
+ CORE_LOCK_VAR;
+// if (strlen(name) < strlen(DEVICE_PREFIX))
+// return -1;
+ name += strlen(DEVICE_PREFIX);
+
+ LOCK_CORE();
+ for (i = 0; i < oss_num_cdevs; i++)
+ {
+ oss_cdev_t *cdev = oss_cdevs[i];
+ //dprintf("oss:find_cdev: cdev %p, ->d %p, %s <> %s\n", cdev, cdev?cdev->d:NULL, cdev?cdev->name:"-", name);
+ if (cdev && cdev->d && !strncmp(cdev->name, name, 32))
+ {
+ which = i;
+ break;
+ }
+ }
+ UNLOCK_CORE();
+
+ return which;
+}
+
+static status_t
+ossdrv_open(const char *name, uint32 oflags, void **cookie)
+{
+ ossdev_cookie_t *c;
+ status_t err;
+ int dev, tmpdev;
+ oss_cdev_t *cdev;
+ CORE_LOCK_VAR;
+ FENTRYA("%s, %ld, ", name, oflags);
+
+ dev = find_cdev(name);
+ err = ENOENT;
+ if (dev < 0)
+ goto err1;
+ err = ENXIO;
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d == NULL)
+ goto err1;
+
+ DDB (cmn_err
+ (CE_CONT, "oss_cdev_open(%d): %s, class=%d, instance=%d\n", dev,
+ cdev->name, cdev->dev_class, cdev->instance));
+
+ err = ENODEV;
+ if (cdev->d->open == NULL)
+ goto err1;
+
+ err = ENOMEM;
+ c = malloc(sizeof(ossdev_cookie_t));
+ if (!c)
+ goto err1;
+
+ switch (oflags & O_RWMASK)
+ {
+ case O_RDONLY:
+ c->file.mode = OPEN_READ;
+ break;
+ case O_WRONLY:
+ c->file.mode = OPEN_WRITE;
+ break;
+ case O_RDWR:
+ c->file.mode = OPEN_READWRITE;
+ break;
+ default:
+ err = EINVAL;
+ goto err2;
+ }
+ //c->file.flags = oflags;
+ c->file.acc_flags = oflags;
+
+ tmpdev = -1;
+ err =
+ cdev->d->open (cdev->instance, cdev->dev_class, &c->file, 0, 0, &tmpdev);
+ if (err < 0)
+ goto err3;
+ if (tmpdev > -1)
+ dev = tmpdev;
+
+ c->minor = dev;
+ c->cdev = cdev = oss_cdevs[dev];
+
+ //XXX:locking
+ LOCK_CORE();
+ oss_open_devices++;
+ //open_count[dev]++;
+ UNLOCK_CORE();
+
+ *cookie = c;
+ FEXITR(B_OK);
+ return B_OK;
+
+err3:
+err2:
+ free(c);
+err1:
+ FEXITR(err);
+ return err;
+}
+
+
+static status_t
+ossdrv_close(void *cookie)
+{
+ FENTRY();
+ FEXIT();
+ return B_OK;
+}
+
+
+static status_t
+ossdrv_freecookie(ossdev_cookie_t *cookie)
+{
+ oss_cdev_t *cdev = cookie->cdev;
+ int dev = cookie->minor;
+ CORE_LOCK_VAR;
+ status_t err;
+ FENTRY();
+
+ err = ENXIO;
+ if (dev >= OSS_MAX_CDEVS)
+ goto err;
+
+#if 0 // not safe (not locked)
+ err = B_OK;
+ if (open_count[dev] == 0) /* Not opened */
+ goto err;
+#endif
+
+ err = ENXIO;
+ if (cdev != oss_cdevs[dev])
+ goto err;
+
+ //in close or free ??
+ cdev->d->close (cdev->instance, &cookie->file);
+
+ LOCK_CORE();
+ oss_open_devices--;
+ //open_count[dev]--;
+ UNLOCK_CORE();
+
+ free(cookie);
+ err = B_OK;
+err:
+ FEXITR(err);
+ return B_OK;
+}
+
+/* note: IOC stuff seems to not collide with the base ioctls from Drivers.h
+ * as long as the type field is printable ascii (>32). Lucky are we.
+ */
+static status_t
+ossdrv_ioctl(ossdev_cookie_t *cookie, uint32 op, void *buffer, size_t length)
+{
+ oss_cdev_t *cdev = cookie->cdev;
+ status_t err = ENXIO;
+ uint32 cmd = op;
+ int len = 0;
+ char buf[4096];
+ FENTRYA(", %lx, , %ld", op, length);
+
+ if ((cdev != oss_cdevs[cookie->minor]) || cdev->d->ioctl == NULL)
+ goto err1;
+
+ if (cmd & (SIOC_OUT | SIOC_IN))
+ {
+
+ len = (cmd >> 16) & SIOCPARM_MASK;
+ if (len < 0)
+ len = 0;
+ if (len > sizeof (buf))
+ {
+ cmn_err (CE_WARN, "Bad ioctl buffer size %d\n", len);
+ err = EFAULT;
+ goto err1;
+ }
+
+ if ((cmd & SIOC_IN) && len > 0)
+ {
+ memcpy (buf, buffer, len);
+ //return EFAULT;
+ }
+
+ }
+
+ err = cdev->d->ioctl (cdev->instance, &cookie->file, cmd, (ioctl_arg) buf);
+
+ if ((cmd & SIOC_OUT) && len > 0)
+ {
+ memcpy (buffer, buf, len);
+ //return EFAULT;
+ }
+
+
+err1:
+ FEXITR(err);
+ return err;
+}
+
+
+static status_t
+ossdrv_read(ossdev_cookie_t *cookie, off_t pos, void *buffer, size_t *_length)
+{
+ oss_cdev_t *cdev = cookie->cdev;
+ uio_t uio;
+ int count = *_length;
+ int err;
+ FENTRYA(", %Ld, , %ld", pos, *_length);
+
+ err = ENXIO;
+ if ((cdev != oss_cdevs[cookie->minor]) || cdev->d->read == NULL)
+ goto err;
+ //files[dev].acc_flags = uiop->uio_fmode;
+ if ((err = oss_create_uio (&uio, buffer, count, UIO_READ, 0)) < 0)
+ goto err;
+
+ err = cdev->d->read (cdev->instance, &cookie->file, &uio, count);
+ //*_length = (err > 0) ? err : 0;
+ if (err < 0)
+ goto err;
+
+ *_length = err;
+ err = B_OK;
+ FEXITR(err);
+ return err;
+
+err:
+ *_length = 0;
+ FEXITR(err);
+ return err;
+}
+
+
+static status_t
+ossdrv_write(ossdev_cookie_t *cookie, off_t pos, const void *buffer, size_t *_length)
+{
+ oss_cdev_t *cdev = cookie->cdev;
+ uio_t uio;
+ int count = *_length;
+ int err;
+ FENTRYA(", %Ld, , %ld", pos, *_length);
+
+ err = ENXIO;
+ if ((cdev != oss_cdevs[cookie->minor]) || cdev->d->write == NULL)
+ goto err;
+ //files[dev].acc_flags = uiop->uio_fmode;
+ if ((err = oss_create_uio (&uio, (void *)buffer, count, UIO_WRITE, 0)) < 0)
+ goto err;
+
+ err = cdev->d->write (cdev->instance, &cookie->file, &uio, count);
+ //*_length = (err > 0) ? err : 0;
+ if (err < 0)
+ goto err;
+
+ *_length = err;
+ err = B_OK;
+ FEXITR(err);
+ return err;
+
+err:
+ *_length = 0;
+ FEXITR(err);
+ return err;
+}
+
+
+device_hooks oss_driver_hooks = {
+ &ossdrv_open,
+ &ossdrv_close,
+ (device_free_hook)&ossdrv_freecookie,
+ (device_control_hook)&ossdrv_ioctl,
+ (device_read_hook)&ossdrv_read,
+ (device_write_hook)&ossdrv_write,
+ /* Leave select/deselect/readv/writev undefined. The kernel will
+ * use its own default implementation. The basic hooks above this
+ * line MUST be defined, however. */
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
diff --git a/kernel/OS/BeOS/os_beos.h b/kernel/OS/BeOS/os_beos.h
new file mode 100644
index 0000000..1e8f0b5
--- /dev/null
+++ b/kernel/OS/BeOS/os_beos.h
@@ -0,0 +1,471 @@
+#ifndef _OS_H_
+#define _OS_H_
+
+/*
+ * Purpose: OS specific definitions for BeOS/Haiku
+ *
+ */
+/*
+ *
+ * This file is part of Open Sound System.
+ *
+ * Copyright (C) 4Front Technologies 1996-2007.
+ *
+ * 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. Please contact sales@opensound.com for further info.
+ *
+ */
+#define OS_VERSION "5"
+#define __inline__ inline
+#define __inline inline
+#define EXTERN_C extern "C"
+
+/*
+ * Debugging and misc settings
+ */
+#undef DO_TIMINGS
+#undef MUTEX_CHECKS
+#undef MEMDEBUG
+/* very verbose */
+//#define DO_DEBUG_FUNC_CALLS
+/* XXX */
+#define DEBUG_KDLCMD 1
+//#define ENABLE_IMUX 1
+//#define ENABLE_SOFTOSS 1
+
+/*
+ * Disable support for per-application features such as /dev/dsp device
+ * selection based on command name. Requires working GET_PROCESS_NAME
+ * macro implementation.
+ */
+//Disable??
+//#define APPLIST_SUPPORT
+#define USE_DEVICE_SUBDIRS
+/* no VDEV */
+#undef VDEV_SUPPORT
+
+//XXX: try to avoid crashing
+#define MIDI_DISABLED 1
+
+#include <OS.h>
+#include <stdarg.h>
+//#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <oss_errno.h>
+#include <sys/uio.h>
+#include <fcntl.h>
+#ifdef __HAIKU__
+#include <poll.h>
+#endif
+//#include <sys/malloc.h>
+#include <malloc.h>
+
+
+#include <KernelExport.h>
+#include <Drivers.h>
+#include <PCI.h>
+
+#ifndef ENOTSUP
+#define ENOTSUP ENOSYS
+#endif
+
+#define OSS_CONTIG_AREA_NAME "OSS CONTIG MEM"
+#define OSS_PCI_AREA_NAME "OSS PCI MEM"
+#define OSS_WQ_SEM_NAME "OSS WAITQ: "
+
+//#define DEVICE_PREFIX "audio/oss/"
+#define DEVICE_PREFIX ""
+#define DEVICE_NAME_LEN (32+sizeof(DEVICE_PREFIX))
+
+#define OSS_CONFIG_FILE_PREFIX "oss_"
+
+#ifdef _KERNEL_MODE
+
+/* references to modules */
+extern pci_module_info *gPCI;
+
+#endif /* _KERNEL_MODE */
+
+/*
+ * Some integer types
+ */
+#if defined(amd64) || defined(sparc) // 64bit ? not yet
+typedef uint64 oss_native_word; /* Same as the address and status register size */
+#else
+typedef uint32 oss_native_word; /* Same as the address and status register size */
+#endif
+
+typedef int64 oss_int64_t; /* Signed 64 bit integer */
+typedef uint64 oss_uint64_t; /* Unsigned 64 bit integer */
+typedef unsigned long offset_t;
+
+
+extern void oss_cmn_err (int level, char *format, ...);
+#define CE_CONT 0
+#define CE_NOTE 1
+#define CE_WARN 2
+#define CE_PANIC 3
+#define cmn_err oss_cmn_err
+
+//snooze(1000000); \
+
+#ifdef DO_DEBUG_FUNC_CALLS
+/* verbose debugging */
+#define FENTRY() \
+dprintf("oss>%s()\n", __FUNCTION__)
+#define FENTRYA(f,a...) \
+dprintf("oss>%s(" f ")\n", __FUNCTION__, a)
+#define FEXIT() \
+dprintf("oss<%s\n", __FUNCTION__)
+#define FEXITR(e) \
+dprintf("oss<%s returned 0x%08lx\n", __FUNCTION__, (uint32)e)
+#else
+#define FENTRY() {}
+#define FENTRYA(f,a...) {}
+#define FEXIT() {}
+#define FEXITR(e) {}
+#endif
+
+struct _dev_info_t
+{
+ //struct pci_dev *pcidev;
+ struct pci_info pciinfo; //XXX: ptr or not ???
+};
+typedef struct _dev_info_t dev_info_t;
+
+
+/*
+ * timeout wrappers
+ */
+#undef timeout
+#define timeout oss_timeout
+#undef untimeout
+#define untimeout oss_untimeout
+typedef int timeout_id_t;
+extern timeout_id_t oss_timeout (void (*func) (void *), void *arg,
+ unsigned long long ticks);
+extern void oss_untimeout (timeout_id_t id);
+
+#define uiomove oss_uiomove
+typedef enum uio_rw
+{ UIO_READ, UIO_WRITE } uio_rw_t;
+struct uio
+{
+ char *ptr;
+ int resid;
+ int kernel_space; /* Set if this uio points to a kernel space buffer */
+ uio_rw_t rw;
+};
+typedef struct uio uio_t;
+extern int oss_uiomove (void *address, size_t nbytes, enum uio_rw rwflag,
+ uio_t * uio);
+extern int oss_create_uio (uio_t * uiop, char *buf, size_t count, uio_rw_t rw,
+ int is_kernel);
+
+
+
+/*
+ * Mutexes
+ */
+
+#ifdef MUTEX_CHECKS
+/* Debugging version */
+struct _oss_mutex_t
+{
+ spinlock lock;
+ thread_id owner;
+ char *file;
+ int line;
+ int busy_flags;
+#define CNTX_INTR 1
+#define CNTX_USER 2
+};
+
+typedef struct _oss_mutex_t oss_mutex_t;
+extern void debug_mutex_init (oss_mutex_t * mutex, char *file, int line);
+extern void debug_mutex_destroy (oss_mutex_t * mutex, char *file, int line);
+extern void debug_mutex_enter (oss_mutex_t * mutex, char *file, int line, oss_native_word *flags);
+extern void debug_mutex_exit (oss_mutex_t * mutex, char *file, int line, oss_native_word *flags);
+
+#define MUTEX_INIT(osdev, mutex, hier) debug_mutex_init(&mutex, NULL, __FILE__, __LINE__)
+#define MUTEX_CLEANUP(mutex) debug_mutex_destroy(&mutex, __FILE__, __LINE__)
+#define MUTEX_ENTER_IRQDISABLE(mutex, flags) debug_mutex_enter(&mutex, __FILE__, __LINE__, &flags)
+#define MUTEX_ENTER(mutex, flags) debug_mutex_enter(&mutex, __FILE__, __LINE__, NULL)
+#define MUTEX_EXIT_IRQRESTORE(mutex, flags) debug_mutex_exit(&mutex, __FILE__, __LINE__, &flags)
+#define MUTEX_EXIT(mutex, flags) debug_mutex_exit(&mutex, __FILE__, __LINE__, NULL)
+#else
+typedef spinlock oss_mutex_t;
+#define MUTEX_INIT(osdev, mutex, hier) { mutex = 0; }
+#define MUTEX_CLEANUP(mutex)
+#define MUTEX_ENTER_IRQDISABLE(mutex, flags) \
+{ \
+ flags = (oss_native_word) disable_interrupts(); \
+ acquire_spinlock(&(mutex)); \
+}
+#define MUTEX_ENTER(mutex, flags) acquire_spinlock(&(mutex))
+#define MUTEX_EXIT_IRQRESTORE(mutex, flags) \
+{ \
+ release_spinlock(&(mutex)); \
+ restore_interrupts((cpu_status)(flags)); \
+}
+#define MUTEX_EXIT(mutex, flags) release_spinlock(&(mutex))
+#endif
+
+/* The soundcard.h could be in a nonstandard place so include it here. */
+#include "soundcard.h"
+
+typedef struct udi_usb_devc udi_usb_devc;
+struct _oss_device_t
+{
+#ifdef NEEDED_FOR_DRIVERS
+ int instance;
+ void *devc;
+ char *name;
+#endif
+
+ int cardnum;
+ int dev_type;
+ int instance;
+ int available;
+ dev_info_t *dip;
+ int unloaded;
+ void *osid;
+ void *devc;
+ char *name;
+ char *hw_info;
+ char nick[16];
+ char modname[32];
+ char handle[32];
+ int num_audio_engines;
+ int num_audioplay, num_audiorec, num_audioduplex;
+ int num_mididevs;
+ int num_mixerdevs;
+ int num_loopdevs;
+ int first_mixer; /* This must be set to -1 by osdev_create() */
+
+ volatile int refcount; /* Nonzero means that the device is needed by some other (virtual) driver. */
+
+/* Interrupts */
+
+ long irq; //XXX:init =-1
+ oss_tophalf_handler_t tophalf_handler;
+ oss_bottomhalf_handler_t bottomhalf_handler;
+ oss_mutex_t mutex;
+
+};
+
+/* XXX we'll deal with select() later */
+#undef ALLOW_SELECT
+/* BeOS doesn't support mmap. Haiku does, so FIXME someday */
+#undef ALLOW_BUFFER_MAPPING
+
+/*
+ * Sleep/wakeup
+ */
+
+#ifdef _KERNEL
+struct oss_wait_queue
+{
+//XXX:
+// oss_mutex_t mutex;
+ char name[32];
+ sem_id sem;
+ unsigned long flags;
+// struct selinfo poll_info;
+};
+#endif
+
+/* Busy wait routine */
+#define oss_udelay(d) spin((bigtime_t)d)
+
+
+/* usec time base */
+#undef HZ
+/* XXX: might need to be lower to handle casts to long */
+#define OSS_HZ 1000000
+
+/* System wall timer access */
+extern unsigned long oss_get_time (void);
+#define GET_JIFFIES() oss_get_time()
+
+
+/*
+ * INB() and OUTB() should be obvious. NOTE! The order of
+ * paratemeters of OUTB() is different than on some other
+ * operating systems.
+ */
+
+/* I/O Mapped devices */
+#define INB(o, p) gPCI->read_io_8(p)
+#define INW(o, p) gPCI->read_io_16(p)
+#define INL(o, p) gPCI->read_io_32(p)
+
+#define OUTB(o, v, p) gPCI->write_io_8(p,v)
+#define OUTW(o, v, p) gPCI->write_io_16(p,v)
+#define OUTL(o, v, p) gPCI->write_io_32(p,v)
+
+/* Memory Mapped devices */
+#define PCI_READB(osdev, addr) *(volatile unsigned char *)(addr)
+#define PCI_READW(osdev, addr) *(volatile unsigned short *)(addr)
+#define PCI_READL(osdev, addr) *(volatile unsigned int *)(addr)
+
+#define PCI_WRITEB(osdev, addr, data) *(volatile unsigned char *)(addr)=data
+#define PCI_WRITEW(osdev, addr, data) *(volatile unsigned short *)(addr)=data
+#define PCI_WRITEL(osdev, addr, data) *(volatile unsigned int *)(addr)=data
+
+typedef void *oss_dma_handle_t;
+
+/*
+ * When a error (such as EINVAL) is returned by a function,
+ * the following macro is used. The driver assumes that a
+ * error is signalled by returning a negative value.
+ */
+
+/*
+ KERNEL_MALLOC() allocates requested number of memory and
+ KERNEL_FREE is used to free it.
+ These macros are never called from interrupt, in addition the
+ nbytes will never be more than 4096 bytes. Generally the driver
+ will allocate memory in blocks of 4k. If the kernel has just a
+ page level memory allocation, 4K can be safely used as the size
+ (the nbytes parameter can be ignored).
+*/
+#define KERNEL_MALLOC(nbytes) calloc(1,nbytes)
+#define KERNEL_FREE(addr) {if (addr)free(addr);addr=NULL;}
+
+extern void *oss_contig_malloc (oss_device_t * osdev, int sz,
+ oss_uint64_t memlimit,
+ oss_native_word * phaddr);
+extern void oss_contig_free (oss_device_t * osdev, void *p, int sz);
+extern oss_native_word oss_virt_to_bus (void *addr);
+#define CONTIG_MALLOC(osdev, sz, memlimit, phaddr, handle) oss_contig_malloc(osdev, sz, memlimit, phaddr)
+#define CONTIG_FREE(osdev, p, sz, handle) oss_contig_free(osdev, p, sz)
+
+/*
+ * PMALLOC is used to allocate memory that will get automatically freed when
+ * OSS unloads. Usable for per-instance structures allocated when OSS modules
+ * are being loaded.
+ */
+extern void *oss_pmalloc (size_t sz);
+
+//#define PMALLOC(osdev, sz) oss_pmalloc(sz)
+
+/*
+ * Timer macros
+ *
+ * These macros are obsolete and should not be used in any new code.
+ * Use the timeout mechanism (see the timeout(9F) Solaris man page).
+ */
+#define DEFINE_TIMER(name, proc) static timeout_id_t name = 0
+#define REMOVE_TIMER(name, proc) {if (name != 0) untimeout(name);}
+#define INIT_TIMER(name,proc)
+typedef void (*timeout_func_t) (void *);
+#define ACTIVATE_TIMER(name, proc, time) \
+ name=timeout((timeout_func_t)proc, (void*)&name, time)
+#endif
+
+struct fileinfo
+{
+ int mode; /* Open mode */
+ //int flags;
+ int acc_flags;
+};
+#define ISSET_FILE_FLAG(fileinfo, flag) (fileinfo->acc_flags & (flag) ? 1:0)
+
+#define OSS_OS "BeOS"
+#define OSS_OS_LONGNAME "BeOS R" OS_VERSION
+
+typedef void (*softintr_func_t) (int);
+
+struct oss_softintr
+{
+ int id;
+ softintr_func_t func;
+ volatile int armed, running;
+};
+
+struct _oss_poll_event_t
+{
+ short events, revents;
+ struct thread *p;
+ struct cdev *bsd_dev;
+};
+typedef struct _oss_poll_event_t oss_poll_event_t;
+#ifndef POLLIN
+/* events & revents - compatible with the B_SELECT_xxx definitions in Drivers.h */
+#define POLLIN 0x0001 /* any readable data available */
+#define POLLOUT 0x0002 /* file descriptor is writeable */
+#define POLLRDNORM POLLIN
+#define POLLWRNORM POLLOUT
+#define POLLRDBAND 0x0008 /* priority readable data */
+#define POLLWRBAND 0x0010 /* priority data can be written */
+#define POLLPRI 0x0020 /* high priority readable data */
+#endif
+
+extern int detect_trace;
+#define DDB(x) if (detect_trace) x
+
+extern caddr_t oss_map_pci_mem (oss_device_t * osdev, int nr, int phaddr,
+ int size);
+extern void oss_unmap_pci_mem (void *addr);
+#define MAP_PCI_IOADDR(osdev, nr, io) (oss_native_word)io
+#define MAP_PCI_MEM(osdev, ix, phaddr, size) oss_map_pci_mem(osdev, ix, phaddr, size)
+#define UNMAP_PCI_MEM(osdev, ix, ph, virt, size) oss_unmap_pci_mem(virt)
+#define UNMAP_PCI_IOADDR(osdev, ix) {}
+
+#define GET_PROCESS_PID(f) find_thread(NULL)
+#define GET_PROCESS_UID() getuid()
+#define GET_PROCESS_NAME(f) NULL
+
+#define abs(x) ((x) >= 0 ? (x) : -(x))
+
+/*
+ * Interface with the front-end driver
+ */
+extern status_t init_osscore (void);
+extern status_t uninit_osscore (void);
+extern status_t oss_probe_pci (void);
+extern status_t oss_load_drivers (void);
+extern status_t oss_unload_all_drivers (void);
+
+/*
+ * osscore module for use by low-level driver
+ */
+#define OSS_CORE_MODULE_NAME "media/oss/oss_core/v1"
+#define OSS_MODULES_PREFIX "media/oss/drivers/"
+#define OSS_MODULES_SUFFIX "/v1"
+#define OSS_MAKE_DRV_MOD_NAME(nick) OSS_MODULES_PREFIX nick OSS_MODULES_SUFFIX
+typedef struct oss_drv_module_info {
+ module_info minfo;
+ int (*driver_probe)(void);
+ int (*driver_attach)(oss_device_t *osdev);
+ int (*driver_detach)(oss_device_t *osdev);
+} oss_drv_module_info;
+
+typedef struct oss_core_module_info {
+ module_info minfo;
+ status_t (*init_osscore) (void);
+ status_t (*uninit_osscore) (void);
+ const char **(*oss_publish_devices) (void);
+ device_hooks *(*oss_get_driver_hooks) (void);
+ status_t (*oss_probe_pci) (void);
+ status_t (*oss_load_drivers) (void);
+ status_t (*oss_unload_all_drivers) (void);
+} oss_core_module_info;
+extern oss_core_module_info *gOSSCore;
+
+//XXX: not yet
+#ifdef ASMODULES
+
+struct oss_core_module {
+ module_info minfo;
+ void (*oss_foo)(void);
+};
+extern struct oss_core_info *gOSSCore;
+#ifdef BUILDING_DRIVER
+ #define oss_foo gOSSCore->oss_foo
+#endif
+#endif /* ASMODULES */
diff --git a/kernel/OS/FreeBSD/.config b/kernel/OS/FreeBSD/.config
new file mode 100644
index 0000000..816ac62
--- /dev/null
+++ b/kernel/OS/FreeBSD/.config
@@ -0,0 +1 @@
+mode=kernel
diff --git a/kernel/OS/FreeBSD/os_freebsd.c b/kernel/OS/FreeBSD/os_freebsd.c
new file mode 100644
index 0000000..58b11cc
--- /dev/null
+++ b/kernel/OS/FreeBSD/os_freebsd.c
@@ -0,0 +1,1107 @@
+/*
+ * Purpose: Operating system abstraction functions for FreeBSD
+ */
+/*
+ *
+ * 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"
+#include <oss_pci.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/sx.h>
+#include <sys/mman.h>
+#include <sys/lockmgr.h>
+#include <fs/devfs/devfs.h>
+#include <sys/poll.h>
+#include <sys/param.h>
+#include <sys/filio.h>
+
+/* Function prototypes */
+static d_open_t oss_open;
+static d_close_t oss_close;
+static d_read_t oss_read;
+static d_write_t oss_write;
+static d_ioctl_t oss_ioctl;
+static d_poll_t oss_poll;
+static d_mmap_t oss_mmap;
+
+/* Character device entry points */
+
+static struct cdevsw oss_cdevsw = {
+ .d_version = D_VERSION,
+ .d_flags = D_TRACKCLOSE,
+ .d_open = oss_open,
+ .d_close = oss_close,
+ .d_read = oss_read,
+ .d_write = oss_write,
+ .d_ioctl = oss_ioctl,
+ .d_poll = oss_poll,
+ .d_mmap = oss_mmap,
+ .d_name = "oss"
+};
+
+static int oss_major = 30;
+oss_device_t *core_osdev = NULL;
+static int open_devices = 0;
+static int refcount = 0;
+
+#define MAX_CARDS 32
+int oss_num_cards = 0;
+static oss_device_t *cards[MAX_CARDS];
+static int oss_expired = 0;
+
+
+int
+__oss_alloc_dmabuf (int dev, dmap_p dmap, unsigned int alloc_flags,
+ oss_uint64_t maxaddr, int direction)
+{
+ void *tmpbuf;
+ 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;
+
+ 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;
+
+ tmpbuf = CONTIG_MALLOC (dmap->osdev, size, maxaddr, &phaddr, NULL);
+ if (tmpbuf == NULL)
+ return OSS_ENOMEM;
+ dmap->dmabuf = tmpbuf;
+ dmap->buffsize = size;
+ dmap->dmabuf_phys = phaddr;
+
+ return 0;
+}
+
+void
+oss_free_dmabuf (int dev, dmap_p dmap)
+{
+ if (dmap->dmabuf == NULL)
+ return;
+
+ CONTIG_FREE (dmap->osdev, dmap->dmabuf, dmap->buffsize, NULL);
+ dmap->dmabuf = NULL;
+ dmap->buffsize = 0;
+ dmap->dmabuf_phys = 0;
+}
+
+oss_wait_queue_t *
+oss_create_wait_queue (oss_device_t * osdev, const char *name)
+{
+ oss_wait_queue_t *wq;
+
+ if ((wq = PMALLOC (NULL, sizeof (*wq))) == NULL)
+ return NULL;
+
+ MUTEX_INIT (osdev, wq->mutex, MH_TOP);
+
+ return wq;
+}
+
+void
+oss_reset_wait_queue (oss_wait_queue_t * wq)
+{
+ wq->flags = 0;
+}
+
+void
+oss_remove_wait_queue (oss_wait_queue_t * wq)
+{
+ MUTEX_CLEANUP (wq->mutex);
+}
+
+int
+oss_sleep (oss_wait_queue_t * wq, oss_mutex_t * mutex, int ticks,
+ oss_native_word * flags, unsigned int *status)
+{
+ int flag;
+ *status = 0;
+
+ if (wq == NULL)
+ return 0;
+
+ wq->flags = 0;
+#ifdef USE_SX_LOCK
+ flag = sx_sleep (wq, *mutex, PRIBIO | PCATCH, "oss", ticks);
+#else
+#if __FreeBSD_version >= 602000
+ flag = msleep_spin (wq, *mutex, "oss", ticks);
+#else
+ flag = msleep (wq, *mutex, PRIBIO | PCATCH, "oss", ticks);
+#endif
+#endif
+ if (flag == EWOULDBLOCK) /* Timeout */
+ {
+ return 0;
+ }
+
+ if (flag != 0)
+ {
+ *status |= WK_SIGNAL;
+ }
+
+ return 1;
+}
+
+int
+oss_register_poll (oss_wait_queue_t * wq, oss_mutex_t * mutex,
+ oss_native_word * flags, oss_poll_event_t * ev)
+{
+ MUTEX_EXIT_IRQRESTORE (*mutex, *flags);
+ selrecord (ev->p, &wq->poll_info);
+ MUTEX_ENTER_IRQDISABLE (*mutex, *flags);
+ return 0;
+}
+
+void
+oss_wakeup (oss_wait_queue_t * wq, oss_mutex_t * mutex,
+ oss_native_word * flags, short events)
+{
+ MUTEX_EXIT_IRQRESTORE (*mutex, *flags);
+ wakeup (wq);
+ selwakeup (&wq->poll_info);
+ MUTEX_ENTER_IRQDISABLE (*mutex, *flags);
+}
+
+void
+oss_register_module (char *name)
+{
+ refcount++;
+}
+
+void
+oss_unregister_module (char *name)
+{
+ refcount--;
+}
+
+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 ((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);
+ if (osdev->dip != NULL)
+ device_set_desc (osdev->dip, name);
+ return OSS_ENXIO;
+}
+
+void
+oss_unregister_device (oss_device_t * osdev)
+{
+ // NOP
+}
+
+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_EIO;
+}
+
+void *
+oss_find_minor_info (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 oss_cdevs[i]->info;
+ }
+
+ return NULL;
+}
+
+int
+oss_disable_device (oss_device_t * osdev)
+{
+ int i;
+
+ if (osdev->refcount > 0)
+ return OSS_EBUSY;
+
+ if (open_devices > 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;
+}
+
+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->shortname[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;
+}
+
+static int
+grow_array(oss_device_t *osdev, oss_cdev_t ***arr, int *size, int element_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 * element_size))==NULL)
+ return 0;
+
+ memset(new, 0, new_size * element_size);
+ if (old != NULL)
+ memcpy(new, old, old_size * element_size);
+
+ *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)
+{
+ struct cdev *bsd_cdev;
+ oss_cdev_t *cdev = NULL;
+ int i, num;
+
+ 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, sizeof(oss_cdev_t*), 100))
+ {
+ cmn_err (CE_WARN, "Cannot allocate new 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) - 1);
+ else
+ strcpy (cdev->name, "NONE");
+ cdev->name[sizeof (cdev->name) - 1] = 0;
+ oss_cdevs[num] = cdev;
+
+ if (!(flags & CHDEV_VIRTUAL) && (name != NULL))
+ {
+ bsd_cdev =
+ make_dev (&oss_cdevsw, num, UID_ROOT, GID_WHEEL, 0666, name, 0);
+ cdev->info = bsd_cdev;
+ }
+}
+
+#define MAX_MEMBLOCKS 4096
+static void *memblocks[MAX_MEMBLOCKS];
+static int nmemblocks = 0;
+
+void *
+oss_pmalloc (size_t sz)
+{
+ void *tmp;
+
+ tmp = KERNEL_MALLOC (sz);
+
+ if (nmemblocks < MAX_MEMBLOCKS)
+ memblocks[nmemblocks++] = tmp;
+
+ return tmp;
+}
+
+int
+oss_uiomove (void *address, size_t nbytes, enum uio_rw rwflag, uio_t * uio_p)
+{
+ int err;
+
+#undef uiomove
+ err = uiomove (address, nbytes, uio_p);
+
+ return err;
+}
+
+#undef timeout
+#undef untimeout
+
+typedef struct tmout_desc
+{
+ volatile int active;
+ int timestamp;
+ void (*func) (void *);
+ void *arg;
+
+ struct callout_handle timer;
+} tmout_desc_t;
+
+static volatile int next_id = 0;
+#define MAX_TMOUTS 128
+
+tmout_desc_t tmouts[MAX_TMOUTS] = { {0} };
+
+int timeout_random = 0x12123400;
+
+void
+oss_timer_callback (void *arg)
+{
+ int ix;
+ tmout_desc_t *tmout = arg;
+
+ timeout_random++;
+
+ if (!tmout->active)
+ return;
+
+ arg = tmout->arg;
+ tmout->active = 0;
+ tmout->timestamp = 0;
+
+ tmout->func (arg);
+}
+
+timeout_id_t
+oss_timeout (void (*func) (void *), void *arg, unsigned long long ticks)
+{
+ tmout_desc_t *tmout = NULL;
+ int id, n;
+
+ timeout_random++;
+
+ n = 0;
+ id = -1;
+
+ while (id == -1 && n < MAX_TMOUTS)
+ {
+ if (!tmouts[next_id].active)
+ {
+ tmouts[next_id].active = 1;
+ id = next_id++;
+ tmout = &tmouts[id];
+ break;
+ }
+
+ next_id = (next_id + 1) % MAX_TMOUTS;
+ }
+
+ if (id == -1) /* No timer slots available */
+ {
+ cmn_err (CE_CONT, "Timeout table full\n");
+ return 0;
+ }
+
+ tmout->func = func;
+ tmout->arg = arg;
+ tmout->timestamp = id | (timeout_random & ~0xff);
+
+ tmout->timer = timeout (oss_timer_callback, tmout, ticks);
+
+ return id | (timeout_random & ~0xff);
+}
+
+void
+oss_untimeout (timeout_id_t id)
+{
+ tmout_desc_t *tmout;
+ int ix;
+
+ ix = id & 0xff;
+ if (ix < 0 || ix >= MAX_TMOUTS)
+ return;
+
+ timeout_random++;
+ tmout = &tmouts[ix];
+
+ if (tmout->timestamp != id) /* Expired timer */
+ return;
+ if (tmout->active)
+ untimeout (oss_timer_callback, tmout, tmout->timer);
+ tmout->active = 0;
+ tmout->timestamp = 0;
+}
+
+int
+oss_get_procinfo (int what)
+{
+ switch (what)
+ {
+ case OSS_GET_PROCINFO_UID:
+ return oss_get_uid();
+ }
+
+ return EINVAL;
+}
+
+unsigned long
+oss_get_time (void)
+{
+ struct timeval timecopy;
+
+ getmicrotime (&timecopy);
+ return timecopy.tv_usec / (1000000 / hz) + (u_long) timecopy.tv_sec * hz;
+}
+
+caddr_t
+oss_map_pci_mem (oss_device_t * osdev, int nr, int paddr, int psize)
+{
+ void *vaddr = 0;
+ u_int32_t poffs;
+
+ poffs = paddr - trunc_page (paddr);
+ vaddr = (caddr_t) pmap_mapdev (paddr - poffs, psize + poffs) + poffs;
+
+ return vaddr;
+}
+
+void
+oss_pci_byteswap (oss_device_t * osdev, int mode)
+{
+ // NOP
+}
+
+void
+oss_pcie_init (oss_device_t * osdev, int flags)
+{
+ /* TODO: Should we do something? */
+}
+
+static time_t
+oss_get_walltime (void)
+{
+ struct timeval timecopy;
+
+ getmicrotime (&timecopy);
+ return timecopy.tv_sec;
+}
+
+int
+soundcard_attach (void)
+{
+ oss_device_t *osdev;
+
+ if ((osdev = PMALLOC (NULL, sizeof (*osdev))) == NULL)
+ {
+ return ENOSPC;
+ }
+
+ memset (osdev, 0, sizeof (*osdev));
+ core_osdev = osdev;
+
+#ifdef LICENSED_VERSION
+ if (!oss_license_handle_time (oss_get_walltime ()))
+ {
+ 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
+
+ osdev->major = oss_major;
+ oss_register_device (osdev, "OSS core services");
+
+ oss_common_init (osdev);
+
+ return 0;
+}
+
+int
+soundcard_detach (void)
+{
+ int i;
+
+ if (refcount > 0 || open_devices > 0)
+ return EBUSY;
+
+ oss_unload_drivers ();
+
+ osdev_delete (core_osdev);
+
+ for (i = 0; i < nmemblocks; i++)
+ KERNEL_FREE (memblocks[i]);
+ nmemblocks = 0;
+
+ return 0;
+}
+
+static void
+init_fileinfo (struct fileinfo *fi, int flags)
+{
+ memset (fi, 0, sizeof (*fi));
+ if ((flags & FREAD) && (flags & FWRITE))
+ fi->mode = OPEN_READWRITE;
+ else if (flags & FREAD)
+ fi->mode = OPEN_READ;
+ else if (flags & FWRITE)
+ fi->mode = OPEN_WRITE;
+ fi->acc_flags = flags;
+ fi->pid = -1;
+ fi->dev = -1;
+ fi->cmd = NULL;
+}
+
+static int
+oss_read (struct cdev *bsd_dev, struct uio *buf, int flags)
+{
+ int retval;
+ int dev;
+ oss_cdev_t *cdev;
+#ifndef VDEV_SUPPORT
+ struct fileinfo _fi, * fi = &_fi;
+ dev = MINOR (bsd_dev);
+ init_fileinfo (fi, flags);
+#else
+ struct fileinfo * fi;
+ if (oss_file_get_private ((void **)&fi)) return ENXIO;
+ dev = fi->dev;
+#endif
+
+ if (dev >= oss_num_cdevs)
+ return ENXIO;
+
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d == NULL)
+ return ENXIO;
+
+ if (cdev->d->read == NULL)
+ {
+ return ENODEV;
+ }
+
+ retval = cdev->d->read (cdev->instance, fi, buf, buf->uio_resid);
+ if (retval < 0)
+ return -retval;
+ return 0;
+
+}
+
+static int
+oss_write (struct cdev *bsd_dev, struct uio *buf, int flags)
+{
+ int retval;
+ int dev;
+ oss_cdev_t *cdev;
+#ifndef VDEV_SUPPORT
+ struct fileinfo _fi, * fi = &_fi;
+ dev = MINOR (bsd_dev);
+ init_fileinfo (fi, flags);
+#else
+ struct fileinfo * fi;
+ if (oss_file_get_private ((void **)&fi)) return ENXIO;
+ dev = fi->dev;
+#endif
+
+ if (dev >= oss_num_cdevs)
+ return ENXIO;
+
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d == NULL)
+ return ENXIO;
+
+ if (cdev->d->write == NULL)
+ {
+ return ENODEV;
+ }
+
+ retval = cdev->d->write (cdev->instance, fi, buf, buf->uio_resid);
+ if (retval < 0)
+ return -retval;
+ return 0;
+}
+
+static int
+oss_open (struct cdev *bsd_dev, int flags, int mode, struct thread *p)
+{
+ int dev = MINOR (bsd_dev);
+ oss_cdev_t *cdev;
+ struct fileinfo fi;
+ int tmpdev, retval;
+
+ if (dev >= oss_num_cdevs)
+ return ENXIO;
+
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d == NULL)
+ return ENXIO;
+
+ if (cdev->d->open == NULL)
+ {
+ return ENODEV;
+ }
+
+ init_fileinfo (&fi, flags);
+ fi.pid = p->td_proc->p_pid;
+ fi.cmd = p->td_proc->p_comm;
+ tmpdev = dev;
+
+ retval =
+ cdev->d->open (cdev->instance, cdev->dev_class, &fi, 0, 0, &tmpdev);
+
+ if (tmpdev != -1) fi.dev = tmpdev;
+ else fi.dev = dev;
+ if (retval < 0)
+ return -retval;
+
+#ifdef VDEV_SUPPORT
+ if (oss_file_set_private (p, (void *)&fi, sizeof (struct fileinfo)))
+ return ENXIO;
+#endif
+
+ open_devices++;
+ return 0;
+}
+
+static int
+oss_close (struct cdev *bsd_dev, int flags, int mode, struct thread *p)
+{
+ int dev;
+ oss_cdev_t *cdev;
+#ifndef VDEV_SUPPORT
+ struct fileinfo _fi, * fi = &_fi;
+ dev = MINOR (bsd_dev);
+ init_fileinfo (fi, flags);
+#else
+ struct fileinfo * fi;
+ if (oss_file_get_private ((void **)&fi)) return ENXIO;
+ dev = fi->dev;
+#endif
+
+ if (dev >= oss_num_cdevs)
+ return ENXIO;
+
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d == NULL)
+ return ENXIO;
+
+ if (cdev->d->close == NULL)
+ {
+ return ENODEV;
+ }
+
+ cdev->d->close (cdev->instance, fi);
+ open_devices--;
+ return 0;
+}
+
+static int
+oss_ioctl (struct cdev *bsd_dev, u_long cmd, caddr_t arg, int mode,
+ struct thread *p)
+{
+ int retval;
+ int dev;
+ oss_cdev_t *cdev;
+#ifndef VDEV_SUPPORT
+ struct fileinfo _fi, * fi = &_fi;
+ dev = MINOR (bsd_dev);
+ init_fileinfo (fi, mode);
+#else
+ struct fileinfo * fi;
+ if (oss_file_get_private ((void **)&fi)) return ENXIO;
+ dev = fi->dev;
+#endif
+
+ if (dev >= oss_num_cdevs)
+ return ENXIO;
+
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d == NULL)
+ return ENXIO;
+
+ if (cdev->d->ioctl == NULL)
+ {
+ return ENODEV;
+ }
+
+ switch (cmd)
+ {
+ /*
+ * FreeBSD uses these ioctls to (un)set nonblocking I/O for devices. e.g.
+ * in case of fcntl (fd, F_SETFL, O_RDONLY|O_NONBLOCK) it will fire
+ * both ioctls.
+ * We deal with them here, and not in oss_audio_core because struct file
+ * isn't available in oss_audio_ioctl and we want the flags to remain
+ * accurate. oss_audio_core checks for O_NONBLOCK, and will pick
+ * up the change next read/write.
+ */
+ case FIONBIO:
+ if (arg != NULL)
+ {
+ if (*arg) fi->acc_flags |= O_NONBLOCK;
+ else fi->acc_flags &= ~O_NONBLOCK;
+ }
+ case FIOASYNC:
+ return 0;
+ default: break;
+ }
+
+ retval = cdev->d->ioctl (cdev->instance, fi, cmd, (ioctl_arg) arg);
+ if (retval < 0)
+ return -retval;
+ return 0;
+}
+
+static int
+oss_poll (struct cdev *bsd_dev, int events, struct thread *p)
+{
+ int retval;
+ int dev;
+ oss_cdev_t *cdev;
+ oss_poll_event_t ev;
+ int err;
+#ifndef VDEV_SUPPORT
+ struct fileinfo _fi, * fi = &_fi;
+ dev = MINOR (bsd_dev);
+ init_fileinfo (fi, 0);
+#else
+ struct fileinfo * fi;
+ if (oss_file_get_private ((void **)&fi)) return ENXIO;
+ dev = fi->dev;
+#endif
+
+ if (dev >= oss_num_cdevs)
+ return ENXIO;
+
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d == NULL)
+ return ENXIO;
+
+ if (cdev->d->chpoll == NULL)
+ {
+ return ENODEV;
+ }
+
+ ev.events = events;
+ ev.revents = 0;
+ ev.p = p;
+ ev.bsd_dev = bsd_dev;
+
+ err = cdev->d->chpoll (cdev->instance, fi, &ev);
+ if (err < 0)
+ {
+ return -err;
+ }
+ return ev.revents;
+}
+
+#if defined(D_VERSION_03) && (D_VERSION == D_VERSION_03)
+static int
+oss_mmap (struct cdev *bsd_dev, vm_ooffset_t offset, vm_paddr_t * paddr,
+ int nprot, vm_memattr_t *memattr)
+#else
+static int
+oss_mmap (struct cdev *bsd_dev, vm_offset_t offset, vm_paddr_t * paddr,
+ int nprot)
+#endif
+{
+ int retval;
+ int dev;
+ oss_cdev_t *cdev;
+ oss_poll_event_t ev;
+ dmap_p dmap = NULL;
+ int err;
+#ifndef VDEV_SUPPORT
+ dev = MINOR (bsd_dev);
+#else
+ struct fileinfo * fi;
+ if (oss_file_get_private ((void **)&fi)) return ENXIO;
+ dev = fi->dev;
+#endif
+
+ if (dev >= oss_num_cdevs)
+ return ENXIO;
+
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d == NULL)
+ return ENXIO;
+
+ if (nprot & PROT_EXEC)
+ return EACCES;
+
+ if ((cdev->dev_class != OSS_DEV_DSP) &&
+ (cdev->dev_class != OSS_DEV_DSP_ENGINE)) /* Only mmapable devices */
+ {
+ cmn_err (CE_NOTE, "mmap() is only possible with DSP devices (%d)\n",
+ cdev->dev_class);
+ return EINVAL;
+ }
+
+ dev = cdev->instance;
+
+ if (dev < 0 || dev >= num_audio_engines)
+ return ENODEV;
+
+ if (nprot & PROT_WRITE)
+ dmap = audio_engines[dev]->dmap_out;
+ else
+ dmap = audio_engines[dev]->dmap_in;
+
+ if (dmap == NULL)
+ return EIO;
+
+ if (dmap->dmabuf_phys == 0)
+ return EIO;
+
+ if (dmap->flags & DMAP_COOKED)
+ {
+ cmn_err (CE_WARN,
+ "mmap() not possible with currently selected sample format.\n");
+ return EIO;
+ }
+
+ dmap->mapping_flags |= DMA_MAP_MAPPED;
+ *paddr = dmap->dmabuf_phys + offset;
+
+ return 0;
+}
+
+oss_device_t *
+osdev_create (dev_info_t * dip, int dev_type, int instance, const char *nick,
+ const char *handle)
+{
+ oss_device_t *osdev = NULL;
+ int i, err;
+ caddr_t addr;
+ off_t region_size;
+
+ if (handle == NULL)
+ handle = nick;
+
+ /*
+ * Don't accept any more drivers if expired
+ */
+ if (oss_expired && oss_num_cards > 0)
+ return NULL;
+
+ for (i = 0; i < oss_num_cards; i++)
+ {
+ if (cards[i]->dip == dip)
+ {
+ osdev = cards[i];
+ break;
+ }
+ }
+
+ if (osdev == NULL)
+ {
+ if (oss_num_cards >= MAX_CARDS)
+ {
+ cmn_err (CE_WARN, "Too many OSS devices. At most %d permitted.\n",
+ MAX_CARDS);
+ return NULL;
+ }
+
+ if ((osdev = PMALLOC (NULL, sizeof (*osdev))) == NULL)
+ {
+ cmn_err (CE_WARN, "osdev_create: Out of memory\n");
+ return NULL;
+ }
+
+ osdev->cardnum = oss_num_cards;
+ cards[oss_num_cards++] = osdev;
+ }
+
+ osdev->dip = dip;
+ osdev->osid = dip;
+ osdev->available = 1;
+ osdev->instance = instance;
+ osdev->dev_type = dev_type;
+ osdev->devc = NULL;
+ osdev->first_mixer = -1;
+ sprintf (osdev->nick, "%s%d", nick, instance);
+ strcpy (osdev->modname, nick);
+
+/*
+ * Create the device handle
+ */
+ switch (dev_type)
+ {
+ case DRV_PCI:
+ {
+ sprintf (osdev->handle, "OSS-PCI");
+ }
+ 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)
+ {
+ if (oss_cdevs[i]->info != NULL)
+ destroy_dev (oss_cdevs[i]->info);
+ oss_cdevs[i]->d = NULL;
+ oss_cdevs[i]->info = NULL;
+ oss_cdevs[i]->osdev = NULL;
+ strcpy (oss_cdevs[i]->name, "Removed device");
+ }
+}
+
+void *
+oss_get_osid (oss_device_t * osdev)
+{
+ return osdev->osid;
+}
+
+void
+oss_inc_intrcount (oss_device_t * osdev, int claimed)
+{
+ osdev->intrcount++;
+
+ if (claimed)
+ osdev->ackcount++;
+}
diff --git a/kernel/OS/FreeBSD/os_freebsd.h b/kernel/OS/FreeBSD/os_freebsd.h
new file mode 100644
index 0000000..161a2e3
--- /dev/null
+++ b/kernel/OS/FreeBSD/os_freebsd.h
@@ -0,0 +1,263 @@
+#ifndef _OS_H_
+#define _OS_H_
+
+/*
+ * Purpose: OS specific definitions for FreeBSD
+ *
+ */
+/*
+ *
+ * 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.
+ *
+ */
+#define OS_VERSION "6"
+#define __inline__ inline
+#define __inline inline
+#define EXTERN_C extern "C"
+
+/*
+ * Debugging and misc settings
+ */
+#undef MUTEX_CHECKS
+#undef MEMDEBUG
+
+#if (!defined(__i386__) && !defined(__x86_64__)) || defined(CONFIG_OSS_FIXDEPOINT)
+// Floating point is not supported or it's disabled
+#undef CONFIG_OSS_VMIX_FLOAT
+#endif
+
+/*
+ * Disable support for per-application features such as /dev/dsp device
+ * selection based on command name. Requires working GET_PROCESS_NAME
+ * macro implementation.
+ */
+#undef APPLIST_SUPPORT
+#define USE_DEVICE_SUBDIRS
+
+#include <stdarg.h>
+#include <sys/types.h>
+#ifdef _KERNEL
+#include <sys/systm.h>
+#endif
+#include <sys/param.h>
+#include <sys/uio.h>
+#include <sys/fcntl.h>
+#include <sys/poll.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/kernel.h>
+#include <machine/cpufunc.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <sys/selinfo.h>
+#include <oss_errno.h>
+
+#if __FreeBSD_version >= 800062
+#define MINOR(x) dev2unit(x)
+#else
+#define MINOR(x) minor(x)
+#endif
+
+#undef timeout
+#define timeout oss_timeout
+#undef untimeout
+#define untimeout oss_untimeout
+typedef int timeout_id_t;
+extern timeout_id_t oss_timeout (void (*func) (void *), void *arg,
+ unsigned long long ticks);
+extern void oss_untimeout (timeout_id_t id);
+
+#include "kernel/OS/FreeBSD/wrapper/bsddefs.h"
+
+#ifdef USE_SX_LOCK
+#include <sys/proc.h> /* XXX for curthread */
+#include <sys/sx.h>
+#else
+#include <sys/mutex.h>
+#endif
+
+
+#define uiomove oss_uiomove
+typedef struct uio uio_t;
+extern int oss_uiomove (void *address, size_t nbytes, enum uio_rw rwflag,
+ uio_t * uio_p);
+
+#undef HZ
+#define OSS_HZ hz
+
+/* The soundcard.h could be in a nonstandard place so include it here. */
+#include "soundcard.h"
+
+typedef struct udi_usb_devc udi_usb_devc;
+
+#define ALLOW_SELECT
+#define ALLOW_BUFFER_MAPPING
+
+/*
+ * Sleep/wakeup
+ */
+
+#ifdef _KERNEL
+struct oss_wait_queue
+{
+ oss_mutex_t mutex;
+ unsigned long flags;
+ struct selinfo poll_info;
+};
+#endif
+
+/* Busy wait routine */
+
+/* System wall timer access */
+extern unsigned long oss_get_time (void);
+#define GET_JIFFIES() oss_get_time()
+
+/*
+ * Mutexes
+ */
+
+#ifdef USE_SX_LOCK
+struct sx;
+#define MUTEX_INIT(osdev, mutex, hier) \
+do { \
+ mutex = malloc(sizeof(*mutex), M_DEVBUF, M_WAITOK | M_ZERO); \
+ sx_init(mutex, "oss"); \
+} while (0)
+#define MUTEX_CLEANUP(mutex) \
+do { \
+ sx_destroy(mutex); \
+ free(mutex, M_DEVBUF); \
+} while (0)
+#define MUTEX_ENTER_IRQDISABLE(mutex, flags) sx_xlock(mutex)
+#define MUTEX_ENTER(mutex, flags) sx_slock(mutex)
+#define MUTEX_EXIT_IRQRESTORE(mutex, flags) sx_xunlock(mutex)
+#define MUTEX_EXIT(mutex, flags) sx_sunlock(mutex)
+#else /* !USE_SX_LOCK */
+struct mtx;
+#define MUTEX_INIT(osdev, mutex, hier) \
+do { \
+ mutex = malloc(sizeof(*mutex), M_DEVBUF, M_WAITOK | M_ZERO); \
+ mtx_init(mutex, "oss", NULL, MTX_RECURSE | MTX_SPIN); \
+} while (0)
+#define MUTEX_CLEANUP(mutex) \
+do { \
+ mtx_destroy(mutex); \
+ free(mutex, M_DEVBUF); \
+} while (0)
+#define MUTEX_ENTER_IRQDISABLE(mutex, flags) mtx_lock_spin_flags(mutex, flags)
+#define MUTEX_ENTER(mutex, flags) mtx_lock_spin(mutex)
+#define MUTEX_EXIT_IRQRESTORE(mutex, flags) mtx_unlock_spin_flags(mutex, flags)
+#define MUTEX_EXIT(mutex, flags) mtx_unlock_spin(mutex)
+#endif /* USE_SX_LOCK */
+
+
+/*
+ * INB() and OUTB() should be obvious. NOTE! The order of
+ * paratemeters of OUTB() is different than on some other
+ * operating systems.
+ */
+
+/* I/O Mapped devices */
+#define INB(o, p) inb(p)
+#define INW(o, p) inw(p)
+#define INL(o, p) inl(p)
+
+#define OUTB(o, v, p) outb(p,v)
+#define OUTW(o, v, p) outw(p,v)
+#define OUTL(o, v, p) outl(p,v)
+
+/* Memory Mapped devices */
+#define PCI_READL(osp, p) readl(p)
+#define PCI_READW(osp, p) readw(p)
+#define PCI_READB(osp, p) readb(p)
+#define PCI_WRITEL(osp, addr, data) writel(addr, data)
+#define PCI_WRITEW(osp, addr, data) writew(addr, data)
+#define PCI_WRITEB(osp, addr, data) writeb(addr, data)
+
+typedef void *oss_dma_handle_t;
+
+/*
+ KERNEL_MALLOC() allocates requested number of memory and
+ KERNEL_FREE is used to free it.
+ These macros are never called from interrupt, in addition the
+ nbytes will never be more than 4096 bytes. Generally the driver
+ will allocate memory in blocks of 4k. If the kernel has just a
+ page level memory allocation, 4K can be safely used as the size
+ (the nbytes parameter can be ignored).
+*/
+#define KERNEL_MALLOC(nbytes) malloc(nbytes, M_DEVBUF, M_NOWAIT|M_ZERO)
+#define KERNEL_FREE(addr) {if (addr)free(addr, M_DEVBUF);addr=NULL;}
+
+#define CONTIG_MALLOC(osdev, sz, memlimit, phaddr, handle) oss_contig_malloc(sz, memlimit, phaddr)
+#define CONTIG_FREE(osdev, p, sz, handle) oss_contig_free(p, sz)
+
+/*
+ * Timer macros
+ *
+ * These macros are obsolete and should not be used in any new code.
+ * Use the timeout mechanism (see the timeout(9F) Solaris man page).
+ */
+#define DEFINE_TIMER(name, proc) static timeout_id_t name = 0
+#define REMOVE_TIMER(name, proc) {if (name != 0) untimeout(name);}
+#define INIT_TIMER(name,proc)
+typedef void (*timeout_func_t) (void *);
+#define ACTIVATE_TIMER(name, proc, time) \
+ name=timeout((timeout_func_t)proc, (void*)&name, time)
+#endif
+
+struct fileinfo
+{
+ int mode; /* Open mode */
+ int acc_flags;
+ int pid;
+ int dev;
+ char *cmd;
+};
+#define ISSET_FILE_FLAG(fileinfo, flag) (fileinfo->acc_flags & (flag) ? 1:0)
+
+#define OSS_OS "FreeBSD"
+#define OSS_OS_LONGNAME "FreeBSD " OS_VERSION
+
+typedef void (*softintr_func_t) (int);
+
+struct oss_softintr
+{
+ int id;
+ softintr_func_t func;
+ volatile int armed, running;
+};
+
+struct _oss_poll_event_t
+{
+ short events, revents;
+ struct thread *p;
+ struct cdev *bsd_dev;
+};
+typedef struct _oss_poll_event_t oss_poll_event_t;
+
+extern int detect_trace;
+#define DDB(x) if (detect_trace) x
+
+extern caddr_t oss_map_pci_mem (oss_device_t * osdev, int nr, int phaddr,
+ int size);
+#define MAP_PCI_IOADDR(osdev, nr, io) (oss_native_word)(io)
+#define MAP_PCI_MEM(osdev, ix, phaddr, size) oss_map_pci_mem(osdev, ix, phaddr, size)
+#define UNMAP_PCI_MEM(osdev, ix, ph, virt, size) {}
+#define UNMAP_PCI_IOADDR(osdev, ix) {}
+
+#define GET_PROCESS_PID(f) f->pid
+#define GET_PROCESS_NAME(f) f->cmd
+
+#define abs(x) ((x) >= 0 ? (x) : -(x))
+
+/*
+ * PCI config space access (in os.c)
+ */
+extern char *oss_pci_read_devpath (dev_info_t * dip);
diff --git a/kernel/OS/FreeBSD/wrapper/bsddefs.h b/kernel/OS/FreeBSD/wrapper/bsddefs.h
new file mode 100644
index 0000000..c22965c
--- /dev/null
+++ b/kernel/OS/FreeBSD/wrapper/bsddefs.h
@@ -0,0 +1,150 @@
+/*
+ * Purpose: Definitions for routines and variables exported by osscore.c
+ *
+ * Do not make any modifications to these settings because OSS core modules
+ * have been compiled against them. Full rebuild of OSS will be required if
+ * this file is changed.
+ */
+/*
+ *
+ * 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 <sys/types.h>
+#if 0 /* __FreeBSD_version >= 700031 */
+/* Some crashes have been reported with SX on 7-STABLE/8-CURRENT:
+ * http://4front-tech.com/forum/viewtopic.php?t=2718
+ * http://4front-tech.com/forum/viewtopic.php?t=2563
+ */
+#define USE_SX_LOCK 1
+#endif
+#undef VDEV_SUPPORT
+#if __FreeBSD_version >= 700111
+#define VDEV_SUPPORT
+extern int oss_file_set_private (struct thread *p, void *v, size_t l);
+extern int oss_file_get_private (void **v);
+#endif
+extern int oss_get_uid (void);
+
+typedef struct device dev_info_t;
+typedef long long oss_int64_t; /* Signed 64 bit integer */
+typedef unsigned long long oss_uint64_t; /* Unsigned 64 bit integer */
+typedef unsigned long offset_t;
+
+/*
+ * Some integer types
+ */
+#if defined(__amd64__)
+typedef unsigned long long oss_native_word; /* Same as the address and status register size */
+#else
+typedef unsigned long oss_native_word; /* Same as the address and status register size */
+#endif
+
+struct _oss_device_t
+{
+ int cardnum;
+ int dev_type;
+ int instance;
+ int available;
+ dev_info_t *dip;
+ void *osid;
+ void *devc;
+ char *name;
+ char *hw_info;
+ int major;
+ char nick[16];
+ char modname[16];
+ char handle[32];
+ int num_audio_engines;
+ int num_audioplay, num_audiorec, num_audioduplex;
+ int num_mididevs;
+ int num_mixerdevs;
+ int num_loopdevs;
+ int first_mixer; /* This must be set to -1 by osdev_create() */
+
+ int intrcount;
+ int ackcount;
+ volatile int refcount; /* Nonzero means that the device is needed by some other (virtual) driver. */
+
+};
+
+extern void cmn_err (int level, char *format, ...);
+#define CE_CONT 0
+#define CE_NOTE 1
+#define CE_WARN 2
+#define CE_PANIC 3
+
+#ifdef USE_SX_LOCK
+typedef struct sx *oss_mutex_t;
+#else
+typedef struct mtx *oss_mutex_t;
+#endif
+
+typedef int ddi_iblock_cookie_t;
+
+extern void oss_udelay (unsigned long t);
+
+#ifdef _KERNEL
+#define memset oss_memset
+extern void *oss_memset (void *t, int val, int l);
+#endif
+
+extern oss_device_t *osdev_create (dev_info_t * dip, int dev_type,
+ int instance, const char *nick,
+ const char *handle);
+extern void osdev_delete (oss_device_t * osdev);
+
+extern char *oss_pci_read_devpath (dev_info_t * dip);
+extern int pci_read_config_byte (oss_device_t * osdev, offset_t where,
+ unsigned char *val);
+extern int pci_read_config_irq (oss_device_t * osdev, offset_t where,
+ unsigned char *val);
+extern int pci_read_config_word (oss_device_t * osdev, offset_t where,
+ unsigned short *val);
+extern int pci_read_config_dword (oss_device_t * osdev, offset_t where,
+ unsigned int *val);
+extern int pci_write_config_byte (oss_device_t * osdev, offset_t where,
+ unsigned char val);
+extern int pci_write_config_word (oss_device_t * osdev, offset_t where,
+ unsigned short val);
+extern int pci_write_config_dword (oss_device_t * osdev, offset_t where,
+ unsigned int val);
+#ifndef OSS_CONFIG_H
+/* These definitions must match with oss_config.h */
+typedef int (*oss_tophalf_handler_t) (struct _oss_device_t * osdev);
+typedef void (*oss_bottomhalf_handler_t) (struct _oss_device_t * osdev);
+#endif
+
+extern int oss_register_interrupts (oss_device_t * osdev, int intrnum,
+ oss_tophalf_handler_t top,
+ oss_bottomhalf_handler_t bottom);
+extern void oss_unregister_interrupts (oss_device_t * osdev);
+
+extern void *oss_contig_malloc (unsigned long sz, unsigned long memlimit,
+ oss_native_word * phaddr);
+extern void oss_contig_free (void *p, unsigned long sz);
+
+extern void oss_register_module (char *name);
+extern void oss_unregister_module (char *name);
+extern void *oss_find_minor_info (int dev_class, int instance);
+extern int oss_find_minor (int dev_class, int instance);
+extern void oss_inc_intrcount (oss_device_t * osdev, int claimed);
+
+#define FP_SUPPORT
+
+#ifdef FP_SUPPORT
+typedef short fp_env_t[512];
+typedef unsigned int fp_flags_t[4];
+extern int oss_fp_check (void);
+extern void oss_fp_save (short *envbuf, fp_flags_t flags);
+extern void oss_fp_restore (short *envbuf, fp_flags_t flags);
+# define FP_SAVE(envbuf, flags) oss_fp_save(envbuf, flags)
+# define FP_RESTORE(envbuf, flags) oss_fp_restore(envbuf, flags)
+#endif
diff --git a/kernel/OS/Linux/.config b/kernel/OS/Linux/.config
new file mode 100644
index 0000000..816ac62
--- /dev/null
+++ b/kernel/OS/Linux/.config
@@ -0,0 +1 @@
+mode=kernel
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);
+}
diff --git a/kernel/OS/Linux/os_linux.h b/kernel/OS/Linux/os_linux.h
new file mode 100644
index 0000000..d881859
--- /dev/null
+++ b/kernel/OS/Linux/os_linux.h
@@ -0,0 +1,287 @@
+#ifndef _OS_H_
+#define _OS_H_
+
+/*
+ * Purpose: OS specific definitions for Linux
+ *
+ * Under Linux os.h (this file) defines just the macros, functions and
+ * structures used by the code compiled in the development system. However
+ * there are other Linux specific definitions contained in {!nlink Linux/wrap.h}
+ * that are used both by the code compiled in the devlopment and target systems.
+ * This means that some definitions found in os.h under some other operating
+ * systems may be in wrap.h under 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.
+ *
+ */
+
+#define OS_VERSION "2.6.x"
+#define __EXTENDED__
+#define OSS_MAINLINE_BUILD
+
+/*
+ * Debugging and misc settings
+ */
+#undef MUTEX_CHECKS
+#undef MEMDEBUG
+#define VDEV_SUPPORT
+
+#if (!defined(__i386__) && !defined(__x86_64__)) || defined(CONFIG_OSS_FIXDEPOINT)
+// Floating point is not supported or it's disabled
+#undef CONFIG_OSS_VMIX_FLOAT
+#endif
+
+/*
+ * Disable support for per-application features such as /dev/dsp device
+ * selection based on command name. Requires working GET_PROCESS_NAME
+ * macro implementation.
+ */
+
+#undef APPLIST_SUPPORT
+#define USE_DEVICE_SUBDIRS
+#define EXTERN_C
+
+#define __invalid_size_argument_for_IOC 0 /* Dummy define to cure some broken ioctl.h versions */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/signal.h>
+#include <oss_errno.h>
+#include <sys/file.h>
+#include "oss_ddi.h"
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+#include <asm/poll.h>
+#include "kernel/OS/Linux/wrapper/wrap.h"
+
+#undef HZ
+extern int oss_hz;
+#define OSS_HZ oss_hz
+
+/* The soundcard.h could be in a nonstandard place so include it here. */
+#include "soundcard.h"
+
+struct _oss_device_t
+{
+ int cardnum;
+ int dev_type;
+ int available;
+ int instance;
+ dev_info_t *dip;
+ void *devc;
+ char *name;
+ char nick[16];
+ char handle[32];
+ int num_audio_engines;
+ int num_audioplay, num_audiorec, num_audioduplex;
+ int num_mididevs;
+ int num_mixerdevs;
+ int num_loopdevs;
+ int first_mixer; /* This must be set to -1 by osdev_create() */
+ int major;
+ struct module *owner; /* Pointer to THISMODULE (needed by osscore.c) */
+ char modname[32];
+ char *hw_info;
+
+ volatile int refcount; /* Nonzero means that the device is needed by some other (virtual) driver. */
+
+/* Interrupts */
+
+ ddi_iblock_cookie_t iblock_cookie; /* Dummy field under Linux */
+ void *irqparms;
+ int intrcount, ackcount;
+
+/* PCI related fields */
+
+#ifdef _KERNEL
+ ddi_acc_handle_t pci_config_handle;
+ ddi_acc_handle_t acc_handle;
+ int swap_mode; /* 0=DDI_STRUCTURE_NEVERSWAP_ACC, 1=DDI_STRUCTURE_LE_ACC */
+#endif
+};
+
+#define ALLOW_BUFFER_MAPPING
+#define ALLOW_SELECT
+#define SEL_IN 0
+#define SEL_OUT 1
+#define SEL_EX 0xffffffff
+
+/* Busy wait routine */
+#define oss_udelay drv_usecwait
+/* System wall timer access */
+#define GET_JIFFIES() oss_get_jiffies()
+
+extern inline unsigned int
+__inb (unsigned short port)
+{
+ unsigned int _v;
+ __asm__ __volatile__ ("in" "b" " %" "w" "1,%" "b" "0":"=a" (_v):"d" (port),
+ "0" (0));
+ return _v;
+}
+extern inline unsigned int
+__inw (unsigned short port)
+{
+ unsigned int _v;
+ __asm__ __volatile__ ("in" "w" " %" "w" "1,%" "w" "0":"=a" (_v):"d" (port),
+ "0" (0));
+ return _v;
+}
+extern inline unsigned int
+__inl (unsigned short port)
+{
+ unsigned int _v;
+ __asm__ __volatile__ ("in" "l" " %" "w" "1,%" "" "0":"=a" (_v):"d" (port));
+ return _v;
+}
+
+extern inline void
+__outb (unsigned char value, unsigned short port)
+{
+ __asm__ __volatile__ ("out" "b" " %" "b" "0,%" "w" "1"::"a" (value),
+ "d" (port));
+}
+extern inline void
+__outw (unsigned short value, unsigned short port)
+{
+ __asm__ __volatile__ ("out" "w" " %" "w" "0,%" "w" "1"::"a" (value),
+ "d" (port));
+}
+extern inline void
+__outl (unsigned int value, unsigned short port)
+{
+ __asm__ __volatile__ ("out" "l" " %" "0,%" "w" "1"::"a" (value),
+ "d" (port));
+}
+
+#define INB(osdev,a) __inb(a)
+#define INW(osdev,a) __inw(a)
+#define INL(osdev,a) __inl(a)
+
+#define OUTB(osdev, d, a) __outb(d, a)
+
+#define OUTW(osdev, d, a) __outw(d, a)
+#define OUTL(osdev, d, a) __outl(d, a)
+
+#define PCI_READL(osdev, p) (*(volatile unsigned int *) (p))
+#define PCI_WRITEL(osdev, addr, data) (*(volatile unsigned int *) (addr) = (data))
+#define PCI_READW(osdev, p) (*(volatile unsigned short *) (p))
+#define PCI_WRITEW(osdev, addr, data) (*(volatile unsigned short *) (addr) = (data))
+#define PCI_READB(osdev, p) (*(volatile unsigned char *) (p))
+#define PCI_WRITEB(osdev, addr, data) (*(volatile unsigned char *) (addr) = (data))
+
+/*
+ KERNEL_MALLOC() allocates requested number of memory and
+ KERNEL_FREE is used to free it.
+ These macros are never called from interrupt, in addition the
+ nbytes will never be more than 4096 bytes. Generally the driver
+ will allocate memory in blocks of 4k. If the kernel has just a
+ page level memory allocation, 4K can be safely used as the size
+ (the nbytes parameter can be ignored).
+*/
+#ifdef MEMDEBUG
+extern void *oss_kmem_alloc (size_t size, char *file, int line);
+extern void oss_kmem_free (void *addr);
+#define KERNEL_MALLOC(nbytes) oss_kmem_alloc(nbytes, __FILE__, __LINE__)
+#define KERNEL_FREE(addr) oss_kmem_free(addr)
+extern void *oss_contig_malloc (oss_device_t * osdev, int sz,
+ oss_uint64_t memlimit,
+ oss_native_word * phaddr, char *file,
+ int line);
+extern void oss_contig_free (oss_device_t * osdev, void *p, int sz);
+extern oss_native_word oss_virt_to_bus (void *addr);
+#define CONTIG_MALLOC(osdev, sz, memlimit, phaddr, handle) oss_contig_malloc(osdev, sz, memlimit, phaddr, __FILE__, __LINE__)
+#define CONTIG_FREE(osdev, p, sz, handle) oss_contig_free(osdev, p, sz)
+#else
+#define KERNEL_MALLOC(nbytes) oss_kmem_alloc(nbytes)
+#define KERNEL_FREE(addr) oss_kmem_free(addr)
+#define CONTIG_MALLOC(osdev, sz, memlimit, phaddr, handle) oss_contig_malloc(osdev, sz, memlimit, phaddr)
+#define CONTIG_FREE(osdev, p, sz, handle) oss_contig_free(osdev, p, sz)
+#endif
+
+/*
+ * Timer macros
+ *
+ * These macros are obsolete and should not be used in any new code.
+ * Use the timeout mechanism (see the timeout(9F) Solaris man page).
+ */
+#define DEFINE_TIMER(name, proc) static timeout_id_t name = 0
+#define REMOVE_TIMER(name, proc) {if (name != 0) oss_untimeout(name);}
+#define INIT_TIMER(name,proc)
+typedef void (*timeout_func_t) (void *);
+#define ACTIVATE_TIMER(name, proc, time) \
+ name=oss_timeout((timeout_func_t)proc, (void*)&name, time)
+
+#endif
+
+#define OSS_OS "Linux"
+#define OSS_OS_LONGNAME "Linux"
+
+#undef DMA_TRY_PSEUDOINIT
+
+int get_dma_residue (int chn);
+void disable_dma (int chn);
+void enable_dma (int chn);
+
+typedef void (*softintr_func_t) (int);
+
+struct oss_softintr
+{
+ int id;
+ softintr_func_t func;
+ volatile int armed, running;
+};
+
+#define MUTEX_INIT(osdev, mutex, hier) mutex=oss_mutex_init()
+#define MUTEX_CLEANUP(mutex) {oss_mutex_cleanup(mutex);mutex=NULL;}
+#define MUTEX_ENTER_IRQDISABLE(mutex, flags) flags=0;oss_spin_lock_irqsave(mutex, &flags)
+#define MUTEX_EXIT_IRQRESTORE(mutex, flags) oss_spin_unlock_irqrestore(mutex, flags);(flags)++
+#define MUTEX_ENTER(mutex, flags) flags=0;oss_spin_lock(mutex)
+#define MUTEX_EXIT(mutex, flags) oss_spin_unlock(mutex);(flags)++
+
+extern int detect_trace;
+#define DDB(x) if (detect_trace) x
+
+#define MAP_PCI_IOADDR(osdev, nr, io) (oss_native_word)io
+#define MAP_PCI_MEM(osdev, ix, phaddr, size) oss_map_pci_mem(osdev, size, phaddr)
+#define UNMAP_PCI_MEM(osdev, ix, ph, virt, size) oss_unmap_pci_mem(virt)
+#define UNMAP_PCI_IOADDR(osdev, ix) {}
+
+#define GET_PROCESS_PID(x) oss_get_pid()
+#define GET_PROCESS_UID(x) oss_get_uid()
+
+#define GET_PROCESS_NAME(x) oss_get_procname()
+
+#define pci_read_config_irq oss_pci_read_config_irq
+#define pci_read_config_byte oss_pci_read_config_byte
+#define pci_read_config_word oss_pci_read_config_word
+#define pci_read_config_dword oss_pci_read_config_dword
+#define pci_write_config_byte oss_pci_write_config_byte
+#define pci_write_config_word oss_pci_write_config_word
+#define pci_write_config_dword oss_pci_write_config_dword
+#define pci_enable_msi oss_pci_enable_msi
+
+#define VM_READ 0x1
+#define VM_WRITE 0x2
+
+#define FP_SUPPORT
+
+#ifdef FP_SUPPORT
+typedef short fp_env_t[512];
+typedef unsigned int fp_flags_t[4];
+extern int oss_fp_check (void);
+extern void oss_fp_save (short *envbuf, fp_flags_t flags);
+extern void oss_fp_restore (short *envbuf, fp_flags_t flags);
+# define FP_SAVE(envbuf, flags) oss_fp_save(envbuf, flags)
+# define FP_RESTORE(envbuf, flags) oss_fp_restore(envbuf, flags)
+#endif
+
+#include "oss_pci.h"
diff --git a/kernel/OS/Linux/oss_ddi.h b/kernel/OS/Linux/oss_ddi.h
new file mode 100644
index 0000000..36111fe
--- /dev/null
+++ b/kernel/OS/Linux/oss_ddi.h
@@ -0,0 +1,46 @@
+/*
+ * Purpose: Solaris compatible partial DDI interface for OSS/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.
+ *
+ */
+#ifndef NULL
+#define NULL 0
+#endif
+
+typedef int ddi_iblock_cookie_t;
+typedef int kmutex_t;
+typedef int cred_t;
+
+typedef int ddi_acc_handle_t;
+typedef int kcondvar_t;
+typedef int ddi_dma_handle_t;
+typedef int ddi_dma_cookie_t;
+typedef int ddi_dma_win_t;
+typedef int ddi_dma_seg_t;
+typedef int offset_t;
+typedef int ddi_info_cmd_t;
+typedef int ddi_attach_cmd_t;
+typedef int ddi_detach_cmd_t;
+
+#include <stdint.h>
+
+typedef struct _ddi_dma_attr_t
+{
+#define DMA_ATTR_V0 0
+ int a, b, c, d, e, f, g, h, i, j, k, l, m, n;
+} ddi_dma_attr_t;
+
+struct pollhead
+{
+ int dummy;
+};
diff --git a/kernel/OS/Linux/wrapper/.nomake b/kernel/OS/Linux/wrapper/.nomake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/kernel/OS/Linux/wrapper/.nomake
diff --git a/kernel/OS/Linux/wrapper/wrap.h b/kernel/OS/Linux/wrapper/wrap.h
new file mode 100644
index 0000000..0a3d3b9
--- /dev/null
+++ b/kernel/OS/Linux/wrapper/wrap.h
@@ -0,0 +1,288 @@
+/*
+ * Purpose: Wrapper routines for Linux kernel services
+ *
+ * The functions and structures declared here are part of the osscore.c
+ * file that is compiled in the target system. This file must not be
+ * modified in the target system because the precompiled binaries included
+ * in the OSS installation package depend on it too.
+ */
+/*
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Some integer types
+ */
+#if defined(__x86_64__)
+typedef unsigned long long oss_native_word; /* Same as the address and status register size */
+#else
+typedef unsigned long oss_native_word; /* Same as the address and status register size */
+#endif
+typedef long long oss_int64_t; /* Signed 64 bit integer */
+typedef unsigned long long oss_uint64_t; /* Unsigned 64 bit integer */
+
+extern char *oss_strcpy (char *s1, const char *s2);
+extern void *oss_memcpy (void *t_, const void *f_, size_t l);
+extern void *oss_memset (void *t, int val, size_t l);
+extern int oss_strcmp (const char *s1, const char *s2);
+extern size_t oss_strlen (const char *s);
+extern char *oss_strncpy (char *s1, const char *s2, size_t l);
+extern void oss_udelay (unsigned long d);
+
+typedef struct _oss_mutex_t *oss_mutex_t;
+typedef struct _poll_table_handle oss_poll_table_handle_t;
+typedef struct _file_handle_t oss_file_handle_t;
+
+struct _oss_poll_event_t
+{
+ short events, revents;
+ oss_poll_table_handle_t *wait;
+ oss_file_handle_t *file;
+};
+typedef struct _oss_poll_event_t oss_poll_event_t;
+
+extern oss_mutex_t oss_mutex_init (void);
+extern void oss_mutex_cleanup (oss_mutex_t mutex);
+extern void oss_spin_lock_irqsave (oss_mutex_t mutex,
+ oss_native_word * flags);
+extern void oss_spin_unlock_irqrestore (oss_mutex_t mutex,
+ oss_native_word flags);
+extern void oss_spin_lock (oss_mutex_t mutex);
+extern void oss_spin_unlock (oss_mutex_t mutex);
+extern unsigned long long oss_get_jiffies (void);
+extern char *oss_get_procname (void);
+extern int oss_get_pid (void);
+extern int oss_get_uid (void);
+
+struct oss_wait_queue;
+struct module;
+struct _oss_device_t;
+struct pci_dev;
+
+typedef void *oss_dma_handle_t; /* Unused type */
+
+/*
+ * Sleep/wakeup/poll support. These definitions are duplicates from
+ * oss_config.h which is the official place. Both definitions must match.
+ */
+
+extern struct oss_wait_queue *oss_create_wait_queue (oss_device_t * osdev,
+ const char *name);
+extern void oss_reset_wait_queue (struct oss_wait_queue *wq);
+extern void oss_remove_wait_queue (struct oss_wait_queue *wq);
+extern int oss_sleep (struct oss_wait_queue *wq, oss_mutex_t * mutex,
+ int ticks, oss_native_word * flags,
+ unsigned int *status);
+extern int oss_register_poll (struct oss_wait_queue *wq, oss_mutex_t * mutex,
+ oss_native_word * flags, oss_poll_event_t * ev);
+extern void oss_wakeup (struct oss_wait_queue *wq, oss_mutex_t * mutex,
+ oss_native_word * flags, short events);
+
+extern void oss_cmn_err (int level, const char *format, ...);
+#define CE_CONT 0
+#define CE_NOTE 1
+#define CE_WARN 2
+#define CE_PANIC 3
+
+typedef int timeout_id_t;
+extern timeout_id_t oss_timeout (void (*func) (void *), void *arg,
+ unsigned long long ticks);
+extern void oss_untimeout (timeout_id_t id);
+
+extern int sprintf (char *buf, const char *s, ...);
+
+typedef enum uio_rw
+{ UIO_READ, UIO_WRITE } uio_rw_t;
+struct uio
+{
+ char *ptr;
+ int resid;
+ int kernel_space; /* Set if this uio points to a kernel space buffer */
+ uio_rw_t rw;
+};
+typedef struct uio uio_t;
+
+extern int oss_uiomove (void *address, size_t nbytes, enum uio_rw rwflag,
+ uio_t * uio_p);
+extern int oss_create_uio (uio_t * uiop, char *buf, size_t count, uio_rw_t rw,
+ int is_kernel);
+extern void *oss_kmem_alloc (size_t size);
+extern void oss_kmem_free (void *addr);
+extern void *oss_pmalloc (size_t sz);
+extern oss_native_word oss_virt_to_bus (void *addr);
+extern void oss_reserve_pages (oss_native_word start_addr,
+ oss_native_word end_addr);
+extern void oss_unreserve_pages (oss_native_word start_addr,
+ oss_native_word end_addr);
+extern void *oss_contig_malloc (oss_device_t * osdev, int sz,
+ oss_uint64_t memlimit,
+ oss_native_word * phaddr);
+extern void oss_contig_free (oss_device_t * osdev, void *p, int sz);
+
+extern time_t oss_get_time (void);
+
+typedef struct _inode_handle_t oss_inode_handle_t;
+typedef struct _vm_aread_handle oss_vm_area_handle_t;
+
+extern int oss_vma_get_flags (oss_vm_area_handle_t *);
+
+typedef struct oss_file_operation_handle
+{
+ ssize_t (*read) (oss_file_handle_t *, char *, size_t, loff_t *);
+ ssize_t (*write) (oss_file_handle_t *, char *, size_t, loff_t *);
+ int (*readdir) (oss_inode_handle_t *, oss_file_handle_t *, void *, int);
+ unsigned int (*poll) (oss_file_handle_t *, oss_poll_table_handle_t *);
+ int (*ioctl) (oss_inode_handle_t *, oss_file_handle_t *, unsigned int,
+ unsigned long);
+ int (*mmap) (oss_file_handle_t *, oss_vm_area_handle_t *);
+ int (*open) (oss_inode_handle_t *, oss_file_handle_t *);
+ int (*release) (oss_inode_handle_t *, oss_file_handle_t *);
+ long (*compat_ioctl) (oss_file_handle_t *, unsigned int, unsigned long);
+ long (*unlocked_ioctl) (oss_file_handle_t *, unsigned int, unsigned long);
+ int (*fsync) (oss_inode_handle_t *, oss_file_handle_t *);
+ int (*fasync) (oss_inode_handle_t *, oss_file_handle_t *, int);
+}
+oss_file_operation_handle_t;
+
+extern int oss_do_mmap (oss_vm_area_handle_t * vma,
+ oss_native_word dmabuf_phys, int bytes_in_use);
+extern int oss_register_chrdev (oss_device_t * osdev, unsigned int major,
+ const char *name,
+ oss_file_operation_handle_t * op);
+extern void oss_register_minor (int major, int minor, char *name);
+extern int oss_unregister_chrdev (unsigned int major, const char *name);
+
+extern int oss_inode_get_minor (oss_inode_handle_t * inode);
+extern int oss_file_get_flags (oss_file_handle_t * file);
+extern void *oss_file_get_private (oss_file_handle_t * file);
+extern void oss_file_set_private (oss_file_handle_t * file, void *v);
+
+extern void oss_inc_refcounts (void);
+extern void oss_dec_refcounts (void);
+
+/*
+ * Redefinitions of some routines defined in oss_config.h
+ * just to ensure they are defined in the same way in both places. The
+ * osscore/wrapper modules only include wrap.h so they can't see the "official"
+ * declarations in oss_config.h.
+ */
+
+typedef struct _dev_info_t dev_info_t;
+extern dev_info_t *oss_create_pcidip (struct pci_dev *pcidev);
+extern oss_device_t *osdev_create (dev_info_t * dip, int dev_type,
+ int instance, const char *nick,
+ const char *handle);
+
+extern void osdev_delete (oss_device_t * osdev);
+
+/*
+ * PCI config space access (in osscore.c)
+ */
+extern char *oss_pci_read_devpath (dev_info_t * dip);
+extern int osscore_pci_read_config_byte (dev_info_t * dip, unsigned int where,
+ unsigned char *val);
+extern int osscore_pci_read_config_irq (dev_info_t * dip, unsigned int where,
+ unsigned char *val);
+extern int osscore_pci_read_config_word (dev_info_t * dip, unsigned int where,
+ unsigned short *val);
+extern int osscore_pci_read_config_dword (dev_info_t * dip,
+ unsigned int where,
+ unsigned int *val);
+extern int osscore_pci_write_config_byte (dev_info_t * dip,
+ unsigned int where,
+ unsigned char val);
+extern int osscore_pci_write_config_word (dev_info_t * dip,
+ unsigned int where,
+ unsigned short val);
+extern int osscore_pci_write_config_dword (dev_info_t * dip,
+ unsigned int where,
+ unsigned int val);
+
+extern int osscore_pci_enable_msi (dev_info_t * dip);
+
+extern void *oss_map_pci_mem (oss_device_t * osdev, int size,
+ unsigned long offset);
+
+extern void oss_unmap_pci_mem (void *addr);
+
+extern int oss_copy_to_user (void *to, const void *from, unsigned long n);
+extern int oss_copy_from_user (void *to, const void *from, unsigned long n);
+
+extern void oss_register_module (struct module *mod);
+extern void oss_unregister_module (struct module *mod);
+
+#ifdef _KERNEL
+extern char *oss_strcpy (char *s1, const char *s2);
+#undef strcpy
+#define strcpy oss_strcpy
+
+extern void *oss_memcpy (void *t_, const void *f_, size_t l);
+#undef memcpy
+#define memcpy oss_memcpy
+
+extern void *oss_memset (void *t, int val, size_t l);
+#undef memset
+#define memset oss_memset
+
+extern int oss_strcmp (const char *s1, const char *s2);
+#undef strcmp
+#define strcmp oss_strcmp
+extern int oss_strncmp (const char *s1, const char *s2, size_t len);
+#undef strncmp
+#define strncmp oss_strncmp
+
+#undef strlen
+#define strlen oss_strlen
+
+#undef strncpy
+#define strncpy oss_strncpy
+#endif // KERNEL
+
+#undef timeout
+#define timeout oss_timeout
+
+#undef untimeout
+#define untimeout oss_untimeout
+
+#define drv_usecwait oss_udelay
+
+#define uiomove oss_uiomove
+
+#define cmn_err oss_cmn_err
+
+struct fileinfo
+{
+ int mode; /* Open mode */
+ int acc_flags;
+};
+#define ISSET_FILE_FLAG(fileinfo, flag) (fileinfo->acc_flags & (flag) ? 1:0)
+
+/*
+ * USB related definitions
+ */
+typedef struct udi_usb_devc udi_usb_devc;
+
+/*
+ * Functions exported by os.c
+ */
+extern int oss_init_osscore (oss_device_t * osdev);
+extern void oss_uninit_osscore (oss_device_t * osdev);
+extern void osdev_set_owner (oss_device_t * osdev, struct module *owner);
+extern void osdev_set_major (oss_device_t * osdev, int major);
+extern void osdev_set_irqparms (oss_device_t * osdev, void *irqparms);
+extern void *osdev_get_irqparms (oss_device_t * osdev);
+extern void oss_inc_intrcount(oss_device_t *osdev, int claimed);
+extern struct module *osdev_get_owner (oss_device_t * osdev);
+extern char *osdev_get_nick (oss_device_t * osdev);
+extern int osdev_get_instance (oss_device_t * osdev);
+extern int oss_request_major (oss_device_t * osdev, int major, char *module);
+extern int oss_register_device (oss_device_t * osdev, const char *name); /* from oss_config.h */
+
diff --git a/kernel/OS/SCO_SV/.config b/kernel/OS/SCO_SV/.config
new file mode 100644
index 0000000..816ac62
--- /dev/null
+++ b/kernel/OS/SCO_SV/.config
@@ -0,0 +1 @@
+mode=kernel
diff --git a/kernel/OS/SCO_SV/module.inc b/kernel/OS/SCO_SV/module.inc
new file mode 100644
index 0000000..8891691
--- /dev/null
+++ b/kernel/OS/SCO_SV/module.inc
@@ -0,0 +1,277 @@
+/*
+ * Purpose: OSS module wrapper for SCO OpenServer/UnixWare
+ *
+ * This file will be included from the auto-generated drv_cfg.c files. Under
+ * UnixWare and OpenServer this will will be compiled during the initial build
+ * of OSS (in the development system).
+ */
+/*
+ *
+ * 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 <errno.h>
+
+static int ossdrv_config (cfg_func_t func, void *idata, rm_key_t key);
+#if DRIVER_TYPE==DRV_VIRTUAL || DRIVER_TYPE==DRV_VMIX
+oss_device_t *osdev = NULL;
+#endif
+/*
+ * Driver information structures, for drv_attach().
+ */
+static const drvops_t oss_ops = {
+ ossdrv_config,
+ oss_open,
+ oss_close,
+ oss_devinfo,
+ oss_biostart,
+ oss_ioctl,
+ NULL, /* drvctl */
+ NULL /* mmap */
+};
+
+static const drvinfo_t oss_drvinfo = {
+ &oss_ops,
+ DRIVER_NICK,
+ D_MP, /* MP-safe */
+ NULL, /* Not a STREAMS driver */
+ 256 /* Must match $maxchan in Node file */
+};
+
+static int
+rd_hex (char *s)
+{
+/*
+ * Convert a 4 digit hexadecimal string to integer value
+ */
+ int v = 0;
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ char c = *s++;
+
+ if (c >= '0' && c <= '9')
+ {
+ v = (v << 4) | (c - '0');
+ continue;
+ }
+
+ if (c >= 'A' && c <= 'F')
+ {
+ v = (v << 4) | (c - 'A' + 10);
+ continue;
+ }
+
+ if (c >= 'a' && c <= 'f')
+ {
+ v = (v << 4) | (c - 'a' + 10);
+ continue;
+ }
+ }
+
+ return v;
+}
+
+static int
+cfg_add (void *idata, rm_key_t key)
+{
+ int err;
+ cm_args_t cma;
+ cm_num_t btype;
+ char id[32];
+ int vendor, product;
+ static int instance = 0;
+ oss_device_t *osdev;
+
+ cm_begin_trans (key, RM_READ);
+ cma.cm_key = key;
+ cma.cm_param = CM_BRDBUSTYPE;
+ cma.cm_val = &btype;
+ cma.cm_vallen = sizeof (btype);
+ cma.cm_n = 0;
+ err = cm_getval (&cma);
+ cm_end_trans (key);
+
+ if (err != 0 || btype != CM_BUS_PCI)
+ {
+ cmn_err (CE_WARN, "Bad BUS type %d\n", btype);
+ return ENODEV;
+ }
+
+ if ((osdev =
+ osdev_create (&key, DRIVER_TYPE, instance, DRIVER_NICK, NULL)) == NULL)
+ {
+ return EIO;
+ }
+
+ cm_begin_trans (key, RM_READ);
+ cma.cm_key = key;
+ cma.cm_param = CM_BRDID;
+ cma.cm_val = id;
+ cma.cm_vallen = sizeof (id);
+ cma.cm_n = 0;
+ err = cm_getval (&cma);
+ cm_end_trans (key);
+
+ vendor = rd_hex (id + 2);
+ product = rd_hex (id + 6);
+
+ osdev->vendor = vendor;
+ osdev->product = product;
+ osdev->drvinfo = (drvinfo_t *) & oss_drvinfo;
+ osdev->key = key;
+
+ if (!DRIVER_ATTACH (osdev))
+ {
+ cmn_err (CE_WARN, "Attach failed\n");
+ osdev_delete (osdev);
+ return EIO;
+ }
+
+ *(void **) idata = osdev;
+ oss_audio_delayed_attach ();
+
+ instance++;
+
+ return 0;
+}
+
+static int
+cfg_remove (void *idata)
+{
+ oss_device_t *osdev = idata;
+
+ if (idata == NULL)
+ {
+ cmn_err (CE_WARN, DRIVER_NICK ": ossdrv_detach: dip==NULL\n");
+ return EIO;
+ }
+
+ if (osdev == NULL)
+ {
+ cmn_err (CE_WARN, DRIVER_NICK ": Bad idatata\n");
+ return 0;
+ }
+
+ if (DRIVER_DETACH (osdev) <= 0)
+ {
+ DDB (cmn_err (CE_WARN, "Driver busy - cannot detach\n"));
+ return EBUSY;
+ }
+
+ osdev_delete (osdev);
+
+ DDB (cmn_err (CE_CONT, "Detach done " DRIVER_NICK, "\n"));
+ return 0;
+}
+
+#if DRIVER_TYPE==DRV_VIRTUAL || DRIVER_TYPE==DRV_VMIX
+static int
+attach_virtual (void)
+{
+ DDB (cmn_err (CE_CONT, "Attach started " DRIVER_NICK "\n"));
+ if ((osdev =
+ osdev_create (NULL, DRIVER_TYPE, 0, DRIVER_NICK, NULL)) == NULL)
+ {
+ return EIO;
+ }
+
+ osdev->drvinfo = &oss_drvinfo;
+
+ if (!DRIVER_ATTACH (osdev))
+ {
+ cmn_err (CE_WARN, "Attach failed\n");
+ osdev_delete (osdev);
+ return EIO;
+ }
+
+ return 0;
+}
+
+static int
+detach_virtual (void)
+{
+ if (osdev == NULL)
+ {
+ return 0;
+ }
+
+ if (DRIVER_DETACH (osdev) <= 0)
+ {
+ DDB (cmn_err (CE_WARN, "Driver busy - cannot detach\n"));
+ return EBUSY;
+ }
+
+ osdev_delete (osdev);
+
+ return 0;
+}
+#endif
+
+static int
+ossdrv_config (cfg_func_t func, void *idata, rm_key_t key)
+{
+ switch (func)
+ {
+ case CFG_ADD:
+ return cfg_add (idata, key);
+ break;
+
+ case CFG_REMOVE:
+ return cfg_remove (idata);
+ break;
+
+ case CFG_VERIFY:
+ return 0;
+ break;
+
+ }
+
+ return EOPNOTSUPP;
+}
+
+/*
+ * Driver entry point routines
+ */
+
+int
+_load ()
+{
+ int err;
+
+ if ((err = drv_attach (&oss_drvinfo)) != 0)
+ {
+ cmn_err (CE_WARN, "drv_attach failed %d\n", err);
+ return err;
+ }
+
+#if DRIVER_TYPE==DRV_VIRTUAL || DRIVER_TYPE==DRV_VMIX
+ attach_virtual ();
+#endif
+
+ return 0;
+}
+
+int
+_unload ()
+{
+ extern volatile int oss_open_devices;
+
+ if (oss_open_devices > 0)
+ return EBUSY;
+
+#if DRIVER_TYPE==DRV_VIRTUAL || DRIVER_TYPE==DRV_VMIX
+ detach_virtual ();
+#endif
+
+ drv_detach (&oss_drvinfo);
+ return 0;
+}
diff --git a/kernel/OS/SCO_SV/os_sco.c b/kernel/OS/SCO_SV/os_sco.c
new file mode 100644
index 0000000..b5380ef
--- /dev/null
+++ b/kernel/OS/SCO_SV/os_sco.c
@@ -0,0 +1,1679 @@
+/*
+ * Purpose: Operating system abstraction functions for SCO OpenServer/UnixWare
+ */
+/*
+ *
+ * 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"
+#include <oss_pci.h>
+#include <sys/exec.h>
+#include <sys/user.h>
+#include <errno.h>
+
+/*
+ * MAX_CARDS must be larger than life. The system will panic if there are
+ * more sound devices (cards os sound chips) than MAX_CARDS.
+ */
+#define MAX_CARDS 32
+
+static oss_device_t *cards[MAX_CARDS];
+int oss_num_cards = 0;
+static int oss_expired = 0;
+
+volatile int oss_open_devices = 0;
+
+static bcb_t *oss_bcb;
+
+/*
+ * Driver information structures, for drv_attach().
+ */
+static int oss_config (cfg_func_t func, void *idata, rm_key_t key);
+
+static const drvops_t oss_ops = {
+ oss_config,
+ oss_open,
+ oss_close,
+ oss_devinfo,
+ oss_biostart,
+ oss_ioctl,
+ NULL, /* drvctl */
+ NULL /* mmap */
+};
+
+static const drvinfo_t oss_drvinfo = {
+ &oss_ops,
+ "osscore",
+ D_MP, /* MP-safe */
+ NULL, /* Not a STREAMS driver */
+ 10 /* Must match $maxchan in Node file */
+};
+
+static physreq_t *physreq_isa = NULL; /* 24 bits */
+static physreq_t *physreq_28bit = NULL;
+static physreq_t *physreq_30bit = NULL;
+static physreq_t *physreq_31bit = NULL;
+static physreq_t *physreq_32bit = NULL;
+
+#ifdef MEMDEBUG
+typedef struct
+{
+ void *addr;
+ int size;
+ char file[40];
+ int line;
+} mem_block_t;
+
+#define MAX_MEMBLOCKS 1024
+
+static mem_block_t memblocks[MAX_MEMBLOCKS];
+static int num_memblocks = 0;
+#endif
+
+#ifdef MEMDEBUG
+void *
+oss_kmem_alloc (size_t size, int flags, char *file, int line)
+#else
+void *
+oss_kmem_alloc (size_t size, int flags)
+#endif
+{
+/*
+ * This routine allocates a memory block and stores length of it in
+ * the beginning. This length information can be used when later unallocating
+ * the memory.
+ */
+
+ char *ptr;
+ uint64_t *len;
+
+ ptr = kmem_zalloc (size + sizeof (uint64_t), flags);
+#ifdef MEMDEBUG
+ cmn_err (CE_CONT, "kmalloc(%d, %s:%d)=%x\n", size, file, line, ptr);
+#endif
+
+ if (ptr == NULL)
+ return NULL;
+
+ len = (uint64_t *) ptr;
+
+ ptr += sizeof (uint64_t);
+ *len = size + sizeof (uint64_t);
+
+#ifdef MEMDEBUG
+#if 1
+ {
+ int i;
+ for (i = 0; i < num_memblocks; i++)
+ if (memblocks[i].addr == NULL)
+ {
+ memblocks[i].addr = ptr;
+ memblocks[i].size = size;
+ strncpy (memblocks[i].file, file, 39);
+ memblocks[i].line = line;
+ return ptr;
+ }
+ }
+#endif
+
+ if (num_memblocks < MAX_MEMBLOCKS)
+ {
+ memblocks[num_memblocks].addr = ptr;
+ memblocks[num_memblocks].size = size;
+ strncpy (memblocks[num_memblocks].file, file, 39);
+ memblocks[num_memblocks].line = line;
+ num_memblocks++;
+ }
+#endif
+
+ return ptr;
+}
+
+void
+#ifdef MEMDEBUG
+oss_kmem_free (void *addr, char *file, int line)
+#else
+oss_kmem_free (void *addr)
+#endif
+{
+ uint64_t *len;
+ int i;
+
+ char *ptr = addr;
+
+ if (addr == NULL)
+ return;
+
+ ptr -= sizeof (uint64_t);
+
+ len = (uint64_t *) ptr;
+
+ kmem_free (ptr, *len);
+#ifdef MEMDEBUG
+ {
+ int i;
+
+ for (i = 0; i < num_memblocks; i++)
+ if (addr == memblocks[i].addr)
+ {
+ memblocks[i].addr = NULL;
+ return;
+ }
+ }
+ cmn_err (CE_WARN, "Bad kfree(%x, %s:%d)\n", addr, file, line);
+#endif
+}
+
+/*
+ * Table for permanently allocated memory (to be freed by _fini)
+ */
+#define OSS_MAX_MEM 1024
+void *oss_mem_blocks[OSS_MAX_MEM];
+int oss_nblocks = 0;
+
+void *
+#ifdef MEMDEBUG
+oss_pmalloc (size_t size, char *file, int line)
+#else
+oss_pmalloc (size_t size)
+#endif
+{
+ void *mem_ptr;
+#ifdef MEMDEBUG
+ mem_ptr = (oss_mem_blocks[oss_nblocks] =
+ oss_kmem_alloc (size, KM_SLEEP, file, line));
+#else
+ mem_ptr = (oss_mem_blocks[oss_nblocks] = KERNEL_MALLOC (size));
+#endif
+
+ if (oss_nblocks <= OSS_MAX_MEM)
+ oss_nblocks++;
+ else
+ cmn_err (CE_NOTE, "Out of mem blocks\n");
+ return mem_ptr;
+}
+
+int
+__oss_alloc_dmabuf (int dev, dmap_p dmap, unsigned int alloc_flags,
+ oss_uint64_t maxaddr, int direction)
+{
+ void *p;
+ 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;
+
+/*
+ * 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;
+
+ if ((p =
+ oss_contig_malloc (audio_engines[dev]->osdev, size, maxaddr,
+ &phaddr)) == NULL)
+ return OSS_ENOMEM;
+
+ dmap->dmabuf = p;
+ dmap->dmabuf_phys = phaddr;
+ dmap->buffsize = size;
+
+ return 0;
+}
+
+void
+oss_free_dmabuf (int dev, dmap_p dmap)
+{
+ if (dmap->dmabuf == NULL)
+ return;
+
+ oss_contig_free (audio_engines[dev]->osdev, dmap->dmabuf, dmap->buffsize);
+ dmap->dmabuf = NULL;
+ dmap->dmabuf_phys = 0;
+ dmap->buffsize = 0;
+}
+
+void *
+oss_contig_malloc (oss_device_t * osdev, int size, oss_uint64_t memlimit,
+ oss_native_word * phaddr)
+{
+ void *p = NULL;
+ physreq_t *preqp = physreq_32bit;
+ paddr32_t pa;
+
+ *phaddr = 0;
+
+ switch (memlimit)
+ {
+ case MEMLIMIT_ISA:
+ preqp = physreq_isa;
+ break;
+ case MEMLIMIT_28BITS:
+ preqp = physreq_28bit;
+ break;
+ case MEMLIMIT_30BITS:
+ preqp = physreq_30bit;
+ break;
+ case MEMLIMIT_31BITS:
+ preqp = physreq_31bit;
+ break;
+ case MEMLIMIT_32BITS:
+ preqp = physreq_32bit;
+ break;
+
+ default:
+ cmn_err (CE_WARN, "osscore: Bad DMA memlimit for %s\n", osdev->nick);
+ }
+
+ if ((p = kmem_alloc_phys (size, preqp, &pa, 0)) == NULL)
+ {
+ cmn_err (CE_WARN, "osscore: kmem_alloc_phys() failed\n");
+ return NULL;
+ }
+
+ *phaddr = pa;
+ return p;
+}
+
+void
+oss_contig_free (oss_device_t * osdev, void *p, int sz)
+{
+ if (p)
+ kmem_free (p, sz);
+}
+
+/*
+ * Wait queue support
+ */
+oss_wait_queue_t *
+oss_create_wait_queue (oss_device_t * osdev, const char *name)
+{
+ oss_wait_queue_t *q;
+
+ if ((q = KERNEL_MALLOC (sizeof (*q))) == NULL)
+ {
+ cmn_err (CE_WARN, "osscore: Cannot allocate memory for a wait queue\n");
+ return NULL;
+ }
+
+ memset (q, 0, sizeof (*q));
+
+ if ((q->sv = SV_ALLOC (KM_SLEEP)) == NULL)
+ {
+ cmn_err (CE_WARN,
+ "osscore: Cannot allocate synchronization variable\n");
+ return NULL;
+ }
+
+ return q;
+}
+
+void
+oss_reset_wait_queue (oss_wait_queue_t * wq)
+{
+ // NOP
+}
+
+void
+oss_remove_wait_queue (oss_wait_queue_t * wq)
+{
+ SV_DEALLOC (wq->sv);
+ KERNEL_FREE (wq);
+}
+
+static void
+sleep_timeout (caddr_t arg)
+{
+ oss_wait_queue_t *wq = (oss_wait_queue_t *) arg;
+
+ SV_BROADCAST (wq->sv, 0);
+}
+
+int
+oss_sleep (oss_wait_queue_t * wq, oss_mutex_t * mutex, int ticks,
+ oss_native_word * flags, unsigned int *status)
+{
+ timeout_id_t tid;
+
+ *status = 0;
+ wq->flags = 0;
+
+ if (wq == NULL)
+ {
+ cmn_err (CE_WARN, "osscore: Unallocated wait queue\n");
+ *status |= WK_SIGNAL;
+ return 1;
+ }
+ if (ticks > 0)
+ tid = timeout (sleep_timeout, wq, ticks);
+
+ /*
+ * Note SV_WAIT_SIG() will release the mutex/lock so we must re-acquire
+ * it before returning.
+ */
+#ifdef MUTEX_CHECKS
+ // Pop mutex because it will be released by SV_WAIT_SIG()
+ pop_mutex (*mutex, __FILE__, __LINE__);
+#endif
+ if (!SV_WAIT_SIG (wq->sv, prihi, *mutex)) /* Signal */
+ {
+ *status |= WK_SIGNAL;
+ wq->flags |= WK_WAKEUP; /* Needed to prevent false timeout messages */
+ }
+
+ MUTEX_ENTER_IRQDISABLE (*mutex, *flags);
+ if (ticks > 0 && (wq->flags & WK_WAKEUP))
+ untimeout (tid);
+
+ return (wq->flags & WK_WAKEUP);
+}
+
+int
+oss_register_poll (oss_wait_queue_t * wq, oss_mutex_t * mutex,
+ oss_native_word * flags, oss_poll_event_t * ev)
+{
+ // NOP: DDI8 doesn't support chpoll
+}
+
+void
+oss_wakeup (oss_wait_queue_t * wq, oss_mutex_t * mutex,
+ oss_native_word * flags, short events)
+{
+ wq->flags |= WK_WAKEUP;
+ SV_BROADCAST (wq->sv, 0);
+}
+
+void *
+oss_get_osid (oss_device_t * osdev)
+{
+ return osdev->osid;
+}
+
+static int
+grow_array(oss_device_t *osdev, oss_cdev_t ***arr, int *size, int element_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 * element_size))==NULL)
+ return 0;
+
+ memset(new, 0, new_size * element_size);
+ if (old != NULL)
+ memcpy(new, old, old_size * element_size);
+
+ *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 i, num;
+ oss_cdev_t *cdev = NULL;
+
+ 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, sizeof(oss_cdev_t*), 100))
+ {
+ cmn_err (CE_WARN, "Cannot allocate new 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) - 1);
+ else
+ strcpy (cdev->name, "NONE");
+ cdev->name[sizeof (cdev->name) - 1] = 0;
+ oss_cdevs[num] = cdev;
+}
+
+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_EIO;
+}
+
+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->shortname[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) - 1);
+ ci->hw_info[sizeof (ci->hw_info) - 1] = 0;
+
+ 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;
+}
+
+/*
+ * Some standard C library routines
+ */
+void *
+memset (void *t, int c, size_t l)
+{
+ int i;
+
+ if (t == NULL)
+ return NULL;
+
+ for (i = 0; i < l; i++)
+ ((char *) t)[i] = c;
+
+ return t;
+}
+
+void *
+memcpy (void *t, const void *s, size_t l)
+{
+ bcopy (s, t, l);
+ return t;
+}
+
+oss_device_t *
+osdev_create (dev_info_t * dip, int dev_type, int instance, const char *nick,
+ const char *handle)
+{
+ oss_device_t *osdev = NULL;
+ int i, err;
+ caddr_t addr;
+ dev_info_t ldip = 0;
+
+ if (dip == NULL)
+ dip = &ldip;
+
+ if (handle == NULL)
+ handle = nick;
+
+ /*
+ * Don't accept any more drivers if expired
+ */
+ if (oss_expired && oss_num_cards > 0)
+ return NULL;
+
+/*
+ * Check if a driver/device was reinserted
+ */
+ if (dip != &ldip) /* Not a virtual driver */
+ for (i = 0; i < oss_num_cards; i++)
+ {
+ if (!cards[i]->available && cards[i]->key == *dip)
+ {
+ osdev = cards[i];
+ break;
+ }
+ }
+
+ if (osdev == NULL)
+ {
+ if (oss_num_cards >= MAX_CARDS)
+ {
+ cmn_err (CE_WARN, "Too many OSS devices. At most %d permitted.\n",
+ MAX_CARDS);
+ return NULL;
+ }
+
+ if ((osdev = PMALLOC (NULL, sizeof (*osdev))) == NULL)
+ {
+ cmn_err (CE_WARN, "osdev_create: Out of memory\n");
+ return NULL;
+ }
+
+ osdev->cardnum = oss_num_cards;
+ cards[oss_num_cards++] = osdev;
+ }
+ osdev->key = *dip;
+ osdev->osid = dip;
+ osdev->available = 1;
+ osdev->first_mixer = -1;
+ osdev->instance = instance;
+ osdev->dev_type = dev_type;
+ osdev->devc = NULL;
+ MUTEX_INIT (osdev, osdev->mutex, MH_GLOBAL);
+ sprintf (osdev->nick, "%s%d", nick, instance);
+ strcpy (osdev->modname, nick);
+
+ switch (dev_type)
+ {
+ case DRV_PCI:
+ //pci_config_setup (dip, &osdev->pci_config_handle);
+ break;
+
+ case DRV_VIRTUAL:
+ case DRV_VMIX:
+ case DRV_STREAMS:
+ /* NOP */
+ break;
+
+ case DRV_USB:
+ /* NOP */
+ break;
+
+ default:
+ cmn_err (CE_WARN, "Bad device type\n");
+ return NULL;
+ }
+
+/*
+ * Create the device handle
+ */
+ switch (dev_type)
+ {
+ case DRV_PCI:
+ {
+ unsigned int subvendor = 0;
+ pci_read_config_dword (osdev, 0x2c, &subvendor);
+
+ sprintf (osdev->handle, "PCI%08x-%d", subvendor, instance);
+ }
+ break;
+
+#if 0
+ case DRV_USB:
+ sprintf (osdev->handle, "USB-%s%d", handle, instance);
+ break;
+#endif
+
+ 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;
+
+ if (!osdev->available)
+ {
+ cmn_err (CE_WARN, "device %s, osdev already deleted\n", osdev->nick);
+ return;
+ }
+
+ osdev->available = 0;
+
+ switch (osdev->dev_type)
+ {
+ case DRV_PCI:
+ break;
+ }
+
+/*
+ * 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");
+ }
+ MUTEX_CLEANUP (osdev->mutex);
+}
+
+int
+oss_register_device (oss_device_t * osdev, const char *name)
+{
+ 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;
+}
+
+int
+oss_disable_device (oss_device_t * osdev)
+{
+ int i;
+/*
+ * This routine should check if the device is ready to be unloaded (no devices are in use).
+ * If the device cannot be unloaded this routine must return OSS_EBUSY.
+ *
+ * If the device can be unloaded then disable any timers or other features that may cause the
+ * device to be called. Also mark the audio/midi/mixer/etc devices of this device to be disabled.
+ * However the interrupt handler should still stay enabled. The low level driver will call
+ * oss_unregister_interrupts() after it has cleared the interrupt enable register.
+ */
+ if (osdev->refcount > 0)
+ {
+ return OSS_EBUSY;
+ }
+
+/*
+ * Now mark all devices unavailable (for the time being)
+ */
+
+ 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_unregister_device (oss_device_t * osdev)
+{
+}
+
+#ifdef MUTEX_CHECKS
+static int oss_context = 0; /* 0=user context, 1=interrupt context */
+#endif
+
+static int
+ossintr (void *idata)
+{
+ oss_device_t *osdev = idata;
+ oss_native_word flags;
+#ifdef MUTEX_CHECKS
+ int saved_context;
+ saved_context = oss_context;
+ if (oss_context == 1)
+ cmn_err (CE_WARN, "Recursive interrupt\n");
+ oss_context = 1;
+#endif
+
+ MUTEX_ENTER_IRQDISABLE (osdev->mutex, flags);
+
+ if (!osdev->tophalf_handler (osdev))
+ {
+ MUTEX_EXIT_IRQRESTORE (osdev->mutex, flags);
+#ifdef MUTEX_CHECKS
+ oss_context = saved_context;
+#endif
+ return ISTAT_NONE;
+ }
+
+ if (osdev->bottomhalf_handler != NULL)
+ osdev->bottomhalf_handler (osdev);
+
+ MUTEX_EXIT_IRQRESTORE (osdev->mutex, flags);
+#ifdef MUTEX_CHECKS
+ oss_context = saved_context;
+#endif
+
+ return ISTAT_ASSERTED;
+}
+
+int
+oss_register_interrupts (oss_device_t * osdev, int intrnum,
+ oss_tophalf_handler_t top,
+ oss_bottomhalf_handler_t bottom)
+{
+ int err;
+
+ if (intrnum != 0)
+ {
+ cmn_err (CE_WARN, "Bad interrupt index (%d) for %s\n", intrnum,
+ osdev->name);
+ return OSS_EINVAL;
+ }
+
+ if (osdev == NULL)
+ {
+ cmn_err (CE_WARN, "oss_register_interrupts: Bad osdev\n");
+ return OSS_EINVAL;
+ }
+
+ if (osdev->tophalf_handler != NULL || osdev->bottomhalf_handler != NULL)
+ {
+ cmn_err (CE_WARN, "Interrupts already registered for %s\n",
+ osdev->name);
+ return OSS_EINVAL;
+ }
+
+ if (top == NULL)
+ {
+ cmn_err (CE_WARN, "Bad interrupt handler for %s\n", osdev->name);
+ return OSS_EINVAL;
+ }
+
+ osdev->tophalf_handler = top;
+ osdev->bottomhalf_handler = bottom;
+ if (cm_intr_attach
+ (osdev->key, ossintr, osdev, osdev->drvinfo, &osdev->intr_cookie) == 0)
+ {
+ cmn_err (CE_WARN, "cm_intr_attach failed for %s\n", osdev->nick);
+ }
+
+ return 0;
+}
+
+void
+oss_unregister_interrupts (oss_device_t * osdev)
+{
+ if (osdev->intr_cookie != NULL)
+ cm_intr_detach (osdev->intr_cookie);
+ osdev->intr_cookie = NULL;
+}
+
+static char *
+ksprintn (ul, base, lenp)
+ register u_long ul;
+ register int base, *lenp;
+{ /* A long in base 8, plus NULL. */
+ static char buf[sizeof (long) * NBBY / 3 + 2];
+ register char *p;
+
+ p = buf;
+ do
+ {
+ *++p = "0123456789abcdef"[ul % base];
+ }
+ while (ul /= base);
+ if (lenp)
+ *lenp = p - buf;
+ return (p);
+}
+
+int
+oss_sprintf (char *buf, char *cfmt, ...)
+{
+ const char *fmt = cfmt;
+ register char *p, *bp;
+ register int ch, base;
+ unsigned long ul;
+ int lflag;
+ int count = 10;
+ va_list ap;
+
+ va_start (ap, fmt);
+ for (bp = buf;;)
+ {
+ while ((ch = *(unsigned char *) fmt++) != '%')
+ if ((*bp++ = ch) == '\0')
+ {
+ va_end (ap);
+ return ((bp - buf) - 1);
+ }
+
+ lflag = 0;
+ reswitch:
+ switch (ch = *(unsigned char *) fmt++)
+ {
+ case 'l':
+ lflag = 1;
+ goto reswitch;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ goto reswitch;
+
+ case 'c':
+ *bp++ = va_arg (ap, int);
+ break;
+
+ case 's':
+ p = va_arg (ap, char *);
+ while (*bp++ = *p++)
+ ;
+ --bp;
+ break;
+
+ case 'd':
+ ul = lflag ? va_arg (ap, long) : va_arg (ap, int);
+ if ((long) ul < 0)
+ {
+ *bp++ = '-';
+ ul = -(long) ul;
+ }
+ base = 10;
+ goto number;
+ break;
+
+ case 'o':
+ ul = lflag ? va_arg (ap, unsigned long) : va_arg (ap, unsigned int);
+ base = 8;
+ goto number;
+ break;
+
+ case 'u':
+ ul = lflag ? va_arg (ap, unsigned long) : va_arg (ap, unsigned int);
+ base = 10;
+ goto number;
+ break;
+
+ case 'x':
+ ul = lflag ? va_arg (ap, unsigned long) : va_arg (ap, unsigned int);
+ base = 16;
+ number:
+ for (p = (char *) ksprintn (ul, base, NULL); ch = *p--;)
+ *bp++ = ch;
+ break;
+
+ default:
+ *bp++ = '%';
+ if (lflag)
+ *bp++ = 'l';
+ /* FALLTHROUGH */
+
+ case '%':
+ *bp++ = ch;
+ }
+ }
+
+ /* va_end(ap); */
+}
+
+static physreq_t *
+build_physreq (int bits)
+{
+ physreq_t *pr;
+ long long tmp;
+
+ if ((pr = physreq_alloc (KM_SLEEP)) == NULL)
+ return NULL;
+
+ pr->phys_align = 4096;
+ pr->phys_boundary = 0;
+ pr->phys_dmasize = bits;
+ pr->phys_max_scgth = 0;
+ pr->phys_flags = PREQ_PHYSCONTIG;
+
+ if (physreq_prep (pr, KM_SLEEP) != B_TRUE)
+ {
+ cmn_err (CE_WARN, "osscore: physreq_prep failed\n");
+ }
+
+ return pr;
+}
+
+/*
+ * Driver info device file
+ */
+static int drvinfo_busy = 0;
+static int drvinfo_len = 0, drvinfo_ptr = 0;
+static char *drvinfo_buf = NULL;
+#define DRVINFO_SIZE 4096
+
+static int
+drvinfo_open (int dev, int dev_class, struct fileinfo *file,
+ int recursive, int open_flags, int *redirect)
+{
+ int i;
+
+ if (drvinfo_busy)
+ return OSS_EBUSY;
+ drvinfo_busy = 1;
+
+ if ((drvinfo_buf = KERNEL_MALLOC (DRVINFO_SIZE)) == NULL)
+ {
+ cmn_err (CE_WARN, "Cannot allocate drvinfo buffer\n");
+ return OSS_ENOMEM;
+ }
+
+ drvinfo_len = 0;
+ drvinfo_ptr = 0;
+
+ for (i = 1; i < oss_num_cdevs; i++)
+ if (oss_cdevs[i]->name[0] != 'N' || oss_cdevs[i]->name[1] != 'O' || oss_cdevs[i]->name[2] != 'N' || oss_cdevs[i]->name[3] != 'E') /* Not a dummy placeholder device */
+ if (DRVINFO_SIZE - drvinfo_len > 32)
+ {
+ char *s = drvinfo_buf + drvinfo_len;
+
+ drvinfo_len +=
+ oss_sprintf (s, "%s %s %d\n", oss_cdevs[i]->name,
+ oss_cdevs[i]->osdev->nick, i);
+
+ }
+
+ return 0;
+}
+
+static void
+drvinfo_close (int dev, struct fileinfo *file)
+{
+ KERNEL_FREE (drvinfo_buf);
+ drvinfo_buf = NULL;
+ drvinfo_len = 0;
+ drvinfo_ptr = 0;
+ drvinfo_busy = 0;
+}
+
+static int
+drvinfo_read (int dev, struct fileinfo *file, uio_t * buf, int count)
+{
+ /*
+ * Return at most 'count' bytes from the drvinfo_buf.
+ */
+ int l, c;
+
+ l = count;
+ c = drvinfo_len - drvinfo_ptr;
+
+ if (l > c)
+ l = c;
+ if (l <= 0)
+ return 0;
+
+ if (uiomove (&drvinfo_buf[drvinfo_ptr], l, UIO_READ, buf) != 0)
+ return OSS_EFAULT;
+ drvinfo_ptr += l;
+
+ return l;
+}
+
+static oss_cdev_drv_t drvinfo_cdev_drv = {
+ drvinfo_open,
+ drvinfo_close,
+ drvinfo_read
+};
+
+static void
+install_drvinfo (oss_device_t * osdev)
+{
+ oss_install_chrdev (osdev, "ossinfo", OSS_DEV_MISC, 0, &drvinfo_cdev_drv,
+ 0);
+}
+
+/*
+ * Driver entry point routines
+ */
+
+int
+_load ()
+{
+ int err = 0;
+ oss_device_t *osdev;
+ time_t t;
+
+ if ((err = drv_attach (&oss_drvinfo)) != 0)
+ {
+ cmn_err (CE_WARN, "drv_attach failed %d\n", err);
+ return err;
+ }
+
+#ifdef LICENSED_VERSION
+ if (drv_getparm (TIME, &t) != 0)
+ {
+ cmn_err (CE_WARN, "drv_getparm(TIME) failed\n");
+ return EBUSY;
+ }
+
+ if (!oss_license_handle_time (t))
+ {
+ 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 ((osdev = osdev_create (NULL, DRV_VIRTUAL, 0, "oss", NULL)) == NULL)
+ {
+ cmn_err (CE_WARN, "Creating osdev failed\n");
+ return ENOMEM;
+ }
+
+/*
+ * Allocate physrec structures for various memory ranges. Remember to free them in the _load
+ * entry point.
+ */
+ physreq_isa = build_physreq (24);
+ physreq_28bit = build_physreq (28);
+ physreq_30bit = build_physreq (30);
+ physreq_31bit = build_physreq (31);
+ physreq_32bit = build_physreq (32);
+
+/*
+ * Create the BCB structure
+ */
+ oss_bcb = bcb_alloc (KM_SLEEP);
+ oss_bcb->bcb_addrtypes = BA_UIO;
+ oss_bcb->bcb_flags = 0;
+ oss_bcb->bcb_max_xfer = 0;
+ oss_bcb->bcb_granularity = 1;
+ oss_bcb->bcb_physreqp = physreq_32bit;
+ bcb_prep (oss_bcb, KM_SLEEP);
+
+ install_drvinfo (osdev);
+ oss_common_init (osdev);
+
+ oss_register_device (osdev, "OSS core services");
+
+ return 0;
+}
+
+int
+_unload ()
+{
+ int i;
+ static int already_unloaded = 0;
+
+ if (oss_open_devices > 0)
+ return EBUSY;
+ drv_detach (&oss_drvinfo);
+
+ if (already_unloaded)
+ return 0;
+ already_unloaded = 1;
+
+ oss_unload_drivers ();
+
+ physreq_free (physreq_isa);
+ physreq_free (physreq_28bit);
+ physreq_free (physreq_30bit);
+ physreq_free (physreq_31bit);
+ physreq_free (physreq_32bit);
+
+ bcb_free (oss_bcb);
+
+ for (i = 0; i < oss_nblocks; i++)
+ KERNEL_FREE (oss_mem_blocks[i]);
+ oss_nblocks = 0;
+
+ return 0;
+}
+
+void
+oss_pci_byteswap (oss_device_t * osdev, int mode)
+{
+ // NOP
+}
+
+void
+oss_pcie_init (oss_device_t * osdev, int flags)
+{
+ /* TODO: Should we do something? */
+}
+
+int
+pci_read_config_byte (oss_device_t * osdev, offset_t where,
+ unsigned char *val)
+{
+ *val = 0;
+ if (cm_read_devconfig (osdev->key, where, val, sizeof (*val)) ==
+ sizeof (*val))
+ return PCIBIOS_SUCCESSFUL;
+
+ return PCIBIOS_FAILED;
+}
+
+int
+pci_read_config_irq (oss_device_t * osdev, offset_t where, unsigned char *val)
+{
+ *val = 0;
+ if (cm_read_devconfig (osdev->key, where, val, sizeof (*val)) ==
+ sizeof (*val))
+ return PCIBIOS_SUCCESSFUL;
+
+ return PCIBIOS_FAILED;
+}
+
+
+int
+pci_read_config_word (oss_device_t * osdev, offset_t where,
+ unsigned short *val)
+{
+ *val = 0;
+#if 1
+ if (cm_read_devconfig (osdev->key, where, val, sizeof (*val)) ==
+ sizeof (*val))
+ return PCIBIOS_SUCCESSFUL;
+#else
+ switch (where)
+ {
+ case PCI_VENDOR_ID:
+ *val = osdev->vendor;
+ return PCIBIOS_SUCCESSFUL;
+ break;
+
+ case PCI_DEVICE_ID:
+ *val = osdev->product;
+ return PCIBIOS_SUCCESSFUL;
+ break;
+
+ }
+
+#endif
+ return PCIBIOS_FAILED;
+}
+
+int
+pci_read_config_dword (oss_device_t * osdev, offset_t where,
+ unsigned int *val)
+{
+ *val = 0;
+ if (cm_read_devconfig (osdev->key, where, val, sizeof (*val)) ==
+ sizeof (*val))
+ return PCIBIOS_SUCCESSFUL;
+
+ return PCIBIOS_FAILED;
+}
+
+int
+pci_write_config_byte (oss_device_t * osdev, offset_t where,
+ unsigned char val)
+{
+ if (cm_write_devconfig (osdev->key, where, &val, sizeof (val)) ==
+ sizeof (val))
+ return PCIBIOS_SUCCESSFUL;
+
+ return PCIBIOS_FAILED;
+}
+
+int
+pci_write_config_word (oss_device_t * osdev, offset_t where,
+ unsigned short val)
+{
+ if (cm_write_devconfig (osdev->key, where, &val, sizeof (val)) ==
+ sizeof (val))
+ return PCIBIOS_SUCCESSFUL;
+
+ return PCIBIOS_FAILED;
+}
+
+int
+pci_write_config_dword (oss_device_t * osdev, offset_t where,
+ unsigned int val)
+{
+ if (cm_write_devconfig (osdev->key, where, &val, sizeof (val)) ==
+ sizeof (val))
+ return PCIBIOS_SUCCESSFUL;
+
+ return PCIBIOS_FAILED;
+}
+
+/*
+ * Entry point routines
+ */
+static int
+oss_config (cfg_func_t func, void *idata, rm_key_t key)
+{
+ return EOPNOTSUPP;
+}
+
+int
+oss_devinfo (void *idata, channel_t channel, di_parm_t parm, void *valp)
+{
+ switch (parm)
+ {
+ case DI_MEDIA:
+ break;
+
+ case DI_SIZE:
+ break;
+
+ case DI_RBCBP:
+ *(bcb_t **) valp = oss_bcb;
+ return 0;
+ break;
+
+ case DI_WBCBP:
+ *(bcb_t **) valp = oss_bcb;
+ return 0;
+ break;
+
+ case DI_PHYS_HINT:
+ break;
+
+ }
+ return EOPNOTSUPP;
+}
+
+void
+oss_biostart (void *idata, channel_t channel, buf_t * bp)
+{
+ int dev = channel;
+ oss_cdev_t *cdev;
+ int count = bp->b_un.b_uio->uio_resid;
+ int retval;
+
+ if ((cdev = oss_cdevs[dev]) == NULL)
+ {
+ bioerror (bp, ENXIO);
+ biodone (bp);
+ return;
+ }
+
+ cdev->file.acc_flags = 0;
+
+ if (bp->b_flags & B_READ)
+ {
+ /* Read operation */
+ if (cdev->d->read == NULL)
+ {
+ bioerror (bp, ENXIO);
+ biodone (bp);
+ return;
+ }
+ retval =
+ cdev->d->read (cdev->instance, &cdev->file, bp->b_un.b_uio, count);
+ if (retval < 0)
+ bioerror (bp, -retval);
+ else if (retval < count)
+ bp->b_resid = count - retval;
+
+ biodone (bp);
+ return;
+ }
+
+ /* Write operation */
+ if (cdev->d->write == NULL)
+ {
+ bioerror (bp, ENXIO);
+ biodone (bp);
+ return;
+ }
+ retval =
+ cdev->d->write (cdev->instance, &cdev->file, bp->b_un.b_uio, count);
+ if (retval < 0)
+ bioerror (bp, -retval);
+ else if (retval < count)
+ bp->b_resid = count - retval;
+
+ biodone (bp);
+}
+
+int
+oss_open (void *idata, channel_t * channelp,
+ int open_flags, cred_t * crp, queue_t * q)
+{
+ oss_device_t *osdev;
+ int dev = *channelp, tmpdev;
+ oss_cdev_t *cdev;
+ int retval;
+
+ osdev = idata;
+
+ if (dev >= OSS_MAX_CDEVS)
+ return ENXIO;
+
+ if (dev >= oss_num_cdevs)
+ {
+ return ENODEV;
+ }
+
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d == NULL)
+ return ENODEV;
+
+ if (cdev->d->open == NULL)
+ {
+ return ENODEV;
+ }
+
+ memset (&cdev->file, 0, sizeof (cdev->file));
+ cdev->file.mode = 0;
+ cdev->file.acc_flags = open_flags;
+
+ if (open_flags & FREAD && open_flags & FWRITE)
+ cdev->file.mode = OPEN_READWRITE;
+ else if (open_flags & FREAD)
+ cdev->file.mode = OPEN_READ;
+ else if (open_flags & FWRITE)
+ cdev->file.mode = OPEN_WRITE;
+
+ tmpdev = dev;
+ retval =
+ cdev->d->open (cdev->instance, cdev->dev_class, &cdev->file, 0, 0, &tmpdev);
+ *channelp = tmpdev;
+ dev = tmpdev;
+
+ if (retval < 0)
+ {
+ return -retval;
+ }
+
+ oss_open_devices++;
+ cdev->open_count++;
+
+ return 0;
+}
+
+int
+oss_close (void *idata, channel_t channel,
+ int oflags, cred_t * crp, queue_t * q)
+{
+ oss_cdev_t *cdev;
+ int dev;
+
+ dev = channel;
+
+ if (dev >= OSS_MAX_CDEVS)
+ return ENXIO;
+
+ if ((cdev = oss_cdevs[dev]) == NULL)
+ return ENXIO;
+
+ if (cdev->open_count == 0) /* Not opened */
+ return 0;
+
+ cdev->d->close (cdev->instance, &cdev->file);
+
+ oss_open_devices--;
+ cdev->open_count--;
+ return 0;
+}
+
+int
+oss_ioctl (void *idata, channel_t channel, int cmd, void *arg,
+ int oflags, cred_t * crp, int *rvalp)
+{
+ int dev = channel;
+ int retval;
+ int len = 0;
+ char localbuf[256]; /* All frequently used ioctl calls fit in 256 bytes */
+ char *buf = localbuf, *auxbuf = NULL;
+ oss_cdev_t *cdev;
+
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d->ioctl == NULL)
+ return *rvalp = ENXIO;
+
+ if (oss_expired)
+ return *rvalp = ENODEV;
+
+ if (cmd & (SIOC_OUT | SIOC_IN))
+ {
+
+ len = __SIOC_SIZE (cmd);
+ if (len < 0)
+ len = 0;
+ if (len > sizeof (localbuf))
+ {
+ /*
+ * For the few largest ioctl calls we need to allocate an off-stack
+ * buffer because otherwise the kernel stack will overflow.
+ * This approach is slower but fortunately "sane" applications don't
+ * use these ioctl calls too frequently.
+ */
+ if ((auxbuf = KERNEL_MALLOC (len)) == NULL)
+ {
+ cmn_err (CE_WARN,
+ "Failed to allocate an ioctl buffer of %d bytes\n",
+ len);
+ return *rvalp = ENOMEM;
+ }
+ buf = auxbuf;
+ }
+
+ if ((cmd & SIOC_IN) && len > 0)
+ {
+ if (copyin ((char *) arg, buf, len) == -1)
+ {
+ if (auxbuf != NULL)
+ KERNEL_FREE (auxbuf);
+ return *rvalp = EFAULT;
+ }
+ }
+
+ }
+
+ retval = cdev->d->ioctl (cdev->instance, &cdev->file, cmd, (ioctl_arg) buf);
+
+ if ((cmd & SIOC_OUT) && len > 0)
+ {
+ if (copyout (buf, (char *) arg, len) == -1)
+ {
+ if (auxbuf != NULL)
+ KERNEL_FREE (auxbuf);
+ return *rvalp = EFAULT;
+ }
+ }
+
+ *rvalp = (((retval) < 0) ? -(retval) : 0);
+
+ if (auxbuf != NULL)
+ KERNEL_FREE (auxbuf);
+
+ return *rvalp;
+}
+
+#ifdef MUTEX_CHECKS
+
+typedef struct
+{
+ int active;
+ void *mutex;
+ const char *filename;
+ int line;
+ int context;
+} mutex_debug_t;
+
+static mutex_debug_t mutex_tab[1024];
+static int n_mutexes = 0;
+
+void
+push_mutex (void *mutex, const char *file, int line)
+{
+ int i, n = -1;
+//cmn_err(CE_CONT, "Push mutex %08x, %s:%d, context=%d\n", mutex, file, line, oss_context);
+
+ for (i = 0; n == -1 && i < n_mutexes; i++)
+ if (!mutex_tab[i].active)
+ n = i;
+ else
+ {
+ if (mutex_tab[i].mutex == mutex
+ && mutex_tab[i].context == oss_context)
+ {
+ cmn_err (CE_NOTE, "Mutex %08x already held\n", mutex);
+ cmn_err (CE_CONT, " Locked by %s:%d\n", mutex_tab[i].filename,
+ mutex_tab[i].line);
+ cmn_err (CE_CONT, " Acquire by %s:%d\n", file, line);
+ }
+ }
+
+ if (n == -1)
+ {
+ if (n_mutexes >= 1024)
+ {
+ cmn_err (CE_NOTE, "Mutex debug table full\n");
+ return;
+ }
+ n = n_mutexes++;
+ }
+
+ mutex_tab[n].active = 1;
+ mutex_tab[n].mutex = mutex;
+ mutex_tab[n].filename = file;
+ mutex_tab[n].line = line;
+ mutex_tab[n].context = oss_context;
+}
+
+void
+pop_mutex (void *mutex, const char *file, int line)
+{
+ int i;
+
+//cmn_err(CE_CONT, "Pop mutex %08x, %s:%d, context=%d\n", mutex, file, line, oss_context);
+ for (i = 0; i < n_mutexes; i++)
+ if (mutex_tab[i].active && mutex_tab[i].mutex == mutex
+ && mutex_tab[i].context == oss_context)
+ {
+ mutex_tab[i].active = 0;
+ mutex_tab[i].filename = file;
+ mutex_tab[i].line = line;
+ return;
+ }
+
+ cmn_err (CE_NOTE, "Mutex %08x not locked (%s:%d), context=%d\n",
+ mutex, file, line, oss_context);
+ for (i = 0; i < n_mutexes; i++)
+ if (mutex_tab[i].active == 0 && mutex_tab[i].mutex == mutex)
+ {
+ cmn_err (CE_CONT, " Previous unlock at %s:%d, context=%d\n",
+ mutex_tab[i].filename, mutex_tab[i].line,
+ mutex_tab[i].context);
+ }
+}
+
+void
+print_mutexes (void)
+{
+ int i, n = 0;
+
+ for (i = 0; i < n_mutexes; i++)
+ if (mutex_tab[i].active)
+ n++;
+
+ cmn_err (CE_CONT, "%d mutexes held\n", n);
+
+ for (i = 0; i < n_mutexes; i++)
+ if (mutex_tab[i].active)
+ cmn_err (CE_CONT, " %08x %s:%d\n", mutex_tab[i].mutex,
+ mutex_tab[i].filename, mutex_tab[i].line);
+}
+#endif
+
+int
+oss_get_procinfo(int what)
+{
+ // TODO
+
+ return OSS_EINVAL;
+}
diff --git a/kernel/OS/SCO_SV/os_sco.h b/kernel/OS/SCO_SV/os_sco.h
new file mode 100644
index 0000000..0d5d345
--- /dev/null
+++ b/kernel/OS/SCO_SV/os_sco.h
@@ -0,0 +1,408 @@
+#ifndef _OS_H_
+#define _OS_H_
+
+/*
+ * Purpose: OS specific definitions for SCO OpenServer and SCO UnixWare (DDI8)
+ *
+ */
+/*
+ *
+ * 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.
+ *
+ */
+
+#define OS_VERSION "6"
+#define OpenServer
+
+#if (!defined(i386) && !defined(x86_64)) || defined(CONFIG_OSS_FIXDEPOINT)
+// Floating point is not supported or it's disabled
+#undef CONFIG_OSS_VMIX_FLOAT
+#endif
+
+#if 0
+// Enable kernel level debugging
+#define DEBUG
+/*
+ * NOTE! Virtual devices (such as vmix, imux and midiloop) cannot be used
+ * when OSS is compiled with _LOCKTEST. Such drivers will not pass
+ * deadlock detection because virtual drivers make calls to the audio
+ * core and other drivers that use lower hierarchy levels. For the
+ * reason the system will crash as soon as the virtual devices get used.
+ */
+#define _LOCKTEST
+#define MUTEX_CHECKS
+#undef MEMDEBUG
+#endif
+
+// Timing/tracing analysis stuff. This info can be read with the readtimings utility.
+
+#ifdef DEBUG
+#include <sys/debug.h>
+#endif
+
+#define VDEV_SUPPORT
+#define USE_DEVICE_SUBDIRS
+
+#define __inline__ inline
+#define __inline inline
+#define EXTERN_C extern "C"
+
+/*
+ * Do not export global parameters in oss_core_options.c since they will be
+ * handled in Space.c for osscore
+ */
+#define NO_GLOBAL_OPTIONS
+
+/*
+ * Disable support for per-application features such as /dev/dsp device
+ * selection based on command name. Requires working GET_PROCESS_NAME
+ * macro implementation.
+ */
+#undef APPLIST_SUPPORT
+
+/*
+ * Some integer types
+ */
+#if defined(amd64) || defined(sparc)
+typedef unsigned long long oss_native_word; /* Same as the address and status register size */
+#else
+typedef unsigned long oss_native_word; /* Same as the address and status register size */
+#endif
+
+typedef long long oss_int64_t; /* Signed 64 bit integer */
+typedef unsigned long long oss_uint64_t; /* Unsigned 64 bit integer */
+typedef unsigned long offset_t;
+
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/signal.h>
+#include <oss_errno.h>
+#include <sys/file.h>
+#include <sys/conf.h>
+#include <sys/uio.h>
+#include <sys/map.h>
+#include <sys/debug.h>
+#include <sys/kmem.h>
+#include <sys/cmn_err.h>
+#include <sys/open.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+#include <sys/ksynch.h>
+#include <sys/confmgr.h>
+#include <sys/cm_i386at.h>
+#include <sys/poll.h>
+
+/*
+ * ddi.h must be the last include
+ */
+#include <sys/ddi.h>
+
+#ifndef HZ
+extern int hz;
+#define HZ hz
+#endif
+#define OSS_HZ HZ
+
+/*
+ * Mutexes
+ */
+
+#ifdef _KERNEL
+typedef lock_t *oss_mutex_t;
+#else
+typedef int oss_mutex_t;
+#endif
+
+/* The soundcard.h could be in a nonstandard place so include it here. */
+#include "soundcard.h"
+
+typedef struct udi_usb_devc udi_usb_devc;
+typedef rm_key_t dev_info_t;
+
+struct _oss_device_t
+{
+#ifdef _KERNEL
+ int cardnum;
+ int dev_type;
+ int available;
+ int instance;
+ rm_key_t key;
+ drvinfo_t *drvinfo;
+ void *osid;
+ void *devc;
+ char *name;
+ char nick[16];
+ char modname[16];
+ char handle[32];
+ char *hw_info;
+ int num_audio_engines;
+ int num_audioplay, num_audiorec, num_audioduplex;
+ int num_mididevs;
+ int num_mixerdevs;
+ int num_loopdevs;
+ int first_mixer; /* This must be set to -1 by osdev_create() */
+
+ volatile int refcount; /* Nonzero means that the device is needed by some other (virtual) driver. */
+
+/* Interrupts */
+
+ void *intr_cookie; /* Returned by cm_intr_attach */
+ oss_tophalf_handler_t tophalf_handler;
+ oss_bottomhalf_handler_t bottomhalf_handler;
+ oss_mutex_t mutex;
+
+/* PCI configuration */
+ int vendor, product;
+#else
+ int dummy;
+#endif
+};
+
+/*
+ * Support for select()
+ */
+
+struct _oss_poll_event_t
+{
+ short events, revents;
+ struct pollhead *php;
+ int anyyet;
+};
+typedef struct _oss_poll_event_t oss_poll_event_t;
+
+#define ALLOW_SELECT
+#define SEL_IN 0
+#define SEL_OUT 1
+#define SEL_EX 0xffffffff
+
+/*
+ * Sleep/wakeup
+ */
+
+#ifdef _KERNEL
+struct oss_wait_queue
+{
+ sv_t *sv;
+ short pollevents;
+ volatile unsigned int flags;
+};
+#endif
+
+#define FP_SUPPORT
+
+#ifdef FP_SUPPORT
+typedef short fp_env_t[512];
+typedef unsigned int fp_flags_t[4];
+extern int oss_fp_check (void);
+extern void oss_fp_save (short *envbuf, fp_flags_t flags);
+extern void oss_fp_restore (short *envbuf, fp_flags_t flags);
+# define FP_SAVE(envbuf, flags) oss_fp_save(envbuf, flags)
+# define FP_RESTORE(envbuf, flags) oss_fp_restore(envbuf, flags)
+#endif
+
+/* Busy wait routine */
+#define oss_udelay drv_usecwait
+/* System wall timer access */
+#define GET_JIFFIES() TICKS()
+
+#ifdef MUTEX_CHECKS
+extern void push_mutex (void *mutex, const char *file, int line);
+extern void pop_mutex (void *mutex, const char *file, int line);
+extern void print_mutexes (void);
+#else
+#define push_mutex(a, b, c)
+#define pop_mutex(a, b, c)
+#endif
+
+#ifdef _LOCKTEST
+# define MUTEX_INIT(osdev, mutex, hier) \
+ {\
+ static LKINFO_DECL(mtx_name, __FILE__ ":" #mutex, 0);\
+ mutex=LOCK_ALLOC((uchar_t)(hier), pldisk, &mtx_name, KM_SLEEP);\
+ }
+#else
+# define MUTEX_INIT(osdev, mutex, hier) \
+ {\
+ mutex=LOCK_ALLOC((uchar_t)(hier), pldisk, NULL, KM_SLEEP);\
+ }
+#endif
+
+#define MUTEX_CLEANUP(mutex) LOCK_DEALLOC(mutex)
+#define MUTEX_ENTER_IRQDISABLE(mutex, flags) {push_mutex(mutex, __FILE__, __LINE__);flags=LOCK(mutex, pldisk);}
+#define MUTEX_ENTER(mutex, flags) {push_mutex(mutex, __FILE__, __LINE__);flags=LOCK(mutex, pldisk);}
+#define MUTEX_EXIT_IRQRESTORE(mutex, flags) {pop_mutex(mutex, __FILE__, __LINE__);UNLOCK(mutex, flags);}
+#define MUTEX_EXIT(mutex, flags) {pop_mutex(mutex, __FILE__, __LINE__);UNLOCK(mutex, flags);}
+
+/*
+ * Move bytes from the buffer which the application given in a
+ * write() call.
+ * offs is position relative to the beginning of the buffer in
+ * user space. The count is number of bytes to be moved.
+ */
+#define COPY_FROM_USER(target, source, offs, count) \
+ if (uiomove((target), count, UIO_WRITE, source)) { \
+ cmn_err(CE_WARN, "Bad copyin()!\n"); \
+ }
+/* Like COPY_FOM_USER but for writes. */
+#define COPY_TO_USER(target, offs, source, count) \
+ if (uiomove((source), count, UIO_READ, target)) { \
+ cmn_err(CE_WARN, "Bad copyout()!\n"); \
+ }
+
+/*
+ * INB() and OUTB() should be obvious. NOTE! The order of
+ * paratemeters of OUTB() is different than on some other
+ * operating systems.
+ */
+
+/* I/O Mapped devices */
+#define INB(o, p) inb(p)
+#define INW(o, p) inw(p)
+#define INL(o, p) inl(p)
+
+#define OUTB(o, v, p) outb(p,v)
+#define OUTW(o, v, p) outw(p,v)
+#define OUTL(o, v, p) outl(p,v)
+
+/* Memory Mapped devices */
+#define PCI_READB(osdev, addr) *(volatile unsigned char *)(addr)
+#define PCI_READW(osdev, addr) *(volatile unsigned short *)(addr)
+#define PCI_READL(osdev, addr) *(volatile unsigned int *)(addr)
+
+#define PCI_WRITEB(osdev, addr, data) *(volatile unsigned char *)(addr)=data
+#define PCI_WRITEW(osdev, addr, data) *(volatile unsigned short *)(addr)=data
+#define PCI_WRITEL(osdev, addr, data) *(volatile unsigned int *)(addr)=data
+
+#ifndef TRUE
+#define TRUE (1)
+#define FALSE (0)
+#endif
+
+/*
+ KERNEL_MALLOC() allocates requested number of memory and
+ KERNEL_FREE is used to free it.
+ These macros are never called from interrupt, in addition the
+ nbytes will never be more than 4096 bytes. Generally the driver
+ will allocate memory in blocks of 4k. If the kernel has just a
+ page level memory allocation, 4K can be safely used as the size
+ (the nbytes parameter can be ignored).
+*/
+#ifdef MEMDEBUG
+extern void *oss_kmem_alloc (size_t size, int flags, char *file, int line);
+extern void oss_kmem_free (void *addr, char *file, int line);
+# define KERNEL_MALLOC(nbytes) oss_kmem_alloc(nbytes, KM_SLEEP, __FILE__, __LINE__)
+# define KERNEL_FREE(addr) oss_kmem_free(addr, __FILE__, __LINE__)
+#else
+extern void *oss_kmem_alloc (size_t size, int flags);
+extern void oss_kmem_free (void *addr);
+# define KERNEL_MALLOC(nbytes) oss_kmem_alloc(nbytes, KM_SLEEP)
+# define KERNEL_FREE(addr) oss_kmem_free(addr)
+#endif
+
+typedef void *oss_dma_handle_t;
+
+extern void *oss_contig_malloc (oss_device_t * osdev, int sz,
+ oss_uint64_t memlimit,
+ oss_native_word * phaddr);
+extern void oss_contig_free (oss_device_t * osdev, void *p, int sz);
+extern oss_native_word oss_virt_to_bus (void *addr);
+#define CONTIG_MALLOC(osdev, sz, memlimit, phaddr, handle) oss_contig_malloc(osdev, sz, memlimit, phaddr)
+#define CONTIG_FREE(osdev, p, sz, handle) oss_contig_free(osdev, p, sz)
+
+/*
+ * Timer macros
+ *
+ * These macros are obsolete and should not be used in any new code.
+ * Use the timeout mechanism (see the timeout(9F) Solaris man page).
+ */
+#define timeout(fn, arg, ticks) itimeout(fn, arg, ticks, pltimeout)
+typedef int timeout_id_t;
+#define DEFINE_TIMER(name, proc) static timeout_id_t name = 0
+#define REMOVE_TIMER(name, proc) {if (name != 0) untimeout(name);}
+#define INIT_TIMER(name,proc)
+typedef void (*timeout_func_t) (void *);
+#define ACTIVATE_TIMER(name, proc, time) \
+ name=timeout((timeout_func_t)proc, (void*)&name, time)
+
+#ifdef _KERNEL
+struct os_dma_params
+{
+ int state; /* 0=unavail, 1=avail, 2=busy */
+ oss_device_t *osdev;
+ void *orig_buf;
+
+ volatile int enabled, ignore;
+};
+#define OS_DMA_PARMS \
+ struct os_dma_params dma_parms;
+#endif
+#endif
+struct fileinfo
+{
+ int mode; /* Open mode */
+ int acc_flags;
+};
+#define ISSET_FILE_FLAG(fileinfo, flag) (fileinfo->acc_flags & (flag) ? 1:0)
+
+#define OSS_OS "SCO"
+#define OSS_OS_LONGNAME "SCO OpenServer/UnixWare"
+
+#undef DMA_TRY_PSEUDOINIT
+
+int get_dma_residue (int chn);
+void disable_dma (int chn);
+void enable_dma (int chn);
+
+typedef void (*softintr_func_t) (int);
+
+struct oss_softintr
+{
+ int id;
+ softintr_func_t func;
+ volatile int armed, running;
+};
+
+#undef ALLOW_BUFFER_MAPPING
+
+#undef SMALL_DMABUF_SIZE
+#define SMALL_DMABUF_SIZE (16*1024)
+
+extern int detect_trace;
+#define DDB(x) if (detect_trace) x
+
+#define MAP_PCI_IOADDR(osdev, nr, io) io
+#define MAP_PCI_MEM(osdev, ix, phaddr, size) devmem_mapin(osdev->key, ix, 0, size)
+#define UNMAP_PCI_MEM(osdev, ix, ph, virt, size) devmem_mapout(virt, size)
+#define UNMAP_PCI_IOADDR(osdev, ix) {}
+#define GET_PROCESS_PID(x) -1
+#define GET_PROCESS_NAME(x) NULL
+
+#define abs(x) ((x) >= 0 ? (x) : -(x))
+
+#ifdef _KERNEL
+extern void *oss_memset (void *s, int c, size_t n);
+#define memset oss_memset
+
+extern void *oss_memcpy (void *s1, const void *s2, size_t n);
+#define memcpy oss_memcpy
+int oss_sprintf (char *buf, char *cfmt, ...);
+#define sprintf oss_sprintf
+
+extern int oss_open (void *idata, channel_t * channelp,
+ int oflags, cred_t * crp, queue_t * q);
+extern int oss_close (void *idata, channel_t channel,
+ int oflags, cred_t * crp, queue_t * q);
+extern int oss_ioctl (void *idata, channel_t channel, int cmd, void *arg,
+ int oflags, cred_t * crp, int *rvalp);
+extern int oss_devinfo (void *idata, channel_t channel, di_parm_t parm,
+ void *valp);
+extern void oss_biostart (void *idata, channel_t channel, buf_t * bp);
+
+#endif
diff --git a/kernel/OS/SunOS/.config b/kernel/OS/SunOS/.config
new file mode 100644
index 0000000..816ac62
--- /dev/null
+++ b/kernel/OS/SunOS/.config
@@ -0,0 +1 @@
+mode=kernel
diff --git a/kernel/OS/SunOS/module.inc b/kernel/OS/SunOS/module.inc
new file mode 100644
index 0000000..a522492
--- /dev/null
+++ b/kernel/OS/SunOS/module.inc
@@ -0,0 +1,389 @@
+/*
+ * Purpose: OSS module wrapper for Solaris
+ *
+ * This file will be included from the auto-generated drv_cfg.c files. Under
+ * Solaris this file will be compiled in the development system.
+ */
+/*
+ *
+ * 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 <sys/types.h>
+#include <sys/modctl.h>
+#include <sys/kmem.h>
+#include <sys/conf.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+
+static int ossdrv_getinfo (dev_info_t *, ddi_info_cmd_t, void *, void **);
+static int ossdrv_attach (dev_info_t *, ddi_attach_cmd_t);
+static int ossdrv_detach (dev_info_t *, ddi_detach_cmd_t);
+
+#ifdef OSS_POWER_MANAGE
+static int ossdrv_power (dev_info_t *, int component, int level);
+#endif
+
+/* Entry points structure */
+#if DRIVER_TYPE!=DRV_STREAMS
+
+static struct cb_ops ossdrv_cb_ops = {
+ oss_open,
+ oss_close,
+ nodev, /* not a block driver */
+ nodev, /* no print routine */
+ nodev, /* no dump routine */
+ oss_read,
+ oss_write,
+ oss_ioctl,
+#ifdef ALLOW_BUFFER_MAPPING
+ oss_devmap,
+#else
+ nodev, /* no devmap routine */
+#endif
+ nodev,
+ nodev, /* no segmap routine */
+ oss_chpoll, /* no chpoll routine */
+ ddi_prop_op,
+ 0, /* not a STREAMS driver */
+ D_NEW | D_MP | D_64BIT, /* safe for multi-thread/multi-processor */
+ CB_REV
+};
+#else
+extern struct streamtab DRIVER_STR_INFO;
+
+struct cb_ops ossdrv_streams_cb_ops = {
+ nulldev,
+ nulldev,
+ nodev, /* not a block driver */
+ nodev, /* no print routine */
+ nodev, /* no dump routine */
+ nodev,
+ nodev,
+ nodev,
+ nodev, /* no devmap routine */
+ nodev,
+ nodev, /* no segmap routine */
+ nochpoll, /* no chpoll routine */
+ ddi_prop_op,
+ &DRIVER_STR_INFO, /* cb_str */
+ D_NEW | D_MP | D_64BIT, /* safe for multi-thread/multi-processor */
+ CB_REV,
+ nodev, /* cb_aread */
+ nodev, /* cb_awrite */
+};
+#endif
+
+static struct dev_ops ossdrv_dev_ops = {
+ DEVO_REV, /* devo_rev */
+ 0, /* devo_refcnt */
+ ossdrv_getinfo, /* devo_getinfo */
+ nulldev, /* devo_identify - obsolete */
+#if DRIVER_TYPE==DRV_ISA
+ ossdrv_probe,
+#else
+ nulldev, /* devo_probe */
+#endif
+ ossdrv_attach, /* devo_attach */
+ ossdrv_detach, /* devo_detach */
+ nodev, /* devo_reset */
+#if DRIVER_TYPE==DRV_STREAMS
+ &ossdrv_streams_cb_ops, /* devi_cb_ops */
+#else
+ &ossdrv_cb_ops, /* devi_cb_ops */
+#endif
+ NULL, /* devo_bus_ops */
+#ifdef OSS_POWER_MANAGE
+ ossdrv_power
+#else
+ NULL /* devo_power */
+#endif
+};
+
+static struct modldrv ossdrv_modldrv = {
+ &mod_driverops, /* drv_modops */
+ "OSS " OSS_VERSION_STRING,
+ &ossdrv_dev_ops, /* drv_dev_ops */
+};
+
+static struct modlinkage ossdrv_modlinkage = {
+ MODREV_1, /* ml_rev */
+ (void *) &ossdrv_modldrv, /* ml_linkage */
+ NULL /* NULL terminates the list */
+};
+
+/*
+ * _init, _info, and _fini support loading and unloading the driver.
+ */
+int
+_init (void)
+{
+ int error;
+
+ error = mod_install (&ossdrv_modlinkage);
+
+ return error;
+}
+
+int
+_fini (void)
+{
+ int error;
+
+ error = mod_remove (&ossdrv_modlinkage);
+ return error;
+}
+
+int
+_info (struct modinfo *modinfop)
+{
+ int error;
+
+ error = mod_info (&ossdrv_modlinkage, modinfop);
+
+ return error;
+}
+
+/*ARGSUSED*/
+static int
+ossdrv_getinfo (dev_info_t * dontcare_dip, ddi_info_cmd_t cmd, void *arg,
+ void **result)
+{
+ dev_t dev;
+ register int error;
+ int instance;
+ dev_info_t *dip;
+#ifndef SOL9
+ oss_cdev_t *cdev;
+ int minor;
+
+ dev = (dev_t) arg;
+
+ minor = getminor (dev);
+
+ if (minor >= oss_num_cdevs)
+ {
+ *result = NULL;
+ return DDI_FAILURE;
+ }
+
+ if ((cdev = oss_cdevs[minor]) == NULL || cdev->osdev == NULL)
+ {
+ *result = NULL;
+ return DDI_FAILURE;
+ }
+
+ dip = cdev->osdev->dip;
+#else
+ dip = dontcare_dip;
+#endif
+
+ if (dip == NULL)
+ {
+ /* cmn_err (CE_WARN, "ossdrv_getinfo: dip==NULL\n"); */
+ return DDI_FAILURE;
+ }
+
+ instance = ddi_get_instance (dip);
+
+ switch (cmd)
+ {
+ case DDI_INFO_DEVT2DEVINFO:
+ *result = dip;
+ error = DDI_SUCCESS;
+ break;
+ case DDI_INFO_DEVT2INSTANCE:
+ *result = (void *) (long)instance;
+ error = DDI_SUCCESS;
+ break;
+ default:
+ *result = NULL;
+ error = DDI_FAILURE;
+ }
+
+ DDB (cmn_err (CE_CONT,
+ "oss_getinfo: returns %d, result=%lx instance=%d dev=%x\n",
+ error, (unsigned long)*result, instance, (unsigned int)dev));
+ return error;
+}
+
+static int
+ossdrv_attach (dev_info_t * dip, ddi_attach_cmd_t cmd)
+{
+ int instance;
+ oss_device_t *osdev;
+
+#ifdef OSS_SUSPEND_RESUME
+ if (cmd != DDI_RESUME) /* Allow resume */
+#endif
+ if (cmd != DDI_ATTACH)
+ {
+ cmn_err (CE_WARN, "bad attach cmd %d\n", cmd);
+ return 0;
+ }
+
+ if (dip == NULL)
+ {
+ cmn_err (CE_WARN, "ossdrv_attach: dip==NULL\n");
+ return DDI_FAILURE;
+ }
+
+#ifdef OSS_SUSPEND_RESUME
+ if (cmd == DDI_RESUME)
+ {
+ if ((osdev = (oss_device_t *) ddi_get_driver_private (dip)) == NULL)
+ {
+ cmn_err (CE_WARN, "ddi_get_driver_private() failed\n");
+ return DDI_SUCCESS;
+ }
+ if (!DRIVER_RESUME(osdev))
+ return DDI_FAILURE;
+
+ return DDI_SUCCESS;
+ }
+#endif
+
+ instance = ddi_get_instance (dip);
+ DDB (cmn_err
+ (CE_CONT, "Attach started " DRIVER_NICK "%d (%s)\n", instance,
+ ddi_get_name (dip)));
+
+ if ((osdev =
+ osdev_create (dip, DRIVER_TYPE, instance, DRIVER_NICK, NULL)) == NULL)
+ {
+ return DDI_FAILURE;
+ }
+
+ oss_load_options (osdev, oss_global_options);
+ oss_load_options (osdev, local_driver_options);
+
+#if DRIVER_TYPE==DRV_PCI || DRIVER_TYPE == DRV_ISA
+ {
+ int err;
+ if ((err =
+ ddi_get_iblock_cookie (dip, 0, &osdev->iblock_cookie)) != DDI_SUCCESS)
+ {
+ cmn_err (CE_WARN, "Cannot get iblock cookie (%d)\n", err);
+ return DDI_FAILURE;
+ }
+ }
+#else
+/* NOTE! The USB driver (actually udi.c) will call usb_get_data() to obtain */
+/* the iblock_cookie. There is no need to do that here. */
+ osdev->iblock_cookie = 0;
+#endif
+
+ if (!DRIVER_ATTACH (osdev))
+ {
+ cmn_err (CE_WARN, "Attach failed\n");
+ osdev_delete (osdev);
+ return DDI_FAILURE;
+ }
+
+ ddi_set_driver_private (dip, (caddr_t) osdev);
+ ddi_report_dev (dip);
+#if DRIVER_TYPE != DRV_USB
+ oss_audio_delayed_attach ();
+#endif
+
+ DDB (cmn_err (CE_CONT, "Attach done " DRIVER_NICK "%d\n", instance));
+
+ return DDI_SUCCESS;
+}
+
+static int
+ossdrv_detach (dev_info_t * dip, ddi_detach_cmd_t cmd)
+{
+ oss_device_t *osdev;
+
+#ifdef OSS_SUSPEND_RESUME
+ if (cmd != DDI_SUSPEND) /* Allow suspend */
+#endif
+ if (cmd != DDI_DETACH)
+ {
+ cmn_err (CE_WARN, "bad detach cmd %d\n", cmd);
+ return 0;
+ }
+
+ if (dip == NULL)
+ {
+ cmn_err (CE_WARN, "ossdrv_detach: dip==NULL\n");
+ return DDI_FAILURE;
+ }
+//cmn_err(CE_CONT, "Detach started " DRIVER_NICK "\n");
+
+ DDB (cmn_err
+ (CE_CONT, "Detach started " DRIVER_NICK "(%s)\n", ddi_get_name (dip)));
+ if ((osdev = (oss_device_t *) ddi_get_driver_private (dip)) == NULL)
+ {
+ cmn_err (CE_WARN, "ddi_get_driver_private() failed\n");
+ return DDI_SUCCESS;
+ }
+
+ if (osdev==NULL)
+ {
+ cmn_err (CE_WARN, "Driver osdev==NULL - cannot detach\n");
+ return DDI_FAILURE;
+ }
+
+#ifdef OSS_SUSPEND_RESUME
+ if (cmd == DDI_SUSPEND)
+ {
+ if (!DRIVER_SUSPEND(osdev))
+ return DDI_FAILURE;
+ return DDI_SUCCESS;
+ }
+#endif
+
+ if (DRIVER_DETACH (osdev) <= 0)
+ {
+ cmn_err (CE_WARN, "Driver busy - cannot detach\n");
+ return DDI_FAILURE;
+ }
+
+#if DRIVER_TYPE!=DRV_VMIX
+ osdev_delete (osdev);
+#endif
+
+ DDB (cmn_err (CE_CONT, "Detach done " DRIVER_NICK "\n"));
+ return DDI_SUCCESS;
+}
+
+#ifdef OSS_POWER_MANAGE
+static int
+ossdrv_power (dev_info_t *dip, int component, int level)
+{
+ oss_device_t *osdev;
+
+ if (dip == NULL)
+ {
+ cmn_err (CE_WARN, "ossdrv_detach: dip==NULL\n");
+ return DDI_FAILURE;
+ }
+
+ DDB (cmn_err
+ (CE_CONT, "ossdrv_power " DRIVER_NICK "(%s, %d, %d)\n", ddi_get_name (dip), component, level));
+ if ((osdev = (oss_device_t *) ddi_get_driver_private (dip)) == NULL)
+ {
+ cmn_err (CE_WARN, "ddi_get_driver_private() failed\n");
+ return DDI_SUCCESS;
+ }
+
+ if (osdev==NULL)
+ {
+ cmn_err (CE_WARN, "Driver osdev==NULL - cannot detach\n");
+ return DDI_FAILURE;
+ }
+
+ if (!DRIVER_POWER(osdev, component, level))
+ return DDI_FAILURE;
+
+ return DDI_SUCCESS;
+}
+#endif
diff --git a/kernel/OS/SunOS/os_solaris.c b/kernel/OS/SunOS/os_solaris.c
new file mode 100644
index 0000000..b4ceac3
--- /dev/null
+++ b/kernel/OS/SunOS/os_solaris.c
@@ -0,0 +1,2401 @@
+/*
+ * Purpose: Operating system abstraction functions for Solaris
+ */
+/*
+ *
+ * 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"
+#include <oss_pci.h>
+#if !defined(SOL9) && !defined(SOL8)
+#include <sys/sunldi.h>
+#endif
+#include <sys/mman.h>
+
+#if 1
+/*
+ * Some older DDI routines are used by OSS instead of the latest ones.
+ * In this way the same OSS binary can be run both under Sol10 and Sol11.
+ */
+uint16_t ddi_mem_get16 (ddi_acc_handle_t handle, uint16_t * host_addr);
+uint32_t ddi_mem_get32 (ddi_acc_handle_t handle, uint32_t * host_addr);
+void ddi_mem_put16 (ddi_acc_handle_t handle, uint16_t * dev_addr,
+ uint16_t value);
+void ddi_mem_put32 (ddi_acc_handle_t handle, uint32_t * dev_addr,
+ uint32_t value);
+int ddi_mem_alloc (dev_info_t * dip, ddi_dma_lim_t * limits, uint_t length,
+ uint_t flags, caddr_t * kaddrp, uint_t * real_length);
+void ddi_mem_free (caddr_t kaddr);
+#endif
+
+#if 0
+/* TODO: Disable this debugging stuff */
+unsigned char tmp_status = 0;
+# define UP_STATUS(v) OUTB(NULL, (tmp_status=tmp_status|(v)), 0x378)
+# define DOWN_STATUS(v) OUTB(NULL, (tmp_status=tmp_status&~(v)), 0x378)
+#else
+# define UP_STATUS(v)
+# define DOWN_STATUS(v)
+#endif
+
+static int oss_expired = 0;
+
+static oss_mutex_t osscore_mutex;
+
+#define TRC(x)
+#define TRC2(x)
+
+#define FIX_RET_VALUE(ret) (((ret)<0) ? -(ret) : 0)
+
+static volatile int open_devices = 0;
+static volatile int do_forceload = 0;
+static volatile int forceload_in_progress = 0;
+
+/*
+ * MAX_CARDS must be larger than life. The system will panic if there are
+ * more sound devices (cards os sound chips) than MAX_CARDS.
+ */
+#define MAX_CARDS 32
+
+static oss_device_t *cards[MAX_CARDS];
+int oss_num_cards = 0;
+
+int oss_detach_enabled = 0;
+
+#ifdef MUTEX_CHECKS
+static volatile int inside_intr = 0; /* For mutex debugging only */
+#endif
+
+/*
+ * These are the entry points into our driver that are called when the
+ * driver is loaded, during a system call, or in response to an interrupt.
+ */
+static int oss_getinfo (dev_info_t * dip, ddi_info_cmd_t infocmd, void *arg,
+ void **result);
+static int oss_attach (dev_info_t * dip, ddi_attach_cmd_t cmd);
+static int oss_detach (dev_info_t * dip, ddi_detach_cmd_t cmd);
+static void free_all_contig_memory (void);
+
+/*
+ * DMA memory management
+ */
+
+typedef struct contig_desc
+{
+ int is_special;
+ struct contig_desc *next;
+ unsigned char *first_addr, *last_addr;
+ unsigned long physaddr;
+ void *orig_buf;
+
+ oss_device_t *osdev;
+ ddi_dma_handle_t handle;
+ ddi_dma_handle_t dhandle;
+ ddi_acc_handle_t dma_acc_handle;
+ ddi_dma_cookie_t cookie;
+ ddi_dma_win_t win;
+ ddi_dma_seg_t seg;
+ size_t size;
+}
+contig_desc;
+
+static contig_desc *contig_list = NULL;
+
+#ifdef MEMDEBUG
+typedef struct
+{
+ void *addr;
+ int size;
+ char file[40];
+ int line;
+} mem_block_t;
+
+#define MAX_MEMBLOCKS 1024
+
+static mem_block_t memblocks[MAX_MEMBLOCKS];
+static int num_memblocks = 0;
+#endif
+
+#define CDEV_NUMHASH 79 // Prime number
+static oss_cdev_t *cdev_hash[CDEV_NUMHASH] = {NULL};
+#define compute_cdev_hash(dev_class, instance) (dev_class*13+instance) % CDEV_NUMHASH
+
+static void
+unlink_cdev_hash(oss_cdev_t *this_cdev)
+{
+ oss_cdev_t *cdev = cdev_hash[compute_cdev_hash(this_cdev->dev_class, this_cdev->instance)];
+
+ if (cdev == this_cdev) // First in the hash chain
+ {
+ cdev_hash[compute_cdev_hash(this_cdev->dev_class, this_cdev->instance)] = cdev->hl;
+ return;
+ }
+
+ while (cdev != NULL)
+ {
+ if (cdev->hl == this_cdev)
+ {
+ cdev->hl = this_cdev->hl;
+ return;
+ }
+
+ cdev = cdev->hl;
+ }
+
+ cmn_err(CE_WARN, "unlink_cdev_hash: Cannot find cdev %p\n", this_cdev);
+}
+
+#if 1
+/*
+ * Unfortunately this handy function is not safe (incompatibilities
+ * between kenel versions/builds). So let's hope it gets moved to
+ * the kernel.
+ */
+char *
+oss_get_procname (void) /* Return the command name of the current thread */
+{
+ return ttoproc (curthread)->p_user.u_comm;
+}
+#endif
+
+#ifdef MEMDEBUG
+void *
+oss_kmem_alloc (size_t size, int flags, char *file, int line)
+#else
+void *
+oss_kmem_alloc (size_t size, int flags)
+#endif
+{
+/*
+ * This routine allocates a memory block and stores length of it in
+ * the beginning. This length information can be used when later unallocating
+ * the memory.
+ */
+
+ char *ptr;
+ uint64_t *len;
+
+ ptr = kmem_zalloc (size + sizeof (uint64_t), flags);
+
+ if (ptr == NULL)
+ return NULL;
+
+ len = (uint64_t *) ptr;
+
+ ptr += sizeof (uint64_t);
+ *len = size + sizeof (uint64_t);
+
+#ifdef MEMDEBUG
+#if 1
+ {
+ int i;
+ for (i = 0; i < num_memblocks; i++)
+ if (memblocks[i].addr == NULL)
+ {
+ memblocks[i].addr = ptr;
+ memblocks[i].size = size;
+ strncpy (memblocks[i].file, file, 39);
+ memblocks[i].line = line;
+ return ptr;
+ }
+ }
+#endif
+
+ if (num_memblocks < MAX_MEMBLOCKS)
+ {
+ memblocks[num_memblocks].addr = ptr;
+ memblocks[num_memblocks].size = size;
+ strncpy (memblocks[num_memblocks].file, file, 39);
+ memblocks[num_memblocks].line = line;
+ num_memblocks++;
+ }
+#endif
+
+ return ptr;
+}
+
+void
+oss_kmem_free (void *addr)
+{
+ uint64_t *len;
+
+ char *ptr = addr;
+
+ if (addr == NULL)
+ return;
+
+ ptr -= sizeof (uint64_t);
+
+ len = (uint64_t *) ptr;
+
+ kmem_free (ptr, *len);
+#ifdef MEMDEBUG
+ {
+ int i;
+
+ for (i = 0; i < num_memblocks; i++)
+ if (addr == memblocks[i].addr)
+ {
+ memblocks[i].addr = NULL;
+ break;
+ }
+ }
+#endif
+}
+
+static const ddi_dma_attr_t dma_attr_pci = {
+ DMA_ATTR_V0, // Version
+ 0x00000000ULL, // Address low
+ 0xfffffff0ULL, // Address high
+ 0xffffffffULL, // Counter max
+ 1ULL, // Default byte align
+ 0x7f, // Burst size
+ 0x1, // Minimum xfer size
+ 0xffffffffULL, // Maximum xfer size
+ 0xffffffffULL, // Max segment size
+ 1, // S/G list length
+ 1, // Granularity
+ 0 // Flag
+};
+
+#if !defined(SOL9) && !defined(SOL8)
+static void
+forceload_drivers (dev_t dev, cred_t * credp)
+{
+/*
+ * This routine will be called whenever the first application tries
+ * to access OSS devices. It's purpose is to load all the drivers
+ * just in case they have not been loaded yet. In this way it's possible to
+ * guarantee that the audio device numbering doesn't change between
+ * reboots.
+ */
+ char path[20];
+
+ int i, err;
+ ldi_handle_t lh;
+ ldi_ident_t li;
+ DDB (cmn_err (CE_NOTE, "Forceloading OSS devices\n"));
+
+ if (ldi_ident_from_dev (dev, &li) != 0)
+ {
+ cmn_err (CE_NOTE, "ldi_ident_from_dev failed\n");
+ return;
+ }
+
+ if ((err = ldi_open_by_name ("/dev/sndstat", FWRITE, credp, &lh, li)) != 0)
+ {
+ if (err != ENODEV)
+ cmn_err (CE_NOTE, "Forceload error %d (/dev/sndstat)\n", err);
+ }
+ else
+ err = ldi_close (lh, FWRITE, credp);
+
+ for (i = 0; i < MAX_MIXER_DEV; i++)
+ {
+ sprintf (path, "/dev/mixer%d", i);
+
+ if ((err = ldi_open_by_name (path, FWRITE, credp, &lh, li)) != 0)
+ {
+ if (err != ENODEV)
+ cmn_err (CE_NOTE, "Forceload error %d\n", err);
+ }
+ else
+ err = ldi_close (lh, FWRITE, credp);
+ }
+
+ for (i = 0; i < MAX_AUDIO_DEVFILES; i++)
+ {
+ sprintf (path, "/dev/dsp%d", i);
+
+ if ((err = ldi_open_by_name (path, FWRITE, credp, &lh, li)) != 0)
+ {
+ if (err != ENODEV)
+ cmn_err (CE_NOTE, "Forceload error %d\n", err);
+ }
+ else
+ err = ldi_close (lh, FWRITE, credp);
+ }
+
+ ldi_ident_release (li);
+ DDB (cmn_err (CE_NOTE, "Forceloading OSS devices done\n"));
+}
+
+void
+oss_forceload_drivers (int dev, cred_t * cred_p)
+{
+
+ if (do_forceload)
+ {
+ do_forceload = 0;
+ forceload_in_progress = 1;
+ forceload_drivers (dev, cred_p);
+ forceload_in_progress = 0;
+ }
+}
+#endif
+
+/*ARGSUSED*/
+int
+oss_open (dev_t * dev_p, int open_flags, int otyp, cred_t * cred_p)
+{
+ int retval;
+ dev_t dev = *dev_p;
+ oss_cdev_t *cdev;
+ int tmpdev, maj;
+ oss_native_word flags;
+
+#ifdef DO_TIMINGS
+ oss_timing_printf ("**** oss_open(%x) ****", getminor (dev));
+#endif
+//cmn_err(CE_CONT, "**** oss_open(%x) ****\n", getminor (dev));
+//cmn_err(CE_CONT, " PID %d, cmd %s\n", GET_PROCESS_PID(x), GET_PROCESS_NAME(x));
+ maj = getmajor (dev);
+ dev = getminor (dev);
+
+#if !defined(SOL9) && !defined(SOL8)
+/*
+ * Handle driver forceload
+ */
+
+ if (forceload_in_progress)
+ return ENODEV;
+
+ oss_forceload_drivers (dev, cred_p);
+#endif
+
+ if (dev >= OSS_MAX_CDEVS)
+ return ENXIO;
+
+ if (dev >= oss_num_cdevs)
+ {
+ return ENODEV;
+ }
+
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d == NULL)
+ return ENODEV;
+
+ if (cdev->d->open == NULL)
+ {
+ return ENODEV;
+ }
+
+ memset (&cdev->file, 0, sizeof (cdev->file));
+ cdev->file.mode = 0;
+ cdev->file.acc_flags = open_flags;
+
+ if (open_flags & FREAD && open_flags & FWRITE)
+ cdev->file.mode = OPEN_READWRITE;
+ else if (open_flags & FREAD)
+ cdev->file.mode = OPEN_READ;
+ else if (open_flags & FWRITE)
+ cdev->file.mode = OPEN_WRITE;
+
+ tmpdev = dev;
+ retval =
+ cdev->d->open (cdev->instance, cdev->dev_class, &cdev->file, 0, 0, &tmpdev);
+ *dev_p = makedevice (maj, tmpdev);
+ dev = tmpdev;
+
+ if (retval < 0)
+ {
+ return -retval;
+ }
+
+ MUTEX_ENTER_IRQDISABLE (osscore_mutex, flags);
+ open_devices++;
+ cdev = oss_cdevs[dev]; /* Switch to the cdev that was actually opened */
+
+ cdev->open_count++;
+ if (open_flags & FREAD && open_flags & FWRITE)
+ cdev->file.mode = OPEN_READWRITE;
+ else if (open_flags & FREAD)
+ cdev->file.mode = OPEN_READ;
+ else if (open_flags & FWRITE)
+ cdev->file.mode = OPEN_WRITE;
+
+ oss_reserve_device (cdev->osdev);
+//cmn_err(CE_CONT, "Increment open_devices=%d, refcount=%d\n", open_devices, cdev->osdev->refcount);
+ MUTEX_EXIT_IRQRESTORE (osscore_mutex, flags);
+
+ return 0;
+}
+
+/*ARGSUSED*/
+int
+oss_close (dev_t dev, int flag, int otyp, cred_t * cred_p)
+{
+ oss_cdev_t *cdev;
+ oss_native_word flags;
+#ifdef DO_TIMINGS
+ oss_timing_printf ("***** oss_close(%x) ****", getminor (dev));
+#endif
+//cmn_err(CE_CONT, "***** oss_close(%x) ****\n", getminor (dev));
+//cmn_err(CE_CONT, " PID %d, cmd %s\n", GET_PROCESS_PID(x), GET_PROCESS_NAME(x));
+
+ if (getminor (dev) >= OSS_MAX_CDEVS)
+ {
+ cmn_err (CE_NOTE, "Closing bad minor %d\n", getminor (dev));
+ return ENXIO;
+ }
+
+ dev = getminor (dev);
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d == NULL)
+ {
+ cmn_err (CE_NOTE, "Closing undefined minor %d\n", getminor (dev));
+ return ENXIO;
+ }
+
+
+ if (cdev->open_count == 0) /* Not opened */
+ {
+ cmn_err (CE_NOTE, "Closing minor %d that is not open\n", dev);
+ return 0;
+ }
+
+ cdev->d->close (cdev->instance, &cdev->file);
+
+ MUTEX_ENTER_IRQDISABLE (osscore_mutex, flags);
+ open_devices -= cdev->open_count;
+//cmn_err(CE_CONT, "Decrement open_devices=%d\n", open_devices);
+ oss_unreserve_device (cdev->osdev, cdev->open_count);
+ cdev->open_count = 0;
+ MUTEX_EXIT_IRQRESTORE (osscore_mutex, flags);
+ return 0;
+}
+
+/*ARGSUSED*/
+int
+oss_ioctl (dev_t dev, int cmd, intptr_t arg, int mode, cred_t * cred_p,
+ int *rval_p)
+{
+ int retval;
+ int len = 0;
+ char b[4096], *buf = b;
+ oss_cdev_t *cdev;
+#ifdef DO_TIMINGS
+ oss_timing_printf ("OSS ioctl(%x, %x, %x)", getminor (dev), cmd, arg);
+#endif
+
+ *rval_p = 0;
+
+ dev = getminor (dev);
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d->ioctl == NULL)
+ return ENXIO;
+
+ if (cdev->open_count == 0) /* Not opened */
+ {
+ cmn_err (CE_NOTE, "Call to ioctl on minor %d that is not open\n", dev);
+ return ENXIO;
+ }
+
+ if (oss_expired)
+ return ENODEV;
+
+ if (mode & FKIOCTL) /* Called from kernel space */
+ buf = (char *) arg;
+ else if (cmd & (SIOC_OUT | SIOC_IN))
+ {
+
+ len = (cmd >> 16) & SIOCPARM_MASK;
+ if (len < 0)
+ len = 0;
+ if (len > sizeof (b))
+ {
+ cmn_err (CE_WARN, "Bad ioctl buffer size %d\n", len);
+ return EFAULT;
+ }
+
+ if ((cmd & SIOC_IN) && len > 0)
+ {
+ if (copyin ((char *) arg, buf, len) == -1)
+ return EFAULT;
+ }
+
+ }
+
+ retval = cdev->d->ioctl (cdev->instance, &cdev->file, cmd, (ioctl_arg) buf);
+
+ if (!(mode & FKIOCTL)) /* Not called from kernel space */
+ if ((cmd & SIOC_OUT) && len > 0)
+ {
+ if (copyout (buf, (char *) arg, len) == -1)
+ return EFAULT;
+ }
+
+ return FIX_RET_VALUE (retval);
+}
+
+/*ARGSUSED*/
+int
+oss_read (dev_t dev, struct uio *uiop, cred_t * credp)
+{
+ int count = uiop->uio_resid;
+ int retval;
+ oss_cdev_t *cdev;
+
+ dev = getminor (dev);
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d->read == NULL)
+ return ENXIO;
+
+ if (cdev->open_count == 0) /* Not opened */
+ {
+ cmn_err (CE_NOTE, "Call to read on minor %d that is not open\n", dev);
+ return ENXIO;
+ }
+
+ cdev->file.acc_flags = uiop->uio_fmode;
+
+ retval = cdev->d->read (cdev->instance, &cdev->file, uiop, count);
+
+ return FIX_RET_VALUE (retval);
+}
+
+/*ARGSUSED*/
+int
+oss_write (dev_t dev, struct uio *uiop, cred_t * cred_p)
+{
+ int count = uiop->uio_resid;
+ int retval;
+ oss_cdev_t *cdev;
+
+ dev = getminor (dev);
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d->write == NULL)
+ return ENXIO;
+
+ if (cdev->open_count == 0) /* Not opened */
+ {
+ cmn_err (CE_NOTE, "Call to write on minor %d that is not open\n", dev);
+ return ENXIO;
+ }
+ cdev->file.acc_flags = uiop->uio_fmode;
+
+ retval = cdev->d->write (cdev->instance, &cdev->file, uiop, count);
+ return FIX_RET_VALUE (retval);
+}
+
+int
+oss_chpoll (dev_t dev, short events, int anyyet, short *reventsp,
+ struct pollhead **phpp)
+{
+ oss_cdev_t *cdev;
+ oss_poll_event_t ev;
+ int ret;
+
+#ifdef DO_TIMINGS
+ oss_timing_printf ("***** oss_chpoll(%x) ****", getminor (dev));
+#endif
+
+ if (getminor (dev) >= OSS_MAX_CDEVS)
+ return ENXIO;
+
+ dev = getminor (dev);
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d->chpoll == NULL)
+ return ENXIO;
+
+ if (cdev->open_count == 0) /* Not opened */
+ {
+ cmn_err (CE_NOTE, "Call to chpoll on minor %d that is not open\n", dev);
+ return ENXIO;
+ }
+
+ *reventsp = 0;
+ ev.events = events;
+ ev.anyyet = anyyet;
+ ev.revents = 0;
+ ev.php = NULL;
+
+ ret = cdev->d->chpoll (cdev->instance, &cdev->file, &ev);
+ if (ret < 0)
+ {
+ return -ret;
+ }
+
+ *reventsp |= ev.revents;
+ if (ev.php != NULL)
+ *phpp = ev.php;
+
+ return 0;
+}
+
+#ifdef ALLOW_BUFFER_MAPPING
+int
+oss_devmap (dev_t dev, devmap_cookie_t handle, offset_t off, size_t len,
+ size_t * maplen, uint_t model)
+{
+ oss_cdev_t *cdev;
+ oss_poll_event_t ev;
+ int ret;
+
+#ifdef DO_TIMINGS
+ oss_timing_printf ("***** oss_devmap(%x) ****", getminor (dev));
+#endif
+
+ if (getminor (dev) >= OSS_MAX_CDEVS)
+ {
+ return ENXIO;
+ }
+
+ dev = getminor (dev);
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d == NULL)
+ {
+ return ENXIO;
+ }
+
+ if (cdev->open_count == 0) /* Not opened */
+ {
+ cmn_err (CE_NOTE, "Call to devmap on minor %d that is not open\n", dev);
+ return EPERM;
+ }
+
+ if (cdev->dev_class != OSS_DEV_DSP && cdev->dev_class != OSS_DEV_DSP_ENGINE) /* Only audio devices can be mapped */
+ {
+ return ENXIO;
+ }
+
+ dev = cdev->instance;
+ if (dev < 0 || dev >= num_audio_engines)
+ return ENXIO;
+
+ return ENOTSUP;
+}
+#endif
+
+#if 0
+// Not used in misc modules.
+static struct cb_ops oss_cb_ops = {
+ oss_open,
+ oss_close,
+ nodev, /* not a block driver */
+ nodev, /* no print routine */
+ nodev, /* no dump routine */
+ oss_read,
+ oss_write,
+ oss_ioctl,
+#ifdef ALLOW_BUFFER_MAPPING
+ oss_devmap,
+#else
+ nodev, /* no devmap routine */
+#endif
+ nodev,
+ nodev, /* no segmap routine */
+ oss_chpoll, /* no chpoll routine */
+ ddi_prop_op,
+ 0, /* not a STREAMS driver */
+ D_NEW | D_MP | D_64BIT, /* safe for multi-thread/multi-processor */
+ CB_REV
+};
+
+static struct dev_ops oss_ops = {
+ DEVO_REV, /* DEVO_REV indicated by manual */
+ 0, /* device reference count */
+ oss_getinfo,
+ nulldev,
+ nulldev,
+ oss_attach,
+ oss_detach,
+ nodev, /* device reset routine */
+ &oss_cb_ops,
+ NULL, /* bus operations */
+ NULL /* TODO: Power management */
+};
+#endif
+
+extern struct mod_ops mod_miscops;
+static struct modldrv modldrv = {
+ &mod_miscops,
+ "Open Sound System " OSS_VERSION_STRING " framework"
+ // &oss_ops,
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1, /* MODREV_1 indicated by manual */
+ {(void *) &modldrv,
+ NULL} /* termination of list of linkage structures */
+};
+
+static ddi_device_acc_attr_t acc_attr_neverswap = {
+ DDI_DEVICE_ATTR_V0,
+ DDI_NEVERSWAP_ACC,
+ DDI_STRICTORDER_ACC
+};
+
+#ifdef OSS_BIG_ENDIAN
+static ddi_device_acc_attr_t acc_attr_le_swap = {
+ DDI_DEVICE_ATTR_V0,
+ DDI_STRUCTURE_LE_ACC,
+ DDI_STRICTORDER_ACC
+};
+#endif
+
+
+/*ARGSUSED*/
+static ddi_device_acc_attr_t *
+get_acc_attr (oss_device_t * osdev)
+{
+#ifdef OSS_BIG_ENDIAN
+ if (osdev->swap_mode == 1)
+ {
+ return &acc_attr_le_swap;
+ }
+ else
+#endif
+ {
+ return &acc_attr_neverswap;
+ }
+}
+
+void
+oss_load_options (oss_device_t * osdev, oss_option_map_t map[])
+{
+ int i, val;
+
+ for (i = 0; map[i].name != NULL; i++)
+ {
+ if ((val =
+ ddi_prop_get_int (DDI_DEV_T_ANY, osdev->dip,
+ DDI_PROP_NOTPROM,
+ map[i].name, -12345)) != -12345)
+ {
+ *map[i].ptr = val;
+ }
+ }
+}
+
+static int
+oss_attach (dev_info_t * dip, ddi_attach_cmd_t cmd)
+{
+ oss_device_t *osdev;
+
+ if (cmd != DDI_ATTACH)
+ {
+ cmn_err (CE_WARN, "oss_attach: Command %x\n", cmd);
+ return (DDI_FAILURE);
+ }
+
+ if ((osdev = osdev_create (dip, DRV_VIRTUAL, 0, "osscore", NULL)) == NULL)
+ {
+ cmn_err (CE_WARN, "Creating osdev failed\n");
+ return DDI_FAILURE;
+ }
+
+ MUTEX_INIT (osdev, osscore_mutex, 0);
+
+ oss_load_options (osdev, oss_global_options);
+
+ oss_common_init (osdev);
+
+ ddi_report_dev (dip);
+ oss_register_device (osdev, "OSS core services");
+
+ return (DDI_SUCCESS);
+}
+
+/*
+ * This is a pretty generic getinfo routine as describe in the manual.
+ */
+
+/*ARGSUSED*/
+static int
+oss_getinfo (dev_info_t * dip, ddi_info_cmd_t infocmd, void *arg,
+ void **result)
+{
+ dev_t dev;
+ register int error;
+ int instance;
+
+ dev = (dev_t) arg;
+ instance = getminor (dev) >> 4;
+
+ switch (infocmd)
+ {
+ case DDI_INFO_DEVT2DEVINFO:
+ *result = dip;
+ error = DDI_SUCCESS;
+ break;
+ case DDI_INFO_DEVT2INSTANCE:
+ *result = (void *) (uintptr_t) instance;
+ error = DDI_SUCCESS;
+ break;
+ default:
+ *result = NULL;
+ error = DDI_FAILURE;
+ }
+
+#if 0
+ DDB (cmn_err (CE_CONT,
+ "oss_getinfo: returns %d, result=%x minor=%d instance=%d dev=%x\n",
+ error, *result, minor_num, instance, dev));
+#endif
+ return (error);
+}
+
+/*
+ * _init, _info, and _fini support loading and unloading the driver.
+ */
+int
+_init (void)
+{
+ register int error = 0;
+ error = mod_install (&modlinkage);
+ return error;
+}
+
+int
+_info (struct modinfo *modinfop)
+{
+ return (mod_info (&modlinkage, modinfop));
+}
+
+int
+_fini (void)
+{
+ int status;
+
+#ifdef MEMDEBUG
+ int i;
+#endif
+
+ if ((status = mod_remove (&modlinkage)) != 0)
+ return (status);
+
+ free_all_contig_memory ();
+
+#ifdef MEMDEBUG
+ if (num_memblocks >= MAX_MEMBLOCKS)
+ cmn_err (CE_NOTE, "All memory allocations were not checked\n");
+
+ for (i = 0; i < num_memblocks; i++)
+ {
+ if (memblocks[i].addr != NULL)
+ {
+ cmn_err (CE_NOTE, "Memory leak in %s:%d\n",
+ memblocks[i].file, memblocks[i].line);
+ }
+ }
+#endif
+
+ return status;
+}
+
+/*
+ * When the osscore module is unloaded, oss_detach cleans up and frees the
+ * resources we allocated in oss_attach.
+ */
+static int
+oss_detach (dev_info_t * dip, ddi_detach_cmd_t cmd)
+{
+ static int already_unloaded = 0;
+
+ if (cmd != DDI_DETACH)
+ return DDI_FAILURE;
+
+ if (already_unloaded)
+ return DDI_SUCCESS;
+ already_unloaded = 1;
+//cmn_err(CE_CONT, "Oss detach\n");
+
+ /* instance = ddi_get_instance (dip); */
+
+ /*
+ * Remove the minor nodes created in attach
+ */
+ ddi_remove_minor_node (dip, NULL);
+
+ oss_unload_drivers ();
+
+ MUTEX_CLEANUP (osscore_mutex);
+
+ return (DDI_SUCCESS);
+}
+
+/*
+ * Some support routines
+ */
+void *
+memset (void *t, int c, size_t l)
+{
+ int i;
+
+ for (i = 0; i < l; i++)
+ ((char *) t)[i] = c;
+
+ return t;
+}
+
+#ifdef sparc
+/*
+ * I/O functions that do byte swapping (for Sparc)
+ */
+void
+oss_put16 (ddi_acc_handle_t handle, unsigned short *addr, unsigned short val)
+{
+ val = ((val >> 8) & 0xff) | ((val & 0xff) << 8);
+ ddi_put16 (handle, addr, val);
+}
+
+void
+oss_put32 (ddi_acc_handle_t handle, unsigned int *addr, unsigned int val)
+{
+#ifdef OSS_BIG_ENDIAN
+ val = ((val & 0x000000ff) << 24) |
+ ((val & 0x0000ff00) << 8) |
+ ((val & 0x00ff0000) >> 8) | ((val & 0xff000000) >> 24);
+#endif
+ ddi_put32 (handle, addr, val);
+}
+
+unsigned short
+oss_get16 (ddi_acc_handle_t handle, unsigned short *addr)
+{
+ unsigned short val;
+
+ val = ddi_get16 (handle, addr);
+#ifdef OSS_BIG_ENDIAN
+ val = ((val >> 8) & 0xff) | ((val & 0xff) << 8);
+#endif
+ return val;
+}
+
+unsigned int
+oss_get32 (ddi_acc_handle_t handle, unsigned int *addr)
+{
+ unsigned int val;
+
+ val = ddi_get32 (handle, addr);
+#ifdef OSS_BIG_ENDIAN
+ val = ((val & 0x000000ff) << 24) |
+ ((val & 0x0000ff00) << 8) |
+ ((val & 0x00ff0000) >> 8) | ((val & 0xff000000) >> 24);
+#endif
+ return val;
+}
+
+uint16_t
+oss_mem_get16 (ddi_acc_handle_t handle, uint16_t * addr)
+{
+ uint16_t val;
+
+ val = ddi_mem_get16 (handle, addr);
+#ifdef OSS_BIG_ENDIAN
+ val = ((val >> 8) & 0xff) | ((val & 0xff) << 8);
+#endif
+ return val;
+}
+
+uint32_t
+oss_mem_get32 (ddi_acc_handle_t handle, uint32_t * addr)
+{
+
+ uint32_t val;
+
+ val = ddi_mem_get32 (handle, addr);
+#ifdef OSS_BIG_ENDIAN
+ val = ((val & 0x000000ff) << 24) |
+ ((val & 0x0000ff00) << 8) |
+ ((val & 0x00ff0000) >> 8) | ((val & 0xff000000) >> 24);
+#endif
+ return val;
+}
+
+void
+oss_mem_put16 (ddi_acc_handle_t handle, uint16_t * addr, uint16_t val)
+{
+#ifdef OSS_BIG_ENDIAN
+ val = ((val >> 8) & 0xff) | ((val & 0xff) << 8);
+#endif
+
+ ddi_mem_put16 (handle, addr, val);
+}
+
+void
+oss_mem_put32 (ddi_acc_handle_t handle, uint32_t * addr, uint32_t val)
+{
+#ifdef OSS_BIG_ENDIAN
+ val = ((val & 0x000000ff) << 24) |
+ ((val & 0x0000ff00) << 8) |
+ ((val & 0x00ff0000) >> 8) | ((val & 0xff000000) >> 24);
+#endif
+ ddi_mem_put32 (handle, addr, val);
+}
+#endif
+
+void
+oss_pci_byteswap (oss_device_t * osdev, int mode)
+{
+ osdev->swap_mode = mode;
+}
+
+void
+oss_pcie_init (oss_device_t * osdev, int flags)
+{
+ /* TODO: Should we do something? */
+}
+
+/*ARGSUSED*/
+caddr_t
+oss_map_pci_ioaddr (oss_device_t * osdev, int nr, int io)
+{
+ caddr_t addr;
+ off_t region_size;
+ int err;
+ ddi_device_acc_attr_t *acc_attr;
+
+ if (nr >= OSS_MAX_ACC_HANDLE)
+ {
+ cmn_err(CE_WARN, "Too large I/O region number %d\n", nr);
+
+ return 0;
+ }
+
+ acc_attr = get_acc_attr (osdev);
+
+ if ((err =
+ ddi_dev_regsize (osdev->dip, nr + 1, &region_size)) != DDI_SUCCESS)
+ {
+ cmn_err (CE_WARN, "Getting device regsize failed (%d)\n", err);
+ return 0;
+ }
+
+ if ((err = ddi_regs_map_setup
+ (osdev->dip, nr + 1, &addr, 0, region_size, acc_attr,
+ &osdev->acc_handle[nr])) != DDI_SUCCESS)
+ {
+ cmn_err (CE_WARN, "Register setup failed (%d)\n", err);
+ return 0;
+ }
+
+ return addr;
+}
+
+void
+oss_unmap_pci_ioaddr(oss_device_t * osdev, int nr)
+{
+ if (nr >= OSS_MAX_ACC_HANDLE)
+ {
+ cmn_err(CE_WARN, "Too large I/O region number %d\n", nr);
+ return;
+ }
+
+ ddi_regs_map_free(&osdev->acc_handle[nr]);
+}
+
+int
+pci_read_config_byte (oss_device_t * osdev, offset_t where,
+ unsigned char *val)
+{
+ if (osdev->dev_type != DRV_PCI)
+ return PCIBIOS_FAILED;
+#if defined (sparc)
+ if (where == PCI_INTERRUPT_LINE)
+ *val = 7; /* PC emulation hack */
+ else
+#endif
+ *val = pci_config_get8 (osdev->pci_config_handle, where);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+pci_read_config_irq (oss_device_t * osdev, offset_t where, unsigned char *val)
+{
+ int ret;
+
+ if (osdev->dev_type != DRV_PCI)
+ return PCIBIOS_FAILED;
+ ret = pci_read_config_byte (osdev, where, val);
+ return ret;
+}
+
+
+int
+pci_read_config_word (oss_device_t * osdev, offset_t where,
+ unsigned short *val)
+{
+ if (osdev->dev_type != DRV_PCI)
+ return PCIBIOS_FAILED;
+ *val = pci_config_get16 (osdev->pci_config_handle, where);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+pci_read_config_dword (oss_device_t * osdev, offset_t where,
+ unsigned int *val)
+{
+ if (osdev->dev_type != DRV_PCI)
+ return PCIBIOS_FAILED;
+ *val = pci_config_get32 (osdev->pci_config_handle, where);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+pci_write_config_byte (oss_device_t * osdev, offset_t where,
+ unsigned char val)
+{
+ if (osdev->dev_type != DRV_PCI)
+ return PCIBIOS_FAILED;
+ pci_config_put8 (osdev->pci_config_handle, where, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+pci_write_config_word (oss_device_t * osdev, offset_t where,
+ unsigned short val)
+{
+ if (osdev->dev_type != DRV_PCI)
+ return PCIBIOS_FAILED;
+ pci_config_put16 (osdev->pci_config_handle, where, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+pci_write_config_dword (oss_device_t * osdev, offset_t where,
+ unsigned int val)
+{
+ if (osdev->dev_type != DRV_PCI)
+ return PCIBIOS_FAILED;
+ pci_config_put32 (osdev->pci_config_handle, where, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+void *
+memcpy (void *t, const void *s, size_t l)
+{
+ bcopy (s, t, l);
+ return t;
+}
+
+#ifdef MEMDEBUG
+void *
+oss_contig_malloc (oss_device_t * osdev, int size, oss_uint64_t memlimit,
+ oss_native_word * phaddr, oss_dma_handle_t *dma_handle, char *file, int line)
+#else
+void *
+oss_contig_malloc (oss_device_t * osdev, int size, oss_uint64_t memlimit,
+ oss_native_word * phaddr, oss_dma_handle_t *dma_handle)
+#endif
+{
+/*
+ * Allocate physically contiguous memory (suitable for DMA).
+ *
+ * The memlimit parameter is equal to oss_alloc_dmabuf().
+ */
+ int err;
+#if defined(sparc)
+ uint_t len;
+#else
+ size_t len;
+#endif
+ uint_t count;
+ contig_desc *desc;
+ ddi_dma_attr_t dma_attr;
+ ddi_device_acc_attr_t *acc_attr;
+
+ int flags =
+ DDI_DMA_REDZONE | DDI_DMA_CONSISTENT | DDI_DMA_READ | DDI_DMA_WRITE;
+
+ if (osdev == NULL)
+ {
+ cmn_err (CE_WARN, "oss_contig_malloc: osdev==NULL\n");
+ return NULL;
+ }
+
+ acc_attr = get_acc_attr (osdev);
+
+ memcpy (&dma_attr, &dma_attr_pci, sizeof (ddi_dma_attr_t));
+ dma_attr.dma_attr_addr_hi = memlimit;
+
+ desc = KERNEL_MALLOC (sizeof (contig_desc));
+ if (desc == NULL)
+ {
+ cmn_err (CE_WARN, "Failed to allocate contig buffer descriptor\n");
+ return NULL;
+ }
+
+ desc->osdev = osdev;
+ desc->next = NULL;
+ desc->is_special = 0;
+
+ if ((err = ddi_dma_alloc_handle (osdev->dip,
+ &dma_attr,
+ DDI_DMA_SLEEP,
+ NULL, &desc->dhandle)) != DDI_SUCCESS)
+ {
+ cmn_err (CE_WARN, "Failed to allocate pci DMA handle (%d)\n", err);
+ return NULL;
+ }
+
+ if (dma_handle != NULL)
+ *dma_handle = desc->dhandle;
+
+#ifndef IOMEM_DATA_UNCACHED
+#define IOMEM_DATA_UNCACHED 0 // Fix for Solaris 10
+#endif
+
+#if defined(sparc)
+ if ((err = ddi_mem_alloc (osdev->dip,
+ NULL,
+ size + 4096,
+ 0,
+ (caddr_t *) & desc->first_addr,
+ (uint_t *) & len)) != DDI_SUCCESS)
+
+
+#else
+ if ((err = ddi_dma_mem_alloc (desc->dhandle,
+ size + 4096,
+ acc_attr,
+ flags,
+ DDI_DMA_SLEEP,
+ NULL,
+ (caddr_t *) & desc->first_addr,
+ (size_t *) & len,
+ &desc->dma_acc_handle)) != DDI_SUCCESS)
+#endif
+ {
+ cmn_err (CE_WARN, "Failed to allocate %d bytes of contig memory (%d)\n",
+ size, err);
+ return NULL;
+
+ }
+
+ desc->size = len;
+ desc->orig_buf = desc->first_addr;
+
+ if (desc->first_addr == NULL)
+ {
+ cmn_err (CE_WARN, "Can't allocate a contig buffer\n");
+ return NULL;
+ }
+
+ DDB (cmn_err
+ (CE_CONT, "Allocated contig memory, addr=%x, len=%d\n",
+ (unsigned int) desc->first_addr, desc->size));
+
+ if ((err = ddi_dma_addr_bind_handle (desc->dhandle,
+ NULL,
+ (char *) desc->first_addr,
+ desc->size,
+ flags | DDI_DMA_STREAMING,
+ DDI_DMA_DONTWAIT,
+ NULL,
+ &desc->cookie, &count)) != DDI_SUCCESS)
+ {
+ cmn_err (CE_WARN, "Contig address setup failed (%d)\n", err);
+ return NULL;
+ }
+
+ desc->physaddr = desc->cookie.dmac_address;
+
+ desc->last_addr = desc->first_addr + desc->size - 1;
+ desc->first_addr =
+ (void *) (((unsigned long) desc->first_addr + 4095) & ~4095);
+ desc->physaddr = (desc->physaddr + 4095) & ~4095;
+ *phaddr = desc->physaddr;
+
+ desc->next = contig_list;
+ contig_list = desc;
+/* HW_PRINTF(("Alloc contig: %x-%x, ph=%x\n", desc->first_addr, desc->last_addr, desc->physaddr)); */
+
+ return desc->first_addr;
+}
+
+/*ARGSUSED*/
+void
+oss_contig_free (oss_device_t * osdev, void *p, int sz)
+{
+ int err;
+ contig_desc *d, *desc = NULL, *prev = NULL;
+
+ if (p == NULL)
+ return;
+
+ d = contig_list;
+
+ while (d && desc == NULL)
+ {
+ if (d->is_special)
+ {
+ prev = d;
+ d = d->next;
+ continue;
+ }
+
+ if (d->first_addr == p)
+ {
+ desc = d;
+ break;
+ }
+
+ prev = d;
+ d = d->next;
+ }
+
+ if (desc == NULL)
+ {
+ cmn_err (CE_WARN, "OSS: Can't free memory\n");
+ return;
+ }
+
+ if ((err = ddi_dma_unbind_handle (desc->dhandle)) != DDI_SUCCESS)
+ cmn_err (CE_WARN, "Failed to free DMA handle (%d)\n", err);
+
+#if defined(sparc)
+ ddi_mem_free (desc->orig_buf);
+#else
+ if (desc->dma_acc_handle == NULL)
+ cmn_err (CE_WARN, "desc->dma_acc_handle==NULL\n");
+ else
+ ddi_dma_mem_free (&desc->dma_acc_handle);
+#endif
+ ddi_dma_free_handle (&desc->dhandle);
+
+
+ if (desc == contig_list)
+ contig_list = desc->next;
+ else
+ {
+ prev->next = desc->next;
+ }
+ KERNEL_FREE (desc);
+
+}
+
+static void
+free_all_contig_memory (void)
+{
+ contig_desc *p, *desc = contig_list;
+
+ while (desc != NULL)
+ {
+ p = desc;
+ desc = desc->next;
+
+ if (p->is_special)
+ continue;
+
+ oss_contig_free (p->osdev, p->orig_buf, 0);
+ }
+
+ contig_list = NULL;
+}
+
+#if !defined(SOL9) && !defined(DISABLE_FMA)
+/*ARGSUSED*/
+static int
+oss_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *osdev_)
+{
+ pci_ereport_post(dip, err, NULL);
+ return err->fme_status;
+}
+#endif
+
+oss_device_t *
+osdev_create (dev_info_t * dip, int dev_type, int instance, const char *nick,
+ const char *handle)
+{
+ oss_device_t *osdev = NULL;
+ int i;
+ ddi_iblock_cookie_t iblk;
+ static int license_checked=0;
+
+#ifdef LICENSED_VERSION
+ if (!license_checked)
+ {
+ timestruc_t ts;
+
+ license_checked = 1;
+ gethrestime (&ts);
+ if (!oss_license_handle_time (ts.tv_sec))
+ {
+ 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 (handle == NULL)
+ handle = nick;
+
+ /*
+ * Don't accept any more drivers if expired
+ */
+ if (oss_expired && oss_num_cards > 0)
+ return NULL;
+
+ /*
+ * Check if the same device is being reinserted.
+ */
+ for (i = 0; i < oss_num_cards; i++)
+ {
+ if (cards[i]->available) /* Not deleted */
+ continue;
+
+ if (cards[i]->dip == dip)
+ {
+ osdev = cards[i];
+ break;
+ }
+ }
+
+#if 1
+ if (osdev == NULL)
+ {
+ /*
+ * Check if there are some deleted devices.
+ */
+ for (i = 0; i < oss_num_cards; i++)
+ {
+ if (cards[i]->available) /* Not deleted */
+ continue;
+
+ osdev = cards[i];
+ break;
+ }
+ }
+#endif
+
+ if (osdev == NULL)
+ {
+ for (i=0;i<oss_num_cards;i++)
+ if (!cards[i]->available)
+ {
+ osdev = cards[i];
+ break;
+ }
+ }
+
+ if (osdev == NULL)
+ {
+ if (oss_num_cards >= MAX_CARDS)
+ {
+ cmn_err (CE_WARN, "Too many OSS devices. At most %d permitted.\n",
+ MAX_CARDS);
+ return NULL;
+ }
+
+ if ((osdev = PMALLOC (NULL, sizeof (*osdev))) == NULL)
+ {
+ cmn_err (CE_WARN, "osdev_create: Out of memory\n");
+ return NULL;
+ }
+ memset (osdev, 0, sizeof (*osdev));
+
+ osdev->cardnum = oss_num_cards;
+ cards[oss_num_cards++] = osdev;
+ }
+
+ osdev->dip = dip;
+ osdev->osid = dip;
+ osdev->available = 1;
+ osdev->instance = instance;
+ osdev->dev_type = dev_type;
+ osdev->devc = NULL;
+ sprintf (osdev->nick, "%s%d", nick, instance);
+ strcpy (osdev->modname, nick);
+ osdev->num_audio_engines = 0;
+ osdev->num_audioplay = 0;
+ osdev->num_audiorec = 0;
+ osdev->num_audioduplex = 0;
+ osdev->num_mididevs = 0;
+ osdev->num_mixerdevs = 0;
+ osdev->first_mixer = -1;
+
+ switch (dev_type)
+ {
+ case DRV_PCI:
+ if (pci_config_setup (dip, &osdev->pci_config_handle) != DDI_SUCCESS)
+ cmn_err (CE_NOTE, "pci_config_setup() failed\n");
+#if !defined(SOL9) && !defined(DISABLE_FMA)
+ osdev->fm_capabilities = DDI_FM_EREPORT_CAPABLE | DDI_FM_DMACHK_CAPABLE |
+ DDI_FM_ERRCB_CAPABLE;
+ ddi_fm_init(dip, &osdev->fm_capabilities, &iblk);
+ ddi_fm_handler_register(dip, oss_fm_error_cb, (void*)osdev);
+ pci_ereport_setup(dip);
+#endif
+ break;
+
+ case DRV_VIRTUAL:
+ case DRV_VMIX:
+ case DRV_STREAMS:
+#if !defined(SOL9) && !defined(DISABLE_FMA)
+ osdev->fm_capabilities=DDI_FM_EREPORT_CAPABLE;
+ ddi_fm_init(dip, &osdev->fm_capabilities, &iblk);
+#endif
+ break;
+
+ case DRV_USB:
+ /* NOP */
+ break;
+
+ default:
+ cmn_err (CE_WARN, "Bad device type\n");
+ return NULL;
+ }
+
+/*
+ * Create the device handle
+ */
+ switch (dev_type)
+ {
+ case DRV_PCI:
+ {
+ unsigned int subvendor;
+ pci_read_config_dword (osdev, 0x2c, &subvendor);
+
+ sprintf (osdev->handle, "PCI%08x-%d", subvendor, instance);
+ }
+ 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;
+
+ if (!osdev->available) /* Already deleted */
+ return;
+
+ osdev->available = 0;
+
+ switch (osdev->dev_type)
+ {
+ case DRV_PCI:
+#if !defined(SOL9) && !defined(DISABLE_FMA)
+ ddi_fm_handler_unregister(osdev->dip);
+ pci_ereport_teardown(osdev->dip);
+#endif
+ pci_config_teardown (&osdev->pci_config_handle);
+#if !defined(SOL9) && !defined(DISABLE_FMA)
+ ddi_fm_fini(osdev->dip);
+#endif
+ osdev->pci_config_handle = NULL;
+ break;
+
+ case DRV_VIRTUAL:
+ case DRV_VMIX:
+ case DRV_STREAMS:
+#if !defined(SOL9) && !defined(DISABLE_FMA)
+ ddi_fm_fini(osdev->dip);
+#endif
+ break;
+ }
+
+ ddi_remove_minor_node (osdev->dip, NULL);
+
+/*
+ * Mark all minor nodes for this module as invalid.
+ */
+ for (i = 0; i < oss_num_cdevs; i++)
+ if (oss_cdevs[i] != NULL)
+ if (oss_cdevs[i]->osdev == osdev)
+ {
+ unlink_cdev_hash(oss_cdevs[i]);
+ oss_cdevs[i]->d = NULL;
+ oss_cdevs[i]->osdev = NULL;
+ oss_cdevs[i]->active = 0; /* Device removed */
+ }
+}
+
+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->shortname[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) - 1);
+ ci->hw_info[sizeof (ci->hw_info) - 1] = 0;
+ ci->intr_count = cards[cardnum]->intrcount;
+ ci->ack_count = cards[cardnum]->ackcount;
+
+ return 0;
+}
+
+static int
+grow_array(oss_device_t *osdev, oss_cdev_t ***arr, int *size, int element_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 * element_size))==NULL)
+ return 0;
+
+ memset(new, 0, new_size * element_size);
+ if (old != NULL)
+ memcpy(new, old, old_size * element_size);
+
+ *size = new_size;
+ *arr = new;
+
+ if (old != NULL)
+ PMFREE(osdev, old);
+
+ return 1;
+}
+
+/*ARGSUSED*/
+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;
+ int hash_link;
+ oss_cdev_t *cdev = NULL;
+
+ if (dev_class != OSS_DEV_STATUS)
+ if (oss_expired && instance > 0)
+ return;
+/*
+ * Find if this dev_class&instance already exists (after previous module
+ * detach).
+ */
+
+ if (flags & CHDEV_REPLUG)
+ 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, sizeof(oss_cdev_t*), 100))
+ {
+ cmn_err (CE_WARN, "Cannot allocate new 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->active = 1;
+ cdev->osdev = osdev;
+ if (name != NULL)
+ strncpy (cdev->name, name, sizeof (cdev->name) - 1);
+ else
+ strcpy (cdev->name, "NONE");
+ cdev->name[sizeof (cdev->name) - 1] = 0;
+ oss_cdevs[num] = cdev;
+
+ cdev->minor = num;
+
+ /*
+ * Add to the cdev_hash list.
+ */
+ hash_link = compute_cdev_hash (dev_class, instance);
+ cdev->hl = cdev_hash[hash_link];
+ cdev_hash[hash_link] = cdev;
+
+/*
+ * Export the device only if name != NULL
+ */
+ if (name != NULL)
+ {
+ char tmp[64], *s;
+ char *dev_type = "oss_sysdev";
+
+/*
+ * Convert "oss/device/node" style names to the
+ * "device,node" style naming required by Solaris.
+ */
+ if (name[0] == 'o' && name[3] == '/') /* oss/ prefix */
+ {
+ strcpy (tmp, name + 4);
+ name = tmp;
+
+ s = tmp;
+ while (*s)
+ {
+ if (*s == '/')
+ *s = ',';
+ s++;
+ }
+ dev_type = "oss_audio";
+ }
+
+ if (ddi_create_minor_node (osdev->dip, name, S_IFCHR, num,
+ dev_type, 0) == DDI_FAILURE)
+ {
+ cmn_err (CE_WARN, "ddi_create_minor_node failed\n");
+ }
+ }
+}
+
+int
+oss_find_minor (int dev_class, int instance)
+{
+ oss_cdev_t *cdev;
+
+ cdev = cdev_hash[compute_cdev_hash(dev_class, instance)];
+
+ while (cdev != NULL)
+ {
+ if (cdev->d != NULL && cdev->dev_class == dev_class
+ && cdev->instance == instance)
+ return cdev->minor;
+ cdev = cdev->hl; /* Next in the hash chain */
+ }
+
+ return OSS_EIO;
+}
+
+int
+__oss_alloc_dmabuf (int dev, dmap_p dmap, unsigned int alloc_flags,
+ oss_uint64_t maxaddr, int direction)
+{
+ int err;
+#if defined(sparc)
+ uint_t len;
+#else
+ size_t len;
+#endif
+ uint_t ncookies;
+ contig_desc *desc;
+ oss_device_t *osdev = dmap->osdev;
+ ddi_dma_attr_t dma_attr;
+ int size = 32 * 1024;
+ extern int dma_buffsize;
+ ddi_device_acc_attr_t *acc_attr;
+
+ int flags = DDI_DMA_REDZONE | DDI_DMA_CONSISTENT |
+ (direction == OPEN_READ) ? DDI_DMA_READ : DDI_DMA_WRITE;
+
+ if (osdev == NULL)
+ {
+ cmn_err (CE_WARN, "oss_alloc_dmabuf: osdev==NULL\n");
+ return OSS_EIO;
+ }
+
+ acc_attr = get_acc_attr (osdev);
+
+ if (dma_buffsize > 16 && dma_buffsize <= 128)
+ size = dma_buffsize * 1024;
+
+/*
+ * 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_LARGE)
+ size = 256 * 1024;
+
+ if ((alloc_flags & DMABUF_SIZE_16BITS) && size > 32 * 1024)
+ size = 32 * 1024;
+
+ memcpy (&dma_attr, &dma_attr_pci, sizeof (ddi_dma_attr_t));
+ dma_attr.dma_attr_addr_hi = maxaddr;
+
+#ifndef SOL9
+ if (osdev->dev_type == DRV_PCI)
+ dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
+#endif
+
+ if (dmap->dmabuf != NULL)
+ return 0; /* Already done */
+
+ dmap->dma_parms.state = 0;
+ dmap->dma_parms.enabled = 1;
+ dmap->dma_parms.ignore = 0;
+
+ if (osdev->dip == NULL)
+ {
+ cmn_err (CE_WARN, "oss_alloc_dmabuf: osdev->dip==NULL\n");
+ return OSS_EIO;
+ }
+
+ if (dmap == NULL)
+ {
+ cmn_err (CE_WARN, "oss_alloc_dmabuf: dmap==NULL\n");
+ return OSS_EIO;
+ }
+
+ if ((err = ddi_dma_alloc_handle (osdev->dip,
+ &dma_attr,
+ DDI_DMA_SLEEP,
+ NULL,
+ &dmap->dmabuf_dma_handle)) != DDI_SUCCESS)
+ {
+ cmn_err (CE_WARN, "Failed to allocate DMA handle (error %d)\n", err);
+ return OSS_ENOMEM;
+ }
+
+
+ dmap->dmabuf = NULL;
+ dmap->buffsize = size;
+
+ err = -1;
+
+ while (err != DDI_SUCCESS && dmap->dmabuf == NULL && dmap->buffsize >= 4096)
+ {
+#if defined(sparc)
+ if ((err = ddi_mem_alloc (osdev->dip,
+ NULL,
+ dmap->buffsize,
+ 0,
+ (caddr_t *) & dmap->dmabuf,
+ (uint_t *) & len)) != DDI_SUCCESS)
+#else
+ if ((err = ddi_dma_mem_alloc (dmap->dmabuf_dma_handle,
+ dmap->buffsize,
+ acc_attr,
+ flags,
+ DDI_DMA_SLEEP,
+ NULL,
+ (caddr_t *) & dmap->dmabuf,
+ (size_t *) & len,
+ &dmap->dma_parms.dma_acc_handle)) !=
+ DDI_SUCCESS)
+#endif
+ {
+ if (!(alloc_flags & DMABUF_QUIET))
+ DDB (cmn_err (CE_WARN,
+ "failed to allocate %d bytes of DMA memory (%d)\n",
+ dmap->buffsize, err));
+ dmap->dmabuf = NULL;
+ dmap->buffsize /= 2;
+ }
+ }
+
+ if (dmap->dmabuf == NULL)
+ {
+ cmn_err (CE_WARN, "Can't allocate a DMA buffer for device %d\n", dev);
+ ddi_dma_free_handle (&dmap->dmabuf_dma_handle);
+ return OSS_ENOMEM;
+ }
+
+ DDB (cmn_err (CE_CONT, "Allocated DMA memory, addr=%x, len=%d\n",
+ (int) dmap->dmabuf, (int) dmap->buffsize));
+
+ dmap->dma_parms.orig_buf = (caddr_t) dmap->dmabuf;
+
+ if ((err = ddi_dma_addr_bind_handle (dmap->dmabuf_dma_handle,
+ NULL,
+ (char *) dmap->dmabuf,
+ dmap->buffsize,
+ flags | DDI_DMA_STREAMING,
+ DDI_DMA_DONTWAIT,
+ NULL,
+ &dmap->dma_parms.cookie,
+ &ncookies)) != DDI_SUCCESS)
+ {
+ cmn_err (CE_WARN, "DMA address setup failed (%d)\n", err);
+
+ return OSS_EIO;
+ }
+
+ dmap->dmabuf =
+ (unsigned char *) ((((unsigned long) dmap->dmabuf) + 4095) & ~4095);
+ dmap->dmabuf_phys = (dmap->dma_parms.cookie.dmac_address + 4095) & ~4095;
+
+ desc = PMALLOC (osdev, sizeof (contig_desc));
+ if (desc == NULL)
+ return OSS_ENOMEM;
+
+ desc->osdev = osdev;
+ desc->next = NULL;
+ desc->is_special = 1;
+ desc->first_addr = dmap->dmabuf;
+ desc->last_addr = dmap->dmabuf + dmap->buffsize - 1;
+ desc->physaddr = dmap->dmabuf_phys;
+ desc->orig_buf = dmap->dma_parms.orig_buf;
+
+ if (contig_list != NULL)
+ desc->next = contig_list;
+/* HW_PRINTF(("Alloc DMA: %x-%x, ph=%x\n", desc->first_addr, desc->last_addr, desc->physaddr)); */
+ contig_list = desc;
+
+ return 0;
+}
+
+/*ARGSUSED*/
+void
+oss_free_dmabuf (int dev, dmap_p dmap)
+{
+ int err;
+
+ if (dmap->dmabuf == NULL)
+ return;
+
+ if ((err = ddi_dma_unbind_handle (dmap->dmabuf_dma_handle)) != DDI_SUCCESS)
+ cmn_err (CE_WARN, "Failed to free DMA handle (%d)\n", err);
+#if defined(sparc)
+ ddi_mem_free (dmap->dma_parms.orig_buf);
+#else
+ ddi_dma_mem_free (&dmap->dma_parms.dma_acc_handle);
+#endif
+ ddi_dma_free_handle (&dmap->dmabuf_dma_handle);
+
+ dmap->dmabuf = NULL;
+ dmap->dmabuf_phys = 0;
+}
+
+/*
+ * Interrupt management
+ */
+static u_int
+oss_intr (caddr_t arg) /* Global interrupt handler */
+{
+ oss_device_t *osdev = (oss_device_t *) arg;
+ int serviced;
+#ifdef MUTEX_CHECKS
+ int x = inside_intr;
+ inside_intr = 1; /* For mutex debugging only */
+#endif
+
+ if (osdev == NULL)
+ {
+#ifdef MUTEX_CHECKS
+ inside_intr = x;
+#endif
+ return DDI_INTR_UNCLAIMED;
+ }
+ osdev->intrcount++;
+
+ UP_STATUS (0x01);
+ serviced = osdev->tophalf_handler (osdev);
+ DOWN_STATUS (0x01);
+
+ if (serviced == 0)
+ return DDI_INTR_UNCLAIMED;
+ osdev->ackcount++;
+
+ if (osdev->bottomhalf_handler == NULL)
+ return DDI_INTR_CLAIMED;
+
+#if 0
+ if (osdev->intr_is_hilevel)
+ {
+/* TODO: Schedule the bottom half handler */
+ }
+ else
+#endif
+ osdev->bottomhalf_handler (osdev);
+
+#ifdef MUTEX_CHECKS
+ inside_intr = x;
+#endif
+ return DDI_INTR_CLAIMED;
+}
+
+int
+oss_register_interrupts (oss_device_t * osdev, int intrnum,
+ oss_tophalf_handler_t top,
+ oss_bottomhalf_handler_t bottom)
+{
+ int err;
+ ddi_idevice_cookie_t ic;
+
+
+ if (intrnum != 0)
+ {
+ cmn_err (CE_WARN, "Bad interrupt index (%d) for %s\n", intrnum,
+ osdev->name);
+ return OSS_EINVAL;
+ }
+
+ if (osdev == NULL)
+ {
+ cmn_err (CE_WARN, "oss_register_interrupts: Bad osdev\n");
+ return OSS_EINVAL;
+ }
+
+ if (osdev->tophalf_handler != NULL || osdev->bottomhalf_handler != NULL)
+ {
+ cmn_err (CE_WARN, "Interrupts already registered for %s\n",
+ osdev->name);
+ return OSS_EINVAL;
+ }
+
+ if (top == NULL)
+ {
+ cmn_err (CE_WARN, "Bad interrupt handler for %s\n", osdev->name);
+ return OSS_EINVAL;
+ }
+
+ osdev->tophalf_handler = top;
+ osdev->bottomhalf_handler = bottom;
+ osdev->intr_is_hilevel = ddi_intr_hilevel (osdev->dip, intrnum);
+ if (osdev->intr_is_hilevel)
+ {
+ if (bottom == NULL)
+ {
+ cmn_err (CE_WARN,
+ "The driver for %s doesn't support hilevel interrupts\n",
+ osdev->name);
+ return OSS_EINVAL;
+ }
+
+ DDB (cmn_err (CE_NOTE, "Using hilevel intr for %s\n", osdev->name));
+
+ /* TODO: Fix hilevel intr handling */
+ cmn_err (CE_WARN, "Hilevel interrupts are not supported yet.\n");
+ return OSS_EINVAL;
+ }
+
+ ddi_get_iblock_cookie (osdev->dip, intrnum, &osdev->iblock_cookie);
+
+ if ((err = ddi_add_intr (osdev->dip, intrnum, NULL, &ic,
+ oss_intr, (caddr_t) osdev)) != DDI_SUCCESS)
+ {
+ cmn_err (CE_WARN, "ddi_add_intr() failed, error=%d\n", err);
+ return OSS_EIO;
+ }
+
+ return 0;
+}
+
+void
+oss_unregister_interrupts (oss_device_t * osdev)
+{
+ ddi_remove_intr (osdev->dip, 0, osdev->iblock_cookie);
+ osdev->tophalf_handler = NULL;
+ osdev->bottomhalf_handler = NULL;
+}
+
+/*ARGSUSED*/
+int
+oss_register_device (oss_device_t * osdev, const char *name)
+{
+
+ 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;
+}
+
+int
+oss_disable_device (oss_device_t * osdev)
+{
+ int i;
+/*
+ * This routine should check if the device is ready to be unloaded (no devices are in use).
+ * If the device cannot be unloaded this routine must return OSS_EBUSY.
+ *
+ * If the device can be unloaded then disable any timers or other features that may cause the
+ * device to be called. Also mark the audio/midi/mixer/etc devices of this device to be disabled.
+ * However the interrupt handler should still stay enabled. The low level driver will call
+ * oss_unregister_interrupts() after it has cleared the interrupt enable register.
+ */
+ if (osdev->refcount > 0 || open_devices > 0)
+ {
+ cmn_err (CE_CONT, "Refcount %d (%s) , open_devices %d\n",
+ osdev->refcount, osdev->nick, open_devices);
+ if (open_devices > 0)
+ {
+ int i;
+
+ for (i = 0; i < oss_num_cdevs; i++)
+ if (oss_cdevs[i]->open_count)
+ {
+ cmn_err (CE_CONT, "%s is opened\n", oss_cdevs[i]->name);
+ }
+ }
+ return OSS_EBUSY;
+ }
+//cmn_err(CE_CONT, "oss_disable_device %s\n", osdev->nick);
+
+/*
+ * Now mark all devices unavailable (for the time being)
+ */
+
+ 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;
+}
+
+/*ARGSUSED*/
+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.
+ */
+
+/*
+ * Force reload of all drivers if any application tries to open any
+ * of the devices.
+ */
+ do_forceload = 1;
+}
+
+void
+oss_reserve_device (oss_device_t * osdev)
+{
+ osdev->refcount++;
+}
+
+void
+oss_unreserve_device (oss_device_t * osdev, int decrement)
+{
+ osdev->refcount -= decrement;
+}
+
+/*
+ * Wait queue support
+ */
+ /*ARGSUSED*/
+ oss_wait_queue_t *
+oss_create_wait_queue (oss_device_t * osdev, const char *name)
+{
+ oss_wait_queue_t *wq;
+
+ if ((wq = PMALLOC (NULL, sizeof (*wq))) == NULL)
+ return NULL;
+
+ cv_init (&wq->cv, NULL, CV_DRIVER, NULL);
+
+ return wq;
+}
+
+void *
+oss_get_osid (oss_device_t * osdev)
+{
+ return osdev->osid;
+}
+
+/*ARGSUSED*/
+void
+oss_reset_wait_queue (oss_wait_queue_t * wq)
+{
+ /* NOP */
+}
+
+void
+oss_remove_wait_queue (oss_wait_queue_t * wq)
+{
+ cv_destroy (&wq->cv);
+}
+
+/*ARGSUSED*/
+int
+oss_sleep (oss_wait_queue_t * wq, oss_mutex_t * mutex, int ticks,
+ oss_native_word * flags, unsigned int *status)
+{
+/*
+ * oss_sleep will return 0 if timeout occurred and 1 otherwise. The WK_SIGNAL bit will be reported on
+ * status if a signal was caught.
+ */
+ *status = 0;
+
+ if (ticks > 0)
+ {
+ int res;
+
+ if ((res =
+ cv_timedwait_sig (&wq->cv, mutex, ddi_get_lbolt () + ticks)) == 0)
+ *status |= WK_SIGNAL; /* Got signal */
+ if (res < 0) /* Timeout */
+ return 0;
+ }
+ else
+ {
+ if (cv_wait_sig (&wq->cv, mutex) == 0)
+ *status |= WK_SIGNAL; /* Got signal */
+ }
+ return 1;
+}
+
+/*ARGSUSED*/
+int
+oss_register_poll (oss_wait_queue_t * wq, oss_mutex_t * mutex,
+ oss_native_word * flags, oss_poll_event_t * ev)
+{
+ ev->php = &wq->ph;
+ wq->pollevents |= ev->events;
+ return 0;
+}
+
+/*ARGSUSED*/
+void
+oss_wakeup (oss_wait_queue_t * wq, oss_mutex_t * mutex,
+ oss_native_word * flags, short events)
+{
+ cv_broadcast (&wq->cv);
+
+ if (wq->pollevents & events)
+ {
+ wq->pollevents &= ~events;
+ MUTEX_EXIT_IRQRESTORE (*mutex, *flags);
+ pollwakeup (&wq->ph, events);
+ MUTEX_ENTER_IRQDISABLE (*mutex, *flags);
+ }
+}
+
+#ifdef MUTEX_CHECKS
+void
+debug_mutex_init (oss_mutex_t * mutex, void *dummy, int typ, void *arg,
+ char *file, int line)
+{
+ memset (mutex, 0, sizeof (mutex));
+ mutex_init (&mutex->mu, dummy, typ, arg);
+}
+
+void
+debug_mutex_destroy (oss_mutex_t * mutex, char *file, int line)
+{
+ mutex_destroy (&mutex->mu);
+}
+
+void
+debug_mutex_enter (oss_mutex_t * mutex, char *file, int line)
+{
+ if (mutex_owned (&mutex->mu))
+ {
+ cmn_err (CE_NOTE, "%s:%d: Re-entrant mutex (%s:%d %d)\n", file, line,
+ mutex->file, mutex->line, mutex->busy_flags);
+ return;
+ }
+
+ mutex->file = file;
+ mutex->line = line;
+ mutex_enter (&mutex->mu);
+}
+
+void
+debug_mutex_exit (oss_mutex_t * mutex, char *file, int line)
+{
+ if (!mutex_owned (&mutex->mu))
+ {
+ cmn_err (CE_NOTE, "Mutex not owned %s:%d\n", file, line);
+ }
+ else
+ mutex_exit (&mutex->mu);
+
+ mutex->file = NULL;
+ mutex->line = 0;
+}
+#endif
+
+int
+oss_get_procinfo(int what)
+{
+
+ switch (what)
+ {
+ case OSS_GET_PROCINFO_UID:
+ return ddi_get_cred()->cr_uid;
+ break;
+
+ case OSS_GET_PROCINFO_GID:
+ return ddi_get_cred()->cr_gid;
+ break;
+
+#if 0
+ case OSS_GET_PROCINFO_PGID:
+ return ddi_get_cred()->cr_pgid;
+ break;
+#endif
+
+ }
+ return OSS_EINVAL;
+}
diff --git a/kernel/OS/SunOS/os_solaris.h b/kernel/OS/SunOS/os_solaris.h
new file mode 100644
index 0000000..2b36b86
--- /dev/null
+++ b/kernel/OS/SunOS/os_solaris.h
@@ -0,0 +1,518 @@
+#ifndef _OS_H_
+#define _OS_H_
+
+/*
+ * Purpose: OS specific definitions for Solaris
+ *
+ */
+/*
+ *
+ * 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.
+ *
+ */
+
+#define OS_VERSION "10"
+#define SUNDDI
+#define __EXTENDED__
+#define Solaris
+
+#if (!defined(i386) && !defined(x86_64)) || defined(CONFIG_OSS_FIXDEPOINT)
+// Floating point is not supported or it's disabled
+#undef CONFIG_OSS_VMIX_FLOAT
+#endif
+
+#define VDEV_SUPPORT
+#define USE_DEVICE_SUBDIRS
+
+#define __inline__ inline
+#define __inline inline
+#define EXTERN_C extern "C"
+
+/*
+ * Debugging and misc settings
+ */
+#undef MUTEX_CHECKS
+#undef MEMDEBUG
+
+/*
+ * Disable support for per-application features such as /dev/dsp device
+ * selection based on command name. Requires working GET_PROCESS_NAME
+ * macro implementation.
+ */
+#undef APPLIST_SUPPORT
+
+/*
+ * Some integer types
+ */
+#if defined(amd64) || defined(sparc)
+typedef unsigned long long oss_native_word; /* Same as the address and status register size */
+#else
+typedef unsigned long oss_native_word; /* Same as the address and status register size */
+#endif
+
+typedef long long oss_int64_t; /* Signed 64 bit integer */
+typedef unsigned long long oss_uint64_t; /* Unsigned 64 bit integer */
+
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/types32.h>
+#include <sys/param.h>
+#include <sys/signal.h>
+#include <oss_errno.h>
+#include <sys/file.h>
+#include <sys/conf.h>
+#include <sys/uio.h>
+#include <sys/map.h>
+#include <sys/debug.h>
+#include <sys/modctl.h>
+#include <sys/kmem.h>
+#include <sys/cmn_err.h>
+#include <sys/open.h>
+#include <sys/stat.h>
+#ifndef sparc
+#include <sys/dditypes.h>
+#include <sys/ddidmareq.h>
+#include <sys/dma_engine.h>
+#endif
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/fcntl.h>
+#include <sys/ddidmareq.h>
+#include <sys/ksynch.h>
+#include <sys/poll.h>
+#ifdef SOL9
+#include <sys/cred.h>
+#else
+#include <sys/cred_impl.h>
+#endif
+
+#ifndef SOL9
+#include <sys/ddifm.h>
+#include <sys/fm/protocol.h>
+#include <sys/fm/util.h>
+#include <sys/fm/io/ddi.h>
+#endif
+
+#undef HZ
+#define OSS_HZ hz
+
+#ifdef sparc
+/*
+ * It's not possible to use SB Live! under Sparc architecture.
+ */
+#define AUDIGY_ONLY
+#endif
+
+/*
+ * Need to use slightly larger buffer because otherwise the interrupt
+ * rate will become too high for Solaris.
+ */
+#undef SMALL_DMABUF_SIZE
+#define SMALL_DMABUF_SIZE (16*1024)
+
+/* The soundcard.h could be in a nonstandard place so include it here. */
+#include "soundcard.h"
+
+typedef struct udi_usb_devc udi_usb_devc;
+
+struct _oss_device_t
+{
+ int cardnum;
+ int dev_type;
+ int instance;
+ int available;
+ dev_info_t *dip;
+ void *osid;
+ void *devc;
+ char *name;
+ char nick[16];
+ char modname[32];
+ char handle[32];
+ int num_audio_engines;
+ int num_audioplay, num_audiorec, num_audioduplex;
+ int num_mididevs;
+ int num_mixerdevs;
+ int num_loopdevs;
+ int first_mixer; /* This must be set to -1 by osdev_create() */
+ char *hw_info;
+
+ volatile int refcount; /* Nonzero means that the device is needed by some other (virtual) driver. */
+
+/* Interrupts */
+
+ ddi_iblock_cookie_t iblock_cookie;
+ int intr_is_hilevel;
+ oss_tophalf_handler_t tophalf_handler;
+ oss_bottomhalf_handler_t bottomhalf_handler;
+ int intrcount, ackcount;
+
+#ifdef _KERNEL
+/* PCI related fields */
+ ddi_acc_handle_t pci_config_handle;
+#define OSS_MAX_ACC_HANDLE 10
+ ddi_acc_handle_t acc_handle[OSS_MAX_ACC_HANDLE];
+ int swap_mode; /* 0=DDI_STRUCTURE_NEVERSWAP_ACC, 1=DDI_STRUCTURE_LE_ACC */
+
+/* USB fields */
+ udi_usb_devc *usbdev;
+
+#ifndef SOL9
+/* Fault management (FMA) */
+ int fm_capabilities;
+#endif
+#endif
+};
+
+/*
+ * Support for select()
+ */
+
+struct _oss_poll_event_t
+{
+ short events, revents;
+ struct pollhead *php;
+ int anyyet;
+};
+typedef struct _oss_poll_event_t oss_poll_event_t;
+
+#define ALLOW_SELECT
+#define SEL_IN 0
+#define SEL_OUT 1
+#define SEL_EX 0xffffffff
+
+/*
+ * Sleep/wakeup
+ */
+
+#ifdef _KERNEL
+struct oss_wait_queue
+{
+ kcondvar_t cv;
+ short pollevents;
+ struct pollhead ph;
+};
+#endif
+
+/* Busy wait routine */
+#define oss_udelay drv_usecwait
+/* System wall timer access */
+#define GET_JIFFIES() ddi_get_lbolt()
+
+/*
+ * Mutexes
+ */
+
+#ifdef MUTEX_CHECKS
+/* Debugging version */
+struct _oss_mutex_t
+{
+ kmutex_t mu;
+ char *file;
+ int line;
+ int busy_flags;
+#define CNTX_INTR 1
+#define CNTX_USER 2
+};
+
+typedef struct _oss_mutex_t oss_mutex_t;
+extern void debug_mutex_init (oss_mutex_t * mutex, void *dummy, int typ,
+ void *arg, char *file, int line);
+extern void debug_mutex_destroy (oss_mutex_t * mutex, char *file, int line);
+extern void debug_mutex_enter (oss_mutex_t * mutex, char *file, int line);
+extern void debug_mutex_exit (oss_mutex_t * mutex, char *file, int line);
+
+#define MUTEX_INIT(osdev, mutex, hier) debug_mutex_init(&mutex, NULL, MUTEX_DRIVER, osdev->iblock_cookie, __FILE__, __LINE__)
+#define MUTEX_CLEANUP(mutex) debug_mutex_destroy(&mutex, __FILE__, __LINE__)
+#define MUTEX_ENTER_IRQDISABLE(mutex, flags) flags=0;debug_mutex_enter(&mutex, __FILE__, __LINE__)
+#define MUTEX_ENTER(mutex, flags) flags=0;debug_mutex_enter(&mutex, __FILE__, __LINE__)
+#define MUTEX_EXIT_IRQRESTORE(mutex, flags) debug_mutex_exit(&mutex, __FILE__, __LINE__);(flags)++
+#define MUTEX_EXIT(mutex, flags) debug_mutex_exit(&mutex, __FILE__, __LINE__);(flags)++
+#else
+typedef kmutex_t oss_mutex_t;
+#define MUTEX_INIT(osdev, mutex, hier) mutex_init(&mutex, NULL, MUTEX_DRIVER, osdev->iblock_cookie)
+#define MUTEX_CLEANUP(mutex) mutex_destroy(&mutex)
+#define MUTEX_ENTER_IRQDISABLE(mutex, flags) flags=0;mutex_enter(&mutex)
+#define MUTEX_ENTER(mutex, flags) flags=0;mutex_enter(&mutex)
+#define MUTEX_EXIT_IRQRESTORE(mutex, flags) mutex_exit(&mutex);(flags)++
+#define MUTEX_EXIT(mutex, flags) mutex_exit(&mutex);(flags)++
+#endif
+
+/*
+ * Move bytes from the buffer which the application given in a
+ * write() call.
+ * offs is position relative to the beginning of the buffer in
+ * user space. The count is number of bytes to be moved.
+ */
+#define COPY_FROM_USER(target, source, offs, count) \
+ if (uiomove((target), count, UIO_WRITE, source)) { \
+ cmn_err(CE_WARN, "Bad copyin()!\n"); \
+ }
+/* Like COPY_FOM_USER but for writes. */
+#define COPY_TO_USER(target, offs, source, count) \
+ if (uiomove((source), count, UIO_READ, target)) { \
+ cmn_err(CE_WARN, "Bad copyout()!\n"); \
+ }
+
+/*
+ * INB() and OUTB() should be obvious. NOTE! The order of
+ * paratemeters of OUTB() is different than on some other
+ * operating systems.
+ */
+
+#ifdef sparc
+#ifdef _KERNEL
+extern void oss_put16 (ddi_acc_handle_t handle, unsigned short *addr,
+ unsigned short value);
+extern void oss_put32 (ddi_acc_handle_t handle, unsigned int *addr,
+ unsigned int value);
+extern unsigned short oss_get16 (ddi_acc_handle_t handle,
+ unsigned short *addr);
+extern unsigned int oss_get32 (ddi_acc_handle_t handle, unsigned int *addr);
+
+#define INB(osdev,port) ddi_get8((osdev)->acc_handle[0], (uint8_t*)(port))
+#define OUTB(osdev, d, port) ddi_put8((osdev)->acc_handle[0], (uint8_t*)(port), (d))
+#define INW(osdev,port) oss_get16((osdev)->acc_handle[0], (uint16_t*)(port))
+#define OUTW(osdev, d, port) oss_put16((osdev)->acc_handle[0], (uint16_t*)(port), (d))
+#define INL(osdev,port) oss_get32((osdev)->acc_handle[0], (uint32_t*)(port))
+#define OUTL(osdev,d, port) oss_put32((osdev)->acc_handle[0], (uint32_t*)(port), (d))
+
+/* Memory Mapped devices */
+extern uint16_t oss_mem_get16 (ddi_acc_handle_t handle, uint16_t * addr);
+extern uint32_t oss_mem_get32 (ddi_acc_handle_t handle, uint32_t * addr);
+extern void oss_mem_put16 (ddi_acc_handle_t handle, uint16_t * add,
+ uint16_t v);
+extern void oss_mem_put32 (ddi_acc_handle_t handle, uint32_t * add,
+ uint32_t v);
+#define PCI_READW(osdev, addr) oss_mem_get16((osdev)->acc_handle[0], (uint16_t*)(addr))
+#define PCI_READL(osdev, addr) oss_mem_get32((osdev)->acc_handle[0], (uint32_t*)(addr))
+#define PCI_WRITEW(osdev, addr, data) oss_mem_put16((osdev)->acc_handle[0], (uint16_t*)(addr), data)
+#define PCI_WRITEL(osdev, addr, data) oss_mem_put32((osdev)->acc_handle[0], (uint32_t*)(addr), data)
+#endif
+#else /* x86/AMD64 */
+/* I/O Mapped devices */
+#define INB(o, p) inb(p)
+#define INW(o, p) inw(p)
+#define INL(o, p) inl(p)
+
+#define OUTB(o, v, p) outb(p,v)
+#define OUTW(o, v, p) outw(p,v)
+#define OUTL(o, v, p) outl(p,v)
+
+/* Memory Mapped devices */
+#define PCI_READW(osdev, addr) ddi_mem_get16((osdev)->acc_handle[0], (uint16_t*)(addr))
+#define PCI_READL(osdev, addr) ddi_mem_get32((osdev)->acc_handle[0], (uint32_t*)(addr))
+#define PCI_WRITEW(osdev, addr, data) ddi_mem_put16((osdev)->acc_handle[0], (uint16_t*)(addr), data)
+#define PCI_WRITEL(osdev, addr, data) ddi_mem_put32((osdev)->acc_handle[0], (uint32_t*)(addr), data)
+#endif
+
+#define PCI_READB(osdev, addr) ddi_mem_get8((osdev)->acc_handle[0], addr)
+#define PCI_WRITEB(osdev, addr, data) ddi_mem_put8((osdev)->acc_handle[0], addr, data)
+
+typedef ddi_dma_handle_t oss_dma_handle_t;
+
+/*
+ KERNEL_MALLOC() allocates requested number of memory and
+ KERNEL_FREE is used to free it.
+ These macros are never called from interrupt, in addition the
+ nbytes will never be more than 4096 bytes. Generally the driver
+ will allocate memory in blocks of 4k. If the kernel has just a
+ page level memory allocation, 4K can be safely used as the size
+ (the nbytes parameter can be ignored).
+*/
+#ifdef MEMDEBUG
+extern void *oss_kmem_alloc (size_t size, int flags, char *file, int line);
+extern void oss_kmem_free (void *addr);
+#define KERNEL_MALLOC(nbytes) oss_kmem_alloc(nbytes, KM_SLEEP, __FILE__, __LINE__)
+#define KERNEL_FREE(addr) oss_kmem_free(addr)
+extern void *oss_contig_malloc (oss_device_t * osdev, int sz,
+ oss_uint64_t memlimit,
+ oss_native_word *phaddr,
+ oss_dma_handle_t *dma_handle,
+ char * file, int line);
+extern void oss_contig_free (oss_device_t * osdev, void *p, int sz);
+#define CONTIG_MALLOC(osdev, sz, memlimit, phaddr, handle) oss_contig_malloc(osdev, sz, memlimit, phaddr, &handle, __FILE__, __LINE__)
+#define CONTIG_FREE(osdev, p, sz, handle) oss_contig_free(osdev, p, sz, handle)
+#else
+extern void *oss_kmem_alloc (size_t size, int flags);
+extern void oss_kmem_free (void *addr);
+#define KERNEL_MALLOC(nbytes) oss_kmem_alloc(nbytes, KM_SLEEP)
+#define KERNEL_FREE(addr) oss_kmem_free(addr)
+extern void *oss_contig_malloc (oss_device_t * osdev, int sz,
+ oss_uint64_t memlimit,
+ oss_native_word * phaddr,
+ oss_dma_handle_t *dma_handle);
+extern void oss_contig_free (oss_device_t * osdev, void *p, int sz);
+#define CONTIG_MALLOC(osdev, sz, memlimit, phaddr, handle) oss_contig_malloc(osdev, sz, memlimit, phaddr, &handle)
+#define CONTIG_FREE(osdev, p, sz, handle) oss_contig_free(osdev, p, sz)
+#endif
+
+/*
+ * Timer macros
+ *
+ * These macros are obsolete and should not be used in any new code.
+ * Use the timeout mechanism (see the timeout(9F) Solaris man page).
+ */
+#define DEFINE_TIMER(name, proc) static timeout_id_t name = 0
+#define REMOVE_TIMER(name, proc) {if (name != 0) untimeout(name);}
+#define INIT_TIMER(name,proc)
+typedef void (*timeout_func_t) (void *);
+#define ACTIVATE_TIMER(name, proc, time) \
+ name=timeout((timeout_func_t)proc, (void*)&name, time)
+
+#define OSS_DMA_SYNC_INBOUND DDI_DMA_SYNC_FORCPU
+#define OSS_DMA_SYNC_OUTBOUND DDI_DMA_SYNC_FORDEV
+#define OSS_DMA_SYNC(handle, offs, len, direc) (ddi_dma_sync(handle, offs, len, direc)==DDI_SUCCESS)
+
+#ifdef _KERNEL
+struct os_dma_params
+{
+ int state; /* 0=unavail, 1=avail, 2=busy */
+ oss_device_t *osdev;
+ ddi_dma_handle_t handle;
+ ddi_acc_handle_t dma_acc_handle;
+ ddi_dma_cookie_t cookie;
+ ddi_dma_win_t win;
+ ddi_dma_seg_t seg;
+ void *orig_buf;
+
+ volatile int enabled, ignore;
+};
+#define OS_DMA_PARMS \
+ struct os_dma_params dma_parms;
+#endif
+#endif
+
+struct fileinfo
+{
+ int mode; /* Open mode */
+ int acc_flags;
+};
+
+#define ISSET_FILE_FLAG(fileinfo, flag) (fileinfo->acc_flags & (flag) ? 1:0)
+
+#ifdef sparc
+#define OSS_OS "Sparc"
+#define OSS_OS_LONGNAME "Solaris (Sparc)"
+#else
+#define OSS_OS "Solaris"
+#define OSS_OS_LONGNAME "Solaris (x86)"
+#endif
+
+#undef DMA_TRY_PSEUDOINIT
+
+int get_dma_residue (int chn);
+void disable_dma (int chn);
+void enable_dma (int chn);
+
+typedef void (*softintr_func_t) (int);
+
+struct oss_softintr
+{
+ int id;
+ softintr_func_t func;
+ volatile int armed, running;
+};
+
+/*
+ * There is apparently no documented way to map DMA buffers allocated
+ * using ddi_dma_mem_alloc() to applications. For this reason we cannot
+ * support mmap() under Solaris.
+ */
+#undef ALLOW_BUFFER_MAPPING
+
+#if 0
+extern int detect_trace;
+#define DDB(x) if (detect_trace) x
+#else
+#define DDB(x) {}
+#endif
+
+/*
+ * PCI I/O and memory address mapping.
+ *
+ * Note that for compatibility with the other operating systems supported by
+ * OSS the region numbering is different. So 0 means BAR0 while under
+ * Solaris (ddi_regs_map_setup) BAR0 is 1. oss_map_pci_ioaddr() will
+ * add 1 to the region number.
+ */
+extern caddr_t oss_map_pci_ioaddr (oss_device_t * osdev, int nr, int io);
+extern void oss_unmap_pci_ioaddr(oss_device_t * osdev, int nr);
+#define MAP_PCI_IOADDR(osdev, nr, io) (oss_native_word)oss_map_pci_ioaddr(osdev, nr, io)
+#define MAP_PCI_MEM(osdev, ix, phaddr, size) oss_map_pci_ioaddr(osdev, ix, phaddr)
+#define UNMAP_PCI_MEM(osdev, ix, ph, virt, size) oss_unmap_pci_ioaddr(osdev, ix)
+#define UNMAP_PCI_IOADDR(osdev, ix) oss_unmap_pci_ioaddr(osdev, ix)
+
+#define GET_PROCESS_PID(x) ddi_get_pid()
+
+/*
+ * Instead of returning UID check if the process has PRIV_SYS_DEVICES privilege.
+ * Report such users as UID=0 (root) and others as UID=1.
+ */
+#define GET_PROCESS_UID() ((drv_priv(ddi_get_cred())==0) ? 0 : 1)
+
+#if 1
+/* TODO: This works OK but may cause crashes with different kernel versions/builds */
+extern char *oss_get_procname (void);
+#define GET_PROCESS_NAME(x) oss_get_procname()
+#endif
+
+#define FP_SUPPORT
+
+#ifdef FP_SUPPORT
+typedef short fp_env_t[512];
+typedef unsigned int fp_flags_t[5];
+extern int oss_fp_check (void);
+extern void oss_fp_save (short *envbuf, fp_flags_t flags);
+extern void oss_fp_restore (short *envbuf, fp_flags_t flags);
+# define FP_SAVE(envbuf, flags) oss_fp_save(envbuf, flags)
+# define FP_RESTORE(envbuf, flags) oss_fp_restore(envbuf, flags)
+#endif
+
+#define abs(x) ((x) >= 0 ? (x) : -(x))
+
+extern int oss_open (dev_t * dev_p, int open_flags, int otyp,
+ cred_t * cred_p);
+extern int oss_close (dev_t dev, int flag, int otyp, cred_t * cred_p);
+extern int oss_ioctl (dev_t dev, int cmd, intptr_t arg, int mode,
+ cred_t * cred_p, int *rval_p);
+extern int oss_read (dev_t dev, struct uio *uiop, cred_t * credp);
+extern int oss_write (dev_t dev, struct uio *uiop, cred_t * cred_p);
+extern int oss_chpoll (dev_t dev, short events, int anyyet, short *reventsp,
+ struct pollhead **phpp);
+#ifdef _KERNEL
+extern int oss_devmap (dev_t dev, devmap_cookie_t handle, offset_t off,
+ size_t len, size_t * maplen, uint_t model);
+
+extern void *oss_memset (void *s, int c, size_t n);
+#define memset oss_memset
+
+extern void *oss_memcpy (void *s1, const void *s2, size_t n);
+#define memcpy oss_memcpy
+#endif
+
+#define DISABLE_FMA
+#if !defined(SOL9) && defined(DDI_FM_DEVICE) && !defined(DISABLE_FMA)
+/*
+ * Fault management (FMA) support.
+ */
+
+#define FMA_EREPORT(osdev, detail, name, type, value) \
+{ \
+ uint64_t ena; \
+ char buf[FM_MAX_CLASS]; \
+ (void) snprintf (buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail); \
+ ena = fm_ena_generate(0, FM_ENA_FMT1); \
+ if (osdev->dip != NULL && osdev->fm_capabilities != 0) \
+ ddi_fm_ereport_post(osdev->dip, buf, ena, DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, name, type, value, NULL); \
+}
+
+#define FMA_IMPACT(osdev, impact) \
+ if (osdev->fm_capabilities != 0) \
+ ddi_fm_service_impact(osdev->dip, impact)
+#endif
diff --git a/kernel/OS/SunOS/udi.c b/kernel/OS/SunOS/udi.c
new file mode 100644
index 0000000..ad4d4fa
--- /dev/null
+++ b/kernel/OS/SunOS/udi.c
@@ -0,0 +1,1365 @@
+/*
+ * Purpose: USB device interface (udi.h) routines for Solaris
+ */
+/*
+ *
+ * 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.
+ *
+ */
+#if !defined(SOL9)
+#include "oss_config.h"
+#include <udi.h>
+
+#define USBDRV_MAJOR_VER 2
+#define USBDRV_MINOR_VER 0
+#include <sys/usb/usba.h>
+#include <sys/strsubr.h>
+
+#undef IO_DEBUG
+int udi_usb_trace = 0;
+
+#define MAX_DEVICE_SLOTS 20
+
+struct udi_usb_devc
+{
+ oss_device_t *osdev;
+ usb_client_dev_data_t *dev_data;
+ char *name;
+
+ const struct usb_device_id *id;
+ const udi_usb_devinfo *udi_usb_dev;
+ char devpath[32];
+
+ int enabled;
+
+ struct usb_interface *iface;
+ udi_usb_driver *drv;
+ void *client_devc;
+ void (*client_disconnect) (void *devc);
+};
+
+#define MAX_DEVC 32
+
+int
+udi_attach_usbdriver (oss_device_t * osdev, const udi_usb_devinfo * devlist,
+ udi_usb_driver * driver)
+{
+ int err, i, nalt, vendor, product, busaddr;
+ udi_usb_devc *usbdev;
+ dev_info_t *dip = osdev->dip;
+ char *name;
+ unsigned long osid;
+ //usb_alt_if_data_t *altif_data;
+ usb_client_dev_data_t *dev_data;
+
+ if (dip==NULL)
+ {
+ cmn_err(CE_WARN, "dip==NULL\n");
+ return 0;
+ }
+
+ name = ddi_get_name (osdev->dip);
+
+ if (strcmp (name, "oss_usb") == 0)
+ {
+ oss_register_device (osdev, "USB audio/MIDI device");
+ return 1;
+ }
+
+ /*
+ * Select the default configuration
+ */
+ if ((err = usb_set_cfg (osdev->dip, USB_DEV_DEFAULT_CONFIG_INDEX,
+ USB_FLAGS_SLEEP, NULL, NULL)) == USB_SUCCESS)
+ {
+ cmn_err (CE_CONT, "usb_set_cfg returned %d\n", err);
+ }
+
+ busaddr = ddi_prop_get_int (DDI_DEV_T_ANY, osdev->dip,
+ DDI_PROP_NOTPROM, "assigned-address", 1234);
+ if ((usbdev = KERNEL_MALLOC (sizeof (*usbdev))) == NULL)
+ {
+ cmn_err (CE_WARN, "udi_attach_usbdriver: Out of memory\n");
+ return 0;
+ }
+
+ memset (usbdev, 0, sizeof (*usbdev));
+ osdev->usbdev = usbdev;
+ usbdev->osdev = osdev;
+
+ if ((err = usb_client_attach (dip, USBDRV_VERSION, 0)) != USB_SUCCESS)
+ {
+ cmn_err (CE_WARN, "usb_client_attach failed, err=%d\n", err);
+ KERNEL_FREE (usbdev);
+ return 0;
+ }
+
+ if ((err =
+ usb_get_dev_data (osdev->dip, &usbdev->dev_data, USB_PARSE_LVL_CFG,
+ 0)) != USB_SUCCESS)
+ {
+ cmn_err (CE_WARN, "usb_get_dev_data failed, err=%d\n", err);
+ KERNEL_FREE (usbdev);
+ return 0;
+ }
+ dev_data = usbdev->dev_data;
+
+ osdev->iblock_cookie = dev_data->dev_iblock_cookie;
+
+ sprintf (usbdev->devpath, "usb%x,%x@port%d", udi_usbdev_get_vendor (usbdev),
+ udi_usbdev_get_product (usbdev), busaddr);
+ oss_register_device (osdev, "USB audio/MIDI device");
+ sprintf (osdev->nick, "usb%x_%x_%d", udi_usbdev_get_vendor (usbdev),
+ udi_usbdev_get_product (usbdev), busaddr);
+
+#if 0
+ if (udi_usb_trace > 5)
+ usb_print_descr_tree (osdev->dip, dev_data);
+#endif
+
+ nalt = 1;
+ if (nalt >= dev_data->dev_curr_cfg->cfg_if[dev_data->dev_curr_if].if_n_alt)
+ nalt = 0;
+
+ //altif_data = &dev_data->dev_curr_cfg->
+ // cfg_if[dev_data->dev_curr_if].if_alt[nalt];
+
+ usbdev->name = usbdev->dev_data->dev_product;
+ vendor = udi_usbdev_get_vendor (usbdev);
+ product = udi_usbdev_get_product (usbdev);
+
+ /* inum = usbdev->dev_data->dev_curr_if; */
+ osid = (vendor << 16) | product;
+ osdev->osid = (void *) osid;
+
+ sprintf (osdev->handle, "usb%x,%x.%d:%d", vendor, product,
+ dev_data->dev_curr_if, osdev->instance);
+
+ for (i = 0; devlist[i].vendor != -1; i++)
+ if (devlist[i].vendor == vendor && devlist[i].product == product)
+ {
+ usbdev->name = devlist[i].name;
+ usbdev->udi_usb_dev = &devlist[i];
+ oss_register_device (osdev, usbdev->name);
+ break;
+ }
+
+ if ((usbdev->client_devc = driver->attach (usbdev, osdev)) == NULL)
+ {
+ cmn_err (CE_WARN, "Client attach failed, err=%d\n", err);
+ udi_unload_usbdriver (osdev);
+ return 0;
+ }
+
+ usbdev->client_disconnect = driver->disconnect;
+
+ return 1;
+}
+
+static char *
+usb_errstr (int err)
+{
+
+ static struct errmsg_
+ {
+ int err;
+ char *str;
+ } errs[] =
+ {
+ {
+ USB_FAILURE, "USB_FAILURE"},
+ {
+ USB_NO_RESOURCES, "USB_NO_RESOURCES"},
+ {
+ USB_NO_BANDWIDTH, "USB_NO_BANDWIDTH"},
+ {
+ USB_NOT_SUPPORTED, "USB_NOT_SUPPORTED"},
+ {
+ USB_PIPE_ERROR, "USB_PIPE_ERROR"},
+ {
+ USB_INVALID_PIPE, "USB_INVALID_PIPE"},
+ {
+ USB_NO_FRAME_NUMBER, "USB_NO_FRAME_NUMBER"},
+ {
+ USB_INVALID_START_FRAME, "USB_INVALID_START_FRAME"},
+ {
+ USB_HC_HARDWARE_ERROR, "USB_HC_HARDWARE_ERROR"},
+ {
+ USB_INVALID_REQUEST, "USB_INVALID_REQUEST"},
+ {
+ USB_INVALID_CONTEXT, "USB_INVALID_CONTEXT"},
+ {
+ USB_INVALID_VERSION, "USB_INVALID_VERSION"},
+ {
+ USB_INVALID_ARGS, "USB_INVALID_ARGS"},
+ {
+ USB_INVALID_PERM, "USB_INVALID_PERM"},
+ {
+ USB_BUSY, "USB_BUSY"},
+ {
+ 0, NULL}
+ };
+
+ int i;
+ static char msg[20];
+
+ for (i = 0; errs[i].err != 0; i++)
+ if (errs[i].err == err)
+ {
+ return errs[i].str;
+ }
+
+ sprintf (msg, "Err %d", err);
+ return msg;
+}
+
+static char *
+usb_cb_err (int err)
+{
+
+ static struct errmsg_
+ {
+ int err;
+ char *str;
+ } errs[] =
+ {
+ {
+ USB_CB_STALL_CLEARED, "USB_CB_STALL_CLEARED"},
+ {
+ USB_CB_FUNCTIONAL_STALL, "USB_CB_FUNCTIONAL_STALL"},
+ {
+ USB_CB_PROTOCOL_STALL, "USB_CB_PROTOCOL_STALL"},
+ {
+ USB_CB_RESET_PIPE, "USB_CB_RESET_PIPE"},
+ {
+ USB_CB_ASYNC_REQ_FAILED, "USB_CB_ASYNC_REQ_FAILED"},
+ {
+ USB_CB_NO_RESOURCES, "USB_CB_NO_RESOURCES"},
+ {
+ USB_CB_SUBMIT_FAILED, "USB_CB_SUBMIT_FAILED"},
+ {
+ USB_CB_INTR_CONTEXT, "USB_CB_INTR_CONTEXT"},
+ {
+ USB_FAILURE, "USB_FAILURE"},
+ {
+ USB_NO_RESOURCES, "USB_NO_RESOURCES"},
+ {
+ USB_NO_BANDWIDTH, "USB_NO_BANDWIDTH"},
+ {
+ USB_NOT_SUPPORTED, "USB_NOT_SUPPORTED"},
+ {
+ USB_PIPE_ERROR, "USB_PIPE_ERROR"},
+ {
+ USB_INVALID_PIPE, "USB_INVALID_PIPE"},
+ {
+ USB_NO_FRAME_NUMBER, "USB_NO_FRAME_NUMBER"},
+ {
+ USB_INVALID_START_FRAME, "USB_INVALID_START_FRAME"},
+ {
+ USB_HC_HARDWARE_ERROR, "USB_HC_HARDWARE_ERROR"},
+ {
+ USB_INVALID_REQUEST, "USB_INVALID_REQUEST"},
+ {
+ USB_INVALID_CONTEXT, "USB_INVALID_CONTEXT"},
+ {
+ USB_INVALID_VERSION, "USB_INVALID_VERSION"},
+ {
+ USB_INVALID_ARGS, "USB_INVALID_ARGS"},
+ {
+ USB_INVALID_PERM, "USB_INVALID_PERM"},
+ {
+ USB_BUSY, "USB_BUSY"},
+ {
+ 0, NULL}
+ };
+
+ int i;
+ static char msg[20];
+
+ if (err == 0)
+ return "USB_CB_NO_INFO";
+
+ for (i = 0; errs[i].err != 0; i++)
+ {
+ if (errs[i].err == err)
+ {
+ return errs[i].str;
+ }
+ }
+
+ sprintf (msg, "CB Err %d", err);
+ return msg;
+}
+
+static char *
+usb_cr_err (int err)
+{
+
+ static struct errmsg_
+ {
+ int err;
+ char *str;
+ } errs[] =
+ {
+ {
+ USB_CR_CRC, "USB_CR_CRC"},
+ {
+ USB_CR_BITSTUFFING, "USB_CR_BITSTUFFING"},
+ {
+ USB_CR_DATA_TOGGLE_MM, "USB_CR_DATA_TOGGLE_MM"},
+ {
+ USB_CR_STALL, "USB_CR_STALL"},
+ {
+ USB_CR_DEV_NOT_RESP, "USB_CR_DEV_NOT_RESP"},
+ {
+ USB_CR_PID_CHECKFAILURE, "USB_CR_PID_CHECKFAILURE"},
+ {
+ USB_CR_UNEXP_PID, "USB_CR_UNEXP_PID"},
+ {
+ USB_CR_DATA_OVERRUN, "USB_CR_DATA_OVERRUN"},
+ {
+ USB_CR_DATA_UNDERRUN, "USB_CR_DATA_UNDERRUN"},
+ {
+ USB_CR_BUFFER_OVERRUN, "USB_CR_BUFFER_OVERRUN"},
+ {
+ USB_CR_BUFFER_UNDERRUN, "USB_CR_BUFFER_UNDERRUN"},
+ {
+ USB_CR_TIMEOUT, "USB_CR_TIMEOUT"},
+ {
+ USB_CR_NOT_ACCESSED, "USB_CR_NOT_ACCESSED"},
+ {
+ USB_CR_NO_RESOURCES, "USB_CR_NO_RESOURCES"},
+ {
+ USB_CR_UNSPECIFIED_ERR, "USB_CR_UNSPECIFIED_ERR"},
+ {
+ USB_CR_STOPPED_POLLING, "USB_CR_STOPPED_POLLING"},
+ {
+ USB_CR_PIPE_CLOSING, "USB_CR_PIPE_CLOSING"},
+ {
+ USB_CR_PIPE_RESET, "USB_CR_PIPE_RESET"},
+ {
+ USB_CR_NOT_SUPPORTED, "USB_CR_NOT_SUPPORTED"},
+ {
+ USB_CR_FLUSHED, "USB_CR_FLUSHED"},
+ {
+ USB_CR_HC_HARDWARE_ERR, "USB_CR_HC_HARDWARE_ERR"},
+ {
+ 0, NULL}
+ };
+
+ int i;
+ static char msg[20];
+
+ if (err == 0)
+ return "USB_CR_OK";
+
+ for (i = 0; errs[i].err != 0; i++)
+ {
+ if (errs[i].err == err)
+ {
+ return errs[i].str;
+ }
+ }
+
+ sprintf (msg, "CR Err %d", err);
+ return msg;
+}
+
+void
+udi_unload_usbdriver (oss_device_t * osdev)
+{
+ udi_usb_devc *usbdev = osdev->usbdev;
+
+ if (usbdev == NULL)
+ return;
+
+ if (usbdev->client_disconnect != NULL)
+ usbdev->client_disconnect (usbdev->client_devc);
+ usb_client_detach (osdev->dip, usbdev->dev_data);
+
+ KERNEL_FREE (usbdev);
+ osdev->usbdev = NULL;
+}
+
+/*
+ * Device access routines
+ */
+
+int
+udi_usbdev_get_class (udi_usb_devc * usbdev)
+{
+ udi_usb_devc *devc = (udi_usb_devc *) usbdev;
+
+ return devc->dev_data->dev_curr_cfg->cfg_if[devc->dev_data->dev_curr_if].
+ if_alt[0].altif_descr.bInterfaceClass;
+}
+
+int
+udi_usbdev_get_subclass (udi_usb_devc * usbdev)
+{
+ udi_usb_devc *devc = (udi_usb_devc *) usbdev;
+
+ return devc->dev_data->dev_curr_cfg->cfg_if[devc->dev_data->dev_curr_if].
+ if_alt[0].altif_descr.bInterfaceSubClass;
+}
+
+int
+udi_usbdev_get_vendor (udi_usb_devc * usbdev)
+{
+ udi_usb_devc *devc = (udi_usb_devc *) usbdev;
+
+ return devc->dev_data->dev_descr->idVendor;
+}
+
+int
+udi_usbdev_get_product (udi_usb_devc * usbdev)
+{
+ udi_usb_devc *devc = (udi_usb_devc *) usbdev;
+
+ return devc->dev_data->dev_descr->idProduct;
+}
+
+int
+udi_usbdev_get_inum (udi_usb_devc * usbdev)
+{
+ udi_usb_devc *devc = (udi_usb_devc *) usbdev;
+
+ return devc->dev_data->dev_curr_if;
+}
+
+int
+udi_usbdev_set_interface (udi_usb_devc * usbdev, int inum, int altset)
+{
+ //udi_usb_devc *devc = (udi_usb_devc *) usbdev;
+
+ if (usb_set_alt_if (usbdev->osdev->dip, inum, altset, USB_FLAGS_SLEEP,
+ NULL, 0) != USB_SUCCESS)
+ {
+ return OSS_EIO;
+ }
+
+ return 0;
+}
+
+unsigned char *
+udi_usbdev_get_endpoint (udi_usb_devc * usbdev, int altsetting, int n,
+ int *len)
+{
+ usb_alt_if_data_t *altif_data;
+ usb_client_dev_data_t *dev_data;
+
+ *len = 0;
+
+ if (usbdev->dev_data == NULL)
+ {
+ cmn_err (CE_WARN, "Missing USB devdata\n");
+ return NULL;
+ }
+ dev_data = usbdev->dev_data;
+
+ if (altsetting < 0
+ || altsetting >=
+ dev_data->dev_curr_cfg->cfg_if[dev_data->dev_curr_if].if_n_alt)
+ {
+ return NULL;
+ }
+
+ altif_data = &dev_data->dev_curr_cfg->
+ cfg_if[dev_data->dev_curr_if].if_alt[altsetting];
+
+ if (altif_data == NULL)
+ return NULL;
+
+ if (n < 0 || n >= altif_data->altif_n_ep)
+ return NULL;
+
+ *len = altif_data->altif_ep[n].ep_descr.bLength;
+ return (unsigned char *) &altif_data->altif_ep[n].ep_descr;
+}
+
+int
+udi_usbdev_get_num_altsettings (udi_usb_devc * usbdev)
+{
+ //udi_usb_devc *devc = (udi_usb_devc *) usbdev;
+ usb_client_dev_data_t *dev_data;
+
+ dev_data = usbdev->dev_data;
+ return dev_data->dev_curr_cfg->cfg_if[dev_data->dev_curr_if].if_n_alt;
+}
+
+unsigned char *
+udi_usbdev_get_altsetting (udi_usb_devc * usbdev, int nalt, int *size)
+{
+ int i, n;
+ usb_cvs_data_t *cvs;
+ usb_alt_if_data_t *altif_data;
+ usb_client_dev_data_t *dev_data;
+ static unsigned char buf[1024];
+
+ dev_data = usbdev->dev_data;
+ if ((unsigned long) dev_data <= 4096)
+ {
+ cmn_err (CE_WARN, "Internal error: dev_data==NULL)\n");
+ return NULL;
+ }
+
+ if (nalt < 0
+ || nalt >=
+ dev_data->dev_curr_cfg->cfg_if[dev_data->dev_curr_if].if_n_alt)
+ {
+ return NULL;
+ }
+
+ altif_data = &dev_data->dev_curr_cfg->
+ cfg_if[dev_data->dev_curr_if].if_alt[nalt];
+
+ if (altif_data == NULL)
+ return NULL;
+
+ n = 0;
+
+ for (i = 0; i < altif_data->altif_n_cvs; i++)
+ {
+ cvs = &altif_data->altif_cvs[i];
+ memcpy (buf + n, cvs->cvs_buf, cvs->cvs_buf_len);
+ n += cvs->cvs_buf_len;
+ }
+
+ cvs = &altif_data->altif_cvs[0];
+ if (cvs == NULL || cvs->cvs_buf == NULL)
+ return NULL;
+
+ *size = n;
+ return buf;
+}
+
+char *
+udi_usbdev_get_name (udi_usb_devc * usbdev)
+{
+ udi_usb_devc *devc = (udi_usb_devc *) usbdev;
+
+ return devc->name;
+}
+
+char *
+udi_usbdev_get_altsetting_labels (udi_usb_devc * usbdev, int if_num,
+ int *default_alt, unsigned int *mask)
+{
+ int i;
+
+ *default_alt = 1;
+ *mask = 0xffffffff;
+
+ if (usbdev->udi_usb_dev == NULL) /* No device definitions available */
+ {
+ return NULL;
+ }
+
+ for (i = 0; usbdev->udi_usb_dev->altsettings[i].altsetting_labels != NULL;
+ i++)
+ if (i == if_num)
+ {
+ *default_alt = usbdev->udi_usb_dev->altsettings[i].default_altsetting;
+ *mask = usbdev->udi_usb_dev->altsettings[i].altsetting_mask;
+ if (*mask == 0)
+ *mask = 0xffffffff;
+ return usbdev->udi_usb_dev->altsettings[i].altsetting_labels;
+ }
+
+ return NULL; /* Not found */
+}
+
+char *
+udi_usbdev_get_string (udi_usb_devc * usbdev, int ix)
+{
+ static char str[256];
+
+ if (usb_get_string_descr
+ (usbdev->osdev->dip, USB_LANG_ID, ix, str,
+ sizeof (str) - 1) != USB_SUCCESS)
+ return NULL;
+ return str;
+}
+
+char *
+udi_usbdev_get_devpath (udi_usb_devc * usbdev)
+{
+ udi_usb_devc *devc = (udi_usb_devc *) usbdev;
+
+ return devc->devpath;
+}
+
+/*ARGSUSED*/
+int
+udi_usb_snd_control_msg (udi_usb_devc * usbdev, unsigned int endpoint,
+ unsigned char rq,
+ unsigned char rqtype,
+ unsigned short value,
+ unsigned short index,
+ void *buf, int len, int timeout)
+{
+
+ int err;
+
+ usb_ctrl_setup_t setup;
+ usb_cr_t completion_reason;
+ usb_cb_flags_t cb_flags;
+ mblk_t *data = NULL;
+
+ if (usbdev == NULL)
+ {
+ cmn_err (CE_CONT, "udi_usb_snd_control_msg: usbdev==NULL\n");
+ return OSS_EFAULT;
+ }
+
+ data = allocb_wait (len + 1, BPRI_HI, STR_NOSIG, NULL);
+
+ memcpy (data->b_wptr, buf, len);
+ data->b_wptr = data->b_rptr + len;
+
+ setup.bmRequestType = rqtype | USB_DEV_REQ_HOST_TO_DEV;
+ setup.bRequest = rq;
+ setup.wValue = value;
+ setup.wIndex = index;
+ setup.wLength = len;
+ setup.attrs = 0;
+
+ if ((err = usb_pipe_ctrl_xfer_wait (usbdev->dev_data->dev_default_ph,
+ &setup,
+ &data,
+ &completion_reason,
+ &cb_flags, 0)) != USB_SUCCESS)
+ {
+ char tmp[128], *s = tmp;
+ unsigned char *p = buf;
+ int i;
+
+ sprintf (s, "Msg (rq=0x%x, val=0x%04x, ix=0x%04x, len=%d): ", rq, value,
+ index, len);
+ for (i = 0; i < len; i++)
+ {
+ s += strlen (s);
+ sprintf (s, "%02x ", p[i]);
+ }
+ cmn_err (CE_CONT, "%s\n", tmp);
+
+ cmn_err (CE_NOTE, "usb_pipe_ctrl_xfer_wait write failed: %s (%s)\n",
+ usb_errstr (err), usb_cb_err (completion_reason));
+ cmn_err (CE_CONT, "bRq %x, wIx %x, wVal %x, wLen %d\n", rq, index,
+ value, len);
+ freemsg (data);
+ return OSS_EIO;
+ }
+
+ freemsg (data);
+ return len;
+}
+
+/*ARGSUSED*/
+int
+udi_usb_rcv_control_msg (udi_usb_devc * usbdev, unsigned int endpoint,
+ unsigned char rq,
+ unsigned char rqtype,
+ unsigned short value,
+ unsigned short index,
+ void *buf, int len, int timeout)
+{
+ int err, l;
+
+ usb_ctrl_setup_t setup;
+ usb_cr_t completion_reason;
+ usb_cb_flags_t cb_flags;
+ mblk_t *data = NULL;
+
+ if (usbdev == NULL)
+ {
+ cmn_err (CE_CONT, "udi_usb_rcv_control_msg: usbdev==NULL\n");
+ return OSS_EFAULT;
+ }
+
+ setup.bmRequestType = rqtype | USB_DEV_REQ_DEV_TO_HOST;
+ setup.bRequest = rq;
+ setup.wValue = value;
+ setup.wIndex = index;
+ setup.wLength = len;
+ setup.attrs = 0;
+
+ if ((err = usb_pipe_ctrl_xfer_wait (usbdev->dev_data->dev_default_ph,
+ &setup,
+ &data,
+ &completion_reason,
+ &cb_flags, 0)) != USB_SUCCESS)
+ {
+ char tmp[128], *s = tmp;
+
+ sprintf (s, "Msg (rq=0x%02x, val=0x%04x, ix=0x%04x, len=%d): ", rq,
+ value, index, len);
+ cmn_err (CE_CONT, "%s\n", tmp);
+ cmn_err (CE_NOTE, "usb_pipe_ctrl_xfer_wait read failed: %s (%s)\n",
+ usb_errstr (err), usb_cb_err (completion_reason));
+ freemsg (data);
+ return OSS_EIO;
+ }
+
+ /*LINTED*/ l = data->b_wptr - data->b_rptr;
+
+ memcpy (buf, data->b_rptr, l);
+ freemsg (data);
+
+ return l;
+}
+
+/* Endpoint/pipe access */
+
+struct _udi_endpoint_handle_t
+{
+ usb_pipe_handle_t pipe_handle;
+ unsigned char *ep_desc;
+ udi_usb_devc *usbdev;
+};
+
+udi_endpoint_handle_t *
+udi_open_endpoint (udi_usb_devc * usbdev, void *ep_desc)
+{
+ udi_endpoint_handle_t *h;
+ int err;
+ usb_pipe_policy_t policy;
+
+ if ((h = KERNEL_MALLOC (sizeof (*h))) == NULL)
+ return NULL;
+
+ policy.pp_max_async_reqs = 2;
+
+ if ((err = usb_pipe_open (usbdev->osdev->dip, ep_desc, &policy,
+ USB_FLAGS_SLEEP, &h->pipe_handle)) != USB_SUCCESS)
+ {
+ cmn_err (CE_WARN, "usb_pipe_open() failed %d (%s)\n", err,
+ usb_cb_err (err));
+ KERNEL_FREE (h);
+ return NULL;
+ }
+
+ h->ep_desc = ep_desc;
+ h->usbdev = usbdev;
+
+ return h;
+}
+
+void
+udi_close_endpoint (udi_endpoint_handle_t * h)
+{
+ usb_pipe_close (h->usbdev->osdev->dip, h->pipe_handle, USB_FLAGS_SLEEP,
+ NULL, 0);
+ KERNEL_FREE (h);
+}
+
+int
+udi_endpoint_get_num (udi_endpoint_handle_t * eph)
+{
+ return eph->ep_desc[2] & 0xff;
+}
+
+/* Request stuff */
+
+struct udi_usb_request
+{
+ dev_info_t *dip;
+ usb_pipe_handle_t pipe_handle;
+ udi_usb_complete_func_t callback;
+ void *callback_arg;
+ int active;
+ int xfer_type;
+ mblk_t *data;
+
+ /*
+ * Recording
+ */
+ int actlen;
+
+ usb_isoc_req_t *isoc_req;
+ usb_bulk_req_t *bulk_req;
+ usb_intr_req_t *intr_req;
+};
+
+ /*ARGSUSED*/
+ udi_usb_request_t
+ * udi_usb_alloc_request (udi_usb_devc * usbdev, udi_endpoint_handle_t * eph,
+ int nframes, int xfer_type)
+{
+ udi_usb_request_t *req;
+
+ if ((req = KERNEL_MALLOC (sizeof (*req))) == NULL)
+ {
+ cmn_err (CE_WARN, "udi_usb_alloc_request: Out of memory\n");
+ return NULL;
+ }
+
+ req->xfer_type = xfer_type;
+ req->dip = usbdev->osdev->dip;
+ req->pipe_handle = eph->pipe_handle;
+
+ switch (xfer_type)
+ {
+ case UDI_USBXFER_ISO_READ:
+ return req;
+ break;
+
+ case UDI_USBXFER_ISO_WRITE:
+ return req;
+ break;
+
+ case UDI_USBXFER_BULK_READ:
+ return req;
+ break;
+
+ case UDI_USBXFER_INTR_READ:
+ return req;
+ break;
+
+ case UDI_USBXFER_BULK_WRITE:
+ return req;
+ break;
+
+ default:
+ cmn_err (CE_WARN, "Internal error - bad transfer type %d\n", xfer_type);
+ KERNEL_FREE (req);
+ return NULL;
+ }
+}
+
+void
+udi_usb_free_request (udi_usb_request_t * req)
+{
+ if (req == NULL)
+ return;
+
+ udi_usb_cancel_request (req);
+
+ if (req->active)
+ {
+ cmn_err (CE_WARN, "Warning: Freeing active request\n");
+ }
+
+ switch (req->xfer_type)
+ {
+ case UDI_USBXFER_ISO_WRITE:
+ req->isoc_req = NULL;
+ break;
+
+ case UDI_USBXFER_ISO_READ:
+ req->isoc_req = NULL;
+ break;
+
+ case UDI_USBXFER_BULK_WRITE:
+ req->bulk_req = NULL;
+ break;
+
+ case UDI_USBXFER_BULK_READ:
+ req->bulk_req = NULL;
+ break;
+
+ case UDI_USBXFER_INTR_READ:
+ req->intr_req = NULL;
+ break;
+
+ default:
+ cmn_err (CE_WARN, "Internal error - bad transfer type %d\n",
+ req->xfer_type);
+ }
+
+ KERNEL_FREE (req);
+}
+
+/*ARGSUSED*/
+static void
+isoc_play_callback (usb_pipe_handle_t ph, usb_isoc_req_t * isoc_req)
+{
+ udi_usb_request_t *req =
+ (udi_usb_request_t *) isoc_req->isoc_client_private;
+
+ usb_free_isoc_req (isoc_req);
+
+ req->isoc_req = NULL;
+ req->active = 0;
+
+ req->callback (req, req->callback_arg);
+}
+
+/*ARGSUSED*/
+static void
+isoc_rec_callback (usb_pipe_handle_t ph, usb_isoc_req_t * isoc_req)
+{
+ int i;
+ udi_usb_request_t *req =
+ (udi_usb_request_t *) isoc_req->isoc_client_private;
+
+ req->data = isoc_req->isoc_data;
+
+ for (i = 0; i < isoc_req->isoc_pkts_count; i++)
+ {
+ int len;
+
+ len = isoc_req->isoc_pkt_descr[i].isoc_pkt_actual_length;
+
+ req->actlen = len;
+
+ req->callback (req, req->callback_arg);
+
+ req->data->b_rptr += len;
+ }
+
+ req->active = 0;
+ usb_free_isoc_req (isoc_req);
+}
+
+/*ARGSUSED*/
+static void
+isoc_exc_callback (usb_pipe_handle_t ph, usb_isoc_req_t * isoc_req)
+{
+ udi_usb_request_t *req =
+ (udi_usb_request_t *) isoc_req->isoc_client_private;
+ usb_cr_t reason;
+
+ reason = isoc_req->isoc_completion_reason;
+
+ usb_free_isoc_req (isoc_req);
+ req->isoc_req = NULL;
+ req->active = 0;
+
+ if (reason && reason != USB_CR_FLUSHED && reason != USB_CR_PIPE_CLOSING)
+ cmn_err (CE_CONT, "USB isoc transfer completion status %s\n",
+ usb_cr_err (reason));
+}
+
+/*ARGSUSED*/
+void
+bulk_play_callback (usb_pipe_handle_t ph, usb_bulk_req_t * bulk_req)
+{
+ udi_usb_request_t *req =
+ (udi_usb_request_t *) bulk_req->bulk_client_private;
+
+ usb_free_bulk_req (bulk_req);
+
+ req->bulk_req = NULL;
+ req->active = 0;
+
+ req->callback (req, req->callback_arg);
+}
+
+/*ARGSUSED*/
+void
+bulk_rec_callback (usb_pipe_handle_t ph, usb_bulk_req_t * bulk_req)
+{
+ udi_usb_request_t *req =
+ (udi_usb_request_t *) bulk_req->bulk_client_private;
+
+ req->data = bulk_req->bulk_data;
+ req->actlen = bulk_req->bulk_len;
+ req->active = 0;
+
+ req->callback (req, req->callback_arg);
+ //usb_free_bulk_req (bulk_req);
+}
+
+/*ARGSUSED*/
+static void
+bulk_exc_callback (usb_pipe_handle_t ph, usb_bulk_req_t * bulk_req)
+{
+ udi_usb_request_t *req =
+ (udi_usb_request_t *) bulk_req->bulk_client_private;
+ usb_cr_t reason;
+
+ reason = bulk_req->bulk_completion_reason;
+
+ usb_free_bulk_req (bulk_req);
+ req->bulk_req = NULL;
+ req->active = 0;
+
+ if (reason && reason != USB_CR_FLUSHED && reason != USB_CR_PIPE_CLOSING)
+ cmn_err (CE_CONT, "USB bulk transfer completion status %s\n",
+ usb_cr_err (reason));
+}
+
+/*ARGSUSED*/
+void
+intr_rec_callback (usb_pipe_handle_t ph, usb_intr_req_t * intr_req)
+{
+ udi_usb_request_t *req =
+ (udi_usb_request_t *) intr_req->intr_client_private;
+
+ req->data = intr_req->intr_data;
+ req->actlen = intr_req->intr_len;
+ req->active = 0;
+
+ req->callback (req, req->callback_arg);
+ //usb_free_intr_req (intr_req);
+}
+
+/*ARGSUSED*/
+static void
+intr_exc_callback (usb_pipe_handle_t ph, usb_intr_req_t * intr_req)
+{
+ udi_usb_request_t *req =
+ (udi_usb_request_t *) intr_req->intr_client_private;
+ usb_cr_t reason;
+
+ reason = intr_req->intr_completion_reason;
+
+ usb_free_intr_req (intr_req);
+ req->intr_req = NULL;
+ req->active = 0;
+
+ if (reason && reason != USB_CR_FLUSHED && reason != USB_CR_PIPE_CLOSING)
+ cmn_err (CE_CONT, "USB intr transfer completion status %s\n",
+ usb_cr_err (reason));
+}
+
+/*ARGSUSED*/
+int
+udi_usb_submit_request (udi_usb_request_t * req,
+ udi_usb_complete_func_t callback, void *callback_arg,
+ udi_endpoint_handle_t * eph, int xfer_type,
+ void *data, int len)
+{
+ int err;
+
+ req->callback = callback;
+ req->callback_arg = callback_arg;
+
+ if (req->active)
+ return 0;
+
+ switch (xfer_type)
+ {
+ case UDI_USBXFER_ISO_WRITE:
+ {
+ usb_isoc_req_t *isoc_req;
+
+ if (req->isoc_req != NULL)
+ isoc_req = req->isoc_req;
+ else
+ {
+ req->data = allocb (len, BPRI_HI);
+ if (req->data == NULL)
+ {
+ cmn_err (CE_WARN, "allocb_wait (isoc) failed\n");
+ KERNEL_FREE (req);
+ return OSS_ENOMEM;
+ }
+
+ if ((isoc_req = usb_alloc_isoc_req (req->dip, 1, 0, 0)) == NULL)
+ {
+ cmn_err (CE_WARN, "usb_alloc_isoc_req failed\n");
+ freemsg (req->data);
+ KERNEL_FREE (req);
+ return OSS_ENOMEM;
+ }
+ req->isoc_req = isoc_req;
+ }
+
+ if (isoc_req == NULL)
+ {
+ cmn_err (CE_WARN, "req->isoc==NULL\n");
+ return OSS_EIO;
+ }
+
+ memcpy (req->data->b_wptr, data, len);
+ req->data->b_wptr += len;
+
+ isoc_req->isoc_data = req->data;
+ isoc_req->isoc_pkt_descr[0].isoc_pkt_length = len;
+ isoc_req->isoc_pkts_count = 1;
+ isoc_req->isoc_pkts_length = len;
+ isoc_req->isoc_attributes =
+ USB_ATTRS_ISOC_XFER_ASAP | USB_ATTRS_AUTOCLEARING;
+ isoc_req->isoc_cb = isoc_play_callback;
+ isoc_req->isoc_exc_cb = isoc_exc_callback;
+ isoc_req->isoc_client_private = (usb_opaque_t) req;
+
+ if ((err =
+ usb_pipe_isoc_xfer (req->pipe_handle, isoc_req,
+ 0)) != USB_SUCCESS)
+ {
+ cmn_err (CE_WARN, "usb_pipe_isoc_xfer failed (%s)\n",
+ usb_errstr (err));
+ return OSS_EIO;
+ }
+ req->active = 1;
+ }
+ break;
+
+ case UDI_USBXFER_ISO_READ:
+ {
+ usb_isoc_req_t *isoc_req;
+
+ if (req->isoc_req != NULL)
+ isoc_req = req->isoc_req;
+ else
+ {
+ if ((isoc_req =
+ usb_alloc_isoc_req (req->dip, 1, len,
+ USB_FLAGS_SLEEP)) == NULL)
+ {
+ cmn_err (CE_WARN, "usb_alloc_isoc_req failed\n");
+ KERNEL_FREE (req);
+ return OSS_ENOMEM;
+ }
+ req->isoc_req = isoc_req;
+ }
+
+ if (isoc_req == NULL)
+ {
+ cmn_err (CE_WARN, "req->isoc==NULL\n");
+ return OSS_EIO;
+ }
+
+ isoc_req->isoc_attributes = USB_ATTRS_ISOC_XFER_ASAP;
+ isoc_req->isoc_cb = isoc_rec_callback;
+ isoc_req->isoc_exc_cb = isoc_exc_callback;
+ isoc_req->isoc_client_private = (usb_opaque_t) req;
+ isoc_req->isoc_pkt_descr[0].isoc_pkt_length = len;
+ isoc_req->isoc_pkts_count = 1;
+ isoc_req->isoc_pkts_length = len;
+ req->active = 1;
+
+ if ((err =
+ usb_pipe_isoc_xfer (req->pipe_handle, isoc_req,
+ USB_FLAGS_NOSLEEP)) != USB_SUCCESS)
+ {
+ cmn_err (CE_WARN, "usb_pipe_isoc_xfer failed (%s)\n",
+ usb_errstr (err));
+ return OSS_EIO;
+ }
+ }
+ break;
+
+ case UDI_USBXFER_BULK_WRITE:
+ {
+ usb_bulk_req_t *bulk_req;
+
+ if (req->bulk_req != NULL)
+ bulk_req = req->bulk_req;
+ else
+ {
+ req->data = allocb (len, BPRI_HI);
+ if (req->data == NULL)
+ {
+ cmn_err (CE_WARN, "allocb_wait (bulk) failed\n");
+ KERNEL_FREE (req);
+ return OSS_ENOMEM;
+ }
+
+ if ((bulk_req = usb_alloc_bulk_req (req->dip, len, 0)) == NULL)
+ {
+ cmn_err (CE_WARN, "usb_alloc_bulk_req failed\n");
+ freemsg (req->data);
+ KERNEL_FREE (req);
+ return OSS_ENOMEM;
+ }
+ req->bulk_req = bulk_req;
+ }
+
+ if (bulk_req == NULL)
+ {
+ cmn_err (CE_WARN, "req->bulk==NULL\n");
+ return OSS_EIO;
+ }
+
+ memcpy (req->data->b_wptr, data, len);
+ req->data->b_wptr += len;
+
+ bulk_req->bulk_data = req->data;
+ bulk_req->bulk_len = len;
+ bulk_req->bulk_timeout = 5; /* 5 seconds */
+ bulk_req->bulk_attributes = USB_ATTRS_AUTOCLEARING;
+ bulk_req->bulk_cb = bulk_play_callback;
+ bulk_req->bulk_exc_cb = bulk_exc_callback;
+ bulk_req->bulk_client_private = (usb_opaque_t) req;
+
+ if ((err =
+ usb_pipe_bulk_xfer (req->pipe_handle, bulk_req,
+ 0)) != USB_SUCCESS)
+ {
+ cmn_err (CE_WARN, "usb_pipe_bulk_xfer failed (%s)\n",
+ usb_errstr (err));
+ return OSS_EIO;
+ }
+ req->active = 1;
+ }
+ break;
+
+ case UDI_USBXFER_BULK_READ:
+ {
+ usb_bulk_req_t *bulk_req;
+
+ if (req->bulk_req != NULL)
+ bulk_req = req->bulk_req;
+ else
+ {
+#if 0
+ req->data = allocb (len, BPRI_HI);
+ if (req->data == NULL)
+ {
+ cmn_err (CE_WARN, "allocb_wait (bulk) failed\n");
+ KERNEL_FREE (req);
+ return OSS_ENOMEM;
+ }
+#endif
+
+ if ((bulk_req =
+ usb_alloc_bulk_req (req->dip, len, USB_FLAGS_SLEEP)) == NULL)
+ {
+ cmn_err (CE_WARN, "usb_alloc_bulk_req failed\n");
+ freemsg (req->data);
+ KERNEL_FREE (req);
+ return OSS_ENOMEM;
+ }
+ req->bulk_req = bulk_req;
+ }
+
+ if (bulk_req == NULL)
+ {
+ cmn_err (CE_WARN, "req->bulk==NULL\n");
+ return OSS_EIO;
+ }
+
+ bulk_req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK;
+ bulk_req->bulk_cb = bulk_rec_callback;
+ bulk_req->bulk_exc_cb = bulk_exc_callback;
+ bulk_req->bulk_client_private = (usb_opaque_t) req;
+ // bulk_req->bulk_data = data;
+ bulk_req->bulk_len = len;
+ bulk_req->bulk_timeout = 0x7fffffff; /* As long as possible */
+ req->active = 1;
+
+ if ((err =
+ usb_pipe_bulk_xfer (req->pipe_handle, bulk_req,
+ USB_FLAGS_NOSLEEP)) != USB_SUCCESS)
+ {
+ cmn_err (CE_WARN, "usb_pipe_bulk_xfer failed (%s)\n",
+ usb_errstr (err));
+ return OSS_EIO;
+ }
+ }
+ break;
+
+ case UDI_USBXFER_INTR_READ:
+ {
+ usb_intr_req_t *intr_req;
+
+ if (req->intr_req != NULL)
+ intr_req = req->intr_req;
+ else
+ {
+#if 0
+ req->data = allocb (len, BPRI_HI);
+ if (req->data == NULL)
+ {
+ cmn_err (CE_WARN, "allocb_wait (intr) failed\n");
+ KERNEL_FREE (req);
+ return OSS_ENOMEM;
+ }
+#endif
+
+ if ((intr_req =
+ usb_alloc_intr_req (req->dip, len, USB_FLAGS_SLEEP)) == NULL)
+ {
+ cmn_err (CE_WARN, "usb_alloc_intr_req failed\n");
+ freemsg (req->data);
+ KERNEL_FREE (req);
+ return OSS_ENOMEM;
+ }
+ req->intr_req = intr_req;
+ }
+
+ if (intr_req == NULL)
+ {
+ cmn_err (CE_WARN, "req->intr==NULL\n");
+ return OSS_EIO;
+ }
+
+ intr_req->intr_attributes =
+ USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_ONE_XFER;
+ intr_req->intr_cb = intr_rec_callback;
+ intr_req->intr_exc_cb = intr_exc_callback;
+ intr_req->intr_client_private = (usb_opaque_t) req;
+ intr_req->intr_data = NULL;
+ intr_req->intr_len = len;
+ intr_req->intr_timeout = 0x7fffffff; /* As long as possible */
+ req->active = 1;
+
+ if ((err =
+ usb_pipe_intr_xfer (req->pipe_handle, intr_req,
+ 0)) != USB_SUCCESS)
+ {
+ cmn_err (CE_WARN, "usb_pipe_intr_xfer failed (%s)\n",
+ usb_errstr (err));
+ return OSS_EIO;
+ }
+ }
+ break;
+
+ default:
+ cmn_err (CE_WARN, "Unimplemented transfer type %d\n", xfer_type);
+ return OSS_EIO;
+ }
+
+ return 0;
+}
+
+int
+udi_usb_request_actlen (udi_usb_request_t * request)
+{
+ return request->actlen;
+}
+
+unsigned char *
+udi_usb_request_actdata (udi_usb_request_t * request)
+{
+ return request->data->b_rptr;
+}
+
+void
+udi_usb_cancel_request (udi_usb_request_t * req)
+{
+ if (req == NULL || !req->active)
+ return;
+
+ req->active = 0;
+ usb_pipe_reset (req->dip, req->pipe_handle, USB_FLAGS_SLEEP, NULL, 0);
+
+ switch (req->xfer_type)
+ {
+ case UDI_USBXFER_ISO_WRITE:
+ break;
+
+ case UDI_USBXFER_ISO_READ:
+ usb_pipe_stop_isoc_polling (req->pipe_handle, USB_FLAGS_SLEEP);
+ //if (req->isoc_req!=NULL)
+ //usb_free_isoc_req(req->isoc_req);
+ req->isoc_req = NULL;
+ break;
+
+ case UDI_USBXFER_BULK_WRITE:
+ break;
+
+ case UDI_USBXFER_BULK_READ:
+ req->bulk_req = NULL;
+ break;
+
+ case UDI_USBXFER_INTR_READ:
+ req->intr_req = NULL;
+ break;
+
+ default:
+ cmn_err (CE_WARN, "Internal error - bad transfer type %d\n",
+ req->xfer_type);
+ }
+}
+#endif
diff --git a/kernel/OS/VxWorks/.config b/kernel/OS/VxWorks/.config
new file mode 100644
index 0000000..816ac62
--- /dev/null
+++ b/kernel/OS/VxWorks/.config
@@ -0,0 +1 @@
+mode=kernel
diff --git a/kernel/OS/VxWorks/linux/ioctl.h b/kernel/OS/VxWorks/linux/ioctl.h
new file mode 100644
index 0000000..937d84c
--- /dev/null
+++ b/kernel/OS/VxWorks/linux/ioctl.h
@@ -0,0 +1,5 @@
+/*
+ * This file is currently required when cross compiling
+ * for VxWorks under Linux.
+ */
+#include <sys/ioctl.h>
diff --git a/kernel/OS/VxWorks/module.inc b/kernel/OS/VxWorks/module.inc
new file mode 100644
index 0000000..31f17f0
--- /dev/null
+++ b/kernel/OS/VxWorks/module.inc
@@ -0,0 +1,127 @@
+#if DRIVER_TYPE == DRV_PCI
+#include <drv/pci/pciConfigLib.h>
+#undef PCI_LATENCY_TIMER
+#include <oss_pci.h>
+
+int
+oss_pci_read_config_byte (oss_device_t * osdev, offset_t where,
+ unsigned char *val)
+{
+ oss_pci_device_t *pd = osdev->dip;
+
+ return pciConfigInByte (pd->bus, pd->dev, pd->func, where, val);
+}
+
+int
+oss_pci_read_config_irq (oss_device_t * osdev, offset_t where,
+ unsigned char *val)
+{
+ oss_pci_device_t *pd = osdev->dip;
+
+ return pciConfigInByte (pd->bus, pd->dev, pd->func, where, val);
+}
+
+int
+oss_pci_read_config_word (oss_device_t * osdev, offset_t where,
+ unsigned short *val)
+{
+ oss_pci_device_t *pd = osdev->dip;
+
+ if (osdev == NULL)
+ {
+ cmn_err (CE_CONT, "oss_pci_read_config_word: osdev==NULL\n");
+ return PCIBIOS_FAILED;
+ }
+
+ return pciConfigInWord (pd->bus, pd->dev, pd->func, where, val);
+}
+
+int
+oss_pci_read_config_dword (oss_device_t * osdev, offset_t where,
+ unsigned int *val)
+{
+ oss_pci_device_t *pd = osdev->dip;
+
+ return pciConfigInLong (pd->bus, pd->dev, pd->func, where, val);
+}
+
+int
+oss_pci_write_config_byte (oss_device_t * osdev, offset_t where,
+ unsigned char val)
+{
+ oss_pci_device_t *pd = osdev->dip;
+
+ return pciConfigOutByte (pd->bus, pd->dev, pd->func, where, val);
+}
+
+int
+oss_pci_write_config_word (oss_device_t * osdev, offset_t where,
+ unsigned short val)
+{
+ oss_pci_device_t *pd = osdev->dip;
+
+ return pciConfigOutWord (pd->bus, pd->dev, pd->func, where, val);
+}
+
+int
+oss_pci_write_config_dword (oss_device_t * osdev, offset_t where,
+ unsigned int val)
+{
+ oss_pci_device_t *pd = osdev->dip;
+
+ return pciConfigOutLong (pd->bus, pd->dev, pd->func, where, val);
+}
+#endif
+
+int
+DRIVER_NAME(void)
+{
+#if DRIVER_TYPE == DRV_PCI
+ int i;
+ int bus, dev, func;
+ unsigned int d, vendor_id, dev_id;
+ static int instance = 0;
+
+ if (id_table[0] == 0)
+ {
+ cmn_err (CE_WARN, DRIVER_NICK ": ID table is empty\n");
+ return OSS_EIO;
+ }
+
+ i=0;
+
+ while ((d=id_table[i]) != 0)
+ {
+ int index=0;
+ vendor_id = (d >> 16) & 0xffff;
+ dev_id = d & 0xffff;
+
+ while (pciFindDevice(vendor_id, dev_id, instance,&bus, &dev, &func) == OK)
+ {
+ oss_pci_device_t *pcidev = malloc(sizeof(*pcidev));
+ oss_device_t *osdev;
+
+
+ cmn_err(CE_CONT, "Found pci device %08x / %d : b=%d, d=%d, f=%d\n", d, index, bus, dev, func);
+
+ pcidev->bus = bus;
+ pcidev->dev = dev;
+ pcidev->func = func;
+
+ if ((osdev =
+ osdev_create ((dev_info_t*)pcidev, DRIVER_TYPE, instance++, DRIVER_NICK,
+ NULL)) == NULL)
+ {
+ return OSS_ENOMEM;
+ }
+
+ index++;
+ }
+
+ i++;
+ }
+
+#endif
+
+ return 0;
+}
diff --git a/kernel/OS/VxWorks/os_vxworks.c b/kernel/OS/VxWorks/os_vxworks.c
new file mode 100644
index 0000000..a679e6c
--- /dev/null
+++ b/kernel/OS/VxWorks/os_vxworks.c
@@ -0,0 +1,1133 @@
+/*
+ * oss_vxworks.c: Common entry points for OSS under VxWorks.
+ */
+
+#include <oss_config.h>
+#include <oss_pci.h>
+#include <drv/pci/pciConfigLib.h>
+#include <memLib.h>
+
+#if 0
+// TODO: Obsolete
+typedef struct oss_device_handle
+{
+ DEV_HDR devHdr;
+ int minor;
+ int valid; /* 1=valid, 0=undefined */
+ struct fileinfo finfo;
+}
+oss_device_handle;
+#endif
+/*
+ * Number of cards supported in the same system.
+ */
+#define MAX_CARDS 8
+
+static oss_device_t *cards[MAX_CARDS];
+int oss_num_cards = 0;
+
+static int oss_driver_num = ERROR;
+static int oss_expired = 0;
+static oss_device_t *core_osdev = NULL;
+
+int oss_hz = 100;
+
+void
+oss_cmn_err (int level, const char *s, ...)
+{
+ char tmp[1024], *a[6];
+ va_list ap;
+ int i, n = 0;
+
+ va_start (ap, s);
+
+ for (i = 0; i < strlen (s); i++)
+ if (s[i] == '%')
+ n++;
+
+ for (i = 0; i < n && i < 6; i++)
+ a[i] = ( (sizeof(char *) == 32) ? ( *((char * **)(ap += ((sizeof(char * *)+sizeof(int)-1) & ~(sizeof(int)-1))))[-1] ) : ( ((char * *)(ap += ((sizeof(char *)+sizeof(int)-1) & ~(sizeof(int)-1))))[-1] ));
+ //a[i] = va_arg (ap, char *); // This was supposed to be used instead of above. Unfortunately va_arg() seems to be buggy
+
+ for (i = n; i < 6; i++)
+ a[i] = NULL;
+
+ if (level == CE_CONT)
+ {
+ sprintf (tmp, s, a[0], a[1], a[2], a[3], a[4], a[5], NULL,
+ NULL, NULL, NULL);
+ printf ("%s", tmp);
+ }
+ else
+ {
+ strcpy (tmp, "osscore: ");
+ sprintf (tmp + strlen (tmp), s, a[0], a[1], a[2], a[3], a[4], a[5],
+ NULL, NULL, NULL, NULL);
+
+ printf ("%s", tmp);
+ }
+
+ va_end (ap);
+}
+
+int
+oss_uiomove (void *addr, size_t nbytes, enum uio_rw rwflag, uio_t * uio)
+{
+/*
+ * NOTE! Returns 0 upon success and EFAULT on failure (instead of -EFAULT
+ * (for Solaris/BSD compatibility)).
+ */
+
+ if (rwflag != uio->rw)
+ {
+ oss_cmn_err (CE_WARN, "uiomove: Bad direction\n");
+ return EFAULT;
+ }
+
+ if (uio->resid < nbytes)
+ {
+ oss_cmn_err (CE_WARN, "uiomove: Bad count %d (%d)\n", nbytes,
+ uio->resid);
+ return EFAULT;
+ }
+
+ if (uio->kernel_space)
+ return EFAULT;
+
+ switch (rwflag)
+ {
+ case UIO_READ:
+ memcpy(uio->ptr, addr, nbytes);
+ break;
+
+ case UIO_WRITE:
+ memcpy(addr, uio->ptr, nbytes);
+ break;
+ }
+
+ uio->resid -= nbytes;
+ uio->ptr += nbytes;
+
+ return 0;
+}
+
+int
+oss_create_uio (uio_t * uio, char *buf, size_t count, uio_rw_t rw,
+ int is_kernel)
+{
+ memset (uio, 0, sizeof (*uio));
+
+ if (is_kernel)
+ {
+ oss_cmn_err (CE_CONT,
+ "oss_create_uio: Kernel space buffers not supported\n");
+ return -EIO;
+ }
+
+ uio->ptr = buf;
+ uio->resid = count;
+ uio->kernel_space = is_kernel;
+ uio->rw = rw;
+
+ return 0;
+}
+
+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;
+}
+
+static void
+register_chrdev(oss_cdev_t *cdev, char *name)
+{
+ if (iosDevAdd ((void *)cdev, name, oss_driver_num) == ERROR)
+ {
+ cmn_err (CE_WARN, "Failed to add device %s\n", name);
+ }
+}
+
+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 (dev_class != OSS_DEV_STATUS)
+ if (oss_expired && instance > 0)
+ return;
+
+ 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);
+ register_chrdev (cdev, name);
+ }
+}
+
+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;
+}
+
+static inline int
+cpy_file (int mode, struct fileinfo *fi)
+{
+ fi->mode = 0;
+ fi->acc_flags = mode;
+
+ 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 void *
+ossOpen (oss_cdev_t *cdev, char *reminder, int mode)
+{
+ int tmpdev, retval;
+ struct fileinfo fi;
+
+ cpy_file (mode, &fi);
+
+ DDB (cmn_err
+ (CE_CONT, "ossOpen(%p): %s, class=%d, instance=%d\n", cdev,
+ cdev->name, cdev->dev_class, cdev->instance));
+
+ if (cdev->d->open == NULL)
+ {
+ errnoSet(ENODEV);
+ return (void*)ERROR;
+ }
+
+ tmpdev = -1;
+ retval =
+ cdev->d->open (cdev->instance, cdev->dev_class, &fi, 0, 0, &tmpdev);
+
+ if (retval < 0)
+ {
+ errnoSet(-retval);
+ return (void*)ERROR;
+ }
+
+ if (tmpdev != -1)
+ {
+ if (tmpdev >= 0 && tmpdev < oss_num_cdevs)
+ {
+ cdev = oss_cdevs[tmpdev];
+ }
+ else
+ {
+ errnoSet(ENODEV);
+ return (void*)ERROR;
+ }
+ }
+
+ errnoSet (0);
+ memcpy(&cdev->file, &fi, sizeof(struct fileinfo));
+
+ return cdev;
+}
+
+static int
+ossClose (oss_cdev_t *cdev)
+{
+ if (cdev->d->close == NULL)
+ {
+ return OK;
+ }
+
+ cdev->d->close (cdev->instance, &cdev->file);
+
+ return OK;
+}
+
+static int
+ossRead (oss_cdev_t *cdev, char *buf, int count)
+{
+ int err, len;
+ uio_t uio;
+
+ if (cdev->d->read == NULL)
+ {
+ errnoSet (ENXIO);
+ return ERROR;
+ }
+
+ if ((err = oss_create_uio (&uio, buf, count, UIO_READ, 0)) < 0)
+ {
+ errnoSet (-err);
+ return ERROR;
+ }
+
+ len = cdev->d->read (cdev->instance, &cdev->file, &uio, count);
+
+ if (len >= 0)
+ return len;
+
+ errnoSet (-len);
+ return ERROR;
+}
+
+static int
+ossWrite (oss_cdev_t *cdev, char *buf, int count)
+{
+ int err, len;
+ uio_t uio;
+
+ if (cdev->d->write == NULL)
+ {
+ errnoSet (ENXIO);
+ return ERROR;
+ }
+
+ if ((err = oss_create_uio (&uio, buf, count, UIO_WRITE, 0)) < 0)
+ {
+ errnoSet (-err);
+ return ERROR;
+ }
+
+ len = cdev->d->write (cdev->instance, &cdev->file, &uio, count);
+
+ if (len >= 0)
+ return len;
+
+ errnoSet (-len);
+ return ERROR;
+}
+
+static int
+ossIoctl (oss_cdev_t *cdev, int cmd, int *arg)
+{
+ int err;
+
+ if (cdev->d->ioctl == NULL)
+ {
+ errnoSet (ENXIO);
+ return ERROR;
+ }
+
+ if ((err = cdev->d->ioctl (cdev->instance, &cdev->file, cmd, (ioctl_arg) arg)) < 0)
+ {
+ errnoSet (-err);
+ return ERROR;
+ }
+ return OK;
+}
+
+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:
+ {
+#if 0
+ // TODO
+ 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);
+#else
+ strcpy(osdev->handle, "PCICARD");
+#endif
+ }
+ 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 *
+oss_get_osid (oss_device_t * osdev)
+{
+ return NULL; // TODO
+}
+
+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
+ossDrv (void)
+{
+ oss_hz = sysClkRateGet();
+
+ if (oss_driver_num != ERROR)
+ {
+ cmn_err (CE_WARN, "OSS is already running\n");
+ return -1;
+ }
+
+#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;
+ return -1;
+ }
+#endif
+
+ oss_driver_num = iosDrvInstall ((FUNCPTR) NULL, /* create */
+ (FUNCPTR) NULL, /* delete */
+ (FUNCPTR) ossOpen, (FUNCPTR) ossClose, (FUNCPTR) ossRead, (FUNCPTR) ossWrite, (FUNCPTR) ossIoctl /* ioctl */
+ );
+ if (oss_driver_num == ERROR)
+ {
+ cmn_err (CE_WARN, "Module osscore failed to install\n");
+ return -1;
+ }
+
+ if ((core_osdev =
+ osdev_create (NULL, DRV_UNKNOWN, 0, "osscore", NULL)) == NULL)
+ {
+ oss_cmn_err (CE_WARN, "Failed to allocate OSDEV structure\n");
+ return -1;
+ }
+ oss_register_device (core_osdev, "OSS core services");
+
+ oss_common_init (core_osdev);
+
+ return oss_driver_num;
+}
+
+int
+ossDrvRemove (void)
+{
+#if 1
+
+ return ERROR;
+#else
+ int i;
+
+ if (oss_driver_num == ERROR)
+ return 0;
+
+ for (i = 0; i < SND_NDEVS; i++)
+ if (oss_files[i].valid)
+ {
+ iosDevDelete (&oss_files[i].devHdr);
+ oss_files[i].valid = 0;
+ }
+
+ if (iosDrvRemove (oss_driver_num, FALSE) == ERROR)
+ {
+ cmn_err (CE_WARN, "Driver busy - cannot remove.\n");
+ return ERROR;
+ }
+
+ // TODO
+ oss_unload_drivers ();
+
+ oss_driver_num = ERROR; /* Mark it free */
+ return OK;
+#endif
+}
+
+#ifdef CONFIG_OSS_VMIX_FLOAT
+
+#undef FP_SAVE
+#undef FP_RESTORE
+#define FP_SAVE(envbuf) asm ("fnsave %0":"=m" (*envbuf));
+#define FP_RESTORE(envbuf) asm ("frstor %0":"=m" (*envbuf));
+
+/* SSE/SSE2 compatible macros */
+#define FX_SAVE(envbuf) asm ("fxsave %0":"=m" (*envbuf));
+#define FX_RESTORE(envbuf) asm ("fxrstor %0":"=m" (*envbuf));
+
+static int old_arch = 0; /* No SSE/SSE2 instructions */
+
+#if defined(__amd64__)
+#define AMD64
+#endif
+
+static inline void
+cpuid (int op, int *eax, int *ebx, int *ecx, int *edx)
+{
+__asm__ ("cpuid": "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx):"0" (op), "c"
+ (0));
+}
+
+#ifdef AMD64
+# define local_save_flags(x) asm volatile("pushfq ; popq %0":"=g" (x):)
+# define local_restore_flags(x) asm volatile("pushq %0 ; popfq"::"g" (x):"memory", "cc")
+#else
+# define local_save_flags(x) asm volatile("pushfl ; popl %0":"=g" (x):)
+# define local_restore_flags(x) asm volatile("pushl %0 ; popfl"::"g" (x):"memory", "cc")
+#endif
+
+static inline unsigned long
+read_cr0 (void)
+{
+ unsigned long cr0;
+#ifdef AMD64
+asm ("movq %%cr0,%0":"=r" (cr0));
+#else
+asm ("movl %%cr0,%0":"=r" (cr0));
+#endif
+ return cr0;
+}
+
+static inline void
+write_cr0 (unsigned long val)
+{
+#ifdef AMD64
+ asm ("movq %0,%%cr0"::"r" (val));
+#else
+ asm ("movl %0,%%cr0"::"r" (val));
+#endif
+}
+
+static inline unsigned long
+read_cr4 (void)
+{
+ unsigned long cr4;
+#ifdef AMD64
+asm ("movq %%cr4,%0":"=r" (cr4));
+#else
+asm ("movl %%cr4,%0":"=r" (cr4));
+#endif
+ return cr4;
+}
+
+static inline void
+write_cr4 (unsigned long val)
+{
+#ifdef AMD64
+ asm ("movq %0,%%cr4"::"r" (val));
+#else
+ asm ("movl %0,%%cr4"::"r" (val));
+#endif
+}
+static inline unsigned long long
+read_mxcsr (void)
+{
+ unsigned long long mxcsr;
+ asm volatile ("stmxcsr %0":"=m" (mxcsr));
+ return mxcsr;
+}
+
+static inline void
+write_mxcsr (unsigned long long val)
+{
+ asm volatile ("ldmxcsr %0"::"m" (val));
+}
+
+int
+oss_fp_check (void)
+{
+ int eax, ebx, ecx, edx;
+#define FLAGS_ID (1<<21)
+
+ oss_native_word flags_reg;
+
+ local_save_flags (flags_reg);
+ flags_reg &= ~FLAGS_ID;
+ local_restore_flags (flags_reg);
+
+ local_save_flags (flags_reg);
+ if (flags_reg & FLAGS_ID)
+ return 0;
+
+ flags_reg |= FLAGS_ID;
+ local_restore_flags (flags_reg);
+
+ local_save_flags (flags_reg);
+ if (!(flags_reg & FLAGS_ID))
+ return 0;
+
+//#define CPUID_FXSR (1<<24)
+//#define CPUID_SSE (1<<25)
+//#define CPUID_SSE2 (1<<26)
+
+ cpuid (1, &eax, &ebx, &ecx, &edx);
+
+ if (!(edx & CPUID_FXSR))
+ return -1;
+
+ /*
+ * Older machines require different FP handling than the latest ones. Use the SSE
+ * instruction set as an indicator.
+ */
+ if (!(edx & CPUID_SSE))
+ old_arch = 1;
+
+ return 1;
+}
+
+void
+oss_fp_save (short *envbuf, unsigned int flags[])
+{
+ flags[0] = read_cr0 ();
+ write_cr0 (flags[0] & ~0x0e); /* Clear CR0.TS/MP/EM */
+
+ if (old_arch)
+ {
+ FP_SAVE (envbuf);
+ }
+ else
+ {
+ flags[1] = read_cr4 ();
+ write_cr4 (flags[1] | 0x600); /* Set OSFXSR & OSXMMEXCEPT */
+ FX_SAVE (envbuf);
+ asm ("fninit");
+ asm ("fwait");
+ write_mxcsr (0x1f80);
+ }
+ flags[2] = read_cr0 ();
+}
+
+void
+oss_fp_restore (short *envbuf, unsigned int flags[])
+{
+ asm ("fwait");
+ if (old_arch)
+ {
+ FP_RESTORE (envbuf);
+ }
+ else
+ {
+ FX_RESTORE (envbuf);
+ write_cr4 (flags[1]); /* Restore cr4 */
+ }
+ write_cr0 (flags[0]); /* Restore cr0 */
+}
+#endif
+
+typedef struct tmout_desc
+{
+ volatile int active;
+ int timestamp;
+ void (*func) (void *);
+ void *arg;
+
+ WDOG_ID id;
+
+} tmout_desc_t;
+
+static volatile int next_id = 0;
+#define MAX_TMOUTS 128
+
+tmout_desc_t tmouts[MAX_TMOUTS] = { {0} };
+
+int timeout_random = 0x12123400;
+
+void
+oss_timer_callback (int id)
+{
+ tmout_desc_t *tmout;
+ int ix;
+ void *arg;
+
+ timeout_random++;
+
+ ix = id & 0xff;
+ if (ix < 0 || ix >= MAX_TMOUTS)
+ return;
+ tmout = &tmouts[ix];
+
+ if (tmout->timestamp != id) /* Expired timer */
+ return;
+
+ if (!tmout->active)
+ return;
+
+ arg = tmout->arg;
+ tmout->active = 0;
+ tmout->timestamp = 0;
+
+ tmout->func (arg);
+ wdDelete(tmout->id);
+}
+
+timeout_id_t
+oss_timeout (void (*func) (void *), void *arg,
+ unsigned long long ticks)
+{
+
+ tmout_desc_t *tmout = NULL;
+ int id, n;
+
+ timeout_random++;
+
+ n = 0;
+ id = -1;
+
+ while (id == -1 && n < MAX_TMOUTS)
+ {
+ if (!tmouts[next_id].active)
+ {
+ tmouts[next_id].active = 1;
+ id = next_id++;
+ tmout = &tmouts[id];
+ break;
+ }
+
+ next_id = (next_id + 1) % MAX_TMOUTS;
+ }
+
+ if (id == -1) /* No timer slots available */
+ {
+ oss_cmn_err (CE_WARN, "Timeout table full\n");
+ return 0;
+ }
+
+ tmout->func = func;
+ tmout->arg = arg;
+ tmout->timestamp = id | (timeout_random & ~0xff);
+
+ if ((tmout->id=wdCreate()) == NULL)
+ return 0;
+
+ wdStart(tmout->id, ticks, (FUNCPTR)oss_timer_callback, (int)tmout->timestamp);
+ return id | (timeout_random & ~0xff);
+}
+
+void
+oss_untimeout (timeout_id_t id)
+{
+ tmout_desc_t *tmout;
+ int ix;
+
+ ix = id & 0xff;
+ if (ix < 0 || ix >= MAX_TMOUTS)
+ return;
+
+ timeout_random++;
+ tmout = &tmouts[ix];
+
+ if (tmout->timestamp != id) /* Expired timer */
+ return;
+ if (tmout->active)
+ {
+ wdCancel(tmout->id);
+ wdDelete(tmout->id);
+ }
+
+ tmout->active = 0;
+ tmout->timestamp = 0;
+}
+
+void
+oss_udelay(unsigned long ticks)
+{
+ // TODO
+}
+
+void *
+oss_contig_malloc (oss_device_t * osdev, int buffsize, oss_uint64_t memlimit,
+ oss_native_word * phaddr)
+{
+ char *start_addr, *end_addr;
+
+ *phaddr = 0;
+
+ start_addr = NULL;
+
+ // TODO: See if there is a previously freed buffer available
+
+ start_addr = (char *) valloc (buffsize);
+
+ if (start_addr == NULL)
+ {
+ cmn_err (CE_NOTE, "Failed to allocate memory buffer of %d bytes\n",
+ buffsize);
+ return NULL;
+ }
+ else
+ {
+ /* make some checks */
+ end_addr = start_addr + buffsize - 1;
+ }
+
+ *phaddr = (oss_native_word)start_addr;
+ return start_addr;
+}
+
+void
+oss_contig_free (oss_device_t * osdev, void *p, int buffsize)
+{
+ if (p == NULL)
+ return;
+
+ // TODO: Put the freed memory block to available list
+ cmn_err (CE_WARN, "Cannot free %d bytes of DMA buffer\n", buffsize);
+}
+
+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;
+}
+
+/*
+ * Sleep/wakeup
+ */
+
+struct oss_wait_queue
+{
+ volatile int flags;
+ SEM_ID wq;
+};
+
+struct oss_wait_queue *
+oss_create_wait_queue (oss_device_t * osdev, const char *name)
+{
+ struct oss_wait_queue *wq;
+
+ if ((wq = malloc (sizeof (*wq))) == NULL)
+ {
+ oss_cmn_err (CE_WARN, "vmalloc(%d) failed (wq)\n", sizeof (*wq));
+ return NULL;
+ }
+ wq->wq = semBCreate(SEM_Q_FIFO, SEM_EMPTY);
+
+ return wq;
+}
+
+void
+oss_reset_wait_queue (struct oss_wait_queue *wq)
+{
+ // TODO: ?
+}
+
+void
+oss_remove_wait_queue (struct oss_wait_queue *wq)
+{
+ free (wq);
+}
+
+int
+oss_sleep (struct oss_wait_queue *wq, oss_mutex_t * mutex, int ticks,
+ oss_native_word * flags, unsigned int *status)
+{
+ int result;
+
+ *status = 0;
+
+ if (wq == NULL)
+ return 0;
+
+ wq->flags = 0;
+
+ if (ticks <= 0)
+ ticks = WAIT_FOREVER;
+
+ result =
+ semTake(wq->wq, ticks);
+
+ if (result == ERROR) /* Signal received */
+ {
+ *status |= WK_SIGNAL;
+ return 1;
+ }
+
+ if (!(wq->flags & WK_WAKEUP)) /* Timeout */
+ {
+ return 0;
+ }
+
+ return 1;
+}
+
+int
+oss_register_poll (struct oss_wait_queue *wq, oss_mutex_t * mutex,
+ oss_native_word * flags, oss_poll_event_t * ev)
+{
+ // TODO: ?
+ return 0;
+}
+
+void
+oss_wakeup (struct oss_wait_queue *wq, oss_mutex_t * mutex,
+ oss_native_word * flags, short events)
+{
+ if (wq == NULL)
+ return;
+
+ wq->flags |= WK_WAKEUP;
+ semFlush(wq->wq);
+}
diff --git a/kernel/OS/VxWorks/os_vxworks.h b/kernel/OS/VxWorks/os_vxworks.h
new file mode 100644
index 0000000..275aa34
--- /dev/null
+++ b/kernel/OS/VxWorks/os_vxworks.h
@@ -0,0 +1,297 @@
+#ifndef _OS_H_
+#define _OS_H_
+
+/*
+ * Purpose: OS specific definitions for VxWorks
+ *
+ */
+/*
+ *
+ * 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.
+ *
+ */
+
+#define OS_VERSION "5.5"
+
+#if (!defined(i386) && !defined(x86_64)) || defined(CONFIG_OSS_FIXDEPOINT)
+// Floating point is not supported or it's disabled
+#undef CONFIG_OSS_VMIX_FLOAT
+#endif
+
+#define VDEV_SUPPORT
+#undef USE_DEVICE_SUBDIRS
+
+#define __inline__ inline
+#define __inline inline
+#define EXTERN_C extern "C"
+
+/*
+ * Disable support for per-application features such as /dev/dsp device
+ * selection based on command name. Requires working GET_PROCESS_NAME
+ * macro implementation.
+ */
+#undef APPLIST_SUPPORT
+
+#undef ALLOW_BUFFER_MAPPING
+
+/*
+ * Some integer types
+ */
+#if defined(amd64) || defined(sparc)
+typedef unsigned long long oss_native_word; /* Same as the address and status register size */
+#else
+typedef unsigned long oss_native_word; /* Same as the address and status register size */
+#endif
+
+typedef long long oss_int64_t; /* Signed 64 bit integer */
+typedef unsigned long long oss_uint64_t; /* Unsigned 64 bit integer */
+
+#include <stdarg.h>
+#include <sys/types.h>
+#include "vxWorks.h"
+#include "iv.h"
+#include "ioLib.h"
+#include "fioLib.h"
+#include "iosLib.h"
+#include "wdLib.h"
+#include "intLib.h"
+#include "tickLib.h"
+#include "errnoLib.h"
+#include "sysLib.h"
+#include "objLib.h"
+#include "vmLib.h"
+#include "semLib.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <oss_errno.h>
+/*
+ * Mutexes
+ */
+typedef int oss_mutex_t;
+#define MUTEX_INIT(osdev, mutex, hier)
+#define MUTEX_CLEANUP(mutex)
+#define MUTEX_ENTER_IRQDISABLE(mutex, flags) {flags=0;mutex=0;}
+#define MUTEX_ENTER(mutex, flags) {flags=0;mutex=0;}
+#define MUTEX_EXIT_IRQRESTORE(mutex, flags) (flags)++
+#define MUTEX_EXIT(mutex, flags) (flags)++
+
+/*
+ * Fileinfo structure
+ */
+struct fileinfo
+{
+ int mode; /* Open mode */
+ int acc_flags;
+};
+#define ISSET_FILE_FLAG(fileinfo, flag) (fileinfo->acc_flags & (flag) ? 1:0)
+
+/*
+ * Misc types
+ */
+typedef int oss_dma_handle_t;
+typedef int oss_poll_event_t;
+typedef int offset_t;
+
+/*
+ * uio_/uiomove()
+ */
+typedef enum uio_rw uio_rw_t;
+typedef struct oss_uio
+{
+ char *ptr;
+ int resid;
+ int kernel_space; /* Set if this uio points to a kernel space buffer */
+ uio_rw_t rw;
+} uio_t;
+extern int oss_uiomove (void *address, size_t nbytes, enum uio_rw rwflag,
+ uio_t * uio_p);
+extern int oss_create_uio (uio_t * uiop, char *buf, size_t count, uio_rw_t rw,
+ int is_kernel);
+#define uiomove oss_uiomove
+
+/*
+ * Error handling
+ */
+#define cmn_err oss_cmn_err
+extern int detect_trace;
+#define DDB(x) if (detect_trace) x
+extern void oss_cmn_err (int level, const char *format, ...);
+#define CE_CONT 0
+#define CE_NOTE 1
+#define CE_WARN 2
+#define CE_PANIC 3
+
+/* Busy wait routine */
+extern void oss_udelay(unsigned long ticks);
+/* System wall timer access */
+#define GET_JIFFIES() tickGet()
+extern inline unsigned int
+__inb (unsigned short port)
+{
+ unsigned int _v;
+ __asm__ __volatile__ ("in" "b" " %" "w" "1,%" "b" "0":"=a" (_v):"d" (port),
+ "0" (0));
+ return _v;
+}
+extern inline unsigned int
+__inw (unsigned short port)
+{
+ unsigned int _v;
+ __asm__ __volatile__ ("in" "w" " %" "w" "1,%" "w" "0":"=a" (_v):"d" (port),
+ "0" (0));
+ return _v;
+}
+extern inline unsigned int
+__inl (unsigned short port)
+{
+ unsigned int _v;
+ __asm__ __volatile__ ("in" "l" " %" "w" "1,%" "" "0":"=a" (_v):"d" (port));
+ return _v;
+}
+
+extern inline void
+__outb (unsigned char value, unsigned short port)
+{
+ __asm__ __volatile__ ("out" "b" " %" "b" "0,%" "w" "1"::"a" (value),
+ "d" (port));
+}
+extern inline void
+__outw (unsigned short value, unsigned short port)
+{
+ __asm__ __volatile__ ("out" "w" " %" "w" "0,%" "w" "1"::"a" (value),
+ "d" (port));
+}
+extern inline void
+__outl (unsigned int value, unsigned short port)
+{
+ __asm__ __volatile__ ("out" "l" " %" "0,%" "w" "1"::"a" (value),
+ "d" (port));
+}
+
+#define INB(osdev,a) __inb(a)
+#define INW(osdev,a) __inw(a)
+#define INL(osdev,a) __inl(a)
+
+#define OUTB(osdev, d, a) __outb(d, a)
+
+#define OUTW(osdev, d, a) __outw(d, a)
+#define OUTL(osdev, d, a) __outl(d, a)
+
+#define PCI_READL(osdev, p) (*(volatile unsigned int *) (p))
+#define PCI_WRITEL(osdev, addr, data) (*(volatile unsigned int *) (addr) = (data))
+#define PCI_READW(osdev, p) (*(volatile unsigned short *) (p))
+#define PCI_WRITEW(osdev, addr, data) (*(volatile unsigned short *) (addr) = (data))
+#define PCI_READB(osdev, p) (*(volatile unsigned char *) (p))
+#define PCI_WRITEB(osdev, addr, data) (*(volatile unsigned char *) (addr) = (data))
+
+#define MAP_PCI_IOADDR(osdev, nr, io) (oss_native_word)io
+#define MAP_PCI_MEM(osdev, ix, phaddr, size) (oss_native_word)phaddr
+#define UNMAP_PCI_MEM(osdev, ix, ph, virt, size) {}
+#define UNMAP_PCI_IOADDR(osdev, ix) {}
+/*
+ * Memory allocation and mapping
+ */
+extern void *oss_contig_malloc (oss_device_t * osdev, int sz,
+ oss_uint64_t memlimit,
+ oss_native_word * phaddr);
+extern void oss_contig_free (oss_device_t * osdev, void *p, int sz);
+extern void oss_reserve_pages (oss_native_word start_addr,
+ oss_native_word end_addr);
+extern void oss_unreserve_pages (oss_native_word start_addr,
+ oss_native_word end_addr);
+
+#define KERNEL_MALLOC(nbytes) malloc(nbytes)
+#define KERNEL_FREE(addr) free(addr)
+#define CONTIG_MALLOC(osdev, sz, memlimit, phaddr, handle) oss_contig_malloc(osdev, sz, memlimit, phaddr)
+#define CONTIG_FREE(osdev, p, sz, handle) oss_contig_free(osdev, p, sz)
+
+typedef void dev_info_t;
+
+struct _oss_device_t
+{
+ int cardnum;
+ int dev_type;
+ int available;
+ int instance;
+ dev_info_t *dip;
+ void *devc;
+ char *name;
+ char nick[16];
+ char handle[32];
+ int num_audio_engines;
+ int num_audioplay, num_audiorec, num_audioduplex;
+ int num_mididevs;
+ int num_mixerdevs;
+ int num_loopdevs;
+ int first_mixer; /* This must be set to -1 by osdev_create() */
+ int major;
+ struct module *owner; /* Pointer to THISMODULE (needed by osscore.c) */
+ char modname[32];
+ char *hw_info;
+
+ volatile int refcount; /* Nonzero means that the device is needed by some other (virtual) driver. */
+
+/* Interrupts */
+
+ int iblock_cookie; /* Dummy field under Linux */
+ void *irqparms;
+ int intrcount, ackcount;
+};
+
+typedef struct
+{
+ int bus, dev, func;
+} oss_pci_device_t;
+
+typedef int timeout_id_t;
+extern timeout_id_t oss_timeout (void (*func) (void *), void *arg,
+ unsigned long long ticks);
+extern void oss_untimeout (timeout_id_t id);
+#define timeout oss_timeout
+#define untimeout oss_untimeout
+
+extern int oss_hz;
+#define HZ oss_hz
+#define OSS_HZ HZ
+
+/*
+ * Dummy defines for poll()
+ */
+#define POLLIN 0
+#define POLLOUT 0
+#define POLLRDNORM 0
+#define POLLWRNORM 0
+
+/*
+ * Process info macros
+ */
+#define GET_PROCESS_PID(x) -1
+#define GET_PROCESS_UID(x) 0
+#define GET_PROCESS_NAME(x) NULL
+
+/*
+ * Floating point save/restore support for vmix
+ */
+#define FP_SUPPORT
+
+#ifdef FP_SUPPORT
+typedef short fp_env_t[512];
+typedef unsigned int fp_flags_t[4];
+extern int oss_fp_check (void);
+extern void oss_fp_save (short *envbuf, fp_flags_t flags);
+extern void oss_fp_restore (short *envbuf, fp_flags_t flags);
+#undef FP_SAVE
+#undef FP_RESTORE
+# define FP_SAVE(envbuf, flags) oss_fp_save(envbuf, flags)
+# define FP_RESTORE(envbuf, flags) oss_fp_restore(envbuf, flags)
+#endif
+
+#endif