Deleted Added
sdiff udiff text old ( 67652 ) new ( 70134 )
full compact
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 67652 2000-10-26 20:46:58Z 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#define ESS_BUFFSIZE (4096)
40#define ABS(x) (((x) < 0)? -(x) : (x))
41
42/* audio2 never generates irqs and sounds very noisy */
43#undef ESS18XX_DUPLEX
44
45/* more accurate clocks and split audio1/audio2 rates */
46#define ESS18XX_NEWSPEED
47
48/* channel interface for ESS */
49static void *esschan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir);
50static int esschan_setformat(void *data, u_int32_t format);
51static int esschan_setspeed(void *data, u_int32_t speed);
52static int esschan_setblocksize(void *data, u_int32_t blocksize);
53static int esschan_trigger(void *data, int go);
54static int esschan_getptr(void *data);
55static pcmchan_caps *esschan_getcaps(void *data);
56
57static u_int32_t ess_pfmt[] = {
58 AFMT_U8,
59 AFMT_STEREO | AFMT_U8,
60 AFMT_S8,
61 AFMT_STEREO | AFMT_S8,
62 AFMT_S16_LE,
63 AFMT_STEREO | AFMT_S16_LE,
64 AFMT_U16_LE,

--- 12 unchanged lines hidden (view full) ---

77 AFMT_STEREO | AFMT_S16_LE,
78 AFMT_U16_LE,
79 AFMT_STEREO | AFMT_U16_LE,
80 0
81};
82
83static pcmchan_caps ess_reccaps = {5000, 49000, ess_rfmt, 0};
84
85static pcm_channel ess_chantemplate = {
86 esschan_init,
87 NULL, /* setdir */
88 esschan_setformat,
89 esschan_setspeed,
90 esschan_setblocksize,
91 esschan_trigger,
92 esschan_getptr,
93 esschan_getcaps,
94 NULL, /* free */
95 NULL, /* nop1 */
96 NULL, /* nop2 */
97 NULL, /* nop3 */
98 NULL, /* nop4 */
99 NULL, /* nop5 */
100 NULL, /* nop6 */
101 NULL, /* nop7 */
102};
103
104struct ess_info;
105
106struct ess_chinfo {
107 struct ess_info *parent;
108 pcm_channel *channel;
109 snd_dbuf *buffer;
110 int dir, hwch, stopping;
111 u_int32_t fmt, spd;
112};
113
114struct ess_info {
115 struct resource *io_base; /* I/O address for the board */
116 struct resource *irq;
117 struct resource *drq1;
118 struct resource *drq2;

--- 18 unchanged lines hidden (view full) ---

137static int ess_write(struct ess_info *sc, u_char reg, int val);
138static int ess_read(struct ess_info *sc, u_char reg);
139
140static void ess_intr(void *arg);
141static int ess_setupch(struct ess_info *sc, int ch, int dir, int spd, u_int32_t fmt, int len);
142static int ess_start(struct ess_chinfo *ch);
143static int ess_stop(struct ess_chinfo *ch);
144
145static int essmix_init(snd_mixer *m);
146static int essmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right);
147static int essmix_setrecsrc(snd_mixer *m, u_int32_t src);
148
149static snd_mixer ess_mixer = {
150 "ESS mixer",
151 essmix_init,
152 NULL,
153 NULL,
154 essmix_set,
155 essmix_setrecsrc,
156};
157
158static devclass_t pcm_devclass;
159
160/*
161 * Common code for the midi and pcm functions
162 *
163 * ess_cmd write a single byte to the CMD port.
164 * ess_cmd1 write a CMD + 1 byte arg
165 * ess_cmd2 write a CMD + 2 byte arg

--- 206 unchanged lines hidden (view full) ---

372 isa_dma_acquire(rman_get_start(sc->drq2));
373 isa_dmainit(rman_get_start(sc->drq2), ESS_BUFFSIZE);
374 }
375
376 return 0;
377 } else return ENXIO;
378}
379
380static int
381ess_doattach(device_t dev, struct ess_info *sc)
382{
383 char status[SND_STATUSLEN], buf[64];
384 int ver;
385
386 if (ess_alloc_resources(sc, dev))
387 goto no;
388 if (ess_reset_dsp(sc))
389 goto no;
390 mixer_init(dev, &ess_mixer, sc);
391
392 sc->duplex = 0;
393 sc->newspeed = 0;
394 ver = (ess_getmixer(sc, 0x40) << 8) | ess_rd(sc, SB_MIX_DATA);
395 snprintf(buf, sizeof buf, "ESS %x DSP", ver);
396 device_set_desc_copy(dev, buf);
397 if (bootverbose)
398 device_printf(dev, "ESS%x detected", ver);
399
400 switch (ver) {
401 case 0x1869:
402 case 0x1879:
403#ifdef ESS18XX_DUPLEX
404 sc->duplex = sc->drq2? 1 : 0;
405#endif
406#ifdef ESS18XX_NEWSPEED
407 sc->newspeed = 1;
408#endif
409 break;
410 }
411 if (bootverbose)
412 printf("%s%s\n", sc->duplex? ", duplex" : "",
413 sc->newspeed? ", newspeed" : "");
414
415 if (sc->newspeed)
416 ess_setmixer(sc, 0x71, 0x22);
417
418 bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, ess_intr, sc, &sc->ih);
419 if (!sc->duplex)
420 pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX);
421
422 if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
423 /*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
424 /*highaddr*/BUS_SPACE_MAXADDR,
425 /*filter*/NULL, /*filterarg*/NULL,
426 /*maxsize*/ESS_BUFFSIZE, /*nsegments*/1,
427 /*maxsegz*/0x3ffff,
428 /*flags*/0, &sc->parent_dmat) != 0) {
429 device_printf(dev, "unable to create dma tag\n");
430 goto no;
431 }
432
433 snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld",
434 rman_get_start(sc->io_base), rman_get_start(sc->irq),
435 rman_get_start(sc->drq1));
436 if (sc->drq2)
437 snprintf(status + strlen(status), SND_STATUSLEN - strlen(status),
438 ":%ld", rman_get_start(sc->drq2));
439
440 if (pcm_register(dev, sc, 1, 1))
441 goto no;
442 pcm_addchan(dev, PCMDIR_REC, &ess_chantemplate, sc);
443 pcm_addchan(dev, PCMDIR_PLAY, &ess_chantemplate, sc);
444 pcm_setstatus(dev, status);
445
446 return 0;
447
448no:
449 ess_release_resources(sc, dev);
450 return ENXIO;
451}
452
453static int
454ess_detach(device_t dev)
455{
456 int r;
457 struct ess_info *sc;
458
459 r = pcm_unregister(dev);
460 if (r)
461 return r;
462
463 sc = pcm_getdevinfo(dev);
464 ess_release_resources(sc, dev);
465 return 0;
466}
467
468static void
469ess_intr(void *arg)
470{
471 struct ess_info *sc = (struct ess_info *)arg;
472 int src, pirq, rirq;
473
474 src = 0;
475 if (ess_getmixer(sc, 0x7a) & 0x80)
476 src |= 2;
477 if (ess_rd(sc, 0x0c) & 0x01)
478 src |= 1;
479
480 pirq = (src & sc->pch.hwch)? 1 : 0;
481 rirq = (src & sc->rch.hwch)? 1 : 0;
482
483 if (pirq) {
484 if (sc->pch.stopping) {
485 buf_isadma(sc->pch.buffer, PCMTRIG_STOP);
486 sc->pch.stopping = 0;
487 if (sc->pch.hwch == 1)
488 ess_write(sc, 0xb8, ess_read(sc, 0xb8) & ~0x01);
489 else
490 ess_setmixer(sc, 0x78, ess_getmixer(sc, 0x78) & ~0x03);
491 }
492 chn_intr(sc->pch.channel);
493 }
494
495 if (rirq) {
496 if (sc->rch.stopping) {
497 buf_isadma(sc->rch.buffer, PCMTRIG_STOP);
498 sc->rch.stopping = 0;
499 /* XXX: will this stop audio2? */
500 ess_write(sc, 0xb8, ess_read(sc, 0xb8) & ~0x01);
501 }
502 chn_intr(sc->rch.channel);
503 }
504

--- 147 unchanged lines hidden (view full) ---

652 ess_write(sc, 0xb8, ess_read(sc, 0xb8) & ~0x04);
653 else
654 ess_setmixer(sc, 0x78, ess_getmixer(sc, 0x78) & ~0x10);
655 if (play)
656 ess_cmd(sc, DSP_CMD_SPKOFF);
657 return 0;
658}
659
660/* channel interface for ESS18xx */
661static void *
662esschan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
663{
664 struct ess_info *sc = devinfo;
665 struct ess_chinfo *ch = (dir == PCMDIR_PLAY)? &sc->pch : &sc->rch;
666
667 ch->parent = sc;
668 ch->channel = c;
669 ch->buffer = b;
670 ch->buffer->bufsize = ESS_BUFFSIZE;
671 if (chn_allocbuf(ch->buffer, sc->parent_dmat) == -1)
672 return NULL;
673 ch->dir = dir;
674 ch->hwch = 1;
675 if ((dir == PCMDIR_PLAY) && (sc->duplex))
676 ch->hwch = 2;
677 ch->buffer->chan = rman_get_start((ch->hwch == 1)? sc->drq1 : sc->drq2);
678 return ch;
679}
680
681static int
682esschan_setformat(void *data, u_int32_t format)
683{
684 struct ess_chinfo *ch = data;
685
686 ch->fmt = format;
687 return 0;
688}
689
690static int
691esschan_setspeed(void *data, u_int32_t speed)
692{
693 struct ess_chinfo *ch = data;
694 struct ess_info *sc = ch->parent;
695
696 ch->spd = speed;
697 if (sc->newspeed)
698 ess_calcspeed9(&ch->spd);
699 else
700 ess_calcspeed8(&ch->spd);
701 return ch->spd;
702}
703
704static int
705esschan_setblocksize(void *data, u_int32_t blocksize)
706{
707 return blocksize;
708}
709
710static int
711esschan_trigger(void *data, int go)
712{
713 struct ess_chinfo *ch = data;
714
715 if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
716 return 0;
717
718 switch (go) {
719 case PCMTRIG_START:
720 buf_isadma(ch->buffer, go);
721 ess_start(ch);
722 break;
723
724 case PCMTRIG_STOP:
725 case PCMTRIG_ABORT:
726 default:
727 ess_stop(ch);
728 break;
729 }
730 return 0;
731}
732
733static int
734esschan_getptr(void *data)
735{
736 struct ess_chinfo *ch = data;
737
738 return buf_isadmaptr(ch->buffer);
739}
740
741static pcmchan_caps *
742esschan_getcaps(void *data)
743{
744 struct ess_chinfo *ch = data;
745
746 return (ch->dir == PCMDIR_PLAY)? &ess_playcaps : &ess_reccaps;
747}
748
749/************************************************************/
750
751static int
752essmix_init(snd_mixer *m)
753{
754 struct ess_info *sc = mix_getdevinfo(m);
755
756 mix_setrecdevs(m, SOUND_MASK_CD | SOUND_MASK_MIC | SOUND_MASK_LINE |

--- 94 unchanged lines hidden (view full) ---

851 break;
852 }
853
854 ess_setmixer(sc, 0x1c, recdev);
855
856 return src;
857}
858
859static int
860ess_probe(device_t dev)
861{
862 uintptr_t func, ver, r, f;
863
864 /* The parent device has already been probed. */
865 r = BUS_READ_IVAR(device_get_parent(dev), dev, 0, &func);
866 if (func != SCF_PCM)

--- 8 unchanged lines hidden (view full) ---

875
876 return 0;
877}
878
879static int
880ess_attach(device_t dev)
881{
882 struct ess_info *sc;
883
884 sc = (struct ess_info *)malloc(sizeof *sc, M_DEVBUF, M_NOWAIT);
885 if (!sc)
886 return ENXIO;
887 bzero(sc, sizeof *sc);
888
889 return ess_doattach(dev, sc);
890}
891
892static device_method_t ess_methods[] = {
893 /* Device interface */
894 DEVMETHOD(device_probe, ess_probe),
895 DEVMETHOD(device_attach, ess_attach),
896 DEVMETHOD(device_detach, ess_detach),
897
898 { 0, 0 }
899};
900
901static driver_t ess_driver = {
902 "pcm",
903 ess_methods,
904 sizeof(snddev_info),
905};
906
907DRIVER_MODULE(snd_ess, sbc, ess_driver, pcm_devclass, 0, 0);
908MODULE_DEPEND(snd_ess, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER);
909MODULE_VERSION(snd_ess, 1);
910
911
912static devclass_t esscontrol_devclass;
913
914static struct isa_pnp_id essc_ids[] = {
915 {0x06007316, "ESS Control"},
916 {0}
917};
918

--- 55 unchanged lines hidden ---