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/ad1816.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 Luigi Rizzo, 1997,1998
    4  * Copyright by Hannu Savolainen 1994, 1995
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <dev/sound/pcm/sound.h>
   30 #include <dev/sound/isa/ad1816.h>
   31 
   32 #include "mixer_if.h"
   33 
   34 SND_DECLARE_FILE("$FreeBSD$");
   35 
   36 struct ad1816_info;
   37 
   38 struct ad1816_chinfo {
   39         struct ad1816_info *parent;
   40         struct pcm_channel *channel;
   41         struct snd_dbuf *buffer;
   42         int dir, blksz;
   43 };
   44 
   45 struct ad1816_info {
   46         struct resource *io_base;       /* primary I/O address for the board */
   47         int io_rid;
   48         struct resource *irq;
   49         int irq_rid;
   50         struct resource *drq1;          /* play */
   51         int drq1_rid;
   52         struct resource *drq2;          /* rec */
   53         int drq2_rid;
   54         void *ih;
   55         bus_dma_tag_t parent_dmat;
   56         void *lock;
   57 
   58         unsigned int bufsize;
   59         struct ad1816_chinfo pch, rch;
   60 };
   61 
   62 static u_int32_t ad1816_fmt[] = {
   63         AFMT_U8,
   64         AFMT_STEREO | AFMT_U8,
   65         AFMT_S16_LE,
   66         AFMT_STEREO | AFMT_S16_LE,
   67         AFMT_MU_LAW,
   68         AFMT_STEREO | AFMT_MU_LAW,
   69         AFMT_A_LAW,
   70         AFMT_STEREO | AFMT_A_LAW,
   71         0
   72 };
   73 
   74 static struct pcmchan_caps ad1816_caps = {4000, 55200, ad1816_fmt, 0};
   75 
   76 #define AD1816_MUTE 31          /* value for mute */
   77 
   78 static void
   79 ad1816_lock(struct ad1816_info *ad1816)
   80 {
   81         snd_mtxlock(ad1816->lock);
   82 }
   83 
   84 static void
   85 ad1816_unlock(struct ad1816_info *ad1816)
   86 {
   87         snd_mtxunlock(ad1816->lock);
   88 }
   89 
   90 static int
   91 port_rd(struct resource *port, int off)
   92 {
   93         if (port)
   94                 return bus_space_read_1(rman_get_bustag(port),
   95                                         rman_get_bushandle(port),
   96                                         off);
   97         else
   98                 return -1;
   99 }
  100 
  101 static void
  102 port_wr(struct resource *port, int off, u_int8_t data)
  103 {
  104         if (port)
  105                 bus_space_write_1(rman_get_bustag(port),
  106                                   rman_get_bushandle(port),
  107                                   off, data);
  108 }
  109 
  110 static int
  111 io_rd(struct ad1816_info *ad1816, int reg)
  112 {
  113         return port_rd(ad1816->io_base, reg);
  114 }
  115 
  116 static void
  117 io_wr(struct ad1816_info *ad1816, int reg, u_int8_t data)
  118 {
  119         port_wr(ad1816->io_base, reg, data);
  120 }
  121 
  122 static void
  123 ad1816_intr(void *arg)
  124 {
  125         struct ad1816_info *ad1816 = (struct ad1816_info *)arg;
  126         unsigned char   c, served = 0;
  127 
  128         ad1816_lock(ad1816);
  129         /* get interupt status */
  130         c = io_rd(ad1816, AD1816_INT);
  131 
  132         /* check for stray interupts */
  133         if (c & ~(AD1816_INTRCI | AD1816_INTRPI)) {
  134                 printf("pcm: stray int (%x)\n", c);
  135                 c &= AD1816_INTRCI | AD1816_INTRPI;
  136         }
  137         /* check for capture interupt */
  138         if (sndbuf_runsz(ad1816->rch.buffer) && (c & AD1816_INTRCI)) {
  139                 chn_intr(ad1816->rch.channel);
  140                 served |= AD1816_INTRCI;                /* cp served */
  141         }
  142         /* check for playback interupt */
  143         if (sndbuf_runsz(ad1816->pch.buffer) && (c & AD1816_INTRPI)) {
  144                 chn_intr(ad1816->pch.channel);
  145                 served |= AD1816_INTRPI;                /* pb served */
  146         }
  147         if (served == 0) {
  148                 /* this probably means this is not a (working) ad1816 chip, */
  149                 /* or an error in dma handling                              */
  150                 printf("pcm: int without reason (%x)\n", c);
  151                 c = 0;
  152         } else c &= ~served;
  153         io_wr(ad1816, AD1816_INT, c);
  154         c = io_rd(ad1816, AD1816_INT);
  155         if (c != 0) printf("pcm: int clear failed (%x)\n", c);
  156         ad1816_unlock(ad1816);
  157 }
  158 
  159 static int
  160 ad1816_wait_init(struct ad1816_info *ad1816, int x)
  161 {
  162         int             n = 0;  /* to shut up the compiler... */
  163 
  164         for (; x--;)
  165                 if ((n = (io_rd(ad1816, AD1816_ALE) & AD1816_BUSY)) == 0) DELAY(10);
  166                 else return n;
  167         printf("ad1816_wait_init failed 0x%02x.\n", n);
  168         return -1;
  169 }
  170 
  171 static unsigned short
  172 ad1816_read(struct ad1816_info *ad1816, unsigned int reg)
  173 {
  174         u_short         x = 0;
  175 
  176         if (ad1816_wait_init(ad1816, 100) == -1) return 0;
  177         io_wr(ad1816, AD1816_ALE, 0);
  178         io_wr(ad1816, AD1816_ALE, (reg & AD1816_ALEMASK));
  179         if (ad1816_wait_init(ad1816, 100) == -1) return 0;
  180         x = (io_rd(ad1816, AD1816_HIGH) << 8) | io_rd(ad1816, AD1816_LOW);
  181         return x;
  182 }
  183 
  184 static void
  185 ad1816_write(struct ad1816_info *ad1816, unsigned int reg, unsigned short data)
  186 {
  187         if (ad1816_wait_init(ad1816, 100) == -1) return;
  188         io_wr(ad1816, AD1816_ALE, (reg & AD1816_ALEMASK));
  189         io_wr(ad1816, AD1816_LOW,  (data & 0x000000ff));
  190         io_wr(ad1816, AD1816_HIGH, (data & 0x0000ff00) >> 8);
  191 }
  192 
  193 /* -------------------------------------------------------------------- */
  194 
  195 static int
  196 ad1816mix_init(struct snd_mixer *m)
  197 {
  198         mix_setdevs(m, AD1816_MIXER_DEVICES);
  199         mix_setrecdevs(m, AD1816_REC_DEVICES);
  200         return 0;
  201 }
  202 
  203 static int
  204 ad1816mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
  205 {
  206         struct ad1816_info *ad1816 = mix_getdevinfo(m);
  207         u_short reg = 0;
  208 
  209         /* Scale volumes */
  210         left = AD1816_MUTE - (AD1816_MUTE * left) / 100;
  211         right = AD1816_MUTE - (AD1816_MUTE * right) / 100;
  212 
  213         reg = (left << 8) | right;
  214 
  215         /* do channel selective muting if volume is zero */
  216         if (left == AD1816_MUTE)        reg |= 0x8000;
  217         if (right == AD1816_MUTE)       reg |= 0x0080;
  218 
  219         ad1816_lock(ad1816);
  220         switch (dev) {
  221         case SOUND_MIXER_VOLUME:        /* Register 14 master volume */
  222                 ad1816_write(ad1816, 14, reg);
  223                 break;
  224 
  225         case SOUND_MIXER_CD:    /* Register 15 cd */
  226         case SOUND_MIXER_LINE1:
  227                 ad1816_write(ad1816, 15, reg);
  228                 break;
  229 
  230         case SOUND_MIXER_SYNTH: /* Register 16 synth */
  231                 ad1816_write(ad1816, 16, reg);
  232                 break;
  233 
  234         case SOUND_MIXER_PCM:   /* Register 4 pcm */
  235                 ad1816_write(ad1816, 4, reg);
  236                 break;
  237 
  238         case SOUND_MIXER_LINE:
  239         case SOUND_MIXER_LINE3: /* Register 18 line in */
  240                 ad1816_write(ad1816, 18, reg);
  241                 break;
  242 
  243         case SOUND_MIXER_MIC:   /* Register 19 mic volume */
  244                 ad1816_write(ad1816, 19, reg & ~0xff);  /* mic is mono */
  245                 break;
  246 
  247         case SOUND_MIXER_IGAIN:
  248                 /* and now to something completely different ... */
  249                 ad1816_write(ad1816, 20, ((ad1816_read(ad1816, 20) & ~0x0f0f)
  250                 | (((AD1816_MUTE - left) / 2) << 8) /* four bits of adc gain */
  251                 | ((AD1816_MUTE - right) / 2)));
  252                 break;
  253 
  254         default:
  255                 printf("ad1816_mixer_set(): unknown device.\n");
  256                 break;
  257         }
  258         ad1816_unlock(ad1816);
  259 
  260         left = ((AD1816_MUTE - left) * 100) / AD1816_MUTE;
  261         right = ((AD1816_MUTE - right) * 100) / AD1816_MUTE;
  262 
  263         return left | (right << 8);
  264 }
  265 
  266 static int
  267 ad1816mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
  268 {
  269         struct ad1816_info *ad1816 = mix_getdevinfo(m);
  270         int dev;
  271 
  272         switch (src) {
  273         case SOUND_MASK_LINE:
  274         case SOUND_MASK_LINE3:
  275                 dev = 0x00;
  276                 break;
  277 
  278         case SOUND_MASK_CD:
  279         case SOUND_MASK_LINE1:
  280                 dev = 0x20;
  281                 break;
  282 
  283         case SOUND_MASK_MIC:
  284         default:
  285                 dev = 0x50;
  286                 src = SOUND_MASK_MIC;
  287         }
  288 
  289         dev |= dev << 8;
  290         ad1816_lock(ad1816);
  291         ad1816_write(ad1816, 20, (ad1816_read(ad1816, 20) & ~0x7070) | dev);
  292         ad1816_unlock(ad1816);
  293         return src;
  294 }
  295 
  296 static kobj_method_t ad1816mixer_methods[] = {
  297         KOBJMETHOD(mixer_init,          ad1816mix_init),
  298         KOBJMETHOD(mixer_set,           ad1816mix_set),
  299         KOBJMETHOD(mixer_setrecsrc,     ad1816mix_setrecsrc),
  300         { 0, 0 }
  301 };
  302 MIXER_DECLARE(ad1816mixer);
  303 
  304 /* -------------------------------------------------------------------- */
  305 /* channel interface */
  306 static void *
  307 ad1816chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
  308 {
  309         struct ad1816_info *ad1816 = devinfo;
  310         struct ad1816_chinfo *ch = (dir == PCMDIR_PLAY)? &ad1816->pch : &ad1816->rch;
  311 
  312         ch->parent = ad1816;
  313         ch->channel = c;
  314         ch->buffer = b;
  315         if (sndbuf_alloc(ch->buffer, ad1816->parent_dmat, ad1816->bufsize) == -1) return NULL;
  316         return ch;
  317 }
  318 
  319 static int
  320 ad1816chan_setdir(kobj_t obj, void *data, int dir)
  321 {
  322         struct ad1816_chinfo *ch = data;
  323         struct ad1816_info *ad1816 = ch->parent;
  324 
  325         sndbuf_isadmasetup(ch->buffer, (dir == PCMDIR_PLAY)? ad1816->drq1 : ad1816->drq2);
  326         ch->dir = dir;
  327         return 0;
  328 }
  329 
  330 static int
  331 ad1816chan_setformat(kobj_t obj, void *data, u_int32_t format)
  332 {
  333         struct ad1816_chinfo *ch = data;
  334         struct ad1816_info *ad1816 = ch->parent;
  335         int fmt = AD1816_U8, reg;
  336 
  337         ad1816_lock(ad1816);
  338         if (ch->dir == PCMDIR_PLAY) {
  339                 reg = AD1816_PLAY;
  340                 ad1816_write(ad1816, 8, 0x0000);        /* reset base and current counter */
  341                 ad1816_write(ad1816, 9, 0x0000);        /* for playback and capture */
  342         } else {
  343                 reg = AD1816_CAPT;
  344                 ad1816_write(ad1816, 10, 0x0000);
  345                 ad1816_write(ad1816, 11, 0x0000);
  346         }
  347         switch (format & ~AFMT_STEREO) {
  348         case AFMT_A_LAW:
  349                 fmt = AD1816_ALAW;
  350                 break;
  351 
  352         case AFMT_MU_LAW:
  353                 fmt = AD1816_MULAW;
  354                 break;
  355 
  356         case AFMT_S16_LE:
  357                 fmt = AD1816_S16LE;
  358                 break;
  359 
  360         case AFMT_S16_BE:
  361                 fmt = AD1816_S16BE;
  362                 break;
  363 
  364         case AFMT_U8:
  365                 fmt = AD1816_U8;
  366                 break;
  367         }
  368         if (format & AFMT_STEREO) fmt |= AD1816_STEREO;
  369         io_wr(ad1816, reg, fmt);
  370         ad1816_unlock(ad1816);
  371 
  372         return (0);
  373 }
  374 
  375 static int
  376 ad1816chan_setspeed(kobj_t obj, void *data, u_int32_t speed)
  377 {
  378         struct ad1816_chinfo *ch = data;
  379         struct ad1816_info *ad1816 = ch->parent;
  380 
  381         RANGE(speed, 4000, 55200);
  382         ad1816_lock(ad1816);
  383         ad1816_write(ad1816, (ch->dir == PCMDIR_PLAY)? 2 : 3, speed);
  384         ad1816_unlock(ad1816);
  385         return speed;
  386 }
  387 
  388 static int
  389 ad1816chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
  390 {
  391         struct ad1816_chinfo *ch = data;
  392 
  393         ch->blksz = blocksize;
  394         return ch->blksz;
  395 }
  396 
  397 static int
  398 ad1816chan_trigger(kobj_t obj, void *data, int go)
  399 {
  400         struct ad1816_chinfo *ch = data;
  401         struct ad1816_info *ad1816 = ch->parent;
  402         int wr, reg;
  403 
  404         if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
  405                 return 0;
  406 
  407         sndbuf_isadma(ch->buffer, go);
  408         wr = (ch->dir == PCMDIR_PLAY);
  409         reg = wr? AD1816_PLAY : AD1816_CAPT;
  410         ad1816_lock(ad1816);
  411         switch (go) {
  412         case PCMTRIG_START:
  413                 /* start only if not already running */
  414                 if (!(io_rd(ad1816, reg) & AD1816_ENABLE)) {
  415                         int cnt = ((ch->blksz) >> 2) - 1;
  416                         ad1816_write(ad1816, wr? 8 : 10, cnt); /* count */
  417                         ad1816_write(ad1816, wr? 9 : 11, 0); /* reset cur cnt */
  418                         ad1816_write(ad1816, 1, ad1816_read(ad1816, 1) |
  419                                      (wr? 0x8000 : 0x4000)); /* enable int */
  420                         /* enable playback */
  421                         io_wr(ad1816, reg, io_rd(ad1816, reg) | AD1816_ENABLE);
  422                         if (!(io_rd(ad1816, reg) & AD1816_ENABLE))
  423                                 printf("ad1816: failed to start %s DMA!\n",
  424                                        wr? "play" : "rec");
  425                 }
  426                 break;
  427 
  428         case PCMTRIG_STOP:
  429         case PCMTRIG_ABORT:             /* XXX check this... */
  430                 /* we don't test here if it is running... */
  431                 if (wr) {
  432                         ad1816_write(ad1816, 1, ad1816_read(ad1816, 1) &
  433                                      ~(wr? 0x8000 : 0x4000));
  434                         /* disable int */
  435                         io_wr(ad1816, reg, io_rd(ad1816, reg) & ~AD1816_ENABLE);
  436                         /* disable playback */
  437                         if (io_rd(ad1816, reg) & AD1816_ENABLE)
  438                                 printf("ad1816: failed to stop %s DMA!\n",
  439                                        wr? "play" : "rec");
  440                         ad1816_write(ad1816, wr? 8 : 10, 0); /* reset base cnt */
  441                         ad1816_write(ad1816, wr? 9 : 11, 0); /* reset cur cnt */
  442                 }
  443                 break;
  444         }
  445         ad1816_unlock(ad1816);
  446         return 0;
  447 }
  448 
  449 static int
  450 ad1816chan_getptr(kobj_t obj, void *data)
  451 {
  452         struct ad1816_chinfo *ch = data;
  453         return sndbuf_isadmaptr(ch->buffer);
  454 }
  455 
  456 static struct pcmchan_caps *
  457 ad1816chan_getcaps(kobj_t obj, void *data)
  458 {
  459         return &ad1816_caps;
  460 }
  461 
  462 static kobj_method_t ad1816chan_methods[] = {
  463         KOBJMETHOD(channel_init,                ad1816chan_init),
  464         KOBJMETHOD(channel_setdir,              ad1816chan_setdir),
  465         KOBJMETHOD(channel_setformat,           ad1816chan_setformat),
  466         KOBJMETHOD(channel_setspeed,            ad1816chan_setspeed),
  467         KOBJMETHOD(channel_setblocksize,        ad1816chan_setblocksize),
  468         KOBJMETHOD(channel_trigger,             ad1816chan_trigger),
  469         KOBJMETHOD(channel_getptr,              ad1816chan_getptr),
  470         KOBJMETHOD(channel_getcaps,             ad1816chan_getcaps),
  471         { 0, 0 }
  472 };
  473 CHANNEL_DECLARE(ad1816chan);
  474 
  475 /* -------------------------------------------------------------------- */
  476 
  477 static void
  478 ad1816_release_resources(struct ad1816_info *ad1816, device_t dev)
  479 {
  480         if (ad1816->irq) {
  481                 if (ad1816->ih)
  482                         bus_teardown_intr(dev, ad1816->irq, ad1816->ih);
  483                 bus_release_resource(dev, SYS_RES_IRQ, ad1816->irq_rid, ad1816->irq);
  484                 ad1816->irq = 0;
  485         }
  486         if (ad1816->drq1) {
  487                 isa_dma_release(rman_get_start(ad1816->drq1));
  488                 bus_release_resource(dev, SYS_RES_DRQ, ad1816->drq1_rid, ad1816->drq1);
  489                 ad1816->drq1 = 0;
  490         }
  491         if (ad1816->drq2) {
  492                 isa_dma_release(rman_get_start(ad1816->drq2));
  493                 bus_release_resource(dev, SYS_RES_DRQ, ad1816->drq2_rid, ad1816->drq2);
  494                 ad1816->drq2 = 0;
  495         }
  496         if (ad1816->io_base) {
  497                 bus_release_resource(dev, SYS_RES_IOPORT, ad1816->io_rid, ad1816->io_base);
  498                 ad1816->io_base = 0;
  499         }
  500         if (ad1816->parent_dmat) {
  501                 bus_dma_tag_destroy(ad1816->parent_dmat);
  502                 ad1816->parent_dmat = 0;
  503         }
  504         if (ad1816->lock)
  505                 snd_mtxfree(ad1816->lock);
  506 
  507         free(ad1816, M_DEVBUF);
  508 }
  509 
  510 static int
  511 ad1816_alloc_resources(struct ad1816_info *ad1816, device_t dev)
  512 {
  513         int ok = 1, pdma, rdma;
  514 
  515         if (!ad1816->io_base)
  516                 ad1816->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT, &ad1816->io_rid,
  517                                                   0, ~0, 1, RF_ACTIVE);
  518         if (!ad1816->irq)
  519                 ad1816->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &ad1816->irq_rid,
  520                                               0, ~0, 1, RF_ACTIVE);
  521         if (!ad1816->drq1)
  522                 ad1816->drq1 = bus_alloc_resource(dev, SYS_RES_DRQ, &ad1816->drq1_rid,
  523                                                0, ~0, 1, RF_ACTIVE);
  524         if (!ad1816->drq2)
  525                 ad1816->drq2 = bus_alloc_resource(dev, SYS_RES_DRQ, &ad1816->drq2_rid,
  526                                                0, ~0, 1, RF_ACTIVE);
  527 
  528         if (!ad1816->io_base || !ad1816->drq1 || !ad1816->irq) ok = 0;
  529 
  530         if (ok) {
  531                 pdma = rman_get_start(ad1816->drq1);
  532                 isa_dma_acquire(pdma);
  533                 isa_dmainit(pdma, ad1816->bufsize);
  534                 if (ad1816->drq2) {
  535                         rdma = rman_get_start(ad1816->drq2);
  536                         isa_dma_acquire(rdma);
  537                         isa_dmainit(rdma, ad1816->bufsize);
  538                 } else
  539                         rdma = pdma;
  540                 if (pdma == rdma)
  541                         pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX);
  542         }
  543 
  544         return ok;
  545 }
  546 
  547 static int
  548 ad1816_init(struct ad1816_info *ad1816, device_t dev)
  549 {
  550         ad1816_write(ad1816, 1, 0x2);   /* disable interrupts */
  551         ad1816_write(ad1816, 32, 0x90F0);       /* SoundSys Mode, split fmt */
  552 
  553         ad1816_write(ad1816, 5, 0x8080);        /* FM volume mute */
  554         ad1816_write(ad1816, 6, 0x8080);        /* I2S1 volume mute */
  555         ad1816_write(ad1816, 7, 0x8080);        /* I2S0 volume mute */
  556         ad1816_write(ad1816, 17, 0x8888);       /* VID Volume mute */
  557         ad1816_write(ad1816, 20, 0x5050);       /* recsrc mic, agc off */
  558         /* adc gain is set to 0 */
  559 
  560         return 0;
  561 }
  562 
  563 static int
  564 ad1816_probe(device_t dev)
  565 {
  566         char *s = NULL;
  567         u_int32_t logical_id = isa_get_logicalid(dev);
  568 
  569         switch (logical_id) {
  570         case 0x80719304: /* ADS7180 */
  571                 s = "AD1816";
  572                 break;
  573         }
  574 
  575         if (s) {
  576                 device_set_desc(dev, s);
  577                 return 0;
  578         }
  579         return ENXIO;
  580 }
  581 
  582 static int
  583 ad1816_attach(device_t dev)
  584 {
  585         struct ad1816_info *ad1816;
  586         char status[SND_STATUSLEN], status2[SND_STATUSLEN];
  587 
  588         ad1816 = (struct ad1816_info *)malloc(sizeof *ad1816, M_DEVBUF, M_NOWAIT | M_ZERO);
  589         if (!ad1816) return ENXIO;
  590 
  591         ad1816->lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc");
  592         ad1816->io_rid = 2;
  593         ad1816->irq_rid = 0;
  594         ad1816->drq1_rid = 0;
  595         ad1816->drq2_rid = 1;
  596         ad1816->bufsize = pcm_getbuffersize(dev, 4096, DSP_BUFFSIZE, 65536);
  597 
  598         if (!ad1816_alloc_resources(ad1816, dev)) goto no;
  599         ad1816_init(ad1816, dev);
  600         if (mixer_init(dev, &ad1816mixer_class, ad1816)) goto no;
  601 
  602         snd_setup_intr(dev, ad1816->irq, INTR_MPSAFE, ad1816_intr, ad1816, &ad1816->ih);
  603         if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
  604                         /*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
  605                         /*highaddr*/BUS_SPACE_MAXADDR,
  606                         /*filter*/NULL, /*filterarg*/NULL,
  607                         /*maxsize*/ad1816->bufsize, /*nsegments*/1,
  608                         /*maxsegz*/0x3ffff,
  609                         /*flags*/0, &ad1816->parent_dmat) != 0) {
  610                 device_printf(dev, "unable to create dma tag\n");
  611                 goto no;
  612         }
  613         if (ad1816->drq2)
  614                 snprintf(status2, SND_STATUSLEN, ":%ld", rman_get_start(ad1816->drq2));
  615         else
  616                 status2[0] = '\0';
  617 
  618         snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld%s bufsz %u",
  619                 rman_get_start(ad1816->io_base),
  620                 rman_get_start(ad1816->irq),
  621                 rman_get_start(ad1816->drq1),
  622                 status2,
  623                 ad1816->bufsize);
  624 
  625         if (pcm_register(dev, ad1816, 1, 1)) goto no;
  626         pcm_addchan(dev, PCMDIR_REC, &ad1816chan_class, ad1816);
  627         pcm_addchan(dev, PCMDIR_PLAY, &ad1816chan_class, ad1816);
  628         pcm_setstatus(dev, status);
  629 
  630         return 0;
  631 no:
  632         ad1816_release_resources(ad1816, dev);
  633 
  634         return ENXIO;
  635 
  636 }
  637 
  638 static int
  639 ad1816_detach(device_t dev)
  640 {
  641         int r;
  642         struct ad1816_info *ad1816;
  643 
  644         r = pcm_unregister(dev);
  645         if (r)
  646                 return r;
  647 
  648         ad1816 = pcm_getdevinfo(dev);
  649         ad1816_release_resources(ad1816, dev);
  650         return 0;
  651 }
  652 
  653 static device_method_t ad1816_methods[] = {
  654         /* Device interface */
  655         DEVMETHOD(device_probe,         ad1816_probe),
  656         DEVMETHOD(device_attach,        ad1816_attach),
  657         DEVMETHOD(device_detach,        ad1816_detach),
  658 
  659         { 0, 0 }
  660 };
  661 
  662 static driver_t ad1816_driver = {
  663         "pcm",
  664         ad1816_methods,
  665         PCM_SOFTC_SIZE,
  666 };
  667 
  668 DRIVER_MODULE(snd_ad1816, isa, ad1816_driver, pcm_devclass, 0, 0);
  669 MODULE_DEPEND(snd_ad1816, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER);
  670 MODULE_VERSION(snd_ad1816, 1);
  671 
  672 

Cache object: 76e6ed86b47de1a3b26a5cf03e299847


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