diff options
Diffstat (limited to 'setup/Linux/oss')
24 files changed, 6049 insertions, 0 deletions
diff --git a/setup/Linux/oss/build/Makefile.osscore b/setup/Linux/oss/build/Makefile.osscore new file mode 100644 index 0000000..30d0287 --- /dev/null +++ b/setup/Linux/oss/build/Makefile.osscore @@ -0,0 +1,32 @@ +include /etc/oss.conf + +EXTRA_CFLAGS += -I${OSSLIBDIR}/include/internals -I${OSSLIBDIR}/include/sys + +ifneq ($(KERNELRELEASE),) + + obj-m := osscore.o + +else + + KERNELDIR ?= /lib/modules/$(shell uname -r)/build + PWD := $(shell pwd) +endif + +default: + @echo "static const char __oss_compile_vermagic[]" > ubuntu_version_hack.inc +#The kernel build system saves kernel version (obtained via "utsrelease.h") +#used during compile in a "vermagic" symbol. soundon compares this with +#current version of running kernel to know when to relink modules. +#Some Ubuntu kernels have 'uname -r' output different from "utsrelease.h" +#contents, so we save the previous uname as a fallback check. +# https://bugs.launchpad.net/ubuntu/+source/linux/+bug/247055 + @echo "__attribute__((used))" >> ubuntu_version_hack.inc + @echo "__attribute__((section(\".modinfo\")))" >> ubuntu_version_hack.inc + @echo "= \"$(shell /usr/sbin/ossvermagic -z -s)\";" >> ubuntu_version_hack.inc + + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules + @rm -f ubuntu_version_hack.inc + +clean: + rm -f *.o *.ko *.mod.c *.mod.o .*.cmd core core.* x y z ubuntu_version_hack.inc + rm -rf .tmp_versions diff --git a/setup/Linux/oss/build/Makefile.tmpl b/setup/Linux/oss/build/Makefile.tmpl new file mode 100644 index 0000000..fd331c1 --- /dev/null +++ b/setup/Linux/oss/build/Makefile.tmpl @@ -0,0 +1,21 @@ +include /etc/oss.conf + +EXTRA_CFLAGS += -I${OSSLIBDIR}/include/internals -I${OSSLIBDIR}/include/sys + +ifneq ($(KERNELRELEASE),) + + obj-m := MODNAME.o + +else + + KERNELDIR ?= /lib/modules/$(shell uname -r)/build + PWD := $(shell pwd) + +default: + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules + +endif + +clean: + @rm -f *.o *.ko *.mod.c *.mod.o .*.cmd core core.* x y z + @rm -rf .tmp_versions diff --git a/setup/Linux/oss/build/install.sh b/setup/Linux/oss/build/install.sh new file mode 100644 index 0000000..13fdbc2 --- /dev/null +++ b/setup/Linux/oss/build/install.sh @@ -0,0 +1,347 @@ +#!/bin/sh +if test -f /etc/oss.conf +then + . /etc/oss.conf +else + OSSLIBDIR=/usr/lib/oss + echo "OSSLIBDIR=/usr/lib/oss" > /etc/oss.conf +fi + +[ -z "$LD" ] && LD=ld + +cd $OSSLIBDIR/build + +rm -f $OSSLIBDIR/.cuckoo_installed + +# Check if we should use REGPARM or non-REGPARM modules +if /usr/sbin/ossvermagic -r || /sbin/modinfo ext3|grep -q REGPARM +then + REGPARM=REGPARM + rm -rf $OSSLIBDIR/objects + ln -s $OSSLIBDIR/objects.regparm $OSSLIBDIR/objects + rm -rf $OSSLIBDIR/modules + ln -s $OSSLIBDIR/modules.regparm $OSSLIBDIR/modules +else + REGPARM=NOREGPARM + rm -rf $OSSLIBDIR/objects + ln -s $OSSLIBDIR/objects.noregparm $OSSLIBDIR/objects + rm -rf $OSSLIBDIR/modules + ln -s $OSSLIBDIR/modules.noregparm $OSSLIBDIR/modules +fi + +UNAME=`uname -r` + +if test -f /lib/modules/$UNAME/kernel/oss/vmix.ko || test -f /lib/modules/$UNAME/kernel/oss/ich.ko +then +# Older versions of OSS modules exist under /lib/modules. This indicates that +# previous version of OSS has not been properly uninstalled. Run osdetect +# again to fix rthe situation + + /usr/sbin/soundoff > /dev/null 2>&1 + /usr/sbin/ossdetect +fi + +# Remove previous OSS modules from the system +rm -rf /lib/modules/$UNAME/kernel/oss + +if test -f /usr/lib/oss/build/ich.c +then + # Older v4.0 modules found. Remove them + (cd /usr/lib/oss/build ; rm -f ali5455.c allegro.c als300.c als4000.c apci97.c atiaudio.c audigyls.c audioloop.c audiopci.c cmi8788.c cmpci.c cs4280.c cs4281.c digi32.c digi96.c emu10k1x.c envy24.c envy24ht.c fm801.c geode.c hdaudio.c hdsp.c ich.c imux.c maestro.c neomagic.c ossusb.c riptide.c s3vibes.c sblive.c sbxfi.c softoss.c solo.c sonorus.c trident.c via8233.c via97.c vmix.c vortex.c ymf7xx.c) + echo + echo + echo Error: Older OSS version seems to be installed in your system. + echo Please remove previous /usr/lib/oss directory and the install OSS v4.x again. + soundoff + exit 127 +fi + +if ! test -f $OSSLIBDIR/objects/osscore.o +then + echo Error: OSS core module for $REGPARM kernel is not available in $OSSLIBDIR/objects + exit 1 +fi + +echo +echo OSS build environment set up for $REGPARM kernels + +KERNELDIR=/lib/modules/$UNAME/build +UBUNTUPACKAGES="" + +OK=1 +echo + +if test "`which gcc 2>/dev/null` " = " " +then + echo " gcc" + UBUNTUPACKAGES="$UBUNTUPACKAGES gcc" + OK=0 +fi + +if test "`which make 2>/dev/null` " = " " +then + echo " make" + UBUNTUPACKAGES="$UBUNTUPACKAGES make" + OK=0 +fi + +if test "`which ld 2>/dev/null` " = " " +then + echo " binutils" + UBUNTUPACKAGES="$UBUNTUPACKAGES binutils" + OK=0 +fi + +if ! test -f /usr/include/stdio.h +then + echo " C library headers (glibc-devel or build-essential)" + OK=0 + UBUNTUPACKAGES="$UBUNTUPACKAGES build-essentials" +fi + +if test "$OK " = "0 " +then + echo + echo 'Error: The above Linux package(s) seem to be missing from your system.' + echo ' Please install them and then try to install OSS again.' + echo + echo Please refer to the documentation of your Linux distribution if you + echo have problems with installing the packages. + echo + + if grep -q Ubuntu /etc/issue # Ubuntu? + then + echo You can use the following commands to download and install all + echo required packages: + echo + + for n in $UBUNTUPACKAGES + do + echo " apt-get install $n" + done + + exit 1 + fi + + exit 1 +fi + + +if ! test -f $KERNELDIR/Makefile && ! test -f /lib/modules/$UNAME/sources/Makefile +then + echo + echo 'Warning: Cannot locate the Linux kernel development package for' + echo ' Linux kernel version ' $UNAME + echo ' Please install the kernel development package if linking the' + echo ' OSS modules fails.' + echo + echo The kernel development package may be called kernel-devel, kernel-smp-devel, + echo kernel-sources, kernel-headers or something like that. Please refer + echo to the documentation of your Linux distribution if there are any + echo difficulties in installing the kernel/driver development environment. + echo + + if grep -q 'Fedora Core release' /etc/issue + then + if uname -v|grep -q SMP + then + echo Assuming that you are using Fedora Core 5 or later + echo "the right kernel source package (RPM) is probably called" + echo kernel-smp-devel. + else + echo Assuming that you are using Fedora Core 5 or later + echo "the right kernel source package (RPM) is probably called" + echo kernel-devel. + fi + else + echo For your Linux distribution the right kernel source package + echo might be kernel-source. + fi + echo + + if grep -q Ubuntu /etc/issue || grep -q Debian /etc/issue # Ubuntu or Debian? + then + echo Under Ubuntu you may need to prepare the kernel environment + echo after downloading the kernel sources using + echo + echo " sudo apt-get install linux-headers-$UNAME" + echo " cd /usr/src/linux-headers-$UNAME/" +# echo " sudo make prepare" +# echo " sudo make prepare scripts" + echo + fi +fi + +if ! test -d /lib/modules/$UNAME +then + echo Error: Kernel directory /lib/modules/$UNAME does not exist + exit 1 +fi + +cp -f ../objects/osscore.o osscore_mainline.o + +rm -f Makefile +ln -s Makefile.osscore Makefile + +echo Building module osscore + +if ! make KERNELDIR=$KERNELDIR> build.list 2>&1 +then + echo Failed to compile OSS + cat build.list + exit 2 +fi + +if ! test -d /lib/modules/$UNAME/kernel/oss +then + mkdir /lib/modules/$UNAME/kernel/oss +fi + +if ! test -d /lib/modules/$UNAME/kernel/oss +then + echo OSS module directory /lib/modules/$UNAME/kernel/oss does not exist. + exit 3 +fi + +if ! $LD -r osscore.ko osscore_mainline.o -o /lib/modules/$UNAME/kernel/oss/osscore.ko +then + echo Linking the osscore module failed + exit 5 +fi + +if test -f Module.symvers +then + #Take generated symbol information and add it to module.inc + echo "static const struct modversion_info ____versions[]" > osscore_symbols.inc + echo " __attribute__((used))" >> osscore_symbols.inc + echo "__attribute__((section(\"__versions\"))) = {" >> osscore_symbols.inc + sed -e "s:^:{:" -e "s:\t:, \":" -e "s:\t\(.\)*:\"},:" < Module.symvers >> osscore_symbols.inc + echo "};" >> osscore_symbols.inc +else + echo > osscore_symbols.inc +fi + +#depmod -a + +for n in ../modules/*.o +do + N=`basename $n .o` + echo Building module $N + + rm -f $N_mainline.o Makefile + + sed "s/MODNAME/$N/" < Makefile.tmpl > Makefile + ln -s $n $N_mainline.o + + if ! make KERNELDIR=$KERNELDIR > build.list 2>&1 + then + echo Compiling module $N failed + cat build.list + exit 4 + fi + + if ! $LD -r $N.ko $N_mainline.o -o /lib/modules/$UNAME/kernel/oss/$N.ko + then + echo Linking $N module failed + exit 6 + fi + + rm -f $N_mainline.o + make clean +done + +rm -f Makefile + +echo "depmod -a" +depmod -a + +# Copy config files for any new driver modules + +if ! test -d $OSSLIBDIR/conf +then + mkdir $OSSLIBDIR/conf +fi + +if test -d $OSSLIBDIR/conf.tmpl +then + for n in $OSSLIBDIR/conf.tmpl/*.conf + do + N=`basename $n` + + if ! test -f $OSSLIBDIR/conf/$N + then + cp -f $n $OSSLIBDIR/conf/ + fi + done + rm -rf $OSSLIBDIR/conf.tmpl +fi + +if ! test -f $OSSLIBDIR/etc/installed_drivers +then + echo "-----------------------------" + /usr/sbin/ossdetect -v + echo "-----------------------------" + echo +fi + +if ! test -d /etc/init.d +then + mkdir /etc/init.d +fi + +rm -f /etc/init.d/oss /etc/rc.d/rc3.d/S89oss /etc/rc3.d/S89oss +cp -f $OSSLIBDIR/etc/S89oss /etc/init.d/oss + +chmod 744 /etc/init.d/oss + +if test -x /sbin/chkconfig +then + /sbin/chkconfig oss on > /dev/null 2>&1 +else + if test -x /usr/sbin/update-rc.d + then + /usr/sbin/update-rc.d oss defaults > /dev/null 2>&1 + else + if test -d etc/rc.d/rc3.d + then + rm -f /etc/rc.d/rc3.d/S89oss + ln -s /etc/init.d/oss /etc/rc.d/rc3.d/S89oss + else + if test -d /etc/rc3.d + then + rm -f /etc/rc3.d/S89oss + ln -s /etc/init.d/oss /etc/rc3.d/S89oss + fi + fi + fi +fi + +# Install ALSA interface module (Cuckoo) +#(cd $OSSLIBDIR/cuckoo && make clean) > /dev/null 2>&1 +#if (cd $OSSLIBDIR/cuckoo && make install) > /var/log/cuckoo.log 2>&1 +#then +# touch $OSSLIBDIR/.cuckoo_installed +#fi +#(cd $OSSLIBDIR/cuckoo && make clean) > /dev/null 2>&1 + +# Remove bogus char major 14 device files left from earlier OSS versions. + +rm -f `ls -l -d /dev/*|grep ^c|grep ' 14, '|sed 's/.* //'` + +# Recompile libflashsupport.so if possible. Otherwise use the precompiled +# version. +(cd $OSSLIBDIR/lib;cc -m64 -shared -fPIC -O2 -Wall -Werror flashsupport.c -o $OSSLIBDIR/lib/libflashsupport_64.so) > /dev/null 2>&1 +(cd $OSSLIBDIR/lib;cc -m32 -shared -fPIC -O2 -Wall -Werror flashsupport.c -o $OSSLIBDIR/lib/libflashsupport_32.so) > /dev/null 2>&1 + +if test ! -f $OSSLIBDIR/etc/userdefs +then + echo "autosave_mixer yes" > $OSSLIBDIR/etc/userdefs +fi + +# Hal 0.5.0+ hotplug +mkdir -p /usr/lib/hal/scripts +ln -sf $OSSLIBDIR/scripts/oss_usb-create-devices /usr/lib/hal/scripts/ +mkdir -p /usr/share/hal/fdi/policy/20thirdparty/ +ln -sf $OSSLIBDIR/scripts/90-oss_usb-create-device.fdi /usr/share/hal/fdi/policy/20thirdparty/ + +exit 0 diff --git a/setup/Linux/oss/build/module.inc b/setup/Linux/oss/build/module.inc new file mode 100644 index 0000000..4e34003 --- /dev/null +++ b/setup/Linux/oss/build/module.inc @@ -0,0 +1,245 @@ +/* + * Purpose: Template for OSS modules under Linux + * + * This file is included by the low level driver modules when they are + * compiled in the target system. In this way this file can be modified + * for non-standard kernels by the customer. Compiling in the target is + * necessary because the driver/module framework of Linux cannot support + * binary drivers. Another reason is that the kbuild mechanism used to build + * kernel modules under Linux is not compatible with the way how the source + * code of OSS is organized. + */ +/* + * Copyright (C) 4Front Technologies 2005-2007. Released under GPL2 license. + */ +#define strcpy dummy_strcpy +#include <linux/version.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include "timestamp.h" +#include "oss_exports.h" +#include "wrap.h" +#include "ossddk.h" +#include "ossdip.h" +#undef strcpy +#define strcpy oss_strcpy +#undef strlen +#define strlen oss_strlen + +static int module_major = 0; +static int instance = 0; + +MODULE_LICENSE ("GPL v2"); +MODULE_DESCRIPTION ("Open Sound System '" DRIVER_PURPOSE "' driver module"); +MODULE_AUTHOR ("4Front Technologies (support@opensound.com)"); + +extern int DRIVER_ATTACH (oss_device_t * osdev); +extern int DRIVER_DETACH (oss_device_t * osdev); + +#if DRIVER_TYPE==DRV_PCI +#define DRIVER_TYPE_OK + +#include "pci_wrapper.inc" + +// MODULE_DEVICE_TABLE(pci, id_table); +static struct pci_driver osspci_driver = { + .name = DRIVER_NICK, + .id_table = id_table, + .probe = osspci_probe, + .remove = osspci_remove +}; + +static int __init +pcidrv_init (void) +{ + int err; + + if ((err = pci_register_driver (&osspci_driver)) < 0) + return err; + oss_register_module (THIS_MODULE); + return 0; +} + +static void __exit +pcidrv_exit (void) +{ + if (module_major > 0) + { + oss_unregister_chrdev (module_major, DRIVER_NICK); + } + pci_unregister_driver (&osspci_driver); + oss_unregister_module (THIS_MODULE); +} + +module_init (pcidrv_init); +module_exit (pcidrv_exit); +#endif /* PCI driver */ + +#if DRIVER_TYPE==DRV_VIRTUAL || DRIVER_TYPE==DRV_VMIX +#define DRIVER_TYPE_OK +static oss_device_t *osdev = NULL; + +static int +virtualdrv_init (void) +{ + static int instance = 0, maj; + + if ((osdev = + osdev_create (NULL, DRIVER_TYPE, instance++, DRIVER_NICK, + NULL)) == NULL) + { + return -ENOMEM; + } + osdev_set_owner (osdev, THIS_MODULE); + maj = oss_request_major (osdev, 0, DRIVER_NICK); + osdev_set_major (osdev, maj); + if (!DRIVER_ATTACH (osdev)) + return -EIO; + oss_register_module (THIS_MODULE); + oss_audio_delayed_attach (); + return 0; +} + +static void +virtualdrv_exit (void) +{ + + if (!DRIVER_DETACH (osdev)) + printk (KERN_ALERT DRIVER_NICK ": Unloading busy device\n"); + osdev_delete (osdev); + oss_unregister_module (THIS_MODULE); +} + +module_init (virtualdrv_init); +module_exit (virtualdrv_exit); +#endif /* Virtual driver */ + +#if DRIVER_TYPE==DRV_USB +#define DRIVER_TYPE_OK +oss_device_t *osdev = NULL; +static int usb_major = 0; + +#include "usb_wrapper.inc" + +static int +usbdrv_init (void) +{ + int res; + + if (udi_usb_installed) + return 0; + if ((osdev = + osdev_create (NULL, DRV_VIRTUAL, instance++, DRIVER_NICK, + NULL)) == NULL) + { + return -ENOMEM; + } + osdev_set_owner (osdev, THIS_MODULE); + usb_major = oss_request_major (osdev, 0, DRIVER_NICK); + if (usb_major < 0) + { + oss_cmn_err (CE_WARN, "Failed to allocate USB major (%d)\n", usb_major); + return -EIO; + } + osdev_set_major (osdev, usb_major); + oss_register_device (osdev, "USB audio core services"); + if (!DRIVER_ATTACH (osdev)) + return -EIO; + oss_register_module (THIS_MODULE); + oss_audio_delayed_attach (); + + udi_usb_installed = 1; + + if ((res = usb_register (&oss_usb)) < 0) + { + printk ("oss: usb_register failed, err=%d\n", res); + drv = NULL; + return -ENXIO; + } + return 0; +} + +static void +usbdrv_exit (void) +{ + if (!udi_usb_installed) + return; + if (!DRIVER_DETACH (osdev)) + printk (KERN_ALERT DRIVER_NICK ": Unloading busy device\n"); + usb_deregister (&oss_usb); + udi_usb_installed = 0; + known_devices = NULL; + osdev_delete (osdev); + osdev = NULL; + oss_unregister_module (THIS_MODULE); +} + +module_init (usbdrv_init); +module_exit (usbdrv_exit); +#endif /* USB driver */ + +#ifndef DRIVER_TYPE_OK +#error Unrecognized driver type +#endif + +char * +strcpy (char *s1, const char *s2) +{ + char *s = s1; + + while (*s2) + *s1++ = *s2++; + *s1 = 0; + return s; +} + +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] = 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); + printk ("%s", tmp); + } + else + { + 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); + printk (KERN_ALERT "%s", tmp); + } +#if 0 + /* This may cause a crash under SMP */ + if (sound_started) + store_msg (tmp); +#endif + + va_end (ap); +} + +#include "osscore_symbols.inc" diff --git a/setup/Linux/oss/build/osscore.c b/setup/Linux/oss/build/osscore.c new file mode 100644 index 0000000..1a029b4 --- /dev/null +++ b/setup/Linux/oss/build/osscore.c @@ -0,0 +1,2214 @@ +/* + * Purpose: Linux kernel version specific wrapper routines. + * + * This file will be shipped in source format and compiled in the target + * (customer) system. In this way minor changes between Linux versions + * can be fixed by the customer. + */ + +/* + * Copyright (C) 4Front Technologies 2005-2009. Released under GPL2 license. + */ +//#include <linux/config.h> +typedef int *ioctl_arg; +#include <linux/init.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <stdarg.h> +#include <linux/vmalloc.h> +#include "timestamp.h" +#include "local_config.h" +#include "oss_exports.h" +#include "wrap.h" +#include "ossdip.h" +#include <linux/version.h> +#include <linux/fs.h> +#include <linux/poll.h> +#include <linux/time.h> +#include <linux/proc_fs.h> +#include <linux/spinlock.h> +#include <linux/pci.h> +#include <linux/irq.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#undef strlen +#undef strcpy +#define strlen oss_strlen +#define strcpy oss_strcpy + +typedef struct _smap_t dmap_t; + +#include "soundcard.h" +#include "audio_core.h" +#include "mixer_core.h" +#include "ubuntu_version_hack.inc" + +MODULE_LICENSE ("GPL v2"); +MODULE_DESCRIPTION ("Open Sound System core services"); +MODULE_AUTHOR ("4Front Technologies (support@opensound.com)"); + +struct _oss_mutex_t +{ + /* Caution! This definition must match cuckoo.h */ + spinlock_t lock; + int filler; /* Make sure this structure doesn't become zero length */ +}; + +static oss_device_t *core_osdev = NULL; +/* + * Minor device list + */ +#define MAX_MINOR 256 +typedef struct +{ + int major, minor; + char name[32]; +} oss_minor_t; + +static oss_minor_t minors[MAX_MINOR]; +static int nminors = 0; + +/* + * Sleep flags. Make sure these definitions match oss_config.h. + */ +#define WK_NONE 0x00 +#define WK_WAKEUP 0x01 +#define WK_TIMEOUT 0x02 +#define WK_SIGNAL 0x04 +#define WK_SLEEP 0x08 +#define WK_SELECT 0x10 + +time_t +oss_get_time (void) +{ +#if 1 + return get_seconds (); +#else + return xtime.tv_sec; +#endif +} + +void *oss_memset (void *t, int val, size_t l); + +void * +oss_kmem_alloc (size_t size) +{ + void *ptr; + if ((ptr = vmalloc (size)) == NULL) + { + oss_cmn_err (CE_WARN, "vmalloc(%d) failed\n", size); + return NULL; + } + memset (ptr, 0, size); + return ptr; +} + +void +oss_kmem_free (void *addr) +{ + vfree (addr); +} + +/* oss_pmalloc() moved to os_linux.c */ + +extern oss_native_word +oss_virt_to_bus (void *addr) +{ + return virt_to_bus (addr); +} + +void * +oss_memcpy (void *t_, const void *f_, size_t l) +{ + unsigned char *t = t_; + unsigned const char *f = f_; + int i; + + for (i = 0; i < l; i++) + *t++ = *f++; + + return t; +} + +void * +oss_memset (void *t, int val, size_t l) +{ + char *c = t; + while (l-- > 0) + *c++ = val; + + return t; +} + +int +oss_strcmp (const char *s1, const char *s2) +{ + while (*s1 && *s2) + { + if (*s1 != *s2) + return *s1 - *s2; + s1++; + s2++; + } + + return *s1 - *s2; +} + +int +oss_strncmp (const char *s1, const char *s2, size_t len) +{ + while (*s1 && *s2 && len--) + { + if (*s1 != *s2) + return *s1 - *s2; + s1++; + s2++; + } + + return *s1 - *s2; +} + +char * +oss_strcpy (char *s1, const char *s2) +{ + char *s = s1; + + while (*s2) + *s1++ = *s2++; + *s1 = '\0'; + return s; +} + +size_t +oss_strlen (const char *s) +{ + int i; + + for (i = 0; s[i]; i++); + + return i; +} + +char * +oss_strncpy (char *s1, const char *s2, size_t l) +{ + char *s = s1; + int n = 0; + + while (*s2) + { + if (n++ >= l) + return s; + + *s1++ = *s2++; + } + *s1 = '\0'; + return s; +} + +int oss_hz = HZ; +extern int max_intrate; +extern int detect_trace; +extern int src_quality; +extern int flat_device_model; +extern int vmix_disabled; +extern int vmix_no_autoattach; +extern int vmix_loopdevs; +extern int ac97_amplifier; +extern int ac97_recselect; +extern int cooked_enable; +extern int dma_buffsize; +extern int excl_policy; +extern int mixer_muted; + +module_param (oss_hz, int, S_IRUGO); +module_param (max_intrate, int, S_IRUGO); +module_param (detect_trace, int, S_IRUGO); +module_param (src_quality, int, S_IRUGO); +module_param (flat_device_model, int, S_IRUGO); +module_param (vmix_disabled, int, S_IRUGO); +module_param (vmix_no_autoattach, int, S_IRUGO); +module_param (vmix_loopdevs, int, S_IRUGO); +module_param (ac97_amplifier, int, S_IRUGO); +module_param (ac97_recselect, int, S_IRUGO); +module_param (cooked_enable, int, S_IRUGO); +module_param (dma_buffsize, int, S_IRUGO); +module_param (excl_policy, int, S_IRUGO); +module_param (mixer_muted, int, S_IRUGO); + +static struct proc_dir_entry *oss_proc_root = NULL; +static struct proc_dir_entry *oss_proc_devfiles = NULL; + +static ssize_t +oss_read_devfiles (struct file *file, char __user * buf, size_t count, + loff_t * ppos) +{ + static char tmp[8192]; + char *s; + static int eof = 0; + int i; + + if (eof) + { + eof = 0; + return 0; + } + + *tmp = 0; + s = tmp; + + for (i = 0; i < nminors; i++) + { + if (strlen (tmp) > sizeof (tmp) - 20) + { + printk (KERN_ALERT "osscore: Procfs buffer too small\n"); + return -ENOMEM; + } + + s += sprintf (s, "%s %d %d\n", + minors[i].name, minors[i].major, minors[i].minor); + } + + if (copy_to_user (buf, (void *) tmp, strlen (tmp))) + return -EFAULT; + + eof = 1; + return strlen (tmp); +} + +static struct file_operations oss_proc_operations = { + .read = oss_read_devfiles, +}; + +static void +init_proc_fs (void) +{ + if ((oss_proc_root = + create_proc_entry ("opensound", 0700 | S_IFDIR, NULL)) == NULL) + { + oss_cmn_err (CE_CONT, "Cannot create /proc/opensound\n"); + return; + } + + if ((oss_proc_devfiles = + create_proc_entry ("devfiles", 0600, oss_proc_root)) == NULL) + { + oss_cmn_err (CE_CONT, "Cannot create /proc/opensound/devfiles\n"); + return; + } + + oss_proc_devfiles->proc_fops = &oss_proc_operations; +} + +static void +uninit_proc_fs (void) +{ + if (oss_proc_root) + { + if (oss_proc_devfiles) + remove_proc_entry ("devfiles", oss_proc_root); + remove_proc_entry ("opensound", NULL); + } +} + +static int +osscore_init (void) +{ + if ((core_osdev = + osdev_create (NULL, DRV_UNKNOWN, 0, "osscore", NULL)) == NULL) + { + oss_cmn_err (CE_WARN, "Failed to allocate OSDEV structure\n"); + return -ENOMEM; + } + + osdev_set_owner (core_osdev, THIS_MODULE); + + init_proc_fs (); + + return oss_init_osscore (core_osdev); +} + +static void +osscore_exit (void) +{ + uninit_proc_fs (); + oss_uninit_osscore (core_osdev); +} + +void +oss_udelay (unsigned long d) +{ + udelay (d); +} + +oss_mutex_t +oss_mutex_init (void) +{ + oss_mutex_t mutex; + + if ((mutex = vmalloc (sizeof (*mutex))) == NULL) + { + oss_cmn_err (CE_WARN, "vmalloc(%d) failed (mutex)\n", sizeof (*mutex)); + return NULL; + } + + spin_lock_init (&(mutex->lock)); + + return mutex; +} + +void +oss_mutex_cleanup (oss_mutex_t mutex) +{ + vfree (mutex); +} + +void +oss_spin_lock_irqsave (oss_mutex_t mutex, oss_native_word * flags) +{ + unsigned long flag; + if (mutex == NULL) + return; + spin_lock_irqsave (&mutex->lock, flag); + *flags = flag; +} + +void +oss_spin_unlock_irqrestore (oss_mutex_t mutex, oss_native_word flags) +{ + if (mutex == NULL) + return; + spin_unlock_irqrestore (&mutex->lock, flags); +} + +void +oss_spin_lock (oss_mutex_t mutex) +{ + if (mutex == NULL) + return; + spin_lock (&mutex->lock); +} + +void +oss_spin_unlock (oss_mutex_t mutex) +{ + if (mutex == NULL) + return; + spin_unlock (&mutex->lock); +} + +void * +oss_map_pci_mem (oss_device_t * osdev, int size, unsigned long offset) +{ +#ifdef __arm__ + return (void*)offset; +#else + return ioremap (offset, size); +#endif +} + +void +oss_unmap_pci_mem (void *addr) +{ +#ifndef __arm__ + iounmap (addr); +#endif +} + +unsigned long long +oss_get_jiffies (void) +{ + return jiffies_64; +} + +char * +oss_get_procname (void) +{ + return current->comm; +} + +int +oss_get_pid (void) +{ + return current->pid; +} + +int +oss_get_uid (void) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) + return current->cred->uid; +#else + return current->uid; +#endif +} + +typedef struct tmout_desc +{ + volatile int active; + int timestamp; + void (*func) (void *); + void *arg; + + struct timer_list 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 (unsigned long 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); +} + +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); + + init_timer (&tmout->timer); + tmout->timer.expires = jiffies + ticks; + tmout->timer.data = id | (timeout_random & ~0xff); + tmout->timer.function = oss_timer_callback; + add_timer (&tmout->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) + del_timer (&tmout->timer); + tmout->active = 0; + tmout->timestamp = 0; +} + +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 compatibilityi)). + */ + + int c; + char *address = addr; + + 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: + c = nbytes; + if (c > 10) + c = 0; + + if ((c = copy_to_user (uio->ptr, address, nbytes) != 0)) + { + uio->resid -= nbytes; + oss_cmn_err (CE_CONT, "copy_to_user(%d) failed (%d)\n", nbytes, c); + return EFAULT; + } + break; + + case UIO_WRITE: + if (copy_from_user (address, uio->ptr, nbytes) != 0) + { + oss_cmn_err (CE_CONT, "copy_from_user failed\n"); + uio->resid -= nbytes; + return EFAULT; + } + 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; +} + +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] = 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); + printk ("%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); + + printk (KERN_ALERT "%s", tmp); + } +#if 0 + /* This may cause a crash under SMP */ + if (sound_started) + store_msg (tmp); +#endif + + va_end (ap); +} + +/* + * Sleep/wakeup + */ + +struct oss_wait_queue +{ + volatile int flags; + wait_queue_head_t wq; +}; + +struct oss_wait_queue * +oss_create_wait_queue (oss_device_t * osdev, const char *name) +{ + struct oss_wait_queue *wq; + + if ((wq = vmalloc (sizeof (*wq))) == NULL) + { + oss_cmn_err (CE_WARN, "vmalloc(%d) failed (wq)\n", sizeof (*wq)); + return NULL; + } + init_waitqueue_head (&wq->wq); + + return wq; +} + +void +oss_reset_wait_queue (struct oss_wait_queue *wq) +{ + wq->flags = 0; +} + +void +oss_remove_wait_queue (struct oss_wait_queue *wq) +{ + vfree (wq); +} + +int +oss_sleep (struct oss_wait_queue *wq, oss_mutex_t * mutex, int ticks, + oss_native_word * flags, unsigned int *status) +{ + int result = 0; + *status = 0; + + if (wq == NULL) + return 0; + + wq->flags = 0; + oss_spin_unlock_irqrestore (*mutex, *flags); + + if (ticks <= 0) + result = wait_event_interruptible (wq->wq, (wq->flags & WK_WAKEUP)); + else + result = + wait_event_interruptible_timeout (wq->wq, (wq->flags & WK_WAKEUP), + ticks); + + oss_spin_lock_irqsave (*mutex, flags); + + if (result < 0) /* 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) +{ + oss_spin_unlock_irqrestore (*mutex, *flags); + poll_wait ((struct file *) ev->file, &wq->wq, + (struct poll_table_struct *) ev->wait); + oss_spin_lock_irqsave (*mutex, flags); + 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; + oss_spin_unlock_irqrestore (*mutex, *flags); + wake_up (&wq->wq); + oss_spin_lock_irqsave (*mutex, flags); +} + +void +oss_reserve_pages (oss_native_word start_addr, oss_native_word end_addr) +{ + struct page *page, *lastpage; + + lastpage = virt_to_page (end_addr); + + for (page = virt_to_page (start_addr); page <= lastpage; page++) + set_bit (PG_reserved, &page->flags); +} + +void +oss_unreserve_pages (oss_native_word start_addr, oss_native_word end_addr) +{ + struct page *page, *lastpage; + + lastpage = virt_to_page (end_addr); + + for (page = virt_to_page (start_addr); page <= lastpage; page++) + clear_bit (PG_reserved, &page->flags); +} + +void * +oss_contig_malloc (oss_device_t * osdev, int buffsize, oss_uint64_t memlimit, + oss_native_word * phaddr) +{ + char *start_addr, *end_addr; + int sz, size; + int flags = 0; + + *phaddr = 0; + +#ifdef GFP_DMA32 + if (memlimit < 0x0000000100000000LL) + flags |= GFP_DMA32; +#endif + + if (memlimit < 0x00000000ffffffffLL) + flags |= GFP_DMA; + + start_addr = NULL; + + for (sz = 0, size = PAGE_SIZE; size < buffsize; sz++, size <<= 1); + + if (buffsize != (PAGE_SIZE * (1 << sz))) + { +#if 0 + printk + ("Contig_malloc: Invalid size %d != %ld\n", buffsize, + PAGE_SIZE * (1 << sz)); +#endif + } + + start_addr = (char *) __get_free_pages (GFP_KERNEL | flags, sz); + + 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; + + oss_reserve_pages ((oss_native_word) start_addr, + (oss_native_word) end_addr); + } + + *phaddr = virt_to_bus (start_addr); + return start_addr; +} + +void +oss_contig_free (oss_device_t * osdev, void *p, int buffsize) +{ + int sz, size; + caddr_t start_addr, end_addr; + + if (p == NULL) + return; + + for (sz = 0, size = PAGE_SIZE; size < buffsize; sz++, size <<= 1); + + start_addr = p; + end_addr = p + buffsize - 1; + + oss_unreserve_pages ((oss_native_word) start_addr, + (oss_native_word) end_addr); + free_pages ((unsigned long) p, sz); +} + +/* + * These typedefs must match definition of struct file_operations. + * (See notes in routine oss_register_chrdev). + */ +typedef ssize_t (*read_t) (struct file *, char *, size_t, loff_t *); +typedef ssize_t (*write_t) (struct file *, const char *, size_t, loff_t *); +typedef unsigned int (*poll_t) (struct file *, poll_table *); +typedef poll_table select_table; + +typedef int (*readdir_t) (struct inode *, struct file *, void *, filldir_t); +typedef int (*ioctl_t) (struct inode *, struct file *, unsigned int, + unsigned long); +typedef long (*new_ioctl_t) (struct file *, unsigned int, unsigned long); +typedef int (*mmap_t) (struct file *, struct vm_area_struct *); +typedef int (*open_t) (struct inode *, struct file *); + +typedef int (*release_t) (struct inode *, struct file *); +typedef int (*fasync_t) (int, struct file *, int); +typedef int (*fsync_t) (struct inode *, struct file *); + +static loff_t +oss_no_llseek (struct file *file, loff_t offset, int orig) +{ + return -EINVAL; +} + +static int +oss_no_fsync (struct file *f, struct dentry *d, int datasync) +{ + return -EINVAL; +} + +static int +oss_no_fasync (int x, struct file *f, int m) +{ + return -EINVAL; +} + +/* + * Wrappers for installing and uninstalling character and block devices. + * + * The oss_file_operation_handle structure differs from kernel's + * file_operations structure in parameters of the driver entry points. + * Kernel inode, file, wait_struct, vm_are_struct etc. typed arguments + * are replaced by wrapper handles. + */ + +static struct file_operations * +alloc_fop (oss_device_t * osdev, struct oss_file_operation_handle *op) +{ +/* + * This routine performs initialization of kernel file_operations structure + * from oss_file_operation_handle structure. Each procedure pointer is copied + * to a temporary variable before doing the actual assignment. This + * prevents unnecessary warnings while it still enables compatibility + * warnings. + * + * Any warning given by this routine may indicate that kernel fs + * call interface has changed significantly (added parameters to the routines). + * In this case definition routine in oss_file_operation_handle must be updated + * and WRAPPER_VERSION must be incremented. + */ + + struct file_operations *fop; + + poll_t tmp_poll = (poll_t) op->poll; + read_t tmp_read = (read_t) op->read; + write_t tmp_write = (write_t) op->write; + /* readdir_t tmp_readdir = (readdir_t)op->readdir; */ +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,35) + ioctl_t tmp_ioctl = (ioctl_t) op->ioctl; +#endif + mmap_t tmp_mmap = (mmap_t) op->mmap; + open_t tmp_open = (open_t) op->open; + release_t tmp_release = (release_t) op->release; + new_ioctl_t tmp_unlocked_ioctl = (new_ioctl_t) op->unlocked_ioctl; + new_ioctl_t tmp_compat_ioctl = (new_ioctl_t) op->compat_ioctl; + + fop = (struct file_operations *) + oss_kmem_alloc (sizeof (struct file_operations)); + + memset ((char *) fop, 0, sizeof (struct file_operations)); + +/* + * Now the assignment + */ + fop->llseek = oss_no_llseek; + fop->read = tmp_read; + fop->write = tmp_write; + fop->readdir = NULL; /* tmp_readdir; */ + fop->poll = tmp_poll; +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,35) + fop->ioctl = tmp_ioctl; +#endif + fop->mmap = tmp_mmap; + fop->open = tmp_open; + fop->release = tmp_release; + fop->fsync = oss_no_fsync; + fop->fasync = oss_no_fasync; + fop->lock = NULL; + fop->flush = NULL; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + fop->owner = osdev_get_owner (osdev); +#endif +#ifdef HAVE_UNLOCKED_IOCTL + fop->unlocked_ioctl = tmp_unlocked_ioctl; +#endif +#ifdef HAVE_COMPAT_IOCTL + fop->compat_ioctl = tmp_compat_ioctl; +#endif + + return fop; +} + +int +oss_register_chrdev (oss_device_t * osdev, unsigned int major, + const char *name, struct oss_file_operation_handle *op) +{ + int maj; + maj = register_chrdev (major, name, alloc_fop (osdev, op)); + + return maj; +} + +void +oss_register_minor (int major, int minor, char *name) +{ + if (nminors >= MAX_MINOR) + { + oss_cmn_err (CE_WARN, "Too many device files\n"); + return; + } + + minors[nminors].major = major; + minors[nminors].minor = minor; + strcpy (minors[nminors].name, name); + nminors++; +} + +int +oss_unregister_chrdev (unsigned int major, const char *name) +{ + unregister_chrdev (major, name); + return 0; +} + +int +oss_inode_get_minor (oss_inode_handle_t * inode) +{ + return MINOR (((struct inode *) inode)->i_rdev); +} + +int +oss_file_get_flags (oss_file_handle_t * file) +{ + return ((struct file *) file)->f_flags; +} + +void * +oss_file_get_private (oss_file_handle_t * file) +{ + return ((struct file *) file)->private_data; +} + +void +oss_file_set_private (oss_file_handle_t * file, void *v) +{ + ((struct file *) file)->private_data = v; +} + +int +oss_vma_get_flags (oss_vm_area_handle_t * vma) +{ + return ((struct vm_area_struct *) vma)->vm_flags; +} + +int +oss_do_mmap (oss_vm_area_handle_t * v, oss_native_word dmabuf_phys, + int bytes_in_use) +{ + struct vm_area_struct *vma = (struct vm_area_struct *) v; + int res, size; + + if (vma->vm_pgoff != 0) + { + oss_cmn_err (CE_WARN, "mmap() offset must be 0.\n"); + return -EINVAL; + } + + size = vma->vm_end - vma->vm_start; + + if (size != bytes_in_use) + { + oss_cmn_err (CE_WARN, "mmap() size = %ld. Should be %d\n", + size, bytes_in_use); + return -EBUSY; + } + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13) + res = io_remap_page_range (vma, vma->vm_start, + dmabuf_phys, size, vma->vm_page_prot); + +#else + res = io_remap_pfn_range (vma, vma->vm_start, + dmabuf_phys >> PAGE_SHIFT, + size, vma->vm_page_prot); +#endif + + if (res) + { + oss_cmn_err (CE_WARN, "io_remap_pfn_range returned %d\n", res); + return -EAGAIN; + } + + return 0; +} + +/* As a special exception, if you link this library with other files, + some of which are compiled with GCC, to produce an executable, + this library does not by itself cause the resulting executable + to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +typedef unsigned int UQItype __attribute__ ((mode (QI))); +typedef int SItype __attribute__ ((mode (SI))); +typedef unsigned int USItype __attribute__ ((mode (SI))); +typedef int DItype __attribute__ ((mode (DI))); +typedef unsigned int UDItype __attribute__ ((mode (DI))); + +typedef int word_type __attribute__ ((mode (__word__))); + +/* DIstructs are pairs of SItype values in the order determined by + little/big ENDIAN. */ + +#if defined(__i386__) || defined(__x86_64__) +struct DIstruct +{ + SItype low, high; +}; +#endif + + +#ifndef __arm__ +/* We need this union to unpack/pack DImode values, since we don't have + any arithmetic yet. Incoming DImode parameters are stored into the + `ll' field, and the unpacked result is read from the struct `s'. */ + +typedef union +{ + struct DIstruct s; + DItype ll; +} DIunion; + + +/* From gcc/longlong.h */ + +#ifndef SI_TYPE_SIZE +#define SI_TYPE_SIZE 32 +#endif + +#define __BITS4 (SI_TYPE_SIZE / 4) +#define __ll_B (1L << (SI_TYPE_SIZE / 2)) +#define __ll_lowpart(t) ((USItype) (t) % __ll_B) +#define __ll_highpart(t) ((USItype) (t) / __ll_B) + +#if defined(__i386__) || defined(__x86_64__) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subl %5,%1\n" \ + "sbbl %3,%0" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "0" ((USItype) (ah)), \ + "g" ((USItype) (bh)), \ + "1" ((USItype) (al)), \ + "g" ((USItype) (bl))) +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("mull %3" \ + : "=a" ((USItype) (w0)), \ + "=d" ((USItype) (w1)) \ + : "%0" ((USItype) (u)), \ + "rm" ((USItype) (v))) +#define udiv_qrnnd(q, r, n1, n0, d) \ + __asm__ ("divl %4" \ + : "=a" ((USItype) (q)), \ + "=d" ((USItype) (r)) \ + : "0" ((USItype) (n0)), \ + "1" ((USItype) (n1)), \ + "rm" ((USItype) (d))) +#define count_leading_zeros(count, x) \ + do { \ + USItype __cbtmp; \ + __asm__ ("bsrl %1,%0" \ + : "=r" (__cbtmp) : "rm" ((USItype) (x))); \ + (count) = __cbtmp ^ 31; \ + } while (0) +#endif /* __i386__ */ + +/* If this machine has no inline assembler, use C macros. */ + +/* Define this unconditionally, so it can be used for debugging. */ +#define __udiv_qrnnd_c(q, r, n1, n0, d) \ + do { \ + USItype __d1, __d0, __q1, __q0; \ + USItype __r1, __r0, __m; \ + __d1 = __ll_highpart (d); \ + __d0 = __ll_lowpart (d); \ + \ + __r1 = (n1) % __d1; \ + __q1 = (n1) / __d1; \ + __m = (USItype) __q1 * __d0; \ + __r1 = __r1 * __ll_B | __ll_highpart (n0); \ + if (__r1 < __m) \ + { \ + __q1--, __r1 += (d); \ + if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\ + if (__r1 < __m) \ + __q1--, __r1 += (d); \ + } \ + __r1 -= __m; \ + \ + __r0 = __r1 % __d1; \ + __q0 = __r1 / __d1; \ + __m = (USItype) __q0 * __d0; \ + __r0 = __r0 * __ll_B | __ll_lowpart (n0); \ + if (__r0 < __m) \ + { \ + __q0--, __r0 += (d); \ + if (__r0 >= (d)) \ + if (__r0 < __m) \ + __q0--, __r0 += (d); \ + } \ + __r0 -= __m; \ + \ + (q) = (USItype) __q1 * __ll_B | __q0; \ + (r) = __r0; \ + } while (0) + +/* If udiv_qrnnd was not defined for this processor, use __udiv_qrnnd_c. */ +#if !defined (udiv_qrnnd) +#define UDIV_NEEDS_NORMALIZATION 1 +#define udiv_qrnnd __udiv_qrnnd_c +#endif + +/* End of gcc/longlong.h */ + + +static inline DItype +__negdi2 (DItype u) +{ + DIunion w; + DIunion uu; + + uu.ll = u; + + w.s.low = -uu.s.low; + w.s.high = -uu.s.high - ((USItype) w.s.low > 0); + + return w.ll; +} + +static inline UDItype +__udivmoddi4 (UDItype n, UDItype d, UDItype * rp) +{ + DIunion ww; + DIunion nn, dd; + DIunion rr; + USItype d0, d1, n0, n1, n2; + USItype q0, q1; + USItype b, bm; + + nn.ll = n; + dd.ll = d; + + d0 = dd.s.low; + d1 = dd.s.high; + n0 = nn.s.low; + n1 = nn.s.high; + +#ifndef UDIV_NEEDS_NORMALIZATION + if (d1 == 0) + { + if (d0 > n1) + { + /* 0q = nn / 0D */ + + udiv_qrnnd (q0, n0, n1, n0, d0); + q1 = 0; + + /* Remainder in n0. */ + } + else + { + /* qq = NN / 0d */ + + if (d0 == 0) + d0 = 1 / d0; /* Divide intentionally by zero. */ + + udiv_qrnnd (q1, n1, 0, n1, d0); + udiv_qrnnd (q0, n0, n1, n0, d0); + + /* Remainder in n0. */ + } + + if (rp != 0) + { + rr.s.low = n0; + rr.s.high = 0; + *rp = rr.ll; + } + } + +#else /* UDIV_NEEDS_NORMALIZATION */ + + if (d1 == 0) + { + if (d0 > n1) + { + /* 0q = nn / 0D */ + + count_leading_zeros (bm, d0); + + if (bm != 0) + { + /* Normalize, i.e. make the most significant bit of the + denominator set. */ + + d0 = d0 << bm; + n1 = (n1 << bm) | (n0 >> (SI_TYPE_SIZE - bm)); + n0 = n0 << bm; + } + + udiv_qrnnd (q0, n0, n1, n0, d0); + q1 = 0; + + /* Remainder in n0 >> bm. */ + } + else + { + /* qq = NN / 0d */ + + if (d0 == 0) + d0 = 1 / d0; /* Divide intentionally by zero. */ + + count_leading_zeros (bm, d0); + + if (bm == 0) + { + /* From (n1 >= d0) /\ (the most significant bit of d0 is set), + conclude (the most significant bit of n1 is set) /\ (the + leading quotient digit q1 = 1). + + This special case is necessary, not an optimization. + (Shifts counts of SI_TYPE_SIZE are undefined.) */ + + n1 -= d0; + q1 = 1; + } + else + { + /* Normalize. */ + + b = SI_TYPE_SIZE - bm; + + d0 = d0 << bm; + n2 = n1 >> b; + n1 = (n1 << bm) | (n0 >> b); + n0 = n0 << bm; + + udiv_qrnnd (q1, n1, n2, n1, d0); + } + + /* n1 != d0... */ + + udiv_qrnnd (q0, n0, n1, n0, d0); + + /* Remainder in n0 >> bm. */ + } + + if (rp != 0) + { + rr.s.low = n0 >> bm; + rr.s.high = 0; + *rp = rr.ll; + } + } +#endif /* UDIV_NEEDS_NORMALIZATION */ + + else + { + if (d1 > n1) + { + /* 00 = nn / DD */ + + q0 = 0; + q1 = 0; + + /* Remainder in n1n0. */ + if (rp != 0) + { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } + else + { + /* 0q = NN / dd */ + + count_leading_zeros (bm, d1); + if (bm == 0) + { + /* From (n1 >= d1) /\ (the most significant bit of d1 is set), + conclude (the most significant bit of n1 is set) /\ (the + quotient digit q0 = 0 or 1). + + This special case is necessary, not an optimization. */ + + /* The condition on the next line takes advantage of that + n1 >= d1 (true due to program flow). */ + if (n1 > d1 || n0 >= d0) + { + q0 = 1; + sub_ddmmss (n1, n0, n1, n0, d1, d0); + } + else + q0 = 0; + + q1 = 0; + + if (rp != 0) + { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } + else + { + USItype m1, m0; + /* Normalize. */ + + b = SI_TYPE_SIZE - bm; + + d1 = (d1 << bm) | (d0 >> b); + d0 = d0 << bm; + n2 = n1 >> b; + n1 = (n1 << bm) | (n0 >> b); + n0 = n0 << bm; + + udiv_qrnnd (q0, n1, n2, n1, d1); + umul_ppmm (m1, m0, q0, d0); + + if (m1 > n1 || (m1 == n1 && m0 > n0)) + { + q0--; + sub_ddmmss (m1, m0, m1, m0, d1, d0); + } + + q1 = 0; + + /* Remainder in (n1n0 - m1m0) >> bm. */ + if (rp != 0) + { + sub_ddmmss (n1, n0, n1, n0, m1, m0); + rr.s.low = (n1 << b) | (n0 >> bm); + rr.s.high = n1 >> bm; + *rp = rr.ll; + } + } + } + } + + ww.s.low = q0; + ww.s.high = q1; + return ww.ll; +} + +DItype +__divdi3 (DItype u, DItype v) +{ + word_type c = 0; + DIunion uu, vv; + DItype w; + + uu.ll = u; + vv.ll = v; + + if (uu.s.high < 0) + c = ~c, uu.ll = __negdi2 (uu.ll); + if (vv.s.high < 0) + c = ~c, vv.ll = __negdi2 (vv.ll); + + w = __udivmoddi4 (uu.ll, vv.ll, (UDItype *) 0); + if (c) + w = __negdi2 (w); + + return w; +} + + +DItype +__moddi3 (DItype u, DItype v) +{ + word_type c = 0; + DIunion uu, vv; + DItype w; + + uu.ll = u; + vv.ll = v; + + if (uu.s.high < 0) + c = ~c, uu.ll = __negdi2 (uu.ll); + if (vv.s.high < 0) + vv.ll = __negdi2 (vv.ll); + + (void) __udivmoddi4 (uu.ll, vv.ll, (UDItype *) & w); + if (c) + w = __negdi2 (w); + + return w; +} + + +UDItype +__umoddi3 (UDItype u, UDItype v) +{ + UDItype w; + + (void) __udivmoddi4 (u, v, (UDItype *) & w); + + return w; +} + + +UDItype +__udivdi3 (UDItype n, UDItype d) +{ + return __udivmoddi4 (n, d, (UDItype *) 0); +} +#endif + +#ifdef __arm__ +void +raise(void) +{ + oss_cmn_err (CE_PANIC, "raise() got called\n"); +} + +#endif + +dev_info_t * +oss_create_pcidip (struct pci_dev * pcidev) +{ + dev_info_t *dip; + + if ((dip = oss_pmalloc (sizeof (*dip))) == NULL) + return NULL; + + memset (dip, 0, sizeof (*dip)); + dip->pcidev = pcidev; + + return dip; +} + +int +osscore_pci_read_config_byte (dev_info_t * dip, unsigned int where, + unsigned char *val) +{ + return pci_read_config_byte (dip->pcidev, where, val); +} + +int +osscore_pci_read_config_irq (dev_info_t * dip, unsigned int where, + unsigned char *val) +{ + *val = dip->pcidev->irq; + return 0; // PCIBIOS_SUCCESSFUL +} + +int +osscore_pci_read_config_word (dev_info_t * dip, unsigned int where, + unsigned short *val) +{ + if (dip == NULL) + { + oss_cmn_err (CE_CONT, "osscore_pci_read_config_word: dip==NULL\n"); + return -1; + } + return pci_read_config_word (dip->pcidev, where, val); +} + +int +osscore_pci_read_config_dword (dev_info_t * dip, unsigned int where, + unsigned int *val) +{ + return pci_read_config_dword (dip->pcidev, where, val); +} + +int +osscore_pci_write_config_byte (dev_info_t * dip, unsigned int where, + unsigned char val) +{ + return pci_write_config_byte (dip->pcidev, where, val); +} + +int +osscore_pci_write_config_word (dev_info_t * dip, unsigned int where, + unsigned short val) +{ + return pci_write_config_word (dip->pcidev, where, val); +} + +int +osscore_pci_write_config_dword (dev_info_t * dip, unsigned int where, + unsigned int val) +{ + return pci_write_config_dword (dip->pcidev, where, val); +} + +int +osscore_pci_enable_msi (dev_info_t * dip) +{ + pci_enable_msi (dip->pcidev); + return (dip->pcidev->irq); +} + +/* 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); + +typedef struct +{ + int irq; + oss_device_t *osdev; + oss_tophalf_handler_t top; + oss_bottomhalf_handler_t bottom; +} osscore_intr_t; + +#define MAX_INTRS 32 + +static osscore_intr_t intrs[MAX_INTRS] = { {0} }; +static int nintrs = 0; + +static irqreturn_t +osscore_intr (int irq, void *arg) +{ + int serviced; + osscore_intr_t *intr = arg; + + if (intr->osdev == NULL || intr->top == NULL) /* Removed interrupt */ + return 0; + + serviced = intr->top (intr->osdev); + oss_inc_intrcount (intr->osdev, serviced); + if (serviced) + { + if (intr->bottom != NULL) + intr->bottom (intr->osdev); + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +extern int oss_pci_read_config_irq (oss_device_t * osdev, unsigned long where, + unsigned char *val); + +char * +oss_pci_read_devpath (dev_info_t * dip) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30) + return dev_name(&dip->pcidev->dev); +#else + return dip->pcidev->dev.bus_id; +#endif +} + +int +oss_register_interrupts (oss_device_t * osdev, int irqnum, + oss_tophalf_handler_t top, + oss_bottomhalf_handler_t bottom) +{ + + unsigned char pci_irq_line; + osscore_intr_t *intr; + char *name; + int err; + + if (nintrs >= MAX_INTRS) + { + oss_cmn_err (CE_CONT, + "oss_register_interrupts: Too many interrupt handlers\n"); + return -ENOMEM; + } + + intr = &intrs[nintrs]; + + if (oss_pci_read_config_irq (osdev, PCI_INTERRUPT_LINE, &pci_irq_line) > 0) + return -EIO; + + intr->irq = pci_irq_line; + intr->osdev = osdev; + intr->top = top; + intr->bottom = bottom; + + name = osdev_get_nick (osdev); +#ifndef IRQF_SHARED +#define IRQF_SHARED SA_SHIRQ +#endif + + if ((err = + request_irq (pci_irq_line, osscore_intr, IRQF_SHARED, name, intr)) < 0) + { + oss_cmn_err (CE_CONT, "request_irq(%d) failed, err=%d\n", pci_irq_line, + err); + return err; + } + + nintrs++; + + return 0; +} + +void +oss_unregister_interrupts (oss_device_t * osdev) +{ + int i; + + for (i = 0; i < nintrs; i++) + if (intrs[i].osdev == osdev) + { + free_irq (intrs[i].irq, &intrs[i]); + intrs[i].osdev = NULL; + intrs[i].top = NULL; + intrs[i].bottom = NULL; + } +} + +int +oss_copy_to_user (void *to, const void *from, unsigned long n) +{ + return copy_to_user (to, from, n); +} + +int +oss_copy_from_user (void *to, const void *from, unsigned long n) +{ + return copy_from_user (to, from, n); +} + +static int refcount = 0; + +typedef struct +{ + struct module *module; + int active; +} oss_module_t; + +#define OSS_MAX_MODULES 50 + +static oss_module_t oss_modules[OSS_MAX_MODULES]; +static int num_oss_modules = 0; + +void +oss_inc_refcounts (void) +{ + int i; + refcount++; + for (i = 0; i < num_oss_modules; i++) + if (oss_modules[i].active) + { + if (!try_module_get (oss_modules[i].module)) + oss_cmn_err (CE_WARN, "try_module_get() failed\n"); + } +} + +void +oss_dec_refcounts (void) +{ + int i; + refcount--; + for (i = 0; i < num_oss_modules; i++) + if (oss_modules[i].active) + { + module_put (oss_modules[i].module); + } +} + +void +oss_register_module (struct module *mod) +{ + int i, n = -1; + + for (i = 0; i < num_oss_modules; i++) + if (!oss_modules[i].active) + { + n = i; + break; + } + + if (n == -1) + { + if (num_oss_modules >= OSS_MAX_MODULES) + { + printk (KERN_ALERT "Too many OSS modules\n"); + return; + } + + n = num_oss_modules++; + } + + oss_modules[n].module = mod; + oss_modules[n].active = 1; +} + +void +oss_unregister_module (struct module *mod) +{ + int i; + + for (i = 0; i < num_oss_modules; i++) + if (oss_modules[i].active && oss_modules[i].module == mod) + { + oss_modules[i].active = 0; + oss_modules[i].module = NULL; + return; + } +} + +module_init (osscore_init); +module_exit (osscore_exit); + +#ifdef CONFIG_OSS_VMIX_FLOAT + +#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 0 +static inline unsigned long +read_cr0 (void) +{ + unsigned long cr0; + asm volatile ("movq %%cr0,%0":"=r" (cr0)); + return cr0; +} + +static inline void +write_cr0 (unsigned long val) +{ + asm volatile ("movq %0,%%cr0"::"r" (val)); +} + +static inline unsigned long +read_cr4 (void) +{ + unsigned long cr4; + asm volatile ("movq %%cr4,%0":"=r" (cr4)); + return cr4; +} + +static inline void +write_cr4 (unsigned long val) +{ + asm volatile ("movq %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_irq_restore (flags_reg); + + local_save_flags (flags_reg); + if (flags_reg & FLAGS_ID) + return 0; + + flags_reg |= FLAGS_ID; + local_irq_restore (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 + +#if 0 +void +__stack_chk_fail (void) +{ + panic ("__stack_chk_fail\n"); +} +#endif + +/* + * Exported symbols + */ + +#define EXPORT_FUNC(name) extern void name(void);EXPORT_SYMBOL(name); +#define EXPORT_DATA(name) extern int name;EXPORT_SYMBOL(name); + +/* EXPORT_SYMBOL (__stack_chk_fail); */ + +#ifdef CONFIG_OSS_VMIX_FLOAT +EXPORT_SYMBOL (oss_fp_check); +EXPORT_SYMBOL (oss_fp_save); +EXPORT_SYMBOL (oss_fp_restore); +#endif + +EXPORT_SYMBOL (oss_register_chrdev); +EXPORT_SYMBOL (oss_unregister_chrdev); +EXPORT_SYMBOL (oss_reserve_pages); +EXPORT_SYMBOL (oss_unreserve_pages); +EXPORT_FUNC (ac97_install); +EXPORT_FUNC (ac97_install_full); +EXPORT_FUNC (ac97_playrate); +EXPORT_FUNC (ac97_recrate); +EXPORT_FUNC (ac97_varrate); +EXPORT_FUNC (ac97_override_control); +EXPORT_FUNC (ac97_init_ext); +EXPORT_FUNC (ac97_mixer_set); +EXPORT_FUNC (ac97_spdif_setup); +EXPORT_FUNC (ac97_spdifout_ctl); +EXPORT_FUNC (ac97_remove_control); +EXPORT_SYMBOL (ac97_amplifier); +EXPORT_FUNC (ac97_disable_spdif); +EXPORT_FUNC (ac97_enable_spdif); +EXPORT_FUNC (ac97_mixext_ctl); +EXPORT_FUNC (ac97_spdifin_ctl); +EXPORT_FUNC (oss_pci_byteswap); +EXPORT_SYMBOL (mixer_ext_truncate); +EXPORT_SYMBOL (mixer_ext_rebuild_all); +EXPORT_FUNC (remux_install); +EXPORT_SYMBOL (oss_strlen); +EXPORT_SYMBOL (oss_strcmp); +EXPORT_FUNC (oss_install_mididev); +EXPORT_DATA (detect_trace); +EXPORT_SYMBOL (dmap_get_qhead); +EXPORT_SYMBOL (dmap_get_qtail); +EXPORT_FUNC (oss_alloc_dmabuf); +EXPORT_SYMBOL (oss_contig_free); +EXPORT_SYMBOL (oss_contig_malloc); +EXPORT_FUNC (oss_disable_device); +EXPORT_FUNC (oss_free_dmabuf); +EXPORT_SYMBOL (oss_map_pci_mem); +EXPORT_SYMBOL (oss_install_audiodev); +EXPORT_SYMBOL (oss_install_audiodev_with_devname); +EXPORT_FUNC (oss_audio_set_error); +EXPORT_SYMBOL (load_mixer_volumes); +EXPORT_SYMBOL (oss_unmap_pci_mem); +EXPORT_SYMBOL (oss_memset); +EXPORT_SYMBOL (oss_mutex_cleanup); +EXPORT_SYMBOL (oss_mutex_init); +EXPORT_SYMBOL (oss_register_device); +EXPORT_SYMBOL (oss_register_interrupts); +EXPORT_SYMBOL (oss_inc_intrcount); +EXPORT_SYMBOL (oss_spin_lock); +EXPORT_SYMBOL (oss_spin_lock_irqsave); +EXPORT_SYMBOL (oss_spin_unlock); +EXPORT_SYMBOL (oss_spin_unlock_irqrestore); +EXPORT_SYMBOL (oss_udelay); +EXPORT_FUNC (oss_unregister_device); +EXPORT_SYMBOL (oss_unregister_interrupts); +EXPORT_SYMBOL (oss_virt_to_bus); +EXPORT_FUNC (oss_pci_read_config_byte); +EXPORT_FUNC (oss_pci_read_config_word); +EXPORT_FUNC (oss_pci_read_config_dword); +EXPORT_FUNC (oss_pci_write_config_byte); +EXPORT_FUNC (oss_pci_write_config_word); +EXPORT_FUNC (oss_pci_write_config_dword); +EXPORT_FUNC (oss_pci_enable_msi); +EXPORT_SYMBOL (oss_pci_read_config_irq); +EXPORT_SYMBOL (oss_pci_read_devpath); +EXPORT_SYMBOL (oss_get_jiffies); +EXPORT_SYMBOL (mixer_find_ext); +EXPORT_SYMBOL (oss_install_mixer); +EXPORT_SYMBOL (oss_strcpy); +EXPORT_SYMBOL (oss_kmem_free); +#ifndef __arm__ +EXPORT_FUNC (uart401_init); +EXPORT_FUNC (uart401_disable); +EXPORT_FUNC (uart401_irq); +#endif +EXPORT_SYMBOL (mixer_ext_set_init_fn); +EXPORT_SYMBOL (mixer_ext_set_vmix_init_fn); +#ifdef CONFIG_OSS_VMIX +EXPORT_FUNC (vmix_attach_audiodev); +EXPORT_FUNC (vmix_detach_audiodev); +EXPORT_FUNC (vmix_change_devnames); +#endif +EXPORT_SYMBOL (mixer_ext_set_strings); +EXPORT_SYMBOL (mixer_ext_create_group); +EXPORT_SYMBOL (mixer_ext_create_group_flags); +EXPORT_SYMBOL (mixer_ext_create_control); +EXPORT_SYMBOL (oss_strncpy); +EXPORT_SYMBOL (oss_memcpy); +EXPORT_SYMBOL (oss_kmem_alloc); +EXPORT_DATA (oss_hz); +EXPORT_FUNC (oss_spdif_open); +EXPORT_FUNC (oss_spdif_ioctl); +EXPORT_FUNC (oss_spdif_install); +EXPORT_FUNC (oss_spdif_uninstall); +EXPORT_FUNC (oss_spdif_close); +EXPORT_FUNC (oss_spdif_mix_init); +EXPORT_FUNC (oss_spdif_setrate); +EXPORT_FUNC (create_new_card); +EXPORT_FUNC (oss_audio_ioctl); +EXPORT_FUNC (oss_audio_open_engine); +EXPORT_FUNC (oss_audio_release); +EXPORT_FUNC (oss_audio_set_rate); +EXPORT_SYMBOL (oss_uiomove); +EXPORT_SYMBOL (oss_get_pid); +EXPORT_SYMBOL (oss_get_uid); +EXPORT_SYMBOL (oss_get_procname); +EXPORT_SYMBOL (mix_cvt); +EXPORT_FUNC (oss_audio_set_format); +EXPORT_FUNC (oss_audio_set_channels); +EXPORT_FUNC (midiparser_create); +EXPORT_FUNC (midiparser_input); +EXPORT_FUNC (midiparser_unalloc); +EXPORT_FUNC (mixer_ext_create_device); +EXPORT_SYMBOL (mixer_ext_recrw); +EXPORT_SYMBOL (mixer_ext_rw); +EXPORT_SYMBOL (mixer_ext_set_enum); +EXPORT_SYMBOL (mixer_ext_set_description); +EXPORT_SYMBOL (osdev_create); +EXPORT_FUNC (osdev_clone); +EXPORT_SYMBOL (osdev_delete); +EXPORT_FUNC (oss_audio_chpoll); +EXPORT_FUNC (oss_audio_delayed_attach); +EXPORT_FUNC (oss_audio_read); +EXPORT_FUNC (oss_audio_write); +EXPORT_SYMBOL (oss_create_wait_queue); +EXPORT_SYMBOL (oss_remove_wait_queue); +EXPORT_SYMBOL (oss_reset_wait_queue); +EXPORT_SYMBOL (oss_sleep); +EXPORT_SYMBOL (oss_strncmp); +EXPORT_SYMBOL (oss_timeout); +EXPORT_SYMBOL (oss_untimeout); +EXPORT_SYMBOL (oss_wakeup); +#if 0 +EXPORT_FUNC (ossddk_ac97_install); +EXPORT_FUNC (ossddk_ac97_is_varrate); +EXPORT_FUNC (ossddk_ac97_remove); +EXPORT_FUNC (ossddk_ac97_set_ext_init); +EXPORT_FUNC (ossddk_ac97_set_playrate); +EXPORT_FUNC (ossddk_ac97_set_recrate); +EXPORT_FUNC (ossddk_adev_get_devc); +EXPORT_FUNC (ossddk_adev_get_dmapin); +EXPORT_FUNC (ossddk_adev_get_dmapout); +EXPORT_FUNC (ossddk_adev_get_flags); +EXPORT_FUNC (ossddk_adev_get_label); +EXPORT_FUNC (ossddk_adev_get_portc); +EXPORT_FUNC (ossddk_adev_get_portc_play); +EXPORT_FUNC (ossddk_adev_get_portc_record); +EXPORT_FUNC (ossddk_adev_get_songname); +EXPORT_FUNC (ossddk_adev_set_buflimits); +EXPORT_FUNC (ossddk_adev_set_caps); +EXPORT_FUNC (ossddk_adev_set_channels); +EXPORT_FUNC (ossddk_adev_set_devc); +EXPORT_FUNC (ossddk_adev_set_enable_flag); +EXPORT_FUNC (ossddk_adev_set_flags); +EXPORT_FUNC (ossddk_adev_set_formats); +EXPORT_FUNC (ossddk_adev_set_label); +EXPORT_FUNC (ossddk_adev_set_magic); +EXPORT_FUNC (ossddk_adev_set_mixer); +EXPORT_FUNC (ossddk_adev_set_portc); +EXPORT_FUNC (ossddk_adev_set_portc_play); +EXPORT_FUNC (ossddk_adev_set_portc_record); +EXPORT_FUNC (ossddk_adev_set_portnum); +EXPORT_FUNC (ossddk_adev_set_rates); +EXPORT_FUNC (ossddk_adev_set_ratesource); +EXPORT_FUNC (ossddk_adev_set_songname); +EXPORT_FUNC (ossddk_adev_set_unloaded_flag); +EXPORT_FUNC (ossddk_audio_inputintr); +EXPORT_FUNC (ossddk_audio_outputintr); +EXPORT_FUNC (ossddk_disable_device); +EXPORT_FUNC (ossddk_dmap_get_buffsize); +EXPORT_FUNC (ossddk_dmap_get_buffused); +EXPORT_FUNC (ossddk_dmap_get_dmabuf); +EXPORT_FUNC (ossddk_dmap_get_fragsize); +EXPORT_FUNC (ossddk_dmap_get_numfrags); +EXPORT_FUNC (ossddk_dmap_get_phys); +EXPORT_FUNC (ossddk_dmap_get_private); +EXPORT_FUNC (ossddk_dmap_get_qhead); +EXPORT_FUNC (ossddk_dmap_get_qtail); +EXPORT_FUNC (ossddk_dmap_set_buffsize); +EXPORT_FUNC (ossddk_dmap_set_callback); +EXPORT_FUNC (ossddk_dmap_set_dmabuf); +EXPORT_FUNC (ossddk_dmap_set_fragsize); +EXPORT_FUNC (ossddk_dmap_set_numfrags); +EXPORT_FUNC (ossddk_dmap_set_phys); +EXPORT_FUNC (ossddk_dmap_set_playerror); +EXPORT_FUNC (ossddk_dmap_set_private); +EXPORT_FUNC (ossddk_dmap_set_recerror); +EXPORT_FUNC (ossddk_install_audiodev); +EXPORT_FUNC (ossddk_install_mixer); +EXPORT_FUNC (ossddk_mixer_create_control); +EXPORT_FUNC (ossddk_mixer_create_group); +EXPORT_FUNC (ossddk_mixer_get_devc); +EXPORT_FUNC (ossddk_mixer_set_strings); +EXPORT_FUNC (ossddk_mixer_touch); +EXPORT_FUNC (ossddk_mixer_truncate); +EXPORT_FUNC (ossddk_osdev_get_devc); +EXPORT_FUNC (ossddk_register_device); +EXPORT_FUNC (ossddk_unregister_device); +#endif +EXPORT_SYMBOL (osdev_set_major); +EXPORT_SYMBOL (osdev_set_owner); +EXPORT_SYMBOL (osdev_get_owner); +EXPORT_SYMBOL (oss_create_pcidip); +EXPORT_SYMBOL (touch_mixer); +EXPORT_SYMBOL (oss_mixer_ext); +EXPORT_SYMBOL (oss_request_major); +EXPORT_SYMBOL (audio_engines); +EXPORT_DATA (midi_devs); +EXPORT_SYMBOL (mixer_devs); +EXPORT_SYMBOL (mixer_devs_p); +EXPORT_DATA (num_audio_engines); +EXPORT_DATA (num_mididevs); +EXPORT_SYMBOL (num_mixers); +EXPORT_DATA (oss_timing_mutex); +EXPORT_DATA (oss_num_cards); +EXPORT_FUNC (oss_do_timing); +EXPORT_FUNC (oss_do_timing2); +EXPORT_FUNC (oss_timing_enter); +EXPORT_FUNC (oss_timing_leave); +#ifndef __arm__ +EXPORT_SYMBOL (__udivdi3); +EXPORT_SYMBOL (__umoddi3); +EXPORT_SYMBOL (__divdi3); +#else +EXPORT_SYMBOL (raise); +#endif +EXPORT_SYMBOL (oss_copy_from_user); +EXPORT_SYMBOL (oss_copy_to_user); +EXPORT_SYMBOL (osdev_set_irqparms); +EXPORT_SYMBOL (osdev_get_irqparms); +EXPORT_SYMBOL (osdev_get_nick); +EXPORT_SYMBOL (osdev_get_instance); +EXPORT_SYMBOL (oss_inc_refcounts); +EXPORT_SYMBOL (oss_dec_refcounts); +EXPORT_SYMBOL (oss_register_module); +EXPORT_SYMBOL (oss_unregister_module); +EXPORT_SYMBOL (oss_audio_reset); +EXPORT_SYMBOL (oss_audio_start_syncgroup); +EXPORT_SYMBOL (oss_encode_enum); +EXPORT_SYMBOL (dmap_get_qlen); +EXPORT_SYMBOL (num_audio_devfiles); +EXPORT_SYMBOL (oss_audio_inc_byte_counter); +EXPORT_SYMBOL (oss_audio_register_client); +EXPORT_SYMBOL (audio_devfiles); +EXPORT_FUNC (oss_get_cardinfo); +EXPORT_SYMBOL (oss_pmalloc); +EXPORT_SYMBOL (oss_add_audio_devlist); +EXPORT_FUNC (oss_memblk_malloc); +EXPORT_FUNC (oss_memblk_free); +EXPORT_FUNC (oss_memblk_unalloc); +EXPORT_DATA (oss_global_memblk); +EXPORT_FUNC (oss_get_procinfo); +EXPORT_DATA (mixer_muted); + +#ifdef CONFIG_OSS_MIDI +EXPORT_FUNC (oss_midi_ioctl); +EXPORT_FUNC (oss_midi_copy_timer); +#endif diff --git a/setup/Linux/oss/build/ossdip.h b/setup/Linux/oss/build/ossdip.h new file mode 100644 index 0000000..811e70a --- /dev/null +++ b/setup/Linux/oss/build/ossdip.h @@ -0,0 +1,10 @@ +/* + * Purpose: Definition of the _dev_info_t structure for Linux + */ +#ifndef OSSDIP_H +#define OSSDIP_H +struct _dev_info_t +{ + struct pci_dev *pcidev; +}; +#endif diff --git a/setup/Linux/oss/build/pci_wrapper.inc b/setup/Linux/oss/build/pci_wrapper.inc new file mode 100644 index 0000000..e08ec3a --- /dev/null +++ b/setup/Linux/oss/build/pci_wrapper.inc @@ -0,0 +1,93 @@ +/* + * Purpose: PCI wrapper routines for Linux + * + * This source file contains probe and remove routines for PCI devices. + * This code will be compiled in the target system. + */ +/* + * Copyright (C) 4Front Technologies 2005-2007. Released under GPL2 license. + */ +typedef struct +{ + struct pci_dev *pcidev; + oss_device_t *osdev; +} dev_map_t; + +#define MAX_INSTANCE 10 +static dev_map_t dev_map[MAX_INSTANCE]; +static int n_devmap = 0; + +static int __devinit +osspci_probe (struct pci_dev *pcidev, const struct pci_device_id *pciid) +{ + oss_device_t *osdev; + dev_info_t *dip; + + if (n_devmap >= MAX_INSTANCE) + { + printk (KERN_ALERT "oss: Too many instances of " DRIVER_NICK); + return -ENOMEM; + } + + if ((dip = oss_create_pcidip (pcidev)) == NULL) + return -ENOMEM; + + if ((osdev = + osdev_create (dip, DRIVER_TYPE, instance++, DRIVER_NICK, + NULL)) == NULL) + { + return -ENOMEM; + } + + osdev_set_owner (osdev, THIS_MODULE); + + if (module_major == 0) + module_major = oss_request_major (osdev, 0, DRIVER_NICK); + if (module_major <= 0) + { + printk (KERN_ALERT "Failed to allocate major device for " DRIVER_NICK); + return -EIO; + + } + osdev_set_major (osdev, module_major); + + pci_enable_device (pcidev); + if (!DRIVER_ATTACH (osdev)) + { + pci_disable_device (pcidev); + return -EIO; + } + + dev_map[n_devmap].pcidev = pcidev; + dev_map[n_devmap++].osdev = osdev; + oss_audio_delayed_attach (); + + return 0; +} + +static void __devexit +osspci_remove (struct pci_dev *pcidev) +{ + int i; + oss_device_t *osdev; + + for (i = 0; i < n_devmap; i++) + if (dev_map[i].pcidev == pcidev) + { + osdev = dev_map[i].osdev; + if (!DRIVER_DETACH (osdev)) + printk (KERN_ALERT DRIVER_NICK ": Unloading busy device\n"); + pci_disable_device (dev_map[i].pcidev); + osdev_delete (osdev); + + return; + } + + printk (KERN_ALERT DRIVER_NICK ": Can't find the PCI device to detach\n"); +} + +void +oss_pcie_init (oss_device_t * osdev, int flags) +{ + /* TODO: Do we need to do something here? */ +} diff --git a/setup/Linux/oss/build/usb_wrapper.inc b/setup/Linux/oss/build/usb_wrapper.inc new file mode 100644 index 0000000..ee199a7 --- /dev/null +++ b/setup/Linux/oss/build/usb_wrapper.inc @@ -0,0 +1,730 @@ +/* + * Purpose: Low level USB wrapper routines for Linux (2.6.x and later) + * + * This file contains the Linux specific USB support routines defined in udi.h + */ +/* + * Copyright (C) 4Front Technologies 2005-2007. Released under GPL2 license. + */ +#include "udi.h" + +#undef IO_DEBUG +static const udi_usb_devinfo *known_devices = NULL; + +#define MAX_DEVICE_SLOTS 20 + +int udi_usb_trace = 0; + +static udi_usb_driver *drv = NULL; +extern void *oss_pmalloc (size_t sz); + +struct udi_usb_devc +{ + struct usb_device *usb_dev; + const struct usb_device_id *id; + const udi_usb_devinfo *udi_usb_dev; + char *devpath; + + int enabled; + + int vendor, product, class, subclass; + struct usb_interface *iface; + int iface_number; + char *dev_name; + char *altsetting_labels; + int default_altsetting; + unsigned int altsetting_mask; + udi_usb_driver *drv; + void *client_devc; + int num_altsettings; + int usb_version; + struct usb_host_interface *altsetting; + +}; + +struct _udi_endpoint_handle_t +{ + unsigned char desc[32]; +}; + +#define MAX_DEVC 32 + +static udi_usb_devc usb_devc_list[MAX_DEVC] = { {0} }; +static int ndevs = 0; + +udi_endpoint_handle_t * +udi_open_endpoint (udi_usb_devc * usbdev, void *ep_descr) +{ + return (udi_endpoint_handle_t *) ep_descr; +} + +void +udi_close_endpoint (udi_endpoint_handle_t * eph) +{ + // NOP +} + +int +udi_endpoint_get_num (udi_endpoint_handle_t * eph) +{ + return eph->desc[2] /* & 0x7f */; +} + +#if 1 +static void +dump_configs (struct usb_device *dev) +{ + int c; + + printk ("#configs %d\n", dev->descriptor.bNumConfigurations); + + for (c = 0; c < dev->descriptor.bNumConfigurations; c++) + { + int i, j, k; + struct usb_host_config *config = &dev->config[c]; + + printk ("\tConfig #%d - #interfaces=%d\n", c, + config->desc.bNumInterfaces); + + for (j = 0; j < config->desc.bNumInterfaces; j++) + { + struct usb_interface *ifp = config->interface[j]; + printk ("\t\tInterface #%d - altsettings=%d\n", j, + ifp->num_altsetting); + + for (k = 0; k < ifp->num_altsetting; k++) + { + struct usb_host_interface *alt = &ifp->altsetting[k]; + unsigned char *buf = alt->extra; + + printk ("\t\t\tAlt setting #%d:\n", k); + + for (i = 0; i < alt->extralen; i++) + { + if (!(i % 8)) + { + if (i) + printk ("\n"); + printk ("\t\t\t%04x: ", i); + } + printk ("%02x ", buf[i]); + } + + printk ("\n"); + } + } + } +} +#endif + +static int +udi_attach_usbdev (struct usb_device *dev, + oss_device_t * osdev, + char *devpath, + struct usb_interface *iface, + const struct usb_device_id *id, + const udi_usb_devinfo * udi_usb_dev) +{ + int cfg_num, ep; + + udi_usb_devc *devc = &usb_devc_list[ndevs]; + struct usb_host_interface *alts; + + if (ndevs >= MAX_DEVC) + { + printk ("OSS: Too many USB audio/midi devices\n"); + return -ENODEV; + } + + if (udi_usb_trace > 1) + printk ("OSS: Attaching USB device %x:%x/%d, class=%x:%x, name=%s\n", + dev->descriptor.idVendor, dev->descriptor.idProduct, + iface->altsetting[0].desc.bInterfaceNumber, + iface->altsetting[0].desc.bInterfaceClass, + iface->altsetting[0].desc.bInterfaceSubClass, udi_usb_dev->name); + + devc->usb_dev = dev; + devc->id = id; + devc->udi_usb_dev = udi_usb_dev; + + devc->vendor = dev->descriptor.idVendor; + devc->product = dev->descriptor.idProduct; + devc->usb_version = dev->descriptor.bcdUSB >> 8; + devc->class = iface->altsetting[0].desc.bInterfaceClass; + devc->subclass = iface->altsetting[0].desc.bInterfaceSubClass; + devc->iface_number = iface->altsetting[0].desc.bInterfaceNumber; + devc->iface = iface; + devc->dev_name = udi_usb_dev->name; + devc->devpath = devpath; + devc->num_altsettings = iface->num_altsetting; + devc->altsetting = iface->altsetting; + + alts = &iface->altsetting[devc->num_altsettings - 1]; + ep = 0; + + if (alts->desc.bNumEndpoints > 1) + ep = 1; + + if (udi_usb_trace > 2) + { + int i; + + for (i = 0; i < alts->desc.bNumEndpoints; i++) + { + printk ("Endpoint: %02x\n", + alts->endpoint[i].desc.bEndpointAddress); + } + } + + cfg_num = 0; + + devc->enabled = 1; + devc->drv = drv; + + if (udi_usb_trace > 2) + dump_configs (dev); + + if ((devc->client_devc = drv->attach (devc, osdev)) == NULL) + { + return -EIO; + } + + ndevs++; + + usb_set_intfdata (iface, devc); + return 0; +} + +static char *prev_devices[32] = { NULL }; +static int nprev_devices = 0; + +static int +udi_usb_probe (struct usb_interface *iface, const struct usb_device_id *id) +{ + int i; + static int ncalls = 0; + oss_device_t *osdev = NULL; + dev_info_t *dip = NULL; // TODO + + char nick[32]; + int inst = 0; + + struct usb_device *dev = interface_to_usbdev (iface); + + if (ncalls++ > 100) + return -EIO; + + sprintf (nick, "usb%04x%04x-", dev->descriptor.idVendor, + dev->descriptor.idProduct); + +/* + * Find out how many instances of this device (ID) are already attached. + */ + + for (i = 0; i < nprev_devices; i++) + { + if (strcmp (nick, prev_devices[i]) == 0) + { + inst++; + } + } + + prev_devices[nprev_devices] = oss_pmalloc (strlen (nick) + 1); + strcpy (prev_devices[nprev_devices], nick); + if (nprev_devices < 32) + nprev_devices++; + + if ((osdev = osdev_create (dip, DRV_USB, inst, nick, NULL)) == NULL) + { + return -ENOMEM; + } + osdev_set_owner (osdev, THIS_MODULE); + osdev_set_major (osdev, usb_major); + + i = 0; + if (udi_usb_trace > 1) + printk ("\n\nProbing dev=%s id=%x:%x/%d\n", dev->devpath, + dev->descriptor.idVendor, + dev->descriptor.idProduct, + iface->altsetting[0].desc.bInterfaceNumber); + + while (i >= 0 && known_devices[i].vendor >= 0) + { + if (dev->descriptor.idVendor == known_devices[i].vendor && + dev->descriptor.idProduct == known_devices[i].product) + { + int ret; + const udi_usb_devinfo *d = &known_devices[i]; + ret = udi_attach_usbdev (dev, osdev, dev->devpath, iface, id, d); + return ret; + } + else + i++; + } + +/* Try the "generic" device */ + { + int ret; + const udi_usb_devinfo *d = &known_devices[i]; + ret = udi_attach_usbdev (dev, osdev, dev->devpath, iface, id, d); + return ret; + } + + return -ENODEV; +} + +static void +udi_usb_disconnect (struct usb_interface *iface) +{ + udi_usb_devc *devc = usb_get_intfdata (iface); + //struct usb_device *dev = interface_to_usbdev (iface); + + if (devc == (udi_usb_devc *) - 1) + return; + + if (!devc->enabled) + return; + + if (udi_usb_trace > 0) + printk ("OSS: Disconnect USB device %x:%x %s\n", devc->vendor, + devc->product, devc->udi_usb_dev->name); + devc->drv->disconnect (devc->client_devc); + devc->enabled = 0; +} + +static struct usb_driver oss_usb = { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) +owner:THIS_MODULE, +#endif +name:"oss_usb", +probe:udi_usb_probe, +disconnect:udi_usb_disconnect, +id_table:udi_usb_table +}; + +static int udi_usb_installed = 0; + +int +udi_attach_usbdriver (oss_device_t * osdev, const udi_usb_devinfo * devlist, + udi_usb_driver * driver) +{ + drv = driver; + known_devices = devlist; + return 1; +} + +void +udi_unload_usbdriver (oss_device_t * osdev) +{ +} + +/* + * Device access routines + */ + +int +udi_usbdev_get_class (udi_usb_devc * usbdev) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + + return devc->class; +} + +int +udi_usbdev_get_subclass (udi_usb_devc * usbdev) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + + return devc->subclass; +} + +int +udi_usbdev_get_vendor (udi_usb_devc * usbdev) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + + return devc->vendor; +} + +int +udi_usbdev_get_product (udi_usb_devc * usbdev) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + + return devc->product; +} + +int +udi_usbdev_get_inum (udi_usb_devc * usbdev) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + + return devc->iface_number; +} + +int +udi_usbdev_set_interface (udi_usb_devc * usbdev, int inum, int altset) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + + return usb_set_interface (devc->usb_dev, inum, altset); +} + +unsigned char * +udi_usbdev_get_endpoint (udi_usb_devc * usbdev, int altsetting, int n, + int *len) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + int num_endpoints; + struct usb_device *dev; + struct usb_host_interface *alts; + struct usb_interface *iface; + + dev = devc->usb_dev; + iface = devc->iface; + + if (altsetting >= devc->num_altsettings) + return NULL; + + alts = &iface->altsetting[altsetting]; + + num_endpoints = alts->desc.bNumEndpoints; + + if (n >= num_endpoints) + return NULL; + + *len = alts->endpoint[n].desc.bLength; + return (unsigned char *) &alts->endpoint[n].desc; +} + +int +udi_usbdev_get_num_altsettings (udi_usb_devc * usbdev) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + + return devc->num_altsettings; +} + +int +udi_usbdev_get_usb_version (udi_usb_devc * usbdev) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + + return devc->usb_version; +} + +unsigned char * +udi_usbdev_get_altsetting (udi_usb_devc * usbdev, int n, int *size) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + struct usb_host_interface *alt; + + if (n < 0 || n >= devc->num_altsettings) + { + /* printk("udi usb: Bad altsetting %d (%d)\n", n, n >= devc->num_altsettings); */ + return NULL; + } + + alt = &devc->altsetting[n]; + + *size = alt->extralen; + return alt->extra; +} + +char * +udi_usbdev_get_name (udi_usb_devc * usbdev) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + + return devc->dev_name == NULL ? "Unknown" : devc->dev_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) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + static char str[100]; + int err; + + if (ix == 0) + return NULL; + + if ((err = usb_string (devc->usb_dev, ix, str, sizeof (str) - 1)) != 0) + { + return NULL; + } + + return str; +} + +char * +udi_usbdev_get_devpath (udi_usb_devc * usbdev) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + + return devc->devpath; +} + +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) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + int err; + + if (!devc->enabled) + return -EPIPE; + + if (timeout < 0) + timeout = 0; + +#ifdef IO_DEBUG + printk ("Snd %x (%x) rq=%x, rt=%x, v=%x, ix=%x, l=%d %02x %02x\n", + devc->usb_dev, + usb_sndctrlpipe (devc->usb_dev, endpoint), + rq, rqtype, value, index, len, b[0], b[1]); +#endif + err = usb_control_msg (devc->usb_dev, + usb_sndctrlpipe (devc->usb_dev, endpoint), + rq, rqtype, value, index, buf, len, timeout); +#ifdef IO_DEBUG + if (err < 0) + printk ("Usb write error %d\n", err); +#endif + + return err; +} + +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) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + int err; + + if (!devc->enabled) + return -EPIPE; + + if (timeout < 0) + timeout = 0; + +#ifdef IO_DEBUG + printk ("Rcv %x (%x) rq=%x, rt=%x, v=%x, ix=%x, l=%d\n", + devc->usb_dev, + (unsigned int) usb_rcvctrlpipe (devc->usb_dev, endpoint), + rq, rqtype | USB_DIR_IN, value, index, len); +#endif + err = usb_control_msg (devc->usb_dev, + (unsigned int) usb_rcvctrlpipe (devc->usb_dev, + endpoint), rq, + rqtype | USB_DIR_IN, value, index, buf, len, + timeout); +#ifdef IO_DEBUG + if (err < 0) + printk ("Usb read error %d\n", err); + else + printk ("Got %02x %02x\n", b[0], b[1]); +#endif + + return err; +} + +/* Request stuff */ + +struct udi_usb_request +{ + struct urb *urb; + udi_usb_complete_func_t callback; + void *callback_arg; + int active; + void *data; +}; + +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 *rq; + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + + if ((rq = kmalloc (sizeof (*rq), GFP_KERNEL)) == NULL) + { + printk ("udi_usb_alloc_request: Out of memory\n"); + return NULL; + } + + memset (rq, 0, sizeof (*rq)); + + if ((rq->urb = usb_alloc_urb (nframes, 0)) == NULL) + { + kfree (rq); + printk ("udi_usb_alloc_request: Failed to allocate URB\n"); + return NULL; + } + + rq->urb->dev = devc->usb_dev; + rq->urb->number_of_packets = nframes; + rq->active = 0; + + return rq; +} + +void +udi_usb_free_request (udi_usb_request_t * request) +{ + if (request == NULL) + return; + + udi_usb_cancel_request (request); + + usb_free_urb (request->urb); + kfree (request); +} + +unsigned char * +udi_usb_request_actdata (udi_usb_request_t * request) +{ + return request->data; +} + +static void +complete_func (struct urb *urb) +{ + udi_usb_request_t *request = urb->context; + + request->active = 0; + request->callback (request, request->callback_arg); +} + +int +udi_usb_submit_request (udi_usb_request_t * request, + udi_usb_complete_func_t callback, void *callback_arg, + udi_endpoint_handle_t * eph, int xfer_type, + void *data, int data_len) +{ + struct urb *urb; + struct usb_device *d; + int i, err; + int endpoint = eph->desc[2] & 0x7f; + + if (request == NULL) + return -EINVAL; + + urb = request->urb; + d = urb->dev; + request->callback = callback; + request->callback_arg = callback_arg; + request->data = data; + urb->complete = (usb_complete_t) complete_func; + urb->context = request; + urb->transfer_buffer = data; + + for (i = 0; i < urb->number_of_packets; i++) + { + urb->iso_frame_desc[i].status = 0; + urb->iso_frame_desc[i].length = data_len; + urb->iso_frame_desc[i].offset = i * data_len; + } + + urb->transfer_buffer_length = urb->actual_length = data_len; + + switch (xfer_type) + { + case UDI_USBXFER_ISO_WRITE: + urb->pipe = usb_sndisocpipe (urb->dev, endpoint); + urb->transfer_flags = URB_ISO_ASAP; + urb->interval = 1; + break; + + case UDI_USBXFER_ISO_READ: + urb->pipe = usb_rcvisocpipe (urb->dev, endpoint); + urb->transfer_flags = URB_ISO_ASAP; + urb->interval = 1; + break; + + case UDI_USBXFER_BULK_READ: + usb_fill_bulk_urb (urb, d, usb_rcvbulkpipe (d, endpoint), + data, data_len, + (usb_complete_t) complete_func, request); + break; + + case UDI_USBXFER_INTR_READ: + usb_fill_int_urb (urb, d, usb_rcvintpipe (d, endpoint), + data, data_len, + (usb_complete_t) complete_func, request, 8); + break; + + case UDI_USBXFER_BULK_WRITE: + usb_fill_bulk_urb (urb, d, usb_sndbulkpipe (d, endpoint), + data, data_len, + (usb_complete_t) complete_func, request); + break; + + default: + printk ("udi usb: Bad xfer type %d\n", xfer_type); + return -EINVAL; + } + +#ifdef SLAB_ATOMIC + if ((err = usb_submit_urb (request->urb, SLAB_ATOMIC)) >= 0) + request->active = 1; +#else + /* + * Linux 2.6.20 and later don't have SLAB_ATOMIC + */ + if ((err = usb_submit_urb (request->urb, GFP_ATOMIC)) >= 0) + request->active = 1; +#endif + return err; +} + +int +udi_usb_request_actlen (udi_usb_request_t * request) +{ + return request->urb->actual_length; +} + +void +udi_usb_cancel_request (udi_usb_request_t * request) +{ + if (request == NULL || !request->active) + return; + + usb_kill_urb (request->urb); + +} diff --git a/setup/Linux/oss/cuckoo/Makefile b/setup/Linux/oss/cuckoo/Makefile new file mode 100644 index 0000000..da9013b --- /dev/null +++ b/setup/Linux/oss/cuckoo/Makefile @@ -0,0 +1,23 @@ +ccflags-y += -I/usr/lib/oss + +ifneq ($(KERNELRELEASE),) + + obj-m := cuckoo.o cuckoo_pcm.o cuckoo_mixer.o + +else + + KERNELDIR ?= /lib/modules/$(shell uname -r)/build + PWD := $(shell pwd) + +default: + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules + +endif + +install: default + cp *.ko /lib/modules/`uname -r`/kernel/oss + depmod -a + +clean: + rm -f *.o *.ko *.mod.c *.mod.o .*.cmd core core.* x y z + rm -rf .tmp_versions Modules.symvers diff --git a/setup/Linux/oss/cuckoo/checksum.h b/setup/Linux/oss/cuckoo/checksum.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/setup/Linux/oss/cuckoo/checksum.h diff --git a/setup/Linux/oss/cuckoo/cuckoo.c b/setup/Linux/oss/cuckoo/cuckoo.c new file mode 100644 index 0000000..b7a04a6 --- /dev/null +++ b/setup/Linux/oss/cuckoo/cuckoo.c @@ -0,0 +1,251 @@ +/* + * This software module makes it possible to use Open Sound System for Linux + * (the _professional_ version) as a low level driver source for ALSA. + * + * Copyright (C) 2004-2009 Hannu Savolainen (hannu@opensound.com). + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ + +/* + * !!!!!!!!!!!!!!!!!!!! Important !!!!!!!!!!!!!!!!!! + * + * If this file doesn't compile, you must not try to resolve the problem + * without perfect understanding of internals of Linux kernel, ALSA and + * Open Sound System. + * + * Instead you need to check that you are using the version of this file + * that matches the versions of ALSA, OSS and Linux you are currently using. + */ + +#ifndef KBUILD_MODNAME +#define KBUILD_MODNAME cuckoo +#endif + +#include "cuckoo.h" + +#include "./checksum.h" + +#ifdef VERMAGIC_STRING +static const char vermagic[] = VERMAGIC_STRING; +#endif + +MODULE_AUTHOR ("Hannu Savolainen <hannu@opensound.com>"); +MODULE_LICENSE ("GPL v2"); +//MODULE_CLASSES("{sound}"); +MODULE_DESCRIPTION ("OSS low level driver interface for ALSA"); + +#define CUCKOO_MAXCARD SNDRV_CARDS +static int index[CUCKOO_MAXCARD] = SNDRV_DEFAULT_IDX; +static char *id[CUCKOO_MAXCARD] = SNDRV_DEFAULT_STR; +static int enable[CUCKOO_MAXCARD] = SNDRV_DEFAULT_ENABLE_PNP; + +static int +snd_cuckoo_free (cuckoo_t * chip) +{ + // TODO + return 0; +} + +static int +snd_cuckoo_dev_free (snd_device_t * device) +{ + cuckoo_t *cuckoo = (cuckoo_t *) device->device_data; + return snd_cuckoo_free (cuckoo); +} + +static int +snd_cuckoo_create (snd_card_t * card, int osscard, cuckoo_t ** rchip) +{ + cuckoo_t *chip; + int err; + + static snd_device_ops_t ops = { + .dev_free = snd_cuckoo_dev_free + }; + + *rchip = NULL; + + if ((chip = (cuckoo_t *) kmalloc (sizeof (cuckoo_t), GFP_KERNEL)) == NULL) + return -ENOMEM; + + chip->card = card; + chip->osscard = osscard; + chip->ncapture = chip->nplay = chip->npcm = 0; + + if ((err = snd_device_new (card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) + { + snd_cuckoo_free (chip); + return err; + } + + *rchip = chip; + return 0; +} + +static snd_card_t *cards[SNDRV_CARDS]; +static int ncards = 0; + +int +init_module (void) +{ + int err; + int dev, cardno; + char tmp[100]; + int pass; + +#if 0 + // TODO + if ((err = udi_connect (WRAPPER_VERSION)) < 0) + return err; + + if (strcmp (oss_checksum, cuckoo_checksum) != 0) + { + printk + ("cuckoo: Error OSS incompatibility problem. Please recompile.\n"); + return -EIO; + } +#endif + + for (pass = 0; pass < 2; pass++) + { + cardno = -1; + + for (dev = 0; dev < num_audio_engines; dev++) + { + adev_p adev = audio_engines[dev]; + cuckoo_t *chip; + snd_card_t *card = NULL; + + if (pass == 0) + { + // Ignore non-virtual devices + if (!(adev->flags & ADEV_VIRTUAL)) + continue; + } + else + { + // Ignore virtual devices + if ((adev->flags & ADEV_VIRTUAL)) + continue; + } + + if (adev->card_number < 0) + { + printk ("cuckoo: Ignored audio device %d - %s\n", dev, + adev->name); + continue; + } + + if (adev->card_number != cardno) + { + oss_card_info cd; + + cardno = adev->card_number; + + if (oss_get_cardinfo (cardno, &cd) < 0) + { + printk ("oss_get_cardinfo(%d) failed\n", cardno); + continue; + } + + // printk("Card %d: %s/%s\n", cardno, cd.shortname, cd.longname); + printk ("Card %d: %s/%s\n", cardno, cd.shortname, cd.longname); + + if (ncards >= CUCKOO_MAXCARD) + { + printk + ("Cuckoo: Too many audio devices (%d), only %d supported. by ALSA.\n", + num_audio_engines, CUCKOO_MAXCARD); + return -EIO; + } + + if (!enable[ncards]) + { + printk ("cuckoo: Device was not enabled (yet)\n"); + return -EIO; + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31) + if ((card = + snd_card_new (index[ncards], id[ncards], THIS_MODULE, + 0)) == NULL) +#else + if ( + snd_card_create (index[ncards], id[ncards], THIS_MODULE, + 0, &card) != 0) +#endif + { + printk ("cuckoo: Can't create a card instance\n"); + return -EIO; + } + + if ((err = snd_cuckoo_create (card, cardno, &chip)) < 0) + { + printk ("cuckoo: Couldn't create a chip instance (%d)\n", + err); + snd_card_free (card); + return err; + } + +#define oss_version_string "v4.x" // TODO + sprintf (tmp, "OSS %s", oss_version_string); + strlcpy (card->driver, tmp); + strlcpy (card->shortname, cd.shortname); + strlcpy (card->longname, cd.longname); + + if ((err = install_pcm_instances (chip, cardno)) < 0) + return err; + + if ((err = install_mixer_instances (chip, cardno)) < 0) + return err; + + // if ((err=install_midiport_instances(chip, cardno))<0) + // return err; + + if ((err = snd_card_register (card)) < 0) + { + printk ("cuckoo: Couldn't register card(%s) err=%d\n", + card->shortname, err); + continue; // TODO: Should handle this in more intelligent way + + snd_card_free (card); + return err; + } + + cards[ncards++] = card; + } + } + } + + return 0; +} + +void +cleanup_module (void) +{ + int i; + + for (i = 0; i < ncards; i++) + snd_card_free (cards[i]); +} + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,5)) +#undef unix +struct module __this_module + __attribute__ ((section (".gnu.linkonce.this_module"))) = +{ + .name = __stringify (KBUILD_MODNAME),.init = init_module, +#ifdef CONFIG_MODULE_UNLOAD + .exit = cleanup_module +#endif +}; +#endif diff --git a/setup/Linux/oss/cuckoo/cuckoo.h b/setup/Linux/oss/cuckoo/cuckoo.h new file mode 100644 index 0000000..3df2966 --- /dev/null +++ b/setup/Linux/oss/cuckoo/cuckoo.h @@ -0,0 +1,171 @@ +/* + * This software module makes it possible to use Open Ssund System for Linux + * (the _professional_ version) as a low level driver source for ALSA. + * + * Copyright (C) 2004-2006 Hannu Savolainen (hannu@voimakentta.net). + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ + +#define _KERNEL + +/* + * !!!!!!!!!!!!!!!!!!!! Important !!!!!!!!!!!!!!!!!! + * + * If this file doesn't compile, you must not try to resolve the problem + * without perfect understanding of internals of Linux kernel, ALSA and + * Open Sound System. + * + * Instead you need to check that you are using the version of this file + * that matches the versions of ALSA, OSS and Linux you are currently using. + */ + +#define _KERNEL +#include "../include/sys/soundcard.h" + +#include <linux/version.h> + +#define _LOOSE_KERNEL_NAMES + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18) +#include <linux/config.h> +#else +#include <linux/autoconf.h> +#endif + +#if !defined(__SMP__) && defined(CONFIG_SMP) +#define __SMP__ +#endif +#include <linux/module.h> + +#include <stdarg.h> + +extern int oss_get_cardinfo (int cardnum, oss_card_info * ci); /* from oss_config.h */ + +#include <linux/param.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/signal.h> +#include <linux/fcntl.h> +#include <linux/sched.h> +#include <linux/timer.h> +#include <linux/tty.h> +#include <linux/mm.h> +#include <linux/ctype.h> +#include <linux/delay.h> +#include <linux/vmalloc.h> +#include <asm/processor.h> +#include <asm/io.h> +#include <linux/pci.h> +#include <linux/apm_bios.h> +#include <asm/segment.h> +#include <asm/uaccess.h> +#include <linux/poll.h> + +#include <asm/system.h> +#include <asm/dma.h> +#include <linux/wait.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/ioport.h> +//#include <asm/mach-default/irq_vectors.h> +#include <linux/interrupt.h> +#include <linux/pm.h> + +struct _oss_mutex_t +{ + /* Caution! This definition must match Linux/osscore.c */ + spinlock_t lock; +}; + +#define audio_devs dummy_audio_devs + +#include "../include/internals/oss_exports.h" +#include "../build/wrap.h" +#include "../include/internals/ossddk.h" + +typedef struct oss_wait_queue oss_wait_queue_t; /* This must match oss_config.h */ + +#include "../include/internals/ossddk.h" + +//#include <sound/driver.h> +#include <sound/core.h> +#include <sound/control.h> +#include <sound/pcm.h> + +#include "../build/osscore_symbols.inc" + +#define SNDRV_GET_ID +#include <sound/initval.h> + +typedef caddr_t ioctl_arg; +typedef char snd_rw_buf; + +typedef int sound_os_info; + +#define WR_BUF_CONST const + +#include "../include/internals/audio_core.h" +#include "../include/internals/mixer_core.h" + +typedef struct _snd_cuckoo cuckoo_t, chip_t; + +typedef struct +{ + adev_p adev; +} cuckoo_pcm_t; + +#define MAX_OSSPCM 24 // Max # of PCM devices/card instance + +#if 1 +// Older ALSA versions used to define these... +typedef struct snd_card snd_card_t; +typedef struct snd_pcm snd_pcm_t; +typedef struct snd_rawmidi snd_rawmidi_t; +typedef struct snd_rawmidi_substream snd_rawmidi_substream_t; +typedef struct snd_rawmidi_ops snd_rawmidi_ops_t; +typedef struct snd_kcontrol snd_kcontrol_t; +typedef struct snd_kcontrol_new snd_kcontrol_new_t; +typedef struct snd_ctl_elem_info snd_ctl_elem_info_t; +typedef struct snd_ctl_elem_value snd_ctl_elem_value_t; +typedef struct snd_pcm_substream snd_pcm_substream_t; +typedef struct snd_pcm_hardware snd_pcm_hardware_t; +typedef struct snd_pcm_runtime snd_pcm_runtime_t; +typedef struct snd_pcm_hw_params snd_pcm_hw_params_t; +typedef struct snd_pcm_ops snd_pcm_ops_t; +typedef struct snd_device snd_device_t; +typedef struct snd_device_ops snd_device_ops_t; +#endif + +struct _snd_cuckoo +{ + snd_card_t *card; + snd_pcm_t *pcm[MAX_OSSPCM]; + adev_p play_adev[MAX_OSSPCM], capture_adev[MAX_OSSPCM]; + int osscard; + int nplay, ncapture, npcm; +}; + +#define cuckoo_t_magic 0xaabbccdd +#define chip__tmagic cuckoo_t_magic + +//#define OPEN_READ PCM_ENABLE_INPUT +//#define OPEN_WRITE PCM_ENABLE_OUTPUT + +extern int install_mixer_instances (cuckoo_t * chip, int cardno); +extern int install_midiport_instances (cuckoo_t * chip, int cardno); +extern int install_pcm_instances (cuckoo_t * chip, int cardno); + +// Disable locking for now +#define udi_spin_lock_irqsave(a, b) *(b)=0 +#define udi_spin_unlock_irqrestore(a, b) + +#define strlcpy(a, b) {strncpy(a, b, sizeof(a)-1);a[sizeof(a)-1]=0;} diff --git a/setup/Linux/oss/cuckoo/cuckoo_midi.c b/setup/Linux/oss/cuckoo/cuckoo_midi.c new file mode 100644 index 0000000..949379b --- /dev/null +++ b/setup/Linux/oss/cuckoo/cuckoo_midi.c @@ -0,0 +1,310 @@ +/* + * This software module makes it possible to use Open Sound System for Linux + * (the _professional_ version) as a low level driver source for ALSA. + * + * Copyright (C) 2004 Hannu Savolainen (hannu@voimakentta.net). + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ + +/* + * !!!!!!!!!!!!!!!!!!!! Important !!!!!!!!!!!!!!!!!! + * + * If this file doesn't compile, you must not try to resolve the problem + * without perfect understanding of internals of Linux kernel, ALSA and + * Open Sound System. + * + * Instead you need to check that you are using the version of this file + * that matches the versions of ALSA, OSS and Linux you are currently using. + */ + +#include "cuckoo.h" +#include <sound/rawmidi.h> +#include <midi_core.h> + +static snd_rawmidi_t *rmidis[256] = { NULL }; + +static int +cuckoo_uart_input_open (snd_rawmidi_substream_t * substream) +{ +#if 0 + mpu401_t *mpu; + int err; + + mpu = + snd_magic_cast (mpu401_t, substream->rmidi->private_data, return -ENXIO); + if (mpu->open_input && (err = mpu->open_input (mpu)) < 0) + return err; + if (!test_bit (MPU401_MODE_BIT_OUTPUT, &mpu->mode)) + { + cuckoo_uart_cmd (mpu, MPU401_RESET, 1); + cuckoo_uart_cmd (mpu, MPU401_ENTER_UART, 1); + } + mpu->substream_input = substream; + atomic_set (&mpu->rx_loop, 1); + set_bit (MPU401_MODE_BIT_INPUT, &mpu->mode); +#endif + return 0; +} + +static int +cuckoo_uart_output_open (snd_rawmidi_substream_t * substream) +{ + int dev; + + dev = (int) substream->rmidi->private_data; + + printk ("Output open %d\n", dev); + + return -EIO; +#if 0 + mpu401_t *mpu; + int err; + if (mpu->open_output && (err = mpu->open_output (mpu)) < 0) + return err; + if (!test_bit (MPU401_MODE_BIT_INPUT, &mpu->mode)) + { + cuckoo_uart_cmd (mpu, MPU401_RESET, 1); + cuckoo_uart_cmd (mpu, MPU401_ENTER_UART, 1); + } + mpu->substream_output = substream; + atomic_set (&mpu->tx_loop, 1); + set_bit (MPU401_MODE_BIT_OUTPUT, &mpu->mode); +#endif + return 0; +} + +static int +cuckoo_uart_input_close (snd_rawmidi_substream_t * substream) +{ +#if 0 + mpu401_t *mpu; + + mpu = + snd_magic_cast (mpu401_t, substream->rmidi->private_data, return -ENXIO); + clear_bit (MPU401_MODE_BIT_INPUT, &mpu->mode); + mpu->substream_input = NULL; + if (!test_bit (MPU401_MODE_BIT_OUTPUT, &mpu->mode)) + cuckoo_uart_cmd (mpu, MPU401_RESET, 0); + if (mpu->close_input) + mpu->close_input (mpu); +#endif + return 0; +} + +static int +cuckoo_uart_output_close (snd_rawmidi_substream_t * substream) +{ +#if 0 + mpu401_t *mpu; + + mpu = + snd_magic_cast (mpu401_t, substream->rmidi->private_data, return -ENXIO); + clear_bit (MPU401_MODE_BIT_OUTPUT, &mpu->mode); + mpu->substream_output = NULL; + if (!test_bit (MPU401_MODE_BIT_INPUT, &mpu->mode)) + cuckoo_uart_cmd (mpu, MPU401_RESET, 0); + if (mpu->close_output) + mpu->close_output (mpu); +#endif + return 0; +} + +static void +cuckoo_uart_input_trigger (snd_rawmidi_substream_t * substream, int up) +{ +#if 0 + unsigned long flags; + mpu401_t *mpu; + int max = 64; + + mpu = snd_magic_cast (mpu401_t, substream->rmidi->private_data, return); + if (up) + { + if (!test_and_set_bit (MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode)) + { + /* first time - flush FIFO */ + while (max-- > 0) + mpu->read (mpu, MPU401D (mpu)); + if (mpu->irq < 0) + cuckoo_uart_add_timer (mpu, 1); + } + + /* read data in advance */ + /* prevent double enter via rawmidi->event callback */ + if (atomic_dec_and_test (&mpu->rx_loop)) + { + local_irq_save (flags); + if (spin_trylock (&mpu->input_lock)) + { + cuckoo_uart_input_read (mpu); + spin_unlock (&mpu->input_lock); + } + local_irq_restore (flags); + } + atomic_inc (&mpu->rx_loop); + } + else + { + if (mpu->irq < 0) + cuckoo_uart_remove_timer (mpu, 1); + clear_bit (MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode); + } +#endif +} + +#if 0 +static void +cuckoo_uart_input_read (void *mpu) +{ + int max = 128; + unsigned char byte; + + while (max-- > 0) + { + if (cuckoo_input_avail (mpu)) + { + byte = mpu->read (mpu, MPU401D (mpu)); + if (test_bit (MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode)) + snd_rawmidi_receive (mpu->substream_input, &byte, 1); + } + else + { + break; /* input not available */ + } + } +} +#endif + +#if 0 +static void +cuckoo_uart_output_write (void *mpu) +{ + unsigned char byte; + int max = 256, timeout; + + do + { + if (snd_rawmidi_transmit_peek (mpu->substream_output, &byte, 1) == 1) + { + for (timeout = 100; timeout > 0; timeout--) + { + if (cuckoo_output_ready (mpu)) + { + mpu->write (mpu, byte, MPU401D (mpu)); + snd_rawmidi_transmit_ack (mpu->substream_output, 1); + break; + } + } + if (timeout == 0) + break; /* Tx FIFO full - try again later */ + } + else + { + cuckoo_uart_remove_timer (mpu, 0); + break; /* no other data - leave the tx loop */ + } + } + while (--max > 0); +} +#endif + +static void +cuckoo_uart_output_trigger (snd_rawmidi_substream_t * substream, int up) +{ + int dev; + + dev = (int) substream->rmidi->private_data; + printk ("Output trigger %d\n", dev); +#if 0 + if (up) + { + set_bit (MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode); + + /* try to add the timer at each output trigger, + * since the output timer might have been removed in + * cuckoo_uart_output_write(). + */ + cuckoo_uart_add_timer (mpu, 0); + + /* output pending data */ + /* prevent double enter via rawmidi->event callback */ + if (atomic_dec_and_test (&mpu->tx_loop)) + { + local_irq_save (flags); + if (spin_trylock (&mpu->output_lock)) + { + cuckoo_uart_output_write (mpu); + spin_unlock (&mpu->output_lock); + } + local_irq_restore (flags); + } + atomic_inc (&mpu->tx_loop); + } + else + { + cuckoo_uart_remove_timer (mpu, 0); + clear_bit (MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode); + } +#endif +} + +static snd_rawmidi_ops_t cuckoo_uart_output = { + .open = cuckoo_uart_output_open, + .close = cuckoo_uart_output_close, + .trigger = cuckoo_uart_output_trigger, +}; + +static snd_rawmidi_ops_t cuckoo_uart_input = { + .open = cuckoo_uart_input_open, + .close = cuckoo_uart_input_close, + .trigger = cuckoo_uart_input_trigger, +}; + +extern mididev_p *midi_devs; + +int +install_midiport_instances (cuckoo_t * chip, int cardno) +{ + int dev, devix = 0; + + for (dev = 0; dev < num_mididevs; dev++) + if (midi_devs[dev]->card_number == cardno) + { + mididev_p mididev = midi_devs[dev]; + snd_rawmidi_t *rmidi; + int err; + +//printk("Midi device %s\n", mididev->info.name); + + if ((err = snd_rawmidi_new (chip->card, mididev->name, devix, + 1, 1, &rmidi)) < 0) + { + printk ("cuckoo: Failed to register rawmidi device, err=%d\n", + err); + return 0; + } + + rmidi->private_data = (void *) dev; + strcpy (rmidi->name, mididev->name); + rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | + SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; + snd_rawmidi_set_ops (rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, + &cuckoo_uart_output); + snd_rawmidi_set_ops (rmidi, SNDRV_RAWMIDI_STREAM_INPUT, + &cuckoo_uart_input); + + devix++; + rmidis[dev] = rmidi; + } // dev + + return 0; +} diff --git a/setup/Linux/oss/cuckoo/cuckoo_mixer.c b/setup/Linux/oss/cuckoo/cuckoo_mixer.c new file mode 100644 index 0000000..6d2bb6d --- /dev/null +++ b/setup/Linux/oss/cuckoo/cuckoo_mixer.c @@ -0,0 +1,389 @@ +/* + * This software module makes it possible to use Open Sound System for Linux + * (the _professional_ version) as a low level driver source for ALSA. + * + * Copyright (C) 2004 Hannu Savolainen (hannu@voimakentta.net). + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ + +/* + * !!!!!!!!!!!!!!!!!!!! Important !!!!!!!!!!!!!!!!!! + * + * If this file doesn't compile, you must not try to resolve the problem + * without perfect understanding of internals of Linux kernel, ALSA and + * Open Sound System. + * + * Instead you need to check that you are using the version of this file + * that matches the versions of ALSA, OSS and Linux you are currently using. + */ + +#include "cuckoo.h" + +MODULE_AUTHOR ("Hannu Savolainen <hannu@opensound.com>"); +MODULE_LICENSE ("GPL v2"); +MODULE_DESCRIPTION ("OSS mixer low level driver interface for ALSA"); + +typedef struct +{ + char *name, *data; +} enum_entry_t; + +#if 0 +static void +downshift (char *s) +{ + while (*s) + { + if (*s >= 'A' && *s <= 'Z') + *s += 32; + s++; + } +} +#endif + +static int +get_mixer_info (snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo) +{ + oss_mixext ext; + int dev, ix; + + dev = ext.dev = kcontrol->private_value >> 16; + ix = ext.ctrl = kcontrol->private_value & 0xffff;; + + oss_mixer_ext (dev, OSS_DEV_MIXER, SNDCTL_MIX_EXTINFO, (caddr_t) & ext); + + switch (ext.type) + { + case MIXT_STEREOSLIDER: + case MIXT_STEREOVU: + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = ext.minvalue; + uinfo->value.integer.max = ext.maxvalue; + break; + + case MIXT_MONOSLIDER: + case MIXT_MONOVU: + case MIXT_SLIDER: + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = ext.minvalue; + uinfo->value.integer.max = ext.maxvalue; + break; + + case MIXT_ONOFF: + case MIXT_MUTE: + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + break; + + case MIXT_ENUM: + { + static const char *texts[] = { + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", + "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", + "30", "31", "32" + }; + oss_mixer_enuminfo enumdef; + uinfo->value.enumerated.items = ext.maxvalue; + + if (uinfo->value.enumerated.item < 0) + uinfo->value.enumerated.item = 0; + if (uinfo->value.enumerated.item >= ext.maxvalue) + uinfo->value.enumerated.item = ext.maxvalue - 1; + if (uinfo->value.enumerated.item > 31) + uinfo->value.enumerated.item = 31; + strcpy (uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + + enumdef.dev = ext.dev; + enumdef.ctrl = ext.ctrl; + if (oss_mixer_ext + (dev, OSS_DEV_MIXER, SNDCTL_MIX_ENUMINFO, + (caddr_t) & enumdef) >= 0) + { + char *text; + + text = + &enumdef.strings[enumdef. + strindex[uinfo->value.enumerated.item]]; + strcpy (uinfo->value.enumerated.name, text); + } + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = ext.maxvalue; + } + break; + + default: + printk ("cuckoo: mixer_info(%d/%d) - unknown type %d\n", dev, ix, + ext.type); + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = ext.minvalue; + uinfo->value.integer.max = ext.maxvalue; + return 0; + } + + return 0; +} + +static int +mixer_get (snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + oss_mixext ext; + oss_mixer_value val; + int dev, ix, err; + + dev = ext.dev = kcontrol->private_value >> 16; + ix = ext.ctrl = kcontrol->private_value & 0xffff;; + if ((err = + oss_mixer_ext (dev, OSS_DEV_MIXER, SNDCTL_MIX_EXTINFO, + (caddr_t) & ext)) < 0) + return err; + + val.dev = dev; + val.ctrl = ix; + val.timestamp = ext.timestamp; + if ((err = + oss_mixer_ext (dev, OSS_DEV_MIXER, SNDCTL_MIX_READ, + (caddr_t) & val)) < 0) + return err; + + switch (ext.type) + { + case MIXT_STEREOVU: + case MIXT_STEREOSLIDER: + ucontrol->value.integer.value[0] = val.value & 0xff; // Left + ucontrol->value.integer.value[1] = (val.value >> 8) & 0xff; // Right + break; + + case MIXT_MONOSLIDER: + case MIXT_MONOVU: + case MIXT_SLIDER: + ucontrol->value.integer.value[0] = val.value & 0xff; + break; + + case MIXT_ONOFF: + case MIXT_MUTE: + ucontrol->value.integer.value[0] = !!val.value; + break; + + case MIXT_ENUM: + ucontrol->value.integer.value[0] = val.value; + break; + + default: + printk ("cuckoo: mixer_get(%d/%d) - unknown type %d\n", dev, ix, + ext.type); + ucontrol->value.integer.value[0] = val.value & 0xff; + return 0; + } + + return 0; +} + +static int +mixer_put (snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + oss_mixext ext; + oss_mixer_value val; + int dev, ix, err; + + dev = ext.dev = kcontrol->private_value >> 16; + ix = ext.ctrl = kcontrol->private_value & 0xffff;; + if ((err = + oss_mixer_ext (dev, OSS_DEV_MIXER, SNDCTL_MIX_EXTINFO, + (caddr_t) & ext)) < 0) + return err; + + val.dev = dev; + val.ctrl = ix; + val.timestamp = ext.timestamp; + + switch (ext.type) + { + case MIXT_STEREOSLIDER: + val.value = ucontrol->value.integer.value[0] | // Left + ucontrol->value.integer.value[1] << 8; // Right + if ((err = + oss_mixer_ext (dev, OSS_DEV_MIXER, SNDCTL_MIX_WRITE, + (caddr_t) & val)) < 0) + return err; + break; + + case MIXT_MONOSLIDER: + case MIXT_SLIDER: + val.value = ucontrol->value.integer.value[0]; + if ((err = + oss_mixer_ext (dev, OSS_DEV_MIXER, SNDCTL_MIX_WRITE, + (caddr_t) & val)) < 0) + return err; + break; + + case MIXT_ONOFF: + case MIXT_MUTE: + val.value = !!ucontrol->value.integer.value[0]; + if ((err = + oss_mixer_ext (dev, OSS_DEV_MIXER, SNDCTL_MIX_WRITE, + (caddr_t) & val)) < 0) + return err; + break; + + case MIXT_ENUM: + val.value = ucontrol->value.integer.value[0]; + if ((err = + oss_mixer_ext (dev, OSS_DEV_MIXER, SNDCTL_MIX_WRITE, + (caddr_t) & val)) < 0) + return err; + break; + + case MIXT_MONOVU: + case MIXT_STEREOVU: + return -EPERM; + + default: + printk ("cuckoo: mixer_put(%d/%d) - unknown type %d\n", dev, ix, + ext.type); + val.value = ucontrol->value.integer.value[0]; + if ((err = + oss_mixer_ext (dev, OSS_DEV_MIXER, SNDCTL_MIX_WRITE, + (caddr_t) & val)) < 0) + return err; + } + + return 0; +} + +static void +add_control (cuckoo_t * chip, int dev, int ix, oss_mixext * ext, char *name) +{ + int i, ok, err = 0; + snd_kcontrol_new_t my_control; + +// Upshift the name if it's an single part one + + ok = 0; + for (i = 0; i < strlen (name); i++) + if (name[i] == '.') + ok = 1; + if (!ok) + for (i = 0; i < strlen (name); i++) + if (name[i] >= 'a' && name[i] <= 'z') + name[i] -= 32; + +// Add the control + + memset (&my_control, 0, sizeof (my_control)); + + my_control.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + my_control.name = name; + my_control.index = 0; + my_control.access = 0; + + if (ext->flags & MIXF_READABLE) + my_control.access |= SNDRV_CTL_ELEM_ACCESS_READ; + if (ext->flags & MIXF_WRITEABLE) + my_control.access |= SNDRV_CTL_ELEM_ACCESS_WRITE; + if ((ext->flags & 0x3) == MIXF_READABLE) /* Read only */ + my_control.access |= SNDRV_CTL_ELEM_ACCESS_VOLATILE; + + my_control.private_value = (dev << 16) | ix; + my_control.info = get_mixer_info; + my_control.get = mixer_get; + my_control.put = mixer_put; + + switch (ext->type) + { + case MIXT_ENUM: + case MIXT_ONOFF: + case MIXT_MUTE: + case MIXT_STEREOSLIDER: + case MIXT_SLIDER: + case MIXT_MONOSLIDER: + case MIXT_MONOVU: + case MIXT_STEREOVU: + if ((err = + snd_ctl_add (chip->card, snd_ctl_new1 (&my_control, chip))) < 0) + { + printk ("cuckoo: snd_ctl_add(%s) failed, err=%d\n", ext->extname, + err); + return; + } + break; + } +} + +int +install_mixer_instances (cuckoo_t * chip, int cardno) +{ + int dev; + mixer_operations_t **cuckoo_mixer_devs = mixer_devs_p; + + for (dev = 0; dev < num_mixers; dev++) + if (cuckoo_mixer_devs[dev]->card_number == cardno) + { + int nrext, i, sz; + + touch_mixer (dev); + + nrext = dev; + oss_mixer_ext (dev, OSS_DEV_MIXER, SNDCTL_MIX_NREXT, + (ioctl_arg) & nrext); + + if (nrext == 0) + continue; + + sz = nrext * (sizeof (char *) + 32); // 32 characters / name (average) + + for (i = 0; i < nrext; i++) + { + oss_mixext ext; + int parent = 0; + oss_mixext_root *root = NULL; + + ext.dev = dev; + ext.ctrl = i; + oss_mixer_ext (dev, OSS_DEV_MIXER, SNDCTL_MIX_EXTINFO, + (caddr_t) & ext); + + switch (ext.type) + { + case MIXT_DEVROOT: + root = (oss_mixext_root *) & ext.data; + break; + + case MIXT_GROUP: + parent = ext.parent; + break; + + case MIXT_MARKER: + break; + + default: + add_control (chip, dev, i, &ext, ext.extname); + break; + } // Switch + + } // i + + + } // dev + + return 0; +} + +EXPORT_SYMBOL (install_mixer_instances); diff --git a/setup/Linux/oss/cuckoo/cuckoo_pcm.c b/setup/Linux/oss/cuckoo/cuckoo_pcm.c new file mode 100644 index 0000000..2ae08b5 --- /dev/null +++ b/setup/Linux/oss/cuckoo/cuckoo_pcm.c @@ -0,0 +1,810 @@ +/* + * This software module makes it possible to use Open Sound System for Linux + * (the _professional_ version) as a low level driver source for ALSA. + * + * Copyright (C) 2004 Hannu Savolainen (hannu@voimakentta.net). + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ + +/* + * !!!!!!!!!!!!!!!!!!!! Important !!!!!!!!!!!!!!!!!! + * + * If this file doesn't compile, you must not try to resolve the problem + * without perfect understanding of internals of Linux kernel, ALSA and + * Open Sound System. + * + * Instead you need to check that you are using the version of this file + * that matches the versions of ALSA, OSS and Linux you are currently using. + */ + +#include "cuckoo.h" + +MODULE_AUTHOR ("Hannu Savolainen <hannu@opensound.com>"); +MODULE_LICENSE ("GPL v2"); +MODULE_DESCRIPTION ("OSS PCM low level driver interface for ALSA"); + +static snd_pcm_substream_t *cuckoo_playsubstream[256] = { NULL }; +static snd_pcm_substream_t *cuckoo_capturesubstream[256] = { NULL }; + +static snd_pcm_hardware_t snd_cuckoo_playback = { + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START), + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, + .rate_min = 4000, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = (64 * 1024), + .period_bytes_min = 64, + .period_bytes_max = (32 * 1024), + .periods_min = 2, + .periods_max = 1024, + .fifo_size = 0, +}; + +static snd_pcm_hardware_t snd_cuckoo_capture = { + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START), + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, + .rate_min = 4000, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = (128 * 1024), + .period_bytes_min = 64, + .period_bytes_max = (64 * 1024), + .periods_min = 2, + .periods_max = 1024, + .fifo_size = 0, +}; + +static void +cuckoo_outputintr (int dev, int notify_only) +{ + snd_pcm_substream_t *substream; + adev_t *adev; + dmap_t *dmap; + oss_native_word flags; + + if (dev < 0 || dev > 255) + return; + + adev = audio_devfiles[dev]; + dmap = adev->dmap_out; + + dmap->fragment_counter = (dmap->fragment_counter + 1) % dmap->nfrags; + + substream = cuckoo_playsubstream[dev]; + if (substream == NULL) + return; + + udi_spin_lock_irqsave (&adev->mutex, &flags); + snd_pcm_period_elapsed (substream); + udi_spin_unlock_irqrestore (&adev->mutex, flags); +} + +static void +cuckoo_inputintr (int dev, int intr_flags) +{ + snd_pcm_substream_t *substream; + adev_t *adev; + dmap_t *dmap; + oss_native_word flags; + + if (dev < 0 || dev > 255) + return; + + adev = audio_devfiles[dev]; + dmap = adev->dmap_in; + + dmap->fragment_counter = (dmap->fragment_counter + 1) % dmap->nfrags; + + substream = cuckoo_capturesubstream[dev]; + if (substream == NULL) + return; + + udi_spin_lock_irqsave (&adev->mutex, &flags); + snd_pcm_period_elapsed (substream); + udi_spin_unlock_irqrestore (&adev->mutex, flags); +} + +static void +copy_hw_caps (snd_pcm_runtime_t * runtime, adev_t * adev, int dir) +{ + u64 fmts = 0; + int i; + unsigned int fmtmask; + + if (dir == OPEN_WRITE) + { + fmtmask = adev->oformat_mask; + } + else + { + fmtmask = adev->iformat_mask; + } + + for (i = 0; i < 32; i++) + switch (fmtmask & (1 << i)) + { + case AFMT_MU_LAW: + fmts |= SNDRV_PCM_FMTBIT_MU_LAW; + break; + case AFMT_A_LAW: + fmts |= SNDRV_PCM_FMTBIT_A_LAW; + break; + case AFMT_IMA_ADPCM: + fmts |= SNDRV_PCM_FMTBIT_IMA_ADPCM; + break; + case AFMT_U8: + fmts |= SNDRV_PCM_FMTBIT_U8; + break; + case AFMT_S8: + fmts |= SNDRV_PCM_FMTBIT_S8; + break; + case AFMT_S16_LE: + fmts |= SNDRV_PCM_FMTBIT_S16_LE; + break; + case AFMT_S16_BE: + fmts |= SNDRV_PCM_FMTBIT_S16_BE; + break; + case AFMT_S24_LE: + fmts |= SNDRV_PCM_FMTBIT_S24_LE; + break; + case AFMT_S24_BE: + fmts |= SNDRV_PCM_FMTBIT_S24_BE; + break; + case AFMT_S32_LE: + fmts |= SNDRV_PCM_FMTBIT_S32_LE; + break; + case AFMT_S32_BE: + fmts |= SNDRV_PCM_FMTBIT_S32_BE; + break; + case AFMT_MPEG: + fmts |= SNDRV_PCM_FMTBIT_MPEG; + break; + case AFMT_FLOAT: + fmts |= SNDRV_PCM_FMTBIT_FLOAT_LE; + break; + case AFMT_SPDIF_RAW: + fmts |= SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE; + break; + } + + runtime->hw.formats = fmts; + + if (adev->min_block > 0) + runtime->hw.period_bytes_min = adev->min_block; + if (adev->max_block > 0) + runtime->hw.period_bytes_max = adev->max_block; + + if (adev->flags & ADEV_NOMMAP) + runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID); + + if (adev->max_rate > adev->min_rate) + { + runtime->hw.rate_min = adev->min_rate; + runtime->hw.rate_max = adev->max_rate; + } + + if (!(adev->caps & DSP_CAP_FREERATE)) + runtime->hw.rates &= + ~(SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000); +} + +static int +snd_cuckoo_playback_open (snd_pcm_substream_t * substream) +{ + cuckoo_t *chip = snd_pcm_substream_chip (substream); + snd_pcm_runtime_t *runtime = substream->runtime; + int snum = substream->number; + int err; + adev_t *adev; + oss_native_word flags; + struct fileinfo tmp_finfo; + + if (snum < 0 || snum >= chip->npcm) + { + printk ("cuckoo: Playback open - bad substream index %d\n", snum); + return -EIO; + } + + adev = chip->play_adev[snum]; + printk ("cuckoo_playback_open(%d=%s)\n", adev->engine_num, adev->name); + + cuckoo_playsubstream[adev->engine_num] = substream; + + if (adev->dmap_out == NULL || adev->dmap_out->dmabuf == NULL) + { + printk ("cuckoo: dev %d - no buffer available\n", adev->engine_num); + return -ENOMEM; + } + + if (adev->open_mode != 0) + { + udi_spin_unlock_irqrestore (&adev->mutex, flags); + return -EBUSY; + } + + tmp_finfo.mode = OPEN_WRITE; + tmp_finfo.acc_flags = 0; + if ((err = + oss_audio_open_engine (adev->engine_num, OSS_DEV_DSP, + &tmp_finfo, 1, OF_SMALLBUF, + NULL)) < 0) + { + return err; + } + + udi_spin_lock_irqsave (&adev->mutex, &flags); + adev->open_mode = OPEN_WRITE; + runtime->hw = snd_cuckoo_playback; + copy_hw_caps (runtime, adev, OPEN_WRITE); + snd_pcm_set_sync (substream); + adev->pid = current->pid; + strncpy (adev->cmd, current->comm, sizeof (adev->cmd) - 1); + adev->cmd[sizeof (adev->cmd) - 1] = 0; + adev->outputintr = cuckoo_outputintr; + udi_spin_unlock_irqrestore (&adev->mutex, flags); + + return 0; +} + +static int +snd_cuckoo_capture_open (snd_pcm_substream_t * substream) +{ + cuckoo_t *chip = snd_pcm_substream_chip (substream); + snd_pcm_runtime_t *runtime = substream->runtime; + int snum = substream->number; + int err; + adev_t *adev; + oss_native_word flags; + struct fileinfo tmp_finfo; + + if (snum < 0 || snum >= chip->npcm) + { + printk ("cuckoo: Capture open - bad substream index %d\n", snum); + return -EIO; + } + + adev = chip->capture_adev[snum]; + + cuckoo_capturesubstream[adev->engine_num] = substream; + + if (adev->dmap_in == NULL || adev->dmap_in->dmabuf == NULL) + { + printk ("cuckoo: dev %d - no buffer available\n", adev->engine_num); + return -ENOMEM; + } + + if (adev->open_mode != 0) + { + udi_spin_unlock_irqrestore (&adev->mutex, flags); + return -EBUSY; + } + + tmp_finfo.mode = OPEN_READ; + tmp_finfo.acc_flags = 0; + if ((err = + oss_audio_open_engine (adev->engine_num, OSS_DEV_DSP, + &tmp_finfo, 1, OF_SMALLBUF, + NULL)) < 0) + { + return err; + } + + udi_spin_lock_irqsave (&adev->mutex, &flags); + adev->open_mode = OPEN_READ; + runtime->hw = snd_cuckoo_capture; + copy_hw_caps (runtime, adev, OPEN_READ); + snd_pcm_set_sync (substream); + adev->pid = current->pid; + strncpy (adev->cmd, current->comm, sizeof (adev->cmd) - 1); + adev->cmd[sizeof (adev->cmd) - 1] = 0; + adev->inputintr = cuckoo_inputintr; + udi_spin_unlock_irqrestore (&adev->mutex, flags); + + return 0; +} + +static int +snd_cuckoo_playback_close (snd_pcm_substream_t * substream) +{ + cuckoo_t *chip = snd_pcm_substream_chip (substream); + int snum = substream->number; + adev_t *adev; + oss_native_word flags; + struct fileinfo tmp_finfo; + + if (snum < 0 || snum >= chip->npcm) + return -ENXIO; + + adev = chip->play_adev[snum]; + + udi_spin_lock_irqsave (&adev->mutex, &flags); + cuckoo_playsubstream[adev->engine_num] = NULL; + udi_spin_unlock_irqrestore (&adev->mutex, flags); + + tmp_finfo.mode = OPEN_WRITE; + tmp_finfo.acc_flags = 0; + oss_audio_release (adev->engine_num, &tmp_finfo); + + return 0; +} + +static int +snd_cuckoo_capture_close (snd_pcm_substream_t * substream) +{ + cuckoo_t *chip = snd_pcm_substream_chip (substream); + int snum = substream->number; + adev_t *adev; + oss_native_word flags; + struct fileinfo tmp_finfo; + + if (snum < 0 || snum >= chip->npcm) + return -ENXIO; + + adev = chip->capture_adev[snum]; + + udi_spin_lock_irqsave (&adev->mutex, &flags); + cuckoo_capturesubstream[adev->engine_num] = NULL; + udi_spin_unlock_irqrestore (&adev->mutex, flags); + + tmp_finfo.mode = OPEN_READ; + tmp_finfo.acc_flags = 0; + oss_audio_release (adev->engine_num, &tmp_finfo); + + return 0; +} + +static int +snd_cuckoo_playback_hw_params (snd_pcm_substream_t * substream, + snd_pcm_hw_params_t * hw_params) +{ + cuckoo_t *chip = snd_pcm_substream_chip (substream); + snd_pcm_runtime_t *runtime = substream->runtime; + int snum = substream->number; + adev_t *adev; + dmap_t *dmap; + + if (snum < 0 || snum >= chip->npcm) + return -ENXIO; + + adev = chip->play_adev[snum]; + dmap = adev->dmap_out; + + if (dmap->dmabuf == NULL) + return -ENOMEM; + + runtime->dma_area = dmap->dmabuf; + runtime->dma_addr = dmap->dmabuf_phys; + runtime->dma_bytes = dmap->buffsize; + memset (dmap->dmabuf, 0, dmap->buffsize); + + return 0; +} + +static int +snd_cuckoo_capture_hw_params (snd_pcm_substream_t * substream, + snd_pcm_hw_params_t * hw_params) +{ + cuckoo_t *chip = snd_pcm_substream_chip (substream); + snd_pcm_runtime_t *runtime = substream->runtime; + int snum = substream->number; + adev_t *adev; + dmap_t *dmap; + + if (snum < 0 || snum >= chip->npcm) + return -ENXIO; + + adev = chip->capture_adev[snum]; + dmap = adev->dmap_in; + + if (dmap->dmabuf == NULL) + return -ENOMEM; + + runtime->dma_area = dmap->dmabuf; + runtime->dma_addr = dmap->dmabuf_phys; + runtime->dma_bytes = dmap->buffsize; + memset (dmap->dmabuf, 0, dmap->buffsize); + + return 0; +} + +static int +snd_cuckoo_hw_free (snd_pcm_substream_t * substream) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + + runtime->dma_area = NULL; + runtime->dma_addr = 0; + runtime->dma_bytes = 0; + + return 0; +} + +static int +snd_cuckoo_playback_prepare (snd_pcm_substream_t * substream) +{ + cuckoo_t *chip = snd_pcm_substream_chip (substream); + snd_pcm_runtime_t *runtime = substream->runtime; + int snum = substream->number, err; + adev_t *adev; + oss_native_word flags; + dmap_t *dmap; + + if (snum < 0 || snum >= chip->npcm) + return -ENXIO; + + adev = chip->play_adev[snum]; + dmap = adev->dmap_out; + + udi_spin_lock_irqsave (&adev->mutex, &flags); + + adev->d->adrv_set_format (adev->engine_num, + snd_pcm_format_width (runtime->format)); + runtime->channels = + adev->d->adrv_set_channels (adev->engine_num, runtime->channels); + runtime->rate = adev->d->adrv_set_rate (adev->engine_num, runtime->rate); + adev->user_parms.rate = adev->user_parms.rate = runtime->rate; + + dmap->bytes_in_use = snd_pcm_lib_buffer_bytes (substream); + dmap->fragment_size = snd_pcm_lib_period_bytes (substream); + +#if 1 + { + int f, s;; + + f = dmap->fragment_size / 4; + if (f < 128) + f = dmap->fragment_size / 2; + if (f < 128) + f = dmap->fragment_size; + + s = dmap->bytes_in_use; + while (s > f) + s /= 2; + + dmap->fragment_size = s; + } +#endif + + if (adev->max_block > 0 && dmap->fragment_size > adev->max_block) + dmap->fragment_size = adev->max_block; + if (adev->min_block > 0 && dmap->fragment_size < adev->min_block) + dmap->fragment_size = adev->min_block; + if (dmap->fragment_size < 8) + dmap->fragment_size = 8; + dmap->nfrags = dmap->bytes_in_use / dmap->fragment_size; + + err = + adev->d->adrv_prepare_for_output (adev->engine_num, dmap->fragment_size, + dmap->nfrags); + cuckoo_playsubstream[adev->engine_num] = substream; + udi_spin_unlock_irqrestore (&adev->mutex, flags); + return err; +} + +static int +snd_cuckoo_capture_prepare (snd_pcm_substream_t * substream) +{ + cuckoo_t *chip = snd_pcm_substream_chip (substream); + snd_pcm_runtime_t *runtime = substream->runtime; + int snum = substream->number, err; + adev_t *adev; + oss_native_word flags; + dmap_t *dmap; + + if (snum < 0 || snum >= chip->npcm) + return -ENXIO; + + adev = chip->capture_adev[snum]; + dmap = adev->dmap_in; + + udi_spin_lock_irqsave (&adev->mutex, &flags); + + adev->d->adrv_set_format (adev->engine_num, + snd_pcm_format_width (runtime->format)); + adev->d->adrv_set_channels (adev->engine_num, runtime->channels); + adev->d->adrv_set_rate (adev->engine_num, runtime->rate); + + dmap->bytes_in_use = snd_pcm_lib_buffer_bytes (substream); + dmap->fragment_size = snd_pcm_lib_period_bytes (substream); + +#if 1 + { + int f, s;; + + f = dmap->fragment_size / 4; + if (f < 128) + f = dmap->fragment_size / 2; + if (f < 128) + f = dmap->fragment_size; + + s = dmap->bytes_in_use; + while (s > f) + s /= 2; + + dmap->fragment_size = s; + } +#endif + + if (adev->max_block > 0 && dmap->fragment_size > adev->max_block) + dmap->fragment_size = adev->max_block; + if (adev->min_block > 0 && dmap->fragment_size < adev->min_block) + dmap->fragment_size = adev->min_block; + if (dmap->fragment_size < 8) + dmap->fragment_size = 8; + dmap->nfrags = dmap->bytes_in_use / dmap->fragment_size; + + err = + adev->d->adrv_prepare_for_input (adev->engine_num, dmap->fragment_size, + dmap->nfrags); + cuckoo_capturesubstream[adev->engine_num] = substream; + udi_spin_unlock_irqrestore (&adev->mutex, flags); + return err; +} + +static int +snd_cuckoo_playback_trigger (snd_pcm_substream_t * substream, int cmd) +{ + cuckoo_t *chip = snd_pcm_substream_chip (substream); + //snd_pcm_runtime_t *runtime = substream->runtime; + int snum = substream->number; + adev_t *adev; + oss_native_word flags; + dmap_t *dmap; + int err = 0; + + if (snum < 0 || snum >= chip->npcm) + return -ENXIO; + + adev = chip->play_adev[snum]; + dmap = adev->dmap_out; + + udi_spin_lock_irqsave (&adev->mutex, &flags); + + switch (cmd) + { + case SNDRV_PCM_TRIGGER_START: + adev->d->adrv_output_block (adev->engine_num, dmap->dmabuf_phys, + dmap->bytes_in_use, dmap->fragment_size, 0); + adev->d->adrv_trigger (adev->engine_num, PCM_ENABLE_OUTPUT); + break; + + case SNDRV_PCM_TRIGGER_STOP: + adev->d->adrv_trigger (adev->engine_num, 0); + break; + + default: + printk ("cuckoo: Bad trigger cmd %x\n", cmd); + err = -EIO; + goto fail; + } + +fail: + udi_spin_unlock_irqrestore (&adev->mutex, flags); + return err; +} + +static int +snd_cuckoo_capture_trigger (snd_pcm_substream_t * substream, int cmd) +{ + cuckoo_t *chip = snd_pcm_substream_chip (substream); + //snd_pcm_runtime_t *runtime = substream->runtime; + int snum = substream->number; + adev_t *adev; + oss_native_word flags; + dmap_t *dmap; + int err = 0; + + if (snum < 0 || snum >= chip->npcm) + return -ENXIO; + + adev = chip->capture_adev[snum]; + dmap = adev->dmap_in; + + udi_spin_lock_irqsave (&adev->mutex, &flags); + + switch (cmd) + { + case SNDRV_PCM_TRIGGER_START: + adev->d->adrv_start_input (adev->engine_num, dmap->dmabuf_phys, + dmap->bytes_in_use, dmap->fragment_size, 0); + adev->d->adrv_trigger (adev->engine_num, PCM_ENABLE_INPUT); + break; + + case SNDRV_PCM_TRIGGER_STOP: + adev->d->adrv_trigger (adev->engine_num, 0); + break; + + default: + printk ("cuckoo: Bad trigger cmd %x\n", cmd); + err = -EIO; + goto fail; + } + +fail: + udi_spin_unlock_irqrestore (&adev->mutex, flags); + return err; +} + +static snd_pcm_uframes_t +snd_cuckoo_playback_pointer (snd_pcm_substream_t * substream) +{ + cuckoo_t *chip = snd_pcm_substream_chip (substream); + //snd_pcm_runtime_t *runtime = substream->runtime; + int snum = substream->number; + adev_t *adev; + dmap_t *dmap; + int pos; + + if (snum < 0 || snum >= chip->npcm) + return -ENXIO; + + adev = chip->play_adev[snum]; + dmap = adev->dmap_out; + + if (adev->d->adrv_get_output_pointer != NULL) + pos = + adev->d->adrv_get_output_pointer (adev->engine_num, dmap, PCM_ENABLE_OUTPUT); + else + { + pos = dmap->fragment_counter * dmap->fragment_size; + } + pos = bytes_to_frames (substream->runtime, pos); + + return pos; +} + +static snd_pcm_uframes_t +snd_cuckoo_capture_pointer (snd_pcm_substream_t * substream) +{ + cuckoo_t *chip = snd_pcm_substream_chip (substream); + //snd_pcm_runtime_t *runtime = substream->runtime; + int snum = substream->number; + adev_t *adev; + dmap_t *dmap; + int pos; + + if (snum < 0 || snum >= chip->npcm) + return -ENXIO; + + adev = chip->capture_adev[snum]; + dmap = adev->dmap_in; + + if (adev->d->adrv_get_input_pointer != NULL) + pos = + adev->d->adrv_get_input_pointer (adev->engine_num, dmap, PCM_ENABLE_INPUT); + else + { + pos = dmap->fragment_counter * dmap->fragment_size; + } + pos = bytes_to_frames (substream->runtime, pos); + + return pos; +} + +static snd_pcm_ops_t snd_cuckoo_playback_ops = { + .open = snd_cuckoo_playback_open, + .close = snd_cuckoo_playback_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_cuckoo_playback_hw_params, + .hw_free = snd_cuckoo_hw_free, + .prepare = snd_cuckoo_playback_prepare, + .trigger = snd_cuckoo_playback_trigger, + .pointer = snd_cuckoo_playback_pointer, +}; + +static snd_pcm_ops_t snd_cuckoo_capture_ops = { + .open = snd_cuckoo_capture_open, + .close = snd_cuckoo_capture_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_cuckoo_capture_hw_params, + .hw_free = snd_cuckoo_hw_free, + .prepare = snd_cuckoo_capture_prepare, + .trigger = snd_cuckoo_capture_trigger, + .pointer = snd_cuckoo_capture_pointer, +}; + +int +install_pcm_instances (cuckoo_t * chip, int cardno) +{ + int dev, err, ok = 0; + int ninputs = 0, noutputs = 0; + + for (dev = 0; dev < num_audio_devfiles; dev++) + if (audio_devfiles[dev]->card_number == cardno) + { + adev_t *adev = audio_devfiles[dev]; + adev_t *nextdev = audio_devfiles[dev + 1]; + snd_pcm_t *pcm; + + ninputs = noutputs = 0; + + ok = 0; +/* Special handling for shadow devices */ + if (dev < num_audio_devfiles - 1 && (adev->flags & ADEV_DUPLEX)) + if ((nextdev->flags & ADEV_DUPLEX) + && (nextdev->flags & ADEV_SHADOW)) + ok = 1; + +// Devices with one recording engine and multiple playback ones + if (dev < num_audio_devfiles - 1 && (adev->flags & ADEV_DUPLEX)) + if (adev->card_number == nextdev->card_number) + if ((nextdev->flags & ADEV_NOINPUT)) + ok = 1; + + if (ok) // Device needs special handling + { + if ((err = + snd_pcm_new (chip->card, "OSS/Linux", chip->npcm, 1, 1, + &pcm)) < 0) + { + printk ("cuckoo: snd_pcm_new failed - error %d\n", err); + return err; + } + + pcm->private_data = chip; + chip->pcm[chip->npcm++] = pcm; + strlcpy (pcm->name, adev->name); + + chip->capture_adev[chip->ncapture++] = nextdev; + snd_pcm_set_ops (pcm, SNDRV_PCM_STREAM_CAPTURE, + &snd_cuckoo_capture_ops); + + chip->play_adev[chip->nplay++] = adev; + snd_pcm_set_ops (pcm, SNDRV_PCM_STREAM_PLAYBACK, + &snd_cuckoo_playback_ops); + + dev++; + continue; + } + + if (!(adev->flags & ADEV_NOINPUT)) + ninputs = 1; + if (!(adev->flags & ADEV_NOOUTPUT)) + noutputs = 1; + + if ((err = + snd_pcm_new (chip->card, "OSS/Linux", chip->npcm, noutputs, + ninputs, &pcm)) < 0) + { + printk ("cuckoo: snd_pcm_new failed - error %d\n", err); + return err; + } + + pcm->private_data = chip; + chip->pcm[chip->npcm++] = pcm; + strlcpy (pcm->name, adev->name); + + if (noutputs > 0) + { + chip->play_adev[chip->nplay++] = adev; + snd_pcm_set_ops (pcm, SNDRV_PCM_STREAM_PLAYBACK, + &snd_cuckoo_playback_ops); + } + + if (ninputs > 0) + { + chip->capture_adev[chip->ncapture++] = adev; + snd_pcm_set_ops (pcm, SNDRV_PCM_STREAM_CAPTURE, + &snd_cuckoo_capture_ops); + } + } + + return 0; +} + +EXPORT_SYMBOL (install_pcm_instances); diff --git a/setup/Linux/oss/etc/S89oss b/setup/Linux/oss/etc/S89oss new file mode 100755 index 0000000..5a1cdcd --- /dev/null +++ b/setup/Linux/oss/etc/S89oss @@ -0,0 +1,80 @@ +#!/bin/bash +# +# /etc/rc.d/init.d/oss +# +# Starts the OSS sound driver +# +# chkconfig: 2345 80 20 +# description: Open Sound System for Linux (OSS/Linux) is a \ +# commercial quality sound driver distributed by 4Front Technologies \ +# (http://www.opensound.com). + +### BEGIN INIT INFO +# Provides: oss +# Required-Start: $local_fs $remote_fs +# Should-Start: +# Required-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Start OSS +### END INIT INFO + +# Source function library. +if test -f /lib/lsb/init-functions +then +. /lib/lsb/init-functions +fi + +if test -f /etc/rc.d/init.d/functions +then +. /etc/rc.d/init.d/functions +fi + +# Add oss configuration. +. /etc/oss.conf + +RETVAL=0 + +# +# See how we were called. +# +case "$1" in + start) + # Check if OSS is already running + echo -n 'Starting Open Sound System: ' + if ! test -f /usr/sbin/soundon + then + exit 0 + fi + + if test -f $OSSLIBDIR/starting + then + ls -l $OSSLIBDIR/starting + echo Previous start of OSS crashed the system + echo Please resolve the situation and remove file + echo \"$OSSLIBDIR/starting\". Then start OSS by + echo running soundon + exit 0 + fi + + if ! /usr/sbin/soundon + then + echo Starting OSS failed + fi + rm -f $OSSLIBDIR/starting + ;; + stop) + echo -n 'Stopping Open Sound System: ' + + /usr/sbin/savemixer + exit 0 + ;; + restart) + $0 stop + /usr/sbin/soundoff + $0 start + ;; + *) + echo "Usage: $0 {start|stop|restart}" + exit 1 +esac diff --git a/setup/Linux/oss/scripts/90-oss_usb-create-device.fdi b/setup/Linux/oss/scripts/90-oss_usb-create-device.fdi new file mode 100644 index 0000000..28744f9 --- /dev/null +++ b/setup/Linux/oss/scripts/90-oss_usb-create-device.fdi @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<deviceinfo version="0.2"> + <device> + <match key="info.linux.driver" string="oss_usb"> + <append key="info.callouts.add" type="strlist">oss_usb-create-devices</append> + </match> + </device> +</deviceinfo> diff --git a/setup/Linux/oss/scripts/killprocs.sh b/setup/Linux/oss/scripts/killprocs.sh new file mode 100755 index 0000000..ce8d26d --- /dev/null +++ b/setup/Linux/oss/scripts/killprocs.sh @@ -0,0 +1,17 @@ +#!/bin/sh +PROCS="`fuser /dev/mixer* /dev/dsp* /dev/audio* /dev/sequencer /dev/music /dev/midi* 2>/dev/null`" + +if test "$PROCS " = " " +then + exit 0 +fi + +for pid in $PROCS +do + #ps ax|grep "^ *$pid " + echo killing $pid + kill $pid +done + +sleep 2 +exit 0 diff --git a/setup/Linux/oss/scripts/oss_usb-create-devices b/setup/Linux/oss/scripts/oss_usb-create-devices new file mode 100644 index 0000000..a6de13c --- /dev/null +++ b/setup/Linux/oss/scripts/oss_usb-create-devices @@ -0,0 +1,4 @@ +#!/bin/sh + +/usr/sbin/ossdetect -d +/usr/sbin/ossdevlinks diff --git a/setup/Linux/oss/scripts/remove_drv.sh b/setup/Linux/oss/scripts/remove_drv.sh new file mode 100644 index 0000000..55cc1b4 --- /dev/null +++ b/setup/Linux/oss/scripts/remove_drv.sh @@ -0,0 +1,164 @@ +#!/bin/sh +if test -f /etc/oss.conf +then + . /etc/oss.conf +else + OSSLIBDIR=/usr/lib/oss +fi + +# This script wipes out the previously installed sound drivers +# from the system. + +# Backup all kernel sound drivers (ALSA) and remove the kernel/sound +# directory from the system. Untar the backup package to return ALSA +# back in business. + +if test -x /sbin/chkconfig +then + /sbin/chkconfig alsasound off > /dev/null 2>&1 +elif test -x /usr/sbin/update-rc.d +then + /usr/sbin/update-rc.d -f alsa-utils remove > /dev/null 2>&1 +elif test -x /usr/sbin/alsa +then + /usr/sbin/alsa force-unload > /dev/null 2>&1 +fi + +if test -d /lib/modules/`uname -r`/kernel/sound +then + if ! test -f /lib/modules/`uname -r`/sound-preoss.tar.bz2 + then + (cd /lib/modules/`uname -r`; tar cfj /lib/modules/`uname -r`/sound-preoss.tar.bz2 kernel/sound) + fi + + rm -rf /lib/modules/`uname -r`/kernel/sound + depmod -a +fi + +# Kill all applications using ALSA or OSS/Free devices + +# We have to use ugly replacement of fuser since this command got broken +# in some Linux recent distributions. + +KILL=0 + +for n in /proc/[0-9]* +do + PID=`basename $n` + if test "`ls -l $n/fd/* 2>/dev/null|grep /dev/snd` " != " " + then + KILL=1 + fi + + if test "`ls -l $n/fd/* 2>/dev/null|grep /dev/mixer` " != " " + then + KILL=1 + fi +done + +if ! test -d $OSSLIBDIR/save +then + mkdir $OSSLIBDIR/save +fi + +if test "$KILL " = "1 " +then +echo killing + rm -f /dev/mixer.old + mv /dev/mixer /dev/mixer.old 2>/dev/null + #if test -d /dev/snd + #then + #(cd /;tar cfj $OSSLIBDIR/save/alsadevs.tar.bz2 dev/snd) + #fi + + #mv /dev/snd /dev/snd.osssave + #fuser -k -s /dev/mixer.old /dev/snd.osssave/* +fi + +# Remove all loaded ALSA modules +SOUNDDEVS= + +if test -f /dev/mixer.old +then + SOUNDDEVS="$SOUNDDEVS /dev/mixer.old" +fi + +if test -d /dev/snd.osssave +then + SOUNDDEVS="$SOUNDDEVS /dev/snd.osssave/*" +fi + +for timeout in 0 1 2 3 4 5 6 7 8 9 10 11 +do + if test "`cat /proc/modules|grep ^snd_|sed 's/ .*//'` " = " " + then + break + fi + + if test $timeout -gt 10 + then + echo Cannot unload the ALSA modules. Apparently there is some + echo application keeping them busy. + echo Please reboot your system and try to start OSS again. + ps ax + lsmod + cat /proc/devices + cat /proc/interrupts + exit 1 + fi + + if test "$SOUNDDEVS " != " " + then + fuser -s -9 $SOUNDDEVS + else + echo Cannot find any processes using the conflicting sound driver + fi + + for n in `cat /proc/modules|grep ^snd_|sed 's/ .*//'` + do + rmmod $n + #rmmod $n >/dev/null 2>&1 + done + + sleep 1 +done + +rmmod snd > /dev/null 2>&1 + +# Remove soundcore +rmmod soundcore > /dev/null 2>&1 + +rm -f /dev/mixer.old + +if cat /proc/devices|grep -q '^ *14 ' +then + + echo There still appears to be another sound driver hanging around + + lsmod + cat /proc/devices|grep '^ *14 ' + cat /proc/interrupts + + exit 1 +fi + +for n in /dev/sndstat /dev/mixer* /dev/dsp* /dev/midi* /dev/sequencer /dev/music +do + if readlink $n >/dev/null 2>&1 + then # Symbolic link + if readlink $n | grep -q asound + then # Link to ALSA devices + rm -f $n + fi + fi +done + +# Disable automatic startup of ALSA during system bootup + +if test "`ls /etc/rc.d/rc*/*alsasound*` " != " " > /dev/null 2>&1 +then + (cd /;tar cfj $OSSLIBDIR/save/alsarc/tar.bz2 etc/rc.d/rc*/*alsasound*) + rm -f /etc/rc.d/rc*/*alsasound* +fi > /dev/null 2>&1 + +exit 0 diff --git a/setup/Linux/oss/scripts/restore_drv.sh b/setup/Linux/oss/scripts/restore_drv.sh new file mode 100644 index 0000000..9046d04 --- /dev/null +++ b/setup/Linux/oss/scripts/restore_drv.sh @@ -0,0 +1,63 @@ +#!/bin/sh +if test -f /etc/oss.conf +then + . /etc/oss.conf +else + OSSLIBDIR=/usr/lib/oss +fi + +/usr/sbin/soundoff + +rm -rf /lib/modules/`uname -r`/kernel/oss + +if test -x /sbin/chkconfig +then /sbin/chkconfig oss off > /dev/null 2>&1 +else + if test -x /sbin/update-rc.d + then /usr/sbin/update-rc.d -f oss remove > /dev/null 2>&1 + fi +fi + +rm -f /etc/init.d/oss + +if ! test -d /lib/modules/`uname -r`/kernel/sound +then + if test -f /lib/modules/`uname -r`/sound-preoss.tar.bz2 + then + (cd /lib/modules/`uname -r`; tar xfj sound-preoss.tar.bz2) + /sbin/depmod -a + fi +fi + +rm -f /lib/modules/`uname -r`/sound-preoss.tar.bz2 + +if test -f $OSSLIBDIR/sysfiles.list +then + rm -f `cat $OSSLIBDIR/sysfiles.list` +fi + +if test -f $OSSLIBDIR/save/alsadevs.tar.bz2 +then + (cd /;tar xfj $OSSLIBDIR/save/alsadevs.tar.bz2) +fi + +if test -f $OSSLIBDIR/save/alsarc/tar.bz2 +then + (cd /;tar xfj $OSSLIBDIR/save/alsarc/tar.bz2) +fi + +rm -f /dev/dsp* /dev/midi* /dev/mixer* /dev/sndstat + +/sbin/ldconfig + +if test -x /sbin/chkconfig +then + /sbin/chkconfig alsasound on > /dev/null 2>&1 +else + if test -x /usr/sbin/update-rc.d + then + /usr/sbin/update-rc.d alsa-utils defaults > /dev/null 2>&1 + fi +fi + +exit 0 diff --git a/setup/Linux/oss/scripts/setup-alsa.sh b/setup/Linux/oss/scripts/setup-alsa.sh new file mode 100644 index 0000000..fdcf4ff --- /dev/null +++ b/setup/Linux/oss/scripts/setup-alsa.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +# This script will restgore selected ALSA modules that were earlier removed by +# remove_drv.sh + +if test -d /proc/asound +then +# ALSA is already loaded + exit 0 +fi + +if ! test -f /lib/modules/`uname -r`/sound-preoss.tar.bz2 +then + echo ALSA backup archive /lib/modules/`uname -r`/sound-preoss.tar.bz2 not found. Cannot continue. + exit 1 +fi + +RESTORE=kernel/sound/soundcore.ko + +for n in snd snd-pcm snd-timer snd-page-alloc +do + RESTORE="$RESTORE kernel/sound/core/$n.ko kernel/sound/acore/$n.ko" +done + +(cd /lib/modules/`uname -r` && tar xvfj sound-preoss.tar.bz2 $RESTORE) + +if test -d /dev/snd.save && ! test -d /dev/snd +then + mv /dev/snd.save /dev/snd +fi + +exit 0 diff --git a/setup/Linux/oss/scripts/showprocs.sh b/setup/Linux/oss/scripts/showprocs.sh new file mode 100755 index 0000000..827bb33 --- /dev/null +++ b/setup/Linux/oss/scripts/showprocs.sh @@ -0,0 +1,28 @@ +#!/bin/sh +PROCS="`fuser /dev/mixer* /dev/dsp* /dev/audio* /dev/sequencer /dev/music /dev/midi*|sed 's/.* //'|sort|uniq`" + +if test "$PROCS " = " " +then + exit 0 +fi + +if test "$1 " != "-q " +then +echo $PROCS +echo +echo "NOTICE!" +echo "=======" +echo +echo There are some programs still using OSS devices. You may need to stop them +echo manually: +echo +fi + +for pid in $PROCS +do + ps ax|grep "^ *$pid " +done + +echo + +exit 0 diff --git a/setup/Linux/oss/soundon.user b/setup/Linux/oss/soundon.user new file mode 100644 index 0000000..da31b6d --- /dev/null +++ b/setup/Linux/oss/soundon.user @@ -0,0 +1,7 @@ +#!/bin/sh +# +# This script can be used to run programs every time OSS is started. +# By default, this script is disabled, and contains no commands. +# To enable, add executable permissions to this file, and edit below +# commands to be run. +exit 0 |