1 /* $NetBSD: ucbsnd.c,v 1.15 2003/07/15 02:29:31 lukem Exp $ */ 2 3 /*- 4 * Copyright (c) 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * Device driver for PHILIPS UCB1200 Advanced modem/audio analog front-end 41 * Audio codec part. 42 * 43 * /dev/ucbsnd0 : sampling rate 22.154kHz monoral 16bit straight PCM device. 44 */ 45 46 #include <sys/cdefs.h> 47 __KERNEL_RCSID(0, "$NetBSD: ucbsnd.c,v 1.15 2003/07/15 02:29:31 lukem Exp $"); 48 49 #include "opt_use_poll.h" 50 51 #include <sys/param.h> 52 #include <sys/systm.h> 53 #include <sys/conf.h> 54 #include <sys/malloc.h> 55 #include <sys/device.h> 56 #include <sys/proc.h> 57 #include <sys/endian.h> 58 59 #include <mips/cache.h> 60 61 #include <machine/bus.h> 62 #include <machine/intr.h> 63 64 #include <hpcmips/tx/tx39var.h> 65 #include <hpcmips/tx/tx39sibvar.h> 66 #include <hpcmips/tx/tx39sibreg.h> 67 #include <hpcmips/tx/tx39icureg.h> 68 #include <hpcmips/tx/txsnd.h> 69 70 #include <hpcmips/dev/ucb1200var.h> 71 #include <hpcmips/dev/ucb1200reg.h> 72 73 #define AUDIOUNIT(x) (minor(x)&0x0f) 74 #define AUDIODEV(x) (minor(x)&0xf0) 75 #define splaudio splbio /* XXX */ 76 77 #ifdef UCBSNDDEBUG 78 int ucbsnd_debug = 1; 79 #define DPRINTF(arg) if (ucbsnd_debug) printf arg; 80 #define DPRINTFN(n, arg) if (ucbsnd_debug > (n)) printf arg; 81 #else 82 #define DPRINTF(arg) 83 #define DPRINTFN(n, arg) 84 #endif 85 86 #define UCBSND_BUFBLOCK 5 87 /* 88 * XXX temporary DMA buffer 89 */ 90 static u_int8_t dmabuf_static[TX39_SIBDMA_SIZE * UCBSND_BUFBLOCK] __attribute__((__aligned__(16))); /* XXX */ 91 static size_t dmabufcnt_static[UCBSND_BUFBLOCK]; /* XXX */ 92 93 enum ucbsnd_state { 94 /* 0 */ UCBSND_IDLE, 95 /* 1 */ UCBSND_INIT, 96 /* 2 */ UCBSND_ENABLE_SAMPLERATE, 97 /* 3 */ UCBSND_ENABLE_OUTPUTPATH, 98 /* 4 */ UCBSND_ENABLE_SETVOLUME, 99 /* 5 */ UCBSND_ENABLE_SPEAKER0, 100 /* 6 */ UCBSND_ENABLE_SPEAKER1, 101 /* 7 */ UCBSND_TRANSITION_PIO, 102 /* 8 */ UCBSND_PIO, 103 /* 9 */ UCBSND_TRANSITION_DISABLE, 104 /*10 */ UCBSND_DISABLE_OUTPUTPATH, 105 /*11 */ UCBSND_DISABLE_SPEAKER0, 106 /*12 */ UCBSND_DISABLE_SPEAKER1, 107 /*13 */ UCBSND_DISABLE_SIB, 108 /*14 */ UCBSND_DMASTART, 109 /*15 */ UCBSND_DMAEND, 110 }; 111 112 struct ring_buf { 113 u_int32_t rb_buf; /* buffer start address */ 114 size_t *rb_bufcnt; /* effective data count (max rb_blksize)*/ 115 116 size_t rb_bufsize; /* total amount of buffer */ 117 int rb_blksize; /* DMA block size */ 118 int rb_maxblks; /* # of blocks in ring */ 119 120 int rb_inp; /* start of input (to buffer) */ 121 int rb_outp; /* output pointer */ 122 }; 123 124 struct ucbsnd_softc { 125 struct device sc_dev; 126 struct device *sc_sib; /* parent (TX39 SIB module) */ 127 struct device *sc_ucb; /* parent (UCB1200 module) */ 128 tx_chipset_tag_t sc_tc; 129 130 struct tx_sound_tag sc_tag; 131 int sc_mute; 132 133 /* 134 * audio codec state machine 135 */ 136 int sa_transfer_mode; 137 #define UCBSND_TRANSFERMODE_DMA 0 138 #define UCBSND_TRANSFERMODE_PIO 1 139 enum ucbsnd_state sa_state; 140 int sa_snd_attenuation; 141 #define UCBSND_DEFAULT_ATTENUATION 0 /* Full volume */ 142 int sa_snd_rate; /* passed down from SIB module */ 143 int sa_tel_rate; 144 void* sa_sf0ih; 145 void* sa_sndih; 146 int sa_retry; 147 int sa_cnt; /* misc counter */ 148 149 /* 150 * input buffer 151 */ 152 size_t sa_dmacnt; 153 struct ring_buf sc_rb; 154 }; 155 156 int ucbsnd_match(struct device*, struct cfdata*, void*); 157 void ucbsnd_attach(struct device*, struct device*, void*); 158 159 int ucbsnd_exec_output(void*); 160 int ucbsnd_busy(void*); 161 162 void ucbsnd_sound_init(struct ucbsnd_softc*); 163 void __ucbsnd_sound_click(tx_sound_tag_t); 164 void __ucbsnd_sound_mute(tx_sound_tag_t, int); 165 166 int ucbsndwrite_subr(struct ucbsnd_softc *, u_int32_t *, size_t, 167 struct uio *); 168 169 int ringbuf_allocate(struct ring_buf*, size_t, int); 170 void ringbuf_deallocate(struct ring_buf*); 171 void ringbuf_reset(struct ring_buf*); 172 int ringbuf_full(struct ring_buf*); 173 void *ringbuf_producer_get(struct ring_buf*); 174 void ringbuf_producer_return(struct ring_buf*, size_t); 175 void *ringbuf_consumer_get(struct ring_buf*, size_t*); 176 void ringbuf_consumer_return(struct ring_buf*); 177 178 CFATTACH_DECL(ucbsnd, sizeof(struct ucbsnd_softc), 179 ucbsnd_match, ucbsnd_attach, NULL, NULL); 180 181 dev_type_open(ucbsndopen); 182 dev_type_close(ucbsndclose); 183 dev_type_read(ucbsndread); 184 dev_type_write(ucbsndwrite); 185 186 const struct cdevsw ucbsnd_cdevsw = { 187 ucbsndopen, ucbsndclose, ucbsndread, ucbsndwrite, nullioctl, 188 nostop, notty, nopoll, nullmmap, nokqfilter, 189 }; 190 191 int 192 ucbsnd_match(struct device *parent, struct cfdata *cf, void *aux) 193 { 194 195 return (1); 196 } 197 198 void 199 ucbsnd_attach(struct device *parent, struct device *self, void *aux) 200 { 201 struct ucb1200_attach_args *ucba = aux; 202 struct ucbsnd_softc *sc = (void*)self; 203 tx_chipset_tag_t tc; 204 205 tc = sc->sc_tc = ucba->ucba_tc; 206 sc->sc_sib = ucba->ucba_sib; 207 sc->sc_ucb = ucba->ucba_ucb; 208 209 /* register sound functions */ 210 ucbsnd_sound_init(sc); 211 212 sc->sa_snd_rate = ucba->ucba_snd_rate; 213 sc->sa_tel_rate = ucba->ucba_tel_rate; 214 215 sc->sa_snd_attenuation = UCBSND_DEFAULT_ATTENUATION; 216 #define KHZ(a) ((a) / 1000), (((a) % 1000)) 217 printf(": audio %d.%03d kHz telecom %d.%03d kHz", 218 KHZ((tx39sib_clock(sc->sc_sib) * 2) / 219 (sc->sa_snd_rate * 64)), 220 KHZ((tx39sib_clock(sc->sc_sib) * 2) / 221 (sc->sa_tel_rate * 64))); 222 223 ucb1200_state_install(parent, ucbsnd_busy, self, 224 UCB1200_SND_MODULE); 225 226 ringbuf_allocate(&sc->sc_rb, TX39_SIBDMA_SIZE, UCBSND_BUFBLOCK); 227 228 printf("\n"); 229 } 230 231 int 232 ucbsnd_busy(void *arg) 233 { 234 struct ucbsnd_softc *sc = arg; 235 236 return (sc->sa_state != UCBSND_IDLE); 237 } 238 239 int 240 ucbsnd_exec_output(void *arg) 241 { 242 struct ucbsnd_softc *sc = arg; 243 tx_chipset_tag_t tc = sc->sc_tc; 244 txreg_t reg; 245 u_int32_t *buf; 246 size_t bufcnt; 247 248 switch (sc->sa_state) { 249 default: 250 panic("ucbsnd_exec_output: invalid state %d", sc->sa_state); 251 /* NOTREACHED */ 252 break; 253 254 case UCBSND_IDLE: 255 /* nothing to do */ 256 return (0); 257 258 case UCBSND_INIT: 259 sc->sa_sf0ih = tx_intr_establish( 260 tc, MAKEINTR(1, TX39_INTRSTATUS1_SIBSF0INT), 261 IST_EDGE, IPL_TTY, ucbsnd_exec_output, sc); 262 263 sc->sa_state = UCBSND_ENABLE_SAMPLERATE; 264 return (0); 265 266 case UCBSND_ENABLE_SAMPLERATE: 267 /* Enable UCB1200 side sample rate */ 268 reg = TX39_SIBSF0_WRITE; 269 reg = TX39_SIBSF0_REGADDR_SET(reg, UCB1200_AUDIOCTRLA_REG); 270 reg = TX39_SIBSF0_REGDATA_SET(reg, sc->sa_snd_rate); 271 tx_conf_write(tc, TX39_SIBSF0CTRL_REG, reg); 272 273 sc->sa_state = UCBSND_ENABLE_OUTPUTPATH; 274 return (0); 275 276 case UCBSND_ENABLE_OUTPUTPATH: 277 /* Enable UCB1200 side */ 278 reg = TX39_SIBSF0_WRITE; 279 reg = TX39_SIBSF0_REGADDR_SET(reg, UCB1200_AUDIOCTRLB_REG); 280 reg = TX39_SIBSF0_REGDATA_SET(reg, sc->sa_snd_attenuation | 281 UCB1200_AUDIOCTRLB_OUTEN); 282 tx_conf_write(tc, TX39_SIBSF0CTRL_REG, reg); 283 284 /* Enable SIB side */ 285 reg = tx_conf_read(tc, TX39_SIBCTRL_REG); 286 tx_conf_write(tc, TX39_SIBCTRL_REG, 287 reg | TX39_SIBCTRL_ENSND); 288 289 sc->sa_state = UCBSND_ENABLE_SPEAKER0; 290 sc->sa_retry = 10; 291 return (0); 292 case UCBSND_ENABLE_SPEAKER0: 293 /* Speaker on */ 294 295 reg = TX39_SIBSF0_REGADDR_SET(0, UCB1200_IO_DATA_REG); 296 tx_conf_write(tc, TX39_SIBSF0CTRL_REG, reg); 297 298 sc->sa_state = UCBSND_ENABLE_SPEAKER1; 299 return (0); 300 301 case UCBSND_ENABLE_SPEAKER1: 302 reg = tx_conf_read(tc, TX39_SIBSF0STAT_REG); 303 if ((TX39_SIBSF0_REGADDR(reg) != UCB1200_IO_DATA_REG) && 304 --sc->sa_retry > 0) { 305 306 sc->sa_state = UCBSND_ENABLE_SPEAKER0; 307 return (0); 308 } 309 310 if (sc->sa_retry <= 0) { 311 printf("ucbsnd_exec_output: subframe0 busy\n"); 312 313 sc->sa_state = UCBSND_IDLE; 314 return (0); 315 } 316 317 reg |= TX39_SIBSF0_WRITE; 318 reg |= UCB1200_IO_DATA_SPEAKER; 319 tx_conf_write(tc, TX39_SIBSF0CTRL_REG, reg); 320 321 /* 322 * Begin to transfer. 323 */ 324 switch (sc->sa_transfer_mode) { 325 case UCBSND_TRANSFERMODE_DMA: 326 sc->sa_state = UCBSND_DMASTART; 327 sc->sa_dmacnt = 0; 328 break; 329 case UCBSND_TRANSFERMODE_PIO: 330 sc->sa_state = UCBSND_TRANSITION_PIO; 331 break; 332 } 333 334 return (0); 335 case UCBSND_DMASTART: 336 /* get data */ 337 if (sc->sa_dmacnt) /* return previous buffer */ 338 ringbuf_consumer_return(&sc->sc_rb); 339 buf = ringbuf_consumer_get(&sc->sc_rb, &bufcnt); 340 if (buf == 0) { 341 sc->sa_state = UCBSND_DMAEND; 342 return (0); 343 } 344 345 if (sc->sa_dmacnt == 0) { 346 /* change interrupt source */ 347 if (sc->sa_sf0ih) { 348 tx_intr_disestablish(tc, sc->sa_sf0ih); 349 sc->sa_sf0ih = 0; 350 } 351 sc->sa_sndih = tx_intr_establish( 352 tc, MAKEINTR(1, TX39_INTRSTATUS1_SND1_0INT), 353 IST_EDGE, IPL_TTY, ucbsnd_exec_output, sc); 354 } else { 355 wakeup(&sc->sc_rb); 356 } 357 358 /* set DMA buffer address */ 359 tx_conf_write(tc, TX39_SIBSNDTXSTART_REG, 360 MIPS_KSEG0_TO_PHYS(buf)); 361 362 /* set DMA buffer size */ 363 tx_conf_write(tc, TX39_SIBSIZE_REG, 364 TX39_SIBSIZE_SNDSIZE_SET(0, bufcnt)); 365 366 tx_conf_write(tc, TX39_SIBSF0CTRL_REG, TX39_SIBSF0_SNDVALID); 367 368 /* kick DMA */ 369 reg = tx_conf_read(tc, TX39_SIBDMACTRL_REG); 370 reg |= TX39_SIBDMACTRL_ENDMATXSND; 371 tx_conf_write(tc, TX39_SIBDMACTRL_REG, reg); 372 373 /* set next */ 374 sc->sa_dmacnt += bufcnt; 375 376 break; 377 378 case UCBSND_DMAEND: 379 sc->sa_state = UCBSND_TRANSITION_DISABLE; 380 break; 381 case UCBSND_TRANSITION_PIO: 382 /* change interrupt source */ 383 if (sc->sa_sf0ih) { 384 tx_intr_disestablish(tc, sc->sa_sf0ih); 385 sc->sa_sf0ih = 0; 386 } 387 sc->sa_sndih = tx_intr_establish( 388 tc, MAKEINTR(1, TX39_INTRSTATUS1_SNDININT), 389 IST_EDGE, IPL_TTY, ucbsnd_exec_output, sc); 390 391 sc->sa_state = UCBSND_PIO; 392 sc->sa_cnt = 0; 393 return (0); 394 395 case UCBSND_PIO: 396 { 397 /* PIO test routine */ 398 int dummy_data = sc->sa_cnt * 3; 399 tx_conf_write(tc, TX39_SIBSNDHOLD_REG, 400 dummy_data << 16 | dummy_data); 401 tx_conf_write(tc, TX39_SIBSF0CTRL_REG, TX39_SIBSF0_SNDVALID); 402 if (sc->sa_cnt++ > 50) { 403 sc->sa_state = UCBSND_TRANSITION_DISABLE; 404 } 405 return (0); 406 } 407 case UCBSND_TRANSITION_DISABLE: 408 /* change interrupt source */ 409 if (sc->sa_sndih) { 410 tx_intr_disestablish(tc, sc->sa_sndih); 411 sc->sa_sndih = 0; 412 } 413 sc->sa_sf0ih = tx_intr_establish( 414 tc, MAKEINTR(1, TX39_INTRSTATUS1_SIBSF0INT), 415 IST_EDGE, IPL_TTY, ucbsnd_exec_output, sc); 416 417 sc->sa_state = UCBSND_DISABLE_OUTPUTPATH; 418 return (0); 419 420 case UCBSND_DISABLE_OUTPUTPATH: 421 /* disable codec output path and mute */ 422 reg = TX39_SIBSF0_WRITE; 423 reg = TX39_SIBSF0_REGADDR_SET(reg, UCB1200_AUDIOCTRLB_REG); 424 reg = TX39_SIBSF0_REGDATA_SET(reg, UCB1200_AUDIOCTRLB_MUTE); 425 tx_conf_write(tc, TX39_SIBSF0CTRL_REG, reg); 426 427 sc->sa_state = UCBSND_DISABLE_SPEAKER0; 428 sc->sa_retry = 10; 429 return (0); 430 431 case UCBSND_DISABLE_SPEAKER0: 432 /* Speaker off */ 433 reg = TX39_SIBSF0_REGADDR_SET(0, UCB1200_IO_DATA_REG); 434 tx_conf_write(tc, TX39_SIBSF0CTRL_REG, reg); 435 436 sc->sa_state = UCBSND_DISABLE_SPEAKER1; 437 return (0); 438 439 case UCBSND_DISABLE_SPEAKER1: 440 reg = tx_conf_read(tc, TX39_SIBSF0STAT_REG); 441 if ((TX39_SIBSF0_REGADDR(reg) != UCB1200_IO_DATA_REG) && 442 --sc->sa_retry > 0) { 443 444 sc->sa_state = UCBSND_DISABLE_SPEAKER0; 445 return (0); 446 } 447 448 if (sc->sa_retry <= 0) { 449 printf("ucbsnd_exec_output: subframe0 busy\n"); 450 451 sc->sa_state = UCBSND_IDLE; 452 return (0); 453 } 454 455 reg |= TX39_SIBSF0_WRITE; 456 reg &= ~UCB1200_IO_DATA_SPEAKER; 457 tx_conf_write(tc, TX39_SIBSF0CTRL_REG, reg); 458 459 sc->sa_state = UCBSND_DISABLE_SIB; 460 return (0); 461 462 case UCBSND_DISABLE_SIB: 463 /* Disable SIB side */ 464 reg = tx_conf_read(tc, TX39_SIBCTRL_REG); 465 reg &= ~TX39_SIBCTRL_ENSND; 466 tx_conf_write(tc, TX39_SIBCTRL_REG, reg); 467 468 /* end audio disable sequence */ 469 if (sc->sa_sf0ih) { 470 tx_intr_disestablish(tc, sc->sa_sf0ih); 471 sc->sa_sf0ih = 0; 472 } 473 sc->sa_state = UCBSND_IDLE; 474 475 return (0); 476 } 477 478 return (0); 479 } 480 481 /* 482 * global sound interface. 483 */ 484 void 485 ucbsnd_sound_init(struct ucbsnd_softc *sc) 486 { 487 tx_sound_tag_t ts = &sc->sc_tag; 488 tx_chipset_tag_t tc = sc->sc_tc; 489 490 ts->ts_v = sc; 491 ts->ts_click = __ucbsnd_sound_click; 492 ts->ts_mute = __ucbsnd_sound_mute; 493 494 tx_conf_register_sound(tc, ts); 495 } 496 497 void 498 __ucbsnd_sound_click(tx_sound_tag_t arg) 499 { 500 struct ucbsnd_softc *sc = (void*)arg; 501 502 if (!sc->sc_mute && sc->sa_state == UCBSND_IDLE) { 503 sc->sa_transfer_mode = UCBSND_TRANSFERMODE_PIO; 504 sc->sa_state = UCBSND_INIT; 505 ucbsnd_exec_output((void*)sc); 506 } 507 } 508 509 void 510 __ucbsnd_sound_mute(tx_sound_tag_t arg, int onoff) 511 { 512 struct ucbsnd_softc *sc = (void*)arg; 513 514 sc->sc_mute = onoff; 515 } 516 517 /* 518 * device access 519 */ 520 extern struct cfdriver ucbsnd_cd; 521 522 int 523 ucbsndopen(dev_t dev, int flags, int ifmt, struct proc *p) 524 { 525 int unit = AUDIOUNIT(dev); 526 struct ucbsnd_softc *sc; 527 int s; 528 529 if (unit >= ucbsnd_cd.cd_ndevs || 530 (sc = ucbsnd_cd.cd_devs[unit]) == NULL) 531 return (ENXIO); 532 533 s = splaudio(); 534 ringbuf_reset(&sc->sc_rb); 535 splx(s); 536 537 return (0); 538 } 539 540 int 541 ucbsndclose(dev_t dev, int flags, int ifmt, struct proc *p) 542 { 543 int unit = AUDIOUNIT(dev); 544 struct ucbsnd_softc *sc; 545 546 if (unit >= ucbsnd_cd.cd_ndevs || 547 (sc = ucbsnd_cd.cd_devs[unit]) == NULL) 548 return (ENXIO); 549 550 return (0); 551 } 552 553 int 554 ucbsndread(dev_t dev, struct uio *uio, int ioflag) 555 { 556 int unit = AUDIOUNIT(dev); 557 struct ucbsnd_softc *sc; 558 int error = 0; 559 560 if (unit >= ucbsnd_cd.cd_ndevs || 561 (sc = ucbsnd_cd.cd_devs[unit]) == NULL) 562 return (ENXIO); 563 /* not supported yet */ 564 565 return (error); 566 } 567 568 int 569 ucbsndwrite_subr(struct ucbsnd_softc *sc, u_int32_t *buf, size_t bufsize, 570 struct uio *uio) 571 { 572 int i, s, error; 573 574 error = uiomove(buf, bufsize, uio); 575 /* 576 * inverse endian for UCB1200 577 */ 578 for (i = 0; i < bufsize / sizeof(int); i++) 579 buf[i] = htobe32(buf[i]); 580 mips_dcache_wbinv_range((vaddr_t)buf, bufsize); 581 582 ringbuf_producer_return(&sc->sc_rb, bufsize); 583 584 s = splaudio(); 585 if (sc->sa_state == UCBSND_IDLE && ringbuf_full(&sc->sc_rb)) { 586 sc->sa_transfer_mode = UCBSND_TRANSFERMODE_DMA; 587 sc->sa_state = UCBSND_INIT; 588 ucbsnd_exec_output((void*)sc); 589 } 590 splx(s); 591 592 return (error); 593 } 594 595 int 596 ucbsndwrite(dev_t dev, struct uio *uio, int ioflag) 597 { 598 int unit = AUDIOUNIT(dev); 599 struct ucbsnd_softc *sc; 600 int len, error = 0; 601 int i, n, s, rest; 602 void *buf; 603 604 if (unit >= ucbsnd_cd.cd_ndevs || 605 (sc = ucbsnd_cd.cd_devs[unit]) == NULL) 606 return (ENXIO); 607 608 len = uio->uio_resid; 609 n = (len + TX39_SIBDMA_SIZE - 1) / TX39_SIBDMA_SIZE; 610 rest = len % TX39_SIBDMA_SIZE; 611 612 if (rest) 613 --n; 614 615 for (i = 0; i < n; i++) { 616 while (!(buf = ringbuf_producer_get(&sc->sc_rb))) { 617 error = tsleep(&sc->sc_rb, PRIBIO, "ucbsnd", 1000); 618 if (error) 619 goto errout; 620 } 621 622 error = ucbsndwrite_subr(sc, buf, TX39_SIBDMA_SIZE, uio); 623 if (error) 624 goto out; 625 } 626 627 if (rest) { 628 while (!(buf = ringbuf_producer_get(&sc->sc_rb))) { 629 error = tsleep(&sc->sc_rb, PRIBIO, "ucbsnd", 1000); 630 if (error) 631 goto errout; 632 } 633 634 error = ucbsndwrite_subr(sc, buf, rest, uio); 635 } 636 637 out: 638 return (error); 639 errout: 640 printf("%s: timeout. reset ring-buffer.\n", sc->sc_dev.dv_xname); 641 s = splaudio(); 642 ringbuf_reset(&sc->sc_rb); 643 splx(s); 644 645 return (error); 646 } 647 648 /* 649 * Ring buffer. 650 */ 651 int 652 ringbuf_allocate(struct ring_buf *rb, size_t blksize, int maxblk) 653 { 654 rb->rb_bufsize = blksize * maxblk; 655 rb->rb_blksize = blksize; 656 rb->rb_maxblks = maxblk; 657 #if notyet 658 rb->rb_buf = (u_int32_t)malloc(rb->rb_bufsize, M_DEVBUF, M_WAITOK); 659 #else 660 rb->rb_buf = (u_int32_t)dmabuf_static; 661 #endif 662 if (rb->rb_buf == 0) { 663 printf("ringbuf_allocate: can't allocate buffer\n"); 664 return (1); 665 } 666 memset((char*)rb->rb_buf, 0, rb->rb_bufsize); 667 #if notyet 668 rb->rb_bufcnt = malloc(rb->rb_maxblks * sizeof(size_t), M_DEVBUF, 669 M_WAITOK); 670 #else 671 rb->rb_bufcnt = dmabufcnt_static; 672 #endif 673 if (rb->rb_bufcnt == 0) { 674 printf("ringbuf_allocate: can't allocate buffer\n"); 675 return (1); 676 } 677 memset((char*)rb->rb_bufcnt, 0, rb->rb_maxblks * sizeof(size_t)); 678 679 ringbuf_reset(rb); 680 681 return (0); 682 } 683 684 void 685 ringbuf_deallocate(struct ring_buf *rb) 686 { 687 #if notyet 688 free((void*)rb->rb_buf, M_DEVBUF); 689 free(rb->rb_bufcnt, M_DEVBUF); 690 #endif 691 } 692 693 void 694 ringbuf_reset(struct ring_buf *rb) 695 { 696 rb->rb_outp = 0; 697 rb->rb_inp = 0; 698 } 699 700 int 701 ringbuf_full(struct ring_buf *rb) 702 { 703 int ret; 704 705 ret = rb->rb_outp == rb->rb_maxblks; 706 707 return (ret); 708 } 709 710 void* 711 ringbuf_producer_get(struct ring_buf *rb) 712 { 713 u_int32_t ret; 714 int s; 715 716 s = splaudio(); 717 ret = ringbuf_full(rb) ? 0 : 718 rb->rb_buf + rb->rb_inp * rb->rb_blksize; 719 splx(s); 720 721 return (void *)ret; 722 } 723 724 void 725 ringbuf_producer_return(struct ring_buf *rb, size_t cnt) 726 { 727 int s; 728 729 assert(cnt <= rb->rb_blksize); 730 731 s = splaudio(); 732 rb->rb_outp++; 733 734 rb->rb_bufcnt[rb->rb_inp] = cnt; 735 rb->rb_inp = (rb->rb_inp + 1) % rb->rb_maxblks; 736 splx(s); 737 } 738 739 void* 740 ringbuf_consumer_get(struct ring_buf *rb, size_t *cntp) 741 { 742 u_int32_t p; 743 int idx; 744 745 if (rb->rb_outp == 0) 746 return (0); 747 748 idx = (rb->rb_inp - rb->rb_outp + rb->rb_maxblks) % rb->rb_maxblks; 749 750 p = rb->rb_buf + idx * rb->rb_blksize; 751 *cntp = rb->rb_bufcnt[idx]; 752 753 return (void *)p; 754 } 755 756 void 757 ringbuf_consumer_return(struct ring_buf *rb) 758 { 759 760 if (rb->rb_outp > 0) 761 rb->rb_outp--; 762 } 763