summaryrefslogtreecommitdiff
path: root/setup/FreeBSD/oss/build
diff options
context:
space:
mode:
Diffstat (limited to 'setup/FreeBSD/oss/build')
-rw-r--r--setup/FreeBSD/oss/build/Makefile.osscore7
-rw-r--r--setup/FreeBSD/oss/build/Makefile.tmpl8
-rw-r--r--setup/FreeBSD/oss/build/bsdpci.inc153
-rw-r--r--setup/FreeBSD/oss/build/bsdvirtual.inc83
-rw-r--r--setup/FreeBSD/oss/build/devid.h5
-rw-r--r--setup/FreeBSD/oss/build/install.sh75
-rw-r--r--setup/FreeBSD/oss/build/module.inc89
-rw-r--r--setup/FreeBSD/oss/build/osscore.c559
8 files changed, 979 insertions, 0 deletions
diff --git a/setup/FreeBSD/oss/build/Makefile.osscore b/setup/FreeBSD/oss/build/Makefile.osscore
new file mode 100644
index 0000000..e1f428b
--- /dev/null
+++ b/setup/FreeBSD/oss/build/Makefile.osscore
@@ -0,0 +1,7 @@
+SRCS=osscore.c
+KMOD=osscore
+OBJS += osscore_mainline.o
+SRCS += device_if.h bus_if.h pci_if.h
+
+.include <bsd.kmod.mk>
+
diff --git a/setup/FreeBSD/oss/build/Makefile.tmpl b/setup/FreeBSD/oss/build/Makefile.tmpl
new file mode 100644
index 0000000..1653841
--- /dev/null
+++ b/setup/FreeBSD/oss/build/Makefile.tmpl
@@ -0,0 +1,8 @@
+SRCS=MODNAME.c
+KMOD=MODNAME
+OBJS += MODNAME_mainline.o
+SRCS += device_if.h bus_if.h pci_if.h
+CFLAGS += -I../include/internals
+
+.include <bsd.kmod.mk>
+
diff --git a/setup/FreeBSD/oss/build/bsdpci.inc b/setup/FreeBSD/oss/build/bsdpci.inc
new file mode 100644
index 0000000..5cb0b55
--- /dev/null
+++ b/setup/FreeBSD/oss/build/bsdpci.inc
@@ -0,0 +1,153 @@
+/*
+ * Purpose: Wrapper functions for PCI drivers under FreeBSD
+ */
+/*
+ * Copyright (C) 4Front Technologies 2005-2007. Released under BSD license.
+ */
+#include <dev/pci/pcivar.h> /* For pci_get macros! */
+#include <dev/pci/pcireg.h>
+
+/* PCI Support Functions */
+
+static oss_device_t *device_list[16];
+static device_t bsd_devices[16];
+static int ndevs = 0;
+
+/*
+ * Compare the device ID of this device against the IDs that this driver
+ * supports. If there is a match, set the description and return success.
+ */
+static int
+osspci_probe (device_t dev)
+{
+#ifdef DEVTYPE_PCI
+ int i, ok = 0;
+ int vendor, device, class;
+ oss_device_t *osdev;
+
+ for (i = 0; i < ndevs; i++)
+ if (dev == bsd_devices[i]) /* Already detected */
+ {
+ return ENXIO;
+ }
+
+ if (ndevs >= 16)
+ {
+ printf (DRIVER_NICK ": Too many instances\n");
+ return ENXIO;
+ }
+
+ vendor = pci_get_vendor (dev);
+ device = pci_get_device (dev);
+ class = pci_get_class (dev);
+// printf("PCI dev %08lx c=%x, v=%04x, d=%04x\n", (unsigned long)dev, class, vendor, device);
+
+ if (class != 4) /* Not a multimedia device */
+ return ENXIO;
+
+ for (i = 0; id_table[i].vendor != 0; i++)
+ if (vendor == id_table[i].vendor && device == id_table[i].device) /* Match */
+ {
+ ok = 1;
+ break;
+ }
+
+ if (!ok)
+ {
+ return (ENXIO);
+ }
+
+ if ((osdev =
+ osdev_create (dev, DRIVER_TYPE, ndevs, DRIVER_NICK, NULL)) == NULL)
+ {
+ return ENOMEM;
+ }
+ if (!DRIVER_ATTACH (osdev))
+ return EIO;
+
+ bsd_devices[ndevs] = dev;
+ device_list[ndevs++] = osdev;
+#endif
+ return (BUS_PROBE_DEFAULT);
+}
+
+/* Attach function is only called if the probe is successful */
+
+static int
+osspci_attach (device_t dev)
+{
+ return 0;
+}
+
+/* Detach device. */
+
+static int
+osspci_detach (device_t dev)
+{
+ oss_device_t *osdev;
+ int i;
+
+ for (i = 0; i < ndevs; i++)
+ {
+ osdev = device_list[i];
+ if (osdev->dip == dev)
+ {
+ if (device_get_state(dev) == DS_BUSY)
+ device_unbusy(dev);
+ if (!DRIVER_DETACH (osdev))
+ {
+ printf (DRIVER_NICK ": Unloading busy device\n");
+ return EBUSY;
+ }
+ osdev_delete (osdev);
+ }
+ }
+
+ return (0);
+}
+
+/* Called during system shutdown after sync. */
+
+static int
+osspci_shutdown (device_t dev)
+{
+
+ printf ("Mypci shutdown!\n");
+ return (0);
+}
+
+/*
+ * Device suspend routine.
+ */
+static int
+osspci_suspend (device_t dev)
+{
+
+ printf ("Mypci suspend!\n");
+ return (0);
+}
+
+/*
+ * Device resume routine.
+ */
+static int
+osspci_resume (device_t dev)
+{
+
+ printf ("Mypci resume!\n");
+ return (0);
+}
+
+static device_method_t osspci_methods[] = {
+ /* Device interface */
+ DEVMETHOD (device_probe, osspci_probe),
+ DEVMETHOD (device_attach, osspci_attach),
+ DEVMETHOD (device_detach, osspci_detach),
+ DEVMETHOD (device_shutdown, osspci_shutdown),
+ DEVMETHOD (device_suspend, osspci_suspend),
+ DEVMETHOD (device_resume, osspci_resume),
+
+ {0, 0}
+};
+
+static devclass_t osspci_devclass;
diff --git a/setup/FreeBSD/oss/build/bsdvirtual.inc b/setup/FreeBSD/oss/build/bsdvirtual.inc
new file mode 100644
index 0000000..cb5190e
--- /dev/null
+++ b/setup/FreeBSD/oss/build/bsdvirtual.inc
@@ -0,0 +1,83 @@
+/*
+ * Purpose: Wrapper functions for virtual drivers under FreeBSD
+ */
+/*
+ * Copyright (C) 4Front Technologies 2005-2007. Released under BSD license.
+ */
+static int ndevs = 0;
+oss_device_t *device_list[16];
+
+static int
+module_attach (void)
+{
+ oss_device_t *osdev;
+
+ if ((osdev =
+ osdev_create (NULL, DRIVER_TYPE, ndevs, DRIVER_NICK, NULL)) == NULL)
+ {
+ return ENOMEM;
+ }
+ if (!DRIVER_ATTACH (osdev))
+ return EIO;
+ device_list[ndevs++] = osdev;
+
+ return 0;
+}
+
+static int
+module_detach (void)
+{
+ oss_device_t *osdev;
+ int i;
+
+ for (i = 0; i < ndevs; i++)
+ {
+ osdev = device_list[i];
+
+ if (osdev->dip != NULL && device_get_state(osdev->dip) == DS_BUSY)
+ device_unbusy(osdev->dip);
+ if (!DRIVER_DETACH (osdev))
+ {
+ printf (DRIVER_NICK ": Unloading busy device\n");
+ return EBUSY;
+ }
+ osdev_delete (osdev);
+ }
+
+ return 0;
+}
+
+/*
+ * Load handler that deals with the loading and unloading of a KLD.
+ */
+
+static int
+ossmodule_loader (struct module *m, int what, void *arg)
+{
+ int err = 0;
+
+ switch (what)
+ {
+ case MOD_LOAD: /* kldload */
+ return module_attach ();
+ break;
+ case MOD_UNLOAD:
+ return module_detach ();
+ break;
+ default:
+ err = EINVAL;
+ break;
+ }
+ return (err);
+}
+
+/* Declare this module to the rest of the kernel */
+
+static moduledata_t ossmodule_mod = {
+ "ossmodule",
+ ossmodule_loader,
+ NULL
+};
+
+DECLARE_MODULE (ossmodule, ossmodule_mod, SI_SUB_KLD, SI_ORDER_ANY);
+MODULE_VERSION (ossmodule, 4);
diff --git a/setup/FreeBSD/oss/build/devid.h b/setup/FreeBSD/oss/build/devid.h
new file mode 100644
index 0000000..8d6a5c7
--- /dev/null
+++ b/setup/FreeBSD/oss/build/devid.h
@@ -0,0 +1,5 @@
+
+typedef struct
+{
+ unsigned short vendor, device;
+} device_id_t;
diff --git a/setup/FreeBSD/oss/build/install.sh b/setup/FreeBSD/oss/build/install.sh
new file mode 100644
index 0000000..872d43f
--- /dev/null
+++ b/setup/FreeBSD/oss/build/install.sh
@@ -0,0 +1,75 @@
+#!/bin/sh
+
+if test -f /etc/oss.conf
+then
+ . /etc/oss.conf
+else
+ OSSLIBDIR=/usr/lib/oss
+fi
+
+rm -f osscore_mainline.o
+ln -s osscore.lib osscore_mainline.o
+
+rm -f Makefile
+ln -s Makefile.osscore Makefile
+
+echo Compiling module osscore
+
+if ! make > compile.list 2>&1
+then
+ echo Compiling osscore module failed
+ cat compile.list
+ exit 1
+fi
+
+if ! test -d ../modules
+then
+ mkdir ../modules
+fi
+
+if ! test -d ../logs
+then
+ mkdir ../logs
+fi
+
+mv osscore.ko ../modules/
+make clean > /dev/null 2>&1
+
+for n in ../objects/*.o
+do
+ N=`basename $n .o`
+
+ rm -f $N"_mainline.o"
+ ln -s $n $N"_mainline.o"
+
+ rm -f Makefile
+ sed "s/MODNAME/$N/g" < Makefile.tmpl > Makefile
+
+ echo Compiling module $N
+
+ if ! make > compile.list 2>&1
+ then
+ echo Compiling module $N failed
+ cat compile.list
+ exit 2
+ fi
+
+ mv $N.ko* ../modules/
+ make clean > /dev/null 2>&1
+ rm -f Makefile
+done
+
+if ! test -f $OSSLIBDIR/etc/installed_drivers
+then
+ echo "-----------------------------"
+ /usr/sbin/ossdetect -v
+ echo "-----------------------------"
+ echo ""
+fi
+
+if test ! -f $OSSLIBDIR/etc/userdefs
+then
+ echo "autosave_mixer yes" > $OSSLIBDIR/etc/userdefs
+fi
+
+exit 0
diff --git a/setup/FreeBSD/oss/build/module.inc b/setup/FreeBSD/oss/build/module.inc
new file mode 100644
index 0000000..8ed73e9
--- /dev/null
+++ b/setup/FreeBSD/oss/build/module.inc
@@ -0,0 +1,89 @@
+/*
+ * Purpose: Generic OSS driver module interface for FreeBSD
+ *
+ * This file is included by the driver modules when they are compiled
+ * in the target system. In this way this code can be changed for non-srandard
+ * kernels. Compiling this file in the target file makes it also possible
+ * to distribute single OSS binary package that works under as many
+ * FreeBSD versions as possible.
+ */
+/*
+ * Copyright (C) 4Front Technologies 2005-2007. Released under BSD license.
+ */
+
+#include <machine/stdarg.h>
+#include <sys/param.h> /* defines used in kernel.h */
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/kernel.h> /* types used in module initialization */
+#include <sys/conf.h> /* cdevsw struct */
+#include <sys/uio.h> /* uio struct */
+#include <sys/malloc.h>
+
+#include <sys/bus.h> /* structs, prototypes for pci bus stuff */
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <timestamp.h>
+#include <oss_exports.h>
+#include "bsddefs.h"
+
+void
+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;
+
+ strcpy (tmp, DRIVER_NICK ": ");
+ 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);
+ printf ("%s", tmp);
+#if 0
+ /* This may cause a crash under SMP */
+ if (sound_started)
+ store_msg (tmp);
+#endif
+
+ va_end (ap);
+}
+
+extern int DRIVER_ATTACH (oss_device_t * osdev);
+extern int DRIVER_DETACH (oss_device_t * osdev);
+
+#ifdef DEVTYPE_VMIX
+#define TYPE_OK
+#include "bsdvirtual.inc"
+#endif
+
+#ifdef DEVTYPE_PCI
+#define TYPE_OK
+#include "bsdpci.inc"
+#endif
+
+#ifdef DEVTYPE_VIRTUAL
+#define TYPE_OK
+#include "bsdvirtual.inc"
+#endif
+
+#ifndef TYPE_OK
+#error Unrecognized driver type
+#endif
+
+MODULE_DEPEND (DRIVER_NAME, osscore, 4, 4, 4);
diff --git a/setup/FreeBSD/oss/build/osscore.c b/setup/FreeBSD/oss/build/osscore.c
new file mode 100644
index 0000000..5264118
--- /dev/null
+++ b/setup/FreeBSD/oss/build/osscore.c
@@ -0,0 +1,559 @@
+/*
+ * Purpose: OSS core functions that need to be compiled in the target system
+ *
+ * Some parts of the FreeBSD operating system interface of OSS are sensitive
+ * to changes in internal structures of FreeBSD. For this reason these
+ * files have to be compiled in the target system when OSS is installed.
+ * In this way the same OSS binary package can be used with several FreeBSD
+ * versions.
+ */
+#include <machine/stdarg.h>
+#include <sys/param.h> /* defines used in kernel.h */
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/kernel.h> /* types used in module initialization */
+#include <sys/conf.h> /* cdevsw struct */
+#include <sys/uio.h> /* uio struct */
+#include <sys/malloc.h>
+
+#include <sys/bus.h> /* structs, prototypes for pci bus stuff */
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/param.h> /* defines used in kernel.h */
+#include <dev/pci/pcivar.h> /* For pci_get macros! */
+#include <dev/pci/pcireg.h>
+#include <machine/intr_machdep.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <sys/proc.h>
+
+typedef struct _oss_device_t oss_device_t;
+#include "bsddefs.h"
+
+/* The PCIBIOS_* defines must match oss_pci.h */
+#define PCIBIOS_SUCCESSFUL 0x00
+#define PCIBIOS_FAILED -1
+
+extern int soundcard_attach (void);
+extern int soundcard_detach (void);
+
+void *
+memset (void *t, int val, int l)
+{
+ char *c = t;
+ while (l-- > 0)
+ *c++ = val;
+
+ return t;
+}
+
+void
+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;
+
+ 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);
+ printf ("%s", tmp);
+#if 0
+ /* This may cause a crash under SMP */
+ if (sound_started)
+ store_msg (tmp);
+#endif
+
+ va_end (ap);
+}
+
+void
+oss_udelay (unsigned long t)
+{
+ DELAY (t);
+}
+
+typedef struct
+{
+ int irq;
+ oss_device_t *osdev;
+ oss_tophalf_handler_t top;
+ oss_bottomhalf_handler_t bottom;
+ struct resource *irqres;
+ int irqid;
+ void *cookie;
+} osscore_intr_t;
+
+#define MAX_INTRS 32
+
+static osscore_intr_t intrs[MAX_INTRS] = { {0} };
+static int nintrs = 0;
+
+static void
+ossintr (void *arg)
+{
+ osscore_intr_t *intr = arg;
+ int serviced = 0;
+
+ if (intr->top)
+ serviced = intr->top (intr->osdev);
+ if (intr->bottom)
+ intr->bottom (intr->osdev);
+ oss_inc_intrcount (intr->osdev, serviced);
+}
+
+int
+oss_register_interrupts (oss_device_t * osdev, int intrnum,
+ oss_tophalf_handler_t top,
+ oss_bottomhalf_handler_t bottom)
+{
+
+ osscore_intr_t *intr;
+ char name[32];
+
+ if (nintrs >= MAX_INTRS)
+ {
+ cmn_err (CE_CONT,
+ "oss_register_interrupts: Too many interrupt handlers\n");
+ return -ENOMEM;
+ }
+
+ intr = &intrs[nintrs];
+
+ intr->irq = 0;
+ intr->osdev = osdev;
+ intr->top = top;
+ intr->bottom = bottom;
+
+ sprintf (name, "%s%d", osdev->nick, osdev->instance);
+
+ intr->irqid = 0;
+ intr->irqres = bus_alloc_resource (osdev->dip, SYS_RES_IRQ, &(intr->irqid),
+ 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE);
+ if (intr->irqres == NULL)
+ {
+ cmn_err (CE_CONT,
+ "oss_register_interrupts: bus_alloc_resource failed.\n");
+ return -EIO;
+ }
+
+ intr->irq = bus_setup_intr (osdev->dip, intr->irqres,
+ INTR_TYPE_AV | INTR_MPSAFE,
+#if __FreeBSD_version >= 700031
+ NULL,
+#endif
+ ossintr, intr, &(intr->cookie));
+
+ nintrs++;
+
+ return 0;
+}
+
+void
+oss_unregister_interrupts (oss_device_t * osdev)
+{
+ int i;
+
+ for (i = 0; i < nintrs; i++)
+ if (intrs[i].osdev == osdev)
+ {
+ osscore_intr_t *intr;
+
+ intr = &intrs[i];
+ bus_teardown_intr (osdev->dip, intr->irqres, intr->cookie);
+ bus_release_resource (osdev->dip, SYS_RES_IRQ, intr->irqid,
+ intr->irqres);
+ }
+}
+
+/*
+ * PCI config space access
+ */
+char *
+oss_pci_read_devpath (dev_info_t * dip)
+{
+ return "Unknown PCI path"; // TODO
+}
+
+int
+pci_read_config_byte (oss_device_t * osdev, offset_t where,
+ unsigned char *val)
+{
+ *val = pci_read_config (osdev->dip, where, 1);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+pci_read_config_irq (oss_device_t * osdev, offset_t where, unsigned char *val)
+{
+ *val = pci_read_config (osdev->dip, where, 1);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+pci_read_config_word (oss_device_t * osdev, offset_t where,
+ unsigned short *val)
+{
+ *val = pci_read_config (osdev->dip, where, 2);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+pci_read_config_dword (oss_device_t * osdev, offset_t where,
+ unsigned int *val)
+{
+ *val = pci_read_config (osdev->dip, where, 4);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+pci_write_config_byte (oss_device_t * osdev, offset_t where,
+ unsigned char val)
+{
+ pci_write_config (osdev->dip, where, val, 1);
+ return PCIBIOS_FAILED;
+}
+
+int
+pci_write_config_word (oss_device_t * osdev, offset_t where,
+ unsigned short val)
+{
+ pci_write_config (osdev->dip, where, val, 2);
+ return PCIBIOS_FAILED;
+}
+
+int
+pci_write_config_dword (oss_device_t * osdev, offset_t where,
+ unsigned int val)
+{
+ pci_write_config (osdev->dip, where, val, 4);
+ return PCIBIOS_FAILED;
+}
+
+void *
+oss_contig_malloc (unsigned long buffsize, unsigned long memlimit,
+ oss_native_word * phaddr)
+{
+ char *tmpbuf;
+ *phaddr = 0;
+
+ tmpbuf =
+ (char *) contigmalloc (buffsize, M_DEVBUF, M_WAITOK, 0ul, memlimit,
+ PAGE_SIZE, 0ul);
+ if (tmpbuf == NULL)
+ {
+ cmn_err (CE_CONT, "OSS: Unable to allocate %lu bytes for a DMA buffer\n",
+ buffsize);
+ cmn_err (CE_CONT, "run soundoff and run soundon again.\n");
+ return NULL;
+ }
+ *phaddr = vtophys (tmpbuf);
+ return tmpbuf;
+}
+
+void
+oss_contig_free (void *p, unsigned long sz)
+{
+ if (p)
+ contigfree (p, sz, M_DEVBUF);
+}
+
+/*
+ * Load handler that deals with the loading and unloading of a KLD.
+ */
+
+static int
+osscore_loader (struct module *m, int what, void *arg)
+{
+ int err = 0;
+
+ switch (what)
+ {
+ case MOD_LOAD: /* kldload */
+ return soundcard_attach ();
+ break;
+ case MOD_UNLOAD:
+ return soundcard_detach ();
+ break;
+ default:
+ err = EINVAL;
+ break;
+ }
+ return (err);
+}
+
+/* Declare this module to the rest of the kernel */
+
+static moduledata_t osscore_mod = {
+ "osscore",
+ osscore_loader,
+ NULL
+};
+
+#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 */
+
+#define asm __asm__
+
+#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 ("stmxcsr %0":"=m" (mxcsr));
+ return mxcsr;
+}
+
+static inline void
+write_mxcsr (unsigned long long val)
+{
+ asm ("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 OSS_CPUID_FXSR (1<<24)
+#define OSS_CPUID_SSE (1<<25)
+#define OSS_CPUID_SSE2 (1<<26)
+
+ cpuid (1, &eax, &ebx, &ecx, &edx);
+
+ if (!(edx & OSS_CPUID_FXSR))
+ return 0;
+
+ /*
+ * Older machines require different FP handling than the latest ones. Use the SSE
+ * instruction set as an indicator.
+ */
+ if (!(edx & OSS_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 */
+}
+
+#ifdef VDEV_SUPPORT
+static void
+oss_file_free_private (void *v)
+{
+ free (v, M_DEVBUF);
+}
+
+int
+oss_file_get_private (void **v)
+{
+ int error;
+
+ error = devfs_get_cdevpriv (v);
+ if (error)
+ {
+ cmn_err (CE_CONT, "Couldn't retrieve private data from file handle!\n");
+ return error;
+ }
+ return 0;
+}
+
+int
+oss_file_set_private (struct thread *t, void *v, size_t l)
+{
+ int error;
+ void * p;
+
+ p = malloc (l, M_DEVBUF, M_WAITOK);
+ if (p == NULL)
+ {
+ cmn_err (CE_CONT, "Couldn't allocate memory!\n");
+ return -1;
+ }
+ memcpy (p, v, l);
+ error = devfs_set_cdevpriv (p, oss_file_free_private);
+ if (error)
+ {
+ cmn_err (CE_CONT, "Couldn't attach private data to file handle!\n");
+ oss_file_free_private (p);
+ return error;
+ }
+ return 0;
+}
+#endif
+
+int
+oss_get_uid(void)
+{
+ return curthread->td_ucred->cr_uid;
+}
+
+extern int max_intrate;
+extern int detect_trace;
+extern int src_quality;
+extern int flat_device_model;
+extern int vmix_disabled;
+extern int vmix_loopdevs;
+extern int vmix_no_autoattach;
+extern int ac97_amplifier;
+extern int ac97_recselect;
+extern int cooked_enable;
+extern int dma_buffsize;
+extern int excl_policy;
+extern int mixer_muted;
+TUNABLE_INT("osscore.max_intrate", &max_intrate);
+TUNABLE_INT("osscore.detect_trace", &detect_trace);
+TUNABLE_INT("osscore.src_quality", &src_quality);
+TUNABLE_INT("osscore.flat_device_model", &flat_device_model);
+TUNABLE_INT("osscore.vmix_disabled", &vmix_disabled);
+TUNABLE_INT("osscore.vmix_loopdevs", &vmix_loopdevs);
+TUNABLE_INT("osscore.vmix_no_autoattach", &vmix_no_autoattach);
+TUNABLE_INT("osscore.ac97_amplifier", &ac97_amplifier);
+TUNABLE_INT("osscore.ac97_recselect", &ac97_recselect);
+TUNABLE_INT("osscore.cooked_enable", &cooked_enable);
+TUNABLE_INT("osscore.dma_buffsize", &dma_buffsize);
+TUNABLE_INT("osscore.excl_policy", &excl_policy);
+TUNABLE_INT("osscore.mixer_muted", &mixer_muted);
+
+DECLARE_MODULE (osscore, osscore_mod, SI_SUB_KLD, SI_ORDER_ANY);
+MODULE_VERSION (osscore, 4);