sb8.c revision 331722
1/*-
2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
3 * Copyright (c) 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
32#ifdef HAVE_KERNEL_OPTION_HEADERS
33#include "opt_snd.h"
34#endif
35
36#include <dev/sound/pcm/sound.h>
37
38#include  <dev/sound/isa/sb.h>
39#include  <dev/sound/chip.h>
40
41#include <isa/isavar.h>
42
43#include "mixer_if.h"
44
45SND_DECLARE_FILE("$FreeBSD: stable/11/sys/dev/sound/isa/sb8.c 331722 2018-03-29 02:50:57Z eadler $");
46
47#define SB_DEFAULT_BUFSZ	4096
48
49static u_int32_t sb_fmt[] = {
50	SND_FORMAT(AFMT_U8, 1, 0),
51	0
52};
53static struct pcmchan_caps sb200_playcaps = {4000, 23000, sb_fmt, 0};
54static struct pcmchan_caps sb200_reccaps = {4000, 13000, sb_fmt, 0};
55static struct pcmchan_caps sb201_playcaps = {4000, 44100, sb_fmt, 0};
56static struct pcmchan_caps sb201_reccaps = {4000, 15000, sb_fmt, 0};
57
58static u_int32_t sbpro_fmt[] = {
59	SND_FORMAT(AFMT_U8, 1, 0),
60	SND_FORMAT(AFMT_U8, 2, 0),
61	0
62};
63static struct pcmchan_caps sbpro_playcaps = {4000, 44100, sbpro_fmt, 0};
64static struct pcmchan_caps sbpro_reccaps = {4000, 44100, sbpro_fmt, 0};
65
66struct sb_info;
67
68struct sb_chinfo {
69	struct sb_info *parent;
70	struct pcm_channel *channel;
71	struct snd_dbuf *buffer;
72	int dir;
73	u_int32_t fmt, spd, blksz;
74};
75
76struct sb_info {
77	device_t parent_dev;
78    	struct resource *io_base;	/* I/O address for the board */
79    	struct resource *irq;
80   	struct resource *drq;
81    	void *ih;
82    	bus_dma_tag_t parent_dmat;
83
84	unsigned int bufsize;
85    	int bd_id;
86    	u_long bd_flags;       /* board-specific flags */
87    	struct sb_chinfo pch, rch;
88};
89
90static int sb_rd(struct sb_info *sb, int reg);
91static void sb_wr(struct sb_info *sb, int reg, u_int8_t val);
92static int sb_dspready(struct sb_info *sb);
93static int sb_cmd(struct sb_info *sb, u_char val);
94static int sb_cmd1(struct sb_info *sb, u_char cmd, int val);
95static int sb_cmd2(struct sb_info *sb, u_char cmd, int val);
96static u_int sb_get_byte(struct sb_info *sb);
97static void sb_setmixer(struct sb_info *sb, u_int port, u_int value);
98static int sb_getmixer(struct sb_info *sb, u_int port);
99static int sb_reset_dsp(struct sb_info *sb);
100
101static void sb_intr(void *arg);
102static int sb_speed(struct sb_chinfo *ch);
103static int sb_start(struct sb_chinfo *ch);
104static int sb_stop(struct sb_chinfo *ch);
105
106/*
107 * Common code for the midi and pcm functions
108 *
109 * sb_cmd write a single byte to the CMD port.
110 * sb_cmd1 write a CMD + 1 byte arg
111 * sb_cmd2 write a CMD + 2 byte arg
112 * sb_get_byte returns a single byte from the DSP data port
113 */
114
115static void
116sb_lock(struct sb_info *sb) {
117
118	sbc_lock(device_get_softc(sb->parent_dev));
119}
120
121static void
122sb_unlock(struct sb_info *sb) {
123
124	sbc_unlock(device_get_softc(sb->parent_dev));
125}
126
127static int
128port_rd(struct resource *port, int off)
129{
130	return bus_space_read_1(rman_get_bustag(port), rman_get_bushandle(port), off);
131}
132
133static void
134port_wr(struct resource *port, int off, u_int8_t data)
135{
136	bus_space_write_1(rman_get_bustag(port), rman_get_bushandle(port), off, data);
137}
138
139static int
140sb_rd(struct sb_info *sb, int reg)
141{
142	return port_rd(sb->io_base, reg);
143}
144
145static void
146sb_wr(struct sb_info *sb, int reg, u_int8_t val)
147{
148	port_wr(sb->io_base, reg, val);
149}
150
151static int
152sb_dspready(struct sb_info *sb)
153{
154	return ((sb_rd(sb, SBDSP_STATUS) & 0x80) == 0);
155}
156
157static int
158sb_dspwr(struct sb_info *sb, u_char val)
159{
160    	int  i;
161
162    	for (i = 0; i < 1000; i++) {
163		if (sb_dspready(sb)) {
164	    		sb_wr(sb, SBDSP_CMD, val);
165	    		return 1;
166		}
167		if (i > 10) DELAY((i > 100)? 1000 : 10);
168    	}
169    	printf("sb_dspwr(0x%02x) timed out.\n", val);
170    	return 0;
171}
172
173static int
174sb_cmd(struct sb_info *sb, u_char val)
175{
176#if 0
177	printf("sb_cmd: %x\n", val);
178#endif
179    	return sb_dspwr(sb, val);
180}
181
182static int
183sb_cmd1(struct sb_info *sb, u_char cmd, int val)
184{
185#if 0
186    	printf("sb_cmd1: %x, %x\n", cmd, val);
187#endif
188    	if (sb_dspwr(sb, cmd)) {
189		return sb_dspwr(sb, val & 0xff);
190    	} else return 0;
191}
192
193static int
194sb_cmd2(struct sb_info *sb, u_char cmd, int val)
195{
196#if 0
197    	printf("sb_cmd2: %x, %x\n", cmd, val);
198#endif
199    	if (sb_dspwr(sb, cmd)) {
200		return sb_dspwr(sb, val & 0xff) &&
201		       sb_dspwr(sb, (val >> 8) & 0xff);
202    	} else return 0;
203}
204
205/*
206 * in the SB, there is a set of indirect "mixer" registers with
207 * address at offset 4, data at offset 5
208 *
209 * we don't need to interlock these, the mixer lock will suffice.
210 */
211static void
212sb_setmixer(struct sb_info *sb, u_int port, u_int value)
213{
214    	sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
215    	DELAY(10);
216    	sb_wr(sb, SB_MIX_DATA, (u_char) (value & 0xff));
217    	DELAY(10);
218}
219
220static int
221sb_getmixer(struct sb_info *sb, u_int port)
222{
223    	int val;
224
225    	sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
226    	DELAY(10);
227    	val = sb_rd(sb, SB_MIX_DATA);
228    	DELAY(10);
229
230    	return val;
231}
232
233static u_int
234sb_get_byte(struct sb_info *sb)
235{
236    	int i;
237
238    	for (i = 1000; i > 0; i--) {
239		if (sb_rd(sb, DSP_DATA_AVAIL) & 0x80)
240			return sb_rd(sb, DSP_READ);
241		else
242			DELAY(20);
243    	}
244    	return 0xffff;
245}
246
247static int
248sb_reset_dsp(struct sb_info *sb)
249{
250    	sb_wr(sb, SBDSP_RST, 3);
251    	DELAY(100);
252    	sb_wr(sb, SBDSP_RST, 0);
253    	if (sb_get_byte(sb) != 0xAA) {
254        	DEB(printf("sb_reset_dsp 0x%lx failed\n",
255			   rman_get_start(sb->io_base)));
256		return ENXIO;	/* Sorry */
257    	}
258    	return 0;
259}
260
261static void
262sb_release_resources(struct sb_info *sb, device_t dev)
263{
264    	if (sb->irq) {
265    		if (sb->ih)
266			bus_teardown_intr(dev, sb->irq, sb->ih);
267 		bus_release_resource(dev, SYS_RES_IRQ, 0, sb->irq);
268		sb->irq = NULL;
269    	}
270    	if (sb->drq) {
271		isa_dma_release(rman_get_start(sb->drq));
272		bus_release_resource(dev, SYS_RES_DRQ, 0, sb->drq);
273		sb->drq = NULL;
274    	}
275    	if (sb->io_base) {
276		bus_release_resource(dev, SYS_RES_IOPORT, 0, sb->io_base);
277		sb->io_base = NULL;
278    	}
279    	if (sb->parent_dmat) {
280		bus_dma_tag_destroy(sb->parent_dmat);
281		sb->parent_dmat = 0;
282    	}
283     	free(sb, M_DEVBUF);
284}
285
286static int
287sb_alloc_resources(struct sb_info *sb, device_t dev)
288{
289	int rid;
290
291	rid = 0;
292	if (!sb->io_base)
293    		sb->io_base = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
294			&rid, RF_ACTIVE);
295	rid = 0;
296	if (!sb->irq)
297    		sb->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
298			&rid, RF_ACTIVE);
299	rid = 0;
300	if (!sb->drq)
301    		sb->drq = bus_alloc_resource_any(dev, SYS_RES_DRQ,
302			&rid, RF_ACTIVE);
303
304	if (sb->io_base && sb->drq && sb->irq) {
305		isa_dma_acquire(rman_get_start(sb->drq));
306		isa_dmainit(rman_get_start(sb->drq), sb->bufsize);
307
308		return 0;
309	} else return ENXIO;
310}
311
312/************************************************************/
313
314static int
315sbpromix_init(struct snd_mixer *m)
316{
317    	struct sb_info *sb = mix_getdevinfo(m);
318
319	mix_setdevs(m, SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE |
320		       SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_VOLUME);
321
322	mix_setrecdevs(m, SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD);
323
324	sb_setmixer(sb, 0, 1); /* reset mixer */
325
326    	return 0;
327}
328
329static int
330sbpromix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
331{
332    	struct sb_info *sb = mix_getdevinfo(m);
333    	int reg, max;
334    	u_char val;
335
336	max = 7;
337	switch (dev) {
338	case SOUND_MIXER_PCM:
339		reg = 0x04;
340		break;
341
342	case SOUND_MIXER_MIC:
343		reg = 0x0a;
344		max = 3;
345		break;
346
347	case SOUND_MIXER_VOLUME:
348		reg = 0x22;
349		break;
350
351	case SOUND_MIXER_SYNTH:
352		reg = 0x26;
353		break;
354
355	case SOUND_MIXER_CD:
356		reg = 0x28;
357		break;
358
359	case SOUND_MIXER_LINE:
360		reg = 0x2e;
361		break;
362
363	default:
364		return -1;
365	}
366
367	left = (left * max) / 100;
368	right = (dev == SOUND_MIXER_MIC)? left : ((right * max) / 100);
369
370	val = (dev == SOUND_MIXER_MIC)? (left << 1) : (left << 5 | right << 1);
371	sb_setmixer(sb, reg, val);
372
373	left = (left * 100) / max;
374	right = (right * 100) / max;
375
376    	return left | (right << 8);
377}
378
379static u_int32_t
380sbpromix_setrecsrc(struct snd_mixer *m, u_int32_t src)
381{
382    	struct sb_info *sb = mix_getdevinfo(m);
383    	u_char recdev;
384
385	if      (src == SOUND_MASK_LINE)
386		recdev = 0x06;
387	else if (src == SOUND_MASK_CD)
388		recdev = 0x02;
389	else { /* default: mic */
390	    	src = SOUND_MASK_MIC;
391	    	recdev = 0;
392	}
393	sb_setmixer(sb, RECORD_SRC, recdev | (sb_getmixer(sb, RECORD_SRC) & ~0x07));
394
395	return src;
396}
397
398static kobj_method_t sbpromix_mixer_methods[] = {
399    	KOBJMETHOD(mixer_init,		sbpromix_init),
400    	KOBJMETHOD(mixer_set,		sbpromix_set),
401    	KOBJMETHOD(mixer_setrecsrc,	sbpromix_setrecsrc),
402	KOBJMETHOD_END
403};
404MIXER_DECLARE(sbpromix_mixer);
405
406/************************************************************/
407
408static int
409sbmix_init(struct snd_mixer *m)
410{
411    	struct sb_info *sb = mix_getdevinfo(m);
412
413	mix_setdevs(m, SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_CD | SOUND_MASK_VOLUME);
414
415	mix_setrecdevs(m, 0);
416
417	sb_setmixer(sb, 0, 1); /* reset mixer */
418
419    	return 0;
420}
421
422static int
423sbmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
424{
425    	struct sb_info *sb = mix_getdevinfo(m);
426    	int reg, max;
427
428	max = 7;
429	switch (dev) {
430	case SOUND_MIXER_VOLUME:
431		reg = 0x2;
432		break;
433
434	case SOUND_MIXER_SYNTH:
435		reg = 0x6;
436		break;
437
438	case SOUND_MIXER_CD:
439		reg = 0x8;
440		break;
441
442	case SOUND_MIXER_PCM:
443		reg = 0x0a;
444		max = 3;
445		break;
446
447	default:
448		return -1;
449	}
450
451	left = (left * max) / 100;
452
453	sb_setmixer(sb, reg, left << 1);
454
455	left = (left * 100) / max;
456
457    	return left | (left << 8);
458}
459
460static u_int32_t
461sbmix_setrecsrc(struct snd_mixer *m, u_int32_t src)
462{
463	return 0;
464}
465
466static kobj_method_t sbmix_mixer_methods[] = {
467    	KOBJMETHOD(mixer_init,		sbmix_init),
468    	KOBJMETHOD(mixer_set,		sbmix_set),
469    	KOBJMETHOD(mixer_setrecsrc,	sbmix_setrecsrc),
470	KOBJMETHOD_END
471};
472MIXER_DECLARE(sbmix_mixer);
473
474/************************************************************/
475
476static void
477sb_intr(void *arg)
478{
479    	struct sb_info *sb = (struct sb_info *)arg;
480
481	sb_lock(sb);
482    	if (sndbuf_runsz(sb->pch.buffer) > 0) {
483		sb_unlock(sb);
484		chn_intr(sb->pch.channel);
485		sb_lock(sb);
486	}
487
488    	if (sndbuf_runsz(sb->rch.buffer) > 0) {
489		sb_unlock(sb);
490		chn_intr(sb->rch.channel);
491		sb_lock(sb);
492	}
493
494	sb_rd(sb, DSP_DATA_AVAIL); /* int ack */
495	sb_unlock(sb);
496}
497
498static int
499sb_speed(struct sb_chinfo *ch)
500{
501	struct sb_info *sb = ch->parent;
502    	int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
503	int stereo = (AFMT_CHANNEL(ch->fmt) > 1)? 1 : 0;
504	int speed, tmp, thresh, max;
505	u_char tconst;
506
507	if (sb->bd_id >= 0x300) {
508		thresh = stereo? 11025 : 23000;
509		max = stereo? 22050 : 44100;
510	} else if (sb->bd_id > 0x200) {
511		thresh = play? 23000 : 13000;
512		max = play? 44100 : 15000;
513	} else {
514		thresh = 999999;
515		max = play? 23000 : 13000;
516	}
517
518	speed = ch->spd;
519	if (speed > max)
520		speed = max;
521
522	sb_lock(sb);
523	sb->bd_flags &= ~BD_F_HISPEED;
524	if (speed > thresh)
525		sb->bd_flags |= BD_F_HISPEED;
526
527	tmp = 65536 - (256000000 / (speed << stereo));
528	tconst = tmp >> 8;
529
530	sb_cmd1(sb, 0x40, tconst); /* set time constant */
531
532	speed = (256000000 / (65536 - tmp)) >> stereo;
533
534	ch->spd = speed;
535	sb_unlock(sb);
536	return speed;
537}
538
539static int
540sb_start(struct sb_chinfo *ch)
541{
542	struct sb_info *sb = ch->parent;
543    	int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
544    	int stereo = (AFMT_CHANNEL(ch->fmt) > 1)? 1 : 0;
545	int l = ch->blksz;
546	u_char i;
547
548	l--;
549
550	sb_lock(sb);
551	if (play)
552		sb_cmd(sb, DSP_CMD_SPKON);
553
554	if (sb->bd_flags & BD_F_HISPEED)
555		i = play? 0x90 : 0x98;
556	else
557		i = play? 0x1c : 0x2c;
558
559	sb_setmixer(sb, 0x0e, stereo? 2 : 0);
560	sb_cmd2(sb, 0x48, l);
561       	sb_cmd(sb, i);
562
563	sb->bd_flags |= BD_F_DMARUN;
564	sb_unlock(sb);
565	return 0;
566}
567
568static int
569sb_stop(struct sb_chinfo *ch)
570{
571	struct sb_info *sb = ch->parent;
572    	int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
573
574	sb_lock(sb);
575    	if (sb->bd_flags & BD_F_HISPEED)
576		sb_reset_dsp(sb);
577	else {
578#if 0
579		/*
580		 * NOTE: DSP_CMD_DMAEXIT_8 does not work with old
581		 * soundblaster.
582		 */
583		sb_cmd(sb, DSP_CMD_DMAEXIT_8);
584#endif
585		sb_reset_dsp(sb);
586	}
587
588	if (play)
589		sb_cmd(sb, DSP_CMD_SPKOFF); /* speaker off */
590	sb_unlock(sb);
591	sb->bd_flags &= ~BD_F_DMARUN;
592	return 0;
593}
594
595/* channel interface */
596static void *
597sbchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
598{
599	struct sb_info *sb = devinfo;
600	struct sb_chinfo *ch = (dir == PCMDIR_PLAY)? &sb->pch : &sb->rch;
601
602	ch->parent = sb;
603	ch->channel = c;
604	ch->dir = dir;
605	ch->buffer = b;
606	if (sndbuf_alloc(ch->buffer, sb->parent_dmat, 0, sb->bufsize) != 0)
607		return NULL;
608	sndbuf_dmasetup(ch->buffer, sb->drq);
609	return ch;
610}
611
612static int
613sbchan_setformat(kobj_t obj, void *data, u_int32_t format)
614{
615	struct sb_chinfo *ch = data;
616
617	ch->fmt = format;
618	return 0;
619}
620
621static u_int32_t
622sbchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
623{
624	struct sb_chinfo *ch = data;
625
626	ch->spd = speed;
627	return sb_speed(ch);
628}
629
630static u_int32_t
631sbchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
632{
633	struct sb_chinfo *ch = data;
634
635	ch->blksz = blocksize;
636	return ch->blksz;
637}
638
639static int
640sbchan_trigger(kobj_t obj, void *data, int go)
641{
642	struct sb_chinfo *ch = data;
643
644	if (!PCMTRIG_COMMON(go))
645		return 0;
646
647	sndbuf_dma(ch->buffer, go);
648	if (go == PCMTRIG_START)
649		sb_start(ch);
650	else
651		sb_stop(ch);
652	return 0;
653}
654
655static u_int32_t
656sbchan_getptr(kobj_t obj, void *data)
657{
658	struct sb_chinfo *ch = data;
659
660	return sndbuf_dmaptr(ch->buffer);
661}
662
663static struct pcmchan_caps *
664sbchan_getcaps(kobj_t obj, void *data)
665{
666	struct sb_chinfo *ch = data;
667	int p = (ch->dir == PCMDIR_PLAY)? 1 : 0;
668
669	if (ch->parent->bd_id == 0x200)
670		return p? &sb200_playcaps : &sb200_reccaps;
671	if (ch->parent->bd_id < 0x300)
672		return p? &sb201_playcaps : &sb201_reccaps;
673	return p? &sbpro_playcaps : &sbpro_reccaps;
674}
675
676static kobj_method_t sbchan_methods[] = {
677    	KOBJMETHOD(channel_init,		sbchan_init),
678    	KOBJMETHOD(channel_setformat,		sbchan_setformat),
679    	KOBJMETHOD(channel_setspeed,		sbchan_setspeed),
680    	KOBJMETHOD(channel_setblocksize,	sbchan_setblocksize),
681    	KOBJMETHOD(channel_trigger,		sbchan_trigger),
682    	KOBJMETHOD(channel_getptr,		sbchan_getptr),
683    	KOBJMETHOD(channel_getcaps,		sbchan_getcaps),
684	KOBJMETHOD_END
685};
686CHANNEL_DECLARE(sbchan);
687
688/************************************************************/
689
690static int
691sb_probe(device_t dev)
692{
693    	char buf[64];
694	uintptr_t func, ver, r, f;
695
696	/* The parent device has already been probed. */
697	r = BUS_READ_IVAR(device_get_parent(dev), dev, 0, &func);
698	if (func != SCF_PCM)
699		return (ENXIO);
700
701	r = BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver);
702	f = (ver & 0xffff0000) >> 16;
703	ver &= 0x0000ffff;
704	if ((f & BD_F_ESS) || (ver >= 0x400))
705		return (ENXIO);
706
707	snprintf(buf, sizeof buf, "SB DSP %d.%02d", (int) ver >> 8, (int) ver & 0xff);
708
709    	device_set_desc_copy(dev, buf);
710
711	return 0;
712}
713
714static int
715sb_attach(device_t dev)
716{
717    	struct sb_info *sb;
718    	char status[SND_STATUSLEN];
719	uintptr_t ver;
720
721    	sb = malloc(sizeof(*sb), M_DEVBUF, M_WAITOK | M_ZERO);
722	sb->parent_dev = device_get_parent(dev);
723	BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver);
724	sb->bd_id = ver & 0x0000ffff;
725	sb->bd_flags = (ver & 0xffff0000) >> 16;
726	sb->bufsize = pcm_getbuffersize(dev, 4096, SB_DEFAULT_BUFSZ, 65536);
727
728    	if (sb_alloc_resources(sb, dev))
729		goto no;
730    	if (sb_reset_dsp(sb))
731		goto no;
732    	if (mixer_init(dev, (sb->bd_id < 0x300)? &sbmix_mixer_class : &sbpromix_mixer_class, sb))
733		goto no;
734	if (snd_setup_intr(dev, sb->irq, 0, sb_intr, sb, &sb->ih))
735		goto no;
736
737	pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX);
738
739    	if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2,
740			/*boundary*/0,
741			/*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
742			/*highaddr*/BUS_SPACE_MAXADDR,
743			/*filter*/NULL, /*filterarg*/NULL,
744			/*maxsize*/sb->bufsize, /*nsegments*/1,
745			/*maxsegz*/0x3ffff, /*flags*/0,
746			/*lockfunc*/busdma_lock_mutex, /*lockarg*/&Giant,
747			&sb->parent_dmat) != 0) {
748		device_printf(dev, "unable to create dma tag\n");
749		goto no;
750    	}
751
752    	snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd drq %jd bufsz %u %s",
753    	     	rman_get_start(sb->io_base), rman_get_start(sb->irq),
754		rman_get_start(sb->drq), sb->bufsize, PCM_KLDSTRING(snd_sb8));
755
756    	if (pcm_register(dev, sb, 1, 1))
757		goto no;
758	pcm_addchan(dev, PCMDIR_REC, &sbchan_class, sb);
759	pcm_addchan(dev, PCMDIR_PLAY, &sbchan_class, sb);
760
761    	pcm_setstatus(dev, status);
762
763    	return 0;
764
765no:
766    	sb_release_resources(sb, dev);
767    	return ENXIO;
768}
769
770static int
771sb_detach(device_t dev)
772{
773	int r;
774	struct sb_info *sb;
775
776	r = pcm_unregister(dev);
777	if (r)
778		return r;
779
780	sb = pcm_getdevinfo(dev);
781    	sb_release_resources(sb, dev);
782	return 0;
783}
784
785static device_method_t sb_methods[] = {
786	/* Device interface */
787	DEVMETHOD(device_probe,		sb_probe),
788	DEVMETHOD(device_attach,	sb_attach),
789	DEVMETHOD(device_detach,	sb_detach),
790
791	{ 0, 0 }
792};
793
794static driver_t sb_driver = {
795	"pcm",
796	sb_methods,
797	PCM_SOFTC_SIZE,
798};
799
800DRIVER_MODULE(snd_sb8, sbc, sb_driver, pcm_devclass, 0, 0);
801MODULE_DEPEND(snd_sb8, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
802MODULE_DEPEND(snd_sb8, snd_sbc, 1, 1, 1);
803MODULE_VERSION(snd_sb8, 1);
804
805
806
807
808