summaryrefslogtreecommitdiff
path: root/kernel/OS/SCO_SV
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/OS/SCO_SV')
-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
4 files changed, 2365 insertions, 0 deletions
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