xref: /freebsd/sys/dev/sound/pci/hdsp.c (revision 5687c71d)
1*5687c71dSFlorian Walpen /*-
2*5687c71dSFlorian Walpen  * SPDX-License-Identifier: BSD-2-Clause
3*5687c71dSFlorian Walpen  *
4*5687c71dSFlorian Walpen  * Copyright (c) 2012-2016 Ruslan Bukin <br@bsdpad.com>
5*5687c71dSFlorian Walpen  * Copyright (c) 2023-2024 Florian Walpen <dev@submerge.ch>
6*5687c71dSFlorian Walpen  * All rights reserved.
7*5687c71dSFlorian Walpen  *
8*5687c71dSFlorian Walpen  * Redistribution and use in source and binary forms, with or without
9*5687c71dSFlorian Walpen  * modification, are permitted provided that the following conditions
10*5687c71dSFlorian Walpen  * are met:
11*5687c71dSFlorian Walpen  * 1. Redistributions of source code must retain the above copyright
12*5687c71dSFlorian Walpen  *    notice, this list of conditions and the following disclaimer.
13*5687c71dSFlorian Walpen  * 2. Redistributions in binary form must reproduce the above copyright
14*5687c71dSFlorian Walpen  *    notice, this list of conditions and the following disclaimer in the
15*5687c71dSFlorian Walpen  *    documentation and/or other materials provided with the distribution.
16*5687c71dSFlorian Walpen  *
17*5687c71dSFlorian Walpen  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18*5687c71dSFlorian Walpen  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*5687c71dSFlorian Walpen  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*5687c71dSFlorian Walpen  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21*5687c71dSFlorian Walpen  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22*5687c71dSFlorian Walpen  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23*5687c71dSFlorian Walpen  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24*5687c71dSFlorian Walpen  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25*5687c71dSFlorian Walpen  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26*5687c71dSFlorian Walpen  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27*5687c71dSFlorian Walpen  * SUCH DAMAGE.
28*5687c71dSFlorian Walpen  */
29*5687c71dSFlorian Walpen 
30*5687c71dSFlorian Walpen /*
31*5687c71dSFlorian Walpen  * RME HDSP driver for FreeBSD.
32*5687c71dSFlorian Walpen  * Supported cards: HDSP 9632, HDSP 9652.
33*5687c71dSFlorian Walpen  */
34*5687c71dSFlorian Walpen 
35*5687c71dSFlorian Walpen #include <sys/types.h>
36*5687c71dSFlorian Walpen #include <sys/sysctl.h>
37*5687c71dSFlorian Walpen 
38*5687c71dSFlorian Walpen #include <dev/sound/pcm/sound.h>
39*5687c71dSFlorian Walpen #include <dev/sound/pci/hdsp.h>
40*5687c71dSFlorian Walpen 
41*5687c71dSFlorian Walpen #include <dev/pci/pcireg.h>
42*5687c71dSFlorian Walpen #include <dev/pci/pcivar.h>
43*5687c71dSFlorian Walpen 
44*5687c71dSFlorian Walpen #include <mixer_if.h>
45*5687c71dSFlorian Walpen 
46*5687c71dSFlorian Walpen static bool hdsp_unified_pcm = false;
47*5687c71dSFlorian Walpen 
48*5687c71dSFlorian Walpen static SYSCTL_NODE(_hw, OID_AUTO, hdsp, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
49*5687c71dSFlorian Walpen     "PCI HDSP");
50*5687c71dSFlorian Walpen 
51*5687c71dSFlorian Walpen SYSCTL_BOOL(_hw_hdsp, OID_AUTO, unified_pcm, CTLFLAG_RWTUN,
52*5687c71dSFlorian Walpen     &hdsp_unified_pcm, 0, "Combine physical ports in one unified pcm device");
53*5687c71dSFlorian Walpen 
54*5687c71dSFlorian Walpen static struct hdsp_clock_source hdsp_clock_source_table_9632[] = {
55*5687c71dSFlorian Walpen 	{ "internal", HDSP_CLOCK_INTERNAL },
56*5687c71dSFlorian Walpen 	{ "adat",     HDSP_CLOCK_ADAT1    },
57*5687c71dSFlorian Walpen 	{ "spdif",    HDSP_CLOCK_SPDIF    },
58*5687c71dSFlorian Walpen 	{ "word",     HDSP_CLOCK_WORD     },
59*5687c71dSFlorian Walpen 	{ NULL,       HDSP_CLOCK_INTERNAL }
60*5687c71dSFlorian Walpen };
61*5687c71dSFlorian Walpen 
62*5687c71dSFlorian Walpen static struct hdsp_clock_source hdsp_clock_source_table_9652[] = {
63*5687c71dSFlorian Walpen 	{ "internal",  HDSP_CLOCK_INTERNAL  },
64*5687c71dSFlorian Walpen 	{ "adat1",     HDSP_CLOCK_ADAT1     },
65*5687c71dSFlorian Walpen 	{ "adat2",     HDSP_CLOCK_ADAT2     },
66*5687c71dSFlorian Walpen 	{ "adat3",     HDSP_CLOCK_ADAT3     },
67*5687c71dSFlorian Walpen 	{ "spdif",     HDSP_CLOCK_SPDIF     },
68*5687c71dSFlorian Walpen 	{ "word",      HDSP_CLOCK_WORD      },
69*5687c71dSFlorian Walpen 	{ "adat_sync", HDSP_CLOCK_ADAT_SYNC },
70*5687c71dSFlorian Walpen 	{ NULL,        HDSP_CLOCK_INTERNAL  }
71*5687c71dSFlorian Walpen };
72*5687c71dSFlorian Walpen 
73*5687c71dSFlorian Walpen static struct hdsp_channel chan_map_9632[] = {
74*5687c71dSFlorian Walpen 	{ HDSP_CHAN_9632_ADAT,    "adat" },
75*5687c71dSFlorian Walpen 	{ HDSP_CHAN_9632_SPDIF, "s/pdif" },
76*5687c71dSFlorian Walpen 	{ HDSP_CHAN_9632_LINE,    "line" },
77*5687c71dSFlorian Walpen 	{ 0,                        NULL },
78*5687c71dSFlorian Walpen };
79*5687c71dSFlorian Walpen 
80*5687c71dSFlorian Walpen static struct hdsp_channel chan_map_9632_uni[] = {
81*5687c71dSFlorian Walpen 	{ HDSP_CHAN_9632_ALL, "all" },
82*5687c71dSFlorian Walpen 	{ 0,                   NULL },
83*5687c71dSFlorian Walpen };
84*5687c71dSFlorian Walpen 
85*5687c71dSFlorian Walpen static struct hdsp_channel chan_map_9652[] = {
86*5687c71dSFlorian Walpen 	{ HDSP_CHAN_9652_ADAT1,  "adat1" },
87*5687c71dSFlorian Walpen 	{ HDSP_CHAN_9652_ADAT2,  "adat2" },
88*5687c71dSFlorian Walpen 	{ HDSP_CHAN_9652_ADAT3,  "adat3" },
89*5687c71dSFlorian Walpen 	{ HDSP_CHAN_9652_SPDIF, "s/pdif" },
90*5687c71dSFlorian Walpen 	{ 0,                        NULL },
91*5687c71dSFlorian Walpen };
92*5687c71dSFlorian Walpen 
93*5687c71dSFlorian Walpen static struct hdsp_channel chan_map_9652_uni[] = {
94*5687c71dSFlorian Walpen 	{ HDSP_CHAN_9652_ALL, "all" },
95*5687c71dSFlorian Walpen 	{ 0,                   NULL },
96*5687c71dSFlorian Walpen };
97*5687c71dSFlorian Walpen 
98*5687c71dSFlorian Walpen static void
hdsp_intr(void * p)99*5687c71dSFlorian Walpen hdsp_intr(void *p)
100*5687c71dSFlorian Walpen {
101*5687c71dSFlorian Walpen 	struct sc_pcminfo *scp;
102*5687c71dSFlorian Walpen 	struct sc_info *sc;
103*5687c71dSFlorian Walpen 	device_t *devlist;
104*5687c71dSFlorian Walpen 	int devcount;
105*5687c71dSFlorian Walpen 	int status;
106*5687c71dSFlorian Walpen 	int err;
107*5687c71dSFlorian Walpen 	int i;
108*5687c71dSFlorian Walpen 
109*5687c71dSFlorian Walpen 	sc = (struct sc_info *)p;
110*5687c71dSFlorian Walpen 
111*5687c71dSFlorian Walpen 	snd_mtxlock(sc->lock);
112*5687c71dSFlorian Walpen 
113*5687c71dSFlorian Walpen 	status = hdsp_read_1(sc, HDSP_STATUS_REG);
114*5687c71dSFlorian Walpen 	if (status & HDSP_AUDIO_IRQ_PENDING) {
115*5687c71dSFlorian Walpen 		if ((err = device_get_children(sc->dev, &devlist, &devcount)) != 0)
116*5687c71dSFlorian Walpen 			return;
117*5687c71dSFlorian Walpen 
118*5687c71dSFlorian Walpen 		for (i = 0; i < devcount; i++) {
119*5687c71dSFlorian Walpen 			scp = device_get_ivars(devlist[i]);
120*5687c71dSFlorian Walpen 			if (scp->ih != NULL)
121*5687c71dSFlorian Walpen 				scp->ih(scp);
122*5687c71dSFlorian Walpen 		}
123*5687c71dSFlorian Walpen 
124*5687c71dSFlorian Walpen 		hdsp_write_1(sc, HDSP_INTERRUPT_ACK, 0);
125*5687c71dSFlorian Walpen 		free(devlist, M_TEMP);
126*5687c71dSFlorian Walpen 	}
127*5687c71dSFlorian Walpen 
128*5687c71dSFlorian Walpen 	snd_mtxunlock(sc->lock);
129*5687c71dSFlorian Walpen }
130*5687c71dSFlorian Walpen 
131*5687c71dSFlorian Walpen static void
hdsp_dmapsetmap(void * arg,bus_dma_segment_t * segs,int nseg,int error)132*5687c71dSFlorian Walpen hdsp_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
133*5687c71dSFlorian Walpen {
134*5687c71dSFlorian Walpen #if 0
135*5687c71dSFlorian Walpen 	device_printf(sc->dev, "hdsp_dmapsetmap()\n");
136*5687c71dSFlorian Walpen #endif
137*5687c71dSFlorian Walpen }
138*5687c71dSFlorian Walpen 
139*5687c71dSFlorian Walpen static int
hdsp_alloc_resources(struct sc_info * sc)140*5687c71dSFlorian Walpen hdsp_alloc_resources(struct sc_info *sc)
141*5687c71dSFlorian Walpen {
142*5687c71dSFlorian Walpen 
143*5687c71dSFlorian Walpen 	/* Allocate resource. */
144*5687c71dSFlorian Walpen 	sc->csid = PCIR_BAR(0);
145*5687c71dSFlorian Walpen 	sc->cs = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
146*5687c71dSFlorian Walpen 	    &sc->csid, RF_ACTIVE);
147*5687c71dSFlorian Walpen 
148*5687c71dSFlorian Walpen 	if (!sc->cs) {
149*5687c71dSFlorian Walpen 		device_printf(sc->dev, "Unable to map SYS_RES_MEMORY.\n");
150*5687c71dSFlorian Walpen 		return (ENXIO);
151*5687c71dSFlorian Walpen 	}
152*5687c71dSFlorian Walpen 
153*5687c71dSFlorian Walpen 	sc->cst = rman_get_bustag(sc->cs);
154*5687c71dSFlorian Walpen 	sc->csh = rman_get_bushandle(sc->cs);
155*5687c71dSFlorian Walpen 
156*5687c71dSFlorian Walpen 	/* Allocate interrupt resource. */
157*5687c71dSFlorian Walpen 	sc->irqid = 0;
158*5687c71dSFlorian Walpen 	sc->irq = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &sc->irqid,
159*5687c71dSFlorian Walpen 	    RF_ACTIVE | RF_SHAREABLE);
160*5687c71dSFlorian Walpen 
161*5687c71dSFlorian Walpen 	if (!sc->irq ||
162*5687c71dSFlorian Walpen 	    bus_setup_intr(sc->dev, sc->irq, INTR_MPSAFE | INTR_TYPE_AV,
163*5687c71dSFlorian Walpen 		NULL, hdsp_intr, sc, &sc->ih)) {
164*5687c71dSFlorian Walpen 		device_printf(sc->dev, "Unable to alloc interrupt resource.\n");
165*5687c71dSFlorian Walpen 		return (ENXIO);
166*5687c71dSFlorian Walpen 	}
167*5687c71dSFlorian Walpen 
168*5687c71dSFlorian Walpen 	/* Allocate DMA resources. */
169*5687c71dSFlorian Walpen 	if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev),
170*5687c71dSFlorian Walpen 		/*alignment*/4,
171*5687c71dSFlorian Walpen 		/*boundary*/0,
172*5687c71dSFlorian Walpen 		/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
173*5687c71dSFlorian Walpen 		/*highaddr*/BUS_SPACE_MAXADDR,
174*5687c71dSFlorian Walpen 		/*filter*/NULL,
175*5687c71dSFlorian Walpen 		/*filterarg*/NULL,
176*5687c71dSFlorian Walpen 		/*maxsize*/2 * HDSP_DMASEGSIZE,
177*5687c71dSFlorian Walpen 		/*nsegments*/2,
178*5687c71dSFlorian Walpen 		/*maxsegsz*/HDSP_DMASEGSIZE,
179*5687c71dSFlorian Walpen 		/*flags*/0,
180*5687c71dSFlorian Walpen 		/*lockfunc*/NULL,
181*5687c71dSFlorian Walpen 		/*lockarg*/NULL,
182*5687c71dSFlorian Walpen 		/*dmatag*/&sc->dmat) != 0) {
183*5687c71dSFlorian Walpen 		device_printf(sc->dev, "Unable to create dma tag.\n");
184*5687c71dSFlorian Walpen 		return (ENXIO);
185*5687c71dSFlorian Walpen 	}
186*5687c71dSFlorian Walpen 
187*5687c71dSFlorian Walpen 	sc->bufsize = HDSP_DMASEGSIZE;
188*5687c71dSFlorian Walpen 
189*5687c71dSFlorian Walpen 	/* pbuf (play buffer). */
190*5687c71dSFlorian Walpen 	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_WAITOK,
191*5687c71dSFlorian Walpen 	    &sc->pmap)) {
192*5687c71dSFlorian Walpen 		device_printf(sc->dev, "Can't alloc pbuf.\n");
193*5687c71dSFlorian Walpen 		return (ENXIO);
194*5687c71dSFlorian Walpen 	}
195*5687c71dSFlorian Walpen 
196*5687c71dSFlorian Walpen 	if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->bufsize,
197*5687c71dSFlorian Walpen 	    hdsp_dmapsetmap, sc, BUS_DMA_NOWAIT)) {
198*5687c71dSFlorian Walpen 		device_printf(sc->dev, "Can't load pbuf.\n");
199*5687c71dSFlorian Walpen 		return (ENXIO);
200*5687c71dSFlorian Walpen 	}
201*5687c71dSFlorian Walpen 
202*5687c71dSFlorian Walpen 	/* rbuf (rec buffer). */
203*5687c71dSFlorian Walpen 	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_WAITOK,
204*5687c71dSFlorian Walpen 	    &sc->rmap)) {
205*5687c71dSFlorian Walpen 		device_printf(sc->dev, "Can't alloc rbuf.\n");
206*5687c71dSFlorian Walpen 		return (ENXIO);
207*5687c71dSFlorian Walpen 	}
208*5687c71dSFlorian Walpen 
209*5687c71dSFlorian Walpen 	if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->bufsize,
210*5687c71dSFlorian Walpen 	    hdsp_dmapsetmap, sc, BUS_DMA_NOWAIT)) {
211*5687c71dSFlorian Walpen 		device_printf(sc->dev, "Can't load rbuf.\n");
212*5687c71dSFlorian Walpen 		return (ENXIO);
213*5687c71dSFlorian Walpen 	}
214*5687c71dSFlorian Walpen 
215*5687c71dSFlorian Walpen 	bzero(sc->pbuf, sc->bufsize);
216*5687c71dSFlorian Walpen 	bzero(sc->rbuf, sc->bufsize);
217*5687c71dSFlorian Walpen 
218*5687c71dSFlorian Walpen 	return (0);
219*5687c71dSFlorian Walpen }
220*5687c71dSFlorian Walpen 
221*5687c71dSFlorian Walpen static void
hdsp_map_dmabuf(struct sc_info * sc)222*5687c71dSFlorian Walpen hdsp_map_dmabuf(struct sc_info *sc)
223*5687c71dSFlorian Walpen {
224*5687c71dSFlorian Walpen 	uint32_t paddr, raddr;
225*5687c71dSFlorian Walpen 
226*5687c71dSFlorian Walpen 	paddr = vtophys(sc->pbuf);
227*5687c71dSFlorian Walpen 	raddr = vtophys(sc->rbuf);
228*5687c71dSFlorian Walpen 
229*5687c71dSFlorian Walpen 	hdsp_write_4(sc, HDSP_PAGE_ADDR_BUF_OUT, paddr);
230*5687c71dSFlorian Walpen 	hdsp_write_4(sc, HDSP_PAGE_ADDR_BUF_IN, raddr);
231*5687c71dSFlorian Walpen }
232*5687c71dSFlorian Walpen 
233*5687c71dSFlorian Walpen static int
hdsp_sysctl_sample_rate(SYSCTL_HANDLER_ARGS)234*5687c71dSFlorian Walpen hdsp_sysctl_sample_rate(SYSCTL_HANDLER_ARGS)
235*5687c71dSFlorian Walpen {
236*5687c71dSFlorian Walpen 	struct sc_info *sc = oidp->oid_arg1;
237*5687c71dSFlorian Walpen 	int error;
238*5687c71dSFlorian Walpen 	unsigned int speed, multiplier;
239*5687c71dSFlorian Walpen 
240*5687c71dSFlorian Walpen 	speed = sc->force_speed;
241*5687c71dSFlorian Walpen 
242*5687c71dSFlorian Walpen 	/* Process sysctl (unsigned) integer request. */
243*5687c71dSFlorian Walpen 	error = sysctl_handle_int(oidp, &speed, 0, req);
244*5687c71dSFlorian Walpen 	if (error != 0 || req->newptr == NULL)
245*5687c71dSFlorian Walpen 		return (error);
246*5687c71dSFlorian Walpen 
247*5687c71dSFlorian Walpen 	/* Speed from 32000 to 192000, 0 falls back to pcm speed setting. */
248*5687c71dSFlorian Walpen 	sc->force_speed = 0;
249*5687c71dSFlorian Walpen 	if (speed > 0) {
250*5687c71dSFlorian Walpen 		multiplier = 1;
251*5687c71dSFlorian Walpen 		if ((speed > (96000 + 128000) / 2) && sc->type == HDSP_9632)
252*5687c71dSFlorian Walpen 			multiplier = 4;
253*5687c71dSFlorian Walpen 		else if (speed > (48000 + 64000) / 2)
254*5687c71dSFlorian Walpen 			multiplier = 2;
255*5687c71dSFlorian Walpen 
256*5687c71dSFlorian Walpen 		if (speed < ((32000 + 44100) / 2) * multiplier)
257*5687c71dSFlorian Walpen 			sc->force_speed = 32000 * multiplier;
258*5687c71dSFlorian Walpen 		else if (speed < ((44100 + 48000) / 2) * multiplier)
259*5687c71dSFlorian Walpen 			sc->force_speed = 44100 * multiplier;
260*5687c71dSFlorian Walpen 		else
261*5687c71dSFlorian Walpen 			sc->force_speed = 48000 * multiplier;
262*5687c71dSFlorian Walpen 	}
263*5687c71dSFlorian Walpen 
264*5687c71dSFlorian Walpen 	return (0);
265*5687c71dSFlorian Walpen }
266*5687c71dSFlorian Walpen 
267*5687c71dSFlorian Walpen 
268*5687c71dSFlorian Walpen static int
hdsp_sysctl_period(SYSCTL_HANDLER_ARGS)269*5687c71dSFlorian Walpen hdsp_sysctl_period(SYSCTL_HANDLER_ARGS)
270*5687c71dSFlorian Walpen {
271*5687c71dSFlorian Walpen 	struct sc_info *sc = oidp->oid_arg1;
272*5687c71dSFlorian Walpen 	int error;
273*5687c71dSFlorian Walpen 	unsigned int period;
274*5687c71dSFlorian Walpen 
275*5687c71dSFlorian Walpen 	period = sc->force_period;
276*5687c71dSFlorian Walpen 
277*5687c71dSFlorian Walpen 	/* Process sysctl (unsigned) integer request. */
278*5687c71dSFlorian Walpen 	error = sysctl_handle_int(oidp, &period, 0, req);
279*5687c71dSFlorian Walpen 	if (error != 0 || req->newptr == NULL)
280*5687c71dSFlorian Walpen 		return (error);
281*5687c71dSFlorian Walpen 
282*5687c71dSFlorian Walpen 	/* Period is from 2^5 to 2^14, 0 falls back to pcm latency settings. */
283*5687c71dSFlorian Walpen 	sc->force_period = 0;
284*5687c71dSFlorian Walpen 	if (period > 0) {
285*5687c71dSFlorian Walpen 		sc->force_period = 32;
286*5687c71dSFlorian Walpen 		while (sc->force_period < period && sc->force_period < 4096)
287*5687c71dSFlorian Walpen 			sc->force_period <<= 1;
288*5687c71dSFlorian Walpen 	}
289*5687c71dSFlorian Walpen 
290*5687c71dSFlorian Walpen 	return (0);
291*5687c71dSFlorian Walpen }
292*5687c71dSFlorian Walpen 
293*5687c71dSFlorian Walpen static uint32_t
hdsp_control_clock_preference(enum hdsp_clock_type type)294*5687c71dSFlorian Walpen hdsp_control_clock_preference(enum hdsp_clock_type type)
295*5687c71dSFlorian Walpen {
296*5687c71dSFlorian Walpen 	switch (type) {
297*5687c71dSFlorian Walpen 	case HDSP_CLOCK_INTERNAL:
298*5687c71dSFlorian Walpen 		return (HDSP_CONTROL_MASTER);
299*5687c71dSFlorian Walpen 	case HDSP_CLOCK_ADAT1:
300*5687c71dSFlorian Walpen 		return (HDSP_CONTROL_CLOCK(0));
301*5687c71dSFlorian Walpen 	case HDSP_CLOCK_ADAT2:
302*5687c71dSFlorian Walpen 		return (HDSP_CONTROL_CLOCK(1));
303*5687c71dSFlorian Walpen 	case HDSP_CLOCK_ADAT3:
304*5687c71dSFlorian Walpen 		return (HDSP_CONTROL_CLOCK(2));
305*5687c71dSFlorian Walpen 	case HDSP_CLOCK_SPDIF:
306*5687c71dSFlorian Walpen 		return (HDSP_CONTROL_CLOCK(3));
307*5687c71dSFlorian Walpen 	case HDSP_CLOCK_WORD:
308*5687c71dSFlorian Walpen 		return (HDSP_CONTROL_CLOCK(4));
309*5687c71dSFlorian Walpen 	case HDSP_CLOCK_ADAT_SYNC:
310*5687c71dSFlorian Walpen 		return (HDSP_CONTROL_CLOCK(5));
311*5687c71dSFlorian Walpen 	default:
312*5687c71dSFlorian Walpen 		return (HDSP_CONTROL_MASTER);
313*5687c71dSFlorian Walpen 	}
314*5687c71dSFlorian Walpen }
315*5687c71dSFlorian Walpen 
316*5687c71dSFlorian Walpen static int
hdsp_sysctl_clock_preference(SYSCTL_HANDLER_ARGS)317*5687c71dSFlorian Walpen hdsp_sysctl_clock_preference(SYSCTL_HANDLER_ARGS)
318*5687c71dSFlorian Walpen {
319*5687c71dSFlorian Walpen 	struct sc_info *sc;
320*5687c71dSFlorian Walpen 	struct hdsp_clock_source *clock_table, *clock;
321*5687c71dSFlorian Walpen 	char buf[16] = "invalid";
322*5687c71dSFlorian Walpen 	int error;
323*5687c71dSFlorian Walpen 	uint32_t control;
324*5687c71dSFlorian Walpen 
325*5687c71dSFlorian Walpen 	sc = oidp->oid_arg1;
326*5687c71dSFlorian Walpen 
327*5687c71dSFlorian Walpen 	/* Select sync ports table for device type. */
328*5687c71dSFlorian Walpen 	if (sc->type == HDSP_9632)
329*5687c71dSFlorian Walpen 		clock_table = hdsp_clock_source_table_9632;
330*5687c71dSFlorian Walpen 	else if (sc->type == HDSP_9652)
331*5687c71dSFlorian Walpen 		clock_table = hdsp_clock_source_table_9652;
332*5687c71dSFlorian Walpen 	else
333*5687c71dSFlorian Walpen 		return (ENXIO);
334*5687c71dSFlorian Walpen 
335*5687c71dSFlorian Walpen 	/* Extract preferred clock source from control register. */
336*5687c71dSFlorian Walpen 	control = sc->ctrl_register & HDSP_CONTROL_CLOCK_MASK;
337*5687c71dSFlorian Walpen 	for (clock = clock_table; clock->name != NULL; ++clock) {
338*5687c71dSFlorian Walpen 		if (hdsp_control_clock_preference(clock->type) == control)
339*5687c71dSFlorian Walpen 			break;
340*5687c71dSFlorian Walpen 	}
341*5687c71dSFlorian Walpen 	if (clock->name != NULL)
342*5687c71dSFlorian Walpen 		strlcpy(buf, clock->name, sizeof(buf));
343*5687c71dSFlorian Walpen 
344*5687c71dSFlorian Walpen 	/* Process sysctl string request. */
345*5687c71dSFlorian Walpen 	error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
346*5687c71dSFlorian Walpen 	if (error != 0 || req->newptr == NULL)
347*5687c71dSFlorian Walpen 		return (error);
348*5687c71dSFlorian Walpen 
349*5687c71dSFlorian Walpen 	/* Find clock source matching the sysctl string. */
350*5687c71dSFlorian Walpen 	for (clock = clock_table; clock->name != NULL; ++clock) {
351*5687c71dSFlorian Walpen 		if (strncasecmp(buf, clock->name, sizeof(buf)) == 0)
352*5687c71dSFlorian Walpen 			break;
353*5687c71dSFlorian Walpen 	}
354*5687c71dSFlorian Walpen 
355*5687c71dSFlorian Walpen 	/* Set preferred clock source in control register. */
356*5687c71dSFlorian Walpen 	if (clock->name != NULL) {
357*5687c71dSFlorian Walpen 		control = hdsp_control_clock_preference(clock->type);
358*5687c71dSFlorian Walpen 		control &= HDSP_CONTROL_CLOCK_MASK;
359*5687c71dSFlorian Walpen 		snd_mtxlock(sc->lock);
360*5687c71dSFlorian Walpen 		sc->ctrl_register &= ~HDSP_CONTROL_CLOCK_MASK;
361*5687c71dSFlorian Walpen 		sc->ctrl_register |= control;
362*5687c71dSFlorian Walpen 		hdsp_write_4(sc, HDSP_CONTROL_REG, sc->ctrl_register);
363*5687c71dSFlorian Walpen 		snd_mtxunlock(sc->lock);
364*5687c71dSFlorian Walpen 	}
365*5687c71dSFlorian Walpen 	return (0);
366*5687c71dSFlorian Walpen }
367*5687c71dSFlorian Walpen 
368*5687c71dSFlorian Walpen static uint32_t
hdsp_status2_clock_source(enum hdsp_clock_type type)369*5687c71dSFlorian Walpen hdsp_status2_clock_source(enum hdsp_clock_type type)
370*5687c71dSFlorian Walpen {
371*5687c71dSFlorian Walpen 	switch (type) {
372*5687c71dSFlorian Walpen 	case HDSP_CLOCK_INTERNAL:
373*5687c71dSFlorian Walpen 		return (0);
374*5687c71dSFlorian Walpen 	case HDSP_CLOCK_ADAT1:
375*5687c71dSFlorian Walpen 		return (HDSP_STATUS2_CLOCK(0));
376*5687c71dSFlorian Walpen 	case HDSP_CLOCK_ADAT2:
377*5687c71dSFlorian Walpen 		return (HDSP_STATUS2_CLOCK(1));
378*5687c71dSFlorian Walpen 	case HDSP_CLOCK_ADAT3:
379*5687c71dSFlorian Walpen 		return (HDSP_STATUS2_CLOCK(2));
380*5687c71dSFlorian Walpen 	case HDSP_CLOCK_SPDIF:
381*5687c71dSFlorian Walpen 		return (HDSP_STATUS2_CLOCK(3));
382*5687c71dSFlorian Walpen 	case HDSP_CLOCK_WORD:
383*5687c71dSFlorian Walpen 		return (HDSP_STATUS2_CLOCK(4));
384*5687c71dSFlorian Walpen 	case HDSP_CLOCK_ADAT_SYNC:
385*5687c71dSFlorian Walpen 		return (HDSP_STATUS2_CLOCK(5));
386*5687c71dSFlorian Walpen 	default:
387*5687c71dSFlorian Walpen 		return (0);
388*5687c71dSFlorian Walpen 	}
389*5687c71dSFlorian Walpen }
390*5687c71dSFlorian Walpen 
391*5687c71dSFlorian Walpen static int
hdsp_sysctl_clock_source(SYSCTL_HANDLER_ARGS)392*5687c71dSFlorian Walpen hdsp_sysctl_clock_source(SYSCTL_HANDLER_ARGS)
393*5687c71dSFlorian Walpen {
394*5687c71dSFlorian Walpen 	struct sc_info *sc;
395*5687c71dSFlorian Walpen 	struct hdsp_clock_source *clock_table, *clock;
396*5687c71dSFlorian Walpen 	char buf[16] = "invalid";
397*5687c71dSFlorian Walpen 	uint32_t status2;
398*5687c71dSFlorian Walpen 
399*5687c71dSFlorian Walpen 	sc = oidp->oid_arg1;
400*5687c71dSFlorian Walpen 
401*5687c71dSFlorian Walpen 	/* Select sync ports table for device type. */
402*5687c71dSFlorian Walpen 	if (sc->type == HDSP_9632)
403*5687c71dSFlorian Walpen 		clock_table = hdsp_clock_source_table_9632;
404*5687c71dSFlorian Walpen 	else if (sc->type == HDSP_9652)
405*5687c71dSFlorian Walpen 		clock_table = hdsp_clock_source_table_9652;
406*5687c71dSFlorian Walpen 	else
407*5687c71dSFlorian Walpen 		return (ENXIO);
408*5687c71dSFlorian Walpen 
409*5687c71dSFlorian Walpen 	/* Read current (autosync) clock source from status2 register. */
410*5687c71dSFlorian Walpen 	snd_mtxlock(sc->lock);
411*5687c71dSFlorian Walpen 	status2 = hdsp_read_4(sc, HDSP_STATUS2_REG);
412*5687c71dSFlorian Walpen 	status2 &= HDSP_STATUS2_CLOCK_MASK;
413*5687c71dSFlorian Walpen 	snd_mtxunlock(sc->lock);
414*5687c71dSFlorian Walpen 
415*5687c71dSFlorian Walpen 	/* Translate status2 register value to clock source. */
416*5687c71dSFlorian Walpen 	for (clock = clock_table; clock->name != NULL; ++clock) {
417*5687c71dSFlorian Walpen 		/* In clock master mode, override with internal clock source. */
418*5687c71dSFlorian Walpen 		if (sc->ctrl_register & HDSP_CONTROL_MASTER) {
419*5687c71dSFlorian Walpen 			if (clock->type == HDSP_CLOCK_INTERNAL)
420*5687c71dSFlorian Walpen 				break;
421*5687c71dSFlorian Walpen 		} else if (hdsp_status2_clock_source(clock->type) == status2)
422*5687c71dSFlorian Walpen 			break;
423*5687c71dSFlorian Walpen 	}
424*5687c71dSFlorian Walpen 
425*5687c71dSFlorian Walpen 	/* Process sysctl string request. */
426*5687c71dSFlorian Walpen 	if (clock->name != NULL)
427*5687c71dSFlorian Walpen 		strlcpy(buf, clock->name, sizeof(buf));
428*5687c71dSFlorian Walpen 	return (sysctl_handle_string(oidp, buf, sizeof(buf), req));
429*5687c71dSFlorian Walpen }
430*5687c71dSFlorian Walpen 
431*5687c71dSFlorian Walpen static int
hdsp_sysctl_clock_list(SYSCTL_HANDLER_ARGS)432*5687c71dSFlorian Walpen hdsp_sysctl_clock_list(SYSCTL_HANDLER_ARGS)
433*5687c71dSFlorian Walpen {
434*5687c71dSFlorian Walpen 	struct sc_info *sc;
435*5687c71dSFlorian Walpen 	struct hdsp_clock_source *clock_table, *clock;
436*5687c71dSFlorian Walpen 	char buf[256];
437*5687c71dSFlorian Walpen 	int n;
438*5687c71dSFlorian Walpen 
439*5687c71dSFlorian Walpen 	sc = oidp->oid_arg1;
440*5687c71dSFlorian Walpen 	n = 0;
441*5687c71dSFlorian Walpen 
442*5687c71dSFlorian Walpen 	/* Select clock source table for device type. */
443*5687c71dSFlorian Walpen 	if (sc->type == HDSP_9632)
444*5687c71dSFlorian Walpen 		clock_table = hdsp_clock_source_table_9632;
445*5687c71dSFlorian Walpen 	else if (sc->type == HDSP_9652)
446*5687c71dSFlorian Walpen 		clock_table = hdsp_clock_source_table_9652;
447*5687c71dSFlorian Walpen 	else
448*5687c71dSFlorian Walpen 		return (ENXIO);
449*5687c71dSFlorian Walpen 
450*5687c71dSFlorian Walpen 	/* List available clock sources. */
451*5687c71dSFlorian Walpen 	buf[0] = 0;
452*5687c71dSFlorian Walpen 	for (clock = clock_table; clock->name != NULL; ++clock) {
453*5687c71dSFlorian Walpen 		if (n > 0)
454*5687c71dSFlorian Walpen 			n += strlcpy(buf + n, ",", sizeof(buf) - n);
455*5687c71dSFlorian Walpen 		n += strlcpy(buf + n, clock->name, sizeof(buf) - n);
456*5687c71dSFlorian Walpen 	}
457*5687c71dSFlorian Walpen 	return (sysctl_handle_string(oidp, buf, sizeof(buf), req));
458*5687c71dSFlorian Walpen }
459*5687c71dSFlorian Walpen 
460*5687c71dSFlorian Walpen static bool
hdsp_clock_source_locked(enum hdsp_clock_type type,uint32_t status,uint32_t status2)461*5687c71dSFlorian Walpen hdsp_clock_source_locked(enum hdsp_clock_type type, uint32_t status,
462*5687c71dSFlorian Walpen     uint32_t status2)
463*5687c71dSFlorian Walpen {
464*5687c71dSFlorian Walpen 	switch (type) {
465*5687c71dSFlorian Walpen 	case HDSP_CLOCK_INTERNAL:
466*5687c71dSFlorian Walpen 		return (true);
467*5687c71dSFlorian Walpen 	case HDSP_CLOCK_ADAT1:
468*5687c71dSFlorian Walpen 		return ((status >> 3) & 0x01);
469*5687c71dSFlorian Walpen 	case HDSP_CLOCK_ADAT2:
470*5687c71dSFlorian Walpen 		return ((status >> 2) & 0x01);
471*5687c71dSFlorian Walpen 	case HDSP_CLOCK_ADAT3:
472*5687c71dSFlorian Walpen 		return ((status >> 1) & 0x01);
473*5687c71dSFlorian Walpen 	case HDSP_CLOCK_SPDIF:
474*5687c71dSFlorian Walpen 		return (!((status >> 25) & 0x01));
475*5687c71dSFlorian Walpen 	case HDSP_CLOCK_WORD:
476*5687c71dSFlorian Walpen 		return ((status2 >> 3) & 0x01);
477*5687c71dSFlorian Walpen 	case HDSP_CLOCK_ADAT_SYNC:
478*5687c71dSFlorian Walpen 		return ((status >> 5) & 0x01);
479*5687c71dSFlorian Walpen 	default:
480*5687c71dSFlorian Walpen 		return (false);
481*5687c71dSFlorian Walpen 	}
482*5687c71dSFlorian Walpen }
483*5687c71dSFlorian Walpen 
484*5687c71dSFlorian Walpen static bool
hdsp_clock_source_synced(enum hdsp_clock_type type,uint32_t status,uint32_t status2)485*5687c71dSFlorian Walpen hdsp_clock_source_synced(enum hdsp_clock_type type, uint32_t status,
486*5687c71dSFlorian Walpen     uint32_t status2)
487*5687c71dSFlorian Walpen {
488*5687c71dSFlorian Walpen 	switch (type) {
489*5687c71dSFlorian Walpen 	case HDSP_CLOCK_INTERNAL:
490*5687c71dSFlorian Walpen 		return (true);
491*5687c71dSFlorian Walpen 	case HDSP_CLOCK_ADAT1:
492*5687c71dSFlorian Walpen 		return ((status >> 18) & 0x01);
493*5687c71dSFlorian Walpen 	case HDSP_CLOCK_ADAT2:
494*5687c71dSFlorian Walpen 		return ((status >> 17) & 0x01);
495*5687c71dSFlorian Walpen 	case HDSP_CLOCK_ADAT3:
496*5687c71dSFlorian Walpen 		return ((status >> 16) & 0x01);
497*5687c71dSFlorian Walpen 	case HDSP_CLOCK_SPDIF:
498*5687c71dSFlorian Walpen 		return (((status >> 4) & 0x01) && !((status >> 25) & 0x01));
499*5687c71dSFlorian Walpen 	case HDSP_CLOCK_WORD:
500*5687c71dSFlorian Walpen 		return ((status2 >> 4) & 0x01);
501*5687c71dSFlorian Walpen 	case HDSP_CLOCK_ADAT_SYNC:
502*5687c71dSFlorian Walpen 		return ((status >> 27) & 0x01);
503*5687c71dSFlorian Walpen 	default:
504*5687c71dSFlorian Walpen 		return (false);
505*5687c71dSFlorian Walpen 	}
506*5687c71dSFlorian Walpen }
507*5687c71dSFlorian Walpen 
508*5687c71dSFlorian Walpen static int
hdsp_sysctl_sync_status(SYSCTL_HANDLER_ARGS)509*5687c71dSFlorian Walpen hdsp_sysctl_sync_status(SYSCTL_HANDLER_ARGS)
510*5687c71dSFlorian Walpen {
511*5687c71dSFlorian Walpen 	struct sc_info *sc;
512*5687c71dSFlorian Walpen 	struct hdsp_clock_source *clock_table, *clock;
513*5687c71dSFlorian Walpen 	char buf[256];
514*5687c71dSFlorian Walpen 	char *state;
515*5687c71dSFlorian Walpen 	int n;
516*5687c71dSFlorian Walpen 	uint32_t status, status2;
517*5687c71dSFlorian Walpen 
518*5687c71dSFlorian Walpen 	sc = oidp->oid_arg1;
519*5687c71dSFlorian Walpen 	n = 0;
520*5687c71dSFlorian Walpen 
521*5687c71dSFlorian Walpen 	/* Select sync ports table for device type. */
522*5687c71dSFlorian Walpen 	if (sc->type == HDSP_9632)
523*5687c71dSFlorian Walpen 		clock_table = hdsp_clock_source_table_9632;
524*5687c71dSFlorian Walpen 	else if (sc->type == HDSP_9652)
525*5687c71dSFlorian Walpen 		clock_table = hdsp_clock_source_table_9652;
526*5687c71dSFlorian Walpen 	else
527*5687c71dSFlorian Walpen 		return (ENXIO);
528*5687c71dSFlorian Walpen 
529*5687c71dSFlorian Walpen 	/* Read current lock and sync bits from status registers. */
530*5687c71dSFlorian Walpen 	snd_mtxlock(sc->lock);
531*5687c71dSFlorian Walpen 	status = hdsp_read_4(sc, HDSP_STATUS_REG);
532*5687c71dSFlorian Walpen 	status2 = hdsp_read_4(sc, HDSP_STATUS2_REG);
533*5687c71dSFlorian Walpen 	snd_mtxunlock(sc->lock);
534*5687c71dSFlorian Walpen 
535*5687c71dSFlorian Walpen 	/* List clock sources with lock and sync state. */
536*5687c71dSFlorian Walpen 	for (clock = clock_table; clock->name != NULL; ++clock) {
537*5687c71dSFlorian Walpen 		if (clock->type == HDSP_CLOCK_INTERNAL)
538*5687c71dSFlorian Walpen 			continue;
539*5687c71dSFlorian Walpen 		if (n > 0)
540*5687c71dSFlorian Walpen 			n += strlcpy(buf + n, ",", sizeof(buf) - n);
541*5687c71dSFlorian Walpen 		state = "none";
542*5687c71dSFlorian Walpen 		if (hdsp_clock_source_locked(clock->type, status, status2)) {
543*5687c71dSFlorian Walpen 			if (hdsp_clock_source_synced(clock->type, status,
544*5687c71dSFlorian Walpen 			    status2))
545*5687c71dSFlorian Walpen 				state = "sync";
546*5687c71dSFlorian Walpen 			else
547*5687c71dSFlorian Walpen 				state = "lock";
548*5687c71dSFlorian Walpen 		}
549*5687c71dSFlorian Walpen 		n += snprintf(buf + n, sizeof(buf) - n, "%s(%s)",
550*5687c71dSFlorian Walpen 		    clock->name, state);
551*5687c71dSFlorian Walpen 	}
552*5687c71dSFlorian Walpen 	return (sysctl_handle_string(oidp, buf, sizeof(buf), req));
553*5687c71dSFlorian Walpen }
554*5687c71dSFlorian Walpen 
555*5687c71dSFlorian Walpen static int
hdsp_probe(device_t dev)556*5687c71dSFlorian Walpen hdsp_probe(device_t dev)
557*5687c71dSFlorian Walpen {
558*5687c71dSFlorian Walpen 	uint32_t rev;
559*5687c71dSFlorian Walpen 
560*5687c71dSFlorian Walpen 	if (pci_get_vendor(dev) == PCI_VENDOR_XILINX &&
561*5687c71dSFlorian Walpen 	    pci_get_device(dev) == PCI_DEVICE_XILINX_HDSP) {
562*5687c71dSFlorian Walpen 		rev = pci_get_revid(dev);
563*5687c71dSFlorian Walpen 		switch (rev) {
564*5687c71dSFlorian Walpen 		case PCI_REVISION_9632:
565*5687c71dSFlorian Walpen 			device_set_desc(dev, "RME HDSP 9632");
566*5687c71dSFlorian Walpen 			return (0);
567*5687c71dSFlorian Walpen 		case PCI_REVISION_9652:
568*5687c71dSFlorian Walpen 			device_set_desc(dev, "RME HDSP 9652");
569*5687c71dSFlorian Walpen 			return (0);
570*5687c71dSFlorian Walpen 		}
571*5687c71dSFlorian Walpen 	}
572*5687c71dSFlorian Walpen 
573*5687c71dSFlorian Walpen 	return (ENXIO);
574*5687c71dSFlorian Walpen }
575*5687c71dSFlorian Walpen 
576*5687c71dSFlorian Walpen static int
hdsp_init(struct sc_info * sc)577*5687c71dSFlorian Walpen hdsp_init(struct sc_info *sc)
578*5687c71dSFlorian Walpen {
579*5687c71dSFlorian Walpen 	unsigned mixer_controls;
580*5687c71dSFlorian Walpen 
581*5687c71dSFlorian Walpen 	/* Set latency. */
582*5687c71dSFlorian Walpen 	sc->period = 256;
583*5687c71dSFlorian Walpen 	/*
584*5687c71dSFlorian Walpen 	 * The pcm channel latency settings propagate unreliable blocksizes,
585*5687c71dSFlorian Walpen 	 * different for recording and playback, and skewed due to rounding
586*5687c71dSFlorian Walpen 	 * and total buffer size limits.
587*5687c71dSFlorian Walpen 	 * Force period to a consistent default until these issues are fixed.
588*5687c71dSFlorian Walpen 	 */
589*5687c71dSFlorian Walpen 	sc->force_period = 256;
590*5687c71dSFlorian Walpen 	sc->ctrl_register = hdsp_encode_latency(2);
591*5687c71dSFlorian Walpen 
592*5687c71dSFlorian Walpen 	/* Set rate. */
593*5687c71dSFlorian Walpen 	sc->speed = HDSP_SPEED_DEFAULT;
594*5687c71dSFlorian Walpen 	sc->force_speed = 0;
595*5687c71dSFlorian Walpen 	sc->ctrl_register &= ~HDSP_FREQ_MASK;
596*5687c71dSFlorian Walpen 	sc->ctrl_register |= HDSP_FREQ_MASK_DEFAULT;
597*5687c71dSFlorian Walpen 
598*5687c71dSFlorian Walpen 	/* Set internal clock source (master). */
599*5687c71dSFlorian Walpen 	sc->ctrl_register &= ~HDSP_CONTROL_CLOCK_MASK;
600*5687c71dSFlorian Walpen 	sc->ctrl_register |= HDSP_CONTROL_MASTER;
601*5687c71dSFlorian Walpen 
602*5687c71dSFlorian Walpen 	/* SPDIF from coax in, line out. */
603*5687c71dSFlorian Walpen 	sc->ctrl_register &= ~HDSP_CONTROL_SPDIF_COAX;
604*5687c71dSFlorian Walpen 	sc->ctrl_register |= HDSP_CONTROL_SPDIF_COAX;
605*5687c71dSFlorian Walpen 	sc->ctrl_register &= ~HDSP_CONTROL_LINE_OUT;
606*5687c71dSFlorian Walpen 	sc->ctrl_register |= HDSP_CONTROL_LINE_OUT;
607*5687c71dSFlorian Walpen 
608*5687c71dSFlorian Walpen 	hdsp_write_4(sc, HDSP_CONTROL_REG, sc->ctrl_register);
609*5687c71dSFlorian Walpen 
610*5687c71dSFlorian Walpen 	if (sc->type == HDSP_9652)
611*5687c71dSFlorian Walpen 		hdsp_write_4(sc, HDSP_CONTROL2_REG, HDSP_CONTROL2_9652_MIXER);
612*5687c71dSFlorian Walpen 	else
613*5687c71dSFlorian Walpen 		hdsp_write_4(sc, HDSP_CONTROL2_REG, 0);
614*5687c71dSFlorian Walpen 
615*5687c71dSFlorian Walpen 	switch (sc->type) {
616*5687c71dSFlorian Walpen 	case HDSP_9632:
617*5687c71dSFlorian Walpen 		/* Mixer matrix is 2 source rows (input, playback) per output. */
618*5687c71dSFlorian Walpen 		mixer_controls = 2 * HDSP_MIX_SLOTS_9632 * HDSP_MIX_SLOTS_9632;
619*5687c71dSFlorian Walpen 		break;
620*5687c71dSFlorian Walpen 	case HDSP_9652:
621*5687c71dSFlorian Walpen 		/* Mixer matrix is 2 source rows (input, playback) per output. */
622*5687c71dSFlorian Walpen 		mixer_controls = 2 * HDSP_MIX_SLOTS_9652 * HDSP_MIX_SLOTS_9652;
623*5687c71dSFlorian Walpen 		break;
624*5687c71dSFlorian Walpen 	default:
625*5687c71dSFlorian Walpen 		return (ENXIO);
626*5687c71dSFlorian Walpen 	}
627*5687c71dSFlorian Walpen 
628*5687c71dSFlorian Walpen 	/* Initialize mixer matrix by silencing all controls. */
629*5687c71dSFlorian Walpen 	for (unsigned offset = 0; offset < mixer_controls * 2; offset += 4) {
630*5687c71dSFlorian Walpen 		/* Only accepts 4 byte values, pairs of 16 bit volume controls. */
631*5687c71dSFlorian Walpen 		hdsp_write_4(sc, HDSP_MIXER_BASE + offset,
632*5687c71dSFlorian Walpen 		    (HDSP_MIN_GAIN << 16) | HDSP_MIN_GAIN);
633*5687c71dSFlorian Walpen 	}
634*5687c71dSFlorian Walpen 
635*5687c71dSFlorian Walpen 	/* Reset pointer, rewrite frequency (same register) for 9632. */
636*5687c71dSFlorian Walpen 	hdsp_write_4(sc, HDSP_RESET_POINTER, 0);
637*5687c71dSFlorian Walpen 	if (sc->type == HDSP_9632) {
638*5687c71dSFlorian Walpen 		/* Set DDS value. */
639*5687c71dSFlorian Walpen 		hdsp_write_4(sc, HDSP_FREQ_REG, hdsp_freq_reg_value(sc->speed));
640*5687c71dSFlorian Walpen 	}
641*5687c71dSFlorian Walpen 
642*5687c71dSFlorian Walpen 	return (0);
643*5687c71dSFlorian Walpen }
644*5687c71dSFlorian Walpen 
645*5687c71dSFlorian Walpen static int
hdsp_attach(device_t dev)646*5687c71dSFlorian Walpen hdsp_attach(device_t dev)
647*5687c71dSFlorian Walpen {
648*5687c71dSFlorian Walpen 	struct hdsp_channel *chan_map;
649*5687c71dSFlorian Walpen 	struct sc_pcminfo *scp;
650*5687c71dSFlorian Walpen 	struct sc_info *sc;
651*5687c71dSFlorian Walpen 	uint32_t rev;
652*5687c71dSFlorian Walpen 	int i, err;
653*5687c71dSFlorian Walpen 
654*5687c71dSFlorian Walpen #if 0
655*5687c71dSFlorian Walpen 	device_printf(dev, "hdsp_attach()\n");
656*5687c71dSFlorian Walpen #endif
657*5687c71dSFlorian Walpen 
658*5687c71dSFlorian Walpen 	sc = device_get_softc(dev);
659*5687c71dSFlorian Walpen 	sc->lock = snd_mtxcreate(device_get_nameunit(dev),
660*5687c71dSFlorian Walpen 	    "snd_hdsp softc");
661*5687c71dSFlorian Walpen 	sc->dev = dev;
662*5687c71dSFlorian Walpen 
663*5687c71dSFlorian Walpen 	pci_enable_busmaster(dev);
664*5687c71dSFlorian Walpen 	rev = pci_get_revid(dev);
665*5687c71dSFlorian Walpen 	switch (rev) {
666*5687c71dSFlorian Walpen 	case PCI_REVISION_9632:
667*5687c71dSFlorian Walpen 		sc->type = HDSP_9632;
668*5687c71dSFlorian Walpen 		chan_map = hdsp_unified_pcm ? chan_map_9632_uni : chan_map_9632;
669*5687c71dSFlorian Walpen 		break;
670*5687c71dSFlorian Walpen 	case PCI_REVISION_9652:
671*5687c71dSFlorian Walpen 		sc->type = HDSP_9652;
672*5687c71dSFlorian Walpen 		chan_map = hdsp_unified_pcm ? chan_map_9652_uni : chan_map_9652;
673*5687c71dSFlorian Walpen 		break;
674*5687c71dSFlorian Walpen 	default:
675*5687c71dSFlorian Walpen 		return (ENXIO);
676*5687c71dSFlorian Walpen 	}
677*5687c71dSFlorian Walpen 
678*5687c71dSFlorian Walpen 	/* Allocate resources. */
679*5687c71dSFlorian Walpen 	err = hdsp_alloc_resources(sc);
680*5687c71dSFlorian Walpen 	if (err) {
681*5687c71dSFlorian Walpen 		device_printf(dev, "Unable to allocate system resources.\n");
682*5687c71dSFlorian Walpen 		return (ENXIO);
683*5687c71dSFlorian Walpen 	}
684*5687c71dSFlorian Walpen 
685*5687c71dSFlorian Walpen 	if (hdsp_init(sc) != 0)
686*5687c71dSFlorian Walpen 		return (ENXIO);
687*5687c71dSFlorian Walpen 
688*5687c71dSFlorian Walpen 	for (i = 0; i < HDSP_MAX_CHANS && chan_map[i].descr != NULL; i++) {
689*5687c71dSFlorian Walpen 		scp = malloc(sizeof(struct sc_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO);
690*5687c71dSFlorian Walpen 		scp->hc = &chan_map[i];
691*5687c71dSFlorian Walpen 		scp->sc = sc;
692*5687c71dSFlorian Walpen 		scp->dev = device_add_child(dev, "pcm", -1);
693*5687c71dSFlorian Walpen 		device_set_ivars(scp->dev, scp);
694*5687c71dSFlorian Walpen 	}
695*5687c71dSFlorian Walpen 
696*5687c71dSFlorian Walpen 	hdsp_map_dmabuf(sc);
697*5687c71dSFlorian Walpen 
698*5687c71dSFlorian Walpen 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
699*5687c71dSFlorian Walpen 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
700*5687c71dSFlorian Walpen 	    "sync_status", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
701*5687c71dSFlorian Walpen 	    sc, 0, hdsp_sysctl_sync_status, "A",
702*5687c71dSFlorian Walpen 	    "List clock source signal lock and sync status");
703*5687c71dSFlorian Walpen 
704*5687c71dSFlorian Walpen 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
705*5687c71dSFlorian Walpen 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
706*5687c71dSFlorian Walpen 	    "clock_source", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
707*5687c71dSFlorian Walpen 	    sc, 0, hdsp_sysctl_clock_source, "A",
708*5687c71dSFlorian Walpen 	    "Currently effective clock source");
709*5687c71dSFlorian Walpen 
710*5687c71dSFlorian Walpen 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
711*5687c71dSFlorian Walpen 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
712*5687c71dSFlorian Walpen 	    "clock_preference", CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,
713*5687c71dSFlorian Walpen 	    sc, 0, hdsp_sysctl_clock_preference, "A",
714*5687c71dSFlorian Walpen 	    "Set 'internal' (master) or preferred autosync clock source");
715*5687c71dSFlorian Walpen 
716*5687c71dSFlorian Walpen 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
717*5687c71dSFlorian Walpen 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
718*5687c71dSFlorian Walpen 	    "clock_list", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
719*5687c71dSFlorian Walpen 	    sc, 0, hdsp_sysctl_clock_list, "A",
720*5687c71dSFlorian Walpen 	    "List of supported clock sources");
721*5687c71dSFlorian Walpen 
722*5687c71dSFlorian Walpen 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
723*5687c71dSFlorian Walpen 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
724*5687c71dSFlorian Walpen 	    "period", CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE,
725*5687c71dSFlorian Walpen 	    sc, 0, hdsp_sysctl_period, "A",
726*5687c71dSFlorian Walpen 	    "Force period of samples per interrupt (32, 64, ... 4096)");
727*5687c71dSFlorian Walpen 
728*5687c71dSFlorian Walpen 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
729*5687c71dSFlorian Walpen 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
730*5687c71dSFlorian Walpen 	    "sample_rate", CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE,
731*5687c71dSFlorian Walpen 	    sc, 0, hdsp_sysctl_sample_rate, "A",
732*5687c71dSFlorian Walpen 	    "Force sample rate (32000, 44100, 48000, ... 192000)");
733*5687c71dSFlorian Walpen 
734*5687c71dSFlorian Walpen 	return (bus_generic_attach(dev));
735*5687c71dSFlorian Walpen }
736*5687c71dSFlorian Walpen 
737*5687c71dSFlorian Walpen static void
hdsp_dmafree(struct sc_info * sc)738*5687c71dSFlorian Walpen hdsp_dmafree(struct sc_info *sc)
739*5687c71dSFlorian Walpen {
740*5687c71dSFlorian Walpen 
741*5687c71dSFlorian Walpen 	bus_dmamap_unload(sc->dmat, sc->rmap);
742*5687c71dSFlorian Walpen 	bus_dmamap_unload(sc->dmat, sc->pmap);
743*5687c71dSFlorian Walpen 	bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
744*5687c71dSFlorian Walpen 	bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
745*5687c71dSFlorian Walpen 	sc->rbuf = sc->pbuf = NULL;
746*5687c71dSFlorian Walpen }
747*5687c71dSFlorian Walpen 
748*5687c71dSFlorian Walpen static int
hdsp_detach(device_t dev)749*5687c71dSFlorian Walpen hdsp_detach(device_t dev)
750*5687c71dSFlorian Walpen {
751*5687c71dSFlorian Walpen 	struct sc_info *sc;
752*5687c71dSFlorian Walpen 	int err;
753*5687c71dSFlorian Walpen 
754*5687c71dSFlorian Walpen 	sc = device_get_softc(dev);
755*5687c71dSFlorian Walpen 	if (sc == NULL) {
756*5687c71dSFlorian Walpen 		device_printf(dev,"Can't detach: softc is null.\n");
757*5687c71dSFlorian Walpen 		return (0);
758*5687c71dSFlorian Walpen 	}
759*5687c71dSFlorian Walpen 
760*5687c71dSFlorian Walpen 	err = device_delete_children(dev);
761*5687c71dSFlorian Walpen 	if (err)
762*5687c71dSFlorian Walpen 		return (err);
763*5687c71dSFlorian Walpen 
764*5687c71dSFlorian Walpen 	hdsp_dmafree(sc);
765*5687c71dSFlorian Walpen 
766*5687c71dSFlorian Walpen 	if (sc->ih)
767*5687c71dSFlorian Walpen 		bus_teardown_intr(dev, sc->irq, sc->ih);
768*5687c71dSFlorian Walpen 	if (sc->dmat)
769*5687c71dSFlorian Walpen 		bus_dma_tag_destroy(sc->dmat);
770*5687c71dSFlorian Walpen 	if (sc->irq)
771*5687c71dSFlorian Walpen 		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
772*5687c71dSFlorian Walpen 	if (sc->cs)
773*5687c71dSFlorian Walpen 		bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0), sc->cs);
774*5687c71dSFlorian Walpen 	if (sc->lock)
775*5687c71dSFlorian Walpen 		snd_mtxfree(sc->lock);
776*5687c71dSFlorian Walpen 
777*5687c71dSFlorian Walpen 	return (0);
778*5687c71dSFlorian Walpen }
779*5687c71dSFlorian Walpen 
780*5687c71dSFlorian Walpen static device_method_t hdsp_methods[] = {
781*5687c71dSFlorian Walpen 	DEVMETHOD(device_probe,     hdsp_probe),
782*5687c71dSFlorian Walpen 	DEVMETHOD(device_attach,    hdsp_attach),
783*5687c71dSFlorian Walpen 	DEVMETHOD(device_detach,    hdsp_detach),
784*5687c71dSFlorian Walpen 	{ 0, 0 }
785*5687c71dSFlorian Walpen };
786*5687c71dSFlorian Walpen 
787*5687c71dSFlorian Walpen static driver_t hdsp_driver = {
788*5687c71dSFlorian Walpen 	"hdsp",
789*5687c71dSFlorian Walpen 	hdsp_methods,
790*5687c71dSFlorian Walpen 	PCM_SOFTC_SIZE,
791*5687c71dSFlorian Walpen };
792*5687c71dSFlorian Walpen 
793*5687c71dSFlorian Walpen DRIVER_MODULE(snd_hdsp, pci, hdsp_driver, 0, 0);
794