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: releng/5.0/sys/dev/sound/isa/ad1816.c 107285 2002-11-26 18:16:27Z cg $");
   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         struct mtx *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                 return 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         return 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 #if 0
  372         return format;
  373 #else
  374         return 0;
  375 #endif
  376 }
  377 
  378 static int
  379 ad1816chan_setspeed(kobj_t obj, void *data, u_int32_t speed)
  380 {
  381         struct ad1816_chinfo *ch = data;
  382         struct ad1816_info *ad1816 = ch->parent;
  383 
  384         RANGE(speed, 4000, 55200);
  385         ad1816_lock(ad1816);
  386         ad1816_write(ad1816, (ch->dir == PCMDIR_PLAY)? 2 : 3, speed);
  387         ad1816_unlock(ad1816);
  388         return speed;
  389 }
  390 
  391 static int
  392 ad1816chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
  393 {
  394         struct ad1816_chinfo *ch = data;
  395 
  396         ch->blksz = blocksize;
  397         return ch->blksz;
  398 }
  399 
  400 static int
  401 ad1816chan_trigger(kobj_t obj, void *data, int go)
  402 {
  403         struct ad1816_chinfo *ch = data;
  404         struct ad1816_info *ad1816 = ch->parent;
  405         int wr, reg;
  406 
  407         if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
  408                 return 0;
  409 
  410         sndbuf_isadma(ch->buffer, go);
  411         wr = (ch->dir == PCMDIR_PLAY);
  412         reg = wr? AD1816_PLAY : AD1816_CAPT;
  413         ad1816_lock(ad1816);
  414         switch (go) {
  415         case PCMTRIG_START:
  416                 /* start only if not already running */
  417                 if (!(io_rd(ad1816, reg) & AD1816_ENABLE)) {
  418                         int cnt = ((ch->blksz) >> 2) - 1;
  419                         ad1816_write(ad1816, wr? 8 : 10, cnt); /* count */
  420                         ad1816_write(ad1816, wr? 9 : 11, 0); /* reset cur cnt */
  421                         ad1816_write(ad1816, 1, ad1816_read(ad1816, 1) |
  422                                      (wr? 0x8000 : 0x4000)); /* enable int */
  423                         /* enable playback */
  424                         io_wr(ad1816, reg, io_rd(ad1816, reg) | AD1816_ENABLE);
  425                         if (!(io_rd(ad1816, reg) & AD1816_ENABLE))
  426                                 printf("ad1816: failed to start %s DMA!\n",
  427                                        wr? "play" : "rec");
  428                 }
  429                 break;
  430 
  431         case PCMTRIG_STOP:
  432         case PCMTRIG_ABORT:             /* XXX check this... */
  433                 /* we don't test here if it is running... */
  434                 if (wr) {
  435                         ad1816_write(ad1816, 1, ad1816_read(ad1816, 1) &
  436                                      ~(wr? 0x8000 : 0x4000));
  437                         /* disable int */
  438                         io_wr(ad1816, reg, io_rd(ad1816, reg) & ~AD1816_ENABLE);
  439                         /* disable playback */
  440                         if (io_rd(ad1816, reg) & AD1816_ENABLE)
  441                                 printf("ad1816: failed to stop %s DMA!\n",
  442                                        wr? "play" : "rec");
  443                         ad1816_write(ad1816, wr? 8 : 10, 0); /* reset base cnt */
  444                         ad1816_write(ad1816, wr? 9 : 11, 0); /* reset cur cnt */
  445                 }
  446                 break;
  447         }
  448         ad1816_unlock(ad1816);
  449         return 0;
  450 }
  451 
  452 static int
  453 ad1816chan_getptr(kobj_t obj, void *data)
  454 {
  455         struct ad1816_chinfo *ch = data;
  456         return sndbuf_isadmaptr(ch->buffer);
  457 }
  458 
  459 static struct pcmchan_caps *
  460 ad1816chan_getcaps(kobj_t obj, void *data)
  461 {
  462         return &ad1816_caps;
  463 }
  464 
  465 static kobj_method_t ad1816chan_methods[] = {
  466         KOBJMETHOD(channel_init,                ad1816chan_init),
  467         KOBJMETHOD(channel_setdir,              ad1816chan_setdir),
  468         KOBJMETHOD(channel_setformat,           ad1816chan_setformat),
  469         KOBJMETHOD(channel_setspeed,            ad1816chan_setspeed),
  470         KOBJMETHOD(channel_setblocksize,        ad1816chan_setblocksize),
  471         KOBJMETHOD(channel_trigger,             ad1816chan_trigger),
  472         KOBJMETHOD(channel_getptr,              ad1816chan_getptr),
  473         KOBJMETHOD(channel_getcaps,             ad1816chan_getcaps),
  474         { 0, 0 }
  475 };
  476 CHANNEL_DECLARE(ad1816chan);
  477 
  478 /* -------------------------------------------------------------------- */
  479 
  480 static void
  481 ad1816_release_resources(struct ad1816_info *ad1816, device_t dev)
  482 {
  483         if (ad1816->irq) {
  484                 if (ad1816->ih)
  485                         bus_teardown_intr(dev, ad1816->irq, ad1816->ih);
  486                 bus_release_resource(dev, SYS_RES_IRQ, ad1816->irq_rid, ad1816->irq);
  487                 ad1816->irq = 0;
  488         }
  489         if (ad1816->drq1) {
  490                 isa_dma_release(rman_get_start(ad1816->drq1));
  491                 bus_release_resource(dev, SYS_RES_DRQ, ad1816->drq1_rid, ad1816->drq1);
  492                 ad1816->drq1 = 0;
  493         }
  494         if (ad1816->drq2) {
  495                 isa_dma_release(rman_get_start(ad1816->drq2));
  496                 bus_release_resource(dev, SYS_RES_DRQ, ad1816->drq2_rid, ad1816->drq2);
  497                 ad1816->drq2 = 0;
  498         }
  499         if (ad1816->io_base) {
  500                 bus_release_resource(dev, SYS_RES_IOPORT, ad1816->io_rid, ad1816->io_base);
  501                 ad1816->io_base = 0;
  502         }
  503         if (ad1816->parent_dmat) {
  504                 bus_dma_tag_destroy(ad1816->parent_dmat);
  505                 ad1816->parent_dmat = 0;
  506         }
  507         if (ad1816->lock)
  508                 snd_mtxfree(ad1816->lock);
  509 
  510         free(ad1816, M_DEVBUF);
  511 }
  512 
  513 static int
  514 ad1816_alloc_resources(struct ad1816_info *ad1816, device_t dev)
  515 {
  516         int ok = 1, pdma, rdma;
  517 
  518         if (!ad1816->io_base)
  519                 ad1816->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT, &ad1816->io_rid,
  520                                                   0, ~0, 1, RF_ACTIVE);
  521         if (!ad1816->irq)
  522                 ad1816->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &ad1816->irq_rid,
  523                                               0, ~0, 1, RF_ACTIVE);
  524         if (!ad1816->drq1)
  525                 ad1816->drq1 = bus_alloc_resource(dev, SYS_RES_DRQ, &ad1816->drq1_rid,
  526                                                0, ~0, 1, RF_ACTIVE);
  527         if (!ad1816->drq2)
  528                 ad1816->drq2 = bus_alloc_resource(dev, SYS_RES_DRQ, &ad1816->drq2_rid,
  529                                                0, ~0, 1, RF_ACTIVE);
  530 
  531         if (!ad1816->io_base || !ad1816->drq1 || !ad1816->irq) ok = 0;
  532 
  533         if (ok) {
  534                 pdma = rman_get_start(ad1816->drq1);
  535                 isa_dma_acquire(pdma);
  536                 isa_dmainit(pdma, ad1816->bufsize);
  537                 if (ad1816->drq2) {
  538                         rdma = rman_get_start(ad1816->drq2);
  539                         isa_dma_acquire(rdma);
  540                         isa_dmainit(rdma, ad1816->bufsize);
  541                 } else
  542                         rdma = pdma;
  543                 if (pdma == rdma)
  544                         pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX);
  545         }
  546 
  547         return ok;
  548 }
  549 
  550 static int
  551 ad1816_init(struct ad1816_info *ad1816, device_t dev)
  552 {
  553         ad1816_write(ad1816, 1, 0x2);   /* disable interrupts */
  554         ad1816_write(ad1816, 32, 0x90F0);       /* SoundSys Mode, split fmt */
  555 
  556         ad1816_write(ad1816, 5, 0x8080);        /* FM volume mute */
  557         ad1816_write(ad1816, 6, 0x8080);        /* I2S1 volume mute */
  558         ad1816_write(ad1816, 7, 0x8080);        /* I2S0 volume mute */
  559         ad1816_write(ad1816, 17, 0x8888);       /* VID Volume mute */
  560         ad1816_write(ad1816, 20, 0x5050);       /* recsrc mic, agc off */
  561         /* adc gain is set to 0 */
  562 
  563         return 0;
  564 }
  565 
  566 static int
  567 ad1816_probe(device_t dev)
  568 {
  569         char *s = NULL;
  570         u_int32_t logical_id = isa_get_logicalid(dev);
  571 
  572         switch (logical_id) {
  573         case 0x80719304: /* ADS7180 */
  574                 s = "AD1816";
  575                 break;
  576         }
  577 
  578         if (s) {
  579                 device_set_desc(dev, s);
  580                 return 0;
  581         }
  582         return ENXIO;
  583 }
  584 
  585 static int
  586 ad1816_attach(device_t dev)
  587 {
  588         struct ad1816_info *ad1816;
  589         char status[SND_STATUSLEN], status2[SND_STATUSLEN];
  590 
  591         ad1816 = (struct ad1816_info *)malloc(sizeof *ad1816, M_DEVBUF, M_NOWAIT | M_ZERO);
  592         if (!ad1816) return ENXIO;
  593 
  594         ad1816->lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc");
  595         ad1816->io_rid = 2;
  596         ad1816->irq_rid = 0;
  597         ad1816->drq1_rid = 0;
  598         ad1816->drq2_rid = 1;
  599         ad1816->bufsize = pcm_getbuffersize(dev, 4096, DSP_BUFFSIZE, 65536);
  600 
  601         if (!ad1816_alloc_resources(ad1816, dev)) goto no;
  602         ad1816_init(ad1816, dev);
  603         if (mixer_init(dev, &ad1816mixer_class, ad1816)) goto no;
  604 
  605         snd_setup_intr(dev, ad1816->irq, INTR_MPSAFE, ad1816_intr, ad1816, &ad1816->ih);
  606         if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
  607                         /*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
  608                         /*highaddr*/BUS_SPACE_MAXADDR,
  609                         /*filter*/NULL, /*filterarg*/NULL,
  610                         /*maxsize*/ad1816->bufsize, /*nsegments*/1,
  611                         /*maxsegz*/0x3ffff,
  612                         /*flags*/0, &ad1816->parent_dmat) != 0) {
  613                 device_printf(dev, "unable to create dma tag\n");
  614                 goto no;
  615         }
  616         if (ad1816->drq2)
  617                 snprintf(status2, SND_STATUSLEN, ":%ld", rman_get_start(ad1816->drq2));
  618         else
  619                 status2[0] = '\0';
  620 
  621         snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld%s bufsz %u",
  622                 rman_get_start(ad1816->io_base),
  623                 rman_get_start(ad1816->irq),
  624                 rman_get_start(ad1816->drq1),
  625                 status2,
  626                 ad1816->bufsize);
  627 
  628         if (pcm_register(dev, ad1816, 1, 1)) goto no;
  629         pcm_addchan(dev, PCMDIR_REC, &ad1816chan_class, ad1816);
  630         pcm_addchan(dev, PCMDIR_PLAY, &ad1816chan_class, ad1816);
  631         pcm_setstatus(dev, status);
  632 
  633         return 0;
  634 no:
  635         ad1816_release_resources(ad1816, dev);
  636 
  637         return ENXIO;
  638 
  639 }
  640 
  641 static int
  642 ad1816_detach(device_t dev)
  643 {
  644         int r;
  645         struct ad1816_info *ad1816;
  646 
  647         r = pcm_unregister(dev);
  648         if (r)
  649                 return r;
  650 
  651         ad1816 = pcm_getdevinfo(dev);
  652         ad1816_release_resources(ad1816, dev);
  653         return 0;
  654 }
  655 
  656 static device_method_t ad1816_methods[] = {
  657         /* Device interface */
  658         DEVMETHOD(device_probe,         ad1816_probe),
  659         DEVMETHOD(device_attach,        ad1816_attach),
  660         DEVMETHOD(device_detach,        ad1816_detach),
  661 
  662         { 0, 0 }
  663 };
  664 
  665 static driver_t ad1816_driver = {
  666         "pcm",
  667         ad1816_methods,
  668         PCM_SOFTC_SIZE,
  669 };
  670 
  671 DRIVER_MODULE(snd_ad1816, isa, ad1816_driver, pcm_devclass, 0, 0);
  672 MODULE_DEPEND(snd_ad1816, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER);
  673 MODULE_VERSION(snd_ad1816, 1);
  674 
  675 

Cache object: 157fd89bbd3955b7ae857b0128b8da94


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