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