Annotation of src/sys/dev/pad/pad.c, Revision 1.23
1.23 ! nat 1: /* $NetBSD: pad.c,v 1.22 2014/11/18 01:53:17 jmcneill Exp $ */
1.1 jmcneill 2:
3: /*-
4: * Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca>
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: *
16: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26: * POSSIBILITY OF SUCH DAMAGE.
27: */
28:
29: #include <sys/cdefs.h>
1.23 ! nat 30: __KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.22 2014/11/18 01:53:17 jmcneill Exp $");
1.1 jmcneill 31:
32: #include <sys/types.h>
33: #include <sys/param.h>
34: #include <sys/conf.h>
35: #include <sys/buf.h>
36: #include <sys/kmem.h>
37: #include <sys/kernel.h>
38: #include <sys/device.h>
39: #include <sys/proc.h>
40: #include <sys/condvar.h>
41: #include <sys/select.h>
42: #include <sys/audioio.h>
1.5 dyoung 43: #include <sys/vnode.h>
1.13 ahoka 44: #include <sys/module.h>
1.17 jmcneill 45: #include <sys/atomic.h>
1.1 jmcneill 46:
47: #include <dev/audio_if.h>
48: #include <dev/audiovar.h>
49: #include <dev/auconv.h>
1.22 jmcneill 50: #include <dev/auvolconv.h>
1.1 jmcneill 51:
1.2 jmcneill 52: #include <dev/pad/padvar.h>
53:
1.1 jmcneill 54: #define PADUNIT(x) minor(x)
55:
56: extern struct cfdriver pad_cd;
57:
58: typedef struct pad_block {
59: uint8_t *pb_ptr;
60: int pb_len;
61: } pad_block_t;
62:
1.2 jmcneill 63: enum {
64: PAD_OUTPUT_CLASS,
65: PAD_INPUT_CLASS,
66: PAD_OUTPUT_MASTER_VOLUME,
67: PAD_INPUT_DAC_VOLUME,
68: PAD_ENUM_LAST,
69: };
1.1 jmcneill 70:
1.10 christos 71: static int pad_match(device_t, cfdata_t, void *);
1.5 dyoung 72: static void pad_attach(device_t, device_t, void *);
73: static int pad_detach(device_t, int);
74: static void pad_childdet(device_t, device_t);
1.1 jmcneill 75:
76: static int pad_query_encoding(void *, struct audio_encoding *);
77: static int pad_set_params(void *, int, int,
78: audio_params_t *, audio_params_t *,
79: stream_filter_list_t *, stream_filter_list_t *);
80: static int pad_start_output(void *, void *, int,
81: void (*)(void *), void *);
82: static int pad_start_input(void *, void *, int,
83: void (*)(void *), void *);
84: static int pad_halt_output(void *);
85: static int pad_halt_input(void *);
86: static int pad_getdev(void *, struct audio_device *);
87: static int pad_set_port(void *, mixer_ctrl_t *);
88: static int pad_get_port(void *, mixer_ctrl_t *);
89: static int pad_query_devinfo(void *, mixer_devinfo_t *);
90: static int pad_get_props(void *);
91: static int pad_round_blocksize(void *, int, int, const audio_params_t *);
1.17 jmcneill 92: static void pad_get_locks(void *, kmutex_t **, kmutex_t **);
1.1 jmcneill 93:
1.22 jmcneill 94: static stream_filter_t *pad_swvol_filter_le(struct audio_softc *,
95: const audio_params_t *, const audio_params_t *);
96: static stream_filter_t *pad_swvol_filter_be(struct audio_softc *,
97: const audio_params_t *, const audio_params_t *);
98: static void pad_swvol_dtor(stream_filter_t *);
99:
1.1 jmcneill 100: static const struct audio_hw_if pad_hw_if = {
101: .query_encoding = pad_query_encoding,
102: .set_params = pad_set_params,
103: .start_output = pad_start_output,
104: .start_input = pad_start_input,
105: .halt_output = pad_halt_output,
106: .halt_input = pad_halt_input,
107: .getdev = pad_getdev,
108: .set_port = pad_set_port,
109: .get_port = pad_get_port,
110: .query_devinfo = pad_query_devinfo,
111: .get_props = pad_get_props,
112: .round_blocksize = pad_round_blocksize,
1.17 jmcneill 113: .get_locks = pad_get_locks,
1.1 jmcneill 114: };
115:
116: #define PAD_NFORMATS 1
117: static const struct audio_format pad_formats[PAD_NFORMATS] = {
118: { NULL, AUMODE_PLAY|AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_LE, 16, 16,
119: 2, AUFMT_STEREO, 1, { 44100 } },
120: };
121:
122: extern void padattach(int);
123:
124: static int pad_add_block(pad_softc_t *, uint8_t *, int);
125: static int pad_get_block(pad_softc_t *, pad_block_t *, int);
126:
127: dev_type_open(pad_open);
128: dev_type_close(pad_close);
129: dev_type_read(pad_read);
130:
131: const struct cdevsw pad_cdevsw = {
132: .d_open = pad_open,
133: .d_close = pad_close,
134: .d_read = pad_read,
135: .d_write = nowrite,
136: .d_ioctl = noioctl,
137: .d_stop = nostop,
138: .d_tty = notty,
139: .d_poll = nopoll,
140: .d_mmap = nommap,
141: .d_kqfilter = nokqfilter,
1.21 dholland 142: .d_discard = nodiscard,
1.17 jmcneill 143: .d_flag = D_OTHER | D_MPSAFE,
1.1 jmcneill 144: };
145:
1.10 christos 146: CFATTACH_DECL2_NEW(pad, sizeof(pad_softc_t), pad_match, pad_attach, pad_detach,
1.5 dyoung 147: NULL, NULL, pad_childdet);
1.1 jmcneill 148:
149: void
150: padattach(int n)
151: {
152: int i, err;
1.10 christos 153: cfdata_t cf;
1.1 jmcneill 154:
1.11 ad 155: aprint_debug("pad: requested %d units\n", n);
1.1 jmcneill 156:
157: err = config_cfattach_attach(pad_cd.cd_name, &pad_ca);
158: if (err) {
159: aprint_error("%s: couldn't register cfattach: %d\n",
160: pad_cd.cd_name, err);
161: config_cfdriver_detach(&pad_cd);
162: return;
163: }
164:
165: for (i = 0; i < n; i++) {
1.17 jmcneill 166: cf = kmem_alloc(sizeof(struct cfdata), KM_SLEEP);
1.1 jmcneill 167: if (cf == NULL) {
168: aprint_error("%s: couldn't allocate cfdata\n",
169: pad_cd.cd_name);
170: continue;
171: }
172: cf->cf_name = pad_cd.cd_name;
173: cf->cf_atname = pad_cd.cd_name;
174: cf->cf_unit = i;
175: cf->cf_fstate = FSTATE_STAR;
176:
177: (void)config_attach_pseudo(cf);
178: }
179:
180: return;
181: }
182:
183: static int
184: pad_add_block(pad_softc_t *sc, uint8_t *blk, int blksize)
185: {
186: int l;
187:
1.16 jmcneill 188: if (sc->sc_open == 0)
189: return EIO;
190:
1.17 jmcneill 191: KASSERT(mutex_owned(&sc->sc_lock));
192:
1.1 jmcneill 193: if (sc->sc_buflen + blksize > PAD_BUFSIZE)
194: return ENOBUFS;
195:
196: if (sc->sc_wpos + blksize <= PAD_BUFSIZE)
197: memcpy(sc->sc_audiobuf + sc->sc_wpos, blk, blksize);
198: else {
199: l = PAD_BUFSIZE - sc->sc_wpos;
200: memcpy(sc->sc_audiobuf + sc->sc_wpos, blk, l);
201: memcpy(sc->sc_audiobuf, blk + l, blksize - l);
202: }
203:
204: sc->sc_wpos += blksize;
205: if (sc->sc_wpos > PAD_BUFSIZE)
206: sc->sc_wpos -= PAD_BUFSIZE;
207:
208: sc->sc_buflen += blksize;
209:
210: return 0;
211: }
212:
213: static int
214: pad_get_block(pad_softc_t *sc, pad_block_t *pb, int blksize)
215: {
216: int l;
217:
1.17 jmcneill 218: KASSERT(mutex_owned(&sc->sc_lock));
1.1 jmcneill 219: KASSERT(pb != NULL);
220:
221: if (sc->sc_buflen < blksize)
222: return ERESTART;
223:
224: pb->pb_ptr = (sc->sc_audiobuf + sc->sc_rpos);
225: if (sc->sc_rpos + blksize < PAD_BUFSIZE) {
226: pb->pb_len = blksize;
227: sc->sc_rpos += blksize;
228: } else {
229: l = PAD_BUFSIZE - sc->sc_rpos;
230: pb->pb_len = l;
231: sc->sc_rpos = 0;
232: }
233: sc->sc_buflen -= pb->pb_len;
234:
235: return 0;
236: }
237:
238: static int
1.10 christos 239: pad_match(device_t parent, cfdata_t data, void *opaque)
1.1 jmcneill 240: {
1.17 jmcneill 241:
1.1 jmcneill 242: return 1;
243: }
244:
245: static void
1.5 dyoung 246: pad_childdet(device_t self, device_t child)
1.1 jmcneill 247: {
1.5 dyoung 248: pad_softc_t *sc = device_private(self);
249:
250: sc->sc_audiodev = NULL;
251: }
1.1 jmcneill 252:
1.5 dyoung 253: static void
254: pad_attach(device_t parent, device_t self, void *opaque)
255: {
256: pad_softc_t *sc = device_private(self);
1.1 jmcneill 257:
258: aprint_normal_dev(self, "outputs: 44100Hz, 16-bit, stereo\n");
259:
1.10 christos 260: sc->sc_dev = self;
1.1 jmcneill 261: sc->sc_open = 0;
262: if (auconv_create_encodings(pad_formats, PAD_NFORMATS,
263: &sc->sc_encodings) != 0) {
264: aprint_error_dev(self, "couldn't create encodings\n");
265: return;
266: }
267:
268: cv_init(&sc->sc_condvar, device_xname(self));
1.17 jmcneill 269: mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
270: mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_NONE);
1.1 jmcneill 271:
1.2 jmcneill 272: sc->sc_swvol = 255;
1.1 jmcneill 273: sc->sc_buflen = 0;
274: sc->sc_rpos = sc->sc_wpos = 0;
1.10 christos 275: sc->sc_audiodev = (void *)audio_attach_mi(&pad_hw_if, sc, sc->sc_dev);
1.1 jmcneill 276:
1.4 jmcneill 277: if (!pmf_device_register(self, NULL, NULL))
278: aprint_error_dev(self, "couldn't establish power handler\n");
279:
1.1 jmcneill 280: return;
281: }
282:
1.5 dyoung 283: static int
284: pad_detach(device_t self, int flags)
285: {
286: pad_softc_t *sc = device_private(self);
287: int cmaj, mn, rc;
288:
289: cmaj = cdevsw_lookup_major(&pad_cdevsw);
290: mn = device_unit(self);
291: vdevgone(cmaj, mn, mn, VCHR);
292:
293: if ((rc = config_detach_children(self, flags)) != 0)
294: return rc;
295:
296: pmf_device_deregister(self);
297:
1.17 jmcneill 298: mutex_destroy(&sc->sc_lock);
299: mutex_destroy(&sc->sc_intr_lock);
1.5 dyoung 300: cv_destroy(&sc->sc_condvar);
301:
302: auconv_delete_encodings(sc->sc_encodings);
303:
304: return 0;
305: }
306:
1.1 jmcneill 307: int
308: pad_open(dev_t dev, int flags, int fmt, struct lwp *l)
309: {
310: pad_softc_t *sc;
311:
1.8 tsutsui 312: sc = device_lookup_private(&pad_cd, PADUNIT(dev));
1.1 jmcneill 313: if (sc == NULL)
1.12 dyoung 314: return ENXIO;
1.1 jmcneill 315:
1.17 jmcneill 316: if (atomic_swap_uint(&sc->sc_open, 1) != 0) {
1.1 jmcneill 317: return EBUSY;
318: }
319:
320: return 0;
321: }
322:
323: int
324: pad_close(dev_t dev, int flags, int fmt, struct lwp *l)
325: {
326: pad_softc_t *sc;
327:
1.8 tsutsui 328: sc = device_lookup_private(&pad_cd, PADUNIT(dev));
1.1 jmcneill 329: if (sc == NULL)
1.12 dyoung 330: return ENXIO;
1.1 jmcneill 331:
332: KASSERT(sc->sc_open > 0);
1.17 jmcneill 333: sc->sc_open = 0;
1.1 jmcneill 334:
335: return 0;
336: }
337:
338: int
339: pad_read(dev_t dev, struct uio *uio, int flags)
340: {
341: pad_softc_t *sc;
342: pad_block_t pb;
343: void (*intr)(void *);
344: void *intrarg;
345: int err;
346:
1.8 tsutsui 347: sc = device_lookup_private(&pad_cd, PADUNIT(dev));
1.1 jmcneill 348: if (sc == NULL)
1.12 dyoung 349: return ENXIO;
1.1 jmcneill 350:
351: err = 0;
352:
1.17 jmcneill 353: mutex_enter(&sc->sc_lock);
1.1 jmcneill 354: intr = sc->sc_intr;
355: intrarg = sc->sc_intrarg;
356:
1.23 ! nat 357: kpreempt_disable();
1.1 jmcneill 358: while (uio->uio_resid > 0 && !err) {
359: err = pad_get_block(sc, &pb, min(uio->uio_resid, PAD_BLKSIZE));
1.17 jmcneill 360: if (!err) {
361: mutex_exit(&sc->sc_lock);
1.1 jmcneill 362: err = uiomove(pb.pb_ptr, pb.pb_len, uio);
1.17 jmcneill 363: mutex_enter(&sc->sc_lock);
364: continue;
365: }
1.1 jmcneill 366:
1.17 jmcneill 367: if (intr) {
368: mutex_enter(&sc->sc_intr_lock);
369: (*intr)(intrarg);
370: mutex_exit(&sc->sc_intr_lock);
1.1 jmcneill 371: intr = sc->sc_intr;
372: intrarg = sc->sc_intrarg;
373: err = 0;
1.17 jmcneill 374: continue;
375: }
376: err = cv_wait_sig(&sc->sc_condvar, &sc->sc_lock);
377: if (err != 0) {
378: mutex_exit(&sc->sc_lock);
1.23 ! nat 379: kpreempt_enable();
1.17 jmcneill 380: return err;
1.1 jmcneill 381: }
1.17 jmcneill 382: intr = sc->sc_intr;
383: intrarg = sc->sc_intrarg;
1.1 jmcneill 384: }
385:
1.17 jmcneill 386: if (intr) {
387: mutex_enter(&sc->sc_intr_lock);
1.1 jmcneill 388: (*intr)(intrarg);
1.17 jmcneill 389: mutex_exit(&sc->sc_intr_lock);
390: }
391: mutex_exit(&sc->sc_lock);
1.23 ! nat 392: kpreempt_enable();
1.1 jmcneill 393:
394: return err;
395: }
396:
397: static int
398: pad_query_encoding(void *opaque, struct audio_encoding *ae)
399: {
400: pad_softc_t *sc;
401:
402: sc = (pad_softc_t *)opaque;
403:
1.17 jmcneill 404: KASSERT(mutex_owned(&sc->sc_lock));
405:
1.1 jmcneill 406: return auconv_query_encoding(sc->sc_encodings, ae);
407: }
408:
409: static int
410: pad_set_params(void *opaque, int setmode, int usemode,
411: audio_params_t *play, audio_params_t *rec,
412: stream_filter_list_t *pfil, stream_filter_list_t *rfil)
413: {
1.20 christos 414: pad_softc_t *sc __diagused;
1.1 jmcneill 415:
416: sc = (pad_softc_t *)opaque;
417:
1.17 jmcneill 418: KASSERT(mutex_owned(&sc->sc_lock));
419:
1.1 jmcneill 420: if (auconv_set_converter(pad_formats, PAD_NFORMATS, AUMODE_PLAY,
421: play, true, pfil) < 0)
422: return EINVAL;
423: if (auconv_set_converter(pad_formats, PAD_NFORMATS, AUMODE_RECORD,
424: rec, true, rfil) < 0)
425: return EINVAL;
426:
1.2 jmcneill 427: if (pfil->req_size > 0)
428: play = &pfil->filters[0].param;
429: switch (play->encoding) {
430: case AUDIO_ENCODING_SLINEAR_LE:
431: if (play->precision == 16 && play->validbits == 16)
1.22 jmcneill 432: pfil->prepend(pfil, pad_swvol_filter_le, play);
1.2 jmcneill 433: break;
434: case AUDIO_ENCODING_SLINEAR_BE:
435: if (play->precision == 16 && play->validbits == 16)
1.22 jmcneill 436: pfil->prepend(pfil, pad_swvol_filter_be, play);
1.2 jmcneill 437: break;
438: default:
439: break;
440: }
441:
1.1 jmcneill 442: return 0;
443: }
444:
445: static int
446: pad_start_output(void *opaque, void *block, int blksize,
447: void (*intr)(void *), void *intrarg)
448: {
449: pad_softc_t *sc;
450: int err;
451:
452: sc = (pad_softc_t *)opaque;
453:
1.17 jmcneill 454: KASSERT(mutex_owned(&sc->sc_lock));
1.1 jmcneill 455:
456: sc->sc_intr = intr;
457: sc->sc_intrarg = intrarg;
458: sc->sc_blksize = blksize;
459:
460: err = pad_add_block(sc, block, blksize);
461:
1.17 jmcneill 462: cv_broadcast(&sc->sc_condvar);
1.1 jmcneill 463:
464: return err;
465: }
466:
467: static int
468: pad_start_input(void *opaque, void *block, int blksize,
469: void (*intr)(void *), void *intrarg)
470: {
1.20 christos 471: pad_softc_t *sc __diagused;
1.17 jmcneill 472:
473: sc = (pad_softc_t *)opaque;
474:
475: KASSERT(mutex_owned(&sc->sc_lock));
476:
477: return EOPNOTSUPP;
1.1 jmcneill 478: }
479:
480: static int
481: pad_halt_output(void *opaque)
482: {
483: pad_softc_t *sc;
484:
485: sc = (pad_softc_t *)opaque;
1.17 jmcneill 486:
487: KASSERT(mutex_owned(&sc->sc_lock));
488:
1.1 jmcneill 489: sc->sc_intr = NULL;
490: sc->sc_intrarg = NULL;
491: sc->sc_buflen = 0;
492: sc->sc_rpos = sc->sc_wpos = 0;
493:
494: return 0;
495: }
496:
497: static int
498: pad_halt_input(void *opaque)
499: {
1.20 christos 500: pad_softc_t *sc __diagused;
1.17 jmcneill 501:
502: sc = (pad_softc_t *)opaque;
503:
504: KASSERT(mutex_owned(&sc->sc_lock));
505:
1.1 jmcneill 506: return 0;
507: }
508:
509: static int
510: pad_getdev(void *opaque, struct audio_device *ret)
511: {
1.16 jmcneill 512: strlcpy(ret->name, "Virtual Audio", sizeof(ret->name));
513: strlcpy(ret->version, osrelease, sizeof(ret->version));
514: strlcpy(ret->config, "pad", sizeof(ret->config));
1.1 jmcneill 515:
516: return 0;
517: }
518:
519: static int
520: pad_set_port(void *opaque, mixer_ctrl_t *mc)
521: {
1.2 jmcneill 522: pad_softc_t *sc;
523:
524: sc = (pad_softc_t *)opaque;
525:
1.17 jmcneill 526: KASSERT(mutex_owned(&sc->sc_lock));
527:
1.2 jmcneill 528: switch (mc->dev) {
529: case PAD_OUTPUT_MASTER_VOLUME:
530: case PAD_INPUT_DAC_VOLUME:
531: sc->sc_swvol = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO];
532: return 0;
533: }
534:
1.1 jmcneill 535: return ENXIO;
536: }
537:
538: static int
539: pad_get_port(void *opaque, mixer_ctrl_t *mc)
540: {
1.2 jmcneill 541: pad_softc_t *sc;
542:
543: sc = (pad_softc_t *)opaque;
544:
1.17 jmcneill 545: KASSERT(mutex_owned(&sc->sc_lock));
546:
1.2 jmcneill 547: switch (mc->dev) {
548: case PAD_OUTPUT_MASTER_VOLUME:
549: case PAD_INPUT_DAC_VOLUME:
550: mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_swvol;
551: return 0;
552: }
553:
1.1 jmcneill 554: return ENXIO;
555: }
556:
557: static int
558: pad_query_devinfo(void *opaque, mixer_devinfo_t *di)
559: {
1.20 christos 560: pad_softc_t *sc __diagused;
1.2 jmcneill 561:
562: sc = (pad_softc_t *)opaque;
563:
1.17 jmcneill 564: KASSERT(mutex_owned(&sc->sc_lock));
565:
1.2 jmcneill 566: switch (di->index) {
567: case PAD_OUTPUT_CLASS:
568: di->mixer_class = PAD_OUTPUT_CLASS;
569: strcpy(di->label.name, AudioCoutputs);
570: di->type = AUDIO_MIXER_CLASS;
571: di->next = di->prev = AUDIO_MIXER_LAST;
572: return 0;
573: case PAD_INPUT_CLASS:
574: di->mixer_class = PAD_INPUT_CLASS;
575: strcpy(di->label.name, AudioCinputs);
576: di->type = AUDIO_MIXER_CLASS;
577: di->next = di->prev = AUDIO_MIXER_LAST;
578: return 0;
579: case PAD_OUTPUT_MASTER_VOLUME:
580: di->mixer_class = PAD_OUTPUT_CLASS;
581: strcpy(di->label.name, AudioNmaster);
582: di->type = AUDIO_MIXER_VALUE;
583: di->next = di->prev = AUDIO_MIXER_LAST;
584: di->un.v.num_channels = 1;
585: strcpy(di->un.v.units.name, AudioNvolume);
586: return 0;
587: case PAD_INPUT_DAC_VOLUME:
588: di->mixer_class = PAD_INPUT_CLASS;
589: strcpy(di->label.name, AudioNdac);
590: di->type = AUDIO_MIXER_VALUE;
591: di->next = di->prev = AUDIO_MIXER_LAST;
592: di->un.v.num_channels = 1;
593: strcpy(di->un.v.units.name, AudioNvolume);
594: return 0;
595: }
596:
1.1 jmcneill 597: return ENXIO;
598: }
599:
600: static int
601: pad_get_props(void *opaque)
602: {
1.20 christos 603: pad_softc_t *sc __diagused;
1.17 jmcneill 604:
605: sc = (pad_softc_t *)opaque;
606:
607: KASSERT(mutex_owned(&sc->sc_lock));
608:
1.1 jmcneill 609: return 0;
610: }
611:
612: static int
613: pad_round_blocksize(void *opaque, int blksize, int mode,
614: const audio_params_t *p)
615: {
1.20 christos 616: pad_softc_t *sc __diagused;
1.17 jmcneill 617:
618: sc = (pad_softc_t *)opaque;
619: KASSERT(mutex_owned(&sc->sc_lock));
620:
1.1 jmcneill 621: return PAD_BLKSIZE;
622: }
1.13 ahoka 623:
1.17 jmcneill 624: static void
625: pad_get_locks(void *opaque, kmutex_t **intr, kmutex_t **thread)
626: {
627: pad_softc_t *sc;
628:
629: sc = (pad_softc_t *)opaque;
630:
631: *intr = &sc->sc_intr_lock;
632: *thread = &sc->sc_lock;
633: }
634:
1.22 jmcneill 635: static stream_filter_t *
636: pad_swvol_filter_le(struct audio_softc *asc,
637: const audio_params_t *from, const audio_params_t *to)
638: {
639: auvolconv_filter_t *this;
640: device_t dev = audio_get_device(asc);
641: struct pad_softc *sc = device_private(dev);
642:
643: this = kmem_alloc(sizeof(auvolconv_filter_t), KM_SLEEP);
644: this->base.base.fetch_to = auvolconv_slinear16_le_fetch_to;
645: this->base.dtor = pad_swvol_dtor;
646: this->base.set_fetcher = stream_filter_set_fetcher;
647: this->base.set_inputbuffer = stream_filter_set_inputbuffer;
648: this->vol = &sc->sc_swvol;
649:
650: return (stream_filter_t *)this;
651: }
652:
653: static stream_filter_t *
654: pad_swvol_filter_be(struct audio_softc *asc,
655: const audio_params_t *from, const audio_params_t *to)
656: {
657: auvolconv_filter_t *this;
658: device_t dev = audio_get_device(asc);
659: struct pad_softc *sc = device_private(dev);
660:
661: this = kmem_alloc(sizeof(auvolconv_filter_t), KM_SLEEP);
662: this->base.base.fetch_to = auvolconv_slinear16_be_fetch_to;
663: this->base.dtor = pad_swvol_dtor;
664: this->base.set_fetcher = stream_filter_set_fetcher;
665: this->base.set_inputbuffer = stream_filter_set_inputbuffer;
666: this->vol = &sc->sc_swvol;
667:
668: return (stream_filter_t *)this;
669: }
670:
671: static void
672: pad_swvol_dtor(stream_filter_t *this)
673: {
674: if (this)
675: kmem_free(this, sizeof(auvolconv_filter_t));
676: }
677:
1.13 ahoka 678: #ifdef _MODULE
679:
680: MODULE(MODULE_CLASS_DRIVER, pad, NULL);
681:
682: static const struct cfiattrdata audiobuscf_iattrdata = {
683: "audiobus", 0, { { NULL, NULL, 0 }, }
684: };
685: static const struct cfiattrdata * const pad_attrs[] = {
686: &audiobuscf_iattrdata, NULL
687: };
688:
689: CFDRIVER_DECL(pad, DV_DULL, pad_attrs);
690: extern struct cfattach pad_ca;
691: static int padloc[] = { -1, -1 };
692:
693: static struct cfdata pad_cfdata[] = {
694: {
695: .cf_name = "pad",
696: .cf_atname = "pad",
697: .cf_unit = 0,
698: .cf_fstate = FSTATE_STAR,
699: .cf_loc = padloc,
700: .cf_flags = 0,
701: .cf_pspec = NULL,
702: },
1.14 pooka 703: { NULL, NULL, 0, 0, NULL, 0, NULL }
1.13 ahoka 704: };
705:
706: static int
707: pad_modcmd(modcmd_t cmd, void *arg)
708: {
709: devmajor_t cmajor = NODEVMAJOR, bmajor = NODEVMAJOR;
1.19 agc 710: int error;
1.13 ahoka 711:
712: switch (cmd) {
713: case MODULE_CMD_INIT:
714: error = config_cfdriver_attach(&pad_cd);
715: if (error) {
716: return error;
717: }
718:
719: error = config_cfattach_attach(pad_cd.cd_name, &pad_ca);
720: if (error) {
721: config_cfdriver_detach(&pad_cd);
722: aprint_error("%s: unable to register cfattach\n",
723: pad_cd.cd_name);
724:
725: return error;
726: }
727:
728: error = config_cfdata_attach(pad_cfdata, 1);
729: if (error) {
730: config_cfattach_detach(pad_cd.cd_name, &pad_ca);
731: config_cfdriver_detach(&pad_cd);
732: aprint_error("%s: unable to register cfdata\n",
733: pad_cd.cd_name);
734:
735: return error;
736: }
737:
738: error = devsw_attach(pad_cd.cd_name, NULL, &bmajor, &pad_cdevsw, &cmajor);
739: if (error) {
740: error = config_cfdata_detach(pad_cfdata);
741: if (error) {
742: return error;
743: }
744: config_cfattach_detach(pad_cd.cd_name, &pad_ca);
745: config_cfdriver_detach(&pad_cd);
746: aprint_error("%s: unable to register devsw\n",
747: pad_cd.cd_name);
748:
749: return error;
750: }
751:
752: (void)config_attach_pseudo(pad_cfdata);
753:
754: return 0;
755: case MODULE_CMD_FINI:
756: error = config_cfdata_detach(pad_cfdata);
757: if (error) {
758: return error;
759: }
760:
761: config_cfattach_detach(pad_cd.cd_name, &pad_ca);
762: config_cfdriver_detach(&pad_cd);
763: devsw_detach(NULL, &pad_cdevsw);
764:
765: return 0;
766: default:
767: return ENOTTY;
768: }
769: }
770:
771: #endif
CVSweb <webmaster@jp.NetBSD.org>