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