OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [drivers/] [sound/] [maui.c] - Rev 1772

Go to most recent revision | Compare with Previous | Blame | View Log

/*
 * sound/maui.c
 *
 * The low level driver for Turtle Beach Maui and Tropez.
 */
/*
 * Copyright (C) by Hannu Savolainen 1993-1996
 *
 * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
 * Version 2 (June 1991). See the "COPYING" file distributed with this software
 * for more info.
 */
#include <linux/config.h>
 
 
#define USE_SEQ_MACROS
#define USE_SIMPLE_MACROS
 
#include "sound_config.h"
 
#if defined(CONFIG_MAUI)
 
static int      maui_base = 0x330;
 
static volatile int irq_ok = 0;
static int     *maui_osp;
 
#define HOST_DATA_PORT	(maui_base + 2)
#define HOST_STAT_PORT	(maui_base + 3)
#define HOST_CTRL_PORT	(maui_base + 3)
 
#define STAT_TX_INTR	0x40
#define STAT_TX_AVAIL	0x20
#define STAT_TX_IENA	0x10
#define STAT_RX_INTR	0x04
#define STAT_RX_AVAIL	0x02
#define STAT_RX_IENA	0x01
 
static int      (*orig_load_patch) (int dev, int format, const char *addr,
				 int offs, int count, int pmgr_flag) = NULL;
 
#ifdef HAVE_MAUI_BOOT
#include "maui_boot.h"
#else
static unsigned char *maui_os = NULL;
static int      maui_osLen = 0;
 
#endif
 
static wait_handle *maui_sleeper = NULL;
static volatile struct snd_wait maui_sleep_flag =
{0};
 
static int
maui_wait (int mask)
{
  int             i;
 
/*
 * Perform a short initial wait without sleeping
 */
 
  for (i = 0; i < 100; i++)
    {
      if (inb (HOST_STAT_PORT) & mask)
	{
	  return 1;
	}
    }
 
/*
 * Wait up to 15 seconds with sleeping
 */
 
  for (i = 0; i < 150; i++)
    {
      if (inb (HOST_STAT_PORT) & mask)
	{
	  return 1;
	}
 
 
      {
	unsigned long   tlimit;
 
	if (HZ / 10)
	  current_set_timeout (tlimit = jiffies + (HZ / 10));
	else
	  tlimit = (unsigned long) -1;
	maui_sleep_flag.flags = WK_SLEEP;
	module_interruptible_sleep_on (&maui_sleeper);
	if (!(maui_sleep_flag.flags & WK_WAKEUP))
	  {
	    if (jiffies >= tlimit)
	      maui_sleep_flag.flags |= WK_TIMEOUT;
	  }
	maui_sleep_flag.flags &= ~WK_SLEEP;
      };
      if (current_got_fatal_signal ())
	return 0;
    }
 
  return 0;
}
 
static int
maui_read (void)
{
  if (maui_wait (STAT_RX_AVAIL))
    return inb (HOST_DATA_PORT);
 
  return -1;
}
 
static int
maui_write (unsigned char data)
{
  if (maui_wait (STAT_TX_AVAIL))
    {
      outb (data, HOST_DATA_PORT);
      return 1;
    }
  printk ("Maui: Write timeout\n");
 
  return 0;
}
 
void
mauiintr (int irq, void *dev_id, struct pt_regs *dummy)
{
  irq_ok = 1;
}
 
static int
download_code (void)
{
  int             i, lines = 0;
  int             eol_seen = 0, done = 0;
  int             skip = 1;
 
  printk ("Code download (%d bytes): ", maui_osLen);
 
  for (i = 0; i < maui_osLen; i++)
    {
      if (maui_os[i] != '\r')
	if (!skip || (maui_os[i] == 'S' && (i == 0 || maui_os[i - 1] == '\n')))
	  {
	    skip = 0;
 
	    if (maui_os[i] == '\n')
	      eol_seen = skip = 1;
	    else if (maui_os[i] == 'S')
	      {
		if (maui_os[i + 1] == '8')
		  done = 1;
		if (!maui_write (0xF1))
		  goto failure;
		if (!maui_write ('S'))
		  goto failure;
	      }
	    else
	      {
		if (!maui_write (maui_os[i]))
		  goto failure;
	      }
 
	    if (eol_seen)
	      {
		int             c = 0;
 
		int             n;
 
		eol_seen = 0;
 
		for (n = 0; n < 2; n++)
		  if (maui_wait (STAT_RX_AVAIL))
		    {
		      c = inb (HOST_DATA_PORT);
		      break;
		    }
 
		if (c != 0x80)
		  {
		    printk ("Download not acknowledged\n");
		    return 0;
		  }
		else if (!(lines++ % 10))
		  printk (".");
 
		if (done)
		  {
		    printk ("\nDownload complete\n");
		    return 1;
		  }
	      }
	  }
    }
 
failure:
 
  printk ("\nDownload failed!!!\n");
  return 0;
}
 
static int
maui_init (int irq)
{
  int             i;
  unsigned char   bits;
 
  switch (irq)
    {
    case 9:
      bits = 0x00;
      break;
    case 5:
      bits = 0x08;
      break;
    case 12:
      bits = 0x10;
      break;
    case 15:
      bits = 0x18;
      break;
 
    default:
      printk ("Maui: Invalid IRQ %d\n", irq);
      return 0;
    }
 
  outb (0x00, HOST_CTRL_PORT);	/* Reset */
 
  outb (bits, HOST_DATA_PORT);	/* Set the IRQ bits */
  outb (bits | 0x80, HOST_DATA_PORT);	/* Set the IRQ bits again? */
 
  outb (0x80, HOST_CTRL_PORT);	/* Leave reset */
  outb (0x80, HOST_CTRL_PORT);	/* Leave reset */
 
  outb (0xD0, HOST_CTRL_PORT);	/* Cause interrupt */
 
  for (i = 0; i < 1000000 && !irq_ok; i++);
 
  if (!irq_ok)
    return 0;
 
  outb (0x80, HOST_CTRL_PORT);	/* Leave reset */
 
  printk ("Turtle Beach Maui initialization\n");
 
  if (!download_code ())
    return 0;
 
  outb (0xE0, HOST_CTRL_PORT);	/* Normal operation */
 
  /* Select mpu401 mode */
 
  maui_write (0xf0);
  maui_write (1);
  if (maui_read () != 0x80)
    {
      maui_write (0xf0);
      maui_write (1);
      if (maui_read () != 0x80)
	printk ("Maui didn't acknowledge set HW mode command\n");
    }
 
  printk ("Maui initialized OK\n");
  return 1;
}
 
static int
maui_short_wait (int mask)
{
  int             i;
 
  for (i = 0; i < 1000; i++)
    {
      if (inb (HOST_STAT_PORT) & mask)
	{
	  return 1;
	}
    }
 
  return 0;
}
 
int
maui_load_patch (int dev, int format, const char *addr,
		 int offs, int count, int pmgr_flag)
{
 
  struct sysex_info header;
  unsigned long   left, src_offs;
  int             hdr_size = (unsigned long) &header.data[0] - (unsigned long) &header;
  int             i;
 
  if (format == SYSEX_PATCH)	/* Handled by midi_synth.c */
    return orig_load_patch (dev, format, addr, offs, count, pmgr_flag);
 
  if (format != MAUI_PATCH)
    {
      printk ("Maui: Unknown patch format\n");
    }
 
  if (count < hdr_size)
    {
      printk ("Maui error: Patch header too short\n");
      return -(EINVAL);
    }
 
  count -= hdr_size;
 
  /*
   * Copy the header from user space but ignore the first bytes which have
   * been transferred already.
   */
 
  memcpy_fromfs (&((char *) &header)[offs], &(addr)[offs], hdr_size - offs);
 
  if (count < header.len)
    {
      printk ("Maui warning: Host command record too short (%d<%d)\n",
	      count, (int) header.len);
      header.len = count;
    }
 
  left = header.len;
  src_offs = 0;
 
  for (i = 0; i < left; i++)
    {
      unsigned char   data;
 
      data = get_fs_byte (&((addr)[hdr_size + i]));
      if (i == 0 && !(data & 0x80))
	return -(EINVAL);
 
      if (maui_write (data) == -1)
	return -(EIO);
    }
 
  if ((i = maui_read ()) != 0x80)
    {
      if (i != -1)
	printk ("Maui: Error status %02x\n", i);
 
      return -(EIO);
    }
 
  return 0;
}
 
int
probe_maui (struct address_info *hw_config)
{
  int             i;
  int             tmp1, tmp2, ret;
 
  if (check_region (hw_config->io_base, 8))
    return 0;
 
  maui_base = hw_config->io_base;
  maui_osp = hw_config->osp;
 
  if (snd_set_irq_handler (hw_config->irq, mauiintr, "Maui", maui_osp) < 0)
    return 0;
 
  maui_sleep_flag.flags = WK_NONE;
/*
 * Initialize the processor if necessary
 */
 
  if (maui_osLen > 0)
    {
      if (!(inb (HOST_STAT_PORT) & STAT_TX_AVAIL) ||
	  !maui_write (0x9F) ||	/* Report firmware version */
	  !maui_short_wait (STAT_RX_AVAIL) ||
	  maui_read () == -1 || maui_read () == -1)
	if (!maui_init (hw_config->irq))
	  {
	    snd_release_irq (hw_config->irq);
	    return 0;
	  }
    }
 
  if (!maui_write (0xCF))	/* Report hardware version */
    {
      printk ("No WaveFront firmware detected (card uninitialized?)\n");
      snd_release_irq (hw_config->irq);
      return 0;
    }
 
  if ((tmp1 = maui_read ()) == -1 || (tmp2 = maui_read ()) == -1)
    {
      printk ("No WaveFront firmware detected (card uninitialized?)\n");
      snd_release_irq (hw_config->irq);
      return 0;
    }
 
  if (tmp1 == 0xff || tmp2 == 0xff)
    {
      snd_release_irq (hw_config->irq);
      return 0;
    }
 
  if (trace_init)
    printk ("WaveFront hardware version %d.%d\n", tmp1, tmp2);
 
  if (!maui_write (0x9F))	/* Report firmware version */
    return 0;
  if ((tmp1 = maui_read ()) == -1 || (tmp2 = maui_read ()) == -1)
    return 0;
 
  if (trace_init)
    printk ("WaveFront firmware version %d.%d\n", tmp1, tmp2);
 
  if (!maui_write (0x85))	/* Report free DRAM */
    return 0;
  tmp1 = 0;
  for (i = 0; i < 4; i++)
    {
      tmp1 |= maui_read () << (7 * i);
    }
  if (trace_init)
    printk ("Available DRAM %dk\n", tmp1 / 1024);
 
  for (i = 0; i < 1000; i++)
    if (probe_mpu401 (hw_config))
      break;
 
  ret = probe_mpu401 (hw_config);
 
  if (ret)
    request_region (hw_config->io_base + 2, 6, "Maui");
 
  return ret;
}
 
void
attach_maui (struct address_info *hw_config)
{
  int             this_dev = num_midis;
 
  conf_printf ("Maui", hw_config);
 
  hw_config->irq *= -1;
  hw_config->name = "Maui";
  attach_mpu401 (hw_config);
 
  if (num_midis > this_dev)	/* The MPU401 driver installed itself */
    {
      struct synth_operations *synth;
 
      /*
       * Intercept patch loading calls so that they can be handled
       * by the Maui driver.
       */
 
      synth = midi_devs[this_dev]->converter;
 
      if (synth != NULL)
	{
	  orig_load_patch = synth->load_patch;
	  synth->load_patch = &maui_load_patch;
	}
      else
	printk ("Maui: Can't install patch loader\n");
    }
}
 
void
unload_maui (struct address_info *hw_config)
{
  int             irq = hw_config->irq;
 
  release_region (hw_config->io_base + 2, 6);
 
  unload_mpu401 (hw_config);
 
  if (irq < 0)
    irq = -irq;
 
  if (irq > 0)
    snd_release_irq (irq);
}
 
 
#endif
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.