sbc.c revision 82180
1/*
2 * Copyright (c) 1999 Seigo Tanimura
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
27#include <dev/sound/chip.h>
28#include <dev/sound/pcm/sound.h>
29#include <dev/sound/isa/sb.h>
30
31SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/isa/sbc.c 82180 2001-08-23 11:30:52Z cg $");
32
33#define IO_MAX	3
34#define IRQ_MAX	1
35#define DRQ_MAX	2
36#define INTR_MAX	2
37
38struct sbc_softc;
39
40struct sbc_ihl {
41	driver_intr_t *intr[INTR_MAX];
42	void *intr_arg[INTR_MAX];
43	struct sbc_softc *parent;
44};
45
46/* Here is the parameter structure per a device. */
47struct sbc_softc {
48	device_t dev; /* device */
49	device_t child_pcm, child_midi1, child_midi2;
50
51	int io_rid[IO_MAX]; /* io port rids */
52	struct resource *io[IO_MAX]; /* io port resources */
53	int io_alloced[IO_MAX]; /* io port alloc flag */
54
55	int irq_rid[IRQ_MAX]; /* irq rids */
56	struct resource *irq[IRQ_MAX]; /* irq resources */
57	int irq_alloced[IRQ_MAX]; /* irq alloc flag */
58
59	int drq_rid[DRQ_MAX]; /* drq rids */
60	struct resource *drq[DRQ_MAX]; /* drq resources */
61	int drq_alloced[DRQ_MAX]; /* drq alloc flag */
62
63	struct sbc_ihl ihl[IRQ_MAX];
64
65	void *ih[IRQ_MAX];
66
67	void *lock;
68
69	u_int32_t bd_ver;
70};
71
72static int sbc_probe(device_t dev);
73static int sbc_attach(device_t dev);
74static void sbc_intr(void *p);
75
76static struct resource *sbc_alloc_resource(device_t bus, device_t child, int type, int *rid,
77					   u_long start, u_long end, u_long count, u_int flags);
78static int sbc_release_resource(device_t bus, device_t child, int type, int rid,
79				struct resource *r);
80static int sbc_setup_intr(device_t dev, device_t child, struct resource *irq,
81   	       int flags, driver_intr_t *intr, void *arg,
82   	       void **cookiep);
83static int sbc_teardown_intr(device_t dev, device_t child, struct resource *irq,
84  		  void *cookie);
85
86static int alloc_resource(struct sbc_softc *scp);
87static int release_resource(struct sbc_softc *scp);
88
89static devclass_t sbc_devclass;
90
91static int io_range[3] = {0x10, 0x2, 0x4};
92
93#ifdef PC98 /* I/O address table for PC98 */
94static bus_addr_t pcm_iat[] = {
95	0x000, 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700,
96	0x800, 0x900, 0xa00, 0xb00, 0xc00, 0xd00, 0xe00, 0xf00
97};
98static bus_addr_t midi_iat[] = {
99	0x000, 0x100
100};
101static bus_addr_t opl_iat[] = {
102	0x000, 0x100, 0x200, 0x300
103};
104static bus_addr_t *sb_iat[] = { pcm_iat, midi_iat, opl_iat };
105#endif
106
107static int sb_rd(struct resource *io, int reg);
108static void sb_wr(struct resource *io, int reg, u_int8_t val);
109static int sb_dspready(struct resource *io);
110static int sb_cmd(struct resource *io, u_char val);
111static u_int sb_get_byte(struct resource *io);
112static void sb_setmixer(struct resource *io, u_int port, u_int value);
113
114static void
115sbc_lockinit(struct sbc_softc *scp)
116{
117	scp->lock = snd_mtxcreate(device_get_nameunit(scp->dev));
118}
119
120static void
121sbc_lockdestroy(struct sbc_softc *scp)
122{
123	snd_mtxfree(scp->lock);
124}
125
126void
127sbc_lock(struct sbc_softc *scp)
128{
129	snd_mtxlock(scp->lock);
130}
131
132void
133sbc_unlock(struct sbc_softc *scp)
134{
135	snd_mtxunlock(scp->lock);
136}
137
138static int
139sb_rd(struct resource *io, int reg)
140{
141	return bus_space_read_1(rman_get_bustag(io),
142				rman_get_bushandle(io),
143				reg);
144}
145
146static void
147sb_wr(struct resource *io, int reg, u_int8_t val)
148{
149	return bus_space_write_1(rman_get_bustag(io),
150				 rman_get_bushandle(io),
151				 reg, val);
152}
153
154static int
155sb_dspready(struct resource *io)
156{
157	return ((sb_rd(io, SBDSP_STATUS) & 0x80) == 0);
158}
159
160static int
161sb_dspwr(struct resource *io, u_char val)
162{
163    	int  i;
164
165    	for (i = 0; i < 1000; i++) {
166		if (sb_dspready(io)) {
167	    		sb_wr(io, SBDSP_CMD, val);
168	    		return 1;
169		}
170		if (i > 10) DELAY((i > 100)? 1000 : 10);
171    	}
172    	printf("sb_dspwr(0x%02x) timed out.\n", val);
173    	return 0;
174}
175
176static int
177sb_cmd(struct resource *io, u_char val)
178{
179    	return sb_dspwr(io, val);
180}
181
182static void
183sb_setmixer(struct resource *io, u_int port, u_int value)
184{
185    	u_long   flags;
186
187    	flags = spltty();
188    	sb_wr(io, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
189    	DELAY(10);
190    	sb_wr(io, SB_MIX_DATA, (u_char) (value & 0xff));
191    	DELAY(10);
192    	splx(flags);
193}
194
195static u_int
196sb_get_byte(struct resource *io)
197{
198    	int i;
199
200    	for (i = 1000; i > 0; i--) {
201		if (sb_rd(io, DSP_DATA_AVAIL) & 0x80)
202			return sb_rd(io, DSP_READ);
203		else
204			DELAY(20);
205    	}
206    	return 0xffff;
207}
208
209static int
210sb_reset_dsp(struct resource *io)
211{
212    	sb_wr(io, SBDSP_RST, 3);
213    	DELAY(100);
214    	sb_wr(io, SBDSP_RST, 0);
215    	return (sb_get_byte(io) == 0xAA)? 0 : ENXIO;
216}
217
218static int
219sb_identify_board(struct resource *io)
220{
221	int ver, essver, rev;
222
223    	sb_cmd(io, DSP_CMD_GETVER);	/* Get version */
224    	ver = (sb_get_byte(io) << 8) | sb_get_byte(io);
225	if (ver < 0x100 || ver > 0x4ff) return 0;
226    	if (ver == 0x0301) {
227	    	/* Try to detect ESS chips. */
228	    	sb_cmd(io, DSP_CMD_GETID); /* Return ident. bytes. */
229	    	essver = (sb_get_byte(io) << 8) | sb_get_byte(io);
230	    	rev = essver & 0x000f;
231	    	essver &= 0xfff0;
232	    	if (essver == 0x4880) ver |= 0x1000;
233	    	else if (essver == 0x6880) ver = 0x0500 | rev;
234	}
235	return ver;
236}
237
238static struct isa_pnp_id sbc_ids[] = {
239	{0x01008c0e, "Creative ViBRA16C"},		/* CTL0001 */
240	{0x31008c0e, "Creative SB16/SB32"},		/* CTL0031 */
241	{0x41008c0e, "Creative SB16/SB32"},		/* CTL0041 */
242	{0x42008c0e, "Creative SB AWE64"},		/* CTL0042 */
243	{0x43008c0e, "Creative ViBRA16X"},		/* CTL0043 */
244	{0x44008c0e, "Creative SB AWE64 Gold"},		/* CTL0044 */
245	{0x45008c0e, "Creative SB AWE64"},		/* CTL0045 */
246
247	{0x01000000, "Avance Logic ALS100+"},		/* @@@0001 - ViBRA16X clone */
248	{0x01100000, "Avance Asound 110"},		/* @@@1001 */
249	{0x01200000, "Avance Logic ALS120"},		/* @@@2001 - ViBRA16X clone */
250
251	{0x81167316, "ESS ES1681"},			/* ESS1681 */
252	{0x02017316, "ESS ES1688"},			/* ESS1688 */
253	{0x68187316, "ESS ES1868"},			/* ESS1868 */
254	{0x03007316, "ESS ES1869"},			/* ESS1869 */
255	{0x69187316, "ESS ES1869"},			/* ESS1869 */
256	{0xabb0110e, "ESS ES1869 (Compaq OEM)"},	/* CPQb0ab */
257	{0xacb0110e, "ESS ES1869 (Compaq OEM)"},	/* CPQb0ac */
258	{0x78187316, "ESS ES1878"},			/* ESS1878 */
259	{0x79187316, "ESS ES1879"},			/* ESS1879 */
260	{0x88187316, "ESS ES1888"},			/* ESS1888 */
261	{0x07017316, "ESS ES1888 (DEC OEM)"},		/* ESS0107 */
262	{0x06017316, "ESS ES1888 (Dell OEM)"},          /* ESS0106 */
263	{0}
264};
265
266static int
267sbc_probe(device_t dev)
268{
269	char *s = NULL;
270	u_int32_t lid, vid;
271
272	lid = isa_get_logicalid(dev);
273	vid = isa_get_vendorid(dev);
274	if (lid) {
275		if (lid == 0x01000000 && vid != 0x01009305) /* ALS0001 */
276			return ENXIO;
277		/* Check pnp ids */
278		return ISA_PNP_PROBE(device_get_parent(dev), dev, sbc_ids);
279	} else {
280		int rid = 0, ver;
281	    	struct resource *io;
282
283#ifdef PC98
284		io = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid,
285					 pcm_iat, 16, RF_ACTIVE);
286#else
287		io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
288		  		    	0, ~0, 16, RF_ACTIVE);
289#endif
290		if (!io) goto bad;
291#ifdef PC98
292		isa_load_resourcev(io, pcm_iat, 16);
293#endif
294    		if (sb_reset_dsp(io)) goto bad2;
295		ver = sb_identify_board(io);
296		if (ver == 0) goto bad2;
297		switch ((ver & 0x00000f00) >> 8) {
298		case 1:
299			device_set_desc(dev, "SoundBlaster 1.0 (not supported)");
300			s = NULL;
301			break;
302
303		case 2:
304			s = "SoundBlaster 2.0";
305			break;
306
307		case 3:
308			s = (ver & 0x0000f000)? "ESS 488" : "SoundBlaster Pro";
309			break;
310
311		case 4:
312			s = "SoundBlaster 16";
313			break;
314
315		case 5:
316			s = (ver & 0x00000008)? "ESS 688" : "ESS 1688";
317			break;
318	     	}
319		if (s) device_set_desc(dev, s);
320bad2:		bus_release_resource(dev, SYS_RES_IOPORT, rid, io);
321bad:		return s? 0 : ENXIO;
322	}
323}
324
325static int
326sbc_attach(device_t dev)
327{
328	char *err = NULL;
329	struct sbc_softc *scp;
330	struct sndcard_func *func;
331	u_int32_t logical_id = isa_get_logicalid(dev);
332    	int flags = device_get_flags(dev);
333	int f, dh, dl, x, irq, i;
334
335    	if (!logical_id && (flags & DV_F_DUAL_DMA)) {
336        	bus_set_resource(dev, SYS_RES_DRQ, 1,
337				 flags & DV_F_DRQ_MASK, 1);
338    	}
339
340	scp = device_get_softc(dev);
341	bzero(scp, sizeof(*scp));
342	scp->dev = dev;
343	sbc_lockinit(scp);
344	err = "alloc_resource";
345	if (alloc_resource(scp)) goto bad;
346
347	err = "sb_reset_dsp";
348	if (sb_reset_dsp(scp->io[0])) goto bad;
349	err = "sb_identify_board";
350	scp->bd_ver = sb_identify_board(scp->io[0]) & 0x00000fff;
351	if (scp->bd_ver == 0) goto bad;
352	f = 0;
353	if (logical_id == 0x01200000 && scp->bd_ver < 0x0400) scp->bd_ver = 0x0499;
354	switch ((scp->bd_ver & 0x0f00) >> 8) {
355    	case 1: /* old sound blaster has nothing... */
356		break;
357
358    	case 2:
359		f |= BD_F_DUP_MIDI;
360		if (scp->bd_ver > 0x200) f |= BD_F_MIX_CT1335;
361		break;
362
363	case 5:
364		f |= BD_F_ESS;
365		scp->bd_ver = 0x0301;
366    	case 3:
367		f |= BD_F_DUP_MIDI | BD_F_MIX_CT1345;
368		break;
369
370    	case 4:
371    		f |= BD_F_SB16 | BD_F_MIX_CT1745;
372		if (scp->drq[0]) dl = rman_get_start(scp->drq[0]); else dl = -1;
373		if (scp->drq[1]) dh = rman_get_start(scp->drq[1]); else dh = dl;
374		if (!logical_id && (dh < dl)) {
375			struct resource *r;
376			r = scp->drq[0];
377			scp->drq[0] = scp->drq[1];
378			scp->drq[1] = r;
379			dl = rman_get_start(scp->drq[0]);
380			dh = rman_get_start(scp->drq[1]);
381		}
382		/* soft irq/dma configuration */
383		x = -1;
384		irq = rman_get_start(scp->irq[0]);
385#ifdef PC98
386		/* SB16 in PC98 use different IRQ table */
387		if	(irq == 3) x = 1;
388		else if (irq == 5) x = 8;
389		else if (irq == 10) x = 2;
390		else if (irq == 12) x = 4;
391		if (x == -1) {
392			err = "bad irq (3/5/10/12 valid)";
393			goto bad;
394		}
395		else sb_setmixer(scp->io[0], IRQ_NR, x);
396		/* SB16 in PC98 use different dma setting */
397		sb_setmixer(scp->io[0], DMA_NR, dh == 0 ? 1 : 2);
398#else
399		if      (irq == 5) x = 2;
400		else if (irq == 7) x = 4;
401		else if (irq == 9) x = 1;
402		else if (irq == 10) x = 8;
403		if (x == -1) {
404			err = "bad irq (5/7/9/10 valid)";
405			goto bad;
406		}
407		else sb_setmixer(scp->io[0], IRQ_NR, x);
408		sb_setmixer(scp->io[0], DMA_NR, (1 << dh) | (1 << dl));
409#endif
410		if (bootverbose) {
411			device_printf(dev, "setting card to irq %d, drq %d", irq, dl);
412			if (dl != dh) printf(", %d", dh);
413			printf("\n");
414    		}
415		break;
416    	}
417
418	switch (logical_id) {
419    	case 0x43008c0e:	/* CTL0043 */
420	case 0x01200000:
421	case 0x01000000:
422		f |= BD_F_SB16X;
423		break;
424	}
425	scp->bd_ver |= f << 16;
426
427	err = "setup_intr";
428	for (i = 0; i < IRQ_MAX; i++) {
429		scp->ihl[i].parent = scp;
430		if (snd_setup_intr(dev, scp->irq[i], INTR_MPSAFE, sbc_intr, &scp->ihl[i], &scp->ih[i]))
431			goto bad;
432	}
433
434	/* PCM Audio */
435	func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO);
436	if (func == NULL) goto bad;
437	func->func = SCF_PCM;
438	scp->child_pcm = device_add_child(dev, "pcm", -1);
439	device_set_ivars(scp->child_pcm, func);
440
441	/* Midi Interface */
442	func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO);
443	if (func == NULL) goto bad;
444	func->func = SCF_MIDI;
445	scp->child_midi1 = device_add_child(dev, "midi", -1);
446	device_set_ivars(scp->child_midi1, func);
447
448	/* OPL FM Synthesizer */
449	func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO);
450	if (func == NULL) goto bad;
451	func->func = SCF_SYNTH;
452	scp->child_midi2 = device_add_child(dev, "midi", -1);
453	device_set_ivars(scp->child_midi2, func);
454
455	/* probe/attach kids */
456	bus_generic_attach(dev);
457
458	return (0);
459
460bad:	if (err) device_printf(dev, "%s\n", err);
461	release_resource(scp);
462	return (ENXIO);
463}
464
465static int
466sbc_detach(device_t dev)
467{
468	struct sbc_softc *scp = device_get_softc(dev);
469
470	sbc_lock(scp);
471	device_delete_child(dev, scp->child_midi2);
472	device_delete_child(dev, scp->child_midi1);
473	device_delete_child(dev, scp->child_pcm);
474	release_resource(scp);
475	sbc_lockdestroy(scp);
476	return bus_generic_detach(dev);
477}
478
479static void
480sbc_intr(void *p)
481{
482	struct sbc_ihl *ihl = p;
483	int i;
484
485	/* sbc_lock(ihl->parent); */
486	i = 0;
487	while (i < INTR_MAX) {
488		if (ihl->intr[i] != NULL) ihl->intr[i](ihl->intr_arg[i]);
489		i++;
490	}
491	/* sbc_unlock(ihl->parent); */
492}
493
494static int
495sbc_setup_intr(device_t dev, device_t child, struct resource *irq,
496   	       int flags, driver_intr_t *intr, void *arg,
497   	       void **cookiep)
498{
499	struct sbc_softc *scp = device_get_softc(dev);
500	struct sbc_ihl *ihl = NULL;
501	int i, ret;
502
503	sbc_lock(scp);
504	i = 0;
505	while (i < IRQ_MAX) {
506		if (irq == scp->irq[i]) ihl = &scp->ihl[i];
507		i++;
508	}
509	ret = 0;
510	if (ihl == NULL) ret = EINVAL;
511	i = 0;
512	while ((ret == 0) && (i < INTR_MAX)) {
513		if (ihl->intr[i] == NULL) {
514			ihl->intr[i] = intr;
515			ihl->intr_arg[i] = arg;
516			*cookiep = &ihl->intr[i];
517			ret = -1;
518		} else i++;
519	}
520	sbc_unlock(scp);
521	return (ret > 0)? EINVAL : 0;
522}
523
524static int
525sbc_teardown_intr(device_t dev, device_t child, struct resource *irq,
526  		  void *cookie)
527{
528	struct sbc_softc *scp = device_get_softc(dev);
529	struct sbc_ihl *ihl = NULL;
530	int i, ret;
531
532	sbc_lock(scp);
533	i = 0;
534	while (i < IRQ_MAX) {
535		if (irq == scp->irq[i]) ihl = &scp->ihl[i];
536		i++;
537	}
538	ret = 0;
539	if (ihl == NULL) ret = EINVAL;
540	i = 0;
541	while ((ret == 0) && (i < INTR_MAX)) {
542		if (cookie == &ihl->intr[i]) {
543			ihl->intr[i] = NULL;
544			ihl->intr_arg[i] = NULL;
545			return 0;
546		} else i++;
547	}
548	sbc_unlock(scp);
549	return (ret > 0)? EINVAL : 0;
550}
551
552static struct resource *
553sbc_alloc_resource(device_t bus, device_t child, int type, int *rid,
554		      u_long start, u_long end, u_long count, u_int flags)
555{
556	struct sbc_softc *scp;
557	int *alloced, rid_max, alloced_max;
558	struct resource **res;
559#ifdef PC98
560	int i;
561#endif
562
563	scp = device_get_softc(bus);
564	switch (type) {
565	case SYS_RES_IOPORT:
566		alloced = scp->io_alloced;
567		res = scp->io;
568#ifdef PC98
569		rid_max = 0;
570		for (i = 0; i < IO_MAX; i++)
571			rid_max += io_range[i];
572#else
573		rid_max = IO_MAX - 1;
574#endif
575		alloced_max = 1;
576		break;
577	case SYS_RES_DRQ:
578		alloced = scp->drq_alloced;
579		res = scp->drq;
580		rid_max = DRQ_MAX - 1;
581		alloced_max = 1;
582		break;
583	case SYS_RES_IRQ:
584		alloced = scp->irq_alloced;
585		res = scp->irq;
586		rid_max = IRQ_MAX - 1;
587		alloced_max = INTR_MAX; /* pcm and mpu may share the irq. */
588		break;
589	default:
590		return (NULL);
591	}
592
593	if (*rid > rid_max || alloced[*rid] == alloced_max)
594		return (NULL);
595
596	alloced[*rid]++;
597	return (res[*rid]);
598}
599
600static int
601sbc_release_resource(device_t bus, device_t child, int type, int rid,
602			struct resource *r)
603{
604	struct sbc_softc *scp;
605	int *alloced, rid_max;
606
607	scp = device_get_softc(bus);
608	switch (type) {
609	case SYS_RES_IOPORT:
610		alloced = scp->io_alloced;
611		rid_max = IO_MAX - 1;
612		break;
613	case SYS_RES_DRQ:
614		alloced = scp->drq_alloced;
615		rid_max = DRQ_MAX - 1;
616		break;
617	case SYS_RES_IRQ:
618		alloced = scp->irq_alloced;
619		rid_max = IRQ_MAX - 1;
620		break;
621	default:
622		return (1);
623	}
624
625	if (rid > rid_max || alloced[rid] == 0)
626		return (1);
627
628	alloced[rid]--;
629	return (0);
630}
631
632static int
633sbc_read_ivar(device_t bus, device_t dev, int index, uintptr_t * result)
634{
635	struct sbc_softc *scp = device_get_softc(bus);
636	struct sndcard_func *func = device_get_ivars(dev);
637
638	switch (index) {
639	case 0:
640		*result = func->func;
641		break;
642
643	case 1:
644		*result = scp->bd_ver;
645	      	break;
646
647	default:
648		return ENOENT;
649	}
650
651	return 0;
652}
653
654static int
655sbc_write_ivar(device_t bus, device_t dev,
656	       int index, uintptr_t value)
657{
658	switch (index) {
659	case 0:
660	case 1:
661  		return EINVAL;
662
663	default:
664		return (ENOENT);
665	}
666}
667
668static int
669alloc_resource(struct sbc_softc *scp)
670{
671	int i;
672
673	for (i = 0 ; i < IO_MAX ; i++) {
674		if (scp->io[i] == NULL) {
675#ifdef PC98
676			scp->io_rid[i] = i > 0 ?
677				scp->io_rid[i - 1] + io_range[i - 1] : 0;
678			scp->io[i] = isa_alloc_resourcev(scp->dev,
679							 SYS_RES_IOPORT,
680							 &scp->io_rid[i],
681							 sb_iat[i],
682							 io_range[i],
683							 RF_ACTIVE);
684			if (scp->io[i] != NULL)
685				isa_load_resourcev(scp->io[i], sb_iat[i],
686						   io_range[i]);
687#else
688			scp->io_rid[i] = i;
689			scp->io[i] = bus_alloc_resource(scp->dev, SYS_RES_IOPORT, &scp->io_rid[i],
690							0, ~0, io_range[i], RF_ACTIVE);
691#endif
692			if (i == 0 && scp->io[i] == NULL)
693				return (1);
694			scp->io_alloced[i] = 0;
695		}
696	}
697	for (i = 0 ; i < DRQ_MAX ; i++) {
698		if (scp->drq[i] == NULL) {
699			scp->drq_rid[i] = i;
700			scp->drq[i] = bus_alloc_resource(scp->dev, SYS_RES_DRQ, &scp->drq_rid[i],
701							 0, ~0, 1, RF_ACTIVE);
702			if (i == 0 && scp->drq[i] == NULL)
703				return (1);
704			scp->drq_alloced[i] = 0;
705		}
706	}
707	for (i = 0 ; i < IRQ_MAX ; i++) {
708	 	if (scp->irq[i] == NULL) {
709			scp->irq_rid[i] = i;
710			scp->irq[i] = bus_alloc_resource(scp->dev, SYS_RES_IRQ, &scp->irq_rid[i],
711							 0, ~0, 1, RF_ACTIVE);
712			if (i == 0 && scp->irq[i] == NULL)
713				return (1);
714			scp->irq_alloced[i] = 0;
715		}
716	}
717	return (0);
718}
719
720static int
721release_resource(struct sbc_softc *scp)
722{
723	int i;
724
725	for (i = 0 ; i < IO_MAX ; i++) {
726		if (scp->io[i] != NULL) {
727			bus_release_resource(scp->dev, SYS_RES_IOPORT, scp->io_rid[i], scp->io[i]);
728			scp->io[i] = NULL;
729		}
730	}
731	for (i = 0 ; i < DRQ_MAX ; i++) {
732		if (scp->drq[i] != NULL) {
733			bus_release_resource(scp->dev, SYS_RES_DRQ, scp->drq_rid[i], scp->drq[i]);
734			scp->drq[i] = NULL;
735		}
736	}
737	for (i = 0 ; i < IRQ_MAX ; i++) {
738		if (scp->irq[i] != NULL) {
739			if (scp->ih[i] != NULL)
740				bus_teardown_intr(scp->dev, scp->irq[i], scp->ih[i]);
741			scp->ih[i] = NULL;
742			bus_release_resource(scp->dev, SYS_RES_IRQ, scp->irq_rid[i], scp->irq[i]);
743			scp->irq[i] = NULL;
744		}
745	}
746	return (0);
747}
748
749static device_method_t sbc_methods[] = {
750	/* Device interface */
751	DEVMETHOD(device_probe,		sbc_probe),
752	DEVMETHOD(device_attach,	sbc_attach),
753	DEVMETHOD(device_detach,	sbc_detach),
754	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
755	DEVMETHOD(device_suspend,	bus_generic_suspend),
756	DEVMETHOD(device_resume,	bus_generic_resume),
757
758	/* Bus interface */
759	DEVMETHOD(bus_read_ivar,	sbc_read_ivar),
760	DEVMETHOD(bus_write_ivar,	sbc_write_ivar),
761	DEVMETHOD(bus_print_child,	bus_generic_print_child),
762	DEVMETHOD(bus_alloc_resource,	sbc_alloc_resource),
763	DEVMETHOD(bus_release_resource,	sbc_release_resource),
764	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
765	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
766	DEVMETHOD(bus_setup_intr,	sbc_setup_intr),
767	DEVMETHOD(bus_teardown_intr,	sbc_teardown_intr),
768
769	{ 0, 0 }
770};
771
772static driver_t sbc_driver = {
773	"sbc",
774	sbc_methods,
775	sizeof(struct sbc_softc),
776};
777
778/* sbc can be attached to an isa bus. */
779DRIVER_MODULE(snd_sbc, isa, sbc_driver, sbc_devclass, 0, 0);
780MODULE_DEPEND(snd_sbc, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER);
781MODULE_VERSION(snd_sbc, 1);
782