[BACK]Return to pss.c CVS log [TXT][DIR] Up to [local] / sys / dev / isa

Annotation of sys/dev/isa/pss.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: pss.c,v 1.22 2003/04/27 11:22:53 ho Exp $ */
        !             2: /*     $NetBSD: pss.c,v 1.38 1998/01/12 09:43:44 thorpej Exp $ */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1994 John Brezak
        !             6:  * Copyright (c) 1991-1993 Regents of the University of California.
        !             7:  * All rights reserved.
        !             8:  *
        !             9:  * Redistribution and use in source and binary forms, with or without
        !            10:  * modification, are permitted provided that the following conditions
        !            11:  * are met:
        !            12:  * 1. Redistributions of source code must retain the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer.
        !            14:  * 2. Redistributions in binary form must reproduce the above copyright
        !            15:  *    notice, this list of conditions and the following disclaimer in the
        !            16:  *    documentation and/or other materials provided with the distribution.
        !            17:  * 3. All advertising materials mentioning features or use of this software
        !            18:  *    must display the following acknowledgement:
        !            19:  *     This product includes software developed by the Computer Systems
        !            20:  *     Engineering Group at Lawrence Berkeley Laboratory.
        !            21:  * 4. Neither the name of the University nor of the Laboratory may be used
        !            22:  *    to endorse or promote products derived from this software without
        !            23:  *    specific prior written permission.
        !            24:  *
        !            25:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            26:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            27:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            28:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            29:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            30:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            31:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            32:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            33:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            34:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            35:  * SUCH DAMAGE.
        !            36:  *
        !            37:  */
        !            38:
        !            39: /*
        !            40:  * Copyright (c) 1993 Analog Devices Inc. All rights reserved
        !            41:  *
        !            42:  * Portions provided by Marc.Hoffman@analog.com and
        !            43:  * Greg.Yukna@analog.com .
        !            44:  *
        !            45:  */
        !            46:
        !            47: /*
        !            48:  * Todo:
        !            49:  *     - Provide PSS driver to access DSP
        !            50:  *     - Provide MIDI driver to access MPU
        !            51:  *     - Finish support for CD drive (Sony and SCSI)
        !            52:  */
        !            53:
        !            54: #include <sys/param.h>
        !            55: #include <sys/systm.h>
        !            56: #include <sys/errno.h>
        !            57: #include <sys/ioctl.h>
        !            58: #include <sys/syslog.h>
        !            59: #include <sys/device.h>
        !            60: #include <sys/proc.h>
        !            61: #include <sys/buf.h>
        !            62:
        !            63: #include <machine/cpu.h>
        !            64: #include <machine/intr.h>
        !            65: #include <machine/bus.h>
        !            66:
        !            67: #include <sys/audioio.h>
        !            68: #include <dev/audio_if.h>
        !            69:
        !            70: #include <dev/isa/isavar.h>
        !            71: #include <dev/isa/isadmavar.h>
        !            72:
        !            73: #include <dev/isa/ad1848var.h>
        !            74: #include <dev/isa/wssreg.h>
        !            75: #include <dev/isa/pssreg.h>
        !            76:
        !            77: /* XXX Default WSS base */
        !            78: #define WSS_BASE_ADDRESS 0x0530
        !            79:
        !            80: /*
        !            81:  * Mixer devices
        !            82:  */
        !            83: #define PSS_MIC_IN_LVL         0
        !            84: #define PSS_LINE_IN_LVL                1
        !            85: #define PSS_DAC_LVL            2
        !            86: #define PSS_REC_LVL            3
        !            87: #define PSS_MON_LVL            4
        !            88: #define PSS_MASTER_VOL         5
        !            89: #define PSS_MASTER_TREBLE      6
        !            90: #define PSS_MASTER_BASS                7
        !            91: #define PSS_MIC_IN_MUTE                8
        !            92: #define PSS_LINE_IN_MUTE       9
        !            93: #define PSS_DAC_MUTE           10
        !            94:
        !            95: #define PSS_OUTPUT_MODE                11
        !            96: #define        PSS_SPKR_MONO   0
        !            97: #define        PSS_SPKR_STEREO 1
        !            98: #define        PSS_SPKR_PSEUDO 2
        !            99: #define        PSS_SPKR_SPATIAL 3
        !           100:
        !           101: #define PSS_RECORD_SOURCE      12
        !           102:
        !           103: /* Classes */
        !           104: #define PSS_INPUT_CLASS                13
        !           105: #define PSS_RECORD_CLASS       14
        !           106: #define PSS_MONITOR_CLASS      15
        !           107: #define PSS_OUTPUT_CLASS       16
        !           108:
        !           109:
        !           110: struct pss_softc {
        !           111:        struct  device sc_dev;          /* base device */
        !           112:        void    *sc_ih;                 /* interrupt vectoring */
        !           113:
        !           114:        int     sc_iobase;              /* I/O port base address */
        !           115:        int     sc_drq;                 /* dma channel */
        !           116:
        !           117:        struct  ad1848_softc *ad1848_sc;
        !           118:
        !           119:        int     out_port;
        !           120:
        !           121:        struct  ad1848_volume master_volume;
        !           122:        int     master_mode;
        !           123:
        !           124:        int     monitor_treble;
        !           125:        int     monitor_bass;
        !           126:
        !           127:        int     mic_mute, cd_mute, dac_mute;
        !           128: };
        !           129:
        !           130: #ifdef notyet
        !           131: struct mpu_softc {
        !           132:        struct  device sc_dev;          /* base device */
        !           133:        void    *sc_ih;                 /* interrupt vectoring */
        !           134:
        !           135:        int     sc_iobase;              /* MIDI I/O port base address */
        !           136:        int     sc_irq;                 /* MIDI interrupt */
        !           137: };
        !           138:
        !           139: struct pcd_softc {
        !           140:        struct  device sc_dev;          /* base device */
        !           141:        void    *sc_ih;                 /* interrupt vectoring */
        !           142:
        !           143:        int     sc_iobase;              /* CD I/O port base address */
        !           144:        int     sc_irq;                 /* CD interrupt */
        !           145: };
        !           146: #endif
        !           147:
        !           148: #ifdef AUDIO_DEBUG
        !           149: #define DPRINTF(x)     if (pssdebug) printf x
        !           150: int    pssdebug = 0;
        !           151: #else
        !           152: #define DPRINTF(x)
        !           153: #endif
        !           154:
        !           155: int    pssprobe(struct device *, void *, void *);
        !           156: void   pssattach(struct device *, struct device *, void *);
        !           157:
        !           158: int    spprobe(struct device *, void *, void *);
        !           159: void   spattach(struct device *, struct device *, void *);
        !           160:
        !           161: #ifdef notyet
        !           162: int    mpuprobe(struct device *, void *, void *);
        !           163: void   mpuattach(struct device *, struct device *, void *);
        !           164:
        !           165: int    pcdprobe(struct device *, void *, void *);
        !           166: void   pcdattach(struct device *, struct device *, void *);
        !           167: #endif
        !           168:
        !           169: int    pssintr(void *);
        !           170: #ifdef notyet
        !           171: int    mpuintr(void *);
        !           172: #endif
        !           173:
        !           174: int    pss_speaker_ctl(void *, int);
        !           175:
        !           176: int    pss_getdev(void *, struct audio_device *);
        !           177:
        !           178: int    pss_mixer_set_port(void *, mixer_ctrl_t *);
        !           179: int    pss_mixer_get_port(void *, mixer_ctrl_t *);
        !           180: int    pss_query_devinfo(void *, mixer_devinfo_t *);
        !           181:
        !           182: #ifdef PSS_DSP
        !           183: void   pss_dspwrite(struct pss_softc *, int);
        !           184: #endif
        !           185: void   pss_setaddr(int, int);
        !           186: int    pss_setint(int, int);
        !           187: int    pss_setdma(int, int);
        !           188: int    pss_testirq(struct pss_softc *, int);
        !           189: int    pss_testdma(struct pss_softc *, int);
        !           190: #ifdef notyet
        !           191: int    pss_reset_dsp(struct pss_softc *);
        !           192: int    pss_download_dsp(struct pss_softc *, u_char *, int);
        !           193: #endif
        !           194: #ifdef AUDIO_DEBUG
        !           195: void   pss_dump_regs(struct pss_softc *);
        !           196: #endif
        !           197: int    pss_set_master_gain(struct pss_softc *, struct ad1848_volume *);
        !           198: int    pss_set_master_mode(struct pss_softc *, int);
        !           199: int    pss_set_treble(struct pss_softc *, u_int);
        !           200: int    pss_set_bass(struct pss_softc *, u_int);
        !           201: int    pss_get_master_gain(struct pss_softc *, struct ad1848_volume *);
        !           202: int    pss_get_master_mode(struct pss_softc *, u_int *);
        !           203: int    pss_get_treble(struct pss_softc *, u_char *);
        !           204: int    pss_get_bass(struct pss_softc *, u_char *);
        !           205:
        !           206: #ifdef AUDIO_DEBUG
        !           207: void   wss_dump_regs(struct ad1848_softc *);
        !           208: #endif
        !           209:
        !           210: /*
        !           211:  * Define our interface to the higher level audio driver.
        !           212:  */
        !           213:
        !           214: struct audio_hw_if pss_audio_if = {
        !           215:        ad1848_open,
        !           216:        ad1848_close,
        !           217:        NULL,
        !           218:        ad1848_query_encoding,
        !           219:        ad1848_set_params,
        !           220:        ad1848_round_blocksize,
        !           221:        ad1848_commit_settings,
        !           222:        ad1848_dma_init_output,
        !           223:        ad1848_dma_init_input,
        !           224:        ad1848_dma_output,
        !           225:        ad1848_dma_input,
        !           226:        ad1848_halt_out_dma,
        !           227:        ad1848_halt_in_dma,
        !           228:        pss_speaker_ctl,
        !           229:        pss_getdev,
        !           230:        NULL,
        !           231:        pss_mixer_set_port,
        !           232:        pss_mixer_get_port,
        !           233:        pss_query_devinfo,
        !           234:        ad1848_malloc,
        !           235:        ad1848_free,
        !           236:        ad1848_round,
        !           237:        ad1848_mappage,
        !           238:        ad1848_get_props,
        !           239:        NULL,
        !           240:        NULL
        !           241: };
        !           242:
        !           243:
        !           244: /* Interrupt translation for WSS config */
        !           245: static u_char wss_interrupt_bits[16] = {
        !           246:     0xff, 0xff, 0xff, 0xff,
        !           247:     0xff, 0xff, 0xff, 0x08,
        !           248:     0xff, 0x10, 0x18, 0x20,
        !           249:     0xff, 0xff, 0xff, 0xff
        !           250: };
        !           251: /* ditto for WSS DMA channel */
        !           252: static u_char wss_dma_bits[4] = {1, 2, 0, 3};
        !           253:
        !           254: struct cfattach pss_ca = {
        !           255:        sizeof(struct pss_softc), pssprobe, pssattach
        !           256: };
        !           257:
        !           258: struct cfdriver pss_cd = {
        !           259:        NULL, "pss", DV_DULL, 1
        !           260: };
        !           261:
        !           262: struct cfattach sp_ca = {
        !           263:        sizeof(struct ad1848_softc), spprobe, spattach
        !           264: };
        !           265:
        !           266: struct cfdriver sp_cd = {
        !           267:        NULL, "sp", DV_DULL
        !           268: };
        !           269:
        !           270: #ifdef notyet
        !           271: struct cfattach mpu_ca = {
        !           272:        sizeof(struct mpu_softc), mpuprobe, mpuattach
        !           273: };
        !           274:
        !           275: struct cfdriver mpu_cd = {
        !           276:        NULL, "mpu", DV_DULL
        !           277: };
        !           278:
        !           279: struct cfattach pcd_ca = {
        !           280:        sizeof(struct pcd_softc), pcdprobe, pcdattach
        !           281: };
        !           282:
        !           283: struct cfdriver pcd_cd = {
        !           284:        NULL, "pcd", DV_DULL
        !           285: };
        !           286: #endif
        !           287:
        !           288: struct audio_device pss_device = {
        !           289:        "pss,ad1848",
        !           290:        "",
        !           291:        "PSS"
        !           292: };
        !           293:
        !           294: #ifdef PSS_DSP
        !           295: void
        !           296: pss_dspwrite(sc, data)
        !           297:        struct pss_softc *sc;
        !           298:        int data;
        !           299: {
        !           300:     int i;
        !           301:     int pss_base = sc->sc_iobase;
        !           302:
        !           303:     /*
        !           304:      * Note! the i<5000000 is an emergency exit. The dsp_command() is sometimes
        !           305:      * called while interrupts are disabled. This means that the timer is
        !           306:      * disabled also. However the timeout situation is a abnormal condition.
        !           307:      * Normally the DSP should be ready to accept commands after just couple of
        !           308:      * loops.
        !           309:      */
        !           310:     for (i = 0; i < 5000000; i++) {
        !           311:        if (inw(pss_base+PSS_STATUS) & PSS_WRITE_EMPTY) {
        !           312:            outw(pss_base+PSS_DATA, data);
        !           313:            return;
        !           314:        }
        !           315:     }
        !           316:     printf ("pss: DSP Command (%04x) Timeout.\n", data);
        !           317: }
        !           318: #endif /* PSS_DSP */
        !           319:
        !           320: void
        !           321: pss_setaddr(addr, configAddr)
        !           322:        int addr;
        !           323:        int configAddr;
        !           324: {
        !           325:     int val;
        !           326:
        !           327:     val = inw(configAddr);
        !           328:     val &= ADDR_MASK;
        !           329:     val |= (addr << 4);
        !           330:     outw(configAddr,val);
        !           331: }
        !           332:
        !           333: /* pss_setint
        !           334:  * This function sets the correct bits in the
        !           335:  * configuration register to
        !           336:  * enable the chosen interrupt.
        !           337:  */
        !           338: int
        !           339: pss_setint(intNum, configAddress)
        !           340:        int intNum;
        !           341:        int configAddress;
        !           342: {
        !           343:     int val;
        !           344:
        !           345:     switch(intNum) {
        !           346:     case 3:
        !           347:        val = inw(configAddress);
        !           348:        val &= INT_MASK;
        !           349:        val |= INT_3_BITS;
        !           350:        break;
        !           351:     case 5:
        !           352:        val = inw(configAddress);
        !           353:        val &= INT_MASK;
        !           354:        val |= INT_5_BITS;
        !           355:        break;
        !           356:     case 7:
        !           357:        val = inw(configAddress);
        !           358:        val &= INT_MASK;
        !           359:        val |= INT_7_BITS;
        !           360:        break;
        !           361:     case 9:
        !           362:        val = inw(configAddress);
        !           363:        val &= INT_MASK;
        !           364:        val |= INT_9_BITS;
        !           365:        break;
        !           366:     case 10:
        !           367:        val = inw(configAddress);
        !           368:        val &= INT_MASK;
        !           369:        val |= INT_10_BITS;
        !           370:        break;
        !           371:     case 11:
        !           372:        val = inw(configAddress);
        !           373:        val &= INT_MASK;
        !           374:        val |= INT_11_BITS;
        !           375:        break;
        !           376:     case 12:
        !           377:        val = inw(configAddress);
        !           378:        val &= INT_MASK;
        !           379:        val |= INT_12_BITS;
        !           380:        break;
        !           381:     default:
        !           382:        DPRINTF(("pss_setint: invalid irq (%d)\n", intNum));
        !           383:        return 1;
        !           384:     }
        !           385:     outw(configAddress,val);
        !           386:     return 0;
        !           387: }
        !           388:
        !           389: int
        !           390: pss_setdma(dmaNum, configAddress)
        !           391:        int dmaNum;
        !           392:        int configAddress;
        !           393: {
        !           394:     int val;
        !           395:
        !           396:     switch(dmaNum) {
        !           397:     case 0:
        !           398:        val = inw(configAddress);
        !           399:        val &= DMA_MASK;
        !           400:        val |= DMA_0_BITS;
        !           401:        break;
        !           402:     case 1:
        !           403:        val = inw(configAddress);
        !           404:        val &= DMA_MASK;
        !           405:        val |= DMA_1_BITS;
        !           406:        break;
        !           407:     case 3:
        !           408:        val = inw(configAddress);
        !           409:        val &= DMA_MASK;
        !           410:        val |= DMA_3_BITS;
        !           411:        break;
        !           412:     case 5:
        !           413:        val = inw(configAddress);
        !           414:        val &= DMA_MASK;
        !           415:        val |= DMA_5_BITS;
        !           416:        break;
        !           417:     case 6:
        !           418:        val = inw(configAddress);
        !           419:        val &= DMA_MASK;
        !           420:        val |= DMA_6_BITS;
        !           421:        break;
        !           422:     case 7:
        !           423:        val = inw(configAddress);
        !           424:        val &= DMA_MASK;
        !           425:        val |= DMA_7_BITS;
        !           426:        break;
        !           427:     default:
        !           428:        DPRINTF(("pss_setdma: invalid drq (%d)\n", dmaNum));
        !           429:        return 1;
        !           430:     }
        !           431:     outw(configAddress, val);
        !           432:     return 0;
        !           433: }
        !           434:
        !           435: /*
        !           436:  * This function tests an interrupt number to see if
        !           437:  * it is available. It takes the interrupt button
        !           438:  * as its argument and returns TRUE if the interrupt
        !           439:  * is ok.
        !           440: */
        !           441: int
        !           442: pss_testirq(struct pss_softc *sc, int intNum)
        !           443: {
        !           444:     int config = sc->sc_iobase + PSS_CONFIG;
        !           445:     int val;
        !           446:     int ret;
        !           447:     int i;
        !           448:
        !           449:     /* Set the interrupt bits */
        !           450:     switch(intNum) {
        !           451:     case 3:
        !           452:        val = inw(config);
        !           453:        val &= INT_MASK;        /* Special: 0 */
        !           454:        break;
        !           455:     case 5:
        !           456:        val = inw(config);
        !           457:        val &= INT_MASK;
        !           458:        val |= INT_TEST_BIT | INT_5_BITS;
        !           459:        break;
        !           460:     case 7:
        !           461:        val = inw(config);
        !           462:        val &= INT_MASK;
        !           463:        val |= INT_TEST_BIT | INT_7_BITS;
        !           464:        break;
        !           465:     case 9:
        !           466:        val = inw(config);
        !           467:        val &= INT_MASK;
        !           468:        val |= INT_TEST_BIT | INT_9_BITS;
        !           469:        break;
        !           470:     case 10:
        !           471:        val = inw(config);
        !           472:        val &= INT_MASK;
        !           473:        val |= INT_TEST_BIT | INT_10_BITS;
        !           474:        break;
        !           475:     case 11:
        !           476:        val = inw(config);
        !           477:        val &= INT_MASK;
        !           478:        val |= INT_TEST_BIT | INT_11_BITS;
        !           479:        break;
        !           480:     case 12:
        !           481:        val = inw(config);
        !           482:        val &= INT_MASK;
        !           483:        val |= INT_TEST_BIT | INT_12_BITS;
        !           484:        break;
        !           485:     default:
        !           486:        DPRINTF(("pss_testirq: invalid irq (%d)\n", intNum));
        !           487:        return 0;
        !           488:     }
        !           489:     outw(config, val);
        !           490:
        !           491:     /* Check if the interrupt is in use */
        !           492:     /* Do it a few times in case there is a delay */
        !           493:     ret = 0;
        !           494:     for (i = 0; i < 5; i++) {
        !           495:        val = inw(config);
        !           496:        if (val & INT_TEST_PASS) {
        !           497:            ret = 1;
        !           498:            break;
        !           499:        }
        !           500:     }
        !           501:
        !           502:     /* Clear the Test bit and the interrupt bits */
        !           503:     val = inw(config);
        !           504:     val &= INT_TEST_BIT_MASK & INT_MASK;
        !           505:     outw(config, val);
        !           506:     return(ret);
        !           507: }
        !           508:
        !           509: /*
        !           510:  * This function tests a dma channel to see if
        !           511:  * it is available. It takes the DMA channel button
        !           512:  * as its argument and returns TRUE if the channel
        !           513:  * is ok.
        !           514:  */
        !           515: int
        !           516: pss_testdma(sc, dmaNum)
        !           517:        struct pss_softc *sc;
        !           518:        int dmaNum;
        !           519: {
        !           520:     int config = sc->sc_iobase + PSS_CONFIG;
        !           521:     int val;
        !           522:     int i, ret;
        !           523:
        !           524:     switch (dmaNum) {
        !           525:     case 0:
        !           526:        val = inw(config);
        !           527:        val &= DMA_MASK;
        !           528:        val |= DMA_TEST_BIT | DMA_0_BITS;
        !           529:        break;
        !           530:     case 1:
        !           531:        val = inw(config);
        !           532:        val &= DMA_MASK;
        !           533:        val |= DMA_TEST_BIT | DMA_1_BITS;
        !           534:        break;
        !           535:     case 3:
        !           536:        val = inw(config);
        !           537:        val &= DMA_MASK;
        !           538:        val |= DMA_TEST_BIT | DMA_3_BITS;
        !           539:        break;
        !           540:     case 5:
        !           541:        val = inw(config);
        !           542:        val &= DMA_MASK;
        !           543:        val |= DMA_TEST_BIT | DMA_5_BITS;
        !           544:        break;
        !           545:     case 6:
        !           546:        val = inw(config);
        !           547:        val &= DMA_MASK;
        !           548:        val |= DMA_TEST_BIT | DMA_6_BITS;
        !           549:        break;
        !           550:     case 7:
        !           551:        val = inw(config);
        !           552:        val &= DMA_MASK;
        !           553:        val |= DMA_TEST_BIT | DMA_7_BITS;
        !           554:        break;
        !           555:     default:
        !           556:        DPRINTF(("pss_testdma: invalid drq (%d)\n", dmaNum));
        !           557:        return 0;
        !           558:     }
        !           559:     outw(config, val);
        !           560:
        !           561:     /* Check if the DMA channel is in use */
        !           562:     /* Do it a few times in case there is a delay */
        !           563:     ret = 0;
        !           564:     for (i = 0; i < 3; i++) {
        !           565:        val = inw(config);
        !           566:        if (val & DMA_TEST_PASS) {
        !           567:            ret = 1;
        !           568:            break;
        !           569:        }
        !           570:     }
        !           571:
        !           572:     /* Clear the Test bit and the DMA bits */
        !           573:     val = inw(config);
        !           574:     val &= DMA_TEST_BIT_MASK & DMA_MASK;
        !           575:     outw(config, val);
        !           576:     return(ret);
        !           577: }
        !           578:
        !           579: #ifdef notyet
        !           580: int
        !           581: pss_reset_dsp(sc)
        !           582:        struct pss_softc *sc;
        !           583: {
        !           584:     u_long i;
        !           585:     int pss_base = sc->sc_iobase;
        !           586:
        !           587:     outw(pss_base+PSS_CONTROL, PSS_RESET);
        !           588:
        !           589:     for (i = 0; i < 32768; i++)
        !           590:        inw(pss_base+PSS_CONTROL);
        !           591:
        !           592:     outw(pss_base+PSS_CONTROL, 0);
        !           593:
        !           594:     return 1;
        !           595: }
        !           596:
        !           597: /*
        !           598:  * This function loads an image into the PSS
        !           599:  * card.  The function loads the file by
        !           600:  * resetting the dsp and feeding it the boot bytes.
        !           601:  * First you feed the ASIC the first byte of
        !           602:  * the boot sequence. The ASIC waits until it
        !           603:  * detects a BMS and RD and asserts BR
        !           604:  * and outputs the byte.  The host must poll for
        !           605:  * the BG signal. It then feeds the ASIC another
        !           606:  * byte which removes BR.
        !           607:  */
        !           608: int
        !           609: pss_download_dsp(sc, block, size)
        !           610:        struct pss_softc *sc;
        !           611:        u_char *block;
        !           612:        int size;
        !           613: {
        !           614:     int i, val, count;
        !           615:     int pss_base = sc->sc_iobase;
        !           616:
        !           617:     DPRINTF(("pss: downloading boot code..."));
        !           618:
        !           619:     /* Warn DSP software that a boot is coming */
        !           620:     outw(pss_base+PSS_DATA, 0x00fe);
        !           621:
        !           622:     for (i = 0; i < 32768; i++)
        !           623:        if (inw(pss_base+PSS_DATA) == 0x5500)
        !           624:            break;
        !           625:     outw(pss_base+PSS_DATA, *block++);
        !           626:
        !           627:     pss_reset_dsp(sc);
        !           628:
        !           629:     DPRINTF(("start "));
        !           630:
        !           631:     count = 1;
        !           632:     while(1) {
        !           633:        int j;
        !           634:        for (j=0; j<327670; j++) {
        !           635:            /* Wait for BG to appear */
        !           636:            if (inw(pss_base+PSS_STATUS) & PSS_FLAG3)
        !           637:                break;
        !           638:        }
        !           639:
        !           640:        if (j==327670) {
        !           641:            /* It's ok we timed out when the file was empty */
        !           642:            if (count >= size)
        !           643:                break;
        !           644:            else {
        !           645:                printf("\npss: DownLoad timeout problems, byte %d=%d\n",
        !           646:                       count, size);
        !           647:                return 0;
        !           648:            }
        !           649:        }
        !           650:        /* Send the next byte */
        !           651:        outw(pss_base+PSS_DATA, *block++);
        !           652:        count++;
        !           653:     }
        !           654:
        !           655:     outw(pss_base+PSS_DATA, 0);
        !           656:     for (i = 0; i < 32768; i++)
        !           657:        (void) inw(pss_base+PSS_STATUS);
        !           658:
        !           659:     DPRINTF(("downloaded\n"));
        !           660:
        !           661:     for (i = 0; i < 32768; i++) {
        !           662:        val = inw(pss_base+PSS_STATUS);
        !           663:        if (val & PSS_READ_FULL)
        !           664:            break;
        !           665:     }
        !           666:
        !           667:     /* now read the version */
        !           668:     for (i = 0; i < 32000; i++) {
        !           669:        val = inw(pss_base+PSS_STATUS);
        !           670:        if (val & PSS_READ_FULL)
        !           671:            break;
        !           672:     }
        !           673:     if (i == 32000)
        !           674:        return 0;
        !           675:
        !           676:     (void) inw(pss_base+PSS_DATA);
        !           677:
        !           678:     return 1;
        !           679: }
        !           680: #endif /* notyet */
        !           681:
        !           682: #ifdef AUDIO_DEBUG
        !           683: void
        !           684: wss_dump_regs(sc)
        !           685:        struct ad1848_softc *sc;
        !           686: {
        !           687:
        !           688:     printf("WSS reg: status=%02x\n",
        !           689:           (u_char)inb(sc->sc_iobase-WSS_CODEC+WSS_STATUS));
        !           690: }
        !           691:
        !           692: void
        !           693: pss_dump_regs(sc)
        !           694:        struct pss_softc *sc;
        !           695: {
        !           696:
        !           697:     printf("PSS regs: status=%04x vers=%04x ",
        !           698:           (u_short)inw(sc->sc_iobase+PSS_STATUS),
        !           699:           (u_short)inw(sc->sc_iobase+PSS_ID_VERS));
        !           700:
        !           701:     printf("config=%04x wss_config=%04x\n",
        !           702:           (u_short)inw(sc->sc_iobase+PSS_CONFIG),
        !           703:           (u_short)inw(sc->sc_iobase+PSS_WSS_CONFIG));
        !           704: }
        !           705: #endif
        !           706:
        !           707: /*
        !           708:  * Probe for the PSS hardware.
        !           709:  */
        !           710: int
        !           711: pssprobe(parent, self, aux)
        !           712:     struct device *parent;
        !           713:     void *self;
        !           714:     void *aux;
        !           715: {
        !           716:     struct pss_softc *sc = self;
        !           717:     struct isa_attach_args *ia = aux;
        !           718:     int iobase = ia->ia_iobase;
        !           719:
        !           720:     if (!PSS_BASE_VALID(iobase)) {
        !           721:        DPRINTF(("pss: configured iobase %x invalid\n", iobase));
        !           722:        return 0;
        !           723:     }
        !           724:
        !           725:     /* Need to probe for iobase when IOBASEUNK {0x220 0x240} */
        !           726:     if (iobase == IOBASEUNK) {
        !           727:
        !           728:        iobase = 0x220;
        !           729:        if ((inw(iobase+PSS_ID_VERS) & 0xff00) == 0x4500)
        !           730:            goto pss_found;
        !           731:
        !           732:        iobase = 0x240;
        !           733:        if ((inw(iobase+PSS_ID_VERS) & 0xff00) == 0x4500)
        !           734:            goto pss_found;
        !           735:
        !           736:        DPRINTF(("pss: no PSS found (at 0x220 or 0x240)\n"));
        !           737:        return 0;
        !           738:     }
        !           739:     else if ((inw(iobase+PSS_ID_VERS) & 0xff00) != 0x4500) {
        !           740:        DPRINTF(("pss: not a PSS - %x\n", inw(iobase+PSS_ID_VERS)));
        !           741:        return 0;
        !           742:     }
        !           743:
        !           744: pss_found:
        !           745:     sc->sc_iobase = iobase;
        !           746:
        !           747:     /* Clear WSS config */
        !           748:     pss_setaddr(WSS_BASE_ADDRESS, sc->sc_iobase+PSS_WSS_CONFIG); /* XXX! */
        !           749:     outb(WSS_BASE_ADDRESS+WSS_CONFIG, 0);
        !           750:
        !           751:     /* Clear config registers (POR reset state) */
        !           752:     outw(sc->sc_iobase+PSS_CONFIG, 0);
        !           753:     outw(sc->sc_iobase+PSS_WSS_CONFIG, 0);
        !           754:     outw(sc->sc_iobase+SB_CONFIG, 0);
        !           755:     outw(sc->sc_iobase+MIDI_CONFIG, 0);
        !           756:     outw(sc->sc_iobase+CD_CONFIG, 0);
        !           757:
        !           758:     if (ia->ia_irq == IRQUNK) {
        !           759:        int i;
        !           760:        for (i = 0; i < 16; i++) {
        !           761:            if (pss_testirq(sc, i) != 0)
        !           762:                break;
        !           763:        }
        !           764:        if (i == 16) {
        !           765:            DPRINTF(("pss: unable to locate free IRQ channel\n"));
        !           766:            return 0;
        !           767:        }
        !           768:        else {
        !           769:            ia->ia_irq = i;
        !           770:            DPRINTF(("pss: found IRQ %d free\n", i));
        !           771:        }
        !           772:     }
        !           773:     else {
        !           774:        if (pss_testirq(sc, ia->ia_irq) == 0) {
        !           775:            DPRINTF(("pss: configured IRQ unavailable (%d)\n", ia->ia_irq));
        !           776:            return 0;
        !           777:        }
        !           778:     }
        !           779:
        !           780:     /* XXX Need to deal with DRQUNK */
        !           781:     if (pss_testdma(sc, ia->ia_drq) == 0) {
        !           782:        DPRINTF(("pss: configured DMA channel unavailable (%d)\n", ia->ia_drq));
        !           783:        return 0;
        !           784:     }
        !           785:
        !           786:     ia->ia_iosize = PSS_NPORT;
        !           787:
        !           788:     /* Initialize PSS irq and dma */
        !           789:     pss_setint(ia->ia_irq, sc->sc_iobase+PSS_CONFIG);
        !           790:     pss_setdma(sc->sc_drq, sc->sc_iobase+PSS_CONFIG);
        !           791:
        !           792: #ifdef notyet
        !           793:     /* Setup the Game port */
        !           794: #ifdef PSS_GAMEPORT
        !           795:     DPRINTF(("Turning Game Port On.\n"));
        !           796:     outw(sc->sc_iobase+PSS_STATUS, inw(sc->sc_iobase+PSS_STATUS) | GAME_BIT);
        !           797: #else
        !           798:     outw(sc->sc_iobase+PSS_STATUS, inw(sc->sc_iobase+PSS_STATUS) & GAME_BIT_MASK);
        !           799: #endif
        !           800:
        !           801:     /* Reset DSP */
        !           802:     pss_reset_dsp(sc);
        !           803: #endif /* notyet */
        !           804:
        !           805:     return 1;
        !           806: }
        !           807:
        !           808: /*
        !           809:  * Probe for the Soundport (ad1848)
        !           810:  */
        !           811: int
        !           812: spprobe(parent, match, aux)
        !           813:     struct device *parent;
        !           814:     void *match, *aux;
        !           815: {
        !           816:     struct ad1848_softc *sc = match;
        !           817:     struct pss_softc *pc = (void *) parent;
        !           818:     struct cfdata *cf = (void *)sc->sc_dev.dv_cfdata;
        !           819:     struct isa_attach_args *ia = aux;
        !           820:     u_char bits;
        !           821:     int i;
        !           822:
        !           823:     sc->sc_iot = ia->ia_iot;
        !           824:     sc->sc_iobase = cf->cf_iobase + WSS_CODEC;
        !           825:
        !           826:     /* Set WSS io address */
        !           827:     pss_setaddr(cf->cf_iobase, pc->sc_iobase+PSS_WSS_CONFIG);
        !           828:
        !           829:     /* Is there an ad1848 chip at the WSS iobase ? */
        !           830:     if (ad1848_probe(sc) == 0) {
        !           831:        DPRINTF(("sp: no ad1848 ? iobase=%x\n", sc->sc_iobase));
        !           832:        return 0;
        !           833:     }
        !           834:
        !           835:     /* Setup WSS interrupt and DMA if auto */
        !           836:     if (cf->cf_irq == IRQUNK) {
        !           837:
        !           838:        /* Find unused IRQ for WSS */
        !           839:        for (i = 0; i < 12; i++) {
        !           840:            if (wss_interrupt_bits[i] != 0xff) {
        !           841:                if (pss_testirq(pc, i))
        !           842:                    break;
        !           843:            }
        !           844:        }
        !           845:        if (i == 12) {
        !           846:            DPRINTF(("sp: unable to locate free IRQ for WSS\n"));
        !           847:            return 0;
        !           848:        }
        !           849:        else {
        !           850:            cf->cf_irq = i;
        !           851:            sc->sc_irq = i;
        !           852:            DPRINTF(("sp: found IRQ %d free\n", i));
        !           853:        }
        !           854:     }
        !           855:     else {
        !           856:        sc->sc_irq = cf->cf_irq;
        !           857:        if (pss_testirq(pc, sc->sc_irq) == 0) {
        !           858:            DPRINTF(("sp: configured IRQ unavailable (%d)\n", sc->sc_irq));
        !           859:            return 0;
        !           860:        }
        !           861:     }
        !           862:
        !           863:     if (cf->cf_drq == DRQUNK) {
        !           864:        /* Find unused DMA channel for WSS */
        !           865:        for (i = 0; i < 4; i++) {
        !           866:            if (wss_dma_bits[i]) {
        !           867:                if (pss_testdma(pc, i))
        !           868:                    break;
        !           869:            }
        !           870:        }
        !           871:        if (i == 4) {
        !           872:            DPRINTF(("sp: unable to locate free DMA channel for WSS\n"));
        !           873:            return 0;
        !           874:        }
        !           875:        else {
        !           876:            sc->sc_drq = cf->cf_drq = i;
        !           877:            DPRINTF(("sp: found DMA %d free\n", i));
        !           878:        }
        !           879:     }
        !           880:     else {
        !           881:        if (pss_testdma(pc, sc->sc_drq) == 0) {
        !           882:            DPRINTF(("sp: configured DMA channel unavailable (%d)\n", sc->sc_drq));
        !           883:            return 0;
        !           884:        }
        !           885:        sc->sc_drq = cf->cf_drq;
        !           886:     }
        !           887:     sc->sc_recdrq = sc->sc_drq;
        !           888:
        !           889:     /* Set WSS config registers */
        !           890:     if ((bits = wss_interrupt_bits[sc->sc_irq]) == 0xff) {
        !           891:        DPRINTF(("sp: invalid interrupt configuration (irq=%d)\n", sc->sc_irq));
        !           892:        return 0;
        !           893:     }
        !           894:
        !           895:     outb(sc->sc_iobase+WSS_CONFIG, (bits | 0x40));
        !           896:     if ((inb(sc->sc_iobase+WSS_STATUS) & 0x40) == 0)   /* XXX What do these bits mean ? */
        !           897:        DPRINTF(("sp: IRQ %x\n", inb(sc->sc_iobase+WSS_STATUS)));
        !           898:
        !           899:     outb(sc->sc_iobase+WSS_CONFIG, (bits | wss_dma_bits[sc->sc_drq]));
        !           900:
        !           901:     pc->ad1848_sc = sc;
        !           902:     sc->parent = pc;
        !           903:
        !           904:     return 1;
        !           905: }
        !           906:
        !           907: #ifdef notyet
        !           908: int
        !           909: mpuprobe(parent, match, aux)
        !           910:     struct device *parent;
        !           911:     void *match, *aux;
        !           912: {
        !           913:     struct mpu_softc *sc = match;
        !           914:     struct pss_softc *pc = (void *) parent;
        !           915:     struct cfdata *cf = (void *)sc->sc_dev.dv_cfdata;
        !           916:
        !           917:     /* Check if midi is enabled; if it is check the interrupt */
        !           918:     sc->sc_iobase = cf->cf_iobase;
        !           919:
        !           920:     if (cf->cf_irq == IRQUNK) {
        !           921:        int i;
        !           922:        for (i = 0; i < 16; i++) {
        !           923:            if (pss_testirq(pc, i) != 0)
        !           924:                break;
        !           925:        }
        !           926:        if (i == 16) {
        !           927:            printf("mpu: unable to locate free IRQ channel for MIDI\n");
        !           928:            return 0;
        !           929:        }
        !           930:        else {
        !           931:            cf->cf_irq = i;
        !           932:            sc->sc_irq = i;
        !           933:            DPRINTF(("mpu: found IRQ %d free\n", i));
        !           934:        }
        !           935:     }
        !           936:     else {
        !           937:        sc->sc_irq = cf->cf_irq;
        !           938:
        !           939:        if (pss_testirq(pc, sc->sc_irq) == 0) {
        !           940:            printf("pss: configured MIDI IRQ unavailable (%d)\n", sc->sc_irq);
        !           941:            return 0;
        !           942:        }
        !           943:     }
        !           944:
        !           945:     outw(pc->sc_iobase+MIDI_CONFIG,0);
        !           946:     DPRINTF(("pss: mpu port 0x%x irq %d\n", sc->sc_iobase, sc->sc_irq));
        !           947:     pss_setaddr(sc->sc_iobase, pc->sc_iobase+MIDI_CONFIG);
        !           948:     pss_setint(sc->sc_irq, pc->sc_iobase+MIDI_CONFIG);
        !           949:
        !           950:     return 1;
        !           951: }
        !           952:
        !           953: int
        !           954: pcdprobe(parent, match, aux)
        !           955:     struct device *parent;
        !           956:     void *match, *aux;
        !           957: {
        !           958:     struct pcd_softc *sc = match;
        !           959:     struct pss_softc *pc = (void *) parent;
        !           960:     struct cfdata *cf = (void *)sc->sc_dev.dv_cfdata;
        !           961:     u_short val;
        !           962:
        !           963:     sc->sc_iobase = cf->cf_iobase;
        !           964:
        !           965:     pss_setaddr(sc->sc_iobase, pc->sc_iobase+CD_CONFIG);
        !           966:
        !           967:     /* Set the correct irq polarity. */
        !           968:     val = inw(pc->sc_iobase+CD_CONFIG);
        !           969:     outw(pc->sc_iobase+CD_CONFIG, 0);
        !           970:     val &= CD_POL_MASK;
        !           971:     val |= CD_POL_BIT; /* XXX if (pol) */
        !           972:     outw(pc->sc_iobase+CD_CONFIG, val);
        !           973:
        !           974:     if (cf->cf_irq == IRQUNK) {
        !           975:        int i;
        !           976:        for (i = 0; i < 16; i++) {
        !           977:            if (pss_testirq(pc, i) != 0)
        !           978:                break;
        !           979:        }
        !           980:        if (i == 16) {
        !           981:            printf("pcd: unable to locate free IRQ channel for CD\n");
        !           982:            return 0;
        !           983:        }
        !           984:        else {
        !           985:            cf->cf_irq = i;
        !           986:            sc->sc_irq = i;
        !           987:            DPRINTF(("pcd: found IRQ %d free\n", i));
        !           988:        }
        !           989:     }
        !           990:     else {
        !           991:        sc->sc_irq = cf->cf_irq;
        !           992:
        !           993:        if (pss_testirq(pc, sc->sc_irq) == 0) {
        !           994:            printf("pcd: configured CD IRQ unavailable (%d)\n", sc->sc_irq);
        !           995:            return 0;
        !           996:        }
        !           997:        return 1;
        !           998:     }
        !           999:     pss_setint(sc->sc_irq, pc->sc_iobase+CD_CONFIG);
        !          1000:
        !          1001:     return 1;
        !          1002: }
        !          1003: #endif /* notyet */
        !          1004:
        !          1005: /*
        !          1006:  * Attach hardware to driver, attach hardware driver to audio
        !          1007:  * pseudo-device driver .
        !          1008:  */
        !          1009: void
        !          1010: pssattach(parent, self, aux)
        !          1011:     struct device *parent, *self;
        !          1012:     void *aux;
        !          1013: {
        !          1014:     struct pss_softc *sc = (struct pss_softc *)self;
        !          1015:     struct isa_attach_args *ia = (struct isa_attach_args *)aux;
        !          1016:     int iobase = ia->ia_iobase;
        !          1017:     u_char vers;
        !          1018:     struct ad1848_volume vol = {150, 150};
        !          1019:
        !          1020:     sc->sc_iobase = iobase;
        !          1021:     sc->sc_drq = ia->ia_drq;
        !          1022:
        !          1023:     /* Setup interrupt handler for PSS */
        !          1024:     sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, IPL_AUDIO,
        !          1025:        pssintr, sc, sc->sc_dev.dv_xname);
        !          1026:
        !          1027:     vers = (inw(sc->sc_iobase+PSS_ID_VERS)&0xff) - 1;
        !          1028:     printf(": ESC614%c\n", (vers > 0)?'A'+vers:' ');
        !          1029:
        !          1030:     (void)config_found(self, ia->ia_ic, NULL);         /* XXX */
        !          1031:
        !          1032:     sc->out_port = PSS_MASTER_VOL;
        !          1033:
        !          1034:     (void)pss_set_master_mode(sc, PSS_SPKR_STEREO);
        !          1035:     (void)pss_set_master_gain(sc, &vol);
        !          1036:     (void)pss_set_treble(sc, AUDIO_MAX_GAIN/2);
        !          1037:     (void)pss_set_bass(sc, AUDIO_MAX_GAIN/2);
        !          1038:
        !          1039:     audio_attach_mi(&pss_audio_if, sc->ad1848_sc, &sc->ad1848_sc->sc_dev);
        !          1040: }
        !          1041:
        !          1042: void
        !          1043: spattach(parent, self, aux)
        !          1044:     struct device *parent, *self;
        !          1045:     void *aux;
        !          1046: {
        !          1047:     struct ad1848_softc *sc = (struct ad1848_softc *)self;
        !          1048:     struct cfdata *cf = (void *)sc->sc_dev.dv_cfdata;
        !          1049:     isa_chipset_tag_t ic = aux;                                /* XXX */
        !          1050:     int iobase = cf->cf_iobase;
        !          1051:
        !          1052:     sc->sc_iobase = iobase;
        !          1053:     sc->sc_drq = cf->cf_drq;
        !          1054:
        !          1055:     sc->sc_ih = isa_intr_establish(ic, cf->cf_irq, IST_EDGE, IPL_AUDIO,
        !          1056:        ad1848_intr, sc, sc->sc_dev.dv_xname);
        !          1057:
        !          1058:     sc->sc_isa = parent->dv_parent;
        !          1059:
        !          1060:     ad1848_attach(sc);
        !          1061:
        !          1062:     printf("\n");
        !          1063: }
        !          1064:
        !          1065: #ifdef notyet
        !          1066: void
        !          1067: mpuattach(parent, self, aux)
        !          1068:     struct device *parent, *self;
        !          1069:     void *aux;
        !          1070: {
        !          1071:     struct mpu_softc *sc = (struct mpu_softc *)self;
        !          1072:     struct cfdata *cf = (void *)sc->sc_dev.dv_cfdata;
        !          1073:     isa_chipset_tag_t ic = aux;                                /* XXX */
        !          1074:     int iobase = cf->cf_iobase;
        !          1075:
        !          1076:     sc->sc_iobase = iobase;
        !          1077:
        !          1078:     sc->sc_ih = isa_intr_establish(ic, cf->cf_irq, IST_EDGE, IPL_AUDIO,
        !          1079:        mpuintr, sc, sc->sc_dev.dv_xname);
        !          1080:
        !          1081:     /* XXX might use pssprint func ?? */
        !          1082:     printf(" port 0x%x/%d irq %d\n",
        !          1083:           sc->sc_iobase, MIDI_NPORT, cf->cf_irq);
        !          1084: }
        !          1085:
        !          1086: void
        !          1087: pcdattach(parent, self, aux)
        !          1088:     struct device *parent, *self;
        !          1089:     void *aux;
        !          1090: {
        !          1091:     struct pcd_softc *sc = (struct pcd_softc *)self;
        !          1092:     struct cfdata *cf = (void *)sc->sc_dev.dv_cfdata;
        !          1093:     int iobase = cf->cf_iobase;
        !          1094:
        !          1095:     /*
        !          1096:      * The pss driver simply enables the cd interface. The CD
        !          1097:      * appropriate driver - scsi (aic6360) or Sony needs to be
        !          1098:      * used after this to handle the device.
        !          1099:      */
        !          1100:     sc->sc_iobase = iobase;
        !          1101:
        !          1102:     /* XXX might use pssprint func ?? */
        !          1103:     printf(" port 0x%x/%d irq %d\n",
        !          1104:           sc->sc_iobase, 2, cf->cf_irq);
        !          1105: }
        !          1106: #endif /* notyet */
        !          1107:
        !          1108:
        !          1109: int
        !          1110: pss_set_master_gain(sc, gp)
        !          1111:     struct pss_softc *sc;
        !          1112:     struct ad1848_volume *gp;
        !          1113: {
        !          1114:     DPRINTF(("pss_set_master_gain: %d:%d\n", gp->left, gp->right));
        !          1115:
        !          1116: #ifdef PSS_DSP
        !          1117:     if (gp->left > PHILLIPS_VOL_MAX)
        !          1118:        gp->left = PHILLIPS_VOL_MAX;
        !          1119:     if (gp->left < PHILLIPS_VOL_MIN)
        !          1120:        gp->left = PHILLIPS_VOL_MIN;
        !          1121:     if (gp->right > PHILLIPS_VOL_MAX)
        !          1122:        gp->right = PHILLIPS_VOL_MAX;
        !          1123:     if (gp->right < PHILLIPS_VOL_MIN)
        !          1124:        gp->right = PHILLIPS_VOL_MIN;
        !          1125:
        !          1126:     pss_dspwrite(sc, SET_MASTER_COMMAND);
        !          1127:     pss_dspwrite(sc, MASTER_VOLUME_LEFT|(PHILLIPS_VOL_CONSTANT + gp->left / PHILLIPS_VOL_STEP));
        !          1128:     pss_dspwrite(sc, SET_MASTER_COMMAND);
        !          1129:     pss_dspwrite(sc, MASTER_VOLUME_RIGHT|(PHILLIPS_VOL_CONSTANT + gp->right / PHILLIPS_VOL_STEP));
        !          1130: #endif
        !          1131:
        !          1132:     sc->master_volume = *gp;
        !          1133:     return(0);
        !          1134: }
        !          1135:
        !          1136: int
        !          1137: pss_set_master_mode(sc, mode)
        !          1138:     struct pss_softc *sc;
        !          1139:     int mode;
        !          1140: {
        !          1141:     short phillips_mode;
        !          1142:
        !          1143:     DPRINTF(("pss_set_master_mode: %d\n", mode));
        !          1144:
        !          1145:     if (mode == PSS_SPKR_STEREO)
        !          1146:        phillips_mode = PSS_STEREO;
        !          1147:     else if (mode == PSS_SPKR_PSEUDO)
        !          1148:        phillips_mode = PSS_PSEUDO;
        !          1149:     else if (mode == PSS_SPKR_SPATIAL)
        !          1150:        phillips_mode = PSS_SPATIAL;
        !          1151:     else if (mode == PSS_SPKR_MONO)
        !          1152:        phillips_mode = PSS_MONO;
        !          1153:     else
        !          1154:        return (EINVAL);
        !          1155:
        !          1156: #ifdef PSS_DSP
        !          1157:     pss_dspwrite(sc, SET_MASTER_COMMAND);
        !          1158:     pss_dspwrite(sc, MASTER_SWITCH | mode);
        !          1159: #endif
        !          1160:
        !          1161:     sc->master_mode = mode;
        !          1162:
        !          1163:     return(0);
        !          1164: }
        !          1165:
        !          1166: int
        !          1167: pss_set_treble(sc, treb)
        !          1168:     struct pss_softc *sc;
        !          1169:     u_int treb;
        !          1170: {
        !          1171:     DPRINTF(("pss_set_treble: %d\n", treb));
        !          1172:
        !          1173: #ifdef PSS_DSP
        !          1174:     if (treb > PHILLIPS_TREBLE_MAX)
        !          1175:        treb = PHILLIPS_TREBLE_MAX;
        !          1176:     if (treb < PHILLIPS_TREBLE_MIN)
        !          1177:        treb = PHILLIPS_TREBLE_MIN;
        !          1178:     pss_dspwrite(sc, SET_MASTER_COMMAND);
        !          1179:     pss_dspwrite(sc, MASTER_TREBLE|(PHILLIPS_TREBLE_CONSTANT + treb / PHILLIPS_TREBLE_STEP));
        !          1180: #endif
        !          1181:
        !          1182:     sc->monitor_treble = treb;
        !          1183:
        !          1184:     return(0);
        !          1185: }
        !          1186:
        !          1187: int
        !          1188: pss_set_bass(sc, bass)
        !          1189:     struct pss_softc *sc;
        !          1190:     u_int bass;
        !          1191: {
        !          1192:     DPRINTF(("pss_set_bass: %d\n", bass));
        !          1193:
        !          1194: #ifdef PSS_DSP
        !          1195:     if (bass > PHILLIPS_BASS_MAX)
        !          1196:        bass = PHILLIPS_BASS_MAX;
        !          1197:     if (bass < PHILLIPS_BASS_MIN)
        !          1198:        bass = PHILLIPS_BASS_MIN;
        !          1199:     pss_dspwrite(sc, SET_MASTER_COMMAND);
        !          1200:     pss_dspwrite(sc, MASTER_BASS|(PHILLIPS_BASS_CONSTANT + bass / PHILLIPS_BASS_STEP));
        !          1201: #endif
        !          1202:
        !          1203:     sc->monitor_bass = bass;
        !          1204:
        !          1205:     return(0);
        !          1206: }
        !          1207:
        !          1208: int
        !          1209: pss_get_master_gain(sc, gp)
        !          1210:     struct pss_softc *sc;
        !          1211:     struct ad1848_volume *gp;
        !          1212: {
        !          1213:     *gp = sc->master_volume;
        !          1214:     return(0);
        !          1215: }
        !          1216:
        !          1217: int
        !          1218: pss_get_master_mode(sc, mode)
        !          1219:     struct pss_softc *sc;
        !          1220:     u_int *mode;
        !          1221: {
        !          1222:     *mode = sc->master_mode;
        !          1223:     return(0);
        !          1224: }
        !          1225:
        !          1226: int
        !          1227: pss_get_treble(sc, tp)
        !          1228:     struct pss_softc *sc;
        !          1229:     u_char *tp;
        !          1230: {
        !          1231:     *tp = sc->monitor_treble;
        !          1232:     return(0);
        !          1233: }
        !          1234:
        !          1235: int
        !          1236: pss_get_bass(sc, bp)
        !          1237:     struct pss_softc *sc;
        !          1238:     u_char *bp;
        !          1239: {
        !          1240:     *bp = sc->monitor_bass;
        !          1241:     return(0);
        !          1242: }
        !          1243:
        !          1244: int
        !          1245: pss_speaker_ctl(addr, newstate)
        !          1246:     void *addr;
        !          1247:     int newstate;
        !          1248: {
        !          1249:     return(0);
        !          1250: }
        !          1251:
        !          1252: int
        !          1253: pssintr(arg)
        !          1254:        void *arg;
        !          1255: {
        !          1256:     struct pss_softc *sc = arg;
        !          1257:     u_short sr;
        !          1258:
        !          1259:     sr = inw(sc->sc_iobase+PSS_STATUS);
        !          1260:
        !          1261:     DPRINTF(("pssintr: sc=%p st=%x\n", sc, sr));
        !          1262:
        !          1263:     /* Acknowledge intr */
        !          1264:     outw(sc->sc_iobase+PSS_IRQ_ACK, 0);
        !          1265:
        !          1266:     /* Is it one of ours ? */
        !          1267:     if (sr & (PSS_WRITE_EMPTY|PSS_READ_FULL|PSS_IRQ|PSS_DMQ_TC)) {
        !          1268:        /* XXX do something */
        !          1269:        return 1;
        !          1270:     }
        !          1271:
        !          1272:     return 0;
        !          1273: }
        !          1274:
        !          1275: #ifdef notyet
        !          1276: int
        !          1277: mpuintr(arg)
        !          1278:        void *arg;
        !          1279: {
        !          1280:     struct mpu_softc *sc = arg;
        !          1281:     u_char sr;
        !          1282:
        !          1283:     sr = inb(sc->sc_iobase+MIDI_STATUS_REG);
        !          1284:
        !          1285:     printf("mpuintr: sc=%p sr=%x\n", sc, sr);
        !          1286:
        !          1287:     /* XXX Need to clear intr */
        !          1288:     return 1;
        !          1289: }
        !          1290: #endif
        !          1291:
        !          1292: int
        !          1293: pss_getdev(addr, retp)
        !          1294:     void *addr;
        !          1295:     struct audio_device *retp;
        !          1296: {
        !          1297:     DPRINTF(("pss_getdev: retp=%p\n", retp));
        !          1298:
        !          1299:     *retp = pss_device;
        !          1300:     return 0;
        !          1301: }
        !          1302:
        !          1303: static ad1848_devmap_t mappings[] = {
        !          1304: { PSS_MIC_IN_LVL, AD1848_KIND_LVL, AD1848_AUX2_CHANNEL },
        !          1305: { PSS_LINE_IN_LVL, AD1848_KIND_LVL, AD1848_AUX1_CHANNEL },
        !          1306: { PSS_DAC_LVL, AD1848_KIND_LVL, AD1848_DAC_CHANNEL },
        !          1307: { PSS_MON_LVL, AD1848_KIND_LVL, AD1848_MONO_CHANNEL },
        !          1308: { PSS_MIC_IN_MUTE, AD1848_KIND_MUTE, AD1848_AUX2_CHANNEL },
        !          1309: { PSS_LINE_IN_MUTE, AD1848_KIND_MUTE, AD1848_AUX1_CHANNEL },
        !          1310: { PSS_DAC_MUTE, AD1848_KIND_MUTE, AD1848_DAC_CHANNEL },
        !          1311: { PSS_REC_LVL, AD1848_KIND_RECORDGAIN, -1 },
        !          1312: { PSS_RECORD_SOURCE, AD1848_KIND_RECORDSOURCE, -1}
        !          1313: };
        !          1314:
        !          1315: static int nummap = sizeof(mappings) / sizeof(mappings[0]);
        !          1316:
        !          1317: int
        !          1318: pss_mixer_set_port(addr, cp)
        !          1319:     void *addr;
        !          1320:     mixer_ctrl_t *cp;
        !          1321: {
        !          1322:     struct ad1848_softc *ac = addr;
        !          1323:     struct pss_softc *sc = ac->parent;
        !          1324:     struct ad1848_volume vol;
        !          1325:     int error = ad1848_mixer_set_port(ac, mappings, nummap, cp);
        !          1326:
        !          1327:     if (error != ENXIO)
        !          1328:       return (error);
        !          1329:
        !          1330:     switch (cp->dev) {
        !          1331:     case PSS_MASTER_VOL:       /* master volume */
        !          1332:        if (cp->type == AUDIO_MIXER_VALUE) {
        !          1333:            if (ad1848_to_vol(cp, &vol))
        !          1334:                error = pss_set_master_gain(sc, &vol);
        !          1335:        }
        !          1336:        break;
        !          1337:
        !          1338:     case PSS_OUTPUT_MODE:
        !          1339:        if (cp->type == AUDIO_MIXER_ENUM)
        !          1340:            error = pss_set_master_mode(sc, cp->un.ord);
        !          1341:        break;
        !          1342:
        !          1343:     case PSS_MASTER_TREBLE:    /* master treble */
        !          1344:        if (cp->type == AUDIO_MIXER_VALUE && cp->un.value.num_channels == 1)
        !          1345:            error = pss_set_treble(sc, (u_char)cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]);
        !          1346:        break;
        !          1347:
        !          1348:     case PSS_MASTER_BASS:      /* master bass */
        !          1349:        if (cp->type == AUDIO_MIXER_VALUE && cp->un.value.num_channels == 1)
        !          1350:            error = pss_set_bass(sc, (u_char)cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]);
        !          1351:        break;
        !          1352:
        !          1353:     default:
        !          1354:            return ENXIO;
        !          1355:            /*NOTREACHED*/
        !          1356:     }
        !          1357:
        !          1358:     return 0;
        !          1359: }
        !          1360:
        !          1361: int
        !          1362: pss_mixer_get_port(addr, cp)
        !          1363:     void *addr;
        !          1364:     mixer_ctrl_t *cp;
        !          1365: {
        !          1366:     struct ad1848_softc *ac = addr;
        !          1367:     struct pss_softc *sc = ac->parent;
        !          1368:     struct ad1848_volume vol;
        !          1369:     u_char eq;
        !          1370:     int error = ad1848_mixer_get_port(ac, mappings, nummap, cp);
        !          1371:
        !          1372:     if (error != ENXIO)
        !          1373:       return (error);
        !          1374:
        !          1375:     error = EINVAL;
        !          1376:
        !          1377:     switch (cp->dev) {
        !          1378:     case PSS_MASTER_VOL:       /* master volume */
        !          1379:        if (cp->type == AUDIO_MIXER_VALUE) {
        !          1380:            error = pss_get_master_gain(sc, &vol);
        !          1381:            if (!error)
        !          1382:                ad1848_from_vol(cp, &vol);
        !          1383:        }
        !          1384:        break;
        !          1385:
        !          1386:     case PSS_MASTER_TREBLE:    /* master treble */
        !          1387:        if (cp->type == AUDIO_MIXER_VALUE && cp->un.value.num_channels == 1) {
        !          1388:            error = pss_get_treble(sc, &eq);
        !          1389:            if (!error)
        !          1390:                cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = eq;
        !          1391:        }
        !          1392:        break;
        !          1393:
        !          1394:     case PSS_MASTER_BASS:      /* master bass */
        !          1395:        if (cp->type == AUDIO_MIXER_VALUE && cp->un.value.num_channels == 1) {
        !          1396:            error = pss_get_bass(sc, &eq);
        !          1397:            if (!error)
        !          1398:                cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = eq;
        !          1399:        }
        !          1400:        break;
        !          1401:
        !          1402:     case PSS_OUTPUT_MODE:
        !          1403:        if (cp->type == AUDIO_MIXER_ENUM)
        !          1404:            error = pss_get_master_mode(sc, &cp->un.ord);
        !          1405:        break;
        !          1406:
        !          1407:     default:
        !          1408:        error = ENXIO;
        !          1409:        break;
        !          1410:     }
        !          1411:
        !          1412:     return(error);
        !          1413: }
        !          1414:
        !          1415: int
        !          1416: pss_query_devinfo(addr, dip)
        !          1417:     void *addr;
        !          1418:     mixer_devinfo_t *dip;
        !          1419: {
        !          1420:     DPRINTF(("pss_query_devinfo: index=%d\n", dip->index));
        !          1421:
        !          1422:     switch(dip->index) {
        !          1423:     case PSS_MIC_IN_LVL:       /* Microphone */
        !          1424:        dip->type = AUDIO_MIXER_VALUE;
        !          1425:        dip->mixer_class = PSS_INPUT_CLASS;
        !          1426:        dip->prev = AUDIO_MIXER_LAST;
        !          1427:        dip->next = PSS_MIC_IN_MUTE;
        !          1428:        strlcpy(dip->label.name, AudioNmicrophone, sizeof dip->label.name);
        !          1429:        dip->un.v.num_channels = 2;
        !          1430:        strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1431:            sizeof dip->un.v.units.name);
        !          1432:        break;
        !          1433:
        !          1434:     case PSS_LINE_IN_LVL:      /* line/CD */
        !          1435:        dip->type = AUDIO_MIXER_VALUE;
        !          1436:        dip->mixer_class = PSS_INPUT_CLASS;
        !          1437:        dip->prev = AUDIO_MIXER_LAST;
        !          1438:        dip->next = PSS_LINE_IN_MUTE;
        !          1439:        strlcpy(dip->label.name, AudioNcd, sizeof dip->label.name);
        !          1440:        dip->un.v.num_channels = 2;
        !          1441:        strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1442:            sizeof dip->un.v.units.name);
        !          1443:        break;
        !          1444:
        !          1445:     case PSS_DAC_LVL:          /*  dacout */
        !          1446:        dip->type = AUDIO_MIXER_VALUE;
        !          1447:        dip->mixer_class = PSS_INPUT_CLASS;
        !          1448:        dip->prev = AUDIO_MIXER_LAST;
        !          1449:        dip->next = PSS_DAC_MUTE;
        !          1450:        strlcpy(dip->label.name, AudioNdac, sizeof dip->label.name);
        !          1451:        dip->un.v.num_channels = 2;
        !          1452:        strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1453:            sizeof dip->un.v.units.name);
        !          1454:        break;
        !          1455:
        !          1456:     case PSS_REC_LVL:  /* record level */
        !          1457:        dip->type = AUDIO_MIXER_VALUE;
        !          1458:        dip->mixer_class = PSS_RECORD_CLASS;
        !          1459:        dip->prev = AUDIO_MIXER_LAST;
        !          1460:        dip->next = PSS_RECORD_SOURCE;
        !          1461:        strlcpy(dip->label.name, AudioNrecord, sizeof dip->label.name);
        !          1462:        dip->un.v.num_channels = 2;
        !          1463:        strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1464:            sizeof dip->un.v.units.name);
        !          1465:        break;
        !          1466:
        !          1467:     case PSS_MON_LVL:  /* monitor level */
        !          1468:        dip->type = AUDIO_MIXER_VALUE;
        !          1469:        dip->mixer_class = PSS_MONITOR_CLASS;
        !          1470:        dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1471:        strlcpy(dip->label.name, AudioNmonitor, sizeof dip->label.name);
        !          1472:        dip->un.v.num_channels = 1;
        !          1473:        strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1474:            sizeof dip->un.v.units.name);
        !          1475:        break;
        !          1476:
        !          1477:     case PSS_MASTER_VOL:       /* master volume */
        !          1478:        dip->type = AUDIO_MIXER_VALUE;
        !          1479:        dip->mixer_class = PSS_OUTPUT_CLASS;
        !          1480:        dip->prev = AUDIO_MIXER_LAST;
        !          1481:        dip->next = PSS_OUTPUT_MODE;
        !          1482:        strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name);
        !          1483:        dip->un.v.num_channels = 2;
        !          1484:        strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1485:            sizeof dip->un.v.units.name);
        !          1486:        break;
        !          1487:
        !          1488:     case PSS_MASTER_TREBLE:    /* master treble */
        !          1489:        dip->type = AUDIO_MIXER_VALUE;
        !          1490:        dip->mixer_class = PSS_OUTPUT_CLASS;
        !          1491:        dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1492:        strlcpy(dip->label.name, AudioNtreble, sizeof dip->label.name);
        !          1493:        dip->un.v.num_channels = 1;
        !          1494:        strlcpy(dip->un.v.units.name, AudioNtreble,
        !          1495:            sizeof dip->un.v.units.name);
        !          1496:        break;
        !          1497:
        !          1498:     case PSS_MASTER_BASS:      /* master bass */
        !          1499:        dip->type = AUDIO_MIXER_VALUE;
        !          1500:        dip->mixer_class = PSS_OUTPUT_CLASS;
        !          1501:        dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1502:        strlcpy(dip->label.name, AudioNbass, sizeof dip->label.name);
        !          1503:        dip->un.v.num_channels = 1;
        !          1504:        strlcpy(dip->un.v.units.name, AudioNbass, sizeof dip->un.v.units.name);
        !          1505:        break;
        !          1506:
        !          1507:     case PSS_OUTPUT_CLASS:                     /* output class descriptor */
        !          1508:        dip->type = AUDIO_MIXER_CLASS;
        !          1509:        dip->mixer_class = PSS_OUTPUT_CLASS;
        !          1510:        dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1511:        strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name);
        !          1512:        break;
        !          1513:
        !          1514:     case PSS_INPUT_CLASS:                      /* input class descriptor */
        !          1515:        dip->type = AUDIO_MIXER_CLASS;
        !          1516:        dip->mixer_class = PSS_INPUT_CLASS;
        !          1517:        dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1518:        strlcpy(dip->label.name, AudioCinputs, sizeof dip->label.name);
        !          1519:        break;
        !          1520:
        !          1521:     case PSS_MONITOR_CLASS:                    /* monitor class descriptor */
        !          1522:        dip->type = AUDIO_MIXER_CLASS;
        !          1523:        dip->mixer_class = PSS_MONITOR_CLASS;
        !          1524:        dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1525:        strlcpy(dip->label.name, AudioCmonitor, sizeof dip->label.name);
        !          1526:        break;
        !          1527:
        !          1528:     case PSS_RECORD_CLASS:                     /* record source class */
        !          1529:        dip->type = AUDIO_MIXER_CLASS;
        !          1530:        dip->mixer_class = PSS_RECORD_CLASS;
        !          1531:        dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1532:        strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
        !          1533:        break;
        !          1534:
        !          1535:     case PSS_MIC_IN_MUTE:
        !          1536:        dip->mixer_class = PSS_INPUT_CLASS;
        !          1537:        dip->type = AUDIO_MIXER_ENUM;
        !          1538:        dip->prev = PSS_MIC_IN_LVL;
        !          1539:        dip->next = AUDIO_MIXER_LAST;
        !          1540:        goto mute;
        !          1541:
        !          1542:     case PSS_LINE_IN_MUTE:
        !          1543:        dip->mixer_class = PSS_INPUT_CLASS;
        !          1544:        dip->type = AUDIO_MIXER_ENUM;
        !          1545:        dip->prev = PSS_LINE_IN_LVL;
        !          1546:        dip->next = AUDIO_MIXER_LAST;
        !          1547:        goto mute;
        !          1548:
        !          1549:     case PSS_DAC_MUTE:
        !          1550:        dip->mixer_class = PSS_INPUT_CLASS;
        !          1551:        dip->type = AUDIO_MIXER_ENUM;
        !          1552:        dip->prev = PSS_DAC_LVL;
        !          1553:        dip->next = AUDIO_MIXER_LAST;
        !          1554:     mute:
        !          1555:        strlcpy(dip->label.name, AudioNmute, sizeof dip->label.name);
        !          1556:        dip->un.e.num_mem = 2;
        !          1557:        strlcpy(dip->un.e.member[0].label.name, AudioNoff,
        !          1558:            sizeof dip->un.e.member[0].label.name);
        !          1559:        dip->un.e.member[0].ord = 0;
        !          1560:        strlcpy(dip->un.e.member[1].label.name, AudioNon,
        !          1561:            sizeof dip->un.e.member[1].label.name);
        !          1562:        dip->un.e.member[1].ord = 1;
        !          1563:        break;
        !          1564:
        !          1565:     case PSS_OUTPUT_MODE:
        !          1566:        dip->mixer_class = PSS_OUTPUT_CLASS;
        !          1567:        dip->type = AUDIO_MIXER_ENUM;
        !          1568:        dip->prev = PSS_MASTER_VOL;
        !          1569:        dip->next = AUDIO_MIXER_LAST;
        !          1570:        strlcpy(dip->label.name, AudioNmode, sizeof dip->label.name);
        !          1571:        dip->un.e.num_mem = 4;
        !          1572:        strlcpy(dip->un.e.member[0].label.name, AudioNmono,
        !          1573:            sizeof dip->un.e.member[0].label.name);
        !          1574:        dip->un.e.member[0].ord = PSS_SPKR_MONO;
        !          1575:        strlcpy(dip->un.e.member[1].label.name, AudioNstereo,
        !          1576:            sizeof dip->un.e.member[1].label.name);
        !          1577:        dip->un.e.member[1].ord = PSS_SPKR_STEREO;
        !          1578:        strlcpy(dip->un.e.member[2].label.name, AudioNpseudo,
        !          1579:            sizeof dip->un.e.member[2].label.name);
        !          1580:        dip->un.e.member[2].ord = PSS_SPKR_PSEUDO;
        !          1581:        strlcpy(dip->un.e.member[3].label.name, AudioNspatial,
        !          1582:            sizeof dip->un.e.member[3].label.name);
        !          1583:        dip->un.e.member[3].ord = PSS_SPKR_SPATIAL;
        !          1584:        break;
        !          1585:
        !          1586:     case PSS_RECORD_SOURCE:
        !          1587:        dip->mixer_class = PSS_RECORD_CLASS;
        !          1588:        dip->type = AUDIO_MIXER_ENUM;
        !          1589:        dip->prev = PSS_REC_LVL;
        !          1590:        dip->next = AUDIO_MIXER_LAST;
        !          1591:        strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
        !          1592:        dip->un.e.num_mem = 3;
        !          1593:        strlcpy(dip->un.e.member[0].label.name, AudioNmicrophone,
        !          1594:            sizeof dip->un.e.member[0].label.name);
        !          1595:        dip->un.e.member[0].ord = PSS_MIC_IN_LVL;
        !          1596:        strlcpy(dip->un.e.member[1].label.name, AudioNcd,
        !          1597:            sizeof dip->un.e.member[1].label.name);
        !          1598:        dip->un.e.member[1].ord = PSS_LINE_IN_LVL;
        !          1599:        strlcpy(dip->un.e.member[2].label.name, AudioNdac,
        !          1600:            sizeof dip->un.e.member[2].label.name);
        !          1601:        dip->un.e.member[2].ord = PSS_DAC_LVL;
        !          1602:        break;
        !          1603:
        !          1604:     default:
        !          1605:        return ENXIO;
        !          1606:        /*NOTREACHED*/
        !          1607:     }
        !          1608:     DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
        !          1609:
        !          1610:     return 0;
        !          1611: }

CVSweb