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