| 1 | /* |
| 2 | * Copyright (c) 2001 George Reid <greid@ukug.uk.freebsd.org> |
| 3 | * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> |
| 4 | * Copyright Luigi Rizzo, 1997,1998 |
| 5 | * Copyright by Hannu Savolainen 1994, 1995 |
| 6 | * All rights reserved. |
| 7 | * |
| 8 | * Redistribution and use in source and binary forms, with or without |
| 9 | * modification, are permitted provided that the following conditions |
| 10 | * are met: |
| 11 | * 1. Redistributions of source code must retain the above copyright |
| 12 | * notice, this list of conditions and the following disclaimer. |
| 13 | * 2. Redistributions in binary form must reproduce the above copyright |
| 14 | * notice, this list of conditions and the following disclaimer in the |
| 15 | * documentation and/or other materials provided with the distribution. |
| 16 | * |
| 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
| 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
| 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 27 | * SUCH DAMAGE. |
| 28 | */ |
| 29 | |
| 30 | #include <dev/sound/pcm/sound.h> |
| 31 | |
| 32 | SND_DECLARE_FILE("$FreeBSD: src/sys/dev/sound/isa/mss.c,v 1.48.2.11 2002/12/24 21:17:41 semenu Exp $"); |
| 33 | |
| 34 | /* board-specific include files */ |
| 35 | #include <dev/sound/isa/mss.h> |
| 36 | #include <dev/sound/isa/sb.h> |
| 37 | #include <dev/sound/chip.h> |
| 38 | |
| 39 | #include "mixer_if.h" |
| 40 | |
| 41 | #define MSS_DEFAULT_BUFSZ (4096) |
| 42 | #define abs(x) (((x) < 0) ? -(x) : (x)) |
| 43 | #define MSS_INDEXED_REGS 0x20 |
| 44 | #define OPL_INDEXED_REGS 0x19 |
| 45 | |
| 46 | struct mss_info; |
| 47 | |
| 48 | struct mss_chinfo { |
| 49 | struct mss_info *parent; |
| 50 | struct pcm_channel *channel; |
| 51 | struct snd_dbuf *buffer; |
| 52 | int dir; |
| 53 | u_int32_t fmt, blksz; |
| 54 | }; |
| 55 | |
| 56 | struct mss_info { |
| 57 | struct resource *io_base; /* primary I/O address for the board */ |
| 58 | int io_rid; |
| 59 | struct resource *conf_base; /* and the opti931 also has a config space */ |
| 60 | int conf_rid; |
| 61 | struct resource *irq; |
| 62 | int irq_rid; |
| 63 | struct resource *drq1; /* play */ |
| 64 | int drq1_rid; |
| 65 | struct resource *drq2; /* rec */ |
| 66 | int drq2_rid; |
| 67 | void *ih; |
| 68 | bus_dma_tag_t parent_dmat; |
| 69 | void *lock; |
| 70 | |
| 71 | char mss_indexed_regs[MSS_INDEXED_REGS]; |
| 72 | char opl_indexed_regs[OPL_INDEXED_REGS]; |
| 73 | int bd_id; /* used to hold board-id info, eg. sb version, |
| 74 | * mss codec type, etc. etc. |
| 75 | */ |
| 76 | int opti_offset; /* offset from config_base for opti931 */ |
| 77 | u_long bd_flags; /* board-specific flags */ |
| 78 | int optibase; /* base address for OPTi9xx config */ |
| 79 | struct resource *indir; /* Indirect register index address */ |
| 80 | int indir_rid; |
| 81 | int password; /* password for opti9xx cards */ |
| 82 | int passwdreg; /* password register */ |
| 83 | unsigned int bufsize; |
| 84 | struct mss_chinfo pch, rch; |
| 85 | }; |
| 86 | |
| 87 | static int mss_probe(device_t dev); |
| 88 | static int mss_attach(device_t dev); |
| 89 | |
| 90 | static driver_intr_t mss_intr; |
| 91 | |
| 92 | /* prototypes for local functions */ |
| 93 | static int mss_detect(device_t dev, struct mss_info *mss); |
| 94 | static int opti_detect(device_t dev, struct mss_info *mss); |
| 95 | static char *ymf_test(device_t dev, struct mss_info *mss); |
| 96 | static void ad_unmute(struct mss_info *mss); |
| 97 | |
| 98 | /* mixer set funcs */ |
| 99 | static int mss_mixer_set(struct mss_info *mss, int dev, int left, int right); |
| 100 | static int mss_set_recsrc(struct mss_info *mss, int mask); |
| 101 | |
| 102 | /* io funcs */ |
| 103 | static int ad_wait_init(struct mss_info *mss, int x); |
| 104 | static int ad_read(struct mss_info *mss, int reg); |
| 105 | static void ad_write(struct mss_info *mss, int reg, u_char data); |
| 106 | static void ad_write_cnt(struct mss_info *mss, int reg, u_short data); |
| 107 | static void ad_enter_MCE(struct mss_info *mss); |
| 108 | static void ad_leave_MCE(struct mss_info *mss); |
| 109 | |
| 110 | /* OPTi-specific functions */ |
| 111 | static void opti_write(struct mss_info *mss, u_char reg, |
| 112 | u_char data); |
| 113 | static u_char opti_read(struct mss_info *mss, u_char reg); |
| 114 | static int opti_init(device_t dev, struct mss_info *mss); |
| 115 | |
| 116 | /* io primitives */ |
| 117 | static void conf_wr(struct mss_info *mss, u_char reg, u_char data); |
| 118 | static u_char conf_rd(struct mss_info *mss, u_char reg); |
| 119 | |
| 120 | static int pnpmss_probe(device_t dev); |
| 121 | static int pnpmss_attach(device_t dev); |
| 122 | |
| 123 | static driver_intr_t opti931_intr; |
| 124 | |
| 125 | static u_int32_t mss_fmt[] = { |
| 126 | AFMT_U8, |
| 127 | AFMT_STEREO | AFMT_U8, |
| 128 | AFMT_S16_LE, |
| 129 | AFMT_STEREO | AFMT_S16_LE, |
| 130 | AFMT_MU_LAW, |
| 131 | AFMT_STEREO | AFMT_MU_LAW, |
| 132 | AFMT_A_LAW, |
| 133 | AFMT_STEREO | AFMT_A_LAW, |
| 134 | 0 |
| 135 | }; |
| 136 | static struct pcmchan_caps mss_caps = {4000, 48000, mss_fmt, 0}; |
| 137 | |
| 138 | static u_int32_t guspnp_fmt[] = { |
| 139 | AFMT_U8, |
| 140 | AFMT_STEREO | AFMT_U8, |
| 141 | AFMT_S16_LE, |
| 142 | AFMT_STEREO | AFMT_S16_LE, |
| 143 | AFMT_A_LAW, |
| 144 | AFMT_STEREO | AFMT_A_LAW, |
| 145 | 0 |
| 146 | }; |
| 147 | static struct pcmchan_caps guspnp_caps = {4000, 48000, guspnp_fmt, 0}; |
| 148 | |
| 149 | static u_int32_t opti931_fmt[] = { |
| 150 | AFMT_U8, |
| 151 | AFMT_STEREO | AFMT_U8, |
| 152 | AFMT_S16_LE, |
| 153 | AFMT_STEREO | AFMT_S16_LE, |
| 154 | 0 |
| 155 | }; |
| 156 | static struct pcmchan_caps opti931_caps = {4000, 48000, opti931_fmt, 0}; |
| 157 | |
| 158 | #define MD_AD1848 0x91 |
| 159 | #define MD_AD1845 0x92 |
| 160 | #define MD_CS42XX 0xA1 |
| 161 | #define MD_OPTI930 0xB0 |
| 162 | #define MD_OPTI931 0xB1 |
| 163 | #define MD_OPTI925 0xB2 |
| 164 | #define MD_OPTI924 0xB3 |
| 165 | #define MD_GUSPNP 0xB8 |
| 166 | #define MD_GUSMAX 0xB9 |
| 167 | #define MD_YM0020 0xC1 |
| 168 | #define MD_VIVO 0xD1 |
| 169 | |
| 170 | #define DV_F_TRUE_MSS 0x00010000 /* mss _with_ base regs */ |
| 171 | |
| 172 | #define FULL_DUPLEX(x) ((x)->bd_flags & BD_F_DUPLEX) |
| 173 | |
| 174 | static void |
| 175 | mss_lock(struct mss_info *mss) |
| 176 | { |
| 177 | snd_mtxlock(mss->lock); |
| 178 | } |
| 179 | |
| 180 | static void |
| 181 | mss_unlock(struct mss_info *mss) |
| 182 | { |
| 183 | snd_mtxunlock(mss->lock); |
| 184 | } |
| 185 | |
| 186 | static int |
| 187 | port_rd(struct resource *port, int off) |
| 188 | { |
| 189 | if (port) |
| 190 | return bus_space_read_1(rman_get_bustag(port), |
| 191 | rman_get_bushandle(port), |
| 192 | off); |
| 193 | else |
| 194 | return -1; |
| 195 | } |
| 196 | |
| 197 | static void |
| 198 | port_wr(struct resource *port, int off, u_int8_t data) |
| 199 | { |
| 200 | if (port) |
| 201 | bus_space_write_1(rman_get_bustag(port), |
| 202 | rman_get_bushandle(port), |
| 203 | off, data); |
| 204 | } |
| 205 | |
| 206 | static int |
| 207 | io_rd(struct mss_info *mss, int reg) |
| 208 | { |
| 209 | if (mss->bd_flags & BD_F_MSS_OFFSET) reg -= 4; |
| 210 | return port_rd(mss->io_base, reg); |
| 211 | } |
| 212 | |
| 213 | static void |
| 214 | io_wr(struct mss_info *mss, int reg, u_int8_t data) |
| 215 | { |
| 216 | if (mss->bd_flags & BD_F_MSS_OFFSET) reg -= 4; |
| 217 | port_wr(mss->io_base, reg, data); |
| 218 | } |
| 219 | |
| 220 | static void |
| 221 | conf_wr(struct mss_info *mss, u_char reg, u_char value) |
| 222 | { |
| 223 | port_wr(mss->conf_base, 0, reg); |
| 224 | port_wr(mss->conf_base, 1, value); |
| 225 | } |
| 226 | |
| 227 | static u_char |
| 228 | conf_rd(struct mss_info *mss, u_char reg) |
| 229 | { |
| 230 | port_wr(mss->conf_base, 0, reg); |
| 231 | return port_rd(mss->conf_base, 1); |
| 232 | } |
| 233 | |
| 234 | static void |
| 235 | opti_wr(struct mss_info *mss, u_char reg, u_char value) |
| 236 | { |
| 237 | port_wr(mss->conf_base, mss->opti_offset + 0, reg); |
| 238 | port_wr(mss->conf_base, mss->opti_offset + 1, value); |
| 239 | } |
| 240 | |
| 241 | static u_char |
| 242 | opti_rd(struct mss_info *mss, u_char reg) |
| 243 | { |
| 244 | port_wr(mss->conf_base, mss->opti_offset + 0, reg); |
| 245 | return port_rd(mss->conf_base, mss->opti_offset + 1); |
| 246 | } |
| 247 | |
| 248 | static void |
| 249 | gus_wr(struct mss_info *mss, u_char reg, u_char value) |
| 250 | { |
| 251 | port_wr(mss->conf_base, 3, reg); |
| 252 | port_wr(mss->conf_base, 5, value); |
| 253 | } |
| 254 | |
| 255 | static u_char |
| 256 | gus_rd(struct mss_info *mss, u_char reg) |
| 257 | { |
| 258 | port_wr(mss->conf_base, 3, reg); |
| 259 | return port_rd(mss->conf_base, 5); |
| 260 | } |
| 261 | |
| 262 | static void |
| 263 | mss_release_resources(struct mss_info *mss, device_t dev) |
| 264 | { |
| 265 | if (mss->irq) { |
| 266 | if (mss->ih) |
| 267 | bus_teardown_intr(dev, mss->irq, mss->ih); |
| 268 | bus_release_resource(dev, SYS_RES_IRQ, mss->irq_rid, |
| 269 | mss->irq); |
| 270 | mss->irq = 0; |
| 271 | } |
| 272 | if (mss->drq2) { |
| 273 | if (mss->drq2 != mss->drq1) { |
| 274 | isa_dma_release(rman_get_start(mss->drq2)); |
| 275 | bus_release_resource(dev, SYS_RES_DRQ, mss->drq2_rid, |
| 276 | mss->drq2); |
| 277 | } |
| 278 | mss->drq2 = 0; |
| 279 | } |
| 280 | if (mss->drq1) { |
| 281 | isa_dma_release(rman_get_start(mss->drq1)); |
| 282 | bus_release_resource(dev, SYS_RES_DRQ, mss->drq1_rid, |
| 283 | mss->drq1); |
| 284 | mss->drq1 = 0; |
| 285 | } |
| 286 | if (mss->io_base) { |
| 287 | bus_release_resource(dev, SYS_RES_IOPORT, mss->io_rid, |
| 288 | mss->io_base); |
| 289 | mss->io_base = 0; |
| 290 | } |
| 291 | if (mss->conf_base) { |
| 292 | bus_release_resource(dev, SYS_RES_IOPORT, mss->conf_rid, |
| 293 | mss->conf_base); |
| 294 | mss->conf_base = 0; |
| 295 | } |
| 296 | if (mss->indir) { |
| 297 | bus_release_resource(dev, SYS_RES_IOPORT, mss->indir_rid, |
| 298 | mss->indir); |
| 299 | mss->indir = 0; |
| 300 | } |
| 301 | if (mss->parent_dmat) { |
| 302 | bus_dma_tag_destroy(mss->parent_dmat); |
| 303 | mss->parent_dmat = 0; |
| 304 | } |
| 305 | if (mss->lock) snd_mtxfree(mss->lock); |
| 306 | |
| 307 | free(mss, M_DEVBUF); |
| 308 | } |
| 309 | |
| 310 | static int |
| 311 | mss_alloc_resources(struct mss_info *mss, device_t dev) |
| 312 | { |
| 313 | int pdma, rdma, ok = 1; |
| 314 | if (!mss->io_base) |
| 315 | mss->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT, &mss->io_rid, |
| 316 | 0, ~0, 1, RF_ACTIVE); |
| 317 | if (!mss->irq) |
| 318 | mss->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &mss->irq_rid, |
| 319 | 0, ~0, 1, RF_ACTIVE); |
| 320 | if (!mss->drq1) |
| 321 | mss->drq1 = bus_alloc_resource(dev, SYS_RES_DRQ, &mss->drq1_rid, |
| 322 | 0, ~0, 1, RF_ACTIVE); |
| 323 | if (mss->conf_rid >= 0 && !mss->conf_base) |
| 324 | mss->conf_base = bus_alloc_resource(dev, SYS_RES_IOPORT, &mss->conf_rid, |
| 325 | 0, ~0, 1, RF_ACTIVE); |
| 326 | if (mss->drq2_rid >= 0 && !mss->drq2) |
| 327 | mss->drq2 = bus_alloc_resource(dev, SYS_RES_DRQ, &mss->drq2_rid, |
| 328 | 0, ~0, 1, RF_ACTIVE); |
| 329 | |
| 330 | if (!mss->io_base || !mss->drq1 || !mss->irq) ok = 0; |
| 331 | if (mss->conf_rid >= 0 && !mss->conf_base) ok = 0; |
| 332 | if (mss->drq2_rid >= 0 && !mss->drq2) ok = 0; |
| 333 | |
| 334 | if (ok) { |
| 335 | pdma = rman_get_start(mss->drq1); |
| 336 | isa_dma_acquire(pdma); |
| 337 | isa_dmainit(pdma, mss->bufsize); |
| 338 | mss->bd_flags &= ~BD_F_DUPLEX; |
| 339 | if (mss->drq2) { |
| 340 | rdma = rman_get_start(mss->drq2); |
| 341 | isa_dma_acquire(rdma); |
| 342 | isa_dmainit(rdma, mss->bufsize); |
| 343 | mss->bd_flags |= BD_F_DUPLEX; |
| 344 | } else mss->drq2 = mss->drq1; |
| 345 | } |
| 346 | return ok; |
| 347 | } |
| 348 | |
| 349 | /* |
| 350 | * The various mixers use a variety of bitmasks etc. The Voxware |
| 351 | * driver had a very nice technique to describe a mixer and interface |
| 352 | * to it. A table defines, for each channel, which register, bits, |
| 353 | * offset, polarity to use. This procedure creates the new value |
| 354 | * using the table and the old value. |
| 355 | */ |
| 356 | |
| 357 | static void |
| 358 | change_bits(mixer_tab *t, u_char *regval, int dev, int chn, int newval) |
| 359 | { |
| 360 | u_char mask; |
| 361 | int shift; |
| 362 | |
| 363 | DEB(printf("ch_bits dev %d ch %d val %d old 0x%02x " |
| 364 | "r %d p %d bit %d off %d\n", |
| 365 | dev, chn, newval, *regval, |
| 366 | (*t)[dev][chn].regno, (*t)[dev][chn].polarity, |
| 367 | (*t)[dev][chn].nbits, (*t)[dev][chn].bitoffs ) ); |
| 368 | |
| 369 | if ( (*t)[dev][chn].polarity == 1) /* reverse */ |
| 370 | newval = 100 - newval ; |
| 371 | |
| 372 | mask = (1 << (*t)[dev][chn].nbits) - 1; |
| 373 | newval = (int) ((newval * mask) + 50) / 100; /* Scale it */ |
| 374 | shift = (*t)[dev][chn].bitoffs /*- (*t)[dev][LEFT_CHN].nbits + 1*/; |
| 375 | |
| 376 | *regval &= ~(mask << shift); /* Filter out the previous value */ |
| 377 | *regval |= (newval & mask) << shift; /* Set the new value */ |
| 378 | } |
| 379 | |
| 380 | /* -------------------------------------------------------------------- */ |
| 381 | /* only one source can be set... */ |
| 382 | static int |
| 383 | mss_set_recsrc(struct mss_info *mss, int mask) |
| 384 | { |
| 385 | u_char recdev; |
| 386 | |
| 387 | switch (mask) { |
| 388 | case SOUND_MASK_LINE: |
| 389 | case SOUND_MASK_LINE3: |
| 390 | recdev = 0; |
| 391 | break; |
| 392 | |
| 393 | case SOUND_MASK_CD: |
| 394 | case SOUND_MASK_LINE1: |
| 395 | recdev = 0x40; |
| 396 | break; |
| 397 | |
| 398 | case SOUND_MASK_IMIX: |
| 399 | recdev = 0xc0; |
| 400 | break; |
| 401 | |
| 402 | case SOUND_MASK_MIC: |
| 403 | default: |
| 404 | mask = SOUND_MASK_MIC; |
| 405 | recdev = 0x80; |
| 406 | } |
| 407 | ad_write(mss, 0, (ad_read(mss, 0) & 0x3f) | recdev); |
| 408 | ad_write(mss, 1, (ad_read(mss, 1) & 0x3f) | recdev); |
| 409 | return mask; |
| 410 | } |
| 411 | |
| 412 | /* there are differences in the mixer depending on the actual sound card. */ |
| 413 | static int |
| 414 | mss_mixer_set(struct mss_info *mss, int dev, int left, int right) |
| 415 | { |
| 416 | int regoffs; |
| 417 | mixer_tab *mix_d; |
| 418 | u_char old, val; |
| 419 | |
| 420 | switch (mss->bd_id) { |
| 421 | case MD_OPTI931: |
| 422 | mix_d = &opti931_devices; |
| 423 | break; |
| 424 | case MD_OPTI930: |
| 425 | mix_d = &opti930_devices; |
| 426 | break; |
| 427 | default: |
| 428 | mix_d = &mix_devices; |
| 429 | } |
| 430 | |
| 431 | if ((*mix_d)[dev][LEFT_CHN].nbits == 0) { |
| 432 | DEB(printf("nbits = 0 for dev %d\n", dev)); |
| 433 | return -1; |
| 434 | } |
| 435 | |
| 436 | if ((*mix_d)[dev][RIGHT_CHN].nbits == 0) right = left; /* mono */ |
| 437 | |
| 438 | /* Set the left channel */ |
| 439 | |
| 440 | regoffs = (*mix_d)[dev][LEFT_CHN].regno; |
| 441 | old = val = ad_read(mss, regoffs); |
| 442 | /* if volume is 0, mute chan. Otherwise, unmute. */ |
| 443 | if (regoffs != 0) val = (left == 0)? old | 0x80 : old & 0x7f; |
| 444 | change_bits(mix_d, &val, dev, LEFT_CHN, left); |
| 445 | ad_write(mss, regoffs, val); |
| 446 | |
| 447 | DEB(printf("LEFT: dev %d reg %d old 0x%02x new 0x%02x\n", |
| 448 | dev, regoffs, old, val)); |
| 449 | |
| 450 | if ((*mix_d)[dev][RIGHT_CHN].nbits != 0) { /* have stereo */ |
| 451 | /* Set the right channel */ |
| 452 | regoffs = (*mix_d)[dev][RIGHT_CHN].regno; |
| 453 | old = val = ad_read(mss, regoffs); |
| 454 | if (regoffs != 1) val = (right == 0)? old | 0x80 : old & 0x7f; |
| 455 | change_bits(mix_d, &val, dev, RIGHT_CHN, right); |
| 456 | ad_write(mss, regoffs, val); |
| 457 | |
| 458 | DEB(printf("RIGHT: dev %d reg %d old 0x%02x new 0x%02x\n", |
| 459 | dev, regoffs, old, val)); |
| 460 | } |
| 461 | return 0; /* success */ |
| 462 | } |
| 463 | |
| 464 | /* -------------------------------------------------------------------- */ |
| 465 | |
| 466 | static int |
| 467 | mssmix_init(struct snd_mixer *m) |
| 468 | { |
| 469 | struct mss_info *mss = mix_getdevinfo(m); |
| 470 | |
| 471 | mix_setdevs(m, MODE2_MIXER_DEVICES); |
| 472 | mix_setrecdevs(m, MSS_REC_DEVICES); |
| 473 | switch(mss->bd_id) { |
| 474 | case MD_OPTI930: |
| 475 | mix_setdevs(m, OPTI930_MIXER_DEVICES); |
| 476 | break; |
| 477 | |
| 478 | case MD_OPTI931: |
| 479 | mix_setdevs(m, OPTI931_MIXER_DEVICES); |
| 480 | mss_lock(mss); |
| 481 | ad_write(mss, 20, 0x88); |
| 482 | ad_write(mss, 21, 0x88); |
| 483 | mss_unlock(mss); |
| 484 | break; |
| 485 | |
| 486 | case MD_AD1848: |
| 487 | mix_setdevs(m, MODE1_MIXER_DEVICES); |
| 488 | break; |
| 489 | |
| 490 | case MD_GUSPNP: |
| 491 | case MD_GUSMAX: |
| 492 | /* this is only necessary in mode 3 ... */ |
| 493 | mss_lock(mss); |
| 494 | ad_write(mss, 22, 0x88); |
| 495 | ad_write(mss, 23, 0x88); |
| 496 | mss_unlock(mss); |
| 497 | break; |
| 498 | } |
| 499 | return 0; |
| 500 | } |
| 501 | |
| 502 | static int |
| 503 | mssmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) |
| 504 | { |
| 505 | struct mss_info *mss = mix_getdevinfo(m); |
| 506 | |
| 507 | mss_lock(mss); |
| 508 | mss_mixer_set(mss, dev, left, right); |
| 509 | mss_unlock(mss); |
| 510 | |
| 511 | return left | (right << 8); |
| 512 | } |
| 513 | |
| 514 | static int |
| 515 | mssmix_setrecsrc(struct snd_mixer *m, u_int32_t src) |
| 516 | { |
| 517 | struct mss_info *mss = mix_getdevinfo(m); |
| 518 | |
| 519 | mss_lock(mss); |
| 520 | src = mss_set_recsrc(mss, src); |
| 521 | mss_unlock(mss); |
| 522 | return src; |
| 523 | } |
| 524 | |
| 525 | static kobj_method_t mssmix_mixer_methods[] = { |
| 526 | KOBJMETHOD(mixer_init, mssmix_init), |
| 527 | KOBJMETHOD(mixer_set, mssmix_set), |
| 528 | KOBJMETHOD(mixer_setrecsrc, mssmix_setrecsrc), |
| 529 | { 0, 0 } |
| 530 | }; |
| 531 | MIXER_DECLARE(mssmix_mixer); |
| 532 | |
| 533 | /* -------------------------------------------------------------------- */ |
| 534 | |
| 535 | static int |
| 536 | ymmix_init(struct snd_mixer *m) |
| 537 | { |
| 538 | struct mss_info *mss = mix_getdevinfo(m); |
| 539 | |
| 540 | mssmix_init(m); |
| 541 | mix_setdevs(m, mix_getdevs(m) | SOUND_MASK_VOLUME | SOUND_MASK_MIC |
| 542 | | SOUND_MASK_BASS | SOUND_MASK_TREBLE); |
| 543 | /* Set master volume */ |
| 544 | mss_lock(mss); |
| 545 | conf_wr(mss, OPL3SAx_VOLUMEL, 7); |
| 546 | conf_wr(mss, OPL3SAx_VOLUMER, 7); |
| 547 | mss_unlock(mss); |
| 548 | |
| 549 | return 0; |
| 550 | } |
| 551 | |
| 552 | static int |
| 553 | ymmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) |
| 554 | { |
| 555 | struct mss_info *mss = mix_getdevinfo(m); |
| 556 | int t, l, r; |
| 557 | |
| 558 | mss_lock(mss); |
| 559 | switch (dev) { |
| 560 | case SOUND_MIXER_VOLUME: |
| 561 | if (left) t = 15 - (left * 15) / 100; |
| 562 | else t = 0x80; /* mute */ |
| 563 | conf_wr(mss, OPL3SAx_VOLUMEL, t); |
| 564 | if (right) t = 15 - (right * 15) / 100; |
| 565 | else t = 0x80; /* mute */ |
| 566 | conf_wr(mss, OPL3SAx_VOLUMER, t); |
| 567 | break; |
| 568 | |
| 569 | case SOUND_MIXER_MIC: |
| 570 | t = left; |
| 571 | if (left) t = 31 - (left * 31) / 100; |
| 572 | else t = 0x80; /* mute */ |
| 573 | conf_wr(mss, OPL3SAx_MIC, t); |
| 574 | break; |
| 575 | |
| 576 | case SOUND_MIXER_BASS: |
| 577 | l = (left * 7) / 100; |
| 578 | r = (right * 7) / 100; |
| 579 | t = (r << 4) | l; |
| 580 | conf_wr(mss, OPL3SAx_BASS, t); |
| 581 | break; |
| 582 | |
| 583 | case SOUND_MIXER_TREBLE: |
| 584 | l = (left * 7) / 100; |
| 585 | r = (right * 7) / 100; |
| 586 | t = (r << 4) | l; |
| 587 | conf_wr(mss, OPL3SAx_TREBLE, t); |
| 588 | break; |
| 589 | |
| 590 | default: |
| 591 | mss_mixer_set(mss, dev, left, right); |
| 592 | } |
| 593 | mss_unlock(mss); |
| 594 | |
| 595 | return left | (right << 8); |
| 596 | } |
| 597 | |
| 598 | static int |
| 599 | ymmix_setrecsrc(struct snd_mixer *m, u_int32_t src) |
| 600 | { |
| 601 | struct mss_info *mss = mix_getdevinfo(m); |
| 602 | mss_lock(mss); |
| 603 | src = mss_set_recsrc(mss, src); |
| 604 | mss_unlock(mss); |
| 605 | return src; |
| 606 | } |
| 607 | |
| 608 | static kobj_method_t ymmix_mixer_methods[] = { |
| 609 | KOBJMETHOD(mixer_init, ymmix_init), |
| 610 | KOBJMETHOD(mixer_set, ymmix_set), |
| 611 | KOBJMETHOD(mixer_setrecsrc, ymmix_setrecsrc), |
| 612 | { 0, 0 } |
| 613 | }; |
| 614 | MIXER_DECLARE(ymmix_mixer); |
| 615 | |
| 616 | /* -------------------------------------------------------------------- */ |
| 617 | /* |
| 618 | * XXX This might be better off in the gusc driver. |
| 619 | */ |
| 620 | static void |
| 621 | gusmax_setup(struct mss_info *mss, device_t dev, struct resource *alt) |
| 622 | { |
| 623 | static const unsigned char irq_bits[16] = { |
| 624 | 0, 0, 0, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7 |
| 625 | }; |
| 626 | static const unsigned char dma_bits[8] = { |
| 627 | 0, 1, 0, 2, 0, 3, 4, 5 |
| 628 | }; |
| 629 | device_t parent = device_get_parent(dev); |
| 630 | unsigned char irqctl, dmactl; |
| 631 | int s; |
| 632 | |
| 633 | s = splhigh(); |
| 634 | |
| 635 | port_wr(alt, 0x0f, 0x05); |
| 636 | port_wr(alt, 0x00, 0x0c); |
| 637 | port_wr(alt, 0x0b, 0x00); |
| 638 | |
| 639 | port_wr(alt, 0x0f, 0x00); |
| 640 | |
| 641 | irqctl = irq_bits[isa_get_irq(parent)]; |
| 642 | /* Share the IRQ with the MIDI driver. */ |
| 643 | irqctl |= 0x40; |
| 644 | dmactl = dma_bits[isa_get_drq(parent)]; |
| 645 | if (device_get_flags(parent) & DV_F_DUAL_DMA) |
| 646 | dmactl |= dma_bits[device_get_flags(parent) & DV_F_DRQ_MASK] |
| 647 | << 3; |
| 648 | |
| 649 | /* |
| 650 | * Set the DMA and IRQ control latches. |
| 651 | */ |
| 652 | port_wr(alt, 0x00, 0x0c); |
| 653 | port_wr(alt, 0x0b, dmactl | 0x80); |
| 654 | port_wr(alt, 0x00, 0x4c); |
| 655 | port_wr(alt, 0x0b, irqctl); |
| 656 | |
| 657 | port_wr(alt, 0x00, 0x0c); |
| 658 | port_wr(alt, 0x0b, dmactl); |
| 659 | port_wr(alt, 0x00, 0x4c); |
| 660 | port_wr(alt, 0x0b, irqctl); |
| 661 | |
| 662 | port_wr(mss->conf_base, 2, 0); |
| 663 | port_wr(alt, 0x00, 0x0c); |
| 664 | port_wr(mss->conf_base, 2, 0); |
| 665 | |
| 666 | splx(s); |
| 667 | } |
| 668 | |
| 669 | static int |
| 670 | mss_init(struct mss_info *mss, device_t dev) |
| 671 | { |
| 672 | u_char r6, r9; |
| 673 | struct resource *alt; |
| 674 | int rid, tmp; |
| 675 | |
| 676 | mss->bd_flags |= BD_F_MCE_BIT; |
| 677 | switch(mss->bd_id) { |
| 678 | case MD_OPTI931: |
| 679 | /* |
| 680 | * The MED3931 v.1.0 allocates 3 bytes for the config |
| 681 | * space, whereas v.2.0 allocates 4 bytes. What I know |
| 682 | * for sure is that the upper two ports must be used, |
| 683 | * and they should end on a boundary of 4 bytes. So I |
| 684 | * need the following trick. |
| 685 | */ |
| 686 | mss->opti_offset = |
| 687 | (rman_get_start(mss->conf_base) & ~3) + 2 |
| 688 | - rman_get_start(mss->conf_base); |
| 689 | BVDDB(printf("mss_init: opti_offset=%d\n", mss->opti_offset)); |
| 690 | opti_wr(mss, 4, 0xd6); /* fifo empty, OPL3, audio enable, SB3.2 */ |
| 691 | ad_write(mss, 10, 2); /* enable interrupts */ |
| 692 | opti_wr(mss, 6, 2); /* MCIR6: mss enable, sb disable */ |
| 693 | opti_wr(mss, 5, 0x28); /* MCIR5: codec in exp. mode,fifo */ |
| 694 | break; |
| 695 | |
| 696 | case MD_GUSPNP: |
| 697 | case MD_GUSMAX: |
| 698 | gus_wr(mss, 0x4c /* _URSTI */, 0);/* Pull reset */ |
| 699 | DELAY(1000 * 30); |
| 700 | /* release reset and enable DAC */ |
| 701 | gus_wr(mss, 0x4c /* _URSTI */, 3); |
| 702 | DELAY(1000 * 30); |
| 703 | /* end of reset */ |
| 704 | |
| 705 | rid = 0; |
| 706 | alt = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, |
| 707 | 0, ~0, 1, RF_ACTIVE); |
| 708 | if (alt == NULL) { |
| 709 | printf("XXX couldn't init GUS PnP/MAX\n"); |
| 710 | break; |
| 711 | } |
| 712 | port_wr(alt, 0, 0xC); /* enable int and dma */ |
| 713 | if (mss->bd_id == MD_GUSMAX) |
| 714 | gusmax_setup(mss, dev, alt); |
| 715 | bus_release_resource(dev, SYS_RES_IOPORT, rid, alt); |
| 716 | |
| 717 | /* |
| 718 | * unmute left & right line. Need to go in mode3, unmute, |
| 719 | * and back to mode 2 |
| 720 | */ |
| 721 | tmp = ad_read(mss, 0x0c); |
| 722 | ad_write(mss, 0x0c, 0x6c); /* special value to enter mode 3 */ |
| 723 | ad_write(mss, 0x19, 0); /* unmute left */ |
| 724 | ad_write(mss, 0x1b, 0); /* unmute right */ |
| 725 | ad_write(mss, 0x0c, tmp); /* restore old mode */ |
| 726 | |
| 727 | /* send codec interrupts on irq1 and only use that one */ |
| 728 | gus_wr(mss, 0x5a, 0x4f); |
| 729 | |
| 730 | /* enable access to hidden regs */ |
| 731 | tmp = gus_rd(mss, 0x5b /* IVERI */); |
| 732 | gus_wr(mss, 0x5b, tmp | 1); |
| 733 | BVDDB(printf("GUS: silicon rev %c\n", 'A' + ((tmp & 0xf) >> 4))); |
| 734 | break; |
| 735 | |
| 736 | case MD_YM0020: |
| 737 | conf_wr(mss, OPL3SAx_DMACONF, 0xa9); /* dma-b rec, dma-a play */ |
| 738 | r6 = conf_rd(mss, OPL3SAx_DMACONF); |
| 739 | r9 = conf_rd(mss, OPL3SAx_MISC); /* version */ |
| 740 | BVDDB(printf("Yamaha: ver 0x%x DMA config 0x%x\n", r6, r9);) |
| 741 | /* yamaha - set volume to max */ |
| 742 | conf_wr(mss, OPL3SAx_VOLUMEL, 0); |
| 743 | conf_wr(mss, OPL3SAx_VOLUMER, 0); |
| 744 | conf_wr(mss, OPL3SAx_DMACONF, FULL_DUPLEX(mss)? 0xa9 : 0x8b); |
| 745 | break; |
| 746 | } |
| 747 | if (FULL_DUPLEX(mss) && mss->bd_id != MD_OPTI931) |
| 748 | ad_write(mss, 12, ad_read(mss, 12) | 0x40); /* mode 2 */ |
| 749 | ad_enter_MCE(mss); |
| 750 | ad_write(mss, 9, FULL_DUPLEX(mss)? 0 : 4); |
| 751 | ad_leave_MCE(mss); |
| 752 | ad_write(mss, 10, 2); /* int enable */ |
| 753 | io_wr(mss, MSS_STATUS, 0); /* Clear interrupt status */ |
| 754 | /* the following seem required on the CS4232 */ |
| 755 | ad_unmute(mss); |
| 756 | return 0; |
| 757 | } |
| 758 | |
| 759 | |
| 760 | /* |
| 761 | * main irq handler for the CS423x. The OPTi931 code is |
| 762 | * a separate one. |
| 763 | * The correct way to operate for a device with multiple internal |
| 764 | * interrupt sources is to loop on the status register and ack |
| 765 | * interrupts until all interrupts are served and none are reported. At |
| 766 | * this point the IRQ line to the ISA IRQ controller should go low |
| 767 | * and be raised at the next interrupt. |
| 768 | * |
| 769 | * Since the ISA IRQ controller is sent EOI _before_ passing control |
| 770 | * to the isr, it might happen that we serve an interrupt early, in |
| 771 | * which case the status register at the next interrupt should just |
| 772 | * say that there are no more interrupts... |
| 773 | */ |
| 774 | |
| 775 | static void |
| 776 | mss_intr(void *arg) |
| 777 | { |
| 778 | struct mss_info *mss = arg; |
| 779 | u_char c = 0, served = 0; |
| 780 | int i; |
| 781 | |
| 782 | DEB(printf("mss_intr\n")); |
| 783 | mss_lock(mss); |
| 784 | ad_read(mss, 11); /* fake read of status bits */ |
| 785 | |
| 786 | /* loop until there are interrupts, but no more than 10 times. */ |
| 787 | for (i = 10; i > 0 && io_rd(mss, MSS_STATUS) & 1; i--) { |
| 788 | /* get exact reason for full-duplex boards */ |
| 789 | c = FULL_DUPLEX(mss)? ad_read(mss, 24) : 0x30; |
| 790 | c &= ~served; |
| 791 | if (sndbuf_runsz(mss->pch.buffer) && (c & 0x10)) { |
| 792 | served |= 0x10; |
| 793 | chn_intr(mss->pch.channel); |
| 794 | } |
| 795 | if (sndbuf_runsz(mss->rch.buffer) && (c & 0x20)) { |
| 796 | served |= 0x20; |
| 797 | chn_intr(mss->rch.channel); |
| 798 | } |
| 799 | /* now ack the interrupt */ |
| 800 | if (FULL_DUPLEX(mss)) ad_write(mss, 24, ~c); /* ack selectively */ |
| 801 | else io_wr(mss, MSS_STATUS, 0); /* Clear interrupt status */ |
| 802 | } |
| 803 | if (i == 10) { |
| 804 | BVDDB(printf("mss_intr: irq, but not from mss\n")); |
| 805 | } else if (served == 0) { |
| 806 | BVDDB(printf("mss_intr: unexpected irq with reason %x\n", c)); |
| 807 | /* |
| 808 | * this should not happen... I have no idea what to do now. |
| 809 | * maybe should do a sanity check and restart dmas ? |
| 810 | */ |
| 811 | io_wr(mss, MSS_STATUS, 0); /* Clear interrupt status */ |
| 812 | } |
| 813 | mss_unlock(mss); |
| 814 | } |
| 815 | |
| 816 | /* |
| 817 | * AD_WAIT_INIT waits if we are initializing the board and |
| 818 | * we cannot modify its settings |
| 819 | */ |
| 820 | static int |
| 821 | ad_wait_init(struct mss_info *mss, int x) |
| 822 | { |
| 823 | int arg = x, n = 0; /* to shut up the compiler... */ |
| 824 | for (; x > 0; x--) |
| 825 | if ((n = io_rd(mss, MSS_INDEX)) & MSS_IDXBUSY) DELAY(10); |
| 826 | else return n; |
| 827 | printf("AD_WAIT_INIT FAILED %d 0x%02x\n", arg, n); |
| 828 | return n; |
| 829 | } |
| 830 | |
| 831 | static int |
| 832 | ad_read(struct mss_info *mss, int reg) |
| 833 | { |
| 834 | int x; |
| 835 | |
| 836 | ad_wait_init(mss, 201000); |
| 837 | x = io_rd(mss, MSS_INDEX) & ~MSS_IDXMASK; |
| 838 | io_wr(mss, MSS_INDEX, (u_char)(reg & MSS_IDXMASK) | x); |
| 839 | x = io_rd(mss, MSS_IDATA); |
| 840 | /* printf("ad_read %d, %x\n", reg, x); */ |
| 841 | return x; |
| 842 | } |
| 843 | |
| 844 | static void |
| 845 | ad_write(struct mss_info *mss, int reg, u_char data) |
| 846 | { |
| 847 | int x; |
| 848 | |
| 849 | /* printf("ad_write %d, %x\n", reg, data); */ |
| 850 | ad_wait_init(mss, 1002000); |
| 851 | x = io_rd(mss, MSS_INDEX) & ~MSS_IDXMASK; |
| 852 | io_wr(mss, MSS_INDEX, (u_char)(reg & MSS_IDXMASK) | x); |
| 853 | io_wr(mss, MSS_IDATA, data); |
| 854 | } |
| 855 | |
| 856 | static void |
| 857 | ad_write_cnt(struct mss_info *mss, int reg, u_short cnt) |
| 858 | { |
| 859 | ad_write(mss, reg+1, cnt & 0xff); |
| 860 | ad_write(mss, reg, cnt >> 8); /* upper base must be last */ |
| 861 | } |
| 862 | |
| 863 | static void |
| 864 | wait_for_calibration(struct mss_info *mss) |
| 865 | { |
| 866 | int t; |
| 867 | |
| 868 | /* |
| 869 | * Wait until the auto calibration process has finished. |
| 870 | * |
| 871 | * 1) Wait until the chip becomes ready (reads don't return 0x80). |
| 872 | * 2) Wait until the ACI bit of I11 gets on |
| 873 | * 3) Wait until the ACI bit of I11 gets off |
| 874 | */ |
| 875 | |
| 876 | t = ad_wait_init(mss, 1000000); |
| 877 | if (t & MSS_IDXBUSY) printf("mss: Auto calibration timed out(1).\n"); |
| 878 | |
| 879 | /* |
| 880 | * The calibration mode for chips that support it is set so that |
| 881 | * we never see ACI go on. |
| 882 | */ |
| 883 | if (mss->bd_id == MD_GUSMAX || mss->bd_id == MD_GUSPNP) { |
| 884 | for (t = 100; t > 0 && (ad_read(mss, 11) & 0x20) == 0; t--); |
| 885 | } else { |
| 886 | /* |
| 887 | * XXX This should only be enabled for cards that *really* |
| 888 | * need it. Are there any? |
| 889 | */ |
| 890 | for (t = 100; t > 0 && (ad_read(mss, 11) & 0x20) == 0; t--) DELAY(100); |
| 891 | } |
| 892 | for (t = 100; t > 0 && ad_read(mss, 11) & 0x20; t--) DELAY(100); |
| 893 | } |
| 894 | |
| 895 | static void |
| 896 | ad_unmute(struct mss_info *mss) |
| 897 | { |
| 898 | ad_write(mss, 6, ad_read(mss, 6) & ~I6_MUTE); |
| 899 | ad_write(mss, 7, ad_read(mss, 7) & ~I6_MUTE); |
| 900 | } |
| 901 | |
| 902 | static void |
| 903 | ad_enter_MCE(struct mss_info *mss) |
| 904 | { |
| 905 | int prev; |
| 906 | |
| 907 | mss->bd_flags |= BD_F_MCE_BIT; |
| 908 | ad_wait_init(mss, 203000); |
| 909 | prev = io_rd(mss, MSS_INDEX); |
| 910 | prev &= ~MSS_TRD; |
| 911 | io_wr(mss, MSS_INDEX, prev | MSS_MCE); |
| 912 | } |
| 913 | |
| 914 | static void |
| 915 | ad_leave_MCE(struct mss_info *mss) |
| 916 | { |
| 917 | u_char prev; |
| 918 | |
| 919 | if ((mss->bd_flags & BD_F_MCE_BIT) == 0) { |
| 920 | DEB(printf("--- hey, leave_MCE: MCE bit was not set!\n")); |
| 921 | return; |
| 922 | } |
| 923 | |
| 924 | ad_wait_init(mss, 1000000); |
| 925 | |
| 926 | mss->bd_flags &= ~BD_F_MCE_BIT; |
| 927 | |
| 928 | prev = io_rd(mss, MSS_INDEX); |
| 929 | prev &= ~MSS_TRD; |
| 930 | io_wr(mss, MSS_INDEX, prev & ~MSS_MCE); /* Clear the MCE bit */ |
| 931 | wait_for_calibration(mss); |
| 932 | } |
| 933 | |
| 934 | static int |
| 935 | mss_speed(struct mss_chinfo *ch, int speed) |
| 936 | { |
| 937 | struct mss_info *mss = ch->parent; |
| 938 | /* |
| 939 | * In the CS4231, the low 4 bits of I8 are used to hold the |
| 940 | * sample rate. Only a fixed number of values is allowed. This |
| 941 | * table lists them. The speed-setting routines scans the table |
| 942 | * looking for the closest match. This is the only supported method. |
| 943 | * |
| 944 | * In the CS4236, there is an alternate metod (which we do not |
| 945 | * support yet) which provides almost arbitrary frequency setting. |
| 946 | * In the AD1845, it looks like the sample rate can be |
| 947 | * almost arbitrary, and written directly to a register. |
| 948 | * In the OPTi931, there is a SB command which provides for |
| 949 | * almost arbitrary frequency setting. |
| 950 | * |
| 951 | */ |
| 952 | ad_enter_MCE(mss); |
| 953 | if (mss->bd_id == MD_AD1845) { /* Use alternate speed select regs */ |
| 954 | ad_write(mss, 22, (speed >> 8) & 0xff); /* Speed MSB */ |
| 955 | ad_write(mss, 23, speed & 0xff); /* Speed LSB */ |
| 956 | /* XXX must also do something in I27 for the ad1845 */ |
| 957 | } else { |
| 958 | int i, sel = 0; /* assume entry 0 does not contain -1 */ |
| 959 | static int speeds[] = |
| 960 | {8000, 5512, 16000, 11025, 27429, 18900, 32000, 22050, |
| 961 | -1, 37800, -1, 44100, 48000, 33075, 9600, 6615}; |
| 962 | |
| 963 | for (i = 1; i < 16; i++) |
| 964 | if (speeds[i] > 0 && |
| 965 | abs(speed-speeds[i]) < abs(speed-speeds[sel])) sel = i; |
| 966 | speed = speeds[sel]; |
| 967 | ad_write(mss, 8, (ad_read(mss, 8) & 0xf0) | sel); |
| 968 | } |
| 969 | ad_leave_MCE(mss); |
| 970 | |
| 971 | return speed; |
| 972 | } |
| 973 | |
| 974 | /* |
| 975 | * mss_format checks that the format is supported (or defaults to AFMT_U8) |
| 976 | * and returns the bit setting for the 1848 register corresponding to |
| 977 | * the desired format. |
| 978 | * |
| 979 | * fixed lr970724 |
| 980 | */ |
| 981 | |
| 982 | static int |
| 983 | mss_format(struct mss_chinfo *ch, u_int32_t format) |
| 984 | { |
| 985 | struct mss_info *mss = ch->parent; |
| 986 | int i, arg = format & ~AFMT_STEREO; |
| 987 | |
| 988 | /* |
| 989 | * The data format uses 3 bits (just 2 on the 1848). For each |
| 990 | * bit setting, the following array returns the corresponding format. |
| 991 | * The code scans the array looking for a suitable format. In |
| 992 | * case it is not found, default to AFMT_U8 (not such a good |
| 993 | * choice, but let's do it for compatibility...). |
| 994 | */ |
| 995 | |
| 996 | static int fmts[] = |
| 997 | {AFMT_U8, AFMT_MU_LAW, AFMT_S16_LE, AFMT_A_LAW, |
| 998 | -1, AFMT_IMA_ADPCM, AFMT_U16_BE, -1}; |
| 999 | |
| 1000 | ch->fmt = format; |
| 1001 | for (i = 0; i < 8; i++) if (arg == fmts[i]) break; |
| 1002 | arg = i << 1; |
| 1003 | if (format & AFMT_STEREO) arg |= 1; |
| 1004 | arg <<= 4; |
| 1005 | ad_enter_MCE(mss); |
| 1006 | ad_write(mss, 8, (ad_read(mss, 8) & 0x0f) | arg); |
| 1007 | if (FULL_DUPLEX(mss)) ad_write(mss, 28, arg); /* capture mode */ |
| 1008 | ad_leave_MCE(mss); |
| 1009 | return format; |
| 1010 | } |
| 1011 | |
| 1012 | static int |
| 1013 | mss_trigger(struct mss_chinfo *ch, int go) |
| 1014 | { |
| 1015 | struct mss_info *mss = ch->parent; |
| 1016 | u_char m; |
| 1017 | int retry, wr, cnt, ss; |
| 1018 | |
| 1019 | ss = 1; |
| 1020 | ss <<= (ch->fmt & AFMT_STEREO)? 1 : 0; |
| 1021 | ss <<= (ch->fmt & AFMT_16BIT)? 1 : 0; |
| 1022 | |
| 1023 | wr = (ch->dir == PCMDIR_PLAY)? 1 : 0; |
| 1024 | m = ad_read(mss, 9); |
| 1025 | switch (go) { |
| 1026 | case PCMTRIG_START: |
| 1027 | cnt = (ch->blksz / ss) - 1; |
| 1028 | |
| 1029 | DEB(if (m & 4) printf("OUCH! reg 9 0x%02x\n", m);); |
| 1030 | m |= wr? I9_PEN : I9_CEN; /* enable DMA */ |
| 1031 | ad_write_cnt(mss, (wr || !FULL_DUPLEX(mss))? 14 : 30, cnt); |
| 1032 | break; |
| 1033 | |
| 1034 | case PCMTRIG_STOP: |
| 1035 | case PCMTRIG_ABORT: /* XXX check this... */ |
| 1036 | m &= ~(wr? I9_PEN : I9_CEN); /* Stop DMA */ |
| 1037 | #if 0 |
| 1038 | /* |
| 1039 | * try to disable DMA by clearing count registers. Not sure it |
| 1040 | * is needed, and it might cause false interrupts when the |
| 1041 | * DMA is re-enabled later. |
| 1042 | */ |
| 1043 | ad_write_cnt(mss, (wr || !FULL_DUPLEX(mss))? 14 : 30, 0); |
| 1044 | #endif |
| 1045 | } |
| 1046 | /* on the OPTi931 the enable bit seems hard to set... */ |
| 1047 | for (retry = 10; retry > 0; retry--) { |
| 1048 | ad_write(mss, 9, m); |
| 1049 | if (ad_read(mss, 9) == m) break; |
| 1050 | } |
| 1051 | if (retry == 0) BVDDB(printf("stop dma, failed to set bit 0x%02x 0x%02x\n", \ |
| 1052 | m, ad_read(mss, 9))); |
| 1053 | return 0; |
| 1054 | } |
| 1055 | |
| 1056 | |
| 1057 | /* |
| 1058 | * the opti931 seems to miss interrupts when working in full |
| 1059 | * duplex, so we try some heuristics to catch them. |
| 1060 | */ |
| 1061 | static void |
| 1062 | opti931_intr(void *arg) |
| 1063 | { |
| 1064 | struct mss_info *mss = (struct mss_info *)arg; |
| 1065 | u_char masked = 0, i11, mc11, c = 0; |
| 1066 | u_char reason; /* b0 = playback, b1 = capture, b2 = timer */ |
| 1067 | int loops = 10; |
| 1068 | |
| 1069 | #if 0 |
| 1070 | reason = io_rd(mss, MSS_STATUS); |
| 1071 | if (!(reason & 1)) {/* no int, maybe a shared line ? */ |
| 1072 | DEB(printf("intr: flag 0, mcir11 0x%02x\n", ad_read(mss, 11))); |
| 1073 | return; |
| 1074 | } |
| 1075 | #endif |
| 1076 | mss_lock(mss); |
| 1077 | i11 = ad_read(mss, 11); /* XXX what's for ? */ |
| 1078 | again: |
| 1079 | |
| 1080 | c = mc11 = FULL_DUPLEX(mss)? opti_rd(mss, 11) : 0xc; |
| 1081 | mc11 &= 0x0c; |
| 1082 | if (c & 0x10) { |
| 1083 | DEB(printf("Warning: CD interrupt\n");) |
| 1084 | mc11 |= 0x10; |
| 1085 | } |
| 1086 | if (c & 0x20) { |
| 1087 | DEB(printf("Warning: MPU interrupt\n");) |
| 1088 | mc11 |= 0x20; |
| 1089 | } |
| 1090 | if (mc11 & masked) BVDDB(printf("irq reset failed, mc11 0x%02x, 0x%02x\n",\ |
| 1091 | mc11, masked)); |
| 1092 | masked |= mc11; |
| 1093 | /* |
| 1094 | * the nice OPTi931 sets the IRQ line before setting the bits in |
| 1095 | * mc11. So, on some occasions I have to retry (max 10 times). |
| 1096 | */ |
| 1097 | if (mc11 == 0) { /* perhaps can return ... */ |
| 1098 | reason = io_rd(mss, MSS_STATUS); |
| 1099 | if (reason & 1) { |
| 1100 | DEB(printf("one more try...\n");) |
| 1101 | if (--loops) goto again; |
| 1102 | else DDB(printf("intr, but mc11 not set\n");) |
| 1103 | } |
| 1104 | if (loops == 0) BVDDB(printf("intr, nothing in mcir11 0x%02x\n", mc11)); |
| 1105 | mss_unlock(mss); |
| 1106 | return; |
| 1107 | } |
| 1108 | |
| 1109 | if (sndbuf_runsz(mss->rch.buffer) && (mc11 & 8)) chn_intr(mss->rch.channel); |
| 1110 | if (sndbuf_runsz(mss->pch.buffer) && (mc11 & 4)) chn_intr(mss->pch.channel); |
| 1111 | opti_wr(mss, 11, ~mc11); /* ack */ |
| 1112 | if (--loops) goto again; |
| 1113 | mss_unlock(mss); |
| 1114 | DEB(printf("xxx too many loops\n");) |
| 1115 | } |
| 1116 | |
| 1117 | /* -------------------------------------------------------------------- */ |
| 1118 | /* channel interface */ |
| 1119 | static void * |
| 1120 | msschan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) |
| 1121 | { |
| 1122 | struct mss_info *mss = devinfo; |
| 1123 | struct mss_chinfo *ch = (dir == PCMDIR_PLAY)? &mss->pch : &mss->rch; |
| 1124 | |
| 1125 | ch->parent = mss; |
| 1126 | ch->channel = c; |
| 1127 | ch->buffer = b; |
| 1128 | ch->dir = dir; |
| 1129 | if (sndbuf_alloc(ch->buffer, mss->parent_dmat, mss->bufsize) == -1) return NULL; |
| 1130 | sndbuf_isadmasetup(ch->buffer, (dir == PCMDIR_PLAY)? mss->drq1 : mss->drq2); |
| 1131 | return ch; |
| 1132 | } |
| 1133 | |
| 1134 | static int |
| 1135 | msschan_setformat(kobj_t obj, void *data, u_int32_t format) |
| 1136 | { |
| 1137 | struct mss_chinfo *ch = data; |
| 1138 | struct mss_info *mss = ch->parent; |
| 1139 | |
| 1140 | mss_lock(mss); |
| 1141 | mss_format(ch, format); |
| 1142 | mss_unlock(mss); |
| 1143 | return 0; |
| 1144 | } |
| 1145 | |
| 1146 | static int |
| 1147 | msschan_setspeed(kobj_t obj, void *data, u_int32_t speed) |
| 1148 | { |
| 1149 | struct mss_chinfo *ch = data; |
| 1150 | struct mss_info *mss = ch->parent; |
| 1151 | int r; |
| 1152 | |
| 1153 | mss_lock(mss); |
| 1154 | r = mss_speed(ch, speed); |
| 1155 | mss_unlock(mss); |
| 1156 | |
| 1157 | return r; |
| 1158 | } |
| 1159 | |
| 1160 | static int |
| 1161 | msschan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) |
| 1162 | { |
| 1163 | struct mss_chinfo *ch = data; |
| 1164 | |
| 1165 | ch->blksz = blocksize; |
| 1166 | sndbuf_resize(ch->buffer, 2, ch->blksz); |
| 1167 | |
| 1168 | return ch->blksz; |
| 1169 | } |
| 1170 | |
| 1171 | static int |
| 1172 | msschan_trigger(kobj_t obj, void *data, int go) |
| 1173 | { |
| 1174 | struct mss_chinfo *ch = data; |
| 1175 | struct mss_info *mss = ch->parent; |
| 1176 | |
| 1177 | if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) |
| 1178 | return 0; |
| 1179 | |
| 1180 | sndbuf_isadma(ch->buffer, go); |
| 1181 | mss_lock(mss); |
| 1182 | mss_trigger(ch, go); |
| 1183 | mss_unlock(mss); |
| 1184 | return 0; |
| 1185 | } |
| 1186 | |
| 1187 | static int |
| 1188 | msschan_getptr(kobj_t obj, void *data) |
| 1189 | { |
| 1190 | struct mss_chinfo *ch = data; |
| 1191 | return sndbuf_isadmaptr(ch->buffer); |
| 1192 | } |
| 1193 | |
| 1194 | static struct pcmchan_caps * |
| 1195 | msschan_getcaps(kobj_t obj, void *data) |
| 1196 | { |
| 1197 | struct mss_chinfo *ch = data; |
| 1198 | |
| 1199 | switch(ch->parent->bd_id) { |
| 1200 | case MD_OPTI931: |
| 1201 | return &opti931_caps; |
| 1202 | break; |
| 1203 | |
| 1204 | case MD_GUSPNP: |
| 1205 | case MD_GUSMAX: |
| 1206 | return &guspnp_caps; |
| 1207 | break; |
| 1208 | |
| 1209 | default: |
| 1210 | return &mss_caps; |
| 1211 | break; |
| 1212 | } |
| 1213 | } |
| 1214 | |
| 1215 | static kobj_method_t msschan_methods[] = { |
| 1216 | KOBJMETHOD(channel_init, msschan_init), |
| 1217 | KOBJMETHOD(channel_setformat, msschan_setformat), |
| 1218 | KOBJMETHOD(channel_setspeed, msschan_setspeed), |
| 1219 | KOBJMETHOD(channel_setblocksize, msschan_setblocksize), |
| 1220 | KOBJMETHOD(channel_trigger, msschan_trigger), |
| 1221 | KOBJMETHOD(channel_getptr, msschan_getptr), |
| 1222 | KOBJMETHOD(channel_getcaps, msschan_getcaps), |
| 1223 | { 0, 0 } |
| 1224 | }; |
| 1225 | CHANNEL_DECLARE(msschan); |
| 1226 | |
| 1227 | /* -------------------------------------------------------------------- */ |
| 1228 | |
| 1229 | /* |
| 1230 | * mss_probe() is the probe routine. Note, it is not necessary to |
| 1231 | * go through this for PnP devices, since they are already |
| 1232 | * indentified precisely using their PnP id. |
| 1233 | * |
| 1234 | * The base address supplied in the device refers to the old MSS |
| 1235 | * specs where the four 4 registers in io space contain configuration |
| 1236 | * information. Some boards (as an example, early MSS boards) |
| 1237 | * has such a block of registers, whereas others (generally CS42xx) |
| 1238 | * do not. In order to distinguish between the two and do not have |
| 1239 | * to supply two separate probe routines, the flags entry in isa_device |
| 1240 | * has a bit to mark this. |
| 1241 | * |
| 1242 | */ |
| 1243 | |
| 1244 | static int |
| 1245 | mss_probe(device_t dev) |
| 1246 | { |
| 1247 | u_char tmp, tmpx; |
| 1248 | int flags, irq, drq, result = ENXIO, setres = 0; |
| 1249 | struct mss_info *mss; |
| 1250 | |
| 1251 | if (isa_get_logicalid(dev)) return ENXIO; /* not yet */ |
| 1252 | |
| 1253 | mss = (struct mss_info *)malloc(sizeof *mss, M_DEVBUF, M_NOWAIT | M_ZERO); |
| 1254 | if (!mss) return ENXIO; |
| 1255 | |
| 1256 | mss->io_rid = 0; |
| 1257 | mss->conf_rid = -1; |
| 1258 | mss->irq_rid = 0; |
| 1259 | mss->drq1_rid = 0; |
| 1260 | mss->drq2_rid = -1; |
| 1261 | mss->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT, &mss->io_rid, |
| 1262 | 0, ~0, 8, RF_ACTIVE); |
| 1263 | if (!mss->io_base) { |
| 1264 | BVDDB(printf("mss_probe: no address given, try 0x%x\n", 0x530)); |
| 1265 | mss->io_rid = 0; |
| 1266 | /* XXX verify this */ |
| 1267 | setres = 1; |
| 1268 | bus_set_resource(dev, SYS_RES_IOPORT, mss->io_rid, |
| 1269 | 0x530, 8); |
| 1270 | mss->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT, &mss->io_rid, |
| 1271 | 0, ~0, 8, RF_ACTIVE); |
| 1272 | } |
| 1273 | if (!mss->io_base) goto no; |
| 1274 | |
| 1275 | /* got irq/dma regs? */ |
| 1276 | flags = device_get_flags(dev); |
| 1277 | irq = isa_get_irq(dev); |
| 1278 | drq = isa_get_drq(dev); |
| 1279 | |
| 1280 | if (!(device_get_flags(dev) & DV_F_TRUE_MSS)) goto mss_probe_end; |
| 1281 | |
| 1282 | /* |
| 1283 | * Check if the IO port returns valid signature. The original MS |
| 1284 | * Sound system returns 0x04 while some cards |
| 1285 | * (AudioTriX Pro for example) return 0x00 or 0x0f. |
| 1286 | */ |
| 1287 | |
| 1288 | device_set_desc(dev, "MSS"); |
| 1289 | tmpx = tmp = io_rd(mss, 3); |
| 1290 | if (tmp == 0xff) { /* Bus float */ |
| 1291 | BVDDB(printf("I/O addr inactive (%x), try pseudo_mss\n", tmp)); |
| 1292 | device_set_flags(dev, flags & ~DV_F_TRUE_MSS); |
| 1293 | goto mss_probe_end; |
| 1294 | } |
| 1295 | tmp &= 0x3f; |
| 1296 | if (!(tmp == 0x04 || tmp == 0x0f || tmp == 0x00)) { |
| 1297 | BVDDB(printf("No MSS signature detected on port 0x%lx (0x%x)\n", |
| 1298 | rman_get_start(mss->io_base), tmpx)); |
| 1299 | goto no; |
| 1300 | } |
| 1301 | #ifdef PC98 |
| 1302 | if (irq > 12) { |
| 1303 | #else |
| 1304 | if (irq > 11) { |
| 1305 | #endif |
| 1306 | printf("MSS: Bad IRQ %d\n", irq); |
| 1307 | goto no; |
| 1308 | } |
| 1309 | if (!(drq == 0 || drq == 1 || drq == 3)) { |
| 1310 | printf("MSS: Bad DMA %d\n", drq); |
| 1311 | goto no; |
| 1312 | } |
| 1313 | if (tmpx & 0x80) { |
| 1314 | /* 8-bit board: only drq1/3 and irq7/9 */ |
| 1315 | if (drq == 0) { |
| 1316 | printf("MSS: Can't use DMA0 with a 8 bit card/slot\n"); |
| 1317 | goto no; |
| 1318 | } |
| 1319 | if (!(irq == 7 || irq == 9)) { |
| 1320 | printf("MSS: Can't use IRQ%d with a 8 bit card/slot\n", |
| 1321 | irq); |
| 1322 | goto no; |
| 1323 | } |
| 1324 | } |
| 1325 | mss_probe_end: |
| 1326 | result = mss_detect(dev, mss); |
| 1327 | no: |
| 1328 | mss_release_resources(mss, dev); |
| 1329 | #if 0 |
| 1330 | if (setres) ISA_DELETE_RESOURCE(device_get_parent(dev), dev, |
| 1331 | SYS_RES_IOPORT, mss->io_rid); /* XXX ? */ |
| 1332 | #endif |
| 1333 | return result; |
| 1334 | } |
| 1335 | |
| 1336 | static int |
| 1337 | mss_detect(device_t dev, struct mss_info *mss) |
| 1338 | { |
| 1339 | int i; |
| 1340 | u_char tmp = 0, tmp1, tmp2; |
| 1341 | char *name, *yamaha; |
| 1342 | |
| 1343 | if (mss->bd_id != 0) { |
| 1344 | device_printf(dev, "presel bd_id 0x%04x -- %s\n", mss->bd_id, |
| 1345 | device_get_desc(dev)); |
| 1346 | return 0; |
| 1347 | } |
| 1348 | |
| 1349 | name = "AD1848"; |
| 1350 | mss->bd_id = MD_AD1848; /* AD1848 or CS4248 */ |
| 1351 | |
| 1352 | if (opti_detect(dev, mss)) { |
| 1353 | switch (mss->bd_id) { |
| 1354 | case MD_OPTI924: |
| 1355 | name = "OPTi924"; |
| 1356 | break; |
| 1357 | case MD_OPTI930: |
| 1358 | name = "OPTi930"; |
| 1359 | break; |
| 1360 | } |
| 1361 | printf("Found OPTi device %s\n", name); |
| 1362 | if (opti_init(dev, mss) == 0) goto gotit; |
| 1363 | } |
| 1364 | |
| 1365 | /* |
| 1366 | * Check that the I/O address is in use. |
| 1367 | * |
| 1368 | * bit 7 of the base I/O port is known to be 0 after the chip has |
| 1369 | * performed its power on initialization. Just assume this has |
| 1370 | * happened before the OS is starting. |
| 1371 | * |
| 1372 | * If the I/O address is unused, it typically returns 0xff. |
| 1373 | */ |
| 1374 | |
| 1375 | for (i = 0; i < 10; i++) |
| 1376 | if ((tmp = io_rd(mss, MSS_INDEX)) & MSS_IDXBUSY) DELAY(10000); |
| 1377 | else break; |
| 1378 | |
| 1379 | if (i >= 10) { /* Not a AD1848 */ |
| 1380 | BVDDB(printf("mss_detect, busy still set (0x%02x)\n", tmp)); |
| 1381 | goto no; |
| 1382 | } |
| 1383 | /* |
| 1384 | * Test if it's possible to change contents of the indirect |
| 1385 | * registers. Registers 0 and 1 are ADC volume registers. The bit |
| 1386 | * 0x10 is read only so try to avoid using it. |
| 1387 | */ |
| 1388 | |
| 1389 | ad_write(mss, 0, 0xaa); |
| 1390 | ad_write(mss, 1, 0x45);/* 0x55 with bit 0x10 clear */ |
| 1391 | tmp1 = ad_read(mss, 0); |
| 1392 | tmp2 = ad_read(mss, 1); |
| 1393 | if (tmp1 != 0xaa || tmp2 != 0x45) { |
| 1394 | BVDDB(printf("mss_detect error - IREG (%x/%x)\n", tmp1, tmp2)); |
| 1395 | goto no; |
| 1396 | } |
| 1397 | |
| 1398 | ad_write(mss, 0, 0x45); |
| 1399 | ad_write(mss, 1, 0xaa); |
| 1400 | tmp1 = ad_read(mss, 0); |
| 1401 | tmp2 = ad_read(mss, 1); |
| 1402 | if (tmp1 != 0x45 || tmp2 != 0xaa) { |
| 1403 | BVDDB(printf("mss_detect error - IREG2 (%x/%x)\n", tmp1, tmp2)); |
| 1404 | goto no; |
| 1405 | } |
| 1406 | |
| 1407 | /* |
| 1408 | * The indirect register I12 has some read only bits. Lets try to |
| 1409 | * change them. |
| 1410 | */ |
| 1411 | |
| 1412 | tmp = ad_read(mss, 12); |
| 1413 | ad_write(mss, 12, (~tmp) & 0x0f); |
| 1414 | tmp1 = ad_read(mss, 12); |
| 1415 | |
| 1416 | if ((tmp & 0x0f) != (tmp1 & 0x0f)) { |
| 1417 | BVDDB(printf("mss_detect - I12 (0x%02x was 0x%02x)\n", tmp1, tmp)); |
| 1418 | goto no; |
| 1419 | } |
| 1420 | |
| 1421 | /* |
| 1422 | * NOTE! Last 4 bits of the reg I12 tell the chip revision. |
| 1423 | * 0x01=RevB |
| 1424 | * 0x0A=RevC. also CS4231/CS4231A and OPTi931 |
| 1425 | */ |
| 1426 | |
| 1427 | BVDDB(printf("mss_detect - chip revision 0x%02x\n", tmp & 0x0f);) |
| 1428 | |
| 1429 | /* |
| 1430 | * The original AD1848/CS4248 has just 16 indirect registers. This |
| 1431 | * means that I0 and I16 should return the same value (etc.). Ensure |
| 1432 | * that the Mode2 enable bit of I12 is 0. Otherwise this test fails |
| 1433 | * with new parts. |
| 1434 | */ |
| 1435 | |
| 1436 | ad_write(mss, 12, 0); /* Mode2=disabled */ |
| 1437 | #if 0 |
| 1438 | for (i = 0; i < 16; i++) { |
| 1439 | if ((tmp1 = ad_read(mss, i)) != (tmp2 = ad_read(mss, i + 16))) { |
| 1440 | BVDDB(printf("mss_detect warning - I%d: 0x%02x/0x%02x\n", |
| 1441 | i, tmp1, tmp2)); |
| 1442 | /* |
| 1443 | * note - this seems to fail on the 4232 on I11. So we just break |
| 1444 | * rather than fail. (which makes this test pointless - cg) |
| 1445 | */ |
| 1446 | break; /* return 0; */ |
| 1447 | } |
| 1448 | } |
| 1449 | #endif |
| 1450 | /* |
| 1451 | * Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit |
| 1452 | * (0x40). The bit 0x80 is always 1 in CS4248 and CS4231. |
| 1453 | * |
| 1454 | * On the OPTi931, however, I12 is readonly and only contains the |
| 1455 | * chip revision ID (as in the CS4231A). The upper bits return 0. |
| 1456 | */ |
| 1457 | |
| 1458 | ad_write(mss, 12, 0x40); /* Set mode2, clear 0x80 */ |
| 1459 | |
| 1460 | tmp1 = ad_read(mss, 12); |
| 1461 | if (tmp1 & 0x80) name = "CS4248"; /* Our best knowledge just now */ |
| 1462 | if ((tmp1 & 0xf0) == 0x00) { |
| 1463 | BVDDB(printf("this should be an OPTi931\n");) |
| 1464 | } else if ((tmp1 & 0xc0) != 0xC0) goto gotit; |
| 1465 | /* |
| 1466 | * The 4231 has bit7=1 always, and bit6 we just set to 1. |
| 1467 | * We want to check that this is really a CS4231 |
| 1468 | * Verify that setting I0 doesn't change I16. |
| 1469 | */ |
| 1470 | ad_write(mss, 16, 0); /* Set I16 to known value */ |
| 1471 | ad_write(mss, 0, 0x45); |
| 1472 | if ((tmp1 = ad_read(mss, 16)) == 0x45) goto gotit; |
| 1473 | |
| 1474 | ad_write(mss, 0, 0xaa); |
| 1475 | if ((tmp1 = ad_read(mss, 16)) == 0xaa) { /* Rotten bits? */ |
| 1476 | BVDDB(printf("mss_detect error - step H(%x)\n", tmp1)); |
| 1477 | goto no; |
| 1478 | } |
| 1479 | /* Verify that some bits of I25 are read only. */ |
| 1480 | tmp1 = ad_read(mss, 25); /* Original bits */ |
| 1481 | ad_write(mss, 25, ~tmp1); /* Invert all bits */ |
| 1482 | if ((ad_read(mss, 25) & 0xe7) == (tmp1 & 0xe7)) { |
| 1483 | int id; |
| 1484 | |
| 1485 | /* It's at least CS4231 */ |
| 1486 | name = "CS4231"; |
| 1487 | mss->bd_id = MD_CS42XX; |
| 1488 | |
| 1489 | /* |
| 1490 | * It could be an AD1845 or CS4231A as well. |
| 1491 | * CS4231 and AD1845 report the same revision info in I25 |
| 1492 | * while the CS4231A reports different. |
| 1493 | */ |
| 1494 | |
| 1495 | id = ad_read(mss, 25) & 0xe7; |
| 1496 | /* |
| 1497 | * b7-b5 = version number; |
| 1498 | * 100 : all CS4231 |
| 1499 | * 101 : CS4231A |
| 1500 | * |
| 1501 | * b2-b0 = chip id; |
| 1502 | */ |
| 1503 | switch (id) { |
| 1504 | |
| 1505 | case 0xa0: |
| 1506 | name = "CS4231A"; |
| 1507 | mss->bd_id = MD_CS42XX; |
| 1508 | break; |
| 1509 | |
| 1510 | case 0xa2: |
| 1511 | name = "CS4232"; |
| 1512 | mss->bd_id = MD_CS42XX; |
| 1513 | break; |
| 1514 | |
| 1515 | case 0xb2: |
| 1516 | /* strange: the 4231 data sheet says b4-b3 are XX |
| 1517 | * so this should be the same as 0xa2 |
| 1518 | */ |
| 1519 | name = "CS4232A"; |
| 1520 | mss->bd_id = MD_CS42XX; |
| 1521 | break; |
| 1522 | |
| 1523 | case 0x80: |
| 1524 | /* |
| 1525 | * It must be a CS4231 or AD1845. The register I23 |
| 1526 | * of CS4231 is undefined and it appears to be read |
| 1527 | * only. AD1845 uses I23 for setting sample rate. |
| 1528 | * Assume the chip is AD1845 if I23 is changeable. |
| 1529 | */ |
| 1530 | |
| 1531 | tmp = ad_read(mss, 23); |
| 1532 | |
| 1533 | ad_write(mss, 23, ~tmp); |
| 1534 | if (ad_read(mss, 23) != tmp) { /* AD1845 ? */ |
| 1535 | name = "AD1845"; |
| 1536 | mss->bd_id = MD_AD1845; |
| 1537 | } |
| 1538 | ad_write(mss, 23, tmp); /* Restore */ |
| 1539 | |
| 1540 | yamaha = ymf_test(dev, mss); |
| 1541 | if (yamaha) { |
| 1542 | mss->bd_id = MD_YM0020; |
| 1543 | name = yamaha; |
| 1544 | } |
| 1545 | break; |
| 1546 | |
| 1547 | case 0x83: /* CS4236 */ |
| 1548 | case 0x03: /* CS4236 on Intel PR440FX motherboard XXX */ |
| 1549 | name = "CS4236"; |
| 1550 | mss->bd_id = MD_CS42XX; |
| 1551 | break; |
| 1552 | |
| 1553 | default: /* Assume CS4231 */ |
| 1554 | BVDDB(printf("unknown id 0x%02x, assuming CS4231\n", id);) |
| 1555 | mss->bd_id = MD_CS42XX; |
| 1556 | } |
| 1557 | } |
| 1558 | ad_write(mss, 25, tmp1); /* Restore bits */ |
| 1559 | gotit: |
| 1560 | BVDDB(printf("mss_detect() - Detected %s\n", name)); |
| 1561 | device_set_desc(dev, name); |
| 1562 | device_set_flags(dev, |
| 1563 | ((device_get_flags(dev) & ~DV_F_DEV_MASK) | |
| 1564 | ((mss->bd_id << DV_F_DEV_SHIFT) & DV_F_DEV_MASK))); |
| 1565 | return 0; |
| 1566 | no: |
| 1567 | return ENXIO; |
| 1568 | } |
| 1569 | |
| 1570 | static int |
| 1571 | opti_detect(device_t dev, struct mss_info *mss) |
| 1572 | { |
| 1573 | int c; |
| 1574 | static const struct opticard { |
| 1575 | int boardid; |
| 1576 | int passwdreg; |
| 1577 | int password; |
| 1578 | int base; |
| 1579 | int indir_reg; |
| 1580 | } cards[] = { |
| 1581 | { MD_OPTI930, 0, 0xe4, 0xf8f, 0xe0e }, /* 930 */ |
| 1582 | { MD_OPTI924, 3, 0xe5, 0xf8c, 0, }, /* 924 */ |
| 1583 | { 0 }, |
| 1584 | }; |
| 1585 | mss->conf_rid = 3; |
| 1586 | mss->indir_rid = 4; |
| 1587 | for (c = 0; cards[c].base; c++) { |
| 1588 | mss->optibase = cards[c].base; |
| 1589 | mss->password = cards[c].password; |
| 1590 | mss->passwdreg = cards[c].passwdreg; |
| 1591 | mss->bd_id = cards[c].boardid; |
| 1592 | |
| 1593 | if (cards[c].indir_reg) |
| 1594 | mss->indir = bus_alloc_resource(dev, SYS_RES_IOPORT, |
| 1595 | &mss->indir_rid, cards[c].indir_reg, |
| 1596 | cards[c].indir_reg+1, 1, RF_ACTIVE); |
| 1597 | |
| 1598 | mss->conf_base = bus_alloc_resource(dev, SYS_RES_IOPORT, |
| 1599 | &mss->conf_rid, mss->optibase, mss->optibase+9, |
| 1600 | 9, RF_ACTIVE); |
| 1601 | |
| 1602 | if (opti_read(mss, 1) != 0xff) { |
| 1603 | return 1; |
| 1604 | } else { |
| 1605 | if (mss->indir) |
| 1606 | bus_release_resource(dev, SYS_RES_IOPORT, mss->indir_rid, mss->indir); |
| 1607 | mss->indir = NULL; |
| 1608 | if (mss->conf_base) |
| 1609 | bus_release_resource(dev, SYS_RES_IOPORT, mss->conf_rid, mss->conf_base); |
| 1610 | mss->conf_base = NULL; |
| 1611 | } |
| 1612 | } |
| 1613 | return 0; |
| 1614 | } |
| 1615 | |
| 1616 | static char * |
| 1617 | ymf_test(device_t dev, struct mss_info *mss) |
| 1618 | { |
| 1619 | static int ports[] = {0x370, 0x310, 0x538}; |
| 1620 | int p, i, j, version; |
| 1621 | static char *chipset[] = { |
| 1622 | NULL, /* 0 */ |
| 1623 | "OPL3-SA2 (YMF711)", /* 1 */ |
| 1624 | "OPL3-SA3 (YMF715)", /* 2 */ |
| 1625 | "OPL3-SA3 (YMF715)", /* 3 */ |
| 1626 | "OPL3-SAx (YMF719)", /* 4 */ |
| 1627 | "OPL3-SAx (YMF719)", /* 5 */ |
| 1628 | "OPL3-SAx (YMF719)", /* 6 */ |
| 1629 | "OPL3-SAx (YMF719)", /* 7 */ |
| 1630 | }; |
| 1631 | |
| 1632 | for (p = 0; p < 3; p++) { |
| 1633 | mss->conf_rid = 1; |
| 1634 | mss->conf_base = bus_alloc_resource(dev, |
| 1635 | SYS_RES_IOPORT, |
| 1636 | &mss->conf_rid, |
| 1637 | ports[p], ports[p] + 1, 2, |
| 1638 | RF_ACTIVE); |
| 1639 | if (!mss->conf_base) return 0; |
| 1640 | |
| 1641 | /* Test the index port of the config registers */ |
| 1642 | i = port_rd(mss->conf_base, 0); |
| 1643 | port_wr(mss->conf_base, 0, OPL3SAx_DMACONF); |
| 1644 | j = (port_rd(mss->conf_base, 0) == OPL3SAx_DMACONF)? 1 : 0; |
| 1645 | port_wr(mss->conf_base, 0, i); |
| 1646 | if (!j) { |
| 1647 | bus_release_resource(dev, SYS_RES_IOPORT, |
| 1648 | mss->conf_rid, mss->conf_base); |
| 1649 | #ifdef PC98 |
| 1650 | /* PC98 need this. I don't know reason why. */ |
| 1651 | bus_delete_resource(dev, SYS_RES_IOPORT, mss->conf_rid); |
| 1652 | #endif |
| 1653 | mss->conf_base = 0; |
| 1654 | continue; |
| 1655 | } |
| 1656 | version = conf_rd(mss, OPL3SAx_MISC) & 0x07; |
| 1657 | return chipset[version]; |
| 1658 | } |
| 1659 | return NULL; |
| 1660 | } |
| 1661 | |
| 1662 | static int |
| 1663 | mss_doattach(device_t dev, struct mss_info *mss) |
| 1664 | { |
| 1665 | int pdma, rdma, flags = device_get_flags(dev); |
| 1666 | char status[SND_STATUSLEN], status2[SND_STATUSLEN]; |
| 1667 | |
| 1668 | mss->lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc"); |
| 1669 | mss->bufsize = pcm_getbuffersize(dev, 4096, MSS_DEFAULT_BUFSZ, 65536); |
| 1670 | if (!mss_alloc_resources(mss, dev)) goto no; |
| 1671 | mss_init(mss, dev); |
| 1672 | pdma = rman_get_start(mss->drq1); |
| 1673 | rdma = rman_get_start(mss->drq2); |
| 1674 | if (flags & DV_F_TRUE_MSS) { |
| 1675 | /* has IRQ/DMA registers, set IRQ and DMA addr */ |
| 1676 | #ifdef PC98 /* CS423[12] in PC98 can use IRQ3,5,10,12 */ |
| 1677 | static char interrupt_bits[13] = |
| 1678 | {-1, -1, -1, 0x08, -1, 0x10, -1, -1, -1, -1, 0x18, -1, 0x20}; |
| 1679 | #else |
| 1680 | static char interrupt_bits[12] = |
| 1681 | {-1, -1, -1, -1, -1, 0x28, -1, 0x08, -1, 0x10, 0x18, 0x20}; |
| 1682 | #endif |
| 1683 | static char pdma_bits[4] = {1, 2, -1, 3}; |
| 1684 | static char valid_rdma[4] = {1, 0, -1, 0}; |
| 1685 | char bits; |
| 1686 | |
| 1687 | if (!mss->irq || (bits = interrupt_bits[rman_get_start(mss->irq)]) == -1) |
| 1688 | goto no; |
| 1689 | #ifndef PC98 /* CS423[12] in PC98 don't support this. */ |
| 1690 | io_wr(mss, 0, bits | 0x40); /* config port */ |
| 1691 | if ((io_rd(mss, 3) & 0x40) == 0) device_printf(dev, "IRQ Conflict?\n"); |
| 1692 | #endif |
| 1693 | /* Write IRQ+DMA setup */ |
| 1694 | if (pdma_bits[pdma] == -1) goto no; |
| 1695 | bits |= pdma_bits[pdma]; |
| 1696 | if (pdma != rdma) { |
| 1697 | if (rdma == valid_rdma[pdma]) bits |= 4; |
| 1698 | else { |
| 1699 | printf("invalid dual dma config %d:%d\n", pdma, rdma); |
| 1700 | goto no; |
| 1701 | } |
| 1702 | } |
| 1703 | io_wr(mss, 0, bits); |
| 1704 | printf("drq/irq conf %x\n", io_rd(mss, 0)); |
| 1705 | } |
| 1706 | mixer_init(dev, (mss->bd_id == MD_YM0020)? &ymmix_mixer_class : &mssmix_mixer_class, mss); |
| 1707 | switch (mss->bd_id) { |
| 1708 | case MD_OPTI931: |
| 1709 | snd_setup_intr(dev, mss->irq, INTR_MPSAFE, opti931_intr, mss, &mss->ih); |
| 1710 | break; |
| 1711 | default: |
| 1712 | snd_setup_intr(dev, mss->irq, INTR_MPSAFE, mss_intr, mss, &mss->ih); |
| 1713 | } |
| 1714 | if (pdma == rdma) |
| 1715 | pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX); |
| 1716 | if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, |
| 1717 | /*lowaddr*/BUS_SPACE_MAXADDR_24BIT, |
| 1718 | /*highaddr*/BUS_SPACE_MAXADDR, |
| 1719 | /*filter*/NULL, /*filterarg*/NULL, |
| 1720 | /*maxsize*/mss->bufsize, /*nsegments*/1, |
| 1721 | /*maxsegz*/0x3ffff, |
| 1722 | /*flags*/0, &mss->parent_dmat) != 0) { |
| 1723 | device_printf(dev, "unable to create dma tag\n"); |
| 1724 | goto no; |
| 1725 | } |
| 1726 | |
| 1727 | if (pdma != rdma) |
| 1728 | snprintf(status2, SND_STATUSLEN, ":%d", rdma); |
| 1729 | else |
| 1730 | status2[0] = '\0'; |
| 1731 | |
| 1732 | snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %d%s bufsz %u", |
| 1733 | rman_get_start(mss->io_base), rman_get_start(mss->irq), pdma, status2, mss->bufsize); |
| 1734 | |
| 1735 | if (pcm_register(dev, mss, 1, 1)) goto no; |
| 1736 | pcm_addchan(dev, PCMDIR_REC, &msschan_class, mss); |
| 1737 | pcm_addchan(dev, PCMDIR_PLAY, &msschan_class, mss); |
| 1738 | pcm_setstatus(dev, status); |
| 1739 | |
| 1740 | return 0; |
| 1741 | no: |
| 1742 | mss_release_resources(mss, dev); |
| 1743 | return ENXIO; |
| 1744 | } |
| 1745 | |
| 1746 | static int |
| 1747 | mss_detach(device_t dev) |
| 1748 | { |
| 1749 | int r; |
| 1750 | struct mss_info *mss; |
| 1751 | |
| 1752 | r = pcm_unregister(dev); |
| 1753 | if (r) |
| 1754 | return r; |
| 1755 | |
| 1756 | mss = pcm_getdevinfo(dev); |
| 1757 | mss_release_resources(mss, dev); |
| 1758 | |
| 1759 | return 0; |
| 1760 | } |
| 1761 | |
| 1762 | static int |
| 1763 | mss_attach(device_t dev) |
| 1764 | { |
| 1765 | struct mss_info *mss; |
| 1766 | int flags = device_get_flags(dev); |
| 1767 | |
| 1768 | mss = (struct mss_info *)malloc(sizeof *mss, M_DEVBUF, M_NOWAIT | M_ZERO); |
| 1769 | if (!mss) return ENXIO; |
| 1770 | |
| 1771 | mss->io_rid = 0; |
| 1772 | mss->conf_rid = -1; |
| 1773 | mss->irq_rid = 0; |
| 1774 | mss->drq1_rid = 0; |
| 1775 | mss->drq2_rid = -1; |
| 1776 | if (flags & DV_F_DUAL_DMA) { |
| 1777 | bus_set_resource(dev, SYS_RES_DRQ, 1, |
| 1778 | flags & DV_F_DRQ_MASK, 1); |
| 1779 | mss->drq2_rid = 1; |
| 1780 | } |
| 1781 | mss->bd_id = (device_get_flags(dev) & DV_F_DEV_MASK) >> DV_F_DEV_SHIFT; |
| 1782 | if (mss->bd_id == MD_YM0020) ymf_test(dev, mss); |
| 1783 | return mss_doattach(dev, mss); |
| 1784 | } |
| 1785 | |
| 1786 | /* |
| 1787 | * mss_resume() is the code to allow a laptop to resume using the sound |
| 1788 | * card. |
| 1789 | * |
| 1790 | * This routine re-sets the state of the board to the state before going |
| 1791 | * to sleep. According to the yamaha docs this is the right thing to do, |
| 1792 | * but getting DMA restarted appears to be a bit of a trick, so the device |
| 1793 | * has to be closed and re-opened to be re-used, but there is no skipping |
| 1794 | * problem, and volume, bass/treble and most other things are restored |
| 1795 | * properly. |
| 1796 | * |
| 1797 | */ |
| 1798 | |
| 1799 | static int |
| 1800 | mss_resume(device_t dev) |
| 1801 | { |
| 1802 | /* |
| 1803 | * Restore the state taken below. |
| 1804 | */ |
| 1805 | struct mss_info *mss; |
| 1806 | int i; |
| 1807 | |
| 1808 | mss = pcm_getdevinfo(dev); |
| 1809 | |
| 1810 | if (mss->bd_id == MD_YM0020) |
| 1811 | { |
| 1812 | /* This works on a Toshiba Libretto 100CT. */ |
| 1813 | for (i = 0; i < MSS_INDEXED_REGS; i++) |
| 1814 | ad_write(mss, i, mss->mss_indexed_regs[i]); |
| 1815 | for (i = 0; i < OPL_INDEXED_REGS; i++) |
| 1816 | conf_wr(mss, i, mss->opl_indexed_regs[i]); |
| 1817 | mss_intr(mss); |
| 1818 | } |
| 1819 | return 0; |
| 1820 | |
| 1821 | } |
| 1822 | |
| 1823 | /* |
| 1824 | * mss_suspend() is the code that gets called right before a laptop |
| 1825 | * suspends. |
| 1826 | * |
| 1827 | * This code saves the state of the sound card right before shutdown |
| 1828 | * so it can be restored above. |
| 1829 | * |
| 1830 | */ |
| 1831 | |
| 1832 | static int |
| 1833 | mss_suspend(device_t dev) |
| 1834 | { |
| 1835 | int i; |
| 1836 | struct mss_info *mss; |
| 1837 | |
| 1838 | mss = pcm_getdevinfo(dev); |
| 1839 | |
| 1840 | if(mss->bd_id == MD_YM0020) |
| 1841 | { |
| 1842 | /* this stops playback. */ |
| 1843 | conf_wr(mss, 0x12, 0x0c); |
| 1844 | for(i = 0; i < MSS_INDEXED_REGS; i++) |
| 1845 | mss->mss_indexed_regs[i] = ad_read(mss, i); |
| 1846 | for(i = 0; i < OPL_INDEXED_REGS; i++) |
| 1847 | mss->opl_indexed_regs[i] = conf_rd(mss, i); |
| 1848 | mss->opl_indexed_regs[0x12] = 0x0; |
| 1849 | } |
| 1850 | return 0; |
| 1851 | } |
| 1852 | |
| 1853 | static device_method_t mss_methods[] = { |
| 1854 | /* Device interface */ |
| 1855 | DEVMETHOD(device_probe, mss_probe), |
| 1856 | DEVMETHOD(device_attach, mss_attach), |
| 1857 | DEVMETHOD(device_detach, mss_detach), |
| 1858 | DEVMETHOD(device_suspend, mss_suspend), |
| 1859 | DEVMETHOD(device_resume, mss_resume), |
| 1860 | |
| 1861 | { 0, 0 } |
| 1862 | }; |
| 1863 | |
| 1864 | static driver_t mss_driver = { |
| 1865 | "pcm", |
| 1866 | mss_methods, |
| 1867 | PCM_SOFTC_SIZE, |
| 1868 | }; |
| 1869 | |
| 1870 | DRIVER_MODULE(snd_mss, isa, mss_driver, pcm_devclass, 0, 0); |
| 1871 | MODULE_DEPEND(snd_mss, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); |
| 1872 | MODULE_VERSION(snd_mss, 1); |
| 1873 | |
| 1874 | static int |
| 1875 | azt2320_mss_mode(struct mss_info *mss, device_t dev) |
| 1876 | { |
| 1877 | struct resource *sbport; |
| 1878 | int i, ret, rid; |
| 1879 | |
| 1880 | rid = 0; |
| 1881 | ret = -1; |
| 1882 | sbport = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, |
| 1883 | 0, ~0, 1, RF_ACTIVE); |
| 1884 | if (sbport) { |
| 1885 | for (i = 0; i < 1000; i++) { |
| 1886 | if ((port_rd(sbport, SBDSP_STATUS) & 0x80)) |
| 1887 | DELAY((i > 100) ? 1000 : 10); |
| 1888 | else { |
| 1889 | port_wr(sbport, SBDSP_CMD, 0x09); |
| 1890 | break; |
| 1891 | } |
| 1892 | } |
| 1893 | for (i = 0; i < 1000; i++) { |
| 1894 | if ((port_rd(sbport, SBDSP_STATUS) & 0x80)) |
| 1895 | DELAY((i > 100) ? 1000 : 10); |
| 1896 | else { |
| 1897 | port_wr(sbport, SBDSP_CMD, 0x00); |
| 1898 | ret = 0; |
| 1899 | break; |
| 1900 | } |
| 1901 | } |
| 1902 | DELAY(1000); |
| 1903 | bus_release_resource(dev, SYS_RES_IOPORT, rid, sbport); |
| 1904 | } |
| 1905 | return ret; |
| 1906 | } |
| 1907 | |
| 1908 | static struct isa_pnp_id pnpmss_ids[] = { |
| 1909 | {0x0000630e, "CS423x"}, /* CSC0000 */ |
| 1910 | {0x0001630e, "CS423x-PCI"}, /* CSC0100 */ |
| 1911 | {0x01000000, "CMI8330"}, /* @@@0001 */ |
| 1912 | {0x2100a865, "Yamaha OPL-SAx"}, /* YMH0021 */ |
| 1913 | {0x1110d315, "ENSONIQ SoundscapeVIVO"}, /* ENS1011 */ |
| 1914 | {0x1093143e, "OPTi931"}, /* OPT9310 */ |
| 1915 | {0x5092143e, "OPTi925"}, /* OPT9250 XXX guess */ |
| 1916 | {0x0000143e, "OPTi924"}, /* OPT0924 */ |
| 1917 | {0x1022b839, "Neomagic 256AV (non-ac97)"}, /* NMX2210 */ |
| 1918 | {0x01005407, "Aztech 2320"}, /* AZT0001 */ |
| 1919 | #if 0 |
| 1920 | {0x0000561e, "GusPnP"}, /* GRV0000 */ |
| 1921 | #endif |
| 1922 | {0}, |
| 1923 | }; |
| 1924 | |
| 1925 | static int |
| 1926 | pnpmss_probe(device_t dev) |
| 1927 | { |
| 1928 | u_int32_t lid, vid; |
| 1929 | |
| 1930 | lid = isa_get_logicalid(dev); |
| 1931 | vid = isa_get_vendorid(dev); |
| 1932 | if (lid == 0x01000000 && vid != 0x0100a90d) /* CMI0001 */ |
| 1933 | return ENXIO; |
| 1934 | return ISA_PNP_PROBE(device_get_parent(dev), dev, pnpmss_ids); |
| 1935 | } |
| 1936 | |
| 1937 | static int |
| 1938 | pnpmss_attach(device_t dev) |
| 1939 | { |
| 1940 | struct mss_info *mss; |
| 1941 | |
| 1942 | mss = (struct mss_info *)malloc(sizeof *mss, M_DEVBUF, M_NOWAIT | M_ZERO); |
| 1943 | if (!mss) |
| 1944 | return ENXIO; |
| 1945 | |
| 1946 | mss->io_rid = 0; |
| 1947 | mss->conf_rid = -1; |
| 1948 | mss->irq_rid = 0; |
| 1949 | mss->drq1_rid = 0; |
| 1950 | mss->drq2_rid = 1; |
| 1951 | mss->bd_id = MD_CS42XX; |
| 1952 | |
| 1953 | switch (isa_get_logicalid(dev)) { |
| 1954 | case 0x0000630e: /* CSC0000 */ |
| 1955 | case 0x0001630e: /* CSC0100 */ |
| 1956 | mss->bd_flags |= BD_F_MSS_OFFSET; |
| 1957 | break; |
| 1958 | |
| 1959 | case 0x2100a865: /* YHM0021 */ |
| 1960 | mss->io_rid = 1; |
| 1961 | mss->conf_rid = 4; |
| 1962 | mss->bd_id = MD_YM0020; |
| 1963 | break; |
| 1964 | |
| 1965 | case 0x1110d315: /* ENS1011 */ |
| 1966 | mss->io_rid = 1; |
| 1967 | mss->bd_id = MD_VIVO; |
| 1968 | break; |
| 1969 | |
| 1970 | case 0x1093143e: /* OPT9310 */ |
| 1971 | mss->bd_flags |= BD_F_MSS_OFFSET; |
| 1972 | mss->conf_rid = 3; |
| 1973 | mss->bd_id = MD_OPTI931; |
| 1974 | break; |
| 1975 | |
| 1976 | case 0x5092143e: /* OPT9250 XXX guess */ |
| 1977 | mss->io_rid = 1; |
| 1978 | mss->conf_rid = 3; |
| 1979 | mss->bd_id = MD_OPTI925; |
| 1980 | break; |
| 1981 | |
| 1982 | case 0x0000143e: /* OPT0924 */ |
| 1983 | mss->password = 0xe5; |
| 1984 | mss->passwdreg = 3; |
| 1985 | mss->optibase = 0xf0c; |
| 1986 | mss->io_rid = 2; |
| 1987 | mss->conf_rid = 3; |
| 1988 | mss->bd_id = MD_OPTI924; |
| 1989 | mss->bd_flags |= BD_F_924PNP; |
| 1990 | if(opti_init(dev, mss) != 0) |
| 1991 | return ENXIO; |
| 1992 | break; |
| 1993 | |
| 1994 | case 0x1022b839: /* NMX2210 */ |
| 1995 | mss->io_rid = 1; |
| 1996 | break; |
| 1997 | |
| 1998 | case 0x01005407: /* AZT0001 */ |
| 1999 | /* put into MSS mode first (snatched from NetBSD) */ |
| 2000 | if (azt2320_mss_mode(mss, dev) == -1) |
| 2001 | return ENXIO; |
| 2002 | |
| 2003 | mss->bd_flags |= BD_F_MSS_OFFSET; |
| 2004 | mss->io_rid = 2; |
| 2005 | break; |
| 2006 | |
| 2007 | #if 0 |
| 2008 | case 0x0000561e: /* GRV0000 */ |
| 2009 | mss->bd_flags |= BD_F_MSS_OFFSET; |
| 2010 | mss->io_rid = 2; |
| 2011 | mss->conf_rid = 1; |
| 2012 | mss->drq1_rid = 1; |
| 2013 | mss->drq2_rid = 0; |
| 2014 | mss->bd_id = MD_GUSPNP; |
| 2015 | break; |
| 2016 | #endif |
| 2017 | case 0x01000000: /* @@@0001 */ |
| 2018 | mss->drq2_rid = -1; |
| 2019 | break; |
| 2020 | |
| 2021 | /* Unknown MSS default. We could let the CSC0000 stuff match too */ |
| 2022 | default: |
| 2023 | mss->bd_flags |= BD_F_MSS_OFFSET; |
| 2024 | break; |
| 2025 | } |
| 2026 | return mss_doattach(dev, mss); |
| 2027 | } |
| 2028 | |
| 2029 | static int |
| 2030 | opti_init(device_t dev, struct mss_info *mss) |
| 2031 | { |
| 2032 | int flags = device_get_flags(dev); |
| 2033 | int basebits = 0; |
| 2034 | |
| 2035 | if (!mss->conf_base) { |
| 2036 | bus_set_resource(dev, SYS_RES_IOPORT, mss->conf_rid, |
| 2037 | mss->optibase, 0x9); |
| 2038 | |
| 2039 | mss->conf_base = bus_alloc_resource(dev, SYS_RES_IOPORT, |
| 2040 | &mss->conf_rid, mss->optibase, mss->optibase+0x9, |
| 2041 | 0x9, RF_ACTIVE); |
| 2042 | } |
| 2043 | |
| 2044 | if (!mss->conf_base) |
| 2045 | return ENXIO; |
| 2046 | |
| 2047 | if (!mss->io_base) |
| 2048 | mss->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT, |
| 2049 | &mss->io_rid, 0, ~0, 8, RF_ACTIVE); |
| 2050 | |
| 2051 | if (!mss->io_base) /* No hint specified, use 0x530 */ |
| 2052 | mss->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT, |
| 2053 | &mss->io_rid, 0x530, 0x537, 8, RF_ACTIVE); |
| 2054 | |
| 2055 | if (!mss->io_base) |
| 2056 | return ENXIO; |
| 2057 | |
| 2058 | switch (rman_get_start(mss->io_base)) { |
| 2059 | case 0x530: |
| 2060 | basebits = 0x0; |
| 2061 | break; |
| 2062 | case 0xe80: |
| 2063 | basebits = 0x10; |
| 2064 | break; |
| 2065 | case 0xf40: |
| 2066 | basebits = 0x20; |
| 2067 | break; |
| 2068 | case 0x604: |
| 2069 | basebits = 0x30; |
| 2070 | break; |
| 2071 | default: |
| 2072 | printf("opti_init: invalid MSS base address!\n"); |
| 2073 | return ENXIO; |
| 2074 | } |
| 2075 | |
| 2076 | |
| 2077 | switch (mss->bd_id) { |
| 2078 | case MD_OPTI924: |
| 2079 | opti_write(mss, 1, 0x80 | basebits); /* MSS mode */ |
| 2080 | opti_write(mss, 2, 0x00); /* Disable CD */ |
| 2081 | opti_write(mss, 3, 0xf0); /* Disable SB IRQ */ |
| 2082 | opti_write(mss, 4, 0xf0); |
| 2083 | opti_write(mss, 5, 0x00); |
| 2084 | opti_write(mss, 6, 0x02); /* MPU stuff */ |
| 2085 | break; |
| 2086 | |
| 2087 | case MD_OPTI930: |
| 2088 | opti_write(mss, 1, 0x00 | basebits); |
| 2089 | opti_write(mss, 3, 0x00); /* Disable SB IRQ/DMA */ |
| 2090 | opti_write(mss, 4, 0x52); /* Empty FIFO */ |
| 2091 | opti_write(mss, 5, 0x3c); /* Mode 2 */ |
| 2092 | opti_write(mss, 6, 0x02); /* Enable MSS */ |
| 2093 | break; |
| 2094 | } |
| 2095 | |
| 2096 | if (mss->bd_flags & BD_F_924PNP) { |
| 2097 | u_int32_t irq = isa_get_irq(dev); |
| 2098 | u_int32_t drq = isa_get_drq(dev); |
| 2099 | bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1); |
| 2100 | bus_set_resource(dev, SYS_RES_DRQ, mss->drq1_rid, drq, 1); |
| 2101 | if (flags & DV_F_DUAL_DMA) { |
| 2102 | bus_set_resource(dev, SYS_RES_DRQ, 1, |
| 2103 | flags & DV_F_DRQ_MASK, 1); |
| 2104 | mss->drq2_rid = 1; |
| 2105 | } |
| 2106 | } |
| 2107 | |
| 2108 | /* OPTixxx has I/DRQ registers */ |
| 2109 | |
| 2110 | device_set_flags(dev, device_get_flags(dev) | DV_F_TRUE_MSS); |
| 2111 | |
| 2112 | return 0; |
| 2113 | } |
| 2114 | |
| 2115 | static void |
| 2116 | opti_write(struct mss_info *mss, u_char reg, u_char val) |
| 2117 | { |
| 2118 | port_wr(mss->conf_base, mss->passwdreg, mss->password); |
| 2119 | |
| 2120 | switch(mss->bd_id) { |
| 2121 | case MD_OPTI924: |
| 2122 | if (reg > 7) { /* Indirect register */ |
| 2123 | port_wr(mss->conf_base, mss->passwdreg, reg); |
| 2124 | port_wr(mss->conf_base, mss->passwdreg, |
| 2125 | mss->password); |
| 2126 | port_wr(mss->conf_base, 9, val); |
| 2127 | return; |
| 2128 | } |
| 2129 | port_wr(mss->conf_base, reg, val); |
| 2130 | break; |
| 2131 | |
| 2132 | case MD_OPTI930: |
| 2133 | port_wr(mss->indir, 0, reg); |
| 2134 | port_wr(mss->conf_base, mss->passwdreg, mss->password); |
| 2135 | port_wr(mss->indir, 1, val); |
| 2136 | break; |
| 2137 | } |
| 2138 | } |
| 2139 | |
| 2140 | u_char |
| 2141 | opti_read(struct mss_info *mss, u_char reg) |
| 2142 | { |
| 2143 | port_wr(mss->conf_base, mss->passwdreg, mss->password); |
| 2144 | |
| 2145 | switch(mss->bd_id) { |
| 2146 | case MD_OPTI924: |
| 2147 | if (reg > 7) { /* Indirect register */ |
| 2148 | port_wr(mss->conf_base, mss->passwdreg, reg); |
| 2149 | port_wr(mss->conf_base, mss->passwdreg, mss->password); |
| 2150 | return(port_rd(mss->conf_base, 9)); |
| 2151 | } |
| 2152 | return(port_rd(mss->conf_base, reg)); |
| 2153 | break; |
| 2154 | |
| 2155 | case MD_OPTI930: |
| 2156 | port_wr(mss->indir, 0, reg); |
| 2157 | port_wr(mss->conf_base, mss->passwdreg, mss->password); |
| 2158 | return port_rd(mss->indir, 1); |
| 2159 | break; |
| 2160 | } |
| 2161 | return -1; |
| 2162 | } |
| 2163 | |
| 2164 | static device_method_t pnpmss_methods[] = { |
| 2165 | /* Device interface */ |
| 2166 | DEVMETHOD(device_probe, pnpmss_probe), |
| 2167 | DEVMETHOD(device_attach, pnpmss_attach), |
| 2168 | DEVMETHOD(device_detach, mss_detach), |
| 2169 | DEVMETHOD(device_suspend, mss_suspend), |
| 2170 | DEVMETHOD(device_resume, mss_resume), |
| 2171 | |
| 2172 | { 0, 0 } |
| 2173 | }; |
| 2174 | |
| 2175 | static driver_t pnpmss_driver = { |
| 2176 | "pcm", |
| 2177 | pnpmss_methods, |
| 2178 | PCM_SOFTC_SIZE, |
| 2179 | }; |
| 2180 | |
| 2181 | DRIVER_MODULE(snd_pnpmss, isa, pnpmss_driver, pcm_devclass, 0, 0); |
| 2182 | MODULE_DEPEND(snd_pnpmss, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); |
| 2183 | MODULE_VERSION(snd_pnpmss, 1); |
| 2184 | |
| 2185 | static int |
| 2186 | guspcm_probe(device_t dev) |
| 2187 | { |
| 2188 | struct sndcard_func *func; |
| 2189 | |
| 2190 | func = device_get_ivars(dev); |
| 2191 | if (func == NULL || func->func != SCF_PCM) |
| 2192 | return ENXIO; |
| 2193 | |
| 2194 | device_set_desc(dev, "GUS CS4231"); |
| 2195 | return 0; |
| 2196 | } |
| 2197 | |
| 2198 | static int |
| 2199 | guspcm_attach(device_t dev) |
| 2200 | { |
| 2201 | device_t parent = device_get_parent(dev); |
| 2202 | struct mss_info *mss; |
| 2203 | int base, flags; |
| 2204 | unsigned char ctl; |
| 2205 | |
| 2206 | mss = (struct mss_info *)malloc(sizeof *mss, M_DEVBUF, M_NOWAIT | M_ZERO); |
| 2207 | if (mss == NULL) |
| 2208 | return ENOMEM; |
| 2209 | |
| 2210 | mss->bd_flags = BD_F_MSS_OFFSET; |
| 2211 | mss->io_rid = 2; |
| 2212 | mss->conf_rid = 1; |
| 2213 | mss->irq_rid = 0; |
| 2214 | mss->drq1_rid = 1; |
| 2215 | mss->drq2_rid = -1; |
| 2216 | |
| 2217 | if (isa_get_logicalid(parent) == 0) |
| 2218 | mss->bd_id = MD_GUSMAX; |
| 2219 | else { |
| 2220 | mss->bd_id = MD_GUSPNP; |
| 2221 | mss->drq2_rid = 0; |
| 2222 | goto skip_setup; |
| 2223 | } |
| 2224 | |
| 2225 | flags = device_get_flags(parent); |
| 2226 | if (flags & DV_F_DUAL_DMA) |
| 2227 | mss->drq2_rid = 0; |
| 2228 | |
| 2229 | mss->conf_base = bus_alloc_resource(dev, SYS_RES_IOPORT, &mss->conf_rid, |
| 2230 | 0, ~0, 8, RF_ACTIVE); |
| 2231 | |
| 2232 | if (mss->conf_base == NULL) { |
| 2233 | mss_release_resources(mss, dev); |
| 2234 | return ENXIO; |
| 2235 | } |
| 2236 | |
| 2237 | base = isa_get_port(parent); |
| 2238 | |
| 2239 | ctl = 0x40; /* CS4231 enable */ |
| 2240 | if (isa_get_drq(dev) > 3) |
| 2241 | ctl |= 0x10; /* 16-bit dma channel 1 */ |
| 2242 | if ((flags & DV_F_DUAL_DMA) != 0 && (flags & DV_F_DRQ_MASK) > 3) |
| 2243 | ctl |= 0x20; /* 16-bit dma channel 2 */ |
| 2244 | ctl |= (base >> 4) & 0x0f; /* 2X0 -> 3XC */ |
| 2245 | port_wr(mss->conf_base, 6, ctl); |
| 2246 | |
| 2247 | skip_setup: |
| 2248 | return mss_doattach(dev, mss); |
| 2249 | } |
| 2250 | |
| 2251 | static device_method_t guspcm_methods[] = { |
| 2252 | DEVMETHOD(device_probe, guspcm_probe), |
| 2253 | DEVMETHOD(device_attach, guspcm_attach), |
| 2254 | DEVMETHOD(device_detach, mss_detach), |
| 2255 | |
| 2256 | { 0, 0 } |
| 2257 | }; |
| 2258 | |
| 2259 | static driver_t guspcm_driver = { |
| 2260 | "pcm", |
| 2261 | guspcm_methods, |
| 2262 | PCM_SOFTC_SIZE, |
| 2263 | }; |
| 2264 | |
| 2265 | DRIVER_MODULE(snd_guspcm, gusc, guspcm_driver, pcm_devclass, 0, 0); |
| 2266 | MODULE_DEPEND(snd_guspcm, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); |
| 2267 | MODULE_VERSION(snd_guspcm, 1); |
| 2268 | |
| 2269 | |