1 /* $NetBSD: psgpam.c,v 1.2 2022/06/11 14:45:37 tsutsui Exp $ */ 2 3 /* 4 * Copyright (c) 2018 Yosuke Sugahara. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __KERNEL_RCSID(0, "$NetBSD: psgpam.c,v 1.2 2022/06/11 14:45:37 tsutsui Exp $"); 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/device.h> 34 #include <sys/endian.h> 35 #include <sys/kmem.h> 36 #include <sys/sysctl.h> 37 38 #include <sys/cpu.h> 39 #include <sys/audioio.h> 40 #include <dev/audio/audio_if.h> 41 42 #include <machine/autoconf.h> 43 44 #include <luna68k/dev/xpbusvar.h> 45 #include <luna68k/dev/psgpam_enc.h> 46 #include <luna68k/dev/xpcmd.h> 47 #include <luna68k/dev/xplx/xplxdefs.h> 48 49 #include <luna68k/luna68k/isr.h> 50 51 #include "ioconf.h" 52 53 /* 54 * Debug level: 55 * 0: No debug logs 56 * 1: action changes like open/close/set_format... 57 * 2: + normal operations like read/write/ioctl... 58 * 3: + TRACEs except interrupt 59 * 4: + TRACEs including interrupt 60 */ 61 /* Note AUDIO_DEBUG should be sync'ed with src/sys/dev/audio/audio.c */ 62 /* #define AUDIO_DEBUG 1 */ 63 64 #if defined(AUDIO_DEBUG) 65 #define DPRINTF(n, fmt...) do { \ 66 if (psgpamdebug >= (n)) { \ 67 if (cpu_intr_p()) { \ 68 audio_mlog_printf(fmt); \ 69 } else { \ 70 audio_mlog_flush(); \ 71 printf(fmt); \ 72 } \ 73 } \ 74 } while (0) 75 76 /* XXX Parasitic to audio.c... */ 77 extern void audio_mlog_flush(void); 78 extern void audio_mlog_printf(const char *, ...); 79 80 static int psgpamdebug = AUDIO_DEBUG; 81 #else 82 #define DPRINTF(n, fmt...) __nothing 83 #endif 84 85 struct psgpam_softc { 86 device_t sc_dev; 87 vaddr_t sc_shm_base; 88 vsize_t sc_shm_size; 89 90 void (*sc_intr)(void *); 91 void *sc_arg; 92 93 kmutex_t sc_intr_lock; 94 kmutex_t sc_thread_lock; 95 96 int sc_isopen; 97 98 int sc_started; 99 int sc_outcount; 100 int sc_xp_state; 101 uint16_t sc_xp_addr; /* XP buffer addr */ 102 103 int sc_xp_enc; 104 int sc_xp_rept; 105 int sc_xp_cycle_clk; 106 int sc_xp_rept_clk; 107 int sc_xp_rept_max; 108 109 u_int sc_sample_rate; 110 int sc_stride; 111 int sc_dynamic; 112 113 uint8_t *sc_start_ptr; 114 uint8_t *sc_end_ptr; 115 int sc_blksize; 116 int sc_blkcount; 117 int sc_cur_blk_id; 118 119 struct psgpam_codecvar sc_psgpam_codecvar; 120 }; 121 122 static int psgpam_match(device_t, cfdata_t, void *); 123 static void psgpam_attach(device_t, device_t, void *); 124 125 /* MI audio layer interface */ 126 static int psgpam_open(void *, int); 127 static void psgpam_close(void *); 128 static int psgpam_query_format(void *, audio_format_query_t *); 129 static int psgpam_set_format(void *, int, 130 const audio_params_t *, const audio_params_t *, 131 audio_filter_reg_t *, audio_filter_reg_t *); 132 static int psgpam_trigger_output(void *, void *, void *, int, 133 void (*)(void *), void *, const audio_params_t *); 134 static int psgpam_halt_output(void *); 135 static int psgpam_getdev(void *, struct audio_device *); 136 static int psgpam_set_port(void *, mixer_ctrl_t *); 137 static int psgpam_get_port(void *, mixer_ctrl_t *); 138 static int psgpam_query_devinfo(void *, mixer_devinfo_t *); 139 static int psgpam_get_props(void *); 140 static void psgpam_get_locks(void *, kmutex_t **, kmutex_t **); 141 static int psgpam_round_blocksize(void *, int, int, const audio_params_t *); 142 static size_t psgpam_round_buffersize(void *, int, size_t); 143 144 static int psgpam_intr(void *); 145 146 #if defined(AUDIO_DEBUG) 147 static int psgpam_sysctl_debug(SYSCTLFN_PROTO); 148 #endif 149 static int psgpam_sysctl_enc(SYSCTLFN_PROTO); 150 static int psgpam_sysctl_dynamic(SYSCTLFN_PROTO); 151 152 CFATTACH_DECL_NEW(psgpam, sizeof(struct psgpam_softc), 153 psgpam_match, psgpam_attach, NULL, NULL); 154 155 static int psgpam_matched; 156 157 static const struct audio_hw_if psgpam_hw_if = { 158 .open = psgpam_open, 159 .close = psgpam_close, 160 .query_format = psgpam_query_format, 161 .set_format = psgpam_set_format, 162 .trigger_output = psgpam_trigger_output, 163 .halt_output = psgpam_halt_output, 164 .getdev = psgpam_getdev, 165 .set_port = psgpam_set_port, 166 .get_port = psgpam_get_port, 167 .query_devinfo = psgpam_query_devinfo, 168 .get_props = psgpam_get_props, 169 .get_locks = psgpam_get_locks, 170 .round_blocksize = psgpam_round_blocksize, 171 .round_buffersize = psgpam_round_buffersize, 172 }; 173 174 static struct audio_device psgpam_device = { 175 "PSG PAM", 176 "0.2", 177 "", 178 }; 179 180 static struct audio_format psgpam_format = { 181 .mode = AUMODE_PLAY, 182 .encoding = AUDIO_ENCODING_NONE, 183 .validbits = 0, /* filled by query_format */ 184 .precision = 0, /* filled by query_format */ 185 .channels = 1, 186 .channel_mask = AUFMT_MONAURAL, 187 .frequency_type = 0, /* filled by query_format */ 188 .frequency = { 0 }, /* filled by query_format */ 189 }; 190 191 static int 192 psgpam_match(device_t parent, cfdata_t cf, void *aux) 193 { 194 struct xpbus_attach_args *xa = aux; 195 196 if (psgpam_matched) 197 return 0; 198 199 /* Only the first generation LUNA has YM2149 at XP */ 200 if (machtype != LUNA_I) 201 return 0; 202 203 if (strcmp(xa->xa_name, psgpam_cd.cd_name)) 204 return 0; 205 206 psgpam_matched = 1; 207 return 1; 208 } 209 210 static void 211 psgpam_attach(device_t parent, device_t self, void *aux) 212 { 213 struct psgpam_softc *sc; 214 const struct sysctlnode *node; 215 216 sc = device_private(self); 217 sc->sc_dev = self; 218 219 aprint_normal(": HD647180X I/O processor as PSG PAM\n"); 220 221 sc->sc_shm_base = XP_SHM_BASE; 222 sc->sc_shm_size = XP_SHM_SIZE; 223 224 sc->sc_xp_enc = PAM_ENC_PAM2A; 225 sc->sc_sample_rate = 8000; 226 sc->sc_stride = 2; 227 sc->sc_dynamic = 1; 228 229 mutex_init(&sc->sc_thread_lock, MUTEX_DEFAULT, IPL_NONE); 230 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED); 231 232 isrlink_autovec(psgpam_intr, sc, 5, ISRPRI_TTYNOBUF); 233 234 sysctl_createv(NULL, 0, NULL, &node, 235 0, 236 CTLTYPE_NODE, device_xname(sc->sc_dev), 237 SYSCTL_DESCR("psgpam"), 238 NULL, 0, 239 NULL, 0, 240 CTL_HW, 241 CTL_CREATE, CTL_EOL); 242 if (node != NULL) { 243 #if defined(AUDIO_DEBUG) 244 sysctl_createv(NULL, 0, NULL, NULL, 245 CTLFLAG_READWRITE, 246 CTLTYPE_INT, "debug", 247 SYSCTL_DESCR("PSGPAM debug"), 248 psgpam_sysctl_debug, 0, (void *)sc, 0, 249 CTL_HW, node->sysctl_num, 250 CTL_CREATE, CTL_EOL); 251 #endif 252 sysctl_createv(NULL, 0, NULL, NULL, 253 CTLFLAG_READWRITE, 254 CTLTYPE_INT, "enc", 255 SYSCTL_DESCR("PSGPAM encoding"), 256 psgpam_sysctl_enc, 0, (void *)sc, 0, 257 CTL_HW, node->sysctl_num, 258 CTL_CREATE, CTL_EOL); 259 sysctl_createv(NULL, 0, NULL, NULL, 260 CTLFLAG_READWRITE, 261 CTLTYPE_INT, "dynamic", 262 SYSCTL_DESCR("PSGPAM dynamic offset"), 263 psgpam_sysctl_dynamic, 0, (void *)sc, 0, 264 CTL_HW, node->sysctl_num, 265 CTL_CREATE, CTL_EOL); 266 } 267 268 audio_attach_mi(&psgpam_hw_if, sc, sc->sc_dev); 269 } 270 271 /* private functions */ 272 273 static void 274 psgpam_xp_query(struct psgpam_softc *sc) 275 { 276 u_int a; 277 int r; 278 279 if (!sc->sc_isopen) { 280 a = xp_acquire(DEVID_PAM, 0); 281 if (a == 0) { 282 sc->sc_xp_cycle_clk = 65535; 283 sc->sc_xp_rept_clk = 255; 284 sc->sc_xp_rept_max = 0; 285 DPRINTF(1, "XPLX BUSY!\n"); 286 return; 287 } 288 xp_ensure_firmware(); 289 } 290 291 xp_writemem8(PAM_ENC, sc->sc_xp_enc); 292 r = xp_cmd(DEVID_PAM, PAM_CMD_QUERY); 293 if (r != XPLX_R_OK) { 294 sc->sc_xp_cycle_clk = 65535; 295 sc->sc_xp_rept_clk = 255; 296 sc->sc_xp_rept_max = 0; 297 DPRINTF(1, "XPLX QUERY FAIL: %d\n", r); 298 } else { 299 sc->sc_xp_cycle_clk = xp_readmem16le(PAM_CYCLE_CLK); 300 sc->sc_xp_rept_clk = xp_readmem8(PAM_REPT_CLK); 301 sc->sc_xp_rept_max = xp_readmem8(PAM_REPT_MAX); 302 DPRINTF(1, "xp cycle_clk=%d rept_clk=%d rept_max=%d\n", 303 sc->sc_xp_cycle_clk, 304 sc->sc_xp_rept_clk, 305 sc->sc_xp_rept_max); 306 } 307 if (!sc->sc_isopen) { 308 xp_release(DEVID_PAM); 309 } 310 } 311 312 static void 313 psgpam_xp_start(struct psgpam_softc *sc) 314 { 315 316 DPRINTF(3, "XP PAM starting.."); 317 if (xp_readmem8(PAM_RUN) != 0) { 318 DPRINTF(1, "XP PAM already started???\n"); 319 } 320 321 psgpam_xp_query(sc); 322 323 sc->sc_xp_rept = (XP_CPU_FREQ / sc->sc_sample_rate 324 - sc->sc_xp_cycle_clk) / sc->sc_xp_rept_clk; 325 if (sc->sc_xp_rept < 0) 326 sc->sc_xp_rept = 0; 327 if (sc->sc_xp_rept > sc->sc_xp_rept_max) 328 sc->sc_xp_rept = sc->sc_xp_rept_max; 329 xp_writemem8(PAM_REPT, sc->sc_xp_rept); 330 DPRINTF(3, "ENC=%d REPT=%d\n", sc->sc_xp_enc, sc->sc_xp_rept); 331 332 xp_intr5_enable(); 333 xp_cmd_nowait(DEVID_PAM, PAM_CMD_START); 334 335 DPRINTF(3, "XP PAM started\n"); 336 } 337 338 /* MI MD API */ 339 340 static int 341 psgpam_open(void *hdl, int flags) 342 { 343 struct psgpam_softc *sc; 344 u_int a; 345 346 DPRINTF(1, "%s: flags=0x%x\n", __func__, flags); 347 sc = hdl; 348 349 a = xp_acquire(DEVID_PAM, 0); 350 if (a == 0) 351 return EBUSY; 352 353 /* firmware transfer */ 354 xp_ensure_firmware(); 355 356 sc->sc_xp_state = 0; 357 sc->sc_started = 0; 358 sc->sc_outcount = 0; 359 sc->sc_isopen = 1; 360 361 memset(xp_shmptr(PAM_BUF), XP_ATN_RESET, PAM_BUF_LEN); 362 363 return 0; 364 } 365 366 static void 367 psgpam_close(void *hdl) 368 { 369 struct psgpam_softc *sc; 370 371 sc = hdl; 372 373 xp_intr5_disable(); 374 375 xp_release(DEVID_PAM); 376 377 sc->sc_isopen = 0; 378 379 DPRINTF(1, "%s\n", __func__); 380 } 381 382 static int 383 psgpam_query_format(void *hdl, audio_format_query_t *afp) 384 { 385 struct psgpam_softc *sc; 386 u_int freq; 387 uint8_t rept_max; 388 int clk; 389 int i, n; 390 391 #define XP_FREQ_MAXCOUNT 40 392 int f[XP_FREQ_MAXCOUNT]; 393 394 if (afp->index != 0) 395 return EINVAL; 396 397 sc = hdl; 398 399 psgpam_xp_query(sc); 400 switch (sc->sc_xp_enc) { 401 case PAM_ENC_PAM2A: 402 case PAM_ENC_PAM2B: 403 psgpam_format.validbits = 16; 404 psgpam_format.precision = 16; 405 break; 406 case PAM_ENC_PAM3A: 407 case PAM_ENC_PAM3B: 408 psgpam_format.validbits = 32; 409 psgpam_format.precision = 32; 410 break; 411 } 412 413 /* convert xp's max to AUFMT's max */ 414 rept_max = sc->sc_xp_rept_max + 1; 415 416 if (rept_max <= AUFMT_MAX_FREQUENCIES) { 417 /* all choice */ 418 for (i = 0; i < rept_max; i++) { 419 clk = sc->sc_xp_cycle_clk + i * sc->sc_xp_rept_clk; 420 freq = XP_CPU_FREQ / clk; 421 psgpam_format.frequency[i] = freq; 422 } 423 n = rept_max; 424 } else { 425 if (rept_max > XP_FREQ_MAXCOUNT) 426 rept_max = XP_FREQ_MAXCOUNT; 427 428 for (i = 0; i < rept_max; i++) { 429 clk = sc->sc_xp_cycle_clk + i * sc->sc_xp_rept_clk; 430 freq = XP_CPU_FREQ / clk; 431 if (freq < 4000) break; 432 f[i] = freq; 433 } 434 for (; i < XP_FREQ_MAXCOUNT; i++) 435 f[i] = 0; 436 437 /* 438 * keep: first, last 439 * remove: any unusable freq 440 */ 441 for (i = 1; i < rept_max - 1; i++) { 442 if (( 4000 <= f[i] && f[i] < 6000 && 443 f[i - 1] < 6000 && f[i + 1] > 4000) || 444 ( 6000 <= f[i] && f[i] < 8000 && 445 f[i - 1] < 8000 && f[i + 1] > 6000) || 446 ( 8000 <= f[i] && f[i] < 12000 && 447 f[i - 1] < 12000 && f[i + 1] > 8000) || 448 (12000 <= f[i] && f[i] < 16000 && 449 f[i - 1] < 16000 && f[i + 1] > 12000)) { 450 f[i] = 0; 451 } 452 } 453 n = 0; 454 for (i = 0; i < rept_max; i++) { 455 if (f[i] != 0) { 456 psgpam_format.frequency[n] = f[i]; 457 n++; 458 if (n == AUFMT_MAX_FREQUENCIES) 459 break; 460 } 461 } 462 } 463 464 psgpam_format.frequency_type = n; 465 466 afp->fmt = psgpam_format; 467 return 0; 468 } 469 470 static int 471 psgpam_set_format(void *hdl, int setmode, 472 const audio_params_t *play, const audio_params_t *rec, 473 audio_filter_reg_t *pfil, audio_filter_reg_t *rfil) 474 { 475 /* called before open */ 476 477 struct psgpam_softc *sc; 478 479 sc = hdl; 480 DPRINTF(1, "%s: mode=%d %s/%dbit/%dch/%dHz\n", __func__, 481 setmode, audio_encoding_name(play->encoding), 482 play->precision, play->channels, play->sample_rate); 483 484 sc->sc_sample_rate = play->sample_rate; 485 486 /* set filter */ 487 switch (sc->sc_xp_enc) { 488 case PAM_ENC_PAM2A: 489 if (sc->sc_dynamic) { 490 pfil->codec = psgpam_aint_to_pam2a_d; 491 } else { 492 pfil->codec = psgpam_aint_to_pam2a; 493 } 494 sc->sc_stride = 2; 495 break; 496 case PAM_ENC_PAM2B: 497 if (sc->sc_dynamic) { 498 pfil->codec = psgpam_aint_to_pam2b_d; 499 } else { 500 pfil->codec = psgpam_aint_to_pam2b; 501 } 502 sc->sc_stride = 2; 503 break; 504 case PAM_ENC_PAM3A: 505 if (sc->sc_dynamic) { 506 pfil->codec = psgpam_aint_to_pam3a_d; 507 } else { 508 pfil->codec = psgpam_aint_to_pam3a; 509 } 510 sc->sc_stride = 4; 511 break; 512 case PAM_ENC_PAM3B: 513 if (sc->sc_dynamic) { 514 pfil->codec = psgpam_aint_to_pam3b_d; 515 } else { 516 pfil->codec = psgpam_aint_to_pam3b; 517 } 518 sc->sc_stride = 4; 519 break; 520 } 521 psgpam_init_context(&sc->sc_psgpam_codecvar, sc->sc_sample_rate); 522 pfil->context = &sc->sc_psgpam_codecvar; 523 524 return 0; 525 } 526 527 /* marking block */ 528 static void 529 psgpam_mark_blk(struct psgpam_softc *sc, int blk_id) 530 { 531 int markoffset; 532 uint marker; 533 534 markoffset = sc->sc_blksize * (blk_id + 1); 535 536 if (blk_id == sc->sc_blkcount - 1) { 537 marker = XP_ATN_RELOAD; 538 } else { 539 marker = XP_ATN_STAT; 540 } 541 542 /* marking */ 543 uint8_t *start = sc->sc_start_ptr; 544 if (sc->sc_stride == 2) { 545 uint16_t *markptr = (uint16_t*)(start + markoffset); 546 markptr -= 1; 547 *markptr |= marker; 548 } else { 549 /* stride == 4 */ 550 uint32_t *markptr = (uint32_t*)(start + markoffset); 551 markptr -= 1; 552 *markptr |= marker; 553 } 554 } 555 556 static int 557 psgpam_trigger_output(void *hdl, void *start, void *end, int blksize, 558 void (*intr)(void *), void *intrarg, const audio_params_t *param) 559 { 560 void *dp; 561 struct psgpam_softc *sc; 562 563 sc = hdl; 564 565 DPRINTF(2, "%s start=%p end=%p blksize=%d\n", __func__, 566 start, end, blksize); 567 568 sc->sc_outcount++; 569 570 sc->sc_intr = intr; 571 sc->sc_arg = intrarg; 572 sc->sc_blksize = blksize; 573 574 sc->sc_start_ptr = start; 575 sc->sc_end_ptr = end; 576 sc->sc_blkcount = (sc->sc_end_ptr - sc->sc_start_ptr) / sc->sc_blksize; 577 sc->sc_xp_addr = PAM_BUF; 578 579 psgpam_mark_blk(sc, 0); 580 psgpam_mark_blk(sc, 1); 581 582 /* transfer */ 583 dp = xp_shmptr(sc->sc_xp_addr); 584 memcpy(dp, start, blksize * 2); 585 586 /* (preincrement variable in intr) */ 587 sc->sc_cur_blk_id = 1; 588 sc->sc_xp_addr += blksize; 589 590 /* play start */ 591 if (sc->sc_started == 0) { 592 /* set flag first */ 593 sc->sc_started = 1; 594 psgpam_xp_start(sc); 595 } 596 597 return 0; 598 } 599 600 static int 601 psgpam_halt_output(void *hdl) 602 { 603 struct psgpam_softc *sc = hdl; 604 605 DPRINTF(2, "%s\n", __func__); 606 607 xp_intr5_disable(); 608 609 memset(xp_shmptr(PAM_BUF), XP_ATN_RESET, PAM_BUF_LEN); 610 611 sc->sc_started = 0; 612 sc->sc_xp_state = 0; 613 614 return 0; 615 } 616 617 static int 618 psgpam_getdev(void *hdl, struct audio_device *ret) 619 { 620 621 *ret = psgpam_device; 622 return 0; 623 } 624 625 static int 626 psgpam_set_port(void *hdl, mixer_ctrl_t *mc) 627 { 628 629 DPRINTF(2, "%s\n", __func__); 630 return 0; 631 } 632 633 static int 634 psgpam_get_port(void *hdl, mixer_ctrl_t *mc) 635 { 636 637 DPRINTF(2, "%s\n", __func__); 638 return 0; 639 } 640 641 static int 642 psgpam_query_devinfo(void *hdl, mixer_devinfo_t *di) 643 { 644 645 DPRINTF(2, "%s %d\n", __func__, di->index); 646 switch (di->index) { 647 default: 648 return EINVAL; 649 } 650 return 0; 651 } 652 653 static int 654 psgpam_get_props(void *hdl) 655 { 656 657 return AUDIO_PROP_PLAYBACK; 658 } 659 660 static void 661 psgpam_get_locks(void *hdl, kmutex_t **intr, kmutex_t **thread) 662 { 663 struct psgpam_softc *sc = hdl; 664 665 *intr = &sc->sc_intr_lock; 666 *thread = &sc->sc_thread_lock; 667 } 668 669 static int 670 psgpam_round_blocksize(void *hdl, int bs, int mode, 671 const audio_params_t *param) 672 { 673 674 #if 0 675 if (bs < 16384) { 676 return (16384 / bs) * bs; 677 } else { 678 return 16384; 679 } 680 #else 681 return bs; 682 #endif 683 } 684 685 static size_t 686 psgpam_round_buffersize(void *hdl, int direction, size_t bufsize) 687 { 688 689 if (bufsize > 28 * 1024) { 690 bufsize = 28 * 1024; 691 } 692 return bufsize; 693 } 694 695 static int 696 psgpam_intr(void *hdl) 697 { 698 struct psgpam_softc *sc = hdl; 699 700 xp_intr5_acknowledge(); 701 DPRINTF(4, "psgpam intr\n"); 702 703 sc->sc_cur_blk_id++; 704 sc->sc_xp_addr += sc->sc_blksize; 705 if (sc->sc_cur_blk_id == sc->sc_blkcount) { 706 sc->sc_cur_blk_id = 0; 707 sc->sc_xp_addr = PAM_BUF; 708 } 709 psgpam_mark_blk(sc, sc->sc_cur_blk_id); 710 memcpy(xp_shmptr(sc->sc_xp_addr), 711 sc->sc_start_ptr + sc->sc_cur_blk_id * sc->sc_blksize, 712 sc->sc_blksize); 713 714 mutex_spin_enter(&sc->sc_intr_lock); 715 716 if (sc->sc_intr) { 717 sc->sc_intr(sc->sc_arg); 718 } else { 719 DPRINTF(1, "psgpam_intr: spurious interrupt\n"); 720 } 721 722 mutex_spin_exit(&sc->sc_intr_lock); 723 724 /* handled */ 725 return 1; 726 } 727 728 #if defined(AUDIO_DEBUG) 729 /* sysctl */ 730 static int 731 psgpam_sysctl_debug(SYSCTLFN_ARGS) 732 { 733 struct sysctlnode node; 734 int t, error; 735 736 node = *rnode; 737 738 t = psgpamdebug; 739 node.sysctl_data = &t; 740 741 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 742 if (error || newp == NULL) { 743 return error; 744 } 745 746 if (t < 0) 747 return EINVAL; 748 if (t > 4) 749 return EINVAL; 750 psgpamdebug = t; 751 return 0; 752 } 753 #endif 754 755 /* sysctl */ 756 static int 757 psgpam_sysctl_enc(SYSCTLFN_ARGS) 758 { 759 struct sysctlnode node; 760 struct psgpam_softc *sc; 761 int t, error; 762 763 node = *rnode; 764 sc = node.sysctl_data; 765 766 t = sc->sc_xp_enc; 767 node.sysctl_data = &t; 768 769 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 770 if (error || newp == NULL) { 771 return error; 772 } 773 774 if (t < PAM_ENC_PAM2A) 775 return EINVAL; 776 if (t > PAM_ENC_PAM3B) 777 return EINVAL; 778 sc->sc_xp_enc = t; 779 return 0; 780 } 781 782 static int 783 psgpam_sysctl_dynamic(SYSCTLFN_ARGS) 784 { 785 struct sysctlnode node; 786 struct psgpam_softc *sc; 787 int t, error; 788 789 node = *rnode; 790 sc = node.sysctl_data; 791 792 t = sc->sc_dynamic; 793 node.sysctl_data = &t; 794 795 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 796 if (error || newp == NULL) { 797 return error; 798 } 799 800 sc->sc_dynamic = t; 801 return 0; 802 } 803