1/* 2 * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> 3 * Copyright 1997,1998 Luigi Rizzo. 4 * 5 * Derived from files in the Voxware 3.5 distribution, 6 * Copyright by Hannu Savolainen 1994, under the same copyright 7 * conditions. 8 * All rights reserved. --- 14 unchanged lines hidden (view full) --- 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * |
31 * $FreeBSD: head/sys/dev/sound/isa/ess.c 70134 2000-12-18 01:36:41Z cg $ |
32 */ 33 34#include <dev/sound/pcm/sound.h> 35 36#include <dev/sound/isa/sb.h> 37#include <dev/sound/chip.h> 38 |
39#include "mixer_if.h" 40 |
41#define ESS_BUFFSIZE (4096) 42#define ABS(x) (((x) < 0)? -(x) : (x)) 43 44/* audio2 never generates irqs and sounds very noisy */ 45#undef ESS18XX_DUPLEX 46 47/* more accurate clocks and split audio1/audio2 rates */ 48#define ESS18XX_NEWSPEED 49 |
50static u_int32_t ess_pfmt[] = { 51 AFMT_U8, 52 AFMT_STEREO | AFMT_U8, 53 AFMT_S8, 54 AFMT_STEREO | AFMT_S8, 55 AFMT_S16_LE, 56 AFMT_STEREO | AFMT_S16_LE, 57 AFMT_U16_LE, --- 12 unchanged lines hidden (view full) --- 70 AFMT_STEREO | AFMT_S16_LE, 71 AFMT_U16_LE, 72 AFMT_STEREO | AFMT_U16_LE, 73 0 74}; 75 76static pcmchan_caps ess_reccaps = {5000, 49000, ess_rfmt, 0}; 77 |
78struct ess_info; 79 80struct ess_chinfo { 81 struct ess_info *parent; 82 pcm_channel *channel; 83 snd_dbuf *buffer; |
84 int dir, hwch, stopping, run; |
85 u_int32_t fmt, spd; 86}; 87 88struct ess_info { 89 struct resource *io_base; /* I/O address for the board */ 90 struct resource *irq; 91 struct resource *drq1; 92 struct resource *drq2; --- 18 unchanged lines hidden (view full) --- 111static int ess_write(struct ess_info *sc, u_char reg, int val); 112static int ess_read(struct ess_info *sc, u_char reg); 113 114static void ess_intr(void *arg); 115static int ess_setupch(struct ess_info *sc, int ch, int dir, int spd, u_int32_t fmt, int len); 116static int ess_start(struct ess_chinfo *ch); 117static int ess_stop(struct ess_chinfo *ch); 118 |
119static devclass_t pcm_devclass; 120 121/* 122 * Common code for the midi and pcm functions 123 * 124 * ess_cmd write a single byte to the CMD port. 125 * ess_cmd1 write a CMD + 1 byte arg 126 * ess_cmd2 write a CMD + 2 byte arg --- 206 unchanged lines hidden (view full) --- 333 isa_dma_acquire(rman_get_start(sc->drq2)); 334 isa_dmainit(rman_get_start(sc->drq2), ESS_BUFFSIZE); 335 } 336 337 return 0; 338 } else return ENXIO; 339} 340 |
341static void 342ess_intr(void *arg) 343{ 344 struct ess_info *sc = (struct ess_info *)arg; 345 int src, pirq, rirq; 346 347 src = 0; 348 if (ess_getmixer(sc, 0x7a) & 0x80) 349 src |= 2; 350 if (ess_rd(sc, 0x0c) & 0x01) 351 src |= 1; 352 353 pirq = (src & sc->pch.hwch)? 1 : 0; 354 rirq = (src & sc->rch.hwch)? 1 : 0; 355 356 if (pirq) { |
357 if (!sc->pch.run) 358 printf("ess: play intr while not running\n"); |
359 if (sc->pch.stopping) { |
360 sc->pch.run = 0; |
361 buf_isadma(sc->pch.buffer, PCMTRIG_STOP); 362 sc->pch.stopping = 0; 363 if (sc->pch.hwch == 1) 364 ess_write(sc, 0xb8, ess_read(sc, 0xb8) & ~0x01); 365 else 366 ess_setmixer(sc, 0x78, ess_getmixer(sc, 0x78) & ~0x03); 367 } 368 chn_intr(sc->pch.channel); 369 } 370 371 if (rirq) { |
372 if (!sc->rch.run) 373 printf("ess: record intr while not running\n"); |
374 if (sc->rch.stopping) { |
375 sc->rch.run = 0; |
376 buf_isadma(sc->rch.buffer, PCMTRIG_STOP); 377 sc->rch.stopping = 0; 378 /* XXX: will this stop audio2? */ 379 ess_write(sc, 0xb8, ess_read(sc, 0xb8) & ~0x01); 380 } 381 chn_intr(sc->rch.channel); 382 } 383 --- 147 unchanged lines hidden (view full) --- 531 ess_write(sc, 0xb8, ess_read(sc, 0xb8) & ~0x04); 532 else 533 ess_setmixer(sc, 0x78, ess_getmixer(sc, 0x78) & ~0x10); 534 if (play) 535 ess_cmd(sc, DSP_CMD_SPKOFF); 536 return 0; 537} 538 |
539/* -------------------------------------------------------------------- */ |
540/* channel interface for ESS18xx */ 541static void * |
542esschan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) |
543{ 544 struct ess_info *sc = devinfo; 545 struct ess_chinfo *ch = (dir == PCMDIR_PLAY)? &sc->pch : &sc->rch; 546 547 ch->parent = sc; 548 ch->channel = c; 549 ch->buffer = b; 550 ch->buffer->bufsize = ESS_BUFFSIZE; 551 if (chn_allocbuf(ch->buffer, sc->parent_dmat) == -1) 552 return NULL; 553 ch->dir = dir; 554 ch->hwch = 1; 555 if ((dir == PCMDIR_PLAY) && (sc->duplex)) 556 ch->hwch = 2; 557 ch->buffer->chan = rman_get_start((ch->hwch == 1)? sc->drq1 : sc->drq2); 558 return ch; 559} 560 561static int |
562esschan_setformat(kobj_t obj, void *data, u_int32_t format) |
563{ 564 struct ess_chinfo *ch = data; 565 566 ch->fmt = format; 567 return 0; 568} 569 570static int |
571esschan_setspeed(kobj_t obj, void *data, u_int32_t speed) |
572{ 573 struct ess_chinfo *ch = data; 574 struct ess_info *sc = ch->parent; 575 576 ch->spd = speed; 577 if (sc->newspeed) 578 ess_calcspeed9(&ch->spd); 579 else 580 ess_calcspeed8(&ch->spd); 581 return ch->spd; 582} 583 584static int |
585esschan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) |
586{ 587 return blocksize; 588} 589 590static int |
591esschan_trigger(kobj_t obj, void *data, int go) |
592{ 593 struct ess_chinfo *ch = data; 594 595 if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) 596 return 0; 597 598 switch (go) { 599 case PCMTRIG_START: |
600 ch->run = 1; |
601 buf_isadma(ch->buffer, go); 602 ess_start(ch); 603 break; 604 605 case PCMTRIG_STOP: 606 case PCMTRIG_ABORT: 607 default: 608 ess_stop(ch); 609 break; 610 } 611 return 0; 612} 613 614static int |
615esschan_getptr(kobj_t obj, void *data) |
616{ 617 struct ess_chinfo *ch = data; 618 619 return buf_isadmaptr(ch->buffer); 620} 621 622static pcmchan_caps * |
623esschan_getcaps(kobj_t obj, void *data) |
624{ 625 struct ess_chinfo *ch = data; 626 627 return (ch->dir == PCMDIR_PLAY)? &ess_playcaps : &ess_reccaps; 628} 629 |
630static kobj_method_t esschan_methods[] = { 631 KOBJMETHOD(channel_init, esschan_init), 632 KOBJMETHOD(channel_setformat, esschan_setformat), 633 KOBJMETHOD(channel_setspeed, esschan_setspeed), 634 KOBJMETHOD(channel_setblocksize, esschan_setblocksize), 635 KOBJMETHOD(channel_trigger, esschan_trigger), 636 KOBJMETHOD(channel_getptr, esschan_getptr), 637 KOBJMETHOD(channel_getcaps, esschan_getcaps), 638 { 0, 0 } 639}; 640CHANNEL_DECLARE(esschan); 641 |
642/************************************************************/ 643 644static int 645essmix_init(snd_mixer *m) 646{ 647 struct ess_info *sc = mix_getdevinfo(m); 648 649 mix_setrecdevs(m, SOUND_MASK_CD | SOUND_MASK_MIC | SOUND_MASK_LINE | --- 94 unchanged lines hidden (view full) --- 744 break; 745 } 746 747 ess_setmixer(sc, 0x1c, recdev); 748 749 return src; 750} 751 |
752static kobj_method_t essmixer_methods[] = { 753 KOBJMETHOD(mixer_init, essmix_init), 754 KOBJMETHOD(mixer_set, essmix_set), 755 KOBJMETHOD(mixer_setrecsrc, essmix_setrecsrc), 756 { 0, 0 } 757}; 758MIXER_DECLARE(essmixer); 759 760/************************************************************/ 761 |
762static int 763ess_probe(device_t dev) 764{ 765 uintptr_t func, ver, r, f; 766 767 /* The parent device has already been probed. */ 768 r = BUS_READ_IVAR(device_get_parent(dev), dev, 0, &func); 769 if (func != SCF_PCM) --- 8 unchanged lines hidden (view full) --- 778 779 return 0; 780} 781 782static int 783ess_attach(device_t dev) 784{ 785 struct ess_info *sc; |
786 char status[SND_STATUSLEN], buf[64]; 787 int ver; |
788 789 sc = (struct ess_info *)malloc(sizeof *sc, M_DEVBUF, M_NOWAIT); 790 if (!sc) 791 return ENXIO; 792 bzero(sc, sizeof *sc); 793 |
794 if (ess_alloc_resources(sc, dev)) 795 goto no; 796 if (ess_reset_dsp(sc)) 797 goto no; 798 if (mixer_init(dev, &essmixer_class, sc)) 799 goto no; 800 801 sc->duplex = 0; 802 sc->newspeed = 0; 803 ver = (ess_getmixer(sc, 0x40) << 8) | ess_rd(sc, SB_MIX_DATA); 804 snprintf(buf, sizeof buf, "ESS %x DSP", ver); 805 device_set_desc_copy(dev, buf); 806 if (bootverbose) 807 device_printf(dev, "ESS%x detected", ver); 808 809 switch (ver) { 810 case 0x1869: 811 case 0x1879: 812#ifdef ESS18XX_DUPLEX 813 sc->duplex = sc->drq2? 1 : 0; 814#endif 815#ifdef ESS18XX_NEWSPEED 816 sc->newspeed = 1; 817#endif 818 break; 819 } 820 if (bootverbose) 821 printf("%s%s\n", sc->duplex? ", duplex" : "", 822 sc->newspeed? ", newspeed" : ""); 823 824 if (sc->newspeed) 825 ess_setmixer(sc, 0x71, 0x22); 826 827 bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, ess_intr, sc, &sc->ih); 828 if (!sc->duplex) 829 pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX); 830 831 if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, 832 /*lowaddr*/BUS_SPACE_MAXADDR_24BIT, 833 /*highaddr*/BUS_SPACE_MAXADDR, 834 /*filter*/NULL, /*filterarg*/NULL, 835 /*maxsize*/ESS_BUFFSIZE, /*nsegments*/1, 836 /*maxsegz*/0x3ffff, 837 /*flags*/0, &sc->parent_dmat) != 0) { 838 device_printf(dev, "unable to create dma tag\n"); 839 goto no; 840 } 841 842 snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld", 843 rman_get_start(sc->io_base), rman_get_start(sc->irq), 844 rman_get_start(sc->drq1)); 845 if (sc->drq2) 846 snprintf(status + strlen(status), SND_STATUSLEN - strlen(status), 847 ":%ld", rman_get_start(sc->drq2)); 848 849 if (pcm_register(dev, sc, 1, 1)) 850 goto no; 851 pcm_addchan(dev, PCMDIR_REC, &esschan_class, sc); 852 pcm_addchan(dev, PCMDIR_PLAY, &esschan_class, sc); 853 pcm_setstatus(dev, status); 854 855 return 0; 856 857no: 858 ess_release_resources(sc, dev); 859 return ENXIO; |
860} 861 |
862static int 863ess_detach(device_t dev) 864{ 865 int r; 866 struct ess_info *sc; 867 868 r = pcm_unregister(dev); 869 if (r) 870 return r; 871 872 sc = pcm_getdevinfo(dev); 873 ess_release_resources(sc, dev); 874 return 0; 875} 876 |
877static device_method_t ess_methods[] = { 878 /* Device interface */ 879 DEVMETHOD(device_probe, ess_probe), 880 DEVMETHOD(device_attach, ess_attach), 881 DEVMETHOD(device_detach, ess_detach), 882 883 { 0, 0 } 884}; 885 886static driver_t ess_driver = { 887 "pcm", 888 ess_methods, 889 sizeof(snddev_info), 890}; 891 892DRIVER_MODULE(snd_ess, sbc, ess_driver, pcm_devclass, 0, 0); 893MODULE_DEPEND(snd_ess, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); 894MODULE_VERSION(snd_ess, 1); 895 |
896/************************************************************/ |
897 898static devclass_t esscontrol_devclass; 899 900static struct isa_pnp_id essc_ids[] = { 901 {0x06007316, "ESS Control"}, 902 {0} 903}; 904 --- 55 unchanged lines hidden --- |