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