sb16.c revision 84111
1262395Sbapt/* 2262395Sbapt * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> 3262395Sbapt * Copyright 1997,1998 Luigi Rizzo. 4262395Sbapt * 5262395Sbapt * Derived from files in the Voxware 3.5 distribution, 6262395Sbapt * Copyright by Hannu Savolainen 1994, under the same copyright 7262395Sbapt * conditions. 8262395Sbapt * All rights reserved. 9262395Sbapt * 10262395Sbapt * Redistribution and use in source and binary forms, with or without 11262395Sbapt * modification, are permitted provided that the following conditions 12262395Sbapt * are met: 13262395Sbapt * 1. Redistributions of source code must retain the above copyright 14262395Sbapt * notice, this list of conditions and the following disclaimer. 15262395Sbapt * 2. Redistributions in binary form must reproduce the above copyright 16262395Sbapt * notice, this list of conditions and the following disclaimer in the 17262395Sbapt * documentation and/or other materials provided with the distribution. 18262395Sbapt * 19262395Sbapt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20262395Sbapt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21262395Sbapt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22262395Sbapt * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23262395Sbapt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24262395Sbapt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25262395Sbapt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26262395Sbapt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27262395Sbapt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28262395Sbapt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29262395Sbapt * SUCH DAMAGE. 30262395Sbapt */ 31262395Sbapt 32262395Sbapt#include <dev/sound/pcm/sound.h> 33262395Sbapt 34262395Sbapt#include <dev/sound/isa/sb.h> 35262395Sbapt#include <dev/sound/chip.h> 36262395Sbapt 37262395Sbapt#include "mixer_if.h" 38262395Sbapt 39262395SbaptSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/isa/sb16.c 84111 2001-09-29 07:57:07Z cg $"); 40262395Sbapt 41262395Sbapt#define SB16_BUFFSIZE 4096 42262395Sbapt#define PLAIN_SB16(x) ((((x)->bd_flags) & (BD_F_SB16|BD_F_SB16X)) == BD_F_SB16) 43262395Sbapt 44262395Sbaptstatic u_int32_t sb16_fmt8[] = { 45262395Sbapt AFMT_U8, 46262395Sbapt AFMT_STEREO | AFMT_U8, 47262395Sbapt 0 48262395Sbapt}; 49262395Sbaptstatic struct pcmchan_caps sb16_caps8 = {5000, 45000, sb16_fmt8, 0}; 50262395Sbapt 51262395Sbaptstatic u_int32_t sb16_fmt16[] = { 52262395Sbapt AFMT_S16_LE, 53262395Sbapt AFMT_STEREO | AFMT_S16_LE, 54262395Sbapt 0 55262395Sbapt}; 56262395Sbaptstatic struct pcmchan_caps sb16_caps16 = {5000, 45000, sb16_fmt16, 0}; 57262395Sbapt 58262395Sbaptstatic u_int32_t sb16x_fmt[] = { 59262395Sbapt AFMT_U8, 60262395Sbapt AFMT_STEREO | AFMT_U8, 61262395Sbapt AFMT_S16_LE, 62262395Sbapt AFMT_STEREO | AFMT_S16_LE, 63262395Sbapt 0 64262395Sbapt}; 65262395Sbaptstatic struct pcmchan_caps sb16x_caps = {5000, 49000, sb16x_fmt, 0}; 66262395Sbapt 67262395Sbaptstruct sb_info; 68262395Sbapt 69262395Sbaptstruct sb_chinfo { 70262395Sbapt struct sb_info *parent; 71262395Sbapt struct pcm_channel *channel; 72262395Sbapt struct snd_dbuf *buffer; 73262395Sbapt int dir, run, dch; 74262395Sbapt u_int32_t fmt, spd, blksz; 75262395Sbapt}; 76262395Sbapt 77262395Sbaptstruct sb_info { 78262395Sbapt struct resource *io_base; /* I/O address for the board */ 79262395Sbapt struct resource *irq; 80262395Sbapt struct resource *drq1; 81262395Sbapt struct resource *drq2; 82262395Sbapt void *ih; 83262395Sbapt bus_dma_tag_t parent_dmat; 84262395Sbapt 85262395Sbapt unsigned int bufsize; 86262395Sbapt int bd_id; 87262395Sbapt u_long bd_flags; /* board-specific flags */ 88262395Sbapt int prio, prio16; 89262395Sbapt struct sb_chinfo pch, rch; 90262395Sbapt device_t parent_dev; 91262395Sbapt}; 92262395Sbapt 93262395Sbapt#if 0 94262395Sbaptstatic void sb_lock(struct sb_info *sb); 95262395Sbaptstatic void sb_unlock(struct sb_info *sb); 96262395Sbaptstatic int sb_rd(struct sb_info *sb, int reg); 97262395Sbaptstatic void sb_wr(struct sb_info *sb, int reg, u_int8_t val); 98262395Sbaptstatic int sb_cmd(struct sb_info *sb, u_char val); 99262395Sbapt/* static int sb_cmd1(struct sb_info *sb, u_char cmd, int val); */ 100262395Sbaptstatic int sb_cmd2(struct sb_info *sb, u_char cmd, int val); 101262395Sbaptstatic u_int sb_get_byte(struct sb_info *sb); 102262395Sbaptstatic void sb_setmixer(struct sb_info *sb, u_int port, u_int value); 103262395Sbaptstatic int sb_getmixer(struct sb_info *sb, u_int port); 104262395Sbaptstatic int sb_reset_dsp(struct sb_info *sb); 105262395Sbapt 106262395Sbaptstatic void sb_intr(void *arg); 107262395Sbapt#endif 108262395Sbapt 109262395Sbapt/* 110262395Sbapt * Common code for the midi and pcm functions 111262395Sbapt * 112262395Sbapt * sb_cmd write a single byte to the CMD port. 113262395Sbapt * sb_cmd1 write a CMD + 1 byte arg 114262395Sbapt * sb_cmd2 write a CMD + 2 byte arg 115262395Sbapt * sb_get_byte returns a single byte from the DSP data port 116262395Sbapt */ 117262395Sbapt 118262395Sbaptstatic void 119262395Sbaptsb_lock(struct sb_info *sb) { 120262395Sbapt 121262395Sbapt sbc_lock(device_get_softc(sb->parent_dev)); 122262395Sbapt} 123262395Sbapt 124262395Sbaptstatic void 125262395Sbaptsb_unlock(struct sb_info *sb) { 126262395Sbapt 127262395Sbapt sbc_unlock(device_get_softc(sb->parent_dev)); 128262395Sbapt} 129262395Sbapt 130262395Sbaptstatic int 131262395Sbaptport_rd(struct resource *port, int off) 132262395Sbapt{ 133262395Sbapt return bus_space_read_1(rman_get_bustag(port), rman_get_bushandle(port), off); 134262395Sbapt} 135262395Sbapt 136262395Sbaptstatic void 137262395Sbaptport_wr(struct resource *port, int off, u_int8_t data) 138262395Sbapt{ 139262395Sbapt return bus_space_write_1(rman_get_bustag(port), rman_get_bushandle(port), off, data); 140262395Sbapt} 141262395Sbapt 142262395Sbaptstatic int 143262395Sbaptsb_rd(struct sb_info *sb, int reg) 144262395Sbapt{ 145262395Sbapt return port_rd(sb->io_base, reg); 146262395Sbapt} 147262395Sbapt 148262395Sbaptstatic void 149262395Sbaptsb_wr(struct sb_info *sb, int reg, u_int8_t val) 150262395Sbapt{ 151262395Sbapt port_wr(sb->io_base, reg, val); 152262395Sbapt} 153262395Sbapt 154262395Sbaptstatic int 155262395Sbaptsb_dspwr(struct sb_info *sb, u_char val) 156262395Sbapt{ 157262395Sbapt int i; 158262395Sbapt 159262395Sbapt for (i = 0; i < 1000; i++) { 160262395Sbapt if ((sb_rd(sb, SBDSP_STATUS) & 0x80)) 161262395Sbapt DELAY((i > 100)? 1000 : 10); 162262395Sbapt else { 163262395Sbapt sb_wr(sb, SBDSP_CMD, val); 164262395Sbapt return 1; 165262395Sbapt } 166262395Sbapt } 167262395Sbapt#if __FreeBSD_version > 500000 168262395Sbapt if (curthread->td_intr_nesting_level == 0) 169262395Sbapt printf("sb_dspwr(0x%02x) timed out.\n", val); 170262395Sbapt#endif 171262395Sbapt return 0; 172262395Sbapt} 173262395Sbapt 174262395Sbaptstatic int 175262395Sbaptsb_cmd(struct sb_info *sb, u_char val) 176262395Sbapt{ 177262395Sbapt#if 0 178262395Sbapt printf("sb_cmd: %x\n", val); 179262395Sbapt#endif 180262395Sbapt return sb_dspwr(sb, val); 181262395Sbapt} 182262395Sbapt 183262395Sbapt/* 184262395Sbaptstatic int 185262395Sbaptsb_cmd1(struct sb_info *sb, u_char cmd, int val) 186262395Sbapt{ 187262395Sbapt#if 0 188262395Sbapt printf("sb_cmd1: %x, %x\n", cmd, val); 189262395Sbapt#endif 190262395Sbapt if (sb_dspwr(sb, cmd)) { 191262395Sbapt return sb_dspwr(sb, val & 0xff); 192262395Sbapt } else return 0; 193262395Sbapt} 194262395Sbapt*/ 195262395Sbapt 196262395Sbaptstatic int 197262395Sbaptsb_cmd2(struct sb_info *sb, u_char cmd, int val) 198262395Sbapt{ 199262395Sbapt int r; 200262395Sbapt 201262395Sbapt#if 0 202262395Sbapt printf("sb_cmd2: %x, %x\n", cmd, val); 203262395Sbapt#endif 204262395Sbapt sb_lock(sb); 205262395Sbapt r = 0; 206262395Sbapt if (sb_dspwr(sb, cmd)) { 207262395Sbapt if (sb_dspwr(sb, val & 0xff)) { 208262395Sbapt if (sb_dspwr(sb, (val >> 8) & 0xff)) { 209262395Sbapt r = 1; 210262395Sbapt } 211262395Sbapt } 212262395Sbapt } 213262395Sbapt sb_unlock(sb); 214262395Sbapt 215262395Sbapt return r; 216262395Sbapt} 217262395Sbapt 218262395Sbapt/* 219262395Sbapt * in the SB, there is a set of indirect "mixer" registers with 220262395Sbapt * address at offset 4, data at offset 5 221262395Sbapt */ 222262395Sbaptstatic void 223262395Sbaptsb_setmixer(struct sb_info *sb, u_int port, u_int value) 224262395Sbapt{ 225262395Sbapt sb_lock(sb); 226262395Sbapt sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ 227262395Sbapt DELAY(10); 228262395Sbapt sb_wr(sb, SB_MIX_DATA, (u_char) (value & 0xff)); 229262395Sbapt DELAY(10); 230262395Sbapt sb_unlock(sb); 231262395Sbapt} 232262395Sbapt 233262395Sbaptstatic int 234262395Sbaptsb_getmixer(struct sb_info *sb, u_int port) 235262395Sbapt{ 236262395Sbapt int val; 237262395Sbapt 238262395Sbapt sb_lock(sb); 239266636Sbapt sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ 240266636Sbapt DELAY(10); 241266636Sbapt val = sb_rd(sb, SB_MIX_DATA); 242262395Sbapt DELAY(10); 243262395Sbapt sb_unlock(sb); 244262395Sbapt 245262395Sbapt return val; 246262395Sbapt} 247262395Sbapt 248262395Sbaptstatic u_int 249262395Sbaptsb_get_byte(struct sb_info *sb) 250262395Sbapt{ 251262395Sbapt int i; 252262395Sbapt 253262395Sbapt for (i = 1000; i > 0; i--) { 254262395Sbapt if (sb_rd(sb, DSP_DATA_AVAIL) & 0x80) 255262395Sbapt return sb_rd(sb, DSP_READ); 256262395Sbapt else 257262395Sbapt DELAY(20); 258262395Sbapt } 259262395Sbapt return 0xffff; 260262395Sbapt} 261262395Sbapt 262262395Sbaptstatic int 263262395Sbaptsb_reset_dsp(struct sb_info *sb) 264266636Sbapt{ 265266636Sbapt u_char b; 266266636Sbapt 267266636Sbapt sb_lock(sb); 268266636Sbapt sb_wr(sb, SBDSP_RST, 3); 269266636Sbapt DELAY(100); 270266636Sbapt sb_wr(sb, SBDSP_RST, 0); 271266636Sbapt b = sb_get_byte(sb); 272266636Sbapt sb_unlock(sb); 273266636Sbapt if (b != 0xAA) { 274266636Sbapt DEB(printf("sb_reset_dsp 0x%lx failed\n", 275266636Sbapt rman_get_start(d->io_base))); 276266636Sbapt return ENXIO; /* Sorry */ 277262395Sbapt } 278262395Sbapt return 0; 279262395Sbapt} 280262395Sbapt 281262395Sbapt/************************************************************/ 282262395Sbapt 283262395Sbaptstruct sb16_mixent { 284262395Sbapt int reg; 285262395Sbapt int bits; 286262395Sbapt int ofs; 287262395Sbapt int stereo; 288262395Sbapt}; 289262395Sbapt 290266636Sbaptstatic const struct sb16_mixent sb16_mixtab[32] = { 291266636Sbapt [SOUND_MIXER_VOLUME] = { 0x30, 5, 3, 1 }, 292262395Sbapt [SOUND_MIXER_PCM] = { 0x32, 5, 3, 1 }, 293262395Sbapt [SOUND_MIXER_SYNTH] = { 0x34, 5, 3, 1 }, 294262395Sbapt [SOUND_MIXER_CD] = { 0x36, 5, 3, 1 }, 295262395Sbapt [SOUND_MIXER_LINE] = { 0x38, 5, 3, 1 }, 296262395Sbapt [SOUND_MIXER_MIC] = { 0x3a, 5, 3, 0 }, 297262395Sbapt [SOUND_MIXER_SPEAKER] = { 0x3b, 5, 3, 0 }, 298262395Sbapt [SOUND_MIXER_IGAIN] = { 0x3f, 2, 6, 1 }, 299262395Sbapt [SOUND_MIXER_OGAIN] = { 0x41, 2, 6, 1 }, 300262395Sbapt [SOUND_MIXER_TREBLE] = { 0x44, 4, 4, 1 }, 301262395Sbapt [SOUND_MIXER_BASS] = { 0x46, 4, 4, 1 }, 302266636Sbapt}; 303266636Sbapt 304262395Sbaptstatic int 305262395Sbaptsb16mix_init(struct snd_mixer *m) 306262395Sbapt{ 307262395Sbapt struct sb_info *sb = mix_getdevinfo(m); 308262395Sbapt 309262395Sbapt mix_setdevs(m, SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | 310262395Sbapt SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD | 311262395Sbapt SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | 312262395Sbapt SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE); 313262395Sbapt 314262395Sbapt mix_setrecdevs(m, SOUND_MASK_SYNTH | SOUND_MASK_LINE | 315262395Sbapt SOUND_MASK_MIC | SOUND_MASK_CD); 316262395Sbapt 317262395Sbapt sb_setmixer(sb, 0x3c, 0x1f); /* make all output active */ 318262395Sbapt 319262395Sbapt sb_setmixer(sb, 0x3d, 0); /* make all inputs-l off */ 320262395Sbapt sb_setmixer(sb, 0x3e, 0); /* make all inputs-r off */ 321262395Sbapt 322262395Sbapt return 0; 323262395Sbapt} 324262395Sbapt 325262395Sbaptstatic int 326262395Sbaptsb16mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 327262395Sbapt{ 328262395Sbapt struct sb_info *sb = mix_getdevinfo(m); 329262395Sbapt const struct sb16_mixent *e; 330262395Sbapt int max; 331262395Sbapt 332262395Sbapt e = &sb16_mixtab[dev]; 333262395Sbapt max = (1 << e->bits) - 1; 334262395Sbapt 335262395Sbapt left = (left * max) / 100; 336262395Sbapt right = (right * max) / 100; 337262395Sbapt 338262395Sbapt sb_setmixer(sb, e->reg, left << e->ofs); 339262395Sbapt if (e->stereo) 340262395Sbapt sb_setmixer(sb, e->reg + 1, right << e->ofs); 341262395Sbapt else 342262395Sbapt right = left; 343262395Sbapt 344262395Sbapt left = (left * 100) / max; 345262395Sbapt right = (right * 100) / max; 346262395Sbapt 347262395Sbapt return left | (right << 8); 348262395Sbapt} 349266636Sbapt 350262395Sbaptstatic int 351262395Sbaptsb16mix_setrecsrc(struct snd_mixer *m, u_int32_t src) 352266636Sbapt{ 353266636Sbapt struct sb_info *sb = mix_getdevinfo(m); 354262395Sbapt u_char recdev; 355266636Sbapt 356262395Sbapt recdev = 0; 357262395Sbapt if (src & SOUND_MASK_MIC) 358262395Sbapt recdev |= 0x01; /* mono mic */ 359262395Sbapt 360262395Sbapt if (src & SOUND_MASK_CD) 361262395Sbapt recdev |= 0x06; /* l+r cd */ 362262395Sbapt 363262395Sbapt if (src & SOUND_MASK_LINE) 364262395Sbapt recdev |= 0x18; /* l+r line */ 365262395Sbapt 366262395Sbapt if (src & SOUND_MASK_SYNTH) 367266636Sbapt recdev |= 0x60; /* l+r midi */ 368262395Sbapt 369262395Sbapt sb_setmixer(sb, SB16_IMASK_L, recdev); 370262395Sbapt sb_setmixer(sb, SB16_IMASK_R, recdev); 371262395Sbapt 372262395Sbapt /* 373262395Sbapt * since the same volume controls apply to the input and 374262395Sbapt * output sections, the best approach to have a consistent 375262395Sbapt * behaviour among cards would be to disable the output path 376262395Sbapt * on devices which are used to record. 377262395Sbapt * However, since users like to have feedback, we only disable 378262395Sbapt * the mic -- permanently. 379262395Sbapt */ 380262395Sbapt sb_setmixer(sb, SB16_OMASK, 0x1f & ~1); 381262395Sbapt 382262395Sbapt return src; 383262395Sbapt} 384266636Sbapt 385266636Sbaptstatic kobj_method_t sb16mix_mixer_methods[] = { 386266636Sbapt KOBJMETHOD(mixer_init, sb16mix_init), 387266636Sbapt KOBJMETHOD(mixer_set, sb16mix_set), 388266636Sbapt KOBJMETHOD(mixer_setrecsrc, sb16mix_setrecsrc), 389266636Sbapt { 0, 0 } 390266636Sbapt}; 391266636SbaptMIXER_DECLARE(sb16mix_mixer); 392266636Sbapt 393266636Sbapt/************************************************************/ 394266636Sbapt 395266636Sbaptstatic void 396268831Sbaptsb16_release_resources(struct sb_info *sb, device_t dev) 397268831Sbapt{ 398268831Sbapt if (sb->irq) { 399268831Sbapt if (sb->ih) 400268831Sbapt bus_teardown_intr(dev, sb->irq, sb->ih); 401268831Sbapt bus_release_resource(dev, SYS_RES_IRQ, 0, sb->irq); 402268831Sbapt sb->irq = 0; 403268831Sbapt } 404268831Sbapt if (sb->drq2) { 405268831Sbapt if (sb->drq2 != sb->drq1) { 406266636Sbapt isa_dma_release(rman_get_start(sb->drq2)); 407262395Sbapt bus_release_resource(dev, SYS_RES_DRQ, 1, sb->drq2); 408262395Sbapt } 409262395Sbapt sb->drq2 = 0; 410262395Sbapt } 411262395Sbapt if (sb->drq1) { 412262395Sbapt isa_dma_release(rman_get_start(sb->drq1)); 413262395Sbapt bus_release_resource(dev, SYS_RES_DRQ, 0, sb->drq1); 414262395Sbapt sb->drq1 = 0; 415262395Sbapt } 416262395Sbapt if (sb->io_base) { 417262395Sbapt bus_release_resource(dev, SYS_RES_IOPORT, 0, sb->io_base); 418262395Sbapt sb->io_base = 0; 419262395Sbapt } 420262395Sbapt if (sb->parent_dmat) { 421262395Sbapt bus_dma_tag_destroy(sb->parent_dmat); 422262395Sbapt sb->parent_dmat = 0; 423262395Sbapt } 424262395Sbapt free(sb, M_DEVBUF); 425262395Sbapt} 426262395Sbapt 427262395Sbaptstatic int 428262395Sbaptsb16_alloc_resources(struct sb_info *sb, device_t dev) 429262395Sbapt{ 430262395Sbapt int rid; 431262395Sbapt 432262395Sbapt rid = 0; 433262395Sbapt if (!sb->io_base) 434262395Sbapt sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, RF_ACTIVE); 435262395Sbapt 436262395Sbapt rid = 0; 437262395Sbapt if (!sb->irq) 438262395Sbapt sb->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_ACTIVE); 439262395Sbapt 440262395Sbapt rid = 0; 441262395Sbapt if (!sb->drq1) 442262395Sbapt sb->drq1 = bus_alloc_resource(dev, SYS_RES_DRQ, &rid, 0, ~0, 1, RF_ACTIVE); 443262395Sbapt 444262395Sbapt rid = 1; 445262395Sbapt if (!sb->drq2) 446262395Sbapt sb->drq2 = bus_alloc_resource(dev, SYS_RES_DRQ, &rid, 0, ~0, 1, RF_ACTIVE); 447262395Sbapt 448262395Sbapt if (sb->io_base && sb->drq1 && sb->irq) { 449262395Sbapt isa_dma_acquire(rman_get_start(sb->drq1)); 450262395Sbapt isa_dmainit(rman_get_start(sb->drq1), sb->bufsize); 451262395Sbapt 452262395Sbapt if (sb->drq2) { 453262395Sbapt isa_dma_acquire(rman_get_start(sb->drq2)); 454262395Sbapt isa_dmainit(rman_get_start(sb->drq2), sb->bufsize); 455262395Sbapt } else { 456262395Sbapt sb->drq2 = sb->drq1; 457262395Sbapt pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX); 458262395Sbapt } 459262395Sbapt return 0; 460262395Sbapt } else return ENXIO; 461262395Sbapt} 462262395Sbapt 463262395Sbapt/* sbc does locking for us */ 464262395Sbaptstatic void 465262395Sbaptsb_intr(void *arg) 466262395Sbapt{ 467262395Sbapt struct sb_info *sb = (struct sb_info *)arg; 468262395Sbapt int reason = 3, c; 469262395Sbapt 470262395Sbapt /* 471262395Sbapt * The Vibra16X has separate flags for 8 and 16 bit transfers, but 472262395Sbapt * I have no idea how to tell capture from playback interrupts... 473262395Sbapt */ 474262395Sbapt 475262395Sbapt reason = 0; 476262395Sbapt sb_lock(sb); 477262395Sbapt c = sb_getmixer(sb, IRQ_STAT); 478262395Sbapt if (c & 1) 479262395Sbapt sb_rd(sb, DSP_DATA_AVAIL); /* 8-bit int ack */ 480262395Sbapt 481262395Sbapt if (c & 2) 482262395Sbapt sb_rd(sb, DSP_DATA_AVL16); /* 16-bit int ack */ 483262395Sbapt sb_unlock(sb); 484262395Sbapt 485262395Sbapt /* 486262395Sbapt * this tells us if the source is 8-bit or 16-bit dma. We 487262395Sbapt * have to check the io channel to map it to read or write... 488262395Sbapt */ 489262395Sbapt 490262395Sbapt if (sb->bd_flags & BD_F_SB16X) { 491262395Sbapt if (c & 1) { /* 8-bit format */ 492262395Sbapt if (sb->pch.fmt & AFMT_8BIT) 493262395Sbapt reason |= 1; 494262395Sbapt if (sb->rch.fmt & AFMT_8BIT) 495262395Sbapt reason |= 2; 496262395Sbapt } 497262395Sbapt if (c & 2) { /* 16-bit format */ 498262395Sbapt if (sb->pch.fmt & AFMT_16BIT) 499262395Sbapt reason |= 1; 500262395Sbapt if (sb->rch.fmt & AFMT_16BIT) 501262395Sbapt reason |= 2; 502262395Sbapt } 503262395Sbapt } else { 504262395Sbapt if (c & 1) { /* 8-bit dma */ 505262395Sbapt if (sb->pch.dch == 1) 506262395Sbapt reason |= 1; 507262395Sbapt if (sb->rch.dch == 1) 508262395Sbapt reason |= 2; 509262395Sbapt } 510262395Sbapt if (c & 2) { /* 16-bit dma */ 511262395Sbapt if (sb->pch.dch == 2) 512262395Sbapt reason |= 1; 513262395Sbapt if (sb->rch.dch == 2) 514262395Sbapt reason |= 2; 515262395Sbapt } 516262395Sbapt } 517262395Sbapt#if 0 518262395Sbapt printf("sb_intr: reason=%d c=0x%x\n", reason, c); 519262395Sbapt#endif 520262395Sbapt if ((reason & 1) && (sb->pch.run)) 521262395Sbapt chn_intr(sb->pch.channel); 522262395Sbapt 523262395Sbapt if ((reason & 2) && (sb->rch.run)) 524262395Sbapt chn_intr(sb->rch.channel); 525262395Sbapt} 526262395Sbapt 527262395Sbaptstatic int 528262395Sbaptsb_setup(struct sb_info *sb) 529262395Sbapt{ 530262395Sbapt struct sb_chinfo *ch; 531262395Sbapt u_int8_t v; 532262395Sbapt int l, pprio; 533262395Sbapt 534262395Sbapt sb_lock(sb); 535262395Sbapt if (sb->bd_flags & BD_F_DMARUN) 536262395Sbapt sndbuf_isadma(sb->pch.buffer, PCMTRIG_STOP); 537262395Sbapt if (sb->bd_flags & BD_F_DMARUN2) 538262395Sbapt sndbuf_isadma(sb->rch.buffer, PCMTRIG_STOP); 539262395Sbapt sb->bd_flags &= ~(BD_F_DMARUN | BD_F_DMARUN2); 540262395Sbapt 541262395Sbapt sb_reset_dsp(sb); 542262395Sbapt 543262395Sbapt if (sb->bd_flags & BD_F_SB16X) { 544262395Sbapt pprio = sb->pch.run? 1 : 0; 545262395Sbapt sndbuf_isadmasetup(sb->pch.buffer, pprio? sb->drq1 : NULL); 546262395Sbapt sb->pch.dch = pprio? 1 : 0; 547262395Sbapt sndbuf_isadmasetup(sb->rch.buffer, pprio? sb->drq2 : sb->drq1); 548262395Sbapt sb->rch.dch = pprio? 2 : 1; 549262395Sbapt } else { 550262395Sbapt if (sb->pch.run && sb->rch.run) { 551262395Sbapt pprio = (sb->rch.fmt & AFMT_16BIT)? 0 : 1; 552262395Sbapt sndbuf_isadmasetup(sb->pch.buffer, pprio? sb->drq2 : sb->drq1); 553262395Sbapt sb->pch.dch = pprio? 2 : 1; 554262395Sbapt sndbuf_isadmasetup(sb->rch.buffer, pprio? sb->drq1 : sb->drq2); 555262395Sbapt sb->rch.dch = pprio? 1 : 2; 556262395Sbapt } else { 557262395Sbapt if (sb->pch.run) { 558262395Sbapt sndbuf_isadmasetup(sb->pch.buffer, (sb->pch.fmt & AFMT_16BIT)? sb->drq2 : sb->drq1); 559262395Sbapt sb->pch.dch = (sb->pch.fmt & AFMT_16BIT)? 2 : 1; 560262395Sbapt sndbuf_isadmasetup(sb->rch.buffer, (sb->pch.fmt & AFMT_16BIT)? sb->drq1 : sb->drq2); 561263648Sbapt sb->rch.dch = (sb->pch.fmt & AFMT_16BIT)? 1 : 2; 562263648Sbapt } else if (sb->rch.run) { 563263648Sbapt sndbuf_isadmasetup(sb->pch.buffer, (sb->rch.fmt & AFMT_16BIT)? sb->drq1 : sb->drq2); 564263648Sbapt sb->pch.dch = (sb->rch.fmt & AFMT_16BIT)? 1 : 2; 565262395Sbapt sndbuf_isadmasetup(sb->rch.buffer, (sb->rch.fmt & AFMT_16BIT)? sb->drq2 : sb->drq1); 566262395Sbapt sb->rch.dch = (sb->rch.fmt & AFMT_16BIT)? 2 : 1; 567262395Sbapt } 568262395Sbapt } 569262395Sbapt } 570262395Sbapt 571262395Sbapt sndbuf_isadmasetdir(sb->pch.buffer, PCMDIR_PLAY); 572262395Sbapt sndbuf_isadmasetdir(sb->rch.buffer, PCMDIR_REC); 573262395Sbapt 574262395Sbapt /* 575263648Sbapt printf("setup: [pch = %d, pfmt = %d, pgo = %d] [rch = %d, rfmt = %d, rgo = %d]\n", 576263648Sbapt sb->pch.dch, sb->pch.fmt, sb->pch.run, sb->rch.dch, sb->rch.fmt, sb->rch.run); 577262395Sbapt */ 578262395Sbapt 579262395Sbapt ch = &sb->pch; 580262395Sbapt if (ch->run) { 581263648Sbapt l = ch->blksz; 582262395Sbapt if (ch->fmt & AFMT_16BIT) 583262395Sbapt l >>= 1; 584262395Sbapt l--; 585262395Sbapt 586262395Sbapt /* play speed */ 587262395Sbapt RANGE(ch->spd, 5000, 45000); 588262395Sbapt sb_cmd(sb, DSP_CMD_OUT16); 589262395Sbapt sb_cmd(sb, ch->spd >> 8); 590262395Sbapt sb_cmd(sb, ch->spd & 0xff); 591262395Sbapt 592262395Sbapt /* play format, length */ 593262395Sbapt v = DSP_F16_AUTO | DSP_F16_FIFO_ON | DSP_F16_DAC; 594262395Sbapt v |= (ch->fmt & AFMT_16BIT)? DSP_DMA16 : DSP_DMA8; 595262395Sbapt sb_cmd(sb, v); 596262395Sbapt 597262395Sbapt v = (ch->fmt & AFMT_STEREO)? DSP_F16_STEREO : 0; 598262395Sbapt v |= (ch->fmt & AFMT_SIGNED)? DSP_F16_SIGNED : 0; 599262395Sbapt sb_cmd2(sb, v, l); 600262395Sbapt sndbuf_isadma(ch->buffer, PCMTRIG_START); 601262395Sbapt sb->bd_flags |= BD_F_DMARUN; 602262395Sbapt } 603262395Sbapt 604262395Sbapt ch = &sb->rch; 605262395Sbapt if (ch->run) { 606262395Sbapt l = ch->blksz; 607262395Sbapt if (ch->fmt & AFMT_16BIT) 608262395Sbapt l >>= 1; 609262395Sbapt l--; 610262395Sbapt 611262395Sbapt /* record speed */ 612262395Sbapt RANGE(ch->spd, 5000, 45000); 613262395Sbapt sb_cmd(sb, DSP_CMD_IN16); 614262395Sbapt sb_cmd(sb, ch->spd >> 8); 615262395Sbapt sb_cmd(sb, ch->spd & 0xff); 616262395Sbapt 617262395Sbapt /* record format, length */ 618262395Sbapt v = DSP_F16_AUTO | DSP_F16_FIFO_ON | DSP_F16_ADC; 619262395Sbapt v |= (ch->fmt & AFMT_16BIT)? DSP_DMA16 : DSP_DMA8; 620262395Sbapt sb_cmd(sb, v); 621262395Sbapt 622262395Sbapt v = (ch->fmt & AFMT_STEREO)? DSP_F16_STEREO : 0; 623262395Sbapt v |= (ch->fmt & AFMT_SIGNED)? DSP_F16_SIGNED : 0; 624262395Sbapt sb_cmd2(sb, v, l); 625262395Sbapt sndbuf_isadma(ch->buffer, PCMTRIG_START); 626262395Sbapt sb->bd_flags |= BD_F_DMARUN2; 627262395Sbapt } 628262395Sbapt sb_unlock(sb); 629262395Sbapt 630262395Sbapt return 0; 631262395Sbapt} 632262395Sbapt 633262395Sbapt/* channel interface */ 634262395Sbaptstatic void * 635262395Sbaptsb16chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 636262395Sbapt{ 637262395Sbapt struct sb_info *sb = devinfo; 638262395Sbapt struct sb_chinfo *ch = (dir == PCMDIR_PLAY)? &sb->pch : &sb->rch; 639262395Sbapt 640262395Sbapt ch->parent = sb; 641262395Sbapt ch->channel = c; 642262395Sbapt ch->buffer = b; 643262395Sbapt ch->dir = dir; 644262395Sbapt 645262395Sbapt if (sndbuf_alloc(ch->buffer, sb->parent_dmat, sb->bufsize) == -1) 646262395Sbapt return NULL; 647262395Sbapt 648262395Sbapt return ch; 649262395Sbapt} 650262395Sbapt 651262395Sbaptstatic int 652262395Sbaptsb16chan_setformat(kobj_t obj, void *data, u_int32_t format) 653262395Sbapt{ 654262395Sbapt struct sb_chinfo *ch = data; 655262395Sbapt struct sb_info *sb = ch->parent; 656262395Sbapt 657262395Sbapt ch->fmt = format; 658262395Sbapt sb->prio = ch->dir; 659262395Sbapt sb->prio16 = (ch->fmt & AFMT_16BIT)? 1 : 0; 660262395Sbapt 661262395Sbapt return 0; 662262395Sbapt} 663262395Sbapt 664262395Sbaptstatic int 665262395Sbaptsb16chan_setspeed(kobj_t obj, void *data, u_int32_t speed) 666262395Sbapt{ 667262395Sbapt struct sb_chinfo *ch = data; 668262395Sbapt 669262395Sbapt ch->spd = speed; 670262395Sbapt return speed; 671262395Sbapt} 672262395Sbapt 673262395Sbaptstatic int 674262395Sbaptsb16chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 675262395Sbapt{ 676262395Sbapt struct sb_chinfo *ch = data; 677262395Sbapt 678262395Sbapt ch->blksz = blocksize; 679263648Sbapt return ch->blksz; 680263648Sbapt} 681262395Sbapt 682262395Sbaptstatic int 683262395Sbaptsb16chan_trigger(kobj_t obj, void *data, int go) 684262395Sbapt{ 685262395Sbapt struct sb_chinfo *ch = data; 686262395Sbapt struct sb_info *sb = ch->parent; 687262395Sbapt 688262395Sbapt if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) 689262395Sbapt return 0; 690262395Sbapt 691262395Sbapt if (go == PCMTRIG_START) 692262395Sbapt ch->run = 1; 693262395Sbapt else 694262395Sbapt ch->run = 0; 695262395Sbapt 696262395Sbapt sb_setup(sb); 697262395Sbapt 698262395Sbapt return 0; 699262395Sbapt} 700262395Sbapt 701263648Sbaptstatic int 702262395Sbaptsb16chan_getptr(kobj_t obj, void *data) 703262395Sbapt{ 704262395Sbapt struct sb_chinfo *ch = data; 705262395Sbapt 706262395Sbapt return sndbuf_isadmaptr(ch->buffer); 707262395Sbapt} 708262395Sbapt 709262395Sbaptstatic struct pcmchan_caps * 710262395Sbaptsb16chan_getcaps(kobj_t obj, void *data) 711262395Sbapt{ 712262395Sbapt struct sb_chinfo *ch = data; 713262395Sbapt struct sb_info *sb = ch->parent; 714262395Sbapt 715262395Sbapt if ((sb->prio == 0) || (sb->prio == ch->dir)) 716262395Sbapt return &sb16x_caps; 717262395Sbapt else 718262395Sbapt return sb->prio16? &sb16_caps8 : &sb16_caps16; 719262395Sbapt} 720262395Sbapt 721262395Sbaptstatic int 722262395Sbaptsb16chan_resetdone(kobj_t obj, void *data) 723262395Sbapt{ 724262395Sbapt struct sb_chinfo *ch = data; 725262395Sbapt struct sb_info *sb = ch->parent; 726262395Sbapt 727262395Sbapt sb->prio = 0; 728262395Sbapt 729262395Sbapt return 0; 730262395Sbapt} 731263648Sbapt 732262395Sbaptstatic kobj_method_t sb16chan_methods[] = { 733262395Sbapt KOBJMETHOD(channel_init, sb16chan_init), 734262395Sbapt KOBJMETHOD(channel_resetdone, sb16chan_resetdone), 735262395Sbapt KOBJMETHOD(channel_setformat, sb16chan_setformat), 736262395Sbapt KOBJMETHOD(channel_setspeed, sb16chan_setspeed), 737262395Sbapt KOBJMETHOD(channel_setblocksize, sb16chan_setblocksize), 738262395Sbapt KOBJMETHOD(channel_trigger, sb16chan_trigger), 739262395Sbapt KOBJMETHOD(channel_getptr, sb16chan_getptr), 740263648Sbapt KOBJMETHOD(channel_getcaps, sb16chan_getcaps), 741262395Sbapt { 0, 0 } 742262395Sbapt}; 743262395SbaptCHANNEL_DECLARE(sb16chan); 744262395Sbapt 745262395Sbapt/************************************************************/ 746262395Sbapt 747262395Sbaptstatic int 748262395Sbaptsb16_probe(device_t dev) 749262395Sbapt{ 750262395Sbapt char buf[64]; 751262395Sbapt uintptr_t func, ver, r, f; 752262395Sbapt 753262395Sbapt /* The parent device has already been probed. */ 754262395Sbapt r = BUS_READ_IVAR(device_get_parent(dev), dev, 0, &func); 755262395Sbapt if (func != SCF_PCM) 756262395Sbapt return (ENXIO); 757262395Sbapt 758262395Sbapt r = BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver); 759262395Sbapt f = (ver & 0xffff0000) >> 16; 760263648Sbapt ver &= 0x0000ffff; 761263648Sbapt if (f & BD_F_SB16) { 762262395Sbapt snprintf(buf, sizeof buf, "SB16 DSP %d.%02d%s", (int) ver >> 8, (int) ver & 0xff, 763262395Sbapt (f & BD_F_SB16X)? " (ViBRA16X)" : ""); 764262395Sbapt device_set_desc_copy(dev, buf); 765262395Sbapt return 0; 766262395Sbapt } else 767263648Sbapt return (ENXIO); 768262395Sbapt} 769262395Sbapt 770262395Sbaptstatic int 771262395Sbaptsb16_attach(device_t dev) 772262395Sbapt{ 773262395Sbapt struct sb_info *sb; 774262395Sbapt uintptr_t ver; 775262395Sbapt char status[SND_STATUSLEN], status2[SND_STATUSLEN]; 776262395Sbapt 777262395Sbapt sb = (struct sb_info *)malloc(sizeof *sb, M_DEVBUF, M_NOWAIT | M_ZERO); 778262395Sbapt if (!sb) 779263648Sbapt return ENXIO; 780263648Sbapt 781262395Sbapt sb->parent_dev = device_get_parent(dev); 782262395Sbapt BUS_READ_IVAR(sb->parent_dev, dev, 1, &ver); 783262395Sbapt sb->bd_id = ver & 0x0000ffff; 784262395Sbapt sb->bd_flags = (ver & 0xffff0000) >> 16; 785263648Sbapt sb->bufsize = pcm_getbuffersize(dev, 4096, SB16_BUFFSIZE, 65536); 786262395Sbapt 787262395Sbapt if (sb16_alloc_resources(sb, dev)) 788262395Sbapt goto no; 789262395Sbapt if (sb_reset_dsp(sb)) 790262395Sbapt goto no; 791262395Sbapt if (mixer_init(dev, &sb16mix_mixer_class, sb)) 792262395Sbapt goto no; 793262395Sbapt if (snd_setup_intr(dev, sb->irq, INTR_MPSAFE, sb_intr, sb, &sb->ih)) 794262395Sbapt goto no; 795262395Sbapt 796262395Sbapt if (sb->bd_flags & BD_F_SB16X) 797262395Sbapt pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX); 798263648Sbapt 799263648Sbapt sb->prio = 0; 800262395Sbapt 801262395Sbapt if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, 802262395Sbapt /*lowaddr*/BUS_SPACE_MAXADDR_24BIT, 803262395Sbapt /*highaddr*/BUS_SPACE_MAXADDR, 804262395Sbapt /*filter*/NULL, /*filterarg*/NULL, 805262395Sbapt /*maxsize*/sb->bufsize, /*nsegments*/1, 806262395Sbapt /*maxsegz*/0x3ffff, 807262395Sbapt /*flags*/0, &sb->parent_dmat) != 0) { 808262395Sbapt device_printf(dev, "unable to create dma tag\n"); 809262395Sbapt goto no; 810262395Sbapt } 811262395Sbapt 812262395Sbapt if (!(pcm_getflags(dev) & SD_F_SIMPLEX)) 813262395Sbapt snprintf(status2, SND_STATUSLEN, ":%ld", rman_get_start(sb->drq2)); 814262395Sbapt else 815262395Sbapt status2[0] = '\0'; 816262395Sbapt 817262395Sbapt snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld%s bufsz %ud", 818262395Sbapt rman_get_start(sb->io_base), rman_get_start(sb->irq), 819262395Sbapt rman_get_start(sb->drq1), status2, sb->bufsize); 820262395Sbapt 821262395Sbapt if (pcm_register(dev, sb, 1, 1)) 822262395Sbapt goto no; 823262395Sbapt pcm_addchan(dev, PCMDIR_REC, &sb16chan_class, sb); 824262395Sbapt pcm_addchan(dev, PCMDIR_PLAY, &sb16chan_class, sb); 825262395Sbapt 826262395Sbapt pcm_setstatus(dev, status); 827262395Sbapt 828263648Sbapt return 0; 829263648Sbapt 830262395Sbaptno: 831262395Sbapt sb16_release_resources(sb, dev); 832262395Sbapt return ENXIO; 833262395Sbapt} 834262395Sbapt 835262395Sbaptstatic int 836262395Sbaptsb16_detach(device_t dev) 837262395Sbapt{ 838262395Sbapt int r; 839262395Sbapt struct sb_info *sb; 840262395Sbapt 841262395Sbapt r = pcm_unregister(dev); 842262395Sbapt if (r) 843262395Sbapt return r; 844262395Sbapt 845262395Sbapt sb = pcm_getdevinfo(dev); 846262395Sbapt sb16_release_resources(sb, dev); 847262395Sbapt return 0; 848262395Sbapt} 849262395Sbapt 850262395Sbaptstatic device_method_t sb16_methods[] = { 851262395Sbapt /* Device interface */ 852262395Sbapt DEVMETHOD(device_probe, sb16_probe), 853262395Sbapt DEVMETHOD(device_attach, sb16_attach), 854262395Sbapt DEVMETHOD(device_detach, sb16_detach), 855262395Sbapt 856262395Sbapt { 0, 0 } 857262395Sbapt}; 858262395Sbapt 859262395Sbaptstatic driver_t sb16_driver = { 860262395Sbapt "pcm", 861262395Sbapt sb16_methods, 862262395Sbapt PCM_SOFTC_SIZE, 863262395Sbapt}; 864262395Sbapt 865262395SbaptDRIVER_MODULE(snd_sb16, sbc, sb16_driver, pcm_devclass, 0, 0); 866262395SbaptMODULE_DEPEND(snd_sb16, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); 867262395SbaptMODULE_DEPEND(snd_sb16, snd_sbc, 1, 1, 1); 868262395SbaptMODULE_VERSION(snd_sb16, 1); 869262395Sbapt