Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/netbsd-1-5]: src/sys/dev/pci Pull up revisions 1.1-1.4 (new, via patch, ...
details: https://anonhg.NetBSD.org/src/rev/56f580cfcca7
branches: netbsd-1-5
changeset: 491655:56f580cfcca7
user: he <he%NetBSD.org@localhost>
date: Sun May 06 15:12:08 2001 +0000
description:
Pull up revisions 1.1-1.4 (new, via patch, requested by he):
Add driver for Cirrus Logic CrystalClear PCI Audio CS4281.
diffstat:
sys/dev/pci/cs4281.c | 1262 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 1262 insertions(+), 0 deletions(-)
diffs (truncated from 1266 to 300 lines):
diff -r d8ca58c23d84 -r 56f580cfcca7 sys/dev/pci/cs4281.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/dev/pci/cs4281.c Sun May 06 15:12:08 2001 +0000
@@ -0,0 +1,1262 @@
+/* $NetBSD: cs4281.c,v 1.4.2.2 2001/05/06 15:12:08 he Exp $ */
+
+/*
+ * Copyright (c) 2000 Tatoku Ogaito. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Tatoku Ogaito
+ * for the NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Cirrus Logic CS4281 driver.
+ * Data sheets can be found
+ * http://www.cirrus.com/ftp/pub/4281.pdf
+ * ftp://ftp.alsa-project.org/pub/manuals/cirrus/cs4281tm.pdf
+ *
+ * TODO:
+ * 1: midi and FM support
+ * 2: ...
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/fcntl.h>
+#include <sys/device.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+
+#include <dev/pci/pcidevs.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/cs4281reg.h>
+#include <dev/pci/cs428xreg.h>
+
+#include <sys/audioio.h>
+#include <dev/audio_if.h>
+#include <dev/midi_if.h>
+#include <dev/mulaw.h>
+#include <dev/auconv.h>
+
+#include <dev/ic/ac97reg.h>
+#include <dev/ic/ac97var.h>
+
+#include <dev/pci/cs428x.h>
+
+#include <machine/bus.h>
+
+#if defined(ENABLE_SECONDARY_CODEC)
+#define MAX_CHANNELS (4)
+#define MAX_FIFO_SIZE 32 /* 128/4channels */
+#else
+#define MAX_CHANNELS (2)
+#define MAX_FIFO_SIZE 64 /* 128/2channels */
+#endif
+
+/* IF functions for audio driver */
+int cs4281_match(struct device *, struct cfdata *, void *);
+void cs4281_attach(struct device *, struct device *, void *);
+int cs4281_intr(void *);
+int cs4281_query_encoding(void *, struct audio_encoding *);
+int cs4281_set_params(void *, int, int, struct audio_params *, struct audio_params *);
+int cs4281_halt_output(void *);
+int cs4281_halt_input(void *);
+int cs4281_getdev(void *, struct audio_device *);
+int cs4281_trigger_output(void *, void *, void *, int, void (*)(void *),
+ void *, struct audio_params *);
+int cs4281_trigger_input(void *, void *, void *, int, void (*)(void *),
+ void *, struct audio_params *);
+
+void cs4281_reset_codec(void *);
+
+/* Internal functions */
+u_int8_t cs4281_sr2regval(int);
+void cs4281_set_dac_rate(struct cs428x_softc *, int);
+void cs4281_set_adc_rate(struct cs428x_softc *, int);
+int cs4281_init(struct cs428x_softc *, int);
+
+/* Power Management */
+void cs4281_power(int, void *);
+
+struct audio_hw_if cs4281_hw_if = {
+ cs428x_open,
+ cs428x_close,
+ NULL,
+ cs4281_query_encoding,
+ cs4281_set_params,
+ cs428x_round_blocksize,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ cs4281_halt_output,
+ cs4281_halt_input,
+ NULL,
+ cs4281_getdev,
+ NULL,
+ cs428x_mixer_set_port,
+ cs428x_mixer_get_port,
+ cs428x_query_devinfo,
+ cs428x_malloc,
+ cs428x_free,
+ cs428x_round_buffersize,
+ cs428x_mappage,
+ cs428x_get_props,
+ cs4281_trigger_output,
+ cs4281_trigger_input,
+};
+
+#if NMIDI > 0 && 0
+/* Midi Interface */
+void cs4281_midi_close(void*);
+void cs4281_midi_getinfo(void *, struct midi_info *);
+int cs4281_midi_open(void *, int, void (*)(void *, int),
+ void (*)(void *), void *);
+int cs4281_midi_output(void *, int);
+
+struct midi_hw_if cs4281_midi_hw_if = {
+ cs4281_midi_open,
+ cs4281_midi_close,
+ cs4281_midi_output,
+ cs4281_midi_getinfo,
+ 0,
+};
+#endif
+
+struct cfattach clct_ca = {
+ sizeof(struct cs428x_softc), cs4281_match, cs4281_attach
+};
+
+struct audio_device cs4281_device = {
+ "CS4281",
+ "",
+ "cs4281"
+};
+
+
+int
+cs4281_match(parent, match, aux)
+ struct device *parent;
+ struct cfdata *match;
+ void *aux;
+{
+ struct pci_attach_args *pa = (struct pci_attach_args *)aux;
+
+ if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_CIRRUS)
+ return 0;
+ if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_CIRRUS_CS4281)
+ return 1;
+ return 0;
+}
+
+void
+cs4281_attach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct cs428x_softc *sc = (struct cs428x_softc *)self;
+ struct pci_attach_args *pa = (struct pci_attach_args *)aux;
+ pci_chipset_tag_t pc = pa->pa_pc;
+ char const *intrstr;
+ pci_intr_handle_t ih;
+ pcireg_t reg;
+ char devinfo[256];
+ int pci_pwrmgmt_cap_reg, pci_pwrmgmt_csr_reg;
+
+ pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo);
+ printf(": %s (rev. 0x%02x)\n", devinfo, PCI_REVISION(pa->pa_class));
+
+ /* Map I/O register */
+ if (pci_mapreg_map(pa, PCI_BA0,
+ PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0,
+ &sc->ba0t, &sc->ba0h, NULL, NULL)) {
+ printf("%s: can't map BA0 space\n", sc->sc_dev.dv_xname);
+ return;
+ }
+ if (pci_mapreg_map(pa, PCI_BA1,
+ PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0,
+ &sc->ba1t, &sc->ba1h, NULL, NULL)) {
+ printf("%s: can't map BA1 space\n", sc->sc_dev.dv_xname);
+ return;
+ }
+
+ sc->sc_dmatag = pa->pa_dmat;
+
+ /*
+ * Set Power State D0.
+ * Without do this, 0xffffffff is read from all registers after
+ * using Windows.
+ * On my IBM Thinkpad X20, it is set to D3 after using Windows2000.
+ */
+ if (pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_PWRMGMT,
+ &pci_pwrmgmt_cap_reg, 0)) {
+
+ pci_pwrmgmt_csr_reg = pci_pwrmgmt_cap_reg + 4;
+ reg = pci_conf_read(pa->pa_pc, pa->pa_tag,
+ pci_pwrmgmt_csr_reg);
+ if ((reg & PCI_PMCSR_STATE_MASK) != PCI_PMCSR_STATE_D0) {
+ pci_conf_write(pc, pa->pa_tag, pci_pwrmgmt_csr_reg,
+ (reg & ~PCI_PMCSR_STATE_MASK) |
+ PCI_PMCSR_STATE_D0);
+ }
+ }
+
+ /* Enable the device (set bus master flag) */
+ reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
+ pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
+ reg | PCI_COMMAND_MASTER_ENABLE);
+
+#if 0
+ /* LATENCY_TIMER setting */
+ temp1 = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG);
+ if ( PCI_LATTIMER(temp1) < 32 ) {
+ temp1 &= 0xffff00ff;
+ temp1 |= 0x00002000;
+ pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG, temp1);
+ }
+#endif
+
+ /* Map and establish the interrupt. */
+ if (pci_intr_map(pa, pa->pa_intrtag, pa->pa_intrpin,
+ pa->pa_intrline, &ih)) {
+ printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname);
+ return;
+ }
+ intrstr = pci_intr_string(pc, ih);
+
+ sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, cs4281_intr, sc);
+ if (sc->sc_ih == NULL) {
+ printf("%s: couldn't establish interrupt",sc->sc_dev.dv_xname);
+ if (intrstr != NULL)
+ printf(" at %s", intrstr);
+ printf("\n");
+ return;
+ }
+ printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
+
+ /*
+ * Sound System start-up
+ */
+ if (cs4281_init(sc,1) != 0)
+ return;
+
+ sc->type = TYPE_CS4281;
+ sc->halt_input = cs4281_halt_input;
+ sc->halt_output = cs4281_halt_output;
+
+ sc->dma_size = CS4281_BUFFER_SIZE / MAX_CHANNELS;
+ sc->dma_align = 0x10;
+ sc->hw_blocksize = sc->dma_size / 2;
+
+ /* AC 97 attachment */
+ sc->host_if.arg = sc;
+ sc->host_if.attach = cs428x_attach_codec;
+ sc->host_if.read = cs428x_read_codec;
+ sc->host_if.write = cs428x_write_codec;
+ sc->host_if.reset = cs4281_reset_codec;
+ if (ac97_attach(&sc->host_if) != 0) {
+ printf("%s: ac97_attach failed\n", sc->sc_dev.dv_xname);
+ return;
+ }
+ audio_attach_mi(&cs4281_hw_if, sc, &sc->sc_dev);
+
+#if NMIDI > 0 && 0
+ midi_attach_mi(&cs4281_midi_hw_if, sc, &sc->sc_dev);
+#endif
+
+ sc->sc_suspend = PWR_RESUME;
+ sc->sc_powerhook = powerhook_establish(cs4281_power, sc);
+}
+
Home |
Main Index |
Thread Index |
Old Index