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!

oss_geode/oss_geode.c

Driver for the NS/Cyrix/AMD Geode AC97 audio controller

Description




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_geode_cfg.h"
#include "oss_pci.h"
#include "ac97.h"

#define CYRIX_VENDOR_ID			0x1078
#define CYRIX_GEODE			0x0103
#define AMD_VENDOR_ID           	0x1022
#define AMD_CS5536_ID			0x2093
#define NATIONAL_VENDOR_ID		0x100b
#define NATIONAL_SC1200			0x0503

#define CS_READL(devc,addr) INL((devc)->osdev, (unsigned int)((devc)->physaddr) + (addr))
#define CS_READW(devc,addr) INW((devc)->osdev, (unsigned int)((devc)->physaddr) + (addr))
#define CS_READB(devc,addr) INB((devc)->osdev, (unsigned int)((devc)->physaddr) + (addr))
#define CS_WRITEL(devc,addr,val) OUTL((devc)->osdev, (val), (unsigned int)((devc)->physaddr) + (addr))
#define CS_WRITEB(devc,addr,val) OUTB((devc)->osdev, (val), (unsigned int)((devc)->physaddr) + (addr))

#define MAX_PORTC 2

typedef struct
{
  unsigned int ptr;
  unsigned int size;
#define PRD_EOT			0x80000000
#define PRD_EOP			0x40000000
#define PRD_JMP			0x20000000
}
PRD_rec;

typedef struct
{
  int open_mode;
  int speed;
  int bits;
  int channels;
  int trigger_bits;
  int audio_enabled;
  int audiodev;
}
geode_portc;

typedef struct
{
  oss_device_t *osdev;
  int physaddr;
  void *linaddr;
  unsigned char *f3bar;
  int irq;
  char *chip_name;
  oss_mutex_t mutex;
  oss_mutex_t low_mutex;

  int mixer_dev;
  ac97_devc ac97devc;

  geode_portc portc[MAX_PORTC];
  int open_mode;

  PRD_rec *prdin, *prdout;
  unsigned long prdin_phys, prdout_phys;
  oss_dma_handle_t prdin_dma_handle, prdout_dma_handle;

  unsigned int chip;
}
geode_devc;

static int
geodeintr_5530 (oss_device_t * osdev)
{

  geode_devc *devc = osdev->devc;
  geode_portc *portc;
  int i, n;
  int serviced = 0;
  unsigned int pos;
  int ptr;

  for (i = 0; i < MAX_PORTC; i++)
    {
      portc = &devc->portc[i];

      if (portc->trigger_bits & PCM_ENABLE_OUTPUT)
	{
	  dmap_t *dmap;
	  dmap = audio_engines[portc->audiodev]->dmap_out;
	  pos = CS_READL (devc, 0x24);
	  pos = (pos - devc->prdout_phys) / 8;
	  ptr = pos;
	  ptr--;

	  if (ptr < 0)
	    ptr = 0;
	  ptr %= dmap->nfrags;

	  n = 0;
	  while (ptr != dmap_get_qhead (dmap) && n++ < dmap->nfrags)
	    oss_audio_outputintr (portc->audiodev, 0);
	  serviced = 1;
	}


      if (portc->trigger_bits & PCM_ENABLE_INPUT)
	{
	  dmap_t *dmap;

	  dmap = audio_engines[portc->audiodev]->dmap_in;

	  pos = CS_READL (devc, 0x2c);
	  pos = (pos - devc->prdin_phys) / 8;
	  ptr = pos;
	  ptr--;

	  if (ptr < 0)
	    ptr = 0;
	  ptr %= dmap->nfrags;

	  n = 0;
	  while (ptr != dmap_get_qtail (dmap) && n++ < dmap->nfrags)
	    oss_audio_inputintr (portc->audiodev, 0);

	  serviced = 1;
	}
    }
  return serviced;
}

static int
geodeintr_5536 (oss_device_t * osdev)
{

  geode_devc *devc = osdev->devc;
  geode_portc *portc;
  int i, n;
  int serviced = 0;
  unsigned int pos;
  int ptr;
  int irqstat;

  irqstat = CS_READW (devc, 0x12);

  for (i = 0; i < MAX_PORTC; i++)
    {
      portc = &devc->portc[i];

      if (irqstat & 3) /* either gpio or gpio wakeup */
	{
	  CS_READB (devc, 0x00);
	  serviced = 1;
	}


it handled. otherwise, the kernel will find noone has handled the interrupt and therefore disable it

      if (irqstat & 4)
	{
	  CS_READB (devc, 0x21);
	  serviced = 1;
	}

      if (irqstat & 8)
	{
	  CS_READB (devc, 0x29);
	  serviced = 1;
	}

      if ((portc->trigger_bits & PCM_ENABLE_OUTPUT) && (irqstat & 4))
	{
	  dmap_t *dmap;
	  dmap = audio_engines[portc->audiodev]->dmap_out;

	  pos = CS_READL (devc, 0x60);
	  pos = pos - dmap->dmabuf_phys;
	  ptr = pos;
	  ptr--;

	  if (ptr < 0)
	    ptr = 0;
	  ptr %= dmap->nfrags;

	  n = 0;
	  while (ptr != dmap_get_qhead (dmap) && n++ < dmap->nfrags)
	    oss_audio_outputintr (portc->audiodev, 0);
	}


      if ((portc->trigger_bits & PCM_ENABLE_INPUT) && (irqstat & 8))
	{
	  dmap_t *dmap;

	  dmap = audio_engines[portc->audiodev]->dmap_in;

	  pos = CS_READL (devc, 0x64);
	  pos = pos - dmap->dmabuf_phys;
	  ptr = pos;
	  ptr--;

	  if (ptr < 0)
	    ptr = 0;
	  ptr %= dmap->nfrags;

	  n = 0;
	  while (ptr != dmap_get_qtail (dmap) && n++ < dmap->nfrags)
	    oss_audio_inputintr (portc->audiodev, 0);
	}
    }
  return serviced;
}

static int
codec_valid_data (geode_devc * devc, int command, unsigned int *data)
{
  int y;
  for (y = 0; y < 1000; y++)
    {
      *data = CS_READL (devc, 0x08);

      if ((*data & 0x7F000000) != (command & 0x7F000000))
	continue;
      if (devc->chip == AMD_CS5536_ID)
	{
	  if ((*data & 0x00020000) == 0x00020000)
	    return 1;
	}
      else
	{
	  if ((*data & 0x00030000) == 0x00030000)
	    return 1;
	}
    }
  return 0;
}

static int
ac97_read (void *devc_, int wAddr)
{
  geode_devc *devc = devc_;
  int i;
  unsigned int x, y;
  oss_native_word flags;

  MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags);

  for (i = 0; i < 10000; i++)
    if (!(CS_READL (devc, 0x0c) & 0x10000))
      break;

  for (i = 0; i < 10000; i++)
    {
      MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);

      MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags);
      x = (wAddr << 24) | 0x80000000;
      if (devc->chip == AMD_CS5536_ID)
	x = x | 0x10000; /* this chip also need the NEW flag set */
      CS_WRITEL (devc, 0x0c, x);

      if (codec_valid_data (devc, x, &y))
	{
	  MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
	  return y & 0xffff;
	}
    }

  MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
  return OSS_EIO;
}

static int
ac97_write (void *devc_, int wAddr, int wData)
{
  geode_devc *devc = devc_;
  unsigned int tmp, i;
  oss_native_word flags;

  MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags);

  tmp = (wAddr << 24) | wData;
  if (devc->chip == AMD_CS5536_ID)
    tmp = (tmp | 0x10000) & ~0x80000000;
  CS_WRITEL (devc, 0x0c, tmp);

  /* wait for codec to be ready */
  for (i = 0; i <= 10000; i++)
    if (!(CS_READL (devc, 0x0c) & 0x10000))
      break;

  if (i >= 10000)
    {
      cmn_err (CE_WARN, "AC97 write timeout\n");
    }

  MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);

  return 0;
}

static int
geode_audio_set_rate (int dev, int arg)
{
  geode_portc *portc = audio_engines[dev]->portc;
  if (arg == 0)
    return portc->speed;

  if (audio_engines[dev]->flags & ADEV_FIXEDRATE)
    arg = 48000;

  if (arg > 48000)
    arg = 48000;
  if (arg < 8000)
    arg = 8000;
  portc->speed = arg;
  return portc->speed;
}

static short
geode_audio_set_channels (int dev, short arg)
{
  geode_portc *portc = audio_engines[dev]->portc;

  if (arg == 0)
    return portc->channels;

  if (audio_engines[dev]->flags & ADEV_STEREOONLY)
    arg = 2;

  if ((arg != 1) && (arg != 2))
    return portc->channels;
  portc->channels = arg;

  return portc->channels;
}

static unsigned int
geode_audio_set_format (int dev, unsigned int arg)
{
  geode_portc *portc = audio_engines[dev]->portc;

  if (arg == 0)
    return portc->bits;

  if (audio_engines[dev]->flags & ADEV_16BITONLY)
    arg = 16;

  if (!(arg & (AFMT_U8 | AFMT_S16_LE)))
    return portc->bits;
  portc->bits = arg;
  return portc->bits;
}

/*ARGSUSED*/
static int
geode_audio_ioctl (int dev, unsigned int cmd, ioctl_arg arg)
{
  return OSS_EINVAL;
}

static void geode_audio_trigger (int dev, int state);

static void
geode_audio_reset (int dev)
{
  geode_audio_trigger (dev, 0);
}

static void
geode_audio_reset_input (int dev)
{
  geode_portc *portc = audio_engines[dev]->portc;
  geode_audio_trigger (dev, portc->trigger_bits & ~PCM_ENABLE_INPUT);
}

static void
geode_audio_reset_output (int dev)
{
  geode_portc *portc = audio_engines[dev]->portc;
  geode_audio_trigger (dev, portc->trigger_bits & ~PCM_ENABLE_OUTPUT);
}

/*ARGSUSED*/
static int
geode_audio_open (int dev, int mode, int open_flags)
{
  geode_portc *portc = audio_engines[dev]->portc;
  geode_devc *devc = audio_engines[dev]->devc;
  oss_native_word flags;

  MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
  if (portc->open_mode)
    {
      MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
      return OSS_EBUSY;
    }

  if (devc->open_mode & mode)
    {
      MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
      return OSS_EBUSY;
    }

  devc->open_mode |= mode;

  portc->open_mode = mode;
  portc->audio_enabled &= ~mode;

  MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);

  return 0;
}

static void
geode_audio_close (int dev, int mode)
{
  geode_portc *portc = audio_engines[dev]->portc;
  geode_devc *devc = audio_engines[dev]->devc;

  geode_audio_reset (dev);
  portc->open_mode = 0;
  devc->open_mode &= ~mode;
  portc->audio_enabled &= ~mode;
}

/*ARGSUSED*/
static void
geode_audio_output_block (int dev, oss_native_word buf, int count,
			  int fragsize, int intrflag)
{
  geode_portc *portc = audio_engines[dev]->portc;

  portc->audio_enabled |= PCM_ENABLE_OUTPUT;
  portc->trigger_bits &= ~PCM_ENABLE_OUTPUT;
}

/*ARGSUSED*/
static void
geode_audio_start_input (int dev, oss_native_word buf, int count,
			 int fragsize, int intrflag)
{
  geode_portc *portc = audio_engines[dev]->portc;

  portc->audio_enabled |= PCM_ENABLE_INPUT;
  portc->trigger_bits &= ~PCM_ENABLE_INPUT;
}

static void
geode_audio_trigger (int dev, int state)
{
  geode_devc *devc = audio_engines[dev]->devc;
  geode_portc *portc = audio_engines[dev]->portc;
  int i;
  oss_native_word flags;

  MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);

  if (portc->open_mode & OPEN_WRITE)
    {
      if (state & PCM_ENABLE_OUTPUT)
	{
	  if ((portc->audio_enabled & PCM_ENABLE_OUTPUT) &&
	      !(portc->trigger_bits & PCM_ENABLE_OUTPUT))
	    {
	      CS_WRITEB (devc, 0x20, 0x01);
	      CS_WRITEB (devc, 0x21, 0x00);
	      portc->trigger_bits |= PCM_ENABLE_OUTPUT;
	    }
	}
      else
	{
	  if ((portc->audio_enabled & PCM_ENABLE_OUTPUT) &&
	      (portc->trigger_bits & PCM_ENABLE_OUTPUT))
	    {
	      portc->audio_enabled &= ~PCM_ENABLE_OUTPUT;
	      portc->trigger_bits &= ~PCM_ENABLE_OUTPUT;

	      for (i = 0; i < 512; i++)
		{
		  devc->prdout[i].size = PRD_EOT;	/* Stop */
		}
	    }
	}
    }

  if (portc->open_mode & OPEN_READ)
    {
      if (state & PCM_ENABLE_INPUT)
	{
	  if ((portc->audio_enabled & PCM_ENABLE_INPUT) &&
	      !(portc->trigger_bits & PCM_ENABLE_INPUT))
	    {
	      CS_WRITEB (devc, 0x28, 0x09);
	      CS_WRITEB (devc, 0x29, 0x00);
	      portc->trigger_bits |= PCM_ENABLE_INPUT;
	    }
	}
      else
	{
	  if ((portc->audio_enabled & PCM_ENABLE_INPUT) &&
	      (portc->trigger_bits & PCM_ENABLE_INPUT))
	    {
	      portc->audio_enabled &= ~PCM_ENABLE_INPUT;
	      portc->trigger_bits &= ~PCM_ENABLE_INPUT;

	      for (i = 0; i < 512; i++)
		{
		  devc->prdin[i].size = PRD_EOT;	/* Stop */
		}
	    }
	}
    }
  MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
}

/*ARGSUSED*/
static int
geode_audio_prepare_for_input (int dev, int bsize, int bcount)
{
  geode_devc *devc = audio_engines[dev]->devc;
  geode_portc *portc = audio_engines[dev]->portc;
  dmap_t *dmap = audio_engines[dev]->dmap_in;
  int i, stat;
  oss_native_word flags;

  MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
  ac97_recrate (&devc->ac97devc, portc->speed);

#if 0
  if (dmap->nfrags > 256)
    {
      dmap->nfrags = 256;
      dmap->bytes_in_use = 256 * dmap->fragment_size;
    }
#endif


  /* clear out the prd table */
  memset (devc->prdin, 0, 512 * sizeof (PRD_rec));

  /* Clear DMA Bus Master Status */
  stat = CS_READB (devc, 0x29);
  stat++;			/* To supress warnings by lint */

  /* Initialize PRD entries */
  for (i = 0; i < dmap->nfrags; i++)
    {
      devc->prdin[i].ptr = dmap->dmabuf_phys + (i * dmap->fragment_size);
	devc->prdin[i].size = dmap->fragment_size | PRD_EOP;
    }

  /* Initialize the JMP entry back to the beginning */
  devc->prdin[dmap->nfrags].ptr = devc->prdin_phys;
  devc->prdin[dmap->nfrags].size = PRD_JMP | PRD_EOP;

  CS_WRITEL (devc, 0x2c, devc->prdin_phys);

  portc->audio_enabled &= ~PCM_ENABLE_INPUT;
  portc->trigger_bits &= ~PCM_ENABLE_INPUT;
  MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
  return 0;
}

/*ARGSUSED*/
static int
geode_audio_prepare_for_output (int dev, int bsize, int bcount)
{
  geode_devc *devc = audio_engines[dev]->devc;
  geode_portc *portc = audio_engines[dev]->portc;
  dmap_t *dmap = audio_engines[dev]->dmap_out;
  int i, stat;
  oss_native_word flags;

  MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
  ac97_playrate (&devc->ac97devc, portc->speed);
#if 0
  if (dmap->nfrags > 256)
    {
      dmap->nfrags = 256;
      dmap->bytes_in_use = 256 * dmap->fragment_size;
    }
#endif
  /* clear out the PRD table */
  memset (devc->prdout, 0, 512 * sizeof (PRD_rec));


  /* Initialize PRD entries */
  for (i = 0; i < dmap->nfrags; i++)
    {
      devc->prdout[i].ptr = dmap->dmabuf_phys + (i * dmap->fragment_size);
      devc->prdout[i].size = dmap->fragment_size | PRD_EOP;
    }

  /* Initialize the JMP entry back to the beginning */
  devc->prdout[dmap->nfrags].ptr = devc->prdout_phys;
  devc->prdout[dmap->nfrags].size = PRD_JMP | PRD_EOP;

  CS_WRITEL (devc, 0x24, devc->prdout_phys);

  /* Clear DMA Bus master status */
  stat = CS_READB (devc, 0x21);
  stat++;			/* To supress warnings by lint */
  portc->audio_enabled &= ~PCM_ENABLE_OUTPUT;
  portc->trigger_bits &= ~PCM_ENABLE_OUTPUT;
  MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);

  return 0;
}

static int
geode_get_buffer_pointer (int dev, dmap_t * dmap, int direction)
{
  geode_devc *devc = audio_engines[dev]->devc;
  int ptr = 0;
  oss_native_word flags;

  MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags);
  if (direction == PCM_ENABLE_OUTPUT)
    {
      if (devc->chip == AMD_CS5536_ID)
	ptr = CS_READL (devc, 0x60);
      else
	ptr = CS_READL (devc, 0x24);
    }
  if (direction == PCM_ENABLE_INPUT)
    {
      if (devc->chip == AMD_CS5536_ID)
	ptr = CS_READL (devc, 0x64);
      else
	ptr = CS_READL (devc, 0x2c);
    }
  MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
  return ptr - dmap->dmabuf_phys;
}

static const audiodrv_t geode_audio_driver = {
  geode_audio_open,
  geode_audio_close,
  geode_audio_output_block,
  geode_audio_start_input,
  geode_audio_ioctl,
  geode_audio_prepare_for_input,
  geode_audio_prepare_for_output,
  geode_audio_reset,
  NULL,
  NULL,
  geode_audio_reset_input,
  geode_audio_reset_output,
  geode_audio_trigger,
  geode_audio_set_rate,
  geode_audio_set_format,
  geode_audio_set_channels,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,				/* geode_alloc_buffer */
  NULL,				/* geode_free_buffer */
  NULL,
  NULL,
  geode_get_buffer_pointer
};

static int
init_geode (geode_devc * devc)
{
  int i, caps, opts;
  int first_dev = 0;
  oss_native_word phaddr;

  /* Allocate the buffers for the prdin/prdout tables */
  devc->prdin =
    (PRD_rec *) CONTIG_MALLOC (devc->osdev, 512 * sizeof (PRD_rec),
			       MEMLIMIT_32BITS, &phaddr, devc->prdin_dma_handle);
  if (devc->prdin == NULL)
    {
      cmn_err (CE_WARN, "Can't allocate memory for PRD input tables\n");
      return 0;
    }

  devc->prdin_phys = phaddr;

  devc->prdout =
    (PRD_rec *) CONTIG_MALLOC (devc->osdev, 512 * sizeof (PRD_rec),
			       MEMLIMIT_32BITS, &phaddr, devc->prdout_dma_handle);
  if (devc->prdout == NULL)
    {
      cmn_err (CE_WARN, "Can't allocate memory for PRD output tables\n");
      return 0;
    }

  devc->prdout_phys = phaddr;

  /* VSA2 IRQ config method */
  OUTW (devc->osdev, 0xFC53, 0xAC1C);
  OUTW (devc->osdev, 0x108, 0xAC1C);
  OUTW (devc->osdev, devc->irq, 0xAC1E);

  /* VSA1 IRQ config method */
  OUTL (devc->osdev, 0x800090D0, 0x0CF8);
  OUTL (devc->osdev, (devc->irq << 16) | 0xA00A, 0x0CFC);
  oss_udelay (10000);

  /* Now configure the OSS devices */

  devc->mixer_dev =
    ac97_install (&devc->ac97devc, "AC97 Mixer", ac97_read, ac97_write, devc,
		  devc->osdev);

  if (devc->mixer_dev < 0)
    return 0;

  if (devc->chip == AMD_CS5536_ID)
    {

chip, like s/pdif (cs5536 databook, page 89)

      ac97_remove_control (&devc->ac97devc,
	SOUND_MASK_VIDEO | SOUND_MASK_MONO | SOUND_MASK_CD | SOUND_MASK_PHONE,
	0);
    }

  opts = ADEV_AUTOMODE | ADEV_STEREOONLY | ADEV_16BITONLY;

  if (!ac97_varrate (&devc->ac97devc))
    {
      opts |= ADEV_FIXEDRATE;
    }

  for (i = 0; i < MAX_PORTC; i++)
    {
      int adev;
      geode_portc *portc = &devc->portc[i];
      char tmp_name[100];

      if (i == 0)
	{
	  strcpy (tmp_name, devc->chip_name);
	  caps = opts | ADEV_DUPLEX;
	}
      else
	{
	  strcpy (tmp_name, devc->chip_name);
	  caps = opts | ADEV_DUPLEX | ADEV_SHADOW;
	}

      if ((adev = oss_install_audiodev (OSS_AUDIO_DRIVER_VERSION,
					devc->osdev,
					devc->osdev,
					tmp_name,
					&geode_audio_driver,
					sizeof (audiodrv_t),
					caps, AFMT_S16_LE, devc, -1)) < 0)
	{
	  adev = -1;
	  return 0;
	}
      else
	{
	  if (i == 0)
	    first_dev = adev;
	  audio_engines[adev]->portc = portc;
	  audio_engines[adev]->rate_source = first_dev;
	  audio_engines[adev]->mixer_dev = devc->mixer_dev;
	  audio_engines[adev]->min_rate = 8000;
	  audio_engines[adev]->max_rate = 48000;
	  audio_engines[adev]->caps |= PCM_CAP_FREERATE;
	  portc->open_mode = 0;
	  portc->audiodev = adev;
	  portc->audio_enabled = 0;
	  if (caps & ADEV_FIXEDRATE)
	    {
	      audio_engines[adev]->fixed_rate = 48000;
	      audio_engines[adev]->min_rate = 48000;
	    }
#ifdef CONFIG_OSS_VMIX
	  if (i == 0)
	     vmix_attach_audiodev(devc->osdev, adev, -1, 0);
#endif
	}

    }
  return 1;
}

int
oss_geode_attach (oss_device_t * osdev)
{
  unsigned char pci_revision, pci_irq_line /*, pci_latency */ ;
  unsigned short pci_command, vendor, device;
  unsigned int pci_ioaddr;
  int err;
  geode_devc *devc;

  DDB (cmn_err (CE_WARN, "Entered Geode probe routine\n"));

  pci_read_config_word (osdev, PCI_VENDOR_ID, &vendor);
  pci_read_config_word (osdev, PCI_DEVICE_ID, &device);
  if (vendor != CYRIX_VENDOR_ID || device != CYRIX_GEODE)
    if (vendor != NATIONAL_VENDOR_ID || device != NATIONAL_SC1200)
       if (vendor != AMD_VENDOR_ID || device != AMD_CS5536_ID)
      return 0;
  pci_read_config_byte (osdev, PCI_REVISION_ID, &pci_revision);
  pci_read_config_word (osdev, PCI_COMMAND, &pci_command);
  pci_read_config_dword (osdev, PCI_MEM_BASE_ADDRESS_0, &pci_ioaddr);
  pci_read_config_irq (osdev, PCI_INTERRUPT_LINE, &pci_irq_line);

  pci_command |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
  pci_write_config_word (osdev, PCI_COMMAND, pci_command);

  if (pci_ioaddr == 0)
    {
      cmn_err (CE_WARN, "BAR0 not initialized by BIOS\n");
      return 0;
    }


  if ((devc = PMALLOC (osdev, sizeof (*devc))) == NULL)
    {
      cmn_err (CE_WARN, "Out of memory\n");
      return 0;
    }

  devc->osdev = osdev;
  osdev->devc = devc;
  devc->physaddr = pci_ioaddr & ~1UL;
  devc->irq = pci_irq_line;
  devc->chip = device;

  MUTEX_INIT (devc->osdev, devc->mutex, MH_DRV);
  MUTEX_INIT (devc->osdev, devc->low_mutex, MH_DRV + 1);
  if (devc->chip == AMD_CS5536_ID)
    {
      devc->chip_name = "AMD CS5536 AC97 Controller";

      oss_register_device (osdev, devc->chip_name);

      if ((err = oss_register_interrupts (devc->osdev, 0, geodeintr_5536, NULL)) < 0)
	{
	  cmn_err (CE_WARN, "Can't register interrupt handler, err=%d\n", err);
	  return 0;
	}
    }
  else
    {
      devc->chip_name = "Geode/NS5530 AC97 Controller";

      oss_register_device (osdev, devc->chip_name);

      if ((err = oss_register_interrupts (devc->osdev, 0, geodeintr_5530, NULL)) < 0)
	{
	  cmn_err (CE_WARN, "Can't register interrupt handler, err=%d\n", err);
	  return 0;
	}
    }


and all output from it can be interpreted as valid output from codec, it still does only give write timeouts. as the CS_* stuff works, this is worth being fixed only for following good style. when it's fixed, change stuff from this: CS_READL (devc, 0x09) to PCI_READL (devc->osdev, devc->f3bar + 0x09)


devc->f3bar = (unsigned char *) devc->linaddr;


  return init_geode (devc);	/* Detected */
}


int
oss_geode_detach (oss_device_t * osdev)
{
  geode_devc *devc = (geode_devc *) osdev->devc;

  if (oss_disable_device (osdev) < 0)
    return 0;

  CS_WRITEB (devc, 0x20, 0);   /* Disable output */
  CS_WRITEB (devc, 0x28, 0);   /* Disable input */
  CS_WRITEL (devc, 0x24, 0);
  CS_WRITEL (devc, 0x2c, 0);

  oss_unregister_interrupts (devc->osdev);

  MUTEX_CLEANUP (devc->mutex);
  MUTEX_CLEANUP (devc->low_mutex);


UNMAP_PCI_MEM (devc->osdev, 0, devc->physaddr, devc->linaddr, 128);


  if (devc->prdin != NULL)
    CONTIG_FREE (devc->osdev, devc->prdin, 512 * sizeof (PRD_rec), devc->prdin_dma_handle);
  if (devc->prdout != NULL)
    CONTIG_FREE (devc->osdev, devc->prdout, 512 * sizeof (PRD_rec), devc->prdout_dma_handle);

  devc->prdin = devc->prdout = NULL;
  oss_unregister_device (devc->osdev);

  return 1;
}

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