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/pci/neomagic.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 <cg@freebsd.org>
    3  * All rights reserved.
    4  *
    5  * Derived from the public domain Linux driver
    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, WHETHERIN 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 THEPOSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <dev/sound/pcm/sound.h>
   30 #include <dev/sound/pcm/ac97.h>
   31 #include <dev/sound/pci/neomagic.h>
   32 #include <dev/sound/pci/neomagic-coeff.h>
   33 
   34 #include <dev/pci/pcireg.h>
   35 #include <dev/pci/pcivar.h>
   36 
   37 SND_DECLARE_FILE("$FreeBSD$");
   38 
   39 /* -------------------------------------------------------------------- */
   40 
   41 #define NM_BUFFSIZE     16384
   42 
   43 #define NM256AV_PCI_ID  0x800510c8
   44 #define NM256ZX_PCI_ID  0x800610c8
   45 
   46 struct sc_info;
   47 
   48 /* channel registers */
   49 struct sc_chinfo {
   50         int active, spd, dir, fmt;
   51         u_int32_t blksize, wmark;
   52         struct snd_dbuf *buffer;
   53         struct pcm_channel *channel;
   54         struct sc_info *parent;
   55 };
   56 
   57 /* device private data */
   58 struct sc_info {
   59         device_t        dev;
   60         u_int32_t       type;
   61 
   62         struct resource *reg, *irq, *buf;
   63         int             regid, irqid, bufid;
   64         void            *ih;
   65 
   66         u_int32_t       ac97_base, ac97_status, ac97_busy;
   67         u_int32_t       buftop, pbuf, rbuf, cbuf, acbuf;
   68         u_int32_t       playint, recint, misc1int, misc2int;
   69         u_int32_t       irsz, badintr;
   70 
   71         struct sc_chinfo pch, rch;
   72 };
   73 
   74 /* -------------------------------------------------------------------- */
   75 
   76 /*
   77  * prototypes
   78  */
   79 
   80 /* stuff */
   81 static int       nm_loadcoeff(struct sc_info *sc, int dir, int num);
   82 static int       nm_setch(struct sc_chinfo *ch);
   83 static int       nm_init(struct sc_info *);
   84 static void      nm_intr(void *);
   85 
   86 /* talk to the card */
   87 static u_int32_t nm_rd(struct sc_info *, int, int);
   88 static void      nm_wr(struct sc_info *, int, u_int32_t, int);
   89 static u_int32_t nm_rdbuf(struct sc_info *, int, int);
   90 static void      nm_wrbuf(struct sc_info *, int, u_int32_t, int);
   91 
   92 static u_int32_t badcards[] = {
   93         0x0007103c,
   94         0x008f1028,
   95         0x00dd1014,
   96         0x8005110a,
   97 };
   98 #define NUM_BADCARDS (sizeof(badcards) / sizeof(u_int32_t))
   99 
  100 /* The actual rates supported by the card. */
  101 static int samplerates[9] = {
  102         8000,
  103         11025,
  104         16000,
  105         22050,
  106         24000,
  107         32000,
  108         44100,
  109         48000,
  110         99999999
  111 };
  112 
  113 /* -------------------------------------------------------------------- */
  114 
  115 static u_int32_t nm_fmt[] = {
  116         AFMT_U8,
  117         AFMT_STEREO | AFMT_U8,
  118         AFMT_S16_LE,
  119         AFMT_STEREO | AFMT_S16_LE,
  120         0
  121 };
  122 static struct pcmchan_caps nm_caps = {4000, 48000, nm_fmt, 0};
  123 
  124 /* -------------------------------------------------------------------- */
  125 
  126 /* Hardware */
  127 static u_int32_t
  128 nm_rd(struct sc_info *sc, int regno, int size)
  129 {
  130         bus_space_tag_t st = rman_get_bustag(sc->reg);
  131         bus_space_handle_t sh = rman_get_bushandle(sc->reg);
  132 
  133         switch (size) {
  134         case 1:
  135                 return bus_space_read_1(st, sh, regno);
  136         case 2:
  137                 return bus_space_read_2(st, sh, regno);
  138         case 4:
  139                 return bus_space_read_4(st, sh, regno);
  140         default:
  141                 return 0xffffffff;
  142         }
  143 }
  144 
  145 static void
  146 nm_wr(struct sc_info *sc, int regno, u_int32_t data, int size)
  147 {
  148         bus_space_tag_t st = rman_get_bustag(sc->reg);
  149         bus_space_handle_t sh = rman_get_bushandle(sc->reg);
  150 
  151         switch (size) {
  152         case 1:
  153                 bus_space_write_1(st, sh, regno, data);
  154                 break;
  155         case 2:
  156                 bus_space_write_2(st, sh, regno, data);
  157                 break;
  158         case 4:
  159                 bus_space_write_4(st, sh, regno, data);
  160                 break;
  161         }
  162 }
  163 
  164 static u_int32_t
  165 nm_rdbuf(struct sc_info *sc, int regno, int size)
  166 {
  167         bus_space_tag_t st = rman_get_bustag(sc->buf);
  168         bus_space_handle_t sh = rman_get_bushandle(sc->buf);
  169 
  170         switch (size) {
  171         case 1:
  172                 return bus_space_read_1(st, sh, regno);
  173         case 2:
  174                 return bus_space_read_2(st, sh, regno);
  175         case 4:
  176                 return bus_space_read_4(st, sh, regno);
  177         default:
  178                 return 0xffffffff;
  179         }
  180 }
  181 
  182 static void
  183 nm_wrbuf(struct sc_info *sc, int regno, u_int32_t data, int size)
  184 {
  185         bus_space_tag_t st = rman_get_bustag(sc->buf);
  186         bus_space_handle_t sh = rman_get_bushandle(sc->buf);
  187 
  188         switch (size) {
  189         case 1:
  190                 bus_space_write_1(st, sh, regno, data);
  191                 break;
  192         case 2:
  193                 bus_space_write_2(st, sh, regno, data);
  194                 break;
  195         case 4:
  196                 bus_space_write_4(st, sh, regno, data);
  197                 break;
  198         }
  199 }
  200 
  201 /* -------------------------------------------------------------------- */
  202 /* ac97 codec */
  203 static int
  204 nm_waitcd(struct sc_info *sc)
  205 {
  206         int cnt = 10;
  207         int fail = 1;
  208 
  209         while (cnt-- > 0) {
  210                 if (nm_rd(sc, sc->ac97_status, 2) & sc->ac97_busy) {
  211                         DELAY(100);
  212                 } else {
  213                         fail = 0;
  214                         break;
  215                 }
  216         }
  217         return (fail);
  218 }
  219 
  220 static u_int32_t
  221 nm_initcd(kobj_t obj, void *devinfo)
  222 {
  223         struct sc_info *sc = (struct sc_info *)devinfo;
  224 
  225         nm_wr(sc, 0x6c0, 0x01, 1);
  226         nm_wr(sc, 0x6cc, 0x87, 1);
  227         nm_wr(sc, 0x6cc, 0x80, 1);
  228         nm_wr(sc, 0x6cc, 0x00, 1);
  229         return 1;
  230 }
  231 
  232 static int
  233 nm_rdcd(kobj_t obj, void *devinfo, int regno)
  234 {
  235         struct sc_info *sc = (struct sc_info *)devinfo;
  236         u_int32_t x;
  237 
  238         if (!nm_waitcd(sc)) {
  239                 x = nm_rd(sc, sc->ac97_base + regno, 2);
  240                 DELAY(1000);
  241                 return x;
  242         } else {
  243                 device_printf(sc->dev, "ac97 codec not ready\n");
  244                 return -1;
  245         }
  246 }
  247 
  248 static int
  249 nm_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data)
  250 {
  251         struct sc_info *sc = (struct sc_info *)devinfo;
  252         int cnt = 3;
  253 
  254         if (!nm_waitcd(sc)) {
  255                 while (cnt-- > 0) {
  256                         nm_wr(sc, sc->ac97_base + regno, data, 2);
  257                         if (!nm_waitcd(sc)) {
  258                                 DELAY(1000);
  259                                 return 0;
  260                         }
  261                 }
  262         }
  263         device_printf(sc->dev, "ac97 codec not ready\n");
  264         return -1;
  265 }
  266 
  267 static kobj_method_t nm_ac97_methods[] = {
  268         KOBJMETHOD(ac97_init,           nm_initcd),
  269         KOBJMETHOD(ac97_read,           nm_rdcd),
  270         KOBJMETHOD(ac97_write,          nm_wrcd),
  271         { 0, 0 }
  272 };
  273 AC97_DECLARE(nm_ac97);
  274 
  275 /* -------------------------------------------------------------------- */
  276 
  277 static void
  278 nm_ackint(struct sc_info *sc, u_int32_t num)
  279 {
  280         if (sc->type == NM256AV_PCI_ID) {
  281                 nm_wr(sc, NM_INT_REG, num << 1, 2);
  282         } else if (sc->type == NM256ZX_PCI_ID) {
  283                 nm_wr(sc, NM_INT_REG, num, 4);
  284         }
  285 }
  286 
  287 static int
  288 nm_loadcoeff(struct sc_info *sc, int dir, int num)
  289 {
  290         int ofs, sz, i;
  291         u_int32_t addr;
  292 
  293         addr = (dir == PCMDIR_PLAY)? 0x01c : 0x21c;
  294         if (dir == PCMDIR_REC)
  295                 num += 8;
  296         sz = coefficientSizes[num];
  297         ofs = 0;
  298         while (num-- > 0)
  299                 ofs+= coefficientSizes[num];
  300         for (i = 0; i < sz; i++)
  301                 nm_wrbuf(sc, sc->cbuf + i, coefficients[ofs + i], 1);
  302         nm_wr(sc, addr, sc->cbuf, 4);
  303         if (dir == PCMDIR_PLAY)
  304                 sz--;
  305         nm_wr(sc, addr + 4, sc->cbuf + sz, 4);
  306         return 0;
  307 }
  308 
  309 static int
  310 nm_setch(struct sc_chinfo *ch)
  311 {
  312         struct sc_info *sc = ch->parent;
  313         u_int32_t base;
  314         u_int8_t x;
  315 
  316         for (x = 0; x < 8; x++)
  317                 if (ch->spd < (samplerates[x] + samplerates[x + 1]) / 2)
  318                         break;
  319 
  320         if (x == 8) return 1;
  321 
  322         ch->spd = samplerates[x];
  323         nm_loadcoeff(sc, ch->dir, x);
  324 
  325         x <<= 4;
  326         x &= NM_RATE_MASK;
  327         if (ch->fmt & AFMT_16BIT) x |= NM_RATE_BITS_16;
  328         if (ch->fmt & AFMT_STEREO) x |= NM_RATE_STEREO;
  329 
  330         base = (ch->dir == PCMDIR_PLAY)? NM_PLAYBACK_REG_OFFSET : NM_RECORD_REG_OFFSET;
  331         nm_wr(sc, base + NM_RATE_REG_OFFSET, x, 1);
  332         return 0;
  333 }
  334 
  335 /* channel interface */
  336 static void *
  337 nmchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
  338 {
  339         struct sc_info *sc = devinfo;
  340         struct sc_chinfo *ch;
  341         u_int32_t chnbuf;
  342 
  343         chnbuf = (dir == PCMDIR_PLAY)? sc->pbuf : sc->rbuf;
  344         ch = (dir == PCMDIR_PLAY)? &sc->pch : &sc->rch;
  345         ch->active = 0;
  346         ch->blksize = 0;
  347         ch->wmark = 0;
  348         ch->buffer = b;
  349         sndbuf_setup(ch->buffer, (u_int8_t *)rman_get_virtual(sc->buf) + chnbuf, NM_BUFFSIZE);
  350         if (bootverbose)
  351                 device_printf(sc->dev, "%s buf %p\n", (dir == PCMDIR_PLAY)?
  352                               "play" : "rec", sndbuf_getbuf(ch->buffer));
  353         ch->parent = sc;
  354         ch->channel = c;
  355         ch->dir = dir;
  356         return ch;
  357 }
  358 
  359 static int
  360 nmchan_free(kobj_t obj, void *data)
  361 {
  362         return 0;
  363 }
  364 
  365 static int
  366 nmchan_setformat(kobj_t obj, void *data, u_int32_t format)
  367 {
  368         struct sc_chinfo *ch = data;
  369 
  370         ch->fmt = format;
  371         return nm_setch(ch);
  372 }
  373 
  374 static int
  375 nmchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
  376 {
  377         struct sc_chinfo *ch = data;
  378 
  379         ch->spd = speed;
  380         return nm_setch(ch)? 0 : ch->spd;
  381 }
  382 
  383 static int
  384 nmchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
  385 {
  386         struct sc_chinfo *ch = data;
  387 
  388         ch->blksize = blocksize;
  389 
  390         return blocksize;
  391 }
  392 
  393 static int
  394 nmchan_trigger(kobj_t obj, void *data, int go)
  395 {
  396         struct sc_chinfo *ch = data;
  397         struct sc_info *sc = ch->parent;
  398         int ssz;
  399 
  400         if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
  401                 return 0;
  402 
  403         ssz = (ch->fmt & AFMT_16BIT)? 2 : 1;
  404         if (ch->fmt & AFMT_STEREO)
  405                 ssz <<= 1;
  406 
  407         if (ch->dir == PCMDIR_PLAY) {
  408                 if (go == PCMTRIG_START) {
  409                         ch->active = 1;
  410                         ch->wmark = ch->blksize;
  411                         nm_wr(sc, NM_PBUFFER_START, sc->pbuf, 4);
  412                         nm_wr(sc, NM_PBUFFER_END, sc->pbuf + NM_BUFFSIZE - ssz, 4);
  413                         nm_wr(sc, NM_PBUFFER_CURRP, sc->pbuf, 4);
  414                         nm_wr(sc, NM_PBUFFER_WMARK, sc->pbuf + ch->wmark, 4);
  415                         nm_wr(sc, NM_PLAYBACK_ENABLE_REG, NM_PLAYBACK_FREERUN |
  416                                 NM_PLAYBACK_ENABLE_FLAG, 1);
  417                         nm_wr(sc, NM_AUDIO_MUTE_REG, 0, 2);
  418                 } else {
  419                         ch->active = 0;
  420                         nm_wr(sc, NM_PLAYBACK_ENABLE_REG, 0, 1);
  421                         nm_wr(sc, NM_AUDIO_MUTE_REG, NM_AUDIO_MUTE_BOTH, 2);
  422                 }
  423         } else {
  424                 if (go == PCMTRIG_START) {
  425                         ch->active = 1;
  426                         ch->wmark = ch->blksize;
  427                         nm_wr(sc, NM_RECORD_ENABLE_REG, NM_RECORD_FREERUN |
  428                                 NM_RECORD_ENABLE_FLAG, 1);
  429                         nm_wr(sc, NM_RBUFFER_START, sc->rbuf, 4);
  430                         nm_wr(sc, NM_RBUFFER_END, sc->rbuf + NM_BUFFSIZE, 4);
  431                         nm_wr(sc, NM_RBUFFER_CURRP, sc->rbuf, 4);
  432                         nm_wr(sc, NM_RBUFFER_WMARK, sc->rbuf + ch->wmark, 4);
  433                 } else {
  434                         ch->active = 0;
  435                         nm_wr(sc, NM_RECORD_ENABLE_REG, 0, 1);
  436                 }
  437         }
  438         return 0;
  439 }
  440 
  441 static int
  442 nmchan_getptr(kobj_t obj, void *data)
  443 {
  444         struct sc_chinfo *ch = data;
  445         struct sc_info *sc = ch->parent;
  446 
  447         if (ch->dir == PCMDIR_PLAY)
  448                 return nm_rd(sc, NM_PBUFFER_CURRP, 4) - sc->pbuf;
  449         else
  450                 return nm_rd(sc, NM_RBUFFER_CURRP, 4) - sc->rbuf;
  451 }
  452 
  453 static struct pcmchan_caps *
  454 nmchan_getcaps(kobj_t obj, void *data)
  455 {
  456         return &nm_caps;
  457 }
  458 
  459 static kobj_method_t nmchan_methods[] = {
  460         KOBJMETHOD(channel_init,                nmchan_init),
  461         KOBJMETHOD(channel_free,                nmchan_free),
  462         KOBJMETHOD(channel_setformat,           nmchan_setformat),
  463         KOBJMETHOD(channel_setspeed,            nmchan_setspeed),
  464         KOBJMETHOD(channel_setblocksize,        nmchan_setblocksize),
  465         KOBJMETHOD(channel_trigger,             nmchan_trigger),
  466         KOBJMETHOD(channel_getptr,              nmchan_getptr),
  467         KOBJMETHOD(channel_getcaps,             nmchan_getcaps),
  468         { 0, 0 }
  469 };
  470 CHANNEL_DECLARE(nmchan);
  471 
  472 /* The interrupt handler */
  473 static void
  474 nm_intr(void *p)
  475 {
  476         struct sc_info *sc = (struct sc_info *)p;
  477         int status, x;
  478 
  479         status = nm_rd(sc, NM_INT_REG, sc->irsz);
  480         if (status == 0)
  481                 return;
  482 
  483         if (status & sc->playint) {
  484                 status &= ~sc->playint;
  485                 sc->pch.wmark += sc->pch.blksize;
  486                 sc->pch.wmark %= NM_BUFFSIZE;
  487                 nm_wr(sc, NM_PBUFFER_WMARK, sc->pbuf + sc->pch.wmark, 4);
  488 
  489                 nm_ackint(sc, sc->playint);
  490                 chn_intr(sc->pch.channel);
  491         }
  492         if (status & sc->recint) {
  493                 status &= ~sc->recint;
  494                 sc->rch.wmark += sc->rch.blksize;
  495                 sc->rch.wmark %= NM_BUFFSIZE;
  496                 nm_wr(sc, NM_RBUFFER_WMARK, sc->rbuf + sc->rch.wmark, 4);
  497 
  498                 nm_ackint(sc, sc->recint);
  499                 chn_intr(sc->rch.channel);
  500         }
  501         if (status & sc->misc1int) {
  502                 status &= ~sc->misc1int;
  503                 nm_ackint(sc, sc->misc1int);
  504                 x = nm_rd(sc, 0x400, 1);
  505                 nm_wr(sc, 0x400, x | 2, 1);
  506                 device_printf(sc->dev, "misc int 1\n");
  507         }
  508         if (status & sc->misc2int) {
  509                 status &= ~sc->misc2int;
  510                 nm_ackint(sc, sc->misc2int);
  511                 x = nm_rd(sc, 0x400, 1);
  512                 nm_wr(sc, 0x400, x & ~2, 1);
  513                 device_printf(sc->dev, "misc int 2\n");
  514         }
  515         if (status) {
  516                 nm_ackint(sc, status);
  517                 device_printf(sc->dev, "unknown int\n");
  518         }
  519 }
  520 
  521 /* -------------------------------------------------------------------- */
  522 
  523 /*
  524  * Probe and attach the card
  525  */
  526 
  527 static int
  528 nm_init(struct sc_info *sc)
  529 {
  530         u_int32_t ofs, i;
  531 
  532         if (sc->type == NM256AV_PCI_ID) {
  533                 sc->ac97_base = NM_MIXER_OFFSET;
  534                 sc->ac97_status = NM_MIXER_STATUS_OFFSET;
  535                 sc->ac97_busy = NM_MIXER_READY_MASK;
  536 
  537                 sc->buftop = 2560 * 1024;
  538 
  539                 sc->irsz = 2;
  540                 sc->playint = NM_PLAYBACK_INT;
  541                 sc->recint = NM_RECORD_INT;
  542                 sc->misc1int = NM_MISC_INT_1;
  543                 sc->misc2int = NM_MISC_INT_2;
  544         } else if (sc->type == NM256ZX_PCI_ID) {
  545                 sc->ac97_base = NM_MIXER_OFFSET;
  546                 sc->ac97_status = NM2_MIXER_STATUS_OFFSET;
  547                 sc->ac97_busy = NM2_MIXER_READY_MASK;
  548 
  549                 sc->buftop = (nm_rd(sc, 0xa0b, 2)? 6144 : 4096) * 1024;
  550 
  551                 sc->irsz = 4;
  552                 sc->playint = NM2_PLAYBACK_INT;
  553                 sc->recint = NM2_RECORD_INT;
  554                 sc->misc1int = NM2_MISC_INT_1;
  555                 sc->misc2int = NM2_MISC_INT_2;
  556         } else return -1;
  557         sc->badintr = 0;
  558         ofs = sc->buftop - 0x0400;
  559         sc->buftop -= 0x1400;
  560 
  561         if (bootverbose)
  562                 device_printf(sc->dev, "buftop is 0x%08x\n", sc->buftop);
  563         if ((nm_rdbuf(sc, ofs, 4) & NM_SIG_MASK) == NM_SIGNATURE) {
  564                 i = nm_rdbuf(sc, ofs + 4, 4);
  565                 if (i != 0 && i != 0xffffffff) {
  566                         if (bootverbose)
  567                                 device_printf(sc->dev, "buftop is changed to 0x%08x\n", i);
  568                         sc->buftop = i;
  569                 }
  570         }
  571 
  572         sc->cbuf = sc->buftop - NM_MAX_COEFFICIENT;
  573         sc->rbuf = sc->cbuf - NM_BUFFSIZE;
  574         sc->pbuf = sc->rbuf - NM_BUFFSIZE;
  575         sc->acbuf = sc->pbuf - (NM_TOTAL_COEFF_COUNT * 4);
  576 
  577         nm_wr(sc, 0, 0x11, 1);
  578         nm_wr(sc, NM_RECORD_ENABLE_REG, 0, 1);
  579         nm_wr(sc, 0x214, 0, 2);
  580 
  581         return 0;
  582 }
  583 
  584 static int
  585 nm_pci_probe(device_t dev)
  586 {
  587         struct sc_info *sc = NULL;
  588         char *s = NULL;
  589         u_int32_t subdev, i, data;
  590 
  591         subdev = (pci_get_subdevice(dev) << 16) | pci_get_subvendor(dev);
  592         switch (pci_get_devid(dev)) {
  593         case NM256AV_PCI_ID:
  594                 i = 0;
  595                 while ((i < NUM_BADCARDS) && (badcards[i] != subdev))
  596                         i++;
  597 
  598                 /* Try to catch other non-ac97 cards */
  599 
  600                 if (i == NUM_BADCARDS) {
  601                         if (!(sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT | M_ZERO))) {
  602                                 device_printf(dev, "cannot allocate softc\n");
  603                                 return ENXIO;
  604                         }
  605 
  606                         data = pci_read_config(dev, PCIR_COMMAND, 2);
  607                         pci_write_config(dev, PCIR_COMMAND, data |
  608                                          PCIM_CMD_PORTEN | PCIM_CMD_MEMEN |
  609                                          PCIM_CMD_BUSMASTEREN, 2);
  610 
  611                         sc->regid = PCIR_BAR(1);
  612                         sc->reg = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
  613                                                          &sc->regid,
  614                                                          RF_ACTIVE);
  615 
  616                         if (!sc->reg) {
  617                                 device_printf(dev, "unable to map register space\n");
  618                                 pci_write_config(dev, PCIR_COMMAND, data, 2);
  619                                 free(sc, M_DEVBUF);
  620                                 return ENXIO;
  621                         }
  622 
  623                         /*
  624                          * My Panasonic CF-M2EV needs resetting device
  625                          * before checking mixer is present or not.
  626                          * t.ichinoseki@nifty.com.
  627                          */
  628                         nm_wr(sc, 0, 0x11, 1); /* reset device */
  629                         if ((nm_rd(sc, NM_MIXER_PRESENCE, 2) &
  630                                 NM_PRESENCE_MASK) != NM_PRESENCE_VALUE) {
  631                                 i = 0;  /* non-ac97 card, but not listed */
  632                                 DEB(device_printf(dev, "subdev = 0x%x - badcard?\n",
  633                                     subdev));
  634                         }
  635                         pci_write_config(dev, PCIR_COMMAND, data, 2);
  636                         bus_release_resource(dev, SYS_RES_MEMORY, sc->regid,
  637                                              sc->reg);
  638                         free(sc, M_DEVBUF);
  639                 }
  640 
  641                 if (i == NUM_BADCARDS)
  642                         s = "NeoMagic 256AV";
  643                 DEB(else)
  644                         DEB(device_printf(dev, "this is a non-ac97 NM256AV, not attaching\n"));
  645 
  646                 break;
  647 
  648         case NM256ZX_PCI_ID:
  649                 s = "NeoMagic 256ZX";
  650                 break;
  651         }
  652 
  653         if (s) device_set_desc(dev, s);
  654         return s? 0 : ENXIO;
  655 }
  656 
  657 static int
  658 nm_pci_attach(device_t dev)
  659 {
  660         u_int32_t       data;
  661         struct sc_info *sc;
  662         struct ac97_info *codec = 0;
  663         char            status[SND_STATUSLEN];
  664 
  665         if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) {
  666                 device_printf(dev, "cannot allocate softc\n");
  667                 return ENXIO;
  668         }
  669 
  670         sc->dev = dev;
  671         sc->type = pci_get_devid(dev);
  672 
  673         data = pci_read_config(dev, PCIR_COMMAND, 2);
  674         data |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
  675         pci_write_config(dev, PCIR_COMMAND, data, 2);
  676         data = pci_read_config(dev, PCIR_COMMAND, 2);
  677 
  678         sc->bufid = PCIR_BAR(0);
  679         sc->buf = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->bufid,
  680                                          RF_ACTIVE);
  681         sc->regid = PCIR_BAR(1);
  682         sc->reg = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->regid,
  683                                          RF_ACTIVE);
  684 
  685         if (!sc->buf || !sc->reg) {
  686                 device_printf(dev, "unable to map register space\n");
  687                 goto bad;
  688         }
  689 
  690         if (nm_init(sc) == -1) {
  691                 device_printf(dev, "unable to initialize the card\n");
  692                 goto bad;
  693         }
  694 
  695         codec = AC97_CREATE(dev, sc, nm_ac97);
  696         if (codec == NULL) goto bad;
  697         if (mixer_init(dev, ac97_getmixerclass(), codec) == -1) goto bad;
  698 
  699         sc->irqid = 0;
  700         sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid,
  701                                          RF_ACTIVE | RF_SHAREABLE);
  702         if (!sc->irq || snd_setup_intr(dev, sc->irq, 0, nm_intr, sc, &sc->ih)) {
  703                 device_printf(dev, "unable to map interrupt\n");
  704                 goto bad;
  705         }
  706 
  707         snprintf(status, SND_STATUSLEN, "at memory 0x%lx, 0x%lx irq %ld %s",
  708                  rman_get_start(sc->buf), rman_get_start(sc->reg),
  709                  rman_get_start(sc->irq),PCM_KLDSTRING(snd_neomagic));
  710 
  711         if (pcm_register(dev, sc, 1, 1)) goto bad;
  712         pcm_addchan(dev, PCMDIR_REC, &nmchan_class, sc);
  713         pcm_addchan(dev, PCMDIR_PLAY, &nmchan_class, sc);
  714         pcm_setstatus(dev, status);
  715 
  716         return 0;
  717 
  718 bad:
  719         if (codec) ac97_destroy(codec);
  720         if (sc->buf) bus_release_resource(dev, SYS_RES_MEMORY, sc->bufid, sc->buf);
  721         if (sc->reg) bus_release_resource(dev, SYS_RES_MEMORY, sc->regid, sc->reg);
  722         if (sc->ih) bus_teardown_intr(dev, sc->irq, sc->ih);
  723         if (sc->irq) bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
  724         free(sc, M_DEVBUF);
  725         return ENXIO;
  726 }
  727 
  728 static int
  729 nm_pci_detach(device_t dev)
  730 {
  731         int r;
  732         struct sc_info *sc;
  733 
  734         r = pcm_unregister(dev);
  735         if (r)
  736                 return r;
  737 
  738         sc = pcm_getdevinfo(dev);
  739         bus_release_resource(dev, SYS_RES_MEMORY, sc->bufid, sc->buf);
  740         bus_release_resource(dev, SYS_RES_MEMORY, sc->regid, sc->reg);
  741         bus_teardown_intr(dev, sc->irq, sc->ih);
  742         bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
  743         free(sc, M_DEVBUF);
  744 
  745         return 0;
  746 }
  747 
  748 static int
  749 nm_pci_suspend(device_t dev)
  750 {
  751         struct sc_info *sc;
  752 
  753         sc = pcm_getdevinfo(dev);
  754 
  755         /* stop playing */
  756         if (sc->pch.active) {
  757                 nm_wr(sc, NM_PLAYBACK_ENABLE_REG, 0, 1);
  758                 nm_wr(sc, NM_AUDIO_MUTE_REG, NM_AUDIO_MUTE_BOTH, 2);
  759         }
  760         /* stop recording */
  761         if (sc->rch.active) {
  762                 nm_wr(sc, NM_RECORD_ENABLE_REG, 0, 1);
  763         }
  764         return 0;
  765 }
  766 
  767 static int
  768 nm_pci_resume(device_t dev)
  769 {
  770         struct sc_info *sc;
  771 
  772         sc = pcm_getdevinfo(dev);
  773 
  774         /*
  775          * Reinit audio device.
  776          * Don't call nm_init(). It would change buftop if X ran or
  777          * is running. This makes playing and recording buffer address
  778          * shift but these buffers of channel layer are not changed.
  779          * As a result of this inconsistency, periodic noise will be
  780          * generated while playing.
  781          */
  782         nm_wr(sc, 0, 0x11, 1);
  783         nm_wr(sc, 0x214, 0, 2);
  784 
  785         /* Reinit mixer */
  786         if (mixer_reinit(dev) == -1) {
  787                 device_printf(dev, "unable to reinitialize the mixer\n");
  788                 return ENXIO;
  789         }
  790         /* restart playing */
  791         if (sc->pch.active) {
  792                 nm_wr(sc, NM_PLAYBACK_ENABLE_REG, NM_PLAYBACK_FREERUN |
  793                           NM_PLAYBACK_ENABLE_FLAG, 1);
  794                 nm_wr(sc, NM_AUDIO_MUTE_REG, 0, 2);
  795         }
  796         /* restart recording */
  797         if (sc->rch.active) {
  798                 nm_wr(sc, NM_RECORD_ENABLE_REG, NM_RECORD_FREERUN |
  799                           NM_RECORD_ENABLE_FLAG, 1);
  800         }
  801         return 0;
  802 }
  803 
  804 static device_method_t nm_methods[] = {
  805         /* Device interface */
  806         DEVMETHOD(device_probe,         nm_pci_probe),
  807         DEVMETHOD(device_attach,        nm_pci_attach),
  808         DEVMETHOD(device_detach,        nm_pci_detach),
  809         DEVMETHOD(device_suspend,       nm_pci_suspend),
  810         DEVMETHOD(device_resume,        nm_pci_resume),
  811         { 0, 0 }
  812 };
  813 
  814 static driver_t nm_driver = {
  815         "pcm",
  816         nm_methods,
  817         PCM_SOFTC_SIZE,
  818 };
  819 
  820 DRIVER_MODULE(snd_neomagic, pci, nm_driver, pcm_devclass, 0, 0);
  821 MODULE_DEPEND(snd_neomagic, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
  822 MODULE_VERSION(snd_neomagic, 1);

Cache object: 103cfa2da34d6945674e9cbf7125c695


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