1 /* $NetBSD: esm.c,v 1.51 2009/11/26 15:17:09 njoly Exp $ */
4 * Copyright (c) 2002, 2003 Matt Fredette
7 * Copyright (c) 2000, 2001 Rene Hexel <rh@NetBSD.org>
10 * Copyright (c) 2000 Taku YAMAMOTO <taku@cent.saitama-u.ac.jp>
11 * All rights reserved.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * Taku Id: maestro.c,v 1.12 2000/09/06 03:32:34 taku Exp
35 * FreeBSD: /c/ncvs/src/sys/dev/sound/pci/maestro.c,v 1.4 2000/12/18 01:36:35 cg Exp
40 * - hardware volume support
41 * - fix 16-bit stereo recording, add 8-bit recording
48 * This code is based on the FreeBSD driver written by Taku YAMAMOTO
51 * Original credits from the FreeBSD driver:
53 * Part of this code (especially in many magic numbers) was heavily inspired
54 * by the Linux driver originally written by
55 * Alan Cox <alan.cox@linux.org>, modified heavily by
56 * Zach Brown <zab@zabbo.net>.
58 * busdma()-ize and buffer size reduction were suggested by
59 * Cameron Grant <gandalf@vilnya.demon.co.uk>.
60 * Also he showed me the way to use busdma() suite.
62 * Internal speaker problems on NEC VersaPro's and Dell Inspiron 7500
64 * Munehiro Matsuda <haro@tk.kubota.co.jp>,
65 * who brought patches based on the Linux driver with some simplification.
68 #include <sys/cdefs.h>
69 __KERNEL_RCSID(0, "$NetBSD: esm.c,v 1.51 2009/11/26 15:17:09 njoly Exp $");
71 #include <sys/param.h>
72 #include <sys/systm.h>
73 #include <sys/kernel.h>
74 #include <sys/malloc.h>
75 #include <sys/device.h>
79 #include <sys/audioio.h>
80 #include <dev/audio_if.h>
81 #include <dev/mulaw.h>
82 #include <dev/auconv.h>
83 #include <dev/ic/ac97var.h>
84 #include <dev/ic/ac97reg.h>
86 #include <dev/pci/pcidevs.h>
87 #include <dev/pci/pcivar.h>
89 #include <dev/pci/esmreg.h>
90 #include <dev/pci/esmvar.h>
92 #define PCI_CBIO 0x10 /* Configuration Base I/O Address */
96 #define DPRINTF(l,x) do { if (esm_debug & (l)) printf x; } while(0)
97 #define DUMPREG(x) do { if (esm_debug & ESM_DEBUG_REG) \
98 esm_dump_regs(x); } while(0)
99 int esm_debug
= 0xfffc;
100 #define ESM_DEBUG_CODECIO 0x0001
101 #define ESM_DEBUG_IRQ 0x0002
102 #define ESM_DEBUG_DMA 0x0004
103 #define ESM_DEBUG_TIMER 0x0008
104 #define ESM_DEBUG_REG 0x0010
105 #define ESM_DEBUG_PARAM 0x0020
106 #define ESM_DEBUG_APU 0x0040
107 #define ESM_DEBUG_CODEC 0x0080
108 #define ESM_DEBUG_PCI 0x0100
109 #define ESM_DEBUG_RESUME 0x0200
111 #define DPRINTF(x,y) /* nothing */
112 #define DUMPREG(x) /* nothing */
116 #define RANGE(n, l, h) if ((n) < (l) || (n) >= (h)) \
117 printf (#n "=%d out of range (%d, %d) in " \
118 __FILE__ ", line %d\n", (n), (l), (h), __LINE__)
120 #define RANGE(x,y,z) /* nothing */
123 #define inline inline
125 static inline void ringbus_setdest(struct esm_softc
*, int, int);
127 static inline uint16_t wp_rdreg(struct esm_softc
*, uint16_t);
128 static inline void wp_wrreg(struct esm_softc
*, uint16_t, uint16_t);
129 static inline uint16_t wp_rdapu(struct esm_softc
*, int, uint16_t);
130 static inline void wp_wrapu(struct esm_softc
*, int, uint16_t,
132 static inline void wp_settimer(struct esm_softc
*, u_int
);
133 static inline void wp_starttimer(struct esm_softc
*);
134 static inline void wp_stoptimer(struct esm_softc
*);
136 static inline uint16_t wc_rdreg(struct esm_softc
*, uint16_t);
137 static inline void wc_wrreg(struct esm_softc
*, uint16_t, uint16_t);
138 static inline uint16_t wc_rdchctl(struct esm_softc
*, int);
139 static inline void wc_wrchctl(struct esm_softc
*, int, uint16_t);
141 static inline u_int
calc_timer_freq(struct esm_chinfo
*);
142 static void set_timer(struct esm_softc
*);
144 static void esmch_set_format(struct esm_chinfo
*,
145 const audio_params_t
*);
146 static void esmch_combine_input(struct esm_softc
*,
147 struct esm_chinfo
*);
149 static bool esm_suspend(device_t
, pmf_qual_t
);
150 static bool esm_resume(device_t
, pmf_qual_t
);
151 static void esm_childdet(device_t
, device_t
);
152 static int esm_match(device_t
, cfdata_t
, void *);
153 static void esm_attach(device_t
, device_t
, void *);
154 static int esm_detach(device_t
, int);
155 static int esm_intr(void *);
157 static void esm_freemem(struct esm_softc
*, struct esm_dma
*);
158 static int esm_allocmem(struct esm_softc
*, size_t, size_t,
162 CFATTACH_DECL2_NEW(esm
, sizeof(struct esm_softc
),
163 esm_match
, esm_attach
, esm_detach
, NULL
, NULL
, esm_childdet
);
165 const struct audio_hw_if esm_hw_if
= {
172 NULL
, /* commit_settings */
175 NULL
, /* start_output */
176 NULL
, /* start_input */
179 NULL
, /* speaker_ctl */
187 esm_round_buffersize
,
196 struct audio_device esm_device
= {
202 #define MAESTRO_NENCODINGS 8
203 static audio_encoding_t esm_encoding
[MAESTRO_NENCODINGS
] = {
204 { 0, AudioEulinear
, AUDIO_ENCODING_ULINEAR
, 8, 0 },
205 { 1, AudioEmulaw
, AUDIO_ENCODING_ULAW
, 8,
206 AUDIO_ENCODINGFLAG_EMULATED
},
207 { 2, AudioEalaw
, AUDIO_ENCODING_ALAW
, 8, AUDIO_ENCODINGFLAG_EMULATED
},
208 { 3, AudioEslinear
, AUDIO_ENCODING_SLINEAR
, 8, 0 },
209 { 4, AudioEslinear_le
, AUDIO_ENCODING_SLINEAR_LE
, 16, 0 },
210 { 5, AudioEulinear_le
, AUDIO_ENCODING_ULINEAR_LE
, 16,
211 AUDIO_ENCODINGFLAG_EMULATED
},
212 { 6, AudioEslinear_be
, AUDIO_ENCODING_SLINEAR_BE
, 16,
213 AUDIO_ENCODINGFLAG_EMULATED
},
214 { 7, AudioEulinear_be
, AUDIO_ENCODING_ULINEAR_BE
, 16,
215 AUDIO_ENCODINGFLAG_EMULATED
},
218 #define ESM_NFORMATS 4
219 static const struct audio_format esm_formats
[ESM_NFORMATS
] = {
220 {NULL
, AUMODE_PLAY
| AUMODE_RECORD
, AUDIO_ENCODING_SLINEAR_LE
, 16, 16,
221 2, AUFMT_STEREO
, 0, {4000, 48000}},
222 {NULL
, AUMODE_PLAY
| AUMODE_RECORD
, AUDIO_ENCODING_SLINEAR_LE
, 16, 16,
223 1, AUFMT_MONAURAL
, 0, {4000, 48000}},
224 {NULL
, AUMODE_PLAY
| AUMODE_RECORD
, AUDIO_ENCODING_ULINEAR_LE
, 8, 8,
225 2, AUFMT_STEREO
, 0, {4000, 48000}},
226 {NULL
, AUMODE_PLAY
| AUMODE_RECORD
, AUDIO_ENCODING_ULINEAR_LE
, 8, 8,
227 1, AUFMT_MONAURAL
, 0, {4000, 48000}},
230 static const struct esm_quirks esm_quirks
[] = {
231 /* COMPAL 38W2 OEM Notebook, e.g. Dell INSPIRON 5000e */
232 { PCI_VENDOR_COMPAL
, PCI_PRODUCT_COMPAL_38W2
, ESM_QUIRKF_SWAPPEDCH
},
234 /* COMPAQ Armada M700 Notebook */
235 { PCI_VENDOR_COMPAQ
, PCI_PRODUCT_COMPAQ_M700
, ESM_QUIRKF_SWAPPEDCH
},
237 /* NEC Versa Pro LX VA26D */
238 { PCI_VENDOR_NEC
, PCI_PRODUCT_NEC_VA26D
, ESM_QUIRKF_GPIO
},
241 { PCI_VENDOR_NEC
, PCI_PRODUCT_NEC_VERSALX
, ESM_QUIRKF_GPIO
},
243 /* Toshiba Portege */
244 { PCI_VENDOR_TOSHIBA2
, PCI_PRODUCT_TOSHIBA2_PORTEGE
, ESM_QUIRKF_SWAPPEDCH
}
248 esm_get_quirks(pcireg_t subid
)
252 for (i
= 0; i
< __arraycount(esm_quirks
); i
++) {
253 if (PCI_VENDOR(subid
) == esm_quirks
[i
].eq_vendor
&&
254 PCI_PRODUCT(subid
) == esm_quirks
[i
].eq_product
) {
255 return esm_quirks
[i
].eq_quirks
;
264 struct esm_reg_info
{
265 int offset
; /* register offset */
266 int width
; /* 1/2/4 bytes */
268 { PORT_WAVCACHE_CTRL
, 2 },
269 { PORT_HOSTINT_CTRL
, 2 },
270 { PORT_HOSTINT_STAT
, 2 },
271 { PORT_HWVOL_VOICE_SHADOW
, 1 },
272 { PORT_HWVOL_VOICE
, 1 },
273 { PORT_HWVOL_MASTER_SHADOW
, 1 },
274 { PORT_HWVOL_MASTER
, 1 },
275 { PORT_RINGBUS_CTRL
, 4 },
276 { PORT_GPIO_DATA
, 2 },
277 { PORT_GPIO_MASK
, 2 },
278 { PORT_GPIO_DIR
, 2 },
279 { PORT_ASSP_CTRL_A
, 1 },
280 { PORT_ASSP_CTRL_B
, 1 },
281 { PORT_ASSP_CTRL_C
, 1 },
282 { PORT_ASSP_INT_STAT
, 1 }
286 esm_dump_regs(struct esm_softc
*ess
)
290 printf("%s registers:", device_xname(ess
->sc_dev
));
291 for (i
= 0; i
< __arraycount(dump_regs
); i
++) {
294 printf("0x%2.2x: ", dump_regs
[i
].offset
);
295 switch(dump_regs
[i
].width
) {
297 printf("%8.8x, ", bus_space_read_4(ess
->st
, ess
->sh
,
298 dump_regs
[i
].offset
));
301 printf("%4.4x, ", bus_space_read_2(ess
->st
, ess
->sh
,
302 dump_regs
[i
].offset
));
306 bus_space_read_1(ess
->st
, ess
->sh
,
307 dump_regs
[i
].offset
));
315 /* -----------------------------
321 /* -------------------------------------------------------------------- */
324 esm_read_codec(void *sc
, uint8_t regno
, uint16_t *result
)
326 struct esm_softc
*ess
;
330 /* We have to wait for a SAFE time to write addr/data */
331 for (t
= 0; t
< 20; t
++) {
332 if ((bus_space_read_1(ess
->st
, ess
->sh
, PORT_CODEC_STAT
)
333 & CODEC_STAT_MASK
) != CODEC_STAT_PROGLESS
)
335 delay(2); /* 20.8us / 13 */
338 printf("%s: esm_read_codec() PROGLESS timed out.\n",
339 device_xname(ess
->sc_dev
));
341 bus_space_write_1(ess
->st
, ess
->sh
, PORT_CODEC_CMD
,
342 CODEC_CMD_READ
| regno
);
343 delay(21); /* AC97 cycle = 20.8usec */
345 /* Wait for data retrieve */
346 for (t
= 0; t
< 20; t
++) {
347 if ((bus_space_read_1(ess
->st
, ess
->sh
, PORT_CODEC_STAT
)
348 & CODEC_STAT_MASK
) == CODEC_STAT_RW_DONE
)
350 delay(2); /* 20.8us / 13 */
353 /* Timed out, but perform dummy read. */
354 printf("%s: esm_read_codec() RW_DONE timed out.\n",
355 device_xname(ess
->sc_dev
));
357 *result
= bus_space_read_2(ess
->st
, ess
->sh
, PORT_CODEC_REG
);
363 esm_write_codec(void *sc
, uint8_t regno
, uint16_t data
)
365 struct esm_softc
*ess
;
369 /* We have to wait for a SAFE time to write addr/data */
370 for (t
= 0; t
< 20; t
++) {
371 if ((bus_space_read_1(ess
->st
, ess
->sh
, PORT_CODEC_STAT
)
372 & CODEC_STAT_MASK
) != CODEC_STAT_PROGLESS
)
374 delay(2); /* 20.8us / 13 */
377 /* Timed out. Abort writing. */
378 printf("%s: esm_write_codec() PROGLESS timed out.\n",
379 device_xname(ess
->sc_dev
));
383 bus_space_write_2(ess
->st
, ess
->sh
, PORT_CODEC_REG
, data
);
384 bus_space_write_1(ess
->st
, ess
->sh
, PORT_CODEC_CMD
,
385 CODEC_CMD_WRITE
| regno
);
390 /* -------------------------------------------------------------------- */
393 ringbus_setdest(struct esm_softc
*ess
, int src
, int dest
)
397 data
= bus_space_read_4(ess
->st
, ess
->sh
, PORT_RINGBUS_CTRL
);
398 data
&= ~(0xfU
<< src
);
399 data
|= (0xfU
& dest
) << src
;
400 bus_space_write_4(ess
->st
, ess
->sh
, PORT_RINGBUS_CTRL
, data
);
405 static inline uint16_t
406 wp_rdreg(struct esm_softc
*ess
, uint16_t reg
)
409 bus_space_write_2(ess
->st
, ess
->sh
, PORT_DSP_INDEX
, reg
);
410 return bus_space_read_2(ess
->st
, ess
->sh
, PORT_DSP_DATA
);
414 wp_wrreg(struct esm_softc
*ess
, uint16_t reg
, uint16_t data
)
417 bus_space_write_2(ess
->st
, ess
->sh
, PORT_DSP_INDEX
, reg
);
418 bus_space_write_2(ess
->st
, ess
->sh
, PORT_DSP_DATA
, data
);
422 apu_setindex(struct esm_softc
*ess
, uint16_t reg
)
426 wp_wrreg(ess
, WPREG_CRAM_PTR
, reg
);
427 /* Sometimes WP fails to set apu register index. */
428 for (t
= 0; t
< 1000; t
++) {
429 if (bus_space_read_2(ess
->st
, ess
->sh
, PORT_DSP_DATA
) == reg
)
431 bus_space_write_2(ess
->st
, ess
->sh
, PORT_DSP_DATA
, reg
);
434 printf("%s: apu_setindex() timed out.\n", device_xname(ess
->sc_dev
));
437 static inline uint16_t
438 wp_rdapu(struct esm_softc
*ess
, int ch
, uint16_t reg
)
442 apu_setindex(ess
, ((unsigned)ch
<< 4) + reg
);
443 ret
= wp_rdreg(ess
, WPREG_DATA_PORT
);
448 wp_wrapu(struct esm_softc
*ess
, int ch
, uint16_t reg
, uint16_t data
)
452 DPRINTF(ESM_DEBUG_APU
,
453 ("wp_wrapu(%p, ch=%d, reg=0x%x, data=0x%04x)\n",
454 ess
, ch
, reg
, data
));
456 apu_setindex(ess
, ((unsigned)ch
<< 4) + reg
);
457 wp_wrreg(ess
, WPREG_DATA_PORT
, data
);
458 for (t
= 0; t
< 1000; t
++) {
459 if (bus_space_read_2(ess
->st
, ess
->sh
, PORT_DSP_DATA
) == data
)
461 bus_space_write_2(ess
->st
, ess
->sh
, PORT_DSP_DATA
, data
);
464 printf("%s: wp_wrapu() timed out.\n", device_xname(ess
->sc_dev
));
468 wp_settimer(struct esm_softc
*ess
, u_int freq
)
471 u_int prescale
, divide
;
475 divide
= (freq
!= 0) ? (clock
/ freq
) : ~0;
476 RANGE(divide
, WPTIMER_MINDIV
, WPTIMER_MAXDIV
);
478 for (; divide
> 32 << 1; divide
>>= 1)
480 divide
= (divide
+ 1) >> 1;
482 for (; prescale
< 7 && divide
> 2 && !(divide
& 1); divide
>>= 1)
485 DPRINTF(ESM_DEBUG_TIMER
,
486 ("wp_settimer(%p, %u): clock = %u, prescale = %u, divide = %u\n",
487 ess
, freq
, clock
, prescale
, divide
));
489 wp_wrreg(ess
, WPREG_TIMER_ENABLE
, 0);
490 wp_wrreg(ess
, WPREG_TIMER_FREQ
,
491 (prescale
<< WP_TIMER_FREQ_PRESCALE_SHIFT
) | (divide
- 1));
492 wp_wrreg(ess
, WPREG_TIMER_ENABLE
, 1);
496 wp_starttimer(struct esm_softc
*ess
)
499 wp_wrreg(ess
, WPREG_TIMER_START
, 1);
503 wp_stoptimer(struct esm_softc
*ess
)
506 wp_wrreg(ess
, WPREG_TIMER_START
, 0);
507 bus_space_write_2(ess
->st
, ess
->sh
, PORT_INT_STAT
, 1);
512 static inline uint16_t
513 wc_rdreg(struct esm_softc
*ess
, uint16_t reg
)
516 bus_space_write_2(ess
->st
, ess
->sh
, PORT_WAVCACHE_INDEX
, reg
);
517 return bus_space_read_2(ess
->st
, ess
->sh
, PORT_WAVCACHE_DATA
);
521 wc_wrreg(struct esm_softc
*ess
, uint16_t reg
, uint16_t data
)
524 bus_space_write_2(ess
->st
, ess
->sh
, PORT_WAVCACHE_INDEX
, reg
);
525 bus_space_write_2(ess
->st
, ess
->sh
, PORT_WAVCACHE_DATA
, data
);
528 static inline uint16_t
529 wc_rdchctl(struct esm_softc
*ess
, int ch
)
532 return wc_rdreg(ess
, ch
<< 3);
536 wc_wrchctl(struct esm_softc
*ess
, int ch
, uint16_t data
)
539 wc_wrreg(ess
, ch
<< 3, data
);
542 /* -----------------------------
547 esm_attach_codec(void *sc
, struct ac97_codec_if
*codec_if
)
549 struct esm_softc
*ess
;
552 ess
->codec_if
= codec_if
;
558 esm_reset_codec(void *sc
)
566 esm_flags_codec(void *sc
)
568 struct esm_softc
*ess
;
571 return ess
->codec_flags
;
576 esm_initcodec(struct esm_softc
*ess
)
580 DPRINTF(ESM_DEBUG_CODEC
, ("esm_initcodec(%p)\n", ess
));
582 if (bus_space_read_4(ess
->st
, ess
->sh
, PORT_RINGBUS_CTRL
)
583 & RINGBUS_CTRL_ACLINK_ENABLED
) {
584 bus_space_write_4(ess
->st
, ess
->sh
, PORT_RINGBUS_CTRL
, 0);
585 delay(104); /* 20.8us * (4 + 1) */
587 /* XXX - 2nd codec should be looked at. */
588 bus_space_write_4(ess
->st
, ess
->sh
, PORT_RINGBUS_CTRL
,
589 RINGBUS_CTRL_AC97_SWRESET
);
591 bus_space_write_4(ess
->st
, ess
->sh
, PORT_RINGBUS_CTRL
,
592 RINGBUS_CTRL_ACLINK_ENABLED
);
595 esm_read_codec(ess
, 0, &data
);
596 if (bus_space_read_1(ess
->st
, ess
->sh
, PORT_CODEC_STAT
)
598 bus_space_write_4(ess
->st
, ess
->sh
, PORT_RINGBUS_CTRL
, 0);
601 /* Try cold reset. */
602 printf("%s: will perform cold reset.\n", device_xname(ess
->sc_dev
));
603 data
= bus_space_read_2(ess
->st
, ess
->sh
, PORT_GPIO_DIR
);
604 if (pci_conf_read(ess
->pc
, ess
->tag
, 0x58) & 1)
607 ~bus_space_read_2(ess
->st
, ess
->sh
, PORT_GPIO_DATA
);
608 bus_space_write_2(ess
->st
, ess
->sh
, PORT_GPIO_MASK
, 0xff6);
609 bus_space_write_2(ess
->st
, ess
->sh
, PORT_GPIO_DIR
,
611 bus_space_write_2(ess
->st
, ess
->sh
, PORT_GPIO_DATA
, 0x000);
613 bus_space_write_2(ess
->st
, ess
->sh
, PORT_GPIO_DATA
, 0x001);
615 bus_space_write_2(ess
->st
, ess
->sh
, PORT_GPIO_DATA
, 0x009);
617 bus_space_write_2(ess
->st
, ess
->sh
, PORT_GPIO_DIR
, data
);
618 delay(84); /* 20.8us * 4 */
619 bus_space_write_4(ess
->st
, ess
->sh
, PORT_RINGBUS_CTRL
,
620 RINGBUS_CTRL_ACLINK_ENABLED
);
626 esm_init(struct esm_softc
*ess
)
629 /* Reset direct sound. */
630 bus_space_write_2(ess
->st
, ess
->sh
, PORT_HOSTINT_CTRL
,
631 HOSTINT_CTRL_DSOUND_RESET
);
633 bus_space_write_2(ess
->st
, ess
->sh
, PORT_HOSTINT_CTRL
, 0);
636 /* Enable direct sound interruption. */
637 bus_space_write_2(ess
->st
, ess
->sh
, PORT_HOSTINT_CTRL
,
638 HOSTINT_CTRL_DSOUND_INT_ENABLED
);
640 /* Setup Wave Processor. */
642 /* Enable WaveCache */
643 wp_wrreg(ess
, WPREG_WAVE_ROMRAM
,
644 WP_WAVE_VIRTUAL_ENABLED
| WP_WAVE_DRAM_ENABLED
);
645 bus_space_write_2(ess
->st
, ess
->sh
, PORT_WAVCACHE_CTRL
,
646 WAVCACHE_ENABLED
| WAVCACHE_WTSIZE_4MB
);
648 /* Setup Codec/Ringbus. */
650 bus_space_write_4(ess
->st
, ess
->sh
, PORT_RINGBUS_CTRL
,
651 RINGBUS_CTRL_RINGBUS_ENABLED
| RINGBUS_CTRL_ACLINK_ENABLED
);
653 /* Undocumented registers from the Linux driver. */
654 wp_wrreg(ess
, 0x8, 0xB004);
655 wp_wrreg(ess
, 0x9, 0x001B);
656 wp_wrreg(ess
, 0xA, 0x8000);
657 wp_wrreg(ess
, 0xB, 0x3F37);
658 wp_wrreg(ess
, 0xD, 0x7632);
660 wp_wrreg(ess
, WPREG_BASE
, 0x8598); /* Parallel I/O */
661 ringbus_setdest(ess
, RINGBUS_SRC_ADC
,
662 RINGBUS_DEST_STEREO
| RINGBUS_DEST_DSOUND_IN
);
663 ringbus_setdest(ess
, RINGBUS_SRC_DSOUND
,
664 RINGBUS_DEST_STEREO
| RINGBUS_DEST_DAC
);
666 /* Setup ASSP. Needed for Dell Inspiron 7500? */
667 bus_space_write_1(ess
->st
, ess
->sh
, PORT_ASSP_CTRL_B
, 0x00);
668 bus_space_write_1(ess
->st
, ess
->sh
, PORT_ASSP_CTRL_A
, 0x03);
669 bus_space_write_1(ess
->st
, ess
->sh
, PORT_ASSP_CTRL_C
, 0x00);
673 * There seems to be speciality with NEC systems.
675 if (esm_get_quirks(ess
->subid
) & ESM_QUIRKF_GPIO
) {
676 bus_space_write_2(ess
->st
, ess
->sh
, PORT_GPIO_MASK
,
678 bus_space_write_2(ess
->st
, ess
->sh
, PORT_GPIO_DIR
,
679 bus_space_read_2(ess
->st
, ess
->sh
, PORT_GPIO_DIR
) |
681 bus_space_write_2(ess
->st
, ess
->sh
, PORT_GPIO_DATA
,
688 /* Channel controller. */
691 esm_init_output (void *sc
, void *start
, int size
)
693 struct esm_softc
*ess
;
698 if ((char *)start
!= (char *)p
->addr
+ MAESTRO_PLAYBUF_OFF
) {
699 printf("%s: esm_init_output: bad addr %p\n",
700 device_xname(ess
->sc_dev
), start
);
704 ess
->pch
.base
= DMAADDR(p
) + MAESTRO_PLAYBUF_OFF
;
706 DPRINTF(ESM_DEBUG_DMA
, ("%s: pch.base = 0x%x\n",
707 device_xname(ess
->sc_dev
), ess
->pch
.base
));
713 esm_init_input (void *sc
, void *start
, int size
)
715 struct esm_softc
*ess
;
720 if ((char *)start
!= (char *)p
->addr
+ MAESTRO_RECBUF_OFF
) {
721 printf("%s: esm_init_input: bad addr %p\n",
722 device_xname(ess
->sc_dev
), start
);
726 switch (ess
->rch
.aputype
) {
727 case APUTYPE_16BITSTEREO
:
728 ess
->rch
.base
= DMAADDR(p
) + MAESTRO_RECBUF_L_OFF
;
731 ess
->rch
.base
= DMAADDR(p
) + MAESTRO_RECBUF_OFF
;
735 DPRINTF(ESM_DEBUG_DMA
, ("%s: rch.base = 0x%x\n",
736 device_xname(ess
->sc_dev
), ess
->rch
.base
));
742 esm_trigger_output(void *sc
, void *start
, void *end
, int blksize
,
743 void (*intr
)(void *), void *arg
, const audio_params_t
*param
)
746 struct esm_softc
*ess
;
747 struct esm_chinfo
*ch
;
751 unsigned speed
, offset
, wpwa
, dv
;
754 DPRINTF(ESM_DEBUG_DMA
,
755 ("esm_trigger_output(%p, %p, %p, 0x%x, %p, %p, %p)\n",
756 sc
, start
, end
, blksize
, intr
, arg
, param
));
761 speed
= ch
->sample_rate
;
762 apuch
= ch
->num
<< 1;
766 printf("%s: esm_trigger_output: already running",
767 device_xname(ess
->sc_dev
));
772 ess
->sc_pintr
= intr
;
775 if ((char *)start
!= (char *)p
->addr
+ MAESTRO_PLAYBUF_OFF
) {
776 printf("%s: esm_trigger_output: bad addr %p\n",
777 device_xname(ess
->sc_dev
), start
);
781 ess
->pch
.blocksize
= blksize
;
782 ess
->pch
.apublk
= blksize
>> 1;
785 size
= (size_t)(((char *)end
- (char *)start
) >> 1);
786 choffset
= MAESTRO_PLAYBUF_OFF
;
787 offset
= choffset
>> 1;
788 wpwa
= APU_USE_SYSMEM
| ((offset
>> 8) & APU_64KPAGE_MASK
);
790 DPRINTF(ESM_DEBUG_DMA
,
791 ("choffs=0x%x, wpwa=0x%x, size=0x%lx words\n",
792 choffset
, wpwa
, (unsigned long int)size
));
794 switch (ch
->aputype
) {
795 case APUTYPE_16BITSTEREO
:
796 ess
->pch
.apublk
>>= 1;
801 case APUTYPE_8BITSTEREO
:
802 if (ess
->codec_flags
& AC97_HOST_SWAPPED_CHANNELS
)
808 case APUTYPE_8BITLINEAR
:
809 ess
->pch
.apublk
<<= 1;
814 ess
->pch
.apubase
= offset
;
815 ess
->pch
.apubuf
= size
;
816 ess
->pch
.nextirq
= ess
->pch
.apublk
;
821 dv
= (((speed
% 48000) << 16) + 24000) / 48000
822 + ((speed
/ 48000) << 16);
824 for (i
= nch
-1; i
>= 0; i
--) {
825 wp_wrapu(ess
, apuch
+ i
, APUREG_WAVESPACE
, wpwa
& 0xff00);
826 wp_wrapu(ess
, apuch
+ i
, APUREG_CURPTR
, offset
);
827 wp_wrapu(ess
, apuch
+ i
, APUREG_ENDPTR
, offset
+ size
);
828 wp_wrapu(ess
, apuch
+ i
, APUREG_LOOPLEN
, size
- 1);
829 wp_wrapu(ess
, apuch
+ i
, APUREG_AMPLITUDE
, 0xe800);
830 wp_wrapu(ess
, apuch
+ i
, APUREG_POSITION
, 0x8f00
831 | (RADIUS_CENTERCIRCLE
<< APU_RADIUS_SHIFT
)
832 | ((PAN_FRONT
+ pan
) << APU_PAN_SHIFT
));
833 wp_wrapu(ess
, apuch
+ i
, APUREG_FREQ_LOBYTE
, APU_plus6dB
834 | ((dv
& 0xff) << APU_FREQ_LOBYTE_SHIFT
));
835 wp_wrapu(ess
, apuch
+ i
, APUREG_FREQ_HIWORD
, dv
>> 8);
837 if (ch
->aputype
== APUTYPE_16BITSTEREO
)
838 wpwa
|= APU_STEREO
>> 1;
842 wc_wrchctl(ess
, apuch
, ch
->wcreg_tpl
);
844 wc_wrchctl(ess
, apuch
+ 1, ch
->wcreg_tpl
);
846 wp_wrapu(ess
, apuch
, APUREG_APUTYPE
,
847 (ch
->aputype
<< APU_APUTYPE_SHIFT
) | APU_DMA_ENABLED
| 0xf);
848 if (ch
->wcreg_tpl
& WAVCACHE_CHCTL_STEREO
)
849 wp_wrapu(ess
, apuch
+ 1, APUREG_APUTYPE
,
850 (ch
->aputype
<< APU_APUTYPE_SHIFT
) | APU_DMA_ENABLED
| 0xf);
856 esm_trigger_input(void *sc
, void *start
, void *end
, int blksize
,
857 void (*intr
)(void *), void *arg
, const audio_params_t
*param
)
861 struct esm_softc
*ess
;
862 struct esm_chinfo
*ch
;
864 uint32_t chctl
, choffset
;
865 uint32_t speed
, offset
, wpwa
, dv
;
866 uint32_t mixoffset
, mixdv
;
871 DPRINTF(ESM_DEBUG_DMA
,
872 ("esm_trigger_input(%p, %p, %p, 0x%x, %p, %p, %p)\n",
873 sc
, start
, end
, blksize
, intr
, arg
, param
));
877 speed
= ch
->sample_rate
;
878 apuch
= ch
->num
<< 1;
882 printf("%s: esm_trigger_input: already running",
883 device_xname(ess
->sc_dev
));
888 ess
->sc_rintr
= intr
;
891 if ((char *)start
!= (char *)p
->addr
+ MAESTRO_RECBUF_OFF
) {
892 printf("%s: esm_trigger_input: bad addr %p\n",
893 device_xname(ess
->sc_dev
), start
);
897 ess
->rch
.buffer
= (void *)start
;
899 ess
->rch
.blocksize
= blksize
;
900 ess
->rch
.bufsize
= ((char *)end
- (char *)start
);
901 ess
->rch
.apublk
= blksize
>> 1;
904 size
= (size_t)(((char *)end
- (char *)start
) >> 1);
905 choffset
= MAESTRO_RECBUF_OFF
;
906 switch (ch
->aputype
) {
907 case APUTYPE_16BITSTEREO
:
909 choffset
= MAESTRO_RECBUF_L_OFF
;
910 ess
->rch
.apublk
>>= 1;
913 case APUTYPE_16BITLINEAR
:
920 mixsize
= (MAESTRO_MIXBUF_SZ
>> 1) >> 1;
921 mixoffset
= MAESTRO_MIXBUF_OFF
;
923 ess
->rch
.apubase
= (choffset
>> 1);
924 ess
->rch
.apubuf
= size
;
925 ess
->rch
.nextirq
= ess
->rch
.apublk
;
930 if (speed
> 47999) speed
= 47999;
931 if (speed
< 4000) speed
= 4000;
932 dv
= (((speed
% 48000) << 16) + 24000) / 48000
933 + ((speed
/ 48000) << 16);
934 mixdv
= 65536; /* 48 kHz */
936 for (i
= 0; i
< nch
; i
++) {
938 /* Clear all rate conversion WP channel registers first. */
939 for (reg
= 0; reg
< 15; reg
++)
940 wp_wrapu(ess
, apuch
+ i
, reg
, 0);
942 /* Program the WaveCache for the rate conversion WP channel. */
943 chctl
= (DMAADDR(p
) + choffset
- 0x10) &
944 WAVCACHE_CHCTL_ADDRTAG_MASK
;
945 wc_wrchctl(ess
, apuch
+ i
, chctl
);
947 /* Program the rate conversion WP channel. */
948 wp_wrapu(ess
, apuch
+ i
, APUREG_FREQ_LOBYTE
, APU_plus6dB
949 | ((dv
& 0xff) << APU_FREQ_LOBYTE_SHIFT
) | 0x08);
950 wp_wrapu(ess
, apuch
+ i
, APUREG_FREQ_HIWORD
, dv
>> 8);
951 offset
= choffset
>> 1;
952 wpwa
= APU_USE_SYSMEM
| ((offset
>> 8) & APU_64KPAGE_MASK
);
953 wp_wrapu(ess
, apuch
+ i
, APUREG_WAVESPACE
, wpwa
);
954 wp_wrapu(ess
, apuch
+ i
, APUREG_CURPTR
, offset
);
955 wp_wrapu(ess
, apuch
+ i
, APUREG_ENDPTR
, offset
+ size
);
956 wp_wrapu(ess
, apuch
+ i
, APUREG_LOOPLEN
, size
- 1);
957 wp_wrapu(ess
, apuch
+ i
, APUREG_EFFECTS_ENV
, 0x00f0);
958 wp_wrapu(ess
, apuch
+ i
, APUREG_AMPLITUDE
, 0xe800);
959 wp_wrapu(ess
, apuch
+ i
, APUREG_POSITION
, 0x8f00
960 | (RADIUS_CENTERCIRCLE
<< APU_RADIUS_SHIFT
)
961 | (PAN_FRONT
<< APU_PAN_SHIFT
));
962 wp_wrapu(ess
, apuch
+ i
, APUREG_ROUTE
, apuch
+ 2 + i
);
964 DPRINTF(ESM_DEBUG_DMA
,
965 ("choffs=0x%x, wpwa=0x%x, offset=0x%x words, size=0x%lx words\n",
966 choffset
, wpwa
, offset
, (unsigned long int)size
));
968 /* Clear all mixer WP channel registers first. */
969 for (reg
= 0; reg
< 15; reg
++)
970 wp_wrapu(ess
, apuch
+ 2 + i
, reg
, 0);
972 /* Program the WaveCache for the mixer WP channel. */
973 chctl
= (ess
->rch
.base
+ mixoffset
- 0x10) &
974 WAVCACHE_CHCTL_ADDRTAG_MASK
;
975 wc_wrchctl(ess
, apuch
+ 2 + i
, chctl
);
977 /* Program the mixer WP channel. */
978 wp_wrapu(ess
, apuch
+ 2 + i
, APUREG_FREQ_LOBYTE
, APU_plus6dB
979 | ((mixdv
& 0xff) << APU_FREQ_LOBYTE_SHIFT
) | 0x08);
980 wp_wrapu(ess
, apuch
+ 2 + i
, APUREG_FREQ_HIWORD
, mixdv
>> 8);
981 offset
= mixoffset
>> 1;
982 wpwa
= APU_USE_SYSMEM
| ((offset
>> 8) & APU_64KPAGE_MASK
);
983 wp_wrapu(ess
, apuch
+ 2 + i
, APUREG_WAVESPACE
, wpwa
);
984 wp_wrapu(ess
, apuch
+ 2 + i
, APUREG_CURPTR
, offset
);
985 wp_wrapu(ess
, apuch
+ 2 + i
, APUREG_ENDPTR
,
987 wp_wrapu(ess
, apuch
+ 2 + i
, APUREG_LOOPLEN
, mixsize
);
988 wp_wrapu(ess
, apuch
+ 2 + i
, APUREG_EFFECTS_ENV
, 0x00f0);
989 wp_wrapu(ess
, apuch
+ 2 + i
, APUREG_AMPLITUDE
, 0xe800);
990 wp_wrapu(ess
, apuch
+ 2 + i
, APUREG_POSITION
, 0x8f00
991 | (RADIUS_CENTERCIRCLE
<< APU_RADIUS_SHIFT
)
992 | (PAN_FRONT
<< APU_PAN_SHIFT
));
993 wp_wrapu(ess
, apuch
+ 2 + i
, APUREG_ROUTE
,
996 DPRINTF(ESM_DEBUG_DMA
,
997 ("mixoffs=0x%x, wpwa=0x%x, offset=0x%x words, size=0x%lx words\n",
998 mixoffset
, wpwa
, offset
, (unsigned long int)mixsize
));
1000 /* Assume we're going to loop to do the right channel. */
1001 choffset
+= MAESTRO_RECBUF_L_SZ
;
1002 mixoffset
+= MAESTRO_MIXBUF_SZ
>> 1;
1005 wp_wrapu(ess
, apuch
, APUREG_APUTYPE
,
1006 (APUTYPE_RATECONV
<< APU_APUTYPE_SHIFT
) |
1007 APU_DMA_ENABLED
| 0xf);
1009 wp_wrapu(ess
, apuch
+ 1, APUREG_APUTYPE
,
1010 (APUTYPE_RATECONV
<< APU_APUTYPE_SHIFT
) |
1011 APU_DMA_ENABLED
| 0xf);
1012 wp_wrapu(ess
, apuch
+ 2, APUREG_APUTYPE
,
1013 (APUTYPE_INPUTMIXER
<< APU_APUTYPE_SHIFT
) |
1014 APU_DMA_ENABLED
| 0xf);
1016 wp_wrapu(ess
, apuch
+ 3, APUREG_APUTYPE
,
1017 (APUTYPE_RATECONV
<< APU_APUTYPE_SHIFT
) |
1018 APU_DMA_ENABLED
| 0xf);
1024 esm_halt_output(void *sc
)
1026 struct esm_softc
*ess
;
1027 struct esm_chinfo
*ch
;
1029 DPRINTF(ESM_DEBUG_PARAM
, ("esm_halt_output(%p)\n", sc
));
1033 wp_wrapu(ess
, (ch
->num
<< 1), APUREG_APUTYPE
,
1034 APUTYPE_INACTIVE
<< APU_APUTYPE_SHIFT
);
1035 wp_wrapu(ess
, (ch
->num
<< 1) + 1, APUREG_APUTYPE
,
1036 APUTYPE_INACTIVE
<< APU_APUTYPE_SHIFT
);
1046 esm_halt_input(void *sc
)
1048 struct esm_softc
*ess
;
1049 struct esm_chinfo
*ch
;
1051 DPRINTF(ESM_DEBUG_PARAM
, ("esm_halt_input(%p)\n", sc
));
1055 wp_wrapu(ess
, (ch
->num
<< 1), APUREG_APUTYPE
,
1056 APUTYPE_INACTIVE
<< APU_APUTYPE_SHIFT
);
1057 wp_wrapu(ess
, (ch
->num
<< 1) + 1, APUREG_APUTYPE
,
1058 APUTYPE_INACTIVE
<< APU_APUTYPE_SHIFT
);
1059 wp_wrapu(ess
, (ch
->num
<< 1) + 2, APUREG_APUTYPE
,
1060 APUTYPE_INACTIVE
<< APU_APUTYPE_SHIFT
);
1061 wp_wrapu(ess
, (ch
->num
<< 1) + 3, APUREG_APUTYPE
,
1062 APUTYPE_INACTIVE
<< APU_APUTYPE_SHIFT
);
1072 calc_timer_freq(struct esm_chinfo
*ch
)
1076 freq
= (ch
->sample_rate
+ ch
->apublk
- 1) / ch
->apublk
;
1078 DPRINTF(ESM_DEBUG_TIMER
,
1079 ("calc_timer_freq(%p): rate = %u, blk = 0x%x (0x%x): freq = %u\n",
1080 ch
, ch
->sample_rate
, ch
->apublk
, ch
->blocksize
, freq
));
1086 set_timer(struct esm_softc
*ess
)
1088 unsigned freq
, freq2
;
1092 freq
= calc_timer_freq(&ess
->pch
);
1095 freq2
= calc_timer_freq(&ess
->rch
);
1102 for (; freq
< MAESTRO_MINFREQ
; freq
<<= 1)
1106 wp_settimer(ess
, freq
);
1110 esmch_set_format(struct esm_chinfo
*ch
, const audio_params_t
*p
)
1115 wcreg_tpl
= (ch
->base
- 16) & WAVCACHE_CHCTL_ADDRTAG_MASK
;
1116 aputype
= APUTYPE_16BITLINEAR
;
1117 if (p
->channels
== 2) {
1118 wcreg_tpl
|= WAVCACHE_CHCTL_STEREO
;
1121 if (p
->precision
== 8) {
1123 switch (p
->encoding
) {
1124 case AUDIO_ENCODING_ULINEAR
:
1125 case AUDIO_ENCODING_ULINEAR_BE
:
1126 case AUDIO_ENCODING_ULINEAR_LE
:
1127 wcreg_tpl
|= WAVCACHE_CHCTL_U8
;
1131 ch
->wcreg_tpl
= wcreg_tpl
;
1132 ch
->aputype
= aputype
;
1133 ch
->sample_rate
= p
->sample_rate
;
1135 DPRINTF(ESM_DEBUG_PARAM
, ("esmch_set_format: "
1136 "numch=%u, prec=%u, tpl=0x%x, aputype=%d, rate=%u\n",
1137 p
->channels
, p
->precision
, wcreg_tpl
, aputype
, p
->sample_rate
));
1141 * Since we can't record in true stereo, this function combines
1142 * the separately recorded left and right channels into the final
1143 * buffer for the upper layer.
1146 esmch_combine_input(struct esm_softc
*ess
, struct esm_chinfo
*ch
)
1148 size_t offset
, resid
, count
;
1150 const uint32_t *left32s
, *right32s
;
1151 uint32_t left32
, right32
;
1153 /* The current offset into the upper layer buffer. */
1154 offset
= ch
->offset
;
1156 /* The number of bytes left to combine. */
1157 resid
= ch
->blocksize
;
1161 /* The 32-bit words for the left channel. */
1162 left32s
= (const uint32_t *)((char *)ess
->sc_dma
.addr
+
1163 MAESTRO_RECBUF_L_OFF
+ offset
/ 2);
1165 /* The 32-bit words for the right channel. */
1166 right32s
= (const uint32_t *)((char *)ess
->sc_dma
.addr
+
1167 MAESTRO_RECBUF_R_OFF
+ offset
/ 2);
1169 /* The pointer to the 32-bit words we will write. */
1170 dst32s
= (uint32_t *)((char *)ch
->buffer
+ offset
);
1172 /* Get the number of bytes we will combine now. */
1173 count
= ch
->bufsize
- offset
;
1178 if (offset
== ch
->bufsize
)
1181 /* Combine, writing two 32-bit words at a time. */
1182 KASSERT((count
& (sizeof(uint32_t) * 2 - 1)) == 0);
1183 count
/= (sizeof(uint32_t) * 2);
1185 left32
= *(left32s
++);
1186 right32
= *(right32s
++);
1187 /* XXX this endian handling is half-baked at best */
1188 #if BYTE_ORDER == LITTLE_ENDIAN
1189 *(dst32s
++) = (left32
& 0xFFFF) | (right32
<< 16);
1190 *(dst32s
++) = (left32
>> 16) | (right32
& 0xFFFF0000);
1191 #else /* BYTE_ORDER == BIG_ENDIAN */
1192 *(dst32s
++) = (left32
& 0xFFFF0000) | (right32
>> 16);
1193 *(dst32s
++) = (left32
<< 16) | (right32
& 0xFFFF);
1194 #endif /* BYTE_ORDER == BIG_ENDIAN */
1199 /* Update the offset. */
1200 ch
->offset
= offset
;
1204 * Audio interface glue functions
1208 esm_getdev (void *sc
, struct audio_device
*adp
)
1216 esm_round_blocksize(void *sc
, int blk
, int mode
,
1217 const audio_params_t
*param
)
1220 DPRINTF(ESM_DEBUG_PARAM
,
1221 ("esm_round_blocksize(%p, 0x%x)", sc
, blk
));
1223 blk
&= ~0x3f; /* keep good alignment */
1225 DPRINTF(ESM_DEBUG_PARAM
, (" = 0x%x\n", blk
));
1231 esm_query_encoding(void *sc
, struct audio_encoding
*fp
)
1234 DPRINTF(ESM_DEBUG_PARAM
,
1235 ("esm_query_encoding(%p, %d)\n", sc
, fp
->index
));
1237 if (fp
->index
< 0 || fp
->index
>= MAESTRO_NENCODINGS
)
1240 *fp
= esm_encoding
[fp
->index
];
1245 esm_set_params(void *sc
, int setmode
, int usemode
,
1246 audio_params_t
*play
, audio_params_t
*rec
,
1247 stream_filter_list_t
*pfil
, stream_filter_list_t
*rfil
)
1249 struct esm_softc
*ess
;
1251 const audio_params_t
*hw_play
, *hw_rec
;
1252 stream_filter_list_t
*fil
;
1255 DPRINTF(ESM_DEBUG_PARAM
,
1256 ("esm_set_params(%p, 0x%x, 0x%x, %p, %p)\n",
1257 sc
, setmode
, usemode
, play
, rec
));
1261 for (mode
= AUMODE_RECORD
; mode
!= -1;
1262 mode
= mode
== AUMODE_RECORD
? AUMODE_PLAY
: -1) {
1263 if ((setmode
& mode
) == 0)
1266 p
= mode
== AUMODE_PLAY
? play
: rec
;
1268 if (p
->sample_rate
< 4000 || p
->sample_rate
> 48000 ||
1269 (p
->precision
!= 8 && p
->precision
!= 16) ||
1270 (p
->channels
!= 1 && p
->channels
!= 2))
1273 fil
= mode
== AUMODE_PLAY
? pfil
: rfil
;
1274 i
= auconv_set_converter(esm_formats
, ESM_NFORMATS
,
1275 mode
, p
, FALSE
, fil
);
1278 if (fil
->req_size
> 0)
1279 p
= &fil
->filters
[0].param
;
1280 if (mode
== AUMODE_PLAY
)
1287 esmch_set_format(&ess
->pch
, hw_play
);
1290 esmch_set_format(&ess
->rch
, hw_rec
);
1296 esm_set_port(void *sc
, mixer_ctrl_t
*cp
)
1298 struct esm_softc
*ess
;
1301 return ess
->codec_if
->vtbl
->mixer_set_port(ess
->codec_if
, cp
);
1305 esm_get_port(void *sc
, mixer_ctrl_t
*cp
)
1307 struct esm_softc
*ess
;
1310 return ess
->codec_if
->vtbl
->mixer_get_port(ess
->codec_if
, cp
);
1314 esm_query_devinfo(void *sc
, mixer_devinfo_t
*dip
)
1316 struct esm_softc
*ess
;
1319 return ess
->codec_if
->vtbl
->query_devinfo(ess
->codec_if
, dip
);
1323 esm_malloc(void *sc
, int direction
, size_t size
,
1324 struct malloc_type
*pool
, int flags
)
1326 struct esm_softc
*ess
;
1329 DPRINTF(ESM_DEBUG_DMA
,
1330 ("esm_malloc(%p, %d, 0x%lx, %p, 0x%x)",
1331 sc
, direction
, (unsigned long int)size
, pool
, flags
));
1334 * Each buffer can only be allocated once.
1336 if (ess
->rings_alloced
& direction
) {
1337 DPRINTF(ESM_DEBUG_DMA
, (" = 0 (ENOMEM)\n"));
1342 * Mark this buffer as allocated and return its
1343 * kernel virtual address.
1345 ess
->rings_alloced
|= direction
;
1346 off
= (direction
== AUMODE_PLAY
?
1347 MAESTRO_PLAYBUF_OFF
: MAESTRO_RECBUF_OFF
);
1348 DPRINTF(ESM_DEBUG_DMA
, (" = %p (DMAADDR 0x%x)\n",
1349 (char *)ess
->sc_dma
.addr
+ off
,
1350 (int)DMAADDR(&ess
->sc_dma
) + off
));
1351 return (char *)ess
->sc_dma
.addr
+ off
;
1355 esm_free(void *sc
, void *ptr
, struct malloc_type
*pool
)
1357 struct esm_softc
*ess
;
1359 DPRINTF(ESM_DEBUG_DMA
,
1360 ("esm_free(%p, %p, %p)\n",
1363 if ((char *)ptr
== (char *)ess
->sc_dma
.addr
+ MAESTRO_PLAYBUF_OFF
)
1364 ess
->rings_alloced
&= ~AUMODE_PLAY
;
1365 else if ((char *)ptr
== (char *)ess
->sc_dma
.addr
+ MAESTRO_RECBUF_OFF
)
1366 ess
->rings_alloced
&= ~AUMODE_RECORD
;
1370 esm_round_buffersize(void *sc
, int direction
, size_t size
)
1373 if (size
> MAESTRO_PLAYBUF_SZ
)
1374 size
= MAESTRO_PLAYBUF_SZ
;
1375 if (size
> MAESTRO_RECBUF_SZ
)
1376 size
= MAESTRO_RECBUF_SZ
;
1381 esm_mappage(void *sc
, void *mem
, off_t off
, int prot
)
1383 struct esm_softc
*ess
;
1385 DPRINTF(ESM_DEBUG_DMA
,
1386 ("esm_mappage(%p, %p, 0x%lx, 0x%x)\n",
1387 sc
, mem
, (unsigned long)off
, prot
));
1392 if ((char *)mem
== (char *)ess
->sc_dma
.addr
+ MAESTRO_PLAYBUF_OFF
)
1393 off
+= MAESTRO_PLAYBUF_OFF
;
1394 else if ((char *)mem
== (char *)ess
->sc_dma
.addr
+ MAESTRO_RECBUF_OFF
)
1395 off
+= MAESTRO_RECBUF_OFF
;
1398 return bus_dmamem_mmap(ess
->dmat
, ess
->sc_dma
.segs
, ess
->sc_dma
.nsegs
,
1399 off
, prot
, BUS_DMA_WAITOK
);
1403 esm_get_props(void *sc
)
1406 return AUDIO_PROP_MMAP
| AUDIO_PROP_INDEPENDENT
| AUDIO_PROP_FULLDUPLEX
;
1410 /* -----------------------------
1417 struct esm_softc
*ess
;
1424 status
= bus_space_read_1(ess
->st
, ess
->sh
, PORT_HOSTINT_STAT
);
1428 /* Acknowledge all. */
1429 bus_space_write_2(ess
->st
, ess
->sh
, PORT_INT_STAT
, 1);
1430 bus_space_write_1(ess
->st
, ess
->sh
, PORT_HOSTINT_STAT
, 0);
1431 #if 0 /* XXX - HWVOL */
1432 if (status
& HOSTINT_STAT_HWVOL
) {
1434 delta
= bus_space_read_1(ess
->st
, ess
->sh
, PORT_HWVOL_MASTER
)
1437 mixer_set(device_get_softc(ess
->dev
),
1438 SOUND_MIXER_VOLUME
, 0);
1440 mixer_set(device_get_softc(ess
->dev
),
1442 mixer_get(device_get_softc(ess
->dev
),
1444 + ((delta
>> 5) & 0x7) - 4
1445 + ((delta
<< 7) & 0x700) - 0x400);
1447 bus_space_write_1(ess
->st
, ess
->sh
, PORT_HWVOL_MASTER
, 0x88);
1450 #endif /* XXX - HWVOL */
1453 pos
= wp_rdapu(ess
, ess
->pch
.num
<< 1, APUREG_CURPTR
);
1455 DPRINTF(ESM_DEBUG_IRQ
, (" %4.4x/%4.4x ", pos
,
1456 wp_rdapu(ess
, (ess
->pch
.num
<<1)+1, APUREG_CURPTR
)));
1458 pos
-= ess
->pch
.apubase
;
1459 if (pos
>= ess
->pch
.nextirq
&&
1460 pos
- ess
->pch
.nextirq
< ess
->pch
.apubuf
/ 2) {
1461 ess
->pch
.nextirq
+= ess
->pch
.apublk
;
1463 if (ess
->pch
.nextirq
>= ess
->pch
.apubuf
)
1464 ess
->pch
.nextirq
= 0;
1466 if (ess
->sc_pintr
) {
1467 DPRINTF(ESM_DEBUG_IRQ
, ("P\n"));
1468 ess
->sc_pintr(ess
->sc_parg
);
1476 pos
= wp_rdapu(ess
, ess
->rch
.num
<< 1, APUREG_CURPTR
);
1478 DPRINTF(ESM_DEBUG_IRQ
, (" %4.4x/%4.4x ", pos
,
1479 wp_rdapu(ess
, (ess
->rch
.num
<<1)+1, APUREG_CURPTR
)));
1481 pos
-= ess
->rch
.apubase
;
1482 if (pos
>= ess
->rch
.nextirq
&&
1483 pos
- ess
->rch
.nextirq
< ess
->rch
.apubuf
/ 2) {
1484 ess
->rch
.nextirq
+= ess
->rch
.apublk
;
1486 if (ess
->rch
.nextirq
>= ess
->rch
.apubuf
)
1487 ess
->rch
.nextirq
= 0;
1489 if (ess
->sc_rintr
) {
1490 DPRINTF(ESM_DEBUG_IRQ
, ("R\n"));
1491 switch(ess
->rch
.aputype
) {
1492 case APUTYPE_16BITSTEREO
:
1493 esmch_combine_input(ess
, &ess
->rch
);
1496 ess
->sc_rintr(ess
->sc_rarg
);
1507 esm_freemem(struct esm_softc
*sc
, struct esm_dma
*p
)
1512 bus_dmamem_free(sc
->dmat
, p
->segs
, p
->nsegs
);
1514 bus_dmamem_unmap(sc
->dmat
, p
->addr
, p
->size
);
1516 bus_dmamap_destroy(sc
->dmat
, p
->map
);
1518 bus_dmamap_unload(sc
->dmat
, p
->map
);
1524 esm_allocmem(struct esm_softc
*sc
, size_t size
, size_t align
,
1530 error
= bus_dmamem_alloc(sc
->dmat
, p
->size
, align
, 0,
1531 p
->segs
, __arraycount(p
->segs
),
1532 &p
->nsegs
, BUS_DMA_NOWAIT
);
1536 error
= bus_dmamem_map(sc
->dmat
, p
->segs
, p
->nsegs
, p
->size
,
1537 &p
->addr
, BUS_DMA_NOWAIT
|BUS_DMA_COHERENT
);
1541 error
= bus_dmamap_create(sc
->dmat
, p
->size
, 1, p
->size
,
1542 0, BUS_DMA_NOWAIT
, &p
->map
);
1546 error
= bus_dmamap_load(sc
->dmat
, p
->map
, p
->addr
, p
->size
, NULL
,
1554 bus_dmamap_destroy(sc
->dmat
, p
->map
);
1556 bus_dmamem_unmap(sc
->dmat
, p
->addr
, p
->size
);
1558 bus_dmamem_free(sc
->dmat
, p
->segs
, p
->nsegs
);
1565 esm_match(device_t dev
, cfdata_t match
, void *aux
)
1567 struct pci_attach_args
*pa
;
1569 pa
= (struct pci_attach_args
*)aux
;
1570 switch (PCI_VENDOR(pa
->pa_id
)) {
1571 case PCI_VENDOR_ESSTECH
:
1572 switch (PCI_PRODUCT(pa
->pa_id
)) {
1573 case PCI_PRODUCT_ESSTECH_MAESTRO1
:
1574 case PCI_PRODUCT_ESSTECH_MAESTRO2
:
1575 case PCI_PRODUCT_ESSTECH_MAESTRO2E
:
1579 case PCI_VENDOR_ESSTECH2
:
1580 switch (PCI_PRODUCT(pa
->pa_id
)) {
1581 case PCI_PRODUCT_ESSTECH2_MAESTRO1
:
1589 esm_attach(device_t parent
, device_t self
, void *aux
)
1592 struct esm_softc
*ess
;
1593 struct pci_attach_args
*pa
;
1594 const char *intrstr
;
1595 pci_chipset_tag_t pc
;
1597 pci_intr_handle_t ih
;
1600 uint16_t codec_data
;
1604 ess
= device_private(self
);
1606 pa
= (struct pci_attach_args
*)aux
;
1609 aprint_naive(": Audio controller\n");
1611 pci_devinfo(pa
->pa_id
, pa
->pa_class
, 0, devinfo
, sizeof(devinfo
));
1612 revision
= PCI_REVISION(pa
->pa_class
);
1613 aprint_normal(": %s (rev. 0x%02x)\n", devinfo
, revision
);
1615 /* Enable the device. */
1616 csr
= pci_conf_read(pc
, tag
, PCI_COMMAND_STATUS_REG
);
1617 pci_conf_write(pc
, tag
, PCI_COMMAND_STATUS_REG
,
1618 csr
| PCI_COMMAND_MASTER_ENABLE
| PCI_COMMAND_IO_ENABLE
);
1620 /* Map I/O register */
1621 if (pci_mapreg_map(pa
, PCI_CBIO
, PCI_MAPREG_TYPE_IO
, 0,
1622 &ess
->st
, &ess
->sh
, NULL
, &ess
->sz
)) {
1623 aprint_error_dev(ess
->sc_dev
, "can't map i/o space\n");
1627 /* Initialize softc */
1630 ess
->dmat
= pa
->pa_dmat
;
1633 ess
->subid
= pci_conf_read(pc
, tag
, PCI_SUBSYS_ID_REG
);
1635 DPRINTF(ESM_DEBUG_PCI
,
1636 ("%s: sub-system vendor 0x%4.4x, product 0x%4.4x\n",
1637 device_xname(ess
->sc_dev
),
1638 PCI_VENDOR(ess
->subid
), PCI_PRODUCT(ess
->subid
)));
1640 /* Map and establish the interrupt. */
1641 if (pci_intr_map(pa
, &ih
)) {
1642 aprint_error_dev(ess
->sc_dev
, "can't map interrupt\n");
1645 intrstr
= pci_intr_string(pc
, ih
);
1646 ess
->ih
= pci_intr_establish(pc
, ih
, IPL_AUDIO
, esm_intr
, self
);
1647 if (ess
->ih
== NULL
) {
1648 aprint_error_dev(ess
->sc_dev
, "can't establish interrupt");
1649 if (intrstr
!= NULL
)
1650 aprint_error(" at %s", intrstr
);
1654 aprint_normal_dev(ess
->sc_dev
, "interrupting at %s\n",
1658 * Setup PCI config registers
1662 if ((error
= pci_activate(pa
->pa_pc
, pa
->pa_tag
, self
,
1663 pci_activate_null
)) && error
!= EOPNOTSUPP
) {
1664 aprint_error_dev(ess
->sc_dev
, "cannot activate %d\n",
1670 /* Disable all legacy emulations. */
1671 data
= pci_conf_read(pc
, tag
, CONF_LEGACY
);
1672 pci_conf_write(pc
, tag
, CONF_LEGACY
, data
| LEGACY_DISABLED
);
1674 /* Disconnect from CHI. (Makes Dell inspiron 7500 work?)
1675 * Enable posted write.
1676 * Prefer PCI timing rather than that of ISA.
1677 * Don't swap L/R. */
1678 data
= pci_conf_read(pc
, tag
, CONF_MAESTRO
);
1679 data
|= MAESTRO_CHIBUS
| MAESTRO_POSTEDWRITE
| MAESTRO_DMA_PCITIMING
;
1680 data
&= ~MAESTRO_SWAP_LR
;
1681 pci_conf_write(pc
, tag
, CONF_MAESTRO
, data
);
1683 /* initialize sound chip */
1686 esm_read_codec(ess
, 0, &codec_data
);
1687 if (codec_data
== 0x80) {
1688 aprint_error_dev(ess
->sc_dev
, "PT101 codec detected!\n");
1693 * Some cards and Notebooks appear to have left and right channels
1694 * reversed. Check if there is a corresponding quirk entry for
1695 * the subsystem vendor and product and if so, set the appropriate
1698 if (esm_get_quirks(ess
->subid
) & ESM_QUIRKF_SWAPPEDCH
) {
1699 ess
->codec_flags
|= AC97_HOST_SWAPPED_CHANNELS
;
1701 ess
->codec_flags
|= AC97_HOST_DONT_READ
;
1703 /* initialize AC97 host interface */
1704 ess
->host_if
.arg
= self
;
1705 ess
->host_if
.attach
= esm_attach_codec
;
1706 ess
->host_if
.read
= esm_read_codec
;
1707 ess
->host_if
.write
= esm_write_codec
;
1708 ess
->host_if
.reset
= esm_reset_codec
;
1709 ess
->host_if
.flags
= esm_flags_codec
;
1711 if (ac97_attach(&ess
->host_if
, self
) != 0)
1714 /* allocate our DMA region */
1715 if (esm_allocmem(ess
, MAESTRO_DMA_SZ
, MAESTRO_DMA_ALIGN
,
1717 aprint_error_dev(ess
->sc_dev
, "couldn't allocate memory!\n");
1720 ess
->rings_alloced
= 0;
1722 /* set DMA base address */
1723 for (pcmbar
= WAVCACHE_PCMBAR
; pcmbar
< WAVCACHE_PCMBAR
+ 4; pcmbar
++)
1724 wc_wrreg(ess
, pcmbar
,
1725 DMAADDR(&ess
->sc_dma
) >> WAVCACHE_BASEADDR_SHIFT
);
1727 audio_attach_mi(&esm_hw_if
, self
, ess
->sc_dev
);
1729 if (!pmf_device_register(self
, esm_suspend
, esm_resume
))
1730 aprint_error_dev(self
, "couldn't establish power handler\n");
1734 esm_childdet(device_t self
, device_t child
)
1736 /* we hold no child references, so do nothing */
1740 esm_detach(device_t self
, int flags
)
1743 struct esm_softc
*ess
= device_private(self
);
1745 pmf_device_deregister(self
);
1747 if ((rc
= config_detach_children(self
, flags
)) != 0)
1750 /* free our DMA region */
1751 esm_freemem(ess
, &ess
->sc_dma
);
1753 if (ess
->codec_if
!= NULL
)
1754 ess
->codec_if
->vtbl
->detach(ess
->codec_if
);
1756 /* XXX Restore CONF_MAESTRO? */
1757 /* XXX Restore legacy emulations? */
1758 /* XXX Restore PCI config registers? */
1760 if (ess
->ih
!= NULL
)
1761 pci_intr_disestablish(ess
->pc
, ess
->ih
);
1763 bus_space_unmap(ess
->st
, ess
->sh
, ess
->sz
);
1769 esm_suspend(device_t dv
, pmf_qual_t qual
)
1771 struct esm_softc
*ess
= device_private(dv
);
1776 bus_space_write_2(ess
->st
, ess
->sh
, PORT_HOSTINT_CTRL
, 0);
1778 esm_halt_output(ess
);
1779 esm_halt_input(ess
);
1782 /* Power down everything except clock. */
1783 esm_write_codec(ess
, AC97_REG_POWER
, 0xdf00);
1785 bus_space_write_4(ess
->st
, ess
->sh
, PORT_RINGBUS_CTRL
, 0);
1792 esm_resume(device_t dv
, pmf_qual_t qual
)
1794 struct esm_softc
*ess
= device_private(dv
);
1801 /* set DMA base address */
1802 for (pcmbar
= WAVCACHE_PCMBAR
; pcmbar
< WAVCACHE_PCMBAR
+ 4; pcmbar
++)
1803 wc_wrreg(ess
, pcmbar
,
1804 DMAADDR(&ess
->sc_dma
) >> WAVCACHE_BASEADDR_SHIFT
);
1806 ess
->codec_if
->vtbl
->restore_ports(ess
->codec_if
);
1808 if (mixer_reinit(dev
)) {
1809 printf("%s: unable to reinitialize the mixer\n",
1810 device_xname(ess
->sc_dev
));
1818 esm_start_output(ess
);
1820 esm_start_input(ess
);
1822 if (ess
->pactive
|| ess
->ractive
) {