Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / dev / sound / isa / ess.c
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.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
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
32 #include <dev/sound/pcm/sound.h>
33
34 #include  <dev/sound/isa/sb.h>
35 #include  <dev/sound/chip.h>
36
37 #include "mixer_if.h"
38
39 SND_DECLARE_FILE("$FreeBSD: src/sys/dev/sound/isa/ess.c,v 1.3.2.8 2002/12/24 21:17:41 semenu Exp $");
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
50 static 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,
58         AFMT_STEREO | AFMT_U16_LE,
59         0
60 };
61
62 static struct pcmchan_caps ess_playcaps = {5000, 49000, ess_pfmt, 0};
63
64 static u_int32_t ess_rfmt[] = {
65         AFMT_U8,
66         AFMT_STEREO | AFMT_U8,
67         AFMT_S8,
68         AFMT_STEREO | AFMT_S8,
69         AFMT_S16_LE,
70         AFMT_STEREO | AFMT_S16_LE,
71         AFMT_U16_LE,
72         AFMT_STEREO | AFMT_U16_LE,
73         0
74 };
75
76 static struct pcmchan_caps ess_reccaps = {5000, 49000, ess_rfmt, 0};
77
78 struct ess_info;
79
80 struct ess_chinfo {
81         struct ess_info *parent;
82         struct pcm_channel *channel;
83         struct snd_dbuf *buffer;
84         int dir, hwch, stopping, run;
85         u_int32_t fmt, spd, blksz;
86 };
87
88 struct ess_info {
89         device_t parent_dev;
90         struct resource *io_base;       /* I/O address for the board */
91         struct resource *irq;
92         struct resource *drq1;
93         struct resource *drq2;
94         void *ih;
95         bus_dma_tag_t parent_dmat;
96
97         unsigned int bufsize;
98         int type, duplex:1, newspeed:1;
99         u_long bd_flags;       /* board-specific flags */
100         struct ess_chinfo pch, rch;
101 };
102
103 #if 0
104 static int ess_rd(struct ess_info *sc, int reg);
105 static void ess_wr(struct ess_info *sc, int reg, u_int8_t val);
106 static int ess_dspready(struct ess_info *sc);
107 static int ess_cmd(struct ess_info *sc, u_char val);
108 static int ess_cmd1(struct ess_info *sc, u_char cmd, int val);
109 static int ess_get_byte(struct ess_info *sc);
110 static void ess_setmixer(struct ess_info *sc, u_int port, u_int value);
111 static int ess_getmixer(struct ess_info *sc, u_int port);
112 static int ess_reset_dsp(struct ess_info *sc);
113
114 static int ess_write(struct ess_info *sc, u_char reg, int val);
115 static int ess_read(struct ess_info *sc, u_char reg);
116
117 static void ess_intr(void *arg);
118 static int ess_setupch(struct ess_info *sc, int ch, int dir, int spd, u_int32_t fmt, int len);
119 static int ess_start(struct ess_chinfo *ch);
120 static int ess_stop(struct ess_chinfo *ch);
121 #endif
122
123 /*
124  * Common code for the midi and pcm functions
125  *
126  * ess_cmd write a single byte to the CMD port.
127  * ess_cmd1 write a CMD + 1 byte arg
128  * ess_cmd2 write a CMD + 2 byte arg
129  * ess_get_byte returns a single byte from the DSP data port
130  *
131  * ess_write is actually ess_cmd1
132  * ess_read access ext. regs via ess_cmd(0xc0, reg) followed by ess_get_byte
133  */
134
135 static void
136 ess_lock(struct ess_info *sc) {
137
138         sbc_lock(device_get_softc(sc->parent_dev));
139 }
140
141 static void
142 ess_unlock(struct ess_info *sc) {
143
144         sbc_unlock(device_get_softc(sc->parent_dev));
145 }
146
147 static int
148 port_rd(struct resource *port, int off)
149 {
150         return bus_space_read_1(rman_get_bustag(port),
151                                 rman_get_bushandle(port),
152                                 off);
153 }
154
155 static void
156 port_wr(struct resource *port, int off, u_int8_t data)
157 {
158         bus_space_write_1(rman_get_bustag(port),
159                           rman_get_bushandle(port),
160                           off, data);
161 }
162
163 static int
164 ess_rd(struct ess_info *sc, int reg)
165 {
166         return port_rd(sc->io_base, reg);
167 }
168
169 static void
170 ess_wr(struct ess_info *sc, int reg, u_int8_t val)
171 {
172         port_wr(sc->io_base, reg, val);
173 }
174
175 static int
176 ess_dspready(struct ess_info *sc)
177 {
178         return ((ess_rd(sc, SBDSP_STATUS) & 0x80) == 0);
179 }
180
181 static int
182 ess_dspwr(struct ess_info *sc, u_char val)
183 {
184         int  i;
185
186         for (i = 0; i < 1000; i++) {
187                 if (ess_dspready(sc)) {
188                         ess_wr(sc, SBDSP_CMD, val);
189                         return 1;
190                 }
191                 if (i > 10) DELAY((i > 100)? 1000 : 10);
192         }
193         printf("ess_dspwr(0x%02x) timed out.\n", val);
194         return 0;
195 }
196
197 static int
198 ess_cmd(struct ess_info *sc, u_char val)
199 {
200 #if 0
201         printf("ess_cmd: %x\n", val);
202 #endif
203         return ess_dspwr(sc, val);
204 }
205
206 static int
207 ess_cmd1(struct ess_info *sc, u_char cmd, int val)
208 {
209 #if 0
210         printf("ess_cmd1: %x, %x\n", cmd, val);
211 #endif
212         if (ess_dspwr(sc, cmd)) {
213                 return ess_dspwr(sc, val & 0xff);
214         } else return 0;
215 }
216
217 static void
218 ess_setmixer(struct ess_info *sc, u_int port, u_int value)
219 {
220         DEB(printf("ess_setmixer: reg=%x, val=%x\n", port, value);)
221         ess_wr(sc, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
222         DELAY(10);
223         ess_wr(sc, SB_MIX_DATA, (u_char) (value & 0xff));
224         DELAY(10);
225 }
226
227 static int
228 ess_getmixer(struct ess_info *sc, u_int port)
229 {
230         int val;
231         ess_wr(sc, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
232         DELAY(10);
233         val = ess_rd(sc, SB_MIX_DATA);
234         DELAY(10);
235
236         return val;
237 }
238
239 static int
240 ess_get_byte(struct ess_info *sc)
241 {
242         int i;
243
244         for (i = 1000; i > 0; i--) {
245                 if (ess_rd(sc, DSP_DATA_AVAIL) & 0x80)
246                         return ess_rd(sc, DSP_READ);
247                 else
248                         DELAY(20);
249         }
250         return -1;
251 }
252
253 static int
254 ess_write(struct ess_info *sc, u_char reg, int val)
255 {
256         return ess_cmd1(sc, reg, val);
257 }
258
259 static int
260 ess_read(struct ess_info *sc, u_char reg)
261 {
262         return (ess_cmd(sc, 0xc0) && ess_cmd(sc, reg))? ess_get_byte(sc) : -1;
263 }
264
265 static int
266 ess_reset_dsp(struct ess_info *sc)
267 {
268         ess_wr(sc, SBDSP_RST, 3);
269         DELAY(100);
270         ess_wr(sc, SBDSP_RST, 0);
271         if (ess_get_byte(sc) != 0xAA) {
272                 DEB(printf("ess_reset_dsp 0x%lx failed\n",
273                            rman_get_start(sc->io_base)));
274                 return ENXIO;   /* Sorry */
275         }
276         ess_cmd(sc, 0xc6);
277         return 0;
278 }
279
280 static void
281 ess_release_resources(struct ess_info *sc, device_t dev)
282 {
283         if (sc->irq) {
284                 if (sc->ih)
285                         bus_teardown_intr(dev, sc->irq, sc->ih);
286                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
287                 sc->irq = 0;
288         }
289         if (sc->drq1) {
290                 isa_dma_release(rman_get_start(sc->drq1));
291                 bus_release_resource(dev, SYS_RES_DRQ, 0, sc->drq1);
292                 sc->drq1 = 0;
293         }
294         if (sc->drq2) {
295                 isa_dma_release(rman_get_start(sc->drq2));
296                 bus_release_resource(dev, SYS_RES_DRQ, 1, sc->drq2);
297                 sc->drq2 = 0;
298         }
299         if (sc->io_base) {
300                 bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->io_base);
301                 sc->io_base = 0;
302         }
303         if (sc->parent_dmat) {
304                 bus_dma_tag_destroy(sc->parent_dmat);
305                 sc->parent_dmat = 0;
306         }
307         free(sc, M_DEVBUF);
308 }
309
310 static int
311 ess_alloc_resources(struct ess_info *sc, device_t dev)
312 {
313         int rid;
314
315         rid = 0;
316         if (!sc->io_base)
317                 sc->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT,
318                                                  &rid, 0, ~0, 1,
319                                                  RF_ACTIVE);
320         rid = 0;
321         if (!sc->irq)
322                 sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ,
323                                              &rid, 0, ~0, 1,
324                                              RF_ACTIVE);
325         rid = 0;
326         if (!sc->drq1)
327                 sc->drq1 = bus_alloc_resource(dev, SYS_RES_DRQ,
328                                               &rid, 0, ~0, 1,
329                                               RF_ACTIVE);
330         rid = 1;
331         if (!sc->drq2)
332                 sc->drq2 = bus_alloc_resource(dev, SYS_RES_DRQ,
333                                               &rid, 0, ~0, 1,
334                                               RF_ACTIVE);
335
336         if (sc->io_base && sc->drq1 && sc->irq) {
337                 isa_dma_acquire(rman_get_start(sc->drq1));
338                 isa_dmainit(rman_get_start(sc->drq1), sc->bufsize);
339
340                 if (sc->drq2) {
341                         isa_dma_acquire(rman_get_start(sc->drq2));
342                         isa_dmainit(rman_get_start(sc->drq2), sc->bufsize);
343                 }
344
345                 return 0;
346         } else return ENXIO;
347 }
348
349 static void
350 ess_intr(void *arg)
351 {
352         struct ess_info *sc = (struct ess_info *)arg;
353         int src, pirq, rirq;
354
355         ess_lock(sc);
356         src = 0;
357         if (ess_getmixer(sc, 0x7a) & 0x80)
358                 src |= 2;
359         if (ess_rd(sc, 0x0c) & 0x01)
360                 src |= 1;
361
362         pirq = (src & sc->pch.hwch)? 1 : 0;
363         rirq = (src & sc->rch.hwch)? 1 : 0;
364
365         if (pirq) {
366                 if (sc->pch.run)
367                         chn_intr(sc->pch.channel);
368                 if (sc->pch.stopping) {
369                         sc->pch.run = 0;
370                         sndbuf_isadma(sc->pch.buffer, PCMTRIG_STOP);
371                         sc->pch.stopping = 0;
372                         if (sc->pch.hwch == 1)
373                                 ess_write(sc, 0xb8, ess_read(sc, 0xb8) & ~0x01);
374                         else
375                                 ess_setmixer(sc, 0x78, ess_getmixer(sc, 0x78) & ~0x03);
376                 }
377         }
378
379         if (rirq) {
380                 if (sc->rch.run)
381                         chn_intr(sc->rch.channel);
382                 if (sc->rch.stopping) {
383                         sc->rch.run = 0;
384                         sndbuf_isadma(sc->rch.buffer, PCMTRIG_STOP);
385                         sc->rch.stopping = 0;
386                         /* XXX: will this stop audio2? */
387                         ess_write(sc, 0xb8, ess_read(sc, 0xb8) & ~0x01);
388                 }
389         }
390
391         if (src & 2)
392                 ess_setmixer(sc, 0x7a, ess_getmixer(sc, 0x7a) & ~0x80);
393         if (src & 1)
394                 ess_rd(sc, DSP_DATA_AVAIL);
395         ess_unlock(sc);
396 }
397
398 /* utility functions for ESS */
399 static u_int8_t
400 ess_calcspeed8(int *spd)
401 {
402         int speed = *spd;
403         u_int32_t t;
404
405         if (speed > 22000) {
406                 t = (795500 + speed / 2) / speed;
407                 speed = (795500 + t / 2) / t;
408                 t = (256 - t) | 0x80;
409         } else {
410                 t = (397700 + speed / 2) / speed;
411                 speed = (397700 + t / 2) / t;
412                 t = 128 - t;
413         }
414         *spd = speed;
415         return t & 0x000000ff;
416 }
417
418 static u_int8_t
419 ess_calcspeed9(int *spd)
420 {
421         int speed, s0, s1, use0;
422         u_int8_t t0, t1;
423
424         /* rate = source / (256 - divisor) */
425         /* divisor = 256 - (source / rate) */
426         speed = *spd;
427         t0 = 128 - (793800 / speed);
428         s0 = 793800 / (128 - t0);
429
430         t1 = 128 - (768000 / speed);
431         s1 = 768000 / (128 - t1);
432         t1 |= 0x80;
433
434         use0 = (ABS(speed - s0) < ABS(speed - s1))? 1 : 0;
435
436         *spd = use0? s0 : s1;
437         return use0? t0 : t1;
438 }
439
440 static u_int8_t
441 ess_calcfilter(int spd)
442 {
443         int cutoff;
444
445         /* cutoff = 7160000 / (256 - divisor) */
446         /* divisor = 256 - (7160000 / cutoff) */
447         cutoff = (spd * 9 * 82) / 20;
448         return (256 - (7160000 / cutoff));
449 }
450
451 static int
452 ess_setupch(struct ess_info *sc, int ch, int dir, int spd, u_int32_t fmt, int len)
453 {
454         int play = (dir == PCMDIR_PLAY)? 1 : 0;
455         int b16 = (fmt & AFMT_16BIT)? 1 : 0;
456         int stereo = (fmt & AFMT_STEREO)? 1 : 0;
457         int unsign = (fmt == AFMT_U8 || fmt == AFMT_U16_LE)? 1 : 0;
458         u_int8_t spdval, fmtval;
459
460
461         spdval = (sc->newspeed)? ess_calcspeed9(&spd) : ess_calcspeed8(&spd);
462         len = -len;
463
464         if (ch == 1) {
465                 KASSERT((dir == PCMDIR_PLAY) || (dir == PCMDIR_REC), ("ess_setupch: dir1 bad"));
466                 /* transfer length low */
467                 ess_write(sc, 0xa4, len & 0x00ff);
468                 /* transfer length high */
469                 ess_write(sc, 0xa5, (len & 0xff00) >> 8);
470                 /* autoinit, dma dir */
471                 ess_write(sc, 0xb8, 0x04 | (play? 0x00 : 0x0a));
472                 /* mono/stereo */
473                 ess_write(sc, 0xa8, (ess_read(sc, 0xa8) & ~0x03) | (stereo? 0x01 : 0x02));
474                 /* demand mode, 4 bytes/xfer */
475                 ess_write(sc, 0xb9, 0x02);
476                 /* sample rate */
477                 ess_write(sc, 0xa1, spdval);
478                 /* filter cutoff */
479                 ess_write(sc, 0xa2, ess_calcfilter(spd));
480                 /* setup dac/adc */
481                 if (play)
482                         ess_write(sc, 0xb6, unsign? 0x80 : 0x00);
483                 /* mono, b16: signed, load signal */
484                 ess_write(sc, 0xb7, 0x51 | (unsign? 0x00 : 0x20));
485                 /* setup fifo */
486                 ess_write(sc, 0xb7, 0x90 | (unsign? 0x00 : 0x20) |
487                                            (b16? 0x04 : 0x00) |
488                                            (stereo? 0x08 : 0x40));
489                 /* irq control */
490                 ess_write(sc, 0xb1, (ess_read(sc, 0xb1) & 0x0f) | 0x50);
491                 /* drq control */
492                 ess_write(sc, 0xb2, (ess_read(sc, 0xb2) & 0x0f) | 0x50);
493         } else if (ch == 2) {
494                 KASSERT(dir == PCMDIR_PLAY, ("ess_setupch: dir2 bad"));
495                 /* transfer length low */
496                 ess_setmixer(sc, 0x74, len & 0x00ff);
497                 /* transfer length high */
498                 ess_setmixer(sc, 0x76, (len & 0xff00) >> 8);
499                 /* autoinit, 4 bytes/req */
500                 ess_setmixer(sc, 0x78, 0x90);
501                 fmtval = b16 | (stereo << 1) | (unsign << 2);
502                 /* enable irq, set format */
503                 ess_setmixer(sc, 0x7a, 0x40 | fmtval);
504                 if (sc->newspeed) {
505                         /* sample rate */
506                         ess_setmixer(sc, 0x70, spdval);
507                         /* filter cutoff */
508                         ess_setmixer(sc, 0x72, ess_calcfilter(spd));
509                 }
510         }
511
512         return 0;
513 }
514 static int
515 ess_start(struct ess_chinfo *ch)
516 {
517         struct ess_info *sc = ch->parent;
518         int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
519
520         ess_lock(sc);
521         ess_setupch(sc, ch->hwch, ch->dir, ch->spd, ch->fmt, ch->blksz);
522         ch->stopping = 0;
523         if (ch->hwch == 1)
524                 ess_write(sc, 0xb8, ess_read(sc, 0xb8) | 0x01);
525         else
526                 ess_setmixer(sc, 0x78, ess_getmixer(sc, 0x78) | 0x03);
527         if (play)
528                 ess_cmd(sc, DSP_CMD_SPKON);
529         ess_unlock(sc);
530         return 0;
531 }
532
533 static int
534 ess_stop(struct ess_chinfo *ch)
535 {
536         struct ess_info *sc = ch->parent;
537         int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
538
539         ess_lock(sc);
540         ch->stopping = 1;
541         if (ch->hwch == 1)
542                 ess_write(sc, 0xb8, ess_read(sc, 0xb8) & ~0x04);
543         else
544                 ess_setmixer(sc, 0x78, ess_getmixer(sc, 0x78) & ~0x10);
545         if (play)
546                 ess_cmd(sc, DSP_CMD_SPKOFF);
547         ess_unlock(sc);
548         return 0;
549 }
550
551 /* -------------------------------------------------------------------- */
552 /* channel interface for ESS18xx */
553 static void *
554 esschan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
555 {
556         struct ess_info *sc = devinfo;
557         struct ess_chinfo *ch = (dir == PCMDIR_PLAY)? &sc->pch : &sc->rch;
558
559         ch->parent = sc;
560         ch->channel = c;
561         ch->buffer = b;
562         if (sndbuf_alloc(ch->buffer, sc->parent_dmat, sc->bufsize) == -1)
563                 return NULL;
564         ch->dir = dir;
565         ch->hwch = 1;
566         if ((dir == PCMDIR_PLAY) && (sc->duplex))
567                 ch->hwch = 2;
568         sndbuf_isadmasetup(ch->buffer, (ch->hwch == 1)? sc->drq1 : sc->drq2);
569         return ch;
570 }
571
572 static int
573 esschan_setformat(kobj_t obj, void *data, u_int32_t format)
574 {
575         struct ess_chinfo *ch = data;
576
577         ch->fmt = format;
578         return 0;
579 }
580
581 static int
582 esschan_setspeed(kobj_t obj, void *data, u_int32_t speed)
583 {
584         struct ess_chinfo *ch = data;
585         struct ess_info *sc = ch->parent;
586
587         ch->spd = speed;
588         if (sc->newspeed)
589                 ess_calcspeed9(&ch->spd);
590         else
591                 ess_calcspeed8(&ch->spd);
592         return ch->spd;
593 }
594
595 static int
596 esschan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
597 {
598         struct ess_chinfo *ch = data;
599
600         ch->blksz = blocksize;
601         return ch->blksz;
602 }
603
604 static int
605 esschan_trigger(kobj_t obj, void *data, int go)
606 {
607         struct ess_chinfo *ch = data;
608
609         if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
610                 return 0;
611
612         switch (go) {
613         case PCMTRIG_START:
614                 ch->run = 1;
615                 sndbuf_isadma(ch->buffer, go);
616                 ess_start(ch);
617                 break;
618
619         case PCMTRIG_STOP:
620         case PCMTRIG_ABORT:
621         default:
622                 ess_stop(ch);
623                 break;
624         }
625         return 0;
626 }
627
628 static int
629 esschan_getptr(kobj_t obj, void *data)
630 {
631         struct ess_chinfo *ch = data;
632
633         return sndbuf_isadmaptr(ch->buffer);
634 }
635
636 static struct pcmchan_caps *
637 esschan_getcaps(kobj_t obj, void *data)
638 {
639         struct ess_chinfo *ch = data;
640
641         return (ch->dir == PCMDIR_PLAY)? &ess_playcaps : &ess_reccaps;
642 }
643
644 static kobj_method_t esschan_methods[] = {
645         KOBJMETHOD(channel_init,                esschan_init),
646         KOBJMETHOD(channel_setformat,           esschan_setformat),
647         KOBJMETHOD(channel_setspeed,            esschan_setspeed),
648         KOBJMETHOD(channel_setblocksize,        esschan_setblocksize),
649         KOBJMETHOD(channel_trigger,             esschan_trigger),
650         KOBJMETHOD(channel_getptr,              esschan_getptr),
651         KOBJMETHOD(channel_getcaps,             esschan_getcaps),
652         { 0, 0 }
653 };
654 CHANNEL_DECLARE(esschan);
655
656 /************************************************************/
657
658 static int
659 essmix_init(struct snd_mixer *m)
660 {
661         struct ess_info *sc = mix_getdevinfo(m);
662
663         mix_setrecdevs(m, SOUND_MASK_CD | SOUND_MASK_MIC | SOUND_MASK_LINE |
664                           SOUND_MASK_IMIX);
665
666         mix_setdevs(m, SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE |
667                        SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_VOLUME |
668                        SOUND_MASK_LINE1 | SOUND_MASK_SPEAKER);
669
670         ess_setmixer(sc, 0, 0); /* reset */
671
672         return 0;
673 }
674
675 static int
676 essmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
677 {
678         struct ess_info *sc = mix_getdevinfo(m);
679         int preg = 0, rreg = 0, l, r;
680
681         l = (left * 15) / 100;
682         r = (right * 15) / 100;
683         switch (dev) {
684         case SOUND_MIXER_SYNTH:
685                 preg = 0x36;
686                 rreg = 0x6b;
687                 break;
688
689         case SOUND_MIXER_PCM:
690                 preg = 0x14;
691                 rreg = 0x7c;
692                 break;
693
694         case SOUND_MIXER_LINE:
695                 preg = 0x3e;
696                 rreg = 0x6e;
697                 break;
698
699         case SOUND_MIXER_MIC:
700                 preg = 0x1a;
701                 rreg = 0x68;
702                 break;
703
704         case SOUND_MIXER_LINE1:
705                 preg = 0x3a;
706                 rreg = 0x6c;
707                 break;
708
709         case SOUND_MIXER_CD:
710                 preg = 0x38;
711                 rreg = 0x6a;
712                 break;
713
714         case SOUND_MIXER_SPEAKER:
715                 preg = 0x3c;
716                 break;
717
718         case SOUND_MIXER_VOLUME:
719                 l = left? (left * 63) / 100 : 64;
720                 r = right? (right * 63) / 100 : 64;
721                 ess_setmixer(sc, 0x60, l);
722                 ess_setmixer(sc, 0x62, r);
723                 left = (l == 64)? 0 : (l * 100) / 63;
724                 right = (r == 64)? 0 : (r * 100) / 63;
725                 return left | (right << 8);
726         }
727
728         if (preg)
729                 ess_setmixer(sc, preg, (l << 4) | r);
730         if (rreg)
731                 ess_setmixer(sc, rreg, (l << 4) | r);
732
733         left = (l * 100) / 15;
734         right = (r * 100) / 15;
735
736         return left | (right << 8);
737 }
738
739 static int
740 essmix_setrecsrc(struct snd_mixer *m, u_int32_t src)
741 {
742         struct ess_info *sc = mix_getdevinfo(m);
743         u_char recdev;
744
745         switch (src) {
746         case SOUND_MASK_CD:
747                 recdev = 0x02;
748                 break;
749
750         case SOUND_MASK_LINE:
751                 recdev = 0x06;
752                 break;
753
754         case SOUND_MASK_IMIX:
755                 recdev = 0x05;
756                 break;
757
758         case SOUND_MASK_MIC:
759         default:
760                 recdev = 0x00;
761                 src = SOUND_MASK_MIC;
762                 break;
763         }
764
765         ess_setmixer(sc, 0x1c, recdev);
766
767         return src;
768 }
769
770 static kobj_method_t essmixer_methods[] = {
771         KOBJMETHOD(mixer_init,          essmix_init),
772         KOBJMETHOD(mixer_set,           essmix_set),
773         KOBJMETHOD(mixer_setrecsrc,     essmix_setrecsrc),
774         { 0, 0 }
775 };
776 MIXER_DECLARE(essmixer);
777
778 /************************************************************/
779
780 static int
781 ess_probe(device_t dev)
782 {
783         uintptr_t func, ver, r, f;
784
785         /* The parent device has already been probed. */
786         r = BUS_READ_IVAR(device_get_parent(dev), dev, 0, &func);
787         if (func != SCF_PCM)
788                 return (ENXIO);
789
790         r = BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver);
791         f = (ver & 0xffff0000) >> 16;
792         if (!(f & BD_F_ESS))
793                 return (ENXIO);
794
795         device_set_desc(dev, "ESS 18xx DSP");
796
797         return 0;
798 }
799
800 static int
801 ess_attach(device_t dev)
802 {
803         struct ess_info *sc;
804         char status[SND_STATUSLEN], buf[64];
805         int ver;
806
807         sc = (struct ess_info *)malloc(sizeof *sc, M_DEVBUF, M_NOWAIT | M_ZERO);
808         if (!sc)
809                 return ENXIO;
810
811         sc->parent_dev = device_get_parent(dev);
812         sc->bufsize = pcm_getbuffersize(dev, 4096, ESS_BUFFSIZE, 65536);
813         if (ess_alloc_resources(sc, dev))
814                 goto no;
815         if (ess_reset_dsp(sc))
816                 goto no;
817         if (mixer_init(dev, &essmixer_class, sc))
818                 goto no;
819
820         sc->duplex = 0;
821         sc->newspeed = 0;
822         ver = (ess_getmixer(sc, 0x40) << 8) | ess_rd(sc, SB_MIX_DATA);
823         snprintf(buf, sizeof buf, "ESS %x DSP", ver);
824         device_set_desc_copy(dev, buf);
825         if (bootverbose)
826                 device_printf(dev, "ESS%x detected", ver);
827
828         switch (ver) {
829         case 0x1869:
830         case 0x1879:
831 #ifdef ESS18XX_DUPLEX
832                 sc->duplex = sc->drq2? 1 : 0;
833 #endif
834 #ifdef ESS18XX_NEWSPEED
835                 sc->newspeed = 1;
836 #endif
837                 break;
838         }
839         if (bootverbose)
840                 printf("%s%s\n", sc->duplex? ", duplex" : "",
841                                  sc->newspeed? ", newspeed" : "");
842
843         if (sc->newspeed)
844                 ess_setmixer(sc, 0x71, 0x22);
845
846         snd_setup_intr(dev, sc->irq, INTR_MPSAFE, ess_intr, sc, &sc->ih);
847         if (!sc->duplex)
848                 pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX);
849
850         if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
851                         /*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
852                         /*highaddr*/BUS_SPACE_MAXADDR,
853                         /*filter*/NULL, /*filterarg*/NULL,
854                         /*maxsize*/sc->bufsize, /*nsegments*/1,
855                         /*maxsegz*/0x3ffff,
856                         /*flags*/0, &sc->parent_dmat) != 0) {
857                 device_printf(dev, "unable to create dma tag\n");
858                 goto no;
859         }
860
861         if (sc->drq2)
862                 snprintf(buf, SND_STATUSLEN, ":%ld", rman_get_start(sc->drq2));
863         else
864                 buf[0] = '\0';
865
866         snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld%s bufsz %u",
867                 rman_get_start(sc->io_base), rman_get_start(sc->irq),
868                 rman_get_start(sc->drq1), buf, sc->bufsize);
869
870         if (pcm_register(dev, sc, 1, 1))
871                 goto no;
872         pcm_addchan(dev, PCMDIR_REC, &esschan_class, sc);
873         pcm_addchan(dev, PCMDIR_PLAY, &esschan_class, sc);
874         pcm_setstatus(dev, status);
875
876         return 0;
877
878 no:
879         ess_release_resources(sc, dev);
880         return ENXIO;
881 }
882
883 static int
884 ess_detach(device_t dev)
885 {
886         int r;
887         struct ess_info *sc;
888
889         r = pcm_unregister(dev);
890         if (r)
891                 return r;
892
893         sc = pcm_getdevinfo(dev);
894         ess_release_resources(sc, dev);
895         return 0;
896 }
897
898 static int
899 ess_resume(device_t dev)
900 {
901         struct ess_info *sc;
902
903         sc = pcm_getdevinfo(dev);
904
905         if (ess_reset_dsp(sc)) {
906                 device_printf(dev, "unable to reset DSP at resume\n");
907                 return ENXIO;
908         }
909
910         if (mixer_reinit(dev)) {
911                 device_printf(dev, "unable to reinitialize mixer at resume\n");
912                 return ENXIO;
913         }
914
915         return 0;
916 }
917
918 static device_method_t ess_methods[] = {
919         /* Device interface */
920         DEVMETHOD(device_probe,         ess_probe),
921         DEVMETHOD(device_attach,        ess_attach),
922         DEVMETHOD(device_detach,        ess_detach),
923         DEVMETHOD(device_resume,        ess_resume),
924
925         { 0, 0 }
926 };
927
928 static driver_t ess_driver = {
929         "pcm",
930         ess_methods,
931         PCM_SOFTC_SIZE,
932 };
933
934 DRIVER_MODULE(snd_ess, sbc, ess_driver, pcm_devclass, 0, 0);
935 MODULE_DEPEND(snd_ess, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER);
936 MODULE_DEPEND(snd_ess, snd_sbc, 1, 1, 1);
937 MODULE_VERSION(snd_ess, 1);
938
939 /************************************************************/
940
941 static devclass_t esscontrol_devclass;
942
943 static struct isa_pnp_id essc_ids[] = {
944         {0x06007316, "ESS Control"},
945         {0}
946 };
947
948 static int
949 esscontrol_probe(device_t dev)
950 {
951         int i;
952
953         i = ISA_PNP_PROBE(device_get_parent(dev), dev, essc_ids);
954         if (i == 0)
955                 device_quiet(dev);
956         return i;
957 }
958
959 static int
960 esscontrol_attach(device_t dev)
961 {
962 #ifdef notyet
963         struct resource *io;
964         int rid, i, x;
965
966         rid = 0;
967         io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, RF_ACTIVE);
968         x = 0;
969         for (i = 0; i < 0x100; i++) {
970                 port_wr(io, 0, i);
971                 x = port_rd(io, 1);
972                 if ((i & 0x0f) == 0)
973                         printf("%3.3x: ", i);
974                 printf("%2.2x ", x);
975                 if ((i & 0x0f) == 0x0f)
976                         printf("\n");
977         }
978         bus_release_resource(dev, SYS_RES_IOPORT, 0, io);
979         io = NULL;
980 #endif
981
982         return 0;
983 }
984
985 static int
986 esscontrol_detach(device_t dev)
987 {
988         return 0;
989 }
990
991 static device_method_t esscontrol_methods[] = {
992         /* Device interface */
993         DEVMETHOD(device_probe,         esscontrol_probe),
994         DEVMETHOD(device_attach,        esscontrol_attach),
995         DEVMETHOD(device_detach,        esscontrol_detach),
996
997         { 0, 0 }
998 };
999
1000 static driver_t esscontrol_driver = {
1001         "esscontrol",
1002         esscontrol_methods,
1003         1,
1004 };
1005
1006 DRIVER_MODULE(esscontrol, isa, esscontrol_driver, esscontrol_devclass, 0, 0);
1007