sb16.c revision 60958
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 60958 2000-05-26 21:15:47Z cg $
32 */
33
34#include <dev/sound/pcm/sound.h>
35
36#include "sbc.h"
37
38#define __SB_MIXER_C__	/* XXX warning... */
39#include  <dev/sound/isa/sb.h>
40#include  <dev/sound/chip.h>
41
42#define PLAIN_SB16(x) ((((x)->bd_flags) & (BD_F_SB16|BD_F_SB16X)) == BD_F_SB16)
43
44/* channel interface */
45static void *sbchan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir);
46static int sbchan_setdir(void *data, int dir);
47static int sbchan_setformat(void *data, u_int32_t format);
48static int sbchan_setspeed(void *data, u_int32_t speed);
49static int sbchan_setblocksize(void *data, u_int32_t blocksize);
50static int sbchan_trigger(void *data, int go);
51static int sbchan_getptr(void *data);
52static pcmchan_caps *sbchan_getcaps(void *data);
53
54static pcmchan_caps sb_playcaps = {
55	4000, 22050,
56	AFMT_U8,
57	AFMT_U8
58};
59
60static pcmchan_caps sb_reccaps = {
61	4000, 13000,
62	AFMT_U8,
63	AFMT_U8
64};
65
66static pcmchan_caps sbpro_playcaps = {
67	4000, 45000,
68	AFMT_STEREO | AFMT_U8,
69	AFMT_STEREO | AFMT_U8
70};
71
72static pcmchan_caps sbpro_reccaps = {
73	4000, 15000,
74	AFMT_STEREO | AFMT_U8,
75	AFMT_STEREO | AFMT_U8
76};
77
78static pcmchan_caps sb16_hcaps = {
79	5000, 45000,
80	AFMT_STEREO | AFMT_S16_LE,
81	AFMT_STEREO | AFMT_S16_LE
82};
83
84static pcmchan_caps sb16_lcaps = {
85	5000, 45000,
86	AFMT_STEREO | AFMT_U8,
87	AFMT_STEREO | AFMT_U8
88};
89
90static pcmchan_caps sb16x_caps = {
91	5000, 49000,
92	AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
93	AFMT_STEREO | AFMT_S16_LE
94};
95
96static pcm_channel sb_chantemplate = {
97	sbchan_init,
98	sbchan_setdir,
99	sbchan_setformat,
100	sbchan_setspeed,
101	sbchan_setblocksize,
102	sbchan_trigger,
103	sbchan_getptr,
104	sbchan_getcaps,
105};
106
107struct sb_info;
108
109struct sb_chinfo {
110	struct sb_info *parent;
111	pcm_channel *channel;
112	snd_dbuf *buffer;
113	int dir;
114	u_int32_t fmt, spd;
115};
116
117struct sb_info {
118    	struct resource *io_base;	/* I/O address for the board */
119    	struct resource *irq;
120   	struct resource *drq1;
121    	struct resource *drq2;
122    	bus_dma_tag_t parent_dmat;
123
124    	int bd_id;
125    	u_long bd_flags;       /* board-specific flags */
126    	struct sb_chinfo pch, rch;
127};
128
129static int sb_rd(struct sb_info *sb, int reg);
130static void sb_wr(struct sb_info *sb, int reg, u_int8_t val);
131static int sb_dspready(struct sb_info *sb);
132static int sb_cmd(struct sb_info *sb, u_char val);
133static int sb_cmd1(struct sb_info *sb, u_char cmd, int val);
134static int sb_cmd2(struct sb_info *sb, u_char cmd, int val);
135static u_int sb_get_byte(struct sb_info *sb);
136static void sb_setmixer(struct sb_info *sb, u_int port, u_int value);
137static int sb_getmixer(struct sb_info *sb, u_int port);
138static int sb_reset_dsp(struct sb_info *sb);
139
140static void sb_intr(void *arg);
141static int sb_speed(struct sb_chinfo *ch);
142static int sb_start(struct sb_chinfo *ch);
143static int sb_stop(struct sb_chinfo *ch);
144
145static int sbmix_init(snd_mixer *m);
146static int sbmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right);
147static int sbmix_setrecsrc(snd_mixer *m, u_int32_t src);
148
149static snd_mixer sb_mixer = {
150    "SoundBlaster mixer",
151    sbmix_init,
152    sbmix_set,
153    sbmix_setrecsrc,
154};
155
156static devclass_t pcm_devclass;
157
158/*
159 * Common code for the midi and pcm functions
160 *
161 * sb_cmd write a single byte to the CMD port.
162 * sb_cmd1 write a CMD + 1 byte arg
163 * sb_cmd2 write a CMD + 2 byte arg
164 * sb_get_byte returns a single byte from the DSP data port
165 *
166 * ess_write is actually sb_cmd1
167 * ess_read access ext. regs via sb_cmd(0xc0, reg) followed by sb_get_byte
168 */
169
170static int
171port_rd(struct resource *port, int off)
172{
173	return bus_space_read_1(rman_get_bustag(port),
174				rman_get_bushandle(port),
175				off);
176}
177
178static void
179port_wr(struct resource *port, int off, u_int8_t data)
180{
181	return bus_space_write_1(rman_get_bustag(port),
182				 rman_get_bushandle(port),
183				 off, data);
184}
185
186static int
187sb_rd(struct sb_info *sb, int reg)
188{
189	return port_rd(sb->io_base, reg);
190}
191
192static void
193sb_wr(struct sb_info *sb, int reg, u_int8_t val)
194{
195	port_wr(sb->io_base, reg, val);
196}
197
198static int
199sb_dspready(struct sb_info *sb)
200{
201	return ((sb_rd(sb, SBDSP_STATUS) & 0x80) == 0);
202}
203
204static int
205sb_dspwr(struct sb_info *sb, u_char val)
206{
207    	int  i;
208
209    	for (i = 0; i < 1000; i++) {
210		if (sb_dspready(sb)) {
211	    		sb_wr(sb, SBDSP_CMD, val);
212	    		return 1;
213		}
214		if (i > 10) DELAY((i > 100)? 1000 : 10);
215    	}
216    	printf("sb_dspwr(0x%02x) timed out.\n", val);
217    	return 0;
218}
219
220static int
221sb_cmd(struct sb_info *sb, u_char val)
222{
223#if 0
224	printf("sb_cmd: %x\n", val);
225#endif
226    	return sb_dspwr(sb, val);
227}
228
229static int
230sb_cmd1(struct sb_info *sb, u_char cmd, int val)
231{
232#if 0
233    	printf("sb_cmd1: %x, %x\n", cmd, val);
234#endif
235    	if (sb_dspwr(sb, cmd)) {
236		return sb_dspwr(sb, val & 0xff);
237    	} else return 0;
238}
239
240static int
241sb_cmd2(struct sb_info *sb, u_char cmd, int val)
242{
243#if 0
244    	printf("sb_cmd2: %x, %x\n", cmd, val);
245#endif
246    	if (sb_dspwr(sb, cmd)) {
247		return sb_dspwr(sb, val & 0xff) &&
248		       sb_dspwr(sb, (val >> 8) & 0xff);
249    	} else return 0;
250}
251
252/*
253 * in the SB, there is a set of indirect "mixer" registers with
254 * address at offset 4, data at offset 5
255 */
256static void
257sb_setmixer(struct sb_info *sb, u_int port, u_int value)
258{
259    	u_long   flags;
260
261    	flags = spltty();
262    	sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
263    	DELAY(10);
264    	sb_wr(sb, SB_MIX_DATA, (u_char) (value & 0xff));
265    	DELAY(10);
266    	splx(flags);
267}
268
269static int
270sb_getmixer(struct sb_info *sb, u_int port)
271{
272    	int val;
273    	u_long flags;
274
275    	flags = spltty();
276    	sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
277    	DELAY(10);
278    	val = sb_rd(sb, SB_MIX_DATA);
279    	DELAY(10);
280    	splx(flags);
281
282    	return val;
283}
284
285static u_int
286sb_get_byte(struct sb_info *sb)
287{
288    	int i;
289
290    	for (i = 1000; i > 0; i--) {
291		if (sb_rd(sb, DSP_DATA_AVAIL) & 0x80)
292			return sb_rd(sb, DSP_READ);
293		else
294			DELAY(20);
295    	}
296    	return 0xffff;
297}
298
299static int
300sb_reset_dsp(struct sb_info *sb)
301{
302    	sb_wr(sb, SBDSP_RST, 3);
303    	DELAY(100);
304    	sb_wr(sb, SBDSP_RST, 0);
305    	if (sb_get_byte(sb) != 0xAA) {
306        	DEB(printf("sb_reset_dsp 0x%lx failed\n",
307			   rman_get_start(d->io_base)));
308		return ENXIO;	/* Sorry */
309    	}
310    	if (sb->bd_flags & BD_F_ESS)
311		sb_cmd(sb, 0xc6);
312    	return 0;
313}
314
315static void
316sb_release_resources(struct sb_info *sb, device_t dev)
317{
318    	/* should we bus_teardown_intr here? */
319    	if (sb->irq) {
320		bus_release_resource(dev, SYS_RES_IRQ, 0, sb->irq);
321		sb->irq = 0;
322    	}
323    	if (sb->drq1) {
324		bus_release_resource(dev, SYS_RES_DRQ, 0, sb->drq1);
325		sb->drq1 = 0;
326    	}
327    	if (sb->drq2) {
328		bus_release_resource(dev, SYS_RES_DRQ, 1, sb->drq2);
329		sb->drq2 = 0;
330    	}
331    	if (sb->io_base) {
332		bus_release_resource(dev, SYS_RES_IOPORT, 0, sb->io_base);
333		sb->io_base = 0;
334    	}
335    	free(sb, M_DEVBUF);
336}
337
338static int
339sb_alloc_resources(struct sb_info *sb, device_t dev)
340{
341	int rid;
342
343	rid = 0;
344	if (!sb->io_base)
345    		sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT,
346						 &rid, 0, ~0, 1,
347						 RF_ACTIVE);
348	rid = 0;
349	if (!sb->irq)
350    		sb->irq = bus_alloc_resource(dev, SYS_RES_IRQ,
351					     &rid, 0, ~0, 1,
352					     RF_ACTIVE);
353	rid = 0;
354	if (!sb->drq1)
355    		sb->drq1 = bus_alloc_resource(dev, SYS_RES_DRQ,
356					      &rid, 0, ~0, 1,
357					      RF_ACTIVE);
358	rid = 1;
359	if (!sb->drq2)
360        	sb->drq2 = bus_alloc_resource(dev, SYS_RES_DRQ,
361					      &rid, 0, ~0, 1,
362					      RF_ACTIVE);
363
364    	if (sb->io_base && sb->drq1 && sb->irq) {
365		int bs = DSP_BUFFSIZE;
366
367		isa_dma_acquire(rman_get_start(sb->drq1));
368		isa_dmainit(rman_get_start(sb->drq1), bs);
369
370		if (sb->drq2) {
371			isa_dma_acquire(rman_get_start(sb->drq2));
372			isa_dmainit(rman_get_start(sb->drq2), bs);
373		}
374
375		return 0;
376	} else return ENXIO;
377}
378
379static void
380sb16_swap(void *v, int dir)
381{
382	struct sb_info *sb = v;
383	int pb = sb->pch.buffer->dl;
384	int rb = sb->rch.buffer->dl;
385	int pc = sb->pch.buffer->chan;
386	int rc = sb->rch.buffer->chan;
387	int swp = 0;
388
389	if (!pb && !rb) {
390		if (dir == PCMDIR_PLAY && pc < 4)
391			swp = 1;
392		else
393			if (dir == PCMDIR_REC && rc < 4)
394				swp = 1;
395	if (swp) {
396			int t;
397
398			t = sb->pch.buffer->chan;
399			sb->pch.buffer->chan = sb->rch.buffer->chan;
400			sb->rch.buffer->chan = t;
401			sb->pch.buffer->dir = ISADMA_WRITE;
402			sb->rch.buffer->dir = ISADMA_READ;
403		}
404	}
405}
406
407static int
408sb_doattach(device_t dev, struct sb_info *sb)
409{
410    	snddev_info *d = device_get_softc(dev);
411    	void *ih;
412    	char status[SND_STATUSLEN];
413	int bs = DSP_BUFFSIZE;
414
415    	if (sb_alloc_resources(sb, dev))
416		goto no;
417    	if (sb_reset_dsp(sb))
418		goto no;
419    	mixer_init(d, &sb_mixer, sb);
420
421	bus_setup_intr(dev, sb->irq, INTR_TYPE_TTY, sb_intr, sb, &ih);
422    	if ((sb->bd_flags & BD_F_SB16) && !(sb->bd_flags & BD_F_SB16X))
423		pcm_setswap(dev, sb16_swap);
424    	if (!sb->drq2)
425		pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX);
426
427    	if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
428			/*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
429			/*highaddr*/BUS_SPACE_MAXADDR,
430			/*filter*/NULL, /*filterarg*/NULL,
431			/*maxsize*/bs, /*nsegments*/1,
432			/*maxsegz*/0x3ffff,
433			/*flags*/0, &sb->parent_dmat) != 0) {
434		device_printf(dev, "unable to create dma tag\n");
435		goto no;
436    	}
437
438    	snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld",
439    	     	rman_get_start(sb->io_base), rman_get_start(sb->irq),
440		rman_get_start(sb->drq1));
441    	if (sb->drq2)
442		snprintf(status + strlen(status), SND_STATUSLEN - strlen(status),
443			":%ld", rman_get_start(sb->drq2));
444
445    	if (pcm_register(dev, sb, 1, 1))
446		goto no;
447	pcm_addchan(dev, PCMDIR_REC, &sb_chantemplate, sb);
448	pcm_addchan(dev, PCMDIR_PLAY, &sb_chantemplate, sb);
449    	pcm_setstatus(dev, status);
450
451    	return 0;
452
453no:
454    	sb_release_resources(sb, dev);
455    	return ENXIO;
456}
457
458static void
459sb_intr(void *arg)
460{
461    	struct sb_info *sb = (struct sb_info *)arg;
462    	int reason = 3, c;
463
464    	/*
465     	* SB < 4.0 is half duplex and has only 1 bit for int source,
466     	* so we fake it. SB 4.x (SB16) has the int source in a separate
467     	* register.
468     	* The Vibra16X has separate flags for 8 and 16 bit transfers, but
469     	* I have no idea how to tell capture from playback interrupts...
470     	*/
471    	if (sb->bd_flags & BD_F_SB16) {
472    		c = sb_getmixer(sb, IRQ_STAT);
473    		/* this tells us if the source is 8-bit or 16-bit dma. We
474     		* have to check the io channel to map it to read or write...
475     		*/
476    		reason = 0;
477    		if (c & 1) { /* 8-bit dma */
478			if (sb->pch.fmt & AFMT_U8)
479				reason |= 1;
480			if (sb->rch.fmt & AFMT_U8)
481				reason |= 2;
482    		}
483    		if (c & 2) { /* 16-bit dma */
484			if (sb->pch.fmt & AFMT_S16_LE)
485				reason |= 1;
486			if (sb->rch.fmt & AFMT_S16_LE)
487				reason |= 2;
488    		}
489    	} else c = 1;
490#if 0
491    	printf("sb_intr: reason=%d c=0x%x\n", reason, c);
492#endif
493    	if ((reason & 1) && (sb->pch.buffer->dl > 0))
494		chn_intr(sb->pch.channel);
495    	if ((reason & 2) && (sb->rch.buffer->dl > 0))
496		chn_intr(sb->rch.channel);
497    	if (c & 1)
498		sb_rd(sb, DSP_DATA_AVAIL); /* 8-bit int ack */
499    	if (c & 2)
500		sb_rd(sb, DSP_DATA_AVL16); /* 16-bit int ack */
501}
502
503static int
504sb_speed(struct sb_chinfo *ch)
505{
506    	struct sb_info *sb = ch->parent;
507    	int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
508    	int stereo = (ch->fmt & AFMT_STEREO)? 1 : 0;
509	int speed = ch->spd;
510
511    	if (sb->bd_flags & BD_F_SB16) {
512		RANGE(speed, 5000, 45000);
513		sb_cmd(sb, 0x42 - play);
514    		sb_cmd(sb, speed >> 8);
515		sb_cmd(sb, speed & 0xff);
516    	} else {
517		u_char tconst;
518		int max_speed = 45000, tmp;
519        	u_long flags;
520
521    		/* here enforce speed limitations - max 22050 on sb 1.x*/
522    		if (sb->bd_id <= 0x200)
523			max_speed = 22050;
524
525    		/*
526     	 	* SB models earlier than SB Pro have low limit for the
527     	 	* input rate. Note that this is only for input, but since
528     	 	* we do not support separate values for rec & play....
529     	 	*/
530		if (!play) {
531    			if (sb->bd_id <= 0x200)
532				max_speed = 13000;
533    			else
534				if (sb->bd_id < 0x300)
535					max_speed = 15000;
536		}
537    		RANGE(speed, 4000, max_speed);
538    		if (stereo)
539			speed <<= 1;
540
541    		/*
542     	 	* Now the speed should be valid. Compute the value to be
543     	 	* programmed into the board.
544     	 	*/
545    		if (speed > 22050) { /* High speed mode on 2.01/3.xx */
546			tconst = (u_char)
547				((65536 - ((256000000 + speed / 2) / speed))
548				>> 8);
549			sb->bd_flags |= BD_F_HISPEED;
550			tmp = 65536 - (tconst << 8);
551			speed = (256000000 + tmp / 2) / tmp;
552    		} else {
553			sb->bd_flags &= ~BD_F_HISPEED;
554			tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff;
555			tmp = 256 - tconst;
556			speed = (1000000 + tmp / 2) / tmp;
557    		}
558		flags = spltty();
559		sb_cmd1(sb, 0x40, tconst); /* set time constant */
560		splx(flags);
561    		if (stereo)
562			speed >>= 1;
563    	}
564	ch->spd = speed;
565    	return speed;
566}
567
568static int
569sb_start(struct sb_chinfo *ch)
570{
571	struct sb_info *sb = ch->parent;
572    	int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
573    	int b16 = (ch->fmt & AFMT_S16_LE)? 1 : 0;
574    	int stereo = (ch->fmt & AFMT_STEREO)? 1 : 0;
575	int l = ch->buffer->dl;
576	int dh = ch->buffer->chan > 3;
577	u_char i1, i2;
578
579	if (b16 || dh)
580		l >>= 1;
581	l--;
582
583	if (play)
584		sb_cmd(sb, DSP_CMD_SPKON);
585
586	if (sb->bd_flags & BD_F_SB16) {
587	    	i1 = DSP_F16_AUTO | DSP_F16_FIFO_ON;
588	        i1 |= play? DSP_F16_DAC : DSP_F16_ADC;
589	    	i1 |= (b16 || dh)? DSP_DMA16 : DSP_DMA8;
590	    	i2 = (stereo? DSP_F16_STEREO : 0) | (b16? DSP_F16_SIGNED : 0);
591	    	sb_cmd(sb, i1);
592	    	sb_cmd2(sb, i2, l);
593	} else {
594	    	if (sb->bd_flags & BD_F_HISPEED)
595			i1 = play? 0x90 : 0x98;
596	    	else
597			i1 = play? 0x1c : 0x2c;
598	    	sb_setmixer(sb, 0x0e, stereo? 2 : 0);
599	    	sb_cmd2(sb, 0x48, l);
600       	    	sb_cmd(sb, i1);
601	}
602	sb->bd_flags |= BD_F_DMARUN << b16;
603	return 0;
604}
605
606static int
607sb_stop(struct sb_chinfo *ch)
608{
609	struct sb_info *sb = ch->parent;
610    	int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
611    	int b16 = (ch->fmt & AFMT_S16_LE)? 1 : 0;
612
613    	if (sb->bd_flags & BD_F_HISPEED)
614		sb_reset_dsp(sb);
615	else {
616		sb_cmd(sb, b16? DSP_CMD_DMAPAUSE_16 : DSP_CMD_DMAPAUSE_8);
617	       /*
618		* The above seems to have the undocumented side effect of
619		* blocking the other side as well. If the other
620		* channel was active (SB16) I have to re-enable it :(
621		*/
622		if (sb->bd_flags & (BD_F_DMARUN << (1 - b16)))
623			sb_cmd(sb, b16? 0xd4 : 0xd6 );
624	}
625	if (play)
626		sb_cmd(sb, DSP_CMD_SPKOFF); /* speaker off */
627	sb->bd_flags &= ~(BD_F_DMARUN << b16);
628	return 0;
629}
630
631/* channel interface */
632static void *
633sbchan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
634{
635	struct sb_info *sb = devinfo;
636	struct sb_chinfo *ch = (dir == PCMDIR_PLAY)? &sb->pch : &sb->rch;
637	int dch, dl, dh;
638
639	ch->parent = sb;
640	ch->channel = c;
641	ch->buffer = b;
642	ch->buffer->bufsize = DSP_BUFFSIZE;
643	if (chn_allocbuf(ch->buffer, sb->parent_dmat) == -1)
644		return NULL;
645	dch = (dir == PCMDIR_PLAY)? 1 : 0;
646	if (sb->bd_flags & BD_F_SB16X)
647		dch = !dch;
648	dl = rman_get_start(sb->drq1);
649	dh = sb->drq2? rman_get_start(sb->drq2) : dl;
650	ch->buffer->chan = dch? dh : dl;
651	return ch;
652}
653
654static int
655sbchan_setdir(void *data, int dir)
656{
657	struct sb_chinfo *ch = data;
658
659	ch->dir = dir;
660	return 0;
661}
662
663static int
664sbchan_setformat(void *data, u_int32_t format)
665{
666	struct sb_chinfo *ch = data;
667
668	ch->fmt = format;
669	return 0;
670}
671
672static int
673sbchan_setspeed(void *data, u_int32_t speed)
674{
675	struct sb_chinfo *ch = data;
676
677	ch->spd = speed;
678	return sb_speed(ch);
679}
680
681static int
682sbchan_setblocksize(void *data, u_int32_t blocksize)
683{
684	return blocksize;
685}
686
687static int
688sbchan_trigger(void *data, int go)
689{
690	struct sb_chinfo *ch = data;
691
692	if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
693		return 0;
694
695	buf_isadma(ch->buffer, go);
696	if (go == PCMTRIG_START)
697		sb_start(ch);
698	else
699		sb_stop(ch);
700	return 0;
701}
702
703static int
704sbchan_getptr(void *data)
705{
706	struct sb_chinfo *ch = data;
707
708	return buf_isadmaptr(ch->buffer);
709}
710
711static pcmchan_caps *
712sbchan_getcaps(void *data)
713{
714	struct sb_chinfo *ch = data;
715	int p = (ch->dir == PCMDIR_PLAY)? 1 : 0;
716
717	if (ch->parent->bd_id < 0x300)
718		return p? &sb_playcaps : &sb_reccaps;
719	else if (ch->parent->bd_id < 0x400)
720		return p? &sbpro_playcaps : &sbpro_reccaps;
721	else if (ch->parent->bd_flags & BD_F_SB16X)
722		return &sb16x_caps;
723	else
724		return (ch->buffer->chan >= 4)? &sb16_hcaps : &sb16_lcaps;
725}
726
727/************************************************************/
728
729static int
730sbmix_init(snd_mixer *m)
731{
732    	struct sb_info *sb = mix_getdevinfo(m);
733
734    	switch (sb->bd_flags & BD_F_MIX_MASK) {
735    	case BD_F_MIX_CT1345: /* SB 3.0 has 1345 mixer */
736		mix_setdevs(m, SBPRO_MIXER_DEVICES);
737		mix_setrecdevs(m, SBPRO_RECORDING_DEVICES);
738		sb_setmixer(sb, 0, 1); /* reset mixer */
739		sb_setmixer(sb, MIC_VOL, 0x6); /* mic volume max */
740		sb_setmixer(sb, RECORD_SRC, 0x0); /* mic source */
741		sb_setmixer(sb, FM_VOL, 0x0); /* no midi */
742		break;
743
744    	case BD_F_MIX_CT1745: /* SB16 mixer ... */
745		mix_setdevs(m, SB16_MIXER_DEVICES);
746		mix_setrecdevs(m, SB16_RECORDING_DEVICES);
747		sb_setmixer(sb, 0x3c, 0x1f); /* make all output active */
748		sb_setmixer(sb, 0x3d, 0); /* make all inputs-l off */
749		sb_setmixer(sb, 0x3e, 0); /* make all inputs-r off */
750    	}
751    	return 0;
752}
753
754static int
755sbmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
756{
757    	struct sb_info *sb = mix_getdevinfo(m);
758    	int regoffs;
759    	u_char   val;
760    	mixer_tab *iomap;
761
762    	switch (sb->bd_flags & BD_F_MIX_MASK) {
763    	case BD_F_MIX_CT1345:
764		iomap = &sbpro_mix;
765		break;
766
767    	case BD_F_MIX_CT1745:
768		iomap = &sb16_mix;
769		break;
770
771    	default:
772        	return -1;
773    	}
774
775	/* Change left channel */
776    	regoffs = (*iomap)[dev][LEFT_CHN].regno;
777    	if (regoffs != 0) {
778		val = sb_getmixer(sb, regoffs);
779		change_bits(iomap, &val, dev, LEFT_CHN, left);
780		sb_setmixer(sb, regoffs, val);
781	}
782
783	/* Change right channel */
784	regoffs = (*iomap)[dev][RIGHT_CHN].regno;
785	if (regoffs != 0) {
786		val = sb_getmixer(sb, regoffs); /* Read the new one */
787		change_bits(iomap, &val, dev, RIGHT_CHN, right);
788		sb_setmixer(sb, regoffs, val);
789	} else
790		right = left;
791
792    	return left | (right << 8);
793}
794
795static int
796sbmix_setrecsrc(snd_mixer *m, u_int32_t src)
797{
798    	struct sb_info *sb = mix_getdevinfo(m);
799    	u_char recdev;
800
801    	switch (sb->bd_flags & BD_F_MIX_MASK) {
802    	case BD_F_MIX_CT1345:
803		if      (src == SOUND_MASK_LINE)
804			recdev = 0x06;
805		else if (src == SOUND_MASK_CD)
806			recdev = 0x02;
807		else { /* default: mic */
808	    		src = SOUND_MASK_MIC;
809	    		recdev = 0;
810		}
811		sb_setmixer(sb, RECORD_SRC, recdev |
812			    (sb_getmixer(sb, RECORD_SRC) & ~0x07));
813		break;
814
815    	case BD_F_MIX_CT1745: /* sb16 */
816		recdev = 0;
817		if (src & SOUND_MASK_MIC)
818			recdev |= 0x01; /* mono mic */
819		if (src & SOUND_MASK_CD)
820			recdev |= 0x06; /* l+r cd */
821		if (src & SOUND_MASK_LINE)
822			recdev |= 0x18; /* l+r line */
823		if (src & SOUND_MASK_SYNTH)
824			recdev |= 0x60; /* l+r midi */
825		sb_setmixer(sb, SB16_IMASK_L, recdev);
826		sb_setmixer(sb, SB16_IMASK_R, recdev);
827		/*
828	 	* since the same volume controls apply to the input and
829	 	* output sections, the best approach to have a consistent
830	 	* behaviour among cards would be to disable the output path
831	 	* on devices which are used to record.
832	 	* However, since users like to have feedback, we only disable
833	 	* the mic -- permanently.
834	 	*/
835        	sb_setmixer(sb, SB16_OMASK, 0x1f & ~1);
836		break;
837       	}
838    	return src;
839}
840
841static int
842sbsbc_probe(device_t dev)
843{
844    	char buf[64];
845	uintptr_t func, ver, r, f;
846
847	/* The parent device has already been probed. */
848	r = BUS_READ_IVAR(device_get_parent(dev), dev, 0, &func);
849	if (func != SCF_PCM)
850		return (ENXIO);
851
852	r = BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver);
853	f = (ver & 0xffff0000) >> 16;
854	ver &= 0x0000ffff;
855	if (f & BD_F_ESS)
856		return (ENXIO);
857
858	snprintf(buf, sizeof buf, "SB DSP %d.%02d%s", (int) ver >> 8, (int) ver & 0xff,
859		(f & BD_F_SB16X)? " (ViBRA16X)" : "");
860    	device_set_desc_copy(dev, buf);
861
862	return 0;
863}
864
865static int
866sbsbc_attach(device_t dev)
867{
868    	struct sb_info *sb;
869	uintptr_t ver;
870
871    	sb = (struct sb_info *)malloc(sizeof *sb, M_DEVBUF, M_NOWAIT);
872    	if (!sb)
873		return ENXIO;
874    	bzero(sb, sizeof *sb);
875
876	BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver);
877	sb->bd_id = ver & 0x0000ffff;
878	sb->bd_flags = (ver & 0xffff0000) >> 16;
879
880    	return sb_doattach(dev, sb);
881}
882
883static device_method_t sbsbc_methods[] = {
884	/* Device interface */
885	DEVMETHOD(device_probe,		sbsbc_probe),
886	DEVMETHOD(device_attach,	sbsbc_attach),
887
888	{ 0, 0 }
889};
890
891static driver_t sbsbc_driver = {
892	"pcm",
893	sbsbc_methods,
894	sizeof(snddev_info),
895};
896
897DRIVER_MODULE(sbsbc, sbc, sbsbc_driver, pcm_devclass, 0, 0);
898
899
900
901