The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/isa/pas.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: pas.c,v 1.57 2003/05/03 18:11:27 wiz Exp $     */
    2 
    3 /*
    4  * Copyright (c) 1991-1993 Regents of the University of California.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. All advertising materials mentioning features or use of this software
   16  *    must display the following acknowledgement:
   17  *      This product includes software developed by the Computer Systems
   18  *      Engineering Group at Lawrence Berkeley Laboratory.
   19  * 4. Neither the name of the University nor of the Laboratory may be used
   20  *    to endorse or promote products derived from this software without
   21  *    specific prior written permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   33  * SUCH DAMAGE.
   34  *
   35  */
   36 /*
   37  * jfw 7/13/97 - The soundblaster code requires the generic bus-space 
   38  * structures to be set up properly.  Rather than go to the effort of making
   39  * code for a dead line fully generic, properly set up the SB structures and
   40  * leave the rest x86/ISA/default-configuration specific.  If you have a
   41  * REAL computer, go buy a REAL sound card.
   42  */
   43 /*
   44  * Todo:
   45  *      - look at other PAS drivers (for PAS native suport)
   46  *      - use common sb.c once emulation is setup
   47  */
   48 /*
   49  * jfw 6/21/98 - WARNING:  the PAS native IO ports are scattered all around
   50  * IO port space (0x0388, 0x738B, 0xBF88, 0x2789, ...) which will make proper
   51  * reservation a real pain, so I'm not going to do it (while fixing the
   52  * current reservation code to "work").  As a sanity check, I reserve the
   53  * 0x0388 base address, but you probably shouldn't even think of trying this
   54  * driver unless you're certain you have the hardware installed and it doesn't
   55  * conflict with other hardware...
   56  */
   57 
   58 
   59 #include <sys/cdefs.h>
   60 __KERNEL_RCSID(0, "$NetBSD: pas.c,v 1.57 2003/05/03 18:11:27 wiz Exp $");
   61 
   62 #include <sys/param.h>
   63 #include <sys/systm.h>
   64 #include <sys/errno.h>
   65 #include <sys/ioctl.h>
   66 #include <sys/syslog.h>
   67 #include <sys/device.h>
   68 #include <sys/proc.h>
   69 
   70 #include <machine/cpu.h>
   71 #include <machine/intr.h>
   72 #include <machine/bus.h>
   73 #include <machine/pio.h>
   74 
   75 #include <sys/audioio.h>
   76 #include <dev/audio_if.h>
   77 #include <dev/midi_if.h>
   78 
   79 #include <dev/isa/isavar.h>
   80 #include <dev/isa/isadmavar.h>
   81 
   82 #include <dev/isa/sbdspvar.h>
   83 #include <dev/isa/sbreg.h>
   84 
   85 #define DEFINE_TRANSLATIONS
   86 #include <dev/isa/pasreg.h>
   87 
   88 #ifdef AUDIO_DEBUG
   89 #define DPRINTF(x)      if (pasdebug) printf x
   90 int     pasdebug = 0;
   91 #else
   92 #define DPRINTF(x)
   93 #endif
   94 
   95 /*
   96  * Software state, per SoundBlaster card.
   97  * The soundblaster has multiple functionality, which we must demultiplex.
   98  * One approach is to have one major device number for the soundblaster card,
   99  * and use different minor numbers to indicate which hardware function
  100  * we want.  This would make for one large driver.  Instead our approach
  101  * is to partition the design into a set of drivers that share an underlying
  102  * piece of hardware.  Most things are hard to share, for example, the audio
  103  * and midi ports.  For audio, we might want to mix two processes' signals,
  104  * and for midi we might want to merge streams (this is hard due to
  105  * running status).  Moreover, we should be able to re-use the high-level
  106  * modules with other kinds of hardware.  In this module, we only handle the
  107  * most basic communications with the sb card.
  108  */
  109 struct pas_softc {
  110         struct sbdsp_softc sc_sbdsp;    /* base device, &c. */
  111         bus_space_handle_t pas_port_handle;    /* the pas-specific port */
  112 
  113         int model;
  114         int rev;
  115 };
  116 
  117 int     pas_getdev __P((void *, struct audio_device *));
  118 void    pasconf __P((int, int, int, int));
  119 
  120 
  121 /*
  122  * Define our interface to the higher level audio driver.
  123  */
  124 
  125 struct audio_hw_if pas_hw_if = {
  126         sbdsp_open,
  127         sbdsp_close,
  128         0,
  129         sbdsp_query_encoding,
  130         sbdsp_set_params,
  131         sbdsp_round_blocksize,
  132         0,
  133         0,
  134         0,
  135         0,
  136         0,
  137         sbdsp_halt_output,
  138         sbdsp_halt_input,
  139         sbdsp_speaker_ctl,
  140         pas_getdev,
  141         0,
  142         sbdsp_mixer_set_port,
  143         sbdsp_mixer_get_port,
  144         sbdsp_mixer_query_devinfo,
  145         sb_malloc,
  146         sb_free,
  147         sb_round_buffersize,
  148         sb_mappage,
  149         sbdsp_get_props,
  150         sbdsp_trigger_output,
  151         sbdsp_trigger_input,
  152         0,
  153 };
  154 
  155 /* The Address Translation code is used to convert I/O register addresses to
  156    be relative to the given base -register */
  157 
  158 static char *pasnames[] = {
  159         "",
  160         "Plus",
  161         "CDPC",
  162         "16",
  163         "16Basic"
  164 };
  165 
  166 static struct audio_device pas_device = {
  167         "PAS,??",
  168         "",
  169         "pas"
  170 };
  171 
  172 /*XXX assume default I/O base address */
  173 #define pasread(p) inb((p))
  174 #define paswrite(d, p) outb((p), (d))
  175 
  176 void
  177 pasconf(model, sbbase, sbirq, sbdrq)
  178         int model;
  179         int sbbase;
  180         int sbirq;
  181         int sbdrq;
  182 {
  183         paswrite(0x00, INTERRUPT_MASK);
  184         /* Local timer control register */
  185         paswrite(0x36, SAMPLE_COUNTER_CONTROL);
  186         /* Sample rate timer (16 bit) */
  187         paswrite(0x36, SAMPLE_RATE_TIMER);
  188         paswrite(0, SAMPLE_RATE_TIMER);
  189         /* Local timer control register */
  190         paswrite(0x74, SAMPLE_COUNTER_CONTROL);
  191         /* Sample count register (16 bit) */
  192         paswrite(0x74, SAMPLE_BUFFER_COUNTER);
  193         paswrite(0, SAMPLE_BUFFER_COUNTER);
  194 
  195         paswrite(P_C_PCM_MONO | P_C_PCM_DAC_MODE |
  196                   P_C_MIXER_CROSS_L_TO_L | P_C_MIXER_CROSS_R_TO_R,
  197                   PCM_CONTROL);
  198         paswrite(S_M_PCM_RESET | S_M_FM_RESET |
  199                   S_M_SB_RESET | S_M_MIXER_RESET, SERIAL_MIXER);
  200 
  201 /*XXX*/
  202         paswrite(I_C_1_BOOT_RESET_ENABLE|1, IO_CONFIGURATION_1);
  203 
  204         paswrite(I_C_2_PCM_DMA_DISABLED, IO_CONFIGURATION_2);
  205         paswrite(I_C_3_PCM_IRQ_DISABLED, IO_CONFIGURATION_3);
  206         
  207 #ifdef BROKEN_BUS_CLOCK 
  208         paswrite(S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND |
  209                   S_C_1_FM_EMULATE_CLOCK, SYSTEM_CONFIGURATION_1);
  210 #else
  211         paswrite(S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND,
  212                   SYSTEM_CONFIGURATION_1);     
  213 #endif
  214 
  215         /*XXX*/
  216         paswrite(0, SYSTEM_CONFIGURATION_2);
  217         paswrite(0, SYSTEM_CONFIGURATION_3);
  218 
  219         /* Sets mute off and selects filter rate of 17.897 kHz */
  220         paswrite(F_F_MIXER_UNMUTE | 0x01, FILTER_FREQUENCY);
  221 
  222         if (model == PAS_16 || model == PAS_16BASIC)
  223                 paswrite(8, PRESCALE_DIVIDER);
  224         else
  225                 paswrite(0, PRESCALE_DIVIDER);
  226 
  227         paswrite(P_M_MV508_ADDRESS | P_M_MV508_PCM, PARALLEL_MIXER);
  228         paswrite(5, PARALLEL_MIXER);
  229                 
  230         /*
  231          * Setup SoundBlaster emulation.
  232          */
  233         paswrite((sbbase >> 4) & 0xf, EMULATION_ADDRESS);
  234         paswrite(E_C_SB_IRQ_translate[sbirq] | E_C_SB_DMA_translate[sbdrq],
  235                  EMULATION_CONFIGURATION);
  236         paswrite(C_E_SB_ENABLE, COMPATIBILITY_ENABLE);
  237 
  238         /*
  239          * Set mid-range levels.
  240          */
  241         paswrite(P_M_MV508_ADDRESS | P_M_MV508_MODE, PARALLEL_MIXER);
  242         paswrite(P_M_MV508_LOUDNESS | P_M_MV508_ENHANCE_NONE, PARALLEL_MIXER);  
  243 
  244         paswrite(P_M_MV508_ADDRESS | P_M_MV508_MASTER_A, PARALLEL_MIXER);
  245         paswrite(50, PARALLEL_MIXER);
  246         paswrite(P_M_MV508_ADDRESS | P_M_MV508_MASTER_B, PARALLEL_MIXER);
  247         paswrite(50, PARALLEL_MIXER);
  248 
  249         paswrite(P_M_MV508_ADDRESS | P_M_MV508_MIXER | P_M_MV508_SB, PARALLEL_MIXER);
  250         paswrite(P_M_MV508_OUTPUTMIX | 30, PARALLEL_MIXER);
  251 
  252         paswrite(P_M_MV508_ADDRESS | P_M_MV508_MIXER | P_M_MV508_MIC, PARALLEL_MIXER);
  253         paswrite(P_M_MV508_INPUTMIX | 30, PARALLEL_MIXER);
  254 }
  255 
  256 int     pasprobe __P((struct device *, struct cfdata *, void *));
  257 void    pasattach __P((struct device *, struct device *, void *));
  258 static  int pasfind __P((struct device *, struct pas_softc *, 
  259                         struct isa_attach_args *, int));
  260 /* argument to pasfind */
  261 #define PASPROBE  1
  262 #define PASATTACH 0
  263 
  264 CFATTACH_DECL(pas, sizeof(struct pas_softc),
  265     pasprobe, pasattach, NULL, NULL);
  266 
  267 /*
  268  * Probe / attach routines.
  269  */
  270 
  271 int
  272 pasprobe(parent, match, aux)
  273         struct device *parent;
  274         struct cfdata *match;
  275         void *aux;
  276 {
  277         struct isa_attach_args *ia = aux;
  278         struct pas_softc probesc, *sc = &probesc;
  279 
  280         if (ia->ia_nio < 1)
  281                 return (0);
  282         if (ia->ia_nirq < 1)
  283                 return (0);
  284         if (ia->ia_ndrq < 1)
  285                 return (0);
  286 
  287         if (ISA_DIRECT_CONFIG(ia))
  288                 return (0);
  289 
  290         memset(sc, 0, sizeof *sc);
  291         sc->sc_sbdsp.sc_dev.dv_cfdata = match;
  292         strcpy(sc->sc_sbdsp.sc_dev.dv_xname, "pas");
  293         return pasfind(parent, sc, aux, PASPROBE);
  294 }
  295 
  296 /*
  297  * Probe for the soundblaster hardware.
  298  */
  299 static int
  300 pasfind(parent, sc, ia, probing)
  301         struct device *parent;
  302         struct pas_softc *sc;
  303         struct isa_attach_args *ia;
  304         int probing;
  305 {
  306         int iobase;
  307         u_char id, t;
  308         int rc = 0;  /* failure */
  309 
  310         /* ensure we can set this up as a sound blaster */
  311         if (!SB_BASE_VALID(ia->ia_io[0].ir_addr)) {
  312                 printf("pas: configured SB iobase 0x%x invalid\n",
  313                     ia->ia_io[0].ir_addr);
  314                 return 0;
  315         }
  316 
  317         if (bus_space_map(sc->sc_sbdsp.sc_iot, PAS_DEFAULT_BASE, 1, 0,
  318                           &sc->pas_port_handle)) {
  319                 printf("pas: can't map base register %x in probe\n",
  320                        PAS_DEFAULT_BASE);
  321                 return 0;
  322         }
  323 
  324         /*
  325          * WARNING: Setting an option like W:1 or so that disables
  326          * warm boot reset of the card will screw up this detect code
  327          * something fierce.  Adding code to handle this means possibly
  328          * interfering with other cards on the bus if you have something
  329          * on base port 0x388.  SO be forewarned. 
  330          */
  331         /* Talk to first board */
  332         outb(MASTER_DECODE, 0xbc);
  333         /* Set base address */
  334 
  335 #if 0
  336         /* XXX Need to setup pseudo device */
  337         /* XXX What are good io addrs ? */
  338         if (iobase != PAS_DEFAULT_BASE) {
  339                 printf("pas: configured iobase %d invalid\n", iobase);
  340                 return 0;
  341         }
  342 #else
  343         /* Start out talking to native PAS */
  344         iobase = PAS_DEFAULT_BASE;
  345 #endif
  346 
  347         outb(MASTER_DECODE, iobase >> 2);
  348         /* One wait-state */
  349         paswrite(1, WAIT_STATE);
  350 
  351         id = pasread(INTERRUPT_MASK);
  352         if (id == 0xff || id == 0xfe) {
  353                 /* sanity */
  354                 DPRINTF(("pas: bogus card id\n"));
  355                 goto unmap1;
  356         }
  357         /*
  358          * We probably have a PAS-series board, now check for a
  359          * PAS2-series board by trying to change the board revision
  360          * bits.  PAS2-series hardware won't let you do this because
  361          * the bits are read-only.
  362          */
  363         t = id ^ 0xe0;
  364         paswrite(t, INTERRUPT_MASK);
  365         t = inb(INTERRUPT_MASK);
  366         paswrite(id, INTERRUPT_MASK);
  367 
  368         if (t != id) {
  369                 /* Not a PAS2 */
  370                 printf("pas: detected card but PAS2 test failed\n");
  371                 goto unmap1;
  372         }
  373         /*XXX*/
  374         t = pasread(OPERATION_MODE_1) & 0xf;
  375         sc->model = O_M_1_to_card[t];
  376         if (sc->model != 0) {
  377                 sc->rev = pasread(BOARD_REV_ID);
  378         }
  379         else {
  380                 DPRINTF(("pas: bogus model id\n"));
  381                 goto unmap1;
  382         }
  383 
  384         if (sc->model >= 0) {
  385                 if (ia->ia_irq[0].ir_irq == ISACF_IRQ_DEFAULT) {
  386                         printf("pas: sb emulation requires known irq\n");
  387                         goto unmap1;
  388                 } 
  389                 pasconf(sc->model, ia->ia_io[0].ir_addr,
  390                     ia->ia_irq[0].ir_irq, 1);
  391         } else {
  392                 DPRINTF(("pas: could not probe pas\n"));
  393                 goto unmap1;
  394         }
  395 
  396         /* Now a SoundBlaster, so set up proper bus-space hooks
  397          * appropriately
  398          */
  399 
  400         sc->sc_sbdsp.sc_iobase = ia->ia_io[0].ir_addr;
  401         sc->sc_sbdsp.sc_iot = ia->ia_iot;
  402 
  403         /* Map i/o space [we map 24 ports which is the max of the sb and pro */
  404         if (bus_space_map(sc->sc_sbdsp.sc_iot, ia->ia_io[0].ir_addr,
  405             SBP_NPORT, 0, &sc->sc_sbdsp.sc_ioh)) {
  406                 printf("pas: can't map i/o space 0x%x/%d in probe\n",
  407                     ia->ia_io[0].ir_addr, SBP_NPORT);
  408                 goto unmap1;
  409         }
  410 
  411         if (sbdsp_reset(&sc->sc_sbdsp) < 0) {
  412                 DPRINTF(("pas: couldn't reset card\n"));
  413                 goto unmap;
  414         }
  415 
  416         /*
  417          * Cannot auto-discover DMA channel.
  418          */
  419         if (!SB_DRQ_VALID(ia->ia_drq[0].ir_drq)) {
  420                 printf("pas: configured DMA chan %d invalid\n",
  421                     ia->ia_drq[0].ir_drq);
  422                 goto unmap;
  423         }
  424         if (!SB_IRQ_VALID(ia->ia_irq[0].ir_irq)) {
  425                 printf("pas: configured irq chan %d invalid\n",
  426                     ia->ia_drq[0].ir_drq);
  427                 goto unmap;
  428         }
  429 
  430         sc->sc_sbdsp.sc_irq = ia->ia_irq[0].ir_irq;
  431         sc->sc_sbdsp.sc_drq8 = ia->ia_drq[0].ir_drq;
  432         sc->sc_sbdsp.sc_drq16 = -1; /* XXX */
  433         
  434         if (sbdsp_probe(&sc->sc_sbdsp) == 0) {
  435                 DPRINTF(("pas: sbdsp probe failed\n"));
  436                 goto unmap;
  437         }
  438 
  439         rc = 1;
  440 
  441         if (probing) {
  442                 ia->ia_nio = 1;
  443                 ia->ia_io[0].ir_size = SBP_NPORT;
  444 
  445                 ia->ia_nirq = 1;
  446                 ia->ia_ndrq = 1;
  447 
  448                 ia->ia_niomem = 0;
  449         }
  450 
  451  unmap:
  452         if (rc == 0 || probing)
  453                 bus_space_unmap(sc->sc_sbdsp.sc_iot, sc->sc_sbdsp.sc_ioh,
  454                     SBP_NPORT);
  455  unmap1:
  456         if (rc == 0 || probing)
  457                 bus_space_unmap(sc->sc_sbdsp.sc_iot, PAS_DEFAULT_BASE, 1);
  458         return rc;
  459 }
  460 
  461 /*
  462  * Attach hardware to driver, attach hardware driver to audio
  463  * pseudo-device driver .
  464  */
  465 void
  466 pasattach(parent, self, aux)
  467         struct device *parent, *self;
  468         void *aux;
  469 {
  470         struct pas_softc *sc = (struct pas_softc *)self;
  471         struct isa_attach_args *ia = (struct isa_attach_args *)aux;
  472         int iobase = ia->ia_io[0].ir_addr;
  473         
  474         if (!pasfind(parent, sc, ia, PASATTACH)) {
  475                 printf("%s: pasfind failed\n", sc->sc_sbdsp.sc_dev.dv_xname);
  476                 return;
  477         }
  478 
  479         sc->sc_sbdsp.sc_ic = ia->ia_ic;
  480         sc->sc_sbdsp.sc_iobase = iobase;
  481         sc->sc_sbdsp.sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq,
  482             IST_EDGE, IPL_AUDIO, sbdsp_intr, &sc->sc_sbdsp);
  483 
  484         printf(" ProAudio Spectrum %s [rev %d] ", pasnames[sc->model],
  485             sc->rev);
  486         
  487         sbdsp_attach(&sc->sc_sbdsp);
  488 
  489         sprintf(pas_device.name, "pas,%s", pasnames[sc->model]);
  490         sprintf(pas_device.version, "%d", sc->rev);
  491 
  492         audio_attach_mi(&pas_hw_if, &sc->sc_sbdsp, &sc->sc_sbdsp.sc_dev);
  493 }
  494 
  495 int
  496 pas_getdev(addr, retp)
  497         void *addr;
  498         struct audio_device *retp;
  499 {
  500         *retp = pas_device;
  501         return 0;
  502 }

Cache object: cd673c8bf00123ad534f3ae1cd605ee9


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.