1 /* $OpenBSD: auglx.c,v 1.8 2011/07/03 15:47:16 matthew Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Marc Balmer <mbalmer@openbsd.org> 5 * All rights reserved. 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN 16 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* 21 * AMD CS5536 series AC'97 audio driver. 22 * 23 * The following datasheets were helpful in the development of this 24 * driver: 25 * 26 * AMD Geode LX Processors Data Book 27 * http://www.amd.com/files/connectivitysolutions/geode/geode_lx/\ 28 * 33234F_LX_databook.pdf 29 * 30 * AMD Geode CS5536 Companion Device Data Book 31 * http://www.amd.com/files/connectivitysolutions/geode/geode_lx/\ 32 * 33238G_cs5536_db.pdf 33 * 34 * Realtek ALC203 Two-Channel AC'97 2.3 Audio Codec 35 * ftp://202.65.194.211/pc/audio/ALC203_DataSheet_1.6.pdf 36 * 37 * This driver is inspired by the auich(4) and auixp(4) drivers, some 38 * of the hardware-independent functionality has been derived from them 39 * (e.g. memory allocation for the upper level, parameter setting). 40 */ 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/device.h> 45 #include <sys/malloc.h> 46 #include <sys/audioio.h> 47 48 #include <machine/bus.h> 49 50 #include <dev/pci/pcireg.h> 51 #include <dev/pci/pcivar.h> 52 #include <dev/pci/pcidevs.h> 53 #include <dev/audio_if.h> 54 #include <dev/mulaw.h> 55 #include <dev/auconv.h> 56 57 #include <dev/ic/ac97.h> 58 59 #define AUGLX_ACC_BAR 0x10 60 61 /* ACC Native Registers */ 62 #define ACC_GPIO_STATUS 0x00 63 #define ACC_GPIO_CNTL 0x04 64 #define ACC_CODEC_STATUS 0x08 65 #define ACC_CODEC_CNTL 0x0c 66 #define ACC_IRQ_STATUS 0x12 67 #define ACC_ENGINE_CNTL 0x14 68 #define ACC_BM0_CMD 0x20 /* Bus Master 0 Command */ 69 #define ACC_BM0_STATUS 0x21 /* Bus Master 0 IRQ Status */ 70 #define ACC_BM0_PRD 0x24 /* BM0 PRD Table Address */ 71 #define ACC_BM1_CMD 0x28 /* Bus Master 1 Command */ 72 #define ACC_BM1_STATUS 0x29 /* Bus Master 1 IRQ Status */ 73 #define ACC_BM1_PRD 0x2c /* BM1 PRD Table Address */ 74 #define ACC_BM2_CMD 0x30 /* Bus Master 2 Command */ 75 #define ACC_BM2_STATUS 0x31 /* Bus Master 2 IRQ Status */ 76 #define ACC_BM2_PRD 0x34 /* BM2 PRD Table Address */ 77 #define ACC_BM3_CMD 0x38 /* Bus Master 3 Command */ 78 #define ACC_BM3_STATUS 0x39 /* Bus Master 3 IRQ Status */ 79 #define ACC_BM3_PRD 0x3c /* BM3 PRD Table Address */ 80 #define ACC_BM4_CMD 0x40 /* Bus Master 4 Command */ 81 #define ACC_BM4_STATUS 0x41 /* Bus Master 4 IRQ Status */ 82 #define ACC_BM4_PRD 0x44 /* BM4 PRD Table Address */ 83 #define ACC_BM5_CMD 0x48 /* Bus Master 5 Command */ 84 #define ACC_BM5_STATUS 0x49 /* Bus Master 5 IRQ Status */ 85 #define ACC_BM5_PRD 0x4c /* BM5 PRD Table Address */ 86 #define ACC_BM6_CMD 0x50 /* Bus Master 6 Command */ 87 #define ACC_BM6_STATUS 0x51 /* Bus Master 6 IRQ Status */ 88 #define ACC_BM6_PRD 0x54 /* BM6 PRD Table Address */ 89 #define ACC_BM7_CMD 0x58 /* Bus Master 7 Command */ 90 #define ACC_BM7_STATUS 0x59 /* Bus Master 7 IRQ Status */ 91 #define ACC_BM7_PRD 0x5c /* BM7 PRD Table Address */ 92 #define ACC_BM0_PNTR 0x60 /* Bus Master 0 DMA Pointer */ 93 #define ACC_BM1_PNTR 0x64 /* Bus Master 1 DMA Pointer */ 94 #define ACC_BM2_PNTR 0x68 /* Bus Master 2 DMA Pointer */ 95 #define ACC_BM3_PNTR 0x6c /* Bus Master 3 DMA Pointer */ 96 #define ACC_BM4_PNTR 0x70 /* Bus Master 4 DMA Pointer */ 97 #define ACC_BM5_PNTR 0x74 /* Bus Master 5 DMA Pointer */ 98 #define ACC_BM6_PNTR 0x78 /* Bus Master 6 DMA Pointer */ 99 #define ACC_BM7_PNTR 0x7c /* Bus Master 7 DMA Pointer */ 100 101 /* ACC_IRQ_STATUS Bit Definitions */ 102 #define BM7_IRQ_STS 0x0200 /* Audio Bus Master 7 IRQ Status */ 103 #define BM6_IRQ_STS 0x0100 /* Audio Bus Master 6 IRQ Status */ 104 #define BM5_IRQ_STS 0x0080 /* Audio Bus Master 5 IRQ Status */ 105 #define BM4_IRQ_STS 0x0040 /* Audio Bus Master 4 IRQ Status */ 106 #define BM3_IRQ_STS 0x0020 /* Audio Bus Master 3 IRQ Status */ 107 #define BM2_IRQ_STS 0x0010 /* Audio Bus Master 2 IRQ Status */ 108 #define BM1_IRQ_STS 0x0008 /* Audio Bus Master 1 IRQ Status */ 109 #define BM0_IRQ_STS 0x0004 /* Audio Bus Master 0 IRQ Status */ 110 #define WU_IRQ_STS 0x0002 /* Codec GPIO Wakeup IRQ Status */ 111 #define IRQ_STS 0x0001 /* Codec GPIO IRQ Status */ 112 113 /* ACC_ENGINE_CNTL Bit Definitions */ 114 #define SSND_MODE 0x00000001 /* Surround Sound (5.1) Sync. Mode */ 115 116 /* ACC_BM[x]_CMD Bit Descriptions */ 117 #define BMx_CMD_RW 0x08 /* 0: Mem to codec, 1: codec to mem */ 118 #define BMx_CMD_BYTE_ORD 0x04 /* 0: Little Endian, 1: Big Endian */ 119 #define BMx_CMD_BM_CTL_DIS 0x00 /* Disable bus master */ 120 #define BMx_CMD_BM_CTL_EN 0x01 /* Enable bus master */ 121 #define BMx_CMD_BM_CTL_PAUSE 0x03 /* Pause bus master */ 122 123 /* ACC_BM[x]_STATUS Bit Definitions */ 124 #define BMx_BM_EOP_ERR 0x02 /* Bus master error */ 125 #define BMx_BM_EOP 0x01 /* End of page */ 126 127 /* ACC_CODEC_CNTL Bit Definitions */ 128 #define RW_CMD 0x80000000 129 #define PD_PRIM 0x00200000 130 #define PD_SEC 0x00100000 131 #define LNK_SHTDOWN 0x00040000 132 #define LNK_WRM_RST 0x00020000 133 #define CMD_NEW 0x00010000 134 135 /* ACC_CODEC_STATUS Bit Definitions */ 136 #define PRM_RDY_STS 0x00800000 137 #define SEC_RDY_STS 0x00400000 138 #define SDATAIN2_EN 0x00200000 139 #define BM5_SEL 0x00100000 140 #define BM4_SEL 0x00080000 141 #define STS_NEW 0x00020000 142 143 #define AUGLX_TOUT 1000 /* uSec */ 144 145 #define AUGLX_DMALIST_MAX 1 146 #define AUGLX_DMASEG_MAX 65536 147 148 struct auglx_prd { 149 u_int32_t base; 150 u_int32_t size; 151 #define AUGLX_PRD_EOT 0x80000000 152 #define AUGLX_PRD_EOP 0x40000000 153 #define AUGLX_PRD_JMP 0x20000000 154 }; 155 156 #define AUGLX_FIXED_RATE 48000 157 158 struct auglx_dma { 159 bus_dmamap_t map; 160 caddr_t addr; 161 bus_dma_segment_t segs[AUGLX_DMALIST_MAX]; 162 int nsegs; 163 size_t size; 164 struct auglx_dma *next; 165 }; 166 167 struct auglx_softc { 168 struct device sc_dev; 169 void *sc_ih; 170 171 audio_device_t sc_audev; 172 173 bus_space_tag_t sc_iot; 174 bus_space_handle_t sc_ioh; 175 bus_dma_tag_t sc_dmat; 176 177 /* 178 * The CS5536 ACC has eight bus masters to support 5.1 audio. 179 * This driver, however, only supports main playback and recording 180 * since I only have a Realtek ALC203 codec available for testing. 181 */ 182 struct auglx_ring { 183 bus_dmamap_t sc_prd; 184 struct auglx_prd *sc_vprd; 185 int sc_nprd; 186 187 size_t sc_size; 188 int nsegs; 189 bus_dma_segment_t seg; 190 191 void (*intr)(void *); 192 void *arg; 193 } bm0, bm1; /* bm0: output, bm1: input */ 194 195 struct auglx_dma *sc_dmas; 196 197 struct ac97_codec_if *codec_if; 198 struct ac97_host_if host_if; 199 200 int sc_dmamap_flags; 201 }; 202 203 #ifdef AUGLX_DEBUG 204 #define DPRINTF(l,x) do { if (auglx_debug & (l)) printf x; } while(0) 205 int auglx_debug = 0; 206 #define AUGLX_DBG_ACC 0x0001 207 #define AUGLX_DBG_DMA 0x0002 208 #define AUGLX_DBG_IRQ 0x0004 209 #else 210 #define DPRINTF(x,y) /* nothing */ 211 #endif 212 213 struct cfdriver auglx_cd = { 214 NULL, "auglx", DV_DULL 215 }; 216 217 int auglx_open(void *, int); 218 void auglx_close(void *); 219 int auglx_query_encoding(void *, struct audio_encoding *); 220 int auglx_set_params(void *, int, int, struct audio_params *, 221 struct audio_params *); 222 int auglx_round_blocksize(void *, int); 223 int auglx_halt_output(void *); 224 int auglx_halt_input(void *); 225 int auglx_getdev(void *, struct audio_device *); 226 int auglx_set_port(void *, mixer_ctrl_t *); 227 int auglx_get_port(void *, mixer_ctrl_t *); 228 int auglx_query_devinfo(void *, mixer_devinfo_t *); 229 void *auglx_allocm(void *, int, size_t, int, int); 230 void auglx_freem(void *, void *, int); 231 size_t auglx_round_buffersize(void *, int, size_t); 232 paddr_t auglx_mappage(void *, void *, off_t, int); 233 int auglx_get_props(void *); 234 int auglx_trigger_output(void *, void *, void *, int, void (*)(void *), 235 void *, struct audio_params *); 236 int auglx_trigger_input(void *, void *, void *, int, void (*)(void *), 237 void *, struct audio_params *); 238 int auglx_alloc_cdata(struct auglx_softc *); 239 int auglx_alloc_prd(struct auglx_softc *, size_t, struct auglx_ring *); 240 void auglx_free_prd(struct auglx_softc *sc, struct auglx_ring *bm); 241 int auglx_allocmem(struct auglx_softc *, size_t, size_t, struct auglx_dma *); 242 void auglx_freemem(struct auglx_softc *, struct auglx_dma *); 243 void auglx_get_default_params(void *, int, struct audio_params *); 244 245 struct audio_hw_if auglx_hw_if = { 246 auglx_open, 247 auglx_close, 248 NULL, /* drain */ 249 auglx_query_encoding, 250 auglx_set_params, 251 auglx_round_blocksize, 252 NULL, /* commit_setting */ 253 NULL, /* init_output */ 254 NULL, /* init_input */ 255 NULL, /* start_output */ 256 NULL, /* start_input */ 257 auglx_halt_output, 258 auglx_halt_input, 259 NULL, /* speaker_ctl */ 260 auglx_getdev, 261 NULL, /* getfd */ 262 auglx_set_port, 263 auglx_get_port, 264 auglx_query_devinfo, 265 auglx_allocm, 266 auglx_freem, 267 auglx_round_buffersize, 268 auglx_mappage, 269 auglx_get_props, 270 auglx_trigger_output, 271 auglx_trigger_input, 272 auglx_get_default_params 273 }; 274 275 int auglx_match(struct device *, void *, void *); 276 void auglx_attach(struct device *, struct device *, void *); 277 int auglx_activate(struct device *, int); 278 int auglx_intr(void *); 279 280 int auglx_attach_codec(void *, struct ac97_codec_if *); 281 int auglx_read_codec(void *, u_int8_t, u_int16_t *); 282 int auglx_write_codec(void *, u_int8_t, u_int16_t); 283 void auglx_reset_codec(void *); 284 enum ac97_host_flags auglx_flags_codec(void *); 285 286 struct cfattach auglx_ca = { 287 sizeof(struct auglx_softc), auglx_match, auglx_attach, NULL, 288 auglx_activate 289 }; 290 291 const struct pci_matchid auglx_devices[] = { 292 { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_CS5536_AUDIO } 293 }; 294 295 int 296 auglx_match(struct device *parent, void *match, void *aux) 297 { 298 return (pci_matchbyid((struct pci_attach_args *)aux, auglx_devices, 299 sizeof(auglx_devices) / sizeof(auglx_devices[0]))); 300 } 301 302 void 303 auglx_attach(struct device *parent, struct device *self, void *aux) 304 { 305 struct auglx_softc *sc = (struct auglx_softc *)self; 306 struct pci_attach_args *pa = aux; 307 bus_size_t bar_size; 308 pci_intr_handle_t ih; 309 const char *intrstr; 310 311 if (pci_mapreg_map(pa, AUGLX_ACC_BAR, PCI_MAPREG_TYPE_IO, 0, 312 &sc->sc_iot, &sc->sc_ioh, NULL, &bar_size, 0)) { 313 printf(": can't map ACC I/O space\n"); 314 return; 315 } 316 317 sc->sc_dmat = pa->pa_dmat; 318 sc->sc_dmamap_flags = BUS_DMA_COHERENT; 319 320 if (pci_intr_map(pa, &ih)) { 321 printf(": can't map interrupt"); 322 bus_space_unmap(sc->sc_iot, sc->sc_ioh, bar_size); 323 return; 324 } 325 intrstr = pci_intr_string(pa->pa_pc, ih); 326 sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO, auglx_intr, 327 sc, sc->sc_dev.dv_xname); 328 if (!sc->sc_ih) { 329 printf(": can't establish interrupt"); 330 if (intrstr) 331 printf(" at %s", intrstr); 332 printf("\n"); 333 bus_space_unmap(sc->sc_iot, sc->sc_ioh, bar_size); 334 return; 335 } 336 337 strlcpy(sc->sc_audev.name, "CS5536 AC97", sizeof sc->sc_audev.name); 338 snprintf(sc->sc_audev.version, sizeof sc->sc_audev.version, "0x%02x", 339 PCI_REVISION(pa->pa_class)); 340 strlcpy(sc->sc_audev.config, sc->sc_dev.dv_xname, 341 sizeof sc->sc_audev.config); 342 343 printf(": %s, %s\n", intrstr, sc->sc_audev.name); 344 345 sc->host_if.arg = sc; 346 sc->host_if.attach = auglx_attach_codec; 347 sc->host_if.read = auglx_read_codec; 348 sc->host_if.write = auglx_write_codec; 349 sc->host_if.reset = auglx_reset_codec; 350 sc->host_if.flags = auglx_flags_codec; 351 352 if (ac97_attach(&sc->host_if) != 0) { 353 bus_space_unmap(sc->sc_iot, sc->sc_ioh, bar_size); 354 return; 355 } 356 audio_attach_mi(&auglx_hw_if, sc, &sc->sc_dev); 357 } 358 359 /* Functions to communicate with the AC97 Codec via the ACC */ 360 int 361 auglx_read_codec(void *v, u_int8_t reg, u_int16_t *val) 362 { 363 struct auglx_softc *sc = v; 364 u_int32_t codec_cntl, codec_status; 365 int i; 366 367 codec_cntl = RW_CMD | ((u_int32_t)reg << 24) | CMD_NEW; 368 bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_CODEC_CNTL, codec_cntl); 369 370 for (i = AUGLX_TOUT; i; i--) { 371 codec_cntl = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 372 ACC_CODEC_CNTL); 373 if (!(codec_cntl & CMD_NEW)) 374 break; 375 delay(1); 376 } 377 if (codec_cntl & CMD_NEW) { 378 printf("%s: codec read timeout after write\n", 379 sc->sc_dev.dv_xname); 380 return -1; 381 } 382 383 for (i = AUGLX_TOUT; i; i--) { 384 codec_status = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 385 ACC_CODEC_STATUS); 386 if ((codec_status & STS_NEW) && (codec_status >> 24 == reg)) 387 break; 388 delay(10); 389 } 390 if (i == 0) { 391 printf("%s: codec status read timeout, 0x%08x\n", 392 sc->sc_dev.dv_xname, codec_status); 393 return -1; 394 } 395 396 *val = codec_status & 0xffff; 397 DPRINTF(AUGLX_DBG_ACC, ("%s: read codec register 0x%02x: 0x%04x\n", 398 sc->sc_dev.dv_xname, reg, *val)); 399 return 0; 400 } 401 402 int 403 auglx_write_codec(void *v, u_int8_t reg, u_int16_t val) 404 { 405 struct auglx_softc *sc = v; 406 u_int32_t codec_cntl; 407 int i; 408 409 DPRINTF(AUGLX_DBG_ACC, ("%s: write codec register 0x%02x: 0x%04x\n", 410 sc->sc_dev.dv_xname, reg, val)); 411 412 413 codec_cntl = ((u_int32_t)reg << 24) | CMD_NEW | val; 414 bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_CODEC_CNTL, codec_cntl); 415 416 for (i = AUGLX_TOUT; i; i--) { 417 codec_cntl = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 418 ACC_CODEC_CNTL); 419 if (!(codec_cntl & CMD_NEW)) 420 break; 421 delay(1); 422 } 423 if (codec_cntl & CMD_NEW) { 424 printf("%s: codec write timeout\n", sc->sc_dev.dv_xname); 425 return -1; 426 } 427 428 return 0; 429 } 430 431 int 432 auglx_attach_codec(void *v, struct ac97_codec_if *cif) 433 { 434 struct auglx_softc *sc = v; 435 436 sc->codec_if = cif; 437 return 0; 438 } 439 440 void 441 auglx_reset_codec(void *v) 442 { 443 struct auglx_softc *sc = v; 444 u_int32_t codec_cntl; 445 int i; 446 447 codec_cntl = LNK_WRM_RST | CMD_NEW; 448 bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_CODEC_CNTL, codec_cntl); 449 450 for (i = AUGLX_TOUT; i; i--) { 451 codec_cntl = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 452 ACC_CODEC_CNTL); 453 if (!(codec_cntl & CMD_NEW)) 454 continue; 455 delay(1); 456 } 457 if (codec_cntl & CMD_NEW) 458 printf("%s: codec reset timeout\n", sc->sc_dev.dv_xname); 459 } 460 461 enum ac97_host_flags 462 auglx_flags_codec(void *v) 463 { 464 return 0; 465 } 466 467 /* 468 * Audio functions 469 */ 470 int 471 auglx_open(void *v, int flags) 472 { 473 return 0; 474 } 475 476 void 477 auglx_close(void *v) 478 { 479 } 480 481 482 int 483 auglx_query_encoding(void *v, struct audio_encoding *aep) 484 { 485 switch (aep->index) { 486 case 0: 487 strlcpy(aep->name, AudioEulinear, sizeof aep->name); 488 aep->encoding = AUDIO_ENCODING_ULINEAR; 489 aep->precision = 8; 490 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 491 break; 492 case 1: 493 strlcpy(aep->name, AudioEmulaw, sizeof aep->name); 494 aep->encoding = AUDIO_ENCODING_ULAW; 495 aep->precision = 8; 496 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 497 break; 498 case 2: 499 strlcpy(aep->name, AudioEalaw, sizeof aep->name); 500 aep->encoding = AUDIO_ENCODING_ALAW; 501 aep->precision = 8; 502 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 503 break; 504 case 3: 505 strlcpy(aep->name, AudioEslinear, sizeof aep->name); 506 aep->encoding = AUDIO_ENCODING_SLINEAR; 507 aep->precision = 8; 508 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 509 break; 510 case 4: 511 strlcpy(aep->name, AudioEslinear_le, sizeof aep->name); 512 aep->encoding = AUDIO_ENCODING_SLINEAR_LE; 513 aep->precision = 16; 514 aep->flags = 0; 515 break; 516 case 5: 517 strlcpy(aep->name, AudioEulinear_le, sizeof aep->name); 518 aep->encoding = AUDIO_ENCODING_ULINEAR_LE; 519 aep->precision = 16; 520 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 521 break; 522 case 6: 523 strlcpy(aep->name, AudioEslinear_be, sizeof aep->name); 524 aep->encoding = AUDIO_ENCODING_SLINEAR_BE; 525 aep->precision = 16; 526 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 527 break; 528 case 7: 529 strlcpy(aep->name, AudioEulinear_be, sizeof aep->name); 530 aep->encoding = AUDIO_ENCODING_ULINEAR_BE; 531 aep->precision = 16; 532 aep->flags = AUDIO_ENCODINGFLAG_EMULATED; 533 break; 534 default: 535 return EINVAL; 536 } 537 aep->bps = AUDIO_BPS(aep->precision); 538 aep->msb = 1; 539 540 return 0; 541 } 542 543 544 int 545 auglx_set_params(void *v, int setmode, int usemode, struct audio_params *play, 546 struct audio_params *rec) 547 { 548 struct auglx_softc *sc = v; 549 int error; 550 u_int orate; 551 552 if (setmode & AUMODE_PLAY) { 553 play->factor = 1; 554 play->sw_code = NULL; 555 if (play->precision > 16) 556 play->precision = 16; 557 if (play->channels > 2) 558 play->channels = 2; 559 switch(play->encoding) { 560 case AUDIO_ENCODING_ULAW: 561 switch (play->channels) { 562 case 1: 563 play->factor = 4; 564 play->sw_code = mulaw_to_slinear16_le_mts; 565 break; 566 case 2: 567 play->factor = 2; 568 play->sw_code = mulaw_to_slinear16_le; 569 break; 570 default: 571 return EINVAL; 572 } 573 break; 574 case AUDIO_ENCODING_SLINEAR_LE: 575 switch (play->precision) { 576 case 8: 577 switch (play->channels) { 578 case 1: 579 play->factor = 4; 580 play->sw_code = linear8_to_linear16_le_mts; 581 break; 582 case 2: 583 play->factor = 2; 584 play->sw_code = linear8_to_linear16_le; 585 break; 586 default: 587 return EINVAL; 588 } 589 break; 590 case 16: 591 switch (play->channels) { 592 case 1: 593 play->factor = 2; 594 play->sw_code = noswap_bytes_mts; 595 break; 596 case 2: 597 break; 598 default: 599 return EINVAL; 600 } 601 break; 602 default: 603 return (EINVAL); 604 } 605 break; 606 case AUDIO_ENCODING_ULINEAR_LE: 607 switch (play->precision) { 608 case 8: 609 switch (play->channels) { 610 case 1: 611 play->factor = 4; 612 play->sw_code = ulinear8_to_linear16_le_mts; 613 break; 614 case 2: 615 play->factor = 2; 616 play->sw_code = ulinear8_to_linear16_le; 617 break; 618 default: 619 return EINVAL; 620 } 621 break; 622 case 16: 623 switch (play->channels) { 624 case 1: 625 play->factor = 2; 626 play->sw_code = change_sign16_le_mts; 627 break; 628 case 2: 629 play->sw_code = change_sign16_le; 630 break; 631 default: 632 return EINVAL; 633 } 634 break; 635 default: 636 return EINVAL; 637 } 638 break; 639 case AUDIO_ENCODING_ALAW: 640 switch (play->channels) { 641 case 1: 642 play->factor = 4; 643 play->sw_code = alaw_to_slinear16_le_mts; 644 break; 645 case 2: 646 play->factor = 2; 647 play->sw_code = alaw_to_slinear16_le; 648 break; 649 default: 650 return EINVAL; 651 } 652 break; 653 case AUDIO_ENCODING_SLINEAR_BE: 654 switch (play->precision) { 655 case 8: 656 switch (play->channels) { 657 case 1: 658 play->factor = 4; 659 play->sw_code = linear8_to_linear16_le_mts; 660 break; 661 case 2: 662 play->factor = 2; 663 play->sw_code = linear8_to_linear16_le; 664 break; 665 default: 666 return EINVAL; 667 } 668 break; 669 case 16: 670 switch (play->channels) { 671 case 1: 672 play->factor = 2; 673 play->sw_code = swap_bytes_mts; 674 break; 675 case 2: 676 play->sw_code = swap_bytes; 677 break; 678 default: 679 return EINVAL; 680 } 681 break; 682 default: 683 return EINVAL; 684 } 685 break; 686 case AUDIO_ENCODING_ULINEAR_BE: 687 switch (play->precision) { 688 case 8: 689 switch (play->channels) { 690 case 1: 691 play->factor = 4; 692 play->sw_code = ulinear8_to_linear16_le_mts; 693 break; 694 case 2: 695 play->factor = 2; 696 play->sw_code = ulinear8_to_linear16_le; 697 break; 698 default: 699 return EINVAL; 700 } 701 break; 702 case 16: 703 switch (play->channels) { 704 case 1: 705 play->factor = 2; 706 play->sw_code = swap_bytes_change_sign16_le_mts; 707 break; 708 case 2: 709 play->sw_code = swap_bytes_change_sign16_le; 710 break; 711 default: 712 return EINVAL; 713 } 714 break; 715 default: 716 return EINVAL; 717 } 718 break; 719 default: 720 return EINVAL; 721 } 722 play->bps = AUDIO_BPS(play->precision); 723 play->msb = 1; 724 725 orate = play->sample_rate; 726 727 play->sample_rate = orate; 728 error = ac97_set_rate(sc->codec_if, 729 AC97_REG_PCM_LFE_DAC_RATE, &play->sample_rate); 730 if (error) 731 return error; 732 733 play->sample_rate = orate; 734 error = ac97_set_rate(sc->codec_if, 735 AC97_REG_PCM_SURR_DAC_RATE, &play->sample_rate); 736 if (error) 737 return error; 738 739 play->sample_rate = orate; 740 error = ac97_set_rate(sc->codec_if, 741 AC97_REG_PCM_FRONT_DAC_RATE, &play->sample_rate); 742 if (error) 743 return error; 744 } 745 746 if (setmode & AUMODE_RECORD) { 747 rec->factor = 1; 748 rec->sw_code = 0; 749 if (rec->precision > 16) 750 rec->precision = 16; 751 if (rec->channels > 2) 752 rec->channels = 2; 753 switch(rec->encoding) { 754 case AUDIO_ENCODING_ULAW: 755 switch (rec->channels) { 756 case 1: 757 rec->sw_code = slinear16_to_mulaw_le_stm; 758 rec->factor = 4; 759 break; 760 case 2: 761 rec->sw_code = slinear16_to_mulaw_le; 762 rec->factor = 2; 763 break; 764 } 765 break; 766 case AUDIO_ENCODING_ALAW: 767 switch (rec->channels) { 768 case 1: 769 rec->sw_code = slinear16_to_alaw_le_stm; 770 rec->factor = 4; 771 break; 772 case 2: 773 rec->sw_code = slinear16_to_alaw_le; 774 rec->factor = 2; 775 break; 776 } 777 break; 778 case AUDIO_ENCODING_SLINEAR_LE: 779 switch (rec->precision) { 780 case 8: 781 switch (rec->channels) { 782 case 1: 783 rec->sw_code = linear16_to_linear8_le_stm; 784 rec->factor = 4; 785 break; 786 case 2: 787 rec->sw_code = linear16_to_linear8_le; 788 rec->factor = 2; 789 break; 790 } 791 break; 792 case 16: 793 switch (rec->channels) { 794 case 1: 795 rec->sw_code = linear16_decimator; 796 rec->factor = 2; 797 break; 798 case 2: 799 break; 800 } 801 break; 802 default: 803 return EINVAL; 804 } 805 break; 806 case AUDIO_ENCODING_ULINEAR_LE: 807 switch (rec->precision) { 808 case 8: 809 switch (rec->channels) { 810 case 1: 811 rec->sw_code = linear16_to_ulinear8_le_stm; 812 rec->factor = 4; 813 break; 814 case 2: 815 rec->sw_code = linear16_to_ulinear8_le; 816 rec->factor = 2; 817 break; 818 } 819 break; 820 case 16: 821 switch (rec->channels) { 822 case 1: 823 rec->sw_code = change_sign16_le_stm; 824 rec->factor = 2; 825 break; 826 case 2: 827 rec->sw_code = change_sign16_le; 828 break; 829 } 830 break; 831 default: 832 return EINVAL; 833 } 834 break; 835 case AUDIO_ENCODING_SLINEAR_BE: 836 switch (rec->precision) { 837 case 8: 838 switch (rec->channels) { 839 case 1: 840 rec->sw_code = linear16_to_linear8_le_stm; 841 rec->factor = 4; 842 break; 843 case 2: 844 rec->sw_code = linear16_to_linear8_le; 845 rec->factor = 2; 846 break; 847 } 848 break; 849 case 16: 850 switch (rec->channels) { 851 case 1: 852 rec->sw_code = swap_bytes_stm; 853 rec->factor = 2; 854 break; 855 case 2: 856 rec->sw_code = swap_bytes; 857 break; 858 } 859 break; 860 default: 861 return EINVAL; 862 } 863 break; 864 case AUDIO_ENCODING_ULINEAR_BE: 865 switch (rec->precision) { 866 case 8: 867 switch (rec->channels) { 868 case 1: 869 rec->sw_code = linear16_to_ulinear8_le_stm; 870 rec->factor = 4; 871 break; 872 case 2: 873 rec->sw_code = linear16_to_ulinear8_le; 874 rec->factor = 2; 875 break; 876 } 877 break; 878 case 16: 879 switch (rec->channels) { 880 case 1: 881 rec->sw_code = change_sign16_swap_bytes_le_stm; 882 rec->factor = 2; 883 break; 884 case 2: 885 rec->sw_code = change_sign16_swap_bytes_le; 886 break; 887 } 888 break; 889 default: 890 return EINVAL; 891 } 892 break; 893 default: 894 return EINVAL; 895 } 896 rec->bps = AUDIO_BPS(rec->precision); 897 rec->msb = 1; 898 899 error = ac97_set_rate(sc->codec_if, AC97_REG_PCM_LR_ADC_RATE, 900 &rec->sample_rate); 901 if (error) 902 return error; 903 } 904 905 return 0; 906 } 907 908 int 909 auglx_round_blocksize(void *v, int blk) 910 { 911 return (blk + 0x3f) & ~0x3f; 912 } 913 914 int 915 auglx_halt_output(void *v) 916 { 917 struct auglx_softc *sc = v; 918 919 DPRINTF(AUGLX_DBG_DMA, ("%s: halt_output\n", sc->sc_dev.dv_xname)); 920 921 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM0_CMD, 0x00); 922 sc->bm0.intr = NULL; 923 return 0; 924 } 925 926 int 927 auglx_halt_input(void *v) 928 { 929 struct auglx_softc *sc = v; 930 931 DPRINTF(AUGLX_DBG_DMA, 932 ("%s: halt_input\n", sc->sc_dev.dv_xname)); 933 934 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM1_CMD, 0x00); 935 sc->bm1.intr = NULL; 936 return 0; 937 } 938 939 int 940 auglx_getdev(void *v, struct audio_device *adp) 941 { 942 struct auglx_softc *sc = v; 943 *adp = sc->sc_audev; 944 return 0; 945 } 946 947 int 948 auglx_set_port(void *v, mixer_ctrl_t *cp) 949 { 950 struct auglx_softc *sc = v; 951 return sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp); 952 } 953 954 int 955 auglx_get_port(void *v, mixer_ctrl_t *cp) 956 { 957 struct auglx_softc *sc = v; 958 return sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp); 959 } 960 961 int 962 auglx_query_devinfo(void *v, mixer_devinfo_t *dp) 963 { 964 struct auglx_softc *sc = v; 965 return sc->codec_if->vtbl->query_devinfo(sc->codec_if, dp); 966 } 967 968 void * 969 auglx_allocm(void *v, int direction, size_t size, int pool, int flags) 970 { 971 struct auglx_softc *sc = v; 972 struct auglx_dma *p; 973 int error; 974 975 DPRINTF(AUGLX_DBG_DMA, ("%s: request buffer of size %ld, dir %d\n", 976 sc->sc_dev.dv_xname, size, direction)); 977 978 /* can only use 1 segment */ 979 if (size > AUGLX_DMASEG_MAX) { 980 DPRINTF(AUGLX_DBG_DMA, 981 ("%s: requested buffer size too large: %d", \ 982 sc->sc_dev.dv_xname, size)); 983 return NULL; 984 } 985 986 p = malloc(sizeof(*p), pool, flags | M_ZERO); 987 if (!p) 988 return NULL; 989 990 error = auglx_allocmem(sc, size, PAGE_SIZE, p); 991 if (error) { 992 free(p, pool); 993 return NULL; 994 } 995 996 p->next = sc->sc_dmas; 997 sc->sc_dmas = p; 998 999 return p->addr; 1000 } 1001 1002 void 1003 auglx_freem(void *v, void *ptr, int pool) 1004 { 1005 struct auglx_softc *sc; 1006 struct auglx_dma *p, **pp; 1007 1008 sc = v; 1009 for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->next) { 1010 if (p->addr == ptr) { 1011 auglx_freemem(sc, p); 1012 *pp = p->next; 1013 free(p, pool); 1014 return; 1015 } 1016 } 1017 } 1018 1019 1020 size_t 1021 auglx_round_buffersize(void *v, int direction, size_t size) 1022 { 1023 if (size > AUGLX_DMASEG_MAX) 1024 size = AUGLX_DMASEG_MAX; 1025 1026 return size; 1027 } 1028 1029 paddr_t 1030 auglx_mappage(void *v, void *mem, off_t off, int prot) 1031 { 1032 struct auglx_softc *sc = v; 1033 struct auglx_dma *p; 1034 1035 if (off < 0) 1036 return -1; 1037 1038 for (p = sc->sc_dmas; p && p->addr != mem; p = p->next); 1039 if (!p) 1040 return -1; 1041 1042 return bus_dmamem_mmap(sc->sc_dmat, p->segs, p->nsegs, 1043 off, prot, BUS_DMA_WAITOK); 1044 } 1045 1046 int 1047 auglx_get_props(void *v) 1048 { 1049 return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX; 1050 } 1051 1052 int 1053 auglx_intr(void *v) 1054 { 1055 struct auglx_softc *sc = v; 1056 u_int16_t irq_sts; 1057 u_int8_t bm_sts; 1058 1059 irq_sts = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ACC_IRQ_STATUS); 1060 if (irq_sts == 0) 1061 return 0; 1062 1063 if (irq_sts & BM0_IRQ_STS) { 1064 bm_sts = bus_space_read_1(sc->sc_iot, sc->sc_ioh, 1065 ACC_BM0_STATUS); 1066 if (sc->bm0.intr) { 1067 sc->bm0.intr(sc->bm0.arg); 1068 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM0_CMD, 1069 BMx_CMD_BM_CTL_EN); 1070 } 1071 } else if (irq_sts & BM1_IRQ_STS) { 1072 bm_sts = bus_space_read_1(sc->sc_iot, sc->sc_ioh, 1073 ACC_BM1_STATUS); 1074 if (sc->bm1.intr) { 1075 sc->bm1.intr(sc->bm1.arg); 1076 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM1_CMD, 1077 BMx_CMD_RW | BMx_CMD_BM_CTL_EN); 1078 } 1079 } else { 1080 DPRINTF(AUGLX_DBG_IRQ, ("%s: stray intr, status = 0x%04x\n", 1081 sc->sc_dev.dv_xname, irq_sts)); 1082 return -1; 1083 } 1084 return 1; 1085 } 1086 1087 int 1088 auglx_trigger_output(void *v, void *start, void *end, int blksize, 1089 void (*intr)(void *), void *arg, struct audio_params *param) 1090 { 1091 struct auglx_softc *sc = v; 1092 struct auglx_dma *p; 1093 size_t size; 1094 u_int32_t addr; 1095 int i, nprd; 1096 1097 size = (size_t)((caddr_t)end - (caddr_t)start); 1098 DPRINTF(AUGLX_DBG_DMA, ("%s: trigger_output, %p 0x%08x bytes, " 1099 "blksize 0x%04x\n", sc->sc_dev.dv_xname, start, size, blksize)); 1100 1101 for (p = sc->sc_dmas; p && p->addr != start; p = p->next); 1102 if (!p) { 1103 DPRINTF(AUGLX_DBG_DMA, ("%s dma reg not found\n", 1104 sc->sc_dev.dv_xname)); 1105 return -1; 1106 } 1107 1108 /* set up the PRDs */ 1109 nprd = size / blksize; 1110 if (sc->bm0.sc_nprd != nprd + 1) { 1111 if (sc->bm0.sc_nprd > 0) 1112 auglx_free_prd(sc, &sc->bm0); 1113 sc->bm0.sc_nprd = nprd + 1; 1114 auglx_alloc_prd(sc, 1115 sc->bm0.sc_nprd * sizeof(struct auglx_prd), &sc->bm0); 1116 } 1117 DPRINTF(AUGLX_DBG_DMA, ("%s: nprd = %d\n", sc->sc_dev.dv_xname, 1118 nprd)); 1119 addr = p->segs->ds_addr; 1120 for (i = 0; i < nprd; i++) { 1121 sc->bm0.sc_vprd[i].base = addr; 1122 sc->bm0.sc_vprd[i].size = blksize | AUGLX_PRD_EOP; 1123 addr += blksize; 1124 } 1125 sc->bm0.sc_vprd[i].base = sc->bm0.sc_prd->dm_segs[0].ds_addr; 1126 sc->bm0.sc_vprd[i].size = AUGLX_PRD_JMP; 1127 1128 #ifdef AUGLX_DEBUG 1129 for (i = 0; i < sc->bm0.sc_nprd; i++) 1130 DPRINTF(AUGLX_DBG_DMA, ("%s: PRD[%d].base = %p, size %p\n", 1131 sc->sc_dev.dv_xname, i, sc->bm0.sc_vprd[i].base, 1132 sc->bm0.sc_vprd[i].size)); 1133 #endif 1134 sc->bm0.intr = intr; 1135 sc->bm0.arg = arg; 1136 1137 /* Program the BM0 PRD register */ 1138 bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM0_PRD, 1139 sc->bm0.sc_prd->dm_segs[0].ds_addr); 1140 /* Start Audio Bus Master 0 */ 1141 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM0_CMD, 1142 BMx_CMD_BM_CTL_EN); 1143 return 0; 1144 } 1145 1146 int 1147 auglx_trigger_input(void *v, void *start, void *end, int blksize, 1148 void (*intr)(void *), void * arg, struct audio_params *param) 1149 { 1150 struct auglx_softc *sc = v; 1151 struct auglx_dma *p; 1152 size_t size; 1153 u_int32_t addr; 1154 int i, nprd; 1155 1156 size = (size_t)((caddr_t)end - (caddr_t)start); 1157 DPRINTF(AUGLX_DBG_DMA, ("%s: trigger_input, %p 0x%08x bytes, " 1158 "blksize 0x%04x\n", sc->sc_dev.dv_xname, start, size, blksize)); 1159 1160 for (p = sc->sc_dmas; p && p->addr != start; p = p->next); 1161 if (!p) { 1162 DPRINTF(AUGLX_DBG_DMA, ("%s dma reg not found\n", 1163 sc->sc_dev.dv_xname)); 1164 return -1; 1165 } 1166 1167 /* set up the PRDs */ 1168 nprd = size / blksize; 1169 if (sc->bm1.sc_nprd != nprd + 1) { 1170 if (sc->bm1.sc_nprd > 0) 1171 auglx_free_prd(sc, &sc->bm1); 1172 sc->bm1.sc_nprd = nprd + 1; 1173 auglx_alloc_prd(sc, 1174 sc->bm1.sc_nprd * sizeof(struct auglx_prd), &sc->bm1); 1175 } 1176 DPRINTF(AUGLX_DBG_DMA, ("%s: nprd = %d\n", sc->sc_dev.dv_xname, 1177 nprd)); 1178 addr = p->segs->ds_addr; 1179 for (i = 0; i < nprd; i++) { 1180 sc->bm1.sc_vprd[i].base = addr; 1181 sc->bm1.sc_vprd[i].size = blksize | AUGLX_PRD_EOP; 1182 addr += blksize; 1183 } 1184 sc->bm1.sc_vprd[i].base = sc->bm1.sc_prd->dm_segs[0].ds_addr; 1185 sc->bm1.sc_vprd[i].size = AUGLX_PRD_JMP; 1186 1187 #ifdef AUGLX_DEBUG 1188 for (i = 0; i < sc->bm1.sc_nprd; i++) 1189 DPRINTF(AUGLX_DBG_DMA, ("%s: PRD[%d].base = %p, size %p\n", 1190 sc->sc_dev.dv_xname, i, sc->bm1.sc_vprd[i].base, 1191 sc->bm1.sc_vprd[i].size)); 1192 #endif 1193 sc->bm1.intr = intr; 1194 sc->bm1.arg = arg; 1195 1196 /* Program the BM1 PRD register */ 1197 bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM1_PRD, 1198 sc->bm1.sc_prd->dm_segs[0].ds_addr); 1199 /* Start Audio Bus Master 0 */ 1200 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM1_CMD, 1201 BMx_CMD_RW | BMx_CMD_BM_CTL_EN); 1202 return 0; 1203 } 1204 1205 int 1206 auglx_allocmem(struct auglx_softc *sc, size_t size, size_t align, 1207 struct auglx_dma *p) 1208 { 1209 int error; 1210 1211 p->size = size; 1212 error = bus_dmamem_alloc(sc->sc_dmat, p->size, align, 0, p->segs, 1, 1213 &p->nsegs, BUS_DMA_NOWAIT); 1214 if (error) { 1215 DPRINTF(AUGLX_DBG_DMA, 1216 ("%s: bus_dmamem_alloc failed: error %d\n", 1217 sc->sc_dev.dv_xname, error)); 1218 return error; 1219 } 1220 1221 error = bus_dmamem_map(sc->sc_dmat, p->segs, 1, p->size, &p->addr, 1222 BUS_DMA_NOWAIT | sc->sc_dmamap_flags); 1223 if (error) { 1224 DPRINTF(AUGLX_DBG_DMA, 1225 ("%s: bus_dmamem_map failed: error %d\n", 1226 sc->sc_dev.dv_xname, error)); 1227 goto free; 1228 } 1229 1230 error = bus_dmamap_create(sc->sc_dmat, p->size, 1, p->size, 0, 1231 BUS_DMA_NOWAIT, &p->map); 1232 if (error) { 1233 DPRINTF(AUGLX_DBG_DMA, 1234 ("%s: bus_dmamap_create failed: error %d\n", 1235 sc->sc_dev.dv_xname, error)); 1236 goto unmap; 1237 } 1238 1239 error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, p->size, NULL, 1240 BUS_DMA_NOWAIT); 1241 if (error) { 1242 DPRINTF(AUGLX_DBG_DMA, 1243 ("%s: bus_dmamap_load failed: error %d\n", 1244 sc->sc_dev.dv_xname, error)); 1245 goto destroy; 1246 } 1247 return 0; 1248 1249 destroy: 1250 bus_dmamap_destroy(sc->sc_dmat, p->map); 1251 unmap: 1252 bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size); 1253 free: 1254 bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs); 1255 return error; 1256 } 1257 1258 void 1259 auglx_freemem(struct auglx_softc *sc, struct auglx_dma *p) 1260 { 1261 bus_dmamap_unload(sc->sc_dmat, p->map); 1262 bus_dmamap_destroy(sc->sc_dmat, p->map); 1263 bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size); 1264 bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs); 1265 } 1266 1267 void 1268 auglx_get_default_params(void *addr, int mode, struct audio_params *params) 1269 { 1270 ac97_get_default_params(params); 1271 } 1272 1273 int 1274 auglx_alloc_prd(struct auglx_softc *sc, size_t size, struct auglx_ring *bm) 1275 { 1276 int error, rseg; 1277 1278 /* 1279 * Allocate PRD table structure, and create and load the 1280 * DMA map for it. 1281 */ 1282 if ((error = bus_dmamem_alloc(sc->sc_dmat, size, 1283 PAGE_SIZE, 0, &bm->seg, 1, &rseg, 0)) != 0) { 1284 printf("%s: unable to allocate PRD, error = %d\n", 1285 sc->sc_dev.dv_xname, error); 1286 goto fail_0; 1287 } 1288 1289 if ((error = bus_dmamem_map(sc->sc_dmat, &bm->seg, rseg, 1290 size, (caddr_t *)&bm->sc_vprd, 1291 sc->sc_dmamap_flags)) != 0) { 1292 printf("%s: unable to map PRD, error = %d\n", 1293 sc->sc_dev.dv_xname, error); 1294 goto fail_1; 1295 } 1296 1297 if ((error = bus_dmamap_create(sc->sc_dmat, size, 1298 1, size, 0, 0, &bm->sc_prd)) != 0) { 1299 printf("%s: unable to create PRD DMA map, " 1300 "error = %d\n", sc->sc_dev.dv_xname, error); 1301 goto fail_2; 1302 } 1303 1304 if ((error = bus_dmamap_load(sc->sc_dmat, bm->sc_prd, bm->sc_vprd, 1305 size, NULL, 0)) != 0) { 1306 printf("%s: unable tp load control data DMA map, " 1307 "error = %d\n", sc->sc_dev.dv_xname, error); 1308 goto fail_3; 1309 } 1310 1311 return 0; 1312 1313 fail_3: 1314 bus_dmamap_destroy(sc->sc_dmat, bm->sc_prd); 1315 fail_2: 1316 bus_dmamem_unmap(sc->sc_dmat, (caddr_t)bm->sc_vprd, 1317 sizeof(struct auglx_prd)); 1318 fail_1: 1319 bus_dmamem_free(sc->sc_dmat, &bm->seg, rseg); 1320 fail_0: 1321 return error; 1322 } 1323 1324 void 1325 auglx_free_prd(struct auglx_softc *sc, struct auglx_ring *bm) 1326 { 1327 bus_dmamap_unload(sc->sc_dmat, bm->sc_prd); 1328 bus_dmamap_destroy(sc->sc_dmat, bm->sc_prd); 1329 bus_dmamem_unmap(sc->sc_dmat, (caddr_t)bm->sc_vprd, bm->sc_size); 1330 bus_dmamem_free(sc->sc_dmat, &bm->seg, bm->nsegs); 1331 } 1332 1333 int 1334 auglx_activate(struct device *self, int act) 1335 { 1336 struct auglx_softc *sc = (struct auglx_softc *)self; 1337 int rv = 0; 1338 1339 switch (act) { 1340 case DVACT_QUIESCE: 1341 rv = config_activate_children(self, act); 1342 break; 1343 case DVACT_SUSPEND: 1344 break; 1345 case DVACT_RESUME: 1346 ac97_resume(&sc->host_if, sc->codec_if); 1347 rv = config_activate_children(self, act); 1348 break; 1349 case DVACT_DEACTIVATE: 1350 break; 1351 } 1352 return (rv); 1353 } 1354