ad1816.c revision 53465
1193326Sed/* 2193326Sed * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> 3193326Sed * Copyright Luigi Rizzo, 1997,1998 4193326Sed * Copyright by Hannu Savolainen 1994, 1995 5193326Sed * All rights reserved. 6193326Sed * 7193326Sed * Redistribution and use in source and binary forms, with or without 8193326Sed * modification, are permitted provided that the following conditions 9193326Sed * are met: 10193326Sed * 1. Redistributions of source code must retain the above copyright 11193326Sed * notice, this list of conditions and the following disclaimer. 12193326Sed * 2. Redistributions in binary form must reproduce the above copyright 13193326Sed * notice, this list of conditions and the following disclaimer in the 14193326Sed * documentation and/or other materials provided with the distribution. 15205219Srdivacky * 16193326Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17252723Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18218893Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19226890Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20252723Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21252723Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22193326Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23193326Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24252723Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25198092Srdivacky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26193326Sed * SUCH DAMAGE. 27252723Sdim * 28205219Srdivacky * $FreeBSD: head/sys/dev/sound/isa/ad1816.c 53465 1999-11-20 16:50:33Z cg $ 29218893Sdim */ 30205219Srdivacky 31193326Sed#include <dev/sound/pcm/sound.h> 32193326Sed 33193326Sed#if NPCM > 0 && NPNP > 0 34193326Sed 35193326Sed#include <dev/sound/isa/ad1816.h> 36193326Sed 37193326Sedstruct ad1816_info; 38193326Sed 39193326Sedstruct ad1816_chinfo { 40212904Sdim struct ad1816_info *parent; 41212904Sdim pcm_channel *channel; 42193326Sed snd_dbuf *buffer; 43193326Sed int dir; 44226890Sdim}; 45226890Sdim 46193326Sedstruct ad1816_info { 47205408Srdivacky struct resource *io_base; /* primary I/O address for the board */ 48193326Sed int io_rid; 49193326Sed struct resource *irq; 50221345Sdim int irq_rid; 51221345Sdim struct resource *drq1; /* play */ 52221345Sdim int drq1_rid; 53221345Sdim struct resource *drq2; /* rec */ 54221345Sdim int drq2_rid; 55221345Sdim bus_dma_tag_t parent_dmat; 56221345Sdim 57221345Sdim struct ad1816_chinfo pch, rch; 58221345Sdim}; 59221345Sdim 60221345Sdimstatic driver_intr_t ad1816_intr; 61221345Sdimstatic int ad1816_probe(device_t dev); 62221345Sdimstatic int ad1816_attach(device_t dev); 63193326Sed 64193326Sed/* IO primitives */ 65193326Sedstatic int ad1816_wait_init(struct ad1816_info *ad1816, int x); 66200583Srdivackystatic u_short ad1816_read(struct ad1816_info *ad1816, u_int reg); 67193326Sedstatic void ad1816_write(struct ad1816_info *ad1816, u_int reg, u_short data); 68205408Srdivacky 69221345Sdimstatic int ad1816mix_init(snd_mixer *m); 70193326Sedstatic int ad1816mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right); 71193326Sedstatic int ad1816mix_setrecsrc(snd_mixer *m, u_int32_t src); 72212904Sdimstatic snd_mixer ad1816_mixer = { 73212904Sdim "ad1816 mixer", 74245431Sdim ad1816mix_init, 75235633Sdim ad1816mix_set, 76235633Sdim ad1816mix_setrecsrc, 77235633Sdim}; 78235633Sdim 79200583Srdivackystatic devclass_t pcm_devclass; 80212904Sdim 81212904Sdim/* channel interface */ 82205408Srdivackystatic void *ad1816chan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir); 83212904Sdimstatic int ad1816chan_setdir(void *data, int dir); 84200583Srdivackystatic int ad1816chan_setformat(void *data, u_int32_t format); 85200583Srdivackystatic int ad1816chan_setspeed(void *data, u_int32_t speed); 86226890Sdimstatic int ad1816chan_setblocksize(void *data, u_int32_t blocksize); 87207619Srdivackystatic int ad1816chan_trigger(void *data, int go); 88207619Srdivackystatic int ad1816chan_getptr(void *data); 89205219Srdivackystatic pcmchan_caps *ad1816chan_getcaps(void *data); 90218893Sdim 91221345Sdimstatic pcmchan_caps ad1816_caps = { 92221345Sdim 4000, 55200, 93218893Sdim AFMT_STEREO | AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW, 94218893Sdim AFMT_STEREO | AFMT_S16_LE 95205408Srdivacky}; 96218893Sdim 97218893Sdimstatic pcm_channel ad1816_chantemplate = { 98206084Srdivacky ad1816chan_init, 99218893Sdim ad1816chan_setdir, 100245431Sdim ad1816chan_setformat, 101245431Sdim ad1816chan_setspeed, 102245431Sdim ad1816chan_setblocksize, 103245431Sdim ad1816chan_trigger, 104206084Srdivacky ad1816chan_getptr, 105218893Sdim ad1816chan_getcaps, 106218893Sdim}; 107218893Sdim 108218893Sdim#define FULL_DUPLEX(x) (pcm_getflags(x) & SD_F_SIMPLEX) 109218893Sdim#define AD1816_MUTE 31 /* value for mute */ 110218893Sdim 111218893Sdimstatic int 112218893Sdimport_rd(struct resource *port, int off) 113218893Sdim{ 114218893Sdim if (port) 115218893Sdim return bus_space_read_1(rman_get_bustag(port), 116226890Sdim rman_get_bushandle(port), 117221345Sdim off); 118218893Sdim else 119218893Sdim return -1; 120221345Sdim} 121218893Sdim 122207619Srdivackystatic void 123218893Sdimport_wr(struct resource *port, int off, u_int8_t data) 124218893Sdim{ 125221345Sdim if (port) 126218893Sdim return bus_space_write_1(rman_get_bustag(port), 127218893Sdim rman_get_bushandle(port), 128221345Sdim off, data); 129206084Srdivacky} 130218893Sdim 131207619Srdivackystatic int 132218893Sdimio_rd(struct ad1816_info *ad1816, int reg) 133218893Sdim{ 134198092Srdivacky return port_rd(ad1816->io_base, reg); 135205219Srdivacky} 136218893Sdim 137218893Sdimstatic void 138221345Sdimio_wr(struct ad1816_info *ad1816, int reg, u_int8_t data) 139218893Sdim{ 140218893Sdim return port_wr(ad1816->io_base, reg, data); 141221345Sdim} 142218893Sdim 143218893Sdimstatic void 144221345Sdimad1816_intr(void *arg) 145218893Sdim{ 146218893Sdim struct ad1816_info *ad1816 = (struct ad1816_info *)arg; 147218893Sdim unsigned char c, served = 0; 148218893Sdim 149218893Sdim /* get interupt status */ 150221345Sdim c = io_rd(ad1816, AD1816_INT); 151218893Sdim 152221345Sdim /* check for stray interupts */ 153218893Sdim if (c & ~(AD1816_INTRCI | AD1816_INTRPI)) { 154226890Sdim printf("pcm: stray int (%x)\n", c); 155221345Sdim c &= AD1816_INTRCI | AD1816_INTRPI; 156218893Sdim } 157218893Sdim /* check for capture interupt */ 158218893Sdim if (ad1816->rch.buffer->dl && (c & AD1816_INTRCI)) { 159218893Sdim chn_intr(ad1816->rch.channel); 160218893Sdim served |= AD1816_INTRCI; /* cp served */ 161218893Sdim } 162218893Sdim /* check for playback interupt */ 163218893Sdim if (ad1816->pch.buffer->dl && (c & AD1816_INTRPI)) { 164218893Sdim chn_intr(ad1816->pch.channel); 165218893Sdim served |= AD1816_INTRPI; /* pb served */ 166218893Sdim } 167218893Sdim if (served == 0) { 168221345Sdim /* this probably means this is not a (working) ad1816 chip, */ 169218893Sdim /* or an error in dma handling */ 170221345Sdim printf("pcm: int without reason (%x)\n", c); 171218893Sdim c = 0; 172218893Sdim } else c &= ~served; 173218893Sdim io_wr(ad1816, AD1816_INT, c); 174205408Srdivacky c = io_rd(ad1816, AD1816_INT); 175212904Sdim if (c != 0) printf("pcm: int clear failed (%x)\n", c); 176205408Srdivacky} 177205408Srdivacky 178198092Srdivackystatic int 179198092Srdivackyad1816_wait_init(struct ad1816_info *ad1816, int x) 180226890Sdim{ 181193326Sed int n = 0; /* to shut up the compiler... */ 182193326Sed 183198092Srdivacky for (; x--;) 184224145Sdim if ((n = (io_rd(ad1816, AD1816_ALE) & AD1816_BUSY)) == 0) DELAY(10); 185193326Sed else return n; 186193326Sed printf("ad1816_wait_init failed 0x%02x.\n", n); 187198092Srdivacky return -1; 188193326Sed} 189193326Sed 190193326Sedstatic unsigned short 191193326Sedad1816_read(struct ad1816_info *ad1816, unsigned int reg) 192193326Sed{ 193193326Sed int flags; 194193326Sed u_short x = 0; 195245431Sdim 196193326Sed /* we don't want to be blocked here */ 197245431Sdim flags = spltty(); 198193326Sed if (ad1816_wait_init(ad1816, 100) == -1) return 0; 199193326Sed io_wr(ad1816, AD1816_ALE, 0); 200198092Srdivacky io_wr(ad1816, AD1816_ALE, (reg & AD1816_ALEMASK)); 201193326Sed if (ad1816_wait_init(ad1816, 100) == -1) return 0; 202193326Sed x = (io_rd(ad1816, AD1816_HIGH) << 8) | io_rd(ad1816, AD1816_LOW); 203198092Srdivacky splx(flags); 204193326Sed return x; 205193326Sed} 206198092Srdivacky 207193326Sedstatic void 208193326Sedad1816_write(struct ad1816_info *ad1816, unsigned int reg, unsigned short data) 209193326Sed{ 210193326Sed int flags; 211193326Sed 212198092Srdivacky flags = spltty(); 213193326Sed if (ad1816_wait_init(ad1816, 100) == -1) return; 214193326Sed io_wr(ad1816, AD1816_ALE, (reg & AD1816_ALEMASK)); 215193326Sed io_wr(ad1816, AD1816_LOW, (data & 0x000000ff)); 216193326Sed io_wr(ad1816, AD1816_HIGH, (data & 0x0000ff00) >> 8); 217193326Sed splx(flags); 218198092Srdivacky} 219193326Sed 220193326Sedstatic int 221193326Sedad1816mix_init(snd_mixer *m) 222193326Sed{ 223193326Sed mix_setdevs(m, AD1816_MIXER_DEVICES); 224193326Sed mix_setrecdevs(m, AD1816_REC_DEVICES); 225245431Sdim return 0; 226193326Sed} 227193326Sed 228245431Sdimstatic int 229193326Sedad1816mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) 230193326Sed{ 231193326Sed struct ad1816_info *ad1816 = mix_getdevinfo(m); 232193326Sed u_short reg = 0; 233198092Srdivacky 234193326Sed /* Scale volumes */ 235198092Srdivacky left = AD1816_MUTE - (AD1816_MUTE * left) / 100; 236193326Sed right = AD1816_MUTE - (AD1816_MUTE * right) / 100; 237193326Sed 238193326Sed reg = (left << 8) | right; 239193326Sed 240193326Sed /* do channel selective muting if volume is zero */ 241193326Sed if (left == AD1816_MUTE) reg |= 0x8000; 242193326Sed if (right == AD1816_MUTE) reg |= 0x0080; 243193326Sed 244193326Sed switch (dev) { 245193326Sed case SOUND_MIXER_VOLUME: /* Register 14 master volume */ 246193326Sed ad1816_write(ad1816, 14, reg); 247198092Srdivacky break; 248193326Sed 249193326Sed case SOUND_MIXER_CD: /* Register 15 cd */ 250193326Sed case SOUND_MIXER_LINE1: 251193326Sed ad1816_write(ad1816, 15, reg); 252193326Sed break; 253193326Sed 254198092Srdivacky case SOUND_MIXER_SYNTH: /* Register 16 synth */ 255193326Sed ad1816_write(ad1816, 16, reg); 256193326Sed break; 257193326Sed 258193326Sed case SOUND_MIXER_PCM: /* Register 4 pcm */ 259193326Sed ad1816_write(ad1816, 4, reg); 260193326Sed break; 261193326Sed 262245431Sdim case SOUND_MIXER_LINE: 263193326Sed case SOUND_MIXER_LINE3: /* Register 18 line in */ 264193326Sed ad1816_write(ad1816, 18, reg); 265193326Sed break; 266193326Sed 267193326Sed case SOUND_MIXER_MIC: /* Register 19 mic volume */ 268193326Sed ad1816_write(ad1816, 19, reg & ~0xff); /* mic is mono */ 269193326Sed break; 270193326Sed 271193326Sed case SOUND_MIXER_IGAIN: 272193326Sed /* and now to something completely different ... */ 273193326Sed ad1816_write(ad1816, 20, ((ad1816_read(ad1816, 20) & ~0x0f0f) 274193326Sed | (((AD1816_MUTE - left) / 2) << 8) /* four bits of adc gain */ 275193326Sed | ((AD1816_MUTE - right) / 2))); 276193326Sed break; 277193326Sed 278193326Sed default: 279193326Sed printf("ad1816_mixer_set(): unknown device.\n"); 280193326Sed break; 281245431Sdim } 282193326Sed 283193326Sed return left | (right << 8); 284193326Sed} 285193326Sed 286193326Sedstatic int 287198092Srdivackyad1816mix_setrecsrc(snd_mixer *m, u_int32_t src) 288226890Sdim{ 289193326Sed struct ad1816_info *ad1816 = mix_getdevinfo(m); 290193326Sed int dev; 291224145Sdim 292193326Sed switch (src) { 293193326Sed case SOUND_MASK_LINE: 294193326Sed case SOUND_MASK_LINE3: 295193326Sed dev = 0x00; 296193326Sed break; 297193326Sed 298193326Sed case SOUND_MASK_CD: 299193326Sed case SOUND_MASK_LINE1: 300226890Sdim dev = 0x20; 301198092Srdivacky break; 302221345Sdim 303221345Sdim case SOUND_MASK_MIC: 304221345Sdim default: 305221345Sdim dev = 0x50; 306221345Sdim src = SOUND_MASK_MIC; 307221345Sdim } 308193326Sed 309193326Sed dev |= dev << 8; 310193326Sed ad1816_write(ad1816, 20, (ad1816_read(ad1816, 20) & ~0x7070) | dev); 311198092Srdivacky return src; 312193326Sed} 313193326Sed 314245431Sdim/* channel interface */ 315193326Sedstatic void * 316193326Sedad1816chan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) 317193326Sed{ 318193326Sed struct ad1816_info *ad1816 = devinfo; 319193326Sed struct ad1816_chinfo *ch = (dir == PCMDIR_PLAY)? &ad1816->pch : &ad1816->rch; 320193326Sed 321193326Sed ch->parent = ad1816; 322193326Sed ch->channel = c; 323193326Sed ch->buffer = b; 324193326Sed ch->buffer->bufsize = DSP_BUFFSIZE; 325193326Sed if (chn_allocbuf(ch->buffer, ad1816->parent_dmat) == -1) return NULL; 326193326Sed return ch; 327193326Sed} 328193326Sed 329198092Srdivackystatic int 330226890Sdimad1816chan_setdir(void *data, int dir) 331198092Srdivacky{ 332221345Sdim struct ad1816_chinfo *ch = data; 333221345Sdim struct ad1816_info *ad1816 = ch->parent; 334221345Sdim 335221345Sdim ch->buffer->chan = rman_get_start((dir == PCMDIR_PLAY)? 336221345Sdim ad1816->drq1 : ad1816->drq2); 337221345Sdim ch->dir = dir; 338221345Sdim return 0; 339193326Sed} 340193326Sed 341198092Srdivackystatic int 342193326Sedad1816chan_setformat(void *data, u_int32_t format) 343193326Sed{ 344198092Srdivacky struct ad1816_chinfo *ch = data; 345193326Sed struct ad1816_info *ad1816 = ch->parent; 346193326Sed 347193326Sed int fmt = AD1816_U8, reg; 348193326Sed if (ch->dir == PCMDIR_PLAY) { 349193326Sed reg = AD1816_PLAY; 350193326Sed ad1816_write(ad1816, 8, 0x0000); /* reset base and current counter */ 351193326Sed ad1816_write(ad1816, 9, 0x0000); /* for playback and capture */ 352198092Srdivacky } else { 353193326Sed reg = AD1816_CAPT; 354193326Sed ad1816_write(ad1816, 10, 0x0000); 355193326Sed ad1816_write(ad1816, 11, 0x0000); 356193326Sed } 357193326Sed switch (format & ~AFMT_STEREO) { 358198092Srdivacky case AFMT_A_LAW: 359245431Sdim fmt = AD1816_ALAW; 360193326Sed break; 361193326Sed 362193326Sed case AFMT_MU_LAW: 363193326Sed fmt = AD1816_MULAW; 364193326Sed break; 365193326Sed 366193326Sed case AFMT_S16_LE: 367193326Sed fmt = AD1816_S16LE; 368193326Sed break; 369193326Sed 370193326Sed case AFMT_S16_BE: 371193326Sed fmt = AD1816_S16BE; 372193326Sed break; 373245431Sdim 374245431Sdim case AFMT_U8: 375221345Sdim fmt = AD1816_U8; 376245431Sdim break; 377218893Sdim } 378235633Sdim if (format & AFMT_STEREO) fmt |= AD1816_STEREO; 379235633Sdim io_wr(ad1816, reg, fmt); 380218893Sdim return format; 381218893Sdim} 382218893Sdim 383218893Sdimstatic int 384193326Sedad1816chan_setspeed(void *data, u_int32_t speed) 385193326Sed{ 386198092Srdivacky struct ad1816_chinfo *ch = data; 387193326Sed struct ad1816_info *ad1816 = ch->parent; 388193326Sed 389193326Sed RANGE(speed, 4000, 55200); 390193326Sed ad1816_write(ad1816, (ch->dir == PCMDIR_PLAY)? 2 : 3, speed); 391235633Sdim return speed; 392235633Sdim} 393235633Sdim 394235633Sdimstatic int 395193326Sedad1816chan_setblocksize(void *data, u_int32_t blocksize) 396193326Sed{ 397193326Sed return blocksize; 398235633Sdim} 399235633Sdim 400235633Sdimstatic int 401235633Sdimad1816chan_trigger(void *data, int go) 402193326Sed{ 403221345Sdim struct ad1816_chinfo *ch = data; 404221345Sdim struct ad1816_info *ad1816 = ch->parent; 405235633Sdim int wr, reg; 406226890Sdim 407226890Sdim buf_isadma(ch->buffer, go); 408226890Sdim wr = (ch->dir == PCMDIR_PLAY); 409226890Sdim reg = wr? AD1816_PLAY : AD1816_CAPT; 410226890Sdim switch (go) { 411193326Sed case PCMTRIG_START: 412193326Sed /* start only if not already running */ 413193326Sed if (!(io_rd(ad1816, reg) & AD1816_ENABLE)) { 414193326Sed int cnt = ((ch->buffer->dl) >> 2) - 1; 415226890Sdim ad1816_write(ad1816, wr? 8 : 10, cnt); /* count */ 416226890Sdim ad1816_write(ad1816, 1, ad1816_read(ad1816, 1) | 417226890Sdim (wr? 0x8000 : 0x4000)); /* enable int */ 418193326Sed /* enable playback */ 419193326Sed io_wr(ad1816, reg, io_rd(ad1816, reg) | AD1816_ENABLE); 420193326Sed if (!(io_rd(ad1816, reg) & AD1816_ENABLE)) 421198092Srdivacky printf("ad1816: failed to start %s DMA!\n", 422193326Sed wr? "play" : "rec"); 423193326Sed } 424198092Srdivacky break; 425226890Sdim 426226890Sdim case PCMTRIG_STOP: 427226890Sdim case PCMTRIG_ABORT: /* XXX check this... */ 428226890Sdim /* we don't test here if it is running... */ 429193326Sed if (wr) { 430193326Sed ad1816_write(ad1816, 1, ad1816_read(ad1816, 1) & 431193326Sed ~(wr? 0x8000 : 0x4000)); 432193326Sed /* disable int */ 433193326Sed io_wr(ad1816, reg, io_rd(ad1816, reg) & ~AD1816_ENABLE); 434245431Sdim /* disable playback */ 435245431Sdim if (io_rd(ad1816, reg) & AD1816_ENABLE) 436193326Sed printf("ad1816: failed to stop %s DMA!\n", 437198092Srdivacky wr? "play" : "rec"); 438193326Sed ad1816_write(ad1816, wr? 8 : 10, 0); /* reset base cnt */ 439193326Sed ad1816_write(ad1816, wr? 9 : 11, 0); /* reset cur cnt */ 440193326Sed } 441198092Srdivacky break; 442193326Sed } 443193326Sed return 0; 444193326Sed} 445193326Sed 446193326Sedstatic int 447193326Sedad1816chan_getptr(void *data) 448221345Sdim{ 449245431Sdim struct ad1816_chinfo *ch = data; 450245431Sdim return buf_isadmaptr(ch->buffer); 451245431Sdim} 452245431Sdim 453245431Sdimstatic pcmchan_caps * 454245431Sdimad1816chan_getcaps(void *data) 455245431Sdim{ 456245431Sdim return &ad1816_caps; 457245431Sdim} 458245431Sdim 459245431Sdimstatic void 460245431Sdimad1816_release_resources(struct ad1816_info *ad1816, device_t dev) 461221345Sdim{ 462245431Sdim if (ad1816->irq) { 463221345Sdim bus_release_resource(dev, SYS_RES_IRQ, ad1816->irq_rid, 464245431Sdim ad1816->irq); 465245431Sdim ad1816->irq = 0; 466193326Sed } 467193326Sed if (ad1816->drq1) { 468193326Sed bus_release_resource(dev, SYS_RES_DRQ, ad1816->drq1_rid, 469193326Sed ad1816->drq1); 470193326Sed ad1816->drq1 = 0; 471193326Sed } 472193326Sed if (ad1816->drq2) { 473193326Sed bus_release_resource(dev, SYS_RES_DRQ, ad1816->drq2_rid, 474193326Sed ad1816->drq2); 475193326Sed ad1816->drq2 = 0; 476193326Sed } 477193326Sed if (ad1816->io_base) { 478193326Sed bus_release_resource(dev, SYS_RES_IOPORT, ad1816->io_rid, 479193326Sed ad1816->io_base); 480193326Sed ad1816->io_base = 0; 481193326Sed } 482193326Sed free(ad1816, M_DEVBUF); 483193326Sed} 484193326Sed 485193326Sedstatic int 486235633Sdimad1816_alloc_resources(struct ad1816_info *ad1816, device_t dev) 487235633Sdim{ 488235633Sdim int ok = 1, pdma, rdma; 489235633Sdim if (!ad1816->io_base) 490235633Sdim ad1816->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT, &ad1816->io_rid, 491235633Sdim 0, ~0, 1, RF_ACTIVE); 492235633Sdim if (!ad1816->irq) 493235633Sdim ad1816->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &ad1816->irq_rid, 494235633Sdim 0, ~0, 1, RF_ACTIVE); 495235633Sdim if (!ad1816->drq1) 496235633Sdim ad1816->drq1 = bus_alloc_resource(dev, SYS_RES_DRQ, &ad1816->drq1_rid, 497235633Sdim 0, ~0, 1, RF_ACTIVE); 498235633Sdim if (ad1816->drq2_rid >= 0 && !ad1816->drq2) 499235633Sdim ad1816->drq2 = bus_alloc_resource(dev, SYS_RES_DRQ, &ad1816->drq2_rid, 500235633Sdim 0, ~0, 1, RF_ACTIVE); 501235633Sdim 502235633Sdim if (!ad1816->io_base || !ad1816->drq1 || !ad1816->irq) ok = 0; 503235633Sdim if (ad1816->drq2_rid >= 0 && !ad1816->drq2) ok = 0; 504235633Sdim 505226890Sdim if (ok) { 506226890Sdim pdma = rman_get_start(ad1816->drq1); 507226890Sdim isa_dma_acquire(pdma); 508226890Sdim isa_dmainit(pdma, DSP_BUFFSIZE); 509226890Sdim if (ad1816->drq2) { 510226890Sdim rdma = rman_get_start(ad1816->drq2); 511226890Sdim isa_dma_acquire(rdma); 512226890Sdim isa_dmainit(rdma, DSP_BUFFSIZE); 513226890Sdim } else rdma = pdma; 514226890Sdim if (pdma == rdma) 515193326Sed pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX); 516193326Sed } 517221345Sdim return ok; 518221345Sdim} 519221345Sdim 520221345Sdimstatic int 521221345Sdimad1816_init(struct ad1816_info *ad1816, device_t dev) 522221345Sdim{ 523221345Sdim ad1816_write(ad1816, 1, 0x2); /* disable interrupts */ 524221345Sdim ad1816_write(ad1816, 32, 0x90F0); /* SoundSys Mode, split fmt */ 525221345Sdim 526193326Sed ad1816_write(ad1816, 5, 0x8080); /* FM volume mute */ 527235633Sdim ad1816_write(ad1816, 6, 0x8080); /* I2S1 volume mute */ 528235633Sdim ad1816_write(ad1816, 7, 0x8080); /* I2S0 volume mute */ 529235633Sdim ad1816_write(ad1816, 17, 0x8888); /* VID Volume mute */ 530235633Sdim ad1816_write(ad1816, 20, 0x5050); /* recsrc mic, agc off */ 531235633Sdim /* adc gain is set to 0 */ 532235633Sdim 533235633Sdim return 0; 534235633Sdim} 535235633Sdim 536235633Sdimstatic int 537235633Sdimad1816_probe(device_t dev) 538235633Sdim{ 539263509Sdim char *s = NULL; 540263509Sdim u_int32_t logical_id = isa_get_logicalid(dev); 541263509Sdim 542263509Sdim switch (logical_id) { 543263509Sdim case 0x80719304: /* ADS7180 */ 544263509Sdim s = "Terratec Soundsystem BASE 1"; 545263509Sdim break; 546263509Sdim } 547263509Sdim 548263509Sdim if (s) { 549263509Sdim device_set_desc(dev, s); 550263509Sdim return 0; 551263509Sdim } 552263509Sdim return ENXIO; 553263509Sdim} 554263509Sdim 555263509Sdimstatic int 556263509Sdimad1816_attach(device_t dev) 557263509Sdim{ 558263509Sdim struct ad1816_info *ad1816; 559263509Sdim snddev_info *d = device_get_softc(dev); 560263509Sdim void *ih; 561263509Sdim char status[SND_STATUSLEN]; 562263509Sdim 563263509Sdim ad1816 = (struct ad1816_info *)malloc(sizeof *ad1816, M_DEVBUF, M_NOWAIT); 564263509Sdim if (!ad1816) return ENXIO; 565263509Sdim bzero(ad1816, sizeof *ad1816); 566263509Sdim 567263509Sdim ad1816->io_rid = 2; 568263509Sdim ad1816->irq_rid = 0; 569263509Sdim ad1816->drq1_rid = 0; 570263509Sdim ad1816->drq2_rid = 1; 571263509Sdim 572263509Sdim if (!ad1816_alloc_resources(ad1816, dev)) goto no; 573263509Sdim ad1816_init(ad1816, dev); 574263509Sdim mixer_init(d, &ad1816_mixer, ad1816); 575263509Sdim bus_setup_intr(dev, ad1816->irq, INTR_TYPE_TTY, ad1816_intr, ad1816, &ih); 576193326Sed if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, 577226890Sdim /*lowaddr*/BUS_SPACE_MAXADDR_24BIT, 578193326Sed /*highaddr*/BUS_SPACE_MAXADDR, 579193326Sed /*filter*/NULL, /*filterarg*/NULL, 580212904Sdim /*maxsize*/DSP_BUFFSIZE, /*nsegments*/1, 581193326Sed /*maxsegz*/0x3ffff, 582193326Sed /*flags*/0, &ad1816->parent_dmat) != 0) { 583193326Sed device_printf(dev, "unable to create dma tag\n"); 584193326Sed goto no; 585193326Sed } 586226890Sdim snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld", 587226890Sdim rman_get_start(ad1816->io_base), 588226890Sdim rman_get_start(ad1816->irq), 589226890Sdim rman_get_start(ad1816->drq1)); 590226890Sdim if (FULL_DUPLEX(dev)) snprintf(status + strlen(status), 591226890Sdim SND_STATUSLEN - strlen(status), ":%ld", 592226890Sdim rman_get_start(ad1816->drq1)); 593226890Sdim 594226890Sdim if (pcm_register(dev, ad1816, 1, 1)) goto no; 595226890Sdim pcm_addchan(dev, PCMDIR_REC, &ad1816_chantemplate, ad1816); 596193326Sed pcm_addchan(dev, PCMDIR_PLAY, &ad1816_chantemplate, ad1816); 597226890Sdim pcm_setstatus(dev, status); 598226890Sdim 599226890Sdim return 0; 600193326Sedno: 601226890Sdim ad1816_release_resources(ad1816, dev); 602226890Sdim return ENXIO; 603226890Sdim 604226890Sdim} 605226890Sdim 606226890Sdimstatic device_method_t ad1816_methods[] = { 607198092Srdivacky /* Device interface */ 608193326Sed DEVMETHOD(device_probe, ad1816_probe), 609193326Sed DEVMETHOD(device_attach, ad1816_attach), 610226890Sdim 611194711Sed { 0, 0 } 612193326Sed}; 613193326Sed 614224145Sdimstatic driver_t ad1816_driver = { 615226890Sdim "pcm", 616226890Sdim ad1816_methods, 617226890Sdim sizeof(snddev_info), 618226890Sdim}; 619226890Sdim 620226890SdimDRIVER_MODULE(ad1816, isa, ad1816_driver, pcm_devclass, 0, 0); 621224145Sdim 622224145Sdim#endif 623226890Sdim