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
|