root/dev/sbus/cs4231.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cs4231_match
  2. cs4231_attach
  3. cs4231_write
  4. cs4231_read
  5. cs4231_set_speed
  6. speed_struct
  7. cs4231_open
  8. cs4231_setup_output
  9. cs4231_close
  10. cs4231_query_encoding
  11. cs4231_set_params
  12. cs4231_round_blocksize
  13. cs4231_commit_settings
  14. cs4231_halt_output
  15. cs4231_halt_input
  16. cs4231_getdev
  17. cs4231_set_port
  18. cs4231_get_port
  19. cs4231_query_devinfo
  20. cs4231_get_props
  21. cs4231_intr
  22. cs4231_alloc
  23. cs4231_free
  24. cs4231_trigger_output
  25. cs4231_trigger_input

    1 /*      $OpenBSD: cs4231.c,v 1.28 2006/06/02 20:00:56 miod Exp $        */
    2 
    3 /*
    4  * Copyright (c) 1999 Jason L. Wright (jason@thought.net)
    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 ``AS IS'' AND ANY EXPRESS OR
   17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
   20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   25  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   26  * POSSIBILITY OF SUCH DAMAGE.
   27  *
   28  * Effort sponsored in part by the Defense Advanced Research Projects
   29  * Agency (DARPA) and Air Force Research Laboratory, Air Force
   30  * Materiel Command, USAF, under agreement number F30602-01-2-0537.
   31  *
   32  */
   33 
   34 /*
   35  * Driver for CS4231 based audio found in some sun4m systems (cs4231)
   36  * based on ideas from the S/Linux project and the NetBSD project.
   37  */
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/errno.h>
   42 #include <sys/ioctl.h>
   43 #include <sys/device.h>
   44 #include <sys/proc.h>
   45 #include <sys/malloc.h>
   46 
   47 #include <machine/bus.h>
   48 #include <machine/intr.h>
   49 #include <machine/autoconf.h>
   50 
   51 #include <sys/audioio.h>
   52 #include <dev/audio_if.h>
   53 #include <dev/auconv.h>
   54 
   55 #include <dev/ic/ad1848reg.h>
   56 #include <dev/ic/cs4231reg.h>
   57 #include <dev/ic/apcdmareg.h>
   58 #include <dev/sbus/sbusvar.h>
   59 #include <dev/sbus/cs4231var.h>
   60 
   61 #define CSAUDIO_DAC_LVL         0
   62 #define CSAUDIO_LINE_IN_LVL     1
   63 #define CSAUDIO_MIC_LVL         2
   64 #define CSAUDIO_CD_LVL          3
   65 #define CSAUDIO_MONITOR_LVL     4
   66 #define CSAUDIO_OUTPUT_LVL      5
   67 #define CSAUDIO_LINE_IN_MUTE    6
   68 #define CSAUDIO_DAC_MUTE        7
   69 #define CSAUDIO_CD_MUTE         8
   70 #define CSAUDIO_MIC_MUTE        9
   71 #define CSAUDIO_MONITOR_MUTE    10
   72 #define CSAUDIO_OUTPUT_MUTE     11
   73 #define CSAUDIO_REC_LVL         12
   74 #define CSAUDIO_RECORD_SOURCE   13
   75 #define CSAUDIO_OUTPUT          14
   76 #define CSAUDIO_INPUT_CLASS     15
   77 #define CSAUDIO_OUTPUT_CLASS    16
   78 #define CSAUDIO_RECORD_CLASS    17
   79 #define CSAUDIO_MONITOR_CLASS   18
   80 
   81 #define CSPORT_AUX2             0
   82 #define CSPORT_AUX1             1
   83 #define CSPORT_DAC              2
   84 #define CSPORT_LINEIN           3
   85 #define CSPORT_MONO             4
   86 #define CSPORT_MONITOR          5
   87 #define CSPORT_SPEAKER          6
   88 #define CSPORT_LINEOUT          7
   89 #define CSPORT_HEADPHONE        8
   90 #define CSPORT_MICROPHONE       9
   91 
   92 #define MIC_IN_PORT     0
   93 #define LINE_IN_PORT    1
   94 #define AUX1_IN_PORT    2
   95 #define DAC_IN_PORT     3
   96 
   97 #ifdef AUDIO_DEBUG
   98 #define DPRINTF(x)      printf x
   99 #else
  100 #define DPRINTF(x)
  101 #endif
  102 
  103 #define CS_TIMEOUT      90000
  104 
  105 #define CS_PC_LINEMUTE  XCTL0_ENABLE
  106 #define CS_PC_HDPHMUTE  XCTL1_ENABLE
  107 #define CS_AFS_TI       0x40            /* timer interrupt */
  108 #define CS_AFS_CI       0x20            /* capture interrupt */
  109 #define CS_AFS_PI       0x10            /* playback interrupt */
  110 #define CS_AFS_CU       0x08            /* capture underrun */
  111 #define CS_AFS_CO       0x04            /* capture overrun */
  112 #define CS_AFS_PO       0x02            /* playback overrun */
  113 #define CS_AFS_PU       0x01            /* playback underrun */
  114 
  115 #define CS_WRITE(sc,r,v)        \
  116     bus_space_write_1((sc)->sc_bustag, (sc)->sc_regs, (r) << 2, (v))
  117 #define CS_READ(sc,r)           \
  118     bus_space_read_1((sc)->sc_bustag, (sc)->sc_regs, (r) << 2)
  119 
  120 #define APC_WRITE(sc,r,v)       \
  121     bus_space_write_4(sc->sc_bustag, sc->sc_regs, r, v)
  122 #define APC_READ(sc,r)          \
  123     bus_space_read_4(sc->sc_bustag, sc->sc_regs, r)
  124 
  125 int     cs4231_match(struct device *, void *, void *);
  126 void    cs4231_attach(struct device *, struct device *, void *);
  127 int     cs4231_intr(void *);
  128 
  129 int     cs4231_set_speed(struct cs4231_softc *, u_long *);
  130 void    cs4231_setup_output(struct cs4231_softc *sc);
  131 
  132 void            cs4231_write(struct cs4231_softc *, u_int8_t, u_int8_t);
  133 u_int8_t        cs4231_read(struct cs4231_softc *, u_int8_t);
  134 
  135 /* Audio interface */
  136 int     cs4231_open(void *, int);
  137 void    cs4231_close(void *);
  138 int     cs4231_query_encoding(void *, struct audio_encoding *);
  139 int     cs4231_set_params(void *, int, int, struct audio_params *,
  140     struct audio_params *);
  141 int     cs4231_round_blocksize(void *, int);
  142 int     cs4231_commit_settings(void *);
  143 int     cs4231_halt_output(void *);
  144 int     cs4231_halt_input(void *);
  145 int     cs4231_getdev(void *, struct audio_device *);
  146 int     cs4231_set_port(void *, mixer_ctrl_t *);
  147 int     cs4231_get_port(void *, mixer_ctrl_t *);
  148 int     cs4231_query_devinfo(void *, mixer_devinfo_t *);
  149 void *  cs4231_alloc(void *, int, size_t, int, int);
  150 void    cs4231_free(void *, void *, int);
  151 int     cs4231_get_props(void *);
  152 int     cs4231_trigger_output(void *, void *, void *, int,
  153     void (*)(void *), void *, struct audio_params *);
  154 int     cs4231_trigger_input(void *, void *, void *, int,
  155     void (*)(void *), void *, struct audio_params *);
  156 
  157 struct audio_hw_if cs4231_sa_hw_if = {
  158         cs4231_open,
  159         cs4231_close,
  160         0,
  161         cs4231_query_encoding,
  162         cs4231_set_params,
  163         cs4231_round_blocksize,
  164         cs4231_commit_settings,
  165         0,
  166         0,
  167         0,
  168         0,
  169         cs4231_halt_output,
  170         cs4231_halt_input,
  171         0,
  172         cs4231_getdev,
  173         0,
  174         cs4231_set_port,
  175         cs4231_get_port,
  176         cs4231_query_devinfo,
  177         cs4231_alloc,
  178         cs4231_free,
  179         0,
  180         0,
  181         cs4231_get_props,
  182         cs4231_trigger_output,
  183         cs4231_trigger_input
  184 };
  185 
  186 struct cfattach audiocs_ca = {
  187         sizeof (struct cs4231_softc), cs4231_match, cs4231_attach
  188 };
  189 
  190 struct cfdriver audiocs_cd = {
  191         NULL, "audiocs", DV_DULL
  192 };
  193 
  194 struct audio_device cs4231_device = {
  195         "SUNW,CS4231",
  196         "b",
  197         "onboard1",
  198 };
  199 
  200 int
  201 cs4231_match(struct device *parent, void *vcf, void *aux)
  202 {
  203         struct sbus_attach_args *sa = aux;
  204 
  205         return (strcmp("SUNW,CS4231", sa->sa_name) == 0);
  206 }
  207 
  208 void    
  209 cs4231_attach(struct device *parent, struct device *self, void *aux)
  210 {
  211         struct sbus_attach_args *sa = aux;
  212         struct cs4231_softc *sc = (struct cs4231_softc *)self;
  213         int node;
  214         u_int32_t sbusburst, burst;
  215 
  216         node = sa->sa_node;
  217 
  218         /* Pass on the bus tags */
  219         sc->sc_bustag = sa->sa_bustag;
  220         sc->sc_dmatag = sa->sa_dmatag;
  221 
  222         /* Make sure things are sane. */
  223         if (sa->sa_nintr != 1) {
  224                 printf(": expected 1 interrupt, got %d\n", sa->sa_nintr);
  225                 return;
  226         }
  227         if (sa->sa_nreg != 1) {
  228                 printf(": expected 1 register set, got %d\n",
  229                     sa->sa_nreg);
  230                 return;
  231         }
  232 
  233         if (bus_intr_establish(sa->sa_bustag, sa->sa_pri, IPL_AUDIO, 0,
  234             cs4231_intr, sc, self->dv_xname) == NULL) {
  235                 printf(": couldn't establish interrupt, pri %d\n",
  236                     INTLEV(sa->sa_pri));
  237                 return;
  238         }
  239 
  240         if (sbus_bus_map(sa->sa_bustag,
  241             sa->sa_reg[0].sbr_slot,
  242             (bus_addr_t)sa->sa_reg[0].sbr_offset,
  243             (bus_size_t)sa->sa_reg[0].sbr_size,
  244             BUS_SPACE_MAP_LINEAR, 0, &sc->sc_regs) != 0) {
  245                 printf(": couldn't map registers\n");
  246                 return;
  247         }
  248 
  249         sbusburst = ((struct sbus_softc *)parent)->sc_burst;
  250         if (sbusburst == 0)
  251                 sbusburst = SBUS_BURST_32 - 1;  /* 1->16 */
  252         burst = getpropint(node, "burst-sizes", -1);
  253         if (burst == -1)
  254                 burst = sbusburst;
  255         sc->sc_burst = burst & sbusburst;
  256 
  257         printf("\n");
  258 
  259         audio_attach_mi(&cs4231_sa_hw_if, sc, &sc->sc_dev);
  260 
  261         /* Default to speaker, unmuted, reasonable volume */
  262         sc->sc_out_port = CSPORT_SPEAKER;
  263         sc->sc_in_port = CSPORT_MICROPHONE;
  264         sc->sc_mute[CSPORT_SPEAKER] = 1;
  265         sc->sc_mute[CSPORT_MONITOR] = 1;
  266         sc->sc_volume[CSPORT_SPEAKER].left = 192;
  267         sc->sc_volume[CSPORT_SPEAKER].right = 192;
  268 }
  269 
  270 /*
  271  * Write to one of the indexed registers of cs4231.
  272  */
  273 void
  274 cs4231_write(struct cs4231_softc *sc, u_int8_t r, u_int8_t v)
  275 {
  276         CS_WRITE(sc, AD1848_IADDR, r);
  277         CS_WRITE(sc, AD1848_IDATA, v);
  278 }
  279 
  280 /*
  281  * Read from one of the indexed registers of cs4231.
  282  */
  283 u_int8_t
  284 cs4231_read(struct cs4231_softc *sc, u_int8_t r)
  285 {
  286         CS_WRITE(sc, AD1848_IADDR, r);
  287         return (CS_READ(sc, AD1848_IDATA));
  288 }
  289 
  290 int
  291 cs4231_set_speed(struct cs4231_softc *sc, u_long *argp)
  292 {
  293         /*
  294          * The available speeds are in the following table. Keep the speeds in
  295          * the increasing order.
  296          */
  297         typedef struct {
  298                 int speed;
  299                 u_char bits;
  300         } speed_struct;
  301         u_long arg = *argp;
  302 
  303         const static speed_struct speed_table[] = {
  304                 {5510,  (0 << 1) | CLOCK_XTAL2},
  305                 {5510,  (0 << 1) | CLOCK_XTAL2},
  306                 {6620,  (7 << 1) | CLOCK_XTAL2},
  307                 {8000,  (0 << 1) | CLOCK_XTAL1},
  308                 {9600,  (7 << 1) | CLOCK_XTAL1},
  309                 {11025, (1 << 1) | CLOCK_XTAL2},
  310                 {16000, (1 << 1) | CLOCK_XTAL1},
  311                 {18900, (2 << 1) | CLOCK_XTAL2},
  312                 {22050, (3 << 1) | CLOCK_XTAL2},
  313                 {27420, (2 << 1) | CLOCK_XTAL1},
  314                 {32000, (3 << 1) | CLOCK_XTAL1},
  315                 {33075, (6 << 1) | CLOCK_XTAL2},
  316                 {33075, (4 << 1) | CLOCK_XTAL2},
  317                 {44100, (5 << 1) | CLOCK_XTAL2},
  318                 {48000, (6 << 1) | CLOCK_XTAL1},
  319         };
  320 
  321         int i, n, selected = -1;
  322 
  323         n = sizeof(speed_table) / sizeof(speed_struct);
  324 
  325         if (arg < speed_table[0].speed)
  326                 selected = 0;
  327         if (arg > speed_table[n - 1].speed)
  328                 selected = n - 1;
  329 
  330         for (i = 1; selected == -1 && i < n; i++) {
  331                 if (speed_table[i].speed == arg)
  332                         selected = i;
  333                 else if (speed_table[i].speed > arg) {
  334                         int diff1, diff2;
  335 
  336                         diff1 = arg - speed_table[i - 1].speed;
  337                         diff2 = speed_table[i].speed - arg;
  338                         if (diff1 < diff2)
  339                                 selected = i - 1;
  340                         else
  341                                 selected = i;
  342                 }
  343         }
  344 
  345         if (selected == -1)
  346                 selected = 3;
  347 
  348         sc->sc_speed_bits = speed_table[selected].bits;
  349         sc->sc_need_commit = 1;
  350         *argp = speed_table[selected].speed;
  351 
  352         return (0);
  353 }
  354 
  355 /*
  356  * Audio interface functions
  357  */
  358 int
  359 cs4231_open(void *vsc, int flags)
  360 {
  361         struct cs4231_softc *sc = vsc;
  362         int tries;
  363 
  364         if (sc->sc_open)
  365                 return (EBUSY);
  366         sc->sc_open = 1;
  367 
  368         sc->sc_capture.cs_intr = NULL;
  369         sc->sc_capture.cs_arg = NULL;
  370         sc->sc_capture.cs_locked = 0;
  371 
  372         sc->sc_playback.cs_intr = NULL;
  373         sc->sc_playback.cs_arg = NULL;
  374         sc->sc_playback.cs_locked = 0;
  375 
  376         APC_WRITE(sc, APC_CSR, APC_CSR_RESET);
  377         DELAY(10);
  378         APC_WRITE(sc, APC_CSR, 0);
  379         DELAY(10);
  380         APC_WRITE(sc, APC_CSR, APC_READ(sc, APC_CSR) | APC_CSR_CODEC_RESET);
  381 
  382         DELAY(20);
  383 
  384         APC_WRITE(sc, APC_CSR, APC_READ(sc, APC_CSR) & (~APC_CSR_CODEC_RESET));
  385 
  386         for (tries = CS_TIMEOUT;
  387              tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--)
  388                 DELAY(10);
  389         if (tries == 0)
  390                 printf("%s: timeout waiting for reset\n", sc->sc_dev.dv_xname);
  391 
  392         /* Turn on cs4231 mode */
  393         cs4231_write(sc, SP_MISC_INFO,
  394             cs4231_read(sc, SP_MISC_INFO) | MODE2);
  395 
  396         cs4231_setup_output(sc);
  397 
  398         cs4231_write(sc, SP_PIN_CONTROL,
  399             cs4231_read(sc, SP_PIN_CONTROL) | INTERRUPT_ENABLE);
  400 
  401         return (0);
  402 }
  403 
  404 void
  405 cs4231_setup_output(struct cs4231_softc *sc)
  406 {
  407         u_int8_t pc, mi, rm, lm;
  408 
  409         pc = cs4231_read(sc, SP_PIN_CONTROL) | CS_PC_HDPHMUTE | CS_PC_LINEMUTE;
  410 
  411         mi = cs4231_read(sc, CS_MONO_IO_CONTROL) | MONO_OUTPUT_MUTE;
  412 
  413         lm = cs4231_read(sc, SP_LEFT_OUTPUT_CONTROL);
  414         lm &= ~OUTPUT_ATTEN_BITS;
  415         lm |= ((~(sc->sc_volume[CSPORT_SPEAKER].left >> 2)) &
  416             OUTPUT_ATTEN_BITS) | OUTPUT_MUTE;
  417 
  418         rm = cs4231_read(sc, SP_RIGHT_OUTPUT_CONTROL);
  419         rm &= ~OUTPUT_ATTEN_BITS;
  420         rm |= ((~(sc->sc_volume[CSPORT_SPEAKER].right >> 2)) &
  421             OUTPUT_ATTEN_BITS) | OUTPUT_MUTE;
  422 
  423         if (sc->sc_mute[CSPORT_MONITOR]) {
  424                 lm &= ~OUTPUT_MUTE;
  425                 rm &= ~OUTPUT_MUTE;
  426         }
  427 
  428         switch (sc->sc_out_port) {
  429         case CSPORT_HEADPHONE:
  430                 if (sc->sc_mute[CSPORT_SPEAKER])
  431                         pc &= ~CS_PC_HDPHMUTE;
  432                 break;
  433         case CSPORT_SPEAKER:
  434                 if (sc->sc_mute[CSPORT_SPEAKER])
  435                         mi &= ~MONO_OUTPUT_MUTE;
  436                 break;
  437         case CSPORT_LINEOUT:
  438                 if (sc->sc_mute[CSPORT_SPEAKER])
  439                         pc &= ~CS_PC_LINEMUTE;
  440                 break;
  441         }
  442 
  443         cs4231_write(sc, SP_LEFT_OUTPUT_CONTROL, lm);
  444         cs4231_write(sc, SP_RIGHT_OUTPUT_CONTROL, rm);
  445         cs4231_write(sc, SP_PIN_CONTROL, pc);
  446         cs4231_write(sc, CS_MONO_IO_CONTROL, mi);
  447 
  448         /* XXX doesn't really belong here... */
  449         switch (sc->sc_in_port) {
  450         case CSPORT_LINEIN:
  451                 pc = LINE_INPUT;
  452                 break;
  453         case CSPORT_AUX1:
  454                 pc = AUX_INPUT;
  455                 break;
  456         case CSPORT_DAC:
  457                 pc = MIXED_DAC_INPUT;
  458                 break;
  459         case CSPORT_MICROPHONE:
  460         default:
  461                 pc = MIC_INPUT;
  462                 break;
  463         }
  464         lm = cs4231_read(sc, SP_LEFT_INPUT_CONTROL);
  465         rm = cs4231_read(sc, SP_RIGHT_INPUT_CONTROL);
  466         lm &= ~(MIXED_DAC_INPUT | ATTEN_22_5);
  467         rm &= ~(MIXED_DAC_INPUT | ATTEN_22_5);
  468         lm |= pc | (sc->sc_adc.left >> 4);
  469         rm |= pc | (sc->sc_adc.right >> 4);
  470         cs4231_write(sc, SP_LEFT_INPUT_CONTROL, lm);
  471         cs4231_write(sc, SP_RIGHT_INPUT_CONTROL, rm);
  472 }
  473 
  474 void
  475 cs4231_close(void *vsc)
  476 {
  477         struct cs4231_softc *sc = vsc;
  478 
  479         cs4231_halt_input(sc);
  480         cs4231_halt_output(sc);
  481         cs4231_write(sc, SP_PIN_CONTROL,
  482             cs4231_read(sc, SP_PIN_CONTROL) & (~INTERRUPT_ENABLE));
  483         sc->sc_open = 0;
  484 }
  485 
  486 int
  487 cs4231_query_encoding(void *vsc, struct audio_encoding *fp)
  488 {
  489         int err = 0;
  490 
  491         switch (fp->index) {
  492         case 0:
  493                 strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
  494                 fp->encoding = AUDIO_ENCODING_ULAW;
  495                 fp->precision = 8;
  496                 fp->flags = 0;
  497                 break;
  498         case 1:
  499                 strlcpy(fp->name, AudioEalaw, sizeof fp->name);
  500                 fp->encoding = AUDIO_ENCODING_ALAW;
  501                 fp->precision = 8;
  502                 fp->flags = 0;
  503                 break;
  504         case 2:
  505                 strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
  506                 fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
  507                 fp->precision = 16;
  508                 fp->flags = 0;
  509                 break;
  510         case 3:
  511                 strlcpy(fp->name, AudioEulinear, sizeof fp->name);
  512                 fp->encoding = AUDIO_ENCODING_ULINEAR;
  513                 fp->precision = 8;
  514                 fp->flags = 0;
  515                 break;
  516         case 4:
  517                 strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
  518                 fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
  519                 fp->precision = 16;
  520                 fp->flags = 0;
  521                 break;
  522         case 5:
  523                 strlcpy(fp->name, AudioEslinear, sizeof fp->name);
  524                 fp->encoding = AUDIO_ENCODING_SLINEAR;
  525                 fp->precision = 8;
  526                 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
  527                 break;
  528         case 6:
  529                 strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
  530                 fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
  531                 fp->precision = 16;
  532                 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
  533                 break;
  534         case 7:
  535                 strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
  536                 fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
  537                 fp->precision = 16;
  538                 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
  539                 break;
  540         case 8:
  541                 strlcpy(fp->name, AudioEadpcm, sizeof fp->name);
  542                 fp->encoding = AUDIO_ENCODING_ADPCM;
  543                 fp->precision = 8;
  544                 fp->flags = 0;
  545                 break;
  546         default:
  547                 err = EINVAL;
  548         }
  549         return (err);
  550 }
  551 
  552 int
  553 cs4231_set_params(void *vsc, int setmode, int usemode,
  554     struct audio_params *p, struct audio_params *r)
  555 {
  556         struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
  557         int err, bits, enc = p->encoding;
  558         void (*pswcode)(void *, u_char *, int cnt) = NULL;
  559         void (*rswcode)(void *, u_char *, int cnt) = NULL;
  560 
  561         switch (enc) {
  562         case AUDIO_ENCODING_ULAW:
  563                 if (p->precision != 8)
  564                         return (EINVAL);
  565                 bits = FMT_ULAW >> 5;
  566                 break;
  567         case AUDIO_ENCODING_ALAW:
  568                 if (p->precision != 8)
  569                         return (EINVAL);
  570                 bits = FMT_ALAW >> 5;
  571                 break;
  572         case AUDIO_ENCODING_SLINEAR_LE:
  573                 if (p->precision == 8) {
  574                         bits = FMT_PCM8 >> 5;
  575                         pswcode = rswcode = change_sign8;
  576                 } else if (p->precision == 16)
  577                         bits = FMT_TWOS_COMP >> 5;
  578                 else
  579                         return (EINVAL);
  580                 break;
  581         case AUDIO_ENCODING_ULINEAR:
  582                 if (p->precision != 8)
  583                         return (EINVAL);
  584                 bits = FMT_PCM8 >> 5;
  585                 break;
  586         case AUDIO_ENCODING_SLINEAR_BE:
  587                 if (p->precision == 8) {
  588                         bits = FMT_PCM8 >> 5;
  589                         pswcode = rswcode = change_sign8;
  590                 } else if (p->precision == 16)
  591                         bits = FMT_TWOS_COMP_BE >> 5;
  592                 else
  593                         return (EINVAL);
  594                 break;
  595         case AUDIO_ENCODING_SLINEAR:
  596                 if (p->precision != 8)
  597                         return (EINVAL);
  598                 bits = FMT_PCM8 >> 5;
  599                 pswcode = rswcode = change_sign8;
  600                 break;
  601         case AUDIO_ENCODING_ULINEAR_LE:
  602                 if (p->precision == 8)
  603                         bits = FMT_PCM8 >> 5;
  604                 else if (p->precision == 16) {
  605                         bits = FMT_TWOS_COMP >> 5;
  606                         pswcode = rswcode = change_sign16_le;
  607                 } else
  608                         return (EINVAL);
  609                 break;
  610         case AUDIO_ENCODING_ULINEAR_BE:
  611                 if (p->precision == 8)
  612                         bits = FMT_PCM8 >> 5;
  613                 else if (p->precision == 16) {
  614                         bits = FMT_TWOS_COMP_BE >> 5;
  615                         pswcode = rswcode = change_sign16_be;
  616                 } else
  617                         return (EINVAL);
  618                 break;
  619         case AUDIO_ENCODING_ADPCM:
  620                 if (p->precision != 8)
  621                         return (EINVAL);
  622                 bits = FMT_ADPCM >> 5;
  623                 break;
  624         default:
  625                 return (EINVAL);
  626         }
  627 
  628         if (p->channels != 1 && p->channels != 2)
  629                 return (EINVAL);
  630 
  631         err = cs4231_set_speed(sc, &p->sample_rate);
  632         if (err)
  633                 return (err);
  634 
  635         p->sw_code = pswcode;
  636         r->sw_code = rswcode;
  637 
  638         sc->sc_format_bits = bits;
  639         sc->sc_channels = p->channels;
  640         sc->sc_precision = p->precision;
  641         sc->sc_need_commit = 1;
  642         return (0);
  643 }
  644 
  645 int
  646 cs4231_round_blocksize(void *vsc, int blk)
  647 {
  648         return ((blk + 3) & (-4));
  649 }
  650 
  651 int
  652 cs4231_commit_settings(void *vsc)
  653 {
  654         struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
  655         int s, tries;
  656         u_int8_t r, fs;
  657 
  658         if (sc->sc_need_commit == 0)
  659                 return (0);
  660 
  661         fs = sc->sc_speed_bits | (sc->sc_format_bits << 5);
  662         if (sc->sc_channels == 2)
  663                 fs |= FMT_STEREO;
  664 
  665         s = splaudio();
  666 
  667         r = cs4231_read(sc, SP_INTERFACE_CONFIG) | AUTO_CAL_ENABLE;
  668         CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE);
  669         CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE | SP_INTERFACE_CONFIG);
  670         CS_WRITE(sc, AD1848_IDATA, r);
  671 
  672         CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE | SP_CLOCK_DATA_FORMAT);
  673         CS_WRITE(sc, AD1848_IDATA, fs);
  674         CS_READ(sc, AD1848_IDATA);
  675         CS_READ(sc, AD1848_IDATA);
  676         tries = CS_TIMEOUT;
  677         for (tries = CS_TIMEOUT;
  678              tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--)
  679                 DELAY(10);
  680         if (tries == 0)
  681                 printf("%s: timeout committing fspb\n", sc->sc_dev.dv_xname);
  682 
  683         CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE | CS_REC_FORMAT);
  684         CS_WRITE(sc, AD1848_IDATA, fs);
  685         CS_READ(sc, AD1848_IDATA);
  686         CS_READ(sc, AD1848_IDATA);
  687         for (tries = CS_TIMEOUT;
  688              tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--)
  689                 DELAY(10);
  690         if (tries == 0)
  691                 printf("%s: timeout committing cdf\n", sc->sc_dev.dv_xname);
  692 
  693         CS_WRITE(sc, AD1848_IADDR, 0);
  694         for (tries = CS_TIMEOUT;
  695              tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--)
  696                 DELAY(10);
  697         if (tries == 0)
  698                 printf("%s: timeout waiting for !mce\n", sc->sc_dev.dv_xname);
  699 
  700         CS_WRITE(sc, AD1848_IADDR, SP_TEST_AND_INIT);
  701         for (tries = CS_TIMEOUT;
  702              tries && CS_READ(sc, AD1848_IDATA) & AUTO_CAL_IN_PROG; tries--)
  703                 DELAY(10);
  704         if (tries == 0)
  705                 printf("%s: timeout waiting for autocalibration\n",
  706                     sc->sc_dev.dv_xname);
  707 
  708         splx(s);
  709 
  710         sc->sc_need_commit = 0;
  711         return (0);
  712 }
  713 
  714 int
  715 cs4231_halt_output(void *vsc)
  716 {
  717         struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
  718 
  719         /* XXX Kills some capture bits */
  720         APC_WRITE(sc, APC_CSR, APC_READ(sc, APC_CSR) &
  721             ~(APC_CSR_EI | APC_CSR_GIE | APC_CSR_PIE |
  722               APC_CSR_EIE | APC_CSR_PDMA_GO | APC_CSR_PMIE));
  723         cs4231_write(sc, SP_INTERFACE_CONFIG,
  724             cs4231_read(sc, SP_INTERFACE_CONFIG) & (~PLAYBACK_ENABLE));
  725         sc->sc_playback.cs_locked = 0;
  726         return (0);
  727 }
  728 
  729 int
  730 cs4231_halt_input(void *vsc)
  731 {
  732         struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
  733 
  734         /* XXX Kills some playback bits */
  735         APC_WRITE(sc, APC_CSR, APC_CSR_CAPTURE_PAUSE);
  736         cs4231_write(sc, SP_INTERFACE_CONFIG,
  737             cs4231_read(sc, SP_INTERFACE_CONFIG) & (~CAPTURE_ENABLE));
  738         sc->sc_capture.cs_locked = 0;
  739         return (0);
  740 }
  741 
  742 int
  743 cs4231_getdev(void *vsc, struct audio_device *retp)
  744 {
  745         *retp = cs4231_device;
  746         return (0);
  747 }
  748 
  749 int
  750 cs4231_set_port(void *vsc, mixer_ctrl_t *cp)
  751 {
  752         struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
  753         int error = EINVAL;
  754 
  755         DPRINTF(("cs4231_set_port: port=%d type=%d\n", cp->dev, cp->type));
  756 
  757         switch (cp->dev) {
  758         case CSAUDIO_DAC_LVL:
  759                 if (cp->type != AUDIO_MIXER_VALUE)
  760                         break;
  761                 if (cp->un.value.num_channels == 1)
  762                         cs4231_write(sc, SP_LEFT_AUX1_CONTROL,
  763                             cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
  764                             LINE_INPUT_ATTEN_BITS);
  765                 else if (cp->un.value.num_channels == 2) {
  766                         cs4231_write(sc, SP_LEFT_AUX1_CONTROL,
  767                             cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] &
  768                             LINE_INPUT_ATTEN_BITS);
  769                         cs4231_write(sc, SP_RIGHT_AUX1_CONTROL,
  770                             cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] &
  771                             LINE_INPUT_ATTEN_BITS);
  772                 } else
  773                         break;
  774                 error = 0;
  775                 break;
  776         case CSAUDIO_LINE_IN_LVL:
  777                 if (cp->type != AUDIO_MIXER_VALUE)
  778                         break;
  779                 if (cp->un.value.num_channels == 1)
  780                         cs4231_write(sc, CS_LEFT_LINE_CONTROL,
  781                             cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
  782                             AUX_INPUT_ATTEN_BITS);
  783                 else if (cp->un.value.num_channels == 2) {
  784                         cs4231_write(sc, CS_LEFT_LINE_CONTROL,
  785                             cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] &
  786                             AUX_INPUT_ATTEN_BITS);
  787                         cs4231_write(sc, CS_RIGHT_LINE_CONTROL,
  788                             cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] &
  789                             AUX_INPUT_ATTEN_BITS);
  790                 } else
  791                         break;
  792                 error = 0;
  793                 break;
  794         case CSAUDIO_MIC_LVL:
  795                 if (cp->type != AUDIO_MIXER_VALUE)
  796                         break;
  797                 if (cp->un.value.num_channels == 1) {
  798 #if 0
  799                         cs4231_write(sc, CS_MONO_IO_CONTROL,
  800                             cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
  801                             MONO_INPUT_ATTEN_BITS);
  802 #endif
  803                 } else
  804                         break;
  805                 error = 0;
  806                 break;
  807         case CSAUDIO_CD_LVL:
  808                 if (cp->type != AUDIO_MIXER_VALUE)
  809                         break;
  810                 if (cp->un.value.num_channels == 1) {
  811                         cs4231_write(sc, SP_LEFT_AUX2_CONTROL,
  812                             cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
  813                             LINE_INPUT_ATTEN_BITS);
  814                 } else if (cp->un.value.num_channels == 2) {
  815                         cs4231_write(sc, SP_LEFT_AUX2_CONTROL,
  816                             cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] &
  817                             LINE_INPUT_ATTEN_BITS);
  818                         cs4231_write(sc, SP_RIGHT_AUX2_CONTROL,
  819                             cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] &
  820                             LINE_INPUT_ATTEN_BITS);
  821                 } else
  822                         break;
  823                 error = 0;
  824                 break;
  825         case CSAUDIO_MONITOR_LVL:
  826                 if (cp->type != AUDIO_MIXER_VALUE)
  827                         break;
  828                 if (cp->un.value.num_channels == 1)
  829                         cs4231_write(sc, SP_DIGITAL_MIX,
  830                             cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] << 2);
  831                 else
  832                         break;
  833                 error = 0;
  834                 break;
  835         case CSAUDIO_OUTPUT_LVL:
  836                 if (cp->type != AUDIO_MIXER_VALUE)
  837                         break;
  838                 if (cp->un.value.num_channels == 1) {
  839                         sc->sc_volume[CSPORT_SPEAKER].left =
  840                             cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
  841                         sc->sc_volume[CSPORT_SPEAKER].right =
  842                             cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
  843                 }
  844                 else if (cp->un.value.num_channels == 2) {
  845                         sc->sc_volume[CSPORT_SPEAKER].left =
  846                             cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
  847                         sc->sc_volume[CSPORT_SPEAKER].right =
  848                             cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
  849                 }
  850                 else
  851                         break;
  852 
  853                 cs4231_setup_output(sc);
  854                 error = 0;
  855                 break;
  856         case CSAUDIO_OUTPUT:
  857                 if (cp->type != AUDIO_MIXER_ENUM)
  858                         break;
  859                 if (cp->un.ord != CSPORT_LINEOUT &&
  860                     cp->un.ord != CSPORT_SPEAKER &&
  861                     cp->un.ord != CSPORT_HEADPHONE)
  862                         return (EINVAL);
  863                 sc->sc_out_port = cp->un.ord;
  864                 cs4231_setup_output(sc);
  865                 error = 0;
  866                 break;
  867         case CSAUDIO_LINE_IN_MUTE:
  868                 if (cp->type != AUDIO_MIXER_ENUM)
  869                         break;
  870                 sc->sc_mute[CSPORT_LINEIN] = cp->un.ord ? 1 : 0;
  871                 error = 0;
  872                 break;
  873         case CSAUDIO_DAC_MUTE:
  874                 if (cp->type != AUDIO_MIXER_ENUM)
  875                         break;
  876                 sc->sc_mute[CSPORT_AUX1] = cp->un.ord ? 1 : 0;
  877                 error = 0;
  878                 break;
  879         case CSAUDIO_CD_MUTE:
  880                 if (cp->type != AUDIO_MIXER_ENUM)
  881                         break;
  882                 sc->sc_mute[CSPORT_AUX2] = cp->un.ord ? 1 : 0;
  883                 error = 0;
  884                 break;
  885         case CSAUDIO_MIC_MUTE:
  886                 if (cp->type != AUDIO_MIXER_ENUM)
  887                         break;
  888                 sc->sc_mute[CSPORT_MONO] = cp->un.ord ? 1 : 0;
  889                 error = 0;
  890                 break;
  891         case CSAUDIO_MONITOR_MUTE:
  892                 if (cp->type != AUDIO_MIXER_ENUM)
  893                         break;
  894                 sc->sc_mute[CSPORT_MONITOR] = cp->un.ord ? 1 : 0;
  895                 error = 0;
  896                 break;
  897         case CSAUDIO_OUTPUT_MUTE:
  898                 if (cp->type != AUDIO_MIXER_ENUM)
  899                         break;
  900                 sc->sc_mute[CSPORT_SPEAKER] = cp->un.ord ? 1 : 0;
  901                 cs4231_setup_output(sc);
  902                 error = 0;
  903                 break;
  904         case CSAUDIO_REC_LVL:
  905                 if (cp->type != AUDIO_MIXER_VALUE)
  906                         break;
  907                 if (cp->un.value.num_channels == 1) {
  908                         sc->sc_adc.left =
  909                             cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
  910                         sc->sc_adc.right =
  911                             cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
  912                 } else if (cp->un.value.num_channels == 2) {
  913                         sc->sc_adc.left =
  914                             cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
  915                         sc->sc_adc.right =
  916                             cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
  917                 } else
  918                         break;
  919                 cs4231_setup_output(sc);
  920                 error = 0;
  921                 break;
  922         case CSAUDIO_RECORD_SOURCE:
  923                 if (cp->type != AUDIO_MIXER_ENUM)
  924                         break;
  925                 if (cp->un.ord == CSPORT_MICROPHONE ||
  926                     cp->un.ord == CSPORT_LINEIN ||
  927                     cp->un.ord == CSPORT_AUX1 ||
  928                     cp->un.ord == CSPORT_DAC) {
  929                         sc->sc_in_port  = cp->un.ord;
  930                         error = 0;
  931                         cs4231_setup_output(sc);
  932                 }
  933                 break;
  934         }
  935 
  936         return (error);
  937 }
  938 
  939 int
  940 cs4231_get_port(void *vsc, mixer_ctrl_t *cp)
  941 {
  942         struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
  943         int error = EINVAL;
  944 
  945         DPRINTF(("cs4231_get_port: port=%d type=%d\n", cp->dev, cp->type));
  946 
  947         switch (cp->dev) {
  948         case CSAUDIO_DAC_LVL:
  949                 if (cp->type != AUDIO_MIXER_VALUE)
  950                         break;
  951                 if (cp->un.value.num_channels == 1)
  952                         cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]=
  953                             cs4231_read(sc, SP_LEFT_AUX1_CONTROL) &
  954                             LINE_INPUT_ATTEN_BITS;
  955                 else if (cp->un.value.num_channels == 2) {
  956                         cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
  957                             cs4231_read(sc, SP_LEFT_AUX1_CONTROL) &
  958                             LINE_INPUT_ATTEN_BITS;
  959                         cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
  960                             cs4231_read(sc, SP_RIGHT_AUX1_CONTROL) &
  961                             LINE_INPUT_ATTEN_BITS;
  962                 } else
  963                         break;
  964                 error = 0;
  965                 break;
  966         case CSAUDIO_LINE_IN_LVL:
  967                 if (cp->type != AUDIO_MIXER_VALUE)
  968                         break;
  969                 if (cp->un.value.num_channels == 1)
  970                         cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
  971                             cs4231_read(sc, CS_LEFT_LINE_CONTROL) & AUX_INPUT_ATTEN_BITS;
  972                 else if (cp->un.value.num_channels == 2) {
  973                         cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
  974                             cs4231_read(sc, CS_LEFT_LINE_CONTROL) & AUX_INPUT_ATTEN_BITS;
  975                         cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
  976                             cs4231_read(sc, CS_RIGHT_LINE_CONTROL) & AUX_INPUT_ATTEN_BITS;
  977                 } else
  978                         break;
  979                 error = 0;
  980                 break;
  981         case CSAUDIO_MIC_LVL:
  982                 if (cp->type != AUDIO_MIXER_VALUE)
  983                         break;
  984                 if (cp->un.value.num_channels == 1) {
  985 #if 0
  986                         cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
  987                             cs4231_read(sc, CS_MONO_IO_CONTROL) &
  988                             MONO_INPUT_ATTEN_BITS;
  989 #endif
  990                 } else
  991                         break;
  992                 error = 0;
  993                 break;
  994         case CSAUDIO_CD_LVL:
  995                 if (cp->type != AUDIO_MIXER_VALUE)
  996                         break;
  997                 if (cp->un.value.num_channels == 1)
  998                         cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
  999                             cs4231_read(sc, SP_LEFT_AUX2_CONTROL) &
 1000                             LINE_INPUT_ATTEN_BITS;
 1001                 else if (cp->un.value.num_channels == 2) {
 1002                         cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
 1003                             cs4231_read(sc, SP_LEFT_AUX2_CONTROL) &
 1004                             LINE_INPUT_ATTEN_BITS;
 1005                         cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
 1006                             cs4231_read(sc, SP_RIGHT_AUX2_CONTROL) &
 1007                             LINE_INPUT_ATTEN_BITS;
 1008                 }
 1009                 else
 1010                         break;
 1011                 error = 0;
 1012                 break;
 1013         case CSAUDIO_MONITOR_LVL:
 1014                 if (cp->type != AUDIO_MIXER_VALUE)
 1015                         break;
 1016                 if (cp->un.value.num_channels != 1)
 1017                         break;
 1018                 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
 1019                     cs4231_read(sc, SP_DIGITAL_MIX) >> 2;
 1020                 error = 0;
 1021                 break;
 1022         case CSAUDIO_OUTPUT_LVL:
 1023                 if (cp->type != AUDIO_MIXER_VALUE)
 1024                         break;
 1025                 if (cp->un.value.num_channels == 1)
 1026                         cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
 1027                             sc->sc_volume[CSPORT_SPEAKER].left;
 1028                 else if (cp->un.value.num_channels == 2) {
 1029                         cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
 1030                             sc->sc_volume[CSPORT_SPEAKER].left;
 1031                         cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
 1032                             sc->sc_volume[CSPORT_SPEAKER].right;
 1033                 }
 1034                 else
 1035                         break;
 1036                 error = 0;
 1037                 break;
 1038         case CSAUDIO_LINE_IN_MUTE:
 1039                 if (cp->type != AUDIO_MIXER_ENUM)
 1040                         break;
 1041                 cp->un.ord = sc->sc_mute[CSPORT_LINEIN] ? 1 : 0;
 1042                 error = 0;
 1043                 break;
 1044         case CSAUDIO_DAC_MUTE:
 1045                 if (cp->type != AUDIO_MIXER_ENUM)
 1046                         break;
 1047                 cp->un.ord = sc->sc_mute[CSPORT_AUX1] ? 1 : 0;
 1048                 error = 0;
 1049                 break;
 1050         case CSAUDIO_CD_MUTE:
 1051                 if (cp->type != AUDIO_MIXER_ENUM)
 1052                         break;
 1053                 cp->un.ord = sc->sc_mute[CSPORT_AUX2] ? 1 : 0;
 1054                 error = 0;
 1055                 break;
 1056         case CSAUDIO_MIC_MUTE:
 1057                 if (cp->type != AUDIO_MIXER_ENUM)
 1058                         break;
 1059                 cp->un.ord = sc->sc_mute[CSPORT_MONO] ? 1 : 0;
 1060                 error = 0;
 1061                 break;
 1062         case CSAUDIO_MONITOR_MUTE:
 1063                 if (cp->type != AUDIO_MIXER_ENUM)
 1064                         break;
 1065                 cp->un.ord = sc->sc_mute[CSPORT_MONITOR] ? 1 : 0;
 1066                 error = 0;
 1067                 break;
 1068         case CSAUDIO_OUTPUT_MUTE:
 1069                 if (cp->type != AUDIO_MIXER_ENUM)
 1070                         break;
 1071                 cp->un.ord = sc->sc_mute[CSPORT_SPEAKER] ? 1 : 0;
 1072                 error = 0;
 1073                 break;
 1074         case CSAUDIO_REC_LVL:
 1075                 if (cp->type != AUDIO_MIXER_VALUE)
 1076                         break;
 1077                 if (cp->un.value.num_channels == 1) {
 1078                         cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
 1079                             sc->sc_adc.left;
 1080                 } else if (cp->un.value.num_channels == 2) {
 1081                         cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
 1082                             sc->sc_adc.left;
 1083                         cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
 1084                             sc->sc_adc.right;
 1085                 } else
 1086                         break;
 1087                 error = 0;
 1088                 break;
 1089         case CSAUDIO_RECORD_SOURCE:
 1090                 if (cp->type != AUDIO_MIXER_ENUM)
 1091                         break;
 1092                 cp->un.ord = sc->sc_in_port;
 1093                 error = 0;
 1094                 break;
 1095         case CSAUDIO_OUTPUT:
 1096                 if (cp->type != AUDIO_MIXER_ENUM)
 1097                         break;
 1098                 cp->un.ord = sc->sc_out_port;
 1099                 error = 0;
 1100                 break;
 1101         }
 1102         return (error);
 1103 }
 1104 
 1105 int
 1106 cs4231_query_devinfo(void *vsc, mixer_devinfo_t *dip)
 1107 {
 1108         int err = 0;
 1109 
 1110         switch (dip->index) {
 1111         case CSAUDIO_MIC_LVL:           /* mono/microphone mixer */
 1112                 dip->type = AUDIO_MIXER_VALUE;
 1113                 dip->mixer_class = CSAUDIO_INPUT_CLASS;
 1114                 dip->prev = AUDIO_MIXER_LAST;
 1115                 dip->next = CSAUDIO_MIC_MUTE;
 1116                 strlcpy(dip->label.name, AudioNmicrophone,
 1117                     sizeof dip->label.name);
 1118                 dip->un.v.num_channels = 1;
 1119                 strlcpy(dip->un.v.units.name, AudioNvolume,
 1120                     sizeof dip->un.v.units.name);
 1121                 break;
 1122         case CSAUDIO_DAC_LVL:           /* dacout */
 1123                 dip->type = AUDIO_MIXER_VALUE;
 1124                 dip->mixer_class = CSAUDIO_INPUT_CLASS;
 1125                 dip->prev = AUDIO_MIXER_LAST;
 1126                 dip->next = CSAUDIO_DAC_MUTE;
 1127                 strlcpy(dip->label.name, AudioNdac,
 1128                     sizeof dip->label.name);
 1129                 dip->un.v.num_channels = 2;
 1130                 strlcpy(dip->un.v.units.name, AudioNvolume,
 1131                     sizeof dip->un.v.units.name);
 1132                 break;
 1133         case CSAUDIO_LINE_IN_LVL:       /* line */
 1134                 dip->type = AUDIO_MIXER_VALUE;
 1135                 dip->mixer_class = CSAUDIO_INPUT_CLASS;
 1136                 dip->prev = AUDIO_MIXER_LAST;
 1137                 dip->next = CSAUDIO_LINE_IN_MUTE;
 1138                 strlcpy(dip->label.name, AudioNline, sizeof dip->label.name);
 1139                 dip->un.v.num_channels = 2;
 1140                 strlcpy(dip->un.v.units.name, AudioNvolume,
 1141                     sizeof dip->un.v.units.name);
 1142                 break;
 1143         case CSAUDIO_CD_LVL:            /* cd */
 1144                 dip->type = AUDIO_MIXER_VALUE;
 1145                 dip->mixer_class = CSAUDIO_INPUT_CLASS;
 1146                 dip->prev = AUDIO_MIXER_LAST;
 1147                 dip->next = CSAUDIO_CD_MUTE;
 1148                 strlcpy(dip->label.name, AudioNcd, sizeof dip->label.name);
 1149                 dip->un.v.num_channels = 2;
 1150                 strlcpy(dip->un.v.units.name, AudioNvolume,
 1151                     sizeof dip->un.v.units.name);
 1152                 break;
 1153         case CSAUDIO_MONITOR_LVL:       /* monitor level */
 1154                 dip->type = AUDIO_MIXER_VALUE;
 1155                 dip->mixer_class = CSAUDIO_MONITOR_CLASS;
 1156                 dip->prev = AUDIO_MIXER_LAST;
 1157                 dip->next = CSAUDIO_MONITOR_MUTE;
 1158                 strlcpy(dip->label.name, AudioNmonitor,
 1159                     sizeof dip->label.name);
 1160                 dip->un.v.num_channels = 1;
 1161                 strlcpy(dip->un.v.units.name, AudioNvolume,
 1162                     sizeof dip->un.v.units.name);
 1163                 break;
 1164         case CSAUDIO_OUTPUT_LVL:
 1165                 dip->type = AUDIO_MIXER_VALUE;
 1166                 dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
 1167                 dip->prev = AUDIO_MIXER_LAST;
 1168                 dip->next = CSAUDIO_OUTPUT_MUTE;
 1169                 strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
 1170                 dip->un.v.num_channels = 2;
 1171                 strlcpy(dip->un.v.units.name, AudioNvolume,
 1172                     sizeof dip->un.v.units.name);
 1173                 break;
 1174         case CSAUDIO_LINE_IN_MUTE:
 1175                 dip->type = AUDIO_MIXER_ENUM;
 1176                 dip->mixer_class = CSAUDIO_INPUT_CLASS;
 1177                 dip->prev = CSAUDIO_LINE_IN_LVL;
 1178                 dip->next = AUDIO_MIXER_LAST;
 1179                 goto mute;
 1180         case CSAUDIO_DAC_MUTE:
 1181                 dip->type = AUDIO_MIXER_ENUM;
 1182                 dip->mixer_class = CSAUDIO_INPUT_CLASS;
 1183                 dip->prev = CSAUDIO_DAC_LVL;
 1184                 dip->next = AUDIO_MIXER_LAST;
 1185                 goto mute;
 1186         case CSAUDIO_CD_MUTE:
 1187                 dip->type = AUDIO_MIXER_ENUM;
 1188                 dip->mixer_class = CSAUDIO_INPUT_CLASS;
 1189                 dip->prev = CSAUDIO_CD_LVL;
 1190                 dip->next = AUDIO_MIXER_LAST;
 1191                 goto mute;
 1192         case CSAUDIO_MIC_MUTE:
 1193                 dip->type = AUDIO_MIXER_ENUM;
 1194                 dip->mixer_class = CSAUDIO_INPUT_CLASS;
 1195                 dip->prev = CSAUDIO_MIC_LVL;
 1196                 dip->next = AUDIO_MIXER_LAST;
 1197                 goto mute;
 1198         case CSAUDIO_MONITOR_MUTE:
 1199                 dip->type = AUDIO_MIXER_ENUM;
 1200                 dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
 1201                 dip->prev = CSAUDIO_MONITOR_LVL;
 1202                 dip->next = AUDIO_MIXER_LAST;
 1203                 goto mute;
 1204         case CSAUDIO_OUTPUT_MUTE:
 1205                 dip->type = AUDIO_MIXER_ENUM;
 1206                 dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
 1207                 dip->prev = CSAUDIO_OUTPUT_LVL;
 1208                 dip->next = AUDIO_MIXER_LAST;
 1209                 goto mute;
 1210 
 1211         mute:
 1212                 strlcpy(dip->label.name, AudioNmute, sizeof dip->label.name);
 1213                 dip->un.e.num_mem = 2;
 1214                 strlcpy(dip->un.e.member[0].label.name, AudioNon,
 1215                     sizeof dip->un.e.member[0].label.name);
 1216                 dip->un.e.member[0].ord = 0;
 1217                 strlcpy(dip->un.e.member[1].label.name, AudioNoff,
 1218                     sizeof dip->un.e.member[1].label.name);
 1219                 dip->un.e.member[1].ord = 1;
 1220                 break;
 1221         case CSAUDIO_REC_LVL:           /* record level */
 1222                 dip->type = AUDIO_MIXER_VALUE;
 1223                 dip->mixer_class = CSAUDIO_RECORD_CLASS;
 1224                 dip->prev = AUDIO_MIXER_LAST;
 1225                 dip->next = CSAUDIO_RECORD_SOURCE;
 1226                 strlcpy(dip->label.name, AudioNrecord, sizeof dip->label.name);
 1227                 dip->un.v.num_channels = 2;
 1228                 strlcpy(dip->un.v.units.name, AudioNvolume,
 1229                     sizeof dip->un.v.units.name);
 1230                 break;
 1231         case CSAUDIO_RECORD_SOURCE:
 1232                 dip->type = AUDIO_MIXER_ENUM;
 1233                 dip->mixer_class = CSAUDIO_RECORD_CLASS;
 1234                 dip->prev = CSAUDIO_REC_LVL;
 1235                 dip->next = AUDIO_MIXER_LAST;
 1236                 strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
 1237                 dip->un.e.num_mem = 4;
 1238                 strlcpy(dip->un.e.member[0].label.name, AudioNmicrophone,
 1239                     sizeof dip->un.e.member[0].label.name);
 1240                 dip->un.e.member[0].ord = CSPORT_MICROPHONE;
 1241                 strlcpy(dip->un.e.member[1].label.name, AudioNline,
 1242                     sizeof dip->un.e.member[1].label.name);
 1243                 dip->un.e.member[1].ord = CSPORT_LINEIN;
 1244                 strlcpy(dip->un.e.member[2].label.name, AudioNcd,
 1245                     sizeof dip->un.e.member[2].label.name);
 1246                 dip->un.e.member[2].ord = CSPORT_AUX1;
 1247                 strlcpy(dip->un.e.member[3].label.name, AudioNdac,
 1248                     sizeof dip->un.e.member[3].label.name);
 1249                 dip->un.e.member[3].ord = CSPORT_DAC;
 1250                 break;
 1251         case CSAUDIO_OUTPUT:
 1252                 dip->type = AUDIO_MIXER_ENUM;
 1253                 dip->mixer_class = CSAUDIO_MONITOR_CLASS;
 1254                 dip->prev = dip->next = AUDIO_MIXER_LAST;
 1255                 strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
 1256                 dip->un.e.num_mem = 3;
 1257                 strlcpy(dip->un.e.member[0].label.name, AudioNspeaker,
 1258                     sizeof dip->un.e.member[0].label.name);
 1259                 dip->un.e.member[0].ord = CSPORT_SPEAKER;
 1260                 strlcpy(dip->un.e.member[1].label.name, AudioNline,
 1261                     sizeof dip->un.e.member[1].label.name);
 1262                 dip->un.e.member[1].ord = CSPORT_LINEOUT;
 1263                 strlcpy(dip->un.e.member[2].label.name, AudioNheadphone,
 1264                     sizeof dip->un.e.member[2].label.name);
 1265                 dip->un.e.member[2].ord = CSPORT_HEADPHONE;
 1266                 break;
 1267         case CSAUDIO_INPUT_CLASS:       /* input class descriptor */
 1268                 dip->type = AUDIO_MIXER_CLASS;
 1269                 dip->mixer_class = CSAUDIO_INPUT_CLASS;
 1270                 dip->prev = AUDIO_MIXER_LAST;
 1271                 dip->next = AUDIO_MIXER_LAST;
 1272                 strlcpy(dip->label.name, AudioCinputs, sizeof dip->label.name);
 1273                 break;
 1274         case CSAUDIO_OUTPUT_CLASS:      /* output class descriptor */
 1275                 dip->type = AUDIO_MIXER_CLASS;
 1276                 dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
 1277                 dip->prev = AUDIO_MIXER_LAST;
 1278                 dip->next = AUDIO_MIXER_LAST;
 1279                 strlcpy(dip->label.name, AudioCoutputs,
 1280                     sizeof dip->label.name);
 1281                 break;
 1282         case CSAUDIO_MONITOR_CLASS:     /* monitor class descriptor */
 1283                 dip->type = AUDIO_MIXER_CLASS;
 1284                 dip->mixer_class = CSAUDIO_MONITOR_CLASS;
 1285                 dip->prev = AUDIO_MIXER_LAST;
 1286                 dip->next = AUDIO_MIXER_LAST;
 1287                 strlcpy(dip->label.name, AudioCmonitor,
 1288                     sizeof dip->label.name);
 1289                 break;
 1290         case CSAUDIO_RECORD_CLASS:      /* record class descriptor */
 1291                 dip->type = AUDIO_MIXER_CLASS;
 1292                 dip->mixer_class = CSAUDIO_RECORD_CLASS;
 1293                 dip->prev = AUDIO_MIXER_LAST;
 1294                 dip->next = AUDIO_MIXER_LAST;
 1295                 strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
 1296                 break;
 1297         default:
 1298                 err = ENXIO;
 1299         }
 1300 
 1301         return (err);
 1302 }
 1303 
 1304 int
 1305 cs4231_get_props(void *vsc)
 1306 {
 1307         return (AUDIO_PROP_FULLDUPLEX);
 1308 }
 1309 
 1310 /*
 1311  * Hardware interrupt handler
 1312  */
 1313 int
 1314 cs4231_intr(void *vsc)
 1315 {
 1316         struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
 1317         u_int32_t csr;
 1318         u_int8_t reg, status;
 1319         struct cs_dma *p;
 1320         int r = 0;
 1321 
 1322         csr = APC_READ(sc, APC_CSR);
 1323         APC_WRITE(sc, APC_CSR, csr);
 1324 
 1325         if ((csr & APC_CSR_EIE) && (csr & APC_CSR_EI)) {
 1326                 printf("%s: error interrupt\n", sc->sc_dev.dv_xname);
 1327                 r = 1;
 1328         }
 1329 
 1330         if ((csr & APC_CSR_PIE) && (csr & APC_CSR_PI)) {
 1331                 /* playback interrupt */
 1332                 r = 1;
 1333         }
 1334 
 1335         if ((csr & APC_CSR_GIE) && (csr & APC_CSR_GI)) {
 1336                 /* general interrupt */
 1337                 status = CS_READ(sc, AD1848_STATUS);
 1338                 if (status & (INTERRUPT_STATUS | SAMPLE_ERROR)) {
 1339                         reg = cs4231_read(sc, CS_IRQ_STATUS);
 1340                         if (reg & CS_AFS_PI) {
 1341                                 cs4231_write(sc, SP_LOWER_BASE_COUNT, 0xff);
 1342                                 cs4231_write(sc, SP_UPPER_BASE_COUNT, 0xff);
 1343                         }
 1344                         if (reg & CS_AFS_CI) {
 1345                                 cs4231_write(sc, CS_LOWER_REC_CNT, 0xff);
 1346                                 cs4231_write(sc, CS_UPPER_REC_CNT, 0xff);
 1347                         }
 1348                         CS_WRITE(sc, AD1848_STATUS, 0);
 1349                 }
 1350                 r = 1;
 1351         }
 1352 
 1353 
 1354         if (csr & (APC_CSR_PI|APC_CSR_PMI|APC_CSR_PIE|APC_CSR_PD))
 1355                 r = 1;
 1356 
 1357         if ((csr & APC_CSR_PMIE) && (csr & APC_CSR_PMI)) {
 1358                 struct cs_channel *chan = &sc->sc_playback;
 1359                 u_long nextaddr, togo;
 1360 
 1361                 p = chan->cs_curdma;
 1362                 togo = chan->cs_segsz - chan->cs_cnt;
 1363                 if (togo == 0) {
 1364                         nextaddr = (u_int32_t)p->dmamap->dm_segs[0].ds_addr;
 1365                         chan->cs_cnt = togo = chan->cs_blksz;
 1366                 } else {
 1367                         nextaddr = APC_READ(sc, APC_PNVA) + chan->cs_blksz;
 1368                         if (togo > chan->cs_blksz)
 1369                                 togo = chan->cs_blksz;
 1370                         chan->cs_cnt += togo;
 1371                 }
 1372 
 1373                 APC_WRITE(sc, APC_PNVA, nextaddr);
 1374                 APC_WRITE(sc, APC_PNC, togo);
 1375 
 1376                 if (chan->cs_intr != NULL)
 1377                         (*chan->cs_intr)(chan->cs_arg);
 1378                 r = 1;
 1379         }
 1380 
 1381         if ((csr & APC_CSR_CIE) && (csr & APC_CSR_CI)) {
 1382                 if (csr & APC_CSR_CD) {
 1383                         struct cs_channel *chan = &sc->sc_capture;
 1384                         u_long nextaddr, togo;
 1385 
 1386                         p = chan->cs_curdma;
 1387                         togo = chan->cs_segsz - chan->cs_cnt;
 1388                         if (togo == 0) {
 1389                                 nextaddr =
 1390                                     (u_int32_t)p->dmamap->dm_segs[0].ds_addr;
 1391                                 chan->cs_cnt = togo = chan->cs_blksz;
 1392                         } else {
 1393                                 nextaddr = APC_READ(sc, APC_CNVA) +
 1394                                     chan->cs_blksz;
 1395                                 if (togo > chan->cs_blksz)
 1396                                         togo = chan->cs_blksz;
 1397                                 chan->cs_cnt += togo;
 1398                         }
 1399 
 1400                         APC_WRITE(sc, APC_CNVA, nextaddr);
 1401                         APC_WRITE(sc, APC_CNC, togo);
 1402 
 1403                         if (chan->cs_intr != NULL)
 1404                                 (*chan->cs_intr)(chan->cs_arg);
 1405                 }
 1406                 r = 1;
 1407         }
 1408 
 1409         if ((csr & APC_CSR_CMIE) && (csr & APC_CSR_CMI)) {
 1410                 /* capture empty */
 1411                 r = 1;
 1412         }
 1413 
 1414         return (r);
 1415 }
 1416 
 1417 void *
 1418 cs4231_alloc(void *vsc, int direction, size_t size, int pool, int flags)
 1419 {
 1420         struct cs4231_softc *sc = (struct cs4231_softc *)vsc;
 1421         bus_dma_tag_t dmat = sc->sc_dmatag;
 1422         struct cs_dma *p;
 1423 
 1424         p = (struct cs_dma *)malloc(sizeof(struct cs_dma), pool, flags);
 1425         if (p == NULL)
 1426                 return (NULL);
 1427 
 1428         if (bus_dmamap_create(dmat, size, 1, size, 0,
 1429             BUS_DMA_NOWAIT, &p->dmamap) != 0)
 1430                 goto fail;
 1431 
 1432         p->size = size;
 1433 
 1434         if (bus_dmamem_alloc(dmat, size, 64*1024, 0, p->segs,
 1435             sizeof(p->segs)/sizeof(p->segs[0]), &p->nsegs,
 1436             BUS_DMA_NOWAIT) != 0)
 1437                 goto fail1;
 1438 
 1439         if (bus_dmamem_map(dmat, p->segs, p->nsegs, p->size,
 1440             &p->addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT) != 0)
 1441                 goto fail2;
 1442 
 1443         if (bus_dmamap_load(dmat, p->dmamap, p->addr, size, NULL,
 1444             BUS_DMA_NOWAIT) != 0)
 1445                 goto fail3;
 1446 
 1447         p->next = sc->sc_dmas;
 1448         sc->sc_dmas = p;
 1449         return (p->addr);
 1450 
 1451 fail3:
 1452         bus_dmamem_unmap(dmat, p->addr, p->size);
 1453 fail2:
 1454         bus_dmamem_free(dmat, p->segs, p->nsegs);
 1455 fail1:
 1456         bus_dmamap_destroy(dmat, p->dmamap);
 1457 fail:
 1458         free(p, pool);
 1459         return (NULL);
 1460 }
 1461 
 1462 void
 1463 cs4231_free(void *vsc, void *ptr, int pool)
 1464 {
 1465         struct cs4231_softc *sc = vsc;
 1466         bus_dma_tag_t dmat = sc->sc_dmatag;
 1467         struct cs_dma *p, **pp;
 1468 
 1469         for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &(*pp)->next) {
 1470                 if (p->addr != ptr)
 1471                         continue;
 1472                 bus_dmamap_unload(dmat, p->dmamap);
 1473                 bus_dmamem_unmap(dmat, p->addr, p->size);
 1474                 bus_dmamem_free(dmat, p->segs, p->nsegs);
 1475                 bus_dmamap_destroy(dmat, p->dmamap);
 1476                 *pp = p->next;
 1477                 free(p, pool);
 1478                 return;
 1479         }
 1480         printf("%s: attempt to free rogue pointer\n", sc->sc_dev.dv_xname);
 1481 }
 1482 
 1483 int
 1484 cs4231_trigger_output(void *vsc, void *start, void *end, int blksize,
 1485     void (*intr)(void *), void *arg, struct audio_params *param)
 1486 {
 1487         struct cs4231_softc *sc = vsc;
 1488         struct cs_channel *chan = &sc->sc_playback;
 1489         struct cs_dma *p;
 1490         u_int32_t csr;
 1491         u_long n;
 1492 
 1493         if (chan->cs_locked != 0) {
 1494                 printf("%s: trigger_output: already running\n",
 1495                     sc->sc_dev.dv_xname);
 1496                 return (EINVAL);
 1497         }
 1498 
 1499         chan->cs_locked = 1;
 1500         chan->cs_intr = intr;
 1501         chan->cs_arg = arg;
 1502 
 1503         for (p = sc->sc_dmas; p->addr != start; p = p->next)
 1504                 /*EMPTY*/;
 1505         if (p == NULL) {
 1506                 printf("%s: trigger_output: bad addr: %p\n",
 1507                     sc->sc_dev.dv_xname, start);
 1508                 return (EINVAL);
 1509         }
 1510 
 1511         n = (char *)end - (char *)start;
 1512 
 1513         /*
 1514          * Do only `blksize' at a time, so audio_pint() is kept
 1515          * synchronous with us...
 1516          */
 1517         chan->cs_blksz = blksize;
 1518         chan->cs_curdma = p;
 1519         chan->cs_segsz = n;
 1520 
 1521         if (n > chan->cs_blksz)
 1522                 n = chan->cs_blksz;
 1523 
 1524         chan->cs_cnt = n;
 1525 
 1526         csr = APC_READ(sc, APC_CSR);
 1527 
 1528         APC_WRITE(sc, APC_PNVA, (u_long)p->dmamap->dm_segs[0].ds_addr);
 1529         APC_WRITE(sc, APC_PNC, (u_long)n);
 1530 
 1531         if ((csr & APC_CSR_PDMA_GO) == 0 || (csr & APC_CSR_PPAUSE) != 0) {
 1532                 APC_WRITE(sc, APC_CSR,
 1533                     APC_READ(sc, APC_CSR) & ~(APC_CSR_PIE | APC_CSR_PPAUSE));
 1534                 APC_WRITE(sc, APC_CSR, APC_READ(sc, APC_CSR) |
 1535                     APC_CSR_EI | APC_CSR_GIE | APC_CSR_PIE | APC_CSR_EIE |
 1536                     APC_CSR_PMIE | APC_CSR_PDMA_GO);
 1537                 cs4231_write(sc, SP_LOWER_BASE_COUNT, 0xff);
 1538                 cs4231_write(sc, SP_UPPER_BASE_COUNT, 0xff);
 1539                 cs4231_write(sc, SP_INTERFACE_CONFIG,
 1540                     cs4231_read(sc, SP_INTERFACE_CONFIG) | PLAYBACK_ENABLE);
 1541         }
 1542         return (0);
 1543 }
 1544 
 1545 int
 1546 cs4231_trigger_input(void *vsc, void *start, void *end, int blksize,
 1547     void (*intr)(void *), void *arg, struct audio_params *param)
 1548 {
 1549         struct cs4231_softc *sc = vsc;
 1550         struct cs_channel *chan = &sc->sc_capture;
 1551         struct cs_dma *p;
 1552         u_int32_t csr;
 1553         u_long n;
 1554 
 1555         if (chan->cs_locked != 0) {
 1556                 printf("%s: trigger_input: already running\n",
 1557                     sc->sc_dev.dv_xname);
 1558                 return (EINVAL);
 1559         }
 1560         chan->cs_locked = 1;
 1561         chan->cs_intr = intr;
 1562         chan->cs_arg = arg;
 1563 
 1564         for (p = sc->sc_dmas; p->addr != start; p = p->next)
 1565                 /*EMPTY*/;
 1566         if (p == NULL) {
 1567                 printf("%s: trigger_input: bad addr: %p\n",
 1568                     sc->sc_dev.dv_xname, start);
 1569                 return (EINVAL);
 1570         }
 1571 
 1572         n = (char *)end - (char *)start;
 1573 
 1574         /*
 1575          * Do only `blksize' at a time, so audio_cint() is kept
 1576          * synchronous with us...
 1577          */
 1578         chan->cs_blksz = blksize;
 1579         chan->cs_curdma = p;
 1580         chan->cs_segsz = n;
 1581 
 1582         if (n > chan->cs_blksz)
 1583                 n = chan->cs_blksz;
 1584         chan->cs_cnt = n;
 1585 
 1586         APC_WRITE(sc, APC_CNVA, p->dmamap->dm_segs[0].ds_addr);
 1587         APC_WRITE(sc, APC_CNC, (u_long)n);
 1588 
 1589         csr = APC_READ(sc, APC_CSR);
 1590         if ((csr & APC_CSR_CDMA_GO) == 0 || (csr & APC_CSR_CPAUSE) != 0) {
 1591                 csr &= APC_CSR_CPAUSE;
 1592                 csr |= APC_CSR_GIE | APC_CSR_CMIE | APC_CSR_CIE | APC_CSR_EI |
 1593                     APC_CSR_CDMA_GO;
 1594                 APC_WRITE(sc, APC_CSR, csr);
 1595                 cs4231_write(sc, CS_LOWER_REC_CNT, 0xff);
 1596                 cs4231_write(sc, CS_UPPER_REC_CNT, 0xff);
 1597                 cs4231_write(sc, SP_INTERFACE_CONFIG,
 1598                     cs4231_read(sc, SP_INTERFACE_CONFIG) | CAPTURE_ENABLE);
 1599         }
 1600 
 1601         if (APC_READ(sc, APC_CSR) & APC_CSR_CD) {
 1602                 u_long nextaddr, togo;
 1603 
 1604                 p = chan->cs_curdma;
 1605                 togo = chan->cs_segsz - chan->cs_cnt;
 1606                 if (togo == 0) {
 1607                         nextaddr = (u_int32_t)p->dmamap->dm_segs[0].ds_addr;
 1608                         chan->cs_cnt = togo = chan->cs_blksz;
 1609                 } else {
 1610                         nextaddr = APC_READ(sc, APC_CNVA) + chan->cs_blksz;
 1611                         if (togo > chan->cs_blksz)
 1612                                 togo = chan->cs_blksz;
 1613                         chan->cs_cnt += togo;
 1614                 }
 1615 
 1616                 APC_WRITE(sc, APC_CNVA, nextaddr);
 1617                 APC_WRITE(sc, APC_CNC, togo);
 1618         }
 1619 
 1620         return (0);
 1621 }

/* [<][>][^][v][top][bottom][index][help] */