]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/broadcom/bcm2835/bcm2835_audio.c
Fix some of WITNESS complaints and bootup lock by removing msg_avail
[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 #define DEST_AUTO               0
44 #define DEST_HEADPHONES         1
45 #define DEST_HDMI               2
46
47 #define VCHIQ_AUDIO_PACKET_SIZE 4000
48 #define VCHIQ_AUDIO_BUFFER_SIZE 128000
49
50 #define VCHIQ_AUDIO_MAX_VOLUME  
51 /* volume in terms of 0.01dB */
52 #define VCHIQ_AUDIO_VOLUME_MIN -10239
53 #define VCHIQ_AUDIO_VOLUME(db100) (uint32_t)(-((db100) << 8)/100)
54
55 /* dB levels with 5% volume step */
56 static int db_levels[] = {
57         VCHIQ_AUDIO_VOLUME_MIN, -4605, -3794, -3218, -2772,
58         -2407, -2099, -1832, -1597, -1386,
59         -1195, -1021, -861, -713, -575,
60         -446, -325, -210, -102, 0,
61 };
62
63 static uint32_t bcm2835_audio_playfmt[] = {
64         SND_FORMAT(AFMT_U8, 1, 0),
65         SND_FORMAT(AFMT_U8, 2, 0),
66         SND_FORMAT(AFMT_S8, 1, 0),
67         SND_FORMAT(AFMT_S8, 2, 0),
68         SND_FORMAT(AFMT_S16_LE, 1, 0),
69         SND_FORMAT(AFMT_S16_LE, 2, 0),
70         SND_FORMAT(AFMT_U16_LE, 1, 0),
71         SND_FORMAT(AFMT_U16_LE, 2, 0),
72         0
73 };
74
75 static struct pcmchan_caps bcm2835_audio_playcaps = {8000, 48000, bcm2835_audio_playfmt, 0};
76
77 struct bcm2835_audio_info;
78
79 #define PLAYBACK_IDLE           0
80 #define PLAYBACK_STARTING       1
81 #define PLAYBACK_PLAYING        2
82 #define PLAYBACK_STOPPING       3
83
84 struct bcm2835_audio_chinfo {
85         struct bcm2835_audio_info *parent;
86         struct pcm_channel *channel;
87         struct snd_dbuf *buffer;
88         uint32_t fmt, spd, blksz;
89
90         uint32_t complete_pos;
91         uint32_t free_buffer;
92         uint32_t buffered_ptr;
93         int playback_state;
94 };
95
96 struct bcm2835_audio_info {
97         device_t dev;
98         unsigned int bufsz;
99         struct bcm2835_audio_chinfo pch;
100         uint32_t dest, volume;
101         struct mtx *lock;
102         struct intr_config_hook intr_hook;
103
104         /* VCHI data */
105         struct mtx vchi_lock;
106
107         VCHI_INSTANCE_T vchi_instance;
108         VCHI_CONNECTION_T *vchi_connection;
109         VCHI_SERVICE_HANDLE_T vchi_handle;
110
111         struct mtx data_lock;
112         struct cv data_cv;
113
114         /* Unloadign module */
115         int unloading;
116 };
117
118 #define bcm2835_audio_lock(_ess) snd_mtxlock((_ess)->lock)
119 #define bcm2835_audio_unlock(_ess) snd_mtxunlock((_ess)->lock)
120 #define bcm2835_audio_lock_assert(_ess) snd_mtxassert((_ess)->lock)
121
122 #define VCHIQ_VCHI_LOCK(sc)             mtx_lock(&(sc)->vchi_lock)
123 #define VCHIQ_VCHI_UNLOCK(sc)           mtx_unlock(&(sc)->vchi_lock)
124
125 static const char *
126 dest_description(uint32_t dest)
127 {
128         switch (dest) {
129                 case DEST_AUTO:
130                         return "AUTO";
131                         break;
132
133                 case DEST_HEADPHONES:
134                         return "HEADPHONES";
135                         break;
136
137                 case DEST_HDMI:
138                         return "HDMI";
139                         break;
140                 default:
141                         return "UNKNOWN";
142                         break;
143         }
144 }
145
146 static void
147 bcm2835_audio_callback(void *param, const VCHI_CALLBACK_REASON_T reason, void *msg_handle)
148 {
149         struct bcm2835_audio_info *sc = (struct bcm2835_audio_info *)param;
150         int32_t status;
151         uint32_t msg_len;
152         VC_AUDIO_MSG_T m;
153
154         if (reason != VCHI_CALLBACK_MSG_AVAILABLE)
155                 return;
156
157         status = vchi_msg_dequeue(sc->vchi_handle,
158             &m, sizeof m, &msg_len, VCHI_FLAGS_NONE);
159         if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
160                 if (m.u.result.success) {
161                         device_printf(sc->dev, 
162                             "msg type %08x failed\n",
163                             m.type);
164                 }
165         } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
166                 struct bcm2835_audio_chinfo *ch = m.u.complete.cookie;
167
168                 int count = m.u.complete.count & 0xffff;
169                 int perr = (m.u.complete.count & (1U << 30)) != 0;
170
171                 ch->complete_pos = (ch->complete_pos + count) % sndbuf_getsize(ch->buffer);
172                 ch->free_buffer += count;
173
174                 if (perr || ch->free_buffer >= VCHIQ_AUDIO_PACKET_SIZE) {
175                         chn_intr(ch->channel);
176                         cv_signal(&sc->data_cv);
177                 }
178         } else
179                 printf("%s: unknown m.type: %d\n", __func__, m.type);
180 }
181
182 /* VCHIQ stuff */
183 static void
184 bcm2835_audio_init(struct bcm2835_audio_info *sc)
185 {
186         int status;
187
188         /* Initialize and create a VCHI connection */
189         status = vchi_initialise(&sc->vchi_instance);
190         if (status != 0) {
191                 printf("vchi_initialise failed: %d\n", status);
192                 return;
193         }
194
195         status = vchi_connect(NULL, 0, sc->vchi_instance);
196         if (status != 0) {
197                 printf("vchi_connect failed: %d\n", status);
198                 return;
199         }
200
201         SERVICE_CREATION_T params = {
202             VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
203             VC_AUDIO_SERVER_NAME,   /* 4cc service code */
204             sc->vchi_connection,    /* passed in fn pointers */
205             0,  /* rx fifo size */
206             0,  /* tx fifo size */
207             bcm2835_audio_callback,    /* service callback */
208             sc,   /* service callback parameter */
209             1,
210             1,
211             0   /* want crc check on bulk transfers */
212         };
213
214         status = vchi_service_open(sc->vchi_instance, &params,
215             &sc->vchi_handle);
216
217         if (status == 0)
218                 /* Finished with the service for now */
219                 vchi_service_release(sc->vchi_handle);
220         else
221                 sc->vchi_handle = VCHIQ_SERVICE_HANDLE_INVALID;
222 }
223
224 static void
225 bcm2835_audio_release(struct bcm2835_audio_info *sc)
226 {
227         int success;
228
229         if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
230                 vchi_service_use(sc->vchi_handle);
231                 success = vchi_service_close(sc->vchi_handle);
232                 if (success != 0)
233                         printf("vchi_service_close failed: %d\n", success);
234                 sc->vchi_handle = VCHIQ_SERVICE_HANDLE_INVALID;
235         }
236
237         vchi_disconnect(sc->vchi_instance);
238 }
239
240 static void
241 bcm2835_audio_reset_channel(struct bcm2835_audio_chinfo *ch)
242 {
243         ch->free_buffer = VCHIQ_AUDIO_BUFFER_SIZE;
244         ch->playback_state = 0;
245         ch->buffered_ptr = 0;
246         ch->complete_pos = 0;
247
248         sndbuf_reset(ch->buffer);
249 }
250
251 static void
252 bcm2835_audio_start(struct bcm2835_audio_chinfo *ch)
253 {
254         VC_AUDIO_MSG_T m;
255         int ret;
256         struct bcm2835_audio_info *sc = ch->parent;
257
258         VCHIQ_VCHI_LOCK(sc);
259         if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
260                 vchi_service_use(sc->vchi_handle);
261
262                 bcm2835_audio_reset_channel(ch);
263
264                 m.type = VC_AUDIO_MSG_TYPE_START;
265                 ret = vchi_msg_queue(sc->vchi_handle,
266                     &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
267
268                 if (ret != 0)
269                         printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);
270
271                 vchi_service_release(sc->vchi_handle);
272         }
273         VCHIQ_VCHI_UNLOCK(sc);
274
275 }
276
277 static void
278 bcm2835_audio_stop(struct bcm2835_audio_chinfo *ch)
279 {
280         VC_AUDIO_MSG_T m;
281         int ret;
282         struct bcm2835_audio_info *sc = ch->parent;
283
284         VCHIQ_VCHI_LOCK(sc);
285         if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
286                 vchi_service_use(sc->vchi_handle);
287
288                 m.type = VC_AUDIO_MSG_TYPE_STOP;
289                 m.u.stop.draining = 0;
290
291                 ret = vchi_msg_queue(sc->vchi_handle,
292                     &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
293
294                 if (ret != 0)
295                         printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);
296
297                 vchi_service_release(sc->vchi_handle);
298         }
299         VCHIQ_VCHI_UNLOCK(sc);
300 }
301
302 static void
303 bcm2835_audio_open(struct bcm2835_audio_info *sc)
304 {
305         VC_AUDIO_MSG_T m;
306         int ret;
307
308         VCHIQ_VCHI_LOCK(sc);
309         if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
310                 vchi_service_use(sc->vchi_handle);
311
312                 m.type = VC_AUDIO_MSG_TYPE_OPEN;
313                 ret = vchi_msg_queue(sc->vchi_handle,
314                     &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
315
316                 if (ret != 0)
317                         printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);
318
319                 vchi_service_release(sc->vchi_handle);
320         }
321         VCHIQ_VCHI_UNLOCK(sc);
322 }
323
324 static void
325 bcm2835_audio_update_controls(struct bcm2835_audio_info *sc)
326 {
327         VC_AUDIO_MSG_T m;
328         int ret, db;
329
330         VCHIQ_VCHI_LOCK(sc);
331         if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
332                 vchi_service_use(sc->vchi_handle);
333
334                 m.type = VC_AUDIO_MSG_TYPE_CONTROL;
335                 m.u.control.dest = sc->dest;
336                 if (sc->volume > 99)
337                         sc->volume = 99;
338                 db = db_levels[sc->volume/5];
339                 m.u.control.volume = VCHIQ_AUDIO_VOLUME(db);
340
341                 ret = vchi_msg_queue(sc->vchi_handle,
342                     &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
343
344                 if (ret != 0)
345                         printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);
346
347                 vchi_service_release(sc->vchi_handle);
348         }
349         VCHIQ_VCHI_UNLOCK(sc);
350 }
351
352 static void
353 bcm2835_audio_update_params(struct bcm2835_audio_info *sc, struct bcm2835_audio_chinfo *ch)
354 {
355         VC_AUDIO_MSG_T m;
356         int ret;
357
358         VCHIQ_VCHI_LOCK(sc);
359         if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
360                 vchi_service_use(sc->vchi_handle);
361
362                 m.type = VC_AUDIO_MSG_TYPE_CONFIG;
363                 m.u.config.channels = AFMT_CHANNEL(ch->fmt);
364                 m.u.config.samplerate = ch->spd;
365                 m.u.config.bps = AFMT_BIT(ch->fmt);
366
367                 ret = vchi_msg_queue(sc->vchi_handle,
368                     &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
369
370                 if (ret != 0)
371                         printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);
372
373                 vchi_service_release(sc->vchi_handle);
374         }
375         VCHIQ_VCHI_UNLOCK(sc);
376 }
377
378 static __inline uint32_t
379 vchiq_unbuffered_bytes(struct bcm2835_audio_chinfo *ch)
380 {
381         uint32_t size, ready, readyptr, readyend;
382
383         size = sndbuf_getsize(ch->buffer);
384         readyptr = sndbuf_getreadyptr(ch->buffer);
385         ready = sndbuf_getready(ch->buffer);
386
387         readyend = readyptr + ready;
388         /* Normal case */
389         if (ch->buffered_ptr >= readyptr) {
390                 if (readyend > ch->buffered_ptr)
391                         return readyend - ch->buffered_ptr;
392                 else
393                         return 0;
394         }
395         else { /* buffered_ptr overflow */
396                 if (readyend > ch->buffered_ptr + size)
397                         return readyend - ch->buffered_ptr - size;
398                 else
399                         return 0;
400         }
401 }
402
403 static void
404 bcm2835_audio_write_samples(struct bcm2835_audio_chinfo *ch)
405 {
406         struct bcm2835_audio_info *sc = ch->parent;
407         VC_AUDIO_MSG_T m;
408         void *buf;
409         uint32_t count, size;
410         int ret;
411
412         VCHIQ_VCHI_LOCK(sc);
413         if (sc->vchi_handle == VCHIQ_SERVICE_HANDLE_INVALID) {
414                 VCHIQ_VCHI_UNLOCK(sc);
415                 return;
416         }
417
418         vchi_service_use(sc->vchi_handle);
419
420         size = sndbuf_getsize(ch->buffer);
421         count = vchiq_unbuffered_bytes(ch);
422         buf = (uint8_t*)sndbuf_getbuf(ch->buffer) + ch->buffered_ptr;
423
424         if (ch->buffered_ptr + count > size)
425                 count = size - ch->buffered_ptr;
426
427         if (count < VCHIQ_AUDIO_PACKET_SIZE)
428                 goto done;
429
430         count = min(count, ch->free_buffer);
431         count -= count % VCHIQ_AUDIO_PACKET_SIZE;
432
433         m.type = VC_AUDIO_MSG_TYPE_WRITE;
434         m.u.write.count = count;
435         m.u.write.max_packet = VCHIQ_AUDIO_PACKET_SIZE;
436         m.u.write.callback = NULL;
437         m.u.write.cookie = ch;
438         if (buf)
439                 m.u.write.silence = 0;
440         else
441                 m.u.write.silence = 1;
442
443         ret = vchi_msg_queue(sc->vchi_handle,
444             &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
445
446         if (ret != 0)
447                 printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);
448
449         if (buf) {
450                 while (count > 0) {
451                         int bytes = MIN((int)m.u.write.max_packet, (int)count);
452                         ch->free_buffer -= bytes;
453                         ch->buffered_ptr += bytes;
454                         ch->buffered_ptr = ch->buffered_ptr % size;
455                         ret = vchi_msg_queue(sc->vchi_handle,
456                             buf, bytes, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
457                         if (ret != 0)
458                                 printf("%s: vchi_msg_queue failed: %d\n",
459                                     __func__, ret);
460                         buf = (char *)buf + bytes;
461                         count -= bytes;
462                 }
463         }
464 done:
465
466         vchi_service_release(sc->vchi_handle);
467         VCHIQ_VCHI_UNLOCK(sc);
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         mtx_lock(&sc->data_lock);
476         while(1) {
477
478                 if (sc->unloading)
479                         break;
480
481                 if ((ch->playback_state == PLAYBACK_PLAYING) &&
482                     (vchiq_unbuffered_bytes(ch) >= VCHIQ_AUDIO_PACKET_SIZE)
483                     && (ch->free_buffer >= VCHIQ_AUDIO_PACKET_SIZE)) {
484                         bcm2835_audio_write_samples(ch);
485                 } else {
486                         if (ch->playback_state == PLAYBACK_STOPPING) {
487                                 bcm2835_audio_reset_channel(&sc->pch);
488                                 ch->playback_state = PLAYBACK_IDLE;
489                         }
490
491                         cv_wait_sig(&sc->data_cv, &sc->data_lock);
492
493                         if (ch->playback_state == PLAYBACK_STARTING) {
494                                 /* Give it initial kick */
495                                 chn_intr(sc->pch.channel);
496                                 ch->playback_state = PLAYBACK_PLAYING;
497                         }
498                 }
499         }
500         mtx_unlock(&sc->data_lock);
501
502         kproc_exit(0);
503 }
504
505 static void
506 bcm2835_audio_create_worker(struct bcm2835_audio_info *sc)
507 {
508         struct proc *newp;
509
510         if (kproc_create(bcm2835_audio_worker, (void*)sc, &newp, 0, 0,
511             "bcm2835_audio_worker") != 0) {
512                 printf("failed to create bcm2835_audio_worker\n");
513         }
514 }
515
516 /* -------------------------------------------------------------------- */
517 /* channel interface for ESS18xx */
518 static void *
519 bcmchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
520 {
521         struct bcm2835_audio_info *sc = devinfo;
522         struct bcm2835_audio_chinfo *ch = &sc->pch;
523         void *buffer;
524
525         if (dir == PCMDIR_REC)
526                 return NULL;
527
528         ch->parent = sc;
529         ch->channel = c;
530         ch->buffer = b;
531
532         /* default values */
533         ch->spd = 44100;
534         ch->fmt = SND_FORMAT(AFMT_S16_LE, 2, 0);
535         ch->blksz = VCHIQ_AUDIO_PACKET_SIZE;
536
537         buffer = malloc(sc->bufsz, M_DEVBUF, M_WAITOK | M_ZERO);
538
539         if (sndbuf_setup(ch->buffer, buffer, sc->bufsz) != 0) {
540                 free(buffer, M_DEVBUF);
541                 return NULL;
542         }
543
544         bcm2835_audio_update_params(sc, ch);
545
546         return ch;
547 }
548
549 static int
550 bcmchan_free(kobj_t obj, void *data)
551 {
552         struct bcm2835_audio_chinfo *ch = data;
553         void *buffer;
554
555         buffer = sndbuf_getbuf(ch->buffer);
556         if (buffer)
557                 free(buffer, M_DEVBUF);
558
559         return (0);
560 }
561
562 static int
563 bcmchan_setformat(kobj_t obj, void *data, uint32_t format)
564 {
565         struct bcm2835_audio_chinfo *ch = data;
566         struct bcm2835_audio_info *sc = ch->parent;
567
568         bcm2835_audio_lock(sc);
569
570         ch->fmt = format;
571         bcm2835_audio_update_params(sc, ch);
572
573         bcm2835_audio_unlock(sc);
574
575         return 0;
576 }
577
578 static uint32_t
579 bcmchan_setspeed(kobj_t obj, void *data, uint32_t speed)
580 {
581         struct bcm2835_audio_chinfo *ch = data;
582         struct bcm2835_audio_info *sc = ch->parent;
583
584         bcm2835_audio_lock(sc);
585
586         ch->spd = speed;
587         bcm2835_audio_update_params(sc, ch);
588
589         bcm2835_audio_unlock(sc);
590
591         return ch->spd;
592 }
593
594 static uint32_t
595 bcmchan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
596 {
597         struct bcm2835_audio_chinfo *ch = data;
598
599         return ch->blksz;
600 }
601
602 static int
603 bcmchan_trigger(kobj_t obj, void *data, int go)
604 {
605         struct bcm2835_audio_chinfo *ch = data;
606         struct bcm2835_audio_info *sc = ch->parent;
607
608         if (!PCMTRIG_COMMON(go))
609                 return (0);
610
611         bcm2835_audio_lock(sc);
612
613         switch (go) {
614         case PCMTRIG_START:
615                 bcm2835_audio_start(ch);
616                 ch->playback_state = PLAYBACK_STARTING;
617                 /* wakeup worker thread */
618                 cv_signal(&sc->data_cv);
619                 break;
620
621         case PCMTRIG_STOP:
622         case PCMTRIG_ABORT:
623                 ch->playback_state = 1;
624                 bcm2835_audio_stop(ch);
625                 break;
626
627         default:
628                 break;
629         }
630
631         bcm2835_audio_unlock(sc);
632         return 0;
633 }
634
635 static uint32_t
636 bcmchan_getptr(kobj_t obj, void *data)
637 {
638         struct bcm2835_audio_chinfo *ch = data;
639         struct bcm2835_audio_info *sc = ch->parent;
640         uint32_t ret;
641
642         bcm2835_audio_lock(sc);
643
644         ret = ch->complete_pos - (ch->complete_pos % VCHIQ_AUDIO_PACKET_SIZE);
645
646         bcm2835_audio_unlock(sc);
647
648         return ret;
649 }
650
651 static struct pcmchan_caps *
652 bcmchan_getcaps(kobj_t obj, void *data)
653 {
654
655         return &bcm2835_audio_playcaps;
656 }
657
658 static kobj_method_t bcmchan_methods[] = {
659         KOBJMETHOD(channel_init,                bcmchan_init),
660         KOBJMETHOD(channel_free,                bcmchan_free),
661         KOBJMETHOD(channel_setformat,           bcmchan_setformat),
662         KOBJMETHOD(channel_setspeed,            bcmchan_setspeed),
663         KOBJMETHOD(channel_setblocksize,        bcmchan_setblocksize),
664         KOBJMETHOD(channel_trigger,             bcmchan_trigger),
665         KOBJMETHOD(channel_getptr,              bcmchan_getptr),
666         KOBJMETHOD(channel_getcaps,             bcmchan_getcaps),
667         KOBJMETHOD_END
668 };
669 CHANNEL_DECLARE(bcmchan);
670
671 /************************************************************/
672
673 static int
674 bcmmix_init(struct snd_mixer *m)
675 {
676
677         mix_setdevs(m, SOUND_MASK_VOLUME);
678
679         return (0);
680 }
681
682 static int
683 bcmmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
684 {
685         struct bcm2835_audio_info *sc = mix_getdevinfo(m);
686
687         switch (dev) {
688         case SOUND_MIXER_VOLUME:
689                 sc->volume = left;
690                 bcm2835_audio_update_controls(sc);
691                 break;
692
693         default:
694                 break;
695         }
696
697         return left | (left << 8);
698 }
699
700 static kobj_method_t bcmmixer_methods[] = {
701         KOBJMETHOD(mixer_init,          bcmmix_init),
702         KOBJMETHOD(mixer_set,           bcmmix_set),
703         KOBJMETHOD_END
704 };
705
706 MIXER_DECLARE(bcmmixer);
707
708 static int
709 sysctl_bcm2835_audio_dest(SYSCTL_HANDLER_ARGS)
710 {
711         struct bcm2835_audio_info *sc = arg1;
712         int val;
713         int err;
714
715         val = sc->dest;
716         err = sysctl_handle_int(oidp, &val, 0, req);
717         if (err || !req->newptr) /* error || read request */
718                 return (err);
719
720         if ((val < 0) || (val > 2))
721                 return (EINVAL);
722
723         sc->dest = val;
724         device_printf(sc->dev, "destination set to %s\n", dest_description(val));
725         bcm2835_audio_update_controls(sc);
726
727         return (0);
728 }
729
730 static void
731 vchi_audio_sysctl_init(struct bcm2835_audio_info *sc)
732 {
733         struct sysctl_ctx_list *ctx;
734         struct sysctl_oid *tree_node;
735         struct sysctl_oid_list *tree;
736
737         /*
738          * Add system sysctl tree/handlers.
739          */
740         ctx = device_get_sysctl_ctx(sc->dev);
741         tree_node = device_get_sysctl_tree(sc->dev);
742         tree = SYSCTL_CHILDREN(tree_node);
743         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "dest",
744             CTLFLAG_RW | CTLTYPE_UINT, sc, sizeof(*sc),
745             sysctl_bcm2835_audio_dest, "IU", "audio destination, "
746             "0 - auto, 1 - headphones, 2 - HDMI");
747 }
748
749 static void
750 bcm2835_audio_identify(driver_t *driver, device_t parent)
751 {
752
753         BUS_ADD_CHILD(parent, 0, "pcm", 0);
754 }
755
756 static int
757 bcm2835_audio_probe(device_t dev)
758 {
759
760         device_set_desc(dev, "VCHQI audio");
761         return (BUS_PROBE_DEFAULT);
762 }
763
764
765 static void
766 bcm2835_audio_delayed_init(void *xsc)
767 {
768         struct bcm2835_audio_info *sc;
769         char status[SND_STATUSLEN];
770
771         sc = xsc;
772
773         config_intrhook_disestablish(&sc->intr_hook);
774
775         bcm2835_audio_init(sc);
776         bcm2835_audio_open(sc);
777         sc->volume = 75;
778         sc->dest = DEST_AUTO;
779
780         if (mixer_init(sc->dev, &bcmmixer_class, sc)) {
781                 device_printf(sc->dev, "mixer_init failed\n");
782                 goto no;
783         }
784
785         if (pcm_register(sc->dev, sc, 1, 1)) {
786                 device_printf(sc->dev, "pcm_register failed\n");
787                 goto no;
788         }
789
790         pcm_addchan(sc->dev, PCMDIR_PLAY, &bcmchan_class, sc);
791         snprintf(status, SND_STATUSLEN, "at VCHIQ");
792         pcm_setstatus(sc->dev, status);
793
794         bcm2835_audio_reset_channel(&sc->pch);
795         bcm2835_audio_create_worker(sc);
796
797         vchi_audio_sysctl_init(sc);
798
799 no:
800         ;
801 }
802
803 static int
804 bcm2835_audio_attach(device_t dev)
805 {
806         struct bcm2835_audio_info *sc;
807
808         sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
809
810         sc->dev = dev;
811         sc->bufsz = VCHIQ_AUDIO_BUFFER_SIZE;
812
813         sc->lock = snd_mtxcreate(device_get_nameunit(dev), "bcm2835_audio softc");
814
815         mtx_init(&sc->vchi_lock, "bcm2835_audio", "vchi_lock", MTX_DEF);
816         mtx_init(&sc->data_lock, "data_mtx", "data_mtx", MTX_DEF);
817         cv_init(&sc->data_cv, "data_cv");
818         sc->vchi_handle = VCHIQ_SERVICE_HANDLE_INVALID;
819
820         /* 
821          * We need interrupts enabled for VCHI to work properly,
822          * so delay intialization until it happens
823          */
824         sc->intr_hook.ich_func = bcm2835_audio_delayed_init;
825         sc->intr_hook.ich_arg = sc;
826
827         if (config_intrhook_establish(&sc->intr_hook) != 0)
828                 goto no;
829
830         return 0;
831
832 no:
833         return ENXIO;
834 }
835
836 static int
837 bcm2835_audio_detach(device_t dev)
838 {
839         int r;
840         struct bcm2835_audio_info *sc;
841         sc = pcm_getdevinfo(dev);
842
843         /* Stop worker thread */
844         sc->unloading = 1;
845         cv_signal(&sc->data_cv);
846
847         r = pcm_unregister(dev);
848         if (r)
849                 return r;
850
851         mtx_destroy(&sc->vchi_lock);
852         mtx_destroy(&sc->data_lock);
853         cv_destroy(&sc->data_cv);
854
855         bcm2835_audio_release(sc);
856
857         if (sc->lock) {
858                 snd_mtxfree(sc->lock);
859                 sc->lock = NULL;
860         }
861
862         free(sc, M_DEVBUF);
863
864         return 0;
865 }
866
867 static device_method_t bcm2835_audio_methods[] = {
868         /* Device interface */
869         DEVMETHOD(device_identify,      bcm2835_audio_identify),
870         DEVMETHOD(device_probe,         bcm2835_audio_probe),
871         DEVMETHOD(device_attach,        bcm2835_audio_attach),
872         DEVMETHOD(device_detach,        bcm2835_audio_detach),
873
874         { 0, 0 }
875 };
876
877 static driver_t bcm2835_audio_driver = {
878         "pcm",
879         bcm2835_audio_methods,
880         PCM_SOFTC_SIZE,
881 };
882
883 DRIVER_MODULE(bcm2835_audio, vchiq, bcm2835_audio_driver, pcm_devclass, 0, 0);
884 MODULE_DEPEND(bcm2835_audio, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
885 MODULE_DEPEND(bcm2835_audio, vchiq, 1, 1, 1);
886 MODULE_VERSION(bcm2835_audio, 1);