1*e4afd792SAlexander Motin /*- 2*e4afd792SAlexander Motin * Copyright (c) 2012 Ruslan Bukin <br@bsdpad.com> 3*e4afd792SAlexander Motin * All rights reserved. 4*e4afd792SAlexander Motin * 5*e4afd792SAlexander Motin * Redistribution and use in source and binary forms, with or without 6*e4afd792SAlexander Motin * modification, are permitted provided that the following conditions 7*e4afd792SAlexander Motin * are met: 8*e4afd792SAlexander Motin * 1. Redistributions of source code must retain the above copyright 9*e4afd792SAlexander Motin * notice, this list of conditions and the following disclaimer. 10*e4afd792SAlexander Motin * 2. Redistributions in binary form must reproduce the above copyright 11*e4afd792SAlexander Motin * notice, this list of conditions and the following disclaimer in the 12*e4afd792SAlexander Motin * documentation and/or other materials provided with the distribution. 13*e4afd792SAlexander Motin * 14*e4afd792SAlexander Motin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*e4afd792SAlexander Motin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*e4afd792SAlexander Motin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*e4afd792SAlexander Motin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18*e4afd792SAlexander Motin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*e4afd792SAlexander Motin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*e4afd792SAlexander Motin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*e4afd792SAlexander Motin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*e4afd792SAlexander Motin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*e4afd792SAlexander Motin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*e4afd792SAlexander Motin * SUCH DAMAGE. 25*e4afd792SAlexander Motin */ 26*e4afd792SAlexander Motin 27*e4afd792SAlexander Motin /* 28*e4afd792SAlexander Motin * RME HDSPe driver for FreeBSD (pcm-part). 29*e4afd792SAlexander Motin * Supported cards: AIO, RayDAT. 30*e4afd792SAlexander Motin */ 31*e4afd792SAlexander Motin 32*e4afd792SAlexander Motin #include <dev/sound/pcm/sound.h> 33*e4afd792SAlexander Motin #include <dev/sound/pci/hdspe.h> 34*e4afd792SAlexander Motin #include <dev/sound/chip.h> 35*e4afd792SAlexander Motin 36*e4afd792SAlexander Motin #include <dev/pci/pcireg.h> 37*e4afd792SAlexander Motin #include <dev/pci/pcivar.h> 38*e4afd792SAlexander Motin 39*e4afd792SAlexander Motin #include <mixer_if.h> 40*e4afd792SAlexander Motin 41*e4afd792SAlexander Motin SND_DECLARE_FILE("$FreeBSD$"); 42*e4afd792SAlexander Motin 43*e4afd792SAlexander Motin struct hdspe_latency { 44*e4afd792SAlexander Motin uint32_t n; 45*e4afd792SAlexander Motin uint32_t period; 46*e4afd792SAlexander Motin float ms; 47*e4afd792SAlexander Motin }; 48*e4afd792SAlexander Motin 49*e4afd792SAlexander Motin static struct hdspe_latency latency_map[] = { 50*e4afd792SAlexander Motin { 7, 32, 0.7 }, 51*e4afd792SAlexander Motin { 0, 64, 1.5 }, 52*e4afd792SAlexander Motin { 1, 128, 3 }, 53*e4afd792SAlexander Motin { 2, 256, 6 }, 54*e4afd792SAlexander Motin { 3, 512, 12 }, 55*e4afd792SAlexander Motin { 4, 1024, 23 }, 56*e4afd792SAlexander Motin { 5, 2048, 46 }, 57*e4afd792SAlexander Motin { 6, 4096, 93 }, 58*e4afd792SAlexander Motin 59*e4afd792SAlexander Motin { 0, 0, 0 }, 60*e4afd792SAlexander Motin }; 61*e4afd792SAlexander Motin 62*e4afd792SAlexander Motin struct hdspe_rate { 63*e4afd792SAlexander Motin uint32_t speed; 64*e4afd792SAlexander Motin uint32_t reg; 65*e4afd792SAlexander Motin }; 66*e4afd792SAlexander Motin 67*e4afd792SAlexander Motin static struct hdspe_rate rate_map[] = { 68*e4afd792SAlexander Motin { 32000, (HDSPE_FREQ_32000) }, 69*e4afd792SAlexander Motin { 44100, (HDSPE_FREQ_44100) }, 70*e4afd792SAlexander Motin { 48000, (HDSPE_FREQ_48000) }, 71*e4afd792SAlexander Motin { 64000, (HDSPE_FREQ_32000 | HDSPE_FREQ_DOUBLE) }, 72*e4afd792SAlexander Motin { 88200, (HDSPE_FREQ_44100 | HDSPE_FREQ_DOUBLE) }, 73*e4afd792SAlexander Motin { 96000, (HDSPE_FREQ_48000 | HDSPE_FREQ_DOUBLE) }, 74*e4afd792SAlexander Motin { 128000, (HDSPE_FREQ_32000 | HDSPE_FREQ_QUAD) }, 75*e4afd792SAlexander Motin { 176400, (HDSPE_FREQ_44100 | HDSPE_FREQ_QUAD) }, 76*e4afd792SAlexander Motin { 192000, (HDSPE_FREQ_48000 | HDSPE_FREQ_QUAD) }, 77*e4afd792SAlexander Motin 78*e4afd792SAlexander Motin { 0, 0 }, 79*e4afd792SAlexander Motin }; 80*e4afd792SAlexander Motin 81*e4afd792SAlexander Motin 82*e4afd792SAlexander Motin static int 83*e4afd792SAlexander Motin hdspe_hw_mixer(struct sc_chinfo *ch, unsigned int dst, 84*e4afd792SAlexander Motin unsigned int src, unsigned short data) 85*e4afd792SAlexander Motin { 86*e4afd792SAlexander Motin struct sc_pcminfo *scp = ch->parent; 87*e4afd792SAlexander Motin struct sc_info *sc = scp->sc; 88*e4afd792SAlexander Motin int offs = 0; 89*e4afd792SAlexander Motin 90*e4afd792SAlexander Motin if (ch->dir == PCMDIR_PLAY) 91*e4afd792SAlexander Motin offs = 64; 92*e4afd792SAlexander Motin 93*e4afd792SAlexander Motin hdspe_write_4(sc, HDSPE_MIXER_BASE + 94*e4afd792SAlexander Motin ((offs + src + 128 * dst) * sizeof(uint32_t)), 95*e4afd792SAlexander Motin data & 0xFFFF); 96*e4afd792SAlexander Motin 97*e4afd792SAlexander Motin return 0; 98*e4afd792SAlexander Motin }; 99*e4afd792SAlexander Motin 100*e4afd792SAlexander Motin static int 101*e4afd792SAlexander Motin hdspechan_setgain(struct sc_chinfo *ch) 102*e4afd792SAlexander Motin { 103*e4afd792SAlexander Motin 104*e4afd792SAlexander Motin hdspe_hw_mixer(ch, ch->lslot, ch->lslot, 105*e4afd792SAlexander Motin ch->lvol * HDSPE_MAX_GAIN / 100); 106*e4afd792SAlexander Motin hdspe_hw_mixer(ch, ch->rslot, ch->rslot, 107*e4afd792SAlexander Motin ch->rvol * HDSPE_MAX_GAIN / 100); 108*e4afd792SAlexander Motin 109*e4afd792SAlexander Motin return 0; 110*e4afd792SAlexander Motin } 111*e4afd792SAlexander Motin 112*e4afd792SAlexander Motin static int 113*e4afd792SAlexander Motin hdspemixer_init(struct snd_mixer *m) 114*e4afd792SAlexander Motin { 115*e4afd792SAlexander Motin struct sc_pcminfo *scp = mix_getdevinfo(m); 116*e4afd792SAlexander Motin struct sc_info *sc = scp->sc; 117*e4afd792SAlexander Motin int mask; 118*e4afd792SAlexander Motin 119*e4afd792SAlexander Motin if (sc == NULL) 120*e4afd792SAlexander Motin return -1; 121*e4afd792SAlexander Motin 122*e4afd792SAlexander Motin mask = SOUND_MASK_PCM; 123*e4afd792SAlexander Motin 124*e4afd792SAlexander Motin if (scp->hc->play) 125*e4afd792SAlexander Motin mask |= SOUND_MASK_VOLUME; 126*e4afd792SAlexander Motin 127*e4afd792SAlexander Motin if (scp->hc->rec) 128*e4afd792SAlexander Motin mask |= SOUND_MASK_RECLEV; 129*e4afd792SAlexander Motin 130*e4afd792SAlexander Motin snd_mtxlock(sc->lock); 131*e4afd792SAlexander Motin pcm_setflags(scp->dev, pcm_getflags(scp->dev) | SD_F_SOFTPCMVOL); 132*e4afd792SAlexander Motin mix_setdevs(m, mask); 133*e4afd792SAlexander Motin snd_mtxunlock(sc->lock); 134*e4afd792SAlexander Motin 135*e4afd792SAlexander Motin return 0; 136*e4afd792SAlexander Motin } 137*e4afd792SAlexander Motin 138*e4afd792SAlexander Motin static int 139*e4afd792SAlexander Motin hdspemixer_set(struct snd_mixer *m, unsigned dev, 140*e4afd792SAlexander Motin unsigned left, unsigned right) 141*e4afd792SAlexander Motin { 142*e4afd792SAlexander Motin struct sc_pcminfo *scp = mix_getdevinfo(m); 143*e4afd792SAlexander Motin struct sc_chinfo *ch; 144*e4afd792SAlexander Motin int i; 145*e4afd792SAlexander Motin 146*e4afd792SAlexander Motin #if 0 147*e4afd792SAlexander Motin device_printf(scp->dev, "hdspemixer_set() %d %d\n", 148*e4afd792SAlexander Motin left,right); 149*e4afd792SAlexander Motin #endif 150*e4afd792SAlexander Motin 151*e4afd792SAlexander Motin for (i = 0; i < scp->chnum; i++) { 152*e4afd792SAlexander Motin ch = &scp->chan[i]; 153*e4afd792SAlexander Motin if ((dev == SOUND_MIXER_VOLUME && ch->dir == PCMDIR_PLAY) || 154*e4afd792SAlexander Motin (dev == SOUND_MIXER_RECLEV && ch->dir == PCMDIR_REC)) { 155*e4afd792SAlexander Motin ch->lvol = left; 156*e4afd792SAlexander Motin ch->rvol = right; 157*e4afd792SAlexander Motin if (ch->run) 158*e4afd792SAlexander Motin hdspechan_setgain(ch); 159*e4afd792SAlexander Motin } 160*e4afd792SAlexander Motin } 161*e4afd792SAlexander Motin 162*e4afd792SAlexander Motin return 0; 163*e4afd792SAlexander Motin } 164*e4afd792SAlexander Motin 165*e4afd792SAlexander Motin static kobj_method_t hdspemixer_methods[] = { 166*e4afd792SAlexander Motin KOBJMETHOD(mixer_init, hdspemixer_init), 167*e4afd792SAlexander Motin KOBJMETHOD(mixer_set, hdspemixer_set), 168*e4afd792SAlexander Motin KOBJMETHOD_END 169*e4afd792SAlexander Motin }; 170*e4afd792SAlexander Motin MIXER_DECLARE(hdspemixer); 171*e4afd792SAlexander Motin 172*e4afd792SAlexander Motin static void 173*e4afd792SAlexander Motin hdspechan_enable(struct sc_chinfo *ch, int value) 174*e4afd792SAlexander Motin { 175*e4afd792SAlexander Motin struct sc_pcminfo *scp = ch->parent; 176*e4afd792SAlexander Motin struct sc_info *sc = scp->sc; 177*e4afd792SAlexander Motin int reg; 178*e4afd792SAlexander Motin 179*e4afd792SAlexander Motin if (ch->dir == PCMDIR_PLAY) 180*e4afd792SAlexander Motin reg = HDSPE_OUT_ENABLE_BASE; 181*e4afd792SAlexander Motin else 182*e4afd792SAlexander Motin reg = HDSPE_IN_ENABLE_BASE; 183*e4afd792SAlexander Motin 184*e4afd792SAlexander Motin ch->run = value; 185*e4afd792SAlexander Motin 186*e4afd792SAlexander Motin hdspe_write_1(sc, reg + (4 * ch->lslot), value); 187*e4afd792SAlexander Motin hdspe_write_1(sc, reg + (4 * ch->rslot), value); 188*e4afd792SAlexander Motin } 189*e4afd792SAlexander Motin 190*e4afd792SAlexander Motin static int 191*e4afd792SAlexander Motin hdspe_running(struct sc_info *sc) 192*e4afd792SAlexander Motin { 193*e4afd792SAlexander Motin struct sc_pcminfo *scp; 194*e4afd792SAlexander Motin struct sc_chinfo *ch; 195*e4afd792SAlexander Motin int i, j, devcount, err; 196*e4afd792SAlexander Motin device_t *devlist; 197*e4afd792SAlexander Motin 198*e4afd792SAlexander Motin if ((err = device_get_children(sc->dev, &devlist, &devcount)) != 0) 199*e4afd792SAlexander Motin goto bad; 200*e4afd792SAlexander Motin 201*e4afd792SAlexander Motin for (i = 0; i < devcount; i++) { 202*e4afd792SAlexander Motin scp = device_get_ivars(devlist[i]); 203*e4afd792SAlexander Motin for (j = 0; j < scp->chnum; j++) { 204*e4afd792SAlexander Motin ch = &scp->chan[j]; 205*e4afd792SAlexander Motin if (ch->run) 206*e4afd792SAlexander Motin goto bad; 207*e4afd792SAlexander Motin } 208*e4afd792SAlexander Motin } 209*e4afd792SAlexander Motin 210*e4afd792SAlexander Motin return 0; 211*e4afd792SAlexander Motin bad: 212*e4afd792SAlexander Motin 213*e4afd792SAlexander Motin #if 0 214*e4afd792SAlexander Motin device_printf(sc->dev,"hdspe is running\n"); 215*e4afd792SAlexander Motin #endif 216*e4afd792SAlexander Motin 217*e4afd792SAlexander Motin return 1; 218*e4afd792SAlexander Motin } 219*e4afd792SAlexander Motin 220*e4afd792SAlexander Motin static void 221*e4afd792SAlexander Motin hdspe_start_audio(struct sc_info *sc) 222*e4afd792SAlexander Motin { 223*e4afd792SAlexander Motin 224*e4afd792SAlexander Motin sc->ctrl_register |= (HDSPE_AUDIO_INT_ENABLE | HDSPE_ENABLE); 225*e4afd792SAlexander Motin hdspe_write_4(sc, HDSPE_CONTROL_REG, sc->ctrl_register); 226*e4afd792SAlexander Motin } 227*e4afd792SAlexander Motin 228*e4afd792SAlexander Motin static void 229*e4afd792SAlexander Motin hdspe_stop_audio(struct sc_info *sc) 230*e4afd792SAlexander Motin { 231*e4afd792SAlexander Motin 232*e4afd792SAlexander Motin if (hdspe_running(sc) == 1) 233*e4afd792SAlexander Motin return; 234*e4afd792SAlexander Motin 235*e4afd792SAlexander Motin sc->ctrl_register &= ~(HDSPE_AUDIO_INT_ENABLE | HDSPE_ENABLE); 236*e4afd792SAlexander Motin hdspe_write_4(sc, HDSPE_CONTROL_REG, sc->ctrl_register); 237*e4afd792SAlexander Motin } 238*e4afd792SAlexander Motin 239*e4afd792SAlexander Motin /* Multiplex / demultiplex: 2.0 <-> 2 x 1.0. */ 240*e4afd792SAlexander Motin static void 241*e4afd792SAlexander Motin buffer_copy(struct sc_chinfo *ch) 242*e4afd792SAlexander Motin { 243*e4afd792SAlexander Motin struct sc_pcminfo *scp = ch->parent; 244*e4afd792SAlexander Motin struct sc_info *sc = scp->sc; 245*e4afd792SAlexander Motin int length,src,dst; 246*e4afd792SAlexander Motin int ssize, dsize; 247*e4afd792SAlexander Motin int i; 248*e4afd792SAlexander Motin 249*e4afd792SAlexander Motin length = sndbuf_getready(ch->buffer) / 250*e4afd792SAlexander Motin (4 /* Bytes per sample. */ * 2 /* channels */); 251*e4afd792SAlexander Motin 252*e4afd792SAlexander Motin if (ch->dir == PCMDIR_PLAY) { 253*e4afd792SAlexander Motin src = sndbuf_getreadyptr(ch->buffer); 254*e4afd792SAlexander Motin } else { 255*e4afd792SAlexander Motin src = sndbuf_getfreeptr(ch->buffer); 256*e4afd792SAlexander Motin } 257*e4afd792SAlexander Motin 258*e4afd792SAlexander Motin src /= 4; /* Bytes per sample. */ 259*e4afd792SAlexander Motin dst = src / 2; /* Destination buffer twice smaller. */ 260*e4afd792SAlexander Motin 261*e4afd792SAlexander Motin ssize = ch->size / 4; 262*e4afd792SAlexander Motin dsize = ch->size / 8; 263*e4afd792SAlexander Motin 264*e4afd792SAlexander Motin /* 265*e4afd792SAlexander Motin * Use two fragment buffer to avoid sound clipping. 266*e4afd792SAlexander Motin */ 267*e4afd792SAlexander Motin 268*e4afd792SAlexander Motin for (i = 0; i < sc->period * 2 /* fragments */; i++) { 269*e4afd792SAlexander Motin if (ch->dir == PCMDIR_PLAY) { 270*e4afd792SAlexander Motin sc->pbuf[dst + HDSPE_CHANBUF_SAMPLES * ch->lslot] = 271*e4afd792SAlexander Motin ch->data[src]; 272*e4afd792SAlexander Motin sc->pbuf[dst + HDSPE_CHANBUF_SAMPLES * ch->rslot] = 273*e4afd792SAlexander Motin ch->data[src + 1]; 274*e4afd792SAlexander Motin 275*e4afd792SAlexander Motin } else { 276*e4afd792SAlexander Motin ch->data[src] = 277*e4afd792SAlexander Motin sc->rbuf[dst + HDSPE_CHANBUF_SAMPLES * ch->lslot]; 278*e4afd792SAlexander Motin ch->data[src+1] = 279*e4afd792SAlexander Motin sc->rbuf[dst + HDSPE_CHANBUF_SAMPLES * ch->rslot]; 280*e4afd792SAlexander Motin } 281*e4afd792SAlexander Motin 282*e4afd792SAlexander Motin dst+=1; 283*e4afd792SAlexander Motin dst %= dsize; 284*e4afd792SAlexander Motin src+=2; 285*e4afd792SAlexander Motin src %= ssize; 286*e4afd792SAlexander Motin } 287*e4afd792SAlexander Motin } 288*e4afd792SAlexander Motin 289*e4afd792SAlexander Motin static int 290*e4afd792SAlexander Motin clean(struct sc_chinfo *ch){ 291*e4afd792SAlexander Motin struct sc_pcminfo *scp = ch->parent; 292*e4afd792SAlexander Motin struct sc_info *sc = scp->sc; 293*e4afd792SAlexander Motin uint32_t *buf = sc->rbuf; 294*e4afd792SAlexander Motin 295*e4afd792SAlexander Motin if (ch->dir == PCMDIR_PLAY) { 296*e4afd792SAlexander Motin buf = sc->pbuf; 297*e4afd792SAlexander Motin } 298*e4afd792SAlexander Motin 299*e4afd792SAlexander Motin bzero(buf + HDSPE_CHANBUF_SAMPLES * ch->lslot, HDSPE_CHANBUF_SIZE); 300*e4afd792SAlexander Motin bzero(buf + HDSPE_CHANBUF_SAMPLES * ch->rslot, HDSPE_CHANBUF_SIZE); 301*e4afd792SAlexander Motin 302*e4afd792SAlexander Motin return 0; 303*e4afd792SAlexander Motin } 304*e4afd792SAlexander Motin 305*e4afd792SAlexander Motin 306*e4afd792SAlexander Motin /* Channel interface. */ 307*e4afd792SAlexander Motin static void * 308*e4afd792SAlexander Motin hdspechan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, 309*e4afd792SAlexander Motin struct pcm_channel *c, int dir) 310*e4afd792SAlexander Motin { 311*e4afd792SAlexander Motin struct sc_pcminfo *scp = devinfo; 312*e4afd792SAlexander Motin struct sc_info *sc = scp->sc; 313*e4afd792SAlexander Motin struct sc_chinfo *ch; 314*e4afd792SAlexander Motin int num; 315*e4afd792SAlexander Motin 316*e4afd792SAlexander Motin snd_mtxlock(sc->lock); 317*e4afd792SAlexander Motin num = scp->chnum; 318*e4afd792SAlexander Motin 319*e4afd792SAlexander Motin ch = &scp->chan[num]; 320*e4afd792SAlexander Motin ch->lslot = scp->hc->left; 321*e4afd792SAlexander Motin ch->rslot = scp->hc->right; 322*e4afd792SAlexander Motin ch->run = 0; 323*e4afd792SAlexander Motin ch->lvol = 0; 324*e4afd792SAlexander Motin ch->rvol = 0; 325*e4afd792SAlexander Motin 326*e4afd792SAlexander Motin ch->size = HDSPE_CHANBUF_SIZE * 2 /* slots */; 327*e4afd792SAlexander Motin ch->data = malloc(ch->size, M_HDSPE, M_NOWAIT); 328*e4afd792SAlexander Motin 329*e4afd792SAlexander Motin ch->buffer = b; 330*e4afd792SAlexander Motin ch->channel = c; 331*e4afd792SAlexander Motin ch->parent = scp; 332*e4afd792SAlexander Motin 333*e4afd792SAlexander Motin ch->dir = dir; 334*e4afd792SAlexander Motin 335*e4afd792SAlexander Motin snd_mtxunlock(sc->lock); 336*e4afd792SAlexander Motin 337*e4afd792SAlexander Motin if (sndbuf_setup(ch->buffer, ch->data, ch->size) != 0) { 338*e4afd792SAlexander Motin device_printf(scp->dev, "Can't setup sndbuf.\n"); 339*e4afd792SAlexander Motin return NULL; 340*e4afd792SAlexander Motin } 341*e4afd792SAlexander Motin 342*e4afd792SAlexander Motin return ch; 343*e4afd792SAlexander Motin } 344*e4afd792SAlexander Motin 345*e4afd792SAlexander Motin static int 346*e4afd792SAlexander Motin hdspechan_trigger(kobj_t obj, void *data, int go) 347*e4afd792SAlexander Motin { 348*e4afd792SAlexander Motin struct sc_chinfo *ch = data; 349*e4afd792SAlexander Motin struct sc_pcminfo *scp = ch->parent; 350*e4afd792SAlexander Motin struct sc_info *sc = scp->sc; 351*e4afd792SAlexander Motin 352*e4afd792SAlexander Motin snd_mtxlock(sc->lock); 353*e4afd792SAlexander Motin switch (go) { 354*e4afd792SAlexander Motin case PCMTRIG_START: 355*e4afd792SAlexander Motin #if 0 356*e4afd792SAlexander Motin device_printf(scp->dev, "hdspechan_trigger(): start\n"); 357*e4afd792SAlexander Motin #endif 358*e4afd792SAlexander Motin hdspechan_enable(ch, 1); 359*e4afd792SAlexander Motin hdspechan_setgain(ch); 360*e4afd792SAlexander Motin hdspe_start_audio(sc); 361*e4afd792SAlexander Motin break; 362*e4afd792SAlexander Motin 363*e4afd792SAlexander Motin case PCMTRIG_STOP: 364*e4afd792SAlexander Motin case PCMTRIG_ABORT: 365*e4afd792SAlexander Motin #if 0 366*e4afd792SAlexander Motin device_printf(scp->dev, "hdspechan_trigger(): stop or abort\n"); 367*e4afd792SAlexander Motin #endif 368*e4afd792SAlexander Motin clean(ch); 369*e4afd792SAlexander Motin hdspechan_enable(ch, 0); 370*e4afd792SAlexander Motin hdspe_stop_audio(sc); 371*e4afd792SAlexander Motin break; 372*e4afd792SAlexander Motin 373*e4afd792SAlexander Motin case PCMTRIG_EMLDMAWR: 374*e4afd792SAlexander Motin case PCMTRIG_EMLDMARD: 375*e4afd792SAlexander Motin if(ch->run) 376*e4afd792SAlexander Motin buffer_copy(ch); 377*e4afd792SAlexander Motin break; 378*e4afd792SAlexander Motin } 379*e4afd792SAlexander Motin 380*e4afd792SAlexander Motin snd_mtxunlock(sc->lock); 381*e4afd792SAlexander Motin 382*e4afd792SAlexander Motin return 0; 383*e4afd792SAlexander Motin } 384*e4afd792SAlexander Motin 385*e4afd792SAlexander Motin static uint32_t 386*e4afd792SAlexander Motin hdspechan_getptr(kobj_t obj, void *data) 387*e4afd792SAlexander Motin { 388*e4afd792SAlexander Motin struct sc_chinfo *ch = data; 389*e4afd792SAlexander Motin struct sc_pcminfo *scp = ch->parent; 390*e4afd792SAlexander Motin struct sc_info *sc = scp->sc; 391*e4afd792SAlexander Motin uint32_t ret, pos; 392*e4afd792SAlexander Motin 393*e4afd792SAlexander Motin snd_mtxlock(sc->lock); 394*e4afd792SAlexander Motin ret = hdspe_read_2(sc, HDSPE_STATUS_REG); 395*e4afd792SAlexander Motin snd_mtxunlock(sc->lock); 396*e4afd792SAlexander Motin 397*e4afd792SAlexander Motin pos = ret & HDSPE_BUF_POSITION_MASK; 398*e4afd792SAlexander Motin pos *= 2; /* Hardbuf twice bigger. */ 399*e4afd792SAlexander Motin 400*e4afd792SAlexander Motin return pos; 401*e4afd792SAlexander Motin } 402*e4afd792SAlexander Motin 403*e4afd792SAlexander Motin static int 404*e4afd792SAlexander Motin hdspechan_free(kobj_t obj, void *data) 405*e4afd792SAlexander Motin { 406*e4afd792SAlexander Motin struct sc_chinfo *ch = data; 407*e4afd792SAlexander Motin struct sc_pcminfo *scp = ch->parent; 408*e4afd792SAlexander Motin struct sc_info *sc = scp->sc; 409*e4afd792SAlexander Motin 410*e4afd792SAlexander Motin #if 0 411*e4afd792SAlexander Motin device_printf(scp->dev, "hdspechan_free()\n"); 412*e4afd792SAlexander Motin #endif 413*e4afd792SAlexander Motin snd_mtxlock(sc->lock); 414*e4afd792SAlexander Motin if (ch->data != NULL) { 415*e4afd792SAlexander Motin free(ch->data, M_HDSPE); 416*e4afd792SAlexander Motin ch->data = NULL; 417*e4afd792SAlexander Motin } 418*e4afd792SAlexander Motin snd_mtxunlock(sc->lock); 419*e4afd792SAlexander Motin 420*e4afd792SAlexander Motin return 0; 421*e4afd792SAlexander Motin } 422*e4afd792SAlexander Motin 423*e4afd792SAlexander Motin static int 424*e4afd792SAlexander Motin hdspechan_setformat(kobj_t obj, void *data, uint32_t format) 425*e4afd792SAlexander Motin { 426*e4afd792SAlexander Motin struct sc_chinfo *ch = data; 427*e4afd792SAlexander Motin 428*e4afd792SAlexander Motin #if 0 429*e4afd792SAlexander Motin struct sc_pcminfo *scp = ch->parent; 430*e4afd792SAlexander Motin device_printf(scp->dev, "hdspechan_setformat(%d)\n", format); 431*e4afd792SAlexander Motin #endif 432*e4afd792SAlexander Motin 433*e4afd792SAlexander Motin ch->format = format; 434*e4afd792SAlexander Motin 435*e4afd792SAlexander Motin return 0; 436*e4afd792SAlexander Motin } 437*e4afd792SAlexander Motin 438*e4afd792SAlexander Motin static uint32_t 439*e4afd792SAlexander Motin hdspechan_setspeed(kobj_t obj, void *data, uint32_t speed) 440*e4afd792SAlexander Motin { 441*e4afd792SAlexander Motin struct sc_chinfo *ch = data; 442*e4afd792SAlexander Motin struct sc_pcminfo *scp = ch->parent; 443*e4afd792SAlexander Motin struct sc_info *sc = scp->sc; 444*e4afd792SAlexander Motin struct hdspe_rate *hr = NULL; 445*e4afd792SAlexander Motin long long period; 446*e4afd792SAlexander Motin int threshold; 447*e4afd792SAlexander Motin int i; 448*e4afd792SAlexander Motin 449*e4afd792SAlexander Motin #if 0 450*e4afd792SAlexander Motin device_printf(scp->dev, "hdspechan_setspeed(%d)\n", speed); 451*e4afd792SAlexander Motin #endif 452*e4afd792SAlexander Motin 453*e4afd792SAlexander Motin if (hdspe_running(sc) == 1) 454*e4afd792SAlexander Motin goto end; 455*e4afd792SAlexander Motin 456*e4afd792SAlexander Motin /* First look for equal frequency. */ 457*e4afd792SAlexander Motin for (i = 0; rate_map[i].speed != 0; i++) { 458*e4afd792SAlexander Motin if (rate_map[i].speed == speed) 459*e4afd792SAlexander Motin hr = &rate_map[i]; 460*e4afd792SAlexander Motin } 461*e4afd792SAlexander Motin 462*e4afd792SAlexander Motin /* If no match, just find nearest. */ 463*e4afd792SAlexander Motin if (hr == NULL) { 464*e4afd792SAlexander Motin for (i = 0; rate_map[i].speed != 0; i++) { 465*e4afd792SAlexander Motin hr = &rate_map[i]; 466*e4afd792SAlexander Motin threshold = hr->speed + ((rate_map[i + 1].speed != 0) ? 467*e4afd792SAlexander Motin ((rate_map[i + 1].speed - hr->speed) >> 1) : 0); 468*e4afd792SAlexander Motin if (speed < threshold) 469*e4afd792SAlexander Motin break; 470*e4afd792SAlexander Motin } 471*e4afd792SAlexander Motin } 472*e4afd792SAlexander Motin 473*e4afd792SAlexander Motin switch (sc->type) { 474*e4afd792SAlexander Motin case RAYDAT: 475*e4afd792SAlexander Motin case AIO: 476*e4afd792SAlexander Motin period = HDSPE_FREQ_AIO; 477*e4afd792SAlexander Motin break; 478*e4afd792SAlexander Motin default: 479*e4afd792SAlexander Motin /* Unsupported card. */ 480*e4afd792SAlexander Motin goto end; 481*e4afd792SAlexander Motin } 482*e4afd792SAlexander Motin 483*e4afd792SAlexander Motin /* Write frequency on the device. */ 484*e4afd792SAlexander Motin sc->ctrl_register &= ~HDSPE_FREQ_MASK; 485*e4afd792SAlexander Motin sc->ctrl_register |= hr->reg; 486*e4afd792SAlexander Motin hdspe_write_4(sc, HDSPE_CONTROL_REG, sc->ctrl_register); 487*e4afd792SAlexander Motin 488*e4afd792SAlexander Motin speed = hr->speed; 489*e4afd792SAlexander Motin if (speed > 96000) 490*e4afd792SAlexander Motin speed /= 4; 491*e4afd792SAlexander Motin else if (speed > 48000) 492*e4afd792SAlexander Motin speed /= 2; 493*e4afd792SAlexander Motin 494*e4afd792SAlexander Motin /* Set DDS value. */ 495*e4afd792SAlexander Motin period /= speed; 496*e4afd792SAlexander Motin hdspe_write_4(sc, HDSPE_FREQ_REG, period); 497*e4afd792SAlexander Motin 498*e4afd792SAlexander Motin sc->speed = hr->speed; 499*e4afd792SAlexander Motin end: 500*e4afd792SAlexander Motin return sc->speed; 501*e4afd792SAlexander Motin } 502*e4afd792SAlexander Motin 503*e4afd792SAlexander Motin static uint32_t 504*e4afd792SAlexander Motin hdspechan_setblocksize(kobj_t obj, void *data, uint32_t blocksize) 505*e4afd792SAlexander Motin { 506*e4afd792SAlexander Motin struct sc_chinfo *ch = data; 507*e4afd792SAlexander Motin struct sc_pcminfo *scp = ch->parent; 508*e4afd792SAlexander Motin struct sc_info *sc = scp->sc; 509*e4afd792SAlexander Motin struct hdspe_latency *hl = NULL; 510*e4afd792SAlexander Motin int threshold; 511*e4afd792SAlexander Motin int i; 512*e4afd792SAlexander Motin 513*e4afd792SAlexander Motin #if 0 514*e4afd792SAlexander Motin device_printf(scp->dev, "hdspechan_setblocksize(%d)\n", blocksize); 515*e4afd792SAlexander Motin #endif 516*e4afd792SAlexander Motin 517*e4afd792SAlexander Motin if (hdspe_running(sc) == 1) 518*e4afd792SAlexander Motin goto end; 519*e4afd792SAlexander Motin 520*e4afd792SAlexander Motin if (blocksize > HDSPE_LAT_BYTES_MAX) 521*e4afd792SAlexander Motin blocksize = HDSPE_LAT_BYTES_MAX; 522*e4afd792SAlexander Motin else if (blocksize < HDSPE_LAT_BYTES_MIN) 523*e4afd792SAlexander Motin blocksize = HDSPE_LAT_BYTES_MIN; 524*e4afd792SAlexander Motin 525*e4afd792SAlexander Motin blocksize /= 4 /* samples */; 526*e4afd792SAlexander Motin 527*e4afd792SAlexander Motin /* First look for equal latency. */ 528*e4afd792SAlexander Motin for (i = 0; latency_map[i].period != 0; i++) { 529*e4afd792SAlexander Motin if (latency_map[i].period == blocksize) { 530*e4afd792SAlexander Motin hl = &latency_map[i]; 531*e4afd792SAlexander Motin } 532*e4afd792SAlexander Motin } 533*e4afd792SAlexander Motin 534*e4afd792SAlexander Motin /* If no match, just find nearest. */ 535*e4afd792SAlexander Motin if (hl == NULL) { 536*e4afd792SAlexander Motin for (i = 0; latency_map[i].period != 0; i++) { 537*e4afd792SAlexander Motin hl = &latency_map[i]; 538*e4afd792SAlexander Motin threshold = hl->period + ((latency_map[i + 1].period != 0) ? 539*e4afd792SAlexander Motin ((latency_map[i + 1].period - hl->period) >> 1) : 0); 540*e4afd792SAlexander Motin if (blocksize < threshold) 541*e4afd792SAlexander Motin break; 542*e4afd792SAlexander Motin } 543*e4afd792SAlexander Motin } 544*e4afd792SAlexander Motin 545*e4afd792SAlexander Motin snd_mtxlock(sc->lock); 546*e4afd792SAlexander Motin sc->ctrl_register &= ~HDSPE_LAT_MASK; 547*e4afd792SAlexander Motin sc->ctrl_register |= hdspe_encode_latency(hl->n); 548*e4afd792SAlexander Motin hdspe_write_4(sc, HDSPE_CONTROL_REG, sc->ctrl_register); 549*e4afd792SAlexander Motin sc->period = hl->period; 550*e4afd792SAlexander Motin snd_mtxunlock(sc->lock); 551*e4afd792SAlexander Motin 552*e4afd792SAlexander Motin #if 0 553*e4afd792SAlexander Motin device_printf(scp->dev, "New period=%d\n", sc->period); 554*e4afd792SAlexander Motin #endif 555*e4afd792SAlexander Motin 556*e4afd792SAlexander Motin sndbuf_resize(ch->buffer, (HDSPE_CHANBUF_SIZE * 2) / (sc->period * 4), 557*e4afd792SAlexander Motin (sc->period * 4)); 558*e4afd792SAlexander Motin end: 559*e4afd792SAlexander Motin return sndbuf_getblksz(ch->buffer); 560*e4afd792SAlexander Motin } 561*e4afd792SAlexander Motin 562*e4afd792SAlexander Motin static uint32_t hdspe_rfmt[] = { 563*e4afd792SAlexander Motin SND_FORMAT(AFMT_S32_LE, 2, 0), 564*e4afd792SAlexander Motin 0 565*e4afd792SAlexander Motin }; 566*e4afd792SAlexander Motin 567*e4afd792SAlexander Motin static struct pcmchan_caps hdspe_rcaps = {32000, 192000, hdspe_rfmt, 0}; 568*e4afd792SAlexander Motin 569*e4afd792SAlexander Motin static uint32_t hdspe_pfmt[] = { 570*e4afd792SAlexander Motin SND_FORMAT(AFMT_S32_LE, 2, 0), 571*e4afd792SAlexander Motin 0 572*e4afd792SAlexander Motin }; 573*e4afd792SAlexander Motin 574*e4afd792SAlexander Motin static struct pcmchan_caps hdspe_pcaps = {32000, 192000, hdspe_pfmt, 0}; 575*e4afd792SAlexander Motin 576*e4afd792SAlexander Motin static struct pcmchan_caps * 577*e4afd792SAlexander Motin hdspechan_getcaps(kobj_t obj, void *data) 578*e4afd792SAlexander Motin { 579*e4afd792SAlexander Motin struct sc_chinfo *ch = data; 580*e4afd792SAlexander Motin 581*e4afd792SAlexander Motin #if 0 582*e4afd792SAlexander Motin struct sc_pcminfo *scl = ch->parent; 583*e4afd792SAlexander Motin device_printf(scp->dev, "hdspechan_getcaps()\n"); 584*e4afd792SAlexander Motin #endif 585*e4afd792SAlexander Motin 586*e4afd792SAlexander Motin return (ch->dir == PCMDIR_PLAY) ? 587*e4afd792SAlexander Motin &hdspe_pcaps : &hdspe_rcaps; 588*e4afd792SAlexander Motin } 589*e4afd792SAlexander Motin 590*e4afd792SAlexander Motin static kobj_method_t hdspechan_methods[] = { 591*e4afd792SAlexander Motin KOBJMETHOD(channel_init, hdspechan_init), 592*e4afd792SAlexander Motin KOBJMETHOD(channel_free, hdspechan_free), 593*e4afd792SAlexander Motin KOBJMETHOD(channel_setformat, hdspechan_setformat), 594*e4afd792SAlexander Motin KOBJMETHOD(channel_setspeed, hdspechan_setspeed), 595*e4afd792SAlexander Motin KOBJMETHOD(channel_setblocksize, hdspechan_setblocksize), 596*e4afd792SAlexander Motin KOBJMETHOD(channel_trigger, hdspechan_trigger), 597*e4afd792SAlexander Motin KOBJMETHOD(channel_getptr, hdspechan_getptr), 598*e4afd792SAlexander Motin KOBJMETHOD(channel_getcaps, hdspechan_getcaps), 599*e4afd792SAlexander Motin KOBJMETHOD_END 600*e4afd792SAlexander Motin }; 601*e4afd792SAlexander Motin CHANNEL_DECLARE(hdspechan); 602*e4afd792SAlexander Motin 603*e4afd792SAlexander Motin 604*e4afd792SAlexander Motin static int 605*e4afd792SAlexander Motin hdspe_pcm_probe(device_t dev) 606*e4afd792SAlexander Motin { 607*e4afd792SAlexander Motin 608*e4afd792SAlexander Motin #if 0 609*e4afd792SAlexander Motin device_printf(dev,"hdspe_pcm_probe()\n"); 610*e4afd792SAlexander Motin #endif 611*e4afd792SAlexander Motin 612*e4afd792SAlexander Motin return 0; 613*e4afd792SAlexander Motin } 614*e4afd792SAlexander Motin 615*e4afd792SAlexander Motin static uint32_t 616*e4afd792SAlexander Motin hdspe_pcm_intr(struct sc_pcminfo *scp) { 617*e4afd792SAlexander Motin struct sc_chinfo *ch; 618*e4afd792SAlexander Motin struct sc_info *sc = scp->sc; 619*e4afd792SAlexander Motin int i; 620*e4afd792SAlexander Motin 621*e4afd792SAlexander Motin for (i = 0; i < scp->chnum; i++) { 622*e4afd792SAlexander Motin ch = &scp->chan[i]; 623*e4afd792SAlexander Motin snd_mtxunlock(sc->lock); 624*e4afd792SAlexander Motin chn_intr(ch->channel); 625*e4afd792SAlexander Motin snd_mtxlock(sc->lock); 626*e4afd792SAlexander Motin } 627*e4afd792SAlexander Motin 628*e4afd792SAlexander Motin return 0; 629*e4afd792SAlexander Motin } 630*e4afd792SAlexander Motin 631*e4afd792SAlexander Motin static int 632*e4afd792SAlexander Motin hdspe_pcm_attach(device_t dev) 633*e4afd792SAlexander Motin { 634*e4afd792SAlexander Motin struct sc_pcminfo *scp; 635*e4afd792SAlexander Motin char status[SND_STATUSLEN]; 636*e4afd792SAlexander Motin char desc[64]; 637*e4afd792SAlexander Motin int i, err; 638*e4afd792SAlexander Motin 639*e4afd792SAlexander Motin scp = device_get_ivars(dev); 640*e4afd792SAlexander Motin scp->ih = &hdspe_pcm_intr; 641*e4afd792SAlexander Motin 642*e4afd792SAlexander Motin bzero(desc, sizeof(desc)); 643*e4afd792SAlexander Motin snprintf(desc, sizeof(desc), "HDSPe AIO [%s]", scp->hc->descr); 644*e4afd792SAlexander Motin device_set_desc_copy(dev, desc); 645*e4afd792SAlexander Motin 646*e4afd792SAlexander Motin /* 647*e4afd792SAlexander Motin * We don't register interrupt handler with snd_setup_intr 648*e4afd792SAlexander Motin * in pcm device. Mark pcm device as MPSAFE manually. 649*e4afd792SAlexander Motin */ 650*e4afd792SAlexander Motin pcm_setflags(dev, pcm_getflags(dev) | SD_F_MPSAFE); 651*e4afd792SAlexander Motin 652*e4afd792SAlexander Motin err = pcm_register(dev, scp, scp->hc->play, scp->hc->rec); 653*e4afd792SAlexander Motin if (err) { 654*e4afd792SAlexander Motin device_printf(dev, "Can't register pcm.\n"); 655*e4afd792SAlexander Motin return ENXIO; 656*e4afd792SAlexander Motin } 657*e4afd792SAlexander Motin 658*e4afd792SAlexander Motin scp->chnum = 0; 659*e4afd792SAlexander Motin for (i = 0; i < scp->hc->play; i++) { 660*e4afd792SAlexander Motin pcm_addchan(dev, PCMDIR_PLAY, &hdspechan_class, scp); 661*e4afd792SAlexander Motin scp->chnum++; 662*e4afd792SAlexander Motin } 663*e4afd792SAlexander Motin 664*e4afd792SAlexander Motin for (i = 0; i < scp->hc->rec; i++) { 665*e4afd792SAlexander Motin pcm_addchan(dev, PCMDIR_REC, &hdspechan_class, scp); 666*e4afd792SAlexander Motin scp->chnum++; 667*e4afd792SAlexander Motin } 668*e4afd792SAlexander Motin 669*e4afd792SAlexander Motin snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s", 670*e4afd792SAlexander Motin rman_get_start(scp->sc->cs), 671*e4afd792SAlexander Motin rman_get_start(scp->sc->irq), 672*e4afd792SAlexander Motin PCM_KLDSTRING(snd_hdspe)); 673*e4afd792SAlexander Motin pcm_setstatus(dev, status); 674*e4afd792SAlexander Motin 675*e4afd792SAlexander Motin mixer_init(dev, &hdspemixer_class, scp); 676*e4afd792SAlexander Motin 677*e4afd792SAlexander Motin return 0; 678*e4afd792SAlexander Motin } 679*e4afd792SAlexander Motin 680*e4afd792SAlexander Motin static int 681*e4afd792SAlexander Motin hdspe_pcm_detach(device_t dev) 682*e4afd792SAlexander Motin { 683*e4afd792SAlexander Motin int err; 684*e4afd792SAlexander Motin 685*e4afd792SAlexander Motin err = pcm_unregister(dev); 686*e4afd792SAlexander Motin if (err) { 687*e4afd792SAlexander Motin device_printf(dev, "Can't unregister device.\n"); 688*e4afd792SAlexander Motin return err; 689*e4afd792SAlexander Motin } 690*e4afd792SAlexander Motin 691*e4afd792SAlexander Motin return 0; 692*e4afd792SAlexander Motin } 693*e4afd792SAlexander Motin 694*e4afd792SAlexander Motin static device_method_t hdspe_pcm_methods[] = { 695*e4afd792SAlexander Motin DEVMETHOD(device_probe, hdspe_pcm_probe), 696*e4afd792SAlexander Motin DEVMETHOD(device_attach, hdspe_pcm_attach), 697*e4afd792SAlexander Motin DEVMETHOD(device_detach, hdspe_pcm_detach), 698*e4afd792SAlexander Motin { 0, 0 } 699*e4afd792SAlexander Motin }; 700*e4afd792SAlexander Motin 701*e4afd792SAlexander Motin static driver_t hdspe_pcm_driver = { 702*e4afd792SAlexander Motin "pcm", 703*e4afd792SAlexander Motin hdspe_pcm_methods, 704*e4afd792SAlexander Motin PCM_SOFTC_SIZE, 705*e4afd792SAlexander Motin }; 706*e4afd792SAlexander Motin 707*e4afd792SAlexander Motin DRIVER_MODULE(snd_hdspe_pcm, hdspe, hdspe_pcm_driver, pcm_devclass, 0, 0); 708*e4afd792SAlexander Motin MODULE_DEPEND(snd_hdspe, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 709*e4afd792SAlexander Motin MODULE_VERSION(snd_hdspe, 1); 710