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 55a5108eaeSScott Long #include <dev/sound/pcm/sound.h> 56a5108eaeSScott Long #include <dev/sound/pcm/ac97.h> 57a5108eaeSScott Long 5890cf0136SWarner Losh #include <dev/pci/pcireg.h> 5990cf0136SWarner Losh #include <dev/pci/pcivar.h> 60a5108eaeSScott Long 61a5108eaeSScott Long #include <gnu/dev/sound/pci/maestro3_reg.h> 62a5108eaeSScott Long #include <gnu/dev/sound/pci/maestro3_dsp.h> 63a5108eaeSScott Long 6467b1dce3SCameron Grant SND_DECLARE_FILE("$FreeBSD$"); 6567b1dce3SCameron Grant 66a5108eaeSScott Long /* -------------------------------------------------------------------- */ 67a5108eaeSScott Long 68a5108eaeSScott Long enum {CHANGE=0, CALL=1, INTR=2, BORING=3, NONE=-1}; 69a5108eaeSScott Long #ifndef M3_DEBUG_LEVEL 70a5108eaeSScott Long #define M3_DEBUG_LEVEL NONE 71a5108eaeSScott Long #endif 72a5108eaeSScott Long #define M3_DEBUG(level, _msg) {if ((level) <= M3_DEBUG_LEVEL) {printf _msg;}} 73a5108eaeSScott Long 74a5108eaeSScott Long /* -------------------------------------------------------------------- */ 75a5108eaeSScott Long enum { 76a5108eaeSScott Long ESS_ALLEGRO_1, 77a5108eaeSScott Long ESS_MAESTRO3 78a5108eaeSScott Long }; 79a5108eaeSScott Long 80a5108eaeSScott Long static struct m3_card_type { 81a5108eaeSScott Long u_int32_t pci_id; int which; int delay1; int delay2; char *name; 82a5108eaeSScott Long } m3_card_types[] = { 83a5108eaeSScott Long { 0x1988125d, ESS_ALLEGRO_1, 50, 800, "ESS Technology Allegro-1" }, 84a5108eaeSScott Long { 0x1998125d, ESS_MAESTRO3, 20, 500, "ESS Technology Maestro3" }, 85a5108eaeSScott Long { 0x199a125d, ESS_MAESTRO3, 20, 500, "ESS Technology Maestro3" }, 86a5108eaeSScott Long { 0, 0, 0, 0, NULL } 87a5108eaeSScott Long }; 88a5108eaeSScott Long 89018b991eSAriff Abdullah #define M3_BUFSIZE_MIN 4096 90c21880a7SPyun YongHyeon #define M3_BUFSIZE_MAX 65536 91baadfb4cSScott Long #define M3_BUFSIZE_DEFAULT 4096 9273b9d66dSScott Long #define M3_PCHANS 4 /* create /dev/dsp0.[0-N] to use more than one */ 93a5108eaeSScott Long #define M3_RCHANS 1 94e93d24c2SScott Long #define M3_MAXADDR ((1 << 27) - 1) 95a5108eaeSScott Long 96a5108eaeSScott Long struct sc_info; 97a5108eaeSScott Long 98a5108eaeSScott Long struct sc_pchinfo { 99a5108eaeSScott Long u_int32_t spd; 100a5108eaeSScott Long u_int32_t fmt; 10166ef8af5SCameron Grant struct snd_dbuf *buffer; 10266ef8af5SCameron Grant struct pcm_channel *channel; 103a5108eaeSScott Long struct sc_info *parent; 104a5108eaeSScott Long u_int32_t bufsize; 105a5108eaeSScott Long u_int32_t dac_data; 106a5108eaeSScott Long u_int32_t dac_idx; 107a5108eaeSScott Long u_int32_t active; 108018b991eSAriff Abdullah u_int32_t ptr; 109018b991eSAriff Abdullah u_int32_t prevptr; 110a5108eaeSScott Long }; 111a5108eaeSScott Long 112a5108eaeSScott Long struct sc_rchinfo { 113a5108eaeSScott Long u_int32_t spd; 114a5108eaeSScott Long u_int32_t fmt; 11566ef8af5SCameron Grant struct snd_dbuf *buffer; 11666ef8af5SCameron Grant struct pcm_channel *channel; 117a5108eaeSScott Long struct sc_info *parent; 118a5108eaeSScott Long u_int32_t bufsize; 119a5108eaeSScott Long u_int32_t adc_data; 120a5108eaeSScott Long u_int32_t adc_idx; 121a5108eaeSScott Long u_int32_t active; 122018b991eSAriff Abdullah u_int32_t ptr; 123018b991eSAriff Abdullah u_int32_t prevptr; 124a5108eaeSScott Long }; 125a5108eaeSScott Long 126a5108eaeSScott Long struct sc_info { 127a5108eaeSScott Long device_t dev; 128a5108eaeSScott Long u_int32_t type; 129a5108eaeSScott Long int which; 130a5108eaeSScott Long int delay1; 131a5108eaeSScott Long int delay2; 132a5108eaeSScott Long 133a5108eaeSScott Long bus_space_tag_t st; 134a5108eaeSScott Long bus_space_handle_t sh; 135a5108eaeSScott Long bus_dma_tag_t parent_dmat; 136a5108eaeSScott Long 137a5108eaeSScott Long struct resource *reg; 138a5108eaeSScott Long struct resource *irq; 139a5108eaeSScott Long int regtype; 140a5108eaeSScott Long int regid; 141a5108eaeSScott Long int irqid; 142a5108eaeSScott Long void *ih; 143a5108eaeSScott Long 144a5108eaeSScott Long struct sc_pchinfo pch[M3_PCHANS]; 145a5108eaeSScott Long struct sc_rchinfo rch[M3_RCHANS]; 146a5108eaeSScott Long int pch_cnt; 147a5108eaeSScott Long int rch_cnt; 148a5108eaeSScott Long int pch_active_cnt; 149baadfb4cSScott Long unsigned int bufsz; 150a5108eaeSScott Long u_int16_t *savemem; 151c21880a7SPyun YongHyeon 152c21880a7SPyun YongHyeon struct mtx *sc_lock; 153a5108eaeSScott Long }; 154a5108eaeSScott Long 155c21880a7SPyun YongHyeon #define M3_LOCK(_sc) snd_mtxlock((_sc)->sc_lock) 156c21880a7SPyun YongHyeon #define M3_UNLOCK(_sc) snd_mtxunlock((_sc)->sc_lock) 157c21880a7SPyun YongHyeon #define M3_LOCK_ASSERT(_sc) snd_mtxassert((_sc)->sc_lock) 158c21880a7SPyun YongHyeon 159a5108eaeSScott Long /* -------------------------------------------------------------------- */ 160a5108eaeSScott Long 161a5108eaeSScott Long /* play channel interface */ 16266ef8af5SCameron Grant static void *m3_pchan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int); 163a5108eaeSScott Long static int m3_pchan_free(kobj_t, void *); 164a5108eaeSScott Long static int m3_pchan_setformat(kobj_t, void *, u_int32_t); 165a5108eaeSScott Long static int m3_pchan_setspeed(kobj_t, void *, u_int32_t); 166a5108eaeSScott Long static int m3_pchan_setblocksize(kobj_t, void *, u_int32_t); 167a5108eaeSScott Long static int m3_pchan_trigger(kobj_t, void *, int); 168c21880a7SPyun YongHyeon static int m3_pchan_trigger_locked(kobj_t, void *, int); 169018b991eSAriff Abdullah static u_int32_t m3_pchan_getptr_internal(struct sc_pchinfo *); 170018b991eSAriff Abdullah static u_int32_t m3_pchan_getptr(kobj_t, void *); 17166ef8af5SCameron Grant static struct pcmchan_caps *m3_pchan_getcaps(kobj_t, void *); 172a5108eaeSScott Long 173a5108eaeSScott Long /* record channel interface */ 17466ef8af5SCameron Grant static void *m3_rchan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int); 175a5108eaeSScott Long static int m3_rchan_free(kobj_t, void *); 176a5108eaeSScott Long static int m3_rchan_setformat(kobj_t, void *, u_int32_t); 177a5108eaeSScott Long static int m3_rchan_setspeed(kobj_t, void *, u_int32_t); 178a5108eaeSScott Long static int m3_rchan_setblocksize(kobj_t, void *, u_int32_t); 179a5108eaeSScott Long static int m3_rchan_trigger(kobj_t, void *, int); 180c21880a7SPyun YongHyeon static int m3_rchan_trigger_locked(kobj_t, void *, int); 181018b991eSAriff Abdullah static u_int32_t m3_rchan_getptr_internal(struct sc_rchinfo *); 182018b991eSAriff Abdullah static u_int32_t m3_rchan_getptr(kobj_t, void *); 18366ef8af5SCameron Grant static struct pcmchan_caps *m3_rchan_getcaps(kobj_t, void *); 184a5108eaeSScott Long 185018b991eSAriff Abdullah static int m3_chan_active(struct sc_info *); 186018b991eSAriff Abdullah 187a5108eaeSScott Long /* talk to the codec - called from ac97.c */ 188a5108eaeSScott Long static int m3_initcd(kobj_t, void *); 189a5108eaeSScott Long static int m3_rdcd(kobj_t, void *, int); 190a5108eaeSScott Long static int m3_wrcd(kobj_t, void *, int, u_int32_t); 191a5108eaeSScott Long 192a5108eaeSScott Long /* stuff */ 193a5108eaeSScott Long static void m3_intr(void *); 194a5108eaeSScott Long static int m3_power(struct sc_info *, int); 195a5108eaeSScott Long static int m3_init(struct sc_info *); 196a5108eaeSScott Long static int m3_uninit(struct sc_info *); 197a5108eaeSScott Long static u_int8_t m3_assp_halt(struct sc_info *); 198a5108eaeSScott Long static void m3_config(struct sc_info *); 199a5108eaeSScott Long static void m3_amp_enable(struct sc_info *); 200a5108eaeSScott Long static void m3_enable_ints(struct sc_info *); 201a5108eaeSScott Long static void m3_codec_reset(struct sc_info *); 202a5108eaeSScott Long 203a5108eaeSScott Long /* -------------------------------------------------------------------- */ 204a5108eaeSScott Long /* Codec descriptor */ 205a5108eaeSScott Long static kobj_method_t m3_codec_methods[] = { 206a5108eaeSScott Long KOBJMETHOD(ac97_init, m3_initcd), 207a5108eaeSScott Long KOBJMETHOD(ac97_read, m3_rdcd), 208a5108eaeSScott Long KOBJMETHOD(ac97_write, m3_wrcd), 209a5108eaeSScott Long { 0, 0 } 210a5108eaeSScott Long }; 211a5108eaeSScott Long AC97_DECLARE(m3_codec); 212a5108eaeSScott Long 213a5108eaeSScott Long /* -------------------------------------------------------------------- */ 214a5108eaeSScott Long /* channel descriptors */ 215a5108eaeSScott Long 216a5108eaeSScott Long static u_int32_t m3_playfmt[] = { 217a5108eaeSScott Long AFMT_U8, 218a5108eaeSScott Long AFMT_STEREO | AFMT_U8, 219a5108eaeSScott Long AFMT_S16_LE, 220a5108eaeSScott Long AFMT_STEREO | AFMT_S16_LE, 221a5108eaeSScott Long 0 222a5108eaeSScott Long }; 22366ef8af5SCameron Grant static struct pcmchan_caps m3_playcaps = {8000, 48000, m3_playfmt, 0}; 224a5108eaeSScott Long 225a5108eaeSScott Long static kobj_method_t m3_pch_methods[] = { 226a5108eaeSScott Long KOBJMETHOD(channel_init, m3_pchan_init), 227a5108eaeSScott Long KOBJMETHOD(channel_setformat, m3_pchan_setformat), 228a5108eaeSScott Long KOBJMETHOD(channel_setspeed, m3_pchan_setspeed), 229a5108eaeSScott Long KOBJMETHOD(channel_setblocksize, m3_pchan_setblocksize), 230a5108eaeSScott Long KOBJMETHOD(channel_trigger, m3_pchan_trigger), 231a5108eaeSScott Long KOBJMETHOD(channel_getptr, m3_pchan_getptr), 232a5108eaeSScott Long KOBJMETHOD(channel_getcaps, m3_pchan_getcaps), 233a5108eaeSScott Long KOBJMETHOD(channel_free, m3_pchan_free), 234a5108eaeSScott Long { 0, 0 } 235a5108eaeSScott Long }; 236a5108eaeSScott Long CHANNEL_DECLARE(m3_pch); 237a5108eaeSScott Long 238a5108eaeSScott Long static u_int32_t m3_recfmt[] = { 239a5108eaeSScott Long AFMT_U8, 240a5108eaeSScott Long AFMT_STEREO | AFMT_U8, 241a5108eaeSScott Long AFMT_S16_LE, 242a5108eaeSScott Long AFMT_STEREO | AFMT_S16_LE, 243a5108eaeSScott Long 0 244a5108eaeSScott Long }; 24566ef8af5SCameron Grant static struct pcmchan_caps m3_reccaps = {8000, 48000, m3_recfmt, 0}; 246a5108eaeSScott Long 247a5108eaeSScott Long static kobj_method_t m3_rch_methods[] = { 248a5108eaeSScott Long KOBJMETHOD(channel_init, m3_rchan_init), 249a5108eaeSScott Long KOBJMETHOD(channel_setformat, m3_rchan_setformat), 250a5108eaeSScott Long KOBJMETHOD(channel_setspeed, m3_rchan_setspeed), 251a5108eaeSScott Long KOBJMETHOD(channel_setblocksize, m3_rchan_setblocksize), 252a5108eaeSScott Long KOBJMETHOD(channel_trigger, m3_rchan_trigger), 253a5108eaeSScott Long KOBJMETHOD(channel_getptr, m3_rchan_getptr), 254a5108eaeSScott Long KOBJMETHOD(channel_getcaps, m3_rchan_getcaps), 255a5108eaeSScott Long KOBJMETHOD(channel_free, m3_rchan_free), 256a5108eaeSScott Long { 0, 0 } 257a5108eaeSScott Long }; 258a5108eaeSScott Long CHANNEL_DECLARE(m3_rch); 259a5108eaeSScott Long 260a5108eaeSScott Long /* -------------------------------------------------------------------- */ 261a5108eaeSScott Long /* some i/o convenience functions */ 262a5108eaeSScott Long 263a5108eaeSScott Long #define m3_rd_1(sc, regno) bus_space_read_1(sc->st, sc->sh, regno) 264a5108eaeSScott Long #define m3_rd_2(sc, regno) bus_space_read_2(sc->st, sc->sh, regno) 265a5108eaeSScott Long #define m3_rd_4(sc, regno) bus_space_read_4(sc->st, sc->sh, regno) 266a5108eaeSScott Long #define m3_wr_1(sc, regno, data) bus_space_write_1(sc->st, sc->sh, regno, data) 267a5108eaeSScott Long #define m3_wr_2(sc, regno, data) bus_space_write_2(sc->st, sc->sh, regno, data) 268a5108eaeSScott Long #define m3_wr_4(sc, regno, data) bus_space_write_4(sc->st, sc->sh, regno, data) 269a5108eaeSScott Long #define m3_rd_assp_code(sc, index) \ 270a5108eaeSScott Long m3_rd_assp(sc, MEMTYPE_INTERNAL_CODE, index) 271a5108eaeSScott Long #define m3_wr_assp_code(sc, index, data) \ 272a5108eaeSScott Long m3_wr_assp(sc, MEMTYPE_INTERNAL_CODE, index, data) 273a5108eaeSScott Long #define m3_rd_assp_data(sc, index) \ 274a5108eaeSScott Long m3_rd_assp(sc, MEMTYPE_INTERNAL_DATA, index) 275a5108eaeSScott Long #define m3_wr_assp_data(sc, index, data) \ 276a5108eaeSScott Long m3_wr_assp(sc, MEMTYPE_INTERNAL_DATA, index, data) 277a5108eaeSScott Long 278a5108eaeSScott Long static __inline u_int16_t 279a5108eaeSScott Long m3_rd_assp(struct sc_info *sc, u_int16_t region, u_int16_t index) 280a5108eaeSScott Long { 281a5108eaeSScott Long m3_wr_2(sc, DSP_PORT_MEMORY_TYPE, region & MEMTYPE_MASK); 282a5108eaeSScott Long m3_wr_2(sc, DSP_PORT_MEMORY_INDEX, index); 283a5108eaeSScott Long return m3_rd_2(sc, DSP_PORT_MEMORY_DATA); 284a5108eaeSScott Long } 285a5108eaeSScott Long 286a5108eaeSScott Long static __inline void 287a5108eaeSScott Long m3_wr_assp(struct sc_info *sc, u_int16_t region, u_int16_t index, 288a5108eaeSScott Long u_int16_t data) 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 m3_wr_2(sc, DSP_PORT_MEMORY_DATA, data); 293a5108eaeSScott Long } 294a5108eaeSScott Long 295a5108eaeSScott Long static __inline int 296a5108eaeSScott Long m3_wait(struct sc_info *sc) 297a5108eaeSScott Long { 298a5108eaeSScott Long int i; 299a5108eaeSScott Long 300a5108eaeSScott Long for (i=0 ; i<20 ; i++) { 301a5108eaeSScott Long if ((m3_rd_1(sc, CODEC_STATUS) & 1) == 0) { 302a5108eaeSScott Long return 0; 303a5108eaeSScott Long } 304a5108eaeSScott Long DELAY(2); 305a5108eaeSScott Long } 306a5108eaeSScott Long return -1; 307a5108eaeSScott Long } 308a5108eaeSScott Long 309a5108eaeSScott Long /* -------------------------------------------------------------------- */ 310a5108eaeSScott Long /* ac97 codec */ 311a5108eaeSScott Long 312a5108eaeSScott Long static int 313a5108eaeSScott Long m3_initcd(kobj_t kobj, void *devinfo) 314a5108eaeSScott Long { 315a5108eaeSScott Long struct sc_info *sc = (struct sc_info *)devinfo; 316a5108eaeSScott Long u_int32_t data; 317a5108eaeSScott Long 318a5108eaeSScott Long M3_DEBUG(CALL, ("m3_initcd\n")); 319a5108eaeSScott Long 320a5108eaeSScott Long /* init ac-link */ 321a5108eaeSScott Long 322a5108eaeSScott Long data = m3_rd_1(sc, CODEC_COMMAND); 323a5108eaeSScott Long return ((data & 0x1) ? 0 : 1); 324a5108eaeSScott Long } 325a5108eaeSScott Long 326a5108eaeSScott Long static int 327a5108eaeSScott Long m3_rdcd(kobj_t kobj, void *devinfo, int regno) 328a5108eaeSScott Long { 329a5108eaeSScott Long struct sc_info *sc = (struct sc_info *)devinfo; 330a5108eaeSScott Long u_int32_t data; 331a5108eaeSScott Long 332a5108eaeSScott Long if (m3_wait(sc)) { 333a5108eaeSScott Long device_printf(sc->dev, "m3_rdcd timed out.\n"); 334a5108eaeSScott Long return -1; 335a5108eaeSScott Long } 336a5108eaeSScott Long m3_wr_1(sc, CODEC_COMMAND, (regno & 0x7f) | 0x80); 33766ef8af5SCameron Grant DELAY(50); /* ac97 cycle = 20.8 usec */ 338a5108eaeSScott Long if (m3_wait(sc)) { 339a5108eaeSScott Long device_printf(sc->dev, "m3_rdcd timed out.\n"); 340a5108eaeSScott Long return -1; 341a5108eaeSScott Long } 342a5108eaeSScott Long data = m3_rd_2(sc, CODEC_DATA); 343a5108eaeSScott Long return data; 344a5108eaeSScott Long } 345a5108eaeSScott Long 346a5108eaeSScott Long static int 347a5108eaeSScott Long m3_wrcd(kobj_t kobj, void *devinfo, int regno, u_int32_t data) 348a5108eaeSScott Long { 349a5108eaeSScott Long struct sc_info *sc = (struct sc_info *)devinfo; 350a5108eaeSScott Long if (m3_wait(sc)) { 351a5108eaeSScott Long device_printf(sc->dev, "m3_wrcd timed out.\n"); 352a5108eaeSScott Long return -1;; 353a5108eaeSScott Long } 354a5108eaeSScott Long m3_wr_2(sc, CODEC_DATA, data); 355a5108eaeSScott Long m3_wr_1(sc, CODEC_COMMAND, regno & 0x7f); 35666ef8af5SCameron Grant DELAY(50); /* ac97 cycle = 20.8 usec */ 357a5108eaeSScott Long return 0; 358a5108eaeSScott Long } 359a5108eaeSScott Long 360a5108eaeSScott Long /* -------------------------------------------------------------------- */ 361a5108eaeSScott Long /* play channel interface */ 362a5108eaeSScott Long 363a5108eaeSScott Long #define LO(x) (((x) & 0x0000ffff) ) 364a5108eaeSScott Long #define HI(x) (((x) & 0xffff0000) >> 16) 365a5108eaeSScott Long 366a5108eaeSScott Long static void * 36766ef8af5SCameron Grant m3_pchan_init(kobj_t kobj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 368a5108eaeSScott Long { 369a5108eaeSScott Long struct sc_info *sc = devinfo; 370a5108eaeSScott Long struct sc_pchinfo *ch; 371a5108eaeSScott Long u_int32_t bus_addr, i; 372c21880a7SPyun YongHyeon int idx, data_bytes, dac_data; 373c21880a7SPyun YongHyeon int dsp_in_size, dsp_out_size, dsp_in_buf, dsp_out_buf; 374a5108eaeSScott Long 375c21880a7SPyun YongHyeon M3_LOCK(sc); 376c21880a7SPyun YongHyeon idx = sc->pch_cnt; /* dac instance number, no active reuse! */ 377a5108eaeSScott Long M3_DEBUG(CHANGE, ("m3_pchan_init(dac=%d)\n", idx)); 378a5108eaeSScott Long 379a5108eaeSScott Long if (dir != PCMDIR_PLAY) { 380c21880a7SPyun YongHyeon M3_UNLOCK(sc); 381a5108eaeSScott Long device_printf(sc->dev, "m3_pchan_init not PCMDIR_PLAY\n"); 382c21880a7SPyun YongHyeon return (NULL); 383a5108eaeSScott Long } 384a5108eaeSScott Long 385c21880a7SPyun YongHyeon data_bytes = (((MINISRC_TMP_BUFFER_SIZE & ~1) + 386c21880a7SPyun YongHyeon (MINISRC_IN_BUFFER_SIZE & ~1) + 387c21880a7SPyun YongHyeon (MINISRC_OUT_BUFFER_SIZE & ~1) + 4) + 255) &~ 255; 388c21880a7SPyun YongHyeon dac_data = 0x1100 + (data_bytes * idx); 389c21880a7SPyun YongHyeon 390c21880a7SPyun YongHyeon dsp_in_size = MINISRC_IN_BUFFER_SIZE - (0x20 * 2); 391c21880a7SPyun YongHyeon dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x20 * 2); 392c21880a7SPyun YongHyeon dsp_in_buf = dac_data + (MINISRC_TMP_BUFFER_SIZE/2); 393c21880a7SPyun YongHyeon dsp_out_buf = dsp_in_buf + (dsp_in_size/2) + 1; 394c21880a7SPyun YongHyeon 395c21880a7SPyun YongHyeon ch = &sc->pch[idx]; 396a5108eaeSScott Long ch->dac_idx = idx; 397a5108eaeSScott Long ch->dac_data = dac_data; 398a5108eaeSScott Long if (ch->dac_data + data_bytes/2 >= 0x1c00) { 399c21880a7SPyun YongHyeon M3_UNLOCK(sc); 400a5108eaeSScott Long device_printf(sc->dev, "m3_pchan_init: revb mem exhausted\n"); 401c21880a7SPyun YongHyeon return (NULL); 402a5108eaeSScott Long } 403a5108eaeSScott Long 404a5108eaeSScott Long ch->buffer = b; 405a5108eaeSScott Long ch->parent = sc; 406a5108eaeSScott Long ch->channel = c; 407a5108eaeSScott Long ch->fmt = AFMT_U8; 408a5108eaeSScott Long ch->spd = DSP_DEFAULT_SPEED; 409c21880a7SPyun YongHyeon M3_UNLOCK(sc); /* XXX */ 4102e334adfSAriff Abdullah if (sndbuf_alloc(ch->buffer, sc->parent_dmat, 0, sc->bufsz) != 0) { 411a5108eaeSScott Long device_printf(sc->dev, "m3_pchan_init chn_allocbuf failed\n"); 412c21880a7SPyun YongHyeon return (NULL); 413a5108eaeSScott Long } 414c21880a7SPyun YongHyeon M3_LOCK(sc); 415a5108eaeSScott Long ch->bufsize = sndbuf_getsize(ch->buffer); 416a5108eaeSScott Long 417a5108eaeSScott Long /* host dma buffer pointers */ 41838cc9942SOlivier Houchard bus_addr = sndbuf_getbufaddr(ch->buffer); 419a5108eaeSScott Long if (bus_addr & 3) { 420a5108eaeSScott Long device_printf(sc->dev, "m3_pchan_init unaligned bus_addr\n"); 421a5108eaeSScott Long bus_addr = (bus_addr + 4) & ~3; 422a5108eaeSScott Long } 423a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_ADDRL, LO(bus_addr)); 424a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_ADDRH, HI(bus_addr)); 425a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_END_PLUS_1L, 426a5108eaeSScott Long LO(bus_addr + ch->bufsize)); 427a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_END_PLUS_1H, 428a5108eaeSScott Long HI(bus_addr + ch->bufsize)); 429a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_CURRENTL, 430a5108eaeSScott Long LO(bus_addr)); 431a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_CURRENTH, 432a5108eaeSScott Long HI(bus_addr)); 433a5108eaeSScott Long 434a5108eaeSScott Long /* dsp buffers */ 435a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_IN_BUF_BEGIN, dsp_in_buf); 436a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_IN_BUF_END_PLUS_1, 437a5108eaeSScott Long dsp_in_buf + dsp_in_size/2); 438a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_IN_BUF_HEAD, dsp_in_buf); 439a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_IN_BUF_TAIL, dsp_in_buf); 440a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_OUT_BUF_BEGIN, dsp_out_buf); 441a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_OUT_BUF_END_PLUS_1, 442a5108eaeSScott Long dsp_out_buf + dsp_out_size/2); 443a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_OUT_BUF_HEAD, dsp_out_buf); 444a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_OUT_BUF_TAIL, dsp_out_buf); 445a5108eaeSScott Long 446a5108eaeSScott Long /* some per client initializers */ 447a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + SRC3_DIRECTION_OFFSET + 12, 448a5108eaeSScott Long ch->dac_data + 40 + 8); 449a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + SRC3_DIRECTION_OFFSET + 19, 450a5108eaeSScott Long 0x400 + MINISRC_COEF_LOC); 451a5108eaeSScott Long /* enable or disable low pass filter? (0xff if rate> 45000) */ 452a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + SRC3_DIRECTION_OFFSET + 22, 0); 453a5108eaeSScott Long /* tell it which way dma is going? */ 454a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_DMA_CONTROL, 455a5108eaeSScott Long DMACONTROL_AUTOREPEAT + DMAC_PAGE3_SELECTOR + 456a5108eaeSScott Long DMAC_BLOCKF_SELECTOR); 457a5108eaeSScott Long 458a5108eaeSScott Long /* set an armload of static initializers */ 459a5108eaeSScott Long for(i = 0 ; i < (sizeof(pv) / sizeof(pv[0])) ; i++) { 460a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + pv[i].addr, pv[i].val); 461a5108eaeSScott Long } 462a5108eaeSScott Long 463a5108eaeSScott Long /* put us in the packed task lists */ 464a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_INSTANCE0_MINISRC + 465a5108eaeSScott Long (sc->pch_cnt + sc->rch_cnt), 466a5108eaeSScott Long ch->dac_data >> DP_SHIFT_COUNT); 467a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_DMA_XFER0 + (sc->pch_cnt + sc->rch_cnt), 468a5108eaeSScott Long ch->dac_data >> DP_SHIFT_COUNT); 469a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_MIXER_XFER0 + sc->pch_cnt, 470a5108eaeSScott Long ch->dac_data >> DP_SHIFT_COUNT); 471a5108eaeSScott Long 472c21880a7SPyun YongHyeon /* gotta start before stop */ 473c21880a7SPyun YongHyeon m3_pchan_trigger_locked(NULL, ch, PCMTRIG_START); 474c21880a7SPyun YongHyeon /* silence noise on load */ 475c21880a7SPyun YongHyeon m3_pchan_trigger_locked(NULL, ch, PCMTRIG_STOP); 476a5108eaeSScott Long 477a5108eaeSScott Long sc->pch_cnt++; 478c21880a7SPyun YongHyeon M3_UNLOCK(sc); 479c21880a7SPyun YongHyeon 480c21880a7SPyun YongHyeon return (ch); 481a5108eaeSScott Long } 482a5108eaeSScott Long 483a5108eaeSScott Long static int 484a5108eaeSScott Long m3_pchan_free(kobj_t kobj, void *chdata) 485a5108eaeSScott Long { 486a5108eaeSScott Long struct sc_pchinfo *ch = chdata; 487a5108eaeSScott Long struct sc_info *sc = ch->parent; 488a5108eaeSScott Long 489c21880a7SPyun YongHyeon M3_LOCK(sc); 490a5108eaeSScott Long M3_DEBUG(CHANGE, ("m3_pchan_free(dac=%d)\n", ch->dac_idx)); 491a5108eaeSScott Long 492a5108eaeSScott Long /* 493a5108eaeSScott Long * should remove this exact instance from the packed lists, but all 494a5108eaeSScott Long * are released at once (and in a stopped state) so this is ok. 495a5108eaeSScott Long */ 496a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_INSTANCE0_MINISRC + 497a5108eaeSScott Long (sc->pch_cnt - 1) + sc->rch_cnt, 0); 498a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_DMA_XFER0 + 499a5108eaeSScott Long (sc->pch_cnt - 1) + sc->rch_cnt, 0); 500a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_MIXER_XFER0 + (sc->pch_cnt-1), 0); 501a5108eaeSScott Long sc->pch_cnt--; 502c21880a7SPyun YongHyeon M3_UNLOCK(sc); 503c21880a7SPyun YongHyeon 504c21880a7SPyun YongHyeon return (0); 505a5108eaeSScott Long } 506a5108eaeSScott Long 507a5108eaeSScott Long static int 508a5108eaeSScott Long m3_pchan_setformat(kobj_t kobj, void *chdata, u_int32_t format) 509a5108eaeSScott Long { 510a5108eaeSScott Long struct sc_pchinfo *ch = chdata; 511a5108eaeSScott Long struct sc_info *sc = ch->parent; 512a5108eaeSScott Long u_int32_t data; 513a5108eaeSScott Long 514c21880a7SPyun YongHyeon M3_LOCK(sc); 515a5108eaeSScott Long M3_DEBUG(CHANGE, 516a5108eaeSScott Long ("m3_pchan_setformat(dac=%d, format=0x%x{%s-%s})\n", 517a5108eaeSScott Long ch->dac_idx, format, 518a5108eaeSScott Long format & (AFMT_U8|AFMT_S8) ? "8bit":"16bit", 519a5108eaeSScott Long format & AFMT_STEREO ? "STEREO":"MONO")); 520a5108eaeSScott Long 521a5108eaeSScott Long /* mono word */ 522a5108eaeSScott Long data = (format & AFMT_STEREO) ? 0 : 1; 523a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + SRC3_MODE_OFFSET, data); 524a5108eaeSScott Long 525a5108eaeSScott Long /* 8bit word */ 526a5108eaeSScott Long data = ((format & AFMT_U8) || (format & AFMT_S8)) ? 1 : 0; 527a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + SRC3_WORD_LENGTH_OFFSET, data); 528a5108eaeSScott Long 529a5108eaeSScott Long ch->fmt = format; 530c21880a7SPyun YongHyeon M3_UNLOCK(sc); 531c21880a7SPyun YongHyeon 532c21880a7SPyun YongHyeon return (0); 533a5108eaeSScott Long } 534a5108eaeSScott Long 535a5108eaeSScott Long static int 536a5108eaeSScott Long m3_pchan_setspeed(kobj_t kobj, void *chdata, u_int32_t speed) 537a5108eaeSScott Long { 538a5108eaeSScott Long struct sc_pchinfo *ch = chdata; 539a5108eaeSScott Long struct sc_info *sc = ch->parent; 540a5108eaeSScott Long u_int32_t freq; 541a5108eaeSScott Long 542c21880a7SPyun YongHyeon M3_LOCK(sc); 543a5108eaeSScott Long M3_DEBUG(CHANGE, ("m3_pchan_setspeed(dac=%d, speed=%d)\n", 544a5108eaeSScott Long ch->dac_idx, speed)); 545a5108eaeSScott Long 546a5108eaeSScott Long if ((freq = ((speed << 15) + 24000) / 48000) != 0) { 547a5108eaeSScott Long freq--; 548a5108eaeSScott Long } 549a5108eaeSScott Long 550a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_FREQUENCY, freq); 551a5108eaeSScott Long ch->spd = speed; 552c21880a7SPyun YongHyeon M3_UNLOCK(sc); 553c21880a7SPyun YongHyeon 554c21880a7SPyun YongHyeon /* return closest possible speed */ 555c21880a7SPyun YongHyeon return (speed); 556a5108eaeSScott Long } 557a5108eaeSScott Long 558a5108eaeSScott Long static int 559a5108eaeSScott Long m3_pchan_setblocksize(kobj_t kobj, void *chdata, u_int32_t blocksize) 560a5108eaeSScott Long { 561a5108eaeSScott Long struct sc_pchinfo *ch = chdata; 562a5108eaeSScott Long 563a5108eaeSScott Long M3_DEBUG(CHANGE, ("m3_pchan_setblocksize(dac=%d, blocksize=%d)\n", 564a5108eaeSScott Long ch->dac_idx, blocksize)); 565a5108eaeSScott Long 566018b991eSAriff Abdullah return (sndbuf_getblksz(ch->buffer)); 567a5108eaeSScott Long } 568a5108eaeSScott Long 569a5108eaeSScott Long static int 570a5108eaeSScott Long m3_pchan_trigger(kobj_t kobj, void *chdata, int go) 571a5108eaeSScott Long { 572a5108eaeSScott Long struct sc_pchinfo *ch = chdata; 573a5108eaeSScott Long struct sc_info *sc = ch->parent; 574c21880a7SPyun YongHyeon int ret; 575c21880a7SPyun YongHyeon 576bdfbdcecSAriff Abdullah if (!PCMTRIG_COMMON(go)) 577bdfbdcecSAriff Abdullah return (0); 578bdfbdcecSAriff Abdullah 579c21880a7SPyun YongHyeon M3_LOCK(sc); 580c21880a7SPyun YongHyeon ret = m3_pchan_trigger_locked(kobj, chdata, go); 581c21880a7SPyun YongHyeon M3_UNLOCK(sc); 582c21880a7SPyun YongHyeon 583c21880a7SPyun YongHyeon return (ret); 584c21880a7SPyun YongHyeon } 585c21880a7SPyun YongHyeon 586c21880a7SPyun YongHyeon static int 587018b991eSAriff Abdullah m3_chan_active(struct sc_info *sc) 588018b991eSAriff Abdullah { 589018b991eSAriff Abdullah int i, ret; 590018b991eSAriff Abdullah 591018b991eSAriff Abdullah ret = 0; 592018b991eSAriff Abdullah 593018b991eSAriff Abdullah for (i = 0; i < sc->pch_cnt; i++) 594018b991eSAriff Abdullah ret += sc->pch[i].active; 595018b991eSAriff Abdullah 596018b991eSAriff Abdullah for (i = 0; i < sc->rch_cnt; i++) 597018b991eSAriff Abdullah ret += sc->rch[i].active; 598018b991eSAriff Abdullah 599018b991eSAriff Abdullah return (ret); 600018b991eSAriff Abdullah } 601018b991eSAriff Abdullah 602018b991eSAriff Abdullah static int 603c21880a7SPyun YongHyeon m3_pchan_trigger_locked(kobj_t kobj, void *chdata, int go) 604c21880a7SPyun YongHyeon { 605c21880a7SPyun YongHyeon struct sc_pchinfo *ch = chdata; 606c21880a7SPyun YongHyeon struct sc_info *sc = ch->parent; 607a5108eaeSScott Long u_int32_t data; 608a5108eaeSScott Long 609c21880a7SPyun YongHyeon M3_LOCK_ASSERT(sc); 610a5108eaeSScott Long M3_DEBUG(go == PCMTRIG_START ? CHANGE : 611a5108eaeSScott Long go == PCMTRIG_STOP ? CHANGE : 612a5108eaeSScott Long go == PCMTRIG_ABORT ? CHANGE : 613a5108eaeSScott Long CALL, 614a5108eaeSScott Long ("m3_pchan_trigger(dac=%d, go=0x%x{%s})\n", ch->dac_idx, go, 615a5108eaeSScott Long go == PCMTRIG_START ? "PCMTRIG_START" : 616a5108eaeSScott Long go == PCMTRIG_STOP ? "PCMTRIG_STOP" : 617a5108eaeSScott Long go == PCMTRIG_ABORT ? "PCMTRIG_ABORT" : "ignore")); 618a5108eaeSScott Long 619a5108eaeSScott Long switch(go) { 620a5108eaeSScott Long case PCMTRIG_START: 621a5108eaeSScott Long if (ch->active) { 622a5108eaeSScott Long return 0; 623a5108eaeSScott Long } 624a5108eaeSScott Long ch->active = 1; 625018b991eSAriff Abdullah ch->ptr = 0; 626018b991eSAriff Abdullah ch->prevptr = 0; 627a5108eaeSScott Long sc->pch_active_cnt++; 628a5108eaeSScott Long 629a5108eaeSScott Long /*[[inc_timer_users]]*/ 630018b991eSAriff Abdullah if (m3_chan_active(sc) == 1) { 631a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_TIMER_COUNT_RELOAD, 240); 632a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_TIMER_COUNT_CURRENT, 240); 633a5108eaeSScott Long data = m3_rd_2(sc, HOST_INT_CTRL); 634a5108eaeSScott Long m3_wr_2(sc, HOST_INT_CTRL, data | CLKRUN_GEN_ENABLE); 635018b991eSAriff Abdullah } 636a5108eaeSScott Long 637a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_INSTANCE_READY, 1); 638a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_MIXER_TASK_NUMBER, 639a5108eaeSScott Long sc->pch_active_cnt); 640a5108eaeSScott Long break; 641a5108eaeSScott Long 642a5108eaeSScott Long case PCMTRIG_STOP: 643a5108eaeSScott Long case PCMTRIG_ABORT: 644a5108eaeSScott Long if (ch->active == 0) { 645a5108eaeSScott Long return 0; 646a5108eaeSScott Long } 647a5108eaeSScott Long ch->active = 0; 648a5108eaeSScott Long sc->pch_active_cnt--; 649a5108eaeSScott Long 650a5108eaeSScott Long /* XXX should the channel be drained? */ 651a5108eaeSScott Long /*[[dec_timer_users]]*/ 652018b991eSAriff Abdullah if (m3_chan_active(sc) == 0) { 653a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_TIMER_COUNT_RELOAD, 0); 654a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_TIMER_COUNT_CURRENT, 0); 655a5108eaeSScott Long data = m3_rd_2(sc, HOST_INT_CTRL); 656a5108eaeSScott Long m3_wr_2(sc, HOST_INT_CTRL, data & ~CLKRUN_GEN_ENABLE); 657018b991eSAriff Abdullah } 658a5108eaeSScott Long 659a5108eaeSScott Long m3_wr_assp_data(sc, ch->dac_data + CDATA_INSTANCE_READY, 0); 660a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_MIXER_TASK_NUMBER, 661a5108eaeSScott Long sc->pch_active_cnt); 662a5108eaeSScott Long break; 663a5108eaeSScott Long 664a5108eaeSScott Long case PCMTRIG_EMLDMAWR: 665a5108eaeSScott Long /* got play irq, transfer next buffer - ignore if using dma */ 666a5108eaeSScott Long case PCMTRIG_EMLDMARD: 667a5108eaeSScott Long /* got rec irq, transfer next buffer - ignore if using dma */ 668a5108eaeSScott Long default: 669a5108eaeSScott Long break; 670a5108eaeSScott Long } 671a5108eaeSScott Long return 0; 672a5108eaeSScott Long } 673a5108eaeSScott Long 674018b991eSAriff Abdullah static u_int32_t 675018b991eSAriff Abdullah m3_pchan_getptr_internal(struct sc_pchinfo *ch) 676a5108eaeSScott Long { 677a5108eaeSScott Long struct sc_info *sc = ch->parent; 678c21880a7SPyun YongHyeon u_int32_t hi, lo, bus_base, bus_crnt; 679a5108eaeSScott Long 680c21880a7SPyun YongHyeon bus_base = sndbuf_getbufaddr(ch->buffer); 681a5108eaeSScott Long hi = m3_rd_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_CURRENTH); 682a5108eaeSScott Long lo = m3_rd_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_CURRENTL); 683a5108eaeSScott Long bus_crnt = lo | (hi << 16); 684a5108eaeSScott Long 685a5108eaeSScott Long M3_DEBUG(CALL, ("m3_pchan_getptr(dac=%d) result=%d\n", 686a5108eaeSScott Long ch->dac_idx, bus_crnt - bus_base)); 687a5108eaeSScott Long 688a5108eaeSScott Long return (bus_crnt - bus_base); /* current byte offset of channel */ 689a5108eaeSScott Long } 690a5108eaeSScott Long 691018b991eSAriff Abdullah static u_int32_t 692018b991eSAriff Abdullah m3_pchan_getptr(kobj_t kobj, void *chdata) 693018b991eSAriff Abdullah { 694018b991eSAriff Abdullah struct sc_pchinfo *ch = chdata; 695018b991eSAriff Abdullah struct sc_info *sc = ch->parent; 696018b991eSAriff Abdullah u_int32_t ptr; 697018b991eSAriff Abdullah 698018b991eSAriff Abdullah M3_LOCK(sc); 699018b991eSAriff Abdullah ptr = ch->ptr; 700018b991eSAriff Abdullah M3_UNLOCK(sc); 701018b991eSAriff Abdullah 702018b991eSAriff Abdullah return (ptr); 703018b991eSAriff Abdullah } 704018b991eSAriff Abdullah 70566ef8af5SCameron Grant static struct pcmchan_caps * 706a5108eaeSScott Long m3_pchan_getcaps(kobj_t kobj, void *chdata) 707a5108eaeSScott Long { 708a5108eaeSScott Long struct sc_pchinfo *ch = chdata; 709a5108eaeSScott Long 710a5108eaeSScott Long M3_DEBUG(CALL, ("m3_pchan_getcaps(dac=%d)\n", ch->dac_idx)); 711a5108eaeSScott Long 712a5108eaeSScott Long return &m3_playcaps; 713a5108eaeSScott Long } 714a5108eaeSScott Long 715a5108eaeSScott Long /* -------------------------------------------------------------------- */ 716a5108eaeSScott Long /* rec channel interface */ 717a5108eaeSScott Long 718a5108eaeSScott Long static void * 71966ef8af5SCameron Grant m3_rchan_init(kobj_t kobj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 720a5108eaeSScott Long { 721a5108eaeSScott Long struct sc_info *sc = devinfo; 722a5108eaeSScott Long struct sc_rchinfo *ch; 723a5108eaeSScott Long u_int32_t bus_addr, i; 724a5108eaeSScott Long 725c21880a7SPyun YongHyeon int idx, data_bytes, adc_data; 726c21880a7SPyun YongHyeon int dsp_in_size, dsp_out_size, dsp_in_buf, dsp_out_buf; 727a5108eaeSScott Long 728c21880a7SPyun YongHyeon M3_LOCK(sc); 729c21880a7SPyun YongHyeon idx = sc->rch_cnt; /* adc instance number, no active reuse! */ 730a5108eaeSScott Long M3_DEBUG(CHANGE, ("m3_rchan_init(adc=%d)\n", idx)); 731a5108eaeSScott Long 732a5108eaeSScott Long if (dir != PCMDIR_REC) { 733c21880a7SPyun YongHyeon M3_UNLOCK(sc); 734a5108eaeSScott Long device_printf(sc->dev, "m3_pchan_init not PCMDIR_REC\n"); 735c21880a7SPyun YongHyeon return (NULL); 736a5108eaeSScott Long } 737a5108eaeSScott Long 738c21880a7SPyun YongHyeon data_bytes = (((MINISRC_TMP_BUFFER_SIZE & ~1) + 739c21880a7SPyun YongHyeon (MINISRC_IN_BUFFER_SIZE & ~1) + 740c21880a7SPyun YongHyeon (MINISRC_OUT_BUFFER_SIZE & ~1) + 4) + 255) &~ 255; 741c21880a7SPyun YongHyeon adc_data = 0x1100 + (data_bytes * idx) + data_bytes/2; 742c21880a7SPyun YongHyeon dsp_in_size = MINISRC_IN_BUFFER_SIZE + (0x10 * 2); 743c21880a7SPyun YongHyeon dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x10 * 2); 744c21880a7SPyun YongHyeon dsp_in_buf = adc_data + (MINISRC_TMP_BUFFER_SIZE / 2); 745c21880a7SPyun YongHyeon dsp_out_buf = dsp_in_buf + (dsp_in_size / 2) + 1; 746c21880a7SPyun YongHyeon 747c21880a7SPyun YongHyeon ch = &sc->rch[idx]; 748a5108eaeSScott Long ch->adc_idx = idx; 749a5108eaeSScott Long ch->adc_data = adc_data; 750a5108eaeSScott Long if (ch->adc_data + data_bytes/2 >= 0x1c00) { 751c21880a7SPyun YongHyeon M3_UNLOCK(sc); 752a5108eaeSScott Long device_printf(sc->dev, "m3_rchan_init: revb mem exhausted\n"); 753c21880a7SPyun YongHyeon return (NULL); 754a5108eaeSScott Long } 755a5108eaeSScott Long 756a5108eaeSScott Long ch->buffer = b; 757a5108eaeSScott Long ch->parent = sc; 758a5108eaeSScott Long ch->channel = c; 759a5108eaeSScott Long ch->fmt = AFMT_U8; 760a5108eaeSScott Long ch->spd = DSP_DEFAULT_SPEED; 761c21880a7SPyun YongHyeon M3_UNLOCK(sc); /* XXX */ 7622e334adfSAriff Abdullah if (sndbuf_alloc(ch->buffer, sc->parent_dmat, 0, sc->bufsz) != 0) { 763a5108eaeSScott Long device_printf(sc->dev, "m3_rchan_init chn_allocbuf failed\n"); 764c21880a7SPyun YongHyeon return (NULL); 765a5108eaeSScott Long } 766c21880a7SPyun YongHyeon M3_LOCK(sc); 767a5108eaeSScott Long ch->bufsize = sndbuf_getsize(ch->buffer); 768a5108eaeSScott Long 769a5108eaeSScott Long /* host dma buffer pointers */ 77038cc9942SOlivier Houchard bus_addr = sndbuf_getbufaddr(ch->buffer); 771a5108eaeSScott Long if (bus_addr & 3) { 772a5108eaeSScott Long device_printf(sc->dev, "m3_rchan_init unaligned bus_addr\n"); 773a5108eaeSScott Long bus_addr = (bus_addr + 4) & ~3; 774a5108eaeSScott Long } 775a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_ADDRL, LO(bus_addr)); 776a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_ADDRH, HI(bus_addr)); 777a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_END_PLUS_1L, 778a5108eaeSScott Long LO(bus_addr + ch->bufsize)); 779a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_END_PLUS_1H, 780a5108eaeSScott Long HI(bus_addr + ch->bufsize)); 781a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_CURRENTL, 782a5108eaeSScott Long LO(bus_addr)); 783a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_CURRENTH, 784a5108eaeSScott Long HI(bus_addr)); 785a5108eaeSScott Long 786a5108eaeSScott Long /* dsp buffers */ 787a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_IN_BUF_BEGIN, dsp_in_buf); 788a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_IN_BUF_END_PLUS_1, 789a5108eaeSScott Long dsp_in_buf + dsp_in_size/2); 790a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_IN_BUF_HEAD, dsp_in_buf); 791a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_IN_BUF_TAIL, dsp_in_buf); 792a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_OUT_BUF_BEGIN, dsp_out_buf); 793a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_OUT_BUF_END_PLUS_1, 794a5108eaeSScott Long dsp_out_buf + dsp_out_size/2); 795a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_OUT_BUF_HEAD, dsp_out_buf); 796a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_OUT_BUF_TAIL, dsp_out_buf); 797a5108eaeSScott Long 798a5108eaeSScott Long /* some per client initializers */ 799a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + SRC3_DIRECTION_OFFSET + 12, 800a5108eaeSScott Long ch->adc_data + 40 + 8); 801a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_DMA_CONTROL, 802a5108eaeSScott Long DMACONTROL_DIRECTION + DMACONTROL_AUTOREPEAT + 803a5108eaeSScott Long DMAC_PAGE3_SELECTOR + DMAC_BLOCKF_SELECTOR); 804a5108eaeSScott Long 805a5108eaeSScott Long /* set an armload of static initializers */ 806a5108eaeSScott Long for(i = 0 ; i < (sizeof(rv) / sizeof(rv[0])) ; i++) { 807a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + rv[i].addr, rv[i].val); 808a5108eaeSScott Long } 809a5108eaeSScott Long 810a5108eaeSScott Long /* put us in the packed task lists */ 811a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_INSTANCE0_MINISRC + 812a5108eaeSScott Long (sc->pch_cnt + sc->rch_cnt), 813a5108eaeSScott Long ch->adc_data >> DP_SHIFT_COUNT); 814a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_DMA_XFER0 + (sc->pch_cnt + sc->rch_cnt), 815a5108eaeSScott Long ch->adc_data >> DP_SHIFT_COUNT); 816a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_ADC1_XFER0 + sc->rch_cnt, 817a5108eaeSScott Long ch->adc_data >> DP_SHIFT_COUNT); 818a5108eaeSScott Long 819c21880a7SPyun YongHyeon /* gotta start before stop */ 820c21880a7SPyun YongHyeon m3_rchan_trigger_locked(NULL, ch, PCMTRIG_START); 821c21880a7SPyun YongHyeon /* stop on init */ 822c21880a7SPyun YongHyeon m3_rchan_trigger_locked(NULL, ch, PCMTRIG_STOP); 823a5108eaeSScott Long 824a5108eaeSScott Long sc->rch_cnt++; 825c21880a7SPyun YongHyeon M3_UNLOCK(sc); 826c21880a7SPyun YongHyeon 827c21880a7SPyun YongHyeon return (ch); 828a5108eaeSScott Long } 829a5108eaeSScott Long 830a5108eaeSScott Long static int 831a5108eaeSScott Long m3_rchan_free(kobj_t kobj, void *chdata) 832a5108eaeSScott Long { 833a5108eaeSScott Long struct sc_rchinfo *ch = chdata; 834a5108eaeSScott Long struct sc_info *sc = ch->parent; 835a5108eaeSScott Long 836c21880a7SPyun YongHyeon M3_LOCK(sc); 837a5108eaeSScott Long M3_DEBUG(CHANGE, ("m3_rchan_free(adc=%d)\n", ch->adc_idx)); 838a5108eaeSScott Long 839a5108eaeSScott Long /* 840a5108eaeSScott Long * should remove this exact instance from the packed lists, but all 841a5108eaeSScott Long * are released at once (and in a stopped state) so this is ok. 842a5108eaeSScott Long */ 843a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_INSTANCE0_MINISRC + 844a5108eaeSScott Long (sc->rch_cnt - 1) + sc->pch_cnt, 0); 845a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_DMA_XFER0 + 846a5108eaeSScott Long (sc->rch_cnt - 1) + sc->pch_cnt, 0); 847a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_ADC1_XFER0 + (sc->rch_cnt - 1), 0); 848a5108eaeSScott Long sc->rch_cnt--; 849c21880a7SPyun YongHyeon M3_UNLOCK(sc); 850c21880a7SPyun YongHyeon 851c21880a7SPyun YongHyeon return (0); 852a5108eaeSScott Long } 853a5108eaeSScott Long 854a5108eaeSScott Long static int 855a5108eaeSScott Long m3_rchan_setformat(kobj_t kobj, void *chdata, u_int32_t format) 856a5108eaeSScott Long { 857a5108eaeSScott Long struct sc_rchinfo *ch = chdata; 858a5108eaeSScott Long struct sc_info *sc = ch->parent; 859a5108eaeSScott Long u_int32_t data; 860a5108eaeSScott Long 861c21880a7SPyun YongHyeon M3_LOCK(sc); 862a5108eaeSScott Long M3_DEBUG(CHANGE, 863a5108eaeSScott Long ("m3_rchan_setformat(dac=%d, format=0x%x{%s-%s})\n", 864a5108eaeSScott Long ch->adc_idx, format, 865a5108eaeSScott Long format & (AFMT_U8|AFMT_S8) ? "8bit":"16bit", 866a5108eaeSScott Long format & AFMT_STEREO ? "STEREO":"MONO")); 867a5108eaeSScott Long 868a5108eaeSScott Long /* mono word */ 869a5108eaeSScott Long data = (format & AFMT_STEREO) ? 0 : 1; 870a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + SRC3_MODE_OFFSET, data); 871a5108eaeSScott Long 872a5108eaeSScott Long /* 8bit word */ 873a5108eaeSScott Long data = ((format & AFMT_U8) || (format & AFMT_S8)) ? 1 : 0; 874a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + SRC3_WORD_LENGTH_OFFSET, data); 875a5108eaeSScott Long ch->fmt = format; 876c21880a7SPyun YongHyeon M3_UNLOCK(sc); 877c21880a7SPyun YongHyeon 878c21880a7SPyun YongHyeon return (0); 879a5108eaeSScott Long } 880a5108eaeSScott Long 881a5108eaeSScott Long static int 882a5108eaeSScott Long m3_rchan_setspeed(kobj_t kobj, void *chdata, u_int32_t speed) 883a5108eaeSScott Long { 884a5108eaeSScott Long struct sc_rchinfo *ch = chdata; 885a5108eaeSScott Long struct sc_info *sc = ch->parent; 886a5108eaeSScott Long u_int32_t freq; 887a5108eaeSScott Long 888c21880a7SPyun YongHyeon M3_LOCK(sc); 889a5108eaeSScott Long M3_DEBUG(CHANGE, ("m3_rchan_setspeed(adc=%d, speed=%d)\n", 890a5108eaeSScott Long ch->adc_idx, speed)); 891a5108eaeSScott Long 892a5108eaeSScott Long if ((freq = ((speed << 15) + 24000) / 48000) != 0) { 893a5108eaeSScott Long freq--; 894a5108eaeSScott Long } 895a5108eaeSScott Long 896a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_FREQUENCY, freq); 897a5108eaeSScott Long ch->spd = speed; 898c21880a7SPyun YongHyeon M3_UNLOCK(sc); 899c21880a7SPyun YongHyeon 900c21880a7SPyun YongHyeon /* return closest possible speed */ 901c21880a7SPyun YongHyeon return (speed); 902a5108eaeSScott Long } 903a5108eaeSScott Long 904a5108eaeSScott Long static int 905a5108eaeSScott Long m3_rchan_setblocksize(kobj_t kobj, void *chdata, u_int32_t blocksize) 906a5108eaeSScott Long { 907a5108eaeSScott Long struct sc_rchinfo *ch = chdata; 908a5108eaeSScott Long 909a5108eaeSScott Long M3_DEBUG(CHANGE, ("m3_rchan_setblocksize(adc=%d, blocksize=%d)\n", 910a5108eaeSScott Long ch->adc_idx, blocksize)); 911a5108eaeSScott Long 912018b991eSAriff Abdullah return (sndbuf_getblksz(ch->buffer)); 913a5108eaeSScott Long } 914a5108eaeSScott Long 915a5108eaeSScott Long static int 916a5108eaeSScott Long m3_rchan_trigger(kobj_t kobj, void *chdata, int go) 917a5108eaeSScott Long { 918a5108eaeSScott Long struct sc_rchinfo *ch = chdata; 919a5108eaeSScott Long struct sc_info *sc = ch->parent; 920c21880a7SPyun YongHyeon int ret; 921c21880a7SPyun YongHyeon 922bdfbdcecSAriff Abdullah if (!PCMTRIG_COMMON(go)) 923bdfbdcecSAriff Abdullah return (0); 924bdfbdcecSAriff Abdullah 925c21880a7SPyun YongHyeon M3_LOCK(sc); 926c21880a7SPyun YongHyeon ret = m3_rchan_trigger_locked(kobj, chdata, go); 927c21880a7SPyun YongHyeon M3_UNLOCK(sc); 928c21880a7SPyun YongHyeon 929c21880a7SPyun YongHyeon return (ret); 930c21880a7SPyun YongHyeon } 931c21880a7SPyun YongHyeon 932c21880a7SPyun YongHyeon static int 933c21880a7SPyun YongHyeon m3_rchan_trigger_locked(kobj_t kobj, void *chdata, int go) 934c21880a7SPyun YongHyeon { 935c21880a7SPyun YongHyeon struct sc_rchinfo *ch = chdata; 936c21880a7SPyun YongHyeon struct sc_info *sc = ch->parent; 937a5108eaeSScott Long u_int32_t data; 938a5108eaeSScott Long 939c21880a7SPyun YongHyeon M3_LOCK_ASSERT(sc); 940a5108eaeSScott Long M3_DEBUG(go == PCMTRIG_START ? CHANGE : 941a5108eaeSScott Long go == PCMTRIG_STOP ? CHANGE : 942a5108eaeSScott Long go == PCMTRIG_ABORT ? CHANGE : 943a5108eaeSScott Long CALL, 944a5108eaeSScott Long ("m3_rchan_trigger(adc=%d, go=0x%x{%s})\n", ch->adc_idx, go, 945a5108eaeSScott Long go == PCMTRIG_START ? "PCMTRIG_START" : 946a5108eaeSScott Long go == PCMTRIG_STOP ? "PCMTRIG_STOP" : 947a5108eaeSScott Long go == PCMTRIG_ABORT ? "PCMTRIG_ABORT" : "ignore")); 948a5108eaeSScott Long 949a5108eaeSScott Long switch(go) { 950a5108eaeSScott Long case PCMTRIG_START: 951a5108eaeSScott Long if (ch->active) { 952a5108eaeSScott Long return 0; 953a5108eaeSScott Long } 954a5108eaeSScott Long ch->active = 1; 955018b991eSAriff Abdullah ch->ptr = 0; 956018b991eSAriff Abdullah ch->prevptr = 0; 957a5108eaeSScott Long 958a5108eaeSScott Long /*[[inc_timer_users]]*/ 959018b991eSAriff Abdullah if (m3_chan_active(sc) == 1) { 960a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_TIMER_COUNT_RELOAD, 240); 961a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_TIMER_COUNT_CURRENT, 240); 962a5108eaeSScott Long data = m3_rd_2(sc, HOST_INT_CTRL); 963a5108eaeSScott Long m3_wr_2(sc, HOST_INT_CTRL, data | CLKRUN_GEN_ENABLE); 964018b991eSAriff Abdullah } 965a5108eaeSScott Long 966a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_ADC1_REQUEST, 1); 967a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_INSTANCE_READY, 1); 968a5108eaeSScott Long break; 969a5108eaeSScott Long 970a5108eaeSScott Long case PCMTRIG_STOP: 971a5108eaeSScott Long case PCMTRIG_ABORT: 972a5108eaeSScott Long if (ch->active == 0) { 973a5108eaeSScott Long return 0; 974a5108eaeSScott Long } 975a5108eaeSScott Long ch->active = 0; 976a5108eaeSScott Long 977a5108eaeSScott Long /*[[dec_timer_users]]*/ 978018b991eSAriff Abdullah if (m3_chan_active(sc) == 0) { 979a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_TIMER_COUNT_RELOAD, 0); 980a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_TIMER_COUNT_CURRENT, 0); 981a5108eaeSScott Long data = m3_rd_2(sc, HOST_INT_CTRL); 982a5108eaeSScott Long m3_wr_2(sc, HOST_INT_CTRL, data & ~CLKRUN_GEN_ENABLE); 983018b991eSAriff Abdullah } 984a5108eaeSScott Long 985a5108eaeSScott Long m3_wr_assp_data(sc, ch->adc_data + CDATA_INSTANCE_READY, 0); 986a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_ADC1_REQUEST, 0); 987a5108eaeSScott Long break; 988a5108eaeSScott Long 989a5108eaeSScott Long case PCMTRIG_EMLDMAWR: 990a5108eaeSScott Long /* got play irq, transfer next buffer - ignore if using dma */ 991a5108eaeSScott Long case PCMTRIG_EMLDMARD: 992a5108eaeSScott Long /* got rec irq, transfer next buffer - ignore if using dma */ 993a5108eaeSScott Long default: 994a5108eaeSScott Long break; 995a5108eaeSScott Long } 996a5108eaeSScott Long return 0; 997a5108eaeSScott Long } 998a5108eaeSScott Long 999018b991eSAriff Abdullah static u_int32_t 1000018b991eSAriff Abdullah m3_rchan_getptr_internal(struct sc_rchinfo *ch) 1001a5108eaeSScott Long { 1002a5108eaeSScott Long struct sc_info *sc = ch->parent; 1003c21880a7SPyun YongHyeon u_int32_t hi, lo, bus_base, bus_crnt; 1004a5108eaeSScott Long 1005c21880a7SPyun YongHyeon bus_base = sndbuf_getbufaddr(ch->buffer); 1006a5108eaeSScott Long hi = m3_rd_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_CURRENTH); 1007a5108eaeSScott Long lo = m3_rd_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_CURRENTL); 1008a5108eaeSScott Long bus_crnt = lo | (hi << 16); 1009a5108eaeSScott Long 1010a5108eaeSScott Long M3_DEBUG(CALL, ("m3_rchan_getptr(adc=%d) result=%d\n", 1011a5108eaeSScott Long ch->adc_idx, bus_crnt - bus_base)); 1012a5108eaeSScott Long 1013a5108eaeSScott Long return (bus_crnt - bus_base); /* current byte offset of channel */ 1014a5108eaeSScott Long } 1015a5108eaeSScott Long 1016018b991eSAriff Abdullah static u_int32_t 1017018b991eSAriff Abdullah m3_rchan_getptr(kobj_t kobj, void *chdata) 1018018b991eSAriff Abdullah { 1019018b991eSAriff Abdullah struct sc_rchinfo *ch = chdata; 1020018b991eSAriff Abdullah struct sc_info *sc = ch->parent; 1021018b991eSAriff Abdullah u_int32_t ptr; 1022018b991eSAriff Abdullah 1023018b991eSAriff Abdullah M3_LOCK(sc); 1024018b991eSAriff Abdullah ptr = ch->ptr; 1025018b991eSAriff Abdullah M3_UNLOCK(sc); 1026018b991eSAriff Abdullah 1027018b991eSAriff Abdullah return (ptr); 1028018b991eSAriff Abdullah } 1029018b991eSAriff Abdullah 103066ef8af5SCameron Grant static struct pcmchan_caps * 1031a5108eaeSScott Long m3_rchan_getcaps(kobj_t kobj, void *chdata) 1032a5108eaeSScott Long { 1033a5108eaeSScott Long struct sc_rchinfo *ch = chdata; 1034a5108eaeSScott Long 1035a5108eaeSScott Long M3_DEBUG(CALL, ("m3_rchan_getcaps(adc=%d)\n", ch->adc_idx)); 1036a5108eaeSScott Long 1037a5108eaeSScott Long return &m3_reccaps; 1038a5108eaeSScott Long } 1039a5108eaeSScott Long 1040a5108eaeSScott Long /* -------------------------------------------------------------------- */ 1041a5108eaeSScott Long /* The interrupt handler */ 1042a5108eaeSScott Long 1043a5108eaeSScott Long static void 1044a5108eaeSScott Long m3_intr(void *p) 1045a5108eaeSScott Long { 1046a5108eaeSScott Long struct sc_info *sc = (struct sc_info *)p; 1047018b991eSAriff Abdullah struct sc_pchinfo *pch; 1048018b991eSAriff Abdullah struct sc_rchinfo *rch; 1049018b991eSAriff Abdullah u_int32_t status, ctl, i, delta; 1050a5108eaeSScott Long 1051a5108eaeSScott Long M3_DEBUG(INTR, ("m3_intr\n")); 1052a5108eaeSScott Long 1053c21880a7SPyun YongHyeon M3_LOCK(sc); 1054a5108eaeSScott Long status = m3_rd_1(sc, HOST_INT_STATUS); 1055c21880a7SPyun YongHyeon if (!status) { 1056c21880a7SPyun YongHyeon M3_UNLOCK(sc); 1057a5108eaeSScott Long return; 1058c21880a7SPyun YongHyeon } 1059a5108eaeSScott Long 1060a5108eaeSScott Long m3_wr_1(sc, HOST_INT_STATUS, 0xff); /* ack the int? */ 1061a5108eaeSScott Long 1062a5108eaeSScott Long if (status & HV_INT_PENDING) { 1063a5108eaeSScott Long u_int8_t event; 1064a5108eaeSScott Long 1065a5108eaeSScott Long event = m3_rd_1(sc, HW_VOL_COUNTER_MASTER); 1066a5108eaeSScott Long switch (event) { 1067a5108eaeSScott Long case 0x99: 1068a5108eaeSScott Long mixer_hwvol_mute(sc->dev); 1069a5108eaeSScott Long break; 1070a5108eaeSScott Long case 0xaa: 1071a5108eaeSScott Long mixer_hwvol_step(sc->dev, 1, 1); 1072a5108eaeSScott Long break; 1073a5108eaeSScott Long case 0x66: 1074a5108eaeSScott Long mixer_hwvol_step(sc->dev, -1, -1); 1075a5108eaeSScott Long break; 1076a5108eaeSScott Long case 0x88: 1077a5108eaeSScott Long break; 1078a5108eaeSScott Long default: 1079a5108eaeSScott Long device_printf(sc->dev, "Unknown HWVOL event\n"); 1080a5108eaeSScott Long } 1081a5108eaeSScott Long m3_wr_1(sc, HW_VOL_COUNTER_MASTER, 0x88); 1082a5108eaeSScott Long 1083a5108eaeSScott Long } 1084a5108eaeSScott Long 1085a5108eaeSScott Long if (status & ASSP_INT_PENDING) { 1086a5108eaeSScott Long ctl = m3_rd_1(sc, ASSP_CONTROL_B); 1087a5108eaeSScott Long if (!(ctl & STOP_ASSP_CLOCK)) { 1088a5108eaeSScott Long ctl = m3_rd_1(sc, ASSP_HOST_INT_STATUS); 1089a5108eaeSScott Long if (ctl & DSP2HOST_REQ_TIMER) { 1090a5108eaeSScott Long m3_wr_1(sc, ASSP_HOST_INT_STATUS, 1091a5108eaeSScott Long DSP2HOST_REQ_TIMER); 1092a5108eaeSScott Long /*[[ess_update_ptr]]*/ 1093018b991eSAriff Abdullah goto m3_handle_channel_intr; 1094a5108eaeSScott Long } 1095a5108eaeSScott Long } 1096a5108eaeSScott Long } 1097a5108eaeSScott Long 1098018b991eSAriff Abdullah goto m3_handle_channel_intr_out; 1099018b991eSAriff Abdullah 1100018b991eSAriff Abdullah m3_handle_channel_intr: 1101a5108eaeSScott Long for (i=0 ; i<sc->pch_cnt ; i++) { 1102018b991eSAriff Abdullah pch = &sc->pch[i]; 1103018b991eSAriff Abdullah if (pch->active) { 1104018b991eSAriff Abdullah pch->ptr = m3_pchan_getptr_internal(pch); 1105018b991eSAriff Abdullah delta = pch->bufsize + pch->ptr - pch->prevptr; 1106018b991eSAriff Abdullah delta %= pch->bufsize; 1107018b991eSAriff Abdullah if (delta < sndbuf_getblksz(pch->buffer)) 1108018b991eSAriff Abdullah continue; 1109018b991eSAriff Abdullah pch->prevptr = pch->ptr; 1110c21880a7SPyun YongHyeon M3_UNLOCK(sc); 1111018b991eSAriff Abdullah chn_intr(pch->channel); 1112c21880a7SPyun YongHyeon M3_LOCK(sc); 1113a5108eaeSScott Long } 1114a5108eaeSScott Long } 1115a5108eaeSScott Long for (i=0 ; i<sc->rch_cnt ; i++) { 1116018b991eSAriff Abdullah rch = &sc->rch[i]; 1117018b991eSAriff Abdullah if (rch->active) { 1118018b991eSAriff Abdullah rch->ptr = m3_rchan_getptr_internal(rch); 1119018b991eSAriff Abdullah delta = rch->bufsize + rch->ptr - rch->prevptr; 1120018b991eSAriff Abdullah delta %= rch->bufsize; 1121018b991eSAriff Abdullah if (delta < sndbuf_getblksz(rch->buffer)) 1122018b991eSAriff Abdullah continue; 1123018b991eSAriff Abdullah rch->prevptr = rch->ptr; 1124c21880a7SPyun YongHyeon M3_UNLOCK(sc); 1125018b991eSAriff Abdullah chn_intr(rch->channel); 1126c21880a7SPyun YongHyeon M3_LOCK(sc); 1127a5108eaeSScott Long } 1128a5108eaeSScott Long } 1129c21880a7SPyun YongHyeon 1130018b991eSAriff Abdullah m3_handle_channel_intr_out: 1131c21880a7SPyun YongHyeon M3_UNLOCK(sc); 1132a5108eaeSScott Long } 1133a5108eaeSScott Long 1134a5108eaeSScott Long /* -------------------------------------------------------------------- */ 1135a5108eaeSScott Long /* stuff */ 1136a5108eaeSScott Long 1137a5108eaeSScott Long static int 1138a5108eaeSScott Long m3_power(struct sc_info *sc, int state) 1139a5108eaeSScott Long { 1140a5108eaeSScott Long u_int32_t data; 1141a5108eaeSScott Long 1142a5108eaeSScott Long M3_DEBUG(CHANGE, ("m3_power(%d)\n", state)); 1143c21880a7SPyun YongHyeon M3_LOCK_ASSERT(sc); 1144a5108eaeSScott Long 1145a5108eaeSScott Long data = pci_read_config(sc->dev, 0x34, 1); 1146a5108eaeSScott Long if (pci_read_config(sc->dev, data, 1) == 1) { 1147a5108eaeSScott Long pci_write_config(sc->dev, data + 4, state, 1); 1148a5108eaeSScott Long } 1149a5108eaeSScott Long 1150a5108eaeSScott Long return 0; 1151a5108eaeSScott Long } 1152a5108eaeSScott Long 1153a5108eaeSScott Long static int 1154a5108eaeSScott Long m3_init(struct sc_info *sc) 1155a5108eaeSScott Long { 1156a5108eaeSScott Long u_int32_t data, i, size; 1157a5108eaeSScott Long u_int8_t reset_state; 1158a5108eaeSScott Long 1159c21880a7SPyun YongHyeon M3_LOCK_ASSERT(sc); 1160a5108eaeSScott Long M3_DEBUG(CHANGE, ("m3_init\n")); 1161a5108eaeSScott Long 1162a5108eaeSScott Long /* diable legacy emulations. */ 1163a5108eaeSScott Long data = pci_read_config(sc->dev, PCI_LEGACY_AUDIO_CTRL, 2); 1164a5108eaeSScott Long data |= DISABLE_LEGACY; 1165a5108eaeSScott Long pci_write_config(sc->dev, PCI_LEGACY_AUDIO_CTRL, data, 2); 1166a5108eaeSScott Long 1167a5108eaeSScott Long m3_config(sc); 1168a5108eaeSScott Long 1169a5108eaeSScott Long reset_state = m3_assp_halt(sc); 1170a5108eaeSScott Long 1171a5108eaeSScott Long m3_codec_reset(sc); 1172a5108eaeSScott Long 1173a5108eaeSScott Long /* [m3_assp_init] */ 1174a5108eaeSScott Long /* zero kernel data */ 1175a5108eaeSScott Long size = REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA; 1176a5108eaeSScott Long for(i = 0 ; i < size / 2 ; i++) { 1177a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_BASE_ADDR + i, 0); 1178a5108eaeSScott Long } 1179a5108eaeSScott Long /* zero mixer data? */ 1180a5108eaeSScott Long size = REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA; 1181a5108eaeSScott Long for(i = 0 ; i < size / 2 ; i++) { 1182a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_BASE_ADDR2 + i, 0); 1183a5108eaeSScott Long } 1184a5108eaeSScott Long /* init dma pointer */ 1185a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_CURRENT_DMA, 1186a5108eaeSScott Long KDATA_DMA_XFER0); 1187a5108eaeSScott Long /* write kernel into code memory */ 1188a5108eaeSScott Long size = sizeof(assp_kernel_image); 1189a5108eaeSScott Long for(i = 0 ; i < size / 2; i++) { 1190a5108eaeSScott Long m3_wr_assp_code(sc, REV_B_CODE_MEMORY_BEGIN + i, 1191a5108eaeSScott Long assp_kernel_image[i]); 1192a5108eaeSScott Long } 1193a5108eaeSScott Long /* 1194a5108eaeSScott Long * We only have this one client and we know that 0x400 is free in 1195a5108eaeSScott Long * our kernel's mem map, so lets just drop it there. It seems that 1196a5108eaeSScott Long * the minisrc doesn't need vectors, so we won't bother with them.. 1197a5108eaeSScott Long */ 1198a5108eaeSScott Long size = sizeof(assp_minisrc_image); 1199a5108eaeSScott Long for(i = 0 ; i < size / 2; i++) { 1200a5108eaeSScott Long m3_wr_assp_code(sc, 0x400 + i, assp_minisrc_image[i]); 1201a5108eaeSScott Long } 1202a5108eaeSScott Long /* write the coefficients for the low pass filter? */ 1203a5108eaeSScott Long size = sizeof(minisrc_lpf_image); 1204a5108eaeSScott Long for(i = 0; i < size / 2 ; i++) { 1205a5108eaeSScott Long m3_wr_assp_code(sc,0x400 + MINISRC_COEF_LOC + i, 1206a5108eaeSScott Long minisrc_lpf_image[i]); 1207a5108eaeSScott Long } 1208a5108eaeSScott Long m3_wr_assp_code(sc, 0x400 + MINISRC_COEF_LOC + size, 0x8000); 1209a5108eaeSScott Long /* the minisrc is the only thing on our task list */ 1210a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_TASK0, 0x400); 1211a5108eaeSScott Long /* init the mixer number */ 1212a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_MIXER_TASK_NUMBER, 0); 1213a5108eaeSScott Long /* extreme kernel master volume */ 1214a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_DAC_LEFT_VOLUME, ARB_VOLUME); 1215a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_DAC_RIGHT_VOLUME, ARB_VOLUME); 1216a5108eaeSScott Long 1217a5108eaeSScott Long m3_amp_enable(sc); 1218a5108eaeSScott Long 1219a5108eaeSScott Long /* [m3_assp_client_init] (only one client at index 0) */ 1220a5108eaeSScott Long for (i=0x1100 ; i<0x1c00 ; i++) { 1221a5108eaeSScott Long m3_wr_assp_data(sc, i, 0); /* zero entire dac/adc area */ 1222a5108eaeSScott Long } 1223a5108eaeSScott Long 1224a5108eaeSScott Long /* [m3_assp_continue] */ 1225a5108eaeSScott Long m3_wr_1(sc, DSP_PORT_CONTROL_REG_B, reset_state | REGB_ENABLE_RESET); 1226a5108eaeSScott Long 1227a5108eaeSScott Long return 0; 1228a5108eaeSScott Long } 1229a5108eaeSScott Long 1230a5108eaeSScott Long static int 1231a5108eaeSScott Long m3_uninit(struct sc_info *sc) 1232a5108eaeSScott Long { 1233a5108eaeSScott Long M3_DEBUG(CHANGE, ("m3_uninit\n")); 1234a5108eaeSScott Long return 0; 1235a5108eaeSScott Long } 1236a5108eaeSScott Long 1237a5108eaeSScott Long /* -------------------------------------------------------------------- */ 1238a5108eaeSScott Long /* Probe and attach the card */ 1239a5108eaeSScott Long 1240a5108eaeSScott Long static int 1241a5108eaeSScott Long m3_pci_probe(device_t dev) 1242a5108eaeSScott Long { 1243a5108eaeSScott Long struct m3_card_type *card; 1244a5108eaeSScott Long 1245a5108eaeSScott Long M3_DEBUG(CALL, ("m3_pci_probe(0x%x)\n", pci_get_devid(dev))); 1246a5108eaeSScott Long 1247a5108eaeSScott Long for (card = m3_card_types ; card->pci_id ; card++) { 1248a5108eaeSScott Long if (pci_get_devid(dev) == card->pci_id) { 1249a5108eaeSScott Long device_set_desc(dev, card->name); 1250d2b677bbSWarner Losh return BUS_PROBE_DEFAULT; 1251a5108eaeSScott Long } 1252a5108eaeSScott Long } 1253a5108eaeSScott Long return ENXIO; 1254a5108eaeSScott Long } 1255a5108eaeSScott Long 1256a5108eaeSScott Long static int 1257a5108eaeSScott Long m3_pci_attach(device_t dev) 1258a5108eaeSScott Long { 1259a5108eaeSScott Long struct sc_info *sc; 1260a5108eaeSScott Long struct ac97_info *codec = NULL; 1261018b991eSAriff Abdullah u_int32_t data; 1262a5108eaeSScott Long char status[SND_STATUSLEN]; 1263a5108eaeSScott Long struct m3_card_type *card; 1264018b991eSAriff Abdullah int i, len, dacn, adcn; 1265a5108eaeSScott Long 1266a5108eaeSScott Long M3_DEBUG(CALL, ("m3_pci_attach\n")); 1267a5108eaeSScott Long 1268082f6383SAriff Abdullah sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); 1269a5108eaeSScott Long sc->dev = dev; 1270a5108eaeSScott Long sc->type = pci_get_devid(dev); 1271c21880a7SPyun YongHyeon sc->sc_lock = snd_mtxcreate(device_get_nameunit(dev), 12724582b3a1SAriff Abdullah "snd_maestro3 softc"); 1273a5108eaeSScott Long for (card = m3_card_types ; card->pci_id ; card++) { 1274a5108eaeSScott Long if (sc->type == card->pci_id) { 1275a5108eaeSScott Long sc->which = card->which; 1276a5108eaeSScott Long sc->delay1 = card->delay1; 1277a5108eaeSScott Long sc->delay2 = card->delay2; 1278a5108eaeSScott Long break; 1279a5108eaeSScott Long } 1280a5108eaeSScott Long } 1281a5108eaeSScott Long 1282018b991eSAriff Abdullah if (resource_int_value(device_get_name(dev), device_get_unit(dev), 1283018b991eSAriff Abdullah "dac", &i) == 0) { 1284018b991eSAriff Abdullah if (i < 1) 1285018b991eSAriff Abdullah dacn = 1; 1286018b991eSAriff Abdullah else if (i > M3_PCHANS) 1287018b991eSAriff Abdullah dacn = M3_PCHANS; 1288018b991eSAriff Abdullah else 1289018b991eSAriff Abdullah dacn = i; 1290018b991eSAriff Abdullah } else 1291018b991eSAriff Abdullah dacn = M3_PCHANS; 1292018b991eSAriff Abdullah 1293018b991eSAriff Abdullah adcn = M3_RCHANS; 1294018b991eSAriff Abdullah 1295a5108eaeSScott Long data = pci_read_config(dev, PCIR_COMMAND, 2); 1296a5108eaeSScott Long data |= (PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN); 1297a5108eaeSScott Long pci_write_config(dev, PCIR_COMMAND, data, 2); 1298a5108eaeSScott Long 1299e27951b2SJohn Baldwin sc->regid = PCIR_BAR(0); 1300a5108eaeSScott Long sc->regtype = SYS_RES_MEMORY; 13015f96beb9SNate Lawson sc->reg = bus_alloc_resource_any(dev, sc->regtype, &sc->regid, 13025f96beb9SNate Lawson RF_ACTIVE); 1303a5108eaeSScott Long if (!sc->reg) { 1304a5108eaeSScott Long sc->regtype = SYS_RES_IOPORT; 13055f96beb9SNate Lawson sc->reg = bus_alloc_resource_any(dev, sc->regtype, &sc->regid, 13065f96beb9SNate Lawson RF_ACTIVE); 1307a5108eaeSScott Long } 1308a5108eaeSScott Long if (!sc->reg) { 1309a5108eaeSScott Long device_printf(dev, "unable to allocate register space\n"); 1310a5108eaeSScott Long goto bad; 1311a5108eaeSScott Long } 1312a5108eaeSScott Long sc->st = rman_get_bustag(sc->reg); 1313a5108eaeSScott Long sc->sh = rman_get_bushandle(sc->reg); 1314a5108eaeSScott Long 1315a5108eaeSScott Long sc->irqid = 0; 13165f96beb9SNate Lawson sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid, 13175f96beb9SNate Lawson RF_ACTIVE | RF_SHAREABLE); 1318a5108eaeSScott Long if (!sc->irq) { 1319a5108eaeSScott Long device_printf(dev, "unable to allocate interrupt\n"); 1320a5108eaeSScott Long goto bad; 1321a5108eaeSScott Long } 1322a5108eaeSScott Long 1323c21880a7SPyun YongHyeon if (snd_setup_intr(dev, sc->irq, INTR_MPSAFE, m3_intr, sc, &sc->ih)) { 1324a5108eaeSScott Long device_printf(dev, "unable to setup interrupt\n"); 1325a5108eaeSScott Long goto bad; 1326a5108eaeSScott Long } 1327a5108eaeSScott Long 1328018b991eSAriff Abdullah sc->bufsz = pcm_getbuffersize(dev, M3_BUFSIZE_MIN, M3_BUFSIZE_DEFAULT, 1329c21880a7SPyun YongHyeon M3_BUFSIZE_MAX); 1330baadfb4cSScott Long 1331c21880a7SPyun YongHyeon if (bus_dma_tag_create( 13320b989078SAlexander Leidinger bus_get_dma_tag(dev), /* parent */ 1333c21880a7SPyun YongHyeon 2, 0, /* alignment, boundary */ 1334c21880a7SPyun YongHyeon M3_MAXADDR, /* lowaddr */ 1335c21880a7SPyun YongHyeon BUS_SPACE_MAXADDR, /* highaddr */ 1336c21880a7SPyun YongHyeon NULL, NULL, /* filtfunc, filtfuncarg */ 1337c21880a7SPyun YongHyeon sc->bufsz, /* maxsize */ 1338c21880a7SPyun YongHyeon 1, /* nsegments */ 1339c21880a7SPyun YongHyeon 0x3ffff, /* maxsegz */ 1340c21880a7SPyun YongHyeon 0, /* flags */ 1341c21880a7SPyun YongHyeon NULL, /* lockfunc */ 1342c21880a7SPyun YongHyeon NULL, /* lockfuncarg */ 1343c21880a7SPyun YongHyeon &sc->parent_dmat) != 0) { 1344a5108eaeSScott Long device_printf(dev, "unable to create dma tag\n"); 1345a5108eaeSScott Long goto bad; 1346a5108eaeSScott Long } 1347a5108eaeSScott Long 1348c21880a7SPyun YongHyeon M3_LOCK(sc); 1349a5108eaeSScott Long m3_power(sc, 0); /* power up */ 1350a5108eaeSScott Long /* init chip */ 1351c21880a7SPyun YongHyeon i = m3_init(sc); 1352c21880a7SPyun YongHyeon M3_UNLOCK(sc); 1353c21880a7SPyun YongHyeon if (i == -1) { 1354a5108eaeSScott Long device_printf(dev, "unable to initialize the card\n"); 1355a5108eaeSScott Long goto bad; 1356a5108eaeSScott Long } 1357a5108eaeSScott Long 1358a5108eaeSScott Long /* create/init mixer */ 1359a5108eaeSScott Long codec = AC97_CREATE(dev, sc, m3_codec); 1360a5108eaeSScott Long if (codec == NULL) { 1361a5108eaeSScott Long device_printf(dev, "ac97_create error\n"); 1362a5108eaeSScott Long goto bad; 1363a5108eaeSScott Long } 1364a5108eaeSScott Long if (mixer_init(dev, ac97_getmixerclass(), codec)) { 1365a5108eaeSScott Long device_printf(dev, "mixer_init error\n"); 1366a5108eaeSScott Long goto bad; 1367a5108eaeSScott Long } 1368a5108eaeSScott Long 13699ce4f543SRobert Drehmel m3_enable_ints(sc); 13709ce4f543SRobert Drehmel 1371018b991eSAriff Abdullah if (pcm_register(dev, sc, dacn, adcn)) { 1372a5108eaeSScott Long device_printf(dev, "pcm_register error\n"); 1373a5108eaeSScott Long goto bad; 1374a5108eaeSScott Long } 1375018b991eSAriff Abdullah for (i=0 ; i<dacn ; i++) { 1376a5108eaeSScott Long if (pcm_addchan(dev, PCMDIR_PLAY, &m3_pch_class, sc)) { 1377a5108eaeSScott Long device_printf(dev, "pcm_addchan (play) error\n"); 1378a5108eaeSScott Long goto bad; 1379a5108eaeSScott Long } 1380a5108eaeSScott Long } 1381018b991eSAriff Abdullah for (i=0 ; i<adcn ; i++) { 1382a5108eaeSScott Long if (pcm_addchan(dev, PCMDIR_REC, &m3_rch_class, sc)) { 1383a5108eaeSScott Long device_printf(dev, "pcm_addchan (rec) error\n"); 1384a5108eaeSScott Long goto bad; 1385a5108eaeSScott Long } 1386a5108eaeSScott Long } 13870d8ed52eSMathew Kanner snprintf(status, SND_STATUSLEN, "at %s 0x%lx irq %ld %s", 1388a5108eaeSScott Long (sc->regtype == SYS_RES_IOPORT)? "io" : "memory", 1389c21880a7SPyun YongHyeon rman_get_start(sc->reg), rman_get_start(sc->irq), 1390c21880a7SPyun YongHyeon PCM_KLDSTRING(snd_maestro3)); 1391a5108eaeSScott Long if (pcm_setstatus(dev, status)) { 1392a5108eaeSScott Long device_printf(dev, "attach: pcm_setstatus error\n"); 1393a5108eaeSScott Long goto bad; 1394a5108eaeSScott Long } 139573b9d66dSScott Long 139666ef8af5SCameron Grant mixer_hwvol_init(dev); 1397a5108eaeSScott Long 1398a5108eaeSScott Long /* Create the buffer for saving the card state during suspend */ 1399a5108eaeSScott Long len = sizeof(u_int16_t) * (REV_B_CODE_MEMORY_LENGTH + 1400a5108eaeSScott Long REV_B_DATA_MEMORY_LENGTH); 1401082f6383SAriff Abdullah sc->savemem = (u_int16_t*)malloc(len, M_DEVBUF, M_WAITOK | M_ZERO); 1402a5108eaeSScott Long 1403a5108eaeSScott Long return 0; 1404a5108eaeSScott Long 1405a5108eaeSScott Long bad: 1406c21880a7SPyun YongHyeon if (codec) 1407a5108eaeSScott Long ac97_destroy(codec); 1408c21880a7SPyun YongHyeon if (sc->ih) 1409a5108eaeSScott Long bus_teardown_intr(dev, sc->irq, sc->ih); 1410c21880a7SPyun YongHyeon if (sc->irq) 1411a5108eaeSScott Long bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 1412c21880a7SPyun YongHyeon if (sc->reg) 1413c21880a7SPyun YongHyeon bus_release_resource(dev, sc->regtype, sc->regid, sc->reg); 1414c21880a7SPyun YongHyeon if (sc->parent_dmat) 1415a5108eaeSScott Long bus_dma_tag_destroy(sc->parent_dmat); 1416c21880a7SPyun YongHyeon if (sc->sc_lock) 1417c21880a7SPyun YongHyeon snd_mtxfree(sc->sc_lock); 1418a5108eaeSScott Long free(sc, M_DEVBUF); 1419a5108eaeSScott Long return ENXIO; 1420a5108eaeSScott Long } 1421a5108eaeSScott Long 1422a5108eaeSScott Long static int 1423a5108eaeSScott Long m3_pci_detach(device_t dev) 1424a5108eaeSScott Long { 1425a5108eaeSScott Long struct sc_info *sc = pcm_getdevinfo(dev); 1426a5108eaeSScott Long int r; 1427a5108eaeSScott Long 1428a5108eaeSScott Long M3_DEBUG(CALL, ("m3_pci_detach\n")); 1429a5108eaeSScott Long 1430a5108eaeSScott Long if ((r = pcm_unregister(dev)) != 0) { 1431a5108eaeSScott Long return r; 1432a5108eaeSScott Long } 1433c21880a7SPyun YongHyeon 1434c21880a7SPyun YongHyeon M3_LOCK(sc); 1435a5108eaeSScott Long m3_uninit(sc); /* shutdown chip */ 1436a5108eaeSScott Long m3_power(sc, 3); /* power off */ 1437c21880a7SPyun YongHyeon M3_UNLOCK(sc); 1438a5108eaeSScott Long 1439a5108eaeSScott Long bus_teardown_intr(dev, sc->irq, sc->ih); 1440a5108eaeSScott Long bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 1441c21880a7SPyun YongHyeon bus_release_resource(dev, sc->regtype, sc->regid, sc->reg); 1442a5108eaeSScott Long bus_dma_tag_destroy(sc->parent_dmat); 1443a5108eaeSScott Long 1444a5108eaeSScott Long free(sc->savemem, M_DEVBUF); 1445c21880a7SPyun YongHyeon snd_mtxfree(sc->sc_lock); 1446a5108eaeSScott Long free(sc, M_DEVBUF); 1447a5108eaeSScott Long return 0; 1448a5108eaeSScott Long } 1449a5108eaeSScott Long 1450a5108eaeSScott Long static int 1451a5108eaeSScott Long m3_pci_suspend(device_t dev) 1452a5108eaeSScott Long { 1453a5108eaeSScott Long struct sc_info *sc = pcm_getdevinfo(dev); 1454a5108eaeSScott Long int i, index = 0; 1455a5108eaeSScott Long 1456a5108eaeSScott Long M3_DEBUG(CHANGE, ("m3_pci_suspend\n")); 1457a5108eaeSScott Long 1458c21880a7SPyun YongHyeon M3_LOCK(sc); 1459a5108eaeSScott Long for (i=0 ; i<sc->pch_cnt ; i++) { 1460a5108eaeSScott Long if (sc->pch[i].active) { 1461c21880a7SPyun YongHyeon m3_pchan_trigger_locked(NULL, &sc->pch[i], 1462c21880a7SPyun YongHyeon PCMTRIG_STOP); 1463a5108eaeSScott Long } 1464a5108eaeSScott Long } 1465a5108eaeSScott Long for (i=0 ; i<sc->rch_cnt ; i++) { 1466a5108eaeSScott Long if (sc->rch[i].active) { 1467c21880a7SPyun YongHyeon m3_rchan_trigger_locked(NULL, &sc->rch[i], 1468c21880a7SPyun YongHyeon PCMTRIG_STOP); 1469a5108eaeSScott Long } 1470a5108eaeSScott Long } 1471a5108eaeSScott Long DELAY(10 * 1000); /* give things a chance to stop */ 1472a5108eaeSScott Long 1473a5108eaeSScott Long /* Disable interrupts */ 1474a5108eaeSScott Long m3_wr_2(sc, HOST_INT_CTRL, 0); 1475a5108eaeSScott Long m3_wr_1(sc, ASSP_CONTROL_C, 0); 1476a5108eaeSScott Long 1477a5108eaeSScott Long m3_assp_halt(sc); 1478a5108eaeSScott Long 1479a5108eaeSScott Long /* Save the state of the ASSP */ 1480a5108eaeSScott Long for (i = REV_B_CODE_MEMORY_BEGIN; i <= REV_B_CODE_MEMORY_END; i++) 1481c02a39a1SScott Long sc->savemem[index++] = m3_rd_assp_code(sc, i); 1482a5108eaeSScott Long for (i = REV_B_DATA_MEMORY_BEGIN; i <= REV_B_DATA_MEMORY_END; i++) 1483c02a39a1SScott Long sc->savemem[index++] = m3_rd_assp_data(sc, i); 1484a5108eaeSScott Long 1485a5108eaeSScott Long /* Power down the card to D3 state */ 1486a5108eaeSScott Long m3_power(sc, 3); 1487c21880a7SPyun YongHyeon M3_UNLOCK(sc); 1488a5108eaeSScott Long 1489a5108eaeSScott Long return 0; 1490a5108eaeSScott Long } 1491a5108eaeSScott Long 1492a5108eaeSScott Long static int 1493a5108eaeSScott Long m3_pci_resume(device_t dev) 1494a5108eaeSScott Long { 1495a5108eaeSScott Long struct sc_info *sc = pcm_getdevinfo(dev); 1496a5108eaeSScott Long int i, index = 0; 1497a5108eaeSScott Long u_int8_t reset_state; 1498a5108eaeSScott Long 1499a5108eaeSScott Long M3_DEBUG(CHANGE, ("m3_pci_resume\n")); 1500a5108eaeSScott Long 1501c21880a7SPyun YongHyeon M3_LOCK(sc); 1502a5108eaeSScott Long /* Power the card back to D0 */ 1503a5108eaeSScott Long m3_power(sc, 0); 1504a5108eaeSScott Long 1505a5108eaeSScott Long m3_config(sc); 1506a5108eaeSScott Long 1507a5108eaeSScott Long reset_state = m3_assp_halt(sc); 1508a5108eaeSScott Long 15093068bdbaSGuido van Rooij m3_codec_reset(sc); 15103068bdbaSGuido van Rooij 1511a5108eaeSScott Long /* Restore the ASSP state */ 1512a5108eaeSScott Long for (i = REV_B_CODE_MEMORY_BEGIN; i <= REV_B_CODE_MEMORY_END; i++) 15135ffa65f9SScott Long m3_wr_assp_code(sc, i, sc->savemem[index++]); 1514a5108eaeSScott Long for (i = REV_B_DATA_MEMORY_BEGIN; i <= REV_B_DATA_MEMORY_END; i++) 15155ffa65f9SScott Long m3_wr_assp_data(sc, i, sc->savemem[index++]); 1516a5108eaeSScott Long 1517a5108eaeSScott Long /* Restart the DMA engine */ 1518a5108eaeSScott Long m3_wr_assp_data(sc, KDATA_DMA_ACTIVE, 0); 1519a5108eaeSScott Long 1520a5108eaeSScott Long /* [m3_assp_continue] */ 1521a5108eaeSScott Long m3_wr_1(sc, DSP_PORT_CONTROL_REG_B, reset_state | REGB_ENABLE_RESET); 1522a5108eaeSScott Long 1523a5108eaeSScott Long m3_amp_enable(sc); 1524a5108eaeSScott Long 15250a17f47bSRobert Drehmel m3_enable_ints(sc); 15260a17f47bSRobert Drehmel 1527c21880a7SPyun YongHyeon M3_UNLOCK(sc); /* XXX */ 15283068bdbaSGuido van Rooij if (mixer_reinit(dev) == -1) { 15293068bdbaSGuido van Rooij device_printf(dev, "unable to reinitialize the mixer\n"); 1530c21880a7SPyun YongHyeon return (ENXIO); 15313068bdbaSGuido van Rooij } 1532c21880a7SPyun YongHyeon M3_LOCK(sc); 15333068bdbaSGuido van Rooij 1534a5108eaeSScott Long /* Turn the channels back on */ 1535a5108eaeSScott Long for (i=0 ; i<sc->pch_cnt ; i++) { 1536a5108eaeSScott Long if (sc->pch[i].active) { 1537c21880a7SPyun YongHyeon m3_pchan_trigger_locked(NULL, &sc->pch[i], 1538c21880a7SPyun YongHyeon PCMTRIG_START); 1539a5108eaeSScott Long } 1540a5108eaeSScott Long } 1541a5108eaeSScott Long for (i=0 ; i<sc->rch_cnt ; i++) { 1542a5108eaeSScott Long if (sc->rch[i].active) { 1543c21880a7SPyun YongHyeon m3_rchan_trigger_locked(NULL, &sc->rch[i], 1544c21880a7SPyun YongHyeon PCMTRIG_START); 1545a5108eaeSScott Long } 1546a5108eaeSScott Long } 1547a5108eaeSScott Long 1548c21880a7SPyun YongHyeon M3_UNLOCK(sc); 1549a5108eaeSScott Long return 0; 1550a5108eaeSScott Long } 1551a5108eaeSScott Long 1552a5108eaeSScott Long static int 1553a5108eaeSScott Long m3_pci_shutdown(device_t dev) 1554a5108eaeSScott Long { 1555a5108eaeSScott Long struct sc_info *sc = pcm_getdevinfo(dev); 1556a5108eaeSScott Long 1557a5108eaeSScott Long M3_DEBUG(CALL, ("m3_pci_shutdown\n")); 1558a5108eaeSScott Long 1559c21880a7SPyun YongHyeon M3_LOCK(sc); 1560a5108eaeSScott Long m3_power(sc, 3); /* power off */ 1561c21880a7SPyun YongHyeon M3_UNLOCK(sc); 1562c21880a7SPyun YongHyeon 1563a5108eaeSScott Long return 0; 1564a5108eaeSScott Long } 1565a5108eaeSScott Long 1566a5108eaeSScott Long static u_int8_t 1567a5108eaeSScott Long m3_assp_halt(struct sc_info *sc) 1568a5108eaeSScott Long { 1569a5108eaeSScott Long u_int8_t data, reset_state; 1570a5108eaeSScott Long 1571c21880a7SPyun YongHyeon M3_LOCK_ASSERT(sc); 1572c21880a7SPyun YongHyeon 1573a5108eaeSScott Long data = m3_rd_1(sc, DSP_PORT_CONTROL_REG_B); 1574a5108eaeSScott Long reset_state = data & ~REGB_STOP_CLOCK; /* remember for continue */ 1575a5108eaeSScott Long DELAY(10 * 1000); 1576a5108eaeSScott Long m3_wr_1(sc, DSP_PORT_CONTROL_REG_B, reset_state & ~REGB_ENABLE_RESET); 1577a5108eaeSScott Long DELAY(10 * 1000); /* necessary? */ 1578a5108eaeSScott Long 1579a5108eaeSScott Long return reset_state; 1580a5108eaeSScott Long } 1581a5108eaeSScott Long 1582a5108eaeSScott Long static void 1583a5108eaeSScott Long m3_config(struct sc_info *sc) 1584a5108eaeSScott Long { 158573b9d66dSScott Long u_int32_t data, hv_cfg; 158673b9d66dSScott Long int hint; 158773b9d66dSScott Long 1588c21880a7SPyun YongHyeon M3_LOCK_ASSERT(sc); 15897535accfSPyun YongHyeon 15907535accfSPyun YongHyeon M3_UNLOCK(sc); 159173b9d66dSScott Long /* 159273b9d66dSScott Long * The volume buttons can be wired up via two different sets of pins. 159373b9d66dSScott Long * This presents a problem since we can't tell which way it's 159473b9d66dSScott Long * configured. Allow the user to set a hint in order to twiddle 159573b9d66dSScott Long * the proper bits. 159673b9d66dSScott Long */ 159773b9d66dSScott Long if (resource_int_value(device_get_name(sc->dev), 159873b9d66dSScott Long device_get_unit(sc->dev), 159973b9d66dSScott Long "hwvol_config", &hint) == 0) 160073b9d66dSScott Long hv_cfg = (hint > 0) ? HV_BUTTON_FROM_GD : 0; 160173b9d66dSScott Long else 160273b9d66dSScott Long hv_cfg = HV_BUTTON_FROM_GD; 16037535accfSPyun YongHyeon M3_LOCK(sc); 1604a5108eaeSScott Long 1605a5108eaeSScott Long data = pci_read_config(sc->dev, PCI_ALLEGRO_CONFIG, 4); 160663393eeaSScott Long data &= ~HV_BUTTON_FROM_GD; 160773b9d66dSScott Long data |= REDUCED_DEBOUNCE | HV_CTRL_ENABLE | hv_cfg; 1608a5108eaeSScott Long data |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING; 1609a5108eaeSScott Long pci_write_config(sc->dev, PCI_ALLEGRO_CONFIG, data, 4); 1610a5108eaeSScott Long 1611a5108eaeSScott Long m3_wr_1(sc, ASSP_CONTROL_B, RESET_ASSP); 1612a5108eaeSScott Long data = pci_read_config(sc->dev, PCI_ALLEGRO_CONFIG, 4); 1613a5108eaeSScott Long data &= ~INT_CLK_SELECT; 1614a5108eaeSScott Long if (sc->which == ESS_MAESTRO3) { 1615a5108eaeSScott Long data &= ~INT_CLK_MULT_ENABLE; 1616a5108eaeSScott Long data |= INT_CLK_SRC_NOT_PCI; 1617a5108eaeSScott Long } 1618a5108eaeSScott Long data &= ~(CLK_MULT_MODE_SELECT | CLK_MULT_MODE_SELECT_2); 1619a5108eaeSScott Long pci_write_config(sc->dev, PCI_ALLEGRO_CONFIG, data, 4); 1620a5108eaeSScott Long 1621a5108eaeSScott Long if (sc->which == ESS_ALLEGRO_1) { 1622a5108eaeSScott Long data = pci_read_config(sc->dev, PCI_USER_CONFIG, 4); 1623a5108eaeSScott Long data |= IN_CLK_12MHZ_SELECT; 1624a5108eaeSScott Long pci_write_config(sc->dev, PCI_USER_CONFIG, data, 4); 1625a5108eaeSScott Long } 1626a5108eaeSScott Long 1627a5108eaeSScott Long data = m3_rd_1(sc, ASSP_CONTROL_A); 1628a5108eaeSScott Long data &= ~(DSP_CLK_36MHZ_SELECT | ASSP_CLK_49MHZ_SELECT); 1629a5108eaeSScott Long data |= ASSP_CLK_49MHZ_SELECT; /*XXX assumes 49MHZ dsp XXX*/ 1630a5108eaeSScott Long data |= ASSP_0_WS_ENABLE; 1631a5108eaeSScott Long m3_wr_1(sc, ASSP_CONTROL_A, data); 1632a5108eaeSScott Long 1633a5108eaeSScott Long m3_wr_1(sc, ASSP_CONTROL_B, RUN_ASSP); 1634a5108eaeSScott Long } 1635a5108eaeSScott Long 1636a5108eaeSScott Long static void 1637a5108eaeSScott Long m3_enable_ints(struct sc_info *sc) 1638a5108eaeSScott Long { 1639a5108eaeSScott Long u_int8_t data; 1640a5108eaeSScott Long 1641a5108eaeSScott Long m3_wr_2(sc, HOST_INT_CTRL, ASSP_INT_ENABLE | HV_INT_ENABLE); 1642a5108eaeSScott Long data = m3_rd_1(sc, ASSP_CONTROL_C); 1643a5108eaeSScott Long m3_wr_1(sc, ASSP_CONTROL_C, data | ASSP_HOST_INT_ENABLE); 1644a5108eaeSScott Long } 1645a5108eaeSScott Long 1646a5108eaeSScott Long static void 1647a5108eaeSScott Long m3_amp_enable(struct sc_info *sc) 1648a5108eaeSScott Long { 1649a5108eaeSScott Long u_int32_t gpo, polarity_port, polarity; 1650a5108eaeSScott Long u_int16_t data; 1651a5108eaeSScott Long 1652c21880a7SPyun YongHyeon M3_LOCK_ASSERT(sc); 1653c21880a7SPyun YongHyeon 1654a5108eaeSScott Long switch (sc->which) { 1655a5108eaeSScott Long case ESS_ALLEGRO_1: 1656a5108eaeSScott Long polarity_port = 0x1800; 1657a5108eaeSScott Long break; 1658a5108eaeSScott Long case ESS_MAESTRO3: 1659a5108eaeSScott Long polarity_port = 0x1100; 1660a5108eaeSScott Long break; 1661a5108eaeSScott Long default: 1662a5108eaeSScott Long panic("bad sc->which"); 1663a5108eaeSScott Long } 1664a5108eaeSScott Long gpo = (polarity_port >> 8) & 0x0f; 1665a5108eaeSScott Long polarity = polarity_port >> 12; 1666a5108eaeSScott Long polarity = !polarity; /* enable */ 1667a5108eaeSScott Long polarity = polarity << gpo; 1668a5108eaeSScott Long gpo = 1 << gpo; 1669a5108eaeSScott Long m3_wr_2(sc, GPIO_MASK, ~gpo); 1670a5108eaeSScott Long data = m3_rd_2(sc, GPIO_DIRECTION); 1671a5108eaeSScott Long m3_wr_2(sc, GPIO_DIRECTION, data | gpo); 1672a5108eaeSScott Long data = GPO_SECONDARY_AC97 | GPO_PRIMARY_AC97 | polarity; 1673a5108eaeSScott Long m3_wr_2(sc, GPIO_DATA, data); 1674a5108eaeSScott Long m3_wr_2(sc, GPIO_MASK, ~0); 1675a5108eaeSScott Long } 1676a5108eaeSScott Long 1677a5108eaeSScott Long static void 1678a5108eaeSScott Long m3_codec_reset(struct sc_info *sc) 1679a5108eaeSScott Long { 1680a5108eaeSScott Long u_int16_t data, dir; 1681a5108eaeSScott Long int retry = 0; 1682a5108eaeSScott Long 1683c21880a7SPyun YongHyeon M3_LOCK_ASSERT(sc); 1684a5108eaeSScott Long do { 1685a5108eaeSScott Long data = m3_rd_2(sc, GPIO_DIRECTION); 1686a5108eaeSScott Long dir = data | 0x10; /* assuming pci bus master? */ 1687a5108eaeSScott Long 1688a5108eaeSScott Long /* [[remote_codec_config]] */ 1689a5108eaeSScott Long data = m3_rd_2(sc, RING_BUS_CTRL_B); 1690a5108eaeSScott Long m3_wr_2(sc, RING_BUS_CTRL_B, data & ~SECOND_CODEC_ID_MASK); 1691a5108eaeSScott Long data = m3_rd_2(sc, SDO_OUT_DEST_CTRL); 1692a5108eaeSScott Long m3_wr_2(sc, SDO_OUT_DEST_CTRL, data & ~COMMAND_ADDR_OUT); 1693a5108eaeSScott Long data = m3_rd_2(sc, SDO_IN_DEST_CTRL); 1694a5108eaeSScott Long m3_wr_2(sc, SDO_IN_DEST_CTRL, data & ~STATUS_ADDR_IN); 1695a5108eaeSScott Long 1696a5108eaeSScott Long m3_wr_2(sc, RING_BUS_CTRL_A, IO_SRAM_ENABLE); 1697a5108eaeSScott Long DELAY(20); 1698a5108eaeSScott Long 1699a5108eaeSScott Long m3_wr_2(sc, GPIO_DIRECTION, dir & ~GPO_PRIMARY_AC97); 1700a5108eaeSScott Long m3_wr_2(sc, GPIO_MASK, ~GPO_PRIMARY_AC97); 1701a5108eaeSScott Long m3_wr_2(sc, GPIO_DATA, 0); 1702a5108eaeSScott Long m3_wr_2(sc, GPIO_DIRECTION, dir | GPO_PRIMARY_AC97); 1703a5108eaeSScott Long DELAY(sc->delay1 * 1000); /*delay1 (ALLEGRO:50, MAESTRO3:20)*/ 1704a5108eaeSScott Long m3_wr_2(sc, GPIO_DATA, GPO_PRIMARY_AC97); 1705a5108eaeSScott Long DELAY(5); 1706a5108eaeSScott Long m3_wr_2(sc, RING_BUS_CTRL_A, IO_SRAM_ENABLE | 1707a5108eaeSScott Long SERIAL_AC_LINK_ENABLE); 1708a5108eaeSScott Long m3_wr_2(sc, GPIO_MASK, ~0); 1709a5108eaeSScott Long DELAY(sc->delay2 * 1000); /*delay2 (ALLEGRO:800, MAESTRO3:500)*/ 1710a5108eaeSScott Long 1711a5108eaeSScott Long /* [[try read vendor]] */ 1712a5108eaeSScott Long data = m3_rdcd(NULL, sc, 0x7c); 1713a5108eaeSScott Long if ((data == 0) || (data == 0xffff)) { 1714a5108eaeSScott Long retry++; 1715a5108eaeSScott Long if (retry > 3) { 1716a5108eaeSScott Long device_printf(sc->dev, "Codec reset failed\n"); 1717a5108eaeSScott Long break; 1718a5108eaeSScott Long } 1719a5108eaeSScott Long device_printf(sc->dev, "Codec reset retry\n"); 1720a5108eaeSScott Long } else retry = 0; 1721a5108eaeSScott Long } while (retry); 1722a5108eaeSScott Long } 1723a5108eaeSScott Long 1724a5108eaeSScott Long static device_method_t m3_methods[] = { 1725a5108eaeSScott Long DEVMETHOD(device_probe, m3_pci_probe), 1726a5108eaeSScott Long DEVMETHOD(device_attach, m3_pci_attach), 1727a5108eaeSScott Long DEVMETHOD(device_detach, m3_pci_detach), 1728a5108eaeSScott Long DEVMETHOD(device_suspend, m3_pci_suspend), 1729a5108eaeSScott Long DEVMETHOD(device_resume, m3_pci_resume), 1730a5108eaeSScott Long DEVMETHOD(device_shutdown, m3_pci_shutdown), 1731a5108eaeSScott Long { 0, 0 } 1732a5108eaeSScott Long }; 1733a5108eaeSScott Long 1734a5108eaeSScott Long static driver_t m3_driver = { 1735a5108eaeSScott Long "pcm", 1736a5108eaeSScott Long m3_methods, 173767b1dce3SCameron Grant PCM_SOFTC_SIZE, 1738a5108eaeSScott Long }; 1739a5108eaeSScott Long 1740a5108eaeSScott Long DRIVER_MODULE(snd_maestro3, pci, m3_driver, pcm_devclass, 0, 0); 17410739ea1dSSeigo Tanimura MODULE_DEPEND(snd_maestro3, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 1742a5108eaeSScott Long MODULE_VERSION(snd_maestro3, 1); 1743