sbc.c revision 74763
153553Stanimura/*- 253553Stanimura * Copyright (c) 1999 Seigo Tanimura 353553Stanimura * All rights reserved. 453553Stanimura * 553553Stanimura * Redistribution and use in source and binary forms, with or without 653553Stanimura * modification, are permitted provided that the following conditions 753553Stanimura * are met: 853553Stanimura * 1. Redistributions of source code must retain the above copyright 953553Stanimura * notice, this list of conditions and the following disclaimer. 1053553Stanimura * 2. Redistributions in binary form must reproduce the above copyright 1153553Stanimura * notice, this list of conditions and the following disclaimer in the 1253553Stanimura * documentation and/or other materials provided with the distribution. 1353553Stanimura * 1453553Stanimura * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1553553Stanimura * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1653553Stanimura * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1753553Stanimura * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1853553Stanimura * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1953553Stanimura * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2053553Stanimura * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2153553Stanimura * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2253553Stanimura * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2353553Stanimura * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2453553Stanimura * SUCH DAMAGE. 2553553Stanimura * 2653553Stanimura * $FreeBSD: head/sys/dev/sound/isa/sbc.c 74763 2001-03-24 23:10:29Z cg $ 2753553Stanimura */ 2853553Stanimura 2953553Stanimura#include <dev/sound/chip.h> 3054462Scg#include <dev/sound/pcm/sound.h> 3162483Scg#include <dev/sound/isa/sb.h> 3253553Stanimura 3354824Scg#define IO_MAX 3 3454824Scg#define IRQ_MAX 1 3554824Scg#define DRQ_MAX 2 3654824Scg#define INTR_MAX 2 3754824Scg 3874763Scgstruct sbc_softc; 3974763Scg 4054824Scgstruct sbc_ihl { 4154824Scg driver_intr_t *intr[INTR_MAX]; 4254824Scg void *intr_arg[INTR_MAX]; 4374763Scg struct sbc_softc *parent; 4454824Scg}; 4554824Scg 4653553Stanimura/* Here is the parameter structure per a device. */ 4753553Stanimurastruct sbc_softc { 4853553Stanimura device_t dev; /* device */ 4974395Scg device_t child_pcm, child_midi1, child_midi2; 5054462Scg 5154824Scg int io_rid[IO_MAX]; /* io port rids */ 5254824Scg struct resource *io[IO_MAX]; /* io port resources */ 5354824Scg int io_alloced[IO_MAX]; /* io port alloc flag */ 5454462Scg 5554824Scg int irq_rid[IRQ_MAX]; /* irq rids */ 5654824Scg struct resource *irq[IRQ_MAX]; /* irq resources */ 5754824Scg int irq_alloced[IRQ_MAX]; /* irq alloc flag */ 5854462Scg 5954824Scg int drq_rid[DRQ_MAX]; /* drq rids */ 6054824Scg struct resource *drq[DRQ_MAX]; /* drq resources */ 6154824Scg int drq_alloced[DRQ_MAX]; /* drq alloc flag */ 6254462Scg 6354824Scg struct sbc_ihl ihl[IRQ_MAX]; 6454824Scg 6565644Scg void *ih[IRQ_MAX]; 6654824Scg 6774763Scg void *lock; 6874763Scg 6954462Scg u_int32_t bd_ver; 7053553Stanimura}; 7153553Stanimura 7253553Stanimurastatic int sbc_probe(device_t dev); 7353553Stanimurastatic int sbc_attach(device_t dev); 7454824Scgstatic void sbc_intr(void *p); 7554824Scg 7653553Stanimurastatic struct resource *sbc_alloc_resource(device_t bus, device_t child, int type, int *rid, 7754462Scg u_long start, u_long end, u_long count, u_int flags); 7853553Stanimurastatic int sbc_release_resource(device_t bus, device_t child, int type, int rid, 7954462Scg struct resource *r); 8054824Scgstatic int sbc_setup_intr(device_t dev, device_t child, struct resource *irq, 8154824Scg int flags, driver_intr_t *intr, void *arg, 8254824Scg void **cookiep); 8354824Scgstatic int sbc_teardown_intr(device_t dev, device_t child, struct resource *irq, 8454824Scg void *cookie); 8553553Stanimura 8654462Scgstatic int alloc_resource(struct sbc_softc *scp); 8754462Scgstatic int release_resource(struct sbc_softc *scp); 8853553Stanimura 8953553Stanimurastatic devclass_t sbc_devclass; 9053553Stanimura 9154462Scgstatic int io_range[3] = {0x10, 0x2, 0x4}; 9254462Scg 9360711Snyan#ifdef PC98 /* I/O address table for PC98 */ 9460711Snyanstatic bus_addr_t pcm_iat[] = { 9560711Snyan 0x000, 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 9660711Snyan 0x800, 0x900, 0xa00, 0xb00, 0xc00, 0xd00, 0xe00, 0xf00 9760711Snyan}; 9860711Snyanstatic bus_addr_t midi_iat[] = { 9960711Snyan 0x000, 0x100 10060711Snyan}; 10160711Snyanstatic bus_addr_t opl_iat[] = { 10260711Snyan 0x000, 0x100, 0x200, 0x300 10360711Snyan}; 10460711Snyanstatic bus_addr_t *sb_iat[] = { pcm_iat, midi_iat, opl_iat }; 10560711Snyan#endif 10660711Snyan 10754462Scgstatic int sb_rd(struct resource *io, int reg); 10854462Scgstatic void sb_wr(struct resource *io, int reg, u_int8_t val); 10954462Scgstatic int sb_dspready(struct resource *io); 11054462Scgstatic int sb_cmd(struct resource *io, u_char val); 11154462Scgstatic u_int sb_get_byte(struct resource *io); 11254462Scgstatic void sb_setmixer(struct resource *io, u_int port, u_int value); 11354462Scg 11474763Scgstatic void 11574763Scgsbc_lockinit(struct sbc_softc *scp) 11674763Scg{ 11774763Scg scp->lock = snd_mtxcreate(device_get_nameunit(scp->dev)); 11874763Scg} 11974763Scg 12074763Scgstatic void 12174763Scgsbc_lockdestroy(struct sbc_softc *scp) 12274763Scg{ 12374763Scg snd_mtxfree(scp->lock); 12474763Scg} 12574763Scg 12674763Scgvoid 12774763Scgsbc_lock(struct sbc_softc *scp) 12874763Scg{ 12974763Scg snd_mtxlock(scp->lock); 13074763Scg} 13174763Scg 13274763Scgvoid 13374763Scgsbc_unlock(struct sbc_softc *scp) 13474763Scg{ 13574763Scg snd_mtxunlock(scp->lock); 13674763Scg} 13774763Scg 13854462Scgstatic int 13954462Scgsb_rd(struct resource *io, int reg) 14054462Scg{ 14154462Scg return bus_space_read_1(rman_get_bustag(io), 14254462Scg rman_get_bushandle(io), 14354462Scg reg); 14454462Scg} 14554462Scg 14654462Scgstatic void 14754462Scgsb_wr(struct resource *io, int reg, u_int8_t val) 14854462Scg{ 14954462Scg return bus_space_write_1(rman_get_bustag(io), 15054462Scg rman_get_bushandle(io), 15154462Scg reg, val); 15254462Scg} 15354462Scg 15454462Scgstatic int 15554462Scgsb_dspready(struct resource *io) 15654462Scg{ 15754462Scg return ((sb_rd(io, SBDSP_STATUS) & 0x80) == 0); 15854462Scg} 15954462Scg 16054462Scgstatic int 16154462Scgsb_dspwr(struct resource *io, u_char val) 16254462Scg{ 16354462Scg int i; 16454462Scg 16554462Scg for (i = 0; i < 1000; i++) { 16654462Scg if (sb_dspready(io)) { 16754462Scg sb_wr(io, SBDSP_CMD, val); 16854462Scg return 1; 16954462Scg } 17054462Scg if (i > 10) DELAY((i > 100)? 1000 : 10); 17154462Scg } 17254462Scg printf("sb_dspwr(0x%02x) timed out.\n", val); 17354462Scg return 0; 17454462Scg} 17554462Scg 17654462Scgstatic int 17754462Scgsb_cmd(struct resource *io, u_char val) 17854462Scg{ 17954462Scg return sb_dspwr(io, val); 18054462Scg} 18154462Scg 18254462Scgstatic void 18354462Scgsb_setmixer(struct resource *io, u_int port, u_int value) 18454462Scg{ 18554462Scg u_long flags; 18654462Scg 18754462Scg flags = spltty(); 18854462Scg sb_wr(io, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ 18954462Scg DELAY(10); 19054462Scg sb_wr(io, SB_MIX_DATA, (u_char) (value & 0xff)); 19154462Scg DELAY(10); 19254462Scg splx(flags); 19354462Scg} 19454462Scg 19554462Scgstatic u_int 19654462Scgsb_get_byte(struct resource *io) 19754462Scg{ 19854462Scg int i; 19954462Scg 20054462Scg for (i = 1000; i > 0; i--) { 20154462Scg if (sb_rd(io, DSP_DATA_AVAIL) & 0x80) 20254462Scg return sb_rd(io, DSP_READ); 20354462Scg else 20454462Scg DELAY(20); 20554462Scg } 20654462Scg return 0xffff; 20754462Scg} 20854462Scg 20954462Scgstatic int 21054462Scgsb_reset_dsp(struct resource *io) 21154462Scg{ 21254462Scg sb_wr(io, SBDSP_RST, 3); 21354462Scg DELAY(100); 21454462Scg sb_wr(io, SBDSP_RST, 0); 21554462Scg return (sb_get_byte(io) == 0xAA)? 0 : ENXIO; 21654462Scg} 21754462Scg 21854462Scgstatic int 21954462Scgsb_identify_board(struct resource *io) 22054462Scg{ 22154462Scg int ver, essver, rev; 22254462Scg 22354462Scg sb_cmd(io, DSP_CMD_GETVER); /* Get version */ 22454462Scg ver = (sb_get_byte(io) << 8) | sb_get_byte(io); 22554462Scg if (ver < 0x100 || ver > 0x4ff) return 0; 22654462Scg if (ver == 0x0301) { 22754462Scg /* Try to detect ESS chips. */ 22854462Scg sb_cmd(io, DSP_CMD_GETID); /* Return ident. bytes. */ 22954462Scg essver = (sb_get_byte(io) << 8) | sb_get_byte(io); 23054462Scg rev = essver & 0x000f; 23154462Scg essver &= 0xfff0; 23254462Scg if (essver == 0x4880) ver |= 0x1000; 23354462Scg else if (essver == 0x6880) ver = 0x0500 | rev; 23454462Scg } 23554462Scg return ver; 23654462Scg} 23754462Scg 23854118Stanimurastatic struct isa_pnp_id sbc_ids[] = { 23954961Speter {0x01008c0e, "Creative ViBRA16C"}, /* CTL0001 */ 24054961Speter {0x31008c0e, "Creative SB16/SB32"}, /* CTL0031 */ 24154961Speter {0x41008c0e, "Creative SB16/SB32"}, /* CTL0041 */ 24254961Speter {0x42008c0e, "Creative SB AWE64"}, /* CTL0042 */ 24354961Speter {0x43008c0e, "Creative ViBRA16X"}, /* CTL0043 */ 24454961Speter {0x44008c0e, "Creative SB AWE64 Gold"}, /* CTL0044 */ 24554961Speter {0x45008c0e, "Creative SB AWE64"}, /* CTL0045 */ 24654462Scg 24758385Scg {0x01000000, "Avance Logic ALS100+"}, /* @@@0001 - ViBRA16X clone */ 24854961Speter {0x01100000, "Avance Asound 110"}, /* @@@1001 */ 24958385Scg {0x01200000, "Avance Logic ALS120"}, /* @@@2001 - ViBRA16X clone */ 25054462Scg 25170668Simp {0x81167316, "ESS ES1681"}, /* ESS1681 */ 25256721Sgallatin {0x02017316, "ESS ES1688"}, /* ESS1688 */ 25354961Speter {0x68187316, "ESS ES1868"}, /* ESS1868 */ 25461061Skuriyama {0x03007316, "ESS ES1869"}, /* ESS1869 */ 25554961Speter {0x69187316, "ESS ES1869"}, /* ESS1869 */ 25661569Sbrian {0xabb0110e, "ESS ES1869 (Compaq OEM)"}, /* CPQb0ab */ 25754961Speter {0xacb0110e, "ESS ES1869 (Compaq OEM)"}, /* CPQb0ac */ 25855848Sdeischen {0x78187316, "ESS ES1878"}, /* ESS1878 */ 25954961Speter {0x79187316, "ESS ES1879"}, /* ESS1879 */ 26054961Speter {0x88187316, "ESS ES1888"}, /* ESS1888 */ 26154961Speter {0x07017316, "ESS ES1888 (DEC OEM)"}, /* ESS0107 */ 26264845Scg {0x06017316, "ESS ES1888 (Dell OEM)"}, /* ESS0106 */ 26354118Stanimura {0} 26454118Stanimura}; 26554118Stanimura 26653553Stanimurastatic int 26753553Stanimurasbc_probe(device_t dev) 26853553Stanimura{ 26954462Scg char *s = NULL; 27056774Scg u_int32_t lid, vid; 27156774Scg 27256774Scg lid = isa_get_logicalid(dev); 27356774Scg vid = isa_get_vendorid(dev); 27456774Scg if (lid) { 27556774Scg if (lid == 0x01000000 && vid != 0x01009305) /* ALS0001 */ 27656774Scg return ENXIO; 27754462Scg /* Check pnp ids */ 27854462Scg return ISA_PNP_PROBE(device_get_parent(dev), dev, sbc_ids); 27954462Scg } else { 28054462Scg int rid = 0, ver; 28154462Scg struct resource *io; 28253553Stanimura 28360711Snyan#ifdef PC98 28460711Snyan io = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, 28560711Snyan pcm_iat, 16, RF_ACTIVE); 28660711Snyan#else 28754462Scg io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 28854462Scg 0, ~0, 16, RF_ACTIVE); 28960711Snyan#endif 29054462Scg if (!io) goto bad; 29160711Snyan#ifdef PC98 29260711Snyan isa_load_resourcev(io, pcm_iat, 16); 29360711Snyan#endif 29454462Scg if (sb_reset_dsp(io)) goto bad2; 29554462Scg ver = sb_identify_board(io); 29654462Scg if (ver == 0) goto bad2; 29754462Scg switch ((ver & 0x00000f00) >> 8) { 29854462Scg case 1: 29967651Scg device_set_desc(dev, "SoundBlaster 1.0 (not supported)"); 30067651Scg s = NULL; 30167651Scg break; 30267651Scg 30354462Scg case 2: 30467651Scg s = "SoundBlaster 2.0"; 30554462Scg break; 30654462Scg 30754462Scg case 3: 30867651Scg s = (ver & 0x0000f000)? "ESS 488" : "SoundBlaster Pro"; 30954462Scg break; 31054462Scg 31154462Scg case 4: 31267651Scg s = "SoundBlaster 16"; 31354462Scg break; 31454462Scg 31554462Scg case 5: 31654462Scg s = (ver & 0x00000008)? "ESS 688" : "ESS 1688"; 31754462Scg break; 31854462Scg } 31954462Scg if (s) device_set_desc(dev, s); 32054462Scgbad2: bus_release_resource(dev, SYS_RES_IOPORT, rid, io); 32154462Scgbad: return s? 0 : ENXIO; 32254462Scg } 32353553Stanimura} 32453553Stanimura 32553553Stanimurastatic int 32653553Stanimurasbc_attach(device_t dev) 32753553Stanimura{ 32854791Scg char *err = NULL; 32954462Scg struct sbc_softc *scp; 33054462Scg struct sndcard_func *func; 33154462Scg u_int32_t logical_id = isa_get_logicalid(dev); 33254462Scg int flags = device_get_flags(dev); 33354824Scg int f, dh, dl, x, irq, i; 33453553Stanimura 33554462Scg if (!logical_id && (flags & DV_F_DUAL_DMA)) { 33654462Scg bus_set_resource(dev, SYS_RES_DRQ, 1, 33754462Scg flags & DV_F_DRQ_MASK, 1); 33854462Scg } 33954462Scg 34053553Stanimura scp = device_get_softc(dev); 34153553Stanimura bzero(scp, sizeof(*scp)); 34254462Scg scp->dev = dev; 34374763Scg sbc_lockinit(scp); 34454791Scg err = "alloc_resource"; 34554462Scg if (alloc_resource(scp)) goto bad; 34653553Stanimura 34754791Scg err = "sb_reset_dsp"; 34854462Scg if (sb_reset_dsp(scp->io[0])) goto bad; 34954791Scg err = "sb_identify_board"; 35054462Scg scp->bd_ver = sb_identify_board(scp->io[0]) & 0x00000fff; 35154462Scg if (scp->bd_ver == 0) goto bad; 35254791Scg f = 0; 35358385Scg if (logical_id == 0x01200000 && scp->bd_ver < 0x0400) scp->bd_ver = 0x0499; 35454462Scg switch ((scp->bd_ver & 0x0f00) >> 8) { 35554462Scg case 1: /* old sound blaster has nothing... */ 35654462Scg break; 35754462Scg 35854462Scg case 2: 35954462Scg f |= BD_F_DUP_MIDI; 36054462Scg if (scp->bd_ver > 0x200) f |= BD_F_MIX_CT1335; 36154462Scg break; 36254462Scg 36354462Scg case 5: 36454462Scg f |= BD_F_ESS; 36554462Scg scp->bd_ver = 0x0301; 36654462Scg case 3: 36754462Scg f |= BD_F_DUP_MIDI | BD_F_MIX_CT1345; 36854462Scg break; 36954462Scg 37054462Scg case 4: 37154462Scg f |= BD_F_SB16 | BD_F_MIX_CT1745; 37254791Scg if (scp->drq[0]) dl = rman_get_start(scp->drq[0]); else dl = -1; 37354462Scg if (scp->drq[1]) dh = rman_get_start(scp->drq[1]); else dh = dl; 37454846Scg if (!logical_id && (dh < dl)) { 37554846Scg struct resource *r; 37654846Scg r = scp->drq[0]; 37754846Scg scp->drq[0] = scp->drq[1]; 37854846Scg scp->drq[1] = r; 37954846Scg dl = rman_get_start(scp->drq[0]); 38054846Scg dh = rman_get_start(scp->drq[1]); 38154462Scg } 38254791Scg /* soft irq/dma configuration */ 38354791Scg x = -1; 38454824Scg irq = rman_get_start(scp->irq[0]); 38560711Snyan#ifdef PC98 38660711Snyan /* SB16 in PC98 use different IRQ table */ 38760711Snyan if (irq == 3) x = 1; 38860711Snyan else if (irq == 5) x = 8; 38960711Snyan else if (irq == 10) x = 2; 39060711Snyan else if (irq == 12) x = 4; 39160711Snyan if (x == -1) { 39260711Snyan err = "bad irq (3/5/10/12 valid)"; 39360711Snyan goto bad; 39460711Snyan } 39560711Snyan else sb_setmixer(scp->io[0], IRQ_NR, x); 39660711Snyan /* SB16 in PC98 use different dma setting */ 39760711Snyan sb_setmixer(scp->io[0], DMA_NR, dh == 0 ? 1 : 2); 39860711Snyan#else 39954791Scg if (irq == 5) x = 2; 40054791Scg else if (irq == 7) x = 4; 40154791Scg else if (irq == 9) x = 1; 40254791Scg else if (irq == 10) x = 8; 40354791Scg if (x == -1) { 40454791Scg err = "bad irq (5/7/9/10 valid)"; 40554791Scg goto bad; 40654791Scg } 40754791Scg else sb_setmixer(scp->io[0], IRQ_NR, x); 40854791Scg sb_setmixer(scp->io[0], DMA_NR, (1 << dh) | (1 << dl)); 40960711Snyan#endif 41065644Scg if (bootverbose) { 41165644Scg device_printf(dev, "setting card to irq %d, drq %d", irq, dl); 41265644Scg if (dl != dh) printf(", %d", dh); 41365644Scg printf("\n"); 41465644Scg } 41554462Scg break; 41654462Scg } 41754462Scg 41854462Scg switch (logical_id) { 41954961Speter case 0x43008c0e: /* CTL0043 */ 42058385Scg case 0x01200000: 42158385Scg case 0x01000000: 42254462Scg f |= BD_F_SB16X; 42354462Scg break; 42453553Stanimura } 42554462Scg scp->bd_ver |= f << 16; 42653553Stanimura 42754824Scg err = "setup_intr"; 42854824Scg for (i = 0; i < IRQ_MAX; i++) { 42974763Scg scp->ihl[i].parent = scp; 43074763Scg if (snd_setup_intr(dev, scp->irq[i], INTR_MPSAFE, sbc_intr, &scp->ihl[i], &scp->ih[i])) 43154824Scg goto bad; 43254824Scg } 43354824Scg 43454118Stanimura /* PCM Audio */ 43554118Stanimura func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT); 43654462Scg if (func == NULL) goto bad; 43754118Stanimura bzero(func, sizeof(*func)); 43854118Stanimura func->func = SCF_PCM; 43974395Scg scp->child_pcm = device_add_child(dev, "pcm", -1); 44074395Scg device_set_ivars(scp->child_pcm, func); 44154118Stanimura 44254118Stanimura /* Midi Interface */ 44354118Stanimura func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT); 44454462Scg if (func == NULL) goto bad; 44554118Stanimura bzero(func, sizeof(*func)); 44654118Stanimura func->func = SCF_MIDI; 44774395Scg scp->child_midi1 = device_add_child(dev, "midi", -1); 44874395Scg device_set_ivars(scp->child_midi1, func); 44954118Stanimura 45054118Stanimura /* OPL FM Synthesizer */ 45154118Stanimura func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT); 45254462Scg if (func == NULL) goto bad; 45354118Stanimura bzero(func, sizeof(*func)); 45454118Stanimura func->func = SCF_SYNTH; 45574395Scg scp->child_midi2 = device_add_child(dev, "midi", -1); 45674395Scg device_set_ivars(scp->child_midi2, func); 45754118Stanimura 45854462Scg /* probe/attach kids */ 45953553Stanimura bus_generic_attach(dev); 46053553Stanimura 46153553Stanimura return (0); 46254462Scg 46354791Scgbad: if (err) device_printf(dev, "%s\n", err); 46454791Scg release_resource(scp); 46554462Scg return (ENXIO); 46653553Stanimura} 46753553Stanimura 46865644Scgstatic int 46965644Scgsbc_detach(device_t dev) 47065644Scg{ 47165644Scg struct sbc_softc *scp = device_get_softc(dev); 47265644Scg 47374763Scg sbc_lock(scp); 47474395Scg device_delete_child(dev, scp->child_midi2); 47574395Scg device_delete_child(dev, scp->child_midi1); 47674395Scg device_delete_child(dev, scp->child_pcm); 47765644Scg release_resource(scp); 47874763Scg sbc_lockdestroy(scp); 47965644Scg return bus_generic_detach(dev); 48065644Scg} 48165644Scg 48254824Scgstatic void 48354824Scgsbc_intr(void *p) 48454824Scg{ 48554824Scg struct sbc_ihl *ihl = p; 48654824Scg int i; 48754824Scg 48874763Scg /* sbc_lock(ihl->parent); */ 48954824Scg i = 0; 49054824Scg while (i < INTR_MAX) { 49154824Scg if (ihl->intr[i] != NULL) ihl->intr[i](ihl->intr_arg[i]); 49254824Scg i++; 49354824Scg } 49474763Scg /* sbc_unlock(ihl->parent); */ 49554824Scg} 49654824Scg 49754824Scgstatic int 49854824Scgsbc_setup_intr(device_t dev, device_t child, struct resource *irq, 49954824Scg int flags, driver_intr_t *intr, void *arg, 50054824Scg void **cookiep) 50154824Scg{ 50254824Scg struct sbc_softc *scp = device_get_softc(dev); 50354824Scg struct sbc_ihl *ihl = NULL; 50474763Scg int i, ret; 50554824Scg 50674763Scg sbc_lock(scp); 50754824Scg i = 0; 50854824Scg while (i < IRQ_MAX) { 50954824Scg if (irq == scp->irq[i]) ihl = &scp->ihl[i]; 51054824Scg i++; 51154824Scg } 51274763Scg ret = 0; 51374763Scg if (ihl == NULL) ret = EINVAL; 51454824Scg i = 0; 51574763Scg while ((ret == 0) && (i < INTR_MAX)) { 51654824Scg if (ihl->intr[i] == NULL) { 51754824Scg ihl->intr[i] = intr; 51854824Scg ihl->intr_arg[i] = arg; 51954824Scg *cookiep = &ihl->intr[i]; 52074763Scg ret = -1; 52154824Scg } else i++; 52254824Scg } 52374763Scg sbc_unlock(scp); 52474763Scg return (ret > 0)? EINVAL : 0; 52554824Scg} 52654824Scg 52754824Scgstatic int 52854824Scgsbc_teardown_intr(device_t dev, device_t child, struct resource *irq, 52954824Scg void *cookie) 53054824Scg{ 53154824Scg struct sbc_softc *scp = device_get_softc(dev); 53254824Scg struct sbc_ihl *ihl = NULL; 53374763Scg int i, ret; 53454824Scg 53574763Scg sbc_lock(scp); 53654824Scg i = 0; 53754824Scg while (i < IRQ_MAX) { 53854824Scg if (irq == scp->irq[i]) ihl = &scp->ihl[i]; 53954824Scg i++; 54054824Scg } 54174763Scg ret = 0; 54274763Scg if (ihl == NULL) ret = EINVAL; 54354824Scg i = 0; 54474763Scg while ((ret == 0) && (i < INTR_MAX)) { 54554824Scg if (cookie == &ihl->intr[i]) { 54654824Scg ihl->intr[i] = NULL; 54754824Scg ihl->intr_arg[i] = NULL; 54854824Scg return 0; 54954824Scg } else i++; 55054824Scg } 55174763Scg sbc_unlock(scp); 55274763Scg return (ret > 0)? EINVAL : 0; 55354824Scg} 55454824Scg 55553553Stanimurastatic struct resource * 55653553Stanimurasbc_alloc_resource(device_t bus, device_t child, int type, int *rid, 55753553Stanimura u_long start, u_long end, u_long count, u_int flags) 55853553Stanimura{ 55954462Scg struct sbc_softc *scp; 56053553Stanimura int *alloced, rid_max, alloced_max; 56153553Stanimura struct resource **res; 56260711Snyan#ifdef PC98 56360711Snyan int i; 56460711Snyan#endif 56553553Stanimura 56653553Stanimura scp = device_get_softc(bus); 56753553Stanimura switch (type) { 56853553Stanimura case SYS_RES_IOPORT: 56953553Stanimura alloced = scp->io_alloced; 57053553Stanimura res = scp->io; 57160711Snyan#ifdef PC98 57260711Snyan rid_max = 0; 57360711Snyan for (i = 0; i < IO_MAX; i++) 57460711Snyan rid_max += io_range[i]; 57560711Snyan#else 57654824Scg rid_max = IO_MAX - 1; 57760711Snyan#endif 57853553Stanimura alloced_max = 1; 57953553Stanimura break; 58054462Scg case SYS_RES_DRQ: 58154462Scg alloced = scp->drq_alloced; 58254462Scg res = scp->drq; 58354824Scg rid_max = DRQ_MAX - 1; 58454462Scg alloced_max = 1; 58554462Scg break; 58653553Stanimura case SYS_RES_IRQ: 58754824Scg alloced = scp->irq_alloced; 58854824Scg res = scp->irq; 58954824Scg rid_max = IRQ_MAX - 1; 59054824Scg alloced_max = INTR_MAX; /* pcm and mpu may share the irq. */ 59153553Stanimura break; 59253553Stanimura default: 59353553Stanimura return (NULL); 59453553Stanimura } 59553553Stanimura 59653553Stanimura if (*rid > rid_max || alloced[*rid] == alloced_max) 59753553Stanimura return (NULL); 59853553Stanimura 59953553Stanimura alloced[*rid]++; 60054961Speter return (res[*rid]); 60153553Stanimura} 60253553Stanimura 60353553Stanimurastatic int 60453553Stanimurasbc_release_resource(device_t bus, device_t child, int type, int rid, 60553553Stanimura struct resource *r) 60653553Stanimura{ 60754462Scg struct sbc_softc *scp; 60853553Stanimura int *alloced, rid_max; 60953553Stanimura 61053553Stanimura scp = device_get_softc(bus); 61153553Stanimura switch (type) { 61253553Stanimura case SYS_RES_IOPORT: 61353553Stanimura alloced = scp->io_alloced; 61454824Scg rid_max = IO_MAX - 1; 61553553Stanimura break; 61654462Scg case SYS_RES_DRQ: 61754462Scg alloced = scp->drq_alloced; 61854824Scg rid_max = DRQ_MAX - 1; 61954462Scg break; 62053553Stanimura case SYS_RES_IRQ: 62154824Scg alloced = scp->irq_alloced; 62254824Scg rid_max = IRQ_MAX - 1; 62353553Stanimura break; 62453553Stanimura default: 62553553Stanimura return (1); 62653553Stanimura } 62753553Stanimura 62853553Stanimura if (rid > rid_max || alloced[rid] == 0) 62953553Stanimura return (1); 63053553Stanimura 63153553Stanimura alloced[rid]--; 63253553Stanimura return (0); 63353553Stanimura} 63453553Stanimura 63553553Stanimurastatic int 63654462Scgsbc_read_ivar(device_t bus, device_t dev, int index, uintptr_t * result) 63753553Stanimura{ 63854462Scg struct sbc_softc *scp = device_get_softc(bus); 63954462Scg struct sndcard_func *func = device_get_ivars(dev); 64054462Scg 64154462Scg switch (index) { 64254462Scg case 0: 64354462Scg *result = func->func; 64454462Scg break; 64554462Scg 64654462Scg case 1: 64754462Scg *result = scp->bd_ver; 64854462Scg break; 64954462Scg 65054462Scg default: 65154462Scg return ENOENT; 65254462Scg } 65354462Scg 65454462Scg return 0; 65554462Scg} 65654462Scg 65754462Scgstatic int 65854462Scgsbc_write_ivar(device_t bus, device_t dev, 65954462Scg int index, uintptr_t value) 66054462Scg{ 66154462Scg switch (index) { 66254462Scg case 0: 66354462Scg case 1: 66454462Scg return EINVAL; 66554462Scg 66654462Scg default: 66754462Scg return (ENOENT); 66854462Scg } 66954462Scg} 67054462Scg 67154462Scgstatic int 67254462Scgalloc_resource(struct sbc_softc *scp) 67354462Scg{ 67453553Stanimura int i; 67553553Stanimura 67654824Scg for (i = 0 ; i < IO_MAX ; i++) { 67753553Stanimura if (scp->io[i] == NULL) { 67860711Snyan#ifdef PC98 67960711Snyan scp->io_rid[i] = i > 0 ? 68060711Snyan scp->io_rid[i - 1] + io_range[i - 1] : 0; 68160711Snyan scp->io[i] = isa_alloc_resourcev(scp->dev, 68260711Snyan SYS_RES_IOPORT, 68360711Snyan &scp->io_rid[i], 68460711Snyan sb_iat[i], 68560711Snyan io_range[i], 68660711Snyan RF_ACTIVE); 68760711Snyan if (scp->io[i] != NULL) 68860711Snyan isa_load_resourcev(scp->io[i], sb_iat[i], 68960711Snyan io_range[i]); 69060711Snyan#else 69153553Stanimura scp->io_rid[i] = i; 69253553Stanimura scp->io[i] = bus_alloc_resource(scp->dev, SYS_RES_IOPORT, &scp->io_rid[i], 69353553Stanimura 0, ~0, io_range[i], RF_ACTIVE); 69460711Snyan#endif 69554462Scg if (i == 0 && scp->io[i] == NULL) 69653553Stanimura return (1); 69753553Stanimura scp->io_alloced[i] = 0; 69853553Stanimura } 69953553Stanimura } 70054824Scg for (i = 0 ; i < DRQ_MAX ; i++) { 70153553Stanimura if (scp->drq[i] == NULL) { 70253553Stanimura scp->drq_rid[i] = i; 70353553Stanimura scp->drq[i] = bus_alloc_resource(scp->dev, SYS_RES_DRQ, &scp->drq_rid[i], 70453553Stanimura 0, ~0, 1, RF_ACTIVE); 70554462Scg if (i == 0 && scp->drq[i] == NULL) 70653553Stanimura return (1); 70753553Stanimura scp->drq_alloced[i] = 0; 70853553Stanimura } 70953553Stanimura } 71054824Scg for (i = 0 ; i < IRQ_MAX ; i++) { 71165644Scg if (scp->irq[i] == NULL) { 71254824Scg scp->irq_rid[i] = i; 71354824Scg scp->irq[i] = bus_alloc_resource(scp->dev, SYS_RES_IRQ, &scp->irq_rid[i], 71454824Scg 0, ~0, 1, RF_ACTIVE); 71554824Scg if (i == 0 && scp->irq[i] == NULL) 71654824Scg return (1); 71754824Scg scp->irq_alloced[i] = 0; 71854824Scg } 71954462Scg } 72053553Stanimura return (0); 72153553Stanimura} 72253553Stanimura 72353553Stanimurastatic int 72454462Scgrelease_resource(struct sbc_softc *scp) 72553553Stanimura{ 72653553Stanimura int i; 72753553Stanimura 72854824Scg for (i = 0 ; i < IO_MAX ; i++) { 72953553Stanimura if (scp->io[i] != NULL) { 73053553Stanimura bus_release_resource(scp->dev, SYS_RES_IOPORT, scp->io_rid[i], scp->io[i]); 73153553Stanimura scp->io[i] = NULL; 73253553Stanimura } 73353553Stanimura } 73454824Scg for (i = 0 ; i < DRQ_MAX ; i++) { 73553553Stanimura if (scp->drq[i] != NULL) { 73653553Stanimura bus_release_resource(scp->dev, SYS_RES_DRQ, scp->drq_rid[i], scp->drq[i]); 73753553Stanimura scp->drq[i] = NULL; 73853553Stanimura } 73953553Stanimura } 74054824Scg for (i = 0 ; i < IRQ_MAX ; i++) { 74154824Scg if (scp->irq[i] != NULL) { 74265644Scg if (scp->ih[i] != NULL) 74365644Scg bus_teardown_intr(scp->dev, scp->irq[i], scp->ih[i]); 74465644Scg scp->ih[i] = NULL; 74554824Scg bus_release_resource(scp->dev, SYS_RES_IRQ, scp->irq_rid[i], scp->irq[i]); 74654824Scg scp->irq[i] = NULL; 74754824Scg } 74854824Scg } 74953553Stanimura return (0); 75053553Stanimura} 75153553Stanimura 75253553Stanimurastatic device_method_t sbc_methods[] = { 75353553Stanimura /* Device interface */ 75453553Stanimura DEVMETHOD(device_probe, sbc_probe), 75553553Stanimura DEVMETHOD(device_attach, sbc_attach), 75665644Scg DEVMETHOD(device_detach, sbc_detach), 75753553Stanimura DEVMETHOD(device_shutdown, bus_generic_shutdown), 75853553Stanimura DEVMETHOD(device_suspend, bus_generic_suspend), 75953553Stanimura DEVMETHOD(device_resume, bus_generic_resume), 76053553Stanimura 76153553Stanimura /* Bus interface */ 76254462Scg DEVMETHOD(bus_read_ivar, sbc_read_ivar), 76354462Scg DEVMETHOD(bus_write_ivar, sbc_write_ivar), 76453553Stanimura DEVMETHOD(bus_print_child, bus_generic_print_child), 76553553Stanimura DEVMETHOD(bus_alloc_resource, sbc_alloc_resource), 76653553Stanimura DEVMETHOD(bus_release_resource, sbc_release_resource), 76753553Stanimura DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 76853553Stanimura DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 76954824Scg DEVMETHOD(bus_setup_intr, sbc_setup_intr), 77054824Scg DEVMETHOD(bus_teardown_intr, sbc_teardown_intr), 77153553Stanimura 77253553Stanimura { 0, 0 } 77353553Stanimura}; 77453553Stanimura 77553553Stanimurastatic driver_t sbc_driver = { 77653553Stanimura "sbc", 77753553Stanimura sbc_methods, 77853553Stanimura sizeof(struct sbc_softc), 77953553Stanimura}; 78053553Stanimura 78154462Scg/* sbc can be attached to an isa bus. */ 78262483ScgDRIVER_MODULE(snd_sbc, isa, sbc_driver, sbc_devclass, 0, 0); 78362483ScgMODULE_DEPEND(snd_sbc, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); 78462483ScgMODULE_VERSION(snd_sbc, 1); 785