diff options
Diffstat (limited to 'kernel/OS/BeOS')
-rw-r--r-- | kernel/OS/BeOS/.config | 1 | ||||
-rw-r--r-- | kernel/OS/BeOS/driver_beos.c | 104 | ||||
-rw-r--r-- | kernel/OS/BeOS/module.inc | 186 | ||||
-rw-r--r-- | kernel/OS/BeOS/os_beos.c | 2222 | ||||
-rw-r--r-- | kernel/OS/BeOS/os_beos.h | 471 |
5 files changed, 2984 insertions, 0 deletions
diff --git a/kernel/OS/BeOS/.config b/kernel/OS/BeOS/.config new file mode 100644 index 0000000..816ac62 --- /dev/null +++ b/kernel/OS/BeOS/.config @@ -0,0 +1 @@ +mode=kernel diff --git a/kernel/OS/BeOS/driver_beos.c b/kernel/OS/BeOS/driver_beos.c new file mode 100644 index 0000000..61f4bf9 --- /dev/null +++ b/kernel/OS/BeOS/driver_beos.c @@ -0,0 +1,104 @@ +/* + * Purpose: devfs interface for BeOS/Haiku + */ +/* + * + * This file is part of Open Sound System. + * + * Copyright (C) 4Front Technologies 1996-2007. + * + * 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. Please contact sales@opensound.com for further info. + * + */ + +#include "oss_config.h" +#include "midi_core.h" +#include <oss_pci.h> +#include <KernelExport.h> +#include <Drivers.h> + +#define DRIVER_NAME "ossdrv" + +int32 api_version = B_CUR_DRIVER_API_VERSION; + +oss_core_module_info *gOSSCore = NULL; + +// #pragma mark - + +// XXX: malloc it + update it from device list + +const char ** +publish_devices(void) +{ + return gOSSCore->oss_publish_devices(); +} + + +device_hooks * +find_device(const char *name) +{ + FENTRYA("%s", name); + + FEXIT(); + return gOSSCore->oss_get_driver_hooks(); +} + +// #pragma mark - + +status_t +init_hardware(void) +{ + status_t err; + FENTRY(); + + err = get_module(OSS_CORE_MODULE_NAME, (module_info **)&gOSSCore); + if (err < B_OK) { + FEXIT(); + return err; + } + + put_module(OSS_CORE_MODULE_NAME); + + FEXIT(); + return B_OK; +} + +status_t +init_driver(void) +{ + status_t err = ENOMEM; + FENTRY(); + + err = get_module(OSS_CORE_MODULE_NAME, (module_info **)&gOSSCore); + if (err < B_OK) + goto err1; + err = gOSSCore->init_osscore(); + dprintf("oss:init_osscore: 0x%08lx\n", err); + if (err < B_OK) + goto err2; + err = gOSSCore->oss_load_drivers(); + err = B_OK; + FEXITR(err); + return err; + +err2: + put_module(OSS_CORE_MODULE_NAME); +err1: + FEXITR(err); + return err; +} + +void +uninit_driver(void) +{ + status_t err; + FENTRY(); + + err = gOSSCore->oss_unload_all_drivers(); + err = gOSSCore->uninit_osscore(); + dprintf("oss:uninit_osscore: 0x%08lx\n", err); + put_module(OSS_CORE_MODULE_NAME); + FEXIT(); +} diff --git a/kernel/OS/BeOS/module.inc b/kernel/OS/BeOS/module.inc new file mode 100644 index 0000000..be7ab1b --- /dev/null +++ b/kernel/OS/BeOS/module.inc @@ -0,0 +1,186 @@ +/* -*- c -*- + * Purpose: OSS module wrapper for BeOS/Haiku + * + * This file will be included from the auto-generated drv_cfg.c files. Under + * UnixWare and OpenServer this will will be compiled during the initial build + * of OSS (in the development system). + */ +/* + * + * This file is part of Open Sound System. + * + * Copyright (C) 4Front Technologies 1996-2007. + * + * 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. Please contact sales@opensound.com for further info. + * + */ + +#include <PCI.h> + +//pci_module_info *gPCI = NULL; +extern pci_module_info *gPCI; + +#if DRIVER_TYPE==DRV_VIRTUAL +static oss_device_t *osdev = NULL; +#endif + +#if DRIVER_TYPE==DRV_PCI +int DRIVER_PROBE() +{ + oss_device_t *osdev; + pci_info pcii; + uint32 pci_index = 0; + uint32 count = 0; + int err = ENOENT; + static int instance = 0; + FENTRY(); + + /* while there are more pci devices */ + while ((*gPCI->get_nth_pci_info)(pci_index, &pcii) == B_NO_ERROR) + { + int vendor; + bool match = false; + bool sub = true; + + /* we first loop through all subsystem entries, then loop again */ +rescan: + vendor = 0; + /* if we match a supported vendor */ + while (id_table[vendor].vendor) + { + + /* check for function vendor & device id */ + if (!sub && + id_table[vendor].subsystem == false && + id_table[vendor].vendor == pcii.vendor_id && + id_table[vendor].product == pcii.device_id) + { + dprintf("oss: matching pci %04x,%04x\n", id_table[vendor].vendor, id_table[vendor].product); + match = true; + } + + /* check for subsystem vendor & device id */ + if (sub && + id_table[vendor].subsystem == true && + pcii.header_type == 0 && + id_table[vendor].vendor == pcii.u.h0.subsystem_vendor_id && + id_table[vendor].product == pcii.u.h0.subsystem_id) + { + dprintf("oss: matching pci subsystem %04x,%04x\n", id_table[vendor].vendor, id_table[vendor].product); + match = true; + } + + if (match) + { + dev_info_t *di; + di = PMALLOC(NULL, sizeof(dev_info_t)); + if (!di) + break; + memcpy(di, &pcii, sizeof(pcii)); + if ((osdev = + osdev_create (di, DRIVER_TYPE, instance, DRIVER_NICK, NULL)) == NULL) + { + break; + } + + /* should be called once, but we need an osdev */ + oss_load_options (osdev, local_driver_options); + + if (!DRIVER_ATTACH (osdev)) + { + cmn_err (CE_WARN, "Attach failed\n"); + osdev_delete (osdev); + break; + } + + instance++; + count++; + break; + } + vendor++; + } + /* we've checked for subsystem IDs, now rescan for IDs */ + if (!match && sub) { + sub = false; + goto rescan; + } + /* next pci_info struct, please */ + pci_index++; + } + + oss_audio_delayed_attach (); + + if (count) + err = 0; +err: + FEXITR(err); + return err; +} +#endif + +#if DRIVER_TYPE==DRV_VIRTUAL +int DRIVER_PROBE() +{ + int err = EIO; + FENTRY(); + if ((osdev = + osdev_create (NULL, DRIVER_TYPE, 0, DRIVER_NICK, NULL)) == NULL) + { + goto err; + } + + oss_load_options (osdev, local_driver_options); + + if (!DRIVER_ATTACH (osdev)) + { + cmn_err (CE_WARN, "Attach failed\n"); + osdev_delete (osdev); + goto err; + } + + err = 0; +err: + FEXITR(err); + return err; +} +#endif + + + + + + +static status_t +stdops(int32 op, ...) +{ + status_t err; + switch (op) + { + case B_MODULE_INIT: + err = get_module(B_PCI_MODULE_NAME, (module_info **)&gPCI); + return err; + + case B_MODULE_UNINIT: + //err = unload_driver(DRIVER_NICK); + //if (err < B_OK) + // return err; + put_module(B_PCI_MODULE_NAME); + return B_OK; + + } + return B_ERROR; +} + +oss_drv_module_info DRIVER_MODULE_OBJECT = { + { + OSS_MAKE_DRV_MOD_NAME(DRIVER_NICK), + 0, + stdops, + }, + DRIVER_PROBE, + DRIVER_ATTACH, + DRIVER_DETACH +}; + diff --git a/kernel/OS/BeOS/os_beos.c b/kernel/OS/BeOS/os_beos.c new file mode 100644 index 0000000..08587c5 --- /dev/null +++ b/kernel/OS/BeOS/os_beos.c @@ -0,0 +1,2222 @@ +/* + * Purpose: Operating system abstraction functions for BeOS/Haiku + */ +/* + * + * This file is part of Open Sound System. + * + * Copyright (C) 4Front Technologies 1996-2007. + * + * 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. Please contact sales@opensound.com for further info. + * + */ + +#include "oss_config.h" +#include "midi_core.h" +#include <oss_pci.h> +#include <Drivers.h> +#include <KernelExport.h> +#include <driver_settings.h> + +/* + * The BeOS and Haiku kernels are preemptible, + * therefore we must ensure safe access to global variables. + * Such variables are marked by GM. + * Other protected variables: + * - oss_cdevs + * - mixer_devs + * XXX: use a benaphore ?? + */ +#if 0 +// spinlock +static oss_mutex_t osscore_mutex; +#define CORE_LOCK_VAR \ + oss_native_word osscore_mutex_flags +#define CORE_LOCK_INIT() \ + MUTEX_INIT (osdev, osscore_mutex, MH_TOP) +#define CORE_LOCK_CLEANUP() \ + MUTEX_CLEANUP (osscore_mutex) +#define LOCK_CORE() \ + MUTEX_ENTER_IRQDISABLE (osscore_mutex, osscore_mutex_flags) +#define UNLOCK_CORE() \ + MUTEX_EXIT_IRQRESTORE (osscore_mutex, osscore_mutex_flags) +#else +// benaphore +typedef struct benaphore { + sem_id sem; + int32 count; +} benaphore; +benaphore osscore_benaphore; +#define CORE_LOCK_VAR \ + int dummy_ocl +#define CORE_LOCK_INIT() \ + osscore_benaphore.count = 1; \ + osscore_benaphore.sem = create_sem(0, "OSS CORE LOCK") +#define CORE_LOCK_CLEANUP() \ + delete_sem(osscore_benaphore.sem) +#define LOCK_CORE() \ + { \ + if (atomic_add(&osscore_benaphore.count, -1) <= 0) \ + acquire_sem(osscore_benaphore.sem); \ + } +#define UNLOCK_CORE() \ + { \ + if (atomic_add(&osscore_benaphore.count, 1) < 0) \ + release_sem(osscore_benaphore.sem); \ + } +#endif + +#define DEBUG_IRQ 1 +#if DEBUG_IRQ +vint32 irq_count = 0; +#endif + +volatile int oss_open_devices = 0; +#define MAX_CARDS 16 +int oss_num_cards = 0; /* GM */ +static oss_device_t *cards[MAX_CARDS]; /* GM */ +static int oss_expired = 0; +extern int vmix_disabled; + +//static struct fileinfo files[OSS_MAX_CDEVS]; +//static volatile int open_count[OSS_MAX_CDEVS] = { 0 }; +//static volatile int open_devices = 0; /* GM */ + +pci_module_info *gPCI = NULL; + +static char **gDeviceNames = NULL; // buffer for all names + +device_hooks oss_driver_hooks; + +/* + * Table for permanently allocated memory (to be freed by std_op(UNLOAD)) + */ +#define MAX_MEMBLOCKS 4096 +static void *memblocks[MAX_MEMBLOCKS]; /* GM */ +static int nmemblocks = 0; /* GM */ + +void * +oss_contig_malloc (oss_device_t * osdev, int size, oss_uint64_t memlimit, + oss_native_word * phaddr) +{ + status_t err; + area_id id; + void *p = NULL; + uint32 lock = B_CONTIGUOUS; + physical_entry pent[1]; + + *phaddr = 0; + + switch (memlimit) + { + case MEMLIMIT_ISA: + case MEMLIMIT_28BITS: + case MEMLIMIT_30BITS: + case MEMLIMIT_31BITS: + /* no known way to force a physical address limit other than <16M */ + lock = B_LOMEM; + break; + case MEMLIMIT_32BITS: + lock = B_CONTIGUOUS; + break; + + default: + cmn_err (CE_WARN, "Bad DMA memlimit for %s\n", osdev->nick); + } + + /* round up to page size */ + size += B_PAGE_SIZE - 1; + size &= ~(B_PAGE_SIZE - 1); + + if ((err = id = create_area(OSS_CONTIG_AREA_NAME, &p, B_ANY_KERNEL_ADDRESS, + size, lock, 0)) < B_OK) + { + cmn_err (CE_WARN, "create_area() failed\n"); + return NULL; + } + + if ((err = get_memory_map(p, size, pent, 1)) < B_OK) + { + cmn_err (CE_WARN, "get_memory_map() failed\n"); + delete_area(id); + return NULL; + } + //XXX:DEBUG + *phaddr = (oss_native_word)pent[0].address; + dprintf("oss_contig_malloc: area %d @ va %p, pa %p, sz %d\n", id, p, (void *)(*phaddr), size); + return p; +} + +void +oss_contig_free (oss_device_t * osdev, void *p, int sz) +{ + area_id id; + if (p == NULL) + return; + id = area_for(p); + if (id < B_OK) + return; +#ifdef MEMDEBUG + { + area_info ai; + if ((get_area_info(id, &ai) < B_OK) || strncmp(ai.name, OSS_CONTIG_AREA_NAME)) + { + cmn_err (CE_NOTE, "oss_contig_free: bad area (%ld)!\n", id); + return; + } + } +#endif + delete_area(id); +} + +int +__oss_alloc_dmabuf (int dev, dmap_p dmap, unsigned int alloc_flags, + oss_uint64_t maxaddr, int direction) +{ + void *tmpbuf; + oss_native_word phaddr; + int size = 64 * 1024; + extern int dma_buffsize; + + if (dma_buffsize > 16 && dma_buffsize <= 128) + size = dma_buffsize * 1024; + + if (dmap->dmabuf != NULL) + return 0; + +/* + * Some applications and virtual drivers need shorter buffer. + */ + if (dmap->flags & DMAP_SMALLBUF) + { + size = SMALL_DMABUF_SIZE; + } + else if (dmap->flags & DMAP_MEDIUMBUF) + { + size = MEDIUM_DMABUF_SIZE; + } + + if ((alloc_flags & DMABUF_SIZE_16BITS) && size > 32 * 1024) + size = 32 * 1024; + + tmpbuf = CONTIG_MALLOC (dmap->osdev, size, maxaddr, &phaddr, NULL); + if (tmpbuf == NULL) + return OSS_ENOMEM; + dmap->dmabuf = tmpbuf; + dmap->buffsize = size; + dmap->dmabuf_phys = phaddr; + + return 0; +} + +void +oss_free_dmabuf (int dev, dmap_p dmap) +{ + if (dmap->dmabuf == NULL) + return; + + CONTIG_FREE (dmap->osdev, dmap->dmabuf, dmap->buffsize, NULL); + dmap->dmabuf = NULL; + dmap->buffsize = 0; + dmap->dmabuf_phys = 0; +} + + +oss_native_word +oss_virt_to_bus (void *addr) +{ + physical_entry pent[2]; + status_t err; + + if (addr == NULL) + return 0; + + /* XXX: ROUNDUP(B_PAGE_SIZE) ? */ + if ((err = get_memory_map(addr, 1, pent, 2)) < 1) + { + cmn_err (CE_WARN, "Virtual address %x not mapped\n", (int) addr); + return 0; + } + //XXX:which??? + //return (oss_native_word)pent[0].address; + return (oss_native_word)(gPCI->ram_address(pent[0].address)); +} + + +void * +oss_pmalloc (size_t sz) +{ + void *tmp; + + tmp = KERNEL_MALLOC (sz); + + if (nmemblocks < MAX_MEMBLOCKS) + memblocks[nmemblocks++] = tmp; + + return tmp; +} + +int +oss_create_uio (uio_t * uio, char *buf, size_t count, uio_rw_t rw, + int is_kernel) +{ + memset (uio, 0, sizeof (*uio)); + + if (is_kernel) + { + oss_cmn_err (CE_CONT, + "oss_create_uio: Kernel space buffers not supported\n"); + return OSS_EIO; + } + + uio->ptr = buf; + uio->resid = count; + uio->kernel_space = is_kernel; + uio->rw = rw; + + return 0; +} + +int +oss_uiomove (void *address, size_t nbytes, enum uio_rw rwflag, uio_t * uio) +{ + int err = EFAULT; + FENTRY(); + + if (rwflag != uio->rw) + { + oss_cmn_err (CE_WARN, "uiomove: Bad direction\n"); + goto err; + } + + if (uio->resid < nbytes) + { + oss_cmn_err (CE_WARN, "uiomove: Bad count %d (%d)\n", nbytes, + uio->resid); + goto err; + } + + if (uio->kernel_space) + goto err; + + switch (rwflag) + { + case UIO_READ: + //XXX:user_memcpy... + memcpy (uio->ptr, address, nbytes); + break; + + case UIO_WRITE: + //XXX:user_memcpy... + memcpy (address, uio->ptr, nbytes); + break; + } + + uio->resid -= nbytes; + uio->ptr += nbytes; + + err = B_OK; +err: + FEXITR(err); + return err; +} + + +void +oss_cmn_err (int level, char *s, ...) +{ + char tmp[1024], *a[6]; + va_list ap; + int i, n = 0; + + va_start (ap, s); + + for (i = 0; i < strlen (s); i++) + if (s[i] == '%') + n++; + + for (i = 0; i < n && i < 6; i++) + a[i] = va_arg (ap, char *); + + for (i = n; i < 6; i++) + a[i] = NULL; + + if (level == CE_CONT) + { + sprintf (tmp, s, a[0], a[1], a[2], a[3], a[4], a[5], NULL, + NULL, NULL, NULL); + dprintf ("%s", tmp); + } + else + { + strcpy (tmp, "osscore: "); + sprintf (tmp + strlen (tmp), s, a[0], a[1], a[2], a[3], a[4], a[5], + NULL, NULL, NULL, NULL); + if (level == CE_PANIC) + panic (tmp); + + dprintf ("%s", tmp); + } + va_end (ap); +} + + +/* + * Sleep/wakeup + */ + +struct oss_wait_queue * +oss_create_wait_queue (oss_device_t * osdev, const char *name) +{ + struct oss_wait_queue *wq; + status_t err; + FENTRYA(", %s", name); + + if ((wq = malloc (sizeof (*wq))) == NULL) + { + oss_cmn_err (CE_WARN, "malloc(%d) failed (wq)\n", sizeof (*wq)); + return NULL; + } + sprintf(wq->name, OSS_WQ_SEM_NAME "%-20s", name); + err = wq->sem = create_sem(0, wq->name); + if (err < B_OK) + { + free(wq); + oss_cmn_err (CE_WARN, "create_sem() failed (wq)\n"); + return NULL; + } + + return wq; +} + +void +oss_reset_wait_queue (struct oss_wait_queue *wq) +{ + sem_info si; + status_t err; + FENTRY(); + + wq->flags = 0; + err = create_sem(0, wq->name); + if (err >= 0) { + /* replace with the new one */ + delete_sem(wq->sem); + wq->sem = err; + } + + FEXIT(); +} + +void +oss_remove_wait_queue (struct oss_wait_queue *wq) +{ + FENTRY(); + delete_sem(wq->sem); + free (wq); +} + +int +oss_sleep (struct oss_wait_queue *wq, oss_mutex_t * mutex, int ticks, + oss_native_word * flags, unsigned int *status) +{ + bigtime_t timeout = B_INFINITE_TIMEOUT; + uint32 semflags = B_CAN_INTERRUPT | B_RELATIVE_TIMEOUT; + int result = 0; + FENTRYA("(%s), , %d, , ", wq->name, ticks); + *status = 0; + + if (wq == NULL) + return 0; + +#ifdef B_WAKE_ON_TIMEOUT + // Dano only; sure it's what we want ? + if (wq->flags & WK_WAKEUP) + semflags |= B_WAKE_ON_TIMEOUT; +#endif + + wq->flags = 0; + MUTEX_EXIT_IRQRESTORE(*mutex, *flags); + + if (ticks > 0) + timeout = ticks * 1000000LL / OSS_HZ; + result = acquire_sem_etc (wq->sem, 1, semflags, timeout); + //dprintf("oss_sleep:acquire_sem(s:%ld, 1, %x, %Ld): 0x%08lx\n", wq->sem, semflags, timeout, result); + + MUTEX_ENTER_IRQDISABLE (*mutex, *flags); + + if (result == EINTR) /* Signal received */ + { + *status |= WK_SIGNAL; + return 1; + } + + if (result == B_TIMED_OUT) + //if (!(wq->flags & WK_WAKEUP)) /* Timeout */ + { + return 0; + } + + return 1; +} + +int +oss_register_poll (struct oss_wait_queue *wq, oss_mutex_t * mutex, + oss_native_word * flags, oss_poll_event_t * ev) +{ + FENTRYA("(%s), , , , ", wq->name); + dprintf("oss:UNIMPLEMENTED:%s\n", __FUNCTION__); + MUTEX_EXIT_IRQRESTORE(*mutex, *flags); + //poll_wait ((struct file *) ev->file, &wq->wq, (struct wait *) ev->wait); + MUTEX_ENTER_IRQDISABLE (*mutex, *flags); + return 0; +} + +void +oss_wakeup (struct oss_wait_queue *wq, oss_mutex_t * mutex, + oss_native_word * flags, short events) +{ + FENTRYA("(%s), , %x, , ", wq->name, events); + if (wq == NULL) + return; + + wq->flags |= WK_WAKEUP; + MUTEX_EXIT_IRQRESTORE(*mutex, *flags); + + //dprintf("oss_wakeup:release_sem(s:%ld)\n", wq->sem); + release_sem_etc (wq->sem, 1, B_DO_NOT_RESCHEDULE); + //XXX:handle select here + + MUTEX_ENTER_IRQDISABLE (*mutex, *flags); +} + +unsigned long +oss_get_time (void) +{ + return (unsigned long) (system_time() / (1000000 / OSS_HZ)); +} + +typedef struct tmout_desc +{ + struct timer timer; /* MUST be first */ + + volatile int active; + int timestamp; + void (*func) (void *); + void *arg; +} tmout_desc_t; + +static volatile int next_id = 0; +#define MAX_TMOUTS 128 + +tmout_desc_t tmouts[MAX_TMOUTS] = { {0} }; + +int timeout_random = 0x12123400; + +int32 +oss_timer_callback (struct timer *timer) +{ + tmout_desc_t *tmout = (tmout_desc_t *)timer; + int ix; + void *arg; + + timeout_random++; + + if (!tmout->active) + return; + + arg = tmout->arg; + tmout->active = 0; + tmout->timestamp = 0; + + tmout->func (arg); + return B_HANDLED_INTERRUPT;//B_INVOKE_SCHEDULER ?; +} + +timeout_id_t +oss_timeout (void (*func) (void *), void *arg, unsigned long long ticks) +{ + tmout_desc_t *tmout = NULL; + bigtime_t period; + int id, n; + + timeout_random++; + + n = 0; + id = -1; + + while (id == -1 && n < MAX_TMOUTS) + { + if (!tmouts[next_id].active) + { + tmouts[next_id].active = 1; + id = next_id++; + tmout = &tmouts[id]; + break; + } + + next_id = (next_id + 1) % MAX_TMOUTS; + } + + if (id == -1) /* No timer slots available */ + { + oss_cmn_err (CE_WARN, "Timeout table full\n"); + return 0; + } + + tmout->func = func; + tmout->arg = arg; + tmout->timestamp = id | (timeout_random & ~0xff); + + period = ticks * 1000000LL / OSS_HZ; + add_timer (&tmout->timer, oss_timer_callback, period, B_ONE_SHOT_RELATIVE_TIMER); + + return id | (timeout_random & ~0xff); +} + +void +oss_untimeout (timeout_id_t id) +{ + tmout_desc_t *tmout; + int ix; + + ix = id & 0xff; + if (ix < 0 || ix >= MAX_TMOUTS) + return; + + timeout_random++; + tmout = &tmouts[ix]; + + if (tmout->timestamp != id) /* Expired timer */ + return; + if (tmout->active) + cancel_timer (&tmout->timer); + tmout->active = 0; + tmout->timestamp = 0; +} + + +caddr_t +oss_map_pci_mem (oss_device_t * osdev, int nr, int phaddr, int size) +{ + status_t err; + void *va = NULL; + FENTRYA("%p,%d,%u,%d", osdev, nr, phaddr, size); + //XXX:align phaddr ? + /* round up to page size */ + size += B_PAGE_SIZE - 1; + size &= ~(B_PAGE_SIZE - 1); + + err = map_physical_memory(OSS_PCI_AREA_NAME, (void *)phaddr, size, + B_ANY_KERNEL_BLOCK_ADDRESS, 0, &va); + if (err < B_OK) + va = NULL; + FEXITR((uint32)va); + return (caddr_t)va; +} + +void +oss_unmap_pci_mem (void *addr) +{ + area_id id; + if (addr == NULL) + return; + id = area_for(addr); + if (id < B_OK) + return; +#ifdef MEMDEBUG + { + area_info ai; + if ((get_area_info(id, &ai) < B_OK) || strncmp(ai.name, OSS_PCI_AREA_NAME)) + { + cmn_err (CE_NOTE, "oss_unmap_pci_mem: bad area (%ld)!\n", id); + return; + } + } +#endif + delete_area(id); +} + +void +oss_pci_byteswap (oss_device_t * osdev, int mode) +{ + // NOP +} + +void +oss_pcie_init (oss_device_t * osdev, int flags) +{ + /* TODO: Should we do something? */ +} + +int +pci_read_config_byte (oss_device_t * osdev, offset_t where, + unsigned char *val) +{ + if (osdev->dev_type != DRV_PCI || osdev->dip == NULL) + return PCIBIOS_FAILED; + *val = (unsigned char)gPCI->read_pci_config (osdev->dip->pciinfo.bus, + osdev->dip->pciinfo.device, + osdev->dip->pciinfo.function, + (uchar)where, 1); + 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 || osdev->dip == NULL) + return PCIBIOS_FAILED; + *val = (unsigned short)gPCI->read_pci_config (osdev->dip->pciinfo.bus, + osdev->dip->pciinfo.device, + osdev->dip->pciinfo.function, + (uchar)where, 2); + return PCIBIOS_SUCCESSFUL; +} + +int +pci_read_config_dword (oss_device_t * osdev, offset_t where, + unsigned int *val) +{ + if (osdev->dev_type != DRV_PCI || osdev->dip == NULL) + return PCIBIOS_FAILED; + *val = (unsigned int)gPCI->read_pci_config (osdev->dip->pciinfo.bus, + osdev->dip->pciinfo.device, + osdev->dip->pciinfo.function, + (uchar)where, 4); + return PCIBIOS_SUCCESSFUL; +} + +int +pci_write_config_byte (oss_device_t * osdev, offset_t where, + unsigned char val) +{ + if (osdev->dev_type != DRV_PCI || osdev->dip == NULL) + return PCIBIOS_FAILED; + gPCI->write_pci_config (osdev->dip->pciinfo.bus, + osdev->dip->pciinfo.device, + osdev->dip->pciinfo.function, + (uchar)where, 1, 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 || osdev->dip == NULL) + return PCIBIOS_FAILED; + gPCI->write_pci_config (osdev->dip->pciinfo.bus, + osdev->dip->pciinfo.device, + osdev->dip->pciinfo.function, + (uchar)where, 2, 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 || osdev->dip == NULL) + return PCIBIOS_FAILED; + gPCI->write_pci_config (osdev->dip->pciinfo.bus, + osdev->dip->pciinfo.device, + osdev->dip->pciinfo.function, + (uchar)where, 4, val); + return PCIBIOS_SUCCESSFUL; +} + + + +#ifdef MUTEX_CHECKS +static int oss_context = 0; /* 0=user context, 1=interrupt context */ +#endif + +static int32 +ossintr (void *idata) +{ + oss_device_t *osdev = idata; + oss_native_word flags; + //dprintf("oss:intr(%ld)!\n", osdev->irq); +#ifdef MUTEX_CHECKS + int saved_context; + saved_context = oss_context; + if (oss_context == 1) + cmn_err (CE_WARN, "Recursive interrupt\n"); + oss_context = 1; +#endif + + MUTEX_ENTER_IRQDISABLE (osdev->mutex, flags); + + if (!osdev->tophalf_handler (osdev)) + { + MUTEX_EXIT_IRQRESTORE (osdev->mutex, flags); +#ifdef MUTEX_CHECKS + oss_context = saved_context; +#endif + return B_UNHANDLED_INTERRUPT; + } + + if (osdev->bottomhalf_handler != NULL) + osdev->bottomhalf_handler (osdev); + + MUTEX_EXIT_IRQRESTORE (osdev->mutex, flags); +#ifdef MUTEX_CHECKS + oss_context = saved_context; +#endif + + return B_HANDLED_INTERRUPT; +} + +int +oss_register_interrupts (oss_device_t * osdev, int intrnum, + oss_tophalf_handler_t top, + oss_bottomhalf_handler_t bottom) +{ + unsigned char pci_irq_line; + int err; + FENTRYA(", %d, , ", intrnum); + + 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; + } + + // could probably use osdev->dip->pciinfo... + if (pci_read_config_irq (osdev, PCI_INTERRUPT_LINE, &pci_irq_line) > 0) + return OSS_EIO; + + osdev->irq = pci_irq_line; + osdev->tophalf_handler = top; + osdev->bottomhalf_handler = bottom; + err = install_io_interrupt_handler (pci_irq_line, ossintr, osdev, 0); + dprintf("install_io_interrupt_handler (%d, %p, %p, 0) = 0x%08lx\n", pci_irq_line, ossintr, osdev, err); + if (err < B_OK) + { + cmn_err (CE_WARN, "install_io_interrupt_handler failed for %s\n", osdev->nick); + osdev->irq = -1; + osdev->tophalf_handler = NULL; + osdev->bottomhalf_handler = NULL; + return err; + } + +#if DEBUG_IRQ + atomic_add(&irq_count, 1); +#endif + + return 0; +} + +void +oss_unregister_interrupts (oss_device_t * osdev) +{ + status_t err = B_OK; + FENTRY(); + dprintf("remove_io_interrupt_handler (%d, %p, %p)\n", osdev->irq, ossintr, osdev); + if (osdev->irq >= 0) + err = remove_io_interrupt_handler (osdev->irq, ossintr, osdev); + if (err < B_OK) + cmn_err (CE_WARN, "Error removing interrupt index (%d) for %s: %s\n", + osdev->irq, osdev->name, strerror(err)); +#if DEBUG_IRQ + atomic_add(&irq_count, -1); +#endif + osdev->irq = -1; +} + +int +oss_register_device (oss_device_t * osdev, const char *name) +{ + static int dev_instance = 0; + FENTRYA(", %s", name); + + DDB (cmn_err (CE_CONT, "OSS device %d is %s\n", dev_instance++, 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); + FEXITR(0); + return 0; +} + +int +oss_disable_device (oss_device_t * osdev) +{ + int i; + CORE_LOCK_VAR; + FENTRY(); +/* + * 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. + */ + LOCK_CORE(); + if (osdev->refcount > 0 || oss_open_devices > 0) + { + UNLOCK_CORE(); + cmn_err (CE_CONT, "Refcount %d, open_devices %d\n", osdev->refcount, + oss_open_devices); + return OSS_EBUSY; + } + +/* + * Now mark all devices unavailable (for the time being) + */ + + for (i = 0; i < num_mixers; i++) + if (mixer_devs[i]->osdev == osdev) + { + mixer_devs[i]->unloaded = 1; + } + + for (i = 0; i < num_mididevs; i++) + { + if (midi_devs[i]->osdev == osdev) + { + midi_devs[i]->unloaded = 1; + } + } + + for (i = 0; i < num_audio_engines; i++) + if (audio_engines[i]->osdev == osdev) + { + UNLOCK_CORE(); //needed until a benaphore is used. + audio_uninit_device (i); + LOCK_CORE(); + } + + UNLOCK_CORE(); + + FEXIT(); + return 0; +} + +void +oss_unregister_device (oss_device_t * osdev) +{ + FENTRY(); +/* + * 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; + FEXIT(); +} + +void +oss_reserve_device (oss_device_t * osdev) +{ + CORE_LOCK_VAR; + + //XXX:use atomic_add() ? + LOCK_CORE(); + osdev->refcount++; + UNLOCK_CORE(); +} + +void +oss_unreserve_device (oss_device_t * osdev, int decrement) +{ + CORE_LOCK_VAR; + + //XXX:use atomic_add() ? + LOCK_CORE(); + osdev->refcount--; + if (osdev->refcount < 0) + osdev->refcount = 0; + UNLOCK_CORE(); +} + +void * +oss_get_osid (oss_device_t * osdev) +{ +// return osdev->osid; + return osdev->dip; + return NULL; // XXX:TODO +} + +int +oss_get_procinfo(int what) +{ + switch (what) + { + case OSS_GET_PROCINFO_UID: + return getuid(); + break; + } + + return OSS_EINVAL; +} + +oss_device_t * +osdev_create (dev_info_t * dip, int dev_type, int instance, const char *nick, + const char *handle) +{ + oss_device_t *osdev = NULL; + int i, err; + caddr_t addr; + off_t region_size; + CORE_LOCK_VAR; + FENTRYA(", %d, %d, %s, %s", dev_type, instance, nick, handle); + + if (handle == NULL) + handle = nick; + + /* + * Don't accept any more drivers if expired + */ + if (oss_expired && oss_num_cards > 0) + return NULL; + + LOCK_CORE(); + for (i = 0; dip && (i < oss_num_cards); i++) + { + if (cards[i] == NULL) + continue; + if (cards[i]->available) + continue; + if (cards[i]->dip == dip) + { + osdev = cards[i]; + break; + } + } + UNLOCK_CORE(); + + if (osdev == NULL) + { + if ((osdev = PMALLOC (NULL, sizeof (*osdev))) == NULL) + { + cmn_err (CE_WARN, "osdev_create: Out of memory\n"); + return NULL; + } + + LOCK_CORE(); + if (oss_num_cards >= MAX_CARDS) + { + UNLOCK_CORE(); + cmn_err (CE_PANIC, "Too many OSS devices. At most %d permitted.\n", + MAX_CARDS); + return NULL; + } + memset (osdev, 0, sizeof (*osdev)); + + osdev->cardnum = oss_num_cards; + cards[oss_num_cards++] = osdev; + UNLOCK_CORE(); + } + + osdev->dip = dip; + //osdev->osid = dip; + osdev->unloaded = 0; + osdev->available = 1; + osdev->first_mixer = -1; + osdev->instance = instance; + osdev->dev_type = dev_type; + osdev->devc = NULL; + MUTEX_INIT (osdev, osdev->mutex, MH_GLOBAL); + sprintf (osdev->nick, "%s%d", nick, instance); + strcpy (osdev->modname, nick); + + switch (dev_type) + { + case DRV_PCI: + /* NOP */ +#ifdef __HAIKU__ + if (gPCI->reserve_device(osdev->dip->pciinfo.bus, + osdev->dip->pciinfo.device, + osdev->dip->pciinfo.function, + "oss", osdev) != B_OK) { + cmn_err (CE_WARN, "Could not reserve PCI device\n"); + /* XXX: CLEANUP! */ + return NULL; + } +#endif + break; + + case DRV_VIRTUAL: + case DRV_STREAMS: + /* NOP */ + break; + + case DRV_USB: + /* NOP */ + break; + + default: + cmn_err (CE_WARN, "Bad device type\n"); + return NULL; + } + +/* + * Create the device handle + */ + switch (dev_type) + { + case DRV_PCI: + { + unsigned int subvendor; + 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); + } + + FEXIT(); + return osdev; +} + +oss_device_t * +osdev_clone (oss_device_t * orig_osdev, int new_instance) +{ + oss_device_t *osdev; + FENTRYA(", %d", new_instance); + + 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); + + FEXIT(); + return osdev; +} + +void +osdev_delete (oss_device_t * osdev) +{ + int i; + CORE_LOCK_VAR; + + FENTRY(); + if (osdev == NULL) + return; + osdev->available=0; + + switch (osdev->dev_type) + { + case DRV_PCI: + /* NOP */ + //pci_config_teardown (&osdev->pci_config_handle); + //osdev->pci_config_handle = NULL; +#ifdef __HAIKU__ + gPCI->unreserve_device(osdev->dip->pciinfo.bus, + osdev->dip->pciinfo.device, + osdev->dip->pciinfo.function, + "oss", osdev); +#endif + break; + } + +/* + * Mark all minor nodes for this module as invalid. + */ + LOCK_CORE(); + for (i = 0; i < oss_num_cdevs; i++) + if (oss_cdevs[i]->osdev == osdev) + { + oss_cdevs[i]->d = NULL; + oss_cdevs[i]->osdev = NULL; + strcpy (oss_cdevs[i]->name, "Removed device"); + } + UNLOCK_CORE(); + + MUTEX_CLEANUP (osdev->mutex); + osdev->unloaded = 1; + FEXIT(); +} + +static int +grow_array(oss_device_t *osdev, oss_cdev_t ***arr, int *size, int element_size, int increment) +{ + oss_cdev_t **old=*arr, **new = *arr; + int old_size = *size; + int new_size = *size; + + new_size += increment; + + if ((new=PMALLOC(osdev, new_size * element_size))==NULL) + return 0; + + memset(new, 0, new_size * element_size); + if (old != NULL) + memcpy(new, old, old_size * element_size); + + *size = new_size; + *arr = new; + + if (old != NULL) + PMFREE(osdev, old); + + return 1; +} + +void +oss_install_chrdev (oss_device_t * osdev, char *name, int dev_class, + int instance, oss_cdev_drv_t * drv, int flags) +{ +/* + * oss_install_chrdev creates a character device (minor). However if + * name==NULL the device will not be exported (made visible to userland + * clients). + */ + + int i, num; + oss_cdev_t *cdev = NULL; + CORE_LOCK_VAR; + FENTRYA(", %s, %d, %d, , %d", name, dev_class, instance, flags); + + if (dev_class != OSS_DEV_STATUS) + if (oss_expired && instance > 0) + return; +/* + * Find if this dev_class&instance already exists (after previous module + * detach). + */ + + LOCK_CORE(); + 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]; + //dprintf("oss:reusing cdev[%d]\n", num); + memset (cdev, 0, sizeof (*cdev)); + cdev->dev_class = dev_class; + cdev->instance = instance; + cdev->d = drv; + cdev->osdev = osdev; + if (name != NULL) + strncpy (cdev->name, name, sizeof (cdev->name) - 1); + else + strcpy (cdev->name, "NONE"); + cdev->name[sizeof (cdev->name) - 1] = 0; + oss_cdevs[num] = cdev; + break; + } + UNLOCK_CORE(); + + if (cdev == NULL) + { + /* must alloc before locking, the rest must be atomic */ + if ((cdev = PMALLOC (NULL, sizeof (*cdev))) == NULL) + { + cmn_err (CE_WARN, "Cannot allocate character device desc.\n"); + return; + } + + LOCK_CORE(); + 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"); + UNLOCK_CORE(); + return; + } + } + + num = oss_num_cdevs++; + memset (cdev, 0, sizeof (*cdev)); + cdev->dev_class = dev_class; + cdev->instance = instance; + cdev->d = drv; + cdev->osdev = osdev; + if (name != NULL) + strncpy (cdev->name, name, sizeof (cdev->name) - 1); + else + strcpy (cdev->name, "NONE"); + cdev->name[sizeof (cdev->name) - 1] = 0; + oss_cdevs[num] = cdev; + //dprintf("oss:reusing cdev[%d]: @%p\n", num, cdev); + UNLOCK_CORE(); + } + +/* + * Export the device only if name != NULL + */ +#if 0 + if (name != NULL) + { + char tmp[64], *s; + char *dev_type = "oss_sysdev"; + +//XXX: maybe do something ?? + } +#endif + FEXIT(); +} + +int +oss_get_cardinfo (int cardnum, oss_card_info * ci) +{ + CORE_LOCK_VAR; +/* + * Print information about a 'card' in a format suitable for /dev/sndstat + */ + + LOCK_CORE(); + if (cardnum < 0 || cardnum >= oss_num_cards) + { + UNLOCK_CORE(); + 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; + + UNLOCK_CORE(); + + return 0; +} + +/* XXX: major/minors don't exist in BeOS, WTF */ +int +oss_find_minor (int dev_class, int instance) +{ + int i, minor = -1; + CORE_LOCK_VAR; + + LOCK_CORE(); + for (i = 0; i < oss_num_cdevs; i++) + if (oss_cdevs[i]->d != NULL && oss_cdevs[i]->dev_class == dev_class + && oss_cdevs[i]->instance == instance) + { + minor = i; + break; + } + UNLOCK_CORE(); + + return minor; +} + + +#ifdef MUTEX_CHECKS +void +debug_mutex_init (oss_mutex_t * mutex, char *file, int line) +{ + memset (mutex, 0, sizeof (mutex)); + mutex->lock = 0; + mutex->owner = -1; +} + +void +debug_mutex_destroy (oss_mutex_t * mutex, char *file, int line) +{ + if (find_thread(NULL) == mutex->owner) + { + cmn_err (CE_NOTE, "%s:%d: mutex still owned (%d)\n", file, line, mutex->owner); + } + if (mutex->lock) + { + cmn_err (CE_NOTE, "%s:%d: mutex still locked (%d)\n", file, line, mutex->lock); + } +} + +void +debug_mutex_enter (oss_mutex_t * mutex, char *file, int line, oss_native_word *flags) +{ + if (find_thread(NULL) == mutex->owner) + { + 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->busy_flags = flags ? CNTX_INTR : CNTX_USER; + if (flags) + *flags = (oss_native_word) disable_interrupts(); + acquire_spinlock (&mutex->lock); + +} + +void +debug_mutex_exit (oss_mutex_t * mutex, char *file, int line, oss_native_word *flags) +{ + if (find_thread(NULL) != mutex->owner) + { + cmn_err (CE_NOTE, "Mutex not owned %s:%d\n", file, line); + } + else + { + release_spinlock(&mutex->lock); + if (flags) + restore_interrupts((cpu_status)*flags); + } + + mutex->owner = -1; + mutex->file = NULL; + mutex->line = 0; + mutex->busy_flags = 0; +} +#endif + + +void +oss_load_options (oss_device_t * osdev, oss_option_map_t map[]) +{ + char name[32] = OSS_CONFIG_FILE_PREFIX "core"; + void *handle; + const char *valstr; + int i; + + if (osdev == NULL) + return; + + /* if not core module, take the module name */ + if (strcmp(osdev->modname, "oss")) + strncpy (name, osdev->modname, 16); + + dprintf("oss_load_options(): %s\n", name); + handle = load_driver_settings (name); + /* not there */ + if (handle == NULL) + return; + + for (i = 0; map[i].name != NULL; i++) + { + /* discard given without value */ + if ((valstr = + get_driver_parameter (handle, + map[i].name, NULL, NULL)) != NULL) + { + int base = 10; + if (!strncmp (valstr, "0x", 2)) + { + base = 16; + valstr += 2; + } + *map[i].ptr = (int)strtol (valstr, NULL, base); + } + } + unload_driver_settings (handle); +} + +#ifdef DEBUG_KDLCMD +static int +kdl_oss_dump_cards(int argc, char **argv) +{ + int i; + kprintf("oss_num_cards = %d\n", oss_num_cards); + for (i = 0; i < oss_num_cards; i++) + { + if (cards[i] == NULL) + continue; + kprintf("oss_cards[%d] = {\n", i); + kprintf(" cardnum= %d\n", cards[i]->cardnum); + kprintf(" dev_type= %d\n", cards[i]->dev_type); + kprintf(" instance= %d\n", cards[i]->instance); + + kprintf(" unloaded= %d\n", cards[i]->unloaded); + + kprintf(" name= %s\n", cards[i]->name); + kprintf(" nick= %-16s\n", cards[i]->nick); + kprintf(" modname= %-32s\n", cards[i]->modname); + kprintf(" handle= %-32s\n", cards[i]->handle); + kprintf(" num_audio_engines= %d\n", cards[i]->num_audio_engines); + kprintf(" num_audioplay= %d\n", cards[i]->num_audioplay); + kprintf(" num_audiorec= %d\n", cards[i]->num_audiorec); + kprintf(" num_audioduplex= %d\n", cards[i]->num_audioduplex); + kprintf(" num_mididevs= %d\n", cards[i]->num_mididevs); + kprintf(" num_mixerdevs= %d\n", cards[i]->num_mixerdevs); + + kprintf(" refcount= %d\n", cards[i]->refcount); + + kprintf(" irq= %d\n", cards[i]->irq); + kprintf("}\n"); + } + return 0; +} + +static int +kdl_oss_dump_cdevs(int argc, char **argv) +{ + int i; + kprintf("oss_num_cdevs = %d\n", oss_num_cdevs); + for (i = 0; i < oss_num_cdevs; i++) + { + if (oss_cdevs[i] == NULL) + continue; + kprintf("oss_cdevs[%d] = {\n", i); + kprintf(" dev_class= %d\n", oss_cdevs[i]->dev_class); + kprintf(" instance= %d\n", oss_cdevs[i]->instance); + kprintf(" name= %-32s\n", oss_cdevs[i]->name); + kprintf(" osdev= %p\n", oss_cdevs[i]->osdev); + //kprintf(" opencount= %d\n", open_count[i]); + kprintf("}\n"); + } + return 0; +} +#endif + +/* + * Driver entry point routines + */ + +status_t +init_osscore (void) +{ + int err = 0; + oss_device_t *osdev; + FENTRY(); + +#ifdef LICENSED_VERSION +/*WRITEME*/ +#endif + + add_debugger_command("oss_dump_cards", &kdl_oss_dump_cards, "Dump the OSS cards[] array."); + add_debugger_command("oss_dump_cdevs", &kdl_oss_dump_cdevs, "Dump the OSS cdevs[] array."); + + //MUTEX_INIT (osdev, osscore_mutex, MH_TOP); + CORE_LOCK_INIT(); + + if ((osdev = osdev_create (NULL, DRV_VIRTUAL, 0, "oss", NULL)) == NULL) + { + cmn_err (CE_WARN, "Creating osdev failed\n"); + FEXITR(ENOMEM); + return OSS_ENOMEM; + } + + + oss_load_options (osdev, oss_global_options); + + oss_common_init (osdev); + + oss_register_device (osdev, "OSS core services"); + + FEXIT(); + return 0; +} + +status_t +uninit_osscore (void) +{ + int i; + static int already_unloaded = 0; + FENTRY(); + + if (oss_open_devices > 0) + return EBUSY; + + if (already_unloaded) + return 0; + already_unloaded = 1; + + oss_unload_drivers (); + + //LOCK_CORE(); + for (i = 0; i < nmemblocks; i++) + KERNEL_FREE (memblocks[i]); + nmemblocks = 0; + + CORE_LOCK_CLEANUP(); + //MUTEX_CLEANUP (osscore_mutex); + + remove_debugger_command("oss_dump_cdevs", &kdl_oss_dump_cdevs); + remove_debugger_command("oss_dump_cards", &kdl_oss_dump_cards); + +#if DEBUG_IRQ + dprintf("oss: %ld irq handlers left\n", irq_count); +#endif + + + return 0; +} + +const char ** +oss_publish_devices(void) +{ + int i, j; + char *name; + CORE_LOCK_VAR; + + FENTRY(); + + LOCK_CORE(); + gDeviceNames = realloc(gDeviceNames, (oss_num_cdevs + 1) * sizeof(char *) + + (oss_num_cdevs * DEVICE_NAME_LEN)); + if (gDeviceNames == NULL) { + UNLOCK_CORE(); + FEXIT(); + return NULL; + } + name = (char *)(&gDeviceNames[oss_num_cdevs + 1]); + for (i = 0; i < oss_num_cdevs+1; i++) + gDeviceNames[i] = NULL; + //dprintf("oss_num_cdevs = %d\n", oss_num_cdevs); + for (i = 0, j = 0; i < oss_num_cdevs; i++) + { + oss_cdev_t *cdev = oss_cdevs[i]; + if (cdev && cdev->d) + { + strcpy(name, DEVICE_PREFIX); + strncat(name, cdev->name, 32-1); + //dprintf("oss: publishing %s\n", name); + gDeviceNames[j++] = name; + name += DEVICE_NAME_LEN; + } + } + UNLOCK_CORE(); + + FEXIT(); + return (const char**)gDeviceNames; +} + +device_hooks *oss_get_driver_hooks (void) +{ + return &oss_driver_hooks; +} + +status_t +oss_load_drivers (void) +{ + oss_drv_module_info *drv; + char module[256]; + size_t modulesz = sizeof(module); + void *cookie; + status_t err = ENOENT; + FENTRY(); + cookie = open_module_list(OSS_MODULES_PREFIX); + if (cookie == NULL) + goto err1; + while (read_next_module_name(cookie, module, &modulesz) >= B_OK) + { + err = get_module(module, (module_info **)&drv); + if (err >= B_OK) + { + if (drv->driver_probe() < B_OK) + put_module(module); + } + modulesz = sizeof(module); + } + err = B_OK; +err2: + close_module_list(cookie); +err1: + FEXITR(err); + return B_OK; +} + +status_t +oss_probe_pci (void) +{ + FENTRY(); + //XXX:TODO:remove me + //ali5455_probe(); + //atiaudio_probe(); + FEXIT(); + return B_OK; +} + + +static status_t +unload_driver (const char *nick) +{ + oss_drv_module_info *drv; + char module[256]; + status_t err = B_OK; + int i; + CORE_LOCK_VAR; + FENTRYA("%s", nick); + + /* skip ourselves */ + if (!strcmp(nick, "oss")) + goto err1; + + sprintf(module, "%s%s%s", OSS_MODULES_PREFIX, nick, OSS_MODULES_SUFFIX); + err = get_module(module, (module_info **)&drv); + if (err < B_OK) + goto err1; + + err = EBUSY; + + LOCK_CORE(); + /* detach all osdevs for this driver */ + for (i = 0; i < oss_num_cards; i++) + { + oss_device_t *osdev = cards[i]; + if (!osdev) + continue; + if (strncmp(osdev->modname, nick, 32)) + continue; + UNLOCK_CORE(); + err = drv->driver_detach(osdev); + if (err < B_OK) + goto err2; + LOCK_CORE(); + //cards[i] = NULL; // XXX: not sure... + } + UNLOCK_CORE(); + err = B_OK; + put_module(module); + /* twice */ +err2: + put_module(module); +err1: + FEXITR(err); + return err; +} + +status_t +oss_unload_all_drivers(void) +{ + char module[256]; + status_t err = B_OK; + int i; + CORE_LOCK_VAR; + FENTRY(); + + /* for each osdev still around, unload the module it came from, + * which should delete them. + */ + LOCK_CORE(); + for (i = 0; i < oss_num_cards; i++) + { + if (!cards[i]) + continue; + if (cards[i]->unloaded) + continue; + UNLOCK_CORE(); + err = unload_driver(cards[i]->modname); + if (err < B_OK) + break; + LOCK_CORE(); + } + UNLOCK_CORE(); + + FEXITR(err); + return err; +} + + +static status_t +oss_stdops(int32 op, ...) +{ + status_t err; + switch (op) + { + case B_MODULE_INIT: + //vmix_disabled = 1; /* disable vmix */ + err = get_module(B_PCI_MODULE_NAME, (module_info **)&gPCI); + if (err >= B_OK) + { + //XXX:call init_osscore() here + return err; + put_module(B_PCI_MODULE_NAME); + } + return err; + case B_MODULE_UNINIT: + free(gDeviceNames); + put_module(B_PCI_MODULE_NAME); + return B_OK; + + } + return B_ERROR; +} + +oss_core_module_info gOSSCoreModule = { + { + OSS_CORE_MODULE_NAME, + /*B_KEEP_LOADED*/0, + oss_stdops, + }, + init_osscore, + uninit_osscore, + oss_publish_devices, + oss_get_driver_hooks, + oss_probe_pci, + oss_load_drivers, + oss_unload_all_drivers, +}; + +// for f in kernel/drv/*; do echo "extern oss_drv_module_info gModule_$(basename $f);"; done +extern oss_drv_module_info gModule_oss_ali5455; +extern oss_drv_module_info gModule_oss_atiaudio; +extern oss_drv_module_info gModule_oss_audigyls; +//extern oss_drv_module_info gModule_oss_audiocs; +extern oss_drv_module_info gModule_oss_audioloop; +extern oss_drv_module_info gModule_oss_audiopci; +extern oss_drv_module_info gModule_oss_cmi878x; +extern oss_drv_module_info gModule_oss_cmpci; +extern oss_drv_module_info gModule_oss_cs4281; +extern oss_drv_module_info gModule_oss_cs461x; +extern oss_drv_module_info gModule_oss_digi96; +extern oss_drv_module_info gModule_oss_emu10k1x; +extern oss_drv_module_info gModule_oss_envy24; +extern oss_drv_module_info gModule_oss_envy24ht; +extern oss_drv_module_info gModule_oss_fmedia; +extern oss_drv_module_info gModule_oss_geode; +extern oss_drv_module_info gModule_oss_hdaudio; +extern oss_drv_module_info gModule_oss_ich; +//extern oss_drv_module_info gModule_oss_imux; +//extern oss_drv_module_info gModule_oss_midiloop; +//extern oss_drv_module_info gModule_oss_midimix; +//extern oss_drv_module_info gModule_oss_sadasupport; +extern oss_drv_module_info gModule_oss_sblive; +extern oss_drv_module_info gModule_oss_sbpci; +extern oss_drv_module_info gModule_oss_sbxfi; +extern oss_drv_module_info gModule_oss_solo; +extern oss_drv_module_info gModule_oss_trident; +//extern oss_drv_module_info gModule_oss_usb; +//extern oss_drv_module_info gModule_oss_userdev; +extern oss_drv_module_info gModule_oss_via823x; +extern oss_drv_module_info gModule_oss_via97; +extern oss_drv_module_info gModule_oss_ymf7xx; +//extern oss_drv_module_info gModule_osscore; + +module_info *modules[] = { + (module_info *)&gOSSCoreModule, +//for f in kernel/drv/*; do echo " (module_info *)&gModule_$(basename $f),"; done >> kernel/OS/BeOS/os_beos.c (module_info *)&gModule_oss_ali5455, + (module_info *)&gModule_oss_atiaudio, + (module_info *)&gModule_oss_audigyls, + //(module_info *)&gModule_oss_audiocs, + //(module_info *)&gModule_oss_audioloop, + (module_info *)&gModule_oss_audiopci, + (module_info *)&gModule_oss_cmi878x, + (module_info *)&gModule_oss_cmpci, + (module_info *)&gModule_oss_cs4281, + (module_info *)&gModule_oss_cs461x, + (module_info *)&gModule_oss_digi96, + (module_info *)&gModule_oss_emu10k1x, + (module_info *)&gModule_oss_envy24, + (module_info *)&gModule_oss_envy24ht, + (module_info *)&gModule_oss_fmedia, + (module_info *)&gModule_oss_geode, + (module_info *)&gModule_oss_hdaudio, + (module_info *)&gModule_oss_ich, + //(module_info *)&gModule_oss_imux, + //(module_info *)&gModule_oss_midiloop, + //(module_info *)&gModule_oss_midimix, + //(module_info *)&gModule_oss_sadasupport, + (module_info *)&gModule_oss_sblive, + (module_info *)&gModule_oss_sbpci, + (module_info *)&gModule_oss_sbxfi, + (module_info *)&gModule_oss_solo, + (module_info *)&gModule_oss_trident, + //(module_info *)&gModule_oss_usb, + //(module_info *)&gModule_oss_userdev, + (module_info *)&gModule_oss_via823x, + (module_info *)&gModule_oss_via97, + (module_info *)&gModule_oss_ymf7xx, +// (module_info *)&gModule_osscore, + +#if 0 /* OLD */ + + + (module_info *)&gModule_oss_ali5455, + + (module_info *)&gModule_oss_allegro, + (module_info *)&gModule_oss_als300, + (module_info *)&gModule_oss_als4000, + (module_info *)&gModule_oss_apci97, + + (module_info *)&gModule_oss_atiaudio, + + (module_info *)&gModule_oss_audigyls, + //(module_info *)&gModule_oss_audioloop, + (module_info *)&gModule_oss_audiopci, + (module_info *)&gModule_oss_cmi8788, + (module_info *)&gModule_oss_cmpci, + (module_info *)&gModule_oss_cs4280, + (module_info *)&gModule_oss_cs4281, + (module_info *)&gModule_oss_digi32, + (module_info *)&gModule_oss_digi96, + (module_info *)&gModule_oss_emu10k1x, + (module_info *)&gModule_oss_envy24, + (module_info *)&gModule_oss_envy24ht, + (module_info *)&gModule_oss_fm801, + (module_info *)&gModule_oss_geode, + (module_info *)&gModule_oss_hdaudio, + + (module_info *)&gModule_oss_ich, + +#ifdef ENABLE_IMUX + (module_info *)&gModule_oss_imux, +#endif + (module_info *)&gModule_oss_maestro, + (module_info *)&gModule_oss_neomagic, + (module_info *)&gModule_oss_s3vibes, + (module_info *)&gModule_oss_sblive, +#ifdef ENABLE_SOFTOSS + //(module_info *)&gModule_oss_softoss, +#endif + (module_info *)&gModule_oss_solo, + (module_info *)&gModule_oss_trident, + (module_info *)&gModule_oss_via8233, + (module_info *)&gModule_oss_via97, + (module_info *)&gModule_oss_vortex, + (module_info *)&gModule_oss_ymf7xx, +#endif + + NULL +}; + +/* + * Driver hooks + */ + + +typedef struct ossdev_cookie { + int minor; /* index into cdevs[] */ + oss_cdev_t *cdev; + struct fileinfo file; +} ossdev_cookie_t; + +static int find_cdev(const char *name) +{ + int i, which = -1; + CORE_LOCK_VAR; +// if (strlen(name) < strlen(DEVICE_PREFIX)) +// return -1; + name += strlen(DEVICE_PREFIX); + + LOCK_CORE(); + for (i = 0; i < oss_num_cdevs; i++) + { + oss_cdev_t *cdev = oss_cdevs[i]; + //dprintf("oss:find_cdev: cdev %p, ->d %p, %s <> %s\n", cdev, cdev?cdev->d:NULL, cdev?cdev->name:"-", name); + if (cdev && cdev->d && !strncmp(cdev->name, name, 32)) + { + which = i; + break; + } + } + UNLOCK_CORE(); + + return which; +} + +static status_t +ossdrv_open(const char *name, uint32 oflags, void **cookie) +{ + ossdev_cookie_t *c; + status_t err; + int dev, tmpdev; + oss_cdev_t *cdev; + CORE_LOCK_VAR; + FENTRYA("%s, %ld, ", name, oflags); + + dev = find_cdev(name); + err = ENOENT; + if (dev < 0) + goto err1; + err = ENXIO; + if ((cdev = oss_cdevs[dev]) == NULL || cdev->d == NULL) + goto err1; + + DDB (cmn_err + (CE_CONT, "oss_cdev_open(%d): %s, class=%d, instance=%d\n", dev, + cdev->name, cdev->dev_class, cdev->instance)); + + err = ENODEV; + if (cdev->d->open == NULL) + goto err1; + + err = ENOMEM; + c = malloc(sizeof(ossdev_cookie_t)); + if (!c) + goto err1; + + switch (oflags & O_RWMASK) + { + case O_RDONLY: + c->file.mode = OPEN_READ; + break; + case O_WRONLY: + c->file.mode = OPEN_WRITE; + break; + case O_RDWR: + c->file.mode = OPEN_READWRITE; + break; + default: + err = EINVAL; + goto err2; + } + //c->file.flags = oflags; + c->file.acc_flags = oflags; + + tmpdev = -1; + err = + cdev->d->open (cdev->instance, cdev->dev_class, &c->file, 0, 0, &tmpdev); + if (err < 0) + goto err3; + if (tmpdev > -1) + dev = tmpdev; + + c->minor = dev; + c->cdev = cdev = oss_cdevs[dev]; + + //XXX:locking + LOCK_CORE(); + oss_open_devices++; + //open_count[dev]++; + UNLOCK_CORE(); + + *cookie = c; + FEXITR(B_OK); + return B_OK; + +err3: +err2: + free(c); +err1: + FEXITR(err); + return err; +} + + +static status_t +ossdrv_close(void *cookie) +{ + FENTRY(); + FEXIT(); + return B_OK; +} + + +static status_t +ossdrv_freecookie(ossdev_cookie_t *cookie) +{ + oss_cdev_t *cdev = cookie->cdev; + int dev = cookie->minor; + CORE_LOCK_VAR; + status_t err; + FENTRY(); + + err = ENXIO; + if (dev >= OSS_MAX_CDEVS) + goto err; + +#if 0 // not safe (not locked) + err = B_OK; + if (open_count[dev] == 0) /* Not opened */ + goto err; +#endif + + err = ENXIO; + if (cdev != oss_cdevs[dev]) + goto err; + + //in close or free ?? + cdev->d->close (cdev->instance, &cookie->file); + + LOCK_CORE(); + oss_open_devices--; + //open_count[dev]--; + UNLOCK_CORE(); + + free(cookie); + err = B_OK; +err: + FEXITR(err); + return B_OK; +} + +/* note: IOC stuff seems to not collide with the base ioctls from Drivers.h + * as long as the type field is printable ascii (>32). Lucky are we. + */ +static status_t +ossdrv_ioctl(ossdev_cookie_t *cookie, uint32 op, void *buffer, size_t length) +{ + oss_cdev_t *cdev = cookie->cdev; + status_t err = ENXIO; + uint32 cmd = op; + int len = 0; + char buf[4096]; + FENTRYA(", %lx, , %ld", op, length); + + if ((cdev != oss_cdevs[cookie->minor]) || cdev->d->ioctl == NULL) + goto err1; + + if (cmd & (SIOC_OUT | SIOC_IN)) + { + + len = (cmd >> 16) & SIOCPARM_MASK; + if (len < 0) + len = 0; + if (len > sizeof (buf)) + { + cmn_err (CE_WARN, "Bad ioctl buffer size %d\n", len); + err = EFAULT; + goto err1; + } + + if ((cmd & SIOC_IN) && len > 0) + { + memcpy (buf, buffer, len); + //return EFAULT; + } + + } + + err = cdev->d->ioctl (cdev->instance, &cookie->file, cmd, (ioctl_arg) buf); + + if ((cmd & SIOC_OUT) && len > 0) + { + memcpy (buffer, buf, len); + //return EFAULT; + } + + +err1: + FEXITR(err); + return err; +} + + +static status_t +ossdrv_read(ossdev_cookie_t *cookie, off_t pos, void *buffer, size_t *_length) +{ + oss_cdev_t *cdev = cookie->cdev; + uio_t uio; + int count = *_length; + int err; + FENTRYA(", %Ld, , %ld", pos, *_length); + + err = ENXIO; + if ((cdev != oss_cdevs[cookie->minor]) || cdev->d->read == NULL) + goto err; + //files[dev].acc_flags = uiop->uio_fmode; + if ((err = oss_create_uio (&uio, buffer, count, UIO_READ, 0)) < 0) + goto err; + + err = cdev->d->read (cdev->instance, &cookie->file, &uio, count); + //*_length = (err > 0) ? err : 0; + if (err < 0) + goto err; + + *_length = err; + err = B_OK; + FEXITR(err); + return err; + +err: + *_length = 0; + FEXITR(err); + return err; +} + + +static status_t +ossdrv_write(ossdev_cookie_t *cookie, off_t pos, const void *buffer, size_t *_length) +{ + oss_cdev_t *cdev = cookie->cdev; + uio_t uio; + int count = *_length; + int err; + FENTRYA(", %Ld, , %ld", pos, *_length); + + err = ENXIO; + if ((cdev != oss_cdevs[cookie->minor]) || cdev->d->write == NULL) + goto err; + //files[dev].acc_flags = uiop->uio_fmode; + if ((err = oss_create_uio (&uio, (void *)buffer, count, UIO_WRITE, 0)) < 0) + goto err; + + err = cdev->d->write (cdev->instance, &cookie->file, &uio, count); + //*_length = (err > 0) ? err : 0; + if (err < 0) + goto err; + + *_length = err; + err = B_OK; + FEXITR(err); + return err; + +err: + *_length = 0; + FEXITR(err); + return err; +} + + +device_hooks oss_driver_hooks = { + &ossdrv_open, + &ossdrv_close, + (device_free_hook)&ossdrv_freecookie, + (device_control_hook)&ossdrv_ioctl, + (device_read_hook)&ossdrv_read, + (device_write_hook)&ossdrv_write, + /* Leave select/deselect/readv/writev undefined. The kernel will + * use its own default implementation. The basic hooks above this + * line MUST be defined, however. */ + NULL, + NULL, + NULL, + NULL +}; diff --git a/kernel/OS/BeOS/os_beos.h b/kernel/OS/BeOS/os_beos.h new file mode 100644 index 0000000..1e8f0b5 --- /dev/null +++ b/kernel/OS/BeOS/os_beos.h @@ -0,0 +1,471 @@ +#ifndef _OS_H_ +#define _OS_H_ + +/* + * Purpose: OS specific definitions for BeOS/Haiku + * + */ +/* + * + * This file is part of Open Sound System. + * + * Copyright (C) 4Front Technologies 1996-2007. + * + * 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. Please contact sales@opensound.com for further info. + * + */ +#define OS_VERSION "5" +#define __inline__ inline +#define __inline inline +#define EXTERN_C extern "C" + +/* + * Debugging and misc settings + */ +#undef DO_TIMINGS +#undef MUTEX_CHECKS +#undef MEMDEBUG +/* very verbose */ +//#define DO_DEBUG_FUNC_CALLS +/* XXX */ +#define DEBUG_KDLCMD 1 +//#define ENABLE_IMUX 1 +//#define ENABLE_SOFTOSS 1 + +/* + * Disable support for per-application features such as /dev/dsp device + * selection based on command name. Requires working GET_PROCESS_NAME + * macro implementation. + */ +//Disable?? +//#define APPLIST_SUPPORT +#define USE_DEVICE_SUBDIRS +/* no VDEV */ +#undef VDEV_SUPPORT + +//XXX: try to avoid crashing +#define MIDI_DISABLED 1 + +#include <OS.h> +#include <stdarg.h> +//#include <stdint.h> +#include <inttypes.h> +#include <sys/types.h> +#include <sys/param.h> +#include <oss_errno.h> +#include <sys/uio.h> +#include <fcntl.h> +#ifdef __HAIKU__ +#include <poll.h> +#endif +//#include <sys/malloc.h> +#include <malloc.h> + + +#include <KernelExport.h> +#include <Drivers.h> +#include <PCI.h> + +#ifndef ENOTSUP +#define ENOTSUP ENOSYS +#endif + +#define OSS_CONTIG_AREA_NAME "OSS CONTIG MEM" +#define OSS_PCI_AREA_NAME "OSS PCI MEM" +#define OSS_WQ_SEM_NAME "OSS WAITQ: " + +//#define DEVICE_PREFIX "audio/oss/" +#define DEVICE_PREFIX "" +#define DEVICE_NAME_LEN (32+sizeof(DEVICE_PREFIX)) + +#define OSS_CONFIG_FILE_PREFIX "oss_" + +#ifdef _KERNEL_MODE + +/* references to modules */ +extern pci_module_info *gPCI; + +#endif /* _KERNEL_MODE */ + +/* + * Some integer types + */ +#if defined(amd64) || defined(sparc) // 64bit ? not yet +typedef uint64 oss_native_word; /* Same as the address and status register size */ +#else +typedef uint32 oss_native_word; /* Same as the address and status register size */ +#endif + +typedef int64 oss_int64_t; /* Signed 64 bit integer */ +typedef uint64 oss_uint64_t; /* Unsigned 64 bit integer */ +typedef unsigned long offset_t; + + +extern void oss_cmn_err (int level, char *format, ...); +#define CE_CONT 0 +#define CE_NOTE 1 +#define CE_WARN 2 +#define CE_PANIC 3 +#define cmn_err oss_cmn_err + +//snooze(1000000); \ + +#ifdef DO_DEBUG_FUNC_CALLS +/* verbose debugging */ +#define FENTRY() \ +dprintf("oss>%s()\n", __FUNCTION__) +#define FENTRYA(f,a...) \ +dprintf("oss>%s(" f ")\n", __FUNCTION__, a) +#define FEXIT() \ +dprintf("oss<%s\n", __FUNCTION__) +#define FEXITR(e) \ +dprintf("oss<%s returned 0x%08lx\n", __FUNCTION__, (uint32)e) +#else +#define FENTRY() {} +#define FENTRYA(f,a...) {} +#define FEXIT() {} +#define FEXITR(e) {} +#endif + +struct _dev_info_t +{ + //struct pci_dev *pcidev; + struct pci_info pciinfo; //XXX: ptr or not ??? +}; +typedef struct _dev_info_t dev_info_t; + + +/* + * timeout wrappers + */ +#undef timeout +#define timeout oss_timeout +#undef untimeout +#define untimeout oss_untimeout +typedef int timeout_id_t; +extern timeout_id_t oss_timeout (void (*func) (void *), void *arg, + unsigned long long ticks); +extern void oss_untimeout (timeout_id_t id); + +#define uiomove oss_uiomove +typedef enum uio_rw +{ UIO_READ, UIO_WRITE } uio_rw_t; +struct uio +{ + char *ptr; + int resid; + int kernel_space; /* Set if this uio points to a kernel space buffer */ + uio_rw_t rw; +}; +typedef struct uio uio_t; +extern int oss_uiomove (void *address, size_t nbytes, enum uio_rw rwflag, + uio_t * uio); +extern int oss_create_uio (uio_t * uiop, char *buf, size_t count, uio_rw_t rw, + int is_kernel); + + + +/* + * Mutexes + */ + +#ifdef MUTEX_CHECKS +/* Debugging version */ +struct _oss_mutex_t +{ + spinlock lock; + thread_id owner; + 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, 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, oss_native_word *flags); +extern void debug_mutex_exit (oss_mutex_t * mutex, char *file, int line, oss_native_word *flags); + +#define MUTEX_INIT(osdev, mutex, hier) debug_mutex_init(&mutex, NULL, __FILE__, __LINE__) +#define MUTEX_CLEANUP(mutex) debug_mutex_destroy(&mutex, __FILE__, __LINE__) +#define MUTEX_ENTER_IRQDISABLE(mutex, flags) debug_mutex_enter(&mutex, __FILE__, __LINE__, &flags) +#define MUTEX_ENTER(mutex, flags) debug_mutex_enter(&mutex, __FILE__, __LINE__, NULL) +#define MUTEX_EXIT_IRQRESTORE(mutex, flags) debug_mutex_exit(&mutex, __FILE__, __LINE__, &flags) +#define MUTEX_EXIT(mutex, flags) debug_mutex_exit(&mutex, __FILE__, __LINE__, NULL) +#else +typedef spinlock oss_mutex_t; +#define MUTEX_INIT(osdev, mutex, hier) { mutex = 0; } +#define MUTEX_CLEANUP(mutex) +#define MUTEX_ENTER_IRQDISABLE(mutex, flags) \ +{ \ + flags = (oss_native_word) disable_interrupts(); \ + acquire_spinlock(&(mutex)); \ +} +#define MUTEX_ENTER(mutex, flags) acquire_spinlock(&(mutex)) +#define MUTEX_EXIT_IRQRESTORE(mutex, flags) \ +{ \ + release_spinlock(&(mutex)); \ + restore_interrupts((cpu_status)(flags)); \ +} +#define MUTEX_EXIT(mutex, flags) release_spinlock(&(mutex)) +#endif + +/* The soundcard.h could be in a nonstandard place so include it here. */ +#include "soundcard.h" + +typedef struct udi_usb_devc udi_usb_devc; +struct _oss_device_t +{ +#ifdef NEEDED_FOR_DRIVERS + int instance; + void *devc; + char *name; +#endif + + int cardnum; + int dev_type; + int instance; + int available; + dev_info_t *dip; + int unloaded; + void *osid; + void *devc; + char *name; + char *hw_info; + 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() */ + + volatile int refcount; /* Nonzero means that the device is needed by some other (virtual) driver. */ + +/* Interrupts */ + + long irq; //XXX:init =-1 + oss_tophalf_handler_t tophalf_handler; + oss_bottomhalf_handler_t bottomhalf_handler; + oss_mutex_t mutex; + +}; + +/* XXX we'll deal with select() later */ +#undef ALLOW_SELECT +/* BeOS doesn't support mmap. Haiku does, so FIXME someday */ +#undef ALLOW_BUFFER_MAPPING + +/* + * Sleep/wakeup + */ + +#ifdef _KERNEL +struct oss_wait_queue +{ +//XXX: +// oss_mutex_t mutex; + char name[32]; + sem_id sem; + unsigned long flags; +// struct selinfo poll_info; +}; +#endif + +/* Busy wait routine */ +#define oss_udelay(d) spin((bigtime_t)d) + + +/* usec time base */ +#undef HZ +/* XXX: might need to be lower to handle casts to long */ +#define OSS_HZ 1000000 + +/* System wall timer access */ +extern unsigned long oss_get_time (void); +#define GET_JIFFIES() oss_get_time() + + +/* + * INB() and OUTB() should be obvious. NOTE! The order of + * paratemeters of OUTB() is different than on some other + * operating systems. + */ + +/* I/O Mapped devices */ +#define INB(o, p) gPCI->read_io_8(p) +#define INW(o, p) gPCI->read_io_16(p) +#define INL(o, p) gPCI->read_io_32(p) + +#define OUTB(o, v, p) gPCI->write_io_8(p,v) +#define OUTW(o, v, p) gPCI->write_io_16(p,v) +#define OUTL(o, v, p) gPCI->write_io_32(p,v) + +/* Memory Mapped devices */ +#define PCI_READB(osdev, addr) *(volatile unsigned char *)(addr) +#define PCI_READW(osdev, addr) *(volatile unsigned short *)(addr) +#define PCI_READL(osdev, addr) *(volatile unsigned int *)(addr) + +#define PCI_WRITEB(osdev, addr, data) *(volatile unsigned char *)(addr)=data +#define PCI_WRITEW(osdev, addr, data) *(volatile unsigned short *)(addr)=data +#define PCI_WRITEL(osdev, addr, data) *(volatile unsigned int *)(addr)=data + +typedef void *oss_dma_handle_t; + +/* + * When a error (such as EINVAL) is returned by a function, + * the following macro is used. The driver assumes that a + * error is signalled by returning a negative value. + */ + +/* + 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). +*/ +#define KERNEL_MALLOC(nbytes) calloc(1,nbytes) +#define KERNEL_FREE(addr) {if (addr)free(addr);addr=NULL;} + +extern void *oss_contig_malloc (oss_device_t * osdev, int sz, + oss_uint64_t memlimit, + oss_native_word * phaddr); +extern void oss_contig_free (oss_device_t * osdev, void *p, int sz); +extern oss_native_word oss_virt_to_bus (void *addr); +#define CONTIG_MALLOC(osdev, sz, memlimit, phaddr, handle) oss_contig_malloc(osdev, sz, memlimit, phaddr) +#define CONTIG_FREE(osdev, p, sz, handle) oss_contig_free(osdev, p, sz) + +/* + * PMALLOC is used to allocate memory that will get automatically freed when + * OSS unloads. Usable for per-instance structures allocated when OSS modules + * are being loaded. + */ +extern void *oss_pmalloc (size_t sz); + +//#define PMALLOC(osdev, sz) oss_pmalloc(sz) + +/* + * Timer macros + * + * These macros are obsolete and should not be used in any new code. + * Use the timeout mechanism (see the timeout(9F) Solaris man page). + */ +#define 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) +#endif + +struct fileinfo +{ + int mode; /* Open mode */ + //int flags; + int acc_flags; +}; +#define ISSET_FILE_FLAG(fileinfo, flag) (fileinfo->acc_flags & (flag) ? 1:0) + +#define OSS_OS "BeOS" +#define OSS_OS_LONGNAME "BeOS R" OS_VERSION + +typedef void (*softintr_func_t) (int); + +struct oss_softintr +{ + int id; + softintr_func_t func; + volatile int armed, running; +}; + +struct _oss_poll_event_t +{ + short events, revents; + struct thread *p; + struct cdev *bsd_dev; +}; +typedef struct _oss_poll_event_t oss_poll_event_t; +#ifndef POLLIN +/* events & revents - compatible with the B_SELECT_xxx definitions in Drivers.h */ +#define POLLIN 0x0001 /* any readable data available */ +#define POLLOUT 0x0002 /* file descriptor is writeable */ +#define POLLRDNORM POLLIN +#define POLLWRNORM POLLOUT +#define POLLRDBAND 0x0008 /* priority readable data */ +#define POLLWRBAND 0x0010 /* priority data can be written */ +#define POLLPRI 0x0020 /* high priority readable data */ +#endif + +extern int detect_trace; +#define DDB(x) if (detect_trace) x + +extern caddr_t oss_map_pci_mem (oss_device_t * osdev, int nr, int phaddr, + int size); +extern void oss_unmap_pci_mem (void *addr); +#define MAP_PCI_IOADDR(osdev, nr, io) (oss_native_word)io +#define MAP_PCI_MEM(osdev, ix, phaddr, size) oss_map_pci_mem(osdev, ix, phaddr, size) +#define UNMAP_PCI_MEM(osdev, ix, ph, virt, size) oss_unmap_pci_mem(virt) +#define UNMAP_PCI_IOADDR(osdev, ix) {} + +#define GET_PROCESS_PID(f) find_thread(NULL) +#define GET_PROCESS_UID() getuid() +#define GET_PROCESS_NAME(f) NULL + +#define abs(x) ((x) >= 0 ? (x) : -(x)) + +/* + * Interface with the front-end driver + */ +extern status_t init_osscore (void); +extern status_t uninit_osscore (void); +extern status_t oss_probe_pci (void); +extern status_t oss_load_drivers (void); +extern status_t oss_unload_all_drivers (void); + +/* + * osscore module for use by low-level driver + */ +#define OSS_CORE_MODULE_NAME "media/oss/oss_core/v1" +#define OSS_MODULES_PREFIX "media/oss/drivers/" +#define OSS_MODULES_SUFFIX "/v1" +#define OSS_MAKE_DRV_MOD_NAME(nick) OSS_MODULES_PREFIX nick OSS_MODULES_SUFFIX +typedef struct oss_drv_module_info { + module_info minfo; + int (*driver_probe)(void); + int (*driver_attach)(oss_device_t *osdev); + int (*driver_detach)(oss_device_t *osdev); +} oss_drv_module_info; + +typedef struct oss_core_module_info { + module_info minfo; + status_t (*init_osscore) (void); + status_t (*uninit_osscore) (void); + const char **(*oss_publish_devices) (void); + device_hooks *(*oss_get_driver_hooks) (void); + status_t (*oss_probe_pci) (void); + status_t (*oss_load_drivers) (void); + status_t (*oss_unload_all_drivers) (void); +} oss_core_module_info; +extern oss_core_module_info *gOSSCore; + +//XXX: not yet +#ifdef ASMODULES + +struct oss_core_module { + module_info minfo; + void (*oss_foo)(void); +}; +extern struct oss_core_info *gOSSCore; +#ifdef BUILDING_DRIVER + #define oss_foo gOSSCore->oss_foo +#endif +#endif /* ASMODULES */ |