Lines Matching +full:in +full:- +full:ports

1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2012-2021 Ruslan Bukin <br@bsdpad.com>
5 * Copyright (c) 2023-2024 Florian Walpen <dev@submerge.ch>
8 * Redistribution and use in source and binary forms, with or without
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * RME HDSPe driver for FreeBSD (pcm-part).
86 return (hc->ports & (HDSPE_CHAN_AIO_ALL | HDSPE_CHAN_RAY_ALL)); in hdspe_channel_play_ports()
92 return (hc->ports & (HDSPE_CHAN_AIO_ALL_REC | HDSPE_CHAN_RAY_ALL)); in hdspe_channel_rec_ports()
106 hdspe_port_first(uint32_t ports) in hdspe_port_first() argument
108 return (ports & (~(ports - 1))); /* Extract first bit set. */ in hdspe_port_first()
112 hdspe_port_first_row(uint32_t ports) in hdspe_port_first_row() argument
116 /* Restrict ports to one set with contiguous slots. */ in hdspe_port_first_row()
117 if (ports & HDSPE_CHAN_AIO_ALL) in hdspe_port_first_row()
118 ports &= HDSPE_CHAN_AIO_ALL; /* All AIO slots. */ in hdspe_port_first_row()
119 else if (ports & HDSPE_CHAN_RAY_ALL) in hdspe_port_first_row()
120 ports &= HDSPE_CHAN_RAY_ALL; /* All RayDAT slots. */ in hdspe_port_first_row()
122 /* Ends of port rows are followed by a port which is not in the set. */ in hdspe_port_first_row()
123 ends = ports & (~(ports >> 1)); in hdspe_port_first_row()
124 /* First row of contiguous ports ends in the first row end. */ in hdspe_port_first_row()
125 return (ports & (ends ^ (ends - 1))); in hdspe_port_first_row()
129 hdspe_channel_count(uint32_t ports, uint32_t adat_width) in hdspe_channel_count() argument
133 if (ports & HDSPE_CHAN_AIO_ALL) { in hdspe_channel_count()
134 /* AIO ports. */ in hdspe_channel_count()
135 if (ports & HDSPE_CHAN_AIO_LINE) in hdspe_channel_count()
137 if (ports & HDSPE_CHAN_AIO_EXT) in hdspe_channel_count()
139 if (ports & HDSPE_CHAN_AIO_PHONE) in hdspe_channel_count()
141 if (ports & HDSPE_CHAN_AIO_AES) in hdspe_channel_count()
143 if (ports & HDSPE_CHAN_AIO_SPDIF) in hdspe_channel_count()
145 if (ports & HDSPE_CHAN_AIO_ADAT) in hdspe_channel_count()
147 } else if (ports & HDSPE_CHAN_RAY_ALL) { in hdspe_channel_count()
148 /* RayDAT ports. */ in hdspe_channel_count()
149 if (ports & HDSPE_CHAN_RAY_AES) in hdspe_channel_count()
151 if (ports & HDSPE_CHAN_RAY_SPDIF) in hdspe_channel_count()
153 if (ports & HDSPE_CHAN_RAY_ADAT1) in hdspe_channel_count()
155 if (ports & HDSPE_CHAN_RAY_ADAT2) in hdspe_channel_count()
157 if (ports & HDSPE_CHAN_RAY_ADAT3) in hdspe_channel_count()
159 if (ports & HDSPE_CHAN_RAY_ADAT4) in hdspe_channel_count()
167 hdspe_channel_offset(uint32_t subset, uint32_t ports, unsigned int adat_width) in hdspe_channel_offset() argument
171 /* Make sure we have a subset of ports. */ in hdspe_channel_offset()
172 subset &= ports; in hdspe_channel_offset()
173 /* Include all ports preceding the first one of the subset. */ in hdspe_channel_offset()
174 preceding = ports & (~subset & (subset - 1)); in hdspe_channel_offset()
187 /* Exctract the first port (lowest bit) if set of ports. */ in hdspe_port_slot_offset()
189 /* AIO ports */ in hdspe_port_slot_offset()
203 /* RayDAT ports */ in hdspe_port_slot_offset()
222 hdspe_port_slot_width(uint32_t ports, unsigned int adat_width) in hdspe_port_slot_width() argument
227 row = hdspe_port_first_row(ports); in hdspe_port_slot_width()
239 scp = ch->parent; in hdspe_hw_mixer()
240 sc = scp->sc; in hdspe_hw_mixer()
243 if (ch->dir == PCMDIR_PLAY) in hdspe_hw_mixer()
257 uint32_t port, ports; in hdspechan_setgain() local
261 sc = ch->parent->sc; in hdspechan_setgain()
263 /* Iterate through all physical ports of the channel. */ in hdspechan_setgain()
264 ports = ch->ports; in hdspechan_setgain()
265 port = hdspe_port_first(ports); in hdspechan_setgain()
269 hdspe_port_slot_offset(port, hdspe_adat_width(sc->speed)); in hdspechan_setgain()
271 hdspe_port_slot_width(port, hdspe_adat_width(sc->speed)); in hdspechan_setgain()
274 volume = ch->lvol * HDSPE_MAX_GAIN / 100; in hdspechan_setgain()
278 volume = ch->rvol * HDSPE_MAX_GAIN / 100; in hdspechan_setgain()
281 ports &= ~port; in hdspechan_setgain()
282 port = hdspe_port_first(ports); in hdspechan_setgain()
296 sc = scp->sc; in hdspemixer_init()
298 return (-1); in hdspemixer_init()
302 if (hdspe_channel_play_ports(scp->hc)) in hdspemixer_init()
305 if (hdspe_channel_rec_ports(scp->hc)) in hdspemixer_init()
308 snd_mtxlock(sc->lock); in hdspemixer_init()
309 pcm_setflags(scp->dev, pcm_getflags(scp->dev) | SD_F_SOFTPCMVOL); in hdspemixer_init()
311 snd_mtxunlock(sc->lock); in hdspemixer_init()
327 device_printf(scp->dev, "hdspemixer_set() %d %d\n", in hdspemixer_set()
331 for (i = 0; i < scp->chnum; i++) { in hdspemixer_set()
332 ch = &scp->chan[i]; in hdspemixer_set()
333 if ((dev == SOUND_MIXER_VOLUME && ch->dir == PCMDIR_PLAY) || in hdspemixer_set()
334 (dev == SOUND_MIXER_RECLEV && ch->dir == PCMDIR_REC)) { in hdspemixer_set()
335 ch->lvol = left; in hdspemixer_set()
336 ch->rvol = right; in hdspemixer_set()
337 if (ch->run) in hdspemixer_set()
357 uint32_t row, ports; in hdspechan_enable() local
361 scp = ch->parent; in hdspechan_enable()
362 sc = scp->sc; in hdspechan_enable()
364 if (ch->dir == PCMDIR_PLAY) in hdspechan_enable()
369 ch->run = value; in hdspechan_enable()
371 /* Iterate through rows of ports with contiguous slots. */ in hdspechan_enable()
372 ports = ch->ports; in hdspechan_enable()
373 row = hdspe_port_first_row(ports); in hdspechan_enable()
376 hdspe_port_slot_offset(row, hdspe_adat_width(sc->speed)); in hdspechan_enable()
378 hdspe_port_slot_width(row, hdspe_adat_width(sc->speed)); in hdspechan_enable()
384 ports &= ~row; in hdspechan_enable()
385 row = hdspe_port_first_row(ports); in hdspechan_enable()
399 if ((err = device_get_children(sc->dev, &devlist, &devcount)) != 0) in hdspe_running()
404 for (j = 0; j < scp->chnum; j++) { in hdspe_running()
405 ch = &scp->chan[j]; in hdspe_running()
406 if (ch->run) in hdspe_running()
417 device_printf(sc->dev, "hdspe is running\n"); in hdspe_running()
429 sc->ctrl_register |= (HDSPE_AUDIO_INT_ENABLE | HDSPE_ENABLE); in hdspe_start_audio()
430 hdspe_write_4(sc, HDSPE_CONTROL_REG, sc->ctrl_register); in hdspe_start_audio()
440 sc->ctrl_register &= ~(HDSPE_AUDIO_INT_ENABLE | HDSPE_ENABLE); in hdspe_stop_audio()
441 hdspe_write_4(sc, HDSPE_CONTROL_REG, sc->ctrl_register); in hdspe_stop_audio()
450 for (; samples > 0; samples--) { in buffer_mux_write()
460 buffer_mux_port(uint32_t *dma, uint32_t *pcm, uint32_t subset, uint32_t ports, in buffer_mux_port() argument
472 chan_pos = hdspe_channel_offset(subset, ports, pcm_width); in buffer_mux_port()
474 channels = hdspe_channel_count(ports, pcm_width); in buffer_mux_port()
496 for (; samples > 0; samples--) { in buffer_demux_read()
506 buffer_demux_port(uint32_t *dma, uint32_t *pcm, uint32_t subset, uint32_t ports, in buffer_demux_port() argument
518 chan_pos = hdspe_channel_offset(subset, ports, pcm_width); in buffer_demux_port()
520 channels = hdspe_channel_count(ports, pcm_width); in buffer_demux_port()
543 uint32_t row, ports; in buffer_copy() local
549 scp = ch->parent; in buffer_copy()
550 sc = scp->sc; in buffer_copy()
552 n = AFMT_CHANNEL(ch->format); /* n channels */ in buffer_copy()
555 adat_width = hdspe_adat_width(sc->speed); in buffer_copy()
556 if (n == hdspe_channel_count(ch->ports, 2)) in buffer_copy()
558 else if (n == hdspe_channel_count(ch->ports, 4)) in buffer_copy()
564 if (ch->dir == PCMDIR_PLAY) { in buffer_copy()
566 pos = sndbuf_getreadyptr(ch->buffer) / n; in buffer_copy()
567 length = sndbuf_getready(ch->buffer) / n; in buffer_copy()
568 /* Copy no more than 2 periods in advance. */ in buffer_copy()
569 if (length > (sc->period * 4 * 2)) in buffer_copy()
570 length = (sc->period * 4 * 2); in buffer_copy()
572 offset = (ch->position + HDSPE_CHANBUF_SIZE) - pos; in buffer_copy()
576 length -= offset; in buffer_copy()
580 pos = sndbuf_getfreeptr(ch->buffer) / n; in buffer_copy()
585 length = (dma_pos + HDSPE_CHANBUF_SIZE) - pos; in buffer_copy()
589 /* Position and length in samples (4 bytes). */ in buffer_copy()
593 /* Iterate through rows of ports with contiguous slots. */ in buffer_copy()
594 ports = ch->ports; in buffer_copy()
596 row = hdspe_port_first_row(ports); in buffer_copy()
598 row = hdspe_port_first(ports); in buffer_copy()
601 if (ch->dir == PCMDIR_PLAY) in buffer_copy()
602 buffer_mux_port(sc->pbuf, ch->data, row, ch->ports, pos, in buffer_copy()
605 buffer_demux_port(sc->rbuf, ch->data, row, ch->ports, in buffer_copy()
608 ports &= ~row; in buffer_copy()
610 row = hdspe_port_first_row(ports); in buffer_copy()
612 row = hdspe_port_first(ports); in buffer_copy()
615 ch->position = ((pos + length) * 4) % HDSPE_CHANBUF_SIZE; in buffer_copy()
624 uint32_t row, ports; in clean() local
627 scp = ch->parent; in clean()
628 sc = scp->sc; in clean()
629 buf = sc->rbuf; in clean()
631 if (ch->dir == PCMDIR_PLAY) in clean()
632 buf = sc->pbuf; in clean()
634 /* Iterate through rows of ports with contiguous slots. */ in clean()
635 ports = ch->ports; in clean()
636 row = hdspe_port_first_row(ports); in clean()
639 hdspe_adat_width(sc->speed)); in clean()
640 slots = hdspe_port_slot_width(row, hdspe_adat_width(sc->speed)); in clean()
645 ports &= ~row; in clean()
646 row = hdspe_port_first_row(ports); in clean()
649 ch->position = 0; in clean()
663 scp = ch->parent; in hdspechan_free()
664 sc = scp->sc; in hdspechan_free()
667 device_printf(scp->dev, "hdspechan_free()\n"); in hdspechan_free()
670 snd_mtxlock(sc->lock); in hdspechan_free()
671 if (ch->data != NULL) { in hdspechan_free()
672 free(ch->data, M_HDSPE); in hdspechan_free()
673 ch->data = NULL; in hdspechan_free()
675 if (ch->caps != NULL) { in hdspechan_free()
676 free(ch->caps, M_HDSPE); in hdspechan_free()
677 ch->caps = NULL; in hdspechan_free()
679 snd_mtxunlock(sc->lock); in hdspechan_free()
694 sc = scp->sc; in hdspechan_init()
696 snd_mtxlock(sc->lock); in hdspechan_init()
697 num = scp->chnum; in hdspechan_init()
699 ch = &scp->chan[num]; in hdspechan_init()
702 ch->ports = hdspe_channel_play_ports(scp->hc); in hdspechan_init()
704 ch->ports = hdspe_channel_rec_ports(scp->hc); in hdspechan_init()
706 ch->run = 0; in hdspechan_init()
707 ch->lvol = 0; in hdspechan_init()
708 ch->rvol = 0; in hdspechan_init()
711 ch->cap_fmts[0] = in hdspechan_init()
712 SND_FORMAT(AFMT_S32_LE, hdspe_channel_count(ch->ports, 2), 0); in hdspechan_init()
713 ch->cap_fmts[1] = in hdspechan_init()
714 SND_FORMAT(AFMT_S32_LE, hdspe_channel_count(ch->ports, 4), 0); in hdspechan_init()
715 ch->cap_fmts[2] = in hdspechan_init()
716 SND_FORMAT(AFMT_S32_LE, hdspe_channel_count(ch->ports, 8), 0); in hdspechan_init()
717 ch->cap_fmts[3] = 0; in hdspechan_init()
718 ch->caps = malloc(sizeof(struct pcmchan_caps), M_HDSPE, M_NOWAIT); in hdspechan_init()
719 *(ch->caps) = (struct pcmchan_caps) {32000, 192000, ch->cap_fmts, 0}; in hdspechan_init()
722 ch->size = HDSPE_CHANBUF_SIZE * hdspe_channel_count(ch->ports, 8); in hdspechan_init()
723 ch->data = malloc(ch->size, M_HDSPE, M_NOWAIT); in hdspechan_init()
724 ch->position = 0; in hdspechan_init()
726 ch->buffer = b; in hdspechan_init()
727 ch->channel = c; in hdspechan_init()
728 ch->parent = scp; in hdspechan_init()
730 ch->dir = dir; in hdspechan_init()
732 snd_mtxunlock(sc->lock); in hdspechan_init()
734 if (sndbuf_setup(ch->buffer, ch->data, ch->size) != 0) { in hdspechan_init()
735 device_printf(scp->dev, "Can't setup sndbuf.\n"); in hdspechan_init()
751 scp = ch->parent; in hdspechan_trigger()
752 sc = scp->sc; in hdspechan_trigger()
754 snd_mtxlock(sc->lock); in hdspechan_trigger()
758 device_printf(scp->dev, "hdspechan_trigger(): start\n"); in hdspechan_trigger()
768 device_printf(scp->dev, "hdspechan_trigger(): stop or abort\n"); in hdspechan_trigger()
777 if(ch->run) in hdspechan_trigger()
782 snd_mtxunlock(sc->lock); in hdspechan_trigger()
796 scp = ch->parent; in hdspechan_getptr()
797 sc = scp->sc; in hdspechan_getptr()
799 snd_mtxlock(sc->lock); in hdspechan_getptr()
801 snd_mtxunlock(sc->lock); in hdspechan_getptr()
804 pos *= AFMT_CHANNEL(ch->format); /* Hardbuf with multiple channels. */ in hdspechan_getptr()
817 struct sc_pcminfo *scp = ch->parent; in hdspechan_setformat()
818 device_printf(scp->dev, "hdspechan_setformat(%d)\n", format); in hdspechan_setformat()
821 ch->format = format; in hdspechan_setformat()
838 scp = ch->parent; in hdspechan_setspeed()
839 sc = scp->sc; in hdspechan_setspeed()
843 device_printf(scp->dev, "hdspechan_setspeed(%d)\n", speed); in hdspechan_setspeed()
849 if (sc->force_speed > 0) in hdspechan_setspeed()
850 speed = sc->force_speed; in hdspechan_setspeed()
862 threshold = hr->speed + ((rate_map[i + 1].speed != 0) ? in hdspechan_setspeed()
863 ((rate_map[i + 1].speed - hr->speed) >> 1) : 0); in hdspechan_setspeed()
869 switch (sc->type) { in hdspechan_setspeed()
880 sc->ctrl_register &= ~HDSPE_FREQ_MASK; in hdspechan_setspeed()
881 sc->ctrl_register |= hr->reg; in hdspechan_setspeed()
882 hdspe_write_4(sc, HDSPE_CONTROL_REG, sc->ctrl_register); in hdspechan_setspeed()
884 speed = hr->speed; in hdspechan_setspeed()
894 sc->speed = hr->speed; in hdspechan_setspeed()
897 return (sc->speed); in hdspechan_setspeed()
911 scp = ch->parent; in hdspechan_setblocksize()
912 sc = scp->sc; in hdspechan_setblocksize()
916 device_printf(scp->dev, "hdspechan_setblocksize(%d)\n", blocksize); in hdspechan_setblocksize()
929 if (sc->force_period > 0) in hdspechan_setblocksize()
930 blocksize = sc->force_period; in hdspechan_setblocksize()
942 threshold = hl->period + ((latency_map[i + 1].period != 0) ? in hdspechan_setblocksize()
943 ((latency_map[i + 1].period - hl->period) >> 1) : 0); in hdspechan_setblocksize()
949 snd_mtxlock(sc->lock); in hdspechan_setblocksize()
950 sc->ctrl_register &= ~HDSPE_LAT_MASK; in hdspechan_setblocksize()
951 sc->ctrl_register |= hdspe_encode_latency(hl->n); in hdspechan_setblocksize()
952 hdspe_write_4(sc, HDSPE_CONTROL_REG, sc->ctrl_register); in hdspechan_setblocksize()
953 sc->period = hl->period; in hdspechan_setblocksize()
954 snd_mtxunlock(sc->lock); in hdspechan_setblocksize()
957 device_printf(scp->dev, "New period=%d\n", sc->period); in hdspechan_setblocksize()
960 sndbuf_resize(ch->buffer, in hdspechan_setblocksize()
961 (HDSPE_CHANBUF_SIZE * AFMT_CHANNEL(ch->format)) / (sc->period * 4), in hdspechan_setblocksize()
962 (sc->period * 4)); in hdspechan_setblocksize()
965 return (sndbuf_getblksz(ch->buffer)); in hdspechan_setblocksize()
983 struct sc_pcminfo *scl = ch->parent; in hdspechan_getcaps()
984 device_printf(scp->dev, "hdspechan_getcaps()\n"); in hdspechan_getcaps()
987 if (ch->caps != NULL) in hdspechan_getcaps()
988 return (ch->caps); in hdspechan_getcaps()
1024 sc = scp->sc; in hdspe_pcm_intr()
1026 for (i = 0; i < scp->chnum; i++) { in hdspe_pcm_intr()
1027 ch = &scp->chan[i]; in hdspe_pcm_intr()
1028 snd_mtxunlock(sc->lock); in hdspe_pcm_intr()
1029 chn_intr(ch->channel); in hdspe_pcm_intr()
1030 snd_mtxlock(sc->lock); in hdspe_pcm_intr()
1047 scp->ih = &hdspe_pcm_intr; in hdspe_pcm_attach()
1049 if (scp->hc->ports & HDSPE_CHAN_AIO_ALL) in hdspe_pcm_attach()
1051 else if (scp->hc->ports & HDSPE_CHAN_RAY_ALL) in hdspe_pcm_attach()
1055 device_set_descf(dev, "HDSPe %s [%s]", buf, scp->hc->descr); in hdspe_pcm_attach()
1059 * in pcm device. Mark pcm device as MPSAFE manually. in hdspe_pcm_attach()
1062 if (hdspe_channel_count(scp->hc->ports, 8) > HDSPE_MATRIX_MAX) in hdspe_pcm_attach()
1069 play = (hdspe_channel_play_ports(scp->hc)) ? 1 : 0; in hdspe_pcm_attach()
1070 rec = (hdspe_channel_rec_ports(scp->hc)) ? 1 : 0; in hdspe_pcm_attach()
1072 scp->chnum = 0; in hdspe_pcm_attach()
1075 scp->chnum++; in hdspe_pcm_attach()
1080 scp->chnum++; in hdspe_pcm_attach()
1084 rman_get_start(scp->sc->cs), in hdspe_pcm_attach()
1085 rman_get_start(scp->sc->irq), in hdspe_pcm_attach()