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