sb16.c revision 67803
1/*
2 * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
3 * Copyright 1997,1998 Luigi Rizzo.
4 *
5 * Derived from files in the Voxware 3.5 distribution,
6 * Copyright by Hannu Savolainen 1994, under the same copyright
7 * conditions.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * $FreeBSD: head/sys/dev/sound/isa/sb16.c 67803 2000-10-28 19:20:03Z cg $
32 */
33
34#include <dev/sound/pcm/sound.h>
35
36#include  <dev/sound/isa/sb.h>
37#include  <dev/sound/chip.h>
38
39#define SB16_BUFFSIZE	4096
40#define PLAIN_SB16(x) ((((x)->bd_flags) & (BD_F_SB16|BD_F_SB16X)) == BD_F_SB16)
41
42/* channel interface */
43static void *sb16chan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir);
44static int sb16chan_setformat(void *data, u_int32_t format);
45static int sb16chan_setspeed(void *data, u_int32_t speed);
46static int sb16chan_setblocksize(void *data, u_int32_t blocksize);
47static int sb16chan_trigger(void *data, int go);
48static int sb16chan_getptr(void *data);
49static pcmchan_caps *sb16chan_getcaps(void *data);
50static int sb16chan_reset(void *data);
51static int sb16chan_resetdone(void *data);
52
53static u_int32_t sb16_fmt8[] = {
54	AFMT_U8,
55	AFMT_STEREO | AFMT_U8,
56	0
57};
58static pcmchan_caps sb16_caps8 = {5000, 45000, sb16_fmt8, 0};
59
60static u_int32_t sb16_fmt16[] = {
61	AFMT_S16_LE,
62	AFMT_STEREO | AFMT_S16_LE,
63	0
64};
65static pcmchan_caps sb16_caps16 = {5000, 45000, sb16_fmt16, 0};
66
67static u_int32_t sb16x_fmt[] = {
68	AFMT_U8,
69	AFMT_STEREO | AFMT_U8,
70	AFMT_S16_LE,
71	AFMT_STEREO | AFMT_S16_LE,
72	0
73};
74static pcmchan_caps sb16x_caps = {5000, 49000, sb16x_fmt, 0};
75
76static pcm_channel sb_chantemplate = {
77	sb16chan_init,
78	NULL,
79	sb16chan_setformat,
80	sb16chan_setspeed,
81	sb16chan_setblocksize,
82	sb16chan_trigger,
83	sb16chan_getptr,
84	sb16chan_getcaps,
85	NULL, 			/* free */
86	sb16chan_reset,		/* reset */
87	sb16chan_resetdone,	/* resetdone */
88	NULL, 			/* nop3 */
89	NULL, 			/* nop4 */
90	NULL, 			/* nop5 */
91	NULL, 			/* nop6 */
92	NULL, 			/* nop7 */
93};
94
95struct sb_info;
96
97struct sb_chinfo {
98	struct sb_info *parent;
99	pcm_channel *channel;
100	snd_dbuf *buffer;
101	int dir, run, dch;
102	u_int32_t fmt, spd, blksz;
103};
104
105struct sb_info {
106    	struct resource *io_base;	/* I/O address for the board */
107    	struct resource *irq;
108   	struct resource *drq1;
109    	struct resource *drq2;
110    	void *ih;
111    	bus_dma_tag_t parent_dmat;
112
113    	int bd_id;
114    	u_long bd_flags;       /* board-specific flags */
115	int dl, dh, prio, prio16;
116    	struct sb_chinfo pch, rch;
117};
118
119static int sb_rd(struct sb_info *sb, int reg);
120static void sb_wr(struct sb_info *sb, int reg, u_int8_t val);
121static int sb_dspready(struct sb_info *sb);
122static int sb_cmd(struct sb_info *sb, u_char val);
123/* static int sb_cmd1(struct sb_info *sb, u_char cmd, int val); */
124static int sb_cmd2(struct sb_info *sb, u_char cmd, int val);
125static u_int sb_get_byte(struct sb_info *sb);
126static void sb_setmixer(struct sb_info *sb, u_int port, u_int value);
127static int sb_getmixer(struct sb_info *sb, u_int port);
128static int sb_reset_dsp(struct sb_info *sb);
129
130static void sb_intr(void *arg);
131
132static int sb16mix_init(snd_mixer *m);
133static int sb16mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right);
134static int sb16mix_setrecsrc(snd_mixer *m, u_int32_t src);
135
136static snd_mixer sb16_mixer = {
137    	"SoundBlaster 16 mixer",
138    	sb16mix_init,
139	NULL,
140	NULL,
141    	sb16mix_set,
142    	sb16mix_setrecsrc,
143};
144
145static devclass_t pcm_devclass;
146
147/*
148 * Common code for the midi and pcm functions
149 *
150 * sb_cmd write a single byte to the CMD port.
151 * sb_cmd1 write a CMD + 1 byte arg
152 * sb_cmd2 write a CMD + 2 byte arg
153 * sb_get_byte returns a single byte from the DSP data port
154 */
155
156static int
157port_rd(struct resource *port, int off)
158{
159	return bus_space_read_1(rman_get_bustag(port), rman_get_bushandle(port), off);
160}
161
162static void
163port_wr(struct resource *port, int off, u_int8_t data)
164{
165	return bus_space_write_1(rman_get_bustag(port), rman_get_bushandle(port), off, data);
166}
167
168static int
169sb_rd(struct sb_info *sb, int reg)
170{
171	return port_rd(sb->io_base, reg);
172}
173
174static void
175sb_wr(struct sb_info *sb, int reg, u_int8_t val)
176{
177	port_wr(sb->io_base, reg, val);
178}
179
180static int
181sb_dspready(struct sb_info *sb)
182{
183	return ((sb_rd(sb, SBDSP_STATUS) & 0x80) == 0);
184}
185
186static int
187sb_dspwr(struct sb_info *sb, u_char val)
188{
189    	int  i;
190
191    	for (i = 0; i < 1000; i++) {
192		if (sb_dspready(sb)) {
193	    		sb_wr(sb, SBDSP_CMD, val);
194	    		return 1;
195		}
196		if (i > 10) DELAY((i > 100)? 1000 : 10);
197    	}
198    	printf("sb_dspwr(0x%02x) timed out.\n", val);
199    	return 0;
200}
201
202static int
203sb_cmd(struct sb_info *sb, u_char val)
204{
205#if 0
206	printf("sb_cmd: %x\n", val);
207#endif
208    	return sb_dspwr(sb, val);
209}
210
211/*
212static int
213sb_cmd1(struct sb_info *sb, u_char cmd, int val)
214{
215#if 0
216    	printf("sb_cmd1: %x, %x\n", cmd, val);
217#endif
218    	if (sb_dspwr(sb, cmd)) {
219		return sb_dspwr(sb, val & 0xff);
220    	} else return 0;
221}
222*/
223
224static int
225sb_cmd2(struct sb_info *sb, u_char cmd, int val)
226{
227#if 0
228    	printf("sb_cmd2: %x, %x\n", cmd, val);
229#endif
230    	if (sb_dspwr(sb, cmd)) {
231		return sb_dspwr(sb, val & 0xff) &&
232		       sb_dspwr(sb, (val >> 8) & 0xff);
233    	} else return 0;
234}
235
236/*
237 * in the SB, there is a set of indirect "mixer" registers with
238 * address at offset 4, data at offset 5
239 */
240static void
241sb_setmixer(struct sb_info *sb, u_int port, u_int value)
242{
243    	u_long   flags;
244
245    	flags = spltty();
246    	sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
247    	DELAY(10);
248    	sb_wr(sb, SB_MIX_DATA, (u_char) (value & 0xff));
249    	DELAY(10);
250    	splx(flags);
251}
252
253static int
254sb_getmixer(struct sb_info *sb, u_int port)
255{
256    	int val;
257    	u_long flags;
258
259    	flags = spltty();
260    	sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
261    	DELAY(10);
262    	val = sb_rd(sb, SB_MIX_DATA);
263    	DELAY(10);
264    	splx(flags);
265
266    	return val;
267}
268
269static u_int
270sb_get_byte(struct sb_info *sb)
271{
272    	int i;
273
274    	for (i = 1000; i > 0; i--) {
275		if (sb_rd(sb, DSP_DATA_AVAIL) & 0x80)
276			return sb_rd(sb, DSP_READ);
277		else
278			DELAY(20);
279    	}
280    	return 0xffff;
281}
282
283static int
284sb_reset_dsp(struct sb_info *sb)
285{
286    	sb_wr(sb, SBDSP_RST, 3);
287    	DELAY(100);
288    	sb_wr(sb, SBDSP_RST, 0);
289    	if (sb_get_byte(sb) != 0xAA) {
290        	DEB(printf("sb_reset_dsp 0x%lx failed\n",
291			   rman_get_start(d->io_base)));
292		return ENXIO;	/* Sorry */
293    	}
294    	return 0;
295}
296
297/************************************************************/
298
299struct sb16_mixent {
300	int reg;
301	int bits;
302	int ofs;
303	int stereo;
304};
305
306static const struct sb16_mixent sb16_mixtab[32] = {
307    	[SOUND_MIXER_VOLUME]	= { 0x30, 5, 3, 1 },
308    	[SOUND_MIXER_PCM]	= { 0x32, 5, 3, 1 },
309    	[SOUND_MIXER_SYNTH]	= { 0x34, 5, 3, 1 },
310    	[SOUND_MIXER_CD]	= { 0x36, 5, 3, 1 },
311    	[SOUND_MIXER_LINE]	= { 0x38, 5, 3, 1 },
312    	[SOUND_MIXER_MIC]	= { 0x3a, 5, 3, 0 },
313       	[SOUND_MIXER_SPEAKER]	= { 0x3b, 5, 3, 0 },
314    	[SOUND_MIXER_IGAIN]	= { 0x3f, 2, 6, 1 },
315    	[SOUND_MIXER_OGAIN]	= { 0x41, 2, 6, 1 },
316	[SOUND_MIXER_TREBLE]	= { 0x44, 4, 4, 1 },
317    	[SOUND_MIXER_BASS]	= { 0x46, 4, 4, 1 },
318};
319
320static int
321sb16mix_init(snd_mixer *m)
322{
323    	struct sb_info *sb = mix_getdevinfo(m);
324
325	mix_setdevs(m, SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER |
326     		       SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD |
327     		       SOUND_MASK_IGAIN | SOUND_MASK_OGAIN |
328     		       SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE);
329
330	mix_setrecdevs(m, SOUND_MASK_SYNTH | SOUND_MASK_LINE |
331			  SOUND_MASK_MIC | SOUND_MASK_CD);
332
333	sb_setmixer(sb, 0x3c, 0x1f); /* make all output active */
334
335	sb_setmixer(sb, 0x3d, 0); /* make all inputs-l off */
336	sb_setmixer(sb, 0x3e, 0); /* make all inputs-r off */
337
338	return 0;
339}
340
341static int
342sb16mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
343{
344    	struct sb_info *sb = mix_getdevinfo(m);
345    	const struct sb16_mixent *e;
346    	int max;
347
348	e = &sb16_mixtab[dev];
349	max = (1 << e->bits) - 1;
350
351	left = (left * max) / 100;
352	right = (right * max) / 100;
353
354	sb_setmixer(sb, e->reg, left << e->ofs);
355	if (e->stereo)
356		sb_setmixer(sb, e->reg, right << e->ofs);
357	else
358		right = left;
359
360	left = (left * 100) / max;
361	right = (right * 100) / max;
362
363    	return left | (right << 8);
364}
365
366static int
367sb16mix_setrecsrc(snd_mixer *m, u_int32_t src)
368{
369    	struct sb_info *sb = mix_getdevinfo(m);
370    	u_char recdev;
371
372	recdev = 0;
373	if (src & SOUND_MASK_MIC)
374		recdev |= 0x01; /* mono mic */
375
376	if (src & SOUND_MASK_CD)
377		recdev |= 0x06; /* l+r cd */
378
379	if (src & SOUND_MASK_LINE)
380		recdev |= 0x18; /* l+r line */
381
382	if (src & SOUND_MASK_SYNTH)
383		recdev |= 0x60; /* l+r midi */
384
385	sb_setmixer(sb, SB16_IMASK_L, recdev);
386	sb_setmixer(sb, SB16_IMASK_R, recdev);
387
388	/*
389	 * since the same volume controls apply to the input and
390	 * output sections, the best approach to have a consistent
391	 * behaviour among cards would be to disable the output path
392	 * on devices which are used to record.
393	 * However, since users like to have feedback, we only disable
394	 * the mic -- permanently.
395	 */
396        sb_setmixer(sb, SB16_OMASK, 0x1f & ~1);
397
398	return src;
399}
400
401/************************************************************/
402
403static void
404sb16_release_resources(struct sb_info *sb, device_t dev)
405{
406    	if (sb->irq) {
407    		if (sb->ih)
408			bus_teardown_intr(dev, sb->irq, sb->ih);
409 		bus_release_resource(dev, SYS_RES_IRQ, 0, sb->irq);
410		sb->irq = 0;
411    	}
412    	if (sb->drq1) {
413		bus_release_resource(dev, SYS_RES_DRQ, 0, sb->drq1);
414		sb->drq1 = 0;
415    	}
416    	if (sb->drq2) {
417		bus_release_resource(dev, SYS_RES_DRQ, 1, sb->drq2);
418		sb->drq2 = 0;
419    	}
420    	if (sb->io_base) {
421		bus_release_resource(dev, SYS_RES_IOPORT, 0, sb->io_base);
422		sb->io_base = 0;
423    	}
424    	if (sb->parent_dmat) {
425		bus_dma_tag_destroy(sb->parent_dmat);
426		sb->parent_dmat = 0;
427    	}
428     	free(sb, M_DEVBUF);
429}
430
431static int
432sb16_alloc_resources(struct sb_info *sb, device_t dev)
433{
434	int rid;
435
436	rid = 0;
437	if (!sb->io_base)
438    		sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, RF_ACTIVE);
439
440	rid = 0;
441	if (!sb->irq)
442    		sb->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_ACTIVE);
443
444	rid = 0;
445	if (!sb->drq1)
446    		sb->drq1 = bus_alloc_resource(dev, SYS_RES_DRQ, &rid, 0, ~0, 1, RF_ACTIVE);
447
448	rid = 1;
449	if (!sb->drq2)
450        	sb->drq2 = bus_alloc_resource(dev, SYS_RES_DRQ, &rid, 0, ~0, 1, RF_ACTIVE);
451
452    	if (sb->io_base && sb->drq1 && sb->irq) {
453		int bs = SB16_BUFFSIZE;
454
455		isa_dma_acquire(rman_get_start(sb->drq1));
456		isa_dmainit(rman_get_start(sb->drq1), bs);
457
458		if (sb->drq2) {
459			isa_dma_acquire(rman_get_start(sb->drq2));
460			isa_dmainit(rman_get_start(sb->drq2), bs);
461		}
462		return 0;
463	} else return ENXIO;
464}
465
466static void
467sb_intr(void *arg)
468{
469    	struct sb_info *sb = (struct sb_info *)arg;
470    	int reason = 3, c;
471
472    	/*
473     	 * The Vibra16X has separate flags for 8 and 16 bit transfers, but
474     	 * I have no idea how to tell capture from playback interrupts...
475     	 */
476
477	reason = 0;
478    	c = sb_getmixer(sb, IRQ_STAT);
479
480	/*
481	 * this tells us if the source is 8-bit or 16-bit dma. We
482     	 * have to check the io channel to map it to read or write...
483     	 */
484
485    	if (c & 1) { /* 8-bit dma */
486		if (sb->pch.dch == sb->dl)
487			reason |= 1;
488		if (sb->rch.dch == sb->dl)
489			reason |= 2;
490    	}
491
492    	if (c & 2) { /* 16-bit dma */
493		if (sb->pch.dch == sb->dh)
494			reason |= 1;
495		if (sb->rch.dch == sb->dh)
496			reason |= 2;
497    	}
498#if 0
499    	printf("sb_intr: reason=%d c=0x%x\n", reason, c);
500#endif
501    	if ((reason & 1) && (sb->pch.run))
502		chn_intr(sb->pch.channel);
503
504    	if ((reason & 2) && (sb->rch.run))
505		chn_intr(sb->rch.channel);
506
507    	if (c & 1)
508		sb_rd(sb, DSP_DATA_AVAIL); /* 8-bit int ack */
509
510    	if (c & 2)
511		sb_rd(sb, DSP_DATA_AVL16); /* 16-bit int ack */
512}
513
514static int
515sb_setup(struct sb_info *sb)
516{
517	struct sb_chinfo *ch;
518	u_int8_t v;
519	int l, pprio;
520
521	if (sb->bd_flags & BD_F_DMARUN)
522		buf_isadma(sb->pch.buffer, PCMTRIG_STOP);
523	if (sb->bd_flags & BD_F_DMARUN2)
524		buf_isadma(sb->rch.buffer, PCMTRIG_STOP);
525	sb->bd_flags &= ~(BD_F_DMARUN | BD_F_DMARUN2);
526
527	sb_reset_dsp(sb);
528
529	if (sb->bd_flags & BD_F_SB16X) {
530		sb->pch.buffer->chan = sb->dl;
531		sb->rch.buffer->chan = sb->dh;
532	} else {
533		if (sb->pch.run && sb->rch.run) {
534			pprio = (sb->rch.fmt & AFMT_16BIT)? 0 : 1;
535			sb->pch.buffer->chan = pprio? sb->dh : sb->dl;
536			sb->rch.buffer->chan = pprio? sb->dl : sb->dh;
537		} else {
538			if (sb->pch.run) {
539				sb->pch.buffer->chan = (sb->pch.fmt & AFMT_16BIT)? sb->dh : sb->dl;
540				sb->rch.buffer->chan = (sb->pch.fmt & AFMT_16BIT)? sb->dl : sb->dh;
541			} else if (sb->rch.run) {
542				sb->pch.buffer->chan = (sb->rch.fmt & AFMT_16BIT)? sb->dl : sb->dh;
543				sb->rch.buffer->chan = (sb->rch.fmt & AFMT_16BIT)? sb->dh : sb->dl;
544			}
545		}
546	}
547
548	sb->pch.dch = sb->pch.buffer->chan;
549	sb->rch.dch = sb->rch.buffer->chan;
550
551	sb->pch.buffer->dir = ISADMA_WRITE;
552	sb->rch.buffer->dir = ISADMA_READ;
553
554	/*
555	printf("setup: pch = %d, pfmt = %d, rch = %d, rfmt = %d\n",
556	       sb->pch.dch, sb->pch.fmt, sb->rch.dch, sb->rch.fmt);
557	*/
558
559	ch = &sb->pch;
560	if (ch->run) {
561		l = ch->blksz;
562		if (ch->fmt & AFMT_16BIT)
563			l >>= 1;
564		l--;
565
566		/* play speed */
567		RANGE(ch->spd, 5000, 45000);
568		sb_cmd(sb, DSP_CMD_OUT16);
569    		sb_cmd(sb, ch->spd >> 8);
570		sb_cmd(sb, ch->spd & 0xff);
571
572		/* play format, length */
573		v = DSP_F16_AUTO | DSP_F16_FIFO_ON | DSP_F16_DAC;
574		v |= (ch->fmt & AFMT_16BIT)? DSP_DMA16 : DSP_DMA8;
575		sb_cmd(sb, v);
576
577		v = (ch->fmt & AFMT_STEREO)? DSP_F16_STEREO : 0;
578		v |= (ch->fmt & AFMT_SIGNED)? DSP_F16_SIGNED : 0;
579		sb_cmd2(sb, v, l);
580		buf_isadma(ch->buffer, PCMTRIG_START);
581		sb->bd_flags |= BD_F_DMARUN;
582	}
583
584	ch = &sb->rch;
585	if (ch->run) {
586		l = ch->blksz;
587		if (ch->fmt & AFMT_16BIT)
588			l >>= 1;
589		l--;
590
591		/* record speed */
592		RANGE(ch->spd, 5000, 45000);
593		sb_cmd(sb, DSP_CMD_IN16);
594    		sb_cmd(sb, ch->spd >> 8);
595		sb_cmd(sb, ch->spd & 0xff);
596
597		/* record format, length */
598		v = DSP_F16_AUTO | DSP_F16_FIFO_ON | DSP_F16_ADC;
599		v |= (ch->fmt & AFMT_16BIT)? DSP_DMA16 : DSP_DMA8;
600		sb_cmd(sb, v);
601
602		v = (ch->fmt & AFMT_STEREO)? DSP_F16_STEREO : 0;
603		v |= (ch->fmt & AFMT_SIGNED)? DSP_F16_SIGNED : 0;
604		sb_cmd2(sb, v, l);
605		buf_isadma(ch->buffer, PCMTRIG_START);
606		sb->bd_flags |= BD_F_DMARUN2;
607	}
608
609    	return 0;
610}
611
612/* channel interface */
613static void *
614sb16chan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
615{
616	struct sb_info *sb = devinfo;
617	struct sb_chinfo *ch = (dir == PCMDIR_PLAY)? &sb->pch : &sb->rch;
618
619	ch->parent = sb;
620	ch->channel = c;
621	ch->buffer = b;
622	ch->buffer->bufsize = SB16_BUFFSIZE;
623	ch->dir = dir;
624
625	if (chn_allocbuf(ch->buffer, sb->parent_dmat) == -1)
626		return NULL;
627
628	return ch;
629}
630
631static int
632sb16chan_setformat(void *data, u_int32_t format)
633{
634	struct sb_chinfo *ch = data;
635	struct sb_info *sb = ch->parent;
636
637	ch->fmt = format;
638	sb->prio = ch->dir;
639	sb->prio16 = (ch->fmt & AFMT_16BIT)? 1 : 0;
640
641	return 0;
642}
643
644static int
645sb16chan_setspeed(void *data, u_int32_t speed)
646{
647	struct sb_chinfo *ch = data;
648
649	ch->spd = speed;
650	return speed;
651}
652
653static int
654sb16chan_setblocksize(void *data, u_int32_t blocksize)
655{
656	struct sb_chinfo *ch = data;
657
658	ch->blksz = blocksize;
659	return blocksize;
660}
661
662static int
663sb16chan_trigger(void *data, int go)
664{
665	struct sb_chinfo *ch = data;
666	struct sb_info *sb = ch->parent;
667
668	if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
669		return 0;
670
671	if (go == PCMTRIG_START)
672		ch->run = 1;
673	else
674		ch->run = 0;
675	sb_setup(sb);
676
677	return 0;
678}
679
680static int
681sb16chan_getptr(void *data)
682{
683	struct sb_chinfo *ch = data;
684
685	return buf_isadmaptr(ch->buffer);
686}
687
688static pcmchan_caps *
689sb16chan_getcaps(void *data)
690{
691	struct sb_chinfo *ch = data;
692	struct sb_info *sb = ch->parent;
693
694	if ((sb->prio == 0) || (sb->prio == ch->dir))
695		return &sb16x_caps;
696	else
697		return sb->prio16? &sb16_caps8 : &sb16_caps16;
698}
699
700static int
701sb16chan_reset(void *data)
702{
703/*
704	struct sb_chinfo *ch = data;
705	struct sb_info *sb = ch->parent;
706*/
707	return 0;
708}
709
710static int
711sb16chan_resetdone(void *data)
712{
713	struct sb_chinfo *ch = data;
714	struct sb_info *sb = ch->parent;
715
716	sb->prio = 0;
717
718	return 0;
719}
720
721/************************************************************/
722
723static int
724sb16_probe(device_t dev)
725{
726    	char buf[64];
727	uintptr_t func, ver, r, f;
728
729	/* The parent device has already been probed. */
730	r = BUS_READ_IVAR(device_get_parent(dev), dev, 0, &func);
731	if (func != SCF_PCM)
732		return (ENXIO);
733
734	r = BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver);
735	f = (ver & 0xffff0000) >> 16;
736	ver &= 0x0000ffff;
737	if (f & BD_F_SB16) {
738		snprintf(buf, sizeof buf, "SB16 DSP %d.%02d%s", (int) ver >> 8, (int) ver & 0xff,
739			 (f & BD_F_SB16X)? " (ViBRA16X)" : "");
740    		device_set_desc_copy(dev, buf);
741		return 0;
742	} else
743		return (ENXIO);
744}
745
746static int
747sb16_attach(device_t dev)
748{
749    	struct sb_info *sb;
750	uintptr_t ver;
751    	char status[SND_STATUSLEN];
752	int bs = SB16_BUFFSIZE;
753
754    	sb = (struct sb_info *)malloc(sizeof *sb, M_DEVBUF, M_NOWAIT);
755    	if (!sb)
756		return ENXIO;
757    	bzero(sb, sizeof *sb);
758
759	BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver);
760	sb->bd_id = ver & 0x0000ffff;
761	sb->bd_flags = (ver & 0xffff0000) >> 16;
762
763    	if (sb16_alloc_resources(sb, dev))
764		goto no;
765    	if (sb_reset_dsp(sb))
766		goto no;
767	if (mixer_init(dev, &sb16_mixer, sb))
768		goto no;
769	if (bus_setup_intr(dev, sb->irq, INTR_TYPE_TTY, sb_intr, sb, &sb->ih))
770		goto no;
771
772	if (!sb->drq2)
773		pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX);
774
775	sb->dl = rman_get_start(sb->drq1);
776	sb->dh = sb->drq2? rman_get_start(sb->drq2) : sb->dl;
777	sb->prio = 0;
778
779    	if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
780			/*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
781			/*highaddr*/BUS_SPACE_MAXADDR,
782			/*filter*/NULL, /*filterarg*/NULL,
783			/*maxsize*/bs, /*nsegments*/1,
784			/*maxsegz*/0x3ffff,
785			/*flags*/0, &sb->parent_dmat) != 0) {
786		device_printf(dev, "unable to create dma tag\n");
787		goto no;
788    	}
789
790    	snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld",
791    	     	rman_get_start(sb->io_base), rman_get_start(sb->irq),
792		rman_get_start(sb->drq1));
793    	if (sb->drq2)
794		snprintf(status + strlen(status), SND_STATUSLEN - strlen(status),
795			":%ld", rman_get_start(sb->drq2));
796
797    	if (pcm_register(dev, sb, 1, 1))
798		goto no;
799	pcm_addchan(dev, PCMDIR_REC, &sb_chantemplate, sb);
800	pcm_addchan(dev, PCMDIR_PLAY, &sb_chantemplate, sb);
801
802    	pcm_setstatus(dev, status);
803
804    	return 0;
805
806no:
807    	sb16_release_resources(sb, dev);
808    	return ENXIO;
809}
810
811static int
812sb16_detach(device_t dev)
813{
814	int r;
815	struct sb_info *sb;
816
817	r = pcm_unregister(dev);
818	if (r)
819		return r;
820
821	sb = pcm_getdevinfo(dev);
822    	sb16_release_resources(sb, dev);
823	return 0;
824}
825
826static device_method_t sb16_methods[] = {
827	/* Device interface */
828	DEVMETHOD(device_probe,		sb16_probe),
829	DEVMETHOD(device_attach,	sb16_attach),
830	DEVMETHOD(device_detach,	sb16_detach),
831
832	{ 0, 0 }
833};
834
835static driver_t sb16_driver = {
836	"pcm",
837	sb16_methods,
838	sizeof(snddev_info),
839};
840
841DRIVER_MODULE(snd_sb16, sbc, sb16_driver, pcm_devclass, 0, 0);
842MODULE_DEPEND(snd_sb16, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER);
843MODULE_VERSION(snd_sb16, 1);
844
845
846
847
848