Google
 

Open Sound System
The Hitchhiker's Guide to OSS 4.1 Internals

Do you have problems with sound/audio application development? Don't panic! Click here for help!

BeOS/os_beos.c

Operating system abstraction functions for BeOS/Haiku

Description




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();


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,
};


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;
}


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);

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-&#62;minor]) || cdev-&#62;d-&#62;write == NULL) goto err; //files[dev].acc_flags = uiop-&#62;uio_fmode; if ((err = oss_create_uio (&#38;uio, (void *)buffer, count, UIO_WRITE, 0)) &#60; 0) goto err;

err = cdev-&#62;d-&#62;write (cdev-&#62;instance, &#38;cookie-&#62;file, &#38;uio, count); //*_length = (err &#62; 0) ? err : 0; if (err &#60; 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
};

Copyright (C) 4Front Technologies, 2007. All rights reserved.

Back to index OSS web site


Copyright (C) 4Front Technologies, 2007. All rights reserved.
Back to index OSS web site