]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/broadcom/bcm2835/bcm2835_audio.c
Mark more nodes as CTLFLAG_MPSAFE or CTLFLAG_NEEDGIANT (17 of many)
[FreeBSD/FreeBSD.git] / sys / arm / broadcom / bcm2835 / bcm2835_audio.c
1 /*-
2  * Copyright (c) 2015 Oleksandr Tymoshenko <gonzo@freebsd.org>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25
26 #ifdef HAVE_KERNEL_OPTION_HEADERS
27 #include "opt_snd.h"
28 #endif
29
30 #include <dev/sound/pcm/sound.h>
31 #include <dev/sound/chip.h>
32
33 #include "mixer_if.h"
34
35 #include "interface/compat/vchi_bsd.h"
36 #include "interface/vchi/vchi.h"
37 #include "interface/vchiq_arm/vchiq.h"
38
39 #include "vc_vchi_audioserv_defs.h"
40
41 SND_DECLARE_FILE("$FreeBSD$");
42
43 /* Audio destination */
44 #define DEST_AUTO               0
45 #define DEST_HEADPHONES         1
46 #define DEST_HDMI               2
47
48 /* Playback state */
49 #define PLAYBACK_IDLE           0
50 #define PLAYBACK_PLAYING        1
51 #define PLAYBACK_STOPPING       2
52
53 /* Worker thread state */
54 #define WORKER_RUNNING          0
55 #define WORKER_STOPPING         1
56 #define WORKER_STOPPED          2
57
58 /*
59  * Worker thread flags, set to 1 in flags_pending
60  * when driver requests one or another operation
61  * from worker. Cleared to 0 once worker performs
62  * the operations.
63  */
64 #define AUDIO_PARAMS            (1 << 0)
65 #define AUDIO_PLAY              (1 << 1)
66 #define AUDIO_STOP              (1 << 2)
67
68 #define VCHIQ_AUDIO_PACKET_SIZE 4000
69 #define VCHIQ_AUDIO_BUFFER_SIZE 10*VCHIQ_AUDIO_PACKET_SIZE
70
71 #define VCHIQ_AUDIO_MAX_VOLUME  
72 /* volume in terms of 0.01dB */
73 #define VCHIQ_AUDIO_VOLUME_MIN -10239
74 #define VCHIQ_AUDIO_VOLUME(db100) (uint32_t)(-((db100) << 8)/100)
75
76 /* dB levels with 5% volume step */
77 static int db_levels[] = {
78         VCHIQ_AUDIO_VOLUME_MIN, -4605, -3794, -3218, -2772,
79         -2407, -2099, -1832, -1597, -1386,
80         -1195, -1021, -861, -713, -575,
81         -446, -325, -210, -102, 0,
82 };
83
84 static uint32_t bcm2835_audio_playfmt[] = {
85         SND_FORMAT(AFMT_U8, 1, 0),
86         SND_FORMAT(AFMT_U8, 2, 0),
87         SND_FORMAT(AFMT_S8, 1, 0),
88         SND_FORMAT(AFMT_S8, 2, 0),
89         SND_FORMAT(AFMT_S16_LE, 1, 0),
90         SND_FORMAT(AFMT_S16_LE, 2, 0),
91         SND_FORMAT(AFMT_U16_LE, 1, 0),
92         SND_FORMAT(AFMT_U16_LE, 2, 0),
93         0
94 };
95
96 static struct pcmchan_caps bcm2835_audio_playcaps = {8000, 48000, bcm2835_audio_playfmt, 0};
97
98 struct bcm2835_audio_info;
99
100 struct bcm2835_audio_chinfo {
101         struct bcm2835_audio_info *parent;
102         struct pcm_channel *channel;
103         struct snd_dbuf *buffer;
104         uint32_t fmt, spd, blksz;
105
106         /* Pointer to first unsubmitted sample */
107         uint32_t unsubmittedptr;
108         /*
109          * Number of bytes in "submitted but not played"
110          * pseudo-buffer
111          */
112         int available_space;
113         int playback_state;
114         uint64_t callbacks;
115         uint64_t submitted_samples;
116         uint64_t retrieved_samples;
117         uint64_t underruns;
118         int starved;
119 };
120
121 struct bcm2835_audio_info {
122         device_t dev;
123         unsigned int bufsz;
124         struct bcm2835_audio_chinfo pch;
125         uint32_t dest, volume;
126         struct intr_config_hook intr_hook;
127
128         /* VCHI data */
129         VCHI_INSTANCE_T vchi_instance;
130         VCHI_CONNECTION_T *vchi_connection;
131         VCHI_SERVICE_HANDLE_T vchi_handle;
132
133         struct mtx lock;
134         struct cv worker_cv;
135
136         uint32_t flags_pending;
137
138         /* Worker thread state */
139         int worker_state;
140 };
141
142 #define BCM2835_AUDIO_LOCK(sc)          mtx_lock(&(sc)->lock)
143 #define BCM2835_AUDIO_LOCKED(sc)        mtx_assert(&(sc)->lock, MA_OWNED)
144 #define BCM2835_AUDIO_UNLOCK(sc)        mtx_unlock(&(sc)->lock)
145
146 static const char *
147 dest_description(uint32_t dest)
148 {
149         switch (dest) {
150                 case DEST_AUTO:
151                         return "AUTO";
152                         break;
153
154                 case DEST_HEADPHONES:
155                         return "HEADPHONES";
156                         break;
157
158                 case DEST_HDMI:
159                         return "HDMI";
160                         break;
161                 default:
162                         return "UNKNOWN";
163                         break;
164         }
165 }
166
167 static void
168 bcm2835_worker_update_params(struct bcm2835_audio_info *sc)
169 {
170
171         BCM2835_AUDIO_LOCKED(sc);
172
173         sc->flags_pending |= AUDIO_PARAMS;
174         cv_signal(&sc->worker_cv);
175 }
176
177 static void
178 bcm2835_worker_play_start(struct bcm2835_audio_info *sc)
179 {
180         BCM2835_AUDIO_LOCK(sc);
181         sc->flags_pending &= ~(AUDIO_STOP);
182         sc->flags_pending |= AUDIO_PLAY;
183         cv_signal(&sc->worker_cv);
184         BCM2835_AUDIO_UNLOCK(sc);
185 }
186
187 static void
188 bcm2835_worker_play_stop(struct bcm2835_audio_info *sc)
189 {
190         BCM2835_AUDIO_LOCK(sc);
191         sc->flags_pending &= ~(AUDIO_PLAY);
192         sc->flags_pending |= AUDIO_STOP;
193         cv_signal(&sc->worker_cv);
194         BCM2835_AUDIO_UNLOCK(sc);
195 }
196
197 static void
198 bcm2835_audio_callback(void *param, const VCHI_CALLBACK_REASON_T reason, void *msg_handle)
199 {
200         struct bcm2835_audio_info *sc = (struct bcm2835_audio_info *)param;
201         int32_t status;
202         uint32_t msg_len;
203         VC_AUDIO_MSG_T m;
204
205         if (reason != VCHI_CALLBACK_MSG_AVAILABLE)
206                 return;
207
208         status = vchi_msg_dequeue(sc->vchi_handle,
209             &m, sizeof m, &msg_len, VCHI_FLAGS_NONE);
210         if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
211                 if (m.u.result.success) {
212                         device_printf(sc->dev,
213                             "msg type %08x failed\n",
214                             m.type);
215                 }
216         } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
217                 struct bcm2835_audio_chinfo *ch = m.u.complete.cookie;
218
219                 int count = m.u.complete.count & 0xffff;
220                 int perr = (m.u.complete.count & (1U << 30)) != 0;
221                 ch->callbacks++;
222                 if (perr)
223                         ch->underruns++;
224
225                 BCM2835_AUDIO_LOCK(sc);
226                 if (ch->playback_state != PLAYBACK_IDLE) {
227                         /* Prevent LOR */
228                         BCM2835_AUDIO_UNLOCK(sc);
229                         chn_intr(sc->pch.channel);
230                         BCM2835_AUDIO_LOCK(sc);
231                 }
232                 /* We should check again, state might have changed */
233                 if (ch->playback_state != PLAYBACK_IDLE) {
234                         if (!perr) {
235                                 if ((ch->available_space + count)> VCHIQ_AUDIO_BUFFER_SIZE) {
236                                         device_printf(sc->dev, "inconsistent data in callback:\n");
237                                         device_printf(sc->dev, "available_space == %d, count = %d, perr=%d\n",
238                                             ch->available_space, count, perr);
239                                         device_printf(sc->dev,
240                                             "retrieved_samples = %lld, submitted_samples = %lld\n",
241                                             ch->retrieved_samples, ch->submitted_samples);
242                                 }
243                                 ch->available_space += count;
244                                 ch->retrieved_samples += count;
245                         }
246                         if (perr || (ch->available_space >= VCHIQ_AUDIO_PACKET_SIZE))
247                                 cv_signal(&sc->worker_cv);
248                 }
249                 BCM2835_AUDIO_UNLOCK(sc);
250         } else
251                 printf("%s: unknown m.type: %d\n", __func__, m.type);
252 }
253
254 /* VCHIQ stuff */
255 static void
256 bcm2835_audio_init(struct bcm2835_audio_info *sc)
257 {
258         int status;
259
260         /* Initialize and create a VCHI connection */
261         status = vchi_initialise(&sc->vchi_instance);
262         if (status != 0) {
263                 printf("vchi_initialise failed: %d\n", status);
264                 return;
265         }
266
267         status = vchi_connect(NULL, 0, sc->vchi_instance);
268         if (status != 0) {
269                 printf("vchi_connect failed: %d\n", status);
270                 return;
271         }
272
273         SERVICE_CREATION_T params = {
274             VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
275             VC_AUDIO_SERVER_NAME,   /* 4cc service code */
276             sc->vchi_connection,    /* passed in fn pointers */
277             0,  /* rx fifo size */
278             0,  /* tx fifo size */
279             bcm2835_audio_callback,    /* service callback */
280             sc,   /* service callback parameter */
281             1,
282             1,
283             0   /* want crc check on bulk transfers */
284         };
285
286         status = vchi_service_open(sc->vchi_instance, &params,
287             &sc->vchi_handle);
288
289         if (status != 0)
290                 sc->vchi_handle = VCHIQ_SERVICE_HANDLE_INVALID;
291 }
292
293 static void
294 bcm2835_audio_release(struct bcm2835_audio_info *sc)
295 {
296         int success;
297
298         if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
299                 success = vchi_service_close(sc->vchi_handle);
300                 if (success != 0)
301                         printf("vchi_service_close failed: %d\n", success);
302                 vchi_service_release(sc->vchi_handle);
303                 sc->vchi_handle = VCHIQ_SERVICE_HANDLE_INVALID;
304         }
305
306         vchi_disconnect(sc->vchi_instance);
307 }
308
309 static void
310 bcm2835_audio_reset_channel(struct bcm2835_audio_chinfo *ch)
311 {
312
313         ch->available_space = VCHIQ_AUDIO_BUFFER_SIZE;
314         ch->unsubmittedptr = 0;
315         sndbuf_reset(ch->buffer);
316 }
317
318 static void
319 bcm2835_audio_start(struct bcm2835_audio_chinfo *ch)
320 {
321         VC_AUDIO_MSG_T m;
322         int ret;
323         struct bcm2835_audio_info *sc = ch->parent;
324
325         if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
326                 m.type = VC_AUDIO_MSG_TYPE_START;
327                 ret = vchi_msg_queue(sc->vchi_handle,
328                     &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
329
330                 if (ret != 0)
331                         printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);
332         }
333 }
334
335 static void
336 bcm2835_audio_stop(struct bcm2835_audio_chinfo *ch)
337 {
338         VC_AUDIO_MSG_T m;
339         int ret;
340         struct bcm2835_audio_info *sc = ch->parent;
341
342         if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
343                 m.type = VC_AUDIO_MSG_TYPE_STOP;
344                 m.u.stop.draining = 0;
345
346                 ret = vchi_msg_queue(sc->vchi_handle,
347                     &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
348
349                 if (ret != 0)
350                         printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);
351         }
352 }
353
354 static void
355 bcm2835_audio_open(struct bcm2835_audio_info *sc)
356 {
357         VC_AUDIO_MSG_T m;
358         int ret;
359
360         if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
361                 m.type = VC_AUDIO_MSG_TYPE_OPEN;
362                 ret = vchi_msg_queue(sc->vchi_handle,
363                     &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
364
365                 if (ret != 0)
366                         printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);
367         }
368 }
369
370 static void
371 bcm2835_audio_update_controls(struct bcm2835_audio_info *sc, uint32_t volume, uint32_t dest)
372 {
373         VC_AUDIO_MSG_T m;
374         int ret, db;
375
376         if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
377                 m.type = VC_AUDIO_MSG_TYPE_CONTROL;
378                 m.u.control.dest = dest;
379                 if (volume > 99)
380                         volume = 99;
381                 db = db_levels[volume/5];
382                 m.u.control.volume = VCHIQ_AUDIO_VOLUME(db);
383
384                 ret = vchi_msg_queue(sc->vchi_handle,
385                     &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
386
387                 if (ret != 0)
388                         printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);
389         }
390 }
391
392 static void
393 bcm2835_audio_update_params(struct bcm2835_audio_info *sc, uint32_t fmt, uint32_t speed)
394 {
395         VC_AUDIO_MSG_T m;
396         int ret;
397
398         if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
399                 m.type = VC_AUDIO_MSG_TYPE_CONFIG;
400                 m.u.config.channels = AFMT_CHANNEL(fmt);
401                 m.u.config.samplerate = speed;
402                 m.u.config.bps = AFMT_BIT(fmt);
403
404                 ret = vchi_msg_queue(sc->vchi_handle,
405                     &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
406
407                 if (ret != 0)
408                         printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);
409         }
410 }
411
412 static bool
413 bcm2835_audio_buffer_should_sleep(struct bcm2835_audio_chinfo *ch)
414 {
415         
416         if (ch->playback_state != PLAYBACK_PLAYING)
417                 return (true);
418
419         /* Not enough data */
420         if (sndbuf_getready(ch->buffer) < VCHIQ_AUDIO_PACKET_SIZE) {
421                 printf("starve\n");
422                 ch->starved++;
423                 return (true);
424         }
425
426         /* Not enough free space */
427         if (ch->available_space < VCHIQ_AUDIO_PACKET_SIZE) {
428                 return (true);
429         }
430
431         return (false);
432 }
433
434 static void
435 bcm2835_audio_write_samples(struct bcm2835_audio_chinfo *ch, void *buf, uint32_t count)
436 {
437         struct bcm2835_audio_info *sc = ch->parent;
438         VC_AUDIO_MSG_T m;
439         int ret;
440
441         if (sc->vchi_handle == VCHIQ_SERVICE_HANDLE_INVALID) {
442                 return;
443         }
444
445         m.type = VC_AUDIO_MSG_TYPE_WRITE;
446         m.u.write.count = count;
447         m.u.write.max_packet = VCHIQ_AUDIO_PACKET_SIZE;
448         m.u.write.callback = NULL;
449         m.u.write.cookie = ch;
450         m.u.write.silence = 0;
451
452         ret = vchi_msg_queue(sc->vchi_handle,
453             &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
454
455         if (ret != 0)
456                 printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);
457
458         while (count > 0) {
459                 int bytes = MIN((int)m.u.write.max_packet, (int)count);
460                 ret = vchi_msg_queue(sc->vchi_handle,
461                     buf, bytes, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
462                 if (ret != 0)
463                         printf("%s: vchi_msg_queue failed: %d\n",
464                             __func__, ret);
465                 buf = (char *)buf + bytes;
466                 count -= bytes;
467         }
468 }
469
470 static void
471 bcm2835_audio_worker(void *data)
472 {
473         struct bcm2835_audio_info *sc = (struct bcm2835_audio_info *)data;
474         struct bcm2835_audio_chinfo *ch = &sc->pch;
475         uint32_t speed, format;
476         uint32_t volume, dest;
477         uint32_t flags;
478         uint32_t count, size, readyptr;
479         uint8_t *buf;
480
481         ch->playback_state = PLAYBACK_IDLE;
482
483         while (1) {
484                 if (sc->worker_state != WORKER_RUNNING)
485                         break;
486
487                 BCM2835_AUDIO_LOCK(sc);
488                 /*
489                  * wait until there are flags set or buffer is ready
490                  * to consume more samples
491                  */
492                 while ((sc->flags_pending == 0) &&
493                     bcm2835_audio_buffer_should_sleep(ch)) {
494                         cv_wait_sig(&sc->worker_cv, &sc->lock);
495                 }
496                 flags = sc->flags_pending;
497                 /* Clear pending flags */
498                 sc->flags_pending = 0;
499                 BCM2835_AUDIO_UNLOCK(sc);
500
501                 /* Requested to change parameters */
502                 if (flags & AUDIO_PARAMS) {
503                         BCM2835_AUDIO_LOCK(sc);
504                         speed = ch->spd;
505                         format = ch->fmt;
506                         volume = sc->volume;
507                         dest = sc->dest;
508                         BCM2835_AUDIO_UNLOCK(sc);
509                         if (ch->playback_state == PLAYBACK_IDLE)
510                                 bcm2835_audio_update_params(sc, format, speed);
511                         bcm2835_audio_update_controls(sc, volume, dest);
512                 }
513
514                 /* Requested to stop playback */
515                 if ((flags & AUDIO_STOP) &&
516                     (ch->playback_state == PLAYBACK_PLAYING)) {
517                         bcm2835_audio_stop(ch);
518                         BCM2835_AUDIO_LOCK(sc);
519                         bcm2835_audio_reset_channel(&sc->pch);
520                         ch->playback_state = PLAYBACK_IDLE;
521                         BCM2835_AUDIO_UNLOCK(sc);
522                         continue;
523                 }
524
525                 /* Requested to start playback */
526                 if ((flags & AUDIO_PLAY) &&
527                     (ch->playback_state == PLAYBACK_IDLE)) {
528                         BCM2835_AUDIO_LOCK(sc);
529                         ch->playback_state = PLAYBACK_PLAYING;
530                         BCM2835_AUDIO_UNLOCK(sc);
531                         bcm2835_audio_start(ch);
532                 }
533
534                 if (ch->playback_state == PLAYBACK_IDLE)
535                         continue;
536
537                 if (sndbuf_getready(ch->buffer) == 0)
538                         continue;
539
540                 count = sndbuf_getready(ch->buffer);
541                 size = sndbuf_getsize(ch->buffer);
542                 readyptr = sndbuf_getreadyptr(ch->buffer);
543
544                 BCM2835_AUDIO_LOCK(sc);
545                 if (readyptr + count > size)
546                         count = size - readyptr;
547                 count = min(count, ch->available_space);
548                 count -= (count % VCHIQ_AUDIO_PACKET_SIZE);
549                 BCM2835_AUDIO_UNLOCK(sc);
550
551                 if (count < VCHIQ_AUDIO_PACKET_SIZE)
552                         continue;
553
554                 buf = (uint8_t*)sndbuf_getbuf(ch->buffer) + readyptr;
555
556                 bcm2835_audio_write_samples(ch, buf, count);
557                 BCM2835_AUDIO_LOCK(sc);
558                 ch->unsubmittedptr = (ch->unsubmittedptr + count) % sndbuf_getsize(ch->buffer);
559                 ch->available_space -= count;
560                 ch->submitted_samples += count;
561                 KASSERT(ch->available_space >= 0, ("ch->available_space == %d\n", ch->available_space));
562                 BCM2835_AUDIO_UNLOCK(sc);
563         }
564
565         BCM2835_AUDIO_LOCK(sc);
566         sc->worker_state = WORKER_STOPPED;
567         cv_signal(&sc->worker_cv);
568         BCM2835_AUDIO_UNLOCK(sc);
569
570         kproc_exit(0);
571 }
572
573 static void
574 bcm2835_audio_create_worker(struct bcm2835_audio_info *sc)
575 {
576         struct proc *newp;
577
578         sc->worker_state = WORKER_RUNNING;
579         if (kproc_create(bcm2835_audio_worker, (void*)sc, &newp, 0, 0,
580             "bcm2835_audio_worker") != 0) {
581                 printf("failed to create bcm2835_audio_worker\n");
582         }
583 }
584
585 /* -------------------------------------------------------------------- */
586 /* channel interface for VCHI audio */
587 static void *
588 bcmchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
589 {
590         struct bcm2835_audio_info *sc = devinfo;
591         struct bcm2835_audio_chinfo *ch = &sc->pch;
592         void *buffer;
593
594         if (dir == PCMDIR_REC)
595                 return NULL;
596
597         ch->parent = sc;
598         ch->channel = c;
599         ch->buffer = b;
600
601         /* default values */
602         ch->spd = 44100;
603         ch->fmt = SND_FORMAT(AFMT_S16_LE, 2, 0);
604         ch->blksz = VCHIQ_AUDIO_PACKET_SIZE;
605
606         buffer = malloc(sc->bufsz, M_DEVBUF, M_WAITOK | M_ZERO);
607
608         if (sndbuf_setup(ch->buffer, buffer, sc->bufsz) != 0) {
609                 device_printf(sc->dev, "sndbuf_setup failed\n");
610                 free(buffer, M_DEVBUF);
611                 return NULL;
612         }
613
614         BCM2835_AUDIO_LOCK(sc);
615         bcm2835_worker_update_params(sc);
616         BCM2835_AUDIO_UNLOCK(sc);
617
618         return ch;
619 }
620
621 static int
622 bcmchan_free(kobj_t obj, void *data)
623 {
624         struct bcm2835_audio_chinfo *ch = data;
625         void *buffer;
626
627         buffer = sndbuf_getbuf(ch->buffer);
628         if (buffer)
629                 free(buffer, M_DEVBUF);
630
631         return (0);
632 }
633
634 static int
635 bcmchan_setformat(kobj_t obj, void *data, uint32_t format)
636 {
637         struct bcm2835_audio_chinfo *ch = data;
638         struct bcm2835_audio_info *sc = ch->parent;
639
640         BCM2835_AUDIO_LOCK(sc);
641         ch->fmt = format;
642         bcm2835_worker_update_params(sc);
643         BCM2835_AUDIO_UNLOCK(sc);
644
645         return 0;
646 }
647
648 static uint32_t
649 bcmchan_setspeed(kobj_t obj, void *data, uint32_t speed)
650 {
651         struct bcm2835_audio_chinfo *ch = data;
652         struct bcm2835_audio_info *sc = ch->parent;
653
654         BCM2835_AUDIO_LOCK(sc);
655         ch->spd = speed;
656         bcm2835_worker_update_params(sc);
657         BCM2835_AUDIO_UNLOCK(sc);
658
659         return ch->spd;
660 }
661
662 static uint32_t
663 bcmchan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
664 {
665         struct bcm2835_audio_chinfo *ch = data;
666
667         return ch->blksz;
668 }
669
670 static int
671 bcmchan_trigger(kobj_t obj, void *data, int go)
672 {
673         struct bcm2835_audio_chinfo *ch = data;
674         struct bcm2835_audio_info *sc = ch->parent;
675
676         if (!PCMTRIG_COMMON(go))
677                 return (0);
678
679         switch (go) {
680         case PCMTRIG_START:
681                 /* kickstart data flow */
682                 chn_intr(sc->pch.channel);
683                 ch->submitted_samples = 0;
684                 ch->retrieved_samples = 0;
685                 bcm2835_worker_play_start(sc);
686                 break;
687
688         case PCMTRIG_STOP:
689         case PCMTRIG_ABORT:
690                 bcm2835_worker_play_stop(sc);
691                 break;
692
693         default:
694                 break;
695         }
696         return 0;
697 }
698
699 static uint32_t
700 bcmchan_getptr(kobj_t obj, void *data)
701 {
702         struct bcm2835_audio_chinfo *ch = data;
703         struct bcm2835_audio_info *sc = ch->parent;
704         uint32_t ret;
705
706         BCM2835_AUDIO_LOCK(sc);
707         ret = ch->unsubmittedptr;
708         BCM2835_AUDIO_UNLOCK(sc);
709
710         return ret;
711 }
712
713 static struct pcmchan_caps *
714 bcmchan_getcaps(kobj_t obj, void *data)
715 {
716
717         return &bcm2835_audio_playcaps;
718 }
719
720 static kobj_method_t bcmchan_methods[] = {
721         KOBJMETHOD(channel_init,                bcmchan_init),
722         KOBJMETHOD(channel_free,                bcmchan_free),
723         KOBJMETHOD(channel_setformat,           bcmchan_setformat),
724         KOBJMETHOD(channel_setspeed,            bcmchan_setspeed),
725         KOBJMETHOD(channel_setblocksize,        bcmchan_setblocksize),
726         KOBJMETHOD(channel_trigger,             bcmchan_trigger),
727         KOBJMETHOD(channel_getptr,              bcmchan_getptr),
728         KOBJMETHOD(channel_getcaps,             bcmchan_getcaps),
729         KOBJMETHOD_END
730 };
731 CHANNEL_DECLARE(bcmchan);
732
733 /************************************************************/
734
735 static int
736 bcmmix_init(struct snd_mixer *m)
737 {
738
739         mix_setdevs(m, SOUND_MASK_VOLUME);
740
741         return (0);
742 }
743
744 static int
745 bcmmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
746 {
747         struct bcm2835_audio_info *sc = mix_getdevinfo(m);
748
749         switch (dev) {
750         case SOUND_MIXER_VOLUME:
751                 BCM2835_AUDIO_LOCK(sc);
752                 sc->volume = left;
753                 bcm2835_worker_update_params(sc);
754                 BCM2835_AUDIO_UNLOCK(sc);
755
756                 break;
757
758         default:
759                 break;
760         }
761
762         return left | (left << 8);
763 }
764
765 static kobj_method_t bcmmixer_methods[] = {
766         KOBJMETHOD(mixer_init,          bcmmix_init),
767         KOBJMETHOD(mixer_set,           bcmmix_set),
768         KOBJMETHOD_END
769 };
770
771 MIXER_DECLARE(bcmmixer);
772
773 static int
774 sysctl_bcm2835_audio_dest(SYSCTL_HANDLER_ARGS)
775 {
776         struct bcm2835_audio_info *sc = arg1;
777         int val;
778         int err;
779
780         val = sc->dest;
781         err = sysctl_handle_int(oidp, &val, 0, req);
782         if (err || !req->newptr) /* error || read request */
783                 return (err);
784
785         if ((val < 0) || (val > 2))
786                 return (EINVAL);
787
788         BCM2835_AUDIO_LOCK(sc);
789         sc->dest = val;
790         bcm2835_worker_update_params(sc);
791         BCM2835_AUDIO_UNLOCK(sc);
792
793         if (bootverbose)
794                 device_printf(sc->dev, "destination set to %s\n", dest_description(val));
795
796         return (0);
797 }
798
799 static void
800 vchi_audio_sysctl_init(struct bcm2835_audio_info *sc)
801 {
802         struct sysctl_ctx_list *ctx;
803         struct sysctl_oid *tree_node;
804         struct sysctl_oid_list *tree;
805
806         /*
807          * Add system sysctl tree/handlers.
808          */
809         ctx = device_get_sysctl_ctx(sc->dev);
810         tree_node = device_get_sysctl_tree(sc->dev);
811         tree = SYSCTL_CHILDREN(tree_node);
812         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "dest",
813             CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_NEEDGIANT, sc, sizeof(*sc),
814             sysctl_bcm2835_audio_dest, "IU", "audio destination, "
815             "0 - auto, 1 - headphones, 2 - HDMI");
816         SYSCTL_ADD_UQUAD(ctx, tree, OID_AUTO, "callbacks",
817                         CTLFLAG_RD, &sc->pch.callbacks,
818                         "callbacks total");
819         SYSCTL_ADD_UQUAD(ctx, tree, OID_AUTO, "submitted",
820                         CTLFLAG_RD, &sc->pch.submitted_samples,
821                         "last play submitted samples");
822         SYSCTL_ADD_UQUAD(ctx, tree, OID_AUTO, "retrieved",
823                         CTLFLAG_RD, &sc->pch.retrieved_samples,
824                         "last play retrieved samples");
825         SYSCTL_ADD_UQUAD(ctx, tree, OID_AUTO, "underruns",
826                         CTLFLAG_RD, &sc->pch.underruns,
827                         "callback underruns");
828         SYSCTL_ADD_INT(ctx, tree, OID_AUTO, "freebuffer",
829                         CTLFLAG_RD, &sc->pch.available_space,
830                         sc->pch.available_space, "callbacks total");
831         SYSCTL_ADD_INT(ctx, tree, OID_AUTO, "starved",
832                         CTLFLAG_RD, &sc->pch.starved,
833                         sc->pch.starved, "number of starved conditions");
834 }
835
836 static void
837 bcm2835_audio_identify(driver_t *driver, device_t parent)
838 {
839
840         BUS_ADD_CHILD(parent, 0, "pcm", 0);
841 }
842
843 static int
844 bcm2835_audio_probe(device_t dev)
845 {
846
847         device_set_desc(dev, "VCHIQ audio");
848         return (BUS_PROBE_DEFAULT);
849 }
850
851 static void
852 bcm2835_audio_delayed_init(void *xsc)
853 {
854         struct bcm2835_audio_info *sc;
855         char status[SND_STATUSLEN];
856
857         sc = xsc;
858
859         config_intrhook_disestablish(&sc->intr_hook);
860
861         bcm2835_audio_init(sc);
862         bcm2835_audio_open(sc);
863         sc->volume = 75;
864         sc->dest = DEST_AUTO;
865
866         if (mixer_init(sc->dev, &bcmmixer_class, sc)) {
867                 device_printf(sc->dev, "mixer_init failed\n");
868                 goto no;
869         }
870
871         if (pcm_register(sc->dev, sc, 1, 0)) {
872                 device_printf(sc->dev, "pcm_register failed\n");
873                 goto no;
874         }
875
876         pcm_addchan(sc->dev, PCMDIR_PLAY, &bcmchan_class, sc);
877         snprintf(status, SND_STATUSLEN, "at VCHIQ");
878         pcm_setstatus(sc->dev, status);
879
880         bcm2835_audio_reset_channel(&sc->pch);
881         bcm2835_audio_create_worker(sc);
882
883         vchi_audio_sysctl_init(sc);
884
885 no:
886         ;
887 }
888
889 static int
890 bcm2835_audio_attach(device_t dev)
891 {
892         struct bcm2835_audio_info *sc;
893
894         sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
895
896         sc->dev = dev;
897         sc->bufsz = VCHIQ_AUDIO_BUFFER_SIZE;
898
899         mtx_init(&sc->lock, device_get_nameunit(dev),
900             "bcm_audio_lock", MTX_DEF);
901         cv_init(&sc->worker_cv, "worker_cv");
902         sc->vchi_handle = VCHIQ_SERVICE_HANDLE_INVALID;
903
904         /*
905          * We need interrupts enabled for VCHI to work properly,
906          * so delay initialization until it happens.
907          */
908         sc->intr_hook.ich_func = bcm2835_audio_delayed_init;
909         sc->intr_hook.ich_arg = sc;
910
911         if (config_intrhook_establish(&sc->intr_hook) != 0)
912                 goto no;
913
914         return 0;
915
916 no:
917         return ENXIO;
918 }
919
920 static int
921 bcm2835_audio_detach(device_t dev)
922 {
923         int r;
924         struct bcm2835_audio_info *sc;
925         sc = pcm_getdevinfo(dev);
926
927         /* Stop worker thread */
928         BCM2835_AUDIO_LOCK(sc);
929         sc->worker_state = WORKER_STOPPING;
930         cv_signal(&sc->worker_cv);
931         /* Wait for thread to exit */
932         while (sc->worker_state != WORKER_STOPPED)
933                 cv_wait_sig(&sc->worker_cv, &sc->lock);
934         BCM2835_AUDIO_UNLOCK(sc);
935
936         r = pcm_unregister(dev);
937         if (r)
938                 return r;
939
940         mtx_destroy(&sc->lock);
941         cv_destroy(&sc->worker_cv);
942
943         bcm2835_audio_release(sc);
944
945         free(sc, M_DEVBUF);
946
947         return 0;
948 }
949
950 static device_method_t bcm2835_audio_methods[] = {
951         /* Device interface */
952         DEVMETHOD(device_identify,      bcm2835_audio_identify),
953         DEVMETHOD(device_probe,         bcm2835_audio_probe),
954         DEVMETHOD(device_attach,        bcm2835_audio_attach),
955         DEVMETHOD(device_detach,        bcm2835_audio_detach),
956
957         { 0, 0 }
958 };
959
960 static driver_t bcm2835_audio_driver = {
961         "pcm",
962         bcm2835_audio_methods,
963         PCM_SOFTC_SIZE,
964 };
965
966 DRIVER_MODULE(bcm2835_audio, vchiq, bcm2835_audio_driver, pcm_devclass, 0, 0);
967 MODULE_DEPEND(bcm2835_audio, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
968 MODULE_DEPEND(bcm2835_audio, vchiq, 1, 1, 1);
969 MODULE_VERSION(bcm2835_audio, 1);