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