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