Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  gus_main.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *  Routines for Gravis UltraSound soundcards
 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
 */


#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <sound/core.h>
#include <sound/gus.h>
#include <sound/control.h>

#include <asm/dma.h>

MODULE_AUTHOR("Jaroslav Kysela ");
MODULE_DESCRIPTION("Routines for Gravis UltraSound soundcards");
MODULE_LICENSE("GPL");

static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches);

static int snd_gus_joystick_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 uinfo->count = 1;
 uinfo->value.integer.min = 0;
 uinfo->value.integer.max = 31;
 return 0;
}

static int snd_gus_joystick_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
 struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol);
 
 ucontrol->value.integer.value[0] = gus->joystick_dac & 31;
 return 0;
}

static int snd_gus_joystick_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
 struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol);
 unsigned long flags;
 int change;
 unsigned char nval;
 
 nval = ucontrol->value.integer.value[0] & 31;
 spin_lock_irqsave(&gus->reg_lock, flags);
 change = gus->joystick_dac != nval;
 gus->joystick_dac = nval;
 snd_gf1_write8(gus, SNDRV_GF1_GB_JOYSTICK_DAC_LEVEL, gus->joystick_dac);
 spin_unlock_irqrestore(&gus->reg_lock, flags);
 return change;
}

static const struct snd_kcontrol_new snd_gus_joystick_control = {
 .iface = SNDRV_CTL_ELEM_IFACE_CARD,
 .name = "Joystick Speed",
 .info = snd_gus_joystick_info,
 .get = snd_gus_joystick_get,
 .put = snd_gus_joystick_put
};

static void snd_gus_init_control(struct snd_gus_card *gus)
{
 if (!gus->ace_flag)
  snd_ctl_add(gus->card, snd_ctl_new1(&snd_gus_joystick_control, gus));
}

/*
 *
 */


static int snd_gus_free(struct snd_gus_card *gus)
{
 if (gus->gf1.res_port2 == NULL)
  goto __hw_end;
 snd_gf1_stop(gus);
 snd_gus_init_dma_irq(gus, 0);
      __hw_end:
 release_and_free_resource(gus->gf1.res_port1);
 release_and_free_resource(gus->gf1.res_port2);
 if (gus->gf1.irq >= 0)
  free_irq(gus->gf1.irq, (void *) gus);
 if (gus->gf1.dma1 >= 0) {
  disable_dma(gus->gf1.dma1);
  free_dma(gus->gf1.dma1);
 }
 if (!gus->equal_dma && gus->gf1.dma2 >= 0) {
  disable_dma(gus->gf1.dma2);
  free_dma(gus->gf1.dma2);
 }
 kfree(gus);
 return 0;
}

static int snd_gus_dev_free(struct snd_device *device)
{
 struct snd_gus_card *gus = device->device_data;
 return snd_gus_free(gus);
}

int snd_gus_create(struct snd_card *card,
     unsigned long port,
     int irq, int dma1, int dma2,
     int timer_dev,
     int voices,
     int pcm_channels,
     int effect,
     struct snd_gus_card **rgus)
{
 struct snd_gus_card *gus;
 int err;
 static const struct snd_device_ops ops = {
  .dev_free = snd_gus_dev_free,
 };

 *rgus = NULL;
 gus = kzalloc(sizeof(*gus), GFP_KERNEL);
 if (gus == NULL)
  return -ENOMEM;
 spin_lock_init(&gus->reg_lock);
 spin_lock_init(&gus->voice_alloc);
 spin_lock_init(&gus->active_voice_lock);
 spin_lock_init(&gus->event_lock);
 spin_lock_init(&gus->dma_lock);
 spin_lock_init(&gus->pcm_volume_level_lock);
 spin_lock_init(&gus->uart_cmd_lock);
 mutex_init(&gus->dma_mutex);
 gus->gf1.irq = -1;
 gus->gf1.dma1 = -1;
 gus->gf1.dma2 = -1;
 gus->card = card;
 gus->gf1.port = port;
 /* fill register variables for speedup */
 gus->gf1.reg_page = GUSP(gus, GF1PAGE);
 gus->gf1.reg_regsel = GUSP(gus, GF1REGSEL);
 gus->gf1.reg_data8 = GUSP(gus, GF1DATAHIGH);
 gus->gf1.reg_data16 = GUSP(gus, GF1DATALOW);
 gus->gf1.reg_irqstat = GUSP(gus, IRQSTAT);
 gus->gf1.reg_dram = GUSP(gus, DRAM);
 gus->gf1.reg_timerctrl = GUSP(gus, TIMERCNTRL);
 gus->gf1.reg_timerdata = GUSP(gus, TIMERDATA);
 /* allocate resources */
 gus->gf1.res_port1 = request_region(port, 16, "GUS GF1 (Adlib/SB)");
 if (!gus->gf1.res_port1) {
  dev_err(card->dev, "gus: can't grab SB port 0x%lx\n", port);
  snd_gus_free(gus);
  return -EBUSY;
 }
 gus->gf1.res_port2 = request_region(port + 0x100, 12, "GUS GF1 (Synth)");
 if (!gus->gf1.res_port2) {
  dev_err(card->dev, "gus: can't grab synth port 0x%lx\n", port + 0x100);
  snd_gus_free(gus);
  return -EBUSY;
 }
 if (irq >= 0 && request_irq(irq, snd_gus_interrupt, 0, "GUS GF1", (void *) gus)) {
  dev_err(card->dev, "gus: can't grab irq %d\n", irq);
  snd_gus_free(gus);
  return -EBUSY;
 }
 gus->gf1.irq = irq;
 card->sync_irq = irq;
 if (request_dma(dma1, "GUS - 1")) {
  dev_err(card->dev, "gus: can't grab DMA1 %d\n", dma1);
  snd_gus_free(gus);
  return -EBUSY;
 }
 gus->gf1.dma1 = dma1;
 if (dma2 >= 0 && dma1 != dma2) {
  if (request_dma(dma2, "GUS - 2")) {
   dev_err(card->dev, "gus: can't grab DMA2 %d\n", dma2);
   snd_gus_free(gus);
   return -EBUSY;
  }
  gus->gf1.dma2 = dma2;
 } else {
  gus->gf1.dma2 = gus->gf1.dma1;
  gus->equal_dma = 1;
 }
 gus->timer_dev = timer_dev;
 if (voices < 14)
  voices = 14;
 if (voices > 32)
  voices = 32;
 if (pcm_channels < 0)
  pcm_channels = 0;
 if (pcm_channels > 8)
  pcm_channels = 8;
 pcm_channels++;
 pcm_channels &= ~1;
 gus->gf1.effect = effect ? 1 : 0;
 gus->gf1.active_voices = voices;
 gus->gf1.pcm_channels = pcm_channels;
 gus->gf1.volume_ramp = 25;
 gus->gf1.smooth_pan = 1;
 err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, gus, &ops);
 if (err < 0) {
  snd_gus_free(gus);
  return err;
 }
 *rgus = gus;
 return 0;
}

/*
 *  Memory detection routine for plain GF1 soundcards
 */


static int snd_gus_detect_memory(struct snd_gus_card * gus)
{
 int l, idx, local;
 unsigned char d;

 snd_gf1_poke(gus, 0L, 0xaa);
 snd_gf1_poke(gus, 1L, 0x55);
 if (snd_gf1_peek(gus, 0L) != 0xaa || snd_gf1_peek(gus, 1L) != 0x55) {
  dev_err(gus->card->dev,
   "plain GF1 card at 0x%lx without onboard DRAM?\n",
   gus->gf1.port);
  return -ENOMEM;
 }
 for (idx = 1, d = 0xab; idx < 4; idx++, d++) {
  local = idx << 18;
  snd_gf1_poke(gus, local, d);
  snd_gf1_poke(gus, local + 1, d + 1);
  if (snd_gf1_peek(gus, local) != d ||
      snd_gf1_peek(gus, local + 1) != d + 1 ||
      snd_gf1_peek(gus, 0L) != 0xaa)
   break;
 }
#if 1
 gus->gf1.memory = idx << 18;
#else
 gus->gf1.memory = 256 * 1024;
#endif
 for (l = 0, local = gus->gf1.memory; l < 4; l++, local -= 256 * 1024) {
  gus->gf1.mem_alloc.banks_8[l].address =
      gus->gf1.mem_alloc.banks_8[l].size = 0;
  gus->gf1.mem_alloc.banks_16[l].address = l << 18;
  gus->gf1.mem_alloc.banks_16[l].size = local > 0 ? 256 * 1024 : 0;
 }
 gus->gf1.mem_alloc.banks_8[0].size = gus->gf1.memory;
 return 0;  /* some memory were detected */
}

static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches)
{
 struct snd_card *card;
 unsigned long flags;
 int irq, dma1, dma2;
 static const unsigned char irqs[16] =
  {0, 0, 1, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7};
 static const unsigned char dmas[8] =
  {6, 1, 0, 2, 0, 3, 4, 5};

 if (snd_BUG_ON(!gus))
  return -EINVAL;
 card = gus->card;
 if (snd_BUG_ON(!card))
  return -EINVAL;

 gus->mix_cntrl_reg &= 0xf8;
 gus->mix_cntrl_reg |= 0x01; /* disable MIC, LINE IN, enable LINE OUT */
 if (gus->codec_flag || gus->ess_flag) {
  gus->mix_cntrl_reg &= ~1; /* enable LINE IN */
  gus->mix_cntrl_reg |= 4; /* enable MIC */
 }
 dma1 = gus->gf1.dma1;
 dma1 = abs(dma1);
 dma1 = dmas[dma1 & 7];
 dma2 = gus->gf1.dma2;
 dma2 = abs(dma2);
 dma2 = dmas[dma2 & 7];
 dma1 |= gus->equal_dma ? 0x40 : (dma2 << 3);

 if ((dma1 & 7) == 0 || (dma2 & 7) == 0) {
  dev_err(gus->card->dev, "Error! DMA isn't defined.\n");
  return -EINVAL;
 }
 irq = gus->gf1.irq;
 irq = abs(irq);
 irq = irqs[irq & 0x0f];
 if (irq == 0) {
  dev_err(gus->card->dev, "Error! IRQ isn't defined.\n");
  return -EINVAL;
 }
 irq |= 0x40;
#if 0
 card->mixer.mix_ctrl_reg |= 0x10;
#endif

 spin_lock_irqsave(&gus->reg_lock, flags);
 outb(5, GUSP(gus, REGCNTRLS));
 outb(gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
 outb(0x00, GUSP(gus, IRQDMACNTRLREG));
 outb(0, GUSP(gus, REGCNTRLS));
 spin_unlock_irqrestore(&gus->reg_lock, flags);

 udelay(100);

 spin_lock_irqsave(&gus->reg_lock, flags);
 outb(0x00 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
 outb(dma1, GUSP(gus, IRQDMACNTRLREG));
 if (latches) {
  outb(0x40 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
  outb(irq, GUSP(gus, IRQDMACNTRLREG));
 }
 spin_unlock_irqrestore(&gus->reg_lock, flags);

 udelay(100);

 spin_lock_irqsave(&gus->reg_lock, flags);
 outb(0x00 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
 outb(dma1, GUSP(gus, IRQDMACNTRLREG));
 if (latches) {
  outb(0x40 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
  outb(irq, GUSP(gus, IRQDMACNTRLREG));
 }
 spin_unlock_irqrestore(&gus->reg_lock, flags);

 snd_gf1_delay(gus);

 if (latches)
  gus->mix_cntrl_reg |= 0x08; /* enable latches */
 else
  gus->mix_cntrl_reg &= ~0x08; /* disable latches */
 spin_lock_irqsave(&gus->reg_lock, flags);
 outb(gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
 outb(0, GUSP(gus, GF1PAGE));
 spin_unlock_irqrestore(&gus->reg_lock, flags);

 return 0;
}

static int snd_gus_check_version(struct snd_gus_card * gus)
{
 unsigned long flags;
 unsigned char val, rev;
 struct snd_card *card;

 card = gus->card;
 spin_lock_irqsave(&gus->reg_lock, flags);
 outb(0x20, GUSP(gus, REGCNTRLS));
 val = inb(GUSP(gus, REGCNTRLS));
 rev = inb(GUSP(gus, BOARDVERSION));
 spin_unlock_irqrestore(&gus->reg_lock, flags);
 dev_dbg(card->dev, "GF1 [0x%lx] init - val = 0x%x, rev = 0x%x\n", gus->gf1.port, val, rev);
 strscpy(card->driver, "GUS");
 strscpy(card->longname, "Gravis UltraSound Classic (2.4)");
 if ((val != 255 && (val & 0x06)) || (rev >= 5 && rev != 255)) {
  if (rev >= 5 && rev <= 9) {
   gus->ics_flag = 1;
   if (rev == 5)
    gus->ics_flipped = 1;
   card->longname[27] = '3';
   card->longname[29] = rev == 5 ? '5' : '7';
  }
  if (rev >= 10 && rev != 255) {
   if (rev >= 10 && rev <= 11) {
    strscpy(card->driver, "GUS MAX");
    strscpy(card->longname, "Gravis UltraSound MAX");
    gus->max_flag = 1;
   } else if (rev == 0x30) {
    strscpy(card->driver, "GUS ACE");
    strscpy(card->longname, "Gravis UltraSound Ace");
    gus->ace_flag = 1;
   } else if (rev == 0x50) {
    strscpy(card->driver, "GUS Extreme");
    strscpy(card->longname, "Gravis UltraSound Extreme");
    gus->ess_flag = 1;
   } else {
    dev_err(card->dev,
     "unknown GF1 revision number at 0x%lx - 0x%x (0x%x)\n",
     gus->gf1.port, rev, val);
    dev_err(card->dev,
     " please - report to \n");
   }
  }
 }
 strscpy(card->shortname, card->longname, sizeof(card->shortname));
 gus->uart_enable = 1; /* standard GUSes doesn't have midi uart trouble */
 snd_gus_init_control(gus);
 return 0;
}

int snd_gus_initialize(struct snd_gus_card *gus)
{
 int err;

 if (!gus->interwave) {
  err = snd_gus_check_version(gus);
  if (err < 0) {
   dev_err(gus->card->dev, "version check failed\n");
   return err;
  }
  err = snd_gus_detect_memory(gus);
  if (err < 0)
   return err;
 }
 err = snd_gus_init_dma_irq(gus, 1);
 if (err < 0)
  return err;
 snd_gf1_start(gus);
 gus->initialized = 1;
 return 0;
}

  /* gus_io.c */
EXPORT_SYMBOL(snd_gf1_delay);
EXPORT_SYMBOL(snd_gf1_write8);
EXPORT_SYMBOL(snd_gf1_look8);
EXPORT_SYMBOL(snd_gf1_write16);
EXPORT_SYMBOL(snd_gf1_look16);
EXPORT_SYMBOL(snd_gf1_i_write8);
EXPORT_SYMBOL(snd_gf1_i_look8);
EXPORT_SYMBOL(snd_gf1_i_look16);
EXPORT_SYMBOL(snd_gf1_dram_addr);
EXPORT_SYMBOL(snd_gf1_write_addr);
EXPORT_SYMBOL(snd_gf1_poke);
EXPORT_SYMBOL(snd_gf1_peek);
  /* gus_reset.c */
EXPORT_SYMBOL(snd_gf1_alloc_voice);
EXPORT_SYMBOL(snd_gf1_free_voice);
EXPORT_SYMBOL(snd_gf1_ctrl_stop);
EXPORT_SYMBOL(snd_gf1_stop_voice);
  /* gus_mixer.c */
EXPORT_SYMBOL(snd_gf1_new_mixer);
  /* gus_pcm.c */
EXPORT_SYMBOL(snd_gf1_pcm_new);
  /* gus.c */
EXPORT_SYMBOL(snd_gus_create);
EXPORT_SYMBOL(snd_gus_initialize);
  /* gus_irq.c */
EXPORT_SYMBOL(snd_gus_interrupt);
  /* gus_uart.c */
EXPORT_SYMBOL(snd_gf1_rawmidi_new);
  /* gus_dram.c */
EXPORT_SYMBOL(snd_gus_dram_write);
EXPORT_SYMBOL(snd_gus_dram_read);
  /* gus_volume.c */
EXPORT_SYMBOL(snd_gf1_lvol_to_gvol_raw);
EXPORT_SYMBOL(snd_gf1_translate_freq);
  /* gus_mem.c */
EXPORT_SYMBOL(snd_gf1_mem_alloc);
EXPORT_SYMBOL(snd_gf1_mem_xfree);
EXPORT_SYMBOL(snd_gf1_mem_free);
EXPORT_SYMBOL(snd_gf1_mem_lock);

Messung V0.5
C=95 H=96 G=95

¤ Dauer der Verarbeitung: 0.14 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge