1 1.55 andvar /* $NetBSD: auixp.c,v 1.55 2024/02/08 20:30:39 andvar Exp $ */ 2 1.1 reinoud 3 1.1 reinoud /* 4 1.2 reinoud * Copyright (c) 2004, 2005 Reinoud Zandijk <reinoud (at) netbsd.org> 5 1.1 reinoud * All rights reserved. 6 1.1 reinoud * 7 1.1 reinoud * Redistribution and use in source and binary forms, with or without 8 1.1 reinoud * modification, are permitted provided that the following conditions 9 1.1 reinoud * are met: 10 1.1 reinoud * 1. Redistributions of source code must retain the above copyright 11 1.1 reinoud * notice, this list of conditions and the following disclaimer. 12 1.1 reinoud * 2. The name of the author may not be used to endorse or promote products 13 1.1 reinoud * derived from this software without specific prior written permission. 14 1.1 reinoud * 15 1.1 reinoud * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 1.1 reinoud * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 1.1 reinoud * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 1.1 reinoud * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 1.1 reinoud * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 1.1 reinoud * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 1.1 reinoud * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 1.1 reinoud * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 1.1 reinoud * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 1.1 reinoud * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 1.1 reinoud * SUCH DAMAGE. 26 1.1 reinoud */ 27 1.1 reinoud 28 1.1 reinoud 29 1.1 reinoud /* 30 1.1 reinoud * NetBSD audio driver for ATI IXP-{150,200,...} audio driver hardware. 31 1.1 reinoud * 32 1.1 reinoud * Recording and playback has been tested OK on various sample rates and 33 1.1 reinoud * encodings. 34 1.1 reinoud * 35 1.1 reinoud * Known problems and issues : 36 1.1 reinoud * - SPDIF is untested and needs some work still (LED stays off) 37 1.1 reinoud * - 32 bit audio playback failed last time i tried but that might an AC'97 38 1.1 reinoud * codec support problem. 39 1.1 reinoud * - 32 bit recording works but can't try out playing: see above. 40 1.1 reinoud * - no suspend/resume support yet. 41 1.55 andvar * - multiple codecs are `supported' but not tested; the implementation needs 42 1.1 reinoud * some cleaning up. 43 1.1 reinoud */ 44 1.1 reinoud 45 1.1 reinoud #include <sys/cdefs.h> 46 1.55 andvar __KERNEL_RCSID(0, "$NetBSD: auixp.c,v 1.55 2024/02/08 20:30:39 andvar Exp $"); 47 1.1 reinoud 48 1.1 reinoud #include <sys/types.h> 49 1.1 reinoud #include <sys/errno.h> 50 1.1 reinoud #include <sys/null.h> 51 1.1 reinoud #include <sys/param.h> 52 1.1 reinoud #include <sys/systm.h> 53 1.35 jmcneill #include <sys/kmem.h> 54 1.1 reinoud #include <sys/device.h> 55 1.1 reinoud #include <sys/conf.h> 56 1.1 reinoud #include <sys/exec.h> 57 1.1 reinoud #include <sys/select.h> 58 1.1 reinoud #include <sys/audioio.h> 59 1.1 reinoud #include <sys/queue.h> 60 1.24 ad #include <sys/bus.h> 61 1.24 ad #include <sys/intr.h> 62 1.1 reinoud 63 1.46 isaki #include <dev/audio/audio_if.h> 64 1.35 jmcneill 65 1.1 reinoud #include <dev/ic/ac97var.h> 66 1.1 reinoud #include <dev/ic/ac97reg.h> 67 1.1 reinoud 68 1.35 jmcneill #include <dev/pci/pcidevs.h> 69 1.35 jmcneill #include <dev/pci/pcivar.h> 70 1.1 reinoud #include <dev/pci/auixpreg.h> 71 1.1 reinoud #include <dev/pci/auixpvar.h> 72 1.1 reinoud 73 1.1 reinoud 74 1.18 jmcneill /* #define DEBUG_AUIXP */ 75 1.1 reinoud 76 1.1 reinoud 77 1.1 reinoud /* why isn't this base address register not in the headerfile? */ 78 1.1 reinoud #define PCI_CBIO 0x10 79 1.1 reinoud 80 1.1 reinoud 81 1.1 reinoud /* macro's used */ 82 1.1 reinoud #define KERNADDR(p) ((void *)((p)->addr)) 83 1.1 reinoud #define DMAADDR(p) ((p)->map->dm_segs[0].ds_addr) 84 1.1 reinoud 85 1.1 reinoud 86 1.1 reinoud /* the differences might be irrelevant */ 87 1.1 reinoud enum { 88 1.1 reinoud IXP_200, 89 1.1 reinoud IXP_300, 90 1.1 reinoud IXP_400 91 1.1 reinoud }; 92 1.1 reinoud 93 1.1 reinoud 94 1.1 reinoud /* our `cards' */ 95 1.9 thorpej static const struct auixp_card_type { 96 1.1 reinoud uint16_t pci_vendor_id; 97 1.1 reinoud uint16_t pci_product_id; 98 1.1 reinoud int type; 99 1.1 reinoud } auixp_card_types[] = { 100 1.1 reinoud { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_IXP_AUDIO_200, IXP_200 }, 101 1.1 reinoud { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_IXP_AUDIO_300, IXP_300 }, 102 1.1 reinoud { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_IXP_AUDIO_400, IXP_400 }, 103 1.1 reinoud { 0, 0, 0 } 104 1.1 reinoud }; 105 1.1 reinoud 106 1.1 reinoud 107 1.1 reinoud struct audio_device auixp_device = { 108 1.1 reinoud "ATI IXP audio", 109 1.1 reinoud "", 110 1.1 reinoud "auixp" 111 1.1 reinoud }; 112 1.1 reinoud 113 1.46 isaki /* 114 1.46 isaki * current AC'97 driver only supports SPDIF outputting channel 3&4 i.e. STEREO 115 1.46 isaki */ 116 1.46 isaki #define AUIXP_FORMAT(aumode, ch, chmask) \ 117 1.46 isaki { \ 118 1.46 isaki .mode = (aumode), \ 119 1.46 isaki .encoding = AUDIO_ENCODING_SLINEAR_LE, \ 120 1.46 isaki .validbits = 16, \ 121 1.46 isaki .precision = 16, \ 122 1.46 isaki .channels = (ch), \ 123 1.46 isaki .channel_mask = (chmask), \ 124 1.46 isaki .frequency_type = 0, \ 125 1.46 isaki .frequency = { 7000, 48000 }, \ 126 1.46 isaki } 127 1.46 isaki static const struct audio_format auixp_formats[AUIXP_NFORMATS] = { 128 1.46 isaki AUIXP_FORMAT(AUMODE_PLAY | AUMODE_RECORD, 2, AUFMT_STEREO), 129 1.46 isaki AUIXP_FORMAT(AUMODE_PLAY , 4, AUFMT_SURROUND4), 130 1.46 isaki AUIXP_FORMAT(AUMODE_PLAY , 6, AUFMT_DOLBY_5_1), 131 1.46 isaki }; 132 1.1 reinoud 133 1.1 reinoud /* codec detection constant indicating the interrupt flags */ 134 1.1 reinoud #define ALL_CODECS_NOT_READY \ 135 1.1 reinoud (ATI_REG_ISR_CODEC0_NOT_READY |\ 136 1.1 reinoud ATI_REG_ISR_CODEC1_NOT_READY |\ 137 1.1 reinoud ATI_REG_ISR_CODEC2_NOT_READY) 138 1.1 reinoud #define CODEC_CHECK_BITS (ALL_CODECS_NOT_READY|ATI_REG_ISR_NEW_FRAME) 139 1.1 reinoud 140 1.1 reinoud 141 1.1 reinoud /* autoconfig */ 142 1.31 cegger static int auixp_match(device_t, cfdata_t, void *); 143 1.27 dyoung static void auixp_attach(device_t, device_t, void *); 144 1.27 dyoung static int auixp_detach(device_t, int); 145 1.1 reinoud 146 1.1 reinoud 147 1.1 reinoud /* audio(9) function prototypes */ 148 1.46 isaki static int auixp_query_format(void *, audio_format_query_t *); 149 1.46 isaki static int auixp_set_format(void *, int, 150 1.46 isaki const audio_params_t *, const audio_params_t *, 151 1.46 isaki audio_filter_reg_t *, audio_filter_reg_t *); 152 1.9 thorpej static int auixp_commit_settings(void *); 153 1.9 thorpej static int auixp_round_blocksize(void *, int, int, const audio_params_t *); 154 1.9 thorpej static int auixp_trigger_output(void *, void *, void *, int, 155 1.9 thorpej void (*)(void *), 156 1.3 kent void *, const audio_params_t *); 157 1.9 thorpej static int auixp_trigger_input(void *, void *, void *, int, 158 1.9 thorpej void (*)(void *), 159 1.3 kent void *, const audio_params_t *); 160 1.9 thorpej static int auixp_halt_output(void *); 161 1.9 thorpej static int auixp_halt_input(void *); 162 1.9 thorpej static int auixp_set_port(void *, mixer_ctrl_t *); 163 1.9 thorpej static int auixp_get_port(void *, mixer_ctrl_t *); 164 1.9 thorpej static int auixp_query_devinfo(void *, mixer_devinfo_t *); 165 1.35 jmcneill static void * auixp_malloc(void *, int, size_t); 166 1.35 jmcneill static void auixp_free(void *, void *, size_t); 167 1.9 thorpej static int auixp_getdev(void *, struct audio_device *); 168 1.9 thorpej static size_t auixp_round_buffersize(void *, int, size_t); 169 1.9 thorpej static int auixp_get_props(void *); 170 1.9 thorpej static int auixp_intr(void *); 171 1.9 thorpej static int auixp_allocmem(struct auixp_softc *, size_t, size_t, 172 1.4 simonb struct auixp_dma *); 173 1.9 thorpej static int auixp_freemem(struct auixp_softc *, struct auixp_dma *); 174 1.1 reinoud 175 1.1 reinoud /* Supporting subroutines */ 176 1.9 thorpej static int auixp_init(struct auixp_softc *); 177 1.9 thorpej static void auixp_autodetect_codecs(struct auixp_softc *); 178 1.27 dyoung static void auixp_post_config(device_t); 179 1.9 thorpej 180 1.9 thorpej static void auixp_reset_aclink(struct auixp_softc *); 181 1.9 thorpej static int auixp_attach_codec(void *, struct ac97_codec_if *); 182 1.9 thorpej static int auixp_read_codec(void *, uint8_t, uint16_t *); 183 1.9 thorpej static int auixp_write_codec(void *, uint8_t, uint16_t); 184 1.9 thorpej static int auixp_wait_for_codecs(struct auixp_softc *, const char *); 185 1.9 thorpej static int auixp_reset_codec(void *); 186 1.9 thorpej static enum ac97_host_flags auixp_flags_codec(void *); 187 1.9 thorpej 188 1.9 thorpej static void auixp_enable_dma(struct auixp_softc *, struct auixp_dma *); 189 1.9 thorpej static void auixp_disable_dma(struct auixp_softc *, struct auixp_dma *); 190 1.9 thorpej static void auixp_enable_interrupts(struct auixp_softc *); 191 1.9 thorpej static void auixp_disable_interrupts(struct auixp_softc *); 192 1.1 reinoud 193 1.1 reinoud 194 1.1 reinoud /* statics */ 195 1.9 thorpej static void auixp_link_daisychain(struct auixp_softc *, 196 1.9 thorpej struct auixp_dma *, struct auixp_dma *, 197 1.9 thorpej int, int); 198 1.9 thorpej static int auixp_allocate_dma_chain(struct auixp_softc *, 199 1.9 thorpej struct auixp_dma **); 200 1.9 thorpej static void auixp_program_dma_chain(struct auixp_softc *, 201 1.9 thorpej struct auixp_dma *); 202 1.9 thorpej static void auixp_dma_update(struct auixp_softc *, struct auixp_dma *); 203 1.9 thorpej static void auixp_update_busbusy(struct auixp_softc *); 204 1.35 jmcneill static void auixp_get_locks(void *, kmutex_t **, kmutex_t **); 205 1.1 reinoud 206 1.34 dyoung static bool auixp_resume(device_t, const pmf_qual_t *); 207 1.25 jmcneill 208 1.1 reinoud 209 1.1 reinoud #ifdef DEBUG_AUIXP 210 1.9 thorpej static struct auixp_softc *static_sc; 211 1.46 isaki static void auixp_dumpreg(void) __unused; 212 1.1 reinoud # define DPRINTF(x) printf x; 213 1.1 reinoud #else 214 1.1 reinoud # define DPRINTF(x) 215 1.1 reinoud #endif 216 1.1 reinoud 217 1.1 reinoud 218 1.9 thorpej static const struct audio_hw_if auixp_hw_if = { 219 1.46 isaki .query_format = auixp_query_format, 220 1.46 isaki .set_format = auixp_set_format, 221 1.45 isaki .round_blocksize = auixp_round_blocksize, 222 1.45 isaki .commit_settings = auixp_commit_settings, 223 1.45 isaki .halt_output = auixp_halt_output, 224 1.45 isaki .halt_input = auixp_halt_input, 225 1.45 isaki .getdev = auixp_getdev, 226 1.45 isaki .set_port = auixp_set_port, 227 1.45 isaki .get_port = auixp_get_port, 228 1.45 isaki .query_devinfo = auixp_query_devinfo, 229 1.45 isaki .allocm = auixp_malloc, 230 1.45 isaki .freem = auixp_free, 231 1.45 isaki .round_buffersize = auixp_round_buffersize, 232 1.45 isaki .get_props = auixp_get_props, 233 1.45 isaki .trigger_output = auixp_trigger_output, 234 1.45 isaki .trigger_input = auixp_trigger_input, 235 1.45 isaki .get_locks = auixp_get_locks, 236 1.1 reinoud }; 237 1.1 reinoud 238 1.1 reinoud 239 1.39 chs CFATTACH_DECL_NEW(auixp, sizeof(struct auixp_softc), auixp_match, auixp_attach, 240 1.1 reinoud auixp_detach, NULL); 241 1.1 reinoud 242 1.1 reinoud 243 1.1 reinoud /* 244 1.1 reinoud * audio(9) functions 245 1.1 reinoud */ 246 1.1 reinoud 247 1.9 thorpej static int 248 1.46 isaki auixp_query_format(void *hdl, audio_format_query_t *afp) 249 1.3 kent { 250 1.3 kent struct auixp_codec *co; 251 1.3 kent struct auixp_softc *sc; 252 1.1 reinoud 253 1.3 kent co = (struct auixp_codec *) hdl; 254 1.3 kent sc = co->sc; 255 1.46 isaki return audio_query_format(sc->sc_formats, AUIXP_NFORMATS, afp); 256 1.1 reinoud } 257 1.1 reinoud 258 1.1 reinoud 259 1.3 kent static int 260 1.3 kent auixp_set_rate(struct auixp_codec *co, int mode, u_int srate) 261 1.3 kent { 262 1.1 reinoud int ret; 263 1.1 reinoud u_int ratetmp; 264 1.1 reinoud 265 1.1 reinoud ratetmp = srate; 266 1.1 reinoud if (mode == AUMODE_RECORD) { 267 1.3 kent ret = co->codec_if->vtbl->set_rate(co->codec_if, 268 1.3 kent AC97_REG_PCM_LR_ADC_RATE, &ratetmp); 269 1.1 reinoud return ret; 270 1.3 kent } 271 1.1 reinoud 272 1.1 reinoud /* play mode */ 273 1.3 kent ret = co->codec_if->vtbl->set_rate(co->codec_if, 274 1.3 kent AC97_REG_PCM_FRONT_DAC_RATE, &ratetmp); 275 1.4 simonb if (ret) 276 1.4 simonb return ret; 277 1.1 reinoud 278 1.1 reinoud ratetmp = srate; 279 1.3 kent ret = co->codec_if->vtbl->set_rate(co->codec_if, 280 1.3 kent AC97_REG_PCM_SURR_DAC_RATE, &ratetmp); 281 1.4 simonb if (ret) 282 1.4 simonb return ret; 283 1.1 reinoud 284 1.1 reinoud ratetmp = srate; 285 1.3 kent ret = co->codec_if->vtbl->set_rate(co->codec_if, 286 1.3 kent AC97_REG_PCM_LFE_DAC_RATE, &ratetmp); 287 1.1 reinoud return ret; 288 1.1 reinoud } 289 1.1 reinoud 290 1.1 reinoud 291 1.1 reinoud /* commit setting and program ATI IXP chip */ 292 1.9 thorpej static int 293 1.3 kent auixp_commit_settings(void *hdl) 294 1.3 kent { 295 1.3 kent struct auixp_codec *co; 296 1.3 kent struct auixp_softc *sc; 297 1.3 kent bus_space_tag_t iot; 298 1.3 kent bus_space_handle_t ioh; 299 1.1 reinoud struct audio_params *params; 300 1.1 reinoud uint32_t value; 301 1.1 reinoud 302 1.1 reinoud /* XXX would it be better to stop interrupts first? XXX */ 303 1.3 kent co = (struct auixp_codec *) hdl; 304 1.3 kent sc = co->sc; 305 1.3 kent iot = sc->sc_iot; 306 1.3 kent ioh = sc->sc_ioh; 307 1.1 reinoud 308 1.1 reinoud /* process input settings */ 309 1.1 reinoud params = &sc->sc_play_params; 310 1.1 reinoud 311 1.1 reinoud /* set input interleaving (precision) */ 312 1.1 reinoud value = bus_space_read_4(iot, ioh, ATI_REG_CMD); 313 1.1 reinoud value &= ~ATI_REG_CMD_INTERLEAVE_IN; 314 1.4 simonb if (params->precision <= 16) 315 1.4 simonb value |= ATI_REG_CMD_INTERLEAVE_IN; 316 1.1 reinoud bus_space_write_4(iot, ioh, ATI_REG_CMD, value); 317 1.1 reinoud 318 1.1 reinoud /* process output settings */ 319 1.1 reinoud params = &sc->sc_play_params; 320 1.1 reinoud 321 1.1 reinoud value = bus_space_read_4(iot, ioh, ATI_REG_OUT_DMA_SLOT); 322 1.1 reinoud value &= ~ATI_REG_OUT_DMA_SLOT_MASK; 323 1.1 reinoud 324 1.7 reinoud /* TODO SPDIF case for 8 channels */ 325 1.1 reinoud switch (params->channels) { 326 1.1 reinoud case 6: 327 1.1 reinoud value |= ATI_REG_OUT_DMA_SLOT_BIT(7) | 328 1.1 reinoud ATI_REG_OUT_DMA_SLOT_BIT(8); 329 1.1 reinoud /* fallthru */ 330 1.1 reinoud case 4: 331 1.1 reinoud value |= ATI_REG_OUT_DMA_SLOT_BIT(6) | 332 1.1 reinoud ATI_REG_OUT_DMA_SLOT_BIT(9); 333 1.1 reinoud /* fallthru */ 334 1.1 reinoud default: 335 1.1 reinoud value |= ATI_REG_OUT_DMA_SLOT_BIT(3) | 336 1.1 reinoud ATI_REG_OUT_DMA_SLOT_BIT(4); 337 1.1 reinoud break; 338 1.3 kent } 339 1.1 reinoud /* set output threshold */ 340 1.1 reinoud value |= 0x04 << ATI_REG_OUT_DMA_THRESHOLD_SHIFT; 341 1.1 reinoud bus_space_write_4(iot, ioh, ATI_REG_OUT_DMA_SLOT, value); 342 1.1 reinoud 343 1.1 reinoud /* set output interleaving (precision) */ 344 1.1 reinoud value = bus_space_read_4(iot, ioh, ATI_REG_CMD); 345 1.1 reinoud value &= ~ATI_REG_CMD_INTERLEAVE_OUT; 346 1.4 simonb if (params->precision <= 16) 347 1.4 simonb value |= ATI_REG_CMD_INTERLEAVE_OUT; 348 1.1 reinoud bus_space_write_4(iot, ioh, ATI_REG_CMD, value); 349 1.1 reinoud 350 1.1 reinoud /* enable 6 channel reordering */ 351 1.1 reinoud value = bus_space_read_4(iot, ioh, ATI_REG_6CH_REORDER); 352 1.1 reinoud value &= ~ATI_REG_6CH_REORDER_EN; 353 1.4 simonb if (params->channels == 6) 354 1.4 simonb value |= ATI_REG_6CH_REORDER_EN; 355 1.1 reinoud bus_space_write_4(iot, ioh, ATI_REG_6CH_REORDER, value); 356 1.1 reinoud 357 1.1 reinoud if (sc->has_spdif) { 358 1.1 reinoud /* set SPDIF (if present) */ 359 1.1 reinoud value = bus_space_read_4(iot, ioh, ATI_REG_CMD); 360 1.1 reinoud value &= ~ATI_REG_CMD_SPDF_CONFIG_MASK; 361 1.4 simonb value |= ATI_REG_CMD_SPDF_CONFIG_34; /* NetBSD AC'97 default */ 362 1.1 reinoud 363 1.52 andvar /* XXX this prolly is not necessary unless split XXX */ 364 1.1 reinoud value &= ~ATI_REG_CMD_INTERLEAVE_SPDF; 365 1.4 simonb if (params->precision <= 16) 366 1.4 simonb value |= ATI_REG_CMD_INTERLEAVE_SPDF; 367 1.1 reinoud bus_space_write_4(iot, ioh, ATI_REG_CMD, value); 368 1.3 kent } 369 1.1 reinoud 370 1.1 reinoud return 0; 371 1.1 reinoud } 372 1.1 reinoud 373 1.1 reinoud 374 1.1 reinoud /* set audio properties in desired setting */ 375 1.9 thorpej static int 376 1.46 isaki auixp_set_format(void *hdl, int setmode, 377 1.46 isaki const audio_params_t *play, const audio_params_t *rec, 378 1.46 isaki audio_filter_reg_t *pfil, audio_filter_reg_t *rfil) 379 1.3 kent { 380 1.3 kent struct auixp_codec *co; 381 1.3 kent struct auixp_softc *sc; 382 1.46 isaki const audio_params_t *params; 383 1.1 reinoud int mode, index; 384 1.1 reinoud 385 1.1 reinoud /* 386 1.1 reinoud * In current NetBSD AC'97 implementation, SPDF is linked to channel 3 387 1.1 reinoud * and 4 i.e. stereo output. 388 1.1 reinoud */ 389 1.1 reinoud 390 1.3 kent co = (struct auixp_codec *) hdl; 391 1.3 kent sc = co->sc; 392 1.1 reinoud for (mode = AUMODE_RECORD; mode != -1; 393 1.1 reinoud mode = (mode == AUMODE_RECORD) ? AUMODE_PLAY : -1) { 394 1.1 reinoud if ((setmode & mode) == 0) 395 1.1 reinoud continue; 396 1.1 reinoud 397 1.46 isaki params = (mode == AUMODE_PLAY) ? play : rec; 398 1.4 simonb if (params == NULL) 399 1.4 simonb continue; 400 1.1 reinoud 401 1.46 isaki index = audio_indexof_format(sc->sc_formats, AUIXP_NFORMATS, 402 1.46 isaki mode, params); 403 1.1 reinoud 404 1.1 reinoud /* if variable speed and we can't set the desired rate, fail */ 405 1.1 reinoud if ((sc->sc_formats[index].frequency_type != 1) && 406 1.4 simonb auixp_set_rate(co, mode, params->sample_rate)) 407 1.4 simonb return EINVAL; 408 1.1 reinoud 409 1.1 reinoud /* preserve the settings */ 410 1.4 simonb if (mode == AUMODE_PLAY) 411 1.4 simonb sc->sc_play_params = *params; 412 1.4 simonb if (mode == AUMODE_RECORD) 413 1.4 simonb sc->sc_rec_params = *params; 414 1.1 reinoud } 415 1.1 reinoud 416 1.3 kent return 0; 417 1.1 reinoud } 418 1.1 reinoud 419 1.1 reinoud 420 1.1 reinoud /* called to translate a requested blocksize to a hw-possible one */ 421 1.9 thorpej static int 422 1.21 christos auixp_round_blocksize(void *hdl, int bs, int mode, 423 1.21 christos const audio_params_t *param) 424 1.3 kent { 425 1.1 reinoud 426 1.1 reinoud /* 256 kb possible */ 427 1.49 isaki if (bs > 0x10000) 428 1.4 simonb bs = 0x10000; /* 64 kb max */ 429 1.49 isaki bs = rounddown(bs, param->channels * param->precision / NBBY); 430 1.1 reinoud 431 1.49 isaki return bs; 432 1.1 reinoud } 433 1.1 reinoud 434 1.1 reinoud 435 1.1 reinoud /* 436 1.1 reinoud * allocate dma capable memory and record its information for later retrieval 437 1.1 reinoud * when we program the dma chain itself. The trigger routines passes on the 438 1.1 reinoud * kernel virtual address we return here as a reference to the mapping. 439 1.1 reinoud */ 440 1.9 thorpej static void * 441 1.35 jmcneill auixp_malloc(void *hdl, int direction, size_t size) 442 1.3 kent { 443 1.3 kent struct auixp_codec *co; 444 1.3 kent struct auixp_softc *sc; 445 1.1 reinoud struct auixp_dma *dma; 446 1.1 reinoud int error; 447 1.1 reinoud 448 1.3 kent co = (struct auixp_codec *) hdl; 449 1.3 kent sc = co->sc; 450 1.1 reinoud /* get us a auixp_dma structure */ 451 1.35 jmcneill dma = kmem_alloc(sizeof(*dma), KM_SLEEP); 452 1.1 reinoud 453 1.1 reinoud /* get us a dma buffer itself */ 454 1.1 reinoud error = auixp_allocmem(sc, size, 16, dma); 455 1.1 reinoud if (error) { 456 1.35 jmcneill kmem_free(dma, sizeof(*dma)); 457 1.39 chs aprint_error_dev(sc->sc_dev, "auixp_malloc: not enough memory\n"); 458 1.1 reinoud 459 1.1 reinoud return NULL; 460 1.1 reinoud } 461 1.1 reinoud SLIST_INSERT_HEAD(&sc->sc_dma_list, dma, dma_chain); 462 1.1 reinoud 463 1.46 isaki DPRINTF(("auixp_malloc: returning kern %p, hw 0x%08x for %zd bytes " 464 1.4 simonb "in %d segs\n", KERNADDR(dma), (uint32_t) DMAADDR(dma), dma->size, 465 1.4 simonb dma->nsegs) 466 1.1 reinoud ); 467 1.1 reinoud 468 1.3 kent return KERNADDR(dma); 469 1.1 reinoud } 470 1.1 reinoud 471 1.1 reinoud 472 1.1 reinoud /* 473 1.1 reinoud * free and release dma capable memory we allocated before and remove its 474 1.1 reinoud * recording 475 1.1 reinoud */ 476 1.9 thorpej static void 477 1.35 jmcneill auixp_free(void *hdl, void *addr, size_t size) 478 1.3 kent { 479 1.3 kent struct auixp_codec *co; 480 1.3 kent struct auixp_softc *sc; 481 1.1 reinoud struct auixp_dma *dma; 482 1.1 reinoud 483 1.3 kent co = (struct auixp_codec *) hdl; 484 1.3 kent sc = co->sc; 485 1.1 reinoud SLIST_FOREACH(dma, &sc->sc_dma_list, dma_chain) { 486 1.1 reinoud if (KERNADDR(dma) == addr) { 487 1.4 simonb SLIST_REMOVE(&sc->sc_dma_list, dma, auixp_dma, 488 1.4 simonb dma_chain); 489 1.9 thorpej auixp_freemem(sc, dma); 490 1.35 jmcneill kmem_free(dma, sizeof(*dma)); 491 1.1 reinoud return; 492 1.3 kent } 493 1.3 kent } 494 1.1 reinoud } 495 1.1 reinoud 496 1.1 reinoud 497 1.9 thorpej static int 498 1.21 christos auixp_getdev(void *hdl, struct audio_device *ret) 499 1.3 kent { 500 1.3 kent 501 1.1 reinoud *ret = auixp_device; 502 1.3 kent return 0; 503 1.1 reinoud } 504 1.1 reinoud 505 1.1 reinoud 506 1.1 reinoud /* pass request to AC'97 codec code */ 507 1.9 thorpej static int 508 1.3 kent auixp_set_port(void *hdl, mixer_ctrl_t *mc) 509 1.3 kent { 510 1.3 kent struct auixp_codec *co; 511 1.1 reinoud 512 1.3 kent co = (struct auixp_codec *) hdl; 513 1.1 reinoud return co->codec_if->vtbl->mixer_set_port(co->codec_if, mc); 514 1.1 reinoud } 515 1.1 reinoud 516 1.1 reinoud 517 1.1 reinoud /* pass request to AC'97 codec code */ 518 1.9 thorpej static int 519 1.3 kent auixp_get_port(void *hdl, mixer_ctrl_t *mc) 520 1.3 kent { 521 1.3 kent struct auixp_codec *co; 522 1.1 reinoud 523 1.3 kent co = (struct auixp_codec *) hdl; 524 1.1 reinoud return co->codec_if->vtbl->mixer_get_port(co->codec_if, mc); 525 1.1 reinoud } 526 1.1 reinoud 527 1.1 reinoud /* pass request to AC'97 codec code */ 528 1.9 thorpej static int 529 1.3 kent auixp_query_devinfo(void *hdl, mixer_devinfo_t *di) 530 1.3 kent { 531 1.3 kent struct auixp_codec *co; 532 1.1 reinoud 533 1.3 kent co = (struct auixp_codec *) hdl; 534 1.1 reinoud return co->codec_if->vtbl->query_devinfo(co->codec_if, di); 535 1.1 reinoud } 536 1.1 reinoud 537 1.1 reinoud 538 1.9 thorpej static size_t 539 1.21 christos auixp_round_buffersize(void *hdl, int direction, 540 1.20 christos size_t bufsize) 541 1.3 kent { 542 1.4 simonb 543 1.1 reinoud /* XXX force maximum? i.e. 256 kb? */ 544 1.1 reinoud return bufsize; 545 1.1 reinoud } 546 1.1 reinoud 547 1.1 reinoud 548 1.9 thorpej static int 549 1.21 christos auixp_get_props(void *hdl) 550 1.3 kent { 551 1.4 simonb 552 1.47 isaki return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE | 553 1.47 isaki AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX; 554 1.1 reinoud } 555 1.1 reinoud 556 1.1 reinoud 557 1.1 reinoud /* 558 1.1 reinoud * A dma descriptor has dma->nsegs segments defined in dma->segs set up when 559 1.1 reinoud * we claimed the memory. 560 1.1 reinoud * 561 1.1 reinoud * Due to our demand for one contiguous DMA area, we only have one segment. A 562 1.1 reinoud * c_dma structure is about 3 kb for the 256 entries we maximally program 563 1.1 reinoud * -arbitrary limit AFAIK- so all is most likely to be in one segment/page 564 1.1 reinoud * anyway. 565 1.1 reinoud * 566 1.1 reinoud * XXX ought to implement fragmented dma area XXX 567 1.1 reinoud * 568 1.1 reinoud * Note that _v variables depict kernel virtual addresses, _p variables depict 569 1.1 reinoud * physical addresses. 570 1.1 reinoud */ 571 1.9 thorpej static void 572 1.3 kent auixp_link_daisychain(struct auixp_softc *sc, 573 1.1 reinoud struct auixp_dma *c_dma, struct auixp_dma *s_dma, 574 1.1 reinoud int blksize, int blocks) 575 1.1 reinoud { 576 1.1 reinoud atiixp_dma_desc_t *caddr_v, *next_caddr_v; 577 1.1 reinoud uint32_t caddr_p, next_caddr_p, saddr_p; 578 1.1 reinoud int i; 579 1.1 reinoud 580 1.1 reinoud /* just make sure we are not changing when its running */ 581 1.1 reinoud auixp_disable_dma(sc, c_dma); 582 1.1 reinoud 583 1.1 reinoud /* setup dma chain start addresses */ 584 1.1 reinoud caddr_v = KERNADDR(c_dma); 585 1.1 reinoud caddr_p = DMAADDR(c_dma); 586 1.1 reinoud saddr_p = DMAADDR(s_dma); 587 1.1 reinoud 588 1.1 reinoud /* program the requested number of blocks */ 589 1.1 reinoud for (i = 0; i < blocks; i++) { 590 1.1 reinoud /* clear the block just in case */ 591 1.30 cegger memset(caddr_v, 0, sizeof(atiixp_dma_desc_t)); 592 1.1 reinoud 593 1.1 reinoud /* round robin the chain dma addresses for its successor */ 594 1.1 reinoud next_caddr_v = caddr_v + 1; 595 1.1 reinoud next_caddr_p = caddr_p + sizeof(atiixp_dma_desc_t); 596 1.1 reinoud 597 1.1 reinoud if (i == blocks-1) { 598 1.1 reinoud next_caddr_v = KERNADDR(c_dma); 599 1.1 reinoud next_caddr_p = DMAADDR(c_dma); 600 1.3 kent } 601 1.1 reinoud 602 1.1 reinoud /* fill in the hardware dma chain descriptor in little-endian */ 603 1.1 reinoud caddr_v->addr = htole32(saddr_p); 604 1.1 reinoud caddr_v->status = htole16(0); 605 1.4 simonb caddr_v->size = htole16((blksize >> 2)); /* in dwords (!!!) */ 606 1.1 reinoud caddr_v->next = htole32(next_caddr_p); 607 1.1 reinoud 608 1.1 reinoud /* advance slot */ 609 1.4 simonb saddr_p += blksize; /* XXX assuming contiguous XXX */ 610 1.1 reinoud caddr_v = next_caddr_v; 611 1.1 reinoud caddr_p = next_caddr_p; 612 1.3 kent } 613 1.1 reinoud } 614 1.1 reinoud 615 1.1 reinoud 616 1.9 thorpej static int 617 1.3 kent auixp_allocate_dma_chain(struct auixp_softc *sc, struct auixp_dma **dmap) 618 1.3 kent { 619 1.1 reinoud struct auixp_dma *dma; 620 1.1 reinoud int error; 621 1.1 reinoud 622 1.1 reinoud /* allocate keeper of dma area */ 623 1.1 reinoud *dmap = NULL; 624 1.35 jmcneill dma = kmem_zalloc(sizeof(struct auixp_dma), KM_SLEEP); 625 1.1 reinoud 626 1.1 reinoud /* allocate for daisychain of IXP hardware-dma descriptors */ 627 1.4 simonb error = auixp_allocmem(sc, DMA_DESC_CHAIN * sizeof(atiixp_dma_desc_t), 628 1.4 simonb 16, dma); 629 1.1 reinoud if (error) { 630 1.39 chs aprint_error_dev(sc->sc_dev, "can't malloc dma descriptor chain\n"); 631 1.35 jmcneill kmem_free(dma, sizeof(*dma)); 632 1.1 reinoud return ENOMEM; 633 1.3 kent } 634 1.1 reinoud 635 1.1 reinoud /* return info and initialise structure */ 636 1.1 reinoud dma->intr = NULL; 637 1.1 reinoud dma->intrarg = NULL; 638 1.1 reinoud 639 1.1 reinoud *dmap = dma; 640 1.1 reinoud return 0; 641 1.1 reinoud } 642 1.1 reinoud 643 1.1 reinoud 644 1.41 snj /* program dma chain in its link address descriptor */ 645 1.9 thorpej static void 646 1.3 kent auixp_program_dma_chain(struct auixp_softc *sc, struct auixp_dma *dma) 647 1.3 kent { 648 1.3 kent bus_space_tag_t iot; 649 1.3 kent bus_space_handle_t ioh; 650 1.1 reinoud uint32_t value; 651 1.1 reinoud 652 1.3 kent iot = sc->sc_iot; 653 1.3 kent ioh = sc->sc_ioh; 654 1.1 reinoud /* get hardware start address of DMA chain and set valid-flag in it */ 655 1.23 msaitoh /* XXX always at start? XXX */ 656 1.1 reinoud value = DMAADDR(dma); 657 1.1 reinoud value = value | ATI_REG_LINKPTR_EN; 658 1.1 reinoud 659 1.1 reinoud /* reset linkpointer */ 660 1.1 reinoud bus_space_write_4(iot, ioh, dma->linkptr, 0); 661 1.1 reinoud 662 1.1 reinoud /* reset this DMA engine */ 663 1.1 reinoud auixp_disable_dma(sc, dma); 664 1.1 reinoud auixp_enable_dma(sc, dma); 665 1.1 reinoud 666 1.1 reinoud /* program new DMA linkpointer */ 667 1.1 reinoud bus_space_write_4(iot, ioh, dma->linkptr, value); 668 1.1 reinoud } 669 1.1 reinoud 670 1.1 reinoud 671 1.1 reinoud /* called from interrupt code to signal end of one dma-slot */ 672 1.9 thorpej static void 673 1.3 kent auixp_dma_update(struct auixp_softc *sc, struct auixp_dma *dma) 674 1.3 kent { 675 1.4 simonb 676 1.1 reinoud /* be very paranoid */ 677 1.4 simonb if (!dma) 678 1.39 chs panic("%s: update: dma = NULL", device_xname(sc->sc_dev)); 679 1.4 simonb if (!dma->intr) 680 1.39 chs panic("%s: update: dma->intr = NULL", device_xname(sc->sc_dev)); 681 1.1 reinoud 682 1.1 reinoud /* request more input from upper layer */ 683 1.1 reinoud (*dma->intr)(dma->intrarg); 684 1.1 reinoud } 685 1.1 reinoud 686 1.1 reinoud 687 1.1 reinoud /* 688 1.1 reinoud * The magic `busbusy' bit that needs to be set when dma is active; allowing 689 1.1 reinoud * busmastering? 690 1.1 reinoud */ 691 1.9 thorpej static void 692 1.3 kent auixp_update_busbusy(struct auixp_softc *sc) 693 1.3 kent { 694 1.3 kent bus_space_tag_t iot; 695 1.3 kent bus_space_handle_t ioh; 696 1.1 reinoud uint32_t value; 697 1.1 reinoud int running; 698 1.1 reinoud 699 1.3 kent iot = sc->sc_iot; 700 1.3 kent ioh = sc->sc_ioh; 701 1.1 reinoud /* set bus-busy flag when either recording or playing is performed */ 702 1.1 reinoud value = bus_space_read_4(iot, ioh, ATI_REG_IER); 703 1.1 reinoud value &= ~ATI_REG_IER_SET_BUS_BUSY; 704 1.1 reinoud 705 1.1 reinoud running = ((sc->sc_output_dma->running) || (sc->sc_input_dma->running)); 706 1.4 simonb if (running) 707 1.4 simonb value |= ATI_REG_IER_SET_BUS_BUSY; 708 1.1 reinoud 709 1.1 reinoud bus_space_write_4(iot, ioh, ATI_REG_IER, value); 710 1.1 reinoud 711 1.1 reinoud } 712 1.1 reinoud 713 1.1 reinoud 714 1.1 reinoud /* 715 1.1 reinoud * Called from upper audio layer to request playing audio, only called once; 716 1.1 reinoud * audio is refilled by calling the intr() function when space is available 717 1.1 reinoud * again. 718 1.1 reinoud */ 719 1.53 andvar /* XXX almost literally a copy of trigger-input; could be factorised XXX */ 720 1.9 thorpej static int 721 1.3 kent auixp_trigger_output(void *hdl, void *start, void *end, int blksize, 722 1.21 christos void (*intr)(void *), void *intrarg, const audio_params_t *param) 723 1.3 kent { 724 1.3 kent struct auixp_codec *co; 725 1.3 kent struct auixp_softc *sc; 726 1.3 kent struct auixp_dma *chain_dma; 727 1.1 reinoud struct auixp_dma *sound_dma; 728 1.1 reinoud uint32_t blocks; 729 1.1 reinoud 730 1.3 kent co = (struct auixp_codec *) hdl; 731 1.3 kent sc = co->sc; 732 1.3 kent chain_dma = sc->sc_output_dma; 733 1.1 reinoud /* add functions to call back */ 734 1.1 reinoud chain_dma->intr = intr; 735 1.1 reinoud chain_dma->intrarg = intrarg; 736 1.1 reinoud 737 1.1 reinoud /* 738 1.1 reinoud * Program output DMA chain with blocks from [start...end] with 739 1.1 reinoud * blksize fragments. 740 1.1 reinoud * 741 1.1 reinoud * NOTE, we can assume its in one block since we asked for it to be in 742 1.1 reinoud * one contiguous blob; XXX change this? XXX 743 1.1 reinoud */ 744 1.22 christos blocks = (size_t) (((char *) end) - ((char *) start)) / blksize; 745 1.1 reinoud 746 1.1 reinoud /* lookup `start' address in our list of DMA area's */ 747 1.1 reinoud SLIST_FOREACH(sound_dma, &sc->sc_dma_list, dma_chain) { 748 1.4 simonb if (KERNADDR(sound_dma) == start) 749 1.4 simonb break; 750 1.3 kent } 751 1.1 reinoud 752 1.1 reinoud /* not ours ? then bail out */ 753 1.1 reinoud if (!sound_dma) { 754 1.5 fvdl printf("%s: auixp_trigger_output: bad sound addr %p\n", 755 1.39 chs device_xname(sc->sc_dev), start); 756 1.1 reinoud return EINVAL; 757 1.1 reinoud } 758 1.1 reinoud 759 1.1 reinoud /* link round-robin daisychain and program hardware */ 760 1.1 reinoud auixp_link_daisychain(sc, chain_dma, sound_dma, blksize, blocks); 761 1.1 reinoud auixp_program_dma_chain(sc, chain_dma); 762 1.1 reinoud 763 1.1 reinoud /* mark we are now able to run now */ 764 1.1 reinoud chain_dma->running = 1; 765 1.1 reinoud 766 1.1 reinoud /* update bus-flags; XXX programs more flags XXX */ 767 1.1 reinoud auixp_update_busbusy(sc); 768 1.1 reinoud 769 1.1 reinoud /* callbacks happen in interrupt routine */ 770 1.1 reinoud return 0; 771 1.1 reinoud } 772 1.1 reinoud 773 1.1 reinoud 774 1.41 snj /* halt output of audio, just disable its dma and update bus state */ 775 1.9 thorpej static int 776 1.3 kent auixp_halt_output(void *hdl) 777 1.3 kent { 778 1.3 kent struct auixp_codec *co; 779 1.3 kent struct auixp_softc *sc; 780 1.3 kent struct auixp_dma *dma; 781 1.3 kent 782 1.3 kent co = (struct auixp_codec *) hdl; 783 1.3 kent sc = co->sc; 784 1.3 kent dma = sc->sc_output_dma; 785 1.1 reinoud auixp_disable_dma(sc, dma); 786 1.1 reinoud 787 1.1 reinoud dma->running = 0; 788 1.1 reinoud auixp_update_busbusy(sc); 789 1.1 reinoud 790 1.1 reinoud return 0; 791 1.1 reinoud } 792 1.1 reinoud 793 1.1 reinoud 794 1.53 andvar /* XXX almost literally a copy of trigger-output; could be factorised XXX */ 795 1.9 thorpej static int 796 1.3 kent auixp_trigger_input(void *hdl, void *start, void *end, int blksize, 797 1.21 christos void (*intr)(void *), void *intrarg, const audio_params_t *param) 798 1.3 kent { 799 1.3 kent struct auixp_codec *co; 800 1.3 kent struct auixp_softc *sc; 801 1.3 kent struct auixp_dma *chain_dma; 802 1.1 reinoud struct auixp_dma *sound_dma; 803 1.1 reinoud uint32_t blocks; 804 1.1 reinoud 805 1.3 kent co = (struct auixp_codec *) hdl; 806 1.3 kent sc = co->sc; 807 1.3 kent chain_dma = sc->sc_input_dma; 808 1.1 reinoud /* add functions to call back */ 809 1.1 reinoud chain_dma->intr = intr; 810 1.1 reinoud chain_dma->intrarg = intrarg; 811 1.1 reinoud 812 1.1 reinoud /* 813 1.1 reinoud * Program output DMA chain with blocks from [start...end] with 814 1.1 reinoud * blksize fragments. 815 1.1 reinoud * 816 1.1 reinoud * NOTE, we can assume its in one block since we asked for it to be in 817 1.1 reinoud * one contiguous blob; XXX change this? XXX 818 1.1 reinoud */ 819 1.22 christos blocks = (size_t) (((char *) end) - ((char *) start)) / blksize; 820 1.1 reinoud 821 1.1 reinoud /* lookup `start' address in our list of DMA area's */ 822 1.1 reinoud SLIST_FOREACH(sound_dma, &sc->sc_dma_list, dma_chain) { 823 1.4 simonb if (KERNADDR(sound_dma) == start) 824 1.4 simonb break; 825 1.3 kent } 826 1.1 reinoud 827 1.1 reinoud /* not ours ? then bail out */ 828 1.1 reinoud if (!sound_dma) { 829 1.5 fvdl printf("%s: auixp_trigger_input: bad sound addr %p\n", 830 1.39 chs device_xname(sc->sc_dev), start); 831 1.1 reinoud return EINVAL; 832 1.1 reinoud } 833 1.1 reinoud 834 1.1 reinoud /* link round-robin daisychain and program hardware */ 835 1.1 reinoud auixp_link_daisychain(sc, chain_dma, sound_dma, blksize, blocks); 836 1.1 reinoud auixp_program_dma_chain(sc, chain_dma); 837 1.1 reinoud 838 1.1 reinoud /* mark we are now able to run now */ 839 1.1 reinoud chain_dma->running = 1; 840 1.1 reinoud 841 1.1 reinoud /* update bus-flags; XXX programs more flags XXX */ 842 1.1 reinoud auixp_update_busbusy(sc); 843 1.1 reinoud 844 1.1 reinoud /* callbacks happen in interrupt routine */ 845 1.1 reinoud return 0; 846 1.1 reinoud } 847 1.1 reinoud 848 1.1 reinoud 849 1.41 snj /* halt sampling audio, just disable its dma and update bus state */ 850 1.9 thorpej static int 851 1.3 kent auixp_halt_input(void *hdl) 852 1.3 kent { 853 1.3 kent struct auixp_codec *co; 854 1.3 kent struct auixp_softc *sc; 855 1.3 kent struct auixp_dma *dma; 856 1.3 kent 857 1.3 kent co = (struct auixp_codec *) hdl; 858 1.3 kent sc = co->sc; 859 1.11 reinoud dma = sc->sc_input_dma; 860 1.1 reinoud auixp_disable_dma(sc, dma); 861 1.1 reinoud 862 1.1 reinoud dma->running = 0; 863 1.1 reinoud auixp_update_busbusy(sc); 864 1.1 reinoud 865 1.1 reinoud return 0; 866 1.1 reinoud } 867 1.1 reinoud 868 1.1 reinoud 869 1.1 reinoud /* 870 1.1 reinoud * IXP audio interrupt handler 871 1.1 reinoud * 872 1.1 reinoud * note that we return the number of bits handled; the return value is not 873 1.53 andvar * documented but I saw it implemented in other drivers. Prolly returning a 874 1.53 andvar * value > 0 means "I've dealt with it" 875 1.1 reinoud * 876 1.1 reinoud */ 877 1.9 thorpej static int 878 1.3 kent auixp_intr(void *softc) 879 1.3 kent { 880 1.3 kent struct auixp_softc *sc; 881 1.3 kent bus_space_tag_t iot; 882 1.3 kent bus_space_handle_t ioh; 883 1.1 reinoud uint32_t status, enable, detected_codecs; 884 1.3 kent int ret; 885 1.1 reinoud 886 1.3 kent sc = softc; 887 1.35 jmcneill mutex_spin_enter(&sc->sc_intr_lock); 888 1.35 jmcneill 889 1.3 kent iot = sc->sc_iot; 890 1.3 kent ioh = sc->sc_ioh; 891 1.3 kent ret = 0; 892 1.1 reinoud /* get status from the interrupt status register */ 893 1.1 reinoud status = bus_space_read_4(iot, ioh, ATI_REG_ISR); 894 1.1 reinoud 895 1.35 jmcneill if (status == 0) { 896 1.35 jmcneill mutex_spin_exit(&sc->sc_intr_lock); 897 1.5 fvdl return 0; 898 1.35 jmcneill } 899 1.1 reinoud 900 1.39 chs DPRINTF(("%s: (status = %x)\n", device_xname(sc->sc_dev), status)); 901 1.1 reinoud 902 1.1 reinoud /* check DMA UPDATE flags for input & output */ 903 1.1 reinoud if (status & ATI_REG_ISR_IN_STATUS) { 904 1.1 reinoud ret++; DPRINTF(("IN_STATUS\n")); 905 1.1 reinoud auixp_dma_update(sc, sc->sc_input_dma); 906 1.3 kent } 907 1.1 reinoud if (status & ATI_REG_ISR_OUT_STATUS) { 908 1.1 reinoud ret++; DPRINTF(("OUT_STATUS\n")); 909 1.1 reinoud auixp_dma_update(sc, sc->sc_output_dma); 910 1.3 kent } 911 1.1 reinoud 912 1.1 reinoud /* XXX XRUN flags not used/needed yet; should i implement it? XXX */ 913 1.1 reinoud /* acknowledge the interrupts nevertheless */ 914 1.1 reinoud if (status & ATI_REG_ISR_IN_XRUN) { 915 1.1 reinoud ret++; DPRINTF(("IN_XRUN\n")); 916 1.1 reinoud /* auixp_dma_xrun(sc, sc->sc_input_dma); */ 917 1.3 kent } 918 1.1 reinoud if (status & ATI_REG_ISR_OUT_XRUN) { 919 1.1 reinoud ret++; DPRINTF(("OUT_XRUN\n")); 920 1.1 reinoud /* auixp_dma_xrun(sc, sc->sc_output_dma); */ 921 1.3 kent } 922 1.1 reinoud 923 1.1 reinoud /* check if we are looking for codec detection */ 924 1.1 reinoud if (status & CODEC_CHECK_BITS) { 925 1.1 reinoud ret++; 926 1.1 reinoud /* mark missing codecs as not ready */ 927 1.1 reinoud detected_codecs = status & CODEC_CHECK_BITS; 928 1.1 reinoud sc->sc_codec_not_ready_bits |= detected_codecs; 929 1.1 reinoud 930 1.29 msaitoh /* disable detected interrupt sources */ 931 1.1 reinoud enable = bus_space_read_4(iot, ioh, ATI_REG_IER); 932 1.1 reinoud enable &= ~detected_codecs; 933 1.1 reinoud bus_space_write_4(iot, ioh, ATI_REG_IER, enable); 934 1.3 kent } 935 1.1 reinoud 936 1.1 reinoud /* acknowledge interrupt sources */ 937 1.1 reinoud bus_space_write_4(iot, ioh, ATI_REG_ISR, status); 938 1.3 kent 939 1.35 jmcneill mutex_spin_exit(&sc->sc_intr_lock); 940 1.1 reinoud return ret; 941 1.1 reinoud } 942 1.1 reinoud 943 1.1 reinoud 944 1.1 reinoud /* allocate memory for dma purposes; on failure of any of the steps, roll back */ 945 1.9 thorpej static int 946 1.3 kent auixp_allocmem(struct auixp_softc *sc, size_t size, 947 1.3 kent size_t align, struct auixp_dma *dma) 948 1.3 kent { 949 1.1 reinoud int error; 950 1.1 reinoud 951 1.1 reinoud /* remember size */ 952 1.1 reinoud dma->size = size; 953 1.1 reinoud 954 1.1 reinoud /* allocate DMA safe memory but in just one segment for now :( */ 955 1.1 reinoud error = bus_dmamem_alloc(sc->sc_dmat, dma->size, align, 0, 956 1.4 simonb dma->segs, sizeof(dma->segs) / sizeof(dma->segs[0]), &dma->nsegs, 957 1.35 jmcneill BUS_DMA_WAITOK); 958 1.4 simonb if (error) 959 1.4 simonb return error; 960 1.1 reinoud 961 1.1 reinoud /* 962 1.1 reinoud * map allocated memory into kernel virtual address space and keep it 963 1.1 reinoud * coherent with the CPU. 964 1.1 reinoud */ 965 1.1 reinoud error = bus_dmamem_map(sc->sc_dmat, dma->segs, dma->nsegs, dma->size, 966 1.35 jmcneill &dma->addr, BUS_DMA_WAITOK | BUS_DMA_COHERENT); 967 1.4 simonb if (error) 968 1.4 simonb goto free; 969 1.1 reinoud 970 1.1 reinoud /* allocate associated dma handle and initialize it. */ 971 1.1 reinoud error = bus_dmamap_create(sc->sc_dmat, dma->size, 1, dma->size, 0, 972 1.35 jmcneill BUS_DMA_WAITOK, &dma->map); 973 1.4 simonb if (error) 974 1.4 simonb goto unmap; 975 1.1 reinoud 976 1.1 reinoud /* 977 1.1 reinoud * load the dma handle with mappings for a dma transfer; all pages 978 1.1 reinoud * need to be wired. 979 1.1 reinoud */ 980 1.1 reinoud error = bus_dmamap_load(sc->sc_dmat, dma->map, dma->addr, dma->size, NULL, 981 1.35 jmcneill BUS_DMA_WAITOK); 982 1.4 simonb if (error) 983 1.4 simonb goto destroy; 984 1.1 reinoud 985 1.3 kent return 0; 986 1.1 reinoud 987 1.1 reinoud destroy: 988 1.1 reinoud bus_dmamap_destroy(sc->sc_dmat, dma->map); 989 1.1 reinoud unmap: 990 1.1 reinoud bus_dmamem_unmap(sc->sc_dmat, dma->addr, dma->size); 991 1.1 reinoud free: 992 1.1 reinoud bus_dmamem_free(sc->sc_dmat, dma->segs, dma->nsegs); 993 1.1 reinoud 994 1.3 kent return error; 995 1.1 reinoud } 996 1.1 reinoud 997 1.1 reinoud 998 1.1 reinoud /* undo dma mapping and release memory allocated */ 999 1.9 thorpej static int 1000 1.3 kent auixp_freemem(struct auixp_softc *sc, struct auixp_dma *p) 1001 1.3 kent { 1002 1.1 reinoud 1003 1.1 reinoud bus_dmamap_unload(sc->sc_dmat, p->map); 1004 1.1 reinoud bus_dmamap_destroy(sc->sc_dmat, p->map); 1005 1.1 reinoud bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size); 1006 1.1 reinoud bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs); 1007 1.1 reinoud 1008 1.3 kent return 0; 1009 1.1 reinoud } 1010 1.1 reinoud 1011 1.1 reinoud 1012 1.1 reinoud /* 1013 1.1 reinoud * Attachment section 1014 1.1 reinoud */ 1015 1.1 reinoud 1016 1.1 reinoud /* Is it my hardware? */ 1017 1.9 thorpej static int 1018 1.31 cegger auixp_match(device_t dev, cfdata_t match, void *aux) 1019 1.3 kent { 1020 1.3 kent struct pci_attach_args *pa; 1021 1.1 reinoud 1022 1.3 kent pa = (struct pci_attach_args *)aux; 1023 1.1 reinoud switch(PCI_VENDOR(pa->pa_id)) { 1024 1.1 reinoud case PCI_VENDOR_ATI: 1025 1.1 reinoud switch(PCI_PRODUCT(pa->pa_id)) { 1026 1.1 reinoud case PCI_PRODUCT_ATI_IXP_AUDIO_200: 1027 1.1 reinoud case PCI_PRODUCT_ATI_IXP_AUDIO_300: 1028 1.1 reinoud case PCI_PRODUCT_ATI_IXP_AUDIO_400: 1029 1.3 kent return 1; 1030 1.1 reinoud } 1031 1.1 reinoud } 1032 1.1 reinoud 1033 1.3 kent return 0; 1034 1.1 reinoud } 1035 1.1 reinoud 1036 1.1 reinoud 1037 1.1 reinoud /* it is... now hook up and set up the resources we need */ 1038 1.9 thorpej static void 1039 1.27 dyoung auixp_attach(device_t parent, device_t self, void *aux) 1040 1.3 kent { 1041 1.3 kent struct auixp_softc *sc; 1042 1.3 kent struct pci_attach_args *pa; 1043 1.3 kent pcitag_t tag; 1044 1.3 kent pci_chipset_tag_t pc; 1045 1.1 reinoud pci_intr_handle_t ih; 1046 1.9 thorpej const struct auixp_card_type *card; 1047 1.1 reinoud const char *intrstr; 1048 1.1 reinoud uint32_t data; 1049 1.38 drochner int error; 1050 1.40 christos char intrbuf[PCI_INTRSTR_LEN]; 1051 1.1 reinoud 1052 1.27 dyoung sc = device_private(self); 1053 1.39 chs sc->sc_dev = self; 1054 1.3 kent pa = (struct pci_attach_args *)aux; 1055 1.3 kent tag = pa->pa_tag; 1056 1.3 kent pc = pa->pa_pc; 1057 1.1 reinoud #ifdef DEBUG_AUIXP 1058 1.3 kent static_sc = sc; 1059 1.1 reinoud #endif 1060 1.1 reinoud 1061 1.1 reinoud /* print information confirming attachment */ 1062 1.38 drochner pci_aprint_devinfo(pa, "Audio controller"); 1063 1.1 reinoud 1064 1.1 reinoud /* set up details from our set of known `cards'/chips */ 1065 1.1 reinoud for (card = auixp_card_types; card->pci_vendor_id; card++) 1066 1.1 reinoud if (PCI_VENDOR(pa->pa_id) == card->pci_vendor_id && 1067 1.1 reinoud PCI_PRODUCT(pa->pa_id) == card->pci_product_id) { 1068 1.1 reinoud sc->type = card->type; 1069 1.1 reinoud break; 1070 1.1 reinoud } 1071 1.1 reinoud 1072 1.1 reinoud /* device only has 32 bit non prefetchable memory */ 1073 1.1 reinoud /* set MEM space access and enable the card's busmastering */ 1074 1.1 reinoud data = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); 1075 1.1 reinoud data |= (PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE); 1076 1.1 reinoud pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, data); 1077 1.1 reinoud 1078 1.1 reinoud /* map memory; its not sized -> what is the size? max PCI slot size? */ 1079 1.1 reinoud if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_MEM, 0, 1080 1.1 reinoud &sc->sc_iot, &sc->sc_ioh, &sc->sc_iob, &sc->sc_ios)) { 1081 1.39 chs aprint_error_dev(sc->sc_dev, "can't map memory space\n"); 1082 1.1 reinoud return; 1083 1.1 reinoud } 1084 1.1 reinoud 1085 1.1 reinoud /* Initialize softc */ 1086 1.1 reinoud sc->sc_tag = tag; 1087 1.1 reinoud sc->sc_pct = pc; 1088 1.1 reinoud sc->sc_dmat = pa->pa_dmat; 1089 1.1 reinoud SLIST_INIT(&sc->sc_dma_list); 1090 1.1 reinoud 1091 1.1 reinoud /* get us the auixp_dma structures */ 1092 1.1 reinoud auixp_allocate_dma_chain(sc, &sc->sc_output_dma); 1093 1.1 reinoud auixp_allocate_dma_chain(sc, &sc->sc_input_dma); 1094 1.1 reinoud 1095 1.1 reinoud /* when that fails we are dead in the water */ 1096 1.4 simonb if (!sc->sc_output_dma || !sc->sc_input_dma) 1097 1.4 simonb return; 1098 1.1 reinoud 1099 1.1 reinoud #if 0 1100 1.1 reinoud /* could preliminary program DMA chain */ 1101 1.1 reinoud auixp_program_dma_chain(sc, sc->sc_output_dma); 1102 1.1 reinoud auixp_program_dma_chain(sc, sc->sc_input_dma); 1103 1.1 reinoud #endif 1104 1.1 reinoud 1105 1.1 reinoud /* map interrupt on the pci bus */ 1106 1.1 reinoud if (pci_intr_map(pa, &ih)) { 1107 1.39 chs aprint_error_dev(sc->sc_dev, "can't map interrupt\n"); 1108 1.1 reinoud return; 1109 1.1 reinoud } 1110 1.1 reinoud 1111 1.1 reinoud /* where are we connected at ? */ 1112 1.40 christos intrstr = pci_intr_string(pc, ih, intrbuf, sizeof(intrbuf)); 1113 1.1 reinoud 1114 1.35 jmcneill mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 1115 1.36 mrg mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO); 1116 1.35 jmcneill 1117 1.36 mrg /* establish interrupt routine hookup at IPL_AUDIO level */ 1118 1.44 jdolecek sc->sc_ih = pci_intr_establish_xname(pc, ih, IPL_AUDIO, auixp_intr, 1119 1.50 isaki sc, device_xname(self)); 1120 1.1 reinoud if (sc->sc_ih == NULL) { 1121 1.39 chs aprint_error_dev(sc->sc_dev, "can't establish interrupt"); 1122 1.1 reinoud if (intrstr != NULL) 1123 1.32 njoly aprint_error(" at %s", intrstr); 1124 1.32 njoly aprint_error("\n"); 1125 1.1 reinoud return; 1126 1.1 reinoud } 1127 1.39 chs aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr); 1128 1.1 reinoud 1129 1.1 reinoud /* power up chip */ 1130 1.27 dyoung if ((error = pci_activate(pa->pa_pc, pa->pa_tag, self, 1131 1.14 christos pci_activate_null)) && error != EOPNOTSUPP) { 1132 1.39 chs aprint_error_dev(sc->sc_dev, "cannot activate %d\n", 1133 1.14 christos error); 1134 1.14 christos return; 1135 1.14 christos } 1136 1.1 reinoud 1137 1.1 reinoud /* init chip */ 1138 1.1 reinoud if (auixp_init(sc) == -1) { 1139 1.42 msaitoh aprint_error_dev(sc->sc_dev, 1140 1.42 msaitoh "auixp_attach: unable to initialize the card\n"); 1141 1.1 reinoud return; 1142 1.1 reinoud } 1143 1.1 reinoud 1144 1.25 jmcneill if (!pmf_device_register(self, NULL, auixp_resume)) 1145 1.25 jmcneill aprint_error_dev(self, "couldn't establish power handler\n"); 1146 1.1 reinoud 1147 1.1 reinoud /* 1148 1.1 reinoud * delay further configuration of codecs and audio after interrupts 1149 1.1 reinoud * are enabled. 1150 1.1 reinoud */ 1151 1.1 reinoud config_interrupts(self, auixp_post_config); 1152 1.1 reinoud } 1153 1.1 reinoud 1154 1.1 reinoud 1155 1.1 reinoud /* called from autoconfigure system when interrupts are enabled */ 1156 1.9 thorpej static void 1157 1.27 dyoung auixp_post_config(device_t self) 1158 1.3 kent { 1159 1.3 kent struct auixp_softc *sc; 1160 1.1 reinoud struct auixp_codec *codec; 1161 1.1 reinoud int codec_nr; 1162 1.46 isaki int i; 1163 1.1 reinoud 1164 1.27 dyoung sc = device_private(self); 1165 1.1 reinoud /* detect the AC97 codecs */ 1166 1.1 reinoud auixp_autodetect_codecs(sc); 1167 1.1 reinoud 1168 1.1 reinoud /* setup audio translation formats : following codec0 (!) */ 1169 1.1 reinoud codec = &sc->sc_codec[0]; 1170 1.1 reinoud if (!codec->present) { 1171 1.1 reinoud /* nothing??? then invalidate all formats */ 1172 1.1 reinoud for (i = 0; i < AUIXP_NFORMATS; i++) { 1173 1.1 reinoud AUFMT_INVALIDATE(&sc->sc_formats[i]); 1174 1.3 kent } 1175 1.1 reinoud return; 1176 1.3 kent } 1177 1.1 reinoud 1178 1.1 reinoud /* copy formats and invalidate entries not suitable for codec0 */ 1179 1.1 reinoud memcpy(sc->sc_formats, auixp_formats, sizeof(auixp_formats)); 1180 1.35 jmcneill mutex_enter(&sc->sc_lock); 1181 1.1 reinoud sc->has_4ch = AC97_IS_4CH(codec->codec_if); 1182 1.1 reinoud sc->has_6ch = AC97_IS_6CH(codec->codec_if); 1183 1.1 reinoud sc->is_fixed = AC97_IS_FIXED_RATE(codec->codec_if); 1184 1.1 reinoud sc->has_spdif = AC97_HAS_SPDIF(codec->codec_if); 1185 1.35 jmcneill mutex_exit(&sc->sc_lock); 1186 1.1 reinoud 1187 1.1 reinoud for (i = 0; i < AUIXP_NFORMATS; i++) { 1188 1.1 reinoud if (sc->is_fixed) { 1189 1.1 reinoud sc->sc_formats[i].frequency_type = 1; 1190 1.1 reinoud sc->sc_formats[i].frequency[0] = 48000; 1191 1.3 kent } 1192 1.1 reinoud switch (sc->sc_formats[i].channels) { 1193 1.1 reinoud case 4 : 1194 1.4 simonb if (sc->has_4ch) 1195 1.4 simonb break; 1196 1.1 reinoud AUFMT_INVALIDATE(&sc->sc_formats[i]); 1197 1.1 reinoud break; 1198 1.1 reinoud case 6 : 1199 1.4 simonb if (sc->has_6ch) 1200 1.4 simonb break; 1201 1.1 reinoud AUFMT_INVALIDATE(&sc->sc_formats[i]); 1202 1.1 reinoud break; 1203 1.1 reinoud default : 1204 1.1 reinoud break; 1205 1.3 kent } 1206 1.1 reinoud } 1207 1.1 reinoud 1208 1.17 reinoud if (sc->has_spdif) { 1209 1.39 chs aprint_normal_dev(sc->sc_dev, "codec spdif support detected but disabled " 1210 1.28 cegger "for now\n"); 1211 1.17 reinoud sc->has_spdif = 0; 1212 1.17 reinoud } 1213 1.17 reinoud 1214 1.17 reinoud /* fill in the missing details about the dma channels. */ 1215 1.17 reinoud /* for output */ 1216 1.17 reinoud sc->sc_output_dma->linkptr = ATI_REG_OUT_DMA_LINKPTR; 1217 1.17 reinoud sc->sc_output_dma->dma_enable_bit = ATI_REG_CMD_OUT_DMA_EN | 1218 1.17 reinoud ATI_REG_CMD_SEND_EN; 1219 1.17 reinoud /* have spdif? then this too! XXX not seeing LED yet! XXX */ 1220 1.17 reinoud if (sc->has_spdif) 1221 1.17 reinoud sc->sc_output_dma->dma_enable_bit |= ATI_REG_CMD_SPDF_OUT_EN; 1222 1.17 reinoud 1223 1.17 reinoud /* and for input */ 1224 1.17 reinoud sc->sc_input_dma->linkptr = ATI_REG_IN_DMA_LINKPTR; 1225 1.17 reinoud sc->sc_input_dma->dma_enable_bit = ATI_REG_CMD_IN_DMA_EN | 1226 1.17 reinoud ATI_REG_CMD_RECEIVE_EN; 1227 1.17 reinoud 1228 1.35 jmcneill /* attach audio devices for all detected codecs */ 1229 1.35 jmcneill /* XXX wise? look at other multiple-codec able chipsets XXX */ 1230 1.35 jmcneill for (codec_nr = 0; codec_nr < ATI_IXP_CODECS; codec_nr++) { 1231 1.35 jmcneill codec = &sc->sc_codec[codec_nr]; 1232 1.35 jmcneill if (codec->present) 1233 1.39 chs audio_attach_mi(&auixp_hw_if, codec, sc->sc_dev); 1234 1.35 jmcneill } 1235 1.35 jmcneill 1236 1.1 reinoud /* done! now enable all interrupts we can service */ 1237 1.1 reinoud auixp_enable_interrupts(sc); 1238 1.3 kent } 1239 1.1 reinoud 1240 1.9 thorpej static void 1241 1.3 kent auixp_enable_interrupts(struct auixp_softc *sc) 1242 1.3 kent { 1243 1.3 kent bus_space_tag_t iot; 1244 1.3 kent bus_space_handle_t ioh; 1245 1.1 reinoud uint32_t value; 1246 1.1 reinoud 1247 1.3 kent iot = sc->sc_iot; 1248 1.3 kent ioh = sc->sc_ioh; 1249 1.35 jmcneill 1250 1.35 jmcneill mutex_spin_enter(&sc->sc_intr_lock); 1251 1.35 jmcneill 1252 1.1 reinoud /* clear all pending */ 1253 1.1 reinoud bus_space_write_4(iot, ioh, ATI_REG_ISR, 0xffffffff); 1254 1.1 reinoud 1255 1.1 reinoud /* enable all relevant interrupt sources we can handle */ 1256 1.1 reinoud value = bus_space_read_4(iot, ioh, ATI_REG_IER); 1257 1.1 reinoud 1258 1.1 reinoud value |= ATI_REG_IER_IO_STATUS_EN; 1259 1.1 reinoud #ifdef notyet 1260 1.1 reinoud value |= ATI_REG_IER_IN_XRUN_EN; 1261 1.1 reinoud value |= ATI_REG_IER_OUT_XRUN_EN; 1262 1.1 reinoud 1263 1.1 reinoud value |= ATI_REG_IER_SPDIF_XRUN_EN; 1264 1.1 reinoud value |= ATI_REG_IER_SPDF_STATUS_EN; 1265 1.1 reinoud #endif 1266 1.1 reinoud 1267 1.1 reinoud bus_space_write_4(iot, ioh, ATI_REG_IER, value); 1268 1.35 jmcneill 1269 1.35 jmcneill mutex_spin_exit(&sc->sc_intr_lock); 1270 1.1 reinoud } 1271 1.1 reinoud 1272 1.1 reinoud 1273 1.9 thorpej static void 1274 1.3 kent auixp_disable_interrupts(struct auixp_softc *sc) 1275 1.3 kent { 1276 1.3 kent bus_space_tag_t iot; 1277 1.3 kent bus_space_handle_t ioh; 1278 1.1 reinoud 1279 1.3 kent iot = sc->sc_iot; 1280 1.3 kent ioh = sc->sc_ioh; 1281 1.35 jmcneill 1282 1.35 jmcneill mutex_spin_enter(&sc->sc_intr_lock); 1283 1.35 jmcneill 1284 1.1 reinoud /* disable all interrupt sources */ 1285 1.1 reinoud bus_space_write_4(iot, ioh, ATI_REG_IER, 0); 1286 1.1 reinoud 1287 1.1 reinoud /* clear all pending */ 1288 1.1 reinoud bus_space_write_4(iot, ioh, ATI_REG_ISR, 0xffffffff); 1289 1.35 jmcneill 1290 1.35 jmcneill mutex_spin_exit(&sc->sc_intr_lock); 1291 1.1 reinoud } 1292 1.1 reinoud 1293 1.1 reinoud 1294 1.1 reinoud /* dismantle what we've set up by undoing setup */ 1295 1.9 thorpej static int 1296 1.27 dyoung auixp_detach(device_t self, int flags) 1297 1.3 kent { 1298 1.3 kent struct auixp_softc *sc; 1299 1.1 reinoud 1300 1.27 dyoung sc = device_private(self); 1301 1.1 reinoud /* XXX shouldn't we just reset the chip? XXX */ 1302 1.1 reinoud /* 1303 1.1 reinoud * should we explicitly disable interrupt generation and acknowledge 1304 1.1 reinoud * what's left on? better be safe than sorry. 1305 1.1 reinoud */ 1306 1.1 reinoud auixp_disable_interrupts(sc); 1307 1.1 reinoud 1308 1.1 reinoud /* tear down .... */ 1309 1.39 chs config_detach(sc->sc_dev, flags); /* XXX OK? XXX */ 1310 1.35 jmcneill pmf_device_deregister(self); 1311 1.1 reinoud 1312 1.1 reinoud if (sc->sc_ih != NULL) 1313 1.1 reinoud pci_intr_disestablish(sc->sc_pct, sc->sc_ih); 1314 1.1 reinoud if (sc->sc_ios) 1315 1.1 reinoud bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios); 1316 1.1 reinoud 1317 1.35 jmcneill mutex_destroy(&sc->sc_lock); 1318 1.35 jmcneill mutex_destroy(&sc->sc_intr_lock); 1319 1.1 reinoud 1320 1.3 kent return 0; 1321 1.1 reinoud } 1322 1.1 reinoud 1323 1.1 reinoud 1324 1.1 reinoud /* 1325 1.3 kent * codec handling 1326 1.1 reinoud * 1327 1.1 reinoud * IXP audio support can have upto 3 codecs! are they chained ? or 1328 1.1 reinoud * alternative outlets with the same audio feed i.e. with different mixer 1329 1.3 kent * settings? XXX does NetBSD support more than one audio codec? XXX 1330 1.1 reinoud */ 1331 1.1 reinoud 1332 1.1 reinoud 1333 1.9 thorpej static int 1334 1.3 kent auixp_attach_codec(void *aux, struct ac97_codec_if *codec_if) 1335 1.3 kent { 1336 1.3 kent struct auixp_codec *ixp_codec; 1337 1.1 reinoud 1338 1.3 kent ixp_codec = aux; 1339 1.1 reinoud ixp_codec->codec_if = codec_if; 1340 1.1 reinoud ixp_codec->present = 1; 1341 1.1 reinoud 1342 1.3 kent return 0; 1343 1.1 reinoud } 1344 1.1 reinoud 1345 1.1 reinoud 1346 1.9 thorpej static int 1347 1.3 kent auixp_read_codec(void *aux, uint8_t reg, uint16_t *result) 1348 1.3 kent { 1349 1.3 kent struct auixp_codec *co; 1350 1.3 kent struct auixp_softc *sc; 1351 1.3 kent bus_space_tag_t iot; 1352 1.3 kent bus_space_handle_t ioh; 1353 1.1 reinoud uint32_t data; 1354 1.1 reinoud int timeout; 1355 1.1 reinoud 1356 1.3 kent co = aux; 1357 1.3 kent sc = co->sc; 1358 1.3 kent iot = sc->sc_iot; 1359 1.3 kent ioh = sc->sc_ioh; 1360 1.4 simonb if (auixp_wait_for_codecs(sc, "read_codec")) 1361 1.4 simonb return 0xffff; 1362 1.1 reinoud 1363 1.1 reinoud /* build up command for reading codec register */ 1364 1.1 reinoud data = (reg << ATI_REG_PHYS_OUT_ADDR_SHIFT) | 1365 1.1 reinoud ATI_REG_PHYS_OUT_ADDR_EN | 1366 1.1 reinoud ATI_REG_PHYS_OUT_RW | 1367 1.1 reinoud co->codec_nr; 1368 1.1 reinoud 1369 1.1 reinoud bus_space_write_4(iot, ioh, ATI_REG_PHYS_OUT_ADDR, data); 1370 1.1 reinoud 1371 1.4 simonb if (auixp_wait_for_codecs(sc, "read_codec")) 1372 1.4 simonb return 0xffff; 1373 1.1 reinoud 1374 1.1 reinoud /* wait until codec info is clocked in */ 1375 1.1 reinoud timeout = 500; /* 500*2 usec -> 0.001 sec */ 1376 1.1 reinoud do { 1377 1.1 reinoud data = bus_space_read_4(iot, ioh, ATI_REG_PHYS_IN_ADDR); 1378 1.1 reinoud if (data & ATI_REG_PHYS_IN_READ_FLAG) { 1379 1.1 reinoud DPRINTF(("read ac'97 codec reg 0x%x = 0x%08x\n", 1380 1.1 reinoud reg, data >> ATI_REG_PHYS_IN_DATA_SHIFT) 1381 1.1 reinoud ); 1382 1.1 reinoud *result = data >> ATI_REG_PHYS_IN_DATA_SHIFT; 1383 1.1 reinoud return 0; 1384 1.3 kent } 1385 1.1 reinoud DELAY(2); 1386 1.1 reinoud timeout--; 1387 1.1 reinoud } while (timeout > 0); 1388 1.1 reinoud 1389 1.1 reinoud if (reg < 0x7c) 1390 1.4 simonb printf("%s: codec read timeout! (reg %x)\n", 1391 1.39 chs device_xname(sc->sc_dev), reg); 1392 1.1 reinoud 1393 1.1 reinoud return 0xffff; 1394 1.1 reinoud } 1395 1.1 reinoud 1396 1.1 reinoud 1397 1.9 thorpej static int 1398 1.3 kent auixp_write_codec(void *aux, uint8_t reg, uint16_t data) 1399 1.3 kent { 1400 1.3 kent struct auixp_codec *co; 1401 1.3 kent struct auixp_softc *sc; 1402 1.3 kent bus_space_tag_t iot; 1403 1.3 kent bus_space_handle_t ioh; 1404 1.1 reinoud uint32_t value; 1405 1.1 reinoud 1406 1.1 reinoud DPRINTF(("write ac'97 codec reg 0x%x = 0x%08x\n", reg, data)); 1407 1.3 kent co = aux; 1408 1.3 kent sc = co->sc; 1409 1.3 kent iot = sc->sc_iot; 1410 1.3 kent ioh = sc->sc_ioh; 1411 1.4 simonb if (auixp_wait_for_codecs(sc, "write_codec")) 1412 1.4 simonb return -1; 1413 1.1 reinoud 1414 1.1 reinoud /* build up command for writing codec register */ 1415 1.1 reinoud value = (((uint32_t) data) << ATI_REG_PHYS_OUT_DATA_SHIFT) | 1416 1.3 kent (((uint32_t) reg) << ATI_REG_PHYS_OUT_ADDR_SHIFT) | 1417 1.1 reinoud ATI_REG_PHYS_OUT_ADDR_EN | 1418 1.1 reinoud co->codec_nr; 1419 1.1 reinoud 1420 1.1 reinoud bus_space_write_4(iot, ioh, ATI_REG_PHYS_OUT_ADDR, value); 1421 1.1 reinoud 1422 1.1 reinoud return 0; 1423 1.1 reinoud } 1424 1.1 reinoud 1425 1.1 reinoud 1426 1.9 thorpej static int 1427 1.21 christos auixp_reset_codec(void *aux) 1428 1.3 kent { 1429 1.3 kent 1430 1.1 reinoud /* nothing to be done? */ 1431 1.1 reinoud return 0; 1432 1.1 reinoud } 1433 1.1 reinoud 1434 1.1 reinoud 1435 1.9 thorpej static enum ac97_host_flags 1436 1.3 kent auixp_flags_codec(void *aux) 1437 1.3 kent { 1438 1.3 kent struct auixp_codec *ixp_codec; 1439 1.1 reinoud 1440 1.3 kent ixp_codec = aux; 1441 1.3 kent return ixp_codec->codec_flags; 1442 1.1 reinoud } 1443 1.1 reinoud 1444 1.1 reinoud 1445 1.9 thorpej static int 1446 1.6 christos auixp_wait_for_codecs(struct auixp_softc *sc, const char *func) 1447 1.3 kent { 1448 1.3 kent bus_space_tag_t iot; 1449 1.3 kent bus_space_handle_t ioh; 1450 1.1 reinoud uint32_t value; 1451 1.1 reinoud int timeout; 1452 1.1 reinoud 1453 1.3 kent iot = sc->sc_iot; 1454 1.3 kent ioh = sc->sc_ioh; 1455 1.1 reinoud /* wait until all codec transfers are done */ 1456 1.1 reinoud timeout = 500; /* 500*2 usec -> 0.001 sec */ 1457 1.1 reinoud do { 1458 1.1 reinoud value = bus_space_read_4(iot, ioh, ATI_REG_PHYS_OUT_ADDR); 1459 1.4 simonb if ((value & ATI_REG_PHYS_OUT_ADDR_EN) == 0) 1460 1.4 simonb return 0; 1461 1.1 reinoud 1462 1.1 reinoud DELAY(2); 1463 1.1 reinoud timeout--; 1464 1.1 reinoud } while (timeout > 0); 1465 1.1 reinoud 1466 1.39 chs printf("%s: %s: timed out\n", func, device_xname(sc->sc_dev)); 1467 1.1 reinoud return -1; 1468 1.1 reinoud } 1469 1.1 reinoud 1470 1.1 reinoud 1471 1.1 reinoud 1472 1.9 thorpej static void 1473 1.3 kent auixp_autodetect_codecs(struct auixp_softc *sc) 1474 1.3 kent { 1475 1.3 kent bus_space_tag_t iot; 1476 1.3 kent bus_space_handle_t ioh; 1477 1.1 reinoud struct auixp_codec *codec; 1478 1.1 reinoud int timeout, codec_nr; 1479 1.1 reinoud 1480 1.3 kent iot = sc->sc_iot; 1481 1.3 kent ioh = sc->sc_ioh; 1482 1.1 reinoud /* ATI IXP can have upto 3 codecs; mark all codecs as not existing */ 1483 1.1 reinoud sc->sc_codec_not_ready_bits = 0; 1484 1.1 reinoud sc->sc_num_codecs = 0; 1485 1.1 reinoud 1486 1.1 reinoud /* enable all codecs to interrupt as well as the new frame interrupt */ 1487 1.1 reinoud bus_space_write_4(iot, ioh, ATI_REG_IER, CODEC_CHECK_BITS); 1488 1.1 reinoud 1489 1.1 reinoud /* wait for the interrupts to happen */ 1490 1.1 reinoud timeout = 100; /* 100.000 usec -> 0.1 sec */ 1491 1.1 reinoud 1492 1.1 reinoud while (timeout > 0) { 1493 1.1 reinoud DELAY(1000); 1494 1.4 simonb if (sc->sc_codec_not_ready_bits) 1495 1.4 simonb break; 1496 1.1 reinoud timeout--; 1497 1.3 kent } 1498 1.1 reinoud 1499 1.1 reinoud if (timeout == 0) 1500 1.5 fvdl printf("%s: WARNING: timeout during codec detection; " 1501 1.5 fvdl "codecs might be present but haven't interrupted\n", 1502 1.39 chs device_xname(sc->sc_dev)); 1503 1.1 reinoud 1504 1.1 reinoud /* disable all interrupts for now */ 1505 1.1 reinoud auixp_disable_interrupts(sc); 1506 1.1 reinoud 1507 1.1 reinoud /* Attach AC97 host interfaces */ 1508 1.1 reinoud for (codec_nr = 0; codec_nr < ATI_IXP_CODECS; codec_nr++) { 1509 1.1 reinoud codec = &sc->sc_codec[codec_nr]; 1510 1.30 cegger memset(codec, 0, sizeof(struct auixp_codec)); 1511 1.1 reinoud 1512 1.1 reinoud codec->sc = sc; 1513 1.1 reinoud codec->codec_nr = codec_nr; 1514 1.1 reinoud codec->present = 0; 1515 1.1 reinoud 1516 1.1 reinoud codec->host_if.arg = codec; 1517 1.1 reinoud codec->host_if.attach = auixp_attach_codec; 1518 1.1 reinoud codec->host_if.read = auixp_read_codec; 1519 1.1 reinoud codec->host_if.write = auixp_write_codec; 1520 1.1 reinoud codec->host_if.reset = auixp_reset_codec; 1521 1.1 reinoud codec->host_if.flags = auixp_flags_codec; 1522 1.3 kent } 1523 1.1 reinoud 1524 1.1 reinoud if (!(sc->sc_codec_not_ready_bits & ATI_REG_ISR_CODEC0_NOT_READY)) { 1525 1.1 reinoud /* codec 0 present */ 1526 1.5 fvdl DPRINTF(("auixp : YAY! codec 0 present!\n")); 1527 1.39 chs if (ac97_attach(&sc->sc_codec[0].host_if, sc->sc_dev, 1528 1.35 jmcneill &sc->sc_lock) == 0) 1529 1.3 kent sc->sc_num_codecs++; 1530 1.3 kent } 1531 1.1 reinoud 1532 1.1 reinoud if (!(sc->sc_codec_not_ready_bits & ATI_REG_ISR_CODEC1_NOT_READY)) { 1533 1.1 reinoud /* codec 1 present */ 1534 1.5 fvdl DPRINTF(("auixp : YAY! codec 1 present!\n")); 1535 1.39 chs if (ac97_attach(&sc->sc_codec[1].host_if, sc->sc_dev, 1536 1.35 jmcneill &sc->sc_lock) == 0) 1537 1.3 kent sc->sc_num_codecs++; 1538 1.3 kent } 1539 1.1 reinoud 1540 1.1 reinoud if (!(sc->sc_codec_not_ready_bits & ATI_REG_ISR_CODEC2_NOT_READY)) { 1541 1.1 reinoud /* codec 2 present */ 1542 1.5 fvdl DPRINTF(("auixp : YAY! codec 2 present!\n")); 1543 1.39 chs if (ac97_attach(&sc->sc_codec[2].host_if, sc->sc_dev, 1544 1.35 jmcneill &sc->sc_lock) == 0) 1545 1.3 kent sc->sc_num_codecs++; 1546 1.3 kent } 1547 1.1 reinoud 1548 1.1 reinoud if (sc->sc_num_codecs == 0) { 1549 1.5 fvdl printf("%s: no codecs detected or " 1550 1.5 fvdl "no codecs managed to initialise\n", 1551 1.39 chs device_xname(sc->sc_dev)); 1552 1.1 reinoud return; 1553 1.3 kent } 1554 1.1 reinoud 1555 1.3 kent } 1556 1.1 reinoud 1557 1.1 reinoud 1558 1.1 reinoud 1559 1.1 reinoud /* initialisation routines */ 1560 1.1 reinoud 1561 1.9 thorpej static void 1562 1.3 kent auixp_disable_dma(struct auixp_softc *sc, struct auixp_dma *dma) 1563 1.3 kent { 1564 1.3 kent bus_space_tag_t iot; 1565 1.3 kent bus_space_handle_t ioh; 1566 1.1 reinoud uint32_t value; 1567 1.1 reinoud 1568 1.3 kent iot = sc->sc_iot; 1569 1.3 kent ioh = sc->sc_ioh; 1570 1.51 andvar /* lets not stress the DMA engine more than necessary */ 1571 1.1 reinoud value = bus_space_read_4(iot, ioh, ATI_REG_CMD); 1572 1.1 reinoud if (value & dma->dma_enable_bit) { 1573 1.1 reinoud value &= ~dma->dma_enable_bit; 1574 1.1 reinoud bus_space_write_4(iot, ioh, ATI_REG_CMD, value); 1575 1.3 kent } 1576 1.1 reinoud } 1577 1.1 reinoud 1578 1.1 reinoud 1579 1.9 thorpej static void 1580 1.3 kent auixp_enable_dma(struct auixp_softc *sc, struct auixp_dma *dma) 1581 1.3 kent { 1582 1.3 kent bus_space_tag_t iot; 1583 1.3 kent bus_space_handle_t ioh; 1584 1.1 reinoud uint32_t value; 1585 1.1 reinoud 1586 1.3 kent iot = sc->sc_iot; 1587 1.3 kent ioh = sc->sc_ioh; 1588 1.51 andvar /* lets not stress the DMA engine more than necessary */ 1589 1.1 reinoud value = bus_space_read_4(iot, ioh, ATI_REG_CMD); 1590 1.1 reinoud if (!(value & dma->dma_enable_bit)) { 1591 1.1 reinoud value |= dma->dma_enable_bit; 1592 1.1 reinoud bus_space_write_4(iot, ioh, ATI_REG_CMD, value); 1593 1.3 kent } 1594 1.1 reinoud } 1595 1.1 reinoud 1596 1.1 reinoud 1597 1.9 thorpej static void 1598 1.3 kent auixp_reset_aclink(struct auixp_softc *sc) 1599 1.3 kent { 1600 1.7 reinoud bus_space_tag_t iot; 1601 1.7 reinoud bus_space_handle_t ioh; 1602 1.7 reinoud uint32_t value, timeout; 1603 1.7 reinoud 1604 1.7 reinoud iot = sc->sc_iot; 1605 1.7 reinoud ioh = sc->sc_ioh; 1606 1.7 reinoud 1607 1.8 reinoud /* if power is down, power it up */ 1608 1.7 reinoud value = bus_space_read_4(iot, ioh, ATI_REG_CMD); 1609 1.7 reinoud if (value & ATI_REG_CMD_POWERDOWN) { 1610 1.39 chs printf("%s: powering up\n", device_xname(sc->sc_dev)); 1611 1.8 reinoud 1612 1.8 reinoud /* explicitly enable power */ 1613 1.7 reinoud value &= ~ATI_REG_CMD_POWERDOWN; 1614 1.7 reinoud bus_space_write_4(iot, ioh, ATI_REG_CMD, value); 1615 1.7 reinoud 1616 1.8 reinoud /* have to wait at least 10 usec for it to initialise */ 1617 1.8 reinoud DELAY(20); 1618 1.7 reinoud }; 1619 1.7 reinoud 1620 1.39 chs printf("%s: soft resetting aclink\n", device_xname(sc->sc_dev)); 1621 1.8 reinoud 1622 1.8 reinoud /* perform a soft reset */ 1623 1.7 reinoud value = bus_space_read_4(iot, ioh, ATI_REG_CMD); 1624 1.7 reinoud value |= ATI_REG_CMD_AC_SOFT_RESET; 1625 1.7 reinoud bus_space_write_4(iot, ioh, ATI_REG_CMD, value); 1626 1.3 kent 1627 1.54 skrll /* need to read the CMD reg and wait approx. 10 usec to init */ 1628 1.7 reinoud value = bus_space_read_4(iot, ioh, ATI_REG_CMD); 1629 1.8 reinoud DELAY(20); 1630 1.7 reinoud 1631 1.8 reinoud /* clear soft reset flag again */ 1632 1.7 reinoud value = bus_space_read_4(iot, ioh, ATI_REG_CMD); 1633 1.7 reinoud value &= ~ATI_REG_CMD_AC_SOFT_RESET; 1634 1.7 reinoud bus_space_write_4(iot, ioh, ATI_REG_CMD, value); 1635 1.7 reinoud 1636 1.8 reinoud /* check if the ac-link is working; reset device otherwise */ 1637 1.7 reinoud timeout = 10; 1638 1.7 reinoud value = bus_space_read_4(iot, ioh, ATI_REG_CMD); 1639 1.7 reinoud while (!(value & ATI_REG_CMD_ACLINK_ACTIVE)) { 1640 1.8 reinoud printf("%s: not up; resetting aclink hardware\n", 1641 1.39 chs device_xname(sc->sc_dev)); 1642 1.8 reinoud 1643 1.8 reinoud /* dip aclink reset but keep the acsync */ 1644 1.7 reinoud value &= ~ATI_REG_CMD_AC_RESET; 1645 1.7 reinoud value |= ATI_REG_CMD_AC_SYNC; 1646 1.7 reinoud bus_space_write_4(iot, ioh, ATI_REG_CMD, value); 1647 1.7 reinoud 1648 1.8 reinoud /* need to read CMD again and wait again (clocking in issue?) */ 1649 1.7 reinoud value = bus_space_read_4(iot, ioh, ATI_REG_CMD); 1650 1.8 reinoud DELAY(20); 1651 1.7 reinoud 1652 1.8 reinoud /* assert aclink reset again */ 1653 1.7 reinoud value = bus_space_read_4(iot, ioh, ATI_REG_CMD); 1654 1.7 reinoud value |= ATI_REG_CMD_AC_RESET; 1655 1.7 reinoud bus_space_write_4(iot, ioh, ATI_REG_CMD, value); 1656 1.7 reinoud 1657 1.8 reinoud /* check if its active now */ 1658 1.8 reinoud value = bus_space_read_4(iot, ioh, ATI_REG_CMD); 1659 1.8 reinoud 1660 1.8 reinoud timeout--; 1661 1.8 reinoud if (timeout == 0) break; 1662 1.8 reinoud }; 1663 1.7 reinoud 1664 1.8 reinoud if (timeout == 0) { 1665 1.39 chs printf("%s: giving up aclink reset\n", device_xname(sc->sc_dev)); 1666 1.8 reinoud }; 1667 1.8 reinoud if (timeout != 10) { 1668 1.8 reinoud printf("%s: aclink hardware reset successful\n", 1669 1.39 chs device_xname(sc->sc_dev)); 1670 1.7 reinoud }; 1671 1.7 reinoud 1672 1.7 reinoud /* assert reset and sync for safety */ 1673 1.7 reinoud value = bus_space_read_4(iot, ioh, ATI_REG_CMD); 1674 1.7 reinoud value |= ATI_REG_CMD_AC_SYNC | ATI_REG_CMD_AC_RESET; 1675 1.7 reinoud bus_space_write_4(iot, ioh, ATI_REG_CMD, value); 1676 1.1 reinoud } 1677 1.1 reinoud 1678 1.1 reinoud 1679 1.1 reinoud /* chip hard init */ 1680 1.9 thorpej static int 1681 1.3 kent auixp_init(struct auixp_softc *sc) 1682 1.3 kent { 1683 1.3 kent bus_space_tag_t iot; 1684 1.3 kent bus_space_handle_t ioh; 1685 1.1 reinoud uint32_t value; 1686 1.1 reinoud 1687 1.3 kent iot = sc->sc_iot; 1688 1.3 kent ioh = sc->sc_ioh; 1689 1.1 reinoud /* disable all interrupts and clear all sources */ 1690 1.1 reinoud auixp_disable_interrupts(sc); 1691 1.1 reinoud 1692 1.1 reinoud /* clear all DMA enables (preserving rest of settings) */ 1693 1.1 reinoud value = bus_space_read_4(iot, ioh, ATI_REG_CMD); 1694 1.1 reinoud value &= ~( ATI_REG_CMD_IN_DMA_EN | 1695 1.1 reinoud ATI_REG_CMD_OUT_DMA_EN | 1696 1.1 reinoud ATI_REG_CMD_SPDF_OUT_EN ); 1697 1.1 reinoud bus_space_write_4(iot, ioh, ATI_REG_CMD, value); 1698 1.1 reinoud 1699 1.1 reinoud /* Reset AC-link */ 1700 1.1 reinoud auixp_reset_aclink(sc); 1701 1.1 reinoud 1702 1.1 reinoud /* 1703 1.1 reinoud * codecs get auto-detected later 1704 1.1 reinoud * 1705 1.1 reinoud * note: we are NOT enabling interrupts yet, no codecs have been 1706 1.1 reinoud * detected yet nor is anything else set up 1707 1.1 reinoud */ 1708 1.1 reinoud 1709 1.1 reinoud return 0; 1710 1.1 reinoud } 1711 1.1 reinoud 1712 1.25 jmcneill static bool 1713 1.34 dyoung auixp_resume(device_t dv, const pmf_qual_t *qual) 1714 1.3 kent { 1715 1.25 jmcneill struct auixp_softc *sc = device_private(dv); 1716 1.4 simonb 1717 1.35 jmcneill mutex_enter(&sc->sc_lock); 1718 1.25 jmcneill auixp_reset_codec(sc); 1719 1.25 jmcneill delay(1000); 1720 1.25 jmcneill (sc->sc_codec[0].codec_if->vtbl->restore_ports)(sc->sc_codec[0].codec_if); 1721 1.35 jmcneill mutex_exit(&sc->sc_lock); 1722 1.1 reinoud 1723 1.25 jmcneill return true; 1724 1.1 reinoud } 1725 1.1 reinoud 1726 1.1 reinoud #ifdef DEBUG_AUIXP 1727 1.1 reinoud 1728 1.9 thorpej static void 1729 1.3 kent auixp_dumpreg(void) 1730 1.3 kent { 1731 1.3 kent struct auixp_softc *sc; 1732 1.3 kent bus_space_tag_t iot; 1733 1.3 kent bus_space_handle_t ioh; 1734 1.1 reinoud int i; 1735 1.1 reinoud 1736 1.3 kent sc = static_sc; 1737 1.3 kent iot = sc->sc_iot; 1738 1.3 kent ioh = sc->sc_ioh; 1739 1.39 chs printf("%s register dump:\n", device_xname(sc->sc_dev)); 1740 1.1 reinoud for (i = 0; i < 256; i+=4) { 1741 1.1 reinoud printf("\t0x%02x: 0x%08x\n", i, bus_space_read_4(iot, ioh, i)); 1742 1.3 kent } 1743 1.1 reinoud printf("\n"); 1744 1.1 reinoud } 1745 1.1 reinoud #endif 1746 1.35 jmcneill 1747 1.35 jmcneill static void 1748 1.35 jmcneill auixp_get_locks(void *addr, kmutex_t **intr, kmutex_t **proc) 1749 1.35 jmcneill { 1750 1.37 jmcneill struct auixp_codec *co = addr; 1751 1.37 jmcneill struct auixp_softc *sc = co->sc; 1752 1.35 jmcneill 1753 1.35 jmcneill *intr = &sc->sc_intr_lock; 1754 1.35 jmcneill *proc = &sc->sc_lock; 1755 1.35 jmcneill } 1756