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