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