1/* 2 * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. --- 8 unchanged lines hidden (view full) --- 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 * |
25 * $FreeBSD: head/sys/dev/sound/pci/solo.c 70134 2000-12-18 01:36:41Z cg $ |
26 */ 27 28#include <dev/sound/pcm/sound.h> 29 30#include <pci/pcireg.h> 31#include <pci/pcivar.h> 32 33#include <dev/sound/isa/sb.h> 34#include <dev/sound/chip.h> 35 |
36#include "mixer_if.h" 37 |
38#define ESS_BUFFSIZE (16384) 39#define ABS(x) (((x) < 0)? -(x) : (x)) 40 41/* if defined, playback always uses the 2nd channel and full duplex works */ 42#undef ESS18XX_DUPLEX 43 44/* more accurate clocks and split audio1/audio2 rates */ 45#define ESS18XX_NEWSPEED 46 |
47static u_int32_t ess_playfmt[] = { 48 AFMT_U8, 49 AFMT_STEREO | AFMT_U8, 50 AFMT_S8, 51 AFMT_STEREO | AFMT_S8, 52 AFMT_S16_LE, 53 AFMT_STEREO | AFMT_S16_LE, 54 AFMT_U16_LE, --- 13 unchanged lines hidden (view full) --- 68 AFMT_S16_BE, 69 AFMT_STEREO | AFMT_S16_BE, 70 AFMT_U16_BE, 71 AFMT_STEREO | AFMT_U16_BE, 72 0 73}; 74static pcmchan_caps ess_reccaps = {5000, 49000, ess_recfmt, 0}; 75 |
76struct ess_info; 77 78struct ess_chinfo { 79 struct ess_info *parent; 80 pcm_channel *channel; 81 snd_dbuf *buffer; 82 int dir, hwch, stopping; 83 u_int32_t fmt, spd; --- 26 unchanged lines hidden (view full) --- 110static int ess_setupch(struct ess_info *sc, int ch, int dir, int spd, u_int32_t fmt, int len); 111static int ess_start(struct ess_chinfo *ch); 112static int ess_stop(struct ess_chinfo *ch); 113 114static int ess_dmasetup(struct ess_info *sc, int ch, u_int32_t base, u_int16_t cnt, int dir); 115static int ess_dmapos(struct ess_info *sc, int ch); 116static int ess_dmatrigger(struct ess_info *sc, int ch, int go); 117 |
118static devclass_t pcm_devclass; 119 120/* 121 * Common code for the midi and pcm functions 122 * 123 * ess_cmd write a single byte to the CMD port. 124 * ess_cmd1 write a CMD + 1 byte arg 125 * ess_cmd2 write a CMD + 2 byte arg --- 376 unchanged lines hidden (view full) --- 502 if (ch->hwch == 1) 503 ess_write(sc, 0xb8, ess_read(sc, 0xb8) & ~0x04); 504 else 505 ess_setmixer(sc, 0x78, ess_getmixer(sc, 0x78) & ~0x10); 506 DEB(printf("done with stop\n")); 507 return 0; 508} 509 |
510/* -------------------------------------------------------------------- */ |
511/* channel interface for ESS18xx */ 512static void * |
513esschan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) |
514{ 515 struct ess_info *sc = devinfo; 516 struct ess_chinfo *ch = (dir == PCMDIR_PLAY)? &sc->pch : &sc->rch; 517 518 DEB(printf("esschan_init\n")); 519 ch->parent = sc; 520 ch->channel = c; 521 ch->buffer = b; 522 ch->buffer->bufsize = ESS_BUFFSIZE; 523 ch->dir = dir; 524 if (chn_allocbuf(ch->buffer, sc->parent_dmat) == -1) 525 return NULL; 526 ch->hwch = 1; 527 if ((dir == PCMDIR_PLAY) && (sc->duplex)) 528 ch->hwch = 2; 529 return ch; 530} 531 532static int |
533esschan_setformat(kobj_t obj, void *data, u_int32_t format) |
534{ 535 struct ess_chinfo *ch = data; 536 537 ch->fmt = format; 538 return 0; 539} 540 541static int |
542esschan_setspeed(kobj_t obj, void *data, u_int32_t speed) |
543{ 544 struct ess_chinfo *ch = data; 545 struct ess_info *sc = ch->parent; 546 547 ch->spd = speed; 548 if (sc->newspeed) 549 ess_calcspeed9(&ch->spd); 550 else 551 ess_calcspeed8(&ch->spd); 552 return ch->spd; 553} 554 555static int |
556esschan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) |
557{ 558 return blocksize; 559} 560 561static int |
562esschan_trigger(kobj_t obj, void *data, int go) |
563{ 564 struct ess_chinfo *ch = data; 565 struct ess_info *sc = ch->parent; 566 567 DEB(printf("esschan_trigger: %d\n",go)); 568 if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) 569 return 0; 570 --- 9 unchanged lines hidden (view full) --- 580 default: 581 ess_stop(ch); 582 break; 583 } 584 return 0; 585} 586 587static int |
588esschan_getptr(kobj_t obj, void *data) |
589{ 590 struct ess_chinfo *ch = data; 591 struct ess_info *sc = ch->parent; 592 593 return ess_dmapos(sc, ch->hwch); 594} 595 596static pcmchan_caps * |
597esschan_getcaps(kobj_t obj, void *data) |
598{ 599 struct ess_chinfo *ch = data; 600 601 return (ch->dir == PCMDIR_PLAY)? &ess_playcaps : &ess_reccaps; 602} 603 |
604static kobj_method_t esschan_methods[] = { 605 KOBJMETHOD(channel_init, esschan_init), 606 KOBJMETHOD(channel_setformat, esschan_setformat), 607 KOBJMETHOD(channel_setspeed, esschan_setspeed), 608 KOBJMETHOD(channel_setblocksize, esschan_setblocksize), 609 KOBJMETHOD(channel_trigger, esschan_trigger), 610 KOBJMETHOD(channel_getptr, esschan_getptr), 611 KOBJMETHOD(channel_getcaps, esschan_getcaps), 612 { 0, 0 } 613}; 614CHANNEL_DECLARE(esschan); 615 |
616/************************************************************/ 617 618static int 619essmix_init(snd_mixer *m) 620{ 621 struct ess_info *sc = mix_getdevinfo(m); 622 623 mix_setrecdevs(m, SOUND_MASK_CD | SOUND_MASK_MIC | SOUND_MASK_LINE | --- 94 unchanged lines hidden (view full) --- 718 break; 719 } 720 721 ess_setmixer(sc, 0x1c, recdev); 722 723 return src; 724} 725 |
726static kobj_method_t solomixer_methods[] = { 727 KOBJMETHOD(mixer_init, essmix_init), 728 KOBJMETHOD(mixer_set, essmix_set), 729 KOBJMETHOD(mixer_setrecsrc, essmix_setrecsrc), 730 { 0, 0 } 731}; 732MIXER_DECLARE(solomixer); 733 |
734/************************************************************/ 735 736static int 737ess_dmasetup(struct ess_info *sc, int ch, u_int32_t base, u_int16_t cnt, int dir) 738{ 739 KASSERT(ch == 1 || ch == 2, ("bad ch")); 740 sc->dmasz[ch - 1] = cnt; 741 if (ch == 1) { --- 177 unchanged lines hidden (view full) --- 919 920 ddma = rman_get_start(sc->vc) | 1; 921 pci_write_config(dev, PCI_LEGACYCONTROL, 0x805f, 2); 922 pci_write_config(dev, PCI_DDMACONTROL, ddma, 2); 923 pci_write_config(dev, PCI_CONFIG, 0, 2); 924 925 if (ess_reset_dsp(sc)) 926 goto no; |
927 if (mixer_init(dev, &solomixer_class, sc)) 928 goto no; |
929 930 port_wr(sc->io, 0x7, 0xb0, 1); /* enable irqs */ 931#ifdef ESS18XX_DUPLEX 932 sc->duplex = 1; 933#else 934 sc->duplex = 0; 935#endif 936 --- 21 unchanged lines hidden (view full) --- 958 } 959 960 snprintf(status, SND_STATUSLEN, "at io 0x%lx,0x%lx,0x%lx irq %ld", 961 rman_get_start(sc->io), rman_get_start(sc->sb), rman_get_start(sc->vc), 962 rman_get_start(sc->irq)); 963 964 if (pcm_register(dev, sc, 1, 1)) 965 goto no; |
966 pcm_addchan(dev, PCMDIR_REC, &esschan_class, sc); 967 pcm_addchan(dev, PCMDIR_PLAY, &esschan_class, sc); |
968 pcm_setstatus(dev, status); 969 970 return 0; 971 972no: 973 ess_release_resources(sc, dev); 974 return ENXIO; 975} --- 39 unchanged lines hidden --- |