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