ad1816.c revision 166426
1130617Smlaier/*- 2126353Smlaier * Copyright (c) 1999 Cameron Grant <cg@freebsd.org> 3126353Smlaier * Copyright (c) 1997,1998 Luigi Rizzo 4126353Smlaier * Copyright (c) 1994,1995 Hannu Savolainen 5126353Smlaier * All rights reserved. 6126353Smlaier * 7126353Smlaier * Redistribution and use in source and binary forms, with or without 8126353Smlaier * modification, are permitted provided that the following conditions 9126353Smlaier * are met: 10126353Smlaier * 1. Redistributions of source code must retain the above copyright 11126353Smlaier * notice, this list of conditions and the following disclaimer. 12126353Smlaier * 2. Redistributions in binary form must reproduce the above copyright 13126353Smlaier * notice, this list of conditions and the following disclaimer in the 14126353Smlaier * documentation and/or other materials provided with the distribution. 15126353Smlaier * 16126353Smlaier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17126353Smlaier * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18126353Smlaier * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19126353Smlaier * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20126353Smlaier * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21126353Smlaier * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22126353Smlaier * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23126353Smlaier * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24126353Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25126353Smlaier * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26126353Smlaier * SUCH DAMAGE. 27126353Smlaier */ 28126353Smlaier 29126353Smlaier#include <dev/sound/pcm/sound.h> 30126353Smlaier#include <dev/sound/isa/ad1816.h> 31126353Smlaier 32126353Smlaier#include <isa/isavar.h> 33127082Sobrien 34127082Sobrien#include "mixer_if.h" 35127082Sobrien 36126353SmlaierSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/isa/ad1816.c 166426 2007-02-02 13:39:20Z joel $"); 37130617Smlaier 38126353Smlaierstruct ad1816_info; 39126353Smlaier 40126353Smlaierstruct ad1816_chinfo { 41126353Smlaier struct ad1816_info *parent; 42126353Smlaier struct pcm_channel *channel; 43126353Smlaier struct snd_dbuf *buffer; 44126353Smlaier int dir, blksz; 45126353Smlaier}; 46126353Smlaier 47126353Smlaierstruct ad1816_info { 48126353Smlaier struct resource *io_base; /* primary I/O address for the board */ 49126353Smlaier int io_rid; 50126353Smlaier struct resource *irq; 51127024Smlaier int irq_rid; 52126355Smlaier struct resource *drq1; /* play */ 53126355Smlaier int drq1_rid; 54126353Smlaier struct resource *drq2; /* rec */ 55126355Smlaier int drq2_rid; 56126353Smlaier void *ih; 57130617Smlaier bus_dma_tag_t parent_dmat; 58126353Smlaier struct mtx *lock; 59126353Smlaier 60130617Smlaier unsigned int bufsize; 61126353Smlaier struct ad1816_chinfo pch, rch; 62126353Smlaier}; 63130617Smlaier 64130617Smlaierstatic u_int32_t ad1816_fmt[] = { 65126353Smlaier AFMT_U8, 66126353Smlaier AFMT_STEREO | AFMT_U8, 67126353Smlaier AFMT_S16_LE, 68126353Smlaier AFMT_STEREO | AFMT_S16_LE, 69126353Smlaier AFMT_MU_LAW, 70126353Smlaier AFMT_STEREO | AFMT_MU_LAW, 71126353Smlaier AFMT_A_LAW, 72126353Smlaier AFMT_STEREO | AFMT_A_LAW, 73126353Smlaier 0 74126353Smlaier}; 75126353Smlaier 76126353Smlaierstatic struct pcmchan_caps ad1816_caps = {4000, 55200, ad1816_fmt, 0}; 77130617Smlaier 78130617Smlaier#define AD1816_MUTE 31 /* value for mute */ 79130617Smlaier 80130617Smlaierstatic void 81126353Smlaierad1816_lock(struct ad1816_info *ad1816) 82130617Smlaier{ 83130617Smlaier snd_mtxlock(ad1816->lock); 84126353Smlaier} 85130617Smlaier 86130617Smlaierstatic void 87130617Smlaierad1816_unlock(struct ad1816_info *ad1816) 88126353Smlaier{ 89126353Smlaier snd_mtxunlock(ad1816->lock); 90126353Smlaier} 91126353Smlaier 92126353Smlaierstatic int 93130617Smlaierport_rd(struct resource *port, int off) 94130617Smlaier{ 95130617Smlaier if (port) 96130617Smlaier return bus_space_read_1(rman_get_bustag(port), 97130617Smlaier rman_get_bushandle(port), 98130617Smlaier off); 99126353Smlaier else 100130617Smlaier return -1; 101130617Smlaier} 102130617Smlaier 103130617Smlaierstatic void 104130617Smlaierport_wr(struct resource *port, int off, u_int8_t data) 105130617Smlaier{ 106130617Smlaier if (port) 107130617Smlaier bus_space_write_1(rman_get_bustag(port), 108130617Smlaier rman_get_bushandle(port), 109130617Smlaier off, data); 110130617Smlaier} 111130617Smlaier 112130617Smlaierstatic int 113130617Smlaierio_rd(struct ad1816_info *ad1816, int reg) 114130617Smlaier{ 115126353Smlaier return port_rd(ad1816->io_base, reg); 116126353Smlaier} 117126353Smlaier 118126353Smlaierstatic void 119126353Smlaierio_wr(struct ad1816_info *ad1816, int reg, u_int8_t data) 120126353Smlaier{ 121126353Smlaier port_wr(ad1816->io_base, reg, data); 122126353Smlaier} 123126353Smlaier 124126353Smlaierstatic void 125126353Smlaierad1816_intr(void *arg) 126126353Smlaier{ 127126353Smlaier struct ad1816_info *ad1816 = (struct ad1816_info *)arg; 128126353Smlaier unsigned char c, served = 0; 129126353Smlaier 130126353Smlaier ad1816_lock(ad1816); 131126353Smlaier /* get interupt status */ 132126353Smlaier c = io_rd(ad1816, AD1816_INT); 133126353Smlaier 134126353Smlaier /* check for stray interupts */ 135126353Smlaier if (c & ~(AD1816_INTRCI | AD1816_INTRPI)) { 136126353Smlaier printf("pcm: stray int (%x)\n", c); 137126353Smlaier c &= AD1816_INTRCI | AD1816_INTRPI; 138126353Smlaier } 139126353Smlaier /* check for capture interupt */ 140126353Smlaier if (sndbuf_runsz(ad1816->rch.buffer) && (c & AD1816_INTRCI)) { 141126353Smlaier ad1816_unlock(ad1816); 142126353Smlaier chn_intr(ad1816->rch.channel); 143126353Smlaier ad1816_lock(ad1816); 144126353Smlaier served |= AD1816_INTRCI; /* cp served */ 145126353Smlaier } 146126353Smlaier /* check for playback interupt */ 147126353Smlaier if (sndbuf_runsz(ad1816->pch.buffer) && (c & AD1816_INTRPI)) { 148126353Smlaier ad1816_unlock(ad1816); 149126353Smlaier chn_intr(ad1816->pch.channel); 150126353Smlaier ad1816_lock(ad1816); 151126353Smlaier served |= AD1816_INTRPI; /* pb served */ 152126353Smlaier } 153126353Smlaier if (served == 0) { 154126353Smlaier /* this probably means this is not a (working) ad1816 chip, */ 155127024Smlaier /* or an error in dma handling */ 156127024Smlaier printf("pcm: int without reason (%x)\n", c); 157127024Smlaier c = 0; 158126353Smlaier } else c &= ~served; 159127024Smlaier io_wr(ad1816, AD1816_INT, c); 160126353Smlaier c = io_rd(ad1816, AD1816_INT); 161126353Smlaier if (c != 0) printf("pcm: int clear failed (%x)\n", c); 162130617Smlaier ad1816_unlock(ad1816); 163126353Smlaier} 164126353Smlaier 165126353Smlaierstatic int 166126353Smlaierad1816_wait_init(struct ad1816_info *ad1816, int x) 167126353Smlaier{ 168126353Smlaier int n = 0; /* to shut up the compiler... */ 169126353Smlaier 170126353Smlaier for (; x--;) 171126353Smlaier if ((n = (io_rd(ad1816, AD1816_ALE) & AD1816_BUSY)) == 0) DELAY(10); 172126353Smlaier else return n; 173126353Smlaier printf("ad1816_wait_init failed 0x%02x.\n", n); 174126353Smlaier return -1; 175126353Smlaier} 176126353Smlaier 177126353Smlaierstatic unsigned short 178126353Smlaierad1816_read(struct ad1816_info *ad1816, unsigned int reg) 179126353Smlaier{ 180126353Smlaier u_short x = 0; 181126353Smlaier 182126353Smlaier if (ad1816_wait_init(ad1816, 100) == -1) return 0; 183126353Smlaier io_wr(ad1816, AD1816_ALE, 0); 184126353Smlaier io_wr(ad1816, AD1816_ALE, (reg & AD1816_ALEMASK)); 185130617Smlaier if (ad1816_wait_init(ad1816, 100) == -1) return 0; 186130617Smlaier x = (io_rd(ad1816, AD1816_HIGH) << 8) | io_rd(ad1816, AD1816_LOW); 187130617Smlaier return x; 188130617Smlaier} 189130617Smlaier 190130617Smlaierstatic void 191130617Smlaierad1816_write(struct ad1816_info *ad1816, unsigned int reg, unsigned short data) 192130617Smlaier{ 193130617Smlaier if (ad1816_wait_init(ad1816, 100) == -1) return; 194130617Smlaier io_wr(ad1816, AD1816_ALE, (reg & AD1816_ALEMASK)); 195130617Smlaier io_wr(ad1816, AD1816_LOW, (data & 0x000000ff)); 196130617Smlaier io_wr(ad1816, AD1816_HIGH, (data & 0x0000ff00) >> 8); 197130617Smlaier} 198130617Smlaier 199126353Smlaier/* -------------------------------------------------------------------- */ 200126353Smlaier 201126353Smlaierstatic int 202126353Smlaierad1816mix_init(struct snd_mixer *m) 203126353Smlaier{ 204126353Smlaier mix_setdevs(m, AD1816_MIXER_DEVICES); 205126353Smlaier mix_setrecdevs(m, AD1816_REC_DEVICES); 206126353Smlaier return 0; 207126353Smlaier} 208126353Smlaier 209126353Smlaierstatic int 210126353Smlaierad1816mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 211130617Smlaier{ 212126353Smlaier struct ad1816_info *ad1816 = mix_getdevinfo(m); 213126353Smlaier u_short reg = 0; 214126353Smlaier 215130617Smlaier /* Scale volumes */ 216126353Smlaier left = AD1816_MUTE - (AD1816_MUTE * left) / 100; 217130617Smlaier right = AD1816_MUTE - (AD1816_MUTE * right) / 100; 218130617Smlaier 219130617Smlaier reg = (left << 8) | right; 220130617Smlaier 221130617Smlaier /* do channel selective muting if volume is zero */ 222130617Smlaier if (left == AD1816_MUTE) reg |= 0x8000; 223130617Smlaier if (right == AD1816_MUTE) reg |= 0x0080; 224130617Smlaier 225130617Smlaier ad1816_lock(ad1816); 226130617Smlaier switch (dev) { 227130617Smlaier case SOUND_MIXER_VOLUME: /* Register 14 master volume */ 228130617Smlaier ad1816_write(ad1816, 14, reg); 229126353Smlaier break; 230126353Smlaier 231126353Smlaier case SOUND_MIXER_CD: /* Register 15 cd */ 232126353Smlaier case SOUND_MIXER_LINE1: 233130617Smlaier ad1816_write(ad1816, 15, reg); 234130617Smlaier break; 235130617Smlaier 236130617Smlaier case SOUND_MIXER_SYNTH: /* Register 16 synth */ 237130617Smlaier ad1816_write(ad1816, 16, reg); 238130617Smlaier break; 239130617Smlaier 240130617Smlaier case SOUND_MIXER_PCM: /* Register 4 pcm */ 241130617Smlaier ad1816_write(ad1816, 4, reg); 242130617Smlaier break; 243130617Smlaier 244130617Smlaier case SOUND_MIXER_LINE: 245130617Smlaier case SOUND_MIXER_LINE3: /* Register 18 line in */ 246130617Smlaier ad1816_write(ad1816, 18, reg); 247126353Smlaier break; 248126353Smlaier 249126353Smlaier case SOUND_MIXER_MIC: /* Register 19 mic volume */ 250126353Smlaier ad1816_write(ad1816, 19, reg & ~0xff); /* mic is mono */ 251130617Smlaier break; 252126353Smlaier 253126353Smlaier case SOUND_MIXER_IGAIN: 254126353Smlaier /* and now to something completely different ... */ 255130617Smlaier ad1816_write(ad1816, 20, ((ad1816_read(ad1816, 20) & ~0x0f0f) 256130617Smlaier | (((AD1816_MUTE - left) / 2) << 8) /* four bits of adc gain */ 257126353Smlaier | ((AD1816_MUTE - right) / 2))); 258130617Smlaier break; 259130617Smlaier 260130617Smlaier default: 261126353Smlaier printf("ad1816_mixer_set(): unknown device.\n"); 262126353Smlaier break; 263126353Smlaier } 264126353Smlaier ad1816_unlock(ad1816); 265126353Smlaier 266126353Smlaier left = ((AD1816_MUTE - left) * 100) / AD1816_MUTE; 267130617Smlaier right = ((AD1816_MUTE - right) * 100) / AD1816_MUTE; 268130617Smlaier 269130617Smlaier return left | (right << 8); 270130617Smlaier} 271130617Smlaier 272130617Smlaierstatic int 273126353Smlaierad1816mix_setrecsrc(struct snd_mixer *m, u_int32_t src) 274130617Smlaier{ 275126353Smlaier struct ad1816_info *ad1816 = mix_getdevinfo(m); 276126353Smlaier int dev; 277126353Smlaier 278130617Smlaier switch (src) { 279126353Smlaier case SOUND_MASK_LINE: 280126353Smlaier case SOUND_MASK_LINE3: 281126353Smlaier dev = 0x00; 282130617Smlaier break; 283130617Smlaier 284130617Smlaier case SOUND_MASK_CD: 285130617Smlaier case SOUND_MASK_LINE1: 286130617Smlaier dev = 0x20; 287126353Smlaier break; 288126353Smlaier 289126353Smlaier case SOUND_MASK_MIC: 290126353Smlaier default: 291130617Smlaier dev = 0x50; 292126353Smlaier src = SOUND_MASK_MIC; 293130617Smlaier } 294130617Smlaier 295130617Smlaier dev |= dev << 8; 296126353Smlaier ad1816_lock(ad1816); 297126353Smlaier ad1816_write(ad1816, 20, (ad1816_read(ad1816, 20) & ~0x7070) | dev); 298126353Smlaier ad1816_unlock(ad1816); 299126353Smlaier return src; 300126353Smlaier} 301126353Smlaier 302126353Smlaierstatic kobj_method_t ad1816mixer_methods[] = { 303126353Smlaier KOBJMETHOD(mixer_init, ad1816mix_init), 304126353Smlaier KOBJMETHOD(mixer_set, ad1816mix_set), 305126353Smlaier KOBJMETHOD(mixer_setrecsrc, ad1816mix_setrecsrc), 306126353Smlaier { 0, 0 } 307126353Smlaier}; 308130617SmlaierMIXER_DECLARE(ad1816mixer); 309126353Smlaier 310130617Smlaier/* -------------------------------------------------------------------- */ 311130617Smlaier/* channel interface */ 312130617Smlaierstatic void * 313130617Smlaierad1816chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 314126353Smlaier{ 315126353Smlaier struct ad1816_info *ad1816 = devinfo; 316130617Smlaier struct ad1816_chinfo *ch = (dir == PCMDIR_PLAY)? &ad1816->pch : &ad1816->rch; 317130617Smlaier 318130617Smlaier ch->parent = ad1816; 319130617Smlaier ch->channel = c; 320130617Smlaier ch->buffer = b; 321130617Smlaier if (sndbuf_alloc(ch->buffer, ad1816->parent_dmat, ad1816->bufsize) != 0) 322130617Smlaier return NULL; 323130617Smlaier return ch; 324130617Smlaier} 325130617Smlaier 326130617Smlaierstatic int 327130617Smlaierad1816chan_setdir(kobj_t obj, void *data, int dir) 328134578Smlaier{ 329134578Smlaier struct ad1816_chinfo *ch = data; 330134578Smlaier struct ad1816_info *ad1816 = ch->parent; 331130617Smlaier 332134578Smlaier sndbuf_dmasetup(ch->buffer, (dir == PCMDIR_PLAY)? ad1816->drq1 : ad1816->drq2); 333130617Smlaier ch->dir = dir; 334130617Smlaier return 0; 335126353Smlaier} 336130617Smlaier 337126353Smlaierstatic int 338130617Smlaierad1816chan_setformat(kobj_t obj, void *data, u_int32_t format) 339130617Smlaier{ 340130617Smlaier struct ad1816_chinfo *ch = data; 341130617Smlaier struct ad1816_info *ad1816 = ch->parent; 342126353Smlaier int fmt = AD1816_U8, reg; 343126353Smlaier 344130617Smlaier ad1816_lock(ad1816); 345130617Smlaier if (ch->dir == PCMDIR_PLAY) { 346130617Smlaier reg = AD1816_PLAY; 347130617Smlaier ad1816_write(ad1816, 8, 0x0000); /* reset base and current counter */ 348130617Smlaier ad1816_write(ad1816, 9, 0x0000); /* for playback and capture */ 349130617Smlaier } else { 350130617Smlaier reg = AD1816_CAPT; 351130617Smlaier ad1816_write(ad1816, 10, 0x0000); 352130617Smlaier ad1816_write(ad1816, 11, 0x0000); 353130617Smlaier } 354130617Smlaier switch (format & ~AFMT_STEREO) { 355130617Smlaier case AFMT_A_LAW: 356130617Smlaier fmt = AD1816_ALAW; 357130617Smlaier break; 358130617Smlaier 359130617Smlaier case AFMT_MU_LAW: 360130617Smlaier fmt = AD1816_MULAW; 361130617Smlaier break; 362130617Smlaier 363130617Smlaier case AFMT_S16_LE: 364130617Smlaier fmt = AD1816_S16LE; 365130617Smlaier break; 366130617Smlaier 367130617Smlaier case AFMT_S16_BE: 368130617Smlaier fmt = AD1816_S16BE; 369130617Smlaier break; 370130617Smlaier 371130617Smlaier case AFMT_U8: 372130617Smlaier fmt = AD1816_U8; 373130617Smlaier break; 374130617Smlaier } 375130617Smlaier if (format & AFMT_STEREO) fmt |= AD1816_STEREO; 376130617Smlaier io_wr(ad1816, reg, fmt); 377130617Smlaier ad1816_unlock(ad1816); 378130617Smlaier#if 0 379130617Smlaier return format; 380130617Smlaier#else 381130617Smlaier return 0; 382130617Smlaier#endif 383130617Smlaier} 384126353Smlaier 385130617Smlaierstatic int 386130617Smlaierad1816chan_setspeed(kobj_t obj, void *data, u_int32_t speed) 387126353Smlaier{ 388126353Smlaier struct ad1816_chinfo *ch = data; 389126353Smlaier struct ad1816_info *ad1816 = ch->parent; 390126353Smlaier 391130617Smlaier RANGE(speed, 4000, 55200); 392130617Smlaier ad1816_lock(ad1816); 393130617Smlaier ad1816_write(ad1816, (ch->dir == PCMDIR_PLAY)? 2 : 3, speed); 394130617Smlaier ad1816_unlock(ad1816); 395126353Smlaier return speed; 396126353Smlaier} 397130617Smlaier 398130617Smlaierstatic int 399130617Smlaierad1816chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 400130617Smlaier{ 401130617Smlaier struct ad1816_chinfo *ch = data; 402134578Smlaier 403134578Smlaier ch->blksz = blocksize; 404134578Smlaier return ch->blksz; 405130617Smlaier} 406130617Smlaier 407130617Smlaierstatic int 408130617Smlaierad1816chan_trigger(kobj_t obj, void *data, int go) 409130617Smlaier{ 410130617Smlaier struct ad1816_chinfo *ch = data; 411134578Smlaier struct ad1816_info *ad1816 = ch->parent; 412134578Smlaier int wr, reg; 413134578Smlaier 414134578Smlaier if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) 415134578Smlaier return 0; 416134578Smlaier 417134578Smlaier sndbuf_dma(ch->buffer, go); 418134578Smlaier wr = (ch->dir == PCMDIR_PLAY); 419130617Smlaier reg = wr? AD1816_PLAY : AD1816_CAPT; 420134578Smlaier ad1816_lock(ad1816); 421130617Smlaier switch (go) { 422130617Smlaier case PCMTRIG_START: 423134578Smlaier /* start only if not already running */ 424134578Smlaier if (!(io_rd(ad1816, reg) & AD1816_ENABLE)) { 425134578Smlaier int cnt = ((ch->blksz) >> 2) - 1; 426134578Smlaier ad1816_write(ad1816, wr? 8 : 10, cnt); /* count */ 427130617Smlaier ad1816_write(ad1816, wr? 9 : 11, 0); /* reset cur cnt */ 428130617Smlaier ad1816_write(ad1816, 1, ad1816_read(ad1816, 1) | 429134578Smlaier (wr? 0x8000 : 0x4000)); /* enable int */ 430130617Smlaier /* enable playback */ 431130617Smlaier io_wr(ad1816, reg, io_rd(ad1816, reg) | AD1816_ENABLE); 432130617Smlaier if (!(io_rd(ad1816, reg) & AD1816_ENABLE)) 433130617Smlaier printf("ad1816: failed to start %s DMA!\n", 434130617Smlaier wr? "play" : "rec"); 435130617Smlaier } 436130617Smlaier break; 437130617Smlaier 438130617Smlaier case PCMTRIG_STOP: 439130617Smlaier case PCMTRIG_ABORT: /* XXX check this... */ 440130617Smlaier /* we don't test here if it is running... */ 441130617Smlaier if (wr) { 442130617Smlaier ad1816_write(ad1816, 1, ad1816_read(ad1816, 1) & 443130617Smlaier ~(wr? 0x8000 : 0x4000)); 444130617Smlaier /* disable int */ 445130617Smlaier io_wr(ad1816, reg, io_rd(ad1816, reg) & ~AD1816_ENABLE); 446130617Smlaier /* disable playback */ 447130617Smlaier if (io_rd(ad1816, reg) & AD1816_ENABLE) 448130617Smlaier printf("ad1816: failed to stop %s DMA!\n", 449126353Smlaier wr? "play" : "rec"); 450130617Smlaier ad1816_write(ad1816, wr? 8 : 10, 0); /* reset base cnt */ 451130617Smlaier ad1816_write(ad1816, wr? 9 : 11, 0); /* reset cur cnt */ 452130617Smlaier } 453130617Smlaier break; 454130617Smlaier } 455130617Smlaier ad1816_unlock(ad1816); 456130617Smlaier return 0; 457130617Smlaier} 458130617Smlaier 459130617Smlaierstatic int 460130617Smlaierad1816chan_getptr(kobj_t obj, void *data) 461130617Smlaier{ 462130617Smlaier struct ad1816_chinfo *ch = data; 463130617Smlaier return sndbuf_dmaptr(ch->buffer); 464130617Smlaier} 465130617Smlaier 466130617Smlaierstatic struct pcmchan_caps * 467130617Smlaierad1816chan_getcaps(kobj_t obj, void *data) 468130617Smlaier{ 469130617Smlaier return &ad1816_caps; 470130617Smlaier} 471130617Smlaier 472130617Smlaierstatic kobj_method_t ad1816chan_methods[] = { 473130617Smlaier KOBJMETHOD(channel_init, ad1816chan_init), 474130617Smlaier KOBJMETHOD(channel_setdir, ad1816chan_setdir), 475130617Smlaier KOBJMETHOD(channel_setformat, ad1816chan_setformat), 476130617Smlaier KOBJMETHOD(channel_setspeed, ad1816chan_setspeed), 477130617Smlaier KOBJMETHOD(channel_setblocksize, ad1816chan_setblocksize), 478130617Smlaier KOBJMETHOD(channel_trigger, ad1816chan_trigger), 479130617Smlaier KOBJMETHOD(channel_getptr, ad1816chan_getptr), 480130617Smlaier KOBJMETHOD(channel_getcaps, ad1816chan_getcaps), 481130617Smlaier { 0, 0 } 482130617Smlaier}; 483130617SmlaierCHANNEL_DECLARE(ad1816chan); 484130617Smlaier 485130617Smlaier/* -------------------------------------------------------------------- */ 486130617Smlaier 487130617Smlaierstatic void 488130617Smlaierad1816_release_resources(struct ad1816_info *ad1816, device_t dev) 489130617Smlaier{ 490130617Smlaier if (ad1816->irq) { 491130617Smlaier if (ad1816->ih) 492130617Smlaier bus_teardown_intr(dev, ad1816->irq, ad1816->ih); 493130617Smlaier bus_release_resource(dev, SYS_RES_IRQ, ad1816->irq_rid, ad1816->irq); 494130617Smlaier ad1816->irq = 0; 495130617Smlaier } 496130617Smlaier if (ad1816->drq1) { 497130617Smlaier isa_dma_release(rman_get_start(ad1816->drq1)); 498134578Smlaier bus_release_resource(dev, SYS_RES_DRQ, ad1816->drq1_rid, ad1816->drq1); 499134578Smlaier ad1816->drq1 = 0; 500134578Smlaier } 501134578Smlaier if (ad1816->drq2) { 502130617Smlaier isa_dma_release(rman_get_start(ad1816->drq2)); 503134578Smlaier bus_release_resource(dev, SYS_RES_DRQ, ad1816->drq2_rid, ad1816->drq2); 504130617Smlaier ad1816->drq2 = 0; 505130617Smlaier } 506130617Smlaier if (ad1816->io_base) { 507130617Smlaier bus_release_resource(dev, SYS_RES_IOPORT, ad1816->io_rid, ad1816->io_base); 508130617Smlaier ad1816->io_base = 0; 509130617Smlaier } 510130617Smlaier if (ad1816->parent_dmat) { 511130617Smlaier bus_dma_tag_destroy(ad1816->parent_dmat); 512130617Smlaier ad1816->parent_dmat = 0; 513130617Smlaier } 514130617Smlaier if (ad1816->lock) 515130617Smlaier snd_mtxfree(ad1816->lock); 516130617Smlaier 517130617Smlaier free(ad1816, M_DEVBUF); 518130617Smlaier} 519130617Smlaier 520130617Smlaierstatic int 521130617Smlaierad1816_alloc_resources(struct ad1816_info *ad1816, device_t dev) 522130617Smlaier{ 523130617Smlaier int ok = 1, pdma, rdma; 524130617Smlaier 525130617Smlaier if (!ad1816->io_base) 526130617Smlaier ad1816->io_base = bus_alloc_resource_any(dev, 527130617Smlaier SYS_RES_IOPORT, &ad1816->io_rid, RF_ACTIVE); 528130617Smlaier if (!ad1816->irq) 529130617Smlaier ad1816->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 530130617Smlaier &ad1816->irq_rid, RF_ACTIVE); 531134578Smlaier if (!ad1816->drq1) 532134578Smlaier ad1816->drq1 = bus_alloc_resource_any(dev, SYS_RES_DRQ, 533134578Smlaier &ad1816->drq1_rid, RF_ACTIVE); 534134578Smlaier if (!ad1816->drq2) 535134578Smlaier ad1816->drq2 = bus_alloc_resource_any(dev, SYS_RES_DRQ, 536134578Smlaier &ad1816->drq2_rid, RF_ACTIVE); 537134578Smlaier 538134578Smlaier if (!ad1816->io_base || !ad1816->drq1 || !ad1816->irq) ok = 0; 539134578Smlaier 540130617Smlaier if (ok) { 541130617Smlaier pdma = rman_get_start(ad1816->drq1); 542134578Smlaier isa_dma_acquire(pdma); 543130617Smlaier isa_dmainit(pdma, ad1816->bufsize); 544130617Smlaier if (ad1816->drq2) { 545130617Smlaier rdma = rman_get_start(ad1816->drq2); 546130617Smlaier isa_dma_acquire(rdma); 547130617Smlaier isa_dmainit(rdma, ad1816->bufsize); 548130617Smlaier } else 549130617Smlaier rdma = pdma; 550130617Smlaier if (pdma == rdma) 551130617Smlaier pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX); 552126353Smlaier } 553126353Smlaier 554126353Smlaier return ok; 555130617Smlaier} 556130617Smlaier 557126353Smlaierstatic int 558130617Smlaierad1816_init(struct ad1816_info *ad1816, device_t dev) 559130617Smlaier{ 560130617Smlaier ad1816_write(ad1816, 1, 0x2); /* disable interrupts */ 561130617Smlaier ad1816_write(ad1816, 32, 0x90F0); /* SoundSys Mode, split fmt */ 562130617Smlaier 563130617Smlaier ad1816_write(ad1816, 5, 0x8080); /* FM volume mute */ 564130617Smlaier ad1816_write(ad1816, 6, 0x8080); /* I2S1 volume mute */ 565126353Smlaier ad1816_write(ad1816, 7, 0x8080); /* I2S0 volume mute */ 566126353Smlaier ad1816_write(ad1816, 17, 0x8888); /* VID Volume mute */ 567126353Smlaier ad1816_write(ad1816, 20, 0x5050); /* recsrc mic, agc off */ 568126353Smlaier /* adc gain is set to 0 */ 569126353Smlaier 570126353Smlaier return 0; 571126353Smlaier} 572126353Smlaier 573126353Smlaierstatic int 574126353Smlaierad1816_probe(device_t dev) 575126353Smlaier{ 576126353Smlaier char *s = NULL; 577126353Smlaier u_int32_t logical_id = isa_get_logicalid(dev); 578126353Smlaier 579126353Smlaier switch (logical_id) { 580126353Smlaier case 0x80719304: /* ADS7180 */ 581130617Smlaier s = "AD1816"; 582130617Smlaier break; 583126353Smlaier case 0x50719304: /* ADS7150 */ 584130617Smlaier s = "AD1815"; 585130617Smlaier break; 586130617Smlaier } 587126353Smlaier 588126353Smlaier if (s) { 589126353Smlaier device_set_desc(dev, s); 590126353Smlaier return BUS_PROBE_DEFAULT; 591126353Smlaier } 592126353Smlaier return ENXIO; 593126353Smlaier} 594126353Smlaier 595126353Smlaierstatic int 596126353Smlaierad1816_attach(device_t dev) 597126353Smlaier{ 598126353Smlaier struct ad1816_info *ad1816; 599126353Smlaier char status[SND_STATUSLEN], status2[SND_STATUSLEN]; 600126353Smlaier 601126353Smlaier ad1816 = (struct ad1816_info *)malloc(sizeof *ad1816, M_DEVBUF, M_NOWAIT | M_ZERO); 602126353Smlaier if (!ad1816) return ENXIO; 603126353Smlaier 604126353Smlaier ad1816->lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc"); 605126353Smlaier ad1816->io_rid = 2; 606126353Smlaier ad1816->irq_rid = 0; 607126353Smlaier ad1816->drq1_rid = 0; 608130617Smlaier ad1816->drq2_rid = 1; 609126353Smlaier ad1816->bufsize = pcm_getbuffersize(dev, 4096, DSP_BUFFSIZE, 65536); 610126353Smlaier 611126353Smlaier if (!ad1816_alloc_resources(ad1816, dev)) goto no; 612126353Smlaier ad1816_init(ad1816, dev); 613126353Smlaier if (mixer_init(dev, &ad1816mixer_class, ad1816)) goto no; 614126353Smlaier 615130617Smlaier snd_setup_intr(dev, ad1816->irq, 0, ad1816_intr, ad1816, &ad1816->ih); 616126353Smlaier if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, 617126353Smlaier /*lowaddr*/BUS_SPACE_MAXADDR_24BIT, 618126353Smlaier /*highaddr*/BUS_SPACE_MAXADDR, 619126353Smlaier /*filter*/NULL, /*filterarg*/NULL, 620126353Smlaier /*maxsize*/ad1816->bufsize, /*nsegments*/1, 621130617Smlaier /*maxsegz*/0x3ffff, 622130617Smlaier /*flags*/0, /*lockfunc*/busdma_lock_mutex, 623130617Smlaier /*lockarg*/ &Giant, &ad1816->parent_dmat) != 0) { 624126353Smlaier device_printf(dev, "unable to create dma tag\n"); 625126353Smlaier goto no; 626126353Smlaier } 627130617Smlaier if (ad1816->drq2) 628130617Smlaier snprintf(status2, SND_STATUSLEN, ":%ld", rman_get_start(ad1816->drq2)); 629130617Smlaier else 630130617Smlaier status2[0] = '\0'; 631130617Smlaier 632130617Smlaier snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld%s bufsz %u %s", 633130617Smlaier rman_get_start(ad1816->io_base), 634130617Smlaier rman_get_start(ad1816->irq), 635130617Smlaier rman_get_start(ad1816->drq1), 636130617Smlaier status2, 637130617Smlaier ad1816->bufsize, 638130617Smlaier PCM_KLDSTRING(snd_ad1816)); 639130617Smlaier 640130617Smlaier if (pcm_register(dev, ad1816, 1, 1)) goto no; 641130617Smlaier pcm_addchan(dev, PCMDIR_REC, &ad1816chan_class, ad1816); 642130617Smlaier pcm_addchan(dev, PCMDIR_PLAY, &ad1816chan_class, ad1816); 643130617Smlaier pcm_setstatus(dev, status); 644130617Smlaier 645130617Smlaier return 0; 646130617Smlaierno: 647130617Smlaier ad1816_release_resources(ad1816, dev); 648130617Smlaier 649130617Smlaier return ENXIO; 650130617Smlaier 651130617Smlaier} 652130617Smlaier 653130617Smlaierstatic int 654130617Smlaierad1816_detach(device_t dev) 655130617Smlaier{ 656126353Smlaier int r; 657130617Smlaier struct ad1816_info *ad1816; 658130617Smlaier 659126353Smlaier r = pcm_unregister(dev); 660126353Smlaier if (r) 661126353Smlaier return r; 662126353Smlaier 663126353Smlaier ad1816 = pcm_getdevinfo(dev); 664126353Smlaier ad1816_release_resources(ad1816, dev); 665126353Smlaier return 0; 666130617Smlaier} 667130617Smlaier 668130617Smlaierstatic device_method_t ad1816_methods[] = { 669126353Smlaier /* Device interface */ 670126353Smlaier DEVMETHOD(device_probe, ad1816_probe), 671126353Smlaier DEVMETHOD(device_attach, ad1816_attach), 672126353Smlaier DEVMETHOD(device_detach, ad1816_detach), 673126353Smlaier 674130617Smlaier { 0, 0 } 675130617Smlaier}; 676126353Smlaier 677126353Smlaierstatic driver_t ad1816_driver = { 678126353Smlaier "pcm", 679126353Smlaier ad1816_methods, 680126353Smlaier PCM_SOFTC_SIZE, 681130617Smlaier}; 682130617Smlaier 683130617SmlaierDRIVER_MODULE(snd_ad1816, isa, ad1816_driver, pcm_devclass, 0, 0); 684130617SmlaierDRIVER_MODULE(snd_ad1816, acpi, ad1816_driver, pcm_devclass, 0, 0); 685130617SmlaierMODULE_DEPEND(snd_ad1816, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 686130617SmlaierMODULE_VERSION(snd_ad1816, 1); 687126353Smlaier 688126353Smlaier 689126353Smlaier