xref: /freebsd/sys/dev/sound/pci/via82c686.c (revision 77a0943ded95b9e6438f7db70c4a28e4d93946d4)
1 /*
2  * Copyright (c) 2000 David Jones <dej@ox.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28 
29 #include <dev/sound/pcm/sound.h>
30 #include <dev/sound/pcm/ac97.h>
31 
32 #include <pci/pcireg.h>
33 #include <pci/pcivar.h>
34 #include <sys/sysctl.h>
35 
36 #include <dev/sound/pci/via82c686.h>
37 
38 #define VIA_PCI_ID 0x30581106
39 #define	NSEGS		16	/* Number of segments in SGD table */
40 
41 #define SEGS_PER_CHAN	(NSEGS/2)
42 
43 #undef DEB
44 #define DEB(x)
45 
46 struct via_info;
47 
48 struct via_chinfo {
49 	struct via_info *parent;
50 	pcm_channel *channel;
51 	snd_dbuf *buffer;
52 	int dir;
53 };
54 
55 struct via_info {
56 	bus_space_tag_t st;
57 	bus_space_handle_t sh;
58 	bus_dma_tag_t	parent_dmat;
59 	bus_dma_tag_t	sgd_dmat;
60 
61 	struct resource *reg, *irq;
62 	int regid, irqid;
63 	void *ih;
64 
65 	struct via_chinfo pch, rch;
66 	struct via_dma_op *sgd_table;
67 	u_int16_t	codec_caps;
68 };
69 
70 static u_int32_t via_rd(struct via_info *via, int regno, int size);
71 static void via_wr(struct via_info *, int regno, u_int32_t data, int size);
72 
73 int via_waitready_codec(struct via_info *via);
74 int via_waitvalid_codec(struct via_info *via);
75 u_int32_t via_read_codec(void *addr, int reg);
76 void via_write_codec(void *addr, int reg, u_int32_t val);
77 
78 static void via_intr(void *);
79 bus_dmamap_callback_t dma_cb;
80 
81 
82 /* channel interface */
83 static void *viachan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir);
84 static int viachan_setdir(void *data, int dir);
85 static int viachan_setformat(void *data, u_int32_t format);
86 static int viachan_setspeed(void *data, u_int32_t speed);
87 static int viachan_setblocksize(void *data, u_int32_t blocksize);
88 static int viachan_trigger(void *data, int go);
89 static int viachan_getptr(void *data);
90 static pcmchan_caps *viachan_getcaps(void *data);
91 
92 static u_int32_t via_playfmt[] = {
93 	AFMT_U8,
94 	AFMT_STEREO | AFMT_U8,
95 	AFMT_S16_LE,
96 	AFMT_STEREO | AFMT_S16_LE,
97 	0
98 };
99 static pcmchan_caps via_playcaps = {4000, 48000, via_playfmt, 0};
100 
101 static u_int32_t via_recfmt[] = {
102 	AFMT_U8,
103 	AFMT_STEREO | AFMT_U8,
104 	AFMT_S16_LE,
105 	AFMT_STEREO | AFMT_S16_LE,
106 	0
107 };
108 static pcmchan_caps via_reccaps = {4000, 48000, via_recfmt, 0};
109 
110 static pcm_channel via_chantemplate = {
111 	viachan_init,
112 	viachan_setdir,
113 	viachan_setformat,
114 	viachan_setspeed,
115 	viachan_setblocksize,
116 	viachan_trigger,
117 	viachan_getptr,
118 	viachan_getcaps,
119 	NULL, 			/* free */
120 	NULL, 			/* nop1 */
121 	NULL, 			/* nop2 */
122 	NULL, 			/* nop3 */
123 	NULL, 			/* nop4 */
124 	NULL, 			/* nop5 */
125 	NULL, 			/* nop6 */
126 	NULL, 			/* nop7 */
127 };
128 
129 
130 /*
131  *  Probe and attach the card
132  */
133 static int
134 via_probe(device_t dev)
135 {
136 	if (pci_get_devid(dev) == VIA_PCI_ID) {
137 	    device_set_desc(dev, "VIA VT82C686A AC'97 Audio");
138 	    return 0;
139 	}
140 	return ENXIO;
141 }
142 
143 
144 void dma_cb(void *p, bus_dma_segment_t *bds, int a, int b)
145 {
146 }
147 
148 
149 static int
150 via_attach(device_t dev)
151 {
152 	struct via_info *via = 0;
153 	struct ac97_info *codec = 0;
154 	char		status[SND_STATUSLEN];
155 
156 	u_int32_t	data;
157 
158 	u_int16_t	v;
159 	bus_dmamap_t	sgd_dma_map;
160 
161 	if ((via = malloc(sizeof *via, M_DEVBUF, M_NOWAIT)) == NULL) {
162 		device_printf(dev, "cannot allocate softc\n");
163 		return ENXIO;
164 	}
165 	bzero(via, sizeof *via);
166 
167 	/* Get resources */
168 	data = pci_read_config(dev, PCIR_COMMAND, 2);
169 	data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN);
170 	pci_write_config(dev, PCIR_COMMAND, data, 2);
171 	data = pci_read_config(dev, PCIR_COMMAND, 2);
172 
173 	pci_write_config(dev, VIA_PCICONF_MISC,
174 		VIA_PCICONF_ACLINKENAB | VIA_PCICONF_ACSGD |
175 		VIA_PCICONF_ACNOTRST | VIA_PCICONF_ACVSR, 1);
176 
177 	via->regid = PCIR_MAPS;
178 	via->reg = bus_alloc_resource(dev, SYS_RES_IOPORT, &via->regid,
179 		0, ~0, 1, RF_ACTIVE);
180 	if (!via->reg) {
181 		device_printf(dev, "via: Cannot allocate bus resource.");
182 		goto bad;
183 	}
184 	via->st = rman_get_bustag(via->reg);
185 	via->sh = rman_get_bushandle(via->reg);
186 
187 	via->irqid = 0;
188 	via->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &via->irqid,
189 		0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
190 	if (!via->irq
191 	    || bus_setup_intr(dev, via->irq, INTR_TYPE_TTY, via_intr, via, &via->ih)){
192 		device_printf(dev, "unable to map interrupt\n");
193 		goto bad;
194 	}
195 
196 	via_wr(via, VIA_PLAY_MODE,
197 		VIA_RPMODE_AUTOSTART |
198 		VIA_RPMODE_INTR_FLAG | VIA_RPMODE_INTR_EOL, 1);
199 	via_wr(via, VIA_RECORD_MODE,
200 		VIA_RPMODE_AUTOSTART |
201 		VIA_RPMODE_INTR_FLAG | VIA_RPMODE_INTR_EOL, 1);
202 
203 	codec = ac97_create(dev, via, NULL,
204 		via_read_codec, via_write_codec);
205 	if (!codec) goto bad;
206 
207 	mixer_init(dev, &ac97_mixer, codec);
208 
209 	/*
210 	 *  The mixer init resets the codec.  So enabling VRA must be done
211 	 *  afterwards.
212 	 */
213 	v = via_read_codec(via, AC97_REG_EXT_AUDIO_ID);
214 	v &= (AC97_ENAB_VRA | AC97_ENAB_MICVRA);
215 	via_write_codec(via, AC97_REG_EXT_AUDIO_STAT, v);
216 	via->codec_caps = v;
217 	{
218 		v = via_read_codec(via, AC97_REG_EXT_AUDIO_STAT);
219 		DEB(printf("init: codec stat: %d\n", v));
220 	}
221 
222 	if (!(v & AC97_CODEC_DOES_VRA)) {
223 		/* no VRA => can do only 48 kbps */
224 		via_playcaps.minspeed = 48000;
225 		via_reccaps.minspeed = 48000;
226 	}
227 
228 	/* DMA tag for buffers */
229 	if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
230 		/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
231 		/*highaddr*/BUS_SPACE_MAXADDR,
232 		/*filter*/NULL, /*filterarg*/NULL,
233 		/*maxsize*/VIA_BUFFSIZE, /*nsegments*/1, /*maxsegz*/0x3ffff,
234 		/*flags*/0, &via->parent_dmat) != 0) {
235 		device_printf(dev, "unable to create dma tag\n");
236 		goto bad;
237 	}
238 
239 	/*
240 	 *  DMA tag for SGD table.  The 686 uses scatter/gather DMA and
241 	 *  requires a list in memory of work to do.  We need only 16 bytes
242 	 *  for this list, and it is wasteful to allocate 16K.
243 	 */
244 	if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
245 		/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
246 		/*highaddr*/BUS_SPACE_MAXADDR,
247 		/*filter*/NULL, /*filterarg*/NULL,
248 		/*maxsize*/NSEGS * sizeof(struct via_dma_op),
249 		/*nsegments*/1, /*maxsegz*/0x3ffff,
250 		/*flags*/0, &via->sgd_dmat) != 0) {
251 		device_printf(dev, "unable to create dma tag\n");
252 		goto bad;
253 	}
254 
255 	if (bus_dmamem_alloc(via->sgd_dmat, (void **)&via->sgd_table,
256 		BUS_DMA_NOWAIT, &sgd_dma_map) == -1) goto bad;
257 	if (bus_dmamap_load(via->sgd_dmat, sgd_dma_map, via->sgd_table,
258 		NSEGS * sizeof(struct via_dma_op), dma_cb, 0, 0)) goto bad;
259 
260 	snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld",
261 		rman_get_start(via->reg), rman_get_start(via->irq));
262 
263 	/* Register */
264 	if (pcm_register(dev, via, 1, 1)) goto bad;
265 	pcm_addchan(dev, PCMDIR_PLAY, &via_chantemplate, via);
266 	pcm_addchan(dev, PCMDIR_REC, &via_chantemplate, via);
267 	pcm_setstatus(dev, status);
268 	return 0;
269 bad:
270 	if (codec) ac97_destroy(codec);
271 	if (via->reg) bus_release_resource(dev, SYS_RES_IOPORT, via->regid, via->reg);
272 	if (via->ih) bus_teardown_intr(dev, via->irq, via->ih);
273 	if (via->irq) bus_release_resource(dev, SYS_RES_IRQ, via->irqid, via->irq);
274 	if (via->parent_dmat) bus_dma_tag_destroy(via->parent_dmat);
275 	if (via->sgd_dmat) bus_dma_tag_destroy(via->sgd_dmat);
276 	if (via) free(via, M_DEVBUF);
277 	return ENXIO;
278 }
279 
280 static int
281 via_detach(device_t dev)
282 {
283 	int r;
284 	struct via_info *via = 0;
285 
286 	r = pcm_unregister(dev);
287 	if (r)
288 		return r;
289 
290 	via = pcm_getdevinfo(dev);
291 	bus_release_resource(dev, SYS_RES_IOPORT, via->regid, via->reg);
292 	bus_teardown_intr(dev, via->irq, via->ih);
293 	bus_release_resource(dev, SYS_RES_IRQ, via->irqid, via->irq);
294 	bus_dma_tag_destroy(via->parent_dmat);
295 	bus_dma_tag_destroy(via->sgd_dmat);
296 	free(via, M_DEVBUF);
297 	return 0;
298 }
299 
300 
301 static device_method_t via_methods[] = {
302 	DEVMETHOD(device_probe,		via_probe),
303 	DEVMETHOD(device_attach,	via_attach),
304 	DEVMETHOD(device_detach,	via_detach),
305 	{ 0, 0}
306 };
307 
308 static driver_t via_driver = {
309 	"pcm",
310 	via_methods,
311 	sizeof(snddev_info),
312 };
313 
314 static devclass_t pcm_devclass;
315 
316 DRIVER_MODULE(via, pci, via_driver, pcm_devclass, 0, 0);
317 MODULE_DEPEND(via, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER);
318 MODULE_VERSION(via, 1);
319 
320 
321 static u_int32_t
322 via_rd(struct via_info *via, int regno, int size)
323 {
324 
325 	switch (size) {
326 	case 1:
327 		return bus_space_read_1(via->st, via->sh, regno);
328 	case 2:
329 		return bus_space_read_2(via->st, via->sh, regno);
330 	case 4:
331 		return bus_space_read_4(via->st, via->sh, regno);
332 	default:
333 		return 0xFFFFFFFF;
334 	}
335 }
336 
337 
338 static void
339 via_wr(struct via_info *via, int regno, u_int32_t data, int size)
340 {
341 
342 	switch (size) {
343 	case 1:
344 		bus_space_write_1(via->st, via->sh, regno, data);
345 		break;
346 	case 2:
347 		bus_space_write_2(via->st, via->sh, regno, data);
348 		break;
349 	case 4:
350 		bus_space_write_4(via->st, via->sh, regno, data);
351 		break;
352 	}
353 }
354 
355 
356 /* Codec interface */
357 int
358 via_waitready_codec(struct via_info *via)
359 {
360 	int i;
361 
362 	/* poll until codec not busy */
363 	for (i = 0; (i < TIMEOUT) &&
364 	    (via_rd(via, VIA_CODEC_CTL, 4) & VIA_CODEC_BUSY); i++)
365 		DELAY(1);
366 	if (i >= TIMEOUT) {
367 		printf("via: codec busy\n");
368 		return 1;
369 	}
370 
371 	return 0;
372 }
373 
374 
375 int
376 via_waitvalid_codec(struct via_info *via)
377 {
378 	int i;
379 
380 	/* poll until codec valid */
381 	for (i = 0; (i < TIMEOUT) &&
382 	    !(via_rd(via, VIA_CODEC_CTL, 4) & VIA_CODEC_PRIVALID); i++)
383 		    DELAY(1);
384 	if (i >= TIMEOUT) {
385 		printf("via: codec invalid\n");
386 		return 1;
387 	}
388 
389 	return 0;
390 }
391 
392 
393 void
394 via_write_codec(void *addr, int reg, u_int32_t val)
395 {
396 	struct via_info *via = addr;
397 
398 	if (via_waitready_codec(via)) return;
399 
400 	via_wr(via, VIA_CODEC_CTL,
401 		VIA_CODEC_PRIVALID | VIA_CODEC_INDEX(reg) | val, 4);
402 }
403 
404 
405 u_int32_t
406 via_read_codec(void *addr, int reg)
407 {
408 	struct via_info *via = addr;
409 
410 	if (via_waitready_codec(via))
411 		return 1;
412 
413 	via_wr(via, VIA_CODEC_CTL,
414 	    VIA_CODEC_PRIVALID | VIA_CODEC_READ | VIA_CODEC_INDEX(reg),4);
415 
416 	if (via_waitready_codec(via))
417 		return 1;
418 
419 	if (via_waitvalid_codec(via))
420 		return 1;
421 
422 	return via_rd(via, VIA_CODEC_CTL, 2);
423 }
424 
425 
426 /* channel interface */
427 static void *
428 viachan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
429 {
430 	struct via_info *via = devinfo;
431 	struct via_chinfo *ch = (dir == PCMDIR_PLAY) ? &via->pch : &via->rch;
432 
433 	ch->parent = via;
434 	ch->channel = c;
435 	ch->buffer = b;
436 	b->bufsize = VIA_BUFFSIZE;
437 
438 	if (chn_allocbuf(ch->buffer, via->parent_dmat) == -1) return NULL;
439 	return ch;
440 }
441 
442 static int
443 viachan_setdir(void *data, int dir)
444 {
445 	struct via_chinfo *ch = data;
446 	struct via_info *via = ch->parent;
447 	struct via_dma_op *ado;
448 	int i, chunk_size;
449 	int	phys_addr, flag;
450 
451 	ch->dir = dir;
452 	/*
453 	 *  Build the scatter/gather DMA (SGD) table.
454 	 *  There are four slots in the table: two for play, two for record.
455 	 *  This creates two half-buffers, one of which is playing; the other
456 	 *  is feeding.
457 	 */
458 	ado = via->sgd_table;
459 	chunk_size = ch->buffer->bufsize / SEGS_PER_CHAN;
460 
461 	if (dir == PCMDIR_REC) {
462 		ado += SEGS_PER_CHAN;
463 	}
464 
465 DEB(printf("SGD table located at va %p\n", ado));
466 	phys_addr = vtophys(ch->buffer->buf);
467 	for (i = 0; i < SEGS_PER_CHAN; i++) {
468 		ado->ptr = phys_addr;
469 		flag = (i == SEGS_PER_CHAN-1) ?
470 			VIA_DMAOP_EOL : VIA_DMAOP_FLAG;
471 		ado->flags = flag | chunk_size;
472 DEB(printf("ado->ptr/flags = %x/%x\n", phys_addr, flag));
473 		phys_addr += chunk_size;
474 		ado++;
475 	}
476 	return 0;
477 }
478 
479 static int
480 viachan_setformat(void *data, u_int32_t format)
481 {
482 	struct via_chinfo *ch = data;
483 	struct via_info *via = ch->parent;
484 	int	mode, mode_set;
485 
486 	mode_set = 0;
487 	if (format & AFMT_STEREO)
488 		mode_set |= VIA_RPMODE_STEREO;
489 	if (format & AFMT_S16_LE)
490 		mode_set |= VIA_RPMODE_16BIT;
491 
492 	/* Set up for output format */
493 	if (ch->dir == PCMDIR_PLAY) {
494 DEB(printf("set play format: %x\n", format));
495 		mode = via_rd(via, VIA_PLAY_MODE, 1);
496 		mode &= ~(VIA_RPMODE_16BIT | VIA_RPMODE_STEREO);
497 		mode |= mode_set;
498 		via_wr(via, VIA_PLAY_MODE, mode, 1);
499 	}
500 	else {
501 DEB(printf("set record format: %x\n", format));
502 		mode = via_rd(via, VIA_RECORD_MODE, 1);
503 		mode &= ~(VIA_RPMODE_16BIT | VIA_RPMODE_STEREO);
504 		mode |= mode_set;
505 		via_wr(via, VIA_RECORD_MODE, mode, 1);
506 	}
507 
508 	return 0;
509 }
510 
511 static int
512 viachan_setspeed(void *data, u_int32_t speed)
513 {
514 	struct via_chinfo *ch = data;
515 	struct via_info *via = ch->parent;
516 
517 	/*
518 	 *  Basic AC'97 defines a 48 kHz sample rate only.  For other rates,
519 	 *  upsampling is required.
520 	 *
521 	 *  The VT82C686A does not perform upsampling, and neither do we.
522 	 *  If the codec supports variable-rate audio (i.e. does the upsampling
523 	 *  itself), then negotiate the rate with the codec.  Otherwise,
524 	 *  return 48 kHz cuz that's all you got.
525 	 */
526 	if (ch->dir == PCMDIR_PLAY) {
527 DEB(printf("requested play speed: %d\n", speed));
528 		if (via->codec_caps & AC97_CODEC_DOES_VRA) {
529 			via_write_codec(via, AC97_REG_EXT_DAC_RATE, speed);
530 			speed = via_read_codec(via, AC97_REG_EXT_DAC_RATE);
531 		}
532 		else {
533 DEB(printf("VRA not supported!\n"));
534 			speed = 48000;
535 		}
536 DEB(printf("obtained play speed: %d\n", speed));
537 	}
538 	else {
539 DEB(printf("requested record speed: %d\n", speed));
540 		if (via->codec_caps & AC97_CODEC_DOES_VRA) {
541 			via_write_codec(via, AC97_REG_EXT_ADC_RATE, speed);
542 			speed = via_read_codec(via, AC97_REG_EXT_ADC_RATE);
543 		}
544 		else {
545 DEB(printf("VRA not supported!\n"));
546 			speed = 48000;
547 		}
548 DEB(printf("obtained record speed: %d\n", speed));
549 	}
550 	return speed;
551 }
552 
553 static int
554 viachan_setblocksize(void *data, u_int32_t blocksize)
555 {
556 	struct via_chinfo *ch = data;
557 
558 	return ch->buffer->bufsize / 2;
559 }
560 
561 static int
562 viachan_trigger(void *data, int go)
563 {
564 	struct via_chinfo *ch = data;
565 	struct via_info *via = ch->parent;
566 	struct via_dma_op *ado;
567 
568 	if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) return 0;
569 	if (ch->dir == PCMDIR_PLAY) {
570 		if (go == PCMTRIG_START) {
571 			ado = &via->sgd_table[0];
572 DEB(printf("ado located at va=%p pa=%x\n", ado, vtophys(ado)));
573 			via_wr(via, VIA_PLAY_DMAOPS_BASE, vtophys(ado),4);
574 			via_wr(via, VIA_PLAY_CONTROL,
575 				VIA_RPCTRL_START, 1);
576 		}
577 		else {
578 			/* Stop DMA */
579 			via_wr(via, VIA_PLAY_CONTROL,
580 				VIA_RPCTRL_TERMINATE, 1);
581 		}
582 	} else {
583 		if (go == PCMTRIG_START) {
584 			ado = &via->sgd_table[SEGS_PER_CHAN];
585 DEB(printf("ado located at va=%p pa=%x\n", ado, vtophys(ado)));
586 			via_wr(via, VIA_RECORD_DMAOPS_BASE,
587 				vtophys(ado),4);
588 			via_wr(via, VIA_RECORD_CONTROL,
589 				VIA_RPCTRL_START, 1);
590 		}
591 		else {
592 			/* Stop DMA */
593 			via_wr(via, VIA_RECORD_CONTROL,
594 				VIA_RPCTRL_TERMINATE, 1);
595 		}
596 	}
597 
598 DEB(printf("viachan_trigger: go=%d\n", go));
599 	return 0;
600 }
601 
602 static int
603 viachan_getptr(void *data)
604 {
605 	struct via_chinfo *ch = data;
606 	struct via_info *via = ch->parent;
607 	struct via_dma_op *ado;
608 	int	ptr, base, len, seg;
609 	int base1;
610 
611 	if (ch->dir == PCMDIR_PLAY) {
612 		ado = &via->sgd_table[0];
613 		base1 = via_rd(via, VIA_PLAY_DMAOPS_BASE, 4);
614 		len = via_rd(via, VIA_PLAY_DMAOPS_COUNT, 4);
615 		base = via_rd(via, VIA_PLAY_DMAOPS_BASE, 4);
616 		if (base != base1) {	/* Avoid race hazzard	*/
617 			len = via_rd(via, VIA_PLAY_DMAOPS_COUNT, 4);
618 		}
619 DEB(printf("viachan_getptr: len / base = %x / %x\n", len, base));
620 
621 		/* Base points to SGD segment to do, one past current */
622 
623 		/* Determine how many segments have been done */
624 		seg = (base - vtophys(ado)) / sizeof(struct via_dma_op);
625 		if (seg == 0) seg = SEGS_PER_CHAN;
626 
627 		/* Now work out offset: seg less count */
628 		ptr = seg * ch->buffer->bufsize / SEGS_PER_CHAN - len;
629 DEB(printf("return ptr=%d\n", ptr));
630 		return ptr;
631 	}
632 	else {
633 		base1 = via_rd(via, VIA_RECORD_DMAOPS_BASE, 4);
634 		ado = &via->sgd_table[SEGS_PER_CHAN];
635 		len = via_rd(via, VIA_RECORD_DMAOPS_COUNT, 4);
636 		base = via_rd(via, VIA_RECORD_DMAOPS_BASE, 4);
637 		if (base != base1) {	/* Avoid race hazzard	*/
638 			len = via_rd(via, VIA_RECORD_DMAOPS_COUNT, 4);
639 		}
640 DEB(printf("viachan_getptr: len / base = %x / %x\n", len, base));
641 
642 		/* Base points to next block to do, one past current */
643 
644 		/* Determine how many segments have been done */
645 		seg = (base - vtophys(ado)) / sizeof(struct via_dma_op);
646 		if (seg == 0) seg = SEGS_PER_CHAN;
647 
648 		/* Now work out offset: seg less count */
649 		ptr = seg * ch->buffer->bufsize / SEGS_PER_CHAN - len;
650 
651 		/* DMA appears to operate on memory 'lines' of 32 bytes	*/
652 		/* so don't return any part line - it isn't in RAM yet	*/
653 		ptr = ptr & ~0x1f;
654 DEB(printf("return ptr=%d\n", ptr));
655 		return ptr;
656 	}
657 	return 0;
658 }
659 
660 static pcmchan_caps *
661 viachan_getcaps(void *data)
662 {
663 	struct via_chinfo *ch = data;
664 	return (ch->dir == PCMDIR_PLAY) ? &via_playcaps : &via_reccaps;
665 }
666 
667 static void
668 via_intr(void *p)
669 {
670 	struct via_info *via = p;
671 	int		st;
672 
673 DEB(printf("viachan_intr\n"));
674 	/* Read channel */
675 	st = via_rd(via, VIA_PLAY_STAT, 1);
676 	if (st & VIA_RPSTAT_INTR) {
677 		via_wr(via, VIA_PLAY_STAT, VIA_RPSTAT_INTR, 1);
678 		chn_intr(via->pch.channel);
679 	}
680 
681 	/* Write channel */
682 	st = via_rd(via, VIA_RECORD_STAT, 1);
683 	if (st & VIA_RPSTAT_INTR) {
684 		via_wr(via, VIA_RECORD_STAT, VIA_RPSTAT_INTR, 1);
685 		chn_intr(via->rch.channel);
686 	}
687 }
688 
689 
690