diff options
Diffstat (limited to 'kernel/OS/FreeBSD')
-rw-r--r-- | kernel/OS/FreeBSD/.config | 1 | ||||
-rw-r--r-- | kernel/OS/FreeBSD/os_freebsd.c | 1107 | ||||
-rw-r--r-- | kernel/OS/FreeBSD/os_freebsd.h | 263 | ||||
-rw-r--r-- | kernel/OS/FreeBSD/wrapper/bsddefs.h | 150 |
4 files changed, 1521 insertions, 0 deletions
diff --git a/kernel/OS/FreeBSD/.config b/kernel/OS/FreeBSD/.config new file mode 100644 index 0000000..816ac62 --- /dev/null +++ b/kernel/OS/FreeBSD/.config @@ -0,0 +1 @@ +mode=kernel diff --git a/kernel/OS/FreeBSD/os_freebsd.c b/kernel/OS/FreeBSD/os_freebsd.c new file mode 100644 index 0000000..58b11cc --- /dev/null +++ b/kernel/OS/FreeBSD/os_freebsd.c @@ -0,0 +1,1107 @@ +/* + * Purpose: Operating system abstraction functions for FreeBSD + */ +/* + * + * This file is part of Open Sound System. + * + * Copyright (C) 4Front Technologies 1996-2008. + * + * This this source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + */ + +#include "oss_config.h" +#include "midi_core.h" +#include <oss_pci.h> +#include <sys/conf.h> +#include <sys/proc.h> +#include <sys/sx.h> +#include <sys/mman.h> +#include <sys/lockmgr.h> +#include <fs/devfs/devfs.h> +#include <sys/poll.h> +#include <sys/param.h> +#include <sys/filio.h> + +/* Function prototypes */ +static d_open_t oss_open; +static d_close_t oss_close; +static d_read_t oss_read; +static d_write_t oss_write; +static d_ioctl_t oss_ioctl; +static d_poll_t oss_poll; +static d_mmap_t oss_mmap; + +/* Character device entry points */ + +static struct cdevsw oss_cdevsw = { + .d_version = D_VERSION, + .d_flags = D_TRACKCLOSE, + .d_open = oss_open, + .d_close = oss_close, + .d_read = oss_read, + .d_write = oss_write, + .d_ioctl = oss_ioctl, + .d_poll = oss_poll, + .d_mmap = oss_mmap, + .d_name = "oss" +}; + +static int oss_major = 30; +oss_device_t *core_osdev = NULL; +static int open_devices = 0; +static int refcount = 0; + +#define MAX_CARDS 32 +int oss_num_cards = 0; +static oss_device_t *cards[MAX_CARDS]; +static int oss_expired = 0; + + +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; + + if (dmap == NULL) + { + cmn_err (CE_WARN, "oss_alloc_dmabuf: dmap==NULL\n"); + return OSS_EIO; + } + +/* + * 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_wait_queue_t * +oss_create_wait_queue (oss_device_t * osdev, const char *name) +{ + oss_wait_queue_t *wq; + + if ((wq = PMALLOC (NULL, sizeof (*wq))) == NULL) + return NULL; + + MUTEX_INIT (osdev, wq->mutex, MH_TOP); + + return wq; +} + +void +oss_reset_wait_queue (oss_wait_queue_t * wq) +{ + wq->flags = 0; +} + +void +oss_remove_wait_queue (oss_wait_queue_t * wq) +{ + MUTEX_CLEANUP (wq->mutex); +} + +int +oss_sleep (oss_wait_queue_t * wq, oss_mutex_t * mutex, int ticks, + oss_native_word * flags, unsigned int *status) +{ + int flag; + *status = 0; + + if (wq == NULL) + return 0; + + wq->flags = 0; +#ifdef USE_SX_LOCK + flag = sx_sleep (wq, *mutex, PRIBIO | PCATCH, "oss", ticks); +#else +#if __FreeBSD_version >= 602000 + flag = msleep_spin (wq, *mutex, "oss", ticks); +#else + flag = msleep (wq, *mutex, PRIBIO | PCATCH, "oss", ticks); +#endif +#endif + if (flag == EWOULDBLOCK) /* Timeout */ + { + return 0; + } + + if (flag != 0) + { + *status |= WK_SIGNAL; + } + + return 1; +} + +int +oss_register_poll (oss_wait_queue_t * wq, oss_mutex_t * mutex, + oss_native_word * flags, oss_poll_event_t * ev) +{ + MUTEX_EXIT_IRQRESTORE (*mutex, *flags); + selrecord (ev->p, &wq->poll_info); + MUTEX_ENTER_IRQDISABLE (*mutex, *flags); + return 0; +} + +void +oss_wakeup (oss_wait_queue_t * wq, oss_mutex_t * mutex, + oss_native_word * flags, short events) +{ + MUTEX_EXIT_IRQRESTORE (*mutex, *flags); + wakeup (wq); + selwakeup (&wq->poll_info); + MUTEX_ENTER_IRQDISABLE (*mutex, *flags); +} + +void +oss_register_module (char *name) +{ + refcount++; +} + +void +oss_unregister_module (char *name) +{ + refcount--; +} + +void +oss_reserve_device (oss_device_t * osdev) +{ + osdev->refcount++; +} + +void +oss_unreserve_device (oss_device_t * osdev, int decrement) +{ + osdev->refcount--; + if (osdev->refcount < 0) + osdev->refcount = 0; +} + +int +oss_register_device (oss_device_t * osdev, const char *name) +{ + if ((osdev->name = PMALLOC (NULL, strlen (name) + 1)) == NULL) + { + cmn_err (CE_WARN, "Cannot allocate memory for device name\n"); + osdev->name = "Unknown device"; + } + strcpy (osdev->name, name); + if (osdev->dip != NULL) + device_set_desc (osdev->dip, name); + return OSS_ENXIO; +} + +void +oss_unregister_device (oss_device_t * osdev) +{ + // NOP +} + +int +oss_find_minor (int dev_class, int instance) +{ + int i; + + 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) + return i; + + return OSS_EIO; +} + +void * +oss_find_minor_info (int dev_class, int instance) +{ + int i; + + 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) + return oss_cdevs[i]->info; + } + + return NULL; +} + +int +oss_disable_device (oss_device_t * osdev) +{ + int i; + + if (osdev->refcount > 0) + return OSS_EBUSY; + + if (open_devices > 0) + return OSS_EBUSY; + + for (i = 0; i < num_mixers; i++) + if (mixer_devs[i]->osdev == osdev) + { + mixer_devs[i]->unloaded = 1; + } + + for (i = 0; i < num_mididevs; i++) + { + if (midi_devs[i]->osdev == osdev) + { + midi_devs[i]->unloaded = 1; + } + } + + for (i = 0; i < num_audio_engines; i++) + if (audio_engines[i]->osdev == osdev) + { + audio_uninit_device (i); + } + return 0; +} + +int +oss_get_cardinfo (int cardnum, oss_card_info * ci) +{ +/* + * Print information about a 'card' in a format suitable for /dev/sndstat + */ + + if (cardnum < 0 || cardnum >= oss_num_cards) + return OSS_ENXIO; + + if (cards[cardnum]->name != NULL) + strncpy (ci->longname, cards[cardnum]->name, 128); + ci->shortname[127] = 0; + + if (cards[cardnum]->nick != NULL) + strncpy (ci->shortname, cards[cardnum]->nick, 16); + ci->shortname[15] = 0; + + if (cards[cardnum]->hw_info != NULL) + strncpy (ci->hw_info, cards[cardnum]->hw_info, sizeof (ci->hw_info)); + ci->hw_info[sizeof (ci->hw_info) - 1] = 0; + ci->intr_count = cards[cardnum]->intrcount; + ci->ack_count = cards[cardnum]->ackcount; + + return 0; +} + +static int +grow_array(oss_device_t *osdev, oss_cdev_t ***arr, int *size, int element_size, int increment) +{ + oss_cdev_t **old=*arr, **new = *arr; + int old_size = *size; + int new_size = *size; + + new_size += increment; + + if ((new=PMALLOC(osdev, new_size * element_size))==NULL) + return 0; + + memset(new, 0, new_size * element_size); + if (old != NULL) + memcpy(new, old, old_size * element_size); + + *size = new_size; + *arr = new; + + if (old != NULL) + PMFREE(osdev, old); + + return 1; +} + +void +oss_install_chrdev (oss_device_t * osdev, char *name, int dev_class, + int instance, oss_cdev_drv_t * drv, int flags) +{ + struct cdev *bsd_cdev; + oss_cdev_t *cdev = NULL; + int i, num; + + if (dev_class != OSS_DEV_STATUS) + if (oss_expired && instance > 0) + return; +/* + * Find if this dev_class&instance already exists (after previous module + * detach). + */ + + for (num = 0; num < oss_num_cdevs; num++) + if (oss_cdevs[num]->d == NULL) /* Unloaded driver */ + if (oss_cdevs[num]->dev_class == dev_class + && oss_cdevs[num]->instance == instance) + { + cdev = oss_cdevs[num]; + break; + } + + if (cdev == NULL) + { + if (oss_num_cdevs >= OSS_MAX_CDEVS) + { + if (!grow_array(osdev, &oss_cdevs, &oss_max_cdevs, sizeof(oss_cdev_t*), 100)) + { + cmn_err (CE_WARN, "Cannot allocate new minor numbers.\n"); + return; + } + } + + if ((cdev = PMALLOC (NULL, sizeof (*cdev))) == NULL) + { + cmn_err (CE_WARN, "Cannot allocate character device desc.\n"); + return; + } + num = oss_num_cdevs++; + } + + memset (cdev, 0, sizeof (*cdev)); + cdev->dev_class = dev_class; + cdev->instance = instance; + cdev->d = drv; + cdev->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; + + if (!(flags & CHDEV_VIRTUAL) && (name != NULL)) + { + bsd_cdev = + make_dev (&oss_cdevsw, num, UID_ROOT, GID_WHEEL, 0666, name, 0); + cdev->info = bsd_cdev; + } +} + +#define MAX_MEMBLOCKS 4096 +static void *memblocks[MAX_MEMBLOCKS]; +static int nmemblocks = 0; + +void * +oss_pmalloc (size_t sz) +{ + void *tmp; + + tmp = KERNEL_MALLOC (sz); + + if (nmemblocks < MAX_MEMBLOCKS) + memblocks[nmemblocks++] = tmp; + + return tmp; +} + +int +oss_uiomove (void *address, size_t nbytes, enum uio_rw rwflag, uio_t * uio_p) +{ + int err; + +#undef uiomove + err = uiomove (address, nbytes, uio_p); + + return err; +} + +#undef timeout +#undef untimeout + +typedef struct tmout_desc +{ + volatile int active; + int timestamp; + void (*func) (void *); + void *arg; + + struct callout_handle timer; +} tmout_desc_t; + +static volatile int next_id = 0; +#define MAX_TMOUTS 128 + +tmout_desc_t tmouts[MAX_TMOUTS] = { {0} }; + +int timeout_random = 0x12123400; + +void +oss_timer_callback (void *arg) +{ + int ix; + tmout_desc_t *tmout = arg; + + timeout_random++; + + if (!tmout->active) + return; + + arg = tmout->arg; + tmout->active = 0; + tmout->timestamp = 0; + + tmout->func (arg); +} + +timeout_id_t +oss_timeout (void (*func) (void *), void *arg, unsigned long long ticks) +{ + tmout_desc_t *tmout = NULL; + int id, n; + + timeout_random++; + + n = 0; + id = -1; + + while (id == -1 && n < MAX_TMOUTS) + { + if (!tmouts[next_id].active) + { + tmouts[next_id].active = 1; + id = next_id++; + tmout = &tmouts[id]; + break; + } + + next_id = (next_id + 1) % MAX_TMOUTS; + } + + if (id == -1) /* No timer slots available */ + { + cmn_err (CE_CONT, "Timeout table full\n"); + return 0; + } + + tmout->func = func; + tmout->arg = arg; + tmout->timestamp = id | (timeout_random & ~0xff); + + tmout->timer = timeout (oss_timer_callback, tmout, ticks); + + 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) + untimeout (oss_timer_callback, tmout, tmout->timer); + tmout->active = 0; + tmout->timestamp = 0; +} + +int +oss_get_procinfo (int what) +{ + switch (what) + { + case OSS_GET_PROCINFO_UID: + return oss_get_uid(); + } + + return EINVAL; +} + +unsigned long +oss_get_time (void) +{ + struct timeval timecopy; + + getmicrotime (&timecopy); + return timecopy.tv_usec / (1000000 / hz) + (u_long) timecopy.tv_sec * hz; +} + +caddr_t +oss_map_pci_mem (oss_device_t * osdev, int nr, int paddr, int psize) +{ + void *vaddr = 0; + u_int32_t poffs; + + poffs = paddr - trunc_page (paddr); + vaddr = (caddr_t) pmap_mapdev (paddr - poffs, psize + poffs) + poffs; + + return vaddr; +} + +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? */ +} + +static time_t +oss_get_walltime (void) +{ + struct timeval timecopy; + + getmicrotime (&timecopy); + return timecopy.tv_sec; +} + +int +soundcard_attach (void) +{ + oss_device_t *osdev; + + if ((osdev = PMALLOC (NULL, sizeof (*osdev))) == NULL) + { + return ENOSPC; + } + + memset (osdev, 0, sizeof (*osdev)); + core_osdev = osdev; + +#ifdef LICENSED_VERSION + if (!oss_license_handle_time (oss_get_walltime ())) + { + cmn_err (CE_WARN, "This version of Open Sound System has expired\n"); + cmn_err (CE_CONT, + "Please download the latest version from www.opensound.com\n"); + oss_expired = 1; + } +#endif + + osdev->major = oss_major; + oss_register_device (osdev, "OSS core services"); + + oss_common_init (osdev); + + return 0; +} + +int +soundcard_detach (void) +{ + int i; + + if (refcount > 0 || open_devices > 0) + return EBUSY; + + oss_unload_drivers (); + + osdev_delete (core_osdev); + + for (i = 0; i < nmemblocks; i++) + KERNEL_FREE (memblocks[i]); + nmemblocks = 0; + + return 0; +} + +static void +init_fileinfo (struct fileinfo *fi, int flags) +{ + memset (fi, 0, sizeof (*fi)); + if ((flags & FREAD) && (flags & FWRITE)) + fi->mode = OPEN_READWRITE; + else if (flags & FREAD) + fi->mode = OPEN_READ; + else if (flags & FWRITE) + fi->mode = OPEN_WRITE; + fi->acc_flags = flags; + fi->pid = -1; + fi->dev = -1; + fi->cmd = NULL; +} + +static int +oss_read (struct cdev *bsd_dev, struct uio *buf, int flags) +{ + int retval; + int dev; + oss_cdev_t *cdev; +#ifndef VDEV_SUPPORT + struct fileinfo _fi, * fi = &_fi; + dev = MINOR (bsd_dev); + init_fileinfo (fi, flags); +#else + struct fileinfo * fi; + if (oss_file_get_private ((void **)&fi)) return ENXIO; + dev = fi->dev; +#endif + + if (dev >= oss_num_cdevs) + return ENXIO; + + if ((cdev = oss_cdevs[dev]) == NULL || cdev->d == NULL) + return ENXIO; + + if (cdev->d->read == NULL) + { + return ENODEV; + } + + retval = cdev->d->read (cdev->instance, fi, buf, buf->uio_resid); + if (retval < 0) + return -retval; + return 0; + +} + +static int +oss_write (struct cdev *bsd_dev, struct uio *buf, int flags) +{ + int retval; + int dev; + oss_cdev_t *cdev; +#ifndef VDEV_SUPPORT + struct fileinfo _fi, * fi = &_fi; + dev = MINOR (bsd_dev); + init_fileinfo (fi, flags); +#else + struct fileinfo * fi; + if (oss_file_get_private ((void **)&fi)) return ENXIO; + dev = fi->dev; +#endif + + if (dev >= oss_num_cdevs) + return ENXIO; + + if ((cdev = oss_cdevs[dev]) == NULL || cdev->d == NULL) + return ENXIO; + + if (cdev->d->write == NULL) + { + return ENODEV; + } + + retval = cdev->d->write (cdev->instance, fi, buf, buf->uio_resid); + if (retval < 0) + return -retval; + return 0; +} + +static int +oss_open (struct cdev *bsd_dev, int flags, int mode, struct thread *p) +{ + int dev = MINOR (bsd_dev); + oss_cdev_t *cdev; + struct fileinfo fi; + int tmpdev, retval; + + if (dev >= oss_num_cdevs) + return ENXIO; + + if ((cdev = oss_cdevs[dev]) == NULL || cdev->d == NULL) + return ENXIO; + + if (cdev->d->open == NULL) + { + return ENODEV; + } + + init_fileinfo (&fi, flags); + fi.pid = p->td_proc->p_pid; + fi.cmd = p->td_proc->p_comm; + tmpdev = dev; + + retval = + cdev->d->open (cdev->instance, cdev->dev_class, &fi, 0, 0, &tmpdev); + + if (tmpdev != -1) fi.dev = tmpdev; + else fi.dev = dev; + if (retval < 0) + return -retval; + +#ifdef VDEV_SUPPORT + if (oss_file_set_private (p, (void *)&fi, sizeof (struct fileinfo))) + return ENXIO; +#endif + + open_devices++; + return 0; +} + +static int +oss_close (struct cdev *bsd_dev, int flags, int mode, struct thread *p) +{ + int dev; + oss_cdev_t *cdev; +#ifndef VDEV_SUPPORT + struct fileinfo _fi, * fi = &_fi; + dev = MINOR (bsd_dev); + init_fileinfo (fi, flags); +#else + struct fileinfo * fi; + if (oss_file_get_private ((void **)&fi)) return ENXIO; + dev = fi->dev; +#endif + + if (dev >= oss_num_cdevs) + return ENXIO; + + if ((cdev = oss_cdevs[dev]) == NULL || cdev->d == NULL) + return ENXIO; + + if (cdev->d->close == NULL) + { + return ENODEV; + } + + cdev->d->close (cdev->instance, fi); + open_devices--; + return 0; +} + +static int +oss_ioctl (struct cdev *bsd_dev, u_long cmd, caddr_t arg, int mode, + struct thread *p) +{ + int retval; + int dev; + oss_cdev_t *cdev; +#ifndef VDEV_SUPPORT + struct fileinfo _fi, * fi = &_fi; + dev = MINOR (bsd_dev); + init_fileinfo (fi, mode); +#else + struct fileinfo * fi; + if (oss_file_get_private ((void **)&fi)) return ENXIO; + dev = fi->dev; +#endif + + if (dev >= oss_num_cdevs) + return ENXIO; + + if ((cdev = oss_cdevs[dev]) == NULL || cdev->d == NULL) + return ENXIO; + + if (cdev->d->ioctl == NULL) + { + return ENODEV; + } + + switch (cmd) + { + /* + * FreeBSD uses these ioctls to (un)set nonblocking I/O for devices. e.g. + * in case of fcntl (fd, F_SETFL, O_RDONLY|O_NONBLOCK) it will fire + * both ioctls. + * We deal with them here, and not in oss_audio_core because struct file + * isn't available in oss_audio_ioctl and we want the flags to remain + * accurate. oss_audio_core checks for O_NONBLOCK, and will pick + * up the change next read/write. + */ + case FIONBIO: + if (arg != NULL) + { + if (*arg) fi->acc_flags |= O_NONBLOCK; + else fi->acc_flags &= ~O_NONBLOCK; + } + case FIOASYNC: + return 0; + default: break; + } + + retval = cdev->d->ioctl (cdev->instance, fi, cmd, (ioctl_arg) arg); + if (retval < 0) + return -retval; + return 0; +} + +static int +oss_poll (struct cdev *bsd_dev, int events, struct thread *p) +{ + int retval; + int dev; + oss_cdev_t *cdev; + oss_poll_event_t ev; + int err; +#ifndef VDEV_SUPPORT + struct fileinfo _fi, * fi = &_fi; + dev = MINOR (bsd_dev); + init_fileinfo (fi, 0); +#else + struct fileinfo * fi; + if (oss_file_get_private ((void **)&fi)) return ENXIO; + dev = fi->dev; +#endif + + if (dev >= oss_num_cdevs) + return ENXIO; + + if ((cdev = oss_cdevs[dev]) == NULL || cdev->d == NULL) + return ENXIO; + + if (cdev->d->chpoll == NULL) + { + return ENODEV; + } + + ev.events = events; + ev.revents = 0; + ev.p = p; + ev.bsd_dev = bsd_dev; + + err = cdev->d->chpoll (cdev->instance, fi, &ev); + if (err < 0) + { + return -err; + } + return ev.revents; +} + +#if defined(D_VERSION_03) && (D_VERSION == D_VERSION_03) +static int +oss_mmap (struct cdev *bsd_dev, vm_ooffset_t offset, vm_paddr_t * paddr, + int nprot, vm_memattr_t *memattr) +#else +static int +oss_mmap (struct cdev *bsd_dev, vm_offset_t offset, vm_paddr_t * paddr, + int nprot) +#endif +{ + int retval; + int dev; + oss_cdev_t *cdev; + oss_poll_event_t ev; + dmap_p dmap = NULL; + int err; +#ifndef VDEV_SUPPORT + dev = MINOR (bsd_dev); +#else + struct fileinfo * fi; + if (oss_file_get_private ((void **)&fi)) return ENXIO; + dev = fi->dev; +#endif + + if (dev >= oss_num_cdevs) + return ENXIO; + + if ((cdev = oss_cdevs[dev]) == NULL || cdev->d == NULL) + return ENXIO; + + if (nprot & PROT_EXEC) + return EACCES; + + if ((cdev->dev_class != OSS_DEV_DSP) && + (cdev->dev_class != OSS_DEV_DSP_ENGINE)) /* Only mmapable devices */ + { + cmn_err (CE_NOTE, "mmap() is only possible with DSP devices (%d)\n", + cdev->dev_class); + return EINVAL; + } + + dev = cdev->instance; + + if (dev < 0 || dev >= num_audio_engines) + return ENODEV; + + if (nprot & PROT_WRITE) + dmap = audio_engines[dev]->dmap_out; + else + dmap = audio_engines[dev]->dmap_in; + + if (dmap == NULL) + return EIO; + + if (dmap->dmabuf_phys == 0) + return EIO; + + if (dmap->flags & DMAP_COOKED) + { + cmn_err (CE_WARN, + "mmap() not possible with currently selected sample format.\n"); + return EIO; + } + + dmap->mapping_flags |= DMA_MAP_MAPPED; + *paddr = dmap->dmabuf_phys + offset; + + return 0; +} + +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; + + if (handle == NULL) + handle = nick; + + /* + * Don't accept any more drivers if expired + */ + if (oss_expired && oss_num_cards > 0) + return NULL; + + for (i = 0; i < oss_num_cards; i++) + { + if (cards[i]->dip == dip) + { + osdev = cards[i]; + break; + } + } + + if (osdev == NULL) + { + if (oss_num_cards >= MAX_CARDS) + { + cmn_err (CE_WARN, "Too many OSS devices. At most %d permitted.\n", + MAX_CARDS); + return NULL; + } + + if ((osdev = PMALLOC (NULL, sizeof (*osdev))) == NULL) + { + cmn_err (CE_WARN, "osdev_create: Out of memory\n"); + return NULL; + } + + osdev->cardnum = oss_num_cards; + cards[oss_num_cards++] = osdev; + } + + osdev->dip = dip; + osdev->osid = dip; + osdev->available = 1; + osdev->instance = instance; + osdev->dev_type = dev_type; + osdev->devc = NULL; + osdev->first_mixer = -1; + sprintf (osdev->nick, "%s%d", nick, instance); + strcpy (osdev->modname, nick); + +/* + * Create the device handle + */ + switch (dev_type) + { + case DRV_PCI: + { + sprintf (osdev->handle, "OSS-PCI"); + } + break; + + default: + sprintf (osdev->handle, "%s%d", handle, instance); + } + + return osdev; +} + +oss_device_t * +osdev_clone (oss_device_t * orig_osdev, int new_instance) +{ + oss_device_t *osdev; + + osdev = PMALLOC (NULL, sizeof (*osdev)); + if (osdev == NULL) + { + cmn_err (CE_WARN, "osdev_create: Out of memory\n"); + return NULL; + } + memcpy (osdev, orig_osdev, sizeof (*osdev)); + osdev->dev_type = DRV_CLONE; + osdev->instance = new_instance; + sprintf (osdev->nick, "%s%d", orig_osdev->modname, new_instance); + sprintf (osdev->handle, "%s%d", orig_osdev->modname, new_instance); + + return osdev; +} + +void +osdev_delete (oss_device_t * osdev) +{ + int i; + + if (osdev == NULL) + return; + + osdev->available = 0; +/* + * Mark all minor nodes for this module as invalid. + */ + for (i = 0; i < oss_num_cdevs; i++) + if (oss_cdevs[i]->osdev == osdev) + { + if (oss_cdevs[i]->info != NULL) + destroy_dev (oss_cdevs[i]->info); + oss_cdevs[i]->d = NULL; + oss_cdevs[i]->info = NULL; + oss_cdevs[i]->osdev = NULL; + strcpy (oss_cdevs[i]->name, "Removed device"); + } +} + +void * +oss_get_osid (oss_device_t * osdev) +{ + return osdev->osid; +} + +void +oss_inc_intrcount (oss_device_t * osdev, int claimed) +{ + osdev->intrcount++; + + if (claimed) + osdev->ackcount++; +} diff --git a/kernel/OS/FreeBSD/os_freebsd.h b/kernel/OS/FreeBSD/os_freebsd.h new file mode 100644 index 0000000..161a2e3 --- /dev/null +++ b/kernel/OS/FreeBSD/os_freebsd.h @@ -0,0 +1,263 @@ +#ifndef _OS_H_ +#define _OS_H_ + +/* + * Purpose: OS specific definitions for FreeBSD + * + */ +/* + * + * This file is part of Open Sound System. + * + * Copyright (C) 4Front Technologies 1996-2008. + * + * This this source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + */ +#define OS_VERSION "6" +#define __inline__ inline +#define __inline inline +#define EXTERN_C extern "C" + +/* + * Debugging and misc settings + */ +#undef MUTEX_CHECKS +#undef MEMDEBUG + +#if (!defined(__i386__) && !defined(__x86_64__)) || defined(CONFIG_OSS_FIXDEPOINT) +// Floating point is not supported or it's disabled +#undef CONFIG_OSS_VMIX_FLOAT +#endif + +/* + * Disable support for per-application features such as /dev/dsp device + * selection based on command name. Requires working GET_PROCESS_NAME + * macro implementation. + */ +#undef APPLIST_SUPPORT +#define USE_DEVICE_SUBDIRS + +#include <stdarg.h> +#include <sys/types.h> +#ifdef _KERNEL +#include <sys/systm.h> +#endif +#include <sys/param.h> +#include <sys/uio.h> +#include <sys/fcntl.h> +#include <sys/poll.h> +#include <sys/malloc.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/kernel.h> +#include <machine/cpufunc.h> +#include <vm/vm.h> +#include <vm/pmap.h> +#include <sys/selinfo.h> +#include <oss_errno.h> + +#if __FreeBSD_version >= 800062 +#define MINOR(x) dev2unit(x) +#else +#define MINOR(x) minor(x) +#endif + +#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); + +#include "kernel/OS/FreeBSD/wrapper/bsddefs.h" + +#ifdef USE_SX_LOCK +#include <sys/proc.h> /* XXX for curthread */ +#include <sys/sx.h> +#else +#include <sys/mutex.h> +#endif + + +#define uiomove oss_uiomove +typedef struct uio uio_t; +extern int oss_uiomove (void *address, size_t nbytes, enum uio_rw rwflag, + uio_t * uio_p); + +#undef HZ +#define OSS_HZ hz + +/* The soundcard.h could be in a nonstandard place so include it here. */ +#include "soundcard.h" + +typedef struct udi_usb_devc udi_usb_devc; + +#define ALLOW_SELECT +#define ALLOW_BUFFER_MAPPING + +/* + * Sleep/wakeup + */ + +#ifdef _KERNEL +struct oss_wait_queue +{ + oss_mutex_t mutex; + unsigned long flags; + struct selinfo poll_info; +}; +#endif + +/* Busy wait routine */ + +/* System wall timer access */ +extern unsigned long oss_get_time (void); +#define GET_JIFFIES() oss_get_time() + +/* + * Mutexes + */ + +#ifdef USE_SX_LOCK +struct sx; +#define MUTEX_INIT(osdev, mutex, hier) \ +do { \ + mutex = malloc(sizeof(*mutex), M_DEVBUF, M_WAITOK | M_ZERO); \ + sx_init(mutex, "oss"); \ +} while (0) +#define MUTEX_CLEANUP(mutex) \ +do { \ + sx_destroy(mutex); \ + free(mutex, M_DEVBUF); \ +} while (0) +#define MUTEX_ENTER_IRQDISABLE(mutex, flags) sx_xlock(mutex) +#define MUTEX_ENTER(mutex, flags) sx_slock(mutex) +#define MUTEX_EXIT_IRQRESTORE(mutex, flags) sx_xunlock(mutex) +#define MUTEX_EXIT(mutex, flags) sx_sunlock(mutex) +#else /* !USE_SX_LOCK */ +struct mtx; +#define MUTEX_INIT(osdev, mutex, hier) \ +do { \ + mutex = malloc(sizeof(*mutex), M_DEVBUF, M_WAITOK | M_ZERO); \ + mtx_init(mutex, "oss", NULL, MTX_RECURSE | MTX_SPIN); \ +} while (0) +#define MUTEX_CLEANUP(mutex) \ +do { \ + mtx_destroy(mutex); \ + free(mutex, M_DEVBUF); \ +} while (0) +#define MUTEX_ENTER_IRQDISABLE(mutex, flags) mtx_lock_spin_flags(mutex, flags) +#define MUTEX_ENTER(mutex, flags) mtx_lock_spin(mutex) +#define MUTEX_EXIT_IRQRESTORE(mutex, flags) mtx_unlock_spin_flags(mutex, flags) +#define MUTEX_EXIT(mutex, flags) mtx_unlock_spin(mutex) +#endif /* USE_SX_LOCK */ + + +/* + * 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) inb(p) +#define INW(o, p) inw(p) +#define INL(o, p) inl(p) + +#define OUTB(o, v, p) outb(p,v) +#define OUTW(o, v, p) outw(p,v) +#define OUTL(o, v, p) outl(p,v) + +/* Memory Mapped devices */ +#define PCI_READL(osp, p) readl(p) +#define PCI_READW(osp, p) readw(p) +#define PCI_READB(osp, p) readb(p) +#define PCI_WRITEL(osp, addr, data) writel(addr, data) +#define PCI_WRITEW(osp, addr, data) writew(addr, data) +#define PCI_WRITEB(osp, addr, data) writeb(addr, data) + +typedef void *oss_dma_handle_t; + +/* + KERNEL_MALLOC() allocates requested number of memory and + KERNEL_FREE is used to free it. + These macros are never called from interrupt, in addition the + nbytes will never be more than 4096 bytes. Generally the driver + will allocate memory in blocks of 4k. If the kernel has just a + page level memory allocation, 4K can be safely used as the size + (the nbytes parameter can be ignored). +*/ +#define KERNEL_MALLOC(nbytes) malloc(nbytes, M_DEVBUF, M_NOWAIT|M_ZERO) +#define KERNEL_FREE(addr) {if (addr)free(addr, M_DEVBUF);addr=NULL;} + +#define CONTIG_MALLOC(osdev, sz, memlimit, phaddr, handle) oss_contig_malloc(sz, memlimit, phaddr) +#define CONTIG_FREE(osdev, p, sz, handle) oss_contig_free(p, 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 acc_flags; + int pid; + int dev; + char *cmd; +}; +#define ISSET_FILE_FLAG(fileinfo, flag) (fileinfo->acc_flags & (flag) ? 1:0) + +#define OSS_OS "FreeBSD" +#define OSS_OS_LONGNAME "FreeBSD " 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; + +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); +#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) {} +#define UNMAP_PCI_IOADDR(osdev, ix) {} + +#define GET_PROCESS_PID(f) f->pid +#define GET_PROCESS_NAME(f) f->cmd + +#define abs(x) ((x) >= 0 ? (x) : -(x)) + +/* + * PCI config space access (in os.c) + */ +extern char *oss_pci_read_devpath (dev_info_t * dip); diff --git a/kernel/OS/FreeBSD/wrapper/bsddefs.h b/kernel/OS/FreeBSD/wrapper/bsddefs.h new file mode 100644 index 0000000..c22965c --- /dev/null +++ b/kernel/OS/FreeBSD/wrapper/bsddefs.h @@ -0,0 +1,150 @@ +/* + * Purpose: Definitions for routines and variables exported by osscore.c + * + * Do not make any modifications to these settings because OSS core modules + * have been compiled against them. Full rebuild of OSS will be required if + * this file is changed. + */ +/* + * + * This file is part of Open Sound System. + * + * Copyright (C) 4Front Technologies 1996-2008. + * + * This this source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + */ + +#include <sys/types.h> +#if 0 /* __FreeBSD_version >= 700031 */ +/* Some crashes have been reported with SX on 7-STABLE/8-CURRENT: + * http://4front-tech.com/forum/viewtopic.php?t=2718 + * http://4front-tech.com/forum/viewtopic.php?t=2563 + */ +#define USE_SX_LOCK 1 +#endif +#undef VDEV_SUPPORT +#if __FreeBSD_version >= 700111 +#define VDEV_SUPPORT +extern int oss_file_set_private (struct thread *p, void *v, size_t l); +extern int oss_file_get_private (void **v); +#endif +extern int oss_get_uid (void); + +typedef struct device dev_info_t; +typedef long long oss_int64_t; /* Signed 64 bit integer */ +typedef unsigned long long oss_uint64_t; /* Unsigned 64 bit integer */ +typedef unsigned long offset_t; + +/* + * Some integer types + */ +#if defined(__amd64__) +typedef unsigned long long oss_native_word; /* Same as the address and status register size */ +#else +typedef unsigned long oss_native_word; /* Same as the address and status register size */ +#endif + +struct _oss_device_t +{ + int cardnum; + int dev_type; + int instance; + int available; + dev_info_t *dip; + void *osid; + void *devc; + char *name; + char *hw_info; + int major; + char nick[16]; + char modname[16]; + 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() */ + + int intrcount; + int ackcount; + volatile int refcount; /* Nonzero means that the device is needed by some other (virtual) driver. */ + +}; + +extern void cmn_err (int level, char *format, ...); +#define CE_CONT 0 +#define CE_NOTE 1 +#define CE_WARN 2 +#define CE_PANIC 3 + +#ifdef USE_SX_LOCK +typedef struct sx *oss_mutex_t; +#else +typedef struct mtx *oss_mutex_t; +#endif + +typedef int ddi_iblock_cookie_t; + +extern void oss_udelay (unsigned long t); + +#ifdef _KERNEL +#define memset oss_memset +extern void *oss_memset (void *t, int val, int l); +#endif + +extern oss_device_t *osdev_create (dev_info_t * dip, int dev_type, + int instance, const char *nick, + const char *handle); +extern void osdev_delete (oss_device_t * osdev); + +extern char *oss_pci_read_devpath (dev_info_t * dip); +extern int pci_read_config_byte (oss_device_t * osdev, offset_t where, + unsigned char *val); +extern int pci_read_config_irq (oss_device_t * osdev, offset_t where, + unsigned char *val); +extern int pci_read_config_word (oss_device_t * osdev, offset_t where, + unsigned short *val); +extern int pci_read_config_dword (oss_device_t * osdev, offset_t where, + unsigned int *val); +extern int pci_write_config_byte (oss_device_t * osdev, offset_t where, + unsigned char val); +extern int pci_write_config_word (oss_device_t * osdev, offset_t where, + unsigned short val); +extern int pci_write_config_dword (oss_device_t * osdev, offset_t where, + unsigned int val); +#ifndef OSS_CONFIG_H +/* These definitions must match with oss_config.h */ +typedef int (*oss_tophalf_handler_t) (struct _oss_device_t * osdev); +typedef void (*oss_bottomhalf_handler_t) (struct _oss_device_t * osdev); +#endif + +extern int oss_register_interrupts (oss_device_t * osdev, int intrnum, + oss_tophalf_handler_t top, + oss_bottomhalf_handler_t bottom); +extern void oss_unregister_interrupts (oss_device_t * osdev); + +extern void *oss_contig_malloc (unsigned long sz, unsigned long memlimit, + oss_native_word * phaddr); +extern void oss_contig_free (void *p, unsigned long sz); + +extern void oss_register_module (char *name); +extern void oss_unregister_module (char *name); +extern void *oss_find_minor_info (int dev_class, int instance); +extern int oss_find_minor (int dev_class, int instance); +extern void oss_inc_intrcount (oss_device_t * osdev, int claimed); + +#define FP_SUPPORT + +#ifdef FP_SUPPORT +typedef short fp_env_t[512]; +typedef unsigned int fp_flags_t[4]; +extern int oss_fp_check (void); +extern void oss_fp_save (short *envbuf, fp_flags_t flags); +extern void oss_fp_restore (short *envbuf, fp_flags_t flags); +# define FP_SAVE(envbuf, flags) oss_fp_save(envbuf, flags) +# define FP_RESTORE(envbuf, flags) oss_fp_restore(envbuf, flags) +#endif |