Annotation of sys/dev/pci/maestro.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: maestro.c,v 1.21 2006/12/29 13:04:37 pedro Exp $ */
! 2: /* $FreeBSD: /c/ncvs/src/sys/dev/sound/pci/maestro.c,v 1.3 2000/11/21 12:22:11 julian Exp $ */
! 3: /*
! 4: * FreeBSD's ESS Agogo/Maestro driver
! 5: * Converted from FreeBSD's pcm to OpenBSD's audio.
! 6: * Copyright (c) 2000, 2001 David Leonard & Marc Espie
! 7: * All rights reserved.
! 8: *
! 9: * Redistribution and use in source and binary forms, with or without
! 10: * modification, are permitted provided that the following conditions
! 11: * are met:
! 12: * 1. Redistributions of source code must retain the above copyright
! 13: * notice, this list of conditions and the following disclaimer.
! 14: * 2. Redistributions in binary form must reproduce the above copyright
! 15: * notice, this list of conditions and the following disclaimer in the
! 16: * documentation and/or other materials provided with the distribution.
! 17: *
! 18: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 19: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 20: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 21: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 22: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 23: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 24: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 25: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 26: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 27: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 28: * SUCH DAMAGE.
! 29: */
! 30: /*-
! 31: * (FreeBSD) Credits:
! 32: * Copyright (c) 2000 Taku YAMAMOTO <taku@cent.saitama-u.ac.jp>
! 33: *
! 34: * Part of this code (especially in many magic numbers) was heavily inspired
! 35: * by the Linux driver originally written by
! 36: * Alan Cox <alan.cox@linux.org>, modified heavily by
! 37: * Zach Brown <zab@zabbo.net>.
! 38: *
! 39: * busdma()-ize and buffer size reduction were suggested by
! 40: * Cameron Grant <gandalf@vilnya.demon.co.uk>.
! 41: * Also he showed me the way to use busdma() suite.
! 42: *
! 43: * Internal speaker problems on NEC VersaPro's and Dell Inspiron 7500
! 44: * were looked at by
! 45: * Munehiro Matsuda <haro@tk.kubota.co.jp>,
! 46: * who brought patches based on the Linux driver with some simplification.
! 47: */
! 48:
! 49: #include <sys/param.h>
! 50: #include <sys/systm.h>
! 51: #include <sys/kernel.h>
! 52: #include <sys/malloc.h>
! 53: #include <sys/device.h>
! 54: #include <sys/proc.h>
! 55: #include <sys/queue.h>
! 56: #include <sys/fcntl.h>
! 57:
! 58: #include <dev/pci/pcidevs.h>
! 59: #include <dev/pci/pcivar.h>
! 60:
! 61: #include <sys/audioio.h>
! 62: #include <dev/audio_if.h>
! 63: #include <dev/mulaw.h>
! 64: #include <dev/auconv.h>
! 65:
! 66: #include <dev/ic/ac97.h>
! 67:
! 68: /* -----------------------------
! 69: * PCI config registers
! 70: */
! 71:
! 72: /* Legacy emulation */
! 73: #define CONF_LEGACY 0x40
! 74:
! 75: #define LEGACY_DISABLED 0x8000
! 76:
! 77: /* Chip configurations */
! 78: #define CONF_MAESTRO 0x50
! 79: #define MAESTRO_CHIBUS 0x00100000
! 80: #define MAESTRO_POSTEDWRITE 0x00000080
! 81: #define MAESTRO_DMA_PCITIMING 0x00000040
! 82: #define MAESTRO_SWAP_LR 0x00000010
! 83:
! 84: /* ACPI configurations */
! 85: #define CONF_ACPI_STOPCLOCK 0x54
! 86: #define ACPI_PART_2ndC_CLOCK 15
! 87: #define ACPI_PART_CODEC_CLOCK 14
! 88: #define ACPI_PART_978 13 /* Docking station or something */
! 89: #define ACPI_PART_SPDIF 12
! 90: #define ACPI_PART_GLUE 11 /* What? */
! 91: #define ACPI_PART_DAA 10
! 92: #define ACPI_PART_PCI_IF 9
! 93: #define ACPI_PART_HW_VOL 8
! 94: #define ACPI_PART_GPIO 7
! 95: #define ACPI_PART_ASSP 6
! 96: #define ACPI_PART_SB 5
! 97: #define ACPI_PART_FM 4
! 98: #define ACPI_PART_RINGBUS 3
! 99: #define ACPI_PART_MIDI 2
! 100: #define ACPI_PART_GAME_PORT 1
! 101: #define ACPI_PART_WP 0
! 102:
! 103: /* Power management */
! 104: #define CONF_PM_PTR 0x34 /* BYTE R */
! 105: #define PM_CID 0 /* BYTE R */
! 106: #define PPMI_CID 1
! 107: #define PM_CTRL 4 /* BYTE RW */
! 108: #define PPMI_D0 0 /* Full power */
! 109: #define PPMI_D1 1 /* Medium power */
! 110: #define PPMI_D2 2 /* Low power */
! 111: #define PPMI_D3 3 /* Turned off */
! 112:
! 113:
! 114: /* -----------------------------
! 115: * I/O ports
! 116: */
! 117:
! 118: /* Direct Sound Processor (aka Wave Processor) */
! 119: #define PORT_DSP_DATA 0x00 /* WORD RW */
! 120: #define PORT_DSP_INDEX 0x02 /* WORD RW */
! 121: #define PORT_INT_STAT 0x04 /* WORD RW */
! 122: #define PORT_SAMPLE_CNT 0x06 /* WORD RO */
! 123:
! 124: /* WaveCache */
! 125: #define PORT_WAVCACHE_INDEX 0x10 /* WORD RW */
! 126: #define PORT_WAVCACHE_DATA 0x12 /* WORD RW */
! 127: #define WAVCACHE_PCMBAR 0x1fc
! 128: #define WAVCACHE_WTBAR 0x1f0
! 129: #define WAVCACHE_BASEADDR_SHIFT 12
! 130:
! 131: #define WAVCACHE_CHCTL_ADDRTAG_MASK 0xfff8
! 132: #define WAVCACHE_CHCTL_U8 0x0004
! 133: #define WAVCACHE_CHCTL_STEREO 0x0002
! 134: #define WAVCACHE_CHCTL_DECREMENTAL 0x0001
! 135:
! 136: #define PORT_WAVCACHE_CTRL 0x14 /* WORD RW */
! 137: #define WAVCACHE_EXTRA_CH_ENABLED 0x0200
! 138: #define WAVCACHE_ENABLED 0x0100
! 139: #define WAVCACHE_CH_60_ENABLED 0x0080
! 140: #define WAVCACHE_WTSIZE_MASK 0x0060
! 141: #define WAVCACHE_WTSIZE_1MB 0x0000
! 142: #define WAVCACHE_WTSIZE_2MB 0x0020
! 143: #define WAVCACHE_WTSIZE_4MB 0x0040
! 144: #define WAVCACHE_WTSIZE_8MB 0x0060
! 145: #define WAVCACHE_SGC_MASK 0x000c
! 146: #define WAVCACHE_SGC_DISABLED 0x0000
! 147: #define WAVCACHE_SGC_40_47 0x0004
! 148: #define WAVCACHE_SGC_32_47 0x0008
! 149: #define WAVCACHE_TESTMODE 0x0001
! 150:
! 151: /* Host Interruption */
! 152: #define PORT_HOSTINT_CTRL 0x18 /* WORD RW */
! 153: #define HOSTINT_CTRL_SOFT_RESET 0x8000
! 154: #define HOSTINT_CTRL_DSOUND_RESET 0x4000
! 155: #define HOSTINT_CTRL_HW_VOL_TO_PME 0x0400
! 156: #define HOSTINT_CTRL_CLKRUN_ENABLED 0x0100
! 157: #define HOSTINT_CTRL_HWVOL_ENABLED 0x0040
! 158: #define HOSTINT_CTRL_ASSP_INT_ENABLED 0x0010
! 159: #define HOSTINT_CTRL_ISDN_INT_ENABLED 0x0008
! 160: #define HOSTINT_CTRL_DSOUND_INT_ENABLED 0x0004
! 161: #define HOSTINT_CTRL_MPU401_INT_ENABLED 0x0002
! 162: #define HOSTINT_CTRL_SB_INT_ENABLED 0x0001
! 163:
! 164: #define PORT_HOSTINT_STAT 0x1a /* BYTE RW */
! 165: #define HOSTINT_STAT_HWVOL 0x40
! 166: #define HOSTINT_STAT_ASSP 0x10
! 167: #define HOSTINT_STAT_ISDN 0x08
! 168: #define HOSTINT_STAT_DSOUND 0x04
! 169: #define HOSTINT_STAT_MPU401 0x02
! 170: #define HOSTINT_STAT_SB 0x01
! 171:
! 172: /* Hardware volume */
! 173: #define PORT_HWVOL_VOICE_SHADOW 0x1c /* BYTE RW */
! 174: #define PORT_HWVOL_VOICE 0x1d /* BYTE RW */
! 175: #define PORT_HWVOL_MASTER_SHADOW 0x1e /* BYTE RW */
! 176: #define PORT_HWVOL_MASTER 0x1f /* BYTE RW */
! 177:
! 178: /* CODEC */
! 179: #define PORT_CODEC_CMD 0x30 /* BYTE W */
! 180: #define CODEC_CMD_READ 0x80
! 181: #define CODEC_CMD_WRITE 0x00
! 182: #define CODEC_CMD_ADDR_MASK 0x7f
! 183:
! 184: #define PORT_CODEC_STAT 0x30 /* BYTE R */
! 185: #define CODEC_STAT_MASK 0x01
! 186: #define CODEC_STAT_RW_DONE 0x00
! 187: #define CODEC_STAT_PROGLESS 0x01
! 188:
! 189: #define PORT_CODEC_REG 0x32 /* WORD RW */
! 190:
! 191: /* Ring bus control */
! 192: #define PORT_RINGBUS_CTRL 0x34 /* DWORD RW */
! 193: #define RINGBUS_CTRL_I2S_ENABLED 0x80000000
! 194: #define RINGBUS_CTRL_RINGBUS_ENABLED 0x20000000
! 195: #define RINGBUS_CTRL_ACLINK_ENABLED 0x10000000
! 196: #define RINGBUS_CTRL_AC97_SWRESET 0x08000000
! 197: #define RINGBUS_CTRL_IODMA_PLAYBACK_ENABLED 0x04000000
! 198: #define RINGBUS_CTRL_IODMA_RECORD_ENABLED 0x02000000
! 199:
! 200: #define RINGBUS_SRC_MIC 20
! 201: #define RINGBUS_SRC_I2S 16
! 202: #define RINGBUS_SRC_ADC 12
! 203: #define RINGBUS_SRC_MODEM 8
! 204: #define RINGBUS_SRC_DSOUND 4
! 205: #define RINGBUS_SRC_ASSP 0
! 206:
! 207: #define RINGBUS_DEST_MONORAL 000
! 208: #define RINGBUS_DEST_STEREO 010
! 209: #define RINGBUS_DEST_NONE 0
! 210: #define RINGBUS_DEST_DAC 1
! 211: #define RINGBUS_DEST_MODEM_IN 2
! 212: #define RINGBUS_DEST_RESERVED3 3
! 213: #define RINGBUS_DEST_DSOUND_IN 4
! 214: #define RINGBUS_DEST_ASSP_IN 5
! 215:
! 216: /* General Purpose I/O */
! 217: #define PORT_GPIO_DATA 0x60 /* WORD RW */
! 218: #define PORT_GPIO_MASK 0x64 /* WORD RW */
! 219: #define PORT_GPIO_DIR 0x68 /* WORD RW */
! 220:
! 221: /* Application Specific Signal Processor */
! 222: #define PORT_ASSP_MEM_INDEX 0x80 /* DWORD RW */
! 223: #define PORT_ASSP_MEM_DATA 0x84 /* WORD RW */
! 224: #define PORT_ASSP_CTRL_A 0xa2 /* BYTE RW */
! 225: #define PORT_ASSP_CTRL_B 0xa4 /* BYTE RW */
! 226: #define PORT_ASSP_CTRL_C 0xa6 /* BYTE RW */
! 227: #define PORT_ASSP_HOST_WR_INDEX 0xa8 /* BYTE W */
! 228: #define PORT_ASSP_HOST_WR_DATA 0xaa /* BYTE RW */
! 229: #define PORT_ASSP_INT_STAT 0xac /* BYTE RW */
! 230:
! 231:
! 232: /* -----------------------------
! 233: * Wave Processor Indexed Data Registers.
! 234: */
! 235:
! 236: #define WPREG_DATA_PORT 0
! 237: #define WPREG_CRAM_PTR 1
! 238: #define WPREG_CRAM_DATA 2
! 239: #define WPREG_WAVE_DATA 3
! 240: #define WPREG_WAVE_PTR_LOW 4
! 241: #define WPREG_WAVE_PTR_HIGH 5
! 242:
! 243: #define WPREG_TIMER_FREQ 6
! 244: #define WP_TIMER_FREQ_PRESCALE_MASK 0x00e0 /* actual - 9 */
! 245: #define WP_TIMER_FREQ_PRESCALE_SHIFT 5
! 246: #define WP_TIMER_FREQ_DIVIDE_MASK 0x001f
! 247: #define WP_TIMER_FREQ_DIVIDE_SHIFT 0
! 248:
! 249: #define WPREG_WAVE_ROMRAM 7
! 250: #define WP_WAVE_VIRTUAL_ENABLED 0x0400
! 251: #define WP_WAVE_8BITRAM_ENABLED 0x0200
! 252: #define WP_WAVE_DRAM_ENABLED 0x0100
! 253: #define WP_WAVE_RAMSPLIT_MASK 0x00ff
! 254: #define WP_WAVE_RAMSPLIT_SHIFT 0
! 255:
! 256: #define WPREG_BASE 12
! 257: #define WP_PARAOUT_BASE_MASK 0xf000
! 258: #define WP_PARAOUT_BASE_SHIFT 12
! 259: #define WP_PARAIN_BASE_MASK 0x0f00
! 260: #define WP_PARAIN_BASE_SHIFT 8
! 261: #define WP_SERIAL0_BASE_MASK 0x00f0
! 262: #define WP_SERIAL0_BASE_SHIFT 4
! 263: #define WP_SERIAL1_BASE_MASK 0x000f
! 264: #define WP_SERIAL1_BASE_SHIFT 0
! 265:
! 266: #define WPREG_TIMER_ENABLE 17
! 267: #define WPREG_TIMER_START 23
! 268:
! 269:
! 270: /* -----------------------------
! 271: * Audio Processing Unit.
! 272: */
! 273: #define APUREG_APUTYPE 0
! 274: #define APU_DMA_ENABLED 0x4000
! 275: #define APU_INT_ON_LOOP 0x2000
! 276: #define APU_ENDCURVE 0x1000
! 277: #define APU_APUTYPE_MASK 0x00f0
! 278: #define APU_FILTERTYPE_MASK 0x000c
! 279: #define APU_FILTERQ_MASK 0x0003
! 280:
! 281: /* APU types */
! 282: #define APU_APUTYPE_SHIFT 4
! 283:
! 284: #define APUTYPE_INACTIVE 0
! 285: #define APUTYPE_16BITLINEAR 1
! 286: #define APUTYPE_16BITSTEREO 2
! 287: #define APUTYPE_8BITLINEAR 3
! 288: #define APUTYPE_8BITSTEREO 4
! 289: #define APUTYPE_8BITDIFF 5
! 290: #define APUTYPE_DIGITALDELAY 6
! 291: #define APUTYPE_DUALTAP_READER 7
! 292: #define APUTYPE_CORRELATOR 8
! 293: #define APUTYPE_INPUTMIXER 9
! 294: #define APUTYPE_WAVETABLE 10
! 295: #define APUTYPE_RATECONV 11
! 296: #define APUTYPE_16BITPINGPONG 12
! 297: /* APU type 13 through 15 are reserved. */
! 298:
! 299: /* Filter types */
! 300: #define APU_FILTERTYPE_SHIFT 2
! 301:
! 302: #define FILTERTYPE_2POLE_LOPASS 0
! 303: #define FILTERTYPE_2POLE_BANDPASS 1
! 304: #define FILTERTYPE_2POLE_HIPASS 2
! 305: #define FILTERTYPE_1POLE_LOPASS 3
! 306: #define FILTERTYPE_1POLE_HIPASS 4
! 307: #define FILTERTYPE_PASSTHROUGH 5
! 308:
! 309: /* Filter Q */
! 310: #define APU_FILTERQ_SHIFT 0
! 311:
! 312: #define FILTERQ_LESSQ 0
! 313: #define FILTERQ_MOREQ 3
! 314:
! 315: /* APU register 2 */
! 316: #define APUREG_FREQ_LOBYTE 2
! 317: #define APU_FREQ_LOBYTE_MASK 0xff00
! 318: #define APU_plus6dB 0x0010
! 319:
! 320: /* APU register 3 */
! 321: #define APUREG_FREQ_HIWORD 3
! 322: #define APU_FREQ_HIWORD_MASK 0x0fff
! 323:
! 324: /* Frequency */
! 325: #define APU_FREQ_LOBYTE_SHIFT 8
! 326: #define APU_FREQ_HIWORD_SHIFT 0
! 327: #define FREQ_Hz2DIV(freq) (((u_int64_t)(freq) << 16) / 48000)
! 328:
! 329: /* APU register 4 */
! 330: #define APUREG_WAVESPACE 4
! 331: #define APU_STEREO 0x8000
! 332: #define APU_USE_SYSMEM 0x4000
! 333: #define APU_PCMBAR_MASK 0x6000
! 334: #define APU_64KPAGE_MASK 0xff00
! 335:
! 336: /* PCM Base Address Register selection */
! 337: #define APU_PCMBAR_SHIFT 13
! 338:
! 339: /* 64KW (==128KB) Page */
! 340: #define APU_64KPAGE_SHIFT 8
! 341:
! 342: /* APU register 5 - 7 */
! 343: #define APUREG_CURPTR 5
! 344: #define APUREG_ENDPTR 6
! 345: #define APUREG_LOOPLEN 7
! 346:
! 347: /* APU register 9 */
! 348: #define APUREG_AMPLITUDE 9
! 349: #define APU_AMPLITUDE_NOW_MASK 0xff00
! 350: #define APU_AMPLITUDE_DEST_MASK 0x00ff
! 351:
! 352: /* Amplitude now? */
! 353: #define APU_AMPLITUDE_NOW_SHIFT 8
! 354:
! 355: /* APU register 10 */
! 356: #define APUREG_POSITION 10
! 357: #define APU_RADIUS_MASK 0x00c0
! 358: #define APU_PAN_MASK 0x003f
! 359:
! 360: /* Radius control. */
! 361: #define APU_RADIUS_SHIFT 6
! 362: #define RADIUS_CENTERCIRCLE 0
! 363: #define RADIUS_MIDDLE 1
! 364: #define RADIUS_OUTSIDE 2
! 365:
! 366: /* Polar pan. */
! 367: #define APU_PAN_SHIFT 0
! 368: #define PAN_RIGHT 0x00
! 369: #define PAN_FRONT 0x08
! 370: #define PAN_LEFT 0x10
! 371:
! 372:
! 373: /* -----------------------------
! 374: * Limits.
! 375: */
! 376: #define WPWA_MAX ((1 << 22) - 1)
! 377: #define WPWA_MAXADDR ((1 << 23) - 1)
! 378: #define MAESTRO_MAXADDR ((1 << 28) - 1)
! 379:
! 380:
! 381:
! 382: #ifdef AUDIO_DEBUG
! 383: #define DPRINTF(x) if (maestrodebug) printf x
! 384: #define DLPRINTF(i, x) if (maestrodebug & i) printf x
! 385: int maestrodebug = 0;
! 386: u_long maestrointr_called;
! 387: u_long maestrodma_effective;
! 388:
! 389: #define MAESTRODEBUG_INTR 1
! 390: #define MAESTRODEBUG_TIMER 2
! 391: #else
! 392: #define DPRINTF(x)
! 393: #define DLPRINTF(i, x)
! 394: #endif
! 395:
! 396: #define MAESTRO_BUFSIZ 0x4000
! 397: #define lengthof(array) (sizeof (array) / sizeof (array)[0])
! 398:
! 399: #define STEP_VOLUME 0x22
! 400: #define MIDDLE_VOLUME (STEP_VOLUME * 4)
! 401:
! 402: typedef struct salloc_pool {
! 403: struct salloc_zone {
! 404: SLIST_ENTRY(salloc_zone) link;
! 405: caddr_t addr;
! 406: size_t size;
! 407: } *zones;
! 408: SLIST_HEAD(salloc_head, salloc_zone) free, used, spare;
! 409: } *salloc_t;
! 410:
! 411: struct maestro_softc;
! 412:
! 413: #define MAESTRO_PLAY 1
! 414: #define MAESTRO_STEREO 2
! 415: #define MAESTRO_8BIT 4
! 416: #define MAESTRO_UNSIGNED 8
! 417: #define MAESTRO_RUNNING 16
! 418:
! 419: struct maestro_channel {
! 420: struct maestro_softc *sc;
! 421: int num;
! 422: u_int32_t blocksize;
! 423: u_int16_t mode;
! 424: u_int32_t speed;
! 425: u_int32_t dv;
! 426: u_int16_t start;
! 427: u_int16_t threshold;
! 428: u_int16_t end;
! 429: u_int16_t current;
! 430: u_int wpwa;
! 431: void (*intr)(void *);
! 432: void *intr_arg;
! 433: };
! 434:
! 435: struct maestro_softc {
! 436: struct device dev;
! 437:
! 438: void *ih;
! 439: pci_chipset_tag_t pc;
! 440: pcitag_t pt;
! 441:
! 442: #define MAESTRO_FLAG_SETUPGPIO 0x0001
! 443: int flags;
! 444: bus_space_tag_t iot;
! 445: bus_space_handle_t ioh;
! 446: bus_dma_tag_t dmat;
! 447:
! 448: caddr_t dmabase;
! 449: bus_addr_t physaddr;
! 450: size_t dmasize;
! 451: bus_dmamap_t dmamap;
! 452: bus_dma_segment_t dmaseg;
! 453: salloc_t dmapool;
! 454:
! 455: struct ac97_codec_if *codec_if;
! 456: struct ac97_host_if host_if;
! 457: struct audio_device *sc_audev;
! 458:
! 459: void *powerhook;
! 460: int suspend;
! 461:
! 462: struct maestro_channel play;
! 463: struct maestro_channel record;
! 464: };
! 465:
! 466:
! 467: typedef u_int16_t wpreg_t;
! 468: typedef u_int16_t wcreg_t;
! 469:
! 470: salloc_t salloc_new(caddr_t, size_t, int);
! 471: void salloc_destroy(salloc_t);
! 472: caddr_t salloc_alloc(salloc_t, size_t);
! 473: void salloc_free(salloc_t, caddr_t);
! 474: void salloc_insert(salloc_t, struct salloc_head *,
! 475: struct salloc_zone *, int);
! 476:
! 477: int maestro_match(struct device *, void *, void *);
! 478: void maestro_attach(struct device *, struct device *, void *);
! 479: int maestro_intr(void *);
! 480:
! 481: int maestro_open(void *, int);
! 482: void maestro_close(void *);
! 483: int maestro_query_encoding(void *, struct audio_encoding *);
! 484: int maestro_set_params(void *, int, int, struct audio_params *,
! 485: struct audio_params *);
! 486: int maestro_round_blocksize(void *, int);
! 487: int maestro_halt_output(void *);
! 488: int maestro_halt_input(void *);
! 489: int maestro_getdev(void *, struct audio_device *);
! 490: int maestro_set_port(void *, mixer_ctrl_t *);
! 491: int maestro_get_port(void *, mixer_ctrl_t *);
! 492: int maestro_query_devinfo(void *, mixer_devinfo_t *);
! 493: void *maestro_malloc(void *, int, size_t, int, int);
! 494: void maestro_free(void *, void *, int);
! 495: paddr_t maestro_mappage(void *, void *, off_t, int);
! 496: int maestro_get_props(void *);
! 497: int maestro_trigger_output(void *, void *, void *, int, void (*)(void *),
! 498: void *, struct audio_params *);
! 499: int maestro_trigger_input(void *, void *, void *, int, void (*)(void *),
! 500: void *, struct audio_params *);
! 501:
! 502: int maestro_attach_codec(void *, struct ac97_codec_if *);
! 503: int maestro_read_codec(void *, u_int8_t, u_int16_t *);
! 504: int maestro_write_codec(void *, u_int8_t, u_int16_t);
! 505: void maestro_reset_codec(void *);
! 506:
! 507: void maestro_initcodec(void *);
! 508:
! 509: void maestro_set_speed(struct maestro_channel *, u_long *);
! 510: void maestro_init(struct maestro_softc *);
! 511: void maestro_power(struct maestro_softc *, int);
! 512: void maestro_powerhook(int, void *);
! 513:
! 514: void maestro_channel_start(struct maestro_channel *);
! 515: void maestro_channel_stop(struct maestro_channel *);
! 516: void maestro_channel_advance_dma(struct maestro_channel *);
! 517: void maestro_channel_suppress_jitter(struct maestro_channel *);
! 518:
! 519: int maestro_get_flags(struct pci_attach_args *);
! 520:
! 521: void ringbus_setdest(struct maestro_softc *, int, int);
! 522:
! 523: wpreg_t wp_reg_read(struct maestro_softc *, int);
! 524: void wp_reg_write(struct maestro_softc *, int, wpreg_t);
! 525: wpreg_t wp_apu_read(struct maestro_softc *, int, int);
! 526: void wp_apu_write(struct maestro_softc *, int, int, wpreg_t);
! 527: void wp_settimer(struct maestro_softc *, u_int);
! 528: void wp_starttimer(struct maestro_softc *);
! 529: void wp_stoptimer(struct maestro_softc *);
! 530:
! 531: wcreg_t wc_reg_read(struct maestro_softc *, int);
! 532: void wc_reg_write(struct maestro_softc *, int, wcreg_t);
! 533: wcreg_t wc_ctrl_read(struct maestro_softc *, int);
! 534: void wc_ctrl_write(struct maestro_softc *, int, wcreg_t);
! 535:
! 536: u_int maestro_calc_timer_freq(struct maestro_channel *);
! 537: void maestro_update_timer(struct maestro_softc *);
! 538:
! 539: struct cfdriver maestro_cd = {
! 540: NULL, "maestro", DV_DULL
! 541: };
! 542:
! 543: struct cfattach maestro_ca = {
! 544: sizeof (struct maestro_softc), maestro_match, maestro_attach
! 545: };
! 546:
! 547: struct audio_hw_if maestro_hw_if = {
! 548: maestro_open,
! 549: maestro_close,
! 550: NULL,
! 551: maestro_query_encoding,
! 552: maestro_set_params,
! 553: maestro_round_blocksize,
! 554: NULL,
! 555: NULL,
! 556: NULL,
! 557: NULL,
! 558: NULL,
! 559: maestro_halt_output,
! 560: maestro_halt_input,
! 561: NULL,
! 562: maestro_getdev,
! 563: NULL,
! 564: maestro_set_port,
! 565: maestro_get_port,
! 566: maestro_query_devinfo,
! 567: maestro_malloc,
! 568: maestro_free,
! 569: NULL,
! 570: maestro_mappage,
! 571: maestro_get_props,
! 572: maestro_trigger_output,
! 573: maestro_trigger_input
! 574: };
! 575:
! 576: struct audio_device maestro_audev = {
! 577: "ESS Maestro", "", "maestro"
! 578: };
! 579:
! 580: struct {
! 581: u_short vendor, product;
! 582: int flags;
! 583: } maestro_pcitab[] = {
! 584: { PCI_VENDOR_ESSTECH, PCI_PRODUCT_ESSTECH_MAESTROII, 0 },
! 585: { PCI_VENDOR_ESSTECH, PCI_PRODUCT_ESSTECH_MAESTRO2E, 0 },
! 586: { PCI_VENDOR_PLATFORM, PCI_PRODUCT_PLATFORM_ES1849, 0 },
! 587: { PCI_VENDOR_NEC, PCI_PRODUCT_NEC_VERSAMAESTRO, MAESTRO_FLAG_SETUPGPIO },
! 588: { PCI_VENDOR_NEC, PCI_PRODUCT_NEC_VERSAPRONXVA26D, MAESTRO_FLAG_SETUPGPIO }
! 589: };
! 590: #define NMAESTRO_PCITAB lengthof(maestro_pcitab)
! 591:
! 592: int
! 593: maestro_get_flags(pa)
! 594: struct pci_attach_args *pa;
! 595: {
! 596: int i;
! 597:
! 598: /* Distinguish audio devices from modems with the same manfid */
! 599: if (PCI_CLASS(pa->pa_class) != PCI_CLASS_MULTIMEDIA)
! 600: return (-1);
! 601: if (PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_MULTIMEDIA_AUDIO)
! 602: return (-1);
! 603: for (i = 0; i < NMAESTRO_PCITAB; i++)
! 604: if (PCI_VENDOR(pa->pa_id) == maestro_pcitab[i].vendor &&
! 605: PCI_PRODUCT(pa->pa_id) == maestro_pcitab[i].product)
! 606: return (maestro_pcitab[i].flags);
! 607: return (-1);
! 608: }
! 609:
! 610: /* -----------------------------
! 611: * Driver interface.
! 612: */
! 613:
! 614: int
! 615: maestro_match(parent, match, aux)
! 616: struct device *parent;
! 617: void *match;
! 618: void *aux;
! 619: {
! 620: struct pci_attach_args *pa = (struct pci_attach_args *)aux;
! 621:
! 622: if (maestro_get_flags(pa) == -1)
! 623: return (0);
! 624: else
! 625: return (1);
! 626: }
! 627:
! 628: void
! 629: maestro_attach(parent, self, aux)
! 630: struct device *parent;
! 631: struct device *self;
! 632: void *aux;
! 633: {
! 634: struct maestro_softc *sc = (struct maestro_softc *)self;
! 635: struct pci_attach_args *pa = (struct pci_attach_args *)aux;
! 636: pci_chipset_tag_t pc = pa->pa_pc;
! 637: char const *intrstr;
! 638: pci_intr_handle_t ih;
! 639: int error;
! 640: u_int16_t cdata;
! 641: int dmastage = 0;
! 642: int rseg;
! 643:
! 644: sc->sc_audev = &maestro_audev;
! 645: sc->flags = maestro_get_flags(pa);
! 646:
! 647: sc->pc = pa->pa_pc;
! 648: sc->pt = pa->pa_tag;
! 649: sc->dmat = pa->pa_dmat;
! 650:
! 651: /* Map interrupt */
! 652: if (pci_intr_map(pa, &ih)) {
! 653: printf(": couldn't map interrupt\n");
! 654: return;
! 655: }
! 656: intrstr = pci_intr_string(pc, ih);
! 657: sc->ih = pci_intr_establish(pc, ih, IPL_AUDIO, maestro_intr, sc,
! 658: sc->dev.dv_xname);
! 659: if (sc->ih == NULL) {
! 660: printf(": couldn't establish interrupt");
! 661: if (intrstr != NULL)
! 662: printf(" at %s\n", intrstr);
! 663: return;
! 664: }
! 665: printf(": %s", intrstr);
! 666:
! 667: /* Rangers, power up */
! 668: maestro_power(sc, PPMI_D0);
! 669: DELAY(100000);
! 670:
! 671: /* Map i/o */
! 672: if ((error = pci_mapreg_map(pa, PCI_MAPS, PCI_MAPREG_TYPE_IO,
! 673: 0, &sc->iot, &sc->ioh, NULL, NULL, 0)) != 0) {
! 674: printf(", couldn't map i/o space\n");
! 675: goto bad;
! 676: };
! 677:
! 678: /* Allocate fixed DMA segment :-( */
! 679: sc->dmasize = MAESTRO_BUFSIZ * 16;
! 680: if ((error = bus_dmamem_alloc(sc->dmat, sc->dmasize, NBPG, 0,
! 681: &sc->dmaseg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
! 682: printf(", unable to alloc dma, error %d\n", error);
! 683: goto bad;
! 684: }
! 685: dmastage = 1;
! 686: if ((error = bus_dmamem_map(sc->dmat, &sc->dmaseg, 1,
! 687: sc->dmasize, &sc->dmabase, BUS_DMA_NOWAIT |
! 688: BUS_DMA_COHERENT)) != 0) {
! 689: printf(", unable to map dma, error %d\n", error);
! 690: goto bad;
! 691: }
! 692: dmastage = 2;
! 693: if ((error = bus_dmamap_create(sc->dmat, sc->dmasize, 1,
! 694: sc->dmasize, 0, BUS_DMA_NOWAIT, &sc->dmamap)) != 0) {
! 695: printf(", unable to create dma map, error %d\n", error);
! 696: goto bad;
! 697: }
! 698: dmastage = 3;
! 699: if ((error = bus_dmamap_load(sc->dmat, sc->dmamap,
! 700: sc->dmabase, sc->dmasize, NULL, BUS_DMA_NOWAIT)) != 0) {
! 701: printf(", unable to load dma map, error %d\n", error);
! 702: goto bad;
! 703: }
! 704:
! 705: /* XXX
! 706: * The first byte of the allocated memory is not usable,
! 707: * the WP sometimes uses it to store status.
! 708: */
! 709: /* Make DMA memory pool */
! 710: if ((sc->dmapool = salloc_new(sc->dmabase+16, sc->dmasize-16,
! 711: 128/*overkill?*/)) == NULL) {
! 712: printf(", unable to make dma pool\n");
! 713: goto bad;
! 714: }
! 715:
! 716: sc->physaddr = sc->dmamap->dm_segs[0].ds_addr;
! 717:
! 718: printf("\n");
! 719:
! 720: /* Kick device */
! 721: maestro_init(sc);
! 722: maestro_read_codec(sc, 0, &cdata);
! 723: if (cdata == 0x80) {
! 724: printf("%s: PT101 codec unsupported, no mixer\n",
! 725: sc->dev.dv_xname);
! 726: /* Init values from Linux, no idea what this does. */
! 727: maestro_write_codec(sc, 0x2a, 0x0001);
! 728: maestro_write_codec(sc, 0x2C, 0x0000);
! 729: maestro_write_codec(sc, 0x2C, 0xFFFF);
! 730: maestro_write_codec(sc, 0x10, 0x9F1F);
! 731: maestro_write_codec(sc, 0x12, 0x0808);
! 732: maestro_write_codec(sc, 0x14, 0x9F1F);
! 733: maestro_write_codec(sc, 0x16, 0x9F1F);
! 734: maestro_write_codec(sc, 0x18, 0x0404);
! 735: maestro_write_codec(sc, 0x1A, 0x0000);
! 736: maestro_write_codec(sc, 0x1C, 0x0000);
! 737: maestro_write_codec(sc, 0x02, 0x0404);
! 738: maestro_write_codec(sc, 0x04, 0x0808);
! 739: maestro_write_codec(sc, 0x0C, 0x801F);
! 740: maestro_write_codec(sc, 0x0E, 0x801F);
! 741: /* no control over the mixer, sorry */
! 742: sc->codec_if = NULL;
! 743: } else {
! 744: /* Attach the AC'97 */
! 745: sc->host_if.arg = sc;
! 746: sc->host_if.attach = maestro_attach_codec;
! 747: sc->host_if.read = maestro_read_codec;
! 748: sc->host_if.write = maestro_write_codec;
! 749: sc->host_if.reset = maestro_reset_codec;
! 750: if (ac97_attach(&sc->host_if) != 0) {
! 751: printf("%s: couldn't attach codec\n", sc->dev.dv_xname);
! 752: goto bad;
! 753: }
! 754: }
! 755:
! 756: sc->play.mode = MAESTRO_PLAY;
! 757: sc->play.sc = sc;
! 758: sc->play.num = 0;
! 759: sc->record.sc = sc;
! 760: sc->record.num = 2;
! 761: sc->record.mode = 0;
! 762:
! 763: /* Attach audio */
! 764: audio_attach_mi(&maestro_hw_if, sc, &sc->dev);
! 765:
! 766: /* Hook power changes */
! 767: sc->suspend = PWR_RESUME;
! 768: sc->powerhook = powerhook_establish(maestro_powerhook, sc);
! 769:
! 770: return;
! 771:
! 772: bad:
! 773: /* Power down. */
! 774: maestro_power(sc, PPMI_D3);
! 775: if (sc->ih)
! 776: pci_intr_disestablish(pc, sc->ih);
! 777: printf("%s: disabled\n", sc->dev.dv_xname);
! 778: if (sc->dmapool)
! 779: salloc_destroy(sc->dmapool);
! 780: if (dmastage >= 3)
! 781: bus_dmamap_destroy(sc->dmat, sc->dmamap);
! 782: if (dmastage >= 2)
! 783: bus_dmamem_unmap(sc->dmat, sc->dmabase, sc->dmasize);
! 784: if (dmastage >= 1)
! 785: bus_dmamem_free(sc->dmat, &sc->dmaseg, 1);
! 786: }
! 787:
! 788: void
! 789: maestro_init(sc)
! 790: struct maestro_softc *sc;
! 791: {
! 792: int reg;
! 793: pcireg_t data;
! 794:
! 795: /* Disable all legacy emulations. */
! 796: data = pci_conf_read(sc->pc, sc->pt, CONF_LEGACY);
! 797: data |= LEGACY_DISABLED;
! 798: pci_conf_write(sc->pc, sc->pt, CONF_LEGACY, data);
! 799:
! 800: /* Disconnect from CHI. (Makes Dell inspiron 7500 work?)
! 801: * Enable posted write.
! 802: * Prefer PCI timing rather than that of ISA.
! 803: * Don't swap L/R. */
! 804: data = pci_conf_read(sc->pc, sc->pt, CONF_MAESTRO);
! 805: data |= MAESTRO_CHIBUS | MAESTRO_POSTEDWRITE | MAESTRO_DMA_PCITIMING;
! 806: data &= ~MAESTRO_SWAP_LR;
! 807: pci_conf_write(sc->pc, sc->pt, CONF_MAESTRO, data);
! 808: /* Reset direct sound. */
! 809: bus_space_write_2(sc->iot, sc->ioh, PORT_HOSTINT_CTRL,
! 810: HOSTINT_CTRL_DSOUND_RESET);
! 811: DELAY(10000); /* XXX - too long? */
! 812: bus_space_write_2(sc->iot, sc->ioh, PORT_HOSTINT_CTRL, 0);
! 813: DELAY(10000);
! 814:
! 815: /* Enable direct sound and hardware volume control interruptions. */
! 816: bus_space_write_2(sc->iot, sc->ioh, PORT_HOSTINT_CTRL,
! 817: HOSTINT_CTRL_DSOUND_INT_ENABLED | HOSTINT_CTRL_HWVOL_ENABLED);
! 818:
! 819: /* Setup Wave Processor. */
! 820:
! 821: /* Enable WaveCache, set DMA base address. */
! 822: wp_reg_write(sc, WPREG_WAVE_ROMRAM,
! 823: WP_WAVE_VIRTUAL_ENABLED | WP_WAVE_DRAM_ENABLED);
! 824: bus_space_write_2(sc->iot, sc->ioh, PORT_WAVCACHE_CTRL,
! 825: WAVCACHE_ENABLED | WAVCACHE_WTSIZE_4MB);
! 826:
! 827: for (reg = WAVCACHE_PCMBAR; reg < WAVCACHE_PCMBAR + 4; reg++)
! 828: wc_reg_write(sc, reg,
! 829: sc->physaddr >> WAVCACHE_BASEADDR_SHIFT);
! 830:
! 831: /* Setup Codec/Ringbus. */
! 832: maestro_initcodec(sc);
! 833: bus_space_write_4(sc->iot, sc->ioh, PORT_RINGBUS_CTRL,
! 834: RINGBUS_CTRL_RINGBUS_ENABLED | RINGBUS_CTRL_ACLINK_ENABLED);
! 835:
! 836: wp_reg_write(sc, WPREG_BASE, 0x8500); /* Parallel I/O */
! 837: ringbus_setdest(sc, RINGBUS_SRC_ADC,
! 838: RINGBUS_DEST_STEREO | RINGBUS_DEST_DSOUND_IN);
! 839: ringbus_setdest(sc, RINGBUS_SRC_DSOUND,
! 840: RINGBUS_DEST_STEREO | RINGBUS_DEST_DAC);
! 841:
! 842: /* Setup ASSP. Needed for Dell Inspiron 7500? */
! 843: bus_space_write_1(sc->iot, sc->ioh, PORT_ASSP_CTRL_B, 0x00);
! 844: bus_space_write_1(sc->iot, sc->ioh, PORT_ASSP_CTRL_A, 0x03);
! 845: bus_space_write_1(sc->iot, sc->ioh, PORT_ASSP_CTRL_C, 0x00);
! 846:
! 847: /*
! 848: * Reset hw volume to a known value so that we may handle diffs
! 849: * off to AC'97.
! 850: */
! 851:
! 852: bus_space_write_1(sc->iot, sc->ioh, PORT_HWVOL_MASTER, MIDDLE_VOLUME);
! 853: /* Setup GPIO if needed (NEC systems) */
! 854: if (sc->flags & MAESTRO_FLAG_SETUPGPIO) {
! 855: /* Matthew Braithwaite <matt@braithwaite.net> reported that
! 856: * NEC Versa LX doesn't need GPIO operation. */
! 857: bus_space_write_2(sc->iot, sc->ioh,
! 858: PORT_GPIO_MASK, 0x9ff);
! 859: bus_space_write_2(sc->iot, sc->ioh, PORT_GPIO_DIR,
! 860: bus_space_read_2(sc->iot, sc->ioh, PORT_GPIO_DIR) | 0x600);
! 861: bus_space_write_2(sc->iot, sc->ioh,
! 862: PORT_GPIO_DATA, 0x200);
! 863: }
! 864: }
! 865:
! 866: /* -----------------------------
! 867: * Audio interface
! 868: */
! 869:
! 870: int
! 871: maestro_round_blocksize(self, blk)
! 872: void *self;
! 873: int blk;
! 874: {
! 875: return ((blk + 0xf) & ~0xf);
! 876: }
! 877:
! 878: void *
! 879: maestro_malloc(arg, dir, size, pool, flags)
! 880: void *arg;
! 881: int dir;
! 882: size_t size;
! 883: int pool, flags;
! 884: {
! 885: struct maestro_softc *sc = (struct maestro_softc *)arg;
! 886:
! 887: return (salloc_alloc(sc->dmapool, size));
! 888: }
! 889:
! 890: void
! 891: maestro_free(self, ptr, pool)
! 892: void *self, *ptr;
! 893: int pool;
! 894: {
! 895: struct maestro_softc *sc = (struct maestro_softc *)self;
! 896:
! 897: salloc_free(sc->dmapool, ptr);
! 898: }
! 899:
! 900: paddr_t
! 901: maestro_mappage(self, mem, off, prot)
! 902: void *self, *mem;
! 903: off_t off;
! 904: int prot;
! 905: {
! 906: struct maestro_softc *sc = (struct maestro_softc *)self;
! 907:
! 908: if (off < 0)
! 909: return -1;
! 910: return bus_dmamem_mmap(sc->dmat, &sc->dmaseg, 1,
! 911: off, prot, BUS_DMA_WAITOK);
! 912: }
! 913:
! 914: int
! 915: maestro_get_props(self)
! 916: void *self;
! 917: {
! 918: /* struct maestro_softc *sc = (struct maestro_softc *)self; */
! 919:
! 920: return (AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT); /* XXX */
! 921: }
! 922:
! 923: int
! 924: maestro_getdev(self, retp)
! 925: void *self;
! 926: struct audio_device *retp;
! 927: {
! 928: struct maestro_softc *sc = (struct maestro_softc *)self;
! 929:
! 930: *retp = *sc->sc_audev;
! 931: return 0;
! 932: }
! 933:
! 934: int
! 935: maestro_set_port(self, cp)
! 936: void *self;
! 937: mixer_ctrl_t *cp;
! 938: {
! 939: struct ac97_codec_if *c = ((struct maestro_softc *)self)->codec_if;
! 940:
! 941: if (c)
! 942: return (c->vtbl->mixer_set_port(c, cp));
! 943: else
! 944: return (ENXIO);
! 945: }
! 946:
! 947: int
! 948: maestro_get_port(self, cp)
! 949: void *self;
! 950: mixer_ctrl_t *cp;
! 951: {
! 952: struct ac97_codec_if *c = ((struct maestro_softc *)self)->codec_if;
! 953:
! 954: if (c)
! 955: return (c->vtbl->mixer_get_port(c, cp));
! 956: else
! 957: return (ENXIO);
! 958: }
! 959:
! 960: int
! 961: maestro_query_devinfo(self, cp)
! 962: void *self;
! 963: mixer_devinfo_t *cp;
! 964: {
! 965: struct ac97_codec_if *c = ((struct maestro_softc *)self)->codec_if;
! 966:
! 967: if (c)
! 968: return (c->vtbl->query_devinfo(c, cp));
! 969: else
! 970: return (ENXIO);
! 971: }
! 972:
! 973: struct audio_encoding maestro_tab[] = {
! 974: {0, AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE, 16, 0},
! 975: {1, AudioEslinear, AUDIO_ENCODING_SLINEAR, 8, 0},
! 976: {2, AudioEulinear, AUDIO_ENCODING_ULINEAR, 8, 0},
! 977: {3, AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 16,
! 978: AUDIO_ENCODINGFLAG_EMULATED},
! 979: {4, AudioEulinear_le, AUDIO_ENCODING_ULINEAR_LE, 16,
! 980: AUDIO_ENCODINGFLAG_EMULATED},
! 981: {5, AudioEulinear_be, AUDIO_ENCODING_ULINEAR_BE, 16,
! 982: AUDIO_ENCODINGFLAG_EMULATED},
! 983: {6, AudioEmulaw, AUDIO_ENCODING_ULAW, 8,
! 984: AUDIO_ENCODINGFLAG_EMULATED},
! 985: {7, AudioEalaw, AUDIO_ENCODING_ALAW, 8,
! 986: AUDIO_ENCODINGFLAG_EMULATED}
! 987: };
! 988:
! 989: int
! 990: maestro_query_encoding(hdl, fp)
! 991: void *hdl;
! 992: struct audio_encoding *fp;
! 993: {
! 994: if (fp->index < 0 || fp->index >= lengthof(maestro_tab))
! 995: return (EINVAL);
! 996: *fp = maestro_tab[fp->index];
! 997: return (0);
! 998: }
! 999:
! 1000: #define UNUSED __attribute__((unused))
! 1001:
! 1002: void
! 1003: maestro_set_speed(ch, prate)
! 1004: struct maestro_channel *ch;
! 1005: u_long *prate;
! 1006: {
! 1007: ch->speed = *prate;
! 1008: if ((ch->mode & (MAESTRO_8BIT | MAESTRO_STEREO)) == MAESTRO_8BIT)
! 1009: ch->speed /= 2;
! 1010:
! 1011: /* special common case */
! 1012: if (ch->speed == 48000) {
! 1013: ch->dv = 0x10000;
! 1014: } else {
! 1015: /* compute 16 bits fixed point value of speed/48000,
! 1016: * being careful not to overflow */
! 1017: ch->dv = (((ch->speed % 48000) << 16U) + 24000) / 48000
! 1018: + ((ch->speed / 48000) << 16U);
! 1019: /* And this is the real rate obtained */
! 1020: ch->speed = (ch->dv >> 16U) * 48000 +
! 1021: (((ch->dv & 0xffff)*48000)>>16U);
! 1022: }
! 1023: *prate = ch->speed;
! 1024: if ((ch->mode & (MAESTRO_8BIT | MAESTRO_STEREO)) == MAESTRO_8BIT)
! 1025: *prate *= 2;
! 1026: }
! 1027:
! 1028: u_int
! 1029: maestro_calc_timer_freq(ch)
! 1030: struct maestro_channel *ch;
! 1031: {
! 1032: u_int ss = 2;
! 1033:
! 1034: if (ch->mode & MAESTRO_8BIT)
! 1035: ss = 1;
! 1036: return (ch->speed * ss) / ch->blocksize;
! 1037: }
! 1038:
! 1039: void
! 1040: maestro_update_timer(sc)
! 1041: struct maestro_softc *sc;
! 1042: {
! 1043: u_int freq = 0;
! 1044: u_int n;
! 1045:
! 1046: if (sc->play.mode & MAESTRO_RUNNING)
! 1047: freq = maestro_calc_timer_freq(&sc->play);
! 1048: if (sc->record.mode & MAESTRO_RUNNING) {
! 1049: n = maestro_calc_timer_freq(&sc->record);
! 1050: if (freq < n)
! 1051: freq = n;
! 1052: }
! 1053: if (freq) {
! 1054: wp_settimer(sc, freq);
! 1055: wp_starttimer(sc);
! 1056: } else
! 1057: wp_stoptimer(sc);
! 1058: }
! 1059:
! 1060:
! 1061: int
! 1062: maestro_set_params(hdl, setmode, usemode, play, rec)
! 1063: void *hdl;
! 1064: int setmode, usemode;
! 1065: struct audio_params *play, *rec;
! 1066: {
! 1067: struct maestro_softc *sc = (struct maestro_softc *)hdl;
! 1068:
! 1069: if ((setmode & AUMODE_PLAY) == 0)
! 1070: return (0);
! 1071:
! 1072: /* Disallow parameter change on a running audio for now */
! 1073: if (sc->play.mode & MAESTRO_RUNNING)
! 1074: return (EINVAL);
! 1075:
! 1076: if (play->sample_rate < 4000)
! 1077: play->sample_rate = 4000;
! 1078: else if (play->sample_rate > 48000)
! 1079: play->sample_rate = 48000;
! 1080:
! 1081: play->factor = 1;
! 1082: play->sw_code = NULL;
! 1083: if (play->channels != 1 && play->channels != 2)
! 1084: return (EINVAL);
! 1085:
! 1086:
! 1087: sc->play.mode = MAESTRO_PLAY;
! 1088: if (play->channels == 2)
! 1089: sc->play.mode |= MAESTRO_STEREO;
! 1090:
! 1091: if (play->encoding == AUDIO_ENCODING_ULAW) {
! 1092: play->factor = 2;
! 1093: play->sw_code = mulaw_to_slinear16_le;
! 1094: } else if (play->encoding == AUDIO_ENCODING_ALAW) {
! 1095: play->factor = 2;
! 1096: play->sw_code = alaw_to_slinear16_le;
! 1097: } else if (play->precision == 8) {
! 1098: sc->play.mode |= MAESTRO_8BIT;
! 1099: if (play->encoding == AUDIO_ENCODING_ULINEAR_LE ||
! 1100: play->encoding == AUDIO_ENCODING_ULINEAR_BE)
! 1101: sc->play.mode |= MAESTRO_UNSIGNED;
! 1102: }
! 1103: else if (play->encoding == AUDIO_ENCODING_ULINEAR_LE)
! 1104: play->sw_code = change_sign16_le;
! 1105: else if (play->encoding == AUDIO_ENCODING_SLINEAR_BE)
! 1106: play->sw_code = swap_bytes;
! 1107: else if (play->encoding == AUDIO_ENCODING_ULINEAR_BE)
! 1108: play->sw_code = change_sign16_swap_bytes_le;
! 1109: else if (play->encoding != AUDIO_ENCODING_SLINEAR_LE)
! 1110: return (EINVAL);
! 1111:
! 1112: maestro_set_speed(&sc->play, &play->sample_rate);
! 1113: return (0);
! 1114: }
! 1115:
! 1116: int
! 1117: maestro_open(hdl, flags)
! 1118: void *hdl;
! 1119: int flags;
! 1120: {
! 1121: struct maestro_softc *sc = (struct maestro_softc *)hdl;
! 1122: DPRINTF(("%s: open(%d)\n", sc->dev.dv_xname, flags));
! 1123:
! 1124: /* XXX work around VM brokeness */
! 1125: #if 0
! 1126: if ((OFLAGS(flags) & O_ACCMODE) != O_WRONLY)
! 1127: return (EINVAL);
! 1128: #endif
! 1129: sc->play.mode = MAESTRO_PLAY;
! 1130: sc->record.mode = 0;
! 1131: #ifdef AUDIO_DEBUG
! 1132: maestrointr_called = 0;
! 1133: maestrodma_effective = 0;
! 1134: #endif
! 1135: return (0);
! 1136: }
! 1137:
! 1138: void
! 1139: maestro_close(hdl)
! 1140: void *hdl;
! 1141: {
! 1142: struct maestro_softc *sc UNUSED = (struct maestro_softc *)hdl;
! 1143: /* nothing to do */
! 1144: }
! 1145:
! 1146:
! 1147: void
! 1148: maestro_channel_stop(ch)
! 1149: struct maestro_channel *ch;
! 1150: {
! 1151: wp_apu_write(ch->sc, ch->num, APUREG_APUTYPE,
! 1152: APUTYPE_INACTIVE << APU_APUTYPE_SHIFT);
! 1153: if (ch->mode & MAESTRO_STEREO)
! 1154: wp_apu_write(ch->sc, ch->num+1, APUREG_APUTYPE,
! 1155: APUTYPE_INACTIVE << APU_APUTYPE_SHIFT);
! 1156: /* four channels for record... */
! 1157: if (ch->mode & MAESTRO_PLAY)
! 1158: return;
! 1159: wp_apu_write(ch->sc, ch->num+2, APUREG_APUTYPE,
! 1160: APUTYPE_INACTIVE << APU_APUTYPE_SHIFT);
! 1161: if (ch->mode & MAESTRO_STEREO)
! 1162: wp_apu_write(ch->sc, ch->num+3, APUREG_APUTYPE,
! 1163: APUTYPE_INACTIVE << APU_APUTYPE_SHIFT);
! 1164:
! 1165: }
! 1166:
! 1167: int
! 1168: maestro_halt_input(hdl)
! 1169: void *hdl;
! 1170: {
! 1171: struct maestro_softc *sc = (struct maestro_softc *)hdl;
! 1172: maestro_channel_stop(&sc->record);
! 1173: sc->record.mode &= ~MAESTRO_RUNNING;
! 1174: maestro_update_timer(sc);
! 1175: return 0;
! 1176: }
! 1177:
! 1178: int
! 1179: maestro_halt_output(hdl)
! 1180: void *hdl;
! 1181: {
! 1182: struct maestro_softc *sc = (struct maestro_softc *)hdl;
! 1183:
! 1184: maestro_channel_stop(&sc->play);
! 1185: sc->play.mode &= ~MAESTRO_RUNNING;
! 1186: maestro_update_timer(sc);
! 1187: return 0;
! 1188: }
! 1189:
! 1190: int
! 1191: maestro_trigger_input(hdl, start, end, blksize, intr, arg, param)
! 1192: void *hdl;
! 1193: void *start, *end;
! 1194: int blksize;
! 1195: void (*intr)(void *);
! 1196: void *arg;
! 1197: struct audio_params *param;
! 1198: {
! 1199: struct maestro_softc *sc = (struct maestro_softc *)hdl;
! 1200:
! 1201: sc->record.mode |= MAESTRO_RUNNING;
! 1202: sc->record.blocksize = blksize;
! 1203:
! 1204: maestro_channel_start(&sc->record);
! 1205:
! 1206: sc->record.threshold = sc->record.start;
! 1207: maestro_update_timer(sc);
! 1208: return 0;
! 1209: }
! 1210:
! 1211: void
! 1212: maestro_channel_start(ch)
! 1213: struct maestro_channel *ch;
! 1214: {
! 1215: struct maestro_softc *sc = ch->sc;
! 1216: int n = ch->num;
! 1217: int aputype;
! 1218: wcreg_t wcreg = (sc->physaddr - 16) & WAVCACHE_CHCTL_ADDRTAG_MASK;
! 1219:
! 1220: switch(ch->mode & (MAESTRO_STEREO | MAESTRO_8BIT)) {
! 1221: case 0:
! 1222: aputype = APUTYPE_16BITLINEAR;
! 1223: break;
! 1224: case MAESTRO_STEREO:
! 1225: aputype = APUTYPE_16BITSTEREO;
! 1226: break;
! 1227: case MAESTRO_8BIT:
! 1228: aputype = APUTYPE_8BITLINEAR;
! 1229: break;
! 1230: case MAESTRO_8BIT|MAESTRO_STEREO:
! 1231: aputype = APUTYPE_8BITSTEREO;
! 1232: break;
! 1233: }
! 1234: if (ch->mode & MAESTRO_UNSIGNED)
! 1235: wcreg |= WAVCACHE_CHCTL_U8;
! 1236: if ((ch->mode & MAESTRO_STEREO) == 0) {
! 1237: DPRINTF(("Setting mono parameters\n"));
! 1238: wp_apu_write(sc, n, APUREG_WAVESPACE, ch->wpwa & 0xff00);
! 1239: wp_apu_write(sc, n, APUREG_CURPTR, ch->current);
! 1240: wp_apu_write(sc, n, APUREG_ENDPTR, ch->end);
! 1241: wp_apu_write(sc, n, APUREG_LOOPLEN, ch->end - ch->start);
! 1242: wp_apu_write(sc, n, APUREG_AMPLITUDE, 0xe800);
! 1243: wp_apu_write(sc, n, APUREG_POSITION, 0x8f00
! 1244: | (RADIUS_CENTERCIRCLE << APU_RADIUS_SHIFT)
! 1245: | (PAN_FRONT << APU_PAN_SHIFT));
! 1246: wp_apu_write(sc, n, APUREG_FREQ_LOBYTE, APU_plus6dB
! 1247: | ((ch->dv & 0xff) << APU_FREQ_LOBYTE_SHIFT));
! 1248: wp_apu_write(sc, n, APUREG_FREQ_HIWORD, ch->dv >> 8);
! 1249: wc_ctrl_write(sc, n, wcreg);
! 1250: wp_apu_write(sc, n, APUREG_APUTYPE,
! 1251: (aputype << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf);
! 1252: } else {
! 1253: wcreg |= WAVCACHE_CHCTL_STEREO;
! 1254: DPRINTF(("Setting stereo parameters\n"));
! 1255: wp_apu_write(sc, n+1, APUREG_WAVESPACE, ch->wpwa & 0xff00);
! 1256: wp_apu_write(sc, n+1, APUREG_CURPTR, ch->current);
! 1257: wp_apu_write(sc, n+1, APUREG_ENDPTR, ch->end);
! 1258: wp_apu_write(sc, n+1, APUREG_LOOPLEN, ch->end - ch->start);
! 1259: wp_apu_write(sc, n+1, APUREG_AMPLITUDE, 0xe800);
! 1260: wp_apu_write(sc, n+1, APUREG_POSITION, 0x8f00
! 1261: | (RADIUS_CENTERCIRCLE << APU_RADIUS_SHIFT)
! 1262: | (PAN_LEFT << APU_PAN_SHIFT));
! 1263: wp_apu_write(sc, n+1, APUREG_FREQ_LOBYTE, APU_plus6dB
! 1264: | ((ch->dv & 0xff) << APU_FREQ_LOBYTE_SHIFT));
! 1265: wp_apu_write(sc, n+1, APUREG_FREQ_HIWORD, ch->dv >> 8);
! 1266: if (ch->mode & MAESTRO_8BIT)
! 1267: wp_apu_write(sc, n, APUREG_WAVESPACE,
! 1268: ch->wpwa & 0xff00);
! 1269: else
! 1270: wp_apu_write(sc, n, APUREG_WAVESPACE,
! 1271: (ch->wpwa|(APU_STEREO >> 1)) & 0xff00);
! 1272: wp_apu_write(sc, n, APUREG_CURPTR, ch->current);
! 1273: wp_apu_write(sc, n, APUREG_ENDPTR, ch->end);
! 1274: wp_apu_write(sc, n, APUREG_LOOPLEN, ch->end - ch->start);
! 1275: wp_apu_write(sc, n, APUREG_AMPLITUDE, 0xe800);
! 1276: wp_apu_write(sc, n, APUREG_POSITION, 0x8f00
! 1277: | (RADIUS_CENTERCIRCLE << APU_RADIUS_SHIFT)
! 1278: | (PAN_RIGHT << APU_PAN_SHIFT));
! 1279: wp_apu_write(sc, n, APUREG_FREQ_LOBYTE, APU_plus6dB
! 1280: | ((ch->dv & 0xff) << APU_FREQ_LOBYTE_SHIFT));
! 1281: wp_apu_write(sc, n, APUREG_FREQ_HIWORD, ch->dv >> 8);
! 1282: wc_ctrl_write(sc, n, wcreg);
! 1283: wc_ctrl_write(sc, n+1, wcreg);
! 1284: wp_apu_write(sc, n, APUREG_APUTYPE,
! 1285: (aputype << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf);
! 1286: wp_apu_write(sc, n+1, APUREG_APUTYPE,
! 1287: (aputype << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf);
! 1288: }
! 1289: }
! 1290:
! 1291: int
! 1292: maestro_trigger_output(hdl, start, end, blksize, intr, arg, param)
! 1293: void *hdl;
! 1294: void *start, *end;
! 1295: int blksize;
! 1296: void (*intr)(void *);
! 1297: void *arg;
! 1298: struct audio_params *param;
! 1299: {
! 1300: struct maestro_softc *sc = (struct maestro_softc *)hdl;
! 1301:
! 1302: u_int offset = ((caddr_t)start - sc->dmabase) >> 1;
! 1303: u_int size = ((char *)end - (char *)start) >> 1;
! 1304: sc->play.mode |= MAESTRO_RUNNING;
! 1305: sc->play.wpwa = APU_USE_SYSMEM | (offset >> 8);
! 1306: DPRINTF(("maestro_trigger_output: start=%x, end=%x, blksize=%x ",
! 1307: start, end, blksize));
! 1308: DPRINTF(("offset = %x, size=%x\n", offset, size));
! 1309:
! 1310: sc->play.intr = intr;
! 1311: sc->play.intr_arg = arg;
! 1312: sc->play.blocksize = blksize;
! 1313: sc->play.end = offset+size;
! 1314: sc->play.start = offset;
! 1315: sc->play.current = sc->play.start;
! 1316: if ((sc->play.mode & (MAESTRO_STEREO | MAESTRO_8BIT)) == MAESTRO_STEREO) {
! 1317: sc->play.wpwa >>= 1;
! 1318: sc->play.start >>= 1;
! 1319: sc->play.end >>= 1;
! 1320: sc->play.blocksize >>= 1;
! 1321: }
! 1322: maestro_channel_start(&sc->play);
! 1323:
! 1324: sc->play.threshold = sc->play.start;
! 1325: maestro_update_timer(sc);
! 1326:
! 1327: return 0;
! 1328: }
! 1329:
! 1330: /* -----------------------------
! 1331: * Codec interface
! 1332: */
! 1333:
! 1334: int
! 1335: maestro_read_codec(self, regno, datap)
! 1336: void *self;
! 1337: u_int8_t regno;
! 1338: u_int16_t *datap;
! 1339: {
! 1340: struct maestro_softc *sc = (struct maestro_softc *)self;
! 1341: int t;
! 1342:
! 1343: /* We have to wait for a SAFE time to write addr/data */
! 1344: for (t = 0; t < 20; t++) {
! 1345: if ((bus_space_read_1(sc->iot, sc->ioh, PORT_CODEC_STAT)
! 1346: & CODEC_STAT_MASK) != CODEC_STAT_PROGLESS)
! 1347: break;
! 1348: DELAY(2); /* 20.8us / 13 */
! 1349: }
! 1350: if (t == 20)
! 1351: printf("%s: maestro_read_codec() PROGLESS timed out.\n",
! 1352: sc->dev.dv_xname);
! 1353: /* XXX return 1 */
! 1354:
! 1355: bus_space_write_1(sc->iot, sc->ioh, PORT_CODEC_CMD,
! 1356: CODEC_CMD_READ | regno);
! 1357: DELAY(21); /* AC97 cycle = 20.8usec */
! 1358:
! 1359: /* Wait for data retrieve */
! 1360: for (t = 0; t < 20; t++) {
! 1361: if ((bus_space_read_1(sc->iot, sc->ioh, PORT_CODEC_STAT)
! 1362: & CODEC_STAT_MASK) == CODEC_STAT_RW_DONE)
! 1363: break;
! 1364: DELAY(2); /* 20.8us / 13 */
! 1365: }
! 1366: if (t == 20)
! 1367: /* Timed out, but perform dummy read. */
! 1368: printf("%s: maestro_read_codec() RW_DONE timed out.\n",
! 1369: sc->dev.dv_xname);
! 1370:
! 1371: *datap = bus_space_read_2(sc->iot, sc->ioh, PORT_CODEC_REG);
! 1372: return 0;
! 1373: }
! 1374:
! 1375: int
! 1376: maestro_write_codec(self, regno, data)
! 1377: void *self;
! 1378: u_int8_t regno;
! 1379: u_int16_t data;
! 1380: {
! 1381: struct maestro_softc *sc = (struct maestro_softc *)self;
! 1382: int t;
! 1383:
! 1384: /* We have to wait for a SAFE time to write addr/data */
! 1385: for (t = 0; t < 20; t++) {
! 1386: if ((bus_space_read_1(sc->iot, sc->ioh, PORT_CODEC_STAT)
! 1387: & CODEC_STAT_MASK) != CODEC_STAT_PROGLESS)
! 1388: break;
! 1389: DELAY(2); /* 20.8us / 13 */
! 1390: }
! 1391: if (t == 20) {
! 1392: /* Timed out. Abort writing. */
! 1393: printf("%s: maestro_write_codec() PROGLESS timed out.\n",
! 1394: sc->dev.dv_xname);
! 1395: return 1;
! 1396: }
! 1397:
! 1398: bus_space_write_2(sc->iot, sc->ioh, PORT_CODEC_REG, data);
! 1399: bus_space_write_1(sc->iot, sc->ioh, PORT_CODEC_CMD,
! 1400: CODEC_CMD_WRITE | regno);
! 1401:
! 1402: return 0;
! 1403: }
! 1404:
! 1405: int
! 1406: maestro_attach_codec(self, cif)
! 1407: void *self;
! 1408: struct ac97_codec_if *cif;
! 1409: {
! 1410: struct maestro_softc *sc = (struct maestro_softc *)self;
! 1411:
! 1412: sc->codec_if = cif;
! 1413: return 0;
! 1414: }
! 1415:
! 1416: void
! 1417: maestro_reset_codec(self)
! 1418: void *self UNUSED;
! 1419: {
! 1420: }
! 1421:
! 1422: void
! 1423: maestro_initcodec(self)
! 1424: void *self;
! 1425: {
! 1426: struct maestro_softc *sc = (struct maestro_softc *)self;
! 1427: u_int16_t data;
! 1428:
! 1429: if (bus_space_read_4(sc->iot, sc->ioh, PORT_RINGBUS_CTRL)
! 1430: & RINGBUS_CTRL_ACLINK_ENABLED) {
! 1431: bus_space_write_4(sc->iot, sc->ioh, PORT_RINGBUS_CTRL, 0);
! 1432: DELAY(104); /* 20.8us * (4 + 1) */
! 1433: }
! 1434: /* XXX - 2nd codec should be looked at. */
! 1435: bus_space_write_4(sc->iot, sc->ioh,
! 1436: PORT_RINGBUS_CTRL, RINGBUS_CTRL_AC97_SWRESET);
! 1437: DELAY(2);
! 1438: bus_space_write_4(sc->iot, sc->ioh,
! 1439: PORT_RINGBUS_CTRL, RINGBUS_CTRL_ACLINK_ENABLED);
! 1440: DELAY(21);
! 1441:
! 1442: maestro_read_codec(sc, 0, &data);
! 1443: if ((bus_space_read_1(sc->iot, sc->ioh, PORT_CODEC_STAT)
! 1444: & CODEC_STAT_MASK) != 0) {
! 1445: bus_space_write_4(sc->iot, sc->ioh,
! 1446: PORT_RINGBUS_CTRL, 0);
! 1447: DELAY(21);
! 1448:
! 1449: /* Try cold reset. */
! 1450: printf("%s: resetting codec\n", sc->dev.dv_xname);
! 1451:
! 1452: data = bus_space_read_2(sc->iot, sc->ioh, PORT_GPIO_DIR);
! 1453: if (pci_conf_read(sc->pc, sc->pt, 0x58) & 1)
! 1454: data |= 0x10;
! 1455: data |= 0x009 &
! 1456: ~bus_space_read_2(sc->iot, sc->ioh, PORT_GPIO_DATA);
! 1457: bus_space_write_2(sc->iot, sc->ioh,
! 1458: PORT_GPIO_MASK, 0xff6);
! 1459: bus_space_write_2(sc->iot, sc->ioh,
! 1460: PORT_GPIO_DIR, data | 0x009);
! 1461: bus_space_write_2(sc->iot, sc->ioh,
! 1462: PORT_GPIO_DATA, 0x000);
! 1463: DELAY(2);
! 1464: bus_space_write_2(sc->iot, sc->ioh,
! 1465: PORT_GPIO_DATA, 0x001);
! 1466: DELAY(1);
! 1467: bus_space_write_2(sc->iot, sc->ioh,
! 1468: PORT_GPIO_DATA, 0x009);
! 1469: DELAY(500000);
! 1470: bus_space_write_2(sc->iot, sc->ioh,
! 1471: PORT_GPIO_DIR, data);
! 1472: DELAY(84); /* 20.8us * 4 */
! 1473: bus_space_write_4(sc->iot, sc->ioh,
! 1474: PORT_RINGBUS_CTRL, RINGBUS_CTRL_ACLINK_ENABLED);
! 1475: DELAY(21);
! 1476: }
! 1477:
! 1478: /* Check the codec to see is still busy */
! 1479: if ((bus_space_read_1(sc->iot, sc->ioh, PORT_CODEC_STAT) &
! 1480: CODEC_STAT_MASK) != 0) {
! 1481: printf("%s: codec failure\n", sc->dev.dv_xname);
! 1482: }
! 1483: }
! 1484:
! 1485: /* -----------------------------
! 1486: * Power management interface
! 1487: */
! 1488:
! 1489: void
! 1490: maestro_powerhook(why, self)
! 1491: int why;
! 1492: void *self;
! 1493: {
! 1494: struct maestro_softc *sc = (struct maestro_softc *)self;
! 1495:
! 1496: if (why != PWR_RESUME) {
! 1497: /* Power down device on shutdown. */
! 1498: DPRINTF(("maestro: power down\n"));
! 1499: sc->suspend = why;
! 1500: if (sc->record.mode & MAESTRO_RUNNING) {
! 1501: sc->record.current = wp_apu_read(sc, sc->record.num, APUREG_CURPTR);
! 1502: maestro_channel_stop(&sc->record);
! 1503: }
! 1504: if (sc->play.mode & MAESTRO_RUNNING) {
! 1505: sc->play.current = wp_apu_read(sc, sc->play.num, APUREG_CURPTR);
! 1506: maestro_channel_stop(&sc->play);
! 1507: }
! 1508:
! 1509: wp_stoptimer(sc);
! 1510:
! 1511: /* Power down everything except clock. */
! 1512: bus_space_write_2(sc->iot, sc->ioh, PORT_HOSTINT_CTRL, 0);
! 1513: maestro_write_codec(sc, AC97_REG_POWER, 0xdf00);
! 1514: DELAY(20);
! 1515: bus_space_write_4(sc->iot, sc->ioh, PORT_RINGBUS_CTRL, 0);
! 1516: DELAY(1);
! 1517: maestro_power(sc, PPMI_D3);
! 1518: } else {
! 1519: /* Power up device on resume. */
! 1520: DPRINTF(("maestro: power resume\n"));
! 1521: if (sc->suspend == PWR_RESUME) {
! 1522: printf("%s: resume without suspend?\n",
! 1523: sc->dev.dv_xname);
! 1524: sc->suspend = why;
! 1525: return;
! 1526: }
! 1527: sc->suspend = why;
! 1528: maestro_power(sc, PPMI_D0);
! 1529: DELAY(100000);
! 1530: maestro_init(sc);
! 1531: /* Restore codec settings */
! 1532: if (sc->codec_if)
! 1533: sc->codec_if->vtbl->restore_ports(sc->codec_if);
! 1534: if (sc->play.mode & MAESTRO_RUNNING)
! 1535: maestro_channel_start(&sc->play);
! 1536: if (sc->record.mode & MAESTRO_RUNNING)
! 1537: maestro_channel_start(&sc->record);
! 1538: maestro_update_timer(sc);
! 1539: }
! 1540: }
! 1541:
! 1542: void
! 1543: maestro_power(sc, status)
! 1544: struct maestro_softc *sc;
! 1545: int status;
! 1546: {
! 1547: int data;
! 1548:
! 1549: /* Set the power state of the device. */
! 1550: data = pci_conf_read(sc->pc, sc->pt, CONF_PM_PTR);
! 1551: data = pci_conf_read(sc->pc, sc->pt, data);
! 1552: if (data == PPMI_CID)
! 1553: pci_conf_write(sc->pc, sc->pt, data + PM_CTRL, status);
! 1554: }
! 1555:
! 1556: void
! 1557: maestro_channel_advance_dma(ch)
! 1558: struct maestro_channel *ch;
! 1559: {
! 1560: wpreg_t pos;
! 1561: #ifdef AUDIO_DEBUG
! 1562: maestrointr_called++;
! 1563: #endif
! 1564: for (;;) {
! 1565: pos = wp_apu_read(ch->sc, ch->num, APUREG_CURPTR);
! 1566: /* Are we still processing the current dma block ? */
! 1567: if (pos >= ch->threshold &&
! 1568: pos < ch->threshold + ch->blocksize/2)
! 1569: break;
! 1570: ch->threshold += ch->blocksize/2;
! 1571: if (ch->threshold >= ch->end)
! 1572: ch->threshold = ch->start;
! 1573: (*ch->intr)(ch->intr_arg);
! 1574: #ifdef AUDIO_DEBUG
! 1575: maestrodma_effective++;
! 1576: #endif
! 1577: }
! 1578:
! 1579: #ifdef AUDIO_DEBUG
! 1580: if (maestrodebug && maestrointr_called % 64 == 0)
! 1581: printf("maestro: dma advanced %lu for %lu calls\n",
! 1582: maestrodma_effective, maestrointr_called);
! 1583: #endif
! 1584: }
! 1585:
! 1586: /* Some maestro makes sometimes get desynchronized in stereo mode. */
! 1587: void
! 1588: maestro_channel_suppress_jitter(ch)
! 1589: struct maestro_channel *ch;
! 1590: {
! 1591: int cp, diff;
! 1592:
! 1593: /* Verify that both channels are not too far off. */
! 1594: cp = wp_apu_read(ch->sc, ch->num, APUREG_CURPTR);
! 1595: diff = wp_apu_read(ch->sc, ch->num+1, APUREG_CURPTR) - cp;
! 1596: if (diff > 4 || diff < -4)
! 1597: /* Otherwise, directly resynch the 2nd channel. */
! 1598: bus_space_write_2(ch->sc->iot, ch->sc->ioh,
! 1599: PORT_DSP_DATA, cp);
! 1600: }
! 1601:
! 1602: /* -----------------------------
! 1603: * Interrupt handler interface
! 1604: */
! 1605: int
! 1606: maestro_intr(arg)
! 1607: void *arg;
! 1608: {
! 1609: struct maestro_softc *sc = (struct maestro_softc *)arg;
! 1610: u_int16_t status;
! 1611:
! 1612: status = bus_space_read_1(sc->iot, sc->ioh, PORT_HOSTINT_STAT);
! 1613: if (status == 0)
! 1614: return 0; /* Not for us? */
! 1615:
! 1616: /* Acknowledge all. */
! 1617: bus_space_write_2(sc->iot, sc->ioh, PORT_INT_STAT, 1);
! 1618: bus_space_write_1(sc->iot, sc->ioh, PORT_HOSTINT_STAT, status);
! 1619:
! 1620: /* Hardware volume support */
! 1621: if (status & HOSTINT_STAT_HWVOL && sc->codec_if != NULL) {
! 1622: int n, i, delta, v;
! 1623: mixer_ctrl_t hwvol;
! 1624:
! 1625: n = bus_space_read_1(sc->iot, sc->ioh, PORT_HWVOL_MASTER);
! 1626: /* Special case: Mute key */
! 1627: if (n & 0x11) {
! 1628: hwvol.type = AUDIO_MIXER_ENUM;
! 1629: hwvol.dev =
! 1630: sc->codec_if->vtbl->get_portnum_by_name(sc->codec_if,
! 1631: AudioCoutputs, AudioNmaster, AudioNmute);
! 1632: sc->codec_if->vtbl->mixer_get_port(sc->codec_if, &hwvol);
! 1633: hwvol.un.ord = !hwvol.un.ord;
! 1634: } else {
! 1635: hwvol.type = AUDIO_MIXER_VALUE;
! 1636: hwvol.un.value.num_channels = 2;
! 1637: hwvol.dev =
! 1638: sc->codec_if->vtbl->get_portnum_by_name(
! 1639: sc->codec_if, AudioCoutputs, AudioNmaster,
! 1640: NULL);
! 1641: sc->codec_if->vtbl->mixer_get_port(sc->codec_if, &hwvol);
! 1642: /* XXX AC'97 yields five bits for master volume. */
! 1643: delta = (n - MIDDLE_VOLUME)/STEP_VOLUME * 8;
! 1644: for (i = 0; i < hwvol.un.value.num_channels; i++) {
! 1645: v = ((int)hwvol.un.value.level[i]) + delta;
! 1646: if (v < 0)
! 1647: v = 0;
! 1648: else if (v > 255)
! 1649: v = 255;
! 1650: hwvol.un.value.level[i] = v;
! 1651: }
! 1652: }
! 1653: sc->codec_if->vtbl->mixer_set_port(sc->codec_if, &hwvol);
! 1654: /* Reset to compute next diffs */
! 1655: bus_space_write_1(sc->iot, sc->ioh, PORT_HWVOL_MASTER,
! 1656: MIDDLE_VOLUME);
! 1657: }
! 1658:
! 1659: if (sc->play.mode & MAESTRO_RUNNING) {
! 1660: maestro_channel_advance_dma(&sc->play);
! 1661: if (sc->play.mode & MAESTRO_STEREO)
! 1662: maestro_channel_suppress_jitter(&sc->play);
! 1663: }
! 1664:
! 1665: if (sc->record.mode & MAESTRO_RUNNING)
! 1666: maestro_channel_advance_dma(&sc->record);
! 1667:
! 1668: return 1;
! 1669: }
! 1670:
! 1671: /* -----------------------------
! 1672: * Hardware interface
! 1673: */
! 1674:
! 1675: /* Codec/Ringbus */
! 1676:
! 1677: void
! 1678: ringbus_setdest(struct maestro_softc *sc, int src, int dest)
! 1679: {
! 1680: u_int32_t data;
! 1681:
! 1682: data = bus_space_read_4(sc->iot, sc->ioh, PORT_RINGBUS_CTRL);
! 1683: data &= ~(0xfU << src);
! 1684: data |= (0xfU & dest) << src;
! 1685: bus_space_write_4(sc->iot, sc->ioh, PORT_RINGBUS_CTRL, data);
! 1686: }
! 1687:
! 1688: /* Wave Processor */
! 1689:
! 1690: wpreg_t
! 1691: wp_reg_read(struct maestro_softc *sc, int reg)
! 1692: {
! 1693: bus_space_write_2(sc->iot, sc->ioh, PORT_DSP_INDEX, reg);
! 1694: return bus_space_read_2(sc->iot, sc->ioh, PORT_DSP_DATA);
! 1695: }
! 1696:
! 1697: void
! 1698: wp_reg_write(struct maestro_softc *sc, int reg, wpreg_t data)
! 1699: {
! 1700: bus_space_write_2(sc->iot, sc->ioh, PORT_DSP_INDEX, reg);
! 1701: bus_space_write_2(sc->iot, sc->ioh, PORT_DSP_DATA, data);
! 1702: }
! 1703:
! 1704: static void
! 1705: apu_setindex(struct maestro_softc *sc, int reg)
! 1706: {
! 1707: int t;
! 1708:
! 1709: wp_reg_write(sc, WPREG_CRAM_PTR, reg);
! 1710: /* Sometimes WP fails to set apu register index. */
! 1711: for (t = 0; t < 1000; t++) {
! 1712: if (bus_space_read_2(sc->iot, sc->ioh,
! 1713: PORT_DSP_DATA) == reg)
! 1714: break;
! 1715: bus_space_write_2(sc->iot, sc->ioh, PORT_DSP_DATA, reg);
! 1716: }
! 1717: if (t == 1000)
! 1718: printf("%s: apu_setindex() timeout\n", sc->dev.dv_xname);
! 1719: }
! 1720:
! 1721: wpreg_t
! 1722: wp_apu_read(struct maestro_softc *sc, int ch, int reg)
! 1723: {
! 1724: wpreg_t ret;
! 1725:
! 1726: apu_setindex(sc, ((unsigned)ch << 4) + reg);
! 1727: ret = wp_reg_read(sc, WPREG_DATA_PORT);
! 1728: return ret;
! 1729: }
! 1730:
! 1731: void
! 1732: wp_apu_write(struct maestro_softc *sc, int ch, int reg, wpreg_t data)
! 1733: {
! 1734: int t;
! 1735:
! 1736: apu_setindex(sc, ((unsigned)ch << 4) + reg);
! 1737: wp_reg_write(sc, WPREG_DATA_PORT, data);
! 1738: for (t = 0; t < 1000; t++) {
! 1739: if (bus_space_read_2(sc->iot, sc->ioh, PORT_DSP_DATA) == data)
! 1740: break;
! 1741: bus_space_write_2(sc->iot, sc->ioh, PORT_DSP_DATA, data);
! 1742: }
! 1743: if (t == 1000)
! 1744: printf("%s: wp_apu_write() timeout\n", sc->dev.dv_xname);
! 1745: }
! 1746:
! 1747: void
! 1748: wp_settimer(struct maestro_softc *sc, u_int freq)
! 1749: {
! 1750: u_int clock = 48000 << 2;
! 1751: u_int prescale = 0, divide = (freq != 0) ? (clock / freq) : ~0;
! 1752:
! 1753: if (divide < 4)
! 1754: divide = 4;
! 1755: else if (divide > 32 << 8)
! 1756: divide = 32 << 8;
! 1757:
! 1758: for (; divide > 32 << 1; divide >>= 1)
! 1759: prescale++;
! 1760: divide = (divide + 1) >> 1;
! 1761:
! 1762: for (; prescale < 7 && divide > 2 && !(divide & 1); divide >>= 1)
! 1763: prescale++;
! 1764:
! 1765: wp_reg_write(sc, WPREG_TIMER_ENABLE, 0);
! 1766: wp_reg_write(sc, WPREG_TIMER_FREQ,
! 1767: (prescale << WP_TIMER_FREQ_PRESCALE_SHIFT) | (divide - 1));
! 1768: wp_reg_write(sc, WPREG_TIMER_ENABLE, 1);
! 1769: }
! 1770:
! 1771: void
! 1772: wp_starttimer(struct maestro_softc *sc)
! 1773: {
! 1774: wp_reg_write(sc, WPREG_TIMER_START, 1);
! 1775: }
! 1776:
! 1777: void
! 1778: wp_stoptimer(struct maestro_softc *sc)
! 1779: {
! 1780: wp_reg_write(sc, WPREG_TIMER_START, 0);
! 1781: bus_space_write_2(sc->iot, sc->ioh, PORT_INT_STAT, 1);
! 1782: }
! 1783:
! 1784: /* WaveCache */
! 1785:
! 1786: wcreg_t
! 1787: wc_reg_read(struct maestro_softc *sc, int reg)
! 1788: {
! 1789: bus_space_write_2(sc->iot, sc->ioh, PORT_WAVCACHE_INDEX, reg);
! 1790: return bus_space_read_2(sc->iot, sc->ioh, PORT_WAVCACHE_DATA);
! 1791: }
! 1792:
! 1793: void
! 1794: wc_reg_write(struct maestro_softc *sc, int reg, wcreg_t data)
! 1795: {
! 1796: bus_space_write_2(sc->iot, sc->ioh, PORT_WAVCACHE_INDEX, reg);
! 1797: bus_space_write_2(sc->iot, sc->ioh, PORT_WAVCACHE_DATA, data);
! 1798: }
! 1799:
! 1800: u_int16_t
! 1801: wc_ctrl_read(struct maestro_softc *sc, int ch)
! 1802: {
! 1803: return wc_reg_read(sc, ch << 3);
! 1804: }
! 1805:
! 1806: void
! 1807: wc_ctrl_write(struct maestro_softc *sc, int ch, wcreg_t data)
! 1808: {
! 1809: wc_reg_write(sc, ch << 3, data);
! 1810: }
! 1811:
! 1812: /* -----------------------------
! 1813: * Simple zone allocator.
! 1814: * (All memory allocated in advance)
! 1815: */
! 1816:
! 1817: salloc_t
! 1818: salloc_new(addr, size, nzones)
! 1819: caddr_t addr;
! 1820: size_t size;
! 1821: int nzones;
! 1822: {
! 1823: struct salloc_pool *pool;
! 1824: struct salloc_zone *space;
! 1825: int i;
! 1826:
! 1827: MALLOC(pool, salloc_t, sizeof *pool + nzones * sizeof pool->zones[0],
! 1828: M_TEMP, M_NOWAIT);
! 1829: if (pool == NULL)
! 1830: return NULL;
! 1831: SLIST_INIT(&pool->free);
! 1832: SLIST_INIT(&pool->used);
! 1833: SLIST_INIT(&pool->spare);
! 1834: /* Espie says the following line is obvious */
! 1835: pool->zones = (struct salloc_zone *)(pool + 1);
! 1836: for (i = 1; i < nzones; i++)
! 1837: SLIST_INSERT_HEAD(&pool->spare, &pool->zones[i], link);
! 1838: space = &pool->zones[0];
! 1839: space->addr = addr;
! 1840: space->size = size;
! 1841: SLIST_INSERT_HEAD(&pool->free, space, link);
! 1842: return pool;
! 1843: }
! 1844:
! 1845: void
! 1846: salloc_destroy(pool)
! 1847: salloc_t pool;
! 1848: {
! 1849: FREE(pool, M_TEMP);
! 1850: }
! 1851:
! 1852: void
! 1853: salloc_insert(pool, head, zone, merge)
! 1854: salloc_t pool;
! 1855: struct salloc_head *head;
! 1856: struct salloc_zone *zone;
! 1857: int merge;
! 1858: {
! 1859: struct salloc_zone *prev, *next;
! 1860:
! 1861: /*
! 1862: * Insert a zone into an ordered list of zones, possibly
! 1863: * merging adjacent zones.
! 1864: */
! 1865: prev = NULL;
! 1866: SLIST_FOREACH(next, head, link) {
! 1867: if (next->addr > zone->addr)
! 1868: break;
! 1869: prev = next;
! 1870: }
! 1871:
! 1872: if (merge && prev && prev->addr + prev->size == zone->addr) {
! 1873: prev->size += zone->size;
! 1874: SLIST_INSERT_HEAD(&pool->spare, zone, link);
! 1875: zone = prev;
! 1876: } else if (prev)
! 1877: SLIST_INSERT_AFTER(prev, zone, link);
! 1878: else
! 1879: SLIST_INSERT_HEAD(head, zone, link);
! 1880: if (merge && next && zone->addr + zone->size == next->addr) {
! 1881: zone->size += next->size;
! 1882: SLIST_REMOVE(head, next, salloc_zone, link);
! 1883: SLIST_INSERT_HEAD(&pool->spare, next, link);
! 1884: }
! 1885: }
! 1886:
! 1887: caddr_t
! 1888: salloc_alloc(pool, size)
! 1889: salloc_t pool;
! 1890: size_t size;
! 1891: {
! 1892: struct salloc_zone *zone, *uzone;
! 1893:
! 1894: SLIST_FOREACH(zone, &pool->free, link)
! 1895: if (zone->size >= size)
! 1896: break;
! 1897: if (zone == SLIST_END(&pool->free))
! 1898: return NULL;
! 1899: if (zone->size == size) {
! 1900: SLIST_REMOVE(&pool->free, zone, salloc_zone, link);
! 1901: uzone = zone;
! 1902: } else {
! 1903: uzone = SLIST_FIRST(&pool->spare);
! 1904: if (uzone == NULL)
! 1905: return NULL; /* XXX */
! 1906: SLIST_REMOVE_HEAD(&pool->spare, link);
! 1907: uzone->size = size;
! 1908: uzone->addr = zone->addr;
! 1909: zone->size -= size;
! 1910: zone->addr += size;
! 1911: }
! 1912: salloc_insert(pool, &pool->used, uzone, 0);
! 1913: return uzone->addr;
! 1914: }
! 1915:
! 1916: void
! 1917: salloc_free(pool, addr)
! 1918: salloc_t pool;
! 1919: caddr_t addr;
! 1920: {
! 1921: struct salloc_zone *zone;
! 1922:
! 1923: SLIST_FOREACH(zone, &pool->used, link)
! 1924: if (zone->addr == addr)
! 1925: break;
! 1926: #ifdef DIAGNOSTIC
! 1927: if (zone == SLIST_END(&pool->used))
! 1928: panic("salloc_free: freeing unallocated memory");
! 1929: #endif
! 1930: SLIST_REMOVE(&pool->used, zone, salloc_zone, link);
! 1931: salloc_insert(pool, &pool->free, zone, 1);
! 1932: }
CVSweb