sbc.c revision 108064
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 108064 2002-12-18 22:53:24Z semenu $");
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	struct mtx *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), "sound softc");
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	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	{0x46008c0e, "Creative SB AWE64"},		/* CTL0046 */
247
248	{0x01000000, "Avance Logic ALS100+"},		/* @@@0001 - ViBRA16X clone */
249	{0x01100000, "Avance Asound 110"},		/* @@@1001 */
250	{0x01200000, "Avance Logic ALS120"},		/* @@@2001 - ViBRA16X clone */
251
252	{0x81167316, "ESS ES1681"},			/* ESS1681 */
253	{0x02017316, "ESS ES1688"},			/* ESS1688 */
254	{0x68187316, "ESS ES1868"},			/* ESS1868 */
255	{0x03007316, "ESS ES1869"},			/* ESS1869 */
256	{0x69187316, "ESS ES1869"},			/* ESS1869 */
257	{0xabb0110e, "ESS ES1869 (Compaq OEM)"},	/* CPQb0ab */
258	{0xacb0110e, "ESS ES1869 (Compaq OEM)"},	/* CPQb0ac */
259	{0x78187316, "ESS ES1878"},			/* ESS1878 */
260	{0x79187316, "ESS ES1879"},			/* ESS1879 */
261	{0x88187316, "ESS ES1888"},			/* ESS1888 */
262	{0x07017316, "ESS ES1888 (DEC OEM)"},		/* ESS0107 */
263	{0x06017316, "ESS ES1888 (Dell OEM)"},          /* ESS0106 */
264	{0}
265};
266
267static int
268sbc_probe(device_t dev)
269{
270	char *s = NULL;
271	u_int32_t lid, vid;
272
273	lid = isa_get_logicalid(dev);
274	vid = isa_get_vendorid(dev);
275	if (lid) {
276		if (lid == 0x01000000 && vid != 0x01009305) /* ALS0001 */
277			return ENXIO;
278		/* Check pnp ids */
279		return ISA_PNP_PROBE(device_get_parent(dev), dev, sbc_ids);
280	} else {
281		int rid = 0, ver;
282	    	struct resource *io;
283
284#ifdef PC98
285		io = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid,
286					 pcm_iat, 16, RF_ACTIVE);
287#else
288		io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
289		  		    	0, ~0, 16, RF_ACTIVE);
290#endif
291		if (!io) goto bad;
292#ifdef PC98
293		isa_load_resourcev(io, pcm_iat, 16);
294#endif
295    		if (sb_reset_dsp(io)) goto bad2;
296		ver = sb_identify_board(io);
297		if (ver == 0) goto bad2;
298		switch ((ver & 0x00000f00) >> 8) {
299		case 1:
300			device_set_desc(dev, "SoundBlaster 1.0 (not supported)");
301			s = NULL;
302			break;
303
304		case 2:
305			s = "SoundBlaster 2.0";
306			break;
307
308		case 3:
309			s = (ver & 0x0000f000)? "ESS 488" : "SoundBlaster Pro";
310			break;
311
312		case 4:
313			s = "SoundBlaster 16";
314			break;
315
316		case 5:
317			s = (ver & 0x00000008)? "ESS 688" : "ESS 1688";
318			break;
319	     	}
320		if (s) device_set_desc(dev, s);
321bad2:		bus_release_resource(dev, SYS_RES_IOPORT, rid, io);
322bad:		return s? 0 : ENXIO;
323	}
324}
325
326static int
327sbc_attach(device_t dev)
328{
329	char *err = NULL;
330	struct sbc_softc *scp;
331	struct sndcard_func *func;
332	u_int32_t logical_id = isa_get_logicalid(dev);
333    	int flags = device_get_flags(dev);
334	int f, dh, dl, x, irq, i;
335
336    	if (!logical_id && (flags & DV_F_DUAL_DMA)) {
337        	bus_set_resource(dev, SYS_RES_DRQ, 1,
338				 flags & DV_F_DRQ_MASK, 1);
339    	}
340
341	scp = device_get_softc(dev);
342	bzero(scp, sizeof(*scp));
343	scp->dev = dev;
344	sbc_lockinit(scp);
345	err = "alloc_resource";
346	if (alloc_resource(scp)) goto bad;
347
348	err = "sb_reset_dsp";
349	if (sb_reset_dsp(scp->io[0])) goto bad;
350	err = "sb_identify_board";
351	scp->bd_ver = sb_identify_board(scp->io[0]) & 0x00000fff;
352	if (scp->bd_ver == 0) goto bad;
353	f = 0;
354	if (logical_id == 0x01200000 && scp->bd_ver < 0x0400) scp->bd_ver = 0x0499;
355	switch ((scp->bd_ver & 0x0f00) >> 8) {
356    	case 1: /* old sound blaster has nothing... */
357		break;
358
359    	case 2:
360		f |= BD_F_DUP_MIDI;
361		if (scp->bd_ver > 0x200) f |= BD_F_MIX_CT1335;
362		break;
363
364	case 5:
365		f |= BD_F_ESS;
366		scp->bd_ver = 0x0301;
367    	case 3:
368		f |= BD_F_DUP_MIDI | BD_F_MIX_CT1345;
369		break;
370
371    	case 4:
372    		f |= BD_F_SB16 | BD_F_MIX_CT1745;
373		if (scp->drq[0]) dl = rman_get_start(scp->drq[0]); else dl = -1;
374		if (scp->drq[1]) dh = rman_get_start(scp->drq[1]); else dh = dl;
375		if (!logical_id && (dh < dl)) {
376			struct resource *r;
377			r = scp->drq[0];
378			scp->drq[0] = scp->drq[1];
379			scp->drq[1] = r;
380			dl = rman_get_start(scp->drq[0]);
381			dh = rman_get_start(scp->drq[1]);
382		}
383		/* soft irq/dma configuration */
384		x = -1;
385		irq = rman_get_start(scp->irq[0]);
386#ifdef PC98
387		/* SB16 in PC98 use different IRQ table */
388		if	(irq == 3) x = 1;
389		else if (irq == 5) x = 8;
390		else if (irq == 10) x = 2;
391		else if (irq == 12) x = 4;
392		if (x == -1) {
393			err = "bad irq (3/5/10/12 valid)";
394			goto bad;
395		}
396		else sb_setmixer(scp->io[0], IRQ_NR, x);
397		/* SB16 in PC98 use different dma setting */
398		sb_setmixer(scp->io[0], DMA_NR, dh == 0 ? 1 : 2);
399#else
400		if      (irq == 5) x = 2;
401		else if (irq == 7) x = 4;
402		else if (irq == 9) x = 1;
403		else if (irq == 10) x = 8;
404		if (x == -1) {
405			err = "bad irq (5/7/9/10 valid)";
406			goto bad;
407		}
408		else sb_setmixer(scp->io[0], IRQ_NR, x);
409		sb_setmixer(scp->io[0], DMA_NR, (1 << dh) | (1 << dl));
410#endif
411		if (bootverbose) {
412			device_printf(dev, "setting card to irq %d, drq %d", irq, dl);
413			if (dl != dh) printf(", %d", dh);
414			printf("\n");
415    		}
416		break;
417    	}
418
419	switch (logical_id) {
420    	case 0x43008c0e:	/* CTL0043 */
421	case 0x01200000:
422	case 0x01000000:
423		f |= BD_F_SB16X;
424		break;
425	}
426	scp->bd_ver |= f << 16;
427
428	err = "setup_intr";
429	for (i = 0; i < IRQ_MAX; i++) {
430		scp->ihl[i].parent = scp;
431		if (snd_setup_intr(dev, scp->irq[i], INTR_MPSAFE, sbc_intr, &scp->ihl[i], &scp->ih[i]))
432			goto bad;
433	}
434
435	/* PCM Audio */
436	func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO);
437	if (func == NULL) goto bad;
438	func->func = SCF_PCM;
439	scp->child_pcm = device_add_child(dev, "pcm", -1);
440	device_set_ivars(scp->child_pcm, func);
441
442	/* Midi Interface */
443	func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO);
444	if (func == NULL) goto bad;
445	func->func = SCF_MIDI;
446	scp->child_midi1 = device_add_child(dev, "midi", -1);
447	device_set_ivars(scp->child_midi1, func);
448
449	/* OPL FM Synthesizer */
450	func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO);
451	if (func == NULL) goto bad;
452	func->func = SCF_SYNTH;
453	scp->child_midi2 = device_add_child(dev, "midi", -1);
454	device_set_ivars(scp->child_midi2, func);
455
456	/* probe/attach kids */
457	bus_generic_attach(dev);
458
459	return (0);
460
461bad:	if (err) device_printf(dev, "%s\n", err);
462	release_resource(scp);
463	return (ENXIO);
464}
465
466static int
467sbc_detach(device_t dev)
468{
469	struct sbc_softc *scp = device_get_softc(dev);
470
471	sbc_lock(scp);
472	device_delete_child(dev, scp->child_midi2);
473	device_delete_child(dev, scp->child_midi1);
474	device_delete_child(dev, scp->child_pcm);
475	release_resource(scp);
476	sbc_lockdestroy(scp);
477	return bus_generic_detach(dev);
478}
479
480static void
481sbc_intr(void *p)
482{
483	struct sbc_ihl *ihl = p;
484	int i;
485
486	/* sbc_lock(ihl->parent); */
487	i = 0;
488	while (i < INTR_MAX) {
489		if (ihl->intr[i] != NULL) ihl->intr[i](ihl->intr_arg[i]);
490		i++;
491	}
492	/* sbc_unlock(ihl->parent); */
493}
494
495static int
496sbc_setup_intr(device_t dev, device_t child, struct resource *irq,
497   	       int flags, driver_intr_t *intr, void *arg,
498   	       void **cookiep)
499{
500	struct sbc_softc *scp = device_get_softc(dev);
501	struct sbc_ihl *ihl = NULL;
502	int i, ret;
503
504	sbc_lock(scp);
505	i = 0;
506	while (i < IRQ_MAX) {
507		if (irq == scp->irq[i]) ihl = &scp->ihl[i];
508		i++;
509	}
510	ret = 0;
511	if (ihl == NULL) ret = EINVAL;
512	i = 0;
513	while ((ret == 0) && (i < INTR_MAX)) {
514		if (ihl->intr[i] == NULL) {
515			ihl->intr[i] = intr;
516			ihl->intr_arg[i] = arg;
517			*cookiep = &ihl->intr[i];
518			ret = -1;
519		} else i++;
520	}
521	sbc_unlock(scp);
522	return (ret > 0)? EINVAL : 0;
523}
524
525static int
526sbc_teardown_intr(device_t dev, device_t child, struct resource *irq,
527  		  void *cookie)
528{
529	struct sbc_softc *scp = device_get_softc(dev);
530	struct sbc_ihl *ihl = NULL;
531	int i, ret;
532
533	sbc_lock(scp);
534	i = 0;
535	while (i < IRQ_MAX) {
536		if (irq == scp->irq[i]) ihl = &scp->ihl[i];
537		i++;
538	}
539	ret = 0;
540	if (ihl == NULL) ret = EINVAL;
541	i = 0;
542	while ((ret == 0) && (i < INTR_MAX)) {
543		if (cookie == &ihl->intr[i]) {
544			ihl->intr[i] = NULL;
545			ihl->intr_arg[i] = NULL;
546			return 0;
547		} else i++;
548	}
549	sbc_unlock(scp);
550	return (ret > 0)? EINVAL : 0;
551}
552
553static struct resource *
554sbc_alloc_resource(device_t bus, device_t child, int type, int *rid,
555		      u_long start, u_long end, u_long count, u_int flags)
556{
557	struct sbc_softc *scp;
558	int *alloced, rid_max, alloced_max;
559	struct resource **res;
560#ifdef PC98
561	int i;
562#endif
563
564	scp = device_get_softc(bus);
565	switch (type) {
566	case SYS_RES_IOPORT:
567		alloced = scp->io_alloced;
568		res = scp->io;
569#ifdef PC98
570		rid_max = 0;
571		for (i = 0; i < IO_MAX; i++)
572			rid_max += io_range[i];
573#else
574		rid_max = IO_MAX - 1;
575#endif
576		alloced_max = 1;
577		break;
578	case SYS_RES_DRQ:
579		alloced = scp->drq_alloced;
580		res = scp->drq;
581		rid_max = DRQ_MAX - 1;
582		alloced_max = 1;
583		break;
584	case SYS_RES_IRQ:
585		alloced = scp->irq_alloced;
586		res = scp->irq;
587		rid_max = IRQ_MAX - 1;
588		alloced_max = INTR_MAX; /* pcm and mpu may share the irq. */
589		break;
590	default:
591		return (NULL);
592	}
593
594	if (*rid > rid_max || alloced[*rid] == alloced_max)
595		return (NULL);
596
597	alloced[*rid]++;
598	return (res[*rid]);
599}
600
601static int
602sbc_release_resource(device_t bus, device_t child, int type, int rid,
603			struct resource *r)
604{
605	struct sbc_softc *scp;
606	int *alloced, rid_max;
607
608	scp = device_get_softc(bus);
609	switch (type) {
610	case SYS_RES_IOPORT:
611		alloced = scp->io_alloced;
612		rid_max = IO_MAX - 1;
613		break;
614	case SYS_RES_DRQ:
615		alloced = scp->drq_alloced;
616		rid_max = DRQ_MAX - 1;
617		break;
618	case SYS_RES_IRQ:
619		alloced = scp->irq_alloced;
620		rid_max = IRQ_MAX - 1;
621		break;
622	default:
623		return (1);
624	}
625
626	if (rid > rid_max || alloced[rid] == 0)
627		return (1);
628
629	alloced[rid]--;
630	return (0);
631}
632
633static int
634sbc_read_ivar(device_t bus, device_t dev, int index, uintptr_t * result)
635{
636	struct sbc_softc *scp = device_get_softc(bus);
637	struct sndcard_func *func = device_get_ivars(dev);
638
639	switch (index) {
640	case 0:
641		*result = func->func;
642		break;
643
644	case 1:
645		*result = scp->bd_ver;
646	      	break;
647
648	default:
649		return ENOENT;
650	}
651
652	return 0;
653}
654
655static int
656sbc_write_ivar(device_t bus, device_t dev,
657	       int index, uintptr_t value)
658{
659	switch (index) {
660	case 0:
661	case 1:
662  		return EINVAL;
663
664	default:
665		return (ENOENT);
666	}
667}
668
669static int
670alloc_resource(struct sbc_softc *scp)
671{
672	int i;
673
674	for (i = 0 ; i < IO_MAX ; i++) {
675		if (scp->io[i] == NULL) {
676#ifdef PC98
677			scp->io_rid[i] = i > 0 ?
678				scp->io_rid[i - 1] + io_range[i - 1] : 0;
679			scp->io[i] = isa_alloc_resourcev(scp->dev,
680							 SYS_RES_IOPORT,
681							 &scp->io_rid[i],
682							 sb_iat[i],
683							 io_range[i],
684							 RF_ACTIVE);
685			if (scp->io[i] != NULL)
686				isa_load_resourcev(scp->io[i], sb_iat[i],
687						   io_range[i]);
688#else
689			scp->io_rid[i] = i;
690			scp->io[i] = bus_alloc_resource(scp->dev, SYS_RES_IOPORT, &scp->io_rid[i],
691							0, ~0, io_range[i], RF_ACTIVE);
692#endif
693			if (i == 0 && scp->io[i] == NULL)
694				return (1);
695			scp->io_alloced[i] = 0;
696		}
697	}
698	for (i = 0 ; i < DRQ_MAX ; i++) {
699		if (scp->drq[i] == NULL) {
700			scp->drq_rid[i] = i;
701			scp->drq[i] = bus_alloc_resource(scp->dev, SYS_RES_DRQ, &scp->drq_rid[i],
702							 0, ~0, 1, RF_ACTIVE);
703			if (i == 0 && scp->drq[i] == NULL)
704				return (1);
705			scp->drq_alloced[i] = 0;
706		}
707	}
708	for (i = 0 ; i < IRQ_MAX ; i++) {
709	 	if (scp->irq[i] == NULL) {
710			scp->irq_rid[i] = i;
711			scp->irq[i] = bus_alloc_resource(scp->dev, SYS_RES_IRQ, &scp->irq_rid[i],
712							 0, ~0, 1, RF_ACTIVE);
713			if (i == 0 && scp->irq[i] == NULL)
714				return (1);
715			scp->irq_alloced[i] = 0;
716		}
717	}
718	return (0);
719}
720
721static int
722release_resource(struct sbc_softc *scp)
723{
724	int i;
725
726	for (i = 0 ; i < IO_MAX ; i++) {
727		if (scp->io[i] != NULL) {
728			bus_release_resource(scp->dev, SYS_RES_IOPORT, scp->io_rid[i], scp->io[i]);
729			scp->io[i] = NULL;
730		}
731	}
732	for (i = 0 ; i < DRQ_MAX ; i++) {
733		if (scp->drq[i] != NULL) {
734			bus_release_resource(scp->dev, SYS_RES_DRQ, scp->drq_rid[i], scp->drq[i]);
735			scp->drq[i] = NULL;
736		}
737	}
738	for (i = 0 ; i < IRQ_MAX ; i++) {
739		if (scp->irq[i] != NULL) {
740			if (scp->ih[i] != NULL)
741				bus_teardown_intr(scp->dev, scp->irq[i], scp->ih[i]);
742			scp->ih[i] = NULL;
743			bus_release_resource(scp->dev, SYS_RES_IRQ, scp->irq_rid[i], scp->irq[i]);
744			scp->irq[i] = NULL;
745		}
746	}
747	return (0);
748}
749
750static device_method_t sbc_methods[] = {
751	/* Device interface */
752	DEVMETHOD(device_probe,		sbc_probe),
753	DEVMETHOD(device_attach,	sbc_attach),
754	DEVMETHOD(device_detach,	sbc_detach),
755	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
756	DEVMETHOD(device_suspend,	bus_generic_suspend),
757	DEVMETHOD(device_resume,	bus_generic_resume),
758
759	/* Bus interface */
760	DEVMETHOD(bus_read_ivar,	sbc_read_ivar),
761	DEVMETHOD(bus_write_ivar,	sbc_write_ivar),
762	DEVMETHOD(bus_print_child,	bus_generic_print_child),
763	DEVMETHOD(bus_alloc_resource,	sbc_alloc_resource),
764	DEVMETHOD(bus_release_resource,	sbc_release_resource),
765	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
766	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
767	DEVMETHOD(bus_setup_intr,	sbc_setup_intr),
768	DEVMETHOD(bus_teardown_intr,	sbc_teardown_intr),
769
770	{ 0, 0 }
771};
772
773static driver_t sbc_driver = {
774	"sbc",
775	sbc_methods,
776	sizeof(struct sbc_softc),
777};
778
779/* sbc can be attached to an isa bus. */
780DRIVER_MODULE(snd_sbc, isa, sbc_driver, sbc_devclass, 0, 0);
781MODULE_DEPEND(snd_sbc, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER);
782MODULE_VERSION(snd_sbc, 1);
783