1a5108eaeSScott Long /*- 2718cf2ccSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3718cf2ccSPedro F. Giffuni * 4a5108eaeSScott Long * Copyright (c) 2001 Scott Long <scottl@freebsd.org> 5a5108eaeSScott Long * Copyright (c) 2001 Darrell Anderson <anderson@cs.duke.edu> 6a5108eaeSScott Long * All rights reserved. 7a5108eaeSScott Long * 8a5108eaeSScott Long * Redistribution and use in source and binary forms, with or without 9a5108eaeSScott Long * modification, are permitted provided that the following conditions 10a5108eaeSScott Long * are met: 11a5108eaeSScott Long * 1. Redistributions of source code must retain the above copyright 12a5108eaeSScott Long * notice, this list of conditions and the following disclaimer. 13a5108eaeSScott Long * 2. Redistributions in binary form must reproduce the above copyright 14a5108eaeSScott Long * notice, this list of conditions and the following disclaimer in the 15a5108eaeSScott Long * documentation and/or other materials provided with the distribution. 16a5108eaeSScott Long * 17a5108eaeSScott Long * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18a5108eaeSScott Long * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19a5108eaeSScott Long * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20a5108eaeSScott Long * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21a5108eaeSScott Long * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22a5108eaeSScott Long * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23a5108eaeSScott Long * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24a5108eaeSScott Long * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25a5108eaeSScott Long * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26a5108eaeSScott Long * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27a5108eaeSScott Long * SUCH DAMAGE. 28a5108eaeSScott Long */ 29a5108eaeSScott Long 30a5108eaeSScott Long /* 31a5108eaeSScott Long * Maestro-3/Allegro FreeBSD pcm sound driver 32a5108eaeSScott Long * 33a5108eaeSScott Long * executive status summary: 34a5108eaeSScott Long * (+) /dev/dsp multiple concurrent play channels. 35a5108eaeSScott Long * (+) /dev/dsp config (speed, mono/stereo, 8/16 bit). 36a5108eaeSScott Long * (+) /dev/mixer sets left/right volumes. 37a5108eaeSScott Long * (+) /dev/dsp recording works. Tested successfully with the cdrom channel 38a5108eaeSScott Long * (+) apm suspend/resume works, and works properly!. 39a5108eaeSScott Long * (-) hardware volme controls don't work =-( 40a5108eaeSScott Long * (-) setblocksize() does nothing. 41a5108eaeSScott Long * 42a5108eaeSScott Long * The real credit goes to: 43a5108eaeSScott Long * 44a5108eaeSScott Long * Zach Brown for his Linux driver core and helpful technical comments. 45a5108eaeSScott Long * <zab@zabbo.net>, http://www.zabbo.net/maestro3 46a5108eaeSScott Long * 47a5108eaeSScott Long * Cameron Grant created the pcm framework used here nearly verbatim. 48*33f4bccaSEitan Adler * <cg@freebsd.org>, https://people.freebsd.org/~cg/template.c 49a5108eaeSScott Long * 50a5108eaeSScott Long * Taku YAMAMOTO for his Maestro-1/2 FreeBSD driver and sanity reference. 51a5108eaeSScott Long * <taku@cent.saitama-u.ac.jp> 52a5108eaeSScott Long * 53a5108eaeSScott Long * ESS docs explained a few magic registers and numbers. 54a5108eaeSScott Long * http://virgo.caltech.edu/~dmoore/maestro3.pdf.gz 55a5108eaeSScott Long */ 56a5108eaeSScott Long 5790da2b28SAriff Abdullah #ifdef HAVE_KERNEL_OPTION_HEADERS 5890da2b28SAriff Abdullah #include "opt_snd.h" 5990da2b28SAriff Abdullah #endif 6090da2b28SAriff Abdullah 61a5108eaeSScott Long #include <dev/sound/pcm/sound.h> 62a5108eaeSScott Long #include <dev/sound/pcm/ac97.h> 63a5108eaeSScott Long 6490cf0136SWarner Losh #include <dev/pci/pcireg.h> 6590cf0136SWarner Losh #include <dev/pci/pcivar.h> 66a5108eaeSScott Long 675dcd37b1SPedro F. Giffuni #define M3_MODEL 1 685dcd37b1SPedro F. Giffuni 695dcd37b1SPedro F. Giffuni #include <dev/sound/pci/allegro_reg.h> 705dcd37b1SPedro F. Giffuni #include <dev/sound/pci/allegro_code.h> 71a5108eaeSScott Long 7267b1dce3SCameron Grant SND_DECLARE_FILE("$FreeBSD$"); 7367b1dce3SCameron Grant 74a5108eaeSScott Long /* -------------------------------------------------------------------- */ 75a5108eaeSScott Long 76a5108eaeSScott Long enum {CHANGE=0, CALL=1, INTR=2, BORING=3, NONE=-1}; 77a5108eaeSScott Long #ifndef M3_DEBUG_LEVEL 78a5108eaeSScott Long #define M3_DEBUG_LEVEL NONE 79a5108eaeSScott Long #endif 80a5108eaeSScott Long #define M3_DEBUG(level, _msg) {if ((level) <= M3_DEBUG_LEVEL) {printf _msg;}} 81a5108eaeSScott Long 82a5108eaeSScott Long /* -------------------------------------------------------------------- */ 83a5108eaeSScott Long enum { 84a5108eaeSScott Long ESS_ALLEGRO_1, 85a5108eaeSScott Long ESS_MAESTRO3 86a5108eaeSScott Long }; 87a5108eaeSScott Long 88a5108eaeSScott Long static struct m3_card_type { 89a5108eaeSScott Long u_int32_t pci_id; int which; int delay1; int delay2; char *name; 90a5108eaeSScott Long } m3_card_types[] = { 91a5108eaeSScott Long { 0x1988125d, ESS_ALLEGRO_1, 50, 800, "ESS Technology Allegro-1" }, 92a5108eaeSScott Long { 0x1998125d, ESS_MAESTRO3, 20, 500, "ESS Technology Maestro3" }, 93a5108eaeSScott Long { 0x199a125d, ESS_MAESTRO3, 20, 500, "ESS Technology Maestro3" }, 94a5108eaeSScott Long { 0, 0, 0, 0, NULL } 95a5108eaeSScott Long }; 96a5108eaeSScott Long 97018b991eSAriff Abdullah #define M3_BUFSIZE_MIN 4096 98c21880a7SPyun YongHyeon #define M3_BUFSIZE_MAX 65536 99baadfb4cSScott Long #define M3_BUFSIZE_DEFAULT 4096 10073b9d66dSScott Long #define M3_PCHANS 4 /* create /dev/dsp0.[0-N] to use more than one */ 101a5108eaeSScott Long #define M3_RCHANS 1 102e93d24c2SScott Long #define M3_MAXADDR ((1 << 27) - 1) 1035dcd37b1SPedro F. Giffuni #define M3_DEFAULT_VOL 0x6800 104a5108eaeSScott Long 105a5108eaeSScott Long struct sc_info; 106a5108eaeSScott Long 107a5108eaeSScott Long struct sc_pchinfo { 108a5108eaeSScott Long u_int32_t spd; 109a5108eaeSScott Long u_int32_t fmt; 11066ef8af5SCameron Grant struct snd_dbuf *buffer; 11166ef8af5SCameron Grant struct pcm_channel *channel; 112a5108eaeSScott Long struct sc_info *parent; 113a5108eaeSScott Long u_int32_t bufsize; 114a5108eaeSScott Long u_int32_t dac_data; 115a5108eaeSScott Long u_int32_t dac_idx; 116a5108eaeSScott Long u_int32_t active; 117018b991eSAriff Abdullah u_int32_t ptr; 118018b991eSAriff Abdullah u_int32_t prevptr; 119a5108eaeSScott Long }; 120a5108eaeSScott Long 121a5108eaeSScott Long struct sc_rchinfo { 122a5108eaeSScott Long u_int32_t spd; 123a5108eaeSScott Long u_int32_t fmt; 12466ef8af5SCameron Grant struct snd_dbuf *buffer; 12566ef8af5SCameron Grant struct pcm_channel *channel; 126a5108eaeSScott Long struct sc_info *parent; 127a5108eaeSScott Long u_int32_t bufsize; 128a5108eaeSScott Long u_int32_t adc_data; 129a5108eaeSScott Long u_int32_t adc_idx; 130a5108eaeSScott Long u_int32_t active; 131018b991eSAriff Abdullah u_int32_t ptr; 132018b991eSAriff Abdullah u_int32_t prevptr; 133a5108eaeSScott Long }; 134a5108eaeSScott Long 135a5108eaeSScott Long struct sc_info { 136a5108eaeSScott Long device_t dev; 137a5108eaeSScott Long u_int32_t type; 138a5108eaeSScott Long int which; 139a5108eaeSScott Long int delay1; 140a5108eaeSScott Long int delay2; 141a5108eaeSScott Long 142a5108eaeSScott Long bus_space_tag_t st; 143a5108eaeSScott Long bus_space_handle_t sh; 144a5108eaeSScott Long bus_dma_tag_t parent_dmat; 145a5108eaeSScott Long 146a5108eaeSScott Long struct resource *reg; 147a5108eaeSScott Long struct resource *irq; 148a5108eaeSScott Long int regtype; 149a5108eaeSScott Long int regid; 150a5108eaeSScott Long int irqid; 151a5108eaeSScott Long void *ih; 152a5108eaeSScott Long 153a5108eaeSScott Long struct sc_pchinfo pch[M3_PCHANS]; 154a5108eaeSScott Long struct sc_rchinfo rch[M3_RCHANS]; 155a5108eaeSScott Long int pch_cnt; 156a5108eaeSScott Long int rch_cnt; 157a5108eaeSScott Long int pch_active_cnt; 158baadfb4cSScott Long unsigned int bufsz; 159a5108eaeSScott Long u_int16_t *savemem; 160c21880a7SPyun YongHyeon 161c21880a7SPyun YongHyeon struct mtx *sc_lock; 162a5108eaeSScott Long }; 163a5108eaeSScott Long 164c21880a7SPyun YongHyeon #define M3_LOCK(_sc) snd_mtxlock((_sc)->sc_lock) 165c21880a7SPyun YongHyeon #define M3_UNLOCK(_sc) snd_mtxunlock((_sc)->sc_lock) 166c21880a7SPyun YongHyeon #define M3_LOCK_ASSERT(_sc) snd_mtxassert((_sc)->sc_lock) 167c21880a7SPyun YongHyeon 168a5108eaeSScott Long /* -------------------------------------------------------------------- */ 169a5108eaeSScott Long 170a5108eaeSScott Long /* play channel interface */ 17166ef8af5SCameron Grant static void *m3_pchan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int); 172a5108eaeSScott Long static int m3_pchan_free(kobj_t, void *); 173a5108eaeSScott Long static int m3_pchan_setformat(kobj_t, void *, u_int32_t); 17490da2b28SAriff Abdullah static u_int32_t m3_pchan_setspeed(kobj_t, void *, u_int32_t); 17590da2b28SAriff Abdullah static u_int32_t m3_pchan_setblocksize(kobj_t, void *, u_int32_t); 176a5108eaeSScott Long static int m3_pchan_trigger(kobj_t, void *, int); 177c21880a7SPyun YongHyeon static int m3_pchan_trigger_locked(kobj_t, void *, int); 178018b991eSAriff Abdullah static u_int32_t m3_pchan_getptr_internal(struct sc_pchinfo *); 179018b991eSAriff Abdullah static u_int32_t m3_pchan_getptr(kobj_t, void *); 18066ef8af5SCameron Grant static struct pcmchan_caps *m3_pchan_getcaps(kobj_t, void *); 181a5108eaeSScott Long 182a5108eaeSScott Long /* record channel interface */ 18366ef8af5SCameron Grant static void *m3_rchan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int); 184a5108eaeSScott Long static int m3_rchan_free(kobj_t, void *); 185a5108eaeSScott Long static int m3_rchan_setformat(kobj_t, void *, u_int32_t); 18690da2b28SAriff Abdullah static u_int32_t m3_rchan_setspeed(kobj_t, void *, u_int32_t); 18790da2b28SAriff Abdullah static u_int32_t m3_rchan_setblocksize(kobj_t, void *, u_int32_t); 188a5108eaeSScott Long static int m3_rchan_trigger(kobj_t, void *, int); 189c21880a7SPyun YongHyeon static int m3_rchan_trigger_locked(kobj_t, void *, int); 190018b991eSAriff Abdullah static u_int32_t m3_rchan_getptr_internal(struct sc_rchinfo *); 191018b991eSAriff Abdullah static u_int32_t m3_rchan_getptr(kobj_t, void *); 19266ef8af5SCameron Grant static struct pcmchan_caps *m3_rchan_getcaps(kobj_t, void *); 193a5108eaeSScott Long 194018b991eSAriff Abdullah static int m3_chan_active(struct sc_info *); 195018b991eSAriff Abdullah 196a5108eaeSScott Long /* talk to the codec - called from ac97.c */ 19790da2b28SAriff Abdullah static u_int32_t m3_initcd(kobj_t, void *); 198a5108eaeSScott Long static int m3_rdcd(kobj_t, void *, int); 199a5108eaeSScott Long static int m3_wrcd(kobj_t, void *, int, u_int32_t); 200a5108eaeSScott Long 201a5108eaeSScott Long /* stuff */ 202a5108eaeSScott Long static void m3_intr(void *); 203a5108eaeSScott Long static int m3_power(struct sc_info *, int); 204a5108eaeSScott Long static int m3_init(struct sc_info *); 205a5108eaeSScott Long static int m3_uninit(struct sc_info *); 206a5108eaeSScott Long static u_int8_t m3_assp_halt(struct sc_info *); 207a5108eaeSScott Long static void m3_config(struct sc_info *); 208a5108eaeSScott Long static void m3_amp_enable(struct sc_info *); 209a5108eaeSScott Long static void m3_enable_ints(struct sc_info *); 210a5108eaeSScott Long static void m3_codec_reset(struct sc_info *); 211a5108eaeSScott Long 212a5108eaeSScott Long /* -------------------------------------------------------------------- */ 213a5108eaeSScott Long /* Codec descriptor */ 214a5108eaeSScott Long static kobj_method_t m3_codec_methods[] = { 215a5108eaeSScott Long KOBJMETHOD(ac97_init, m3_initcd), 216a5108eaeSScott Long KOBJMETHOD(ac97_read, m3_rdcd), 217a5108eaeSScott Long KOBJMETHOD(ac97_write, m3_wrcd), 21890da2b28SAriff Abdullah KOBJMETHOD_END 219a5108eaeSScott Long }; 220a5108eaeSScott Long AC97_DECLARE(m3_codec); 221a5108eaeSScott Long 222a5108eaeSScott Long /* -------------------------------------------------------------------- */ 223a5108eaeSScott Long /* channel descriptors */ 224a5108eaeSScott Long 225a5108eaeSScott Long static u_int32_t m3_playfmt[] = { 22690da2b28SAriff Abdullah SND_FORMAT(AFMT_U8, 1, 0), 22790da2b28SAriff Abdullah SND_FORMAT(AFMT_U8, 2, 0), 22890da2b28SAriff Abdullah SND_FORMAT(AFMT_S16_LE, 1, 0), 22990da2b28SAriff Abdullah SND_FORMAT(AFMT_S16_LE, 2, 0), 230a5108eaeSScott Long 0 231a5108eaeSScott Long }; 23266ef8af5SCameron Grant static struct pcmchan_caps m3_playcaps = {8000, 48000, m3_playfmt, 0}; 233a5108eaeSScott Long 234a5108eaeSScott Long static kobj_method_t m3_pch_methods[] = { 235a5108eaeSScott Long KOBJMETHOD(channel_init, m3_pchan_init), 236a5108eaeSScott Long KOBJMETHOD(channel_setformat, m3_pchan_setformat), 237a5108eaeSScott Long KOBJMETHOD(channel_setspeed, m3_pchan_setspeed), 238a5108eaeSScott Long KOBJMETHOD(channel_setblocksize, m3_pchan_setblocksize), 239a5108eaeSScott Long KOBJMETHOD(channel_trigger, m3_pchan_trigger), 240a5108eaeSScott Long KOBJMETHOD(channel_getptr, m3_pchan_getptr), 241a5108eaeSScott Long KOBJMETHOD(channel_getcaps, m3_pchan_getcaps), 242a5108eaeSScott Long KOBJMETHOD(channel_free, m3_pchan_free), 24390da2b28SAriff Abdullah KOBJMETHOD_END 244a5108eaeSScott Long }; 245a5108eaeSScott Long CHANNEL_DECLARE(m3_pch); 246a5108eaeSScott Long 247a5108eaeSScott Long static u_int32_t m3_recfmt[] = { 24890da2b28SAriff Abdullah SND_FORMAT(AFMT_U8, 1, 0), 24990da2b28SAriff Abdullah SND_FORMAT(AFMT_U8, 2, 0), 25090da2b28SAriff Abdullah SND_FORMAT(AFMT_S16_LE, 1, 0), 25190da2b28SAriff Abdullah SND_FORMAT(AFMT_S16_LE, 2, 0), 252a5108eaeSScott Long 0 253a5108eaeSScott Long }; 25466ef8af5SCameron Grant static struct pcmchan_caps m3_reccaps = {8000, 48000, m3_recfmt, 0}; 255a5108eaeSScott Long 256a5108eaeSScott Long static kobj_method_t m3_rch_methods[] = { 257a5108eaeSScott Long KOBJMETHOD(channel_init, m3_rchan_init), 258a5108eaeSScott Long KOBJMETHOD(channel_setformat, m3_rchan_setformat), 259a5108eaeSScott Long KOBJMETHOD(channel_setspeed, m3_rchan_setspeed), 260a5108eaeSScott Long KOBJMETHOD(channel_setblocksize, m3_rchan_setblocksize), 261a5108eaeSScott Long KOBJMETHOD(channel_trigger, m3_rchan_trigger), 262a5108eaeSScott Long KOBJMETHOD(channel_getptr, m3_rchan_getptr), 263a5108eaeSScott Long KOBJMETHOD(channel_getcaps, m3_rchan_getcaps), 264a5108eaeSScott Long KOBJMETHOD(channel_free, m3_rchan_free), 26590da2b28SAriff Abdullah KOBJMETHOD_END 266a5108eaeSScott Long }; 267a5108eaeSScott Long CHANNEL_DECLARE(m3_rch); 268a5108eaeSScott Long 269a5108eaeSScott Long /* -------------------------------------------------------------------- */ 270a5108eaeSScott Long /* some i/o convenience functions */ 271a5108eaeSScott Long 272a5108eaeSScott Long #define m3_rd_1(sc, regno) bus_space_read_1(sc->st, sc->sh, regno) 273a5108eaeSScott Long #define m3_rd_2(sc, regno) bus_space_read_2(sc->st, sc->sh, regno) 274a5108eaeSScott Long #define m3_rd_4(sc, regno) bus_space_read_4(sc->st, sc->sh, regno) 275a5108eaeSScott Long #define m3_wr_1(sc, regno, data) bus_space_write_1(sc->st, sc->sh, regno, data) 276a5108eaeSScott Long #define m3_wr_2(sc, regno, data) bus_space_write_2(sc->st, sc->sh, regno, data) 277a5108eaeSScott Long #define m3_wr_4(sc, regno, data) bus_space_write_4(sc->st, sc->sh, regno, data) 278a5108eaeSScott Long #define m3_rd_assp_code(sc, index) \ 279a5108eaeSScott Long m3_rd_assp(sc, MEMTYPE_INTERNAL_CODE, index) 280a5108eaeSScott Long #define m3_wr_assp_code(sc, index, data) \ 281a5108eaeSScott Long m3_wr_assp(sc, MEMTYPE_INTERNAL_CODE, index, data) 282a5108eaeSScott Long #define m3_rd_assp_data(sc, index) \ 283a5108eaeSScott Long m3_rd_assp(sc, MEMTYPE_INTERNAL_DATA, index) 284a5108eaeSScott Long #define m3_wr_assp_data(sc, index, data) \ 285a5108eaeSScott Long m3_wr_assp(sc, MEMTYPE_INTERNAL_DATA, index, data) 286a5108eaeSScott Long 287a5108eaeSScott Long static __inline u_int16_t 288a5108eaeSScott Long m3_rd_assp(struct sc_info *sc, u_int16_t region, u_int16_t index) 289a5108eaeSScott Long { 290a5108eaeSScott Long m3_wr_2(sc, DSP_PORT_MEMORY_TYPE, region & MEMTYPE_MASK); 291a5108eaeSScott Long m3_wr_2(sc, DSP_PORT_MEMORY_INDEX, index); 292a5108eaeSScott Long return m3_rd_2(sc, DSP_PORT_MEMORY_DATA); 293a5108eaeSScott Long } 294a5108eaeSScott Long 295a5108eaeSScott Long static __inline void 296a5108eaeSScott Long m3_wr_assp(struct sc_info *sc, u_int16_t region, u_int16_t index, 297a5108eaeSScott Long u_int16_t data) 298a5108eaeSScott Long { 299a5108eaeSScott Long m3_wr_2(sc, DSP_PORT_MEMORY_TYPE, region & MEMTYPE_MASK); 300a5108eaeSScott Long m3_wr_2(sc, DSP_PORT_MEMORY_INDEX, index); 301a5108eaeSScott Long m3_wr_2(sc, DSP_PORT_MEMORY_DATA, data); 302a5108eaeSScott Long } 303a5108eaeSScott Long 304a5108eaeSScott Long static __inline int 305a5108eaeSScott Long m3_wait(struct sc_info *sc) 306a5108eaeSScott Long { 307a5108eaeSScott Long int i; 308a5108eaeSScott Long 309a5108eaeSScott Long for (i=0 ; i<20 ; i++) { 310a5108eaeSScott Long if ((m3_rd_1(sc, CODEC_STATUS) & 1) == 0) { 311a5108eaeSScott Long return 0; 312a5108eaeSScott Long } 313a5108eaeSScott Long DELAY(2); 314a5108eaeSScott Long } 315a5108eaeSScott Long return -1; 316a5108eaeSScott Long } 317a5108eaeSScott Long 318a5108eaeSScott Long /* -------------------------------------------------------------------- */ 319a5108eaeSScott Long /* ac97 codec */ 320a5108eaeSScott Long 32190da2b28SAriff Abdullah static u_int32_t 322a5108eaeSScott Long m3_initcd(kobj_t kobj, void *devinfo) 323a5108eaeSScott Long { 324a5108eaeSScott Long struct sc_info *sc = (struct sc_info *)devinfo; 325a5108eaeSScott Long u_int32_t data; 326a5108eaeSScott Long 327a5108eaeSScott Long M3_DEBUG(CALL, ("m3_initcd\n")); 328a5108eaeSScott Long 329a5108eaeSScott Long /* init ac-link */ 330a5108eaeSScott Long 331a5108eaeSScott Long data = m3_rd_1(sc, CODEC_COMMAND); 332a5108eaeSScott Long return ((data & 0x1) ? 0 : 1); 333a5108eaeSScott Long } 334a5108eaeSScott Long 335a5108eaeSScott Long static int 336a5108eaeSScott Long m3_rdcd(kobj_t kobj, void *devinfo, int regno) 337a5108eaeSScott Long { 338a5108eaeSScott Long struct sc_info *sc = (struct sc_info *)devinfo; 339a5108eaeSScott Long u_int32_t data; 340a5108eaeSScott Long 341a5108eaeSScott Long if (m3_wait(sc)) { 342a5108eaeSScott Long device_printf(sc->dev, "m3_rdcd timed out.\n"); 343a5108eaeSScott Long return -1; 344a5108eaeSScott Long } 345a5108eaeSScott Long m3_wr_1(sc, CODEC_COMMAND, (regno & 0x7f) | 0x80); 34666ef8af5SCameron Grant DELAY(50); /* ac97 cycle = 20.8 usec */ 347a5108eaeSScott Long if (m3_wait(sc)) { 348a5108eaeSScott Long device_printf(sc->dev, "m3_rdcd timed out.\n"); 349a5108eaeSScott Long return -1; 350a5108eaeSScott Long } 351a5108eaeSScott Long data = m3_rd_2(sc, CODEC_DATA); 352a5108eaeSScott Long return data; 353a5108eaeSScott Long } 354a5108eaeSScott Long 355a5108eaeSScott Long static int 356a5108eaeSScott Long m3_wrcd(kobj_t kobj, void *devinfo, int regno, u_int32_t data) 357a5108eaeSScott Long { 358a5108eaeSScott Long struct sc_info *sc = (struct sc_info *)devinfo; 359a5108eaeSScott Long if (m3_wait(sc)) { 360a5108eaeSScott Long device_printf(sc->dev, "m3_wrcd timed out.\n"); 361c2ede4b3SMartin Blapp return -1; 362a5108eaeSScott Long } 363a5108eaeSScott Long m3_wr_2(sc, CODEC_DATA, data); 364a5108eaeSScott Long m3_wr_1(sc, CODEC_COMMAND, regno & 0x7f); 36566ef8af5SCameron Grant DELAY(50); /* ac97 cycle = 20.8 usec */ 366a5108eaeSScott Long return 0; 367a5108eaeSScott Long } 368a5108eaeSScott Long 369a5108eaeSScott Long /* -------------------------------------------------------------------- */ 370a5108eaeSScott Long /* play channel interface */ 371a5108eaeSScott Long 372a5108eaeSScott Long #define LO(x) (((x) & 0x0000ffff) ) 373a5108eaeSScott Long #define HI(x) (((x) & 0xffff0000) >> 16) 374a5108eaeSScott Long 375a5108eaeSScott Long static void * 37666ef8af5SCameron Grant m3_pchan_init(kobj_t kobj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 377a5108eaeSScott Long { 378a5108eaeSScott Long struct sc_info *sc = devinfo; 379a5108eaeSScott Long struct sc_pchinfo *ch; 380a5108eaeSScott Long u_int32_t bus_addr, i; 381c21880a7SPyun YongHyeon int idx, data_bytes, dac_data; 382c21880a7SPyun YongHyeon int dsp_in_size, dsp_out_size, dsp_in_buf, dsp_out_buf; 383a5108eaeSScott Long 3845dcd37b1SPedro F. Giffuni struct data_word { 3855dcd37b1SPedro F. Giffuni u_int16_t addr, val; 3865dcd37b1SPedro F. Giffuni } pv[] = { 3875dcd37b1SPedro F. Giffuni {CDATA_LEFT_VOLUME, M3_DEFAULT_VOL}, 3885dcd37b1SPedro F. Giffuni {CDATA_RIGHT_VOLUME, M3_DEFAULT_VOL}, 3895dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET, 0} , 3905dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 3, 0x0000}, 3915dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 4, 0}, 3925dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 5, 0}, 3935dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 6, 0}, 3945dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 7, 0}, 3955dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 8, 0}, 3965dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 9, 0}, 3975dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 10, 0x8000}, 3985dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 11, 0xFF00}, 3995dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 13, 0}, 4005dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 14, 0}, 4015dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 15, 0}, 4025dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 16, 8}, 4035dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 17, 50*2}, 4045dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 18, MINISRC_BIQUAD_STAGE - 1}, 4055dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 20, 0}, 4065dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 21, 0} 4075dcd37b1SPedro F. Giffuni }; 4085dcd37b1SPedro F. Giffuni 409c21880a7SPyun YongHyeon M3_LOCK(sc); 410c21880a7SPyun YongHyeon idx = sc->pch_cnt; /* dac instance number, no active reuse! */ 411a5108eaeSScott Long M3_DEBUG(CHANGE, ("m3_pchan_init(dac=%d)\n", idx)); 412a5108eaeSScott Long 413a5108eaeSScott Long if (dir != PCMDIR_PLAY) { 414c21880a7SPyun YongHyeon M3_UNLOCK(sc); 415a5108eaeSScott Long device_printf(sc->dev, "m3_pchan_init not PCMDIR_PLAY\n"); 416c21880a7SPyun YongHyeon return (NULL); 417a5108eaeSScott Long } 418a5108eaeSScott Long 419c21880a7SPyun YongHyeon data_bytes = (((MINISRC_TMP_BUFFER_SIZE & ~1) + 420c21880a7SPyun YongHyeon (MINISRC_IN_BUFFER_SIZE & ~1) + 421c21880a7SPyun YongHyeon (MINISRC_OUT_BUFFER_SIZE & ~1) + 4) + 255) &~ 255; 422c21880a7SPyun YongHyeon dac_data = 0x1100 + (data_bytes * idx); 423c21880a7SPyun YongHyeon 424c21880a7SPyun YongHyeon dsp_in_size = MINISRC_IN_BUFFER_SIZE - (0x20 * 2); 425c21880a7SPyun YongHyeon dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x20 * 2); 426c21880a7SPyun YongHyeon dsp_in_buf = dac_data + (MINISRC_TMP_BUFFER_SIZE/2); 427c21880a7SPyun YongHyeon dsp_out_buf = dsp_in_buf + (dsp_in_size/2) + 1; 428c21880a7SPyun YongHyeon 429c21880a7SPyun YongHyeon ch = &sc->pch[idx]; 430a5108eaeSScott Long ch->dac_idx = idx; 431a5108eaeSScott Long ch->dac_data = dac_data; 432a5108eaeSScott Long if (ch->dac_data + data_bytes/2 >= 0x1c00) { 433c21880a7SPyun YongHyeon M3_UNLOCK(sc); 434a5108eaeSScott Long device_printf(sc->dev, "m3_pchan_init: revb mem exhausted\n"); 435c21880a7SPyun YongHyeon return (NULL); 436a5108eaeSScott Long } 437a5108eaeSScott Long 438a5108eaeSScott Long ch->buffer = b; 439a5108eaeSScott Long ch->parent = sc; 440a5108eaeSScott Long ch->channel = c; 44190da2b28SAriff Abdullah ch->fmt = SND_FORMAT(AFMT_U8, 1, 0); 442a5108eaeSScott Long ch->spd = DSP_DEFAULT_SPEED; 443c21880a7SPyun YongHyeon M3_UNLOCK(sc); /* XXX */ 4442e334adfSAriff Abdullah if (sndbuf_alloc(ch->buffer, sc->parent_dmat, 0, sc->bufsz) != 0) { 445a5108eaeSScott Long device_printf(sc->dev, "m3_pchan_init chn_allocbuf failed\n"); 446c21880a7SPyun YongHyeon return (NULL); 447a5108eaeSScott Long } 448c21880a7SPyun YongHyeon M3_LOCK(sc); 449a5108eaeSScott Long ch->bufsize = sndbuf_getsize(ch->buffer); 450a5108eaeSScott Long 451a5108eaeSScott Long /* host dma buffer pointers */ 45238cc9942SOlivier Houchard bus_addr = sndbuf_getbufaddr(ch->buffer); 453a5108eaeSScott Long if (bus_addr & 3) { 454a5108eaeSScott Long device_printf(sc->dev, "m3_pchan_init unaligned bus_addr\n"); 455a5108eaeSScott Long bus_addr = (bus_addr + 4) & ~3; 456a5108eaeSScott Long } 457a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_ADDRL, LO(bus_addr)); 458a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_ADDRH, HI(bus_addr)); 459a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_END_PLUS_1L, 460a5108eaeSScott Long LO(bus_addr + ch->bufsize)); 461a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_END_PLUS_1H, 462a5108eaeSScott Long HI(bus_addr + ch->bufsize)); 463a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_CURRENTL, 464a5108eaeSScott Long LO(bus_addr)); 465a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_CURRENTH, 466a5108eaeSScott Long HI(bus_addr)); 467a5108eaeSScott Long 468a5108eaeSScott Long /* dsp buffers */ 469a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_IN_BUF_BEGIN, dsp_in_buf); 470a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_IN_BUF_END_PLUS_1, 471a5108eaeSScott Long dsp_in_buf + dsp_in_size/2); 472a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_IN_BUF_HEAD, dsp_in_buf); 473a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_IN_BUF_TAIL, dsp_in_buf); 474a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_OUT_BUF_BEGIN, dsp_out_buf); 475a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_OUT_BUF_END_PLUS_1, 476a5108eaeSScott Long dsp_out_buf + dsp_out_size/2); 477a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_OUT_BUF_HEAD, dsp_out_buf); 478a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_OUT_BUF_TAIL, dsp_out_buf); 479a5108eaeSScott Long 480a5108eaeSScott Long /* some per client initializers */ 481a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + SRC3_DIRECTION_OFFSET + 12, 482a5108eaeSScott Long ch->dac_data + 40 + 8); 483a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + SRC3_DIRECTION_OFFSET + 19, 484a5108eaeSScott Long 0x400 + MINISRC_COEF_LOC); 485a5108eaeSScott Long /* enable or disable low pass filter? (0xff if rate> 45000) */ 486a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + SRC3_DIRECTION_OFFSET + 22, 0); 487a5108eaeSScott Long /* tell it which way dma is going? */ 488a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_DMA_CONTROL, 489a5108eaeSScott Long DMACONTROL_AUTOREPEAT + DMAC_PAGE3_SELECTOR + 490a5108eaeSScott Long DMAC_BLOCKF_SELECTOR); 491a5108eaeSScott Long 492a5108eaeSScott Long /* set an armload of static initializers */ 493a5108eaeSScott Long for(i = 0 ; i < (sizeof(pv) / sizeof(pv[0])) ; i++) { 494a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + pv[i].addr, pv[i].val); 495a5108eaeSScott Long } 496a5108eaeSScott Long 497a5108eaeSScott Long /* put us in the packed task lists */ 498a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_INSTANCE0_MINISRC + 499a5108eaeSScott Long (sc->pch_cnt + sc->rch_cnt), 500a5108eaeSScott Long ch->dac_data >> DP_SHIFT_COUNT); 501a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_DMA_XFER0 + (sc->pch_cnt + sc->rch_cnt), 502a5108eaeSScott Long ch->dac_data >> DP_SHIFT_COUNT); 503a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_MIXER_XFER0 + sc->pch_cnt, 504a5108eaeSScott Long ch->dac_data >> DP_SHIFT_COUNT); 505a5108eaeSScott Long 506c21880a7SPyun YongHyeon /* gotta start before stop */ 507c21880a7SPyun YongHyeon m3_pchan_trigger_locked(NULL, ch, PCMTRIG_START); 508c21880a7SPyun YongHyeon /* silence noise on load */ 509c21880a7SPyun YongHyeon m3_pchan_trigger_locked(NULL, ch, PCMTRIG_STOP); 510a5108eaeSScott Long 511a5108eaeSScott Long sc->pch_cnt++; 512c21880a7SPyun YongHyeon M3_UNLOCK(sc); 513c21880a7SPyun YongHyeon 514c21880a7SPyun YongHyeon return (ch); 515a5108eaeSScott Long } 516a5108eaeSScott Long 517a5108eaeSScott Long static int 518a5108eaeSScott Long m3_pchan_free(kobj_t kobj, void *chdata) 519a5108eaeSScott Long { 520a5108eaeSScott Long struct sc_pchinfo *ch = chdata; 521a5108eaeSScott Long struct sc_info *sc = ch->parent; 522a5108eaeSScott Long 523c21880a7SPyun YongHyeon M3_LOCK(sc); 524a5108eaeSScott Long M3_DEBUG(CHANGE, ("m3_pchan_free(dac=%d)\n", ch->dac_idx)); 525a5108eaeSScott Long 526a5108eaeSScott Long /* 527a5108eaeSScott Long * should remove this exact instance from the packed lists, but all 528a5108eaeSScott Long * are released at once (and in a stopped state) so this is ok. 529a5108eaeSScott Long */ 530a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_INSTANCE0_MINISRC + 531a5108eaeSScott Long (sc->pch_cnt - 1) + sc->rch_cnt, 0); 532a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_DMA_XFER0 + 533a5108eaeSScott Long (sc->pch_cnt - 1) + sc->rch_cnt, 0); 534a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_MIXER_XFER0 + (sc->pch_cnt-1), 0); 535a5108eaeSScott Long sc->pch_cnt--; 536c21880a7SPyun YongHyeon M3_UNLOCK(sc); 537c21880a7SPyun YongHyeon 538c21880a7SPyun YongHyeon return (0); 539a5108eaeSScott Long } 540a5108eaeSScott Long 541a5108eaeSScott Long static int 542a5108eaeSScott Long m3_pchan_setformat(kobj_t kobj, void *chdata, u_int32_t format) 543a5108eaeSScott Long { 544a5108eaeSScott Long struct sc_pchinfo *ch = chdata; 545a5108eaeSScott Long struct sc_info *sc = ch->parent; 546a5108eaeSScott Long u_int32_t data; 547a5108eaeSScott Long 548c21880a7SPyun YongHyeon M3_LOCK(sc); 549a5108eaeSScott Long M3_DEBUG(CHANGE, 550a5108eaeSScott Long ("m3_pchan_setformat(dac=%d, format=0x%x{%s-%s})\n", 551a5108eaeSScott Long ch->dac_idx, format, 552a5108eaeSScott Long format & (AFMT_U8|AFMT_S8) ? "8bit":"16bit", 55390da2b28SAriff Abdullah (AFMT_CHANNEL(format) > 1) ? "STEREO":"MONO")); 554a5108eaeSScott Long 555a5108eaeSScott Long /* mono word */ 55690da2b28SAriff Abdullah data = (AFMT_CHANNEL(format) > 1)? 0 : 1; 557a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + SRC3_MODE_OFFSET, data); 558a5108eaeSScott Long 559a5108eaeSScott Long /* 8bit word */ 560a5108eaeSScott Long data = ((format & AFMT_U8) || (format & AFMT_S8)) ? 1 : 0; 561a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + SRC3_WORD_LENGTH_OFFSET, data); 562a5108eaeSScott Long 563a5108eaeSScott Long ch->fmt = format; 564c21880a7SPyun YongHyeon M3_UNLOCK(sc); 565c21880a7SPyun YongHyeon 566c21880a7SPyun YongHyeon return (0); 567a5108eaeSScott Long } 568a5108eaeSScott Long 56990da2b28SAriff Abdullah static u_int32_t 570a5108eaeSScott Long m3_pchan_setspeed(kobj_t kobj, void *chdata, u_int32_t speed) 571a5108eaeSScott Long { 572a5108eaeSScott Long struct sc_pchinfo *ch = chdata; 573a5108eaeSScott Long struct sc_info *sc = ch->parent; 574a5108eaeSScott Long u_int32_t freq; 575a5108eaeSScott Long 576c21880a7SPyun YongHyeon M3_LOCK(sc); 577a5108eaeSScott Long M3_DEBUG(CHANGE, ("m3_pchan_setspeed(dac=%d, speed=%d)\n", 578a5108eaeSScott Long ch->dac_idx, speed)); 579a5108eaeSScott Long 580a5108eaeSScott Long if ((freq = ((speed << 15) + 24000) / 48000) != 0) { 581a5108eaeSScott Long freq--; 582a5108eaeSScott Long } 583a5108eaeSScott Long 584a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_FREQUENCY, freq); 585a5108eaeSScott Long ch->spd = speed; 586c21880a7SPyun YongHyeon M3_UNLOCK(sc); 587c21880a7SPyun YongHyeon 588c21880a7SPyun YongHyeon /* return closest possible speed */ 589c21880a7SPyun YongHyeon return (speed); 590a5108eaeSScott Long } 591a5108eaeSScott Long 59290da2b28SAriff Abdullah static u_int32_t 593a5108eaeSScott Long m3_pchan_setblocksize(kobj_t kobj, void *chdata, u_int32_t blocksize) 594a5108eaeSScott Long { 595a5108eaeSScott Long struct sc_pchinfo *ch = chdata; 596a5108eaeSScott Long 597a5108eaeSScott Long M3_DEBUG(CHANGE, ("m3_pchan_setblocksize(dac=%d, blocksize=%d)\n", 598a5108eaeSScott Long ch->dac_idx, blocksize)); 599a5108eaeSScott Long 600018b991eSAriff Abdullah return (sndbuf_getblksz(ch->buffer)); 601a5108eaeSScott Long } 602a5108eaeSScott Long 603a5108eaeSScott Long static int 604a5108eaeSScott Long m3_pchan_trigger(kobj_t kobj, void *chdata, int go) 605a5108eaeSScott Long { 606a5108eaeSScott Long struct sc_pchinfo *ch = chdata; 607a5108eaeSScott Long struct sc_info *sc = ch->parent; 608c21880a7SPyun YongHyeon int ret; 609c21880a7SPyun YongHyeon 610bdfbdcecSAriff Abdullah if (!PCMTRIG_COMMON(go)) 611bdfbdcecSAriff Abdullah return (0); 612bdfbdcecSAriff Abdullah 613c21880a7SPyun YongHyeon M3_LOCK(sc); 614c21880a7SPyun YongHyeon ret = m3_pchan_trigger_locked(kobj, chdata, go); 615c21880a7SPyun YongHyeon M3_UNLOCK(sc); 616c21880a7SPyun YongHyeon 617c21880a7SPyun YongHyeon return (ret); 618c21880a7SPyun YongHyeon } 619c21880a7SPyun YongHyeon 620c21880a7SPyun YongHyeon static int 621018b991eSAriff Abdullah m3_chan_active(struct sc_info *sc) 622018b991eSAriff Abdullah { 623018b991eSAriff Abdullah int i, ret; 624018b991eSAriff Abdullah 625018b991eSAriff Abdullah ret = 0; 626018b991eSAriff Abdullah 627018b991eSAriff Abdullah for (i = 0; i < sc->pch_cnt; i++) 628018b991eSAriff Abdullah ret += sc->pch[i].active; 629018b991eSAriff Abdullah 630018b991eSAriff Abdullah for (i = 0; i < sc->rch_cnt; i++) 631018b991eSAriff Abdullah ret += sc->rch[i].active; 632018b991eSAriff Abdullah 633018b991eSAriff Abdullah return (ret); 634018b991eSAriff Abdullah } 635018b991eSAriff Abdullah 636018b991eSAriff Abdullah static int 637c21880a7SPyun YongHyeon m3_pchan_trigger_locked(kobj_t kobj, void *chdata, int go) 638c21880a7SPyun YongHyeon { 639c21880a7SPyun YongHyeon struct sc_pchinfo *ch = chdata; 640c21880a7SPyun YongHyeon struct sc_info *sc = ch->parent; 641a5108eaeSScott Long u_int32_t data; 642a5108eaeSScott Long 643c21880a7SPyun YongHyeon M3_LOCK_ASSERT(sc); 644a5108eaeSScott Long M3_DEBUG(go == PCMTRIG_START ? CHANGE : 645a5108eaeSScott Long go == PCMTRIG_STOP ? CHANGE : 646a5108eaeSScott Long go == PCMTRIG_ABORT ? CHANGE : 647a5108eaeSScott Long CALL, 648a5108eaeSScott Long ("m3_pchan_trigger(dac=%d, go=0x%x{%s})\n", ch->dac_idx, go, 649a5108eaeSScott Long go == PCMTRIG_START ? "PCMTRIG_START" : 650a5108eaeSScott Long go == PCMTRIG_STOP ? "PCMTRIG_STOP" : 651a5108eaeSScott Long go == PCMTRIG_ABORT ? "PCMTRIG_ABORT" : "ignore")); 652a5108eaeSScott Long 653a5108eaeSScott Long switch(go) { 654a5108eaeSScott Long case PCMTRIG_START: 655a5108eaeSScott Long if (ch->active) { 656a5108eaeSScott Long return 0; 657a5108eaeSScott Long } 658a5108eaeSScott Long ch->active = 1; 659018b991eSAriff Abdullah ch->ptr = 0; 660018b991eSAriff Abdullah ch->prevptr = 0; 661a5108eaeSScott Long sc->pch_active_cnt++; 662a5108eaeSScott Long 663a5108eaeSScott Long /*[[inc_timer_users]]*/ 664018b991eSAriff Abdullah if (m3_chan_active(sc) == 1) { 665a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_TIMER_COUNT_RELOAD, 240); 666a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_TIMER_COUNT_CURRENT, 240); 667a5108eaeSScott Long data = m3_rd_2(sc, HOST_INT_CTRL); 668a5108eaeSScott Long m3_wr_2(sc, HOST_INT_CTRL, data | CLKRUN_GEN_ENABLE); 669018b991eSAriff Abdullah } 670a5108eaeSScott Long 671a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_INSTANCE_READY, 1); 672a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_MIXER_TASK_NUMBER, 673a5108eaeSScott Long sc->pch_active_cnt); 674a5108eaeSScott Long break; 675a5108eaeSScott Long 676a5108eaeSScott Long case PCMTRIG_STOP: 677a5108eaeSScott Long case PCMTRIG_ABORT: 678a5108eaeSScott Long if (ch->active == 0) { 679a5108eaeSScott Long return 0; 680a5108eaeSScott Long } 681a5108eaeSScott Long ch->active = 0; 682a5108eaeSScott Long sc->pch_active_cnt--; 683a5108eaeSScott Long 684a5108eaeSScott Long /* XXX should the channel be drained? */ 685a5108eaeSScott Long /*[[dec_timer_users]]*/ 686018b991eSAriff Abdullah if (m3_chan_active(sc) == 0) { 687a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_TIMER_COUNT_RELOAD, 0); 688a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_TIMER_COUNT_CURRENT, 0); 689a5108eaeSScott Long data = m3_rd_2(sc, HOST_INT_CTRL); 690a5108eaeSScott Long m3_wr_2(sc, HOST_INT_CTRL, data & ~CLKRUN_GEN_ENABLE); 691018b991eSAriff Abdullah } 692a5108eaeSScott Long 693a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_INSTANCE_READY, 0); 694a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_MIXER_TASK_NUMBER, 695a5108eaeSScott Long sc->pch_active_cnt); 696a5108eaeSScott Long break; 697a5108eaeSScott Long 698a5108eaeSScott Long case PCMTRIG_EMLDMAWR: 699a5108eaeSScott Long /* got play irq, transfer next buffer - ignore if using dma */ 700a5108eaeSScott Long case PCMTRIG_EMLDMARD: 701a5108eaeSScott Long /* got rec irq, transfer next buffer - ignore if using dma */ 702a5108eaeSScott Long default: 703a5108eaeSScott Long break; 704a5108eaeSScott Long } 705a5108eaeSScott Long return 0; 706a5108eaeSScott Long } 707a5108eaeSScott Long 708018b991eSAriff Abdullah static u_int32_t 709018b991eSAriff Abdullah m3_pchan_getptr_internal(struct sc_pchinfo *ch) 710a5108eaeSScott Long { 711a5108eaeSScott Long struct sc_info *sc = ch->parent; 712c21880a7SPyun YongHyeon u_int32_t hi, lo, bus_base, bus_crnt; 713a5108eaeSScott Long 714c21880a7SPyun YongHyeon bus_base = sndbuf_getbufaddr(ch->buffer); 715a5108eaeSScott Long hi = m3_rd_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_CURRENTH); 716a5108eaeSScott Long lo = m3_rd_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_CURRENTL); 717a5108eaeSScott Long bus_crnt = lo | (hi << 16); 718a5108eaeSScott Long 719a5108eaeSScott Long M3_DEBUG(CALL, ("m3_pchan_getptr(dac=%d) result=%d\n", 720a5108eaeSScott Long ch->dac_idx, bus_crnt - bus_base)); 721a5108eaeSScott Long 722a5108eaeSScott Long return (bus_crnt - bus_base); /* current byte offset of channel */ 723a5108eaeSScott Long } 724a5108eaeSScott Long 725018b991eSAriff Abdullah static u_int32_t 726018b991eSAriff Abdullah m3_pchan_getptr(kobj_t kobj, void *chdata) 727018b991eSAriff Abdullah { 728018b991eSAriff Abdullah struct sc_pchinfo *ch = chdata; 729018b991eSAriff Abdullah struct sc_info *sc = ch->parent; 730018b991eSAriff Abdullah u_int32_t ptr; 731018b991eSAriff Abdullah 732018b991eSAriff Abdullah M3_LOCK(sc); 733018b991eSAriff Abdullah ptr = ch->ptr; 734018b991eSAriff Abdullah M3_UNLOCK(sc); 735018b991eSAriff Abdullah 736018b991eSAriff Abdullah return (ptr); 737018b991eSAriff Abdullah } 738018b991eSAriff Abdullah 73966ef8af5SCameron Grant static struct pcmchan_caps * 740a5108eaeSScott Long m3_pchan_getcaps(kobj_t kobj, void *chdata) 741a5108eaeSScott Long { 742a5108eaeSScott Long struct sc_pchinfo *ch = chdata; 743a5108eaeSScott Long 744a5108eaeSScott Long M3_DEBUG(CALL, ("m3_pchan_getcaps(dac=%d)\n", ch->dac_idx)); 745a5108eaeSScott Long 746a5108eaeSScott Long return &m3_playcaps; 747a5108eaeSScott Long } 748a5108eaeSScott Long 749a5108eaeSScott Long /* -------------------------------------------------------------------- */ 750a5108eaeSScott Long /* rec channel interface */ 751a5108eaeSScott Long 752a5108eaeSScott Long static void * 75366ef8af5SCameron Grant m3_rchan_init(kobj_t kobj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 754a5108eaeSScott Long { 755a5108eaeSScott Long struct sc_info *sc = devinfo; 756a5108eaeSScott Long struct sc_rchinfo *ch; 757a5108eaeSScott Long u_int32_t bus_addr, i; 758a5108eaeSScott Long 759c21880a7SPyun YongHyeon int idx, data_bytes, adc_data; 760c21880a7SPyun YongHyeon int dsp_in_size, dsp_out_size, dsp_in_buf, dsp_out_buf; 761a5108eaeSScott Long 7625dcd37b1SPedro F. Giffuni struct data_word { 7635dcd37b1SPedro F. Giffuni u_int16_t addr, val; 7645dcd37b1SPedro F. Giffuni } rv[] = { 7655dcd37b1SPedro F. Giffuni {CDATA_LEFT_VOLUME, M3_DEFAULT_VOL}, 7665dcd37b1SPedro F. Giffuni {CDATA_RIGHT_VOLUME, M3_DEFAULT_VOL}, 7675dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET, 1}, 7685dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 3, 0x0000}, 7695dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 4, 0}, 7705dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 5, 0}, 7715dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 6, 0}, 7725dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 7, 0}, 7735dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 8, 0}, 7745dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 9, 0}, 7755dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 10, 0x8000}, 7765dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 11, 0xFF00}, 7775dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 13, 0}, 7785dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 14, 0}, 7795dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 15, 0}, 7805dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 16, 50}, 7815dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 17, 8}, 7825dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 18, 0}, 7835dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 19, 0}, 7845dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 20, 0}, 7855dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 21, 0}, 7865dcd37b1SPedro F. Giffuni {SRC3_DIRECTION_OFFSET + 22, 0xff} 7875dcd37b1SPedro F. Giffuni }; 7885dcd37b1SPedro F. Giffuni 789c21880a7SPyun YongHyeon M3_LOCK(sc); 790c21880a7SPyun YongHyeon idx = sc->rch_cnt; /* adc instance number, no active reuse! */ 791a5108eaeSScott Long M3_DEBUG(CHANGE, ("m3_rchan_init(adc=%d)\n", idx)); 792a5108eaeSScott Long 793a5108eaeSScott Long if (dir != PCMDIR_REC) { 794c21880a7SPyun YongHyeon M3_UNLOCK(sc); 795a5108eaeSScott Long device_printf(sc->dev, "m3_pchan_init not PCMDIR_REC\n"); 796c21880a7SPyun YongHyeon return (NULL); 797a5108eaeSScott Long } 798a5108eaeSScott Long 799c21880a7SPyun YongHyeon data_bytes = (((MINISRC_TMP_BUFFER_SIZE & ~1) + 800c21880a7SPyun YongHyeon (MINISRC_IN_BUFFER_SIZE & ~1) + 801c21880a7SPyun YongHyeon (MINISRC_OUT_BUFFER_SIZE & ~1) + 4) + 255) &~ 255; 802c21880a7SPyun YongHyeon adc_data = 0x1100 + (data_bytes * idx) + data_bytes/2; 803c21880a7SPyun YongHyeon dsp_in_size = MINISRC_IN_BUFFER_SIZE + (0x10 * 2); 804c21880a7SPyun YongHyeon dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x10 * 2); 805c21880a7SPyun YongHyeon dsp_in_buf = adc_data + (MINISRC_TMP_BUFFER_SIZE / 2); 806c21880a7SPyun YongHyeon dsp_out_buf = dsp_in_buf + (dsp_in_size / 2) + 1; 807c21880a7SPyun YongHyeon 808c21880a7SPyun YongHyeon ch = &sc->rch[idx]; 809a5108eaeSScott Long ch->adc_idx = idx; 810a5108eaeSScott Long ch->adc_data = adc_data; 811a5108eaeSScott Long if (ch->adc_data + data_bytes/2 >= 0x1c00) { 812c21880a7SPyun YongHyeon M3_UNLOCK(sc); 813a5108eaeSScott Long device_printf(sc->dev, "m3_rchan_init: revb mem exhausted\n"); 814c21880a7SPyun YongHyeon return (NULL); 815a5108eaeSScott Long } 816a5108eaeSScott Long 817a5108eaeSScott Long ch->buffer = b; 818a5108eaeSScott Long ch->parent = sc; 819a5108eaeSScott Long ch->channel = c; 82090da2b28SAriff Abdullah ch->fmt = SND_FORMAT(AFMT_U8, 1, 0); 821a5108eaeSScott Long ch->spd = DSP_DEFAULT_SPEED; 822c21880a7SPyun YongHyeon M3_UNLOCK(sc); /* XXX */ 8232e334adfSAriff Abdullah if (sndbuf_alloc(ch->buffer, sc->parent_dmat, 0, sc->bufsz) != 0) { 824a5108eaeSScott Long device_printf(sc->dev, "m3_rchan_init chn_allocbuf failed\n"); 825c21880a7SPyun YongHyeon return (NULL); 826a5108eaeSScott Long } 827c21880a7SPyun YongHyeon M3_LOCK(sc); 828a5108eaeSScott Long ch->bufsize = sndbuf_getsize(ch->buffer); 829a5108eaeSScott Long 830a5108eaeSScott Long /* host dma buffer pointers */ 83138cc9942SOlivier Houchard bus_addr = sndbuf_getbufaddr(ch->buffer); 832a5108eaeSScott Long if (bus_addr & 3) { 833a5108eaeSScott Long device_printf(sc->dev, "m3_rchan_init unaligned bus_addr\n"); 834a5108eaeSScott Long bus_addr = (bus_addr + 4) & ~3; 835a5108eaeSScott Long } 836a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_ADDRL, LO(bus_addr)); 837a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_ADDRH, HI(bus_addr)); 838a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_END_PLUS_1L, 839a5108eaeSScott Long LO(bus_addr + ch->bufsize)); 840a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_END_PLUS_1H, 841a5108eaeSScott Long HI(bus_addr + ch->bufsize)); 842a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_CURRENTL, 843a5108eaeSScott Long LO(bus_addr)); 844a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_CURRENTH, 845a5108eaeSScott Long HI(bus_addr)); 846a5108eaeSScott Long 847a5108eaeSScott Long /* dsp buffers */ 848a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_IN_BUF_BEGIN, dsp_in_buf); 849a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_IN_BUF_END_PLUS_1, 850a5108eaeSScott Long dsp_in_buf + dsp_in_size/2); 851a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_IN_BUF_HEAD, dsp_in_buf); 852a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_IN_BUF_TAIL, dsp_in_buf); 853a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_OUT_BUF_BEGIN, dsp_out_buf); 854a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_OUT_BUF_END_PLUS_1, 855a5108eaeSScott Long dsp_out_buf + dsp_out_size/2); 856a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_OUT_BUF_HEAD, dsp_out_buf); 857a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_OUT_BUF_TAIL, dsp_out_buf); 858a5108eaeSScott Long 859a5108eaeSScott Long /* some per client initializers */ 860a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + SRC3_DIRECTION_OFFSET + 12, 861a5108eaeSScott Long ch->adc_data + 40 + 8); 862a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_DMA_CONTROL, 863a5108eaeSScott Long DMACONTROL_DIRECTION + DMACONTROL_AUTOREPEAT + 864a5108eaeSScott Long DMAC_PAGE3_SELECTOR + DMAC_BLOCKF_SELECTOR); 865a5108eaeSScott Long 866a5108eaeSScott Long /* set an armload of static initializers */ 867a5108eaeSScott Long for(i = 0 ; i < (sizeof(rv) / sizeof(rv[0])) ; i++) { 868a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + rv[i].addr, rv[i].val); 869a5108eaeSScott Long } 870a5108eaeSScott Long 871a5108eaeSScott Long /* put us in the packed task lists */ 872a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_INSTANCE0_MINISRC + 873a5108eaeSScott Long (sc->pch_cnt + sc->rch_cnt), 874a5108eaeSScott Long ch->adc_data >> DP_SHIFT_COUNT); 875a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_DMA_XFER0 + (sc->pch_cnt + sc->rch_cnt), 876a5108eaeSScott Long ch->adc_data >> DP_SHIFT_COUNT); 877a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_ADC1_XFER0 + sc->rch_cnt, 878a5108eaeSScott Long ch->adc_data >> DP_SHIFT_COUNT); 879a5108eaeSScott Long 880c21880a7SPyun YongHyeon /* gotta start before stop */ 881c21880a7SPyun YongHyeon m3_rchan_trigger_locked(NULL, ch, PCMTRIG_START); 882c21880a7SPyun YongHyeon /* stop on init */ 883c21880a7SPyun YongHyeon m3_rchan_trigger_locked(NULL, ch, PCMTRIG_STOP); 884a5108eaeSScott Long 885a5108eaeSScott Long sc->rch_cnt++; 886c21880a7SPyun YongHyeon M3_UNLOCK(sc); 887c21880a7SPyun YongHyeon 888c21880a7SPyun YongHyeon return (ch); 889a5108eaeSScott Long } 890a5108eaeSScott Long 891a5108eaeSScott Long static int 892a5108eaeSScott Long m3_rchan_free(kobj_t kobj, void *chdata) 893a5108eaeSScott Long { 894a5108eaeSScott Long struct sc_rchinfo *ch = chdata; 895a5108eaeSScott Long struct sc_info *sc = ch->parent; 896a5108eaeSScott Long 897c21880a7SPyun YongHyeon M3_LOCK(sc); 898a5108eaeSScott Long M3_DEBUG(CHANGE, ("m3_rchan_free(adc=%d)\n", ch->adc_idx)); 899a5108eaeSScott Long 900a5108eaeSScott Long /* 901a5108eaeSScott Long * should remove this exact instance from the packed lists, but all 902a5108eaeSScott Long * are released at once (and in a stopped state) so this is ok. 903a5108eaeSScott Long */ 904a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_INSTANCE0_MINISRC + 905a5108eaeSScott Long (sc->rch_cnt - 1) + sc->pch_cnt, 0); 906a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_DMA_XFER0 + 907a5108eaeSScott Long (sc->rch_cnt - 1) + sc->pch_cnt, 0); 908a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_ADC1_XFER0 + (sc->rch_cnt - 1), 0); 909a5108eaeSScott Long sc->rch_cnt--; 910c21880a7SPyun YongHyeon M3_UNLOCK(sc); 911c21880a7SPyun YongHyeon 912c21880a7SPyun YongHyeon return (0); 913a5108eaeSScott Long } 914a5108eaeSScott Long 915a5108eaeSScott Long static int 916a5108eaeSScott Long m3_rchan_setformat(kobj_t kobj, void *chdata, u_int32_t format) 917a5108eaeSScott Long { 918a5108eaeSScott Long struct sc_rchinfo *ch = chdata; 919a5108eaeSScott Long struct sc_info *sc = ch->parent; 920a5108eaeSScott Long u_int32_t data; 921a5108eaeSScott Long 922c21880a7SPyun YongHyeon M3_LOCK(sc); 923a5108eaeSScott Long M3_DEBUG(CHANGE, 924a5108eaeSScott Long ("m3_rchan_setformat(dac=%d, format=0x%x{%s-%s})\n", 925a5108eaeSScott Long ch->adc_idx, format, 926a5108eaeSScott Long format & (AFMT_U8|AFMT_S8) ? "8bit":"16bit", 92790da2b28SAriff Abdullah (AFMT_CHANNEL(format) > 1) ? "STEREO":"MONO")); 928a5108eaeSScott Long 929a5108eaeSScott Long /* mono word */ 93090da2b28SAriff Abdullah data = (AFMT_CHANNEL(format) > 1) ? 0 : 1; 931a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + SRC3_MODE_OFFSET, data); 932a5108eaeSScott Long 933a5108eaeSScott Long /* 8bit word */ 934a5108eaeSScott Long data = ((format & AFMT_U8) || (format & AFMT_S8)) ? 1 : 0; 935a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + SRC3_WORD_LENGTH_OFFSET, data); 936a5108eaeSScott Long ch->fmt = format; 937c21880a7SPyun YongHyeon M3_UNLOCK(sc); 938c21880a7SPyun YongHyeon 939c21880a7SPyun YongHyeon return (0); 940a5108eaeSScott Long } 941a5108eaeSScott Long 94290da2b28SAriff Abdullah static u_int32_t 943a5108eaeSScott Long m3_rchan_setspeed(kobj_t kobj, void *chdata, u_int32_t speed) 944a5108eaeSScott Long { 945a5108eaeSScott Long struct sc_rchinfo *ch = chdata; 946a5108eaeSScott Long struct sc_info *sc = ch->parent; 947a5108eaeSScott Long u_int32_t freq; 948a5108eaeSScott Long 949c21880a7SPyun YongHyeon M3_LOCK(sc); 950a5108eaeSScott Long M3_DEBUG(CHANGE, ("m3_rchan_setspeed(adc=%d, speed=%d)\n", 951a5108eaeSScott Long ch->adc_idx, speed)); 952a5108eaeSScott Long 953a5108eaeSScott Long if ((freq = ((speed << 15) + 24000) / 48000) != 0) { 954a5108eaeSScott Long freq--; 955a5108eaeSScott Long } 956a5108eaeSScott Long 957a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_FREQUENCY, freq); 958a5108eaeSScott Long ch->spd = speed; 959c21880a7SPyun YongHyeon M3_UNLOCK(sc); 960c21880a7SPyun YongHyeon 961c21880a7SPyun YongHyeon /* return closest possible speed */ 962c21880a7SPyun YongHyeon return (speed); 963a5108eaeSScott Long } 964a5108eaeSScott Long 96590da2b28SAriff Abdullah static u_int32_t 966a5108eaeSScott Long m3_rchan_setblocksize(kobj_t kobj, void *chdata, u_int32_t blocksize) 967a5108eaeSScott Long { 968a5108eaeSScott Long struct sc_rchinfo *ch = chdata; 969a5108eaeSScott Long 970a5108eaeSScott Long M3_DEBUG(CHANGE, ("m3_rchan_setblocksize(adc=%d, blocksize=%d)\n", 971a5108eaeSScott Long ch->adc_idx, blocksize)); 972a5108eaeSScott Long 973018b991eSAriff Abdullah return (sndbuf_getblksz(ch->buffer)); 974a5108eaeSScott Long } 975a5108eaeSScott Long 976a5108eaeSScott Long static int 977a5108eaeSScott Long m3_rchan_trigger(kobj_t kobj, void *chdata, int go) 978a5108eaeSScott Long { 979a5108eaeSScott Long struct sc_rchinfo *ch = chdata; 980a5108eaeSScott Long struct sc_info *sc = ch->parent; 981c21880a7SPyun YongHyeon int ret; 982c21880a7SPyun YongHyeon 983bdfbdcecSAriff Abdullah if (!PCMTRIG_COMMON(go)) 984bdfbdcecSAriff Abdullah return (0); 985bdfbdcecSAriff Abdullah 986c21880a7SPyun YongHyeon M3_LOCK(sc); 987c21880a7SPyun YongHyeon ret = m3_rchan_trigger_locked(kobj, chdata, go); 988c21880a7SPyun YongHyeon M3_UNLOCK(sc); 989c21880a7SPyun YongHyeon 990c21880a7SPyun YongHyeon return (ret); 991c21880a7SPyun YongHyeon } 992c21880a7SPyun YongHyeon 993c21880a7SPyun YongHyeon static int 994c21880a7SPyun YongHyeon m3_rchan_trigger_locked(kobj_t kobj, void *chdata, int go) 995c21880a7SPyun YongHyeon { 996c21880a7SPyun YongHyeon struct sc_rchinfo *ch = chdata; 997c21880a7SPyun YongHyeon struct sc_info *sc = ch->parent; 998a5108eaeSScott Long u_int32_t data; 999a5108eaeSScott Long 1000c21880a7SPyun YongHyeon M3_LOCK_ASSERT(sc); 1001a5108eaeSScott Long M3_DEBUG(go == PCMTRIG_START ? CHANGE : 1002a5108eaeSScott Long go == PCMTRIG_STOP ? CHANGE : 1003a5108eaeSScott Long go == PCMTRIG_ABORT ? CHANGE : 1004a5108eaeSScott Long CALL, 1005a5108eaeSScott Long ("m3_rchan_trigger(adc=%d, go=0x%x{%s})\n", ch->adc_idx, go, 1006a5108eaeSScott Long go == PCMTRIG_START ? "PCMTRIG_START" : 1007a5108eaeSScott Long go == PCMTRIG_STOP ? "PCMTRIG_STOP" : 1008a5108eaeSScott Long go == PCMTRIG_ABORT ? "PCMTRIG_ABORT" : "ignore")); 1009a5108eaeSScott Long 1010a5108eaeSScott Long switch(go) { 1011a5108eaeSScott Long case PCMTRIG_START: 1012a5108eaeSScott Long if (ch->active) { 1013a5108eaeSScott Long return 0; 1014a5108eaeSScott Long } 1015a5108eaeSScott Long ch->active = 1; 1016018b991eSAriff Abdullah ch->ptr = 0; 1017018b991eSAriff Abdullah ch->prevptr = 0; 1018a5108eaeSScott Long 1019a5108eaeSScott Long /*[[inc_timer_users]]*/ 1020018b991eSAriff Abdullah if (m3_chan_active(sc) == 1) { 1021a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_TIMER_COUNT_RELOAD, 240); 1022a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_TIMER_COUNT_CURRENT, 240); 1023a5108eaeSScott Long data = m3_rd_2(sc, HOST_INT_CTRL); 1024a5108eaeSScott Long m3_wr_2(sc, HOST_INT_CTRL, data | CLKRUN_GEN_ENABLE); 1025018b991eSAriff Abdullah } 1026a5108eaeSScott Long 1027a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_ADC1_REQUEST, 1); 1028a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_INSTANCE_READY, 1); 1029a5108eaeSScott Long break; 1030a5108eaeSScott Long 1031a5108eaeSScott Long case PCMTRIG_STOP: 1032a5108eaeSScott Long case PCMTRIG_ABORT: 1033a5108eaeSScott Long if (ch->active == 0) { 1034a5108eaeSScott Long return 0; 1035a5108eaeSScott Long } 1036a5108eaeSScott Long ch->active = 0; 1037a5108eaeSScott Long 1038a5108eaeSScott Long /*[[dec_timer_users]]*/ 1039018b991eSAriff Abdullah if (m3_chan_active(sc) == 0) { 1040a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_TIMER_COUNT_RELOAD, 0); 1041a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_TIMER_COUNT_CURRENT, 0); 1042a5108eaeSScott Long data = m3_rd_2(sc, HOST_INT_CTRL); 1043a5108eaeSScott Long m3_wr_2(sc, HOST_INT_CTRL, data & ~CLKRUN_GEN_ENABLE); 1044018b991eSAriff Abdullah } 1045a5108eaeSScott Long 1046a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_INSTANCE_READY, 0); 1047a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_ADC1_REQUEST, 0); 1048a5108eaeSScott Long break; 1049a5108eaeSScott Long 1050a5108eaeSScott Long case PCMTRIG_EMLDMAWR: 1051a5108eaeSScott Long /* got play irq, transfer next buffer - ignore if using dma */ 1052a5108eaeSScott Long case PCMTRIG_EMLDMARD: 1053a5108eaeSScott Long /* got rec irq, transfer next buffer - ignore if using dma */ 1054a5108eaeSScott Long default: 1055a5108eaeSScott Long break; 1056a5108eaeSScott Long } 1057a5108eaeSScott Long return 0; 1058a5108eaeSScott Long } 1059a5108eaeSScott Long 1060018b991eSAriff Abdullah static u_int32_t 1061018b991eSAriff Abdullah m3_rchan_getptr_internal(struct sc_rchinfo *ch) 1062a5108eaeSScott Long { 1063a5108eaeSScott Long struct sc_info *sc = ch->parent; 1064c21880a7SPyun YongHyeon u_int32_t hi, lo, bus_base, bus_crnt; 1065a5108eaeSScott Long 1066c21880a7SPyun YongHyeon bus_base = sndbuf_getbufaddr(ch->buffer); 1067a5108eaeSScott Long hi = m3_rd_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_CURRENTH); 1068a5108eaeSScott Long lo = m3_rd_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_CURRENTL); 1069a5108eaeSScott Long bus_crnt = lo | (hi << 16); 1070a5108eaeSScott Long 1071a5108eaeSScott Long M3_DEBUG(CALL, ("m3_rchan_getptr(adc=%d) result=%d\n", 1072a5108eaeSScott Long ch->adc_idx, bus_crnt - bus_base)); 1073a5108eaeSScott Long 1074a5108eaeSScott Long return (bus_crnt - bus_base); /* current byte offset of channel */ 1075a5108eaeSScott Long } 1076a5108eaeSScott Long 1077018b991eSAriff Abdullah static u_int32_t 1078018b991eSAriff Abdullah m3_rchan_getptr(kobj_t kobj, void *chdata) 1079018b991eSAriff Abdullah { 1080018b991eSAriff Abdullah struct sc_rchinfo *ch = chdata; 1081018b991eSAriff Abdullah struct sc_info *sc = ch->parent; 1082018b991eSAriff Abdullah u_int32_t ptr; 1083018b991eSAriff Abdullah 1084018b991eSAriff Abdullah M3_LOCK(sc); 1085018b991eSAriff Abdullah ptr = ch->ptr; 1086018b991eSAriff Abdullah M3_UNLOCK(sc); 1087018b991eSAriff Abdullah 1088018b991eSAriff Abdullah return (ptr); 1089018b991eSAriff Abdullah } 1090018b991eSAriff Abdullah 109166ef8af5SCameron Grant static struct pcmchan_caps * 1092a5108eaeSScott Long m3_rchan_getcaps(kobj_t kobj, void *chdata) 1093a5108eaeSScott Long { 1094a5108eaeSScott Long struct sc_rchinfo *ch = chdata; 1095a5108eaeSScott Long 1096a5108eaeSScott Long M3_DEBUG(CALL, ("m3_rchan_getcaps(adc=%d)\n", ch->adc_idx)); 1097a5108eaeSScott Long 1098a5108eaeSScott Long return &m3_reccaps; 1099a5108eaeSScott Long } 1100a5108eaeSScott Long 1101a5108eaeSScott Long /* -------------------------------------------------------------------- */ 1102a5108eaeSScott Long /* The interrupt handler */ 1103a5108eaeSScott Long 1104a5108eaeSScott Long static void 1105a5108eaeSScott Long m3_intr(void *p) 1106a5108eaeSScott Long { 1107a5108eaeSScott Long struct sc_info *sc = (struct sc_info *)p; 1108018b991eSAriff Abdullah struct sc_pchinfo *pch; 1109018b991eSAriff Abdullah struct sc_rchinfo *rch; 1110018b991eSAriff Abdullah u_int32_t status, ctl, i, delta; 1111a5108eaeSScott Long 1112a5108eaeSScott Long M3_DEBUG(INTR, ("m3_intr\n")); 1113a5108eaeSScott Long 1114c21880a7SPyun YongHyeon M3_LOCK(sc); 1115a5108eaeSScott Long status = m3_rd_1(sc, HOST_INT_STATUS); 1116c21880a7SPyun YongHyeon if (!status) { 1117c21880a7SPyun YongHyeon M3_UNLOCK(sc); 1118a5108eaeSScott Long return; 1119c21880a7SPyun YongHyeon } 1120a5108eaeSScott Long 1121a5108eaeSScott Long m3_wr_1(sc, HOST_INT_STATUS, 0xff); /* ack the int? */ 1122a5108eaeSScott Long 1123a5108eaeSScott Long if (status & HV_INT_PENDING) { 1124a5108eaeSScott Long u_int8_t event; 1125a5108eaeSScott Long 1126a5108eaeSScott Long event = m3_rd_1(sc, HW_VOL_COUNTER_MASTER); 1127a5108eaeSScott Long switch (event) { 1128a5108eaeSScott Long case 0x99: 1129a5108eaeSScott Long mixer_hwvol_mute(sc->dev); 1130a5108eaeSScott Long break; 1131a5108eaeSScott Long case 0xaa: 1132a5108eaeSScott Long mixer_hwvol_step(sc->dev, 1, 1); 1133a5108eaeSScott Long break; 1134a5108eaeSScott Long case 0x66: 1135a5108eaeSScott Long mixer_hwvol_step(sc->dev, -1, -1); 1136a5108eaeSScott Long break; 1137a5108eaeSScott Long case 0x88: 1138a5108eaeSScott Long break; 1139a5108eaeSScott Long default: 1140a5108eaeSScott Long device_printf(sc->dev, "Unknown HWVOL event\n"); 1141a5108eaeSScott Long } 1142a5108eaeSScott Long m3_wr_1(sc, HW_VOL_COUNTER_MASTER, 0x88); 1143a5108eaeSScott Long 1144a5108eaeSScott Long } 1145a5108eaeSScott Long 1146a5108eaeSScott Long if (status & ASSP_INT_PENDING) { 1147a5108eaeSScott Long ctl = m3_rd_1(sc, ASSP_CONTROL_B); 1148a5108eaeSScott Long if (!(ctl & STOP_ASSP_CLOCK)) { 1149a5108eaeSScott Long ctl = m3_rd_1(sc, ASSP_HOST_INT_STATUS); 1150a5108eaeSScott Long if (ctl & DSP2HOST_REQ_TIMER) { 1151a5108eaeSScott Long m3_wr_1(sc, ASSP_HOST_INT_STATUS, 1152a5108eaeSScott Long DSP2HOST_REQ_TIMER); 1153a5108eaeSScott Long /*[[ess_update_ptr]]*/ 1154018b991eSAriff Abdullah goto m3_handle_channel_intr; 1155a5108eaeSScott Long } 1156a5108eaeSScott Long } 1157a5108eaeSScott Long } 1158a5108eaeSScott Long 1159018b991eSAriff Abdullah goto m3_handle_channel_intr_out; 1160018b991eSAriff Abdullah 1161018b991eSAriff Abdullah m3_handle_channel_intr: 1162a5108eaeSScott Long for (i=0 ; i<sc->pch_cnt ; i++) { 1163018b991eSAriff Abdullah pch = &sc->pch[i]; 1164018b991eSAriff Abdullah if (pch->active) { 1165018b991eSAriff Abdullah pch->ptr = m3_pchan_getptr_internal(pch); 1166018b991eSAriff Abdullah delta = pch->bufsize + pch->ptr - pch->prevptr; 1167018b991eSAriff Abdullah delta %= pch->bufsize; 1168018b991eSAriff Abdullah if (delta < sndbuf_getblksz(pch->buffer)) 1169018b991eSAriff Abdullah continue; 1170018b991eSAriff Abdullah pch->prevptr = pch->ptr; 1171c21880a7SPyun YongHyeon M3_UNLOCK(sc); 1172018b991eSAriff Abdullah chn_intr(pch->channel); 1173c21880a7SPyun YongHyeon M3_LOCK(sc); 1174a5108eaeSScott Long } 1175a5108eaeSScott Long } 1176a5108eaeSScott Long for (i=0 ; i<sc->rch_cnt ; i++) { 1177018b991eSAriff Abdullah rch = &sc->rch[i]; 1178018b991eSAriff Abdullah if (rch->active) { 1179018b991eSAriff Abdullah rch->ptr = m3_rchan_getptr_internal(rch); 1180018b991eSAriff Abdullah delta = rch->bufsize + rch->ptr - rch->prevptr; 1181018b991eSAriff Abdullah delta %= rch->bufsize; 1182018b991eSAriff Abdullah if (delta < sndbuf_getblksz(rch->buffer)) 1183018b991eSAriff Abdullah continue; 1184018b991eSAriff Abdullah rch->prevptr = rch->ptr; 1185c21880a7SPyun YongHyeon M3_UNLOCK(sc); 1186018b991eSAriff Abdullah chn_intr(rch->channel); 1187c21880a7SPyun YongHyeon M3_LOCK(sc); 1188a5108eaeSScott Long } 1189a5108eaeSScott Long } 1190c21880a7SPyun YongHyeon 1191018b991eSAriff Abdullah m3_handle_channel_intr_out: 1192c21880a7SPyun YongHyeon M3_UNLOCK(sc); 1193a5108eaeSScott Long } 1194a5108eaeSScott Long 1195a5108eaeSScott Long /* -------------------------------------------------------------------- */ 1196a5108eaeSScott Long /* stuff */ 1197a5108eaeSScott Long 1198a5108eaeSScott Long static int 1199a5108eaeSScott Long m3_power(struct sc_info *sc, int state) 1200a5108eaeSScott Long { 1201a5108eaeSScott Long u_int32_t data; 1202a5108eaeSScott Long 1203a5108eaeSScott Long M3_DEBUG(CHANGE, ("m3_power(%d)\n", state)); 1204c21880a7SPyun YongHyeon M3_LOCK_ASSERT(sc); 1205a5108eaeSScott Long 1206a5108eaeSScott Long data = pci_read_config(sc->dev, 0x34, 1); 1207a5108eaeSScott Long if (pci_read_config(sc->dev, data, 1) == 1) { 1208a5108eaeSScott Long pci_write_config(sc->dev, data + 4, state, 1); 1209a5108eaeSScott Long } 1210a5108eaeSScott Long 1211a5108eaeSScott Long return 0; 1212a5108eaeSScott Long } 1213a5108eaeSScott Long 1214a5108eaeSScott Long static int 1215a5108eaeSScott Long m3_init(struct sc_info *sc) 1216a5108eaeSScott Long { 1217a5108eaeSScott Long u_int32_t data, i, size; 1218a5108eaeSScott Long u_int8_t reset_state; 1219a5108eaeSScott Long 1220c21880a7SPyun YongHyeon M3_LOCK_ASSERT(sc); 1221a5108eaeSScott Long M3_DEBUG(CHANGE, ("m3_init\n")); 1222a5108eaeSScott Long 1223a5108eaeSScott Long /* diable legacy emulations. */ 1224a5108eaeSScott Long data = pci_read_config(sc->dev, PCI_LEGACY_AUDIO_CTRL, 2); 1225a5108eaeSScott Long data |= DISABLE_LEGACY; 1226a5108eaeSScott Long pci_write_config(sc->dev, PCI_LEGACY_AUDIO_CTRL, data, 2); 1227a5108eaeSScott Long 1228a5108eaeSScott Long m3_config(sc); 1229a5108eaeSScott Long 1230a5108eaeSScott Long reset_state = m3_assp_halt(sc); 1231a5108eaeSScott Long 1232a5108eaeSScott Long m3_codec_reset(sc); 1233a5108eaeSScott Long 1234a5108eaeSScott Long /* [m3_assp_init] */ 1235a5108eaeSScott Long /* zero kernel data */ 1236a5108eaeSScott Long size = REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA; 1237a5108eaeSScott Long for(i = 0 ; i < size / 2 ; i++) { 1238a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_BASE_ADDR + i, 0); 1239a5108eaeSScott Long } 1240a5108eaeSScott Long /* zero mixer data? */ 1241a5108eaeSScott Long size = REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA; 1242a5108eaeSScott Long for(i = 0 ; i < size / 2 ; i++) { 1243a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_BASE_ADDR2 + i, 0); 1244a5108eaeSScott Long } 1245a5108eaeSScott Long /* init dma pointer */ 1246a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_CURRENT_DMA, 1247a5108eaeSScott Long KDATA_DMA_XFER0); 1248a5108eaeSScott Long /* write kernel into code memory */ 12495dcd37b1SPedro F. Giffuni size = sizeof(gaw_kernel_vect_code); 1250a5108eaeSScott Long for(i = 0 ; i < size / 2; i++) { 1251a5108eaeSScott Long m3_wr_assp_code(sc, REV_B_CODE_MEMORY_BEGIN + i, 12525dcd37b1SPedro F. Giffuni gaw_kernel_vect_code[i]); 1253a5108eaeSScott Long } 1254a5108eaeSScott Long /* 1255a5108eaeSScott Long * We only have this one client and we know that 0x400 is free in 1256a5108eaeSScott Long * our kernel's mem map, so lets just drop it there. It seems that 1257a5108eaeSScott Long * the minisrc doesn't need vectors, so we won't bother with them.. 1258a5108eaeSScott Long */ 12595dcd37b1SPedro F. Giffuni size = sizeof(gaw_minisrc_code_0400); 1260a5108eaeSScott Long for(i = 0 ; i < size / 2; i++) { 12615dcd37b1SPedro F. Giffuni m3_wr_assp_code(sc, 0x400 + i, gaw_minisrc_code_0400[i]); 1262a5108eaeSScott Long } 1263a5108eaeSScott Long /* write the coefficients for the low pass filter? */ 12645dcd37b1SPedro F. Giffuni size = sizeof(minisrc_lpf); 1265a5108eaeSScott Long for(i = 0; i < size / 2 ; i++) { 1266a5108eaeSScott Long m3_wr_assp_code(sc,0x400 + MINISRC_COEF_LOC + i, 12675dcd37b1SPedro F. Giffuni minisrc_lpf[i]); 1268a5108eaeSScott Long } 1269a5108eaeSScott Long m3_wr_assp_code(sc, 0x400 + MINISRC_COEF_LOC + size, 0x8000); 1270a5108eaeSScott Long /* the minisrc is the only thing on our task list */ 1271a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_TASK0, 0x400); 1272a5108eaeSScott Long /* init the mixer number */ 1273a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_MIXER_TASK_NUMBER, 0); 1274a5108eaeSScott Long /* extreme kernel master volume */ 12755dcd37b1SPedro F. Giffuni m3_wr_assp_data(sc, KDATA_DAC_LEFT_VOLUME, M3_DEFAULT_VOL); 12765dcd37b1SPedro F. Giffuni m3_wr_assp_data(sc, KDATA_DAC_RIGHT_VOLUME, M3_DEFAULT_VOL); 1277a5108eaeSScott Long 1278a5108eaeSScott Long m3_amp_enable(sc); 1279a5108eaeSScott Long 1280a5108eaeSScott Long /* [m3_assp_client_init] (only one client at index 0) */ 1281a5108eaeSScott Long for (i=0x1100 ; i<0x1c00 ; i++) { 1282a5108eaeSScott Long m3_wr_assp_data(sc, i, 0); /* zero entire dac/adc area */ 1283a5108eaeSScott Long } 1284a5108eaeSScott Long 1285a5108eaeSScott Long /* [m3_assp_continue] */ 1286a5108eaeSScott Long m3_wr_1(sc, DSP_PORT_CONTROL_REG_B, reset_state | REGB_ENABLE_RESET); 1287a5108eaeSScott Long 1288a5108eaeSScott Long return 0; 1289a5108eaeSScott Long } 1290a5108eaeSScott Long 1291a5108eaeSScott Long static int 1292a5108eaeSScott Long m3_uninit(struct sc_info *sc) 1293a5108eaeSScott Long { 1294a5108eaeSScott Long M3_DEBUG(CHANGE, ("m3_uninit\n")); 1295a5108eaeSScott Long return 0; 1296a5108eaeSScott Long } 1297a5108eaeSScott Long 1298a5108eaeSScott Long /* -------------------------------------------------------------------- */ 1299a5108eaeSScott Long /* Probe and attach the card */ 1300a5108eaeSScott Long 1301a5108eaeSScott Long static int 1302a5108eaeSScott Long m3_pci_probe(device_t dev) 1303a5108eaeSScott Long { 1304a5108eaeSScott Long struct m3_card_type *card; 1305a5108eaeSScott Long 1306a5108eaeSScott Long M3_DEBUG(CALL, ("m3_pci_probe(0x%x)\n", pci_get_devid(dev))); 1307a5108eaeSScott Long 1308a5108eaeSScott Long for (card = m3_card_types ; card->pci_id ; card++) { 1309a5108eaeSScott Long if (pci_get_devid(dev) == card->pci_id) { 1310a5108eaeSScott Long device_set_desc(dev, card->name); 1311d2b677bbSWarner Losh return BUS_PROBE_DEFAULT; 1312a5108eaeSScott Long } 1313a5108eaeSScott Long } 1314a5108eaeSScott Long return ENXIO; 1315a5108eaeSScott Long } 1316a5108eaeSScott Long 1317a5108eaeSScott Long static int 1318a5108eaeSScott Long m3_pci_attach(device_t dev) 1319a5108eaeSScott Long { 1320a5108eaeSScott Long struct sc_info *sc; 1321a5108eaeSScott Long struct ac97_info *codec = NULL; 1322a5108eaeSScott Long char status[SND_STATUSLEN]; 1323a5108eaeSScott Long struct m3_card_type *card; 1324018b991eSAriff Abdullah int i, len, dacn, adcn; 1325a5108eaeSScott Long 1326a5108eaeSScott Long M3_DEBUG(CALL, ("m3_pci_attach\n")); 1327a5108eaeSScott Long 1328082f6383SAriff Abdullah sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); 1329a5108eaeSScott Long sc->dev = dev; 1330a5108eaeSScott Long sc->type = pci_get_devid(dev); 1331c21880a7SPyun YongHyeon sc->sc_lock = snd_mtxcreate(device_get_nameunit(dev), 13324582b3a1SAriff Abdullah "snd_maestro3 softc"); 1333a5108eaeSScott Long for (card = m3_card_types ; card->pci_id ; card++) { 1334a5108eaeSScott Long if (sc->type == card->pci_id) { 1335a5108eaeSScott Long sc->which = card->which; 1336a5108eaeSScott Long sc->delay1 = card->delay1; 1337a5108eaeSScott Long sc->delay2 = card->delay2; 1338a5108eaeSScott Long break; 1339a5108eaeSScott Long } 1340a5108eaeSScott Long } 1341a5108eaeSScott Long 1342018b991eSAriff Abdullah if (resource_int_value(device_get_name(dev), device_get_unit(dev), 1343018b991eSAriff Abdullah "dac", &i) == 0) { 1344018b991eSAriff Abdullah if (i < 1) 1345018b991eSAriff Abdullah dacn = 1; 1346018b991eSAriff Abdullah else if (i > M3_PCHANS) 1347018b991eSAriff Abdullah dacn = M3_PCHANS; 1348018b991eSAriff Abdullah else 1349018b991eSAriff Abdullah dacn = i; 1350018b991eSAriff Abdullah } else 1351018b991eSAriff Abdullah dacn = M3_PCHANS; 1352018b991eSAriff Abdullah 1353018b991eSAriff Abdullah adcn = M3_RCHANS; 1354018b991eSAriff Abdullah 1355c68534f1SScott Long pci_enable_busmaster(dev); 1356a5108eaeSScott Long 1357e27951b2SJohn Baldwin sc->regid = PCIR_BAR(0); 1358a5108eaeSScott Long sc->regtype = SYS_RES_MEMORY; 13595f96beb9SNate Lawson sc->reg = bus_alloc_resource_any(dev, sc->regtype, &sc->regid, 13605f96beb9SNate Lawson RF_ACTIVE); 1361a5108eaeSScott Long if (!sc->reg) { 1362a5108eaeSScott Long sc->regtype = SYS_RES_IOPORT; 13635f96beb9SNate Lawson sc->reg = bus_alloc_resource_any(dev, sc->regtype, &sc->regid, 13645f96beb9SNate Lawson RF_ACTIVE); 1365a5108eaeSScott Long } 1366a5108eaeSScott Long if (!sc->reg) { 1367a5108eaeSScott Long device_printf(dev, "unable to allocate register space\n"); 1368a5108eaeSScott Long goto bad; 1369a5108eaeSScott Long } 1370a5108eaeSScott Long sc->st = rman_get_bustag(sc->reg); 1371a5108eaeSScott Long sc->sh = rman_get_bushandle(sc->reg); 1372a5108eaeSScott Long 1373a5108eaeSScott Long sc->irqid = 0; 13745f96beb9SNate Lawson sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid, 13755f96beb9SNate Lawson RF_ACTIVE | RF_SHAREABLE); 1376a5108eaeSScott Long if (!sc->irq) { 1377a5108eaeSScott Long device_printf(dev, "unable to allocate interrupt\n"); 1378a5108eaeSScott Long goto bad; 1379a5108eaeSScott Long } 1380a5108eaeSScott Long 1381c21880a7SPyun YongHyeon if (snd_setup_intr(dev, sc->irq, INTR_MPSAFE, m3_intr, sc, &sc->ih)) { 1382a5108eaeSScott Long device_printf(dev, "unable to setup interrupt\n"); 1383a5108eaeSScott Long goto bad; 1384a5108eaeSScott Long } 1385a5108eaeSScott Long 1386018b991eSAriff Abdullah sc->bufsz = pcm_getbuffersize(dev, M3_BUFSIZE_MIN, M3_BUFSIZE_DEFAULT, 1387c21880a7SPyun YongHyeon M3_BUFSIZE_MAX); 1388baadfb4cSScott Long 1389c21880a7SPyun YongHyeon if (bus_dma_tag_create( 13900b989078SAlexander Leidinger bus_get_dma_tag(dev), /* parent */ 1391c21880a7SPyun YongHyeon 2, 0, /* alignment, boundary */ 1392c21880a7SPyun YongHyeon M3_MAXADDR, /* lowaddr */ 1393c21880a7SPyun YongHyeon BUS_SPACE_MAXADDR, /* highaddr */ 1394c21880a7SPyun YongHyeon NULL, NULL, /* filtfunc, filtfuncarg */ 1395c21880a7SPyun YongHyeon sc->bufsz, /* maxsize */ 1396c21880a7SPyun YongHyeon 1, /* nsegments */ 1397c21880a7SPyun YongHyeon 0x3ffff, /* maxsegz */ 1398c21880a7SPyun YongHyeon 0, /* flags */ 1399c21880a7SPyun YongHyeon NULL, /* lockfunc */ 1400c21880a7SPyun YongHyeon NULL, /* lockfuncarg */ 1401c21880a7SPyun YongHyeon &sc->parent_dmat) != 0) { 1402a5108eaeSScott Long device_printf(dev, "unable to create dma tag\n"); 1403a5108eaeSScott Long goto bad; 1404a5108eaeSScott Long } 1405a5108eaeSScott Long 1406c21880a7SPyun YongHyeon M3_LOCK(sc); 1407a5108eaeSScott Long m3_power(sc, 0); /* power up */ 1408a5108eaeSScott Long /* init chip */ 1409c21880a7SPyun YongHyeon i = m3_init(sc); 1410c21880a7SPyun YongHyeon M3_UNLOCK(sc); 1411c21880a7SPyun YongHyeon if (i == -1) { 1412a5108eaeSScott Long device_printf(dev, "unable to initialize the card\n"); 1413a5108eaeSScott Long goto bad; 1414a5108eaeSScott Long } 1415a5108eaeSScott Long 1416a5108eaeSScott Long /* create/init mixer */ 1417a5108eaeSScott Long codec = AC97_CREATE(dev, sc, m3_codec); 1418a5108eaeSScott Long if (codec == NULL) { 1419a5108eaeSScott Long device_printf(dev, "ac97_create error\n"); 1420a5108eaeSScott Long goto bad; 1421a5108eaeSScott Long } 1422a5108eaeSScott Long if (mixer_init(dev, ac97_getmixerclass(), codec)) { 1423a5108eaeSScott Long device_printf(dev, "mixer_init error\n"); 1424a5108eaeSScott Long goto bad; 1425a5108eaeSScott Long } 1426a5108eaeSScott Long 14279ce4f543SRobert Drehmel m3_enable_ints(sc); 14289ce4f543SRobert Drehmel 1429018b991eSAriff Abdullah if (pcm_register(dev, sc, dacn, adcn)) { 1430a5108eaeSScott Long device_printf(dev, "pcm_register error\n"); 1431a5108eaeSScott Long goto bad; 1432a5108eaeSScott Long } 1433018b991eSAriff Abdullah for (i=0 ; i<dacn ; i++) { 1434a5108eaeSScott Long if (pcm_addchan(dev, PCMDIR_PLAY, &m3_pch_class, sc)) { 1435a5108eaeSScott Long device_printf(dev, "pcm_addchan (play) error\n"); 1436a5108eaeSScott Long goto bad; 1437a5108eaeSScott Long } 1438a5108eaeSScott Long } 1439018b991eSAriff Abdullah for (i=0 ; i<adcn ; i++) { 1440a5108eaeSScott Long if (pcm_addchan(dev, PCMDIR_REC, &m3_rch_class, sc)) { 1441a5108eaeSScott Long device_printf(dev, "pcm_addchan (rec) error\n"); 1442a5108eaeSScott Long goto bad; 1443a5108eaeSScott Long } 1444a5108eaeSScott Long } 1445da1b038aSJustin Hibbits snprintf(status, SND_STATUSLEN, "at %s 0x%jx irq %jd %s", 1446a5108eaeSScott Long (sc->regtype == SYS_RES_IOPORT)? "io" : "memory", 1447c21880a7SPyun YongHyeon rman_get_start(sc->reg), rman_get_start(sc->irq), 1448c21880a7SPyun YongHyeon PCM_KLDSTRING(snd_maestro3)); 1449a5108eaeSScott Long if (pcm_setstatus(dev, status)) { 1450a5108eaeSScott Long device_printf(dev, "attach: pcm_setstatus error\n"); 1451a5108eaeSScott Long goto bad; 1452a5108eaeSScott Long } 145373b9d66dSScott Long 145466ef8af5SCameron Grant mixer_hwvol_init(dev); 1455a5108eaeSScott Long 1456a5108eaeSScott Long /* Create the buffer for saving the card state during suspend */ 1457a5108eaeSScott Long len = sizeof(u_int16_t) * (REV_B_CODE_MEMORY_LENGTH + 1458a5108eaeSScott Long REV_B_DATA_MEMORY_LENGTH); 1459082f6383SAriff Abdullah sc->savemem = (u_int16_t*)malloc(len, M_DEVBUF, M_WAITOK | M_ZERO); 1460a5108eaeSScott Long 1461a5108eaeSScott Long return 0; 1462a5108eaeSScott Long 1463a5108eaeSScott Long bad: 1464c21880a7SPyun YongHyeon if (codec) 1465a5108eaeSScott Long ac97_destroy(codec); 1466c21880a7SPyun YongHyeon if (sc->ih) 1467a5108eaeSScott Long bus_teardown_intr(dev, sc->irq, sc->ih); 1468c21880a7SPyun YongHyeon if (sc->irq) 1469a5108eaeSScott Long bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 1470c21880a7SPyun YongHyeon if (sc->reg) 1471c21880a7SPyun YongHyeon bus_release_resource(dev, sc->regtype, sc->regid, sc->reg); 1472c21880a7SPyun YongHyeon if (sc->parent_dmat) 1473a5108eaeSScott Long bus_dma_tag_destroy(sc->parent_dmat); 1474c21880a7SPyun YongHyeon if (sc->sc_lock) 1475c21880a7SPyun YongHyeon snd_mtxfree(sc->sc_lock); 1476a5108eaeSScott Long free(sc, M_DEVBUF); 1477a5108eaeSScott Long return ENXIO; 1478a5108eaeSScott Long } 1479a5108eaeSScott Long 1480a5108eaeSScott Long static int 1481a5108eaeSScott Long m3_pci_detach(device_t dev) 1482a5108eaeSScott Long { 1483a5108eaeSScott Long struct sc_info *sc = pcm_getdevinfo(dev); 1484a5108eaeSScott Long int r; 1485a5108eaeSScott Long 1486a5108eaeSScott Long M3_DEBUG(CALL, ("m3_pci_detach\n")); 1487a5108eaeSScott Long 1488a5108eaeSScott Long if ((r = pcm_unregister(dev)) != 0) { 1489a5108eaeSScott Long return r; 1490a5108eaeSScott Long } 1491c21880a7SPyun YongHyeon 1492c21880a7SPyun YongHyeon M3_LOCK(sc); 1493a5108eaeSScott Long m3_uninit(sc); /* shutdown chip */ 1494a5108eaeSScott Long m3_power(sc, 3); /* power off */ 1495c21880a7SPyun YongHyeon M3_UNLOCK(sc); 1496a5108eaeSScott Long 1497a5108eaeSScott Long bus_teardown_intr(dev, sc->irq, sc->ih); 1498a5108eaeSScott Long bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 1499c21880a7SPyun YongHyeon bus_release_resource(dev, sc->regtype, sc->regid, sc->reg); 1500a5108eaeSScott Long bus_dma_tag_destroy(sc->parent_dmat); 1501a5108eaeSScott Long 1502a5108eaeSScott Long free(sc->savemem, M_DEVBUF); 1503c21880a7SPyun YongHyeon snd_mtxfree(sc->sc_lock); 1504a5108eaeSScott Long free(sc, M_DEVBUF); 1505a5108eaeSScott Long return 0; 1506a5108eaeSScott Long } 1507a5108eaeSScott Long 1508a5108eaeSScott Long static int 1509a5108eaeSScott Long m3_pci_suspend(device_t dev) 1510a5108eaeSScott Long { 1511a5108eaeSScott Long struct sc_info *sc = pcm_getdevinfo(dev); 1512a5108eaeSScott Long int i, index = 0; 1513a5108eaeSScott Long 1514a5108eaeSScott Long M3_DEBUG(CHANGE, ("m3_pci_suspend\n")); 1515a5108eaeSScott Long 1516c21880a7SPyun YongHyeon M3_LOCK(sc); 1517a5108eaeSScott Long for (i=0 ; i<sc->pch_cnt ; i++) { 1518a5108eaeSScott Long if (sc->pch[i].active) { 1519c21880a7SPyun YongHyeon m3_pchan_trigger_locked(NULL, &sc->pch[i], 1520c21880a7SPyun YongHyeon PCMTRIG_STOP); 1521a5108eaeSScott Long } 1522a5108eaeSScott Long } 1523a5108eaeSScott Long for (i=0 ; i<sc->rch_cnt ; i++) { 1524a5108eaeSScott Long if (sc->rch[i].active) { 1525c21880a7SPyun YongHyeon m3_rchan_trigger_locked(NULL, &sc->rch[i], 1526c21880a7SPyun YongHyeon PCMTRIG_STOP); 1527a5108eaeSScott Long } 1528a5108eaeSScott Long } 1529a5108eaeSScott Long DELAY(10 * 1000); /* give things a chance to stop */ 1530a5108eaeSScott Long 1531a5108eaeSScott Long /* Disable interrupts */ 1532a5108eaeSScott Long m3_wr_2(sc, HOST_INT_CTRL, 0); 1533a5108eaeSScott Long m3_wr_1(sc, ASSP_CONTROL_C, 0); 1534a5108eaeSScott Long 1535a5108eaeSScott Long m3_assp_halt(sc); 1536a5108eaeSScott Long 1537a5108eaeSScott Long /* Save the state of the ASSP */ 1538a5108eaeSScott Long for (i = REV_B_CODE_MEMORY_BEGIN; i <= REV_B_CODE_MEMORY_END; i++) 1539c02a39a1SScott Long sc->savemem[index++] = m3_rd_assp_code(sc, i); 1540a5108eaeSScott Long for (i = REV_B_DATA_MEMORY_BEGIN; i <= REV_B_DATA_MEMORY_END; i++) 1541c02a39a1SScott Long sc->savemem[index++] = m3_rd_assp_data(sc, i); 1542a5108eaeSScott Long 1543a5108eaeSScott Long /* Power down the card to D3 state */ 1544a5108eaeSScott Long m3_power(sc, 3); 1545c21880a7SPyun YongHyeon M3_UNLOCK(sc); 1546a5108eaeSScott Long 1547a5108eaeSScott Long return 0; 1548a5108eaeSScott Long } 1549a5108eaeSScott Long 1550a5108eaeSScott Long static int 1551a5108eaeSScott Long m3_pci_resume(device_t dev) 1552a5108eaeSScott Long { 1553a5108eaeSScott Long struct sc_info *sc = pcm_getdevinfo(dev); 1554a5108eaeSScott Long int i, index = 0; 1555a5108eaeSScott Long u_int8_t reset_state; 1556a5108eaeSScott Long 1557a5108eaeSScott Long M3_DEBUG(CHANGE, ("m3_pci_resume\n")); 1558a5108eaeSScott Long 1559c21880a7SPyun YongHyeon M3_LOCK(sc); 1560a5108eaeSScott Long /* Power the card back to D0 */ 1561a5108eaeSScott Long m3_power(sc, 0); 1562a5108eaeSScott Long 1563a5108eaeSScott Long m3_config(sc); 1564a5108eaeSScott Long 1565a5108eaeSScott Long reset_state = m3_assp_halt(sc); 1566a5108eaeSScott Long 15673068bdbaSGuido van Rooij m3_codec_reset(sc); 15683068bdbaSGuido van Rooij 1569a5108eaeSScott Long /* Restore the ASSP state */ 1570a5108eaeSScott Long for (i = REV_B_CODE_MEMORY_BEGIN; i <= REV_B_CODE_MEMORY_END; i++) 15715ffa65f9SScott Long m3_wr_assp_code(sc, i, sc->savemem[index++]); 1572a5108eaeSScott Long for (i = REV_B_DATA_MEMORY_BEGIN; i <= REV_B_DATA_MEMORY_END; i++) 15735ffa65f9SScott Long m3_wr_assp_data(sc, i, sc->savemem[index++]); 1574a5108eaeSScott Long 1575a5108eaeSScott Long /* Restart the DMA engine */ 1576a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_DMA_ACTIVE, 0); 1577a5108eaeSScott Long 1578a5108eaeSScott Long /* [m3_assp_continue] */ 1579a5108eaeSScott Long m3_wr_1(sc, DSP_PORT_CONTROL_REG_B, reset_state | REGB_ENABLE_RESET); 1580a5108eaeSScott Long 1581a5108eaeSScott Long m3_amp_enable(sc); 1582a5108eaeSScott Long 15830a17f47bSRobert Drehmel m3_enable_ints(sc); 15840a17f47bSRobert Drehmel 1585c21880a7SPyun YongHyeon M3_UNLOCK(sc); /* XXX */ 15863068bdbaSGuido van Rooij if (mixer_reinit(dev) == -1) { 15873068bdbaSGuido van Rooij device_printf(dev, "unable to reinitialize the mixer\n"); 1588c21880a7SPyun YongHyeon return (ENXIO); 15893068bdbaSGuido van Rooij } 1590c21880a7SPyun YongHyeon M3_LOCK(sc); 15913068bdbaSGuido van Rooij 1592a5108eaeSScott Long /* Turn the channels back on */ 1593a5108eaeSScott Long for (i=0 ; i<sc->pch_cnt ; i++) { 1594a5108eaeSScott Long if (sc->pch[i].active) { 1595c21880a7SPyun YongHyeon m3_pchan_trigger_locked(NULL, &sc->pch[i], 1596c21880a7SPyun YongHyeon PCMTRIG_START); 1597a5108eaeSScott Long } 1598a5108eaeSScott Long } 1599a5108eaeSScott Long for (i=0 ; i<sc->rch_cnt ; i++) { 1600a5108eaeSScott Long if (sc->rch[i].active) { 1601c21880a7SPyun YongHyeon m3_rchan_trigger_locked(NULL, &sc->rch[i], 1602c21880a7SPyun YongHyeon PCMTRIG_START); 1603a5108eaeSScott Long } 1604a5108eaeSScott Long } 1605a5108eaeSScott Long 1606c21880a7SPyun YongHyeon M3_UNLOCK(sc); 1607a5108eaeSScott Long return 0; 1608a5108eaeSScott Long } 1609a5108eaeSScott Long 1610a5108eaeSScott Long static int 1611a5108eaeSScott Long m3_pci_shutdown(device_t dev) 1612a5108eaeSScott Long { 1613a5108eaeSScott Long struct sc_info *sc = pcm_getdevinfo(dev); 1614a5108eaeSScott Long 1615a5108eaeSScott Long M3_DEBUG(CALL, ("m3_pci_shutdown\n")); 1616a5108eaeSScott Long 1617c21880a7SPyun YongHyeon M3_LOCK(sc); 1618a5108eaeSScott Long m3_power(sc, 3); /* power off */ 1619c21880a7SPyun YongHyeon M3_UNLOCK(sc); 1620c21880a7SPyun YongHyeon 1621a5108eaeSScott Long return 0; 1622a5108eaeSScott Long } 1623a5108eaeSScott Long 1624a5108eaeSScott Long static u_int8_t 1625a5108eaeSScott Long m3_assp_halt(struct sc_info *sc) 1626a5108eaeSScott Long { 1627a5108eaeSScott Long u_int8_t data, reset_state; 1628a5108eaeSScott Long 1629c21880a7SPyun YongHyeon M3_LOCK_ASSERT(sc); 1630c21880a7SPyun YongHyeon 1631a5108eaeSScott Long data = m3_rd_1(sc, DSP_PORT_CONTROL_REG_B); 1632a5108eaeSScott Long reset_state = data & ~REGB_STOP_CLOCK; /* remember for continue */ 1633a5108eaeSScott Long DELAY(10 * 1000); 1634a5108eaeSScott Long m3_wr_1(sc, DSP_PORT_CONTROL_REG_B, reset_state & ~REGB_ENABLE_RESET); 1635a5108eaeSScott Long DELAY(10 * 1000); /* necessary? */ 1636a5108eaeSScott Long 1637a5108eaeSScott Long return reset_state; 1638a5108eaeSScott Long } 1639a5108eaeSScott Long 1640a5108eaeSScott Long static void 1641a5108eaeSScott Long m3_config(struct sc_info *sc) 1642a5108eaeSScott Long { 164373b9d66dSScott Long u_int32_t data, hv_cfg; 164473b9d66dSScott Long int hint; 164573b9d66dSScott Long 1646c21880a7SPyun YongHyeon M3_LOCK_ASSERT(sc); 16477535accfSPyun YongHyeon 16487535accfSPyun YongHyeon M3_UNLOCK(sc); 164973b9d66dSScott Long /* 165073b9d66dSScott Long * The volume buttons can be wired up via two different sets of pins. 165173b9d66dSScott Long * This presents a problem since we can't tell which way it's 165273b9d66dSScott Long * configured. Allow the user to set a hint in order to twiddle 165373b9d66dSScott Long * the proper bits. 165473b9d66dSScott Long */ 165573b9d66dSScott Long if (resource_int_value(device_get_name(sc->dev), 165673b9d66dSScott Long device_get_unit(sc->dev), 165773b9d66dSScott Long "hwvol_config", &hint) == 0) 165873b9d66dSScott Long hv_cfg = (hint > 0) ? HV_BUTTON_FROM_GD : 0; 165973b9d66dSScott Long else 166073b9d66dSScott Long hv_cfg = HV_BUTTON_FROM_GD; 16617535accfSPyun YongHyeon M3_LOCK(sc); 1662a5108eaeSScott Long 1663a5108eaeSScott Long data = pci_read_config(sc->dev, PCI_ALLEGRO_CONFIG, 4); 166463393eeaSScott Long data &= ~HV_BUTTON_FROM_GD; 166573b9d66dSScott Long data |= REDUCED_DEBOUNCE | HV_CTRL_ENABLE | hv_cfg; 1666a5108eaeSScott Long data |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING; 1667a5108eaeSScott Long pci_write_config(sc->dev, PCI_ALLEGRO_CONFIG, data, 4); 1668a5108eaeSScott Long 1669a5108eaeSScott Long m3_wr_1(sc, ASSP_CONTROL_B, RESET_ASSP); 1670a5108eaeSScott Long data = pci_read_config(sc->dev, PCI_ALLEGRO_CONFIG, 4); 1671a5108eaeSScott Long data &= ~INT_CLK_SELECT; 1672a5108eaeSScott Long if (sc->which == ESS_MAESTRO3) { 1673a5108eaeSScott Long data &= ~INT_CLK_MULT_ENABLE; 1674a5108eaeSScott Long data |= INT_CLK_SRC_NOT_PCI; 1675a5108eaeSScott Long } 1676a5108eaeSScott Long data &= ~(CLK_MULT_MODE_SELECT | CLK_MULT_MODE_SELECT_2); 1677a5108eaeSScott Long pci_write_config(sc->dev, PCI_ALLEGRO_CONFIG, data, 4); 1678a5108eaeSScott Long 1679a5108eaeSScott Long if (sc->which == ESS_ALLEGRO_1) { 1680a5108eaeSScott Long data = pci_read_config(sc->dev, PCI_USER_CONFIG, 4); 1681a5108eaeSScott Long data |= IN_CLK_12MHZ_SELECT; 1682a5108eaeSScott Long pci_write_config(sc->dev, PCI_USER_CONFIG, data, 4); 1683a5108eaeSScott Long } 1684a5108eaeSScott Long 1685a5108eaeSScott Long data = m3_rd_1(sc, ASSP_CONTROL_A); 1686a5108eaeSScott Long data &= ~(DSP_CLK_36MHZ_SELECT | ASSP_CLK_49MHZ_SELECT); 1687a5108eaeSScott Long data |= ASSP_CLK_49MHZ_SELECT; /*XXX assumes 49MHZ dsp XXX*/ 1688a5108eaeSScott Long data |= ASSP_0_WS_ENABLE; 1689a5108eaeSScott Long m3_wr_1(sc, ASSP_CONTROL_A, data); 1690a5108eaeSScott Long 1691a5108eaeSScott Long m3_wr_1(sc, ASSP_CONTROL_B, RUN_ASSP); 1692a5108eaeSScott Long } 1693a5108eaeSScott Long 1694a5108eaeSScott Long static void 1695a5108eaeSScott Long m3_enable_ints(struct sc_info *sc) 1696a5108eaeSScott Long { 1697a5108eaeSScott Long u_int8_t data; 1698a5108eaeSScott Long 1699a5108eaeSScott Long m3_wr_2(sc, HOST_INT_CTRL, ASSP_INT_ENABLE | HV_INT_ENABLE); 1700a5108eaeSScott Long data = m3_rd_1(sc, ASSP_CONTROL_C); 1701a5108eaeSScott Long m3_wr_1(sc, ASSP_CONTROL_C, data | ASSP_HOST_INT_ENABLE); 1702a5108eaeSScott Long } 1703a5108eaeSScott Long 1704a5108eaeSScott Long static void 1705a5108eaeSScott Long m3_amp_enable(struct sc_info *sc) 1706a5108eaeSScott Long { 1707a5108eaeSScott Long u_int32_t gpo, polarity_port, polarity; 1708a5108eaeSScott Long u_int16_t data; 1709a5108eaeSScott Long 1710c21880a7SPyun YongHyeon M3_LOCK_ASSERT(sc); 1711c21880a7SPyun YongHyeon 1712a5108eaeSScott Long switch (sc->which) { 1713a5108eaeSScott Long case ESS_ALLEGRO_1: 1714a5108eaeSScott Long polarity_port = 0x1800; 1715a5108eaeSScott Long break; 1716a5108eaeSScott Long case ESS_MAESTRO3: 1717a5108eaeSScott Long polarity_port = 0x1100; 1718a5108eaeSScott Long break; 1719a5108eaeSScott Long default: 1720a5108eaeSScott Long panic("bad sc->which"); 1721a5108eaeSScott Long } 1722a5108eaeSScott Long gpo = (polarity_port >> 8) & 0x0f; 1723a5108eaeSScott Long polarity = polarity_port >> 12; 1724a5108eaeSScott Long polarity = !polarity; /* enable */ 1725a5108eaeSScott Long polarity = polarity << gpo; 1726a5108eaeSScott Long gpo = 1 << gpo; 1727a5108eaeSScott Long m3_wr_2(sc, GPIO_MASK, ~gpo); 1728a5108eaeSScott Long data = m3_rd_2(sc, GPIO_DIRECTION); 1729a5108eaeSScott Long m3_wr_2(sc, GPIO_DIRECTION, data | gpo); 1730a5108eaeSScott Long data = GPO_SECONDARY_AC97 | GPO_PRIMARY_AC97 | polarity; 1731a5108eaeSScott Long m3_wr_2(sc, GPIO_DATA, data); 1732a5108eaeSScott Long m3_wr_2(sc, GPIO_MASK, ~0); 1733a5108eaeSScott Long } 1734a5108eaeSScott Long 1735a5108eaeSScott Long static void 1736a5108eaeSScott Long m3_codec_reset(struct sc_info *sc) 1737a5108eaeSScott Long { 1738a5108eaeSScott Long u_int16_t data, dir; 1739a5108eaeSScott Long int retry = 0; 1740a5108eaeSScott Long 1741c21880a7SPyun YongHyeon M3_LOCK_ASSERT(sc); 1742a5108eaeSScott Long do { 1743a5108eaeSScott Long data = m3_rd_2(sc, GPIO_DIRECTION); 1744a5108eaeSScott Long dir = data | 0x10; /* assuming pci bus master? */ 1745a5108eaeSScott Long 1746a5108eaeSScott Long /* [[remote_codec_config]] */ 1747a5108eaeSScott Long data = m3_rd_2(sc, RING_BUS_CTRL_B); 1748a5108eaeSScott Long m3_wr_2(sc, RING_BUS_CTRL_B, data & ~SECOND_CODEC_ID_MASK); 1749a5108eaeSScott Long data = m3_rd_2(sc, SDO_OUT_DEST_CTRL); 1750a5108eaeSScott Long m3_wr_2(sc, SDO_OUT_DEST_CTRL, data & ~COMMAND_ADDR_OUT); 1751a5108eaeSScott Long data = m3_rd_2(sc, SDO_IN_DEST_CTRL); 1752a5108eaeSScott Long m3_wr_2(sc, SDO_IN_DEST_CTRL, data & ~STATUS_ADDR_IN); 1753a5108eaeSScott Long 1754a5108eaeSScott Long m3_wr_2(sc, RING_BUS_CTRL_A, IO_SRAM_ENABLE); 1755a5108eaeSScott Long DELAY(20); 1756a5108eaeSScott Long 1757a5108eaeSScott Long m3_wr_2(sc, GPIO_DIRECTION, dir & ~GPO_PRIMARY_AC97); 1758a5108eaeSScott Long m3_wr_2(sc, GPIO_MASK, ~GPO_PRIMARY_AC97); 1759a5108eaeSScott Long m3_wr_2(sc, GPIO_DATA, 0); 1760a5108eaeSScott Long m3_wr_2(sc, GPIO_DIRECTION, dir | GPO_PRIMARY_AC97); 1761a5108eaeSScott Long DELAY(sc->delay1 * 1000); /*delay1 (ALLEGRO:50, MAESTRO3:20)*/ 1762a5108eaeSScott Long m3_wr_2(sc, GPIO_DATA, GPO_PRIMARY_AC97); 1763a5108eaeSScott Long DELAY(5); 1764a5108eaeSScott Long m3_wr_2(sc, RING_BUS_CTRL_A, IO_SRAM_ENABLE | 1765a5108eaeSScott Long SERIAL_AC_LINK_ENABLE); 1766a5108eaeSScott Long m3_wr_2(sc, GPIO_MASK, ~0); 1767a5108eaeSScott Long DELAY(sc->delay2 * 1000); /*delay2 (ALLEGRO:800, MAESTRO3:500)*/ 1768a5108eaeSScott Long 1769a5108eaeSScott Long /* [[try read vendor]] */ 1770a5108eaeSScott Long data = m3_rdcd(NULL, sc, 0x7c); 1771a5108eaeSScott Long if ((data == 0) || (data == 0xffff)) { 1772a5108eaeSScott Long retry++; 1773a5108eaeSScott Long if (retry > 3) { 1774a5108eaeSScott Long device_printf(sc->dev, "Codec reset failed\n"); 1775a5108eaeSScott Long break; 1776a5108eaeSScott Long } 1777a5108eaeSScott Long device_printf(sc->dev, "Codec reset retry\n"); 1778a5108eaeSScott Long } else retry = 0; 1779a5108eaeSScott Long } while (retry); 1780a5108eaeSScott Long } 1781a5108eaeSScott Long 1782a5108eaeSScott Long static device_method_t m3_methods[] = { 1783a5108eaeSScott Long DEVMETHOD(device_probe, m3_pci_probe), 1784a5108eaeSScott Long DEVMETHOD(device_attach, m3_pci_attach), 1785a5108eaeSScott Long DEVMETHOD(device_detach, m3_pci_detach), 1786a5108eaeSScott Long DEVMETHOD(device_suspend, m3_pci_suspend), 1787a5108eaeSScott Long DEVMETHOD(device_resume, m3_pci_resume), 1788a5108eaeSScott Long DEVMETHOD(device_shutdown, m3_pci_shutdown), 1789a5108eaeSScott Long { 0, 0 } 1790a5108eaeSScott Long }; 1791a5108eaeSScott Long 1792a5108eaeSScott Long static driver_t m3_driver = { 1793a5108eaeSScott Long "pcm", 1794a5108eaeSScott Long m3_methods, 179567b1dce3SCameron Grant PCM_SOFTC_SIZE, 1796a5108eaeSScott Long }; 1797a5108eaeSScott Long 1798a5108eaeSScott Long DRIVER_MODULE(snd_maestro3, pci, m3_driver, pcm_devclass, 0, 0); 17990739ea1dSSeigo Tanimura MODULE_DEPEND(snd_maestro3, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 1800a5108eaeSScott Long MODULE_VERSION(snd_maestro3, 1); 1801