Annotation of sys/dev/pci/cs4280.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: cs4280.c,v 1.26 2007/08/01 21:37:21 miod Exp $ */
! 2: /* $NetBSD: cs4280.c,v 1.5 2000/06/26 04:56:23 simonb Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1999, 2000 Tatoku Ogaito. 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: * 3. All advertising materials mentioning features or use of this software
! 16: * must display the following acknowledgement:
! 17: * This product includes software developed by Tatoku Ogaito
! 18: * for the NetBSD Project.
! 19: * 4. The name of the author may not be used to endorse or promote products
! 20: * derived from this software without specific prior written permission
! 21: *
! 22: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 23: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 24: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 25: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 26: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 27: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 28: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 29: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 30: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 31: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 32: */
! 33:
! 34: /*
! 35: * Cirrus Logic CS4280 (and maybe CS461x) driver.
! 36: * Data sheets can be found
! 37: * http://www.cirrus.com/ftp/pubs/4280.pdf
! 38: * http://www.cirrus.com/ftp/pubs/4297.pdf
! 39: * ftp://ftp.alsa-project.org/pub/manuals/cirrus/embedded_audio_spec.pdf
! 40: * ftp://ftp.alsa-project.org/pub/manuals/cirrus/embedded_audio_spec.doc
! 41: */
! 42:
! 43: /*
! 44: * TODO
! 45: * Implement MIDI
! 46: * Joystick support
! 47: */
! 48:
! 49: #ifdef CS4280_DEBUG
! 50: #ifndef MIDI_READY
! 51: #define MIDI_READY
! 52: #endif /* ! MIDI_READY */
! 53: #endif
! 54:
! 55: #ifdef MIDI_READY
! 56: #include "midi.h"
! 57: #endif
! 58:
! 59: #if defined(CS4280_DEBUG)
! 60: #define DPRINTF(x) if (cs4280debug) printf x
! 61: #define DPRINTFN(n,x) if (cs4280debug>(n)) printf x
! 62: int cs4280debug = 0;
! 63: #else
! 64: #define DPRINTF(x)
! 65: #define DPRINTFN(n,x)
! 66: #endif
! 67:
! 68: #include <sys/param.h>
! 69: #include <sys/systm.h>
! 70: #include <sys/kernel.h>
! 71: #include <sys/fcntl.h>
! 72: #include <sys/malloc.h>
! 73: #include <sys/device.h>
! 74:
! 75: #include <dev/pci/pcidevs.h>
! 76: #include <dev/pci/pcivar.h>
! 77: #include <dev/pci/cs4280reg.h>
! 78:
! 79: #include <sys/audioio.h>
! 80: #include <dev/audio_if.h>
! 81: #include <dev/midi_if.h>
! 82: #include <dev/mulaw.h>
! 83: #include <dev/auconv.h>
! 84:
! 85: #include <dev/ic/ac97.h>
! 86:
! 87: #include <machine/bus.h>
! 88:
! 89: #define CSCC_PCI_BA0 0x10
! 90: #define CSCC_PCI_BA1 0x14
! 91:
! 92: struct cs4280_dma {
! 93: bus_dmamap_t map;
! 94: caddr_t addr; /* real dma buffer */
! 95: caddr_t dum; /* dummy buffer for audio driver */
! 96: bus_dma_segment_t segs[1];
! 97: int nsegs;
! 98: size_t size;
! 99: struct cs4280_dma *next;
! 100: };
! 101: #define DMAADDR(p) ((p)->map->dm_segs[0].ds_addr)
! 102: #define BUFADDR(p) ((void *)((p)->dum))
! 103: #define KERNADDR(p) ((void *)((p)->addr))
! 104:
! 105: /*
! 106: * Software state
! 107: */
! 108: struct cs4280_softc {
! 109: struct device sc_dev;
! 110:
! 111: pci_intr_handle_t * sc_ih;
! 112:
! 113: /* I/O (BA0) */
! 114: bus_space_tag_t ba0t;
! 115: bus_space_handle_t ba0h;
! 116:
! 117: /* BA1 */
! 118: bus_space_tag_t ba1t;
! 119: bus_space_handle_t ba1h;
! 120:
! 121: /* DMA */
! 122: bus_dma_tag_t sc_dmatag;
! 123: struct cs4280_dma *sc_dmas;
! 124:
! 125: void (*sc_pintr)(void *); /* dma completion intr handler */
! 126: void *sc_parg; /* arg for sc_intr() */
! 127: char *sc_ps, *sc_pe, *sc_pn;
! 128: int sc_pcount;
! 129: int sc_pi;
! 130: struct cs4280_dma *sc_pdma;
! 131: char *sc_pbuf;
! 132: #ifdef DIAGNOSTIC
! 133: char sc_prun;
! 134: #endif
! 135:
! 136: void (*sc_rintr)(void *); /* dma completion intr handler */
! 137: void *sc_rarg; /* arg for sc_intr() */
! 138: char *sc_rs, *sc_re, *sc_rn;
! 139: int sc_rcount;
! 140: int sc_ri;
! 141: struct cs4280_dma *sc_rdma;
! 142: char *sc_rbuf;
! 143: int sc_rparam; /* record format */
! 144: #ifdef DIAGNOSTIC
! 145: char sc_rrun;
! 146: #endif
! 147:
! 148: #if NMIDI > 0
! 149: void (*sc_iintr)(void *, int); /* midi input ready handler */
! 150: void (*sc_ointr)(void *); /* midi output ready handler */
! 151: void *sc_arg;
! 152: #endif
! 153:
! 154: u_int32_t pctl;
! 155: u_int32_t cctl;
! 156:
! 157: struct ac97_codec_if *codec_if;
! 158: struct ac97_host_if host_if;
! 159:
! 160: char sc_suspend;
! 161: void *sc_powerhook; /* Power Hook */
! 162: u_int16_t ac97_reg[CS4280_SAVE_REG_MAX + 1]; /* Save ac97 registers */
! 163: };
! 164:
! 165: #define BA0READ4(sc, r) bus_space_read_4((sc)->ba0t, (sc)->ba0h, (r))
! 166: #define BA0WRITE4(sc, r, x) bus_space_write_4((sc)->ba0t, (sc)->ba0h, (r), (x))
! 167: #define BA1READ4(sc, r) bus_space_read_4((sc)->ba1t, (sc)->ba1h, (r))
! 168: #define BA1WRITE4(sc, r, x) bus_space_write_4((sc)->ba1t, (sc)->ba1h, (r), (x))
! 169:
! 170: int cs4280_match(struct device *, void *, void *);
! 171: void cs4280_attach(struct device *, struct device *, void *);
! 172: void cs4280_attachhook(void *xsc);
! 173: int cs4280_intr(void *);
! 174: void cs4280_reset(void *);
! 175: int cs4280_download_image(struct cs4280_softc *);
! 176:
! 177: int cs4280_download(struct cs4280_softc *, const u_int32_t *, u_int32_t, u_int32_t);
! 178: int cs4280_allocmem(struct cs4280_softc *, size_t, size_t,
! 179: struct cs4280_dma *);
! 180: int cs4280_freemem(struct cs4280_softc *, struct cs4280_dma *);
! 181:
! 182: #ifdef CS4280_DEBUG
! 183: int cs4280_check_images(struct cs4280_softc *);
! 184: int cs4280_checkimage(struct cs4280_softc *, u_int32_t *, u_int32_t,
! 185: u_int32_t);
! 186: #endif
! 187:
! 188: struct cfdriver clcs_cd = {
! 189: NULL, "clcs", DV_DULL
! 190: };
! 191:
! 192: struct cfattach clcs_ca = {
! 193: sizeof(struct cs4280_softc), cs4280_match, cs4280_attach
! 194: };
! 195:
! 196: int cs4280_init(struct cs4280_softc *, int);
! 197: int cs4280_init2(struct cs4280_softc *, int);
! 198: int cs4280_open(void *, int);
! 199: void cs4280_close(void *);
! 200:
! 201: int cs4280_query_encoding(void *, struct audio_encoding *);
! 202: int cs4280_set_params(void *, int, int, struct audio_params *, struct audio_params *);
! 203: int cs4280_round_blocksize(void *, int);
! 204:
! 205: int cs4280_halt_output(void *);
! 206: int cs4280_halt_input(void *);
! 207:
! 208: int cs4280_getdev(void *, struct audio_device *);
! 209:
! 210: int cs4280_mixer_set_port(void *, mixer_ctrl_t *);
! 211: int cs4280_mixer_get_port(void *, mixer_ctrl_t *);
! 212: int cs4280_query_devinfo(void *addr, mixer_devinfo_t *dip);
! 213: void *cs4280_malloc(void *, int, size_t, int, int);
! 214: void cs4280_free(void *, void *, int);
! 215: size_t cs4280_round_buffersize(void *, int, size_t);
! 216: paddr_t cs4280_mappage(void *, void *, off_t, int);
! 217: int cs4280_get_props(void *);
! 218: int cs4280_trigger_output(void *, void *, void *, int, void (*)(void *),
! 219: void *, struct audio_params *);
! 220: int cs4280_trigger_input(void *, void *, void *, int, void (*)(void *),
! 221: void *, struct audio_params *);
! 222:
! 223:
! 224: void cs4280_set_dac_rate(struct cs4280_softc *, int );
! 225: void cs4280_set_adc_rate(struct cs4280_softc *, int );
! 226: int cs4280_get_portnum_by_name(struct cs4280_softc *, char *, char *,
! 227: char *);
! 228: int cs4280_src_wait(struct cs4280_softc *);
! 229: int cs4280_attach_codec(void *sc, struct ac97_codec_if *);
! 230: int cs4280_read_codec(void *sc, u_int8_t a, u_int16_t *d);
! 231: int cs4280_write_codec(void *sc, u_int8_t a, u_int16_t d);
! 232: void cs4280_reset_codec(void *sc);
! 233:
! 234: void cs4280_power(int, void *);
! 235:
! 236: void cs4280_clear_fifos(struct cs4280_softc *);
! 237:
! 238: #if NMIDI > 0
! 239: void cs4280_midi_close(void *);
! 240: void cs4280_midi_getinfo(void *, struct midi_info *);
! 241: int cs4280_midi_open(void *, int, void (*)(void *, int),
! 242: void (*)(void *), void *);
! 243: int cs4280_midi_output(void *, int);
! 244: #endif
! 245:
! 246: struct audio_hw_if cs4280_hw_if = {
! 247: cs4280_open,
! 248: cs4280_close,
! 249: NULL,
! 250: cs4280_query_encoding,
! 251: cs4280_set_params,
! 252: cs4280_round_blocksize,
! 253: NULL,
! 254: NULL,
! 255: NULL,
! 256: NULL,
! 257: NULL,
! 258: cs4280_halt_output,
! 259: cs4280_halt_input,
! 260: NULL,
! 261: cs4280_getdev,
! 262: NULL,
! 263: cs4280_mixer_set_port,
! 264: cs4280_mixer_get_port,
! 265: cs4280_query_devinfo,
! 266: cs4280_malloc,
! 267: cs4280_free,
! 268: cs4280_round_buffersize,
! 269: 0, /* cs4280_mappage, */
! 270: cs4280_get_props,
! 271: cs4280_trigger_output,
! 272: cs4280_trigger_input,
! 273: };
! 274:
! 275: #if NMIDI > 0
! 276: struct midi_hw_if cs4280_midi_hw_if = {
! 277: cs4280_midi_open,
! 278: cs4280_midi_close,
! 279: cs4280_midi_output,
! 280: 0, /* flush */
! 281: cs4280_midi_getinfo,
! 282: 0, /* ioctl */
! 283: };
! 284: #endif
! 285:
! 286:
! 287:
! 288: struct audio_device cs4280_device = {
! 289: "CS4280",
! 290: "",
! 291: "cs4280"
! 292: };
! 293:
! 294: const struct pci_matchid cs4280_devices[] = {
! 295: { PCI_VENDOR_CIRRUS, PCI_PRODUCT_CIRRUS_CS4280 },
! 296: { PCI_VENDOR_CIRRUS, PCI_PRODUCT_CIRRUS_CS4610 },
! 297: { PCI_VENDOR_CIRRUS, PCI_PRODUCT_CIRRUS_CS4615 },
! 298: };
! 299:
! 300: int
! 301: cs4280_match(parent, ma, aux)
! 302: struct device *parent;
! 303: void *ma;
! 304: void *aux;
! 305: {
! 306: return (pci_matchbyid((struct pci_attach_args *)aux, cs4280_devices,
! 307: sizeof(cs4280_devices)/sizeof(cs4280_devices[0])));
! 308: }
! 309:
! 310: int
! 311: cs4280_read_codec(sc_, add, data)
! 312: void *sc_;
! 313: u_int8_t add;
! 314: u_int16_t *data;
! 315: {
! 316: struct cs4280_softc *sc = sc_;
! 317: int n;
! 318:
! 319: DPRINTFN(5,("read_codec: add=0x%02x ", add));
! 320: /*
! 321: * Make sure that there is not data sitting around from a preivous
! 322: * uncompleted access.
! 323: */
! 324: BA0READ4(sc, CS4280_ACSDA);
! 325:
! 326: /* Set up AC97 control registers. */
! 327: BA0WRITE4(sc, CS4280_ACCAD, add);
! 328: BA0WRITE4(sc, CS4280_ACCDA, 0);
! 329: BA0WRITE4(sc, CS4280_ACCTL,
! 330: ACCTL_RSTN | ACCTL_ESYN | ACCTL_VFRM | ACCTL_CRW | ACCTL_DCV );
! 331:
! 332: if (cs4280_src_wait(sc) < 0) {
! 333: printf("%s: AC97 read prob. (DCV!=0) for add=0x%02x\n",
! 334: sc->sc_dev.dv_xname, add);
! 335: return (1);
! 336: }
! 337:
! 338: /* wait for valid status bit is active */
! 339: n = 0;
! 340: while (!(BA0READ4(sc, CS4280_ACSTS) & ACSTS_VSTS)) {
! 341: delay(1);
! 342: while (++n > 1000) {
! 343: printf("%s: AC97 read fail (VSTS==0) for add=0x%02x\n",
! 344: sc->sc_dev.dv_xname, add);
! 345: return (1);
! 346: }
! 347: }
! 348: *data = BA0READ4(sc, CS4280_ACSDA);
! 349: DPRINTFN(5,("data=0x%04x\n", *data));
! 350: return (0);
! 351: }
! 352:
! 353: int
! 354: cs4280_write_codec(sc_, add, data)
! 355: void *sc_;
! 356: u_int8_t add;
! 357: u_int16_t data;
! 358: {
! 359: struct cs4280_softc *sc = sc_;
! 360:
! 361: DPRINTFN(5,("write_codec: add=0x%02x data=0x%04x\n", add, data));
! 362: BA0WRITE4(sc, CS4280_ACCAD, add);
! 363: BA0WRITE4(sc, CS4280_ACCDA, data);
! 364: BA0WRITE4(sc, CS4280_ACCTL,
! 365: ACCTL_RSTN | ACCTL_ESYN | ACCTL_VFRM | ACCTL_DCV );
! 366:
! 367: if (cs4280_src_wait(sc) < 0) {
! 368: printf("%s: AC97 write fail (DCV!=0) for add=0x%02x data="
! 369: "0x%04x\n", sc->sc_dev.dv_xname, add, data);
! 370: return (1);
! 371: }
! 372: return (0);
! 373: }
! 374:
! 375: int
! 376: cs4280_src_wait(sc)
! 377: struct cs4280_softc *sc;
! 378: {
! 379: int n;
! 380:
! 381: n = 0;
! 382: while ((BA0READ4(sc, CS4280_ACCTL) & ACCTL_DCV)) {
! 383: delay(1000);
! 384: if (++n > 1000)
! 385: return (-1);
! 386: }
! 387: return (0);
! 388: }
! 389:
! 390:
! 391: void
! 392: cs4280_set_adc_rate(sc, rate)
! 393: struct cs4280_softc *sc;
! 394: int rate;
! 395: {
! 396: /* calculate capture rate:
! 397: *
! 398: * capture_coefficient_increment = -round(rate*128*65536/48000;
! 399: * capture_phase_increment = floor(48000*65536*1024/rate);
! 400: * cx = round(48000*65536*1024 - capture_phase_increment*rate);
! 401: * cy = floor(cx/200);
! 402: * capture_sample_rate_correction = cx - 200*cy;
! 403: * capture_delay = ceil(24*48000/rate);
! 404: * capture_num_triplets = floor(65536*rate/24000);
! 405: * capture_group_length = 24000/GCD(rate, 24000);
! 406: * where GCD means "Greatest Common Divisor".
! 407: *
! 408: * capture_coefficient_increment, capture_phase_increment and
! 409: * capture_num_triplets are 32-bit signed quantities.
! 410: * capture_sample_rate_correction and capture_group_length are
! 411: * 16-bit signed quantities.
! 412: * capture_delay is a 14-bit unsigned quantity.
! 413: */
! 414: u_int32_t cci,cpi,cnt,cx,cy, tmp1;
! 415: u_int16_t csrc, cgl, cdlay;
! 416:
! 417: /* XXX
! 418: * Even though, embedded_audio_spec says capture rate range 11025 to
! 419: * 48000, dhwiface.cpp says,
! 420: *
! 421: * "We can only decimate by up to a factor of 1/9th the hardware rate.
! 422: * Return an error if an attempt is made to stray outside that limit."
! 423: *
! 424: * so assume range as 48000/9 to 48000
! 425: */
! 426:
! 427: if (rate < 8000)
! 428: rate = 8000;
! 429: if (rate > 48000)
! 430: rate = 48000;
! 431:
! 432: cx = rate << 16;
! 433: cci = cx / 48000;
! 434: cx -= cci * 48000;
! 435: cx <<= 7;
! 436: cci <<= 7;
! 437: cci += cx / 48000;
! 438: cci = - cci;
! 439:
! 440: cx = 48000 << 16;
! 441: cpi = cx / rate;
! 442: cx -= cpi * rate;
! 443: cx <<= 10;
! 444: cpi <<= 10;
! 445: cy = cx / rate;
! 446: cpi += cy;
! 447: cx -= cy * rate;
! 448:
! 449: cy = cx / 200;
! 450: csrc = cx - 200*cy;
! 451:
! 452: cdlay = ((48000 * 24) + rate - 1) / rate;
! 453: #if 0
! 454: cdlay &= 0x3fff; /* make sure cdlay is 14-bit */
! 455: #endif
! 456:
! 457: cnt = rate << 16;
! 458: cnt /= 24000;
! 459:
! 460: cgl = 1;
! 461: for (tmp1 = 2; tmp1 <= 64; tmp1 *= 2) {
! 462: if (((rate / tmp1) * tmp1) != rate)
! 463: cgl *= 2;
! 464: }
! 465: if (((rate / 3) * 3) != rate)
! 466: cgl *= 3;
! 467: for (tmp1 = 5; tmp1 <= 125; tmp1 *= 5) {
! 468: if (((rate / tmp1) * tmp1) != rate)
! 469: cgl *= 5;
! 470: }
! 471: #if 0
! 472: /* XXX what manual says */
! 473: tmp1 = BA1READ4(sc, CS4280_CSRC) & ~CSRC_MASK;
! 474: tmp1 |= csrc<<16;
! 475: BA1WRITE4(sc, CS4280_CSRC, tmp1);
! 476: #else
! 477: /* suggested by cs461x.c (ALSA driver) */
! 478: BA1WRITE4(sc, CS4280_CSRC, CS4280_MK_CSRC(csrc, cy));
! 479: #endif
! 480:
! 481: #if 0
! 482: /* I am confused. The sample rate calculation section says
! 483: * cci *is* 32-bit signed quantity but in the parameter description
! 484: * section, CCI only assigned 16bit.
! 485: * I believe size of the variable.
! 486: */
! 487: tmp1 = BA1READ4(sc, CS4280_CCI) & ~CCI_MASK;
! 488: tmp1 |= cci<<16;
! 489: BA1WRITE4(sc, CS4280_CCI, tmp1);
! 490: #else
! 491: BA1WRITE4(sc, CS4280_CCI, cci);
! 492: #endif
! 493:
! 494: tmp1 = BA1READ4(sc, CS4280_CD) & ~CD_MASK;
! 495: tmp1 |= cdlay <<18;
! 496: BA1WRITE4(sc, CS4280_CD, tmp1);
! 497:
! 498: BA1WRITE4(sc, CS4280_CPI, cpi);
! 499:
! 500: tmp1 = BA1READ4(sc, CS4280_CGL) & ~CGL_MASK;
! 501: tmp1 |= cgl;
! 502: BA1WRITE4(sc, CS4280_CGL, tmp1);
! 503:
! 504: BA1WRITE4(sc, CS4280_CNT, cnt);
! 505:
! 506: tmp1 = BA1READ4(sc, CS4280_CGC) & ~CGC_MASK;
! 507: tmp1 |= cgl;
! 508: BA1WRITE4(sc, CS4280_CGC, tmp1);
! 509: }
! 510:
! 511: void
! 512: cs4280_set_dac_rate(sc, rate)
! 513: struct cs4280_softc *sc;
! 514: int rate;
! 515: {
! 516: /*
! 517: * playback rate may range from 8000Hz to 48000Hz
! 518: *
! 519: * play_phase_increment = floor(rate*65536*1024/48000)
! 520: * px = round(rate*65536*1024 - play_phase_incremnt*48000)
! 521: * py=floor(px/200)
! 522: * play_sample_rate_correction = px - 200*py
! 523: *
! 524: * play_phase_increment is a 32bit signed quantity.
! 525: * play_sample_rate_correction is a 16bit signed quantity.
! 526: */
! 527: int32_t ppi;
! 528: int16_t psrc;
! 529: u_int32_t px, py;
! 530:
! 531: if (rate < 8000)
! 532: rate = 8000;
! 533: if (rate > 48000)
! 534: rate = 48000;
! 535: px = rate << 16;
! 536: ppi = px/48000;
! 537: px -= ppi*48000;
! 538: ppi <<= 10;
! 539: px <<= 10;
! 540: py = px / 48000;
! 541: ppi += py;
! 542: px -= py*48000;
! 543: py = px/200;
! 544: px -= py*200;
! 545: psrc = px;
! 546: #if 0
! 547: /* what manual says */
! 548: px = BA1READ4(sc, CS4280_PSRC) & ~PSRC_MASK;
! 549: BA1WRITE4(sc, CS4280_PSRC,
! 550: ( ((psrc<<16) & PSRC_MASK) | px ));
! 551: #else
! 552: /* suggested by cs461x.c (ALSA driver) */
! 553: BA1WRITE4(sc, CS4280_PSRC, CS4280_MK_PSRC(psrc,py));
! 554: #endif
! 555: BA1WRITE4(sc, CS4280_PPI, ppi);
! 556: }
! 557:
! 558: void
! 559: cs4280_attachhook(void *xsc)
! 560: {
! 561: struct cs4280_softc *sc = xsc;
! 562: mixer_ctrl_t ctl;
! 563:
! 564: /* Initialization */
! 565: if (cs4280_init2(sc, 1) != 0)
! 566: return;
! 567:
! 568: printf("%s: firmware loaded\n", sc->sc_dev.dv_xname);
! 569:
! 570: /* Turn mute off of DAC, CD and master volumes by default */
! 571: ctl.type = AUDIO_MIXER_ENUM;
! 572: ctl.un.ord = 0; /* off */
! 573:
! 574: ctl.dev = cs4280_get_portnum_by_name(sc, AudioCoutputs,
! 575: AudioNmaster, AudioNmute);
! 576: cs4280_mixer_set_port(sc, &ctl);
! 577:
! 578: ctl.dev = cs4280_get_portnum_by_name(sc, AudioCinputs,
! 579: AudioNdac, AudioNmute);
! 580: cs4280_mixer_set_port(sc, &ctl);
! 581:
! 582: ctl.dev = cs4280_get_portnum_by_name(sc, AudioCinputs,
! 583: AudioNcd, AudioNmute);
! 584: cs4280_mixer_set_port(sc, &ctl);
! 585:
! 586: audio_attach_mi(&cs4280_hw_if, sc, &sc->sc_dev);
! 587:
! 588: #if NMIDI > 0
! 589: midi_attach_mi(&cs4280_midi_hw_if, sc, &sc->sc_dev);
! 590: #endif
! 591: sc->sc_suspend = PWR_RESUME;
! 592: sc->sc_powerhook = powerhook_establish(cs4280_power, sc);
! 593: }
! 594:
! 595: void
! 596: cs4280_attach(parent, self, aux)
! 597: struct device *parent;
! 598: struct device *self;
! 599: void *aux;
! 600: {
! 601: struct cs4280_softc *sc = (struct cs4280_softc *) self;
! 602: struct pci_attach_args *pa = (struct pci_attach_args *) aux;
! 603: pci_chipset_tag_t pc = pa->pa_pc;
! 604: char const *intrstr;
! 605: pci_intr_handle_t ih;
! 606: u_int32_t mem;
! 607:
! 608: /* Map I/O register */
! 609: if (pci_mapreg_map(pa, CSCC_PCI_BA0,
! 610: PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0,
! 611: &sc->ba0t, &sc->ba0h, NULL, NULL, 0)) {
! 612: printf(": can't map BA0 space\n");
! 613: return;
! 614: }
! 615: if (pci_mapreg_map(pa, CSCC_PCI_BA1,
! 616: PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0,
! 617: &sc->ba1t, &sc->ba1h, NULL, NULL, 0)) {
! 618: printf(": can't map BA1 space\n");
! 619: return;
! 620: }
! 621:
! 622: sc->sc_dmatag = pa->pa_dmat;
! 623:
! 624: /* LATENCY_TIMER setting */
! 625: mem = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG);
! 626: if ( PCI_LATTIMER(mem) < 32 ) {
! 627: mem &= 0xffff00ff;
! 628: mem |= 0x00002000;
! 629: pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG, mem);
! 630: }
! 631:
! 632: /* Map and establish the interrupt. */
! 633: if (pci_intr_map(pa, &ih)) {
! 634: printf(": couldn't map interrupt\n");
! 635: return;
! 636: }
! 637: intrstr = pci_intr_string(pc, ih);
! 638:
! 639: sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, cs4280_intr, sc,
! 640: sc->sc_dev.dv_xname);
! 641: if (sc->sc_ih == NULL) {
! 642: printf(": couldn't establish interrupt");
! 643: if (intrstr != NULL)
! 644: printf(" at %s", intrstr);
! 645: printf("\n");
! 646: return;
! 647: }
! 648: printf(": %s\n", intrstr);
! 649:
! 650: /* Initialization */
! 651: if (cs4280_init(sc, 1) != 0)
! 652: return;
! 653:
! 654: mountroothook_establish(cs4280_attachhook, sc);
! 655:
! 656: /* AC 97 attachement */
! 657: sc->host_if.arg = sc;
! 658: sc->host_if.attach = cs4280_attach_codec;
! 659: sc->host_if.read = cs4280_read_codec;
! 660: sc->host_if.write = cs4280_write_codec;
! 661: sc->host_if.reset = cs4280_reset_codec;
! 662:
! 663: if (ac97_attach(&sc->host_if) != 0) {
! 664: printf("%s: ac97_attach failed\n", sc->sc_dev.dv_xname);
! 665: return;
! 666: }
! 667: }
! 668:
! 669: int
! 670: cs4280_intr(p)
! 671: void *p;
! 672: {
! 673: /*
! 674: * XXX
! 675: *
! 676: * Since CS4280 has only 4kB dma buffer and
! 677: * interrupt occurs every 2kB block, I create dummy buffer
! 678: * which returns to audio driver and actual dma buffer
! 679: * using in DMA transfer.
! 680: *
! 681: *
! 682: * ring buffer in audio.c is pointed by BUFADDR
! 683: * <------ ring buffer size == 64kB ------>
! 684: * <-----> blksize == 2048*(sc->sc_[pr]count) kB
! 685: * |= = = =|= = = =|= = = =|= = = =|= = = =|
! 686: * | | | | | | <- call audio_intp every
! 687: * sc->sc_[pr]_count time.
! 688: *
! 689: * actual dma buffer is pointed by KERNADDR
! 690: * <-> dma buffer size = 4kB
! 691: * |= =|
! 692: *
! 693: *
! 694: */
! 695: struct cs4280_softc *sc = p;
! 696: u_int32_t intr, mem;
! 697: char * empty_dma;
! 698: int handled = 0;
! 699:
! 700: /* grab interrupt register then clear it */
! 701: intr = BA0READ4(sc, CS4280_HISR);
! 702: BA0WRITE4(sc, CS4280_HICR, HICR_CHGM | HICR_IEV);
! 703:
! 704: /* Playback Interrupt */
! 705: if (intr & HISR_PINT) {
! 706: handled = 1;
! 707: mem = BA1READ4(sc, CS4280_PFIE);
! 708: BA1WRITE4(sc, CS4280_PFIE, (mem & ~PFIE_PI_MASK) | PFIE_PI_DISABLE);
! 709: if (sc->sc_pintr) {
! 710: if ((sc->sc_pi%sc->sc_pcount) == 0)
! 711: sc->sc_pintr(sc->sc_parg);
! 712: } else {
! 713: printf("unexpected play intr\n");
! 714: }
! 715: /* copy buffer */
! 716: ++sc->sc_pi;
! 717: empty_dma = sc->sc_pdma->addr;
! 718: if (sc->sc_pi&1)
! 719: empty_dma += CS4280_ICHUNK;
! 720: memcpy(empty_dma, sc->sc_pn, CS4280_ICHUNK);
! 721: sc->sc_pn += CS4280_ICHUNK;
! 722: if (sc->sc_pn >= sc->sc_pe)
! 723: sc->sc_pn = sc->sc_ps;
! 724: BA1WRITE4(sc, CS4280_PFIE, mem);
! 725: }
! 726: /* Capture Interrupt */
! 727: if (intr & HISR_CINT) {
! 728: int i;
! 729: int16_t rdata;
! 730:
! 731: handled = 1;
! 732: mem = BA1READ4(sc, CS4280_CIE);
! 733: BA1WRITE4(sc, CS4280_CIE, (mem & ~CIE_CI_MASK) | CIE_CI_DISABLE);
! 734: ++sc->sc_ri;
! 735: empty_dma = sc->sc_rdma->addr;
! 736: if ((sc->sc_ri&1) == 0)
! 737: empty_dma += CS4280_ICHUNK;
! 738:
! 739: /*
! 740: * XXX
! 741: * I think this audio data conversion should be
! 742: * happend in upper layer, but I put this here
! 743: * since there is no conversion function available.
! 744: */
! 745: switch(sc->sc_rparam) {
! 746: case CF_16BIT_STEREO:
! 747: /* just copy it */
! 748: memcpy(sc->sc_rn, empty_dma, CS4280_ICHUNK);
! 749: sc->sc_rn += CS4280_ICHUNK;
! 750: break;
! 751: case CF_16BIT_MONO:
! 752: for (i = 0; i < 512; i++) {
! 753: rdata = *((int16_t *)empty_dma)++>>1;
! 754: rdata += *((int16_t *)empty_dma)++>>1;
! 755: *((int16_t *)sc->sc_rn)++ = rdata;
! 756: }
! 757: break;
! 758: case CF_8BIT_STEREO:
! 759: for (i = 0; i < 512; i++) {
! 760: rdata = *((int16_t*)empty_dma)++;
! 761: *sc->sc_rn++ = rdata >> 8;
! 762: rdata = *((int16_t*)empty_dma)++;
! 763: *sc->sc_rn++ = rdata >> 8;
! 764: }
! 765: break;
! 766: case CF_8BIT_MONO:
! 767: for (i = 0; i < 512; i++) {
! 768: rdata = *((int16_t*)empty_dma)++ >>1;
! 769: rdata += *((int16_t*)empty_dma)++ >>1;
! 770: *sc->sc_rn++ = rdata >>8;
! 771: }
! 772: break;
! 773: default:
! 774: /* Should not reach here */
! 775: printf("unknown sc->sc_rparam: %d\n", sc->sc_rparam);
! 776: }
! 777: if (sc->sc_rn >= sc->sc_re)
! 778: sc->sc_rn = sc->sc_rs;
! 779: BA1WRITE4(sc, CS4280_CIE, mem);
! 780: if (sc->sc_rintr) {
! 781: if ((sc->sc_ri%(sc->sc_rcount)) == 0)
! 782: sc->sc_rintr(sc->sc_rarg);
! 783: } else {
! 784: printf("unexpected record intr\n");
! 785: }
! 786: }
! 787:
! 788: #if NMIDI > 0
! 789: /* Midi port Interrupt */
! 790: if (intr & HISR_MIDI) {
! 791: int data;
! 792:
! 793: handled = 1;
! 794: DPRINTF(("i: %d: ",
! 795: BA0READ4(sc, CS4280_MIDSR)));
! 796: /* Read the received data */
! 797: while ((sc->sc_iintr != NULL) &&
! 798: ((BA0READ4(sc, CS4280_MIDSR) & MIDSR_RBE) == 0)) {
! 799: data = BA0READ4(sc, CS4280_MIDRP) & MIDRP_MASK;
! 800: DPRINTF(("r:%x\n",data));
! 801: sc->sc_iintr(sc->sc_arg, data);
! 802: }
! 803:
! 804: /* Write the data */
! 805: #if 1
! 806: /* XXX:
! 807: * It seems "Transmit Buffer Full" never activate until EOI
! 808: * is delivered. Shall I throw EOI top of this routine ?
! 809: */
! 810: if ((BA0READ4(sc, CS4280_MIDSR) & MIDSR_TBF) == 0) {
! 811: DPRINTF(("w: "));
! 812: if (sc->sc_ointr != NULL)
! 813: sc->sc_ointr(sc->sc_arg);
! 814: }
! 815: #else
! 816: while ((sc->sc_ointr != NULL) &&
! 817: ((BA0READ4(sc, CS4280_MIDSR) & MIDSR_TBF) == 0)) {
! 818: DPRINTF(("w: "));
! 819: sc->sc_ointr(sc->sc_arg);
! 820: }
! 821: #endif
! 822: DPRINTF(("\n"));
! 823: }
! 824: #endif
! 825:
! 826: return handled;
! 827: }
! 828:
! 829:
! 830: /* Download Proceessor Code and Data image */
! 831:
! 832: int
! 833: cs4280_download(sc, src, offset, len)
! 834: struct cs4280_softc *sc;
! 835: const u_int32_t *src;
! 836: u_int32_t offset, len;
! 837: {
! 838: u_int32_t ctr;
! 839:
! 840: #ifdef CS4280_DEBUG
! 841: u_int32_t con, data;
! 842: u_int8_t c0,c1,c2,c3;
! 843: #endif
! 844: if ((offset&3) || (len&3))
! 845: return (-1);
! 846:
! 847: len /= sizeof(u_int32_t);
! 848: for (ctr = 0; ctr < len; ctr++) {
! 849: /* XXX:
! 850: * I cannot confirm this is the right thing or not
! 851: * on BIG-ENDIAN machines.
! 852: */
! 853: BA1WRITE4(sc, offset+ctr*4, htole32(*(src+ctr)));
! 854: #ifdef CS4280_DEBUG
! 855: data = htole32(*(src+ctr));
! 856: c0 = bus_space_read_1(sc->ba1t, sc->ba1h, offset+ctr*4+0);
! 857: c1 = bus_space_read_1(sc->ba1t, sc->ba1h, offset+ctr*4+1);
! 858: c2 = bus_space_read_1(sc->ba1t, sc->ba1h, offset+ctr*4+2);
! 859: c3 = bus_space_read_1(sc->ba1t, sc->ba1h, offset+ctr*4+3);
! 860: con = ( (c3<<24) | (c2<<16) | (c1<<8) | c0 );
! 861: if (data != con ) {
! 862: printf("0x%06x: write=0x%08x read=0x%08x\n",
! 863: offset+ctr*4, data, con);
! 864: return (-1);
! 865: }
! 866: #endif
! 867: }
! 868: return (0);
! 869: }
! 870:
! 871: struct BA1struct *BA1Struct;
! 872:
! 873: int
! 874: cs4280_download_image(sc)
! 875: struct cs4280_softc *sc;
! 876: {
! 877: int idx, err = 0;
! 878: u_int32_t offset = 0;
! 879: static u_char *cs4280_firmware;
! 880: static size_t cs4280_firmwarelen;
! 881:
! 882: if (cs4280_firmware == NULL) {
! 883: err = loadfirmware("cs4280", &cs4280_firmware,
! 884: &cs4280_firmwarelen);
! 885: if (err)
! 886: return (err);
! 887: }
! 888:
! 889: BA1Struct = (struct BA1struct *)cs4280_firmware;
! 890:
! 891: for (idx = 0; idx < BA1_MEMORY_COUNT; ++idx) {
! 892: err = cs4280_download(sc, &BA1Struct->map[offset],
! 893: BA1Struct->memory[idx].offset, BA1Struct->memory[idx].size);
! 894: if (err != 0) {
! 895: printf("%s: load_image failed at %d\n",
! 896: sc->sc_dev.dv_xname, idx);
! 897: return (-1);
! 898: }
! 899: offset += BA1Struct->memory[idx].size / sizeof(u_int32_t);
! 900: }
! 901: return (err);
! 902: }
! 903:
! 904: #ifdef CS4280_DEBUG
! 905: int
! 906: cs4280_checkimage(sc, src, offset, len)
! 907: struct cs4280_softc *sc;
! 908: u_int32_t *src;
! 909: u_int32_t offset, len;
! 910: {
! 911: u_int32_t ctr, data;
! 912: int err = 0;
! 913:
! 914: if ((offset&3) || (len&3))
! 915: return -1;
! 916:
! 917: len /= sizeof(u_int32_t);
! 918: for (ctr = 0; ctr < len; ctr++) {
! 919: /* I cannot confirm this is the right thing
! 920: * on BIG-ENDIAN machines
! 921: */
! 922: data = BA1READ4(sc, offset+ctr*4);
! 923: if (data != htole32(*(src+ctr))) {
! 924: printf("0x%06x: 0x%08x(0x%08x)\n",
! 925: offset+ctr*4, data, *(src+ctr));
! 926: *(src+ctr) = data;
! 927: ++err;
! 928: }
! 929: }
! 930: return (err);
! 931: }
! 932:
! 933: int
! 934: cs4280_check_images(sc)
! 935: struct cs4280_softc *sc;
! 936: {
! 937: int idx, err;
! 938: u_int32_t offset = 0;
! 939:
! 940: err = 0;
! 941: /*for (idx=0; idx < BA1_MEMORY_COUNT; ++idx) { */
! 942: for (idx = 0; idx < 1; ++idx) {
! 943: err = cs4280_checkimage(sc, &BA1Struct->map[offset],
! 944: BA1Struct->memory[idx].offset,
! 945: BA1Struct->memory[idx].size);
! 946: if (err != 0) {
! 947: printf("%s: check_image failed at %d\n",
! 948: sc->sc_dev.dv_xname, idx);
! 949: }
! 950: offset += BA1Struct->memory[idx].size / sizeof(u_int32_t);
! 951: }
! 952: return (err);
! 953: }
! 954:
! 955: #endif
! 956:
! 957: int
! 958: cs4280_attach_codec(sc_, codec_if)
! 959: void *sc_;
! 960: struct ac97_codec_if *codec_if;
! 961: {
! 962: struct cs4280_softc *sc = sc_;
! 963:
! 964: sc->codec_if = codec_if;
! 965: return (0);
! 966: }
! 967:
! 968: void
! 969: cs4280_reset_codec(sc_)
! 970: void *sc_;
! 971: {
! 972: struct cs4280_softc *sc = sc_;
! 973: int n;
! 974:
! 975: /* Reset codec */
! 976: BA0WRITE4(sc, CS4280_ACCTL, 0);
! 977: delay(100); /* delay 100us */
! 978: BA0WRITE4(sc, CS4280_ACCTL, ACCTL_RSTN);
! 979:
! 980: /*
! 981: * It looks like we do the following procedure, too
! 982: */
! 983:
! 984: /* Enable AC-link sync generation */
! 985: BA0WRITE4(sc, CS4280_ACCTL, ACCTL_ESYN | ACCTL_RSTN);
! 986: delay(50*1000); /* XXX delay 50ms */
! 987:
! 988: /* Assert valid frame signal */
! 989: BA0WRITE4(sc, CS4280_ACCTL, ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN);
! 990:
! 991: /* Wait for valid AC97 input slot */
! 992: n = 0;
! 993: while (BA0READ4(sc, CS4280_ACISV) != (ACISV_ISV3 | ACISV_ISV4)) {
! 994: delay(1000);
! 995: if (++n > 1000) {
! 996: printf("reset_codec: AC97 inputs slot ready timeout\n");
! 997: return;
! 998: }
! 999: }
! 1000: }
! 1001:
! 1002:
! 1003: /* Processor Soft Reset */
! 1004: void
! 1005: cs4280_reset(sc_)
! 1006: void *sc_;
! 1007: {
! 1008: struct cs4280_softc *sc = sc_;
! 1009:
! 1010: /* Set RSTSP bit in SPCR (also clear RUN, RUNFR, and DRQEN) */
! 1011: BA1WRITE4(sc, CS4280_SPCR, SPCR_RSTSP);
! 1012: delay(100);
! 1013: /* Clear RSTSP bit in SPCR */
! 1014: BA1WRITE4(sc, CS4280_SPCR, 0);
! 1015: /* enable DMA reqest */
! 1016: BA1WRITE4(sc, CS4280_SPCR, SPCR_DRQEN);
! 1017: }
! 1018:
! 1019: int
! 1020: cs4280_open(addr, flags)
! 1021: void *addr;
! 1022: int flags;
! 1023: {
! 1024: return (0);
! 1025: }
! 1026:
! 1027: void
! 1028: cs4280_close(addr)
! 1029: void *addr;
! 1030: {
! 1031: struct cs4280_softc *sc = addr;
! 1032:
! 1033: cs4280_halt_output(sc);
! 1034: cs4280_halt_input(sc);
! 1035:
! 1036: sc->sc_pintr = 0;
! 1037: sc->sc_rintr = 0;
! 1038: }
! 1039:
! 1040: int
! 1041: cs4280_query_encoding(addr, fp)
! 1042: void *addr;
! 1043: struct audio_encoding *fp;
! 1044: {
! 1045: switch (fp->index) {
! 1046: case 0:
! 1047: strlcpy(fp->name, AudioEulinear, sizeof fp->name);
! 1048: fp->encoding = AUDIO_ENCODING_ULINEAR;
! 1049: fp->precision = 8;
! 1050: fp->flags = 0;
! 1051: break;
! 1052: case 1:
! 1053: strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
! 1054: fp->encoding = AUDIO_ENCODING_ULAW;
! 1055: fp->precision = 8;
! 1056: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 1057: break;
! 1058: case 2:
! 1059: strlcpy(fp->name, AudioEalaw, sizeof fp->name);
! 1060: fp->encoding = AUDIO_ENCODING_ALAW;
! 1061: fp->precision = 8;
! 1062: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 1063: break;
! 1064: case 3:
! 1065: strlcpy(fp->name, AudioEslinear, sizeof fp->name);
! 1066: fp->encoding = AUDIO_ENCODING_SLINEAR;
! 1067: fp->precision = 8;
! 1068: fp->flags = 0;
! 1069: break;
! 1070: case 4:
! 1071: strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
! 1072: fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
! 1073: fp->precision = 16;
! 1074: fp->flags = 0;
! 1075: break;
! 1076: case 5:
! 1077: strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
! 1078: fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
! 1079: fp->precision = 16;
! 1080: fp->flags = 0;
! 1081: break;
! 1082: case 6:
! 1083: strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
! 1084: fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
! 1085: fp->precision = 16;
! 1086: fp->flags = 0;
! 1087: break;
! 1088: case 7:
! 1089: strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
! 1090: fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
! 1091: fp->precision = 16;
! 1092: fp->flags = 0;
! 1093: break;
! 1094: default:
! 1095: return (EINVAL);
! 1096: }
! 1097: return (0);
! 1098: }
! 1099:
! 1100: int
! 1101: cs4280_set_params(addr, setmode, usemode, play, rec)
! 1102: void *addr;
! 1103: int setmode, usemode;
! 1104: struct audio_params *play, *rec;
! 1105: {
! 1106: struct cs4280_softc *sc = addr;
! 1107: struct audio_params *p;
! 1108: int mode;
! 1109:
! 1110: for (mode = AUMODE_RECORD; mode != -1;
! 1111: mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1 ) {
! 1112: if ((setmode & mode) == 0)
! 1113: continue;
! 1114:
! 1115: p = mode == AUMODE_PLAY ? play : rec;
! 1116:
! 1117: if (p == play) {
! 1118: DPRINTFN(5,("play: sample=%ld precision=%d channels=%d\n",
! 1119: p->sample_rate, p->precision, p->channels));
! 1120: /* play back data format may be 8- or 16-bit and
! 1121: * either stereo or mono.
! 1122: * playback rate may range from 8000Hz to 48000Hz
! 1123: */
! 1124: if (p->sample_rate < 8000 || p->sample_rate > 48000 ||
! 1125: (p->precision != 8 && p->precision != 16) ||
! 1126: (p->channels != 1 && p->channels != 2) ) {
! 1127: return (EINVAL);
! 1128: }
! 1129: } else {
! 1130: DPRINTFN(5,("rec: sample=%ld precision=%d channels=%d\n",
! 1131: p->sample_rate, p->precision, p->channels));
! 1132: /* capture data format must be 16bit stereo
! 1133: * and sample rate range from 11025Hz to 48000Hz.
! 1134: *
! 1135: * XXX: it looks like to work with 8000Hz,
! 1136: * although data sheets say lower limit is
! 1137: * 11025 Hz.
! 1138: */
! 1139:
! 1140: if (p->sample_rate < 8000 || p->sample_rate > 48000 ||
! 1141: (p->precision != 8 && p->precision != 16) ||
! 1142: (p->channels != 1 && p->channels != 2) ) {
! 1143: return (EINVAL);
! 1144: }
! 1145: }
! 1146: p->factor = 1;
! 1147: p->sw_code = 0;
! 1148:
! 1149: /* capturing data is slinear */
! 1150: switch (p->encoding) {
! 1151: case AUDIO_ENCODING_SLINEAR_BE:
! 1152: if (mode == AUMODE_RECORD) {
! 1153: if (p->precision == 16)
! 1154: p->sw_code = swap_bytes;
! 1155: }
! 1156: break;
! 1157: case AUDIO_ENCODING_SLINEAR_LE:
! 1158: break;
! 1159: case AUDIO_ENCODING_ULINEAR_BE:
! 1160: if (mode == AUMODE_RECORD) {
! 1161: if (p->precision == 16)
! 1162: p->sw_code = change_sign16_swap_bytes;
! 1163: else
! 1164: p->sw_code = change_sign8;
! 1165: }
! 1166: break;
! 1167: case AUDIO_ENCODING_ULINEAR_LE:
! 1168: if (mode == AUMODE_RECORD) {
! 1169: if (p->precision == 16)
! 1170: p->sw_code = change_sign16;
! 1171: else
! 1172: p->sw_code = change_sign8;
! 1173: }
! 1174: break;
! 1175: case AUDIO_ENCODING_ULAW:
! 1176: if (mode == AUMODE_PLAY) {
! 1177: p->factor = 2;
! 1178: p->sw_code = mulaw_to_slinear16;
! 1179: } else {
! 1180: p->sw_code = slinear8_to_mulaw;
! 1181: }
! 1182: break;
! 1183: case AUDIO_ENCODING_ALAW:
! 1184: if (mode == AUMODE_PLAY) {
! 1185: p->factor = 2;
! 1186: p->sw_code = alaw_to_slinear16;
! 1187: } else {
! 1188: p->sw_code = slinear8_to_alaw;
! 1189: }
! 1190: break;
! 1191: default:
! 1192: return (EINVAL);
! 1193: }
! 1194: }
! 1195:
! 1196: /* set sample rate */
! 1197: cs4280_set_dac_rate(sc, play->sample_rate);
! 1198: cs4280_set_adc_rate(sc, rec->sample_rate);
! 1199: return (0);
! 1200: }
! 1201:
! 1202: int
! 1203: cs4280_round_blocksize(hdl, blk)
! 1204: void *hdl;
! 1205: int blk;
! 1206: {
! 1207: return (blk < CS4280_ICHUNK ? CS4280_ICHUNK : blk & -CS4280_ICHUNK);
! 1208: }
! 1209:
! 1210: size_t
! 1211: cs4280_round_buffersize(addr, direction, size)
! 1212: void *addr;
! 1213: int direction;
! 1214: size_t size;
! 1215: {
! 1216: /* although real dma buffer size is 4KB,
! 1217: * let the audio.c driver use a larger buffer.
! 1218: * ( suggested by Lennart Augustsson. )
! 1219: */
! 1220: return (size);
! 1221: }
! 1222:
! 1223: int
! 1224: cs4280_get_props(hdl)
! 1225: void *hdl;
! 1226: {
! 1227: return (AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX);
! 1228: #ifdef notyet
! 1229: /* XXX
! 1230: * How can I mmap ?
! 1231: */
! 1232: AUDIO_PROP_MMAP
! 1233: #endif
! 1234:
! 1235: }
! 1236:
! 1237: int
! 1238: cs4280_mixer_get_port(addr, cp)
! 1239: void *addr;
! 1240: mixer_ctrl_t *cp;
! 1241: {
! 1242: struct cs4280_softc *sc = addr;
! 1243:
! 1244: return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp));
! 1245: }
! 1246:
! 1247: paddr_t
! 1248: cs4280_mappage(addr, mem, off, prot)
! 1249: void *addr;
! 1250: void *mem;
! 1251: off_t off;
! 1252: int prot;
! 1253: {
! 1254: struct cs4280_softc *sc = addr;
! 1255: struct cs4280_dma *p;
! 1256:
! 1257: if (off < 0)
! 1258: return (-1);
! 1259: for (p = sc->sc_dmas; p && BUFADDR(p) != mem; p = p->next)
! 1260: ;
! 1261: if (!p) {
! 1262: DPRINTF(("cs4280_mappage: bad buffer address\n"));
! 1263: return (-1);
! 1264: }
! 1265: return (bus_dmamem_mmap(sc->sc_dmatag, p->segs, p->nsegs,
! 1266: off, prot, BUS_DMA_WAITOK));
! 1267: }
! 1268:
! 1269:
! 1270: int
! 1271: cs4280_query_devinfo(addr, dip)
! 1272: void *addr;
! 1273: mixer_devinfo_t *dip;
! 1274: {
! 1275: struct cs4280_softc *sc = addr;
! 1276:
! 1277: return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dip));
! 1278: }
! 1279:
! 1280: int
! 1281: cs4280_get_portnum_by_name(sc, class, device, qualifier)
! 1282: struct cs4280_softc *sc;
! 1283: char *class, *device, *qualifier;
! 1284: {
! 1285: return (sc->codec_if->vtbl->get_portnum_by_name(sc->codec_if, class,
! 1286: device, qualifier));
! 1287: }
! 1288:
! 1289: int
! 1290: cs4280_halt_output(addr)
! 1291: void *addr;
! 1292: {
! 1293: struct cs4280_softc *sc = addr;
! 1294: u_int32_t mem;
! 1295:
! 1296: mem = BA1READ4(sc, CS4280_PCTL);
! 1297: BA1WRITE4(sc, CS4280_PCTL, mem & ~PCTL_MASK);
! 1298: #ifdef DIAGNOSTIC
! 1299: sc->sc_prun = 0;
! 1300: #endif
! 1301: return (0);
! 1302: }
! 1303:
! 1304: int
! 1305: cs4280_halt_input(addr)
! 1306: void *addr;
! 1307: {
! 1308: struct cs4280_softc *sc = addr;
! 1309: u_int32_t mem;
! 1310:
! 1311: mem = BA1READ4(sc, CS4280_CCTL);
! 1312: BA1WRITE4(sc, CS4280_CCTL, mem & ~CCTL_MASK);
! 1313: #ifdef DIAGNOSTIC
! 1314: sc->sc_rrun = 0;
! 1315: #endif
! 1316: return (0);
! 1317: }
! 1318:
! 1319: int
! 1320: cs4280_getdev(addr, retp)
! 1321: void *addr;
! 1322: struct audio_device *retp;
! 1323: {
! 1324: *retp = cs4280_device;
! 1325: return (0);
! 1326: }
! 1327:
! 1328: int
! 1329: cs4280_mixer_set_port(addr, cp)
! 1330: void *addr;
! 1331: mixer_ctrl_t *cp;
! 1332: {
! 1333: struct cs4280_softc *sc = addr;
! 1334: int val;
! 1335:
! 1336: val = sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp);
! 1337: DPRINTFN(3,("mixer_set_port: val=%d\n", val));
! 1338: return (val);
! 1339: }
! 1340:
! 1341:
! 1342: int
! 1343: cs4280_freemem(sc, p)
! 1344: struct cs4280_softc *sc;
! 1345: struct cs4280_dma *p;
! 1346: {
! 1347: bus_dmamap_unload(sc->sc_dmatag, p->map);
! 1348: bus_dmamap_destroy(sc->sc_dmatag, p->map);
! 1349: bus_dmamem_unmap(sc->sc_dmatag, p->addr, p->size);
! 1350: bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs);
! 1351: return (0);
! 1352: }
! 1353:
! 1354: int
! 1355: cs4280_allocmem(sc, size, align, p)
! 1356: struct cs4280_softc *sc;
! 1357: size_t size;
! 1358: size_t align;
! 1359: struct cs4280_dma *p;
! 1360: {
! 1361: int error;
! 1362:
! 1363: /* XXX */
! 1364: p->size = size;
! 1365: error = bus_dmamem_alloc(sc->sc_dmatag, p->size, align, 0,
! 1366: p->segs, sizeof(p->segs)/sizeof(p->segs[0]),
! 1367: &p->nsegs, BUS_DMA_NOWAIT);
! 1368: if (error) {
! 1369: printf("%s: unable to allocate dma, error=%d\n",
! 1370: sc->sc_dev.dv_xname, error);
! 1371: return (error);
! 1372: }
! 1373:
! 1374: error = bus_dmamem_map(sc->sc_dmatag, p->segs, p->nsegs, p->size,
! 1375: &p->addr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
! 1376: if (error) {
! 1377: printf("%s: unable to map dma, error=%d\n",
! 1378: sc->sc_dev.dv_xname, error);
! 1379: goto free;
! 1380: }
! 1381:
! 1382: error = bus_dmamap_create(sc->sc_dmatag, p->size, 1, p->size,
! 1383: 0, BUS_DMA_NOWAIT, &p->map);
! 1384: if (error) {
! 1385: printf("%s: unable to create dma map, error=%d\n",
! 1386: sc->sc_dev.dv_xname, error);
! 1387: goto unmap;
! 1388: }
! 1389:
! 1390: error = bus_dmamap_load(sc->sc_dmatag, p->map, p->addr, p->size, NULL,
! 1391: BUS_DMA_NOWAIT);
! 1392: if (error) {
! 1393: printf("%s: unable to load dma map, error=%d\n",
! 1394: sc->sc_dev.dv_xname, error);
! 1395: goto destroy;
! 1396: }
! 1397: return (0);
! 1398:
! 1399: destroy:
! 1400: bus_dmamap_destroy(sc->sc_dmatag, p->map);
! 1401: unmap:
! 1402: bus_dmamem_unmap(sc->sc_dmatag, p->addr, p->size);
! 1403: free:
! 1404: bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs);
! 1405: return (error);
! 1406: }
! 1407:
! 1408:
! 1409: void *
! 1410: cs4280_malloc(addr, direction, size, pool, flags)
! 1411: void *addr;
! 1412: int direction;
! 1413: size_t size;
! 1414: int pool, flags;
! 1415: {
! 1416: struct cs4280_softc *sc = addr;
! 1417: struct cs4280_dma *p;
! 1418: caddr_t q;
! 1419: int error;
! 1420:
! 1421: DPRINTFN(5,("cs4280_malloc: size=%d pool=%d flags=%d\n", size, pool, flags));
! 1422: q = malloc(size, pool, flags);
! 1423: if (!q)
! 1424: return (0);
! 1425: p = malloc(sizeof(*p), pool, flags);
! 1426: if (!p) {
! 1427: free(q,pool);
! 1428: return (0);
! 1429: }
! 1430: /*
! 1431: * cs4280 has fixed 4kB buffer
! 1432: */
! 1433: error = cs4280_allocmem(sc, CS4280_DCHUNK, CS4280_DALIGN, p);
! 1434:
! 1435: if (error) {
! 1436: free(q, pool);
! 1437: free(p, pool);
! 1438: return (0);
! 1439: }
! 1440:
! 1441: p->next = sc->sc_dmas;
! 1442: sc->sc_dmas = p;
! 1443: p->dum = q; /* return to audio driver */
! 1444:
! 1445: return (p->dum);
! 1446: }
! 1447:
! 1448: void
! 1449: cs4280_free(addr, ptr, pool)
! 1450: void *addr;
! 1451: void *ptr;
! 1452: int pool;
! 1453: {
! 1454: struct cs4280_softc *sc = addr;
! 1455: struct cs4280_dma **pp, *p;
! 1456:
! 1457: for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->next) {
! 1458: if (BUFADDR(p) == ptr) {
! 1459: cs4280_freemem(sc, p);
! 1460: *pp = p->next;
! 1461: free(p->dum, pool);
! 1462: free(p, pool);
! 1463: return;
! 1464: }
! 1465: }
! 1466: }
! 1467:
! 1468: int
! 1469: cs4280_trigger_output(addr, start, end, blksize, intr, arg, param)
! 1470: void *addr;
! 1471: void *start, *end;
! 1472: int blksize;
! 1473: void (*intr)(void *);
! 1474: void *arg;
! 1475: struct audio_params *param;
! 1476: {
! 1477: struct cs4280_softc *sc = addr;
! 1478: u_int32_t pfie, pctl, mem, pdtc;
! 1479: struct cs4280_dma *p;
! 1480:
! 1481: #ifdef DIAGNOSTIC
! 1482: if (sc->sc_prun)
! 1483: printf("cs4280_trigger_output: already running\n");
! 1484: sc->sc_prun = 1;
! 1485: #endif
! 1486:
! 1487: DPRINTF(("cs4280_trigger_output: sc=%p start=%p end=%p "
! 1488: "blksize=%d intr=%p(%p)\n", addr, start, end, blksize, intr, arg));
! 1489: sc->sc_pintr = intr;
! 1490: sc->sc_parg = arg;
! 1491:
! 1492: /* stop playback DMA */
! 1493: mem = BA1READ4(sc, CS4280_PCTL);
! 1494: BA1WRITE4(sc, CS4280_PCTL, mem & ~PCTL_MASK);
! 1495:
! 1496: /* setup PDTC */
! 1497: pdtc = BA1READ4(sc, CS4280_PDTC);
! 1498: pdtc &= ~PDTC_MASK;
! 1499: pdtc |= CS4280_MK_PDTC(param->precision * param->channels);
! 1500: BA1WRITE4(sc, CS4280_PDTC, pdtc);
! 1501:
! 1502: DPRINTF(("param: precision=%d factor=%d channels=%d encoding=%d\n",
! 1503: param->precision, param->factor, param->channels,
! 1504: param->encoding));
! 1505: for (p = sc->sc_dmas; p != NULL && BUFADDR(p) != start; p = p->next)
! 1506: ;
! 1507: if (p == NULL) {
! 1508: printf("cs4280_trigger_output: bad addr %p\n", start);
! 1509: return (EINVAL);
! 1510: }
! 1511: if (DMAADDR(p) % CS4280_DALIGN != 0 ) {
! 1512: printf("cs4280_trigger_output: DMAADDR(p)=0x%lx does not start"
! 1513: "4kB align\n", DMAADDR(p));
! 1514: return (EINVAL);
! 1515: }
! 1516:
! 1517: sc->sc_pcount = blksize / CS4280_ICHUNK; /* CS4280_ICHUNK is fixed hardware blksize*/
! 1518: sc->sc_ps = (char *)start;
! 1519: sc->sc_pe = (char *)end;
! 1520: sc->sc_pdma = p;
! 1521: sc->sc_pbuf = KERNADDR(p);
! 1522: sc->sc_pi = 0;
! 1523: sc->sc_pn = sc->sc_ps;
! 1524: if (blksize >= CS4280_DCHUNK) {
! 1525: sc->sc_pn = sc->sc_ps + CS4280_DCHUNK;
! 1526: memcpy(sc->sc_pbuf, start, CS4280_DCHUNK);
! 1527: ++sc->sc_pi;
! 1528: } else {
! 1529: sc->sc_pn = sc->sc_ps + CS4280_ICHUNK;
! 1530: memcpy(sc->sc_pbuf, start, CS4280_ICHUNK);
! 1531: }
! 1532:
! 1533: /* initiate playback dma */
! 1534: BA1WRITE4(sc, CS4280_PBA, DMAADDR(p));
! 1535:
! 1536: /* set PFIE */
! 1537: pfie = BA1READ4(sc, CS4280_PFIE) & ~PFIE_MASK;
! 1538:
! 1539: if (param->precision * param->factor == 8)
! 1540: pfie |= PFIE_8BIT;
! 1541: if (param->channels == 1)
! 1542: pfie |= PFIE_MONO;
! 1543:
! 1544: if (param->encoding == AUDIO_ENCODING_ULINEAR_BE ||
! 1545: param->encoding == AUDIO_ENCODING_SLINEAR_BE)
! 1546: pfie |= PFIE_SWAPPED;
! 1547: if (param->encoding == AUDIO_ENCODING_ULINEAR_BE ||
! 1548: param->encoding == AUDIO_ENCODING_ULINEAR_LE)
! 1549: pfie |= PFIE_UNSIGNED;
! 1550:
! 1551: BA1WRITE4(sc, CS4280_PFIE, pfie | PFIE_PI_ENABLE);
! 1552:
! 1553: cs4280_set_dac_rate(sc, param->sample_rate);
! 1554:
! 1555: pctl = BA1READ4(sc, CS4280_PCTL) & ~PCTL_MASK;
! 1556: pctl |= sc->pctl;
! 1557: BA1WRITE4(sc, CS4280_PCTL, pctl);
! 1558: return (0);
! 1559: }
! 1560:
! 1561: int
! 1562: cs4280_trigger_input(addr, start, end, blksize, intr, arg, param)
! 1563: void *addr;
! 1564: void *start, *end;
! 1565: int blksize;
! 1566: void (*intr)(void *);
! 1567: void *arg;
! 1568: struct audio_params *param;
! 1569: {
! 1570: struct cs4280_softc *sc = addr;
! 1571: u_int32_t cctl, cie;
! 1572: struct cs4280_dma *p;
! 1573:
! 1574: #ifdef DIAGNOSTIC
! 1575: if (sc->sc_rrun)
! 1576: printf("cs4280_trigger_input: already running\n");
! 1577: sc->sc_rrun = 1;
! 1578: #endif
! 1579: DPRINTF(("cs4280_trigger_input: sc=%p start=%p end=%p "
! 1580: "blksize=%d intr=%p(%p)\n", addr, start, end, blksize, intr, arg));
! 1581: sc->sc_rintr = intr;
! 1582: sc->sc_rarg = arg;
! 1583:
! 1584: sc->sc_ri = 0;
! 1585: sc->sc_rcount = blksize / CS4280_ICHUNK; /* CS4280_ICHUNK is fixed hardware blksize*/
! 1586: sc->sc_rs = (char *)start;
! 1587: sc->sc_re = (char *)end;
! 1588: sc->sc_rn = sc->sc_rs;
! 1589:
! 1590: /* setup format information for internal converter */
! 1591: sc->sc_rparam = 0;
! 1592: if (param->precision == 8) {
! 1593: sc->sc_rparam += CF_8BIT;
! 1594: sc->sc_rcount <<= 1;
! 1595: }
! 1596: if (param->channels == 1) {
! 1597: sc->sc_rparam += CF_MONO;
! 1598: sc->sc_rcount <<= 1;
! 1599: }
! 1600:
! 1601: /* stop capture DMA */
! 1602: cctl = BA1READ4(sc, CS4280_CCTL) & ~CCTL_MASK;
! 1603: BA1WRITE4(sc, CS4280_CCTL, cctl);
! 1604:
! 1605: for (p = sc->sc_dmas; p && BUFADDR(p) != start; p = p->next)
! 1606: ;
! 1607: if (!p) {
! 1608: printf("cs4280_trigger_input: bad addr %p\n", start);
! 1609: return (EINVAL);
! 1610: }
! 1611: if (DMAADDR(p) % CS4280_DALIGN != 0) {
! 1612: printf("cs4280_trigger_input: DMAADDR(p)=0x%lx does not start"
! 1613: "4kB align\n", DMAADDR(p));
! 1614: return (EINVAL);
! 1615: }
! 1616: sc->sc_rdma = p;
! 1617: sc->sc_rbuf = KERNADDR(p);
! 1618:
! 1619: /* initiate capture dma */
! 1620: BA1WRITE4(sc, CS4280_CBA, DMAADDR(p));
! 1621:
! 1622: /* set CIE */
! 1623: cie = BA1READ4(sc, CS4280_CIE) & ~CIE_CI_MASK;
! 1624: BA1WRITE4(sc, CS4280_CIE, cie | CIE_CI_ENABLE);
! 1625:
! 1626: cs4280_set_adc_rate(sc, param->sample_rate);
! 1627:
! 1628: cctl = BA1READ4(sc, CS4280_CCTL) & ~CCTL_MASK;
! 1629: cctl |= sc->cctl;
! 1630: BA1WRITE4(sc, CS4280_CCTL, cctl);
! 1631: return (0);
! 1632: }
! 1633:
! 1634:
! 1635: int
! 1636: cs4280_init(sc, init)
! 1637: struct cs4280_softc *sc;
! 1638: int init;
! 1639: {
! 1640: int n;
! 1641: u_int32_t mem;
! 1642:
! 1643: /* Start PLL out in known state */
! 1644: BA0WRITE4(sc, CS4280_CLKCR1, 0);
! 1645: /* Start serial ports out in known state */
! 1646: BA0WRITE4(sc, CS4280_SERMC1, 0);
! 1647:
! 1648: /* Specify type of CODEC */
! 1649: /* XXX should no be here */
! 1650: #define SERACC_CODEC_TYPE_1_03
! 1651: #ifdef SERACC_CODEC_TYPE_1_03
! 1652: BA0WRITE4(sc, CS4280_SERACC, SERACC_HSP | SERACC_CTYPE_1_03); /* AC 97 1.03 */
! 1653: #else
! 1654: BA0WRITE4(sc, CS4280_SERACC, SERACC_HSP | SERACC_CTYPE_2_0); /* AC 97 2.0 */
! 1655: #endif
! 1656:
! 1657: /* Reset codec */
! 1658: BA0WRITE4(sc, CS4280_ACCTL, 0);
! 1659: delay(100); /* delay 100us */
! 1660: BA0WRITE4(sc, CS4280_ACCTL, ACCTL_RSTN);
! 1661:
! 1662: /* Enable AC-link sync generation */
! 1663: BA0WRITE4(sc, CS4280_ACCTL, ACCTL_ESYN | ACCTL_RSTN);
! 1664: delay(50*1000); /* delay 50ms */
! 1665:
! 1666: /* Set the serial port timing configuration */
! 1667: BA0WRITE4(sc, CS4280_SERMC1, SERMC1_PTC_AC97);
! 1668:
! 1669: /* Setup clock control */
! 1670: BA0WRITE4(sc, CS4280_PLLCC, PLLCC_CDR_STATE|PLLCC_LPF_STATE);
! 1671: BA0WRITE4(sc, CS4280_PLLM, PLLM_STATE);
! 1672: BA0WRITE4(sc, CS4280_CLKCR2, CLKCR2_PDIVS_8);
! 1673:
! 1674: /* Power up the PLL */
! 1675: BA0WRITE4(sc, CS4280_CLKCR1, CLKCR1_PLLP);
! 1676: delay(50*1000); /* delay 50ms */
! 1677:
! 1678: /* Turn on clock */
! 1679: mem = BA0READ4(sc, CS4280_CLKCR1) | CLKCR1_SWCE;
! 1680: BA0WRITE4(sc, CS4280_CLKCR1, mem);
! 1681:
! 1682: /* Set the serial port FIFO pointer to the
! 1683: * first sample in FIFO. (not documented) */
! 1684: cs4280_clear_fifos(sc);
! 1685:
! 1686: #if 0
! 1687: /* Set the serial port FIFO pointer to the first sample in the FIFO */
! 1688: BA0WRITE4(sc, CS4280_SERBSP, 0);
! 1689: #endif
! 1690:
! 1691: /* Configure the serial port */
! 1692: BA0WRITE4(sc, CS4280_SERC1, SERC1_SO1EN | SERC1_SO1F_AC97);
! 1693: BA0WRITE4(sc, CS4280_SERC2, SERC2_SI1EN | SERC2_SI1F_AC97);
! 1694: BA0WRITE4(sc, CS4280_SERMC1, SERMC1_MSPE | SERMC1_PTC_AC97);
! 1695:
! 1696: /* Wait for CODEC ready */
! 1697: n = 0;
! 1698: while ((BA0READ4(sc, CS4280_ACSTS) & ACSTS_CRDY) == 0) {
! 1699: delay(125);
! 1700: if (++n > 1000) {
! 1701: printf("%s: codec ready timeout\n",
! 1702: sc->sc_dev.dv_xname);
! 1703: return(1);
! 1704: }
! 1705: }
! 1706:
! 1707: /* Assert valid frame signal */
! 1708: BA0WRITE4(sc, CS4280_ACCTL, ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN);
! 1709:
! 1710: /* Wait for valid AC97 input slot */
! 1711: n = 0;
! 1712: while ((BA0READ4(sc, CS4280_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) !=
! 1713: (ACISV_ISV3 | ACISV_ISV4)) {
! 1714: delay(1000);
! 1715: if (++n > 1000) {
! 1716: printf("AC97 inputs slot ready timeout\n");
! 1717: return(1);
! 1718: }
! 1719: }
! 1720:
! 1721: /* Set AC97 output slot valid signals */
! 1722: BA0WRITE4(sc, CS4280_ACOSV, ACOSV_SLV3 | ACOSV_SLV4);
! 1723:
! 1724: /* reset the processor */
! 1725: cs4280_reset(sc);
! 1726: return (0);
! 1727: }
! 1728:
! 1729: int
! 1730: cs4280_init2(sc, init)
! 1731: struct cs4280_softc *sc;
! 1732: int init;
! 1733: {
! 1734: int n;
! 1735: u_int32_t mem;
! 1736:
! 1737: /* Download the image to the processor */
! 1738: if (cs4280_download_image(sc) != 0) {
! 1739: printf("%s: image download error\n", sc->sc_dev.dv_xname);
! 1740: return(1);
! 1741: }
! 1742:
! 1743: /* Save playback parameter and then write zero.
! 1744: * this ensures that DMA doesn't immediately occur upon
! 1745: * starting the processor core
! 1746: */
! 1747: mem = BA1READ4(sc, CS4280_PCTL);
! 1748: sc->pctl = mem & PCTL_MASK; /* save startup value */
! 1749: cs4280_halt_output(sc);
! 1750:
! 1751: /* Save capture parameter and then write zero.
! 1752: * this ensures that DMA doesn't immediately occur upon
! 1753: * starting the processor core
! 1754: */
! 1755: mem = BA1READ4(sc, CS4280_CCTL);
! 1756: sc->cctl = mem & CCTL_MASK; /* save startup value */
! 1757: cs4280_halt_input(sc);
! 1758:
! 1759: /* MSH: need to power up ADC and DAC? */
! 1760:
! 1761: /* Processor Startup Procedure */
! 1762: BA1WRITE4(sc, CS4280_FRMT, FRMT_FTV);
! 1763: BA1WRITE4(sc, CS4280_SPCR, SPCR_RUN | SPCR_RUNFR | SPCR_DRQEN);
! 1764:
! 1765: /* Monitor RUNFR bit in SPCR for 1 to 0 transition */
! 1766: n = 0;
! 1767: while (BA1READ4(sc, CS4280_SPCR) & SPCR_RUNFR) {
! 1768: delay(10);
! 1769: if (++n > 1000) {
! 1770: printf("SPCR 1->0 transition timeout\n");
! 1771: return(1);
! 1772: }
! 1773: }
! 1774:
! 1775: n = 0;
! 1776: while (!(BA1READ4(sc, CS4280_SPCS) & SPCS_SPRUN)) {
! 1777: delay(10);
! 1778: if (++n > 1000) {
! 1779: printf("SPCS 0->1 transition timeout\n");
! 1780: return(1);
! 1781: }
! 1782: }
! 1783: /* Processor is now running !!! */
! 1784:
! 1785: /* Setup volume */
! 1786: BA1WRITE4(sc, CS4280_PVOL, 0x80008000);
! 1787: BA1WRITE4(sc, CS4280_CVOL, 0x80008000);
! 1788:
! 1789: /* Interrupt enable */
! 1790: BA0WRITE4(sc, CS4280_HICR, HICR_IEV|HICR_CHGM);
! 1791:
! 1792: /* playback interrupt enable */
! 1793: mem = BA1READ4(sc, CS4280_PFIE) & ~PFIE_PI_MASK;
! 1794: mem |= PFIE_PI_ENABLE;
! 1795: BA1WRITE4(sc, CS4280_PFIE, mem);
! 1796: /* capture interrupt enable */
! 1797: mem = BA1READ4(sc, CS4280_CIE) & ~CIE_CI_MASK;
! 1798: mem |= CIE_CI_ENABLE;
! 1799: BA1WRITE4(sc, CS4280_CIE, mem);
! 1800:
! 1801: #if NMIDI > 0
! 1802: /* Reset midi port */
! 1803: mem = BA0READ4(sc, CS4280_MIDCR) & ~MIDCR_MASK;
! 1804: BA0WRITE4(sc, CS4280_MIDCR, mem | MIDCR_MRST);
! 1805: DPRINTF(("midi reset: 0x%x\n", BA0READ4(sc, CS4280_MIDCR)));
! 1806: /* midi interrupt enable */
! 1807: mem |= MIDCR_TXE | MIDCR_RXE | MIDCR_RIE | MIDCR_TIE;
! 1808: BA0WRITE4(sc, CS4280_MIDCR, mem);
! 1809: #endif
! 1810: return(0);
! 1811: }
! 1812:
! 1813: void
! 1814: cs4280_power(why, v)
! 1815: int why;
! 1816: void *v;
! 1817: {
! 1818: struct cs4280_softc *sc = (struct cs4280_softc *)v;
! 1819: int i;
! 1820:
! 1821: DPRINTF(("%s: cs4280_power why=%d\n",
! 1822: sc->sc_dev.dv_xname, why));
! 1823: if (why != PWR_RESUME) {
! 1824: sc->sc_suspend = why;
! 1825:
! 1826: cs4280_halt_output(sc);
! 1827: cs4280_halt_input(sc);
! 1828: /* Save AC97 registers */
! 1829: for(i = 1; i <= CS4280_SAVE_REG_MAX; i++) {
! 1830: if(i == 0x04) /* AC97_REG_MASTER_TONE */
! 1831: continue;
! 1832: cs4280_read_codec(sc, 2*i, &sc->ac97_reg[i]);
! 1833: }
! 1834: /* should I powerdown here ? */
! 1835: cs4280_write_codec(sc, AC97_REG_POWER, CS4280_POWER_DOWN_ALL);
! 1836: } else {
! 1837: if (sc->sc_suspend == PWR_RESUME) {
! 1838: printf("cs4280_power: odd, resume without suspend.\n");
! 1839: sc->sc_suspend = why;
! 1840: return;
! 1841: }
! 1842: sc->sc_suspend = why;
! 1843: cs4280_init(sc, 0);
! 1844: cs4280_init2(sc, 0);
! 1845: cs4280_reset_codec(sc);
! 1846:
! 1847: /* restore ac97 registers */
! 1848: for(i = 1; i <= CS4280_SAVE_REG_MAX; i++) {
! 1849: if(i == 0x04) /* AC97_REG_MASTER_TONE */
! 1850: continue;
! 1851: cs4280_write_codec(sc, 2*i, sc->ac97_reg[i]);
! 1852: }
! 1853: }
! 1854: }
! 1855:
! 1856: void
! 1857: cs4280_clear_fifos(sc)
! 1858: struct cs4280_softc *sc;
! 1859: {
! 1860: int pd = 0, cnt, n;
! 1861: u_int32_t mem;
! 1862:
! 1863: /*
! 1864: * If device power down, power up the device and keep power down
! 1865: * state.
! 1866: */
! 1867: mem = BA0READ4(sc, CS4280_CLKCR1);
! 1868: if (!(mem & CLKCR1_SWCE)) {
! 1869: printf("cs4280_clear_fifo: power down found.\n");
! 1870: BA0WRITE4(sc, CS4280_CLKCR1, mem | CLKCR1_SWCE);
! 1871: pd = 1;
! 1872: }
! 1873: BA0WRITE4(sc, CS4280_SERBWP, 0);
! 1874: for (cnt = 0; cnt < 256; cnt++) {
! 1875: n = 0;
! 1876: while (BA0READ4(sc, CS4280_SERBST) & SERBST_WBSY) {
! 1877: delay(1000);
! 1878: if (++n > 1000) {
! 1879: printf("clear_fifo: fist timeout cnt=%d\n", cnt);
! 1880: break;
! 1881: }
! 1882: }
! 1883: BA0WRITE4(sc, CS4280_SERBAD, cnt);
! 1884: BA0WRITE4(sc, CS4280_SERBCM, SERBCM_WRC);
! 1885: }
! 1886: if (pd)
! 1887: BA0WRITE4(sc, CS4280_CLKCR1, mem);
! 1888: }
! 1889:
! 1890: #if NMIDI > 0
! 1891: int
! 1892: cs4280_midi_open(addr, flags, iintr, ointr, arg)
! 1893: void *addr;
! 1894: int flags;
! 1895: void (*iintr)(void *, int);
! 1896: void (*ointr)(void *);
! 1897: void *arg;
! 1898: {
! 1899: struct cs4280_softc *sc = addr;
! 1900: u_int32_t mem;
! 1901:
! 1902: DPRINTF(("midi_open\n"));
! 1903: sc->sc_iintr = iintr;
! 1904: sc->sc_ointr = ointr;
! 1905: sc->sc_arg = arg;
! 1906:
! 1907: /* midi interrupt enable */
! 1908: mem = BA0READ4(sc, CS4280_MIDCR) & ~MIDCR_MASK;
! 1909: mem |= MIDCR_TXE | MIDCR_RXE | MIDCR_RIE | MIDCR_TIE | MIDCR_MLB;
! 1910: BA0WRITE4(sc, CS4280_MIDCR, mem);
! 1911: #ifdef CS4280_DEBUG
! 1912: if (mem != BA0READ4(sc, CS4280_MIDCR)) {
! 1913: DPRINTF(("midi_open: MIDCR=%d\n", BA0READ4(sc, CS4280_MIDCR)));
! 1914: return(EINVAL);
! 1915: }
! 1916: DPRINTF(("MIDCR=0x%x\n", BA0READ4(sc, CS4280_MIDCR)));
! 1917: #endif
! 1918: return (0);
! 1919: }
! 1920:
! 1921: void
! 1922: cs4280_midi_close(addr)
! 1923: void *addr;
! 1924: {
! 1925: struct cs4280_softc *sc = addr;
! 1926: u_int32_t mem;
! 1927:
! 1928: DPRINTF(("midi_close\n"));
! 1929: mem = BA0READ4(sc, CS4280_MIDCR);
! 1930: mem &= ~MIDCR_MASK;
! 1931: BA0WRITE4(sc, CS4280_MIDCR, mem);
! 1932:
! 1933: sc->sc_iintr = 0;
! 1934: sc->sc_ointr = 0;
! 1935: }
! 1936:
! 1937: int
! 1938: cs4280_midi_output(addr, d)
! 1939: void *addr;
! 1940: int d;
! 1941: {
! 1942: struct cs4280_softc *sc = addr;
! 1943: u_int32_t mem;
! 1944: int x;
! 1945:
! 1946: for (x = 0; x != MIDI_BUSY_WAIT; x++) {
! 1947: if ((BA0READ4(sc, CS4280_MIDSR) & MIDSR_TBF) == 0) {
! 1948: mem = BA0READ4(sc, CS4280_MIDWP) & ~MIDWP_MASK;
! 1949: mem |= d & MIDWP_MASK;
! 1950: DPRINTFN(5,("midi_output d=0x%08x",d));
! 1951: BA0WRITE4(sc, CS4280_MIDWP, mem);
! 1952: if (mem != BA0READ4(sc, CS4280_MIDWP)) {
! 1953: DPRINTF(("Bad write data: %d %d",
! 1954: mem, BA0READ4(sc, CS4280_MIDWP)));
! 1955: return(EIO);
! 1956: }
! 1957: return (0);
! 1958: }
! 1959: delay(MIDI_BUSY_DELAY);
! 1960: }
! 1961: return (EIO);
! 1962: }
! 1963:
! 1964: void
! 1965: cs4280_midi_getinfo(addr, mi)
! 1966: void *addr;
! 1967: struct midi_info *mi;
! 1968: {
! 1969: mi->name = "CS4280 MIDI UART";
! 1970: mi->props = MIDI_PROP_CAN_INPUT | MIDI_PROP_OUT_INTR;
! 1971: }
! 1972:
! 1973: #endif
CVSweb