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/sound/isa/sb8.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 /*
    2  * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
    3  * Copyright 1997,1998 Luigi Rizzo.
    4  *
    5  * Derived from files in the Voxware 3.5 distribution,
    6  * Copyright by Hannu Savolainen 1994, under the same copyright
    7  * conditions.
    8  * All rights reserved.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  */
   31 
   32 #include <dev/sound/pcm/sound.h>
   33 
   34 #include  <dev/sound/isa/sb.h>
   35 #include  <dev/sound/chip.h>
   36 
   37 #include "mixer_if.h"
   38 
   39 SND_DECLARE_FILE("$FreeBSD: releng/5.0/sys/dev/sound/isa/sb8.c 89774 2002-01-25 04:14:12Z scottl $");
   40 
   41 #define SB_DEFAULT_BUFSZ        4096
   42 
   43 static u_int32_t sb_fmt[] = {
   44         AFMT_U8,
   45         0
   46 };
   47 static struct pcmchan_caps sb200_playcaps = {4000, 23000, sb_fmt, 0};
   48 static struct pcmchan_caps sb200_reccaps = {4000, 13000, sb_fmt, 0};
   49 static struct pcmchan_caps sb201_playcaps = {4000, 44100, sb_fmt, 0};
   50 static struct pcmchan_caps sb201_reccaps = {4000, 15000, sb_fmt, 0};
   51 
   52 static u_int32_t sbpro_fmt[] = {
   53         AFMT_U8,
   54         AFMT_STEREO | AFMT_U8,
   55         0
   56 };
   57 static struct pcmchan_caps sbpro_playcaps = {4000, 44100, sbpro_fmt, 0};
   58 static struct pcmchan_caps sbpro_reccaps = {4000, 44100, sbpro_fmt, 0};
   59 
   60 struct sb_info;
   61 
   62 struct sb_chinfo {
   63         struct sb_info *parent;
   64         struct pcm_channel *channel;
   65         struct snd_dbuf *buffer;
   66         int dir;
   67         u_int32_t fmt, spd, blksz;
   68 };
   69 
   70 struct sb_info {
   71         device_t parent_dev;
   72         struct resource *io_base;       /* I/O address for the board */
   73         struct resource *irq;
   74         struct resource *drq;
   75         void *ih;
   76         bus_dma_tag_t parent_dmat;
   77 
   78         unsigned int bufsize;
   79         int bd_id;
   80         u_long bd_flags;       /* board-specific flags */
   81         struct sb_chinfo pch, rch;
   82 };
   83 
   84 static int sb_rd(struct sb_info *sb, int reg);
   85 static void sb_wr(struct sb_info *sb, int reg, u_int8_t val);
   86 static int sb_dspready(struct sb_info *sb);
   87 static int sb_cmd(struct sb_info *sb, u_char val);
   88 static int sb_cmd1(struct sb_info *sb, u_char cmd, int val);
   89 static int sb_cmd2(struct sb_info *sb, u_char cmd, int val);
   90 static u_int sb_get_byte(struct sb_info *sb);
   91 static void sb_setmixer(struct sb_info *sb, u_int port, u_int value);
   92 static int sb_getmixer(struct sb_info *sb, u_int port);
   93 static int sb_reset_dsp(struct sb_info *sb);
   94 
   95 static void sb_intr(void *arg);
   96 static int sb_speed(struct sb_chinfo *ch);
   97 static int sb_start(struct sb_chinfo *ch);
   98 static int sb_stop(struct sb_chinfo *ch);
   99 
  100 /*
  101  * Common code for the midi and pcm functions
  102  *
  103  * sb_cmd write a single byte to the CMD port.
  104  * sb_cmd1 write a CMD + 1 byte arg
  105  * sb_cmd2 write a CMD + 2 byte arg
  106  * sb_get_byte returns a single byte from the DSP data port
  107  */
  108 
  109 static void
  110 sb_lock(struct sb_info *sb) {
  111 
  112         sbc_lock(device_get_softc(sb->parent_dev));
  113 }
  114 
  115 static void
  116 sb_unlock(struct sb_info *sb) {
  117 
  118         sbc_unlock(device_get_softc(sb->parent_dev));
  119 }
  120 
  121 static int
  122 port_rd(struct resource *port, int off)
  123 {
  124         return bus_space_read_1(rman_get_bustag(port), rman_get_bushandle(port), off);
  125 }
  126 
  127 static void
  128 port_wr(struct resource *port, int off, u_int8_t data)
  129 {
  130         return bus_space_write_1(rman_get_bustag(port), rman_get_bushandle(port), off, data);
  131 }
  132 
  133 static int
  134 sb_rd(struct sb_info *sb, int reg)
  135 {
  136         return port_rd(sb->io_base, reg);
  137 }
  138 
  139 static void
  140 sb_wr(struct sb_info *sb, int reg, u_int8_t val)
  141 {
  142         port_wr(sb->io_base, reg, val);
  143 }
  144 
  145 static int
  146 sb_dspready(struct sb_info *sb)
  147 {
  148         return ((sb_rd(sb, SBDSP_STATUS) & 0x80) == 0);
  149 }
  150 
  151 static int
  152 sb_dspwr(struct sb_info *sb, u_char val)
  153 {
  154         int  i;
  155 
  156         for (i = 0; i < 1000; i++) {
  157                 if (sb_dspready(sb)) {
  158                         sb_wr(sb, SBDSP_CMD, val);
  159                         return 1;
  160                 }
  161                 if (i > 10) DELAY((i > 100)? 1000 : 10);
  162         }
  163         printf("sb_dspwr(0x%02x) timed out.\n", val);
  164         return 0;
  165 }
  166 
  167 static int
  168 sb_cmd(struct sb_info *sb, u_char val)
  169 {
  170 #if 0
  171         printf("sb_cmd: %x\n", val);
  172 #endif
  173         return sb_dspwr(sb, val);
  174 }
  175 
  176 static int
  177 sb_cmd1(struct sb_info *sb, u_char cmd, int val)
  178 {
  179 #if 0
  180         printf("sb_cmd1: %x, %x\n", cmd, val);
  181 #endif
  182         if (sb_dspwr(sb, cmd)) {
  183                 return sb_dspwr(sb, val & 0xff);
  184         } else return 0;
  185 }
  186 
  187 static int
  188 sb_cmd2(struct sb_info *sb, u_char cmd, int val)
  189 {
  190 #if 0
  191         printf("sb_cmd2: %x, %x\n", cmd, val);
  192 #endif
  193         if (sb_dspwr(sb, cmd)) {
  194                 return sb_dspwr(sb, val & 0xff) &&
  195                        sb_dspwr(sb, (val >> 8) & 0xff);
  196         } else return 0;
  197 }
  198 
  199 /*
  200  * in the SB, there is a set of indirect "mixer" registers with
  201  * address at offset 4, data at offset 5
  202  *
  203  * we don't need to interlock these, the mixer lock will suffice.
  204  */
  205 static void
  206 sb_setmixer(struct sb_info *sb, u_int port, u_int value)
  207 {
  208         sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
  209         DELAY(10);
  210         sb_wr(sb, SB_MIX_DATA, (u_char) (value & 0xff));
  211         DELAY(10);
  212 }
  213 
  214 static int
  215 sb_getmixer(struct sb_info *sb, u_int port)
  216 {
  217         int val;
  218 
  219         sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
  220         DELAY(10);
  221         val = sb_rd(sb, SB_MIX_DATA);
  222         DELAY(10);
  223 
  224         return val;
  225 }
  226 
  227 static u_int
  228 sb_get_byte(struct sb_info *sb)
  229 {
  230         int i;
  231 
  232         for (i = 1000; i > 0; i--) {
  233                 if (sb_rd(sb, DSP_DATA_AVAIL) & 0x80)
  234                         return sb_rd(sb, DSP_READ);
  235                 else
  236                         DELAY(20);
  237         }
  238         return 0xffff;
  239 }
  240 
  241 static int
  242 sb_reset_dsp(struct sb_info *sb)
  243 {
  244         sb_wr(sb, SBDSP_RST, 3);
  245         DELAY(100);
  246         sb_wr(sb, SBDSP_RST, 0);
  247         if (sb_get_byte(sb) != 0xAA) {
  248                 DEB(printf("sb_reset_dsp 0x%lx failed\n",
  249                            rman_get_start(sb->io_base)));
  250                 return ENXIO;   /* Sorry */
  251         }
  252         return 0;
  253 }
  254 
  255 static void
  256 sb_release_resources(struct sb_info *sb, device_t dev)
  257 {
  258         if (sb->irq) {
  259                 if (sb->ih)
  260                         bus_teardown_intr(dev, sb->irq, sb->ih);
  261                 bus_release_resource(dev, SYS_RES_IRQ, 0, sb->irq);
  262                 sb->irq = 0;
  263         }
  264         if (sb->drq) {
  265                 isa_dma_release(rman_get_start(sb->drq));
  266                 bus_release_resource(dev, SYS_RES_DRQ, 0, sb->drq);
  267                 sb->drq = 0;
  268         }
  269         if (sb->io_base) {
  270                 bus_release_resource(dev, SYS_RES_IOPORT, 0, sb->io_base);
  271                 sb->io_base = 0;
  272         }
  273         if (sb->parent_dmat) {
  274                 bus_dma_tag_destroy(sb->parent_dmat);
  275                 sb->parent_dmat = 0;
  276         }
  277         free(sb, M_DEVBUF);
  278 }
  279 
  280 static int
  281 sb_alloc_resources(struct sb_info *sb, device_t dev)
  282 {
  283         int rid;
  284 
  285         rid = 0;
  286         if (!sb->io_base)
  287                 sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, RF_ACTIVE);
  288         rid = 0;
  289         if (!sb->irq)
  290                 sb->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_ACTIVE);
  291         rid = 0;
  292         if (!sb->drq)
  293                 sb->drq = bus_alloc_resource(dev, SYS_RES_DRQ, &rid, 0, ~0, 1, RF_ACTIVE);
  294 
  295         if (sb->io_base && sb->drq && sb->irq) {
  296                 isa_dma_acquire(rman_get_start(sb->drq));
  297                 isa_dmainit(rman_get_start(sb->drq), sb->bufsize);
  298 
  299                 return 0;
  300         } else return ENXIO;
  301 }
  302 
  303 /************************************************************/
  304 
  305 static int
  306 sbpromix_init(struct snd_mixer *m)
  307 {
  308         struct sb_info *sb = mix_getdevinfo(m);
  309 
  310         mix_setdevs(m, SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE |
  311                        SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_VOLUME);
  312 
  313         mix_setrecdevs(m, SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD);
  314 
  315         sb_setmixer(sb, 0, 1); /* reset mixer */
  316 
  317         return 0;
  318 }
  319 
  320 static int
  321 sbpromix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
  322 {
  323         struct sb_info *sb = mix_getdevinfo(m);
  324         int reg, max;
  325         u_char val;
  326 
  327         max = 7;
  328         switch (dev) {
  329         case SOUND_MIXER_PCM:
  330                 reg = 0x04;
  331                 break;
  332 
  333         case SOUND_MIXER_MIC:
  334                 reg = 0x0a;
  335                 max = 3;
  336                 break;
  337 
  338         case SOUND_MIXER_VOLUME:
  339                 reg = 0x22;
  340                 break;
  341 
  342         case SOUND_MIXER_SYNTH:
  343                 reg = 0x26;
  344                 break;
  345 
  346         case SOUND_MIXER_CD:
  347                 reg = 0x28;
  348                 break;
  349 
  350         case SOUND_MIXER_LINE:
  351                 reg = 0x2e;
  352                 break;
  353 
  354         default:
  355                 return -1;
  356         }
  357 
  358         left = (left * max) / 100;
  359         right = (dev == SOUND_MIXER_MIC)? left : ((right * max) / 100);
  360 
  361         val = (dev == SOUND_MIXER_MIC)? (left << 1) : (left << 5 | right << 1);
  362         sb_setmixer(sb, reg, val);
  363 
  364         left = (left * 100) / max;
  365         right = (right * 100) / max;
  366 
  367         return left | (right << 8);
  368 }
  369 
  370 static int
  371 sbpromix_setrecsrc(struct snd_mixer *m, u_int32_t src)
  372 {
  373         struct sb_info *sb = mix_getdevinfo(m);
  374         u_char recdev;
  375 
  376         if      (src == SOUND_MASK_LINE)
  377                 recdev = 0x06;
  378         else if (src == SOUND_MASK_CD)
  379                 recdev = 0x02;
  380         else { /* default: mic */
  381                 src = SOUND_MASK_MIC;
  382                 recdev = 0;
  383         }
  384         sb_setmixer(sb, RECORD_SRC, recdev | (sb_getmixer(sb, RECORD_SRC) & ~0x07));
  385 
  386         return src;
  387 }
  388 
  389 static kobj_method_t sbpromix_mixer_methods[] = {
  390         KOBJMETHOD(mixer_init,          sbpromix_init),
  391         KOBJMETHOD(mixer_set,           sbpromix_set),
  392         KOBJMETHOD(mixer_setrecsrc,     sbpromix_setrecsrc),
  393         { 0, 0 }
  394 };
  395 MIXER_DECLARE(sbpromix_mixer);
  396 
  397 /************************************************************/
  398 
  399 static int
  400 sbmix_init(struct snd_mixer *m)
  401 {
  402         struct sb_info *sb = mix_getdevinfo(m);
  403 
  404         mix_setdevs(m, SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_CD | SOUND_MASK_VOLUME);
  405 
  406         mix_setrecdevs(m, 0);
  407 
  408         sb_setmixer(sb, 0, 1); /* reset mixer */
  409 
  410         return 0;
  411 }
  412 
  413 static int
  414 sbmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
  415 {
  416         struct sb_info *sb = mix_getdevinfo(m);
  417         int reg, max;
  418 
  419         max = 7;
  420         switch (dev) {
  421         case SOUND_MIXER_VOLUME:
  422                 reg = 0x2;
  423                 break;
  424 
  425         case SOUND_MIXER_SYNTH:
  426                 reg = 0x6;
  427                 break;
  428 
  429         case SOUND_MIXER_CD:
  430                 reg = 0x8;
  431                 break;
  432 
  433         case SOUND_MIXER_PCM:
  434                 reg = 0x0a;
  435                 max = 3;
  436                 break;
  437 
  438         default:
  439                 return -1;
  440         }
  441 
  442         left = (left * max) / 100;
  443 
  444         sb_setmixer(sb, reg, left << 1);
  445 
  446         left = (left * 100) / max;
  447 
  448         return left | (left << 8);
  449 }
  450 
  451 static int
  452 sbmix_setrecsrc(struct snd_mixer *m, u_int32_t src)
  453 {
  454         return 0;
  455 }
  456 
  457 static kobj_method_t sbmix_mixer_methods[] = {
  458         KOBJMETHOD(mixer_init,          sbmix_init),
  459         KOBJMETHOD(mixer_set,           sbmix_set),
  460         KOBJMETHOD(mixer_setrecsrc,     sbmix_setrecsrc),
  461         { 0, 0 }
  462 };
  463 MIXER_DECLARE(sbmix_mixer);
  464 
  465 /************************************************************/
  466 
  467 static void
  468 sb_intr(void *arg)
  469 {
  470         struct sb_info *sb = (struct sb_info *)arg;
  471 
  472         sb_lock(sb);
  473         if (sndbuf_runsz(sb->pch.buffer) > 0)
  474                 chn_intr(sb->pch.channel);
  475 
  476         if (sndbuf_runsz(sb->rch.buffer) > 0)
  477                 chn_intr(sb->rch.channel);
  478 
  479         sb_rd(sb, DSP_DATA_AVAIL); /* int ack */
  480         sb_unlock(sb);
  481 }
  482 
  483 static int
  484 sb_speed(struct sb_chinfo *ch)
  485 {
  486         struct sb_info *sb = ch->parent;
  487         int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
  488         int stereo = (ch->fmt & AFMT_STEREO)? 1 : 0;
  489         int speed, tmp, thresh, max;
  490         u_char tconst;
  491 
  492         if (sb->bd_id >= 0x300) {
  493                 thresh = stereo? 11025 : 23000;
  494                 max = stereo? 22050 : 44100;
  495         } else if (sb->bd_id > 0x200) {
  496                 thresh = play? 23000 : 13000;
  497                 max = play? 44100 : 15000;
  498         } else {
  499                 thresh = 999999;
  500                 max = play? 23000 : 13000;
  501         }
  502 
  503         speed = ch->spd;
  504         if (speed > max)
  505                 speed = max;
  506 
  507         sb_lock(sb);
  508         sb->bd_flags &= ~BD_F_HISPEED;
  509         if (speed > thresh)
  510                 sb->bd_flags |= BD_F_HISPEED;
  511 
  512         tmp = 65536 - (256000000 / (speed << stereo));
  513         tconst = tmp >> 8;
  514 
  515         sb_cmd1(sb, 0x40, tconst); /* set time constant */
  516 
  517         speed = (256000000 / (65536 - tmp)) >> stereo;
  518 
  519         ch->spd = speed;
  520         sb_unlock(sb);
  521         return speed;
  522 }
  523 
  524 static int
  525 sb_start(struct sb_chinfo *ch)
  526 {
  527         struct sb_info *sb = ch->parent;
  528         int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
  529         int stereo = (ch->fmt & AFMT_STEREO)? 1 : 0;
  530         int l = ch->blksz;
  531         u_char i;
  532 
  533         l--;
  534 
  535         sb_lock(sb);
  536         if (play)
  537                 sb_cmd(sb, DSP_CMD_SPKON);
  538 
  539         if (sb->bd_flags & BD_F_HISPEED)
  540                 i = play? 0x90 : 0x98;
  541         else
  542                 i = play? 0x1c : 0x2c;
  543 
  544         sb_setmixer(sb, 0x0e, stereo? 2 : 0);
  545         sb_cmd2(sb, 0x48, l);
  546         sb_cmd(sb, i);
  547 
  548         sb->bd_flags |= BD_F_DMARUN;
  549         sb_unlock(sb);
  550         return 0;
  551 }
  552 
  553 static int
  554 sb_stop(struct sb_chinfo *ch)
  555 {
  556         struct sb_info *sb = ch->parent;
  557         int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
  558 
  559         sb_lock(sb);
  560         if (sb->bd_flags & BD_F_HISPEED)
  561                 sb_reset_dsp(sb);
  562         else
  563                 sb_cmd(sb, DSP_CMD_DMAEXIT_8);
  564 
  565         if (play)
  566                 sb_cmd(sb, DSP_CMD_SPKOFF); /* speaker off */
  567         sb_unlock(sb);
  568         sb->bd_flags &= ~BD_F_DMARUN;
  569         return 0;
  570 }
  571 
  572 /* channel interface */
  573 static void *
  574 sbchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
  575 {
  576         struct sb_info *sb = devinfo;
  577         struct sb_chinfo *ch = (dir == PCMDIR_PLAY)? &sb->pch : &sb->rch;
  578 
  579         ch->parent = sb;
  580         ch->channel = c;
  581         ch->dir = dir;
  582         ch->buffer = b;
  583         if (sndbuf_alloc(ch->buffer, sb->parent_dmat, sb->bufsize) == -1)
  584                 return NULL;
  585         sndbuf_isadmasetup(ch->buffer, sb->drq);
  586         return ch;
  587 }
  588 
  589 static int
  590 sbchan_setformat(kobj_t obj, void *data, u_int32_t format)
  591 {
  592         struct sb_chinfo *ch = data;
  593 
  594         ch->fmt = format;
  595         return 0;
  596 }
  597 
  598 static int
  599 sbchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
  600 {
  601         struct sb_chinfo *ch = data;
  602 
  603         ch->spd = speed;
  604         return sb_speed(ch);
  605 }
  606 
  607 static int
  608 sbchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
  609 {
  610         struct sb_chinfo *ch = data;
  611 
  612         ch->blksz = blocksize;
  613         return ch->blksz;
  614 }
  615 
  616 static int
  617 sbchan_trigger(kobj_t obj, void *data, int go)
  618 {
  619         struct sb_chinfo *ch = data;
  620 
  621         if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
  622                 return 0;
  623 
  624         sndbuf_isadma(ch->buffer, go);
  625         if (go == PCMTRIG_START)
  626                 sb_start(ch);
  627         else
  628                 sb_stop(ch);
  629         return 0;
  630 }
  631 
  632 static int
  633 sbchan_getptr(kobj_t obj, void *data)
  634 {
  635         struct sb_chinfo *ch = data;
  636 
  637         return sndbuf_isadmaptr(ch->buffer);
  638 }
  639 
  640 static struct pcmchan_caps *
  641 sbchan_getcaps(kobj_t obj, void *data)
  642 {
  643         struct sb_chinfo *ch = data;
  644         int p = (ch->dir == PCMDIR_PLAY)? 1 : 0;
  645 
  646         if (ch->parent->bd_id == 0x200)
  647                 return p? &sb200_playcaps : &sb200_reccaps;
  648         if (ch->parent->bd_id < 0x300)
  649                 return p? &sb201_playcaps : &sb201_reccaps;
  650         return p? &sbpro_playcaps : &sbpro_reccaps;
  651 }
  652 
  653 static kobj_method_t sbchan_methods[] = {
  654         KOBJMETHOD(channel_init,                sbchan_init),
  655         KOBJMETHOD(channel_setformat,           sbchan_setformat),
  656         KOBJMETHOD(channel_setspeed,            sbchan_setspeed),
  657         KOBJMETHOD(channel_setblocksize,        sbchan_setblocksize),
  658         KOBJMETHOD(channel_trigger,             sbchan_trigger),
  659         KOBJMETHOD(channel_getptr,              sbchan_getptr),
  660         KOBJMETHOD(channel_getcaps,             sbchan_getcaps),
  661         { 0, 0 }
  662 };
  663 CHANNEL_DECLARE(sbchan);
  664 
  665 /************************************************************/
  666 
  667 static int
  668 sb_probe(device_t dev)
  669 {
  670         char buf[64];
  671         uintptr_t func, ver, r, f;
  672 
  673         /* The parent device has already been probed. */
  674         r = BUS_READ_IVAR(device_get_parent(dev), dev, 0, &func);
  675         if (func != SCF_PCM)
  676                 return (ENXIO);
  677 
  678         r = BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver);
  679         f = (ver & 0xffff0000) >> 16;
  680         ver &= 0x0000ffff;
  681         if ((f & BD_F_ESS) || (ver >= 0x400))
  682                 return (ENXIO);
  683 
  684         snprintf(buf, sizeof buf, "SB DSP %d.%02d", (int) ver >> 8, (int) ver & 0xff);
  685 
  686         device_set_desc_copy(dev, buf);
  687 
  688         return 0;
  689 }
  690 
  691 static int
  692 sb_attach(device_t dev)
  693 {
  694         struct sb_info *sb;
  695         char status[SND_STATUSLEN];
  696         uintptr_t ver;
  697 
  698         sb = (struct sb_info *)malloc(sizeof *sb, M_DEVBUF, M_NOWAIT | M_ZERO);
  699         if (!sb)
  700                 return ENXIO;
  701 
  702         sb->parent_dev = device_get_parent(dev);
  703         BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver);
  704         sb->bd_id = ver & 0x0000ffff;
  705         sb->bd_flags = (ver & 0xffff0000) >> 16;
  706         sb->bufsize = pcm_getbuffersize(dev, 4096, SB_DEFAULT_BUFSZ, 65536);
  707 
  708         if (sb_alloc_resources(sb, dev))
  709                 goto no;
  710         if (sb_reset_dsp(sb))
  711                 goto no;
  712         if (mixer_init(dev, (sb->bd_id < 0x300)? &sbmix_mixer_class : &sbpromix_mixer_class, sb))
  713                 goto no;
  714         if (snd_setup_intr(dev, sb->irq, INTR_MPSAFE, sb_intr, sb, &sb->ih))
  715                 goto no;
  716 
  717         pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX);
  718 
  719         if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
  720                         /*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
  721                         /*highaddr*/BUS_SPACE_MAXADDR,
  722                         /*filter*/NULL, /*filterarg*/NULL,
  723                         /*maxsize*/sb->bufsize, /*nsegments*/1,
  724                         /*maxsegz*/0x3ffff,
  725                         /*flags*/0, &sb->parent_dmat) != 0) {
  726                 device_printf(dev, "unable to create dma tag\n");
  727                 goto no;
  728         }
  729 
  730         snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld bufsz %u",
  731                 rman_get_start(sb->io_base), rman_get_start(sb->irq), rman_get_start(sb->drq), sb->bufsize);
  732 
  733         if (pcm_register(dev, sb, 1, 1))
  734                 goto no;
  735         pcm_addchan(dev, PCMDIR_REC, &sbchan_class, sb);
  736         pcm_addchan(dev, PCMDIR_PLAY, &sbchan_class, sb);
  737 
  738         pcm_setstatus(dev, status);
  739 
  740         return 0;
  741 
  742 no:
  743         sb_release_resources(sb, dev);
  744         return ENXIO;
  745 }
  746 
  747 static int
  748 sb_detach(device_t dev)
  749 {
  750         int r;
  751         struct sb_info *sb;
  752 
  753         r = pcm_unregister(dev);
  754         if (r)
  755                 return r;
  756 
  757         sb = pcm_getdevinfo(dev);
  758         sb_release_resources(sb, dev);
  759         return 0;
  760 }
  761 
  762 static device_method_t sb_methods[] = {
  763         /* Device interface */
  764         DEVMETHOD(device_probe,         sb_probe),
  765         DEVMETHOD(device_attach,        sb_attach),
  766         DEVMETHOD(device_detach,        sb_detach),
  767 
  768         { 0, 0 }
  769 };
  770 
  771 static driver_t sb_driver = {
  772         "pcm",
  773         sb_methods,
  774         PCM_SOFTC_SIZE,
  775 };
  776 
  777 DRIVER_MODULE(snd_sb8, sbc, sb_driver, pcm_devclass, 0, 0);
  778 MODULE_DEPEND(snd_sb8, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER);
  779 MODULE_DEPEND(snd_sb8, snd_sbc, 1, 1, 1);
  780 MODULE_VERSION(snd_sb8, 1);
  781 
  782 
  783 
  784 

Cache object: 490626e93beed9a32f4ffba7db48153f


[ 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.