diff --git a/sys/dev/pci/cmpci.c b/sys/dev/pci/cmpci.c index dc2030f1a0cf..83b08c11321e 100644 --- a/sys/dev/pci/cmpci.c +++ b/sys/dev/pci/cmpci.c @@ -1,11 +1,11 @@ -/* $NetBSD: cmpci.c,v 1.6 2001/01/18 20:28:15 jdolecek Exp $ */ +/* $NetBSD: cmpci.c,v 1.7 2001/02/12 18:47:12 tshiozak Exp $ */ /* * Copyright (c) 2000 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation - * by Takuya SHIOZAKI . + * by Takuya SHIOZAKI . * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,18 +34,13 @@ * C-Media CMI8x38 Audio Chip Support. * * TODO: - * - Legacy MPU, OPL and Joystick support (but, I have no interest...) - * - SPDIF support. - * - * ACKNOWLEDGEMENT: - * - Lennart Augustsson : He touched up this code. + * - Legacy MPU, OPL and Joystick support. * */ -#undef CMPCI_SPDIF_SUPPORT /* XXX: not working */ - #if defined(AUDIO_DEBUG) || defined(DEBUG) -#define DPRINTF(x) printf x +#define DPRINTF(x) if (cmpcidebug) printf x +int cmpcidebug = 0; #else #define DPRINTF(x) #endif @@ -77,22 +72,27 @@ * Low-level HW interface */ static __inline uint8_t cmpci_mixerreg_read __P((struct cmpci_softc *, - uint8_t)); + uint8_t)); static __inline void cmpci_mixerreg_write __P((struct cmpci_softc *, - uint8_t, uint8_t)); + uint8_t, uint8_t)); static __inline void cmpci_reg_partial_write_4 __P((struct cmpci_softc *, - int, int, - uint32_t, uint32_t)); + int, int, + uint32_t, uint32_t)); +static __inline void cmpci_reg_set_1 __P((struct cmpci_softc *, + int, uint8_t)); +static __inline void cmpci_reg_clear_1 __P((struct cmpci_softc *, + int, uint8_t)); static __inline void cmpci_reg_set_4 __P((struct cmpci_softc *, - int, uint32_t)); + int, uint32_t)); static __inline void cmpci_reg_clear_4 __P((struct cmpci_softc *, - int, uint32_t)); + int, uint32_t)); static int cmpci_rate_to_index __P((int)); static __inline int cmpci_index_to_rate __P((int)); static __inline int cmpci_index_to_divider __P((int)); static int cmpci_adjust __P((int, int)); static void cmpci_set_mixer_gain __P((struct cmpci_softc *, int)); +static void cmpci_set_out_ports __P((struct cmpci_softc *)); static int cmpci_set_in_ports __P((struct cmpci_softc *, int)); @@ -114,10 +114,10 @@ static int cmpci_intr __P((void *)); * DMA stuffs */ static int cmpci_alloc_dmamem __P((struct cmpci_softc *, - size_t, int, int, caddr_t *)); + size_t, int, int, caddr_t *)); static int cmpci_free_dmamem __P((struct cmpci_softc *, caddr_t, int)); static struct cmpci_dmanode * cmpci_find_dmamem __P((struct cmpci_softc *, - caddr_t)); + caddr_t)); /* @@ -127,8 +127,8 @@ static int cmpci_open __P((void *, int)); static void cmpci_close __P((void *)); static int cmpci_query_encoding __P((void *, struct audio_encoding *)); static int cmpci_set_params __P((void *, int, int, - struct audio_params *, - struct audio_params *)); + struct audio_params *, + struct audio_params *)); static int cmpci_round_blocksize __P((void *, int)); static int cmpci_halt_output __P((void *)); static int cmpci_halt_input __P((void *)); @@ -142,11 +142,11 @@ static size_t cmpci_round_buffersize __P((void *, int, size_t)); static paddr_t cmpci_mappage __P((void *, void *, off_t, int)); static int cmpci_get_props __P((void *)); static int cmpci_trigger_output __P((void *, void *, void *, int, - void (*)(void *), void *, - struct audio_params *)); + void (*)(void *), void *, + struct audio_params *)); static int cmpci_trigger_input __P((void *, void *, void *, int, - void (*)(void *), void *, - struct audio_params *)); + void (*)(void *), void *, + struct audio_params *)); static struct audio_hw_if cmpci_hw_if = { cmpci_open, /* open */ @@ -223,6 +223,29 @@ cmpci_reg_partial_write_4(sc, no, shift, mask, val) } /* register set/clear bit */ +static __inline void +cmpci_reg_set_1(sc, no, mask) + struct cmpci_softc *sc; + int no; + uint8_t mask; +{ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, no, + (bus_space_read_1(sc->sc_iot, sc->sc_ioh, no) | mask)); + delay(10); +} + +static __inline void +cmpci_reg_clear_1(sc, no, mask) + struct cmpci_softc *sc; + int no; + uint8_t mask; +{ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, no, + (bus_space_read_1(sc->sc_iot, sc->sc_ioh, no) & ~mask)); + delay(10); +} + + static __inline void cmpci_reg_set_4(sc, no, mask) struct cmpci_softc *sc; @@ -230,7 +253,7 @@ cmpci_reg_set_4(sc, no, mask) uint32_t mask; { bus_space_write_4(sc->sc_iot, sc->sc_ioh, no, - (bus_space_read_4(sc->sc_iot, sc->sc_ioh, no) | mask)); + (bus_space_read_4(sc->sc_iot, sc->sc_ioh, no) | mask)); delay(10); } @@ -241,7 +264,7 @@ cmpci_reg_clear_4(sc, no, mask) uint32_t mask; { bus_space_write_4(sc->sc_iot, sc->sc_ioh, no, - (bus_space_read_4(sc->sc_iot, sc->sc_ioh, no) & ~mask)); + (bus_space_read_4(sc->sc_iot, sc->sc_ioh, no) & ~mask)); delay(10); } @@ -260,7 +283,7 @@ static const struct { _RATE(32000), _RATE(44100), _RATE(48000) -#undef _RATE +#undef _RATE }; static int @@ -306,7 +329,8 @@ cmpci_match(parent, match, aux) if ( PCI_VENDOR(pa->pa_id) == PCI_VENDOR_CMEDIA && (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_CMEDIA_CMI8338A || PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_CMEDIA_CMI8338B || - PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_CMEDIA_CMI8738) ) + PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_CMEDIA_CMI8738 || + PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_CMEDIA_CMI8738B) ) return 1; return 0; @@ -321,25 +345,29 @@ cmpci_attach(parent, self, aux) struct pci_attach_args *pa = (struct pci_attach_args *)aux; pci_intr_handle_t ih; char const *strintr; + char devinfo[256]; int i, v; - sc->sc_revision = PCI_REVISION(pa->pa_class); - sc->sc_model = PCI_PRODUCT(pa->pa_id); - switch (sc->sc_model) { + sc->sc_id = pa->pa_id; + sc->sc_class = pa->pa_class; + pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo); + printf(": %s (rev. 0x%02x)\n", devinfo, PCI_REVISION(sc->sc_class)); + switch (PCI_PRODUCT(sc->sc_id)) { case PCI_PRODUCT_CMEDIA_CMI8338A: - printf(": CMI8338A PCI Audio Device\n"); - break; + /*FALLTHROUGH*/ case PCI_PRODUCT_CMEDIA_CMI8338B: - printf(": CMI8338B PCI Audio Device\n"); + sc->sc_capable = CMPCI_CAP_CMI8338; break; case PCI_PRODUCT_CMEDIA_CMI8738: - printf(": CMI8738 PCI Audio Device\n"); + /*FALLTHROUGH*/ + case PCI_PRODUCT_CMEDIA_CMI8738B: + sc->sc_capable = CMPCI_CAP_CMI8738; break; } /* map I/O space */ if (pci_mapreg_map(pa, CMPCI_PCI_IOBASEREG, PCI_MAPREG_TYPE_IO, 0, - &sc->sc_iot, &sc->sc_ioh, NULL, NULL)) { + &sc->sc_iot, &sc->sc_ioh, NULL, NULL)) { printf("%s: failed to map I/O space\n", sc->sc_dev.dv_xname); return; } @@ -388,17 +416,25 @@ cmpci_attach(parent, self, aux) case CMPCI_MIC_SWAP: case CMPCI_LINE_SWAP: case CMPCI_FM_SWAP: + case CMPCI_SPDIF_LOOP: + case CMPCI_SPDIF_OUT_VOLTAGE: + case CMPCI_SPDIF_IN_PHASE: + case CMPCI_REAR: + case CMPCI_INDIVIDUAL: + case CMPCI_REVERSE: + case CMPCI_SURROUND: v = 0; break; case CMPCI_CD_OUT_MUTE: case CMPCI_MIC_OUT_MUTE: case CMPCI_LINE_OUT_MUTE: + case CMPCI_SPDIF_IN_MUTE: v = 1; break; default: v = CMPCI_ADJUST_GAIN(sc, AUDIO_MAX_GAIN / 2); } - sc->gain[i][CMPCI_LEFT] = sc->gain[i][CMPCI_RIGHT] = v; + sc->sc_gain[i][CMPCI_LEFT] = sc->sc_gain[i][CMPCI_RIGHT] = v; cmpci_set_mixer_gain(sc, i); } } @@ -453,10 +489,6 @@ cmpci_open(handle, flags) void *handle; int flags; { -#if 0 - struct cmpci_softc *sc = handle; -#endif - return 0; } @@ -471,10 +503,6 @@ cmpci_query_encoding(handle, fp) void *handle; struct audio_encoding *fp; { -#if 0 - struct cmpci_softc *sc = handle; -#endif - switch (fp->index) { case 0: strcpy(fp->name, AudioEulinear); @@ -647,9 +675,11 @@ cmpci_set_params(handle, setmode, usemode, play, rec) case 16: md_format |= CMPCI_REG_FORMAT_16BIT; if (mode & AUMODE_PLAY) - p->sw_code =swap_bytes_change_sign16_le; + p->sw_code = + swap_bytes_change_sign16_le; else - p->sw_code =change_sign16_swap_bytes_le; + p->sw_code = + change_sign16_swap_bytes_le; break; default: return (EINVAL); @@ -660,68 +690,32 @@ cmpci_set_params(handle, setmode, usemode, play, rec) } if (mode & AUMODE_PLAY) cmpci_reg_partial_write_4(sc, - CMPCI_REG_CHANNEL_FORMAT, CMPCI_REG_CH0_FORMAT_SHIFT, - CMPCI_REG_CH0_FORMAT_MASK, md_format); + CMPCI_REG_CHANNEL_FORMAT, + CMPCI_REG_CH0_FORMAT_SHIFT, + CMPCI_REG_CH0_FORMAT_MASK, md_format); else cmpci_reg_partial_write_4(sc, - CMPCI_REG_CHANNEL_FORMAT, CMPCI_REG_CH1_FORMAT_SHIFT, + CMPCI_REG_CHANNEL_FORMAT, + CMPCI_REG_CH1_FORMAT_SHIFT, CMPCI_REG_CH1_FORMAT_MASK, md_format); /* sample rate */ md_index = cmpci_rate_to_index(p->sample_rate); md_divide = cmpci_index_to_divider(md_index); p->sample_rate = cmpci_index_to_rate(md_index); -#if 0 DPRINTF(("%s: sample:%d, divider=%d\n", sc->sc_dev.dv_xname, (int)p->sample_rate, md_divide)); -#endif if (mode & AUMODE_PLAY) { cmpci_reg_partial_write_4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_DAC_FS_SHIFT, CMPCI_REG_DAC_FS_MASK, md_divide); -#ifdef CMPCI_SPDIF_SUPPORT - switch (md_divide) { - case CMPCI_REG_RATE_44100: - cmpci_reg_clear_4(sc, CMPCI_REG_MISC, - CMPCI_REG_SPDIF_48K); - cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_1, - CMPCI_REG_SPDIF_LOOP); - cmpci_reg_set_4(sc, CMPCI_REG_FUNC_1, - CMPCI_REG_SPDIF0_ENABLE); - break; - case CMPCI_REG_RATE_48000: - cmpci_reg_set_4(sc, CMPCI_REG_MISC, - CMPCI_REG_SPDIF_48K); - cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_1, - CMPCI_REG_SPDIF_LOOP); - cmpci_reg_set_4(sc, CMPCI_REG_FUNC_1, - CMPCI_REG_SPDIF0_ENABLE); - break; - default: - cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_1, - CMPCI_REG_SPDIF0_ENABLE); - cmpci_reg_set_4(sc, CMPCI_REG_FUNC_1, - CMPCI_REG_SPDIF_LOOP); - } -#endif + sc->sc_play.md_divide = md_divide; } else { cmpci_reg_partial_write_4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_ADC_FS_SHIFT, CMPCI_REG_ADC_FS_MASK, md_divide); -#ifdef CMPCI_SPDIF_SUPPORT - if (sc->in_mask & CMPCI_SPDIF_IN) { - switch (md_divide) { - case CMPCI_REG_RATE_44100: - cmpci_reg_set_4(sc, CMPCI_REG_FUNC_1, - CMPCI_REG_SPDIF1_ENABLE); - break; - default: - return EINVAL; - } - } else - cmpci_reg_clear_4(sc, - CMPCI_REG_FUNC_1, CMPCI_REG_SPDIF1_ENABLE); -#endif + sc->sc_rec.md_divide = md_divide; } + cmpci_set_mixer_gain(sc, CMPCI_SPDIF_LOOP); } return 0; } @@ -779,14 +773,15 @@ cmpci_halt_input(handle) /* get audio device information */ static int cmpci_getdev(handle, ad) - void *handle; - struct audio_device *ad; + void *handle; + struct audio_device *ad; { struct cmpci_softc *sc = handle; strncpy(ad->name, "CMI PCI Audio", sizeof(ad->name)); - snprintf(ad->version, sizeof(ad->version), "0x%02x", sc->sc_revision); - switch (sc->sc_model) { + snprintf(ad->version, sizeof(ad->version), "0x%02x", + PCI_REVISION(sc->sc_class)); + switch (PCI_PRODUCT(sc->sc_id)) { case PCI_PRODUCT_CMEDIA_CMI8338A: strncpy(ad->config, "CMI8338A", sizeof(ad->config)); break; @@ -796,6 +791,9 @@ cmpci_getdev(handle, ad) case PCI_PRODUCT_CMEDIA_CMI8738: strncpy(ad->config, "CMI8738", sizeof(ad->config)); break; + case PCI_PRODUCT_CMEDIA_CMI8738B: + strncpy(ad->config, "CMI8738B", sizeof(ad->config)); + break; default: strncpy(ad->config, "unknown", sizeof(ad->config)); } @@ -810,10 +808,6 @@ cmpci_query_devinfo(handle, dip) void *handle; mixer_devinfo_t *dip; { -#if 0 - struct cmpci_softc *sc = handle; -#endif - switch (dip->index) { case CMPCI_MASTER_VOL: dip->type = AUDIO_MIXER_VALUE; @@ -879,11 +873,7 @@ cmpci_query_devinfo(handle, dip) dip->prev = dip->next = AUDIO_MIXER_LAST; strcpy(dip->label.name, AudioNsource); dip->type = AUDIO_MIXER_SET; -#ifdef CMPCI_SPDIF_SUPPORT dip->un.s.num_mem = 5; -#else - dip->un.s.num_mem = 4; -#endif strcpy(dip->un.s.member[0].label.name, AudioNmicrophone); dip->un.s.member[0].mask = 1 << CMPCI_MIC_VOL; strcpy(dip->un.s.member[1].label.name, AudioNcd); @@ -892,10 +882,8 @@ cmpci_query_devinfo(handle, dip) dip->un.s.member[2].mask = 1 << CMPCI_LINE_IN_VOL; strcpy(dip->un.s.member[3].label.name, AudioNfmsynth); dip->un.s.member[3].mask = 1 << CMPCI_FM_VOL; -#ifdef CMPCI_SPDIF_SUPPORT strcpy(dip->un.s.member[4].label.name, CmpciNspdif); - dip->un.s.member[4].mask = 1 << CMPCI_SPDIF_IN; -#endif + dip->un.s.member[4].mask = 1 << CMPCI_SPDIF_CLASS; return 0; case CMPCI_BASS: dip->prev = dip->next = AUDIO_MIXER_LAST; @@ -954,19 +942,81 @@ cmpci_query_devinfo(handle, dip) dip->mixer_class = CMPCI_INPUT_CLASS; dip->prev = dip->next = AUDIO_MIXER_LAST; strcpy(dip->label.name, "agc"); - dip->un.e.num_mem = 2; - strcpy(dip->un.e.member[0].label.name, AudioNoff); - dip->un.e.member[0].ord = 0; - strcpy(dip->un.e.member[1].label.name, AudioNon); - dip->un.e.member[1].ord = 1; - return 0; + goto on_off; case CMPCI_EQUALIZATION_CLASS: dip->type = AUDIO_MIXER_CLASS; dip->mixer_class = CMPCI_EQUALIZATION_CLASS; dip->next = dip->prev = AUDIO_MIXER_LAST; strcpy(dip->label.name, AudioCequalization); return 0; - + case CMPCI_SPDIF_IN_MUTE: + dip->type = AUDIO_MIXER_CLASS; + dip->mixer_class = CMPCI_INPUT_CLASS; + dip->next = dip->prev = AUDIO_MIXER_LAST; + strcpy(dip->label.name, CmpciNspdif); + return 0; + case CMPCI_SPDIF_CLASS: + dip->type = AUDIO_MIXER_CLASS; + dip->mixer_class = CMPCI_SPDIF_CLASS; + dip->next = dip->prev = AUDIO_MIXER_LAST; + strcpy(dip->label.name, CmpciCspdif); + return 0; + case CMPCI_SPDIF_LOOP: + dip->mixer_class = CMPCI_SPDIF_CLASS; + dip->prev = dip->next = AUDIO_MIXER_LAST; + strcpy(dip->label.name, CmpciNloop); + goto on_off; + case CMPCI_SPDIF_LEGACY: + dip->mixer_class = CMPCI_SPDIF_CLASS; + dip->prev = dip->next = AUDIO_MIXER_LAST; + strcpy(dip->label.name, CmpciNlegacy); + goto on_off; + case CMPCI_SPDIF_OUT_VOLTAGE: + dip->mixer_class = CMPCI_SPDIF_CLASS; + dip->prev = dip->next = AUDIO_MIXER_LAST; + strcpy(dip->label.name, CmpciNout_voltage); + dip->type = AUDIO_MIXER_ENUM; + dip->un.e.num_mem = 2; + strcpy(dip->un.e.member[0].label.name, CmpciNlow_v); + dip->un.e.member[0].ord = 0; + strcpy(dip->un.e.member[1].label.name, CmpciNhigh_v); + dip->un.e.member[1].ord = 1; + return 0; + case CMPCI_SPDIF_IN_PHASE: + dip->mixer_class = CMPCI_SPDIF_CLASS; + dip->prev = dip->next = AUDIO_MIXER_LAST; + strcpy(dip->label.name, CmpciNin_phase); + goto on_off; + case CMPCI_REAR: + dip->mixer_class = CMPCI_OUTPUT_CLASS; + dip->prev = AUDIO_MIXER_LAST; + dip->next = CMPCI_INDIVIDUAL; + strcpy(dip->label.name, CmpciNrear); + goto on_off; + case CMPCI_INDIVIDUAL: + dip->mixer_class = CMPCI_OUTPUT_CLASS; + dip->prev = CMPCI_REAR; + dip->next = CMPCI_REVERSE; + strcpy(dip->label.name, CmpciNindividual); + goto on_off; + case CMPCI_REVERSE: + dip->mixer_class = CMPCI_OUTPUT_CLASS; + dip->prev = CMPCI_INDIVIDUAL; + dip->next = AUDIO_MIXER_LAST; + strcpy(dip->label.name, CmpciNreverse); + dip->type = AUDIO_MIXER_ENUM; + dip->un.e.num_mem = 2; + strcpy(dip->un.e.member[0].label.name, CmpciNpositive); + dip->un.e.member[0].ord = 0; + strcpy(dip->un.e.member[1].label.name, CmpciNnegative); + dip->un.e.member[1].ord = 1; + return 0; + case CMPCI_SURROUND: + dip->mixer_class = CMPCI_OUTPUT_CLASS; + dip->prev = dip->next = AUDIO_MIXER_LAST; + strcpy(dip->label.name, CmpciNsurround); + goto on_off; + case CMPCI_CD_IN_MUTE: dip->prev = CMPCI_CD_VOL; dip->next = CMPCI_CD_SWAP; @@ -1005,7 +1055,7 @@ cmpci_query_devinfo(handle, dip) swap: dip->mixer_class = CMPCI_INPUT_CLASS; strcpy(dip->label.name, AudioNswap); - goto mute1; + goto on_off; case CMPCI_CD_OUT_MUTE: dip->prev = CMPCI_CD_SWAP; @@ -1023,7 +1073,7 @@ cmpci_query_devinfo(handle, dip) dip->mixer_class = CMPCI_OUTPUT_CLASS; mute: strcpy(dip->label.name, AudioNmute); - mute1: + on_off: dip->type = AUDIO_MIXER_ENUM; dip->un.e.num_mem = 2; strcpy(dip->un.e.member[0].label.name, AudioNoff); @@ -1060,7 +1110,7 @@ cmpci_alloc_dmamem(sc, size, type, flags, r_addr) n->cd_size = size; error = bus_dmamem_alloc(n->cd_tag, n->cd_size, CMPCI_DMABUF_ALIGN, CMPCI_DMABUF_BOUNDARY, n->cd_segs, - sizeof(n->cd_segs)/sizeof(n->cd_segs[0]), &n->cd_nsegs, w); + sizeof(n->cd_segs)/sizeof(n->cd_segs[0]), &n->cd_nsegs, w); if (error) goto mfree; error = bus_dmamem_map(n->cd_tag, n->cd_segs, n->cd_nsegs, n->cd_size, @@ -1161,9 +1211,9 @@ cmpci_allocm(handle, direction, size, type, flags) static void cmpci_freem(handle, addr, type) - void *handle; - void *addr; - int type; + void *handle; + void *addr; + int type; { struct cmpci_softc *sc = handle; @@ -1222,14 +1272,150 @@ cmpci_set_mixer_gain(sc, port) break; case CMPCI_PCSPEAKER: cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_SPEAKER, - sc->gain[port][CMPCI_LEFT]); + sc->sc_gain[port][CMPCI_LEFT]); + return; + case CMPCI_SPDIF_IN_MUTE: + if (CMPCI_ISCAP(sc, SPDIN_MONITOR)) { + if (sc->sc_gain[CMPCI_SPDIF_IN_MUTE][CMPCI_LR]) + cmpci_reg_set_4(sc, CMPCI_REG_MIXER24, + CMPCI_REG_SPDIN_MONITOR); + else + cmpci_reg_set_4(sc, CMPCI_REG_MIXER24, + CMPCI_REG_SPDIN_MONITOR); + } + + case CMPCI_SPDIF_LOOP: + /*FALLTHROUGH*/ + case CMPCI_SPDIF_LEGACY: + cmpci_set_out_ports(sc); + return; + case CMPCI_SPDIF_OUT_VOLTAGE: + if (CMPCI_ISCAP(sc, SPDOUT_VOLTAGE)) { + if (sc->sc_gain[CMPCI_SPDIF_OUT_VOLTAGE][CMPCI_LR]) + cmpci_reg_set_4(sc, CMPCI_REG_MISC, + CMPCI_REG_5V); + else + cmpci_reg_clear_4(sc, CMPCI_REG_MISC, + CMPCI_REG_5V); + } + return; + case CMPCI_SURROUND: + if (CMPCI_ISCAP(sc, SURROUND)) { + if (sc->sc_gain[CMPCI_SURROUND][CMPCI_LR]) + cmpci_reg_set_1(sc, CMPCI_REG_MIXER24, + CMPCI_REG_SURROUND); + else + cmpci_reg_clear_1(sc, CMPCI_REG_MIXER24, + CMPCI_REG_SURROUND); + } + return; + case CMPCI_REAR: + if (CMPCI_ISCAP(sc, REAR)) { + if (sc->sc_gain[CMPCI_REAR][CMPCI_LR]) + cmpci_reg_set_4(sc, CMPCI_REG_MISC, + CMPCI_REG_N4SPK3D); + else + cmpci_reg_clear_4(sc, CMPCI_REG_MISC, + CMPCI_REG_N4SPK3D); + } + return; + case CMPCI_INDIVIDUAL: + if (CMPCI_ISCAP(sc, INDIVIDUAL_REAR)) { + if (sc->sc_gain[CMPCI_REAR][CMPCI_LR]) + cmpci_reg_set_1(sc, CMPCI_REG_MIXER24, + CMPCI_REG_INDIVIDUAL); + else + cmpci_reg_clear_1(sc, CMPCI_REG_MIXER24, + CMPCI_REG_INDIVIDUAL); + } + return; + case CMPCI_REVERSE: + if (CMPCI_ISCAP(sc, REVERSE_FR)) { + if (sc->sc_gain[CMPCI_REVERSE][CMPCI_LR]) + cmpci_reg_set_1(sc, CMPCI_REG_MIXER24, + CMPCI_REG_REVERSE_FR); + else + cmpci_reg_clear_1(sc, CMPCI_REG_MIXER24, + CMPCI_REG_REVERSE_FR); + } + return; + case CMPCI_SPDIF_IN_PHASE: + if (CMPCI_ISCAP(sc, SPDIN_PHASE)) { + if (sc->sc_gain[CMPCI_SPDIF_IN_PHASE][CMPCI_LR]) + cmpci_reg_set_1(sc, CMPCI_REG_MIXER27, + CMPCI_REG_PHASE); + else + cmpci_reg_clear_1(sc, CMPCI_REG_MIXER27, + CMPCI_REG_PHASE); + } return; default: return; } - cmpci_mixerreg_write(sc, src, sc->gain[port][CMPCI_LEFT]); + cmpci_mixerreg_write(sc, src, sc->sc_gain[port][CMPCI_LEFT]); cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_L_TO_R(src), - sc->gain[port][CMPCI_RIGHT]); + sc->sc_gain[port][CMPCI_RIGHT]); +} + +static void +cmpci_set_out_ports(sc) + struct cmpci_softc *sc; +{ + if (!CMPCI_ISCAP(sc, SPDLOOP)) + return; + if (sc->sc_gain[CMPCI_SPDIF_LOOP][CMPCI_LR]) { + /* loop on */ + cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_1, + CMPCI_REG_SPDIF0_ENABLE | + CMPCI_REG_SPDIF1_ENABLE); + cmpci_reg_clear_4(sc, CMPCI_REG_LEGACY_CTRL, + CMPCI_REG_LEGACY_SPDIF_ENABLE); + cmpci_reg_set_4(sc, CMPCI_REG_FUNC_1, + CMPCI_REG_SPDIF_LOOP); + } else { + /* loop off */ + cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_1, + CMPCI_REG_SPDIF_LOOP); + cmpci_set_in_ports(sc, sc->sc_in_mask); + if (CMPCI_ISCAP(sc, SPDOUT) && + (sc->sc_play.md_divide==CMPCI_REG_RATE_44100 || + (CMPCI_ISCAP(sc, SPDOUT_48K) && + sc->sc_play.md_divide==CMPCI_REG_RATE_48000))) { + cmpci_reg_set_4(sc, CMPCI_REG_FUNC_1, + CMPCI_REG_SPDIF0_ENABLE); + if (CMPCI_ISCAP(sc, XSPDOUT)) + cmpci_reg_set_4(sc, + CMPCI_REG_LEGACY_CTRL, + CMPCI_REG_XSPDIF_ENABLE); + if (sc->sc_play.md_divide==CMPCI_REG_RATE_48000) + cmpci_reg_set_4(sc, + CMPCI_REG_MISC, + CMPCI_REG_SPDIF_48K); + else + cmpci_reg_clear_4(sc, + CMPCI_REG_MISC, + CMPCI_REG_SPDIF_48K); + } else { + cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_1, + CMPCI_REG_SPDIF0_ENABLE); + if (CMPCI_ISCAP(sc, XSPDOUT)) + cmpci_reg_clear_4(sc, + CMPCI_REG_LEGACY_CTRL, + CMPCI_REG_XSPDIF_ENABLE); + if (CMPCI_ISCAP(sc, SPDOUT_48K)) + cmpci_reg_clear_4(sc, + CMPCI_REG_MISC, + CMPCI_REG_SPDIF_48K); + } + if (CMPCI_ISCAP(sc, SPDLEGACY)) { + if (sc->sc_gain[CMPCI_SPDIF_LEGACY][CMPCI_LR]) + cmpci_reg_set_4(sc, CMPCI_REG_LEGACY_CTRL, + CMPCI_REG_LEGACY_SPDIF_ENABLE); + else + cmpci_reg_clear_4(sc, CMPCI_REG_LEGACY_CTRL, + CMPCI_REG_LEGACY_SPDIF_ENABLE); + } + } } static int @@ -1240,16 +1426,13 @@ cmpci_set_in_ports(sc, mask) int bitsl, bitsr; if (mask & ~((1<sc_rec.md_divide == CMPCI_REG_RATE_44100 && + !sc->sc_gain[CMPCI_SPDIF_LOOP][CMPCI_LR]) { + if (mask & (1<in_mask = mask; + sc->sc_in_mask = mask; return 0; } @@ -1294,8 +1491,8 @@ cmpci_set_port(handle, cp) return EINVAL; lgain = rgain = - CMPCI_ADJUST_MIC_GAIN(sc, - cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]); + CMPCI_ADJUST_MIC_GAIN(sc, + cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]); break; case CMPCI_PCSPEAKER: if (cp->un.value.num_channels != 1) @@ -1310,21 +1507,24 @@ cmpci_set_port(handle, cp) switch (cp->un.value.num_channels) { case 1: lgain = rgain = CMPCI_ADJUST_GAIN(sc, - cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]); + cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] + ); break; case 2: lgain = CMPCI_ADJUST_GAIN(sc, - cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]); + cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] + ); rgain = CMPCI_ADJUST_GAIN(sc, - cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]); + cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] + ); break; default: return EINVAL; } break; } - sc->gain[cp->dev][CMPCI_LEFT] = lgain; - sc->gain[cp->dev][CMPCI_RIGHT] = rgain; + sc->sc_gain[cp->dev][CMPCI_LEFT] = lgain; + sc->sc_gain[cp->dev][CMPCI_RIGHT] = rgain; cmpci_set_mixer_gain(sc, cp->dev); break; @@ -1354,7 +1554,7 @@ cmpci_set_port(handle, cp) if (cp->type != AUDIO_MIXER_ENUM) return EINVAL; bits = cmpci_mixerreg_read(sc, CMPCI_SB16_MIXER_OUTMIX); - sc->gain[cp->dev][CMPCI_LR] = cp->un.ord != 0; + sc->sc_gain[cp->dev][CMPCI_LR] = cp->un.ord != 0; if (cp->un.ord) bits = bits & ~mask; else @@ -1388,7 +1588,7 @@ cmpci_set_port(handle, cp) & ~mask; rbits = cmpci_mixerreg_read(sc, CMPCI_SB16_MIXER_ADCMIX_R) & ~mask; - sc->gain[cp->dev][CMPCI_LR] = cp->un.ord != 0; + sc->sc_gain[cp->dev][CMPCI_LR] = cp->un.ord != 0; if (CMPCI_IS_IN_MUTE(cp->dev)) { mute = cp->dev; swap = mute - CMPCI_CD_IN_MUTE + CMPCI_CD_SWAP; @@ -1396,18 +1596,27 @@ cmpci_set_port(handle, cp) swap = cp->dev; mute = swap + CMPCI_CD_IN_MUTE - CMPCI_CD_SWAP; } - if (sc->gain[swap][CMPCI_LR]) { + if (sc->sc_gain[swap][CMPCI_LR]) { mask = lmask; lmask = rmask; rmask = mask; } - if (!sc->gain[mute][CMPCI_LR]) { + if (!sc->sc_gain[mute][CMPCI_LR]) { lbits = lbits | lmask; rbits = rbits | rmask; } cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_ADCMIX_L, lbits); cmpci_mixerreg_write(sc, CMPCI_SB16_MIXER_ADCMIX_R, rbits); break; + case CMPCI_SPDIF_LOOP: + case CMPCI_SPDIF_OUT_VOLTAGE: + case CMPCI_SPDIF_IN_PHASE: + case CMPCI_REAR: + case CMPCI_INDIVIDUAL: + case CMPCI_REVERSE: + case CMPCI_SURROUND: + sc->sc_gain[cp->dev][CMPCI_LR] = cp->un.ord; + break; default: return EINVAL; @@ -1441,13 +1650,13 @@ cmpci_get_port(handle, cp) switch (cp->un.value.num_channels) { case 1: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = - sc->gain[cp->dev][CMPCI_LEFT]; + sc->sc_gain[cp->dev][CMPCI_LEFT]; break; case 2: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = - sc->gain[cp->dev][CMPCI_LEFT]; + sc->sc_gain[cp->dev][CMPCI_LEFT]; cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = - sc->gain[cp->dev][CMPCI_RIGHT]; + sc->sc_gain[cp->dev][CMPCI_RIGHT]; break; default: return EINVAL; @@ -1455,7 +1664,7 @@ cmpci_get_port(handle, cp) break; case CMPCI_RECORD_SOURCE: - cp->un.mask = sc->in_mask; + cp->un.mask = sc->sc_in_mask; break; case CMPCI_AGC: @@ -1473,7 +1682,16 @@ cmpci_get_port(handle, cp) case CMPCI_CD_OUT_MUTE: case CMPCI_MIC_OUT_MUTE: case CMPCI_LINE_OUT_MUTE: - cp->un.ord = sc->gain[cp->dev][CMPCI_LR]; + case CMPCI_SPDIF_IN_MUTE: + case CMPCI_SPDIF_LOOP: + case CMPCI_SPDIF_LEGACY: + case CMPCI_SPDIF_OUT_VOLTAGE: + case CMPCI_SPDIF_IN_PHASE: + case CMPCI_REAR: + case CMPCI_INDIVIDUAL: + case CMPCI_REVERSE: + case CMPCI_SURROUND: + cp->un.ord = sc->sc_gain[cp->dev][CMPCI_LR]; break; default: @@ -1511,8 +1729,8 @@ cmpci_mappage(handle, addr, offset, prot) return -1; return bus_dmamem_mmap(p->cd_tag, p->cd_segs, - sizeof(p->cd_segs)/sizeof(p->cd_segs[0]), - offset, prot, BUS_DMA_WAITOK); + sizeof(p->cd_segs)/sizeof(p->cd_segs[0]), + offset, prot, BUS_DMA_WAITOK); } @@ -1527,12 +1745,12 @@ cmpci_get_props(handle) static int cmpci_trigger_output(handle, start, end, blksize, intr, arg, param) - void *handle; - void *start, *end; - int blksize; - void (*intr) __P((void *)); - void *arg; - struct audio_params *param; + void *handle; + void *start, *end; + int blksize; + void (*intr) __P((void *)); + void *arg; + struct audio_params *param; { struct cmpci_softc *sc = handle; struct cmpci_dmanode *p; @@ -1551,7 +1769,7 @@ cmpci_trigger_output(handle, start, end, blksize, intr, arg, param) DMAADDR(p)); delay(10); bus_space_write_2(sc->sc_iot, sc->sc_ioh, CMPCI_REG_DMA0_BYTES, - ((caddr_t)end - (caddr_t)start + 1) / bps - 1); + ((caddr_t)end - (caddr_t)start + 1) / bps - 1); delay(10); /* set interrupt count */ @@ -1569,12 +1787,12 @@ cmpci_trigger_output(handle, start, end, blksize, intr, arg, param) static int cmpci_trigger_input(handle, start, end, blksize, intr, arg, param) - void *handle; - void *start, *end; - int blksize; - void (*intr) __P((void *)); - void *arg; - struct audio_params *param; + void *handle; + void *start, *end; + int blksize; + void (*intr) __P((void *)); + void *arg; + struct audio_params *param; { struct cmpci_softc *sc = handle; struct cmpci_dmanode *p; @@ -1593,12 +1811,12 @@ cmpci_trigger_input(handle, start, end, blksize, intr, arg, param) DMAADDR(p)); delay(10); bus_space_write_2(sc->sc_iot, sc->sc_ioh, CMPCI_REG_DMA1_BYTES, - ((caddr_t)end - (caddr_t)start + 1) / bps - 1); + ((caddr_t)end - (caddr_t)start + 1) / bps - 1); delay(10); /* set interrupt count */ bus_space_write_2(sc->sc_iot, sc->sc_ioh, CMPCI_REG_DMA1_SAMPLES, - (blksize + bps - 1) / bps - 1); + (blksize + bps - 1) / bps - 1); delay(10); /* start DMA */ diff --git a/sys/dev/pci/cmpcireg.h b/sys/dev/pci/cmpcireg.h index afb2e776891b..496649c6bb69 100644 --- a/sys/dev/pci/cmpcireg.h +++ b/sys/dev/pci/cmpcireg.h @@ -1,11 +1,11 @@ -/* $NetBSD: cmpcireg.h,v 1.1 2000/04/30 21:59:58 augustss Exp $ */ +/* $NetBSD: cmpcireg.h,v 1.2 2001/02/12 18:47:12 tshiozak Exp $ */ /* * Copyright (c) 2000 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation - * by Takuya SHIOZAKI . + * by Takuya SHIOZAKI . * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -116,6 +116,8 @@ #define CMPCI_REG_MISC 0x18 # define CMPCI_REG_SPDIF_48K 0x00008000 # define CMPCI_REG_FM_ENABLE 0x00080000 +# define CMPCI_REG_5V 0x02000000 +# define CMPCI_REG_N4SPK3D 0x04000000 #define CMPCI_REG_SBDATA 0x22 @@ -150,7 +152,7 @@ # define CMPCI_SB16_MIXER_LINE_SRC_R 0x08 # define CMPCI_SB16_MIXER_CD_SRC_R 0x02 # define CMPCI_SB16_MIXER_MIC_SRC 0x01 -# define CMPCI_SB16_MIXER_SRC_R_TO_L(v) ((v) << 1) +# define CMPCI_SB16_MIXER_SRC_R_TO_L(v) ((v) << 1) # define CMPCI_SB16_MIXER_INGAIN_L 0x3F # define CMPCI_SB16_MIXER_INGAIN_R 0x40 @@ -163,9 +165,17 @@ # define CMPCI_SB16_MIXER_BASS_R 0x47 # define CMPCI_SB16_MIXER_L_TO_R(addr) ((addr)+1) -# define CMPCI_ADJUST_MIC_GAIN(sc, x) cmpci_adjust((x), 0xf8) -# define CMPCI_ADJUST_GAIN(sc, x) cmpci_adjust((x), 0xf8) -# define CMPCI_ADJUST_2_GAIN(sc, x) cmpci_adjust((x), 0xc0) +# define CMPCI_ADJUST_MIC_GAIN(sc, x) cmpci_adjust((x), 0xf8) +# define CMPCI_ADJUST_GAIN(sc, x) cmpci_adjust((x), 0xf8) +# define CMPCI_ADJUST_2_GAIN(sc, x) cmpci_adjust((x), 0xc0) + +#define CMPCI_REG_MIXER24 0x24 +# define CMPCI_REG_SPDIN_MONITOR 0x01 +# define CMPCI_REG_SURROUND 0x02 +# define CMPCI_REG_INDIVIDUAL 0x20 +# define CMPCI_REG_REVERSE_FR 0x10 +#define CMPCI_REG_MIXER27 0x27 +# define CMPCI_REG_PHASE 0x04 #define CMPCI_REG_MPU_BASE 0x40 #define CMPCI_REG_MPU_SIZE 0x10 diff --git a/sys/dev/pci/cmpcivar.h b/sys/dev/pci/cmpcivar.h index 0df78f2e2d09..a2e78e1b4daa 100644 --- a/sys/dev/pci/cmpcivar.h +++ b/sys/dev/pci/cmpcivar.h @@ -1,11 +1,11 @@ -/* $NetBSD: cmpcivar.h,v 1.1 2000/04/30 21:59:58 augustss Exp $ */ +/* $NetBSD: cmpcivar.h,v 1.2 2001/02/12 18:47:12 tshiozak Exp $ */ /* * Copyright (c) 2000 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation - * by Takuya SHIOZAKI . + * by Takuya SHIOZAKI . * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -40,13 +40,13 @@ * DMA pool */ struct cmpci_dmanode { - bus_dma_tag_t cd_tag; - int cd_nsegs; - bus_dma_segment_t cd_segs[1]; - bus_dmamap_t cd_map; - caddr_t cd_addr; - size_t cd_size; - struct cmpci_dmanode *cd_next; + bus_dma_tag_t cd_tag; + int cd_nsegs; + bus_dma_segment_t cd_segs[1]; + bus_dmamap_t cd_map; + caddr_t cd_addr; + size_t cd_size; + struct cmpci_dmanode *cd_next; }; typedef struct cmpci_dmanode *cmpci_dmapool_t; @@ -91,14 +91,31 @@ typedef struct cmpci_dmanode *cmpci_dmapool_t; #define CMPCI_MIC_OUT_MUTE 26 #define CMPCI_LINE_OUT_MUTE 27 -#ifdef CMPCI_SPDIF_SUPPORT -#define CMPCI_SPDIF_IN 28 -#define CMPCI_SPDIF_IN_MUTE 29 +#define CMPCI_SPDIF_IN_MUTE 28 +#define CMPCI_SPDIF_CLASS 29 +#define CMPCI_SPDIF_LOOP 30 +#define CMPCI_SPDIF_LEGACY 31 +#define CMPCI_SPDIF_OUT_VOLTAGE 32 +#define CMPCI_SPDIF_IN_PHASE 33 +#define CMPCI_REAR 34 +#define CMPCI_INDIVIDUAL 35 +#define CMPCI_REVERSE 36 +#define CMPCI_SURROUND 37 #define CmpciNspdif "spdif" -#define CMPCI_NDEVS 30 -#else -#define CMPCI_NDEVS 28 -#endif +#define CmpciCspdif "spdif" +#define CmpciNloop "loop" +#define CmpciNlegacy "legacy" +#define CmpciNout_voltage "out_voltage" +#define CmpciNin_phase "in_phase" +#define CmpciNpositive "positive" +#define CmpciNnegative "negative" +#define CmpciNrear "rear" +#define CmpciNindividual "individual" +#define CmpciNreverse "reverse" +#define CmpciNlow_v "0.5V" +#define CmpciNhigh_v "5V" +#define CmpciNsurround "surround" +#define CMPCI_NDEVS 38 #define CMPCI_IS_IN_MUTE(x) ((x) < CMPCI_CD_SWAP) @@ -107,35 +124,64 @@ typedef struct cmpci_dmanode *cmpci_dmapool_t; * softc */ struct cmpci_softc { - struct device sc_dev; + struct device sc_dev; /* model/rev */ - int sc_revision; - int sc_model; + uint32_t sc_id; + uint32_t sc_class; + uint32_t sc_capable; +#define CMPCI_CAP_SPDIN 0x00000001 +#define CMPCI_CAP_SPDOUT 0x00000002 +#define CMPCI_CAP_SPDLOOP 0x00000004 +#define CMPCI_CAP_SPDLEGACY 0x00000008 +#define CMPCI_CAP_SPDIN_MONITOR 0x00000010 +#define CMPCI_CAP_XSPDOUT 0x00000020 +#define CMPCI_CAP_SPDOUT_VOLTAGE 0x00000040 +#define CMPCI_CAP_SPDOUT_48K 0x00000080 +#define CMPCI_CAP_SURROUND 0x00000100 +#define CMPCI_CAP_REAR 0x00000200 +#define CMPCI_CAP_INDIVIDUAL_REAR 0x00000400 +#define CMPCI_CAP_REVERSE_FR 0x00000800 +#define CMPCI_CAP_SPDIN_PHASE 0x00001000 + +#define CMPCI_CAP_CMI8338 (CMPCI_CAP_SPDIN | CMPCI_CAP_SPDOUT | \ + CMPCI_CAP_SPDLOOP | CMPCI_CAP_SPDLEGACY) + +#define CMPCI_CAP_CMI8738 (CMPCI_CAP_CMI8338 | \ + CMPCI_CAP_SPDIN_MONITOR | \ + CMPCI_CAP_XSPDOUT | \ + CMPCI_CAP_SPDOUT_VOLTAGE | \ + CMPCI_CAP_SPDOUT_48K | CMPCI_CAP_SURROUND |\ + CMPCI_CAP_REAR | \ + CMPCI_CAP_INDIVIDUAL_REAR | \ + CMPCI_CAP_REVERSE_FR | \ + CMPCI_CAP_SPDIN_PHASE) +#define CMPCI_ISCAP(sc, name) (sc->sc_capable & CMPCI_CAP_ ## name) /* I/O Base device */ - bus_space_tag_t sc_iot; - bus_space_handle_t sc_ioh; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; /* intr handle */ - pci_intr_handle_t * sc_ih; + pci_intr_handle_t *sc_ih; /* DMA */ - bus_dma_tag_t sc_dmat; - cmpci_dmapool_t sc_dmap; + bus_dma_tag_t sc_dmat; + cmpci_dmapool_t sc_dmap; /* each channel */ struct { - void (*intr) __P((void *)); - void *intr_arg; + void (*intr) __P((void *)); + void *intr_arg; + int md_divide; } sc_play, sc_rec; /* mixer */ - uint8_t gain[CMPCI_NDEVS][2]; -#define CMPCI_LEFT 0 -#define CMPCI_RIGHT 1 -#define CMPCI_LR 0 - uint16_t in_mask; + uint8_t sc_gain[CMPCI_NDEVS][2]; +#define CMPCI_LEFT 0 +#define CMPCI_RIGHT 1 +#define CMPCI_LR 0 + uint16_t sc_in_mask; };