summaryrefslogtreecommitdiff
path: root/kernel/OS/SunOS
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/OS/SunOS')
-rw-r--r--kernel/OS/SunOS/.config1
-rw-r--r--kernel/OS/SunOS/module.inc389
-rw-r--r--kernel/OS/SunOS/os_solaris.c2401
-rw-r--r--kernel/OS/SunOS/os_solaris.h518
-rw-r--r--kernel/OS/SunOS/udi.c1365
5 files changed, 4674 insertions, 0 deletions
diff --git a/kernel/OS/SunOS/.config b/kernel/OS/SunOS/.config
new file mode 100644
index 0000000..816ac62
--- /dev/null
+++ b/kernel/OS/SunOS/.config
@@ -0,0 +1 @@
+mode=kernel
diff --git a/kernel/OS/SunOS/module.inc b/kernel/OS/SunOS/module.inc
new file mode 100644
index 0000000..a522492
--- /dev/null
+++ b/kernel/OS/SunOS/module.inc
@@ -0,0 +1,389 @@
+/*
+ * Purpose: OSS module wrapper for Solaris
+ *
+ * This file will be included from the auto-generated drv_cfg.c files. Under
+ * Solaris this file will be compiled in the development system.
+ */
+/*
+ *
+ * This file is part of Open Sound System.
+ *
+ * Copyright (C) 4Front Technologies 1996-2008.
+ *
+ * This this source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ */
+#include <sys/types.h>
+#include <sys/modctl.h>
+#include <sys/kmem.h>
+#include <sys/conf.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+
+static int ossdrv_getinfo (dev_info_t *, ddi_info_cmd_t, void *, void **);
+static int ossdrv_attach (dev_info_t *, ddi_attach_cmd_t);
+static int ossdrv_detach (dev_info_t *, ddi_detach_cmd_t);
+
+#ifdef OSS_POWER_MANAGE
+static int ossdrv_power (dev_info_t *, int component, int level);
+#endif
+
+/* Entry points structure */
+#if DRIVER_TYPE!=DRV_STREAMS
+
+static struct cb_ops ossdrv_cb_ops = {
+ oss_open,
+ oss_close,
+ nodev, /* not a block driver */
+ nodev, /* no print routine */
+ nodev, /* no dump routine */
+ oss_read,
+ oss_write,
+ oss_ioctl,
+#ifdef ALLOW_BUFFER_MAPPING
+ oss_devmap,
+#else
+ nodev, /* no devmap routine */
+#endif
+ nodev,
+ nodev, /* no segmap routine */
+ oss_chpoll, /* no chpoll routine */
+ ddi_prop_op,
+ 0, /* not a STREAMS driver */
+ D_NEW | D_MP | D_64BIT, /* safe for multi-thread/multi-processor */
+ CB_REV
+};
+#else
+extern struct streamtab DRIVER_STR_INFO;
+
+struct cb_ops ossdrv_streams_cb_ops = {
+ nulldev,
+ nulldev,
+ nodev, /* not a block driver */
+ nodev, /* no print routine */
+ nodev, /* no dump routine */
+ nodev,
+ nodev,
+ nodev,
+ nodev, /* no devmap routine */
+ nodev,
+ nodev, /* no segmap routine */
+ nochpoll, /* no chpoll routine */
+ ddi_prop_op,
+ &DRIVER_STR_INFO, /* cb_str */
+ D_NEW | D_MP | D_64BIT, /* safe for multi-thread/multi-processor */
+ CB_REV,
+ nodev, /* cb_aread */
+ nodev, /* cb_awrite */
+};
+#endif
+
+static struct dev_ops ossdrv_dev_ops = {
+ DEVO_REV, /* devo_rev */
+ 0, /* devo_refcnt */
+ ossdrv_getinfo, /* devo_getinfo */
+ nulldev, /* devo_identify - obsolete */
+#if DRIVER_TYPE==DRV_ISA
+ ossdrv_probe,
+#else
+ nulldev, /* devo_probe */
+#endif
+ ossdrv_attach, /* devo_attach */
+ ossdrv_detach, /* devo_detach */
+ nodev, /* devo_reset */
+#if DRIVER_TYPE==DRV_STREAMS
+ &ossdrv_streams_cb_ops, /* devi_cb_ops */
+#else
+ &ossdrv_cb_ops, /* devi_cb_ops */
+#endif
+ NULL, /* devo_bus_ops */
+#ifdef OSS_POWER_MANAGE
+ ossdrv_power
+#else
+ NULL /* devo_power */
+#endif
+};
+
+static struct modldrv ossdrv_modldrv = {
+ &mod_driverops, /* drv_modops */
+ "OSS " OSS_VERSION_STRING,
+ &ossdrv_dev_ops, /* drv_dev_ops */
+};
+
+static struct modlinkage ossdrv_modlinkage = {
+ MODREV_1, /* ml_rev */
+ (void *) &ossdrv_modldrv, /* ml_linkage */
+ NULL /* NULL terminates the list */
+};
+
+/*
+ * _init, _info, and _fini support loading and unloading the driver.
+ */
+int
+_init (void)
+{
+ int error;
+
+ error = mod_install (&ossdrv_modlinkage);
+
+ return error;
+}
+
+int
+_fini (void)
+{
+ int error;
+
+ error = mod_remove (&ossdrv_modlinkage);
+ return error;
+}
+
+int
+_info (struct modinfo *modinfop)
+{
+ int error;
+
+ error = mod_info (&ossdrv_modlinkage, modinfop);
+
+ return error;
+}
+
+/*ARGSUSED*/
+static int
+ossdrv_getinfo (dev_info_t * dontcare_dip, ddi_info_cmd_t cmd, void *arg,
+ void **result)
+{
+ dev_t dev;
+ register int error;
+ int instance;
+ dev_info_t *dip;
+#ifndef SOL9
+ oss_cdev_t *cdev;
+ int minor;
+
+ dev = (dev_t) arg;
+
+ minor = getminor (dev);
+
+ if (minor >= oss_num_cdevs)
+ {
+ *result = NULL;
+ return DDI_FAILURE;
+ }
+
+ if ((cdev = oss_cdevs[minor]) == NULL || cdev->osdev == NULL)
+ {
+ *result = NULL;
+ return DDI_FAILURE;
+ }
+
+ dip = cdev->osdev->dip;
+#else
+ dip = dontcare_dip;
+#endif
+
+ if (dip == NULL)
+ {
+ /* cmn_err (CE_WARN, "ossdrv_getinfo: dip==NULL\n"); */
+ return DDI_FAILURE;
+ }
+
+ instance = ddi_get_instance (dip);
+
+ switch (cmd)
+ {
+ case DDI_INFO_DEVT2DEVINFO:
+ *result = dip;
+ error = DDI_SUCCESS;
+ break;
+ case DDI_INFO_DEVT2INSTANCE:
+ *result = (void *) (long)instance;
+ error = DDI_SUCCESS;
+ break;
+ default:
+ *result = NULL;
+ error = DDI_FAILURE;
+ }
+
+ DDB (cmn_err (CE_CONT,
+ "oss_getinfo: returns %d, result=%lx instance=%d dev=%x\n",
+ error, (unsigned long)*result, instance, (unsigned int)dev));
+ return error;
+}
+
+static int
+ossdrv_attach (dev_info_t * dip, ddi_attach_cmd_t cmd)
+{
+ int instance;
+ oss_device_t *osdev;
+
+#ifdef OSS_SUSPEND_RESUME
+ if (cmd != DDI_RESUME) /* Allow resume */
+#endif
+ if (cmd != DDI_ATTACH)
+ {
+ cmn_err (CE_WARN, "bad attach cmd %d\n", cmd);
+ return 0;
+ }
+
+ if (dip == NULL)
+ {
+ cmn_err (CE_WARN, "ossdrv_attach: dip==NULL\n");
+ return DDI_FAILURE;
+ }
+
+#ifdef OSS_SUSPEND_RESUME
+ if (cmd == DDI_RESUME)
+ {
+ if ((osdev = (oss_device_t *) ddi_get_driver_private (dip)) == NULL)
+ {
+ cmn_err (CE_WARN, "ddi_get_driver_private() failed\n");
+ return DDI_SUCCESS;
+ }
+ if (!DRIVER_RESUME(osdev))
+ return DDI_FAILURE;
+
+ return DDI_SUCCESS;
+ }
+#endif
+
+ instance = ddi_get_instance (dip);
+ DDB (cmn_err
+ (CE_CONT, "Attach started " DRIVER_NICK "%d (%s)\n", instance,
+ ddi_get_name (dip)));
+
+ if ((osdev =
+ osdev_create (dip, DRIVER_TYPE, instance, DRIVER_NICK, NULL)) == NULL)
+ {
+ return DDI_FAILURE;
+ }
+
+ oss_load_options (osdev, oss_global_options);
+ oss_load_options (osdev, local_driver_options);
+
+#if DRIVER_TYPE==DRV_PCI || DRIVER_TYPE == DRV_ISA
+ {
+ int err;
+ if ((err =
+ ddi_get_iblock_cookie (dip, 0, &osdev->iblock_cookie)) != DDI_SUCCESS)
+ {
+ cmn_err (CE_WARN, "Cannot get iblock cookie (%d)\n", err);
+ return DDI_FAILURE;
+ }
+ }
+#else
+/* NOTE! The USB driver (actually udi.c) will call usb_get_data() to obtain */
+/* the iblock_cookie. There is no need to do that here. */
+ osdev->iblock_cookie = 0;
+#endif
+
+ if (!DRIVER_ATTACH (osdev))
+ {
+ cmn_err (CE_WARN, "Attach failed\n");
+ osdev_delete (osdev);
+ return DDI_FAILURE;
+ }
+
+ ddi_set_driver_private (dip, (caddr_t) osdev);
+ ddi_report_dev (dip);
+#if DRIVER_TYPE != DRV_USB
+ oss_audio_delayed_attach ();
+#endif
+
+ DDB (cmn_err (CE_CONT, "Attach done " DRIVER_NICK "%d\n", instance));
+
+ return DDI_SUCCESS;
+}
+
+static int
+ossdrv_detach (dev_info_t * dip, ddi_detach_cmd_t cmd)
+{
+ oss_device_t *osdev;
+
+#ifdef OSS_SUSPEND_RESUME
+ if (cmd != DDI_SUSPEND) /* Allow suspend */
+#endif
+ if (cmd != DDI_DETACH)
+ {
+ cmn_err (CE_WARN, "bad detach cmd %d\n", cmd);
+ return 0;
+ }
+
+ if (dip == NULL)
+ {
+ cmn_err (CE_WARN, "ossdrv_detach: dip==NULL\n");
+ return DDI_FAILURE;
+ }
+//cmn_err(CE_CONT, "Detach started " DRIVER_NICK "\n");
+
+ DDB (cmn_err
+ (CE_CONT, "Detach started " DRIVER_NICK "(%s)\n", ddi_get_name (dip)));
+ if ((osdev = (oss_device_t *) ddi_get_driver_private (dip)) == NULL)
+ {
+ cmn_err (CE_WARN, "ddi_get_driver_private() failed\n");
+ return DDI_SUCCESS;
+ }
+
+ if (osdev==NULL)
+ {
+ cmn_err (CE_WARN, "Driver osdev==NULL - cannot detach\n");
+ return DDI_FAILURE;
+ }
+
+#ifdef OSS_SUSPEND_RESUME
+ if (cmd == DDI_SUSPEND)
+ {
+ if (!DRIVER_SUSPEND(osdev))
+ return DDI_FAILURE;
+ return DDI_SUCCESS;
+ }
+#endif
+
+ if (DRIVER_DETACH (osdev) <= 0)
+ {
+ cmn_err (CE_WARN, "Driver busy - cannot detach\n");
+ return DDI_FAILURE;
+ }
+
+#if DRIVER_TYPE!=DRV_VMIX
+ osdev_delete (osdev);
+#endif
+
+ DDB (cmn_err (CE_CONT, "Detach done " DRIVER_NICK "\n"));
+ return DDI_SUCCESS;
+}
+
+#ifdef OSS_POWER_MANAGE
+static int
+ossdrv_power (dev_info_t *dip, int component, int level)
+{
+ oss_device_t *osdev;
+
+ if (dip == NULL)
+ {
+ cmn_err (CE_WARN, "ossdrv_detach: dip==NULL\n");
+ return DDI_FAILURE;
+ }
+
+ DDB (cmn_err
+ (CE_CONT, "ossdrv_power " DRIVER_NICK "(%s, %d, %d)\n", ddi_get_name (dip), component, level));
+ if ((osdev = (oss_device_t *) ddi_get_driver_private (dip)) == NULL)
+ {
+ cmn_err (CE_WARN, "ddi_get_driver_private() failed\n");
+ return DDI_SUCCESS;
+ }
+
+ if (osdev==NULL)
+ {
+ cmn_err (CE_WARN, "Driver osdev==NULL - cannot detach\n");
+ return DDI_FAILURE;
+ }
+
+ if (!DRIVER_POWER(osdev, component, level))
+ return DDI_FAILURE;
+
+ return DDI_SUCCESS;
+}
+#endif
diff --git a/kernel/OS/SunOS/os_solaris.c b/kernel/OS/SunOS/os_solaris.c
new file mode 100644
index 0000000..b4ceac3
--- /dev/null
+++ b/kernel/OS/SunOS/os_solaris.c
@@ -0,0 +1,2401 @@
+/*
+ * Purpose: Operating system abstraction functions for Solaris
+ */
+/*
+ *
+ * This file is part of Open Sound System.
+ *
+ * Copyright (C) 4Front Technologies 1996-2008.
+ *
+ * This this source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ */
+
+#include "oss_config.h"
+#include "midi_core.h"
+#include <oss_pci.h>
+#if !defined(SOL9) && !defined(SOL8)
+#include <sys/sunldi.h>
+#endif
+#include <sys/mman.h>
+
+#if 1
+/*
+ * Some older DDI routines are used by OSS instead of the latest ones.
+ * In this way the same OSS binary can be run both under Sol10 and Sol11.
+ */
+uint16_t ddi_mem_get16 (ddi_acc_handle_t handle, uint16_t * host_addr);
+uint32_t ddi_mem_get32 (ddi_acc_handle_t handle, uint32_t * host_addr);
+void ddi_mem_put16 (ddi_acc_handle_t handle, uint16_t * dev_addr,
+ uint16_t value);
+void ddi_mem_put32 (ddi_acc_handle_t handle, uint32_t * dev_addr,
+ uint32_t value);
+int ddi_mem_alloc (dev_info_t * dip, ddi_dma_lim_t * limits, uint_t length,
+ uint_t flags, caddr_t * kaddrp, uint_t * real_length);
+void ddi_mem_free (caddr_t kaddr);
+#endif
+
+#if 0
+/* TODO: Disable this debugging stuff */
+unsigned char tmp_status = 0;
+# define UP_STATUS(v) OUTB(NULL, (tmp_status=tmp_status|(v)), 0x378)
+# define DOWN_STATUS(v) OUTB(NULL, (tmp_status=tmp_status&~(v)), 0x378)
+#else
+# define UP_STATUS(v)
+# define DOWN_STATUS(v)
+#endif
+
+static int oss_expired = 0;
+
+static oss_mutex_t osscore_mutex;
+
+#define TRC(x)
+#define TRC2(x)
+
+#define FIX_RET_VALUE(ret) (((ret)<0) ? -(ret) : 0)
+
+static volatile int open_devices = 0;
+static volatile int do_forceload = 0;
+static volatile int forceload_in_progress = 0;
+
+/*
+ * MAX_CARDS must be larger than life. The system will panic if there are
+ * more sound devices (cards os sound chips) than MAX_CARDS.
+ */
+#define MAX_CARDS 32
+
+static oss_device_t *cards[MAX_CARDS];
+int oss_num_cards = 0;
+
+int oss_detach_enabled = 0;
+
+#ifdef MUTEX_CHECKS
+static volatile int inside_intr = 0; /* For mutex debugging only */
+#endif
+
+/*
+ * These are the entry points into our driver that are called when the
+ * driver is loaded, during a system call, or in response to an interrupt.
+ */
+static int oss_getinfo (dev_info_t * dip, ddi_info_cmd_t infocmd, void *arg,
+ void **result);
+static int oss_attach (dev_info_t * dip, ddi_attach_cmd_t cmd);
+static int oss_detach (dev_info_t * dip, ddi_detach_cmd_t cmd);
+static void free_all_contig_memory (void);
+
+/*
+ * DMA memory management
+ */
+
+typedef struct contig_desc
+{
+ int is_special;
+ struct contig_desc *next;
+ unsigned char *first_addr, *last_addr;
+ unsigned long physaddr;
+ void *orig_buf;
+
+ oss_device_t *osdev;
+ ddi_dma_handle_t handle;
+ ddi_dma_handle_t dhandle;
+ ddi_acc_handle_t dma_acc_handle;
+ ddi_dma_cookie_t cookie;
+ ddi_dma_win_t win;
+ ddi_dma_seg_t seg;
+ size_t size;
+}
+contig_desc;
+
+static contig_desc *contig_list = NULL;
+
+#ifdef MEMDEBUG
+typedef struct
+{
+ void *addr;
+ int size;
+ char file[40];
+ int line;
+} mem_block_t;
+
+#define MAX_MEMBLOCKS 1024
+
+static mem_block_t memblocks[MAX_MEMBLOCKS];
+static int num_memblocks = 0;
+#endif
+
+#define CDEV_NUMHASH 79 // Prime number
+static oss_cdev_t *cdev_hash[CDEV_NUMHASH] = {NULL};
+#define compute_cdev_hash(dev_class, instance) (dev_class*13+instance) % CDEV_NUMHASH
+
+static void
+unlink_cdev_hash(oss_cdev_t *this_cdev)
+{
+ oss_cdev_t *cdev = cdev_hash[compute_cdev_hash(this_cdev->dev_class, this_cdev->instance)];
+
+ if (cdev == this_cdev) // First in the hash chain
+ {
+ cdev_hash[compute_cdev_hash(this_cdev->dev_class, this_cdev->instance)] = cdev->hl;
+ return;
+ }
+
+ while (cdev != NULL)
+ {
+ if (cdev->hl == this_cdev)
+ {
+ cdev->hl = this_cdev->hl;
+ return;
+ }
+
+ cdev = cdev->hl;
+ }
+
+ cmn_err(CE_WARN, "unlink_cdev_hash: Cannot find cdev %p\n", this_cdev);
+}
+
+#if 1
+/*
+ * Unfortunately this handy function is not safe (incompatibilities
+ * between kenel versions/builds). So let's hope it gets moved to
+ * the kernel.
+ */
+char *
+oss_get_procname (void) /* Return the command name of the current thread */
+{
+ return ttoproc (curthread)->p_user.u_comm;
+}
+#endif
+
+#ifdef MEMDEBUG
+void *
+oss_kmem_alloc (size_t size, int flags, char *file, int line)
+#else
+void *
+oss_kmem_alloc (size_t size, int flags)
+#endif
+{
+/*
+ * This routine allocates a memory block and stores length of it in
+ * the beginning. This length information can be used when later unallocating
+ * the memory.
+ */
+
+ char *ptr;
+ uint64_t *len;
+
+ ptr = kmem_zalloc (size + sizeof (uint64_t), flags);
+
+ if (ptr == NULL)
+ return NULL;
+
+ len = (uint64_t *) ptr;
+
+ ptr += sizeof (uint64_t);
+ *len = size + sizeof (uint64_t);
+
+#ifdef MEMDEBUG
+#if 1
+ {
+ int i;
+ for (i = 0; i < num_memblocks; i++)
+ if (memblocks[i].addr == NULL)
+ {
+ memblocks[i].addr = ptr;
+ memblocks[i].size = size;
+ strncpy (memblocks[i].file, file, 39);
+ memblocks[i].line = line;
+ return ptr;
+ }
+ }
+#endif
+
+ if (num_memblocks < MAX_MEMBLOCKS)
+ {
+ memblocks[num_memblocks].addr = ptr;
+ memblocks[num_memblocks].size = size;
+ strncpy (memblocks[num_memblocks].file, file, 39);
+ memblocks[num_memblocks].line = line;
+ num_memblocks++;
+ }
+#endif
+
+ return ptr;
+}
+
+void
+oss_kmem_free (void *addr)
+{
+ uint64_t *len;
+
+ char *ptr = addr;
+
+ if (addr == NULL)
+ return;
+
+ ptr -= sizeof (uint64_t);
+
+ len = (uint64_t *) ptr;
+
+ kmem_free (ptr, *len);
+#ifdef MEMDEBUG
+ {
+ int i;
+
+ for (i = 0; i < num_memblocks; i++)
+ if (addr == memblocks[i].addr)
+ {
+ memblocks[i].addr = NULL;
+ break;
+ }
+ }
+#endif
+}
+
+static const ddi_dma_attr_t dma_attr_pci = {
+ DMA_ATTR_V0, // Version
+ 0x00000000ULL, // Address low
+ 0xfffffff0ULL, // Address high
+ 0xffffffffULL, // Counter max
+ 1ULL, // Default byte align
+ 0x7f, // Burst size
+ 0x1, // Minimum xfer size
+ 0xffffffffULL, // Maximum xfer size
+ 0xffffffffULL, // Max segment size
+ 1, // S/G list length
+ 1, // Granularity
+ 0 // Flag
+};
+
+#if !defined(SOL9) && !defined(SOL8)
+static void
+forceload_drivers (dev_t dev, cred_t * credp)
+{
+/*
+ * This routine will be called whenever the first application tries
+ * to access OSS devices. It's purpose is to load all the drivers
+ * just in case they have not been loaded yet. In this way it's possible to
+ * guarantee that the audio device numbering doesn't change between
+ * reboots.
+ */
+ char path[20];
+
+ int i, err;
+ ldi_handle_t lh;
+ ldi_ident_t li;
+ DDB (cmn_err (CE_NOTE, "Forceloading OSS devices\n"));
+
+ if (ldi_ident_from_dev (dev, &li) != 0)
+ {
+ cmn_err (CE_NOTE, "ldi_ident_from_dev failed\n");
+ return;
+ }
+
+ if ((err = ldi_open_by_name ("/dev/sndstat", FWRITE, credp, &lh, li)) != 0)
+ {
+ if (err != ENODEV)
+ cmn_err (CE_NOTE, "Forceload error %d (/dev/sndstat)\n", err);
+ }
+ else
+ err = ldi_close (lh, FWRITE, credp);
+
+ for (i = 0; i < MAX_MIXER_DEV; i++)
+ {
+ sprintf (path, "/dev/mixer%d", i);
+
+ if ((err = ldi_open_by_name (path, FWRITE, credp, &lh, li)) != 0)
+ {
+ if (err != ENODEV)
+ cmn_err (CE_NOTE, "Forceload error %d\n", err);
+ }
+ else
+ err = ldi_close (lh, FWRITE, credp);
+ }
+
+ for (i = 0; i < MAX_AUDIO_DEVFILES; i++)
+ {
+ sprintf (path, "/dev/dsp%d", i);
+
+ if ((err = ldi_open_by_name (path, FWRITE, credp, &lh, li)) != 0)
+ {
+ if (err != ENODEV)
+ cmn_err (CE_NOTE, "Forceload error %d\n", err);
+ }
+ else
+ err = ldi_close (lh, FWRITE, credp);
+ }
+
+ ldi_ident_release (li);
+ DDB (cmn_err (CE_NOTE, "Forceloading OSS devices done\n"));
+}
+
+void
+oss_forceload_drivers (int dev, cred_t * cred_p)
+{
+
+ if (do_forceload)
+ {
+ do_forceload = 0;
+ forceload_in_progress = 1;
+ forceload_drivers (dev, cred_p);
+ forceload_in_progress = 0;
+ }
+}
+#endif
+
+/*ARGSUSED*/
+int
+oss_open (dev_t * dev_p, int open_flags, int otyp, cred_t * cred_p)
+{
+ int retval;
+ dev_t dev = *dev_p;
+ oss_cdev_t *cdev;
+ int tmpdev, maj;
+ oss_native_word flags;
+
+#ifdef DO_TIMINGS
+ oss_timing_printf ("**** oss_open(%x) ****", getminor (dev));
+#endif
+//cmn_err(CE_CONT, "**** oss_open(%x) ****\n", getminor (dev));
+//cmn_err(CE_CONT, " PID %d, cmd %s\n", GET_PROCESS_PID(x), GET_PROCESS_NAME(x));
+ maj = getmajor (dev);
+ dev = getminor (dev);
+
+#if !defined(SOL9) && !defined(SOL8)
+/*
+ * Handle driver forceload
+ */
+
+ if (forceload_in_progress)
+ return ENODEV;
+
+ oss_forceload_drivers (dev, cred_p);
+#endif
+
+ if (dev >= OSS_MAX_CDEVS)
+ return ENXIO;
+
+ if (dev >= oss_num_cdevs)
+ {
+ return ENODEV;
+ }
+
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d == NULL)
+ return ENODEV;
+
+ if (cdev->d->open == NULL)
+ {
+ return ENODEV;
+ }
+
+ memset (&cdev->file, 0, sizeof (cdev->file));
+ cdev->file.mode = 0;
+ cdev->file.acc_flags = open_flags;
+
+ if (open_flags & FREAD && open_flags & FWRITE)
+ cdev->file.mode = OPEN_READWRITE;
+ else if (open_flags & FREAD)
+ cdev->file.mode = OPEN_READ;
+ else if (open_flags & FWRITE)
+ cdev->file.mode = OPEN_WRITE;
+
+ tmpdev = dev;
+ retval =
+ cdev->d->open (cdev->instance, cdev->dev_class, &cdev->file, 0, 0, &tmpdev);
+ *dev_p = makedevice (maj, tmpdev);
+ dev = tmpdev;
+
+ if (retval < 0)
+ {
+ return -retval;
+ }
+
+ MUTEX_ENTER_IRQDISABLE (osscore_mutex, flags);
+ open_devices++;
+ cdev = oss_cdevs[dev]; /* Switch to the cdev that was actually opened */
+
+ cdev->open_count++;
+ if (open_flags & FREAD && open_flags & FWRITE)
+ cdev->file.mode = OPEN_READWRITE;
+ else if (open_flags & FREAD)
+ cdev->file.mode = OPEN_READ;
+ else if (open_flags & FWRITE)
+ cdev->file.mode = OPEN_WRITE;
+
+ oss_reserve_device (cdev->osdev);
+//cmn_err(CE_CONT, "Increment open_devices=%d, refcount=%d\n", open_devices, cdev->osdev->refcount);
+ MUTEX_EXIT_IRQRESTORE (osscore_mutex, flags);
+
+ return 0;
+}
+
+/*ARGSUSED*/
+int
+oss_close (dev_t dev, int flag, int otyp, cred_t * cred_p)
+{
+ oss_cdev_t *cdev;
+ oss_native_word flags;
+#ifdef DO_TIMINGS
+ oss_timing_printf ("***** oss_close(%x) ****", getminor (dev));
+#endif
+//cmn_err(CE_CONT, "***** oss_close(%x) ****\n", getminor (dev));
+//cmn_err(CE_CONT, " PID %d, cmd %s\n", GET_PROCESS_PID(x), GET_PROCESS_NAME(x));
+
+ if (getminor (dev) >= OSS_MAX_CDEVS)
+ {
+ cmn_err (CE_NOTE, "Closing bad minor %d\n", getminor (dev));
+ return ENXIO;
+ }
+
+ dev = getminor (dev);
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d == NULL)
+ {
+ cmn_err (CE_NOTE, "Closing undefined minor %d\n", getminor (dev));
+ return ENXIO;
+ }
+
+
+ if (cdev->open_count == 0) /* Not opened */
+ {
+ cmn_err (CE_NOTE, "Closing minor %d that is not open\n", dev);
+ return 0;
+ }
+
+ cdev->d->close (cdev->instance, &cdev->file);
+
+ MUTEX_ENTER_IRQDISABLE (osscore_mutex, flags);
+ open_devices -= cdev->open_count;
+//cmn_err(CE_CONT, "Decrement open_devices=%d\n", open_devices);
+ oss_unreserve_device (cdev->osdev, cdev->open_count);
+ cdev->open_count = 0;
+ MUTEX_EXIT_IRQRESTORE (osscore_mutex, flags);
+ return 0;
+}
+
+/*ARGSUSED*/
+int
+oss_ioctl (dev_t dev, int cmd, intptr_t arg, int mode, cred_t * cred_p,
+ int *rval_p)
+{
+ int retval;
+ int len = 0;
+ char b[4096], *buf = b;
+ oss_cdev_t *cdev;
+#ifdef DO_TIMINGS
+ oss_timing_printf ("OSS ioctl(%x, %x, %x)", getminor (dev), cmd, arg);
+#endif
+
+ *rval_p = 0;
+
+ dev = getminor (dev);
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d->ioctl == NULL)
+ return ENXIO;
+
+ if (cdev->open_count == 0) /* Not opened */
+ {
+ cmn_err (CE_NOTE, "Call to ioctl on minor %d that is not open\n", dev);
+ return ENXIO;
+ }
+
+ if (oss_expired)
+ return ENODEV;
+
+ if (mode & FKIOCTL) /* Called from kernel space */
+ buf = (char *) arg;
+ else if (cmd & (SIOC_OUT | SIOC_IN))
+ {
+
+ len = (cmd >> 16) & SIOCPARM_MASK;
+ if (len < 0)
+ len = 0;
+ if (len > sizeof (b))
+ {
+ cmn_err (CE_WARN, "Bad ioctl buffer size %d\n", len);
+ return EFAULT;
+ }
+
+ if ((cmd & SIOC_IN) && len > 0)
+ {
+ if (copyin ((char *) arg, buf, len) == -1)
+ return EFAULT;
+ }
+
+ }
+
+ retval = cdev->d->ioctl (cdev->instance, &cdev->file, cmd, (ioctl_arg) buf);
+
+ if (!(mode & FKIOCTL)) /* Not called from kernel space */
+ if ((cmd & SIOC_OUT) && len > 0)
+ {
+ if (copyout (buf, (char *) arg, len) == -1)
+ return EFAULT;
+ }
+
+ return FIX_RET_VALUE (retval);
+}
+
+/*ARGSUSED*/
+int
+oss_read (dev_t dev, struct uio *uiop, cred_t * credp)
+{
+ int count = uiop->uio_resid;
+ int retval;
+ oss_cdev_t *cdev;
+
+ dev = getminor (dev);
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d->read == NULL)
+ return ENXIO;
+
+ if (cdev->open_count == 0) /* Not opened */
+ {
+ cmn_err (CE_NOTE, "Call to read on minor %d that is not open\n", dev);
+ return ENXIO;
+ }
+
+ cdev->file.acc_flags = uiop->uio_fmode;
+
+ retval = cdev->d->read (cdev->instance, &cdev->file, uiop, count);
+
+ return FIX_RET_VALUE (retval);
+}
+
+/*ARGSUSED*/
+int
+oss_write (dev_t dev, struct uio *uiop, cred_t * cred_p)
+{
+ int count = uiop->uio_resid;
+ int retval;
+ oss_cdev_t *cdev;
+
+ dev = getminor (dev);
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d->write == NULL)
+ return ENXIO;
+
+ if (cdev->open_count == 0) /* Not opened */
+ {
+ cmn_err (CE_NOTE, "Call to write on minor %d that is not open\n", dev);
+ return ENXIO;
+ }
+ cdev->file.acc_flags = uiop->uio_fmode;
+
+ retval = cdev->d->write (cdev->instance, &cdev->file, uiop, count);
+ return FIX_RET_VALUE (retval);
+}
+
+int
+oss_chpoll (dev_t dev, short events, int anyyet, short *reventsp,
+ struct pollhead **phpp)
+{
+ oss_cdev_t *cdev;
+ oss_poll_event_t ev;
+ int ret;
+
+#ifdef DO_TIMINGS
+ oss_timing_printf ("***** oss_chpoll(%x) ****", getminor (dev));
+#endif
+
+ if (getminor (dev) >= OSS_MAX_CDEVS)
+ return ENXIO;
+
+ dev = getminor (dev);
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d->chpoll == NULL)
+ return ENXIO;
+
+ if (cdev->open_count == 0) /* Not opened */
+ {
+ cmn_err (CE_NOTE, "Call to chpoll on minor %d that is not open\n", dev);
+ return ENXIO;
+ }
+
+ *reventsp = 0;
+ ev.events = events;
+ ev.anyyet = anyyet;
+ ev.revents = 0;
+ ev.php = NULL;
+
+ ret = cdev->d->chpoll (cdev->instance, &cdev->file, &ev);
+ if (ret < 0)
+ {
+ return -ret;
+ }
+
+ *reventsp |= ev.revents;
+ if (ev.php != NULL)
+ *phpp = ev.php;
+
+ return 0;
+}
+
+#ifdef ALLOW_BUFFER_MAPPING
+int
+oss_devmap (dev_t dev, devmap_cookie_t handle, offset_t off, size_t len,
+ size_t * maplen, uint_t model)
+{
+ oss_cdev_t *cdev;
+ oss_poll_event_t ev;
+ int ret;
+
+#ifdef DO_TIMINGS
+ oss_timing_printf ("***** oss_devmap(%x) ****", getminor (dev));
+#endif
+
+ if (getminor (dev) >= OSS_MAX_CDEVS)
+ {
+ return ENXIO;
+ }
+
+ dev = getminor (dev);
+ if ((cdev = oss_cdevs[dev]) == NULL || cdev->d == NULL)
+ {
+ return ENXIO;
+ }
+
+ if (cdev->open_count == 0) /* Not opened */
+ {
+ cmn_err (CE_NOTE, "Call to devmap on minor %d that is not open\n", dev);
+ return EPERM;
+ }
+
+ if (cdev->dev_class != OSS_DEV_DSP && cdev->dev_class != OSS_DEV_DSP_ENGINE) /* Only audio devices can be mapped */
+ {
+ return ENXIO;
+ }
+
+ dev = cdev->instance;
+ if (dev < 0 || dev >= num_audio_engines)
+ return ENXIO;
+
+ return ENOTSUP;
+}
+#endif
+
+#if 0
+// Not used in misc modules.
+static struct cb_ops oss_cb_ops = {
+ oss_open,
+ oss_close,
+ nodev, /* not a block driver */
+ nodev, /* no print routine */
+ nodev, /* no dump routine */
+ oss_read,
+ oss_write,
+ oss_ioctl,
+#ifdef ALLOW_BUFFER_MAPPING
+ oss_devmap,
+#else
+ nodev, /* no devmap routine */
+#endif
+ nodev,
+ nodev, /* no segmap routine */
+ oss_chpoll, /* no chpoll routine */
+ ddi_prop_op,
+ 0, /* not a STREAMS driver */
+ D_NEW | D_MP | D_64BIT, /* safe for multi-thread/multi-processor */
+ CB_REV
+};
+
+static struct dev_ops oss_ops = {
+ DEVO_REV, /* DEVO_REV indicated by manual */
+ 0, /* device reference count */
+ oss_getinfo,
+ nulldev,
+ nulldev,
+ oss_attach,
+ oss_detach,
+ nodev, /* device reset routine */
+ &oss_cb_ops,
+ NULL, /* bus operations */
+ NULL /* TODO: Power management */
+};
+#endif
+
+extern struct mod_ops mod_miscops;
+static struct modldrv modldrv = {
+ &mod_miscops,
+ "Open Sound System " OSS_VERSION_STRING " framework"
+ // &oss_ops,
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1, /* MODREV_1 indicated by manual */
+ {(void *) &modldrv,
+ NULL} /* termination of list of linkage structures */
+};
+
+static ddi_device_acc_attr_t acc_attr_neverswap = {
+ DDI_DEVICE_ATTR_V0,
+ DDI_NEVERSWAP_ACC,
+ DDI_STRICTORDER_ACC
+};
+
+#ifdef OSS_BIG_ENDIAN
+static ddi_device_acc_attr_t acc_attr_le_swap = {
+ DDI_DEVICE_ATTR_V0,
+ DDI_STRUCTURE_LE_ACC,
+ DDI_STRICTORDER_ACC
+};
+#endif
+
+
+/*ARGSUSED*/
+static ddi_device_acc_attr_t *
+get_acc_attr (oss_device_t * osdev)
+{
+#ifdef OSS_BIG_ENDIAN
+ if (osdev->swap_mode == 1)
+ {
+ return &acc_attr_le_swap;
+ }
+ else
+#endif
+ {
+ return &acc_attr_neverswap;
+ }
+}
+
+void
+oss_load_options (oss_device_t * osdev, oss_option_map_t map[])
+{
+ int i, val;
+
+ for (i = 0; map[i].name != NULL; i++)
+ {
+ if ((val =
+ ddi_prop_get_int (DDI_DEV_T_ANY, osdev->dip,
+ DDI_PROP_NOTPROM,
+ map[i].name, -12345)) != -12345)
+ {
+ *map[i].ptr = val;
+ }
+ }
+}
+
+static int
+oss_attach (dev_info_t * dip, ddi_attach_cmd_t cmd)
+{
+ oss_device_t *osdev;
+
+ if (cmd != DDI_ATTACH)
+ {
+ cmn_err (CE_WARN, "oss_attach: Command %x\n", cmd);
+ return (DDI_FAILURE);
+ }
+
+ if ((osdev = osdev_create (dip, DRV_VIRTUAL, 0, "osscore", NULL)) == NULL)
+ {
+ cmn_err (CE_WARN, "Creating osdev failed\n");
+ return DDI_FAILURE;
+ }
+
+ MUTEX_INIT (osdev, osscore_mutex, 0);
+
+ oss_load_options (osdev, oss_global_options);
+
+ oss_common_init (osdev);
+
+ ddi_report_dev (dip);
+ oss_register_device (osdev, "OSS core services");
+
+ return (DDI_SUCCESS);
+}
+
+/*
+ * This is a pretty generic getinfo routine as describe in the manual.
+ */
+
+/*ARGSUSED*/
+static int
+oss_getinfo (dev_info_t * dip, ddi_info_cmd_t infocmd, void *arg,
+ void **result)
+{
+ dev_t dev;
+ register int error;
+ int instance;
+
+ dev = (dev_t) arg;
+ instance = getminor (dev) >> 4;
+
+ switch (infocmd)
+ {
+ case DDI_INFO_DEVT2DEVINFO:
+ *result = dip;
+ error = DDI_SUCCESS;
+ break;
+ case DDI_INFO_DEVT2INSTANCE:
+ *result = (void *) (uintptr_t) instance;
+ error = DDI_SUCCESS;
+ break;
+ default:
+ *result = NULL;
+ error = DDI_FAILURE;
+ }
+
+#if 0
+ DDB (cmn_err (CE_CONT,
+ "oss_getinfo: returns %d, result=%x minor=%d instance=%d dev=%x\n",
+ error, *result, minor_num, instance, dev));
+#endif
+ return (error);
+}
+
+/*
+ * _init, _info, and _fini support loading and unloading the driver.
+ */
+int
+_init (void)
+{
+ register int error = 0;
+ error = mod_install (&modlinkage);
+ return error;
+}
+
+int
+_info (struct modinfo *modinfop)
+{
+ return (mod_info (&modlinkage, modinfop));
+}
+
+int
+_fini (void)
+{
+ int status;
+
+#ifdef MEMDEBUG
+ int i;
+#endif
+
+ if ((status = mod_remove (&modlinkage)) != 0)
+ return (status);
+
+ free_all_contig_memory ();
+
+#ifdef MEMDEBUG
+ if (num_memblocks >= MAX_MEMBLOCKS)
+ cmn_err (CE_NOTE, "All memory allocations were not checked\n");
+
+ for (i = 0; i < num_memblocks; i++)
+ {
+ if (memblocks[i].addr != NULL)
+ {
+ cmn_err (CE_NOTE, "Memory leak in %s:%d\n",
+ memblocks[i].file, memblocks[i].line);
+ }
+ }
+#endif
+
+ return status;
+}
+
+/*
+ * When the osscore module is unloaded, oss_detach cleans up and frees the
+ * resources we allocated in oss_attach.
+ */
+static int
+oss_detach (dev_info_t * dip, ddi_detach_cmd_t cmd)
+{
+ static int already_unloaded = 0;
+
+ if (cmd != DDI_DETACH)
+ return DDI_FAILURE;
+
+ if (already_unloaded)
+ return DDI_SUCCESS;
+ already_unloaded = 1;
+//cmn_err(CE_CONT, "Oss detach\n");
+
+ /* instance = ddi_get_instance (dip); */
+
+ /*
+ * Remove the minor nodes created in attach
+ */
+ ddi_remove_minor_node (dip, NULL);
+
+ oss_unload_drivers ();
+
+ MUTEX_CLEANUP (osscore_mutex);
+
+ return (DDI_SUCCESS);
+}
+
+/*
+ * Some support routines
+ */
+void *
+memset (void *t, int c, size_t l)
+{
+ int i;
+
+ for (i = 0; i < l; i++)
+ ((char *) t)[i] = c;
+
+ return t;
+}
+
+#ifdef sparc
+/*
+ * I/O functions that do byte swapping (for Sparc)
+ */
+void
+oss_put16 (ddi_acc_handle_t handle, unsigned short *addr, unsigned short val)
+{
+ val = ((val >> 8) & 0xff) | ((val & 0xff) << 8);
+ ddi_put16 (handle, addr, val);
+}
+
+void
+oss_put32 (ddi_acc_handle_t handle, unsigned int *addr, unsigned int val)
+{
+#ifdef OSS_BIG_ENDIAN
+ val = ((val & 0x000000ff) << 24) |
+ ((val & 0x0000ff00) << 8) |
+ ((val & 0x00ff0000) >> 8) | ((val & 0xff000000) >> 24);
+#endif
+ ddi_put32 (handle, addr, val);
+}
+
+unsigned short
+oss_get16 (ddi_acc_handle_t handle, unsigned short *addr)
+{
+ unsigned short val;
+
+ val = ddi_get16 (handle, addr);
+#ifdef OSS_BIG_ENDIAN
+ val = ((val >> 8) & 0xff) | ((val & 0xff) << 8);
+#endif
+ return val;
+}
+
+unsigned int
+oss_get32 (ddi_acc_handle_t handle, unsigned int *addr)
+{
+ unsigned int val;
+
+ val = ddi_get32 (handle, addr);
+#ifdef OSS_BIG_ENDIAN
+ val = ((val & 0x000000ff) << 24) |
+ ((val & 0x0000ff00) << 8) |
+ ((val & 0x00ff0000) >> 8) | ((val & 0xff000000) >> 24);
+#endif
+ return val;
+}
+
+uint16_t
+oss_mem_get16 (ddi_acc_handle_t handle, uint16_t * addr)
+{
+ uint16_t val;
+
+ val = ddi_mem_get16 (handle, addr);
+#ifdef OSS_BIG_ENDIAN
+ val = ((val >> 8) & 0xff) | ((val & 0xff) << 8);
+#endif
+ return val;
+}
+
+uint32_t
+oss_mem_get32 (ddi_acc_handle_t handle, uint32_t * addr)
+{
+
+ uint32_t val;
+
+ val = ddi_mem_get32 (handle, addr);
+#ifdef OSS_BIG_ENDIAN
+ val = ((val & 0x000000ff) << 24) |
+ ((val & 0x0000ff00) << 8) |
+ ((val & 0x00ff0000) >> 8) | ((val & 0xff000000) >> 24);
+#endif
+ return val;
+}
+
+void
+oss_mem_put16 (ddi_acc_handle_t handle, uint16_t * addr, uint16_t val)
+{
+#ifdef OSS_BIG_ENDIAN
+ val = ((val >> 8) & 0xff) | ((val & 0xff) << 8);
+#endif
+
+ ddi_mem_put16 (handle, addr, val);
+}
+
+void
+oss_mem_put32 (ddi_acc_handle_t handle, uint32_t * addr, uint32_t val)
+{
+#ifdef OSS_BIG_ENDIAN
+ val = ((val & 0x000000ff) << 24) |
+ ((val & 0x0000ff00) << 8) |
+ ((val & 0x00ff0000) >> 8) | ((val & 0xff000000) >> 24);
+#endif
+ ddi_mem_put32 (handle, addr, val);
+}
+#endif
+
+void
+oss_pci_byteswap (oss_device_t * osdev, int mode)
+{
+ osdev->swap_mode = mode;
+}
+
+void
+oss_pcie_init (oss_device_t * osdev, int flags)
+{
+ /* TODO: Should we do something? */
+}
+
+/*ARGSUSED*/
+caddr_t
+oss_map_pci_ioaddr (oss_device_t * osdev, int nr, int io)
+{
+ caddr_t addr;
+ off_t region_size;
+ int err;
+ ddi_device_acc_attr_t *acc_attr;
+
+ if (nr >= OSS_MAX_ACC_HANDLE)
+ {
+ cmn_err(CE_WARN, "Too large I/O region number %d\n", nr);
+
+ return 0;
+ }
+
+ acc_attr = get_acc_attr (osdev);
+
+ if ((err =
+ ddi_dev_regsize (osdev->dip, nr + 1, &region_size)) != DDI_SUCCESS)
+ {
+ cmn_err (CE_WARN, "Getting device regsize failed (%d)\n", err);
+ return 0;
+ }
+
+ if ((err = ddi_regs_map_setup
+ (osdev->dip, nr + 1, &addr, 0, region_size, acc_attr,
+ &osdev->acc_handle[nr])) != DDI_SUCCESS)
+ {
+ cmn_err (CE_WARN, "Register setup failed (%d)\n", err);
+ return 0;
+ }
+
+ return addr;
+}
+
+void
+oss_unmap_pci_ioaddr(oss_device_t * osdev, int nr)
+{
+ if (nr >= OSS_MAX_ACC_HANDLE)
+ {
+ cmn_err(CE_WARN, "Too large I/O region number %d\n", nr);
+ return;
+ }
+
+ ddi_regs_map_free(&osdev->acc_handle[nr]);
+}
+
+int
+pci_read_config_byte (oss_device_t * osdev, offset_t where,
+ unsigned char *val)
+{
+ if (osdev->dev_type != DRV_PCI)
+ return PCIBIOS_FAILED;
+#if defined (sparc)
+ if (where == PCI_INTERRUPT_LINE)
+ *val = 7; /* PC emulation hack */
+ else
+#endif
+ *val = pci_config_get8 (osdev->pci_config_handle, where);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+pci_read_config_irq (oss_device_t * osdev, offset_t where, unsigned char *val)
+{
+ int ret;
+
+ if (osdev->dev_type != DRV_PCI)
+ return PCIBIOS_FAILED;
+ ret = pci_read_config_byte (osdev, where, val);
+ return ret;
+}
+
+
+int
+pci_read_config_word (oss_device_t * osdev, offset_t where,
+ unsigned short *val)
+{
+ if (osdev->dev_type != DRV_PCI)
+ return PCIBIOS_FAILED;
+ *val = pci_config_get16 (osdev->pci_config_handle, where);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+pci_read_config_dword (oss_device_t * osdev, offset_t where,
+ unsigned int *val)
+{
+ if (osdev->dev_type != DRV_PCI)
+ return PCIBIOS_FAILED;
+ *val = pci_config_get32 (osdev->pci_config_handle, where);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+pci_write_config_byte (oss_device_t * osdev, offset_t where,
+ unsigned char val)
+{
+ if (osdev->dev_type != DRV_PCI)
+ return PCIBIOS_FAILED;
+ pci_config_put8 (osdev->pci_config_handle, where, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+pci_write_config_word (oss_device_t * osdev, offset_t where,
+ unsigned short val)
+{
+ if (osdev->dev_type != DRV_PCI)
+ return PCIBIOS_FAILED;
+ pci_config_put16 (osdev->pci_config_handle, where, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+pci_write_config_dword (oss_device_t * osdev, offset_t where,
+ unsigned int val)
+{
+ if (osdev->dev_type != DRV_PCI)
+ return PCIBIOS_FAILED;
+ pci_config_put32 (osdev->pci_config_handle, where, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+void *
+memcpy (void *t, const void *s, size_t l)
+{
+ bcopy (s, t, l);
+ return t;
+}
+
+#ifdef MEMDEBUG
+void *
+oss_contig_malloc (oss_device_t * osdev, int size, oss_uint64_t memlimit,
+ oss_native_word * phaddr, oss_dma_handle_t *dma_handle, char *file, int line)
+#else
+void *
+oss_contig_malloc (oss_device_t * osdev, int size, oss_uint64_t memlimit,
+ oss_native_word * phaddr, oss_dma_handle_t *dma_handle)
+#endif
+{
+/*
+ * Allocate physically contiguous memory (suitable for DMA).
+ *
+ * The memlimit parameter is equal to oss_alloc_dmabuf().
+ */
+ int err;
+#if defined(sparc)
+ uint_t len;
+#else
+ size_t len;
+#endif
+ uint_t count;
+ contig_desc *desc;
+ ddi_dma_attr_t dma_attr;
+ ddi_device_acc_attr_t *acc_attr;
+
+ int flags =
+ DDI_DMA_REDZONE | DDI_DMA_CONSISTENT | DDI_DMA_READ | DDI_DMA_WRITE;
+
+ if (osdev == NULL)
+ {
+ cmn_err (CE_WARN, "oss_contig_malloc: osdev==NULL\n");
+ return NULL;
+ }
+
+ acc_attr = get_acc_attr (osdev);
+
+ memcpy (&dma_attr, &dma_attr_pci, sizeof (ddi_dma_attr_t));
+ dma_attr.dma_attr_addr_hi = memlimit;
+
+ desc = KERNEL_MALLOC (sizeof (contig_desc));
+ if (desc == NULL)
+ {
+ cmn_err (CE_WARN, "Failed to allocate contig buffer descriptor\n");
+ return NULL;
+ }
+
+ desc->osdev = osdev;
+ desc->next = NULL;
+ desc->is_special = 0;
+
+ if ((err = ddi_dma_alloc_handle (osdev->dip,
+ &dma_attr,
+ DDI_DMA_SLEEP,
+ NULL, &desc->dhandle)) != DDI_SUCCESS)
+ {
+ cmn_err (CE_WARN, "Failed to allocate pci DMA handle (%d)\n", err);
+ return NULL;
+ }
+
+ if (dma_handle != NULL)
+ *dma_handle = desc->dhandle;
+
+#ifndef IOMEM_DATA_UNCACHED
+#define IOMEM_DATA_UNCACHED 0 // Fix for Solaris 10
+#endif
+
+#if defined(sparc)
+ if ((err = ddi_mem_alloc (osdev->dip,
+ NULL,
+ size + 4096,
+ 0,
+ (caddr_t *) & desc->first_addr,
+ (uint_t *) & len)) != DDI_SUCCESS)
+
+
+#else
+ if ((err = ddi_dma_mem_alloc (desc->dhandle,
+ size + 4096,
+ acc_attr,
+ flags,
+ DDI_DMA_SLEEP,
+ NULL,
+ (caddr_t *) & desc->first_addr,
+ (size_t *) & len,
+ &desc->dma_acc_handle)) != DDI_SUCCESS)
+#endif
+ {
+ cmn_err (CE_WARN, "Failed to allocate %d bytes of contig memory (%d)\n",
+ size, err);
+ return NULL;
+
+ }
+
+ desc->size = len;
+ desc->orig_buf = desc->first_addr;
+
+ if (desc->first_addr == NULL)
+ {
+ cmn_err (CE_WARN, "Can't allocate a contig buffer\n");
+ return NULL;
+ }
+
+ DDB (cmn_err
+ (CE_CONT, "Allocated contig memory, addr=%x, len=%d\n",
+ (unsigned int) desc->first_addr, desc->size));
+
+ if ((err = ddi_dma_addr_bind_handle (desc->dhandle,
+ NULL,
+ (char *) desc->first_addr,
+ desc->size,
+ flags | DDI_DMA_STREAMING,
+ DDI_DMA_DONTWAIT,
+ NULL,
+ &desc->cookie, &count)) != DDI_SUCCESS)
+ {
+ cmn_err (CE_WARN, "Contig address setup failed (%d)\n", err);
+ return NULL;
+ }
+
+ desc->physaddr = desc->cookie.dmac_address;
+
+ desc->last_addr = desc->first_addr + desc->size - 1;
+ desc->first_addr =
+ (void *) (((unsigned long) desc->first_addr + 4095) & ~4095);
+ desc->physaddr = (desc->physaddr + 4095) & ~4095;
+ *phaddr = desc->physaddr;
+
+ desc->next = contig_list;
+ contig_list = desc;
+/* HW_PRINTF(("Alloc contig: %x-%x, ph=%x\n", desc->first_addr, desc->last_addr, desc->physaddr)); */
+
+ return desc->first_addr;
+}
+
+/*ARGSUSED*/
+void
+oss_contig_free (oss_device_t * osdev, void *p, int sz)
+{
+ int err;
+ contig_desc *d, *desc = NULL, *prev = NULL;
+
+ if (p == NULL)
+ return;
+
+ d = contig_list;
+
+ while (d && desc == NULL)
+ {
+ if (d->is_special)
+ {
+ prev = d;
+ d = d->next;
+ continue;
+ }
+
+ if (d->first_addr == p)
+ {
+ desc = d;
+ break;
+ }
+
+ prev = d;
+ d = d->next;
+ }
+
+ if (desc == NULL)
+ {
+ cmn_err (CE_WARN, "OSS: Can't free memory\n");
+ return;
+ }
+
+ if ((err = ddi_dma_unbind_handle (desc->dhandle)) != DDI_SUCCESS)
+ cmn_err (CE_WARN, "Failed to free DMA handle (%d)\n", err);
+
+#if defined(sparc)
+ ddi_mem_free (desc->orig_buf);
+#else
+ if (desc->dma_acc_handle == NULL)
+ cmn_err (CE_WARN, "desc->dma_acc_handle==NULL\n");
+ else
+ ddi_dma_mem_free (&desc->dma_acc_handle);
+#endif
+ ddi_dma_free_handle (&desc->dhandle);
+
+
+ if (desc == contig_list)
+ contig_list = desc->next;
+ else
+ {
+ prev->next = desc->next;
+ }
+ KERNEL_FREE (desc);
+
+}
+
+static void
+free_all_contig_memory (void)
+{
+ contig_desc *p, *desc = contig_list;
+
+ while (desc != NULL)
+ {
+ p = desc;
+ desc = desc->next;
+
+ if (p->is_special)
+ continue;
+
+ oss_contig_free (p->osdev, p->orig_buf, 0);
+ }
+
+ contig_list = NULL;
+}
+
+#if !defined(SOL9) && !defined(DISABLE_FMA)
+/*ARGSUSED*/
+static int
+oss_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *osdev_)
+{
+ pci_ereport_post(dip, err, NULL);
+ return err->fme_status;
+}
+#endif
+
+oss_device_t *
+osdev_create (dev_info_t * dip, int dev_type, int instance, const char *nick,
+ const char *handle)
+{
+ oss_device_t *osdev = NULL;
+ int i;
+ ddi_iblock_cookie_t iblk;
+ static int license_checked=0;
+
+#ifdef LICENSED_VERSION
+ if (!license_checked)
+ {
+ timestruc_t ts;
+
+ license_checked = 1;
+ gethrestime (&ts);
+ if (!oss_license_handle_time (ts.tv_sec))
+ {
+ cmn_err (CE_WARN, "This version of Open Sound System has expired\n");
+ cmn_err (CE_CONT,
+ "Please download the latest version from www.opensound.com\n");
+ oss_expired = 1;
+ }
+ }
+#endif
+
+ if (handle == NULL)
+ handle = nick;
+
+ /*
+ * Don't accept any more drivers if expired
+ */
+ if (oss_expired && oss_num_cards > 0)
+ return NULL;
+
+ /*
+ * Check if the same device is being reinserted.
+ */
+ for (i = 0; i < oss_num_cards; i++)
+ {
+ if (cards[i]->available) /* Not deleted */
+ continue;
+
+ if (cards[i]->dip == dip)
+ {
+ osdev = cards[i];
+ break;
+ }
+ }
+
+#if 1
+ if (osdev == NULL)
+ {
+ /*
+ * Check if there are some deleted devices.
+ */
+ for (i = 0; i < oss_num_cards; i++)
+ {
+ if (cards[i]->available) /* Not deleted */
+ continue;
+
+ osdev = cards[i];
+ break;
+ }
+ }
+#endif
+
+ if (osdev == NULL)
+ {
+ for (i=0;i<oss_num_cards;i++)
+ if (!cards[i]->available)
+ {
+ osdev = cards[i];
+ break;
+ }
+ }
+
+ if (osdev == NULL)
+ {
+ if (oss_num_cards >= MAX_CARDS)
+ {
+ cmn_err (CE_WARN, "Too many OSS devices. At most %d permitted.\n",
+ MAX_CARDS);
+ return NULL;
+ }
+
+ if ((osdev = PMALLOC (NULL, sizeof (*osdev))) == NULL)
+ {
+ cmn_err (CE_WARN, "osdev_create: Out of memory\n");
+ return NULL;
+ }
+ memset (osdev, 0, sizeof (*osdev));
+
+ osdev->cardnum = oss_num_cards;
+ cards[oss_num_cards++] = osdev;
+ }
+
+ osdev->dip = dip;
+ osdev->osid = dip;
+ osdev->available = 1;
+ osdev->instance = instance;
+ osdev->dev_type = dev_type;
+ osdev->devc = NULL;
+ sprintf (osdev->nick, "%s%d", nick, instance);
+ strcpy (osdev->modname, nick);
+ osdev->num_audio_engines = 0;
+ osdev->num_audioplay = 0;
+ osdev->num_audiorec = 0;
+ osdev->num_audioduplex = 0;
+ osdev->num_mididevs = 0;
+ osdev->num_mixerdevs = 0;
+ osdev->first_mixer = -1;
+
+ switch (dev_type)
+ {
+ case DRV_PCI:
+ if (pci_config_setup (dip, &osdev->pci_config_handle) != DDI_SUCCESS)
+ cmn_err (CE_NOTE, "pci_config_setup() failed\n");
+#if !defined(SOL9) && !defined(DISABLE_FMA)
+ osdev->fm_capabilities = DDI_FM_EREPORT_CAPABLE | DDI_FM_DMACHK_CAPABLE |
+ DDI_FM_ERRCB_CAPABLE;
+ ddi_fm_init(dip, &osdev->fm_capabilities, &iblk);
+ ddi_fm_handler_register(dip, oss_fm_error_cb, (void*)osdev);
+ pci_ereport_setup(dip);
+#endif
+ break;
+
+ case DRV_VIRTUAL:
+ case DRV_VMIX:
+ case DRV_STREAMS:
+#if !defined(SOL9) && !defined(DISABLE_FMA)
+ osdev->fm_capabilities=DDI_FM_EREPORT_CAPABLE;
+ ddi_fm_init(dip, &osdev->fm_capabilities, &iblk);
+#endif
+ break;
+
+ case DRV_USB:
+ /* NOP */
+ break;
+
+ default:
+ cmn_err (CE_WARN, "Bad device type\n");
+ return NULL;
+ }
+
+/*
+ * Create the device handle
+ */
+ switch (dev_type)
+ {
+ case DRV_PCI:
+ {
+ unsigned int subvendor;
+ pci_read_config_dword (osdev, 0x2c, &subvendor);
+
+ sprintf (osdev->handle, "PCI%08x-%d", subvendor, instance);
+ }
+ break;
+
+ case DRV_USB:
+ /* TODO: Get the vendor information */
+ sprintf (osdev->handle, "USB-%s%d", handle, instance);
+ break;
+
+ default:
+ sprintf (osdev->handle, "%s%d", handle, instance);
+ }
+
+ return osdev;
+}
+
+oss_device_t *
+osdev_clone (oss_device_t * orig_osdev, int new_instance)
+{
+ oss_device_t *osdev;
+
+ osdev = PMALLOC (NULL, sizeof (*osdev));
+ if (osdev == NULL)
+ {
+ cmn_err (CE_WARN, "osdev_create: Out of memory\n");
+ return NULL;
+ }
+ memcpy (osdev, orig_osdev, sizeof (*osdev));
+ osdev->dev_type = DRV_CLONE;
+ osdev->instance = new_instance;
+ sprintf (osdev->nick, "%s%d", orig_osdev->modname, new_instance);
+ sprintf (osdev->handle, "%s%d", orig_osdev->modname, new_instance);
+
+ return osdev;
+}
+
+void
+osdev_delete (oss_device_t * osdev)
+{
+ int i;
+
+ if (osdev == NULL)
+ return;
+
+ if (!osdev->available) /* Already deleted */
+ return;
+
+ osdev->available = 0;
+
+ switch (osdev->dev_type)
+ {
+ case DRV_PCI:
+#if !defined(SOL9) && !defined(DISABLE_FMA)
+ ddi_fm_handler_unregister(osdev->dip);
+ pci_ereport_teardown(osdev->dip);
+#endif
+ pci_config_teardown (&osdev->pci_config_handle);
+#if !defined(SOL9) && !defined(DISABLE_FMA)
+ ddi_fm_fini(osdev->dip);
+#endif
+ osdev->pci_config_handle = NULL;
+ break;
+
+ case DRV_VIRTUAL:
+ case DRV_VMIX:
+ case DRV_STREAMS:
+#if !defined(SOL9) && !defined(DISABLE_FMA)
+ ddi_fm_fini(osdev->dip);
+#endif
+ break;
+ }
+
+ ddi_remove_minor_node (osdev->dip, NULL);
+
+/*
+ * Mark all minor nodes for this module as invalid.
+ */
+ for (i = 0; i < oss_num_cdevs; i++)
+ if (oss_cdevs[i] != NULL)
+ if (oss_cdevs[i]->osdev == osdev)
+ {
+ unlink_cdev_hash(oss_cdevs[i]);
+ oss_cdevs[i]->d = NULL;
+ oss_cdevs[i]->osdev = NULL;
+ oss_cdevs[i]->active = 0; /* Device removed */
+ }
+}
+
+int
+oss_get_cardinfo (int cardnum, oss_card_info * ci)
+{
+/*
+ * Print information about a 'card' in a format suitable for /dev/sndstat
+ */
+
+ if (cardnum < 0 || cardnum >= oss_num_cards)
+ return OSS_ENXIO;
+
+ if (cards[cardnum]->name != NULL)
+ strncpy (ci->longname, cards[cardnum]->name, 128);
+ ci->shortname[127] = 0;
+
+ if (cards[cardnum]->nick != NULL)
+ strncpy (ci->shortname, cards[cardnum]->nick, 16);
+ ci->shortname[15] = 0;
+
+ if (cards[cardnum]->hw_info != NULL)
+ strncpy (ci->hw_info, cards[cardnum]->hw_info, sizeof (ci->hw_info) - 1);
+ ci->hw_info[sizeof (ci->hw_info) - 1] = 0;
+ ci->intr_count = cards[cardnum]->intrcount;
+ ci->ack_count = cards[cardnum]->ackcount;
+
+ return 0;
+}
+
+static int
+grow_array(oss_device_t *osdev, oss_cdev_t ***arr, int *size, int element_size, int increment)
+{
+ oss_cdev_t **old=*arr, **new = *arr;
+ int old_size = *size;
+ int new_size = *size;
+
+ new_size += increment;
+
+ if ((new=PMALLOC(osdev, new_size * element_size))==NULL)
+ return 0;
+
+ memset(new, 0, new_size * element_size);
+ if (old != NULL)
+ memcpy(new, old, old_size * element_size);
+
+ *size = new_size;
+ *arr = new;
+
+ if (old != NULL)
+ PMFREE(osdev, old);
+
+ return 1;
+}
+
+/*ARGSUSED*/
+void
+oss_install_chrdev (oss_device_t * osdev, char *name, int dev_class,
+ int instance, oss_cdev_drv_t * drv, int flags)
+{
+/*
+ * oss_install_chrdev creates a character device (minor). However if
+ * name==NULL the device will not be exported (made visible to userland
+ * clients).
+ */
+
+ int num;
+ int hash_link;
+ oss_cdev_t *cdev = NULL;
+
+ if (dev_class != OSS_DEV_STATUS)
+ if (oss_expired && instance > 0)
+ return;
+/*
+ * Find if this dev_class&instance already exists (after previous module
+ * detach).
+ */
+
+ if (flags & CHDEV_REPLUG)
+ for (num = 0; num < oss_num_cdevs; num++)
+ if (oss_cdevs[num]->d == NULL) /* Unloaded driver */
+ if (oss_cdevs[num]->dev_class == dev_class
+ && oss_cdevs[num]->instance == instance)
+ {
+ cdev = oss_cdevs[num];
+ break;
+ }
+
+ if (cdev == NULL)
+ {
+ if (oss_num_cdevs >= OSS_MAX_CDEVS)
+ {
+ if (!grow_array(osdev, &oss_cdevs, &oss_max_cdevs, sizeof(oss_cdev_t*), 100))
+ {
+ cmn_err (CE_WARN, "Cannot allocate new minor numbers.\n");
+ return;
+ }
+ }
+
+ if ((cdev = PMALLOC (NULL, sizeof (*cdev))) == NULL)
+ {
+ cmn_err (CE_WARN, "Cannot allocate character device desc.\n");
+ return;
+ }
+ num = oss_num_cdevs++;
+ }
+
+ memset (cdev, 0, sizeof (*cdev));
+ cdev->dev_class = dev_class;
+ cdev->instance = instance;
+ cdev->d = drv;
+ cdev->active = 1;
+ cdev->osdev = osdev;
+ if (name != NULL)
+ strncpy (cdev->name, name, sizeof (cdev->name) - 1);
+ else
+ strcpy (cdev->name, "NONE");
+ cdev->name[sizeof (cdev->name) - 1] = 0;
+ oss_cdevs[num] = cdev;
+
+ cdev->minor = num;
+
+ /*
+ * Add to the cdev_hash list.
+ */
+ hash_link = compute_cdev_hash (dev_class, instance);
+ cdev->hl = cdev_hash[hash_link];
+ cdev_hash[hash_link] = cdev;
+
+/*
+ * Export the device only if name != NULL
+ */
+ if (name != NULL)
+ {
+ char tmp[64], *s;
+ char *dev_type = "oss_sysdev";
+
+/*
+ * Convert "oss/device/node" style names to the
+ * "device,node" style naming required by Solaris.
+ */
+ if (name[0] == 'o' && name[3] == '/') /* oss/ prefix */
+ {
+ strcpy (tmp, name + 4);
+ name = tmp;
+
+ s = tmp;
+ while (*s)
+ {
+ if (*s == '/')
+ *s = ',';
+ s++;
+ }
+ dev_type = "oss_audio";
+ }
+
+ if (ddi_create_minor_node (osdev->dip, name, S_IFCHR, num,
+ dev_type, 0) == DDI_FAILURE)
+ {
+ cmn_err (CE_WARN, "ddi_create_minor_node failed\n");
+ }
+ }
+}
+
+int
+oss_find_minor (int dev_class, int instance)
+{
+ oss_cdev_t *cdev;
+
+ cdev = cdev_hash[compute_cdev_hash(dev_class, instance)];
+
+ while (cdev != NULL)
+ {
+ if (cdev->d != NULL && cdev->dev_class == dev_class
+ && cdev->instance == instance)
+ return cdev->minor;
+ cdev = cdev->hl; /* Next in the hash chain */
+ }
+
+ return OSS_EIO;
+}
+
+int
+__oss_alloc_dmabuf (int dev, dmap_p dmap, unsigned int alloc_flags,
+ oss_uint64_t maxaddr, int direction)
+{
+ int err;
+#if defined(sparc)
+ uint_t len;
+#else
+ size_t len;
+#endif
+ uint_t ncookies;
+ contig_desc *desc;
+ oss_device_t *osdev = dmap->osdev;
+ ddi_dma_attr_t dma_attr;
+ int size = 32 * 1024;
+ extern int dma_buffsize;
+ ddi_device_acc_attr_t *acc_attr;
+
+ int flags = DDI_DMA_REDZONE | DDI_DMA_CONSISTENT |
+ (direction == OPEN_READ) ? DDI_DMA_READ : DDI_DMA_WRITE;
+
+ if (osdev == NULL)
+ {
+ cmn_err (CE_WARN, "oss_alloc_dmabuf: osdev==NULL\n");
+ return OSS_EIO;
+ }
+
+ acc_attr = get_acc_attr (osdev);
+
+ if (dma_buffsize > 16 && dma_buffsize <= 128)
+ size = dma_buffsize * 1024;
+
+/*
+ * Some applications and virtual drivers need shorter buffer.
+ */
+ if (dmap->flags & DMAP_SMALLBUF)
+ {
+ size = SMALL_DMABUF_SIZE;
+ }
+ else if (dmap->flags & DMAP_MEDIUMBUF)
+ {
+ size = MEDIUM_DMABUF_SIZE;
+ }
+
+ if (alloc_flags & DMABUF_LARGE)
+ size = 256 * 1024;
+
+ if ((alloc_flags & DMABUF_SIZE_16BITS) && size > 32 * 1024)
+ size = 32 * 1024;
+
+ memcpy (&dma_attr, &dma_attr_pci, sizeof (ddi_dma_attr_t));
+ dma_attr.dma_attr_addr_hi = maxaddr;
+
+#ifndef SOL9
+ if (osdev->dev_type == DRV_PCI)
+ dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
+#endif
+
+ if (dmap->dmabuf != NULL)
+ return 0; /* Already done */
+
+ dmap->dma_parms.state = 0;
+ dmap->dma_parms.enabled = 1;
+ dmap->dma_parms.ignore = 0;
+
+ if (osdev->dip == NULL)
+ {
+ cmn_err (CE_WARN, "oss_alloc_dmabuf: osdev->dip==NULL\n");
+ return OSS_EIO;
+ }
+
+ if (dmap == NULL)
+ {
+ cmn_err (CE_WARN, "oss_alloc_dmabuf: dmap==NULL\n");
+ return OSS_EIO;
+ }
+
+ if ((err = ddi_dma_alloc_handle (osdev->dip,
+ &dma_attr,
+ DDI_DMA_SLEEP,
+ NULL,
+ &dmap->dmabuf_dma_handle)) != DDI_SUCCESS)
+ {
+ cmn_err (CE_WARN, "Failed to allocate DMA handle (error %d)\n", err);
+ return OSS_ENOMEM;
+ }
+
+
+ dmap->dmabuf = NULL;
+ dmap->buffsize = size;
+
+ err = -1;
+
+ while (err != DDI_SUCCESS && dmap->dmabuf == NULL && dmap->buffsize >= 4096)
+ {
+#if defined(sparc)
+ if ((err = ddi_mem_alloc (osdev->dip,
+ NULL,
+ dmap->buffsize,
+ 0,
+ (caddr_t *) & dmap->dmabuf,
+ (uint_t *) & len)) != DDI_SUCCESS)
+#else
+ if ((err = ddi_dma_mem_alloc (dmap->dmabuf_dma_handle,
+ dmap->buffsize,
+ acc_attr,
+ flags,
+ DDI_DMA_SLEEP,
+ NULL,
+ (caddr_t *) & dmap->dmabuf,
+ (size_t *) & len,
+ &dmap->dma_parms.dma_acc_handle)) !=
+ DDI_SUCCESS)
+#endif
+ {
+ if (!(alloc_flags & DMABUF_QUIET))
+ DDB (cmn_err (CE_WARN,
+ "failed to allocate %d bytes of DMA memory (%d)\n",
+ dmap->buffsize, err));
+ dmap->dmabuf = NULL;
+ dmap->buffsize /= 2;
+ }
+ }
+
+ if (dmap->dmabuf == NULL)
+ {
+ cmn_err (CE_WARN, "Can't allocate a DMA buffer for device %d\n", dev);
+ ddi_dma_free_handle (&dmap->dmabuf_dma_handle);
+ return OSS_ENOMEM;
+ }
+
+ DDB (cmn_err (CE_CONT, "Allocated DMA memory, addr=%x, len=%d\n",
+ (int) dmap->dmabuf, (int) dmap->buffsize));
+
+ dmap->dma_parms.orig_buf = (caddr_t) dmap->dmabuf;
+
+ if ((err = ddi_dma_addr_bind_handle (dmap->dmabuf_dma_handle,
+ NULL,
+ (char *) dmap->dmabuf,
+ dmap->buffsize,
+ flags | DDI_DMA_STREAMING,
+ DDI_DMA_DONTWAIT,
+ NULL,
+ &dmap->dma_parms.cookie,
+ &ncookies)) != DDI_SUCCESS)
+ {
+ cmn_err (CE_WARN, "DMA address setup failed (%d)\n", err);
+
+ return OSS_EIO;
+ }
+
+ dmap->dmabuf =
+ (unsigned char *) ((((unsigned long) dmap->dmabuf) + 4095) & ~4095);
+ dmap->dmabuf_phys = (dmap->dma_parms.cookie.dmac_address + 4095) & ~4095;
+
+ desc = PMALLOC (osdev, sizeof (contig_desc));
+ if (desc == NULL)
+ return OSS_ENOMEM;
+
+ desc->osdev = osdev;
+ desc->next = NULL;
+ desc->is_special = 1;
+ desc->first_addr = dmap->dmabuf;
+ desc->last_addr = dmap->dmabuf + dmap->buffsize - 1;
+ desc->physaddr = dmap->dmabuf_phys;
+ desc->orig_buf = dmap->dma_parms.orig_buf;
+
+ if (contig_list != NULL)
+ desc->next = contig_list;
+/* HW_PRINTF(("Alloc DMA: %x-%x, ph=%x\n", desc->first_addr, desc->last_addr, desc->physaddr)); */
+ contig_list = desc;
+
+ return 0;
+}
+
+/*ARGSUSED*/
+void
+oss_free_dmabuf (int dev, dmap_p dmap)
+{
+ int err;
+
+ if (dmap->dmabuf == NULL)
+ return;
+
+ if ((err = ddi_dma_unbind_handle (dmap->dmabuf_dma_handle)) != DDI_SUCCESS)
+ cmn_err (CE_WARN, "Failed to free DMA handle (%d)\n", err);
+#if defined(sparc)
+ ddi_mem_free (dmap->dma_parms.orig_buf);
+#else
+ ddi_dma_mem_free (&dmap->dma_parms.dma_acc_handle);
+#endif
+ ddi_dma_free_handle (&dmap->dmabuf_dma_handle);
+
+ dmap->dmabuf = NULL;
+ dmap->dmabuf_phys = 0;
+}
+
+/*
+ * Interrupt management
+ */
+static u_int
+oss_intr (caddr_t arg) /* Global interrupt handler */
+{
+ oss_device_t *osdev = (oss_device_t *) arg;
+ int serviced;
+#ifdef MUTEX_CHECKS
+ int x = inside_intr;
+ inside_intr = 1; /* For mutex debugging only */
+#endif
+
+ if (osdev == NULL)
+ {
+#ifdef MUTEX_CHECKS
+ inside_intr = x;
+#endif
+ return DDI_INTR_UNCLAIMED;
+ }
+ osdev->intrcount++;
+
+ UP_STATUS (0x01);
+ serviced = osdev->tophalf_handler (osdev);
+ DOWN_STATUS (0x01);
+
+ if (serviced == 0)
+ return DDI_INTR_UNCLAIMED;
+ osdev->ackcount++;
+
+ if (osdev->bottomhalf_handler == NULL)
+ return DDI_INTR_CLAIMED;
+
+#if 0
+ if (osdev->intr_is_hilevel)
+ {
+/* TODO: Schedule the bottom half handler */
+ }
+ else
+#endif
+ osdev->bottomhalf_handler (osdev);
+
+#ifdef MUTEX_CHECKS
+ inside_intr = x;
+#endif
+ return DDI_INTR_CLAIMED;
+}
+
+int
+oss_register_interrupts (oss_device_t * osdev, int intrnum,
+ oss_tophalf_handler_t top,
+ oss_bottomhalf_handler_t bottom)
+{
+ int err;
+ ddi_idevice_cookie_t ic;
+
+
+ if (intrnum != 0)
+ {
+ cmn_err (CE_WARN, "Bad interrupt index (%d) for %s\n", intrnum,
+ osdev->name);
+ return OSS_EINVAL;
+ }
+
+ if (osdev == NULL)
+ {
+ cmn_err (CE_WARN, "oss_register_interrupts: Bad osdev\n");
+ return OSS_EINVAL;
+ }
+
+ if (osdev->tophalf_handler != NULL || osdev->bottomhalf_handler != NULL)
+ {
+ cmn_err (CE_WARN, "Interrupts already registered for %s\n",
+ osdev->name);
+ return OSS_EINVAL;
+ }
+
+ if (top == NULL)
+ {
+ cmn_err (CE_WARN, "Bad interrupt handler for %s\n", osdev->name);
+ return OSS_EINVAL;
+ }
+
+ osdev->tophalf_handler = top;
+ osdev->bottomhalf_handler = bottom;
+ osdev->intr_is_hilevel = ddi_intr_hilevel (osdev->dip, intrnum);
+ if (osdev->intr_is_hilevel)
+ {
+ if (bottom == NULL)
+ {
+ cmn_err (CE_WARN,
+ "The driver for %s doesn't support hilevel interrupts\n",
+ osdev->name);
+ return OSS_EINVAL;
+ }
+
+ DDB (cmn_err (CE_NOTE, "Using hilevel intr for %s\n", osdev->name));
+
+ /* TODO: Fix hilevel intr handling */
+ cmn_err (CE_WARN, "Hilevel interrupts are not supported yet.\n");
+ return OSS_EINVAL;
+ }
+
+ ddi_get_iblock_cookie (osdev->dip, intrnum, &osdev->iblock_cookie);
+
+ if ((err = ddi_add_intr (osdev->dip, intrnum, NULL, &ic,
+ oss_intr, (caddr_t) osdev)) != DDI_SUCCESS)
+ {
+ cmn_err (CE_WARN, "ddi_add_intr() failed, error=%d\n", err);
+ return OSS_EIO;
+ }
+
+ return 0;
+}
+
+void
+oss_unregister_interrupts (oss_device_t * osdev)
+{
+ ddi_remove_intr (osdev->dip, 0, osdev->iblock_cookie);
+ osdev->tophalf_handler = NULL;
+ osdev->bottomhalf_handler = NULL;
+}
+
+/*ARGSUSED*/
+int
+oss_register_device (oss_device_t * osdev, const char *name)
+{
+
+ if ((osdev->name = PMALLOC (NULL, strlen (name) + 1)) == NULL)
+ {
+ cmn_err (CE_WARN, "Cannot allocate memory for device name\n");
+ osdev->name = "Unknown device";
+ }
+ strcpy (osdev->name, name);
+ return 0;
+}
+
+int
+oss_disable_device (oss_device_t * osdev)
+{
+ int i;
+/*
+ * This routine should check if the device is ready to be unloaded (no devices are in use).
+ * If the device cannot be unloaded this routine must return OSS_EBUSY.
+ *
+ * If the device can be unloaded then disable any timers or other features that may cause the
+ * device to be called. Also mark the audio/midi/mixer/etc devices of this device to be disabled.
+ * However the interrupt handler should still stay enabled. The low level driver will call
+ * oss_unregister_interrupts() after it has cleared the interrupt enable register.
+ */
+ if (osdev->refcount > 0 || open_devices > 0)
+ {
+ cmn_err (CE_CONT, "Refcount %d (%s) , open_devices %d\n",
+ osdev->refcount, osdev->nick, open_devices);
+ if (open_devices > 0)
+ {
+ int i;
+
+ for (i = 0; i < oss_num_cdevs; i++)
+ if (oss_cdevs[i]->open_count)
+ {
+ cmn_err (CE_CONT, "%s is opened\n", oss_cdevs[i]->name);
+ }
+ }
+ return OSS_EBUSY;
+ }
+//cmn_err(CE_CONT, "oss_disable_device %s\n", osdev->nick);
+
+/*
+ * Now mark all devices unavailable (for the time being)
+ */
+
+ for (i = 0; i < num_mixers; i++)
+ if (mixer_devs[i]->osdev == osdev)
+ {
+ mixer_devs[i]->unloaded = 1;
+ }
+
+ for (i = 0; i < num_mididevs; i++)
+ {
+ if (midi_devs[i]->osdev == osdev)
+ {
+ midi_devs[i]->unloaded = 1;
+ }
+ }
+
+ for (i = 0; i < num_audio_engines; i++)
+ if (audio_engines[i]->osdev == osdev)
+ {
+ audio_uninit_device (i);
+ }
+
+ return 0;
+}
+
+/*ARGSUSED*/
+void
+oss_unregister_device (oss_device_t * osdev)
+{
+/*
+ * Notice! The driver calling this routine (the owner of the osdev parameter)
+ * has already uninitialized itself. Do not do any actions that may call this
+ * driver directly or indirectly.
+ */
+
+/*
+ * Force reload of all drivers if any application tries to open any
+ * of the devices.
+ */
+ do_forceload = 1;
+}
+
+void
+oss_reserve_device (oss_device_t * osdev)
+{
+ osdev->refcount++;
+}
+
+void
+oss_unreserve_device (oss_device_t * osdev, int decrement)
+{
+ osdev->refcount -= decrement;
+}
+
+/*
+ * Wait queue support
+ */
+ /*ARGSUSED*/
+ oss_wait_queue_t *
+oss_create_wait_queue (oss_device_t * osdev, const char *name)
+{
+ oss_wait_queue_t *wq;
+
+ if ((wq = PMALLOC (NULL, sizeof (*wq))) == NULL)
+ return NULL;
+
+ cv_init (&wq->cv, NULL, CV_DRIVER, NULL);
+
+ return wq;
+}
+
+void *
+oss_get_osid (oss_device_t * osdev)
+{
+ return osdev->osid;
+}
+
+/*ARGSUSED*/
+void
+oss_reset_wait_queue (oss_wait_queue_t * wq)
+{
+ /* NOP */
+}
+
+void
+oss_remove_wait_queue (oss_wait_queue_t * wq)
+{
+ cv_destroy (&wq->cv);
+}
+
+/*ARGSUSED*/
+int
+oss_sleep (oss_wait_queue_t * wq, oss_mutex_t * mutex, int ticks,
+ oss_native_word * flags, unsigned int *status)
+{
+/*
+ * oss_sleep will return 0 if timeout occurred and 1 otherwise. The WK_SIGNAL bit will be reported on
+ * status if a signal was caught.
+ */
+ *status = 0;
+
+ if (ticks > 0)
+ {
+ int res;
+
+ if ((res =
+ cv_timedwait_sig (&wq->cv, mutex, ddi_get_lbolt () + ticks)) == 0)
+ *status |= WK_SIGNAL; /* Got signal */
+ if (res < 0) /* Timeout */
+ return 0;
+ }
+ else
+ {
+ if (cv_wait_sig (&wq->cv, mutex) == 0)
+ *status |= WK_SIGNAL; /* Got signal */
+ }
+ return 1;
+}
+
+/*ARGSUSED*/
+int
+oss_register_poll (oss_wait_queue_t * wq, oss_mutex_t * mutex,
+ oss_native_word * flags, oss_poll_event_t * ev)
+{
+ ev->php = &wq->ph;
+ wq->pollevents |= ev->events;
+ return 0;
+}
+
+/*ARGSUSED*/
+void
+oss_wakeup (oss_wait_queue_t * wq, oss_mutex_t * mutex,
+ oss_native_word * flags, short events)
+{
+ cv_broadcast (&wq->cv);
+
+ if (wq->pollevents & events)
+ {
+ wq->pollevents &= ~events;
+ MUTEX_EXIT_IRQRESTORE (*mutex, *flags);
+ pollwakeup (&wq->ph, events);
+ MUTEX_ENTER_IRQDISABLE (*mutex, *flags);
+ }
+}
+
+#ifdef MUTEX_CHECKS
+void
+debug_mutex_init (oss_mutex_t * mutex, void *dummy, int typ, void *arg,
+ char *file, int line)
+{
+ memset (mutex, 0, sizeof (mutex));
+ mutex_init (&mutex->mu, dummy, typ, arg);
+}
+
+void
+debug_mutex_destroy (oss_mutex_t * mutex, char *file, int line)
+{
+ mutex_destroy (&mutex->mu);
+}
+
+void
+debug_mutex_enter (oss_mutex_t * mutex, char *file, int line)
+{
+ if (mutex_owned (&mutex->mu))
+ {
+ cmn_err (CE_NOTE, "%s:%d: Re-entrant mutex (%s:%d %d)\n", file, line,
+ mutex->file, mutex->line, mutex->busy_flags);
+ return;
+ }
+
+ mutex->file = file;
+ mutex->line = line;
+ mutex_enter (&mutex->mu);
+}
+
+void
+debug_mutex_exit (oss_mutex_t * mutex, char *file, int line)
+{
+ if (!mutex_owned (&mutex->mu))
+ {
+ cmn_err (CE_NOTE, "Mutex not owned %s:%d\n", file, line);
+ }
+ else
+ mutex_exit (&mutex->mu);
+
+ mutex->file = NULL;
+ mutex->line = 0;
+}
+#endif
+
+int
+oss_get_procinfo(int what)
+{
+
+ switch (what)
+ {
+ case OSS_GET_PROCINFO_UID:
+ return ddi_get_cred()->cr_uid;
+ break;
+
+ case OSS_GET_PROCINFO_GID:
+ return ddi_get_cred()->cr_gid;
+ break;
+
+#if 0
+ case OSS_GET_PROCINFO_PGID:
+ return ddi_get_cred()->cr_pgid;
+ break;
+#endif
+
+ }
+ return OSS_EINVAL;
+}
diff --git a/kernel/OS/SunOS/os_solaris.h b/kernel/OS/SunOS/os_solaris.h
new file mode 100644
index 0000000..2b36b86
--- /dev/null
+++ b/kernel/OS/SunOS/os_solaris.h
@@ -0,0 +1,518 @@
+#ifndef _OS_H_
+#define _OS_H_
+
+/*
+ * Purpose: OS specific definitions for Solaris
+ *
+ */
+/*
+ *
+ * This file is part of Open Sound System.
+ *
+ * Copyright (C) 4Front Technologies 1996-2008.
+ *
+ * This this source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ */
+
+#define OS_VERSION "10"
+#define SUNDDI
+#define __EXTENDED__
+#define Solaris
+
+#if (!defined(i386) && !defined(x86_64)) || defined(CONFIG_OSS_FIXDEPOINT)
+// Floating point is not supported or it's disabled
+#undef CONFIG_OSS_VMIX_FLOAT
+#endif
+
+#define VDEV_SUPPORT
+#define USE_DEVICE_SUBDIRS
+
+#define __inline__ inline
+#define __inline inline
+#define EXTERN_C extern "C"
+
+/*
+ * Debugging and misc settings
+ */
+#undef MUTEX_CHECKS
+#undef MEMDEBUG
+
+/*
+ * Disable support for per-application features such as /dev/dsp device
+ * selection based on command name. Requires working GET_PROCESS_NAME
+ * macro implementation.
+ */
+#undef APPLIST_SUPPORT
+
+/*
+ * Some integer types
+ */
+#if defined(amd64) || defined(sparc)
+typedef unsigned long long oss_native_word; /* Same as the address and status register size */
+#else
+typedef unsigned long oss_native_word; /* Same as the address and status register size */
+#endif
+
+typedef long long oss_int64_t; /* Signed 64 bit integer */
+typedef unsigned long long oss_uint64_t; /* Unsigned 64 bit integer */
+
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/types32.h>
+#include <sys/param.h>
+#include <sys/signal.h>
+#include <oss_errno.h>
+#include <sys/file.h>
+#include <sys/conf.h>
+#include <sys/uio.h>
+#include <sys/map.h>
+#include <sys/debug.h>
+#include <sys/modctl.h>
+#include <sys/kmem.h>
+#include <sys/cmn_err.h>
+#include <sys/open.h>
+#include <sys/stat.h>
+#ifndef sparc
+#include <sys/dditypes.h>
+#include <sys/ddidmareq.h>
+#include <sys/dma_engine.h>
+#endif
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/fcntl.h>
+#include <sys/ddidmareq.h>
+#include <sys/ksynch.h>
+#include <sys/poll.h>
+#ifdef SOL9
+#include <sys/cred.h>
+#else
+#include <sys/cred_impl.h>
+#endif
+
+#ifndef SOL9
+#include <sys/ddifm.h>
+#include <sys/fm/protocol.h>
+#include <sys/fm/util.h>
+#include <sys/fm/io/ddi.h>
+#endif
+
+#undef HZ
+#define OSS_HZ hz
+
+#ifdef sparc
+/*
+ * It's not possible to use SB Live! under Sparc architecture.
+ */
+#define AUDIGY_ONLY
+#endif
+
+/*
+ * Need to use slightly larger buffer because otherwise the interrupt
+ * rate will become too high for Solaris.
+ */
+#undef SMALL_DMABUF_SIZE
+#define SMALL_DMABUF_SIZE (16*1024)
+
+/* The soundcard.h could be in a nonstandard place so include it here. */
+#include "soundcard.h"
+
+typedef struct udi_usb_devc udi_usb_devc;
+
+struct _oss_device_t
+{
+ int cardnum;
+ int dev_type;
+ int instance;
+ int available;
+ dev_info_t *dip;
+ void *osid;
+ void *devc;
+ char *name;
+ char nick[16];
+ char modname[32];
+ char handle[32];
+ int num_audio_engines;
+ int num_audioplay, num_audiorec, num_audioduplex;
+ int num_mididevs;
+ int num_mixerdevs;
+ int num_loopdevs;
+ int first_mixer; /* This must be set to -1 by osdev_create() */
+ char *hw_info;
+
+ volatile int refcount; /* Nonzero means that the device is needed by some other (virtual) driver. */
+
+/* Interrupts */
+
+ ddi_iblock_cookie_t iblock_cookie;
+ int intr_is_hilevel;
+ oss_tophalf_handler_t tophalf_handler;
+ oss_bottomhalf_handler_t bottomhalf_handler;
+ int intrcount, ackcount;
+
+#ifdef _KERNEL
+/* PCI related fields */
+ ddi_acc_handle_t pci_config_handle;
+#define OSS_MAX_ACC_HANDLE 10
+ ddi_acc_handle_t acc_handle[OSS_MAX_ACC_HANDLE];
+ int swap_mode; /* 0=DDI_STRUCTURE_NEVERSWAP_ACC, 1=DDI_STRUCTURE_LE_ACC */
+
+/* USB fields */
+ udi_usb_devc *usbdev;
+
+#ifndef SOL9
+/* Fault management (FMA) */
+ int fm_capabilities;
+#endif
+#endif
+};
+
+/*
+ * Support for select()
+ */
+
+struct _oss_poll_event_t
+{
+ short events, revents;
+ struct pollhead *php;
+ int anyyet;
+};
+typedef struct _oss_poll_event_t oss_poll_event_t;
+
+#define ALLOW_SELECT
+#define SEL_IN 0
+#define SEL_OUT 1
+#define SEL_EX 0xffffffff
+
+/*
+ * Sleep/wakeup
+ */
+
+#ifdef _KERNEL
+struct oss_wait_queue
+{
+ kcondvar_t cv;
+ short pollevents;
+ struct pollhead ph;
+};
+#endif
+
+/* Busy wait routine */
+#define oss_udelay drv_usecwait
+/* System wall timer access */
+#define GET_JIFFIES() ddi_get_lbolt()
+
+/*
+ * Mutexes
+ */
+
+#ifdef MUTEX_CHECKS
+/* Debugging version */
+struct _oss_mutex_t
+{
+ kmutex_t mu;
+ char *file;
+ int line;
+ int busy_flags;
+#define CNTX_INTR 1
+#define CNTX_USER 2
+};
+
+typedef struct _oss_mutex_t oss_mutex_t;
+extern void debug_mutex_init (oss_mutex_t * mutex, void *dummy, int typ,
+ void *arg, char *file, int line);
+extern void debug_mutex_destroy (oss_mutex_t * mutex, char *file, int line);
+extern void debug_mutex_enter (oss_mutex_t * mutex, char *file, int line);
+extern void debug_mutex_exit (oss_mutex_t * mutex, char *file, int line);
+
+#define MUTEX_INIT(osdev, mutex, hier) debug_mutex_init(&mutex, NULL, MUTEX_DRIVER, osdev->iblock_cookie, __FILE__, __LINE__)
+#define MUTEX_CLEANUP(mutex) debug_mutex_destroy(&mutex, __FILE__, __LINE__)
+#define MUTEX_ENTER_IRQDISABLE(mutex, flags) flags=0;debug_mutex_enter(&mutex, __FILE__, __LINE__)
+#define MUTEX_ENTER(mutex, flags) flags=0;debug_mutex_enter(&mutex, __FILE__, __LINE__)
+#define MUTEX_EXIT_IRQRESTORE(mutex, flags) debug_mutex_exit(&mutex, __FILE__, __LINE__);(flags)++
+#define MUTEX_EXIT(mutex, flags) debug_mutex_exit(&mutex, __FILE__, __LINE__);(flags)++
+#else
+typedef kmutex_t oss_mutex_t;
+#define MUTEX_INIT(osdev, mutex, hier) mutex_init(&mutex, NULL, MUTEX_DRIVER, osdev->iblock_cookie)
+#define MUTEX_CLEANUP(mutex) mutex_destroy(&mutex)
+#define MUTEX_ENTER_IRQDISABLE(mutex, flags) flags=0;mutex_enter(&mutex)
+#define MUTEX_ENTER(mutex, flags) flags=0;mutex_enter(&mutex)
+#define MUTEX_EXIT_IRQRESTORE(mutex, flags) mutex_exit(&mutex);(flags)++
+#define MUTEX_EXIT(mutex, flags) mutex_exit(&mutex);(flags)++
+#endif
+
+/*
+ * Move bytes from the buffer which the application given in a
+ * write() call.
+ * offs is position relative to the beginning of the buffer in
+ * user space. The count is number of bytes to be moved.
+ */
+#define COPY_FROM_USER(target, source, offs, count) \
+ if (uiomove((target), count, UIO_WRITE, source)) { \
+ cmn_err(CE_WARN, "Bad copyin()!\n"); \
+ }
+/* Like COPY_FOM_USER but for writes. */
+#define COPY_TO_USER(target, offs, source, count) \
+ if (uiomove((source), count, UIO_READ, target)) { \
+ cmn_err(CE_WARN, "Bad copyout()!\n"); \
+ }
+
+/*
+ * INB() and OUTB() should be obvious. NOTE! The order of
+ * paratemeters of OUTB() is different than on some other
+ * operating systems.
+ */
+
+#ifdef sparc
+#ifdef _KERNEL
+extern void oss_put16 (ddi_acc_handle_t handle, unsigned short *addr,
+ unsigned short value);
+extern void oss_put32 (ddi_acc_handle_t handle, unsigned int *addr,
+ unsigned int value);
+extern unsigned short oss_get16 (ddi_acc_handle_t handle,
+ unsigned short *addr);
+extern unsigned int oss_get32 (ddi_acc_handle_t handle, unsigned int *addr);
+
+#define INB(osdev,port) ddi_get8((osdev)->acc_handle[0], (uint8_t*)(port))
+#define OUTB(osdev, d, port) ddi_put8((osdev)->acc_handle[0], (uint8_t*)(port), (d))
+#define INW(osdev,port) oss_get16((osdev)->acc_handle[0], (uint16_t*)(port))
+#define OUTW(osdev, d, port) oss_put16((osdev)->acc_handle[0], (uint16_t*)(port), (d))
+#define INL(osdev,port) oss_get32((osdev)->acc_handle[0], (uint32_t*)(port))
+#define OUTL(osdev,d, port) oss_put32((osdev)->acc_handle[0], (uint32_t*)(port), (d))
+
+/* Memory Mapped devices */
+extern uint16_t oss_mem_get16 (ddi_acc_handle_t handle, uint16_t * addr);
+extern uint32_t oss_mem_get32 (ddi_acc_handle_t handle, uint32_t * addr);
+extern void oss_mem_put16 (ddi_acc_handle_t handle, uint16_t * add,
+ uint16_t v);
+extern void oss_mem_put32 (ddi_acc_handle_t handle, uint32_t * add,
+ uint32_t v);
+#define PCI_READW(osdev, addr) oss_mem_get16((osdev)->acc_handle[0], (uint16_t*)(addr))
+#define PCI_READL(osdev, addr) oss_mem_get32((osdev)->acc_handle[0], (uint32_t*)(addr))
+#define PCI_WRITEW(osdev, addr, data) oss_mem_put16((osdev)->acc_handle[0], (uint16_t*)(addr), data)
+#define PCI_WRITEL(osdev, addr, data) oss_mem_put32((osdev)->acc_handle[0], (uint32_t*)(addr), data)
+#endif
+#else /* x86/AMD64 */
+/* I/O Mapped devices */
+#define INB(o, p) inb(p)
+#define INW(o, p) inw(p)
+#define INL(o, p) inl(p)
+
+#define OUTB(o, v, p) outb(p,v)
+#define OUTW(o, v, p) outw(p,v)
+#define OUTL(o, v, p) outl(p,v)
+
+/* Memory Mapped devices */
+#define PCI_READW(osdev, addr) ddi_mem_get16((osdev)->acc_handle[0], (uint16_t*)(addr))
+#define PCI_READL(osdev, addr) ddi_mem_get32((osdev)->acc_handle[0], (uint32_t*)(addr))
+#define PCI_WRITEW(osdev, addr, data) ddi_mem_put16((osdev)->acc_handle[0], (uint16_t*)(addr), data)
+#define PCI_WRITEL(osdev, addr, data) ddi_mem_put32((osdev)->acc_handle[0], (uint32_t*)(addr), data)
+#endif
+
+#define PCI_READB(osdev, addr) ddi_mem_get8((osdev)->acc_handle[0], addr)
+#define PCI_WRITEB(osdev, addr, data) ddi_mem_put8((osdev)->acc_handle[0], addr, data)
+
+typedef ddi_dma_handle_t oss_dma_handle_t;
+
+/*
+ KERNEL_MALLOC() allocates requested number of memory and
+ KERNEL_FREE is used to free it.
+ These macros are never called from interrupt, in addition the
+ nbytes will never be more than 4096 bytes. Generally the driver
+ will allocate memory in blocks of 4k. If the kernel has just a
+ page level memory allocation, 4K can be safely used as the size
+ (the nbytes parameter can be ignored).
+*/
+#ifdef MEMDEBUG
+extern void *oss_kmem_alloc (size_t size, int flags, char *file, int line);
+extern void oss_kmem_free (void *addr);
+#define KERNEL_MALLOC(nbytes) oss_kmem_alloc(nbytes, KM_SLEEP, __FILE__, __LINE__)
+#define KERNEL_FREE(addr) oss_kmem_free(addr)
+extern void *oss_contig_malloc (oss_device_t * osdev, int sz,
+ oss_uint64_t memlimit,
+ oss_native_word *phaddr,
+ oss_dma_handle_t *dma_handle,
+ char * file, int line);
+extern void oss_contig_free (oss_device_t * osdev, void *p, int sz);
+#define CONTIG_MALLOC(osdev, sz, memlimit, phaddr, handle) oss_contig_malloc(osdev, sz, memlimit, phaddr, &handle, __FILE__, __LINE__)
+#define CONTIG_FREE(osdev, p, sz, handle) oss_contig_free(osdev, p, sz, handle)
+#else
+extern void *oss_kmem_alloc (size_t size, int flags);
+extern void oss_kmem_free (void *addr);
+#define KERNEL_MALLOC(nbytes) oss_kmem_alloc(nbytes, KM_SLEEP)
+#define KERNEL_FREE(addr) oss_kmem_free(addr)
+extern void *oss_contig_malloc (oss_device_t * osdev, int sz,
+ oss_uint64_t memlimit,
+ oss_native_word * phaddr,
+ oss_dma_handle_t *dma_handle);
+extern void oss_contig_free (oss_device_t * osdev, void *p, int sz);
+#define CONTIG_MALLOC(osdev, sz, memlimit, phaddr, handle) oss_contig_malloc(osdev, sz, memlimit, phaddr, &handle)
+#define CONTIG_FREE(osdev, p, sz, handle) oss_contig_free(osdev, p, sz)
+#endif
+
+/*
+ * Timer macros
+ *
+ * These macros are obsolete and should not be used in any new code.
+ * Use the timeout mechanism (see the timeout(9F) Solaris man page).
+ */
+#define DEFINE_TIMER(name, proc) static timeout_id_t name = 0
+#define REMOVE_TIMER(name, proc) {if (name != 0) untimeout(name);}
+#define INIT_TIMER(name,proc)
+typedef void (*timeout_func_t) (void *);
+#define ACTIVATE_TIMER(name, proc, time) \
+ name=timeout((timeout_func_t)proc, (void*)&name, time)
+
+#define OSS_DMA_SYNC_INBOUND DDI_DMA_SYNC_FORCPU
+#define OSS_DMA_SYNC_OUTBOUND DDI_DMA_SYNC_FORDEV
+#define OSS_DMA_SYNC(handle, offs, len, direc) (ddi_dma_sync(handle, offs, len, direc)==DDI_SUCCESS)
+
+#ifdef _KERNEL
+struct os_dma_params
+{
+ int state; /* 0=unavail, 1=avail, 2=busy */
+ oss_device_t *osdev;
+ ddi_dma_handle_t handle;
+ ddi_acc_handle_t dma_acc_handle;
+ ddi_dma_cookie_t cookie;
+ ddi_dma_win_t win;
+ ddi_dma_seg_t seg;
+ void *orig_buf;
+
+ volatile int enabled, ignore;
+};
+#define OS_DMA_PARMS \
+ struct os_dma_params dma_parms;
+#endif
+#endif
+
+struct fileinfo
+{
+ int mode; /* Open mode */
+ int acc_flags;
+};
+
+#define ISSET_FILE_FLAG(fileinfo, flag) (fileinfo->acc_flags & (flag) ? 1:0)
+
+#ifdef sparc
+#define OSS_OS "Sparc"
+#define OSS_OS_LONGNAME "Solaris (Sparc)"
+#else
+#define OSS_OS "Solaris"
+#define OSS_OS_LONGNAME "Solaris (x86)"
+#endif
+
+#undef DMA_TRY_PSEUDOINIT
+
+int get_dma_residue (int chn);
+void disable_dma (int chn);
+void enable_dma (int chn);
+
+typedef void (*softintr_func_t) (int);
+
+struct oss_softintr
+{
+ int id;
+ softintr_func_t func;
+ volatile int armed, running;
+};
+
+/*
+ * There is apparently no documented way to map DMA buffers allocated
+ * using ddi_dma_mem_alloc() to applications. For this reason we cannot
+ * support mmap() under Solaris.
+ */
+#undef ALLOW_BUFFER_MAPPING
+
+#if 0
+extern int detect_trace;
+#define DDB(x) if (detect_trace) x
+#else
+#define DDB(x) {}
+#endif
+
+/*
+ * PCI I/O and memory address mapping.
+ *
+ * Note that for compatibility with the other operating systems supported by
+ * OSS the region numbering is different. So 0 means BAR0 while under
+ * Solaris (ddi_regs_map_setup) BAR0 is 1. oss_map_pci_ioaddr() will
+ * add 1 to the region number.
+ */
+extern caddr_t oss_map_pci_ioaddr (oss_device_t * osdev, int nr, int io);
+extern void oss_unmap_pci_ioaddr(oss_device_t * osdev, int nr);
+#define MAP_PCI_IOADDR(osdev, nr, io) (oss_native_word)oss_map_pci_ioaddr(osdev, nr, io)
+#define MAP_PCI_MEM(osdev, ix, phaddr, size) oss_map_pci_ioaddr(osdev, ix, phaddr)
+#define UNMAP_PCI_MEM(osdev, ix, ph, virt, size) oss_unmap_pci_ioaddr(osdev, ix)
+#define UNMAP_PCI_IOADDR(osdev, ix) oss_unmap_pci_ioaddr(osdev, ix)
+
+#define GET_PROCESS_PID(x) ddi_get_pid()
+
+/*
+ * Instead of returning UID check if the process has PRIV_SYS_DEVICES privilege.
+ * Report such users as UID=0 (root) and others as UID=1.
+ */
+#define GET_PROCESS_UID() ((drv_priv(ddi_get_cred())==0) ? 0 : 1)
+
+#if 1
+/* TODO: This works OK but may cause crashes with different kernel versions/builds */
+extern char *oss_get_procname (void);
+#define GET_PROCESS_NAME(x) oss_get_procname()
+#endif
+
+#define FP_SUPPORT
+
+#ifdef FP_SUPPORT
+typedef short fp_env_t[512];
+typedef unsigned int fp_flags_t[5];
+extern int oss_fp_check (void);
+extern void oss_fp_save (short *envbuf, fp_flags_t flags);
+extern void oss_fp_restore (short *envbuf, fp_flags_t flags);
+# define FP_SAVE(envbuf, flags) oss_fp_save(envbuf, flags)
+# define FP_RESTORE(envbuf, flags) oss_fp_restore(envbuf, flags)
+#endif
+
+#define abs(x) ((x) >= 0 ? (x) : -(x))
+
+extern int oss_open (dev_t * dev_p, int open_flags, int otyp,
+ cred_t * cred_p);
+extern int oss_close (dev_t dev, int flag, int otyp, cred_t * cred_p);
+extern int oss_ioctl (dev_t dev, int cmd, intptr_t arg, int mode,
+ cred_t * cred_p, int *rval_p);
+extern int oss_read (dev_t dev, struct uio *uiop, cred_t * credp);
+extern int oss_write (dev_t dev, struct uio *uiop, cred_t * cred_p);
+extern int oss_chpoll (dev_t dev, short events, int anyyet, short *reventsp,
+ struct pollhead **phpp);
+#ifdef _KERNEL
+extern int oss_devmap (dev_t dev, devmap_cookie_t handle, offset_t off,
+ size_t len, size_t * maplen, uint_t model);
+
+extern void *oss_memset (void *s, int c, size_t n);
+#define memset oss_memset
+
+extern void *oss_memcpy (void *s1, const void *s2, size_t n);
+#define memcpy oss_memcpy
+#endif
+
+#define DISABLE_FMA
+#if !defined(SOL9) && defined(DDI_FM_DEVICE) && !defined(DISABLE_FMA)
+/*
+ * Fault management (FMA) support.
+ */
+
+#define FMA_EREPORT(osdev, detail, name, type, value) \
+{ \
+ uint64_t ena; \
+ char buf[FM_MAX_CLASS]; \
+ (void) snprintf (buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail); \
+ ena = fm_ena_generate(0, FM_ENA_FMT1); \
+ if (osdev->dip != NULL && osdev->fm_capabilities != 0) \
+ ddi_fm_ereport_post(osdev->dip, buf, ena, DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, name, type, value, NULL); \
+}
+
+#define FMA_IMPACT(osdev, impact) \
+ if (osdev->fm_capabilities != 0) \
+ ddi_fm_service_impact(osdev->dip, impact)
+#endif
diff --git a/kernel/OS/SunOS/udi.c b/kernel/OS/SunOS/udi.c
new file mode 100644
index 0000000..ad4d4fa
--- /dev/null
+++ b/kernel/OS/SunOS/udi.c
@@ -0,0 +1,1365 @@
+/*
+ * Purpose: USB device interface (udi.h) routines for Solaris
+ */
+/*
+ *
+ * This file is part of Open Sound System.
+ *
+ * Copyright (C) 4Front Technologies 1996-2008.
+ *
+ * This this source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ */
+#if !defined(SOL9)
+#include "oss_config.h"
+#include <udi.h>
+
+#define USBDRV_MAJOR_VER 2
+#define USBDRV_MINOR_VER 0
+#include <sys/usb/usba.h>
+#include <sys/strsubr.h>
+
+#undef IO_DEBUG
+int udi_usb_trace = 0;
+
+#define MAX_DEVICE_SLOTS 20
+
+struct udi_usb_devc
+{
+ oss_device_t *osdev;
+ usb_client_dev_data_t *dev_data;
+ char *name;
+
+ const struct usb_device_id *id;
+ const udi_usb_devinfo *udi_usb_dev;
+ char devpath[32];
+
+ int enabled;
+
+ struct usb_interface *iface;
+ udi_usb_driver *drv;
+ void *client_devc;
+ void (*client_disconnect) (void *devc);
+};
+
+#define MAX_DEVC 32
+
+int
+udi_attach_usbdriver (oss_device_t * osdev, const udi_usb_devinfo * devlist,
+ udi_usb_driver * driver)
+{
+ int err, i, nalt, vendor, product, busaddr;
+ udi_usb_devc *usbdev;
+ dev_info_t *dip = osdev->dip;
+ char *name;
+ unsigned long osid;
+ //usb_alt_if_data_t *altif_data;
+ usb_client_dev_data_t *dev_data;
+
+ if (dip==NULL)
+ {
+ cmn_err(CE_WARN, "dip==NULL\n");
+ return 0;
+ }
+
+ name = ddi_get_name (osdev->dip);
+
+ if (strcmp (name, "oss_usb") == 0)
+ {
+ oss_register_device (osdev, "USB audio/MIDI device");
+ return 1;
+ }
+
+ /*
+ * Select the default configuration
+ */
+ if ((err = usb_set_cfg (osdev->dip, USB_DEV_DEFAULT_CONFIG_INDEX,
+ USB_FLAGS_SLEEP, NULL, NULL)) == USB_SUCCESS)
+ {
+ cmn_err (CE_CONT, "usb_set_cfg returned %d\n", err);
+ }
+
+ busaddr = ddi_prop_get_int (DDI_DEV_T_ANY, osdev->dip,
+ DDI_PROP_NOTPROM, "assigned-address", 1234);
+ if ((usbdev = KERNEL_MALLOC (sizeof (*usbdev))) == NULL)
+ {
+ cmn_err (CE_WARN, "udi_attach_usbdriver: Out of memory\n");
+ return 0;
+ }
+
+ memset (usbdev, 0, sizeof (*usbdev));
+ osdev->usbdev = usbdev;
+ usbdev->osdev = osdev;
+
+ if ((err = usb_client_attach (dip, USBDRV_VERSION, 0)) != USB_SUCCESS)
+ {
+ cmn_err (CE_WARN, "usb_client_attach failed, err=%d\n", err);
+ KERNEL_FREE (usbdev);
+ return 0;
+ }
+
+ if ((err =
+ usb_get_dev_data (osdev->dip, &usbdev->dev_data, USB_PARSE_LVL_CFG,
+ 0)) != USB_SUCCESS)
+ {
+ cmn_err (CE_WARN, "usb_get_dev_data failed, err=%d\n", err);
+ KERNEL_FREE (usbdev);
+ return 0;
+ }
+ dev_data = usbdev->dev_data;
+
+ osdev->iblock_cookie = dev_data->dev_iblock_cookie;
+
+ sprintf (usbdev->devpath, "usb%x,%x@port%d", udi_usbdev_get_vendor (usbdev),
+ udi_usbdev_get_product (usbdev), busaddr);
+ oss_register_device (osdev, "USB audio/MIDI device");
+ sprintf (osdev->nick, "usb%x_%x_%d", udi_usbdev_get_vendor (usbdev),
+ udi_usbdev_get_product (usbdev), busaddr);
+
+#if 0
+ if (udi_usb_trace > 5)
+ usb_print_descr_tree (osdev->dip, dev_data);
+#endif
+
+ nalt = 1;
+ if (nalt >= dev_data->dev_curr_cfg->cfg_if[dev_data->dev_curr_if].if_n_alt)
+ nalt = 0;
+
+ //altif_data = &dev_data->dev_curr_cfg->
+ // cfg_if[dev_data->dev_curr_if].if_alt[nalt];
+
+ usbdev->name = usbdev->dev_data->dev_product;
+ vendor = udi_usbdev_get_vendor (usbdev);
+ product = udi_usbdev_get_product (usbdev);
+
+ /* inum = usbdev->dev_data->dev_curr_if; */
+ osid = (vendor << 16) | product;
+ osdev->osid = (void *) osid;
+
+ sprintf (osdev->handle, "usb%x,%x.%d:%d", vendor, product,
+ dev_data->dev_curr_if, osdev->instance);
+
+ for (i = 0; devlist[i].vendor != -1; i++)
+ if (devlist[i].vendor == vendor && devlist[i].product == product)
+ {
+ usbdev->name = devlist[i].name;
+ usbdev->udi_usb_dev = &devlist[i];
+ oss_register_device (osdev, usbdev->name);
+ break;
+ }
+
+ if ((usbdev->client_devc = driver->attach (usbdev, osdev)) == NULL)
+ {
+ cmn_err (CE_WARN, "Client attach failed, err=%d\n", err);
+ udi_unload_usbdriver (osdev);
+ return 0;
+ }
+
+ usbdev->client_disconnect = driver->disconnect;
+
+ return 1;
+}
+
+static char *
+usb_errstr (int err)
+{
+
+ static struct errmsg_
+ {
+ int err;
+ char *str;
+ } errs[] =
+ {
+ {
+ USB_FAILURE, "USB_FAILURE"},
+ {
+ USB_NO_RESOURCES, "USB_NO_RESOURCES"},
+ {
+ USB_NO_BANDWIDTH, "USB_NO_BANDWIDTH"},
+ {
+ USB_NOT_SUPPORTED, "USB_NOT_SUPPORTED"},
+ {
+ USB_PIPE_ERROR, "USB_PIPE_ERROR"},
+ {
+ USB_INVALID_PIPE, "USB_INVALID_PIPE"},
+ {
+ USB_NO_FRAME_NUMBER, "USB_NO_FRAME_NUMBER"},
+ {
+ USB_INVALID_START_FRAME, "USB_INVALID_START_FRAME"},
+ {
+ USB_HC_HARDWARE_ERROR, "USB_HC_HARDWARE_ERROR"},
+ {
+ USB_INVALID_REQUEST, "USB_INVALID_REQUEST"},
+ {
+ USB_INVALID_CONTEXT, "USB_INVALID_CONTEXT"},
+ {
+ USB_INVALID_VERSION, "USB_INVALID_VERSION"},
+ {
+ USB_INVALID_ARGS, "USB_INVALID_ARGS"},
+ {
+ USB_INVALID_PERM, "USB_INVALID_PERM"},
+ {
+ USB_BUSY, "USB_BUSY"},
+ {
+ 0, NULL}
+ };
+
+ int i;
+ static char msg[20];
+
+ for (i = 0; errs[i].err != 0; i++)
+ if (errs[i].err == err)
+ {
+ return errs[i].str;
+ }
+
+ sprintf (msg, "Err %d", err);
+ return msg;
+}
+
+static char *
+usb_cb_err (int err)
+{
+
+ static struct errmsg_
+ {
+ int err;
+ char *str;
+ } errs[] =
+ {
+ {
+ USB_CB_STALL_CLEARED, "USB_CB_STALL_CLEARED"},
+ {
+ USB_CB_FUNCTIONAL_STALL, "USB_CB_FUNCTIONAL_STALL"},
+ {
+ USB_CB_PROTOCOL_STALL, "USB_CB_PROTOCOL_STALL"},
+ {
+ USB_CB_RESET_PIPE, "USB_CB_RESET_PIPE"},
+ {
+ USB_CB_ASYNC_REQ_FAILED, "USB_CB_ASYNC_REQ_FAILED"},
+ {
+ USB_CB_NO_RESOURCES, "USB_CB_NO_RESOURCES"},
+ {
+ USB_CB_SUBMIT_FAILED, "USB_CB_SUBMIT_FAILED"},
+ {
+ USB_CB_INTR_CONTEXT, "USB_CB_INTR_CONTEXT"},
+ {
+ USB_FAILURE, "USB_FAILURE"},
+ {
+ USB_NO_RESOURCES, "USB_NO_RESOURCES"},
+ {
+ USB_NO_BANDWIDTH, "USB_NO_BANDWIDTH"},
+ {
+ USB_NOT_SUPPORTED, "USB_NOT_SUPPORTED"},
+ {
+ USB_PIPE_ERROR, "USB_PIPE_ERROR"},
+ {
+ USB_INVALID_PIPE, "USB_INVALID_PIPE"},
+ {
+ USB_NO_FRAME_NUMBER, "USB_NO_FRAME_NUMBER"},
+ {
+ USB_INVALID_START_FRAME, "USB_INVALID_START_FRAME"},
+ {
+ USB_HC_HARDWARE_ERROR, "USB_HC_HARDWARE_ERROR"},
+ {
+ USB_INVALID_REQUEST, "USB_INVALID_REQUEST"},
+ {
+ USB_INVALID_CONTEXT, "USB_INVALID_CONTEXT"},
+ {
+ USB_INVALID_VERSION, "USB_INVALID_VERSION"},
+ {
+ USB_INVALID_ARGS, "USB_INVALID_ARGS"},
+ {
+ USB_INVALID_PERM, "USB_INVALID_PERM"},
+ {
+ USB_BUSY, "USB_BUSY"},
+ {
+ 0, NULL}
+ };
+
+ int i;
+ static char msg[20];
+
+ if (err == 0)
+ return "USB_CB_NO_INFO";
+
+ for (i = 0; errs[i].err != 0; i++)
+ {
+ if (errs[i].err == err)
+ {
+ return errs[i].str;
+ }
+ }
+
+ sprintf (msg, "CB Err %d", err);
+ return msg;
+}
+
+static char *
+usb_cr_err (int err)
+{
+
+ static struct errmsg_
+ {
+ int err;
+ char *str;
+ } errs[] =
+ {
+ {
+ USB_CR_CRC, "USB_CR_CRC"},
+ {
+ USB_CR_BITSTUFFING, "USB_CR_BITSTUFFING"},
+ {
+ USB_CR_DATA_TOGGLE_MM, "USB_CR_DATA_TOGGLE_MM"},
+ {
+ USB_CR_STALL, "USB_CR_STALL"},
+ {
+ USB_CR_DEV_NOT_RESP, "USB_CR_DEV_NOT_RESP"},
+ {
+ USB_CR_PID_CHECKFAILURE, "USB_CR_PID_CHECKFAILURE"},
+ {
+ USB_CR_UNEXP_PID, "USB_CR_UNEXP_PID"},
+ {
+ USB_CR_DATA_OVERRUN, "USB_CR_DATA_OVERRUN"},
+ {
+ USB_CR_DATA_UNDERRUN, "USB_CR_DATA_UNDERRUN"},
+ {
+ USB_CR_BUFFER_OVERRUN, "USB_CR_BUFFER_OVERRUN"},
+ {
+ USB_CR_BUFFER_UNDERRUN, "USB_CR_BUFFER_UNDERRUN"},
+ {
+ USB_CR_TIMEOUT, "USB_CR_TIMEOUT"},
+ {
+ USB_CR_NOT_ACCESSED, "USB_CR_NOT_ACCESSED"},
+ {
+ USB_CR_NO_RESOURCES, "USB_CR_NO_RESOURCES"},
+ {
+ USB_CR_UNSPECIFIED_ERR, "USB_CR_UNSPECIFIED_ERR"},
+ {
+ USB_CR_STOPPED_POLLING, "USB_CR_STOPPED_POLLING"},
+ {
+ USB_CR_PIPE_CLOSING, "USB_CR_PIPE_CLOSING"},
+ {
+ USB_CR_PIPE_RESET, "USB_CR_PIPE_RESET"},
+ {
+ USB_CR_NOT_SUPPORTED, "USB_CR_NOT_SUPPORTED"},
+ {
+ USB_CR_FLUSHED, "USB_CR_FLUSHED"},
+ {
+ USB_CR_HC_HARDWARE_ERR, "USB_CR_HC_HARDWARE_ERR"},
+ {
+ 0, NULL}
+ };
+
+ int i;
+ static char msg[20];
+
+ if (err == 0)
+ return "USB_CR_OK";
+
+ for (i = 0; errs[i].err != 0; i++)
+ {
+ if (errs[i].err == err)
+ {
+ return errs[i].str;
+ }
+ }
+
+ sprintf (msg, "CR Err %d", err);
+ return msg;
+}
+
+void
+udi_unload_usbdriver (oss_device_t * osdev)
+{
+ udi_usb_devc *usbdev = osdev->usbdev;
+
+ if (usbdev == NULL)
+ return;
+
+ if (usbdev->client_disconnect != NULL)
+ usbdev->client_disconnect (usbdev->client_devc);
+ usb_client_detach (osdev->dip, usbdev->dev_data);
+
+ KERNEL_FREE (usbdev);
+ osdev->usbdev = NULL;
+}
+
+/*
+ * Device access routines
+ */
+
+int
+udi_usbdev_get_class (udi_usb_devc * usbdev)
+{
+ udi_usb_devc *devc = (udi_usb_devc *) usbdev;
+
+ return devc->dev_data->dev_curr_cfg->cfg_if[devc->dev_data->dev_curr_if].
+ if_alt[0].altif_descr.bInterfaceClass;
+}
+
+int
+udi_usbdev_get_subclass (udi_usb_devc * usbdev)
+{
+ udi_usb_devc *devc = (udi_usb_devc *) usbdev;
+
+ return devc->dev_data->dev_curr_cfg->cfg_if[devc->dev_data->dev_curr_if].
+ if_alt[0].altif_descr.bInterfaceSubClass;
+}
+
+int
+udi_usbdev_get_vendor (udi_usb_devc * usbdev)
+{
+ udi_usb_devc *devc = (udi_usb_devc *) usbdev;
+
+ return devc->dev_data->dev_descr->idVendor;
+}
+
+int
+udi_usbdev_get_product (udi_usb_devc * usbdev)
+{
+ udi_usb_devc *devc = (udi_usb_devc *) usbdev;
+
+ return devc->dev_data->dev_descr->idProduct;
+}
+
+int
+udi_usbdev_get_inum (udi_usb_devc * usbdev)
+{
+ udi_usb_devc *devc = (udi_usb_devc *) usbdev;
+
+ return devc->dev_data->dev_curr_if;
+}
+
+int
+udi_usbdev_set_interface (udi_usb_devc * usbdev, int inum, int altset)
+{
+ //udi_usb_devc *devc = (udi_usb_devc *) usbdev;
+
+ if (usb_set_alt_if (usbdev->osdev->dip, inum, altset, USB_FLAGS_SLEEP,
+ NULL, 0) != USB_SUCCESS)
+ {
+ return OSS_EIO;
+ }
+
+ return 0;
+}
+
+unsigned char *
+udi_usbdev_get_endpoint (udi_usb_devc * usbdev, int altsetting, int n,
+ int *len)
+{
+ usb_alt_if_data_t *altif_data;
+ usb_client_dev_data_t *dev_data;
+
+ *len = 0;
+
+ if (usbdev->dev_data == NULL)
+ {
+ cmn_err (CE_WARN, "Missing USB devdata\n");
+ return NULL;
+ }
+ dev_data = usbdev->dev_data;
+
+ if (altsetting < 0
+ || altsetting >=
+ dev_data->dev_curr_cfg->cfg_if[dev_data->dev_curr_if].if_n_alt)
+ {
+ return NULL;
+ }
+
+ altif_data = &dev_data->dev_curr_cfg->
+ cfg_if[dev_data->dev_curr_if].if_alt[altsetting];
+
+ if (altif_data == NULL)
+ return NULL;
+
+ if (n < 0 || n >= altif_data->altif_n_ep)
+ return NULL;
+
+ *len = altif_data->altif_ep[n].ep_descr.bLength;
+ return (unsigned char *) &altif_data->altif_ep[n].ep_descr;
+}
+
+int
+udi_usbdev_get_num_altsettings (udi_usb_devc * usbdev)
+{
+ //udi_usb_devc *devc = (udi_usb_devc *) usbdev;
+ usb_client_dev_data_t *dev_data;
+
+ dev_data = usbdev->dev_data;
+ return dev_data->dev_curr_cfg->cfg_if[dev_data->dev_curr_if].if_n_alt;
+}
+
+unsigned char *
+udi_usbdev_get_altsetting (udi_usb_devc * usbdev, int nalt, int *size)
+{
+ int i, n;
+ usb_cvs_data_t *cvs;
+ usb_alt_if_data_t *altif_data;
+ usb_client_dev_data_t *dev_data;
+ static unsigned char buf[1024];
+
+ dev_data = usbdev->dev_data;
+ if ((unsigned long) dev_data <= 4096)
+ {
+ cmn_err (CE_WARN, "Internal error: dev_data==NULL)\n");
+ return NULL;
+ }
+
+ if (nalt < 0
+ || nalt >=
+ dev_data->dev_curr_cfg->cfg_if[dev_data->dev_curr_if].if_n_alt)
+ {
+ return NULL;
+ }
+
+ altif_data = &dev_data->dev_curr_cfg->
+ cfg_if[dev_data->dev_curr_if].if_alt[nalt];
+
+ if (altif_data == NULL)
+ return NULL;
+
+ n = 0;
+
+ for (i = 0; i < altif_data->altif_n_cvs; i++)
+ {
+ cvs = &altif_data->altif_cvs[i];
+ memcpy (buf + n, cvs->cvs_buf, cvs->cvs_buf_len);
+ n += cvs->cvs_buf_len;
+ }
+
+ cvs = &altif_data->altif_cvs[0];
+ if (cvs == NULL || cvs->cvs_buf == NULL)
+ return NULL;
+
+ *size = n;
+ return buf;
+}
+
+char *
+udi_usbdev_get_name (udi_usb_devc * usbdev)
+{
+ udi_usb_devc *devc = (udi_usb_devc *) usbdev;
+
+ return devc->name;
+}
+
+char *
+udi_usbdev_get_altsetting_labels (udi_usb_devc * usbdev, int if_num,
+ int *default_alt, unsigned int *mask)
+{
+ int i;
+
+ *default_alt = 1;
+ *mask = 0xffffffff;
+
+ if (usbdev->udi_usb_dev == NULL) /* No device definitions available */
+ {
+ return NULL;
+ }
+
+ for (i = 0; usbdev->udi_usb_dev->altsettings[i].altsetting_labels != NULL;
+ i++)
+ if (i == if_num)
+ {
+ *default_alt = usbdev->udi_usb_dev->altsettings[i].default_altsetting;
+ *mask = usbdev->udi_usb_dev->altsettings[i].altsetting_mask;
+ if (*mask == 0)
+ *mask = 0xffffffff;
+ return usbdev->udi_usb_dev->altsettings[i].altsetting_labels;
+ }
+
+ return NULL; /* Not found */
+}
+
+char *
+udi_usbdev_get_string (udi_usb_devc * usbdev, int ix)
+{
+ static char str[256];
+
+ if (usb_get_string_descr
+ (usbdev->osdev->dip, USB_LANG_ID, ix, str,
+ sizeof (str) - 1) != USB_SUCCESS)
+ return NULL;
+ return str;
+}
+
+char *
+udi_usbdev_get_devpath (udi_usb_devc * usbdev)
+{
+ udi_usb_devc *devc = (udi_usb_devc *) usbdev;
+
+ return devc->devpath;
+}
+
+/*ARGSUSED*/
+int
+udi_usb_snd_control_msg (udi_usb_devc * usbdev, unsigned int endpoint,
+ unsigned char rq,
+ unsigned char rqtype,
+ unsigned short value,
+ unsigned short index,
+ void *buf, int len, int timeout)
+{
+
+ int err;
+
+ usb_ctrl_setup_t setup;
+ usb_cr_t completion_reason;
+ usb_cb_flags_t cb_flags;
+ mblk_t *data = NULL;
+
+ if (usbdev == NULL)
+ {
+ cmn_err (CE_CONT, "udi_usb_snd_control_msg: usbdev==NULL\n");
+ return OSS_EFAULT;
+ }
+
+ data = allocb_wait (len + 1, BPRI_HI, STR_NOSIG, NULL);
+
+ memcpy (data->b_wptr, buf, len);
+ data->b_wptr = data->b_rptr + len;
+
+ setup.bmRequestType = rqtype | USB_DEV_REQ_HOST_TO_DEV;
+ setup.bRequest = rq;
+ setup.wValue = value;
+ setup.wIndex = index;
+ setup.wLength = len;
+ setup.attrs = 0;
+
+ if ((err = usb_pipe_ctrl_xfer_wait (usbdev->dev_data->dev_default_ph,
+ &setup,
+ &data,
+ &completion_reason,
+ &cb_flags, 0)) != USB_SUCCESS)
+ {
+ char tmp[128], *s = tmp;
+ unsigned char *p = buf;
+ int i;
+
+ sprintf (s, "Msg (rq=0x%x, val=0x%04x, ix=0x%04x, len=%d): ", rq, value,
+ index, len);
+ for (i = 0; i < len; i++)
+ {
+ s += strlen (s);
+ sprintf (s, "%02x ", p[i]);
+ }
+ cmn_err (CE_CONT, "%s\n", tmp);
+
+ cmn_err (CE_NOTE, "usb_pipe_ctrl_xfer_wait write failed: %s (%s)\n",
+ usb_errstr (err), usb_cb_err (completion_reason));
+ cmn_err (CE_CONT, "bRq %x, wIx %x, wVal %x, wLen %d\n", rq, index,
+ value, len);
+ freemsg (data);
+ return OSS_EIO;
+ }
+
+ freemsg (data);
+ return len;
+}
+
+/*ARGSUSED*/
+int
+udi_usb_rcv_control_msg (udi_usb_devc * usbdev, unsigned int endpoint,
+ unsigned char rq,
+ unsigned char rqtype,
+ unsigned short value,
+ unsigned short index,
+ void *buf, int len, int timeout)
+{
+ int err, l;
+
+ usb_ctrl_setup_t setup;
+ usb_cr_t completion_reason;
+ usb_cb_flags_t cb_flags;
+ mblk_t *data = NULL;
+
+ if (usbdev == NULL)
+ {
+ cmn_err (CE_CONT, "udi_usb_rcv_control_msg: usbdev==NULL\n");
+ return OSS_EFAULT;
+ }
+
+ setup.bmRequestType = rqtype | USB_DEV_REQ_DEV_TO_HOST;
+ setup.bRequest = rq;
+ setup.wValue = value;
+ setup.wIndex = index;
+ setup.wLength = len;
+ setup.attrs = 0;
+
+ if ((err = usb_pipe_ctrl_xfer_wait (usbdev->dev_data->dev_default_ph,
+ &setup,
+ &data,
+ &completion_reason,
+ &cb_flags, 0)) != USB_SUCCESS)
+ {
+ char tmp[128], *s = tmp;
+
+ sprintf (s, "Msg (rq=0x%02x, val=0x%04x, ix=0x%04x, len=%d): ", rq,
+ value, index, len);
+ cmn_err (CE_CONT, "%s\n", tmp);
+ cmn_err (CE_NOTE, "usb_pipe_ctrl_xfer_wait read failed: %s (%s)\n",
+ usb_errstr (err), usb_cb_err (completion_reason));
+ freemsg (data);
+ return OSS_EIO;
+ }
+
+ /*LINTED*/ l = data->b_wptr - data->b_rptr;
+
+ memcpy (buf, data->b_rptr, l);
+ freemsg (data);
+
+ return l;
+}
+
+/* Endpoint/pipe access */
+
+struct _udi_endpoint_handle_t
+{
+ usb_pipe_handle_t pipe_handle;
+ unsigned char *ep_desc;
+ udi_usb_devc *usbdev;
+};
+
+udi_endpoint_handle_t *
+udi_open_endpoint (udi_usb_devc * usbdev, void *ep_desc)
+{
+ udi_endpoint_handle_t *h;
+ int err;
+ usb_pipe_policy_t policy;
+
+ if ((h = KERNEL_MALLOC (sizeof (*h))) == NULL)
+ return NULL;
+
+ policy.pp_max_async_reqs = 2;
+
+ if ((err = usb_pipe_open (usbdev->osdev->dip, ep_desc, &policy,
+ USB_FLAGS_SLEEP, &h->pipe_handle)) != USB_SUCCESS)
+ {
+ cmn_err (CE_WARN, "usb_pipe_open() failed %d (%s)\n", err,
+ usb_cb_err (err));
+ KERNEL_FREE (h);
+ return NULL;
+ }
+
+ h->ep_desc = ep_desc;
+ h->usbdev = usbdev;
+
+ return h;
+}
+
+void
+udi_close_endpoint (udi_endpoint_handle_t * h)
+{
+ usb_pipe_close (h->usbdev->osdev->dip, h->pipe_handle, USB_FLAGS_SLEEP,
+ NULL, 0);
+ KERNEL_FREE (h);
+}
+
+int
+udi_endpoint_get_num (udi_endpoint_handle_t * eph)
+{
+ return eph->ep_desc[2] & 0xff;
+}
+
+/* Request stuff */
+
+struct udi_usb_request
+{
+ dev_info_t *dip;
+ usb_pipe_handle_t pipe_handle;
+ udi_usb_complete_func_t callback;
+ void *callback_arg;
+ int active;
+ int xfer_type;
+ mblk_t *data;
+
+ /*
+ * Recording
+ */
+ int actlen;
+
+ usb_isoc_req_t *isoc_req;
+ usb_bulk_req_t *bulk_req;
+ usb_intr_req_t *intr_req;
+};
+
+ /*ARGSUSED*/
+ udi_usb_request_t
+ * udi_usb_alloc_request (udi_usb_devc * usbdev, udi_endpoint_handle_t * eph,
+ int nframes, int xfer_type)
+{
+ udi_usb_request_t *req;
+
+ if ((req = KERNEL_MALLOC (sizeof (*req))) == NULL)
+ {
+ cmn_err (CE_WARN, "udi_usb_alloc_request: Out of memory\n");
+ return NULL;
+ }
+
+ req->xfer_type = xfer_type;
+ req->dip = usbdev->osdev->dip;
+ req->pipe_handle = eph->pipe_handle;
+
+ switch (xfer_type)
+ {
+ case UDI_USBXFER_ISO_READ:
+ return req;
+ break;
+
+ case UDI_USBXFER_ISO_WRITE:
+ return req;
+ break;
+
+ case UDI_USBXFER_BULK_READ:
+ return req;
+ break;
+
+ case UDI_USBXFER_INTR_READ:
+ return req;
+ break;
+
+ case UDI_USBXFER_BULK_WRITE:
+ return req;
+ break;
+
+ default:
+ cmn_err (CE_WARN, "Internal error - bad transfer type %d\n", xfer_type);
+ KERNEL_FREE (req);
+ return NULL;
+ }
+}
+
+void
+udi_usb_free_request (udi_usb_request_t * req)
+{
+ if (req == NULL)
+ return;
+
+ udi_usb_cancel_request (req);
+
+ if (req->active)
+ {
+ cmn_err (CE_WARN, "Warning: Freeing active request\n");
+ }
+
+ switch (req->xfer_type)
+ {
+ case UDI_USBXFER_ISO_WRITE:
+ req->isoc_req = NULL;
+ break;
+
+ case UDI_USBXFER_ISO_READ:
+ req->isoc_req = NULL;
+ break;
+
+ case UDI_USBXFER_BULK_WRITE:
+ req->bulk_req = NULL;
+ break;
+
+ case UDI_USBXFER_BULK_READ:
+ req->bulk_req = NULL;
+ break;
+
+ case UDI_USBXFER_INTR_READ:
+ req->intr_req = NULL;
+ break;
+
+ default:
+ cmn_err (CE_WARN, "Internal error - bad transfer type %d\n",
+ req->xfer_type);
+ }
+
+ KERNEL_FREE (req);
+}
+
+/*ARGSUSED*/
+static void
+isoc_play_callback (usb_pipe_handle_t ph, usb_isoc_req_t * isoc_req)
+{
+ udi_usb_request_t *req =
+ (udi_usb_request_t *) isoc_req->isoc_client_private;
+
+ usb_free_isoc_req (isoc_req);
+
+ req->isoc_req = NULL;
+ req->active = 0;
+
+ req->callback (req, req->callback_arg);
+}
+
+/*ARGSUSED*/
+static void
+isoc_rec_callback (usb_pipe_handle_t ph, usb_isoc_req_t * isoc_req)
+{
+ int i;
+ udi_usb_request_t *req =
+ (udi_usb_request_t *) isoc_req->isoc_client_private;
+
+ req->data = isoc_req->isoc_data;
+
+ for (i = 0; i < isoc_req->isoc_pkts_count; i++)
+ {
+ int len;
+
+ len = isoc_req->isoc_pkt_descr[i].isoc_pkt_actual_length;
+
+ req->actlen = len;
+
+ req->callback (req, req->callback_arg);
+
+ req->data->b_rptr += len;
+ }
+
+ req->active = 0;
+ usb_free_isoc_req (isoc_req);
+}
+
+/*ARGSUSED*/
+static void
+isoc_exc_callback (usb_pipe_handle_t ph, usb_isoc_req_t * isoc_req)
+{
+ udi_usb_request_t *req =
+ (udi_usb_request_t *) isoc_req->isoc_client_private;
+ usb_cr_t reason;
+
+ reason = isoc_req->isoc_completion_reason;
+
+ usb_free_isoc_req (isoc_req);
+ req->isoc_req = NULL;
+ req->active = 0;
+
+ if (reason && reason != USB_CR_FLUSHED && reason != USB_CR_PIPE_CLOSING)
+ cmn_err (CE_CONT, "USB isoc transfer completion status %s\n",
+ usb_cr_err (reason));
+}
+
+/*ARGSUSED*/
+void
+bulk_play_callback (usb_pipe_handle_t ph, usb_bulk_req_t * bulk_req)
+{
+ udi_usb_request_t *req =
+ (udi_usb_request_t *) bulk_req->bulk_client_private;
+
+ usb_free_bulk_req (bulk_req);
+
+ req->bulk_req = NULL;
+ req->active = 0;
+
+ req->callback (req, req->callback_arg);
+}
+
+/*ARGSUSED*/
+void
+bulk_rec_callback (usb_pipe_handle_t ph, usb_bulk_req_t * bulk_req)
+{
+ udi_usb_request_t *req =
+ (udi_usb_request_t *) bulk_req->bulk_client_private;
+
+ req->data = bulk_req->bulk_data;
+ req->actlen = bulk_req->bulk_len;
+ req->active = 0;
+
+ req->callback (req, req->callback_arg);
+ //usb_free_bulk_req (bulk_req);
+}
+
+/*ARGSUSED*/
+static void
+bulk_exc_callback (usb_pipe_handle_t ph, usb_bulk_req_t * bulk_req)
+{
+ udi_usb_request_t *req =
+ (udi_usb_request_t *) bulk_req->bulk_client_private;
+ usb_cr_t reason;
+
+ reason = bulk_req->bulk_completion_reason;
+
+ usb_free_bulk_req (bulk_req);
+ req->bulk_req = NULL;
+ req->active = 0;
+
+ if (reason && reason != USB_CR_FLUSHED && reason != USB_CR_PIPE_CLOSING)
+ cmn_err (CE_CONT, "USB bulk transfer completion status %s\n",
+ usb_cr_err (reason));
+}
+
+/*ARGSUSED*/
+void
+intr_rec_callback (usb_pipe_handle_t ph, usb_intr_req_t * intr_req)
+{
+ udi_usb_request_t *req =
+ (udi_usb_request_t *) intr_req->intr_client_private;
+
+ req->data = intr_req->intr_data;
+ req->actlen = intr_req->intr_len;
+ req->active = 0;
+
+ req->callback (req, req->callback_arg);
+ //usb_free_intr_req (intr_req);
+}
+
+/*ARGSUSED*/
+static void
+intr_exc_callback (usb_pipe_handle_t ph, usb_intr_req_t * intr_req)
+{
+ udi_usb_request_t *req =
+ (udi_usb_request_t *) intr_req->intr_client_private;
+ usb_cr_t reason;
+
+ reason = intr_req->intr_completion_reason;
+
+ usb_free_intr_req (intr_req);
+ req->intr_req = NULL;
+ req->active = 0;
+
+ if (reason && reason != USB_CR_FLUSHED && reason != USB_CR_PIPE_CLOSING)
+ cmn_err (CE_CONT, "USB intr transfer completion status %s\n",
+ usb_cr_err (reason));
+}
+
+/*ARGSUSED*/
+int
+udi_usb_submit_request (udi_usb_request_t * req,
+ udi_usb_complete_func_t callback, void *callback_arg,
+ udi_endpoint_handle_t * eph, int xfer_type,
+ void *data, int len)
+{
+ int err;
+
+ req->callback = callback;
+ req->callback_arg = callback_arg;
+
+ if (req->active)
+ return 0;
+
+ switch (xfer_type)
+ {
+ case UDI_USBXFER_ISO_WRITE:
+ {
+ usb_isoc_req_t *isoc_req;
+
+ if (req->isoc_req != NULL)
+ isoc_req = req->isoc_req;
+ else
+ {
+ req->data = allocb (len, BPRI_HI);
+ if (req->data == NULL)
+ {
+ cmn_err (CE_WARN, "allocb_wait (isoc) failed\n");
+ KERNEL_FREE (req);
+ return OSS_ENOMEM;
+ }
+
+ if ((isoc_req = usb_alloc_isoc_req (req->dip, 1, 0, 0)) == NULL)
+ {
+ cmn_err (CE_WARN, "usb_alloc_isoc_req failed\n");
+ freemsg (req->data);
+ KERNEL_FREE (req);
+ return OSS_ENOMEM;
+ }
+ req->isoc_req = isoc_req;
+ }
+
+ if (isoc_req == NULL)
+ {
+ cmn_err (CE_WARN, "req->isoc==NULL\n");
+ return OSS_EIO;
+ }
+
+ memcpy (req->data->b_wptr, data, len);
+ req->data->b_wptr += len;
+
+ isoc_req->isoc_data = req->data;
+ isoc_req->isoc_pkt_descr[0].isoc_pkt_length = len;
+ isoc_req->isoc_pkts_count = 1;
+ isoc_req->isoc_pkts_length = len;
+ isoc_req->isoc_attributes =
+ USB_ATTRS_ISOC_XFER_ASAP | USB_ATTRS_AUTOCLEARING;
+ isoc_req->isoc_cb = isoc_play_callback;
+ isoc_req->isoc_exc_cb = isoc_exc_callback;
+ isoc_req->isoc_client_private = (usb_opaque_t) req;
+
+ if ((err =
+ usb_pipe_isoc_xfer (req->pipe_handle, isoc_req,
+ 0)) != USB_SUCCESS)
+ {
+ cmn_err (CE_WARN, "usb_pipe_isoc_xfer failed (%s)\n",
+ usb_errstr (err));
+ return OSS_EIO;
+ }
+ req->active = 1;
+ }
+ break;
+
+ case UDI_USBXFER_ISO_READ:
+ {
+ usb_isoc_req_t *isoc_req;
+
+ if (req->isoc_req != NULL)
+ isoc_req = req->isoc_req;
+ else
+ {
+ if ((isoc_req =
+ usb_alloc_isoc_req (req->dip, 1, len,
+ USB_FLAGS_SLEEP)) == NULL)
+ {
+ cmn_err (CE_WARN, "usb_alloc_isoc_req failed\n");
+ KERNEL_FREE (req);
+ return OSS_ENOMEM;
+ }
+ req->isoc_req = isoc_req;
+ }
+
+ if (isoc_req == NULL)
+ {
+ cmn_err (CE_WARN, "req->isoc==NULL\n");
+ return OSS_EIO;
+ }
+
+ isoc_req->isoc_attributes = USB_ATTRS_ISOC_XFER_ASAP;
+ isoc_req->isoc_cb = isoc_rec_callback;
+ isoc_req->isoc_exc_cb = isoc_exc_callback;
+ isoc_req->isoc_client_private = (usb_opaque_t) req;
+ isoc_req->isoc_pkt_descr[0].isoc_pkt_length = len;
+ isoc_req->isoc_pkts_count = 1;
+ isoc_req->isoc_pkts_length = len;
+ req->active = 1;
+
+ if ((err =
+ usb_pipe_isoc_xfer (req->pipe_handle, isoc_req,
+ USB_FLAGS_NOSLEEP)) != USB_SUCCESS)
+ {
+ cmn_err (CE_WARN, "usb_pipe_isoc_xfer failed (%s)\n",
+ usb_errstr (err));
+ return OSS_EIO;
+ }
+ }
+ break;
+
+ case UDI_USBXFER_BULK_WRITE:
+ {
+ usb_bulk_req_t *bulk_req;
+
+ if (req->bulk_req != NULL)
+ bulk_req = req->bulk_req;
+ else
+ {
+ req->data = allocb (len, BPRI_HI);
+ if (req->data == NULL)
+ {
+ cmn_err (CE_WARN, "allocb_wait (bulk) failed\n");
+ KERNEL_FREE (req);
+ return OSS_ENOMEM;
+ }
+
+ if ((bulk_req = usb_alloc_bulk_req (req->dip, len, 0)) == NULL)
+ {
+ cmn_err (CE_WARN, "usb_alloc_bulk_req failed\n");
+ freemsg (req->data);
+ KERNEL_FREE (req);
+ return OSS_ENOMEM;
+ }
+ req->bulk_req = bulk_req;
+ }
+
+ if (bulk_req == NULL)
+ {
+ cmn_err (CE_WARN, "req->bulk==NULL\n");
+ return OSS_EIO;
+ }
+
+ memcpy (req->data->b_wptr, data, len);
+ req->data->b_wptr += len;
+
+ bulk_req->bulk_data = req->data;
+ bulk_req->bulk_len = len;
+ bulk_req->bulk_timeout = 5; /* 5 seconds */
+ bulk_req->bulk_attributes = USB_ATTRS_AUTOCLEARING;
+ bulk_req->bulk_cb = bulk_play_callback;
+ bulk_req->bulk_exc_cb = bulk_exc_callback;
+ bulk_req->bulk_client_private = (usb_opaque_t) req;
+
+ if ((err =
+ usb_pipe_bulk_xfer (req->pipe_handle, bulk_req,
+ 0)) != USB_SUCCESS)
+ {
+ cmn_err (CE_WARN, "usb_pipe_bulk_xfer failed (%s)\n",
+ usb_errstr (err));
+ return OSS_EIO;
+ }
+ req->active = 1;
+ }
+ break;
+
+ case UDI_USBXFER_BULK_READ:
+ {
+ usb_bulk_req_t *bulk_req;
+
+ if (req->bulk_req != NULL)
+ bulk_req = req->bulk_req;
+ else
+ {
+#if 0
+ req->data = allocb (len, BPRI_HI);
+ if (req->data == NULL)
+ {
+ cmn_err (CE_WARN, "allocb_wait (bulk) failed\n");
+ KERNEL_FREE (req);
+ return OSS_ENOMEM;
+ }
+#endif
+
+ if ((bulk_req =
+ usb_alloc_bulk_req (req->dip, len, USB_FLAGS_SLEEP)) == NULL)
+ {
+ cmn_err (CE_WARN, "usb_alloc_bulk_req failed\n");
+ freemsg (req->data);
+ KERNEL_FREE (req);
+ return OSS_ENOMEM;
+ }
+ req->bulk_req = bulk_req;
+ }
+
+ if (bulk_req == NULL)
+ {
+ cmn_err (CE_WARN, "req->bulk==NULL\n");
+ return OSS_EIO;
+ }
+
+ bulk_req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK;
+ bulk_req->bulk_cb = bulk_rec_callback;
+ bulk_req->bulk_exc_cb = bulk_exc_callback;
+ bulk_req->bulk_client_private = (usb_opaque_t) req;
+ // bulk_req->bulk_data = data;
+ bulk_req->bulk_len = len;
+ bulk_req->bulk_timeout = 0x7fffffff; /* As long as possible */
+ req->active = 1;
+
+ if ((err =
+ usb_pipe_bulk_xfer (req->pipe_handle, bulk_req,
+ USB_FLAGS_NOSLEEP)) != USB_SUCCESS)
+ {
+ cmn_err (CE_WARN, "usb_pipe_bulk_xfer failed (%s)\n",
+ usb_errstr (err));
+ return OSS_EIO;
+ }
+ }
+ break;
+
+ case UDI_USBXFER_INTR_READ:
+ {
+ usb_intr_req_t *intr_req;
+
+ if (req->intr_req != NULL)
+ intr_req = req->intr_req;
+ else
+ {
+#if 0
+ req->data = allocb (len, BPRI_HI);
+ if (req->data == NULL)
+ {
+ cmn_err (CE_WARN, "allocb_wait (intr) failed\n");
+ KERNEL_FREE (req);
+ return OSS_ENOMEM;
+ }
+#endif
+
+ if ((intr_req =
+ usb_alloc_intr_req (req->dip, len, USB_FLAGS_SLEEP)) == NULL)
+ {
+ cmn_err (CE_WARN, "usb_alloc_intr_req failed\n");
+ freemsg (req->data);
+ KERNEL_FREE (req);
+ return OSS_ENOMEM;
+ }
+ req->intr_req = intr_req;
+ }
+
+ if (intr_req == NULL)
+ {
+ cmn_err (CE_WARN, "req->intr==NULL\n");
+ return OSS_EIO;
+ }
+
+ intr_req->intr_attributes =
+ USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_ONE_XFER;
+ intr_req->intr_cb = intr_rec_callback;
+ intr_req->intr_exc_cb = intr_exc_callback;
+ intr_req->intr_client_private = (usb_opaque_t) req;
+ intr_req->intr_data = NULL;
+ intr_req->intr_len = len;
+ intr_req->intr_timeout = 0x7fffffff; /* As long as possible */
+ req->active = 1;
+
+ if ((err =
+ usb_pipe_intr_xfer (req->pipe_handle, intr_req,
+ 0)) != USB_SUCCESS)
+ {
+ cmn_err (CE_WARN, "usb_pipe_intr_xfer failed (%s)\n",
+ usb_errstr (err));
+ return OSS_EIO;
+ }
+ }
+ break;
+
+ default:
+ cmn_err (CE_WARN, "Unimplemented transfer type %d\n", xfer_type);
+ return OSS_EIO;
+ }
+
+ return 0;
+}
+
+int
+udi_usb_request_actlen (udi_usb_request_t * request)
+{
+ return request->actlen;
+}
+
+unsigned char *
+udi_usb_request_actdata (udi_usb_request_t * request)
+{
+ return request->data->b_rptr;
+}
+
+void
+udi_usb_cancel_request (udi_usb_request_t * req)
+{
+ if (req == NULL || !req->active)
+ return;
+
+ req->active = 0;
+ usb_pipe_reset (req->dip, req->pipe_handle, USB_FLAGS_SLEEP, NULL, 0);
+
+ switch (req->xfer_type)
+ {
+ case UDI_USBXFER_ISO_WRITE:
+ break;
+
+ case UDI_USBXFER_ISO_READ:
+ usb_pipe_stop_isoc_polling (req->pipe_handle, USB_FLAGS_SLEEP);
+ //if (req->isoc_req!=NULL)
+ //usb_free_isoc_req(req->isoc_req);
+ req->isoc_req = NULL;
+ break;
+
+ case UDI_USBXFER_BULK_WRITE:
+ break;
+
+ case UDI_USBXFER_BULK_READ:
+ req->bulk_req = NULL;
+ break;
+
+ case UDI_USBXFER_INTR_READ:
+ req->intr_req = NULL;
+ break;
+
+ default:
+ cmn_err (CE_WARN, "Internal error - bad transfer type %d\n",
+ req->xfer_type);
+ }
+}
+#endif