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