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