Open Sound System |
Do you have problems with sound/audio application development? Don't panic! Click here for help! |
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_via823x_cfg.h" #include <oss_pci.h> #include <ac97.h> #include "via8233.h" static void feed_sgd (via8233_devc * devc, dmap_t * dmap, engine_desc * eng); static int ac97_read (void *devc_, int wIndex) { oss_native_word flags; unsigned int dwWriteValue = 0, dwTmpValue, i = 0; via8233_devc *devc = devc_; /* Index has only 7 bit */ if (wIndex > 0x7F) return 0; MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags); dwWriteValue = ((unsigned int) wIndex << 16) + CODEC_RD; OUTL (devc->osdev, dwWriteValue, devc->base + AC97CODEC); oss_udelay (100); /* Check AC CODEC access time out */ for (i = 0; i < CODEC_TIMEOUT_COUNT; i++) { /* if send command over, break */ if (INL (devc->osdev, devc->base + AC97CODEC) & STA_VALID) break; oss_udelay (50); } if (i == CODEC_TIMEOUT_COUNT) { MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags); return OSS_EIO; } /* Check if Index still ours? If yes, return data, else return FAIL */ dwTmpValue = INL (devc->osdev, devc->base + AC97CODEC); OUTB (devc->osdev, 0x02, devc->base + AC97CODEC + 3); if (((dwTmpValue & CODEC_INDEX) >> 16) == wIndex) { MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags); return ((int) dwTmpValue & CODEC_DATA); } MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags); return OSS_EIO; } static int ac97_write (void *devc_, int wIndex, int wData) { oss_native_word flags; unsigned int dwWriteValue = 0, i = 0; via8233_devc *devc = devc_; MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags); dwWriteValue = ((unsigned int) wIndex << 16) + wData; OUTL (devc->osdev, dwWriteValue, devc->base + AC97CODEC); oss_udelay (100); /* Check AC CODEC access time out */ for (i = 0; i < CODEC_TIMEOUT_COUNT; i++) { /* if send command over, break */ if (!(INL (devc->osdev, devc->base + AC97CODEC) & IN_CMD)) break; oss_udelay (50); } if (i == CODEC_TIMEOUT_COUNT) { MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags); return 0; } MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags); return 1; } static int via8233intr (oss_device_t * osdev) { int serviced = 0, i; via8233_devc *devc = osdev->devc; via8233_portc *portc; engine_desc *eng; unsigned int engine_stat; unsigned int status = 0; oss_native_word flags; MUTEX_ENTER (devc->mutex, flags); status = INL (devc->osdev, devc->base + 0x84); #if 0 // This is reported to cause hang because some status register bits // may be turned on even ehen the device is not interrupting. if (status == 0) {
No interrupts are pending so we can stop without polling all the individual status registers.
MUTEX_EXIT (devc->mutex, flags); return 0; } #endif for (i = 0; i < MAX_PORTC; i++) { portc = &devc->portc[i]; eng = portc->play_engine; if (eng != NULL) if ((eng->mode & OPEN_WRITE) && (portc->trigger_bits & PCM_ENABLE_OUTPUT)) { engine_stat = INB (devc->osdev, eng->base + 0x00); if (engine_stat & 0x01) { oss_audio_outputintr (portc->audiodev, 1); feed_sgd (devc, audio_engines[portc->audiodev]->dmap_out, eng); serviced = 1; } OUTB (devc->osdev, engine_stat, eng->base + 0x00); } eng = portc->rec_engine; if (eng != NULL) if ((eng->mode & OPEN_READ) && (portc->trigger_bits & PCM_ENABLE_INPUT)) { engine_stat = INB (devc->osdev, eng->base + 0x00); if (engine_stat & 0x01) { oss_audio_inputintr (portc->audiodev, 0); feed_sgd (devc, audio_engines[portc->audiodev]->dmap_in, eng); serviced = 1; } OUTB (devc->osdev, engine_stat, eng->base + 0x00); } } MUTEX_EXIT (devc->mutex, flags); return serviced; }
Audio routines
static int via8233_audio_set_rate (int dev, int arg) { via8233_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 < 5000) arg = 5000; portc->speed = arg; return portc->speed; } static short via8233_audio_set_channels (int dev, short arg) { via8233_portc *portc = audio_engines[dev]->portc; if (arg > 6) arg=6; if ((arg != 1) && (arg != 2) && (arg != 4) && (arg != 6)) return portc->channels; portc->channels = arg; return portc->channels; } static unsigned int via8233_audio_set_format (int dev, unsigned int arg) { via8233_portc *portc = audio_engines[dev]->portc; if (arg == 0) return portc->bits; if (!(arg & (AFMT_U8 | AFMT_S16_LE | AFMT_AC3))) return portc->bits; portc->bits = arg; return portc->bits; } /*ARGSUSED*/ static int via8233_audio_ioctl (int dev, unsigned int cmd, ioctl_arg arg) { return OSS_EINVAL; } static void via8233_audio_trigger (int dev, int state); static void via8233_audio_reset (int dev) { via8233_audio_trigger (dev, 0); } static void via8233_audio_reset_input (int dev) { via8233_portc *portc = audio_engines[dev]->portc; via8233_audio_trigger (dev, portc->trigger_bits & ~PCM_ENABLE_INPUT); } static void via8233_audio_reset_output (int dev) { via8233_portc *portc = audio_engines[dev]->portc; via8233_audio_trigger (dev, portc->trigger_bits & ~PCM_ENABLE_OUTPUT); } /*ARGSUSED*/ static int via8233_audio_open (int dev, int mode, int open_flags) { via8233_portc *portc = audio_engines[dev]->portc; via8233_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 via8233_audio_close (int dev, int mode) { via8233_portc *portc = audio_engines[dev]->portc; via8233_devc *devc = audio_engines[dev]->devc; via8233_audio_reset (dev); portc->open_mode = 0; devc->open_mode &= ~mode; portc->audio_enabled &= ~mode; } /*ARGSUSED*/ static void via8233_audio_output_block (int dev, oss_native_word buf, int count, int fragsize, int intrflag) { via8233_portc *portc = audio_engines[dev]->portc; portc->audio_enabled |= PCM_ENABLE_OUTPUT; portc->trigger_bits &= ~PCM_ENABLE_OUTPUT; } /*ARGSUSED*/ static void via8233_audio_start_input (int dev, oss_native_word buf, int count, int fragsize, int intrflag) { via8233_portc *portc = audio_engines[dev]->portc; portc->audio_enabled |= PCM_ENABLE_INPUT; portc->trigger_bits &= ~PCM_ENABLE_INPUT; } static void via8233_audio_trigger (int dev, int state) { via8233_portc *portc = audio_engines[dev]->portc; via8233_devc *devc = audio_engines[dev]->devc; engine_desc *eng; oss_native_word flags; MUTEX_ENTER_IRQDISABLE (devc->mutex, flags); if ((portc->open_mode & OPEN_WRITE) && portc->play_engine != NULL) { eng = portc->play_engine; if (state & PCM_ENABLE_OUTPUT) { if ((portc->audio_enabled & PCM_ENABLE_OUTPUT) && !(portc->trigger_bits & PCM_ENABLE_OUTPUT)) { /* Start with autoinit and SGD flag interrupts enabled */ OUTB (devc->osdev, 0xa1, eng->base + 0x01); portc->trigger_bits |= PCM_ENABLE_OUTPUT; } } else { if ((portc->audio_enabled & PCM_ENABLE_OUTPUT) && (portc->trigger_bits & PCM_ENABLE_OUTPUT)) { OUTB (devc->osdev, 0x40, eng->base + 0x01); /* Stop */ portc->trigger_bits &= ~PCM_ENABLE_OUTPUT; } } } if ((portc->open_mode & OPEN_READ) && portc->rec_engine != NULL) { eng = portc->rec_engine; if (state & PCM_ENABLE_INPUT) { if ((portc->audio_enabled & PCM_ENABLE_INPUT) && !(portc->trigger_bits & PCM_ENABLE_INPUT)) { /* Start with autoinit and SGD flag interrupts enabled */ OUTB (devc->osdev, 0xa1, eng->base + 0x01); portc->trigger_bits |= PCM_ENABLE_INPUT; } } else { if ((portc->audio_enabled & PCM_ENABLE_INPUT) && (portc->trigger_bits & PCM_ENABLE_INPUT)) { portc->trigger_bits &= ~PCM_ENABLE_INPUT; OUTB (devc->osdev, 0x40, eng->base + 0x01); /* Stop */ } } } MUTEX_EXIT_IRQRESTORE (devc->mutex, flags); } static void feed_sgd (via8233_devc * devc, dmap_t * dmap, engine_desc * eng) { unsigned int addr, p, tmp; oss_native_word flags; MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags); addr = dmap->dmabuf_phys + eng->cfrag * dmap->fragment_size; p = eng->sgd_ptr; eng->sgd[p].phaddr = addr; eng->sgd[p].flags = dmap->fragment_size | SGD_FLAG; if (p == (SGD_SIZE - 1)) eng->sgd[p].flags |= SGD_EOL; /* Update the last entry ptr */ tmp = INL (devc->osdev, eng->base + 0x08); tmp &= 0x00ffffff; tmp |= (p << 24); OUTL (devc->osdev, tmp, eng->base + 0x08); eng->prev_sgd = p; eng->frags[p] = eng->cfrag; eng->cfrag = (eng->cfrag + 1) % dmap->nfrags; eng->sgd_ptr = (eng->sgd_ptr + 1) % SGD_SIZE; MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags); } /*ARGSUSED*/ static int via8233_audio_prepare_for_input (int dev, int bsize, int bcount) { via8233_devc *devc = audio_engines[dev]->devc; via8233_portc *portc = audio_engines[dev]->portc; dmap_t *dmap = audio_engines[dev]->dmap_in; engine_desc *eng; int i; unsigned int fmt; oss_native_word flags; if (portc->rec_engine == NULL) { cmn_err (CE_WARN, "No rec engine (dev=%d)\n", dev); return OSS_EIO; } MUTEX_ENTER_IRQDISABLE (devc->mutex, flags); eng = portc->rec_engine; OUTB (devc->osdev, 0x40, eng->base + 0x01); /* Stop */ eng->cfrag = 0; eng->sgd_ptr = 0; eng->prevpos = 0xffffffff; for (i = 0; i < 2; i++) feed_sgd (devc, dmap, eng); OUTL (devc->osdev, eng->sgd_phys, eng->base + 0x04); fmt = 0; if (portc->bits == AFMT_S16_LE) fmt |= (1 << 21); if (portc->channels == 2) fmt |= (1 << 20); if (devc->chip_type != CHIP_8233A) { if (portc->speed == 48000) fmt |= (1 << 20) - 1; else fmt |= ((1024 * portc->speed + 24000) / 48000) * 1024; } fmt |= (eng->prev_sgd << 24); OUTL (devc->osdev, fmt, eng->base + 0x08); ac97_recrate (&devc->ac97devc, portc->speed); portc->audio_enabled &= ~PCM_ENABLE_INPUT; portc->trigger_bits &= ~PCM_ENABLE_INPUT; MUTEX_EXIT_IRQRESTORE (devc->mutex, flags); return 0; } /*ARGSUSED*/ static int via8233_audio_prepare_for_output (int dev, int bsize, int bcount) { via8233_devc *devc = audio_engines[dev]->devc; via8233_portc *portc = audio_engines[dev]->portc; dmap_p dmap = audio_engines[dev]->dmap_out; engine_desc *eng; int i, tmp; oss_native_word flags; MUTEX_ENTER_IRQDISABLE (devc->mutex, flags); eng = portc->play_engine; OUTB (devc->osdev, 0x40, eng->base + 0x01); /* Stop */ eng->cfrag = 0; eng->sgd_ptr = 0; eng->prevpos = 0xffffffff; for (i = 0; i < 2; i++) feed_sgd (devc, dmap, eng); OUTL (devc->osdev, eng->sgd_phys, eng->base + 0x4); ac97_spdifout_ctl (devc->mixer_dev, SPDIFOUT_AUDIO, SNDCTL_MIX_WRITE, 0); if (portc->bits == AFMT_AC3) { portc->channels = 2; portc->bits = 16; } ac97_spdif_setup (devc->mixer_dev, portc->speed, portc->bits); tmp = (portc->bits == AFMT_U8) ? 0 : 0x80; tmp |= portc->channels << 4; OUTB (devc->osdev, tmp, eng->base + 0x02); /* Select channel assignment - not valid for 8233A */ tmp = 0; if (devc->chip_type != CHIP_8233A) { switch (portc->channels) { case 1: tmp = (1 << 0) | (1 << 4); break; case 2: tmp = (1 << 0) | (2 << 4); break; case 4: tmp = (1 << 0) | (2 << 4) | (3 << 8) | (4 << 12); break; case 6: tmp = (1 << 0) | (2 << 4) | (5 << 8) | (6 << 12) | (3 << 16) | (4 << 20); break; default: tmp = 0; break; } } tmp |= 0xFF000000; OUTL (devc->osdev, tmp, eng->base + 0x08); /* need to set the speed twice - for some odd reason */ ac97_playrate (&devc->ac97devc, portc->speed); ac97_playrate (&devc->ac97devc, portc->speed); portc->audio_enabled &= ~PCM_ENABLE_OUTPUT; portc->trigger_bits &= ~PCM_ENABLE_OUTPUT; MUTEX_EXIT_IRQRESTORE (devc->mutex, flags); return 0; } /*ARGSUSED*/ static int via8233_alloc_buffer (int dev, dmap_t * dmap, int direction) { int err; via8233_devc *devc = audio_engines[dev]->devc; via8233_portc *portc = audio_engines[dev]->portc; engine_desc *eng; if (dmap->dmabuf != NULL) return 0; if ((err = oss_alloc_dmabuf (dev, dmap, direction)) < 0) return err; if (direction == PCM_ENABLE_INPUT) { eng = &devc->engines[REC_SGD_NUM]; eng->mode = OPEN_READ; portc->rec_engine = eng; } else { eng = &devc->engines[PLAY_SGD_NUM]; eng->mode = OPEN_WRITE; portc->play_engine = eng; } return 0; } /*ARGSUSED*/ static int via8233_free_buffer (int dev, dmap_t * dmap, int direction) { via8233_portc *portc = audio_engines[dev]->portc; if (dmap->dmabuf == NULL) return 0; oss_free_dmabuf (dev, dmap); dmap->dmabuf = NULL; dmap->dmabuf_phys = 0; if (direction == PCM_ENABLE_OUTPUT) portc->play_engine = NULL; if (direction == PCM_ENABLE_INPUT) portc->rec_engine = NULL; return 0; } static int via8233_get_buffer_pointer (int dev, dmap_t * dmap, int direction) { via8233_portc *portc = audio_engines[dev]->portc; via8233_devc *devc = audio_engines[dev]->devc; unsigned int ptr, pos, tmp; engine_desc *eng; oss_native_word flags; MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags); if (direction == PCM_ENABLE_OUTPUT) { int status; /* int this_sgd, prev_sgd */ ; if (portc->play_engine == NULL || !(portc->trigger_bits & PCM_ENABLE_OUTPUT)) { MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags); return 0; } eng = portc->play_engine; ptr = INL (devc->osdev, eng->base + 0x0c); status = INB (devc->osdev, eng->base + 0x00); if (!(status & 0x80)) /* SGD not triggered */ { MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags); return 0; } #ifdef DO_TIMINGS oss_timing_printf ("rawpos=%d", ptr); #endif #if 0 this_sgd = ptr >> 24; prev_sgd = eng->prevpos >> 24; prev_sgd = (prev_sgd + 1) % SGD_SIZE; /* Increment */ /* Chip bug catcher */ if (((ptr & 0xffffff) == 0) && ((eng->prevpos & 0xffffff) == 0) && (this_sgd == prev_sgd)) ptr = eng->prevpos; else eng->prevpos = ptr; #endif tmp = ptr & 0xffffff; ptr >>= 24; pos = eng->frags[ptr] * dmap->fragment_size; pos += (dmap->fragment_size - tmp) & ~3; #ifdef DO_TIMINGS oss_timing_printf ("Playpos=%d", pos); #endif pos = pos % dmap->bytes_in_use; MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags); return pos; } if (direction == PCM_ENABLE_INPUT) { int status; /* int this_sgd, prev_sgd; */ if (portc->rec_engine == NULL || !(portc->trigger_bits & PCM_ENABLE_INPUT)) { MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags); return 0; } eng = portc->rec_engine; ptr = INL (devc->osdev, eng->base + 0x0c); status = INB (devc->osdev, eng->base + 0x00); if (!(status & 0x80)) /* SGD not triggered */ { MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags); return 0; } #if 0 this_sgd = ptr >> 24; prev_sgd = eng->prevpos >> 24; prev_sgd = (prev_sgd + 1) % SGD_SIZE; /* Increment */ /* Chip bug catcher */ if (((ptr & 0xffffff) == 0) && ((eng->prevpos & 0xffffff) == 0) && (this_sgd == prev_sgd)) ptr = eng->prevpos; else eng->prevpos = ptr; #endif tmp = ptr & 0xffffff; ptr >>= 24; pos = eng->frags[ptr] * dmap->fragment_size; pos += (dmap->fragment_size - tmp) & ~3; #ifdef DO_TIMINGS oss_timing_printf ("Recpos=%d", pos); #endif pos = pos % dmap->bytes_in_use; MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags); return pos; } MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags); return 0; } static const audiodrv_t via8233_audio_driver = { via8233_audio_open, via8233_audio_close, via8233_audio_output_block, via8233_audio_start_input, via8233_audio_ioctl, via8233_audio_prepare_for_input, via8233_audio_prepare_for_output, via8233_audio_reset, NULL, NULL, via8233_audio_reset_input, via8233_audio_reset_output, via8233_audio_trigger, via8233_audio_set_rate, via8233_audio_set_format, via8233_audio_set_channels, NULL, NULL, NULL, /* via8233_check_input, */ NULL, /* via8233_check_output, */ via8233_alloc_buffer, via8233_free_buffer, NULL, NULL, via8233_get_buffer_pointer }; static int via8233_alloc_engines (via8233_devc * devc) { engine_desc *eng; oss_native_word phaddr; int i; for (i = 0; i < MAX_ENGINES; i++) { if (i) { eng = &devc->engines[REC_SGD_NUM]; eng->base = devc->base + 0x60; } else { eng = &devc->engines[PLAY_SGD_NUM]; eng->base = devc->base + 0x40; } if (eng->sgd == NULL) { eng->sgd = CONTIG_MALLOC (devc->osdev, SGD_ALLOC, MEMLIMIT_32BITS, &phaddr, eng->sgd_dma_handle); if (eng->sgd == NULL) { cmn_err (CE_WARN, "can't allocate SGD table\n"); return OSS_ENOSPC; } eng->sgd_phys = phaddr; } } return 0; } static int via8233_init (via8233_devc * devc) { int my_mixer, adev, opts; via8233_portc *portc; int i; char tmp_name[50]; int first_dev = 0; /* allocate the Scatter Gather Engine buffers */ if (via8233_alloc_engines (devc) < 0) { cmn_err (CE_WARN, "Unable to allocate engines\n"); return OSS_ENOSPC; }
Init mixer
my_mixer = ac97_install (&devc->ac97devc, "VIA823x AC97 Mixer", ac97_read, ac97_write, devc, devc->osdev); if (my_mixer == -1) { cmn_err (CE_WARN, "AC97 mixer installation failed\n"); return 0; /* No mixer */ } devc->mixer_dev = my_mixer; mixer_devs[my_mixer]->priority = 10; /* Known motherboard device */ /* enable S/PDIF */ devc->ac97devc.spdif_slot = SPDIF_SLOT34; ac97_spdifout_ctl (devc->mixer_dev, SPDIFOUT_ENABLE, SNDCTL_MIX_WRITE, 1); for (i = 0; i < MAX_PORTC; i++) { opts = ADEV_AUTOMODE; if (!ac97_varrate (&devc->ac97devc)) { opts |= ADEV_FIXEDRATE; } portc = &devc->portc[i]; if (i == 0) { opts |= ADEV_DUPLEX; strcpy (tmp_name, devc->chip_name); } else { opts |= ADEV_DUPLEX | ADEV_SHADOW; strcpy (tmp_name, devc->chip_name); } if ((adev = oss_install_audiodev (OSS_AUDIO_DRIVER_VERSION, devc->osdev, devc->osdev, tmp_name, &via8233_audio_driver, sizeof (audiodrv_t), opts, AFMT_U8 | AFMT_S16_LE | AFMT_AC3, devc, -1)) < 0) { adev = -1; return 1; } else { if (i == 0) first_dev = adev; audio_engines[adev]->portc = portc; audio_engines[adev]->rate_source = first_dev; audio_engines[adev]->mixer_dev = my_mixer; audio_engines[adev]->min_rate = 8000; audio_engines[adev]->max_rate = 48000; audio_engines[adev]->caps |= PCM_CAP_FREERATE; audio_engines[adev]->min_channels = 2; audio_engines[adev]->max_channels = 6; if (opts & ADEV_FIXEDRATE) { audio_engines[adev]->fixed_rate = 48000; audio_engines[adev]->min_rate = 48000; audio_engines[adev]->max_rate = 48000; } portc->open_mode = 0; portc->audio_enabled = 0; portc->audiodev = adev; #ifdef CONFIG_OSS_VMIX if (i == 0) vmix_attach_audiodev(devc->osdev, adev, -1, 0); #endif } } return 1; } int oss_via823x_attach (oss_device_t * osdev) { unsigned char pci_irq_line, pci_revision, bTmp /*, pci_latency */ ; unsigned short pci_command, vendor, device; unsigned int pci_ioaddr; via8233_devc *devc; pci_read_config_word (osdev, PCI_VENDOR_ID, &vendor); pci_read_config_word (osdev, PCI_DEVICE_ID, &device); DDB (cmn_err (CE_CONT, "oss_via823x_attach(Vendor %x, device %x)\n", vendor, device)); if ((vendor != VIA_VENDOR_ID) || (device != VIA_8233_ID && device != VIA_8233A_ID)) { cmn_err (CE_WARN, "Hardware not recognized (vendor=%x, dev=%x)\n", vendor, device); return 0; } pci_read_config_byte (osdev, PCI_REVISION_ID, &pci_revision); pci_read_config_word (osdev, PCI_COMMAND, &pci_command); pci_read_config_irq (osdev, PCI_INTERRUPT_LINE, &pci_irq_line); pci_read_config_dword (osdev, PCI_BASE_ADDRESS_0, &pci_ioaddr); if (pci_ioaddr == 0) { cmn_err (CE_WARN, "I/O address not assigned by BIOS.\n"); return 0; } if (pci_irq_line == 0) { cmn_err (CE_WARN, "IRQ not assigned by BIOS (%d).\n", pci_irq_line); 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->open_mode = 0; devc->chip_type = CHIP_8233; devc->chip_name = "VIA VT8233"; if (pci_revision == 0x50) devc->chip_name = "VIA VT8235"; if (pci_revision == 0x60) devc->chip_name = "VIA VT8237"; if ((device == VIA_8233A_ID) || (device == VIA_8233_ID && pci_revision == 0x40)) { devc->chip_type = CHIP_8233A; devc->chip_name = "VIA VT8233A"; } pci_write_config_byte (osdev, 0x41, 0xc0); /*ENAC97 & deassert RESET */ oss_udelay (10); pci_read_config_byte (osdev, 0x41, &bTmp); oss_udelay (10); if (devc->chip_type == CHIP_8233A) bTmp |= 0x0C; /* Enable var rate support */ else bTmp |= 0x0f; /* enable VRA,SB,DX */ pci_write_config_byte (osdev, 0x41, bTmp); oss_udelay (10); if (devc->chip_type == CHIP_8233A) { pci_read_config_byte (osdev, 0x49, &bTmp); oss_udelay (10); pci_write_config_byte (osdev, 0x49, 0x0); } else { /* set slot 3,4 as SPDIF on VIA8235 - AC3 passthrough magic! */ pci_write_config_byte (osdev, 0x49, 0x1); } devc->base = MAP_PCI_IOADDR (devc->osdev, 0, pci_ioaddr); /* Remove I/O space marker in bit 0. */ devc->base &= ~0x3; pci_command |= PCI_COMMAND_MASTER | PCI_COMMAND_IO; pci_write_config_word (osdev, PCI_COMMAND, pci_command); devc->irq = pci_irq_line; MUTEX_INIT (devc->osdev, devc->mutex, MH_DRV); MUTEX_INIT (devc->osdev, devc->low_mutex, MH_DRV + 1); oss_register_device (osdev, devc->chip_name); if (oss_register_interrupts (devc->osdev, 0, via8233intr, NULL) < 0) { cmn_err (CE_WARN, "Unable to register interrupts\n"); return 0; } return via8233_init (devc); /* Detected */ } int oss_via823x_detach (oss_device_t * osdev) { via8233_devc *devc = (via8233_devc *) osdev->devc; engine_desc *eng; int i; if (oss_disable_device (devc->osdev) < 0) return 0; /* disable S/PDIF */ if (devc->mixer_dev > 0) ac97_spdifout_ctl (devc->mixer_dev, SPDIFOUT_ENABLE, SNDCTL_MIX_WRITE, 0); oss_unregister_interrupts (devc->osdev); for (i = 0; i < MAX_ENGINES; i++) { eng = &devc->engines[i]; if (eng->sgd != NULL) { CONTIG_FREE (devc->osdev, eng->sgd, SGD_ALLOC, eng->sgd_dma_handle); eng->sgd = NULL; } } MUTEX_CLEANUP (devc->mutex); MUTEX_CLEANUP (devc->low_mutex); UNMAP_PCI_IOADDR (devc->osdev, 0); oss_unregister_device (devc->osdev); return 1; }