summaryrefslogtreecommitdiff
path: root/setup/Linux/oss/cuckoo
diff options
context:
space:
mode:
Diffstat (limited to 'setup/Linux/oss/cuckoo')
-rw-r--r--setup/Linux/oss/cuckoo/Makefile23
-rw-r--r--setup/Linux/oss/cuckoo/checksum.h0
-rw-r--r--setup/Linux/oss/cuckoo/cuckoo.c251
-rw-r--r--setup/Linux/oss/cuckoo/cuckoo.h171
-rw-r--r--setup/Linux/oss/cuckoo/cuckoo_midi.c310
-rw-r--r--setup/Linux/oss/cuckoo/cuckoo_mixer.c389
-rw-r--r--setup/Linux/oss/cuckoo/cuckoo_pcm.c810
7 files changed, 1954 insertions, 0 deletions
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);