Annotation of src/sys/dev/pad/pad.c, Revision 1.72
1.72 ! riastrad 1: /* $NetBSD: pad.c,v 1.71 2021/06/14 10:14:58 riastradh 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.72 ! riastrad 30: __KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.71 2021/06/14 10:14:58 riastradh Exp $");
1.1 jmcneill 31:
1.70 riastrad 32: #include <sys/param.h>
1.1 jmcneill 33: #include <sys/types.h>
1.70 riastrad 34:
35: #include <sys/audioio.h>
36: #include <sys/buf.h>
37: #include <sys/condvar.h>
1.1 jmcneill 38: #include <sys/conf.h>
1.70 riastrad 39: #include <sys/device.h>
1.57 nakayama 40: #include <sys/file.h>
41: #include <sys/filedesc.h>
42: #include <sys/kauth.h>
1.70 riastrad 43: #include <sys/kernel.h>
1.1 jmcneill 44: #include <sys/kmem.h>
1.70 riastrad 45: #include <sys/module.h>
1.63 isaki 46: #include <sys/poll.h>
1.1 jmcneill 47: #include <sys/proc.h>
48: #include <sys/select.h>
1.57 nakayama 49: #include <sys/stat.h>
1.70 riastrad 50: #include <sys/vnode.h>
1.1 jmcneill 51:
1.59 isaki 52: #include <dev/audio/audio_if.h>
53: #include <dev/audio/audiovar.h>
1.1 jmcneill 54:
1.2 jmcneill 55: #include <dev/pad/padvar.h>
56:
1.71 riastrad 57: #include "ioconf.h"
58:
1.59 isaki 59: /* #define PAD_DEBUG */
60: #ifdef PAD_DEBUG
61: #define DPRINTF(fmt...) printf(fmt)
62: #else
63: #define DPRINTF(fmt...) /**/
64: #endif
65:
1.57 nakayama 66: #define PADFREQ 44100
67: #define PADCHAN 2
68: #define PADPREC 16
69:
1.1 jmcneill 70: typedef struct pad_block {
71: uint8_t *pb_ptr;
72: int pb_len;
73: } pad_block_t;
74:
1.2 jmcneill 75: enum {
76: PAD_OUTPUT_CLASS,
77: PAD_INPUT_CLASS,
78: PAD_OUTPUT_MASTER_VOLUME,
79: PAD_INPUT_DAC_VOLUME,
80: PAD_ENUM_LAST,
81: };
1.1 jmcneill 82:
1.10 christos 83: static int pad_match(device_t, cfdata_t, void *);
1.5 dyoung 84: static void pad_attach(device_t, device_t, void *);
85: static int pad_detach(device_t, int);
86: static void pad_childdet(device_t, device_t);
1.1 jmcneill 87:
1.59 isaki 88: static int pad_query_format(void *, audio_format_query_t *);
89: static int pad_set_format(void *, int,
90: const audio_params_t *, const audio_params_t *,
91: audio_filter_reg_t *, audio_filter_reg_t *);
1.1 jmcneill 92: static int pad_start_output(void *, void *, int,
1.62 isaki 93: void (*)(void *), void *);
1.1 jmcneill 94: static int pad_halt_output(void *);
95: static int pad_getdev(void *, struct audio_device *);
96: static int pad_set_port(void *, mixer_ctrl_t *);
97: static int pad_get_port(void *, mixer_ctrl_t *);
98: static int pad_query_devinfo(void *, mixer_devinfo_t *);
99: static int pad_get_props(void *);
1.17 jmcneill 100: static void pad_get_locks(void *, kmutex_t **, kmutex_t **);
1.1 jmcneill 101:
1.59 isaki 102: static void pad_done_output(void *);
103: static void pad_swvol_codec(audio_filter_arg_t *);
1.22 jmcneill 104:
1.71 riastrad 105: static void pad_close(struct pad_softc *);
1.62 isaki 106: static int pad_read(struct pad_softc *, off_t *, struct uio *,
107: kauth_cred_t, int);
108:
109: static int fops_pad_close(struct file *);
110: static int fops_pad_read(struct file *, off_t *, struct uio *,
111: kauth_cred_t, int);
112: static int fops_pad_write(struct file *, off_t *, struct uio *,
113: kauth_cred_t, int);
114: static int fops_pad_ioctl(struct file *, u_long, void *);
115: static int fops_pad_kqfilter(struct file *, struct knote *);
116: static int fops_pad_poll(struct file *, int);
117: static int fops_pad_stat(struct file *, struct stat *);
118: static int fops_pad_mmap(struct file *, off_t *, size_t, int, int *, int *,
119: struct uvm_object **, int *);
1.32 pgoyette 120:
1.1 jmcneill 121: static const struct audio_hw_if pad_hw_if = {
1.62 isaki 122: .query_format = pad_query_format,
123: .set_format = pad_set_format,
124: .start_output = pad_start_output,
125: .halt_output = pad_halt_output,
126: .getdev = pad_getdev,
127: .set_port = pad_set_port,
128: .get_port = pad_get_port,
129: .query_devinfo = pad_query_devinfo,
130: .get_props = pad_get_props,
131: .get_locks = pad_get_locks,
1.1 jmcneill 132: };
133:
134: #define PAD_NFORMATS 1
135: static const struct audio_format pad_formats[PAD_NFORMATS] = {
1.59 isaki 136: {
137: .mode = AUMODE_PLAY,
1.60 isaki 138: .encoding = AUDIO_ENCODING_SLINEAR_LE,
1.59 isaki 139: .validbits = PADPREC,
140: .precision = PADPREC,
141: .channels = PADCHAN,
142: .channel_mask = AUFMT_STEREO,
143: .frequency_type = 1,
144: .frequency = { PADFREQ },
145: },
1.1 jmcneill 146: };
147:
148: extern void padattach(int);
149:
1.62 isaki 150: static int pad_add_block(struct pad_softc *, uint8_t *, int);
151: static int pad_get_block(struct pad_softc *, pad_block_t *, int);
1.1 jmcneill 152:
1.71 riastrad 153: static dev_type_open(pad_open);
1.1 jmcneill 154:
155: const struct cdevsw pad_cdevsw = {
1.71 riastrad 156: .d_open = pad_open,
157: .d_close = noclose,
158: .d_read = noread,
1.62 isaki 159: .d_write = nowrite,
160: .d_ioctl = noioctl,
161: .d_stop = nostop,
162: .d_tty = notty,
163: .d_poll = nopoll,
164: .d_mmap = nommap,
165: .d_kqfilter = nokqfilter,
166: .d_discard = nodiscard,
167: .d_flag = D_OTHER | D_MPSAFE,
1.1 jmcneill 168: };
169:
1.57 nakayama 170: const struct fileops pad_fileops = {
1.62 isaki 171: .fo_name = "pad",
172: .fo_read = fops_pad_read,
173: .fo_write = fops_pad_write,
174: .fo_ioctl = fops_pad_ioctl,
175: .fo_fcntl = fnullop_fcntl,
176: .fo_stat = fops_pad_stat,
177: .fo_poll = fops_pad_poll,
178: .fo_close = fops_pad_close,
179: .fo_mmap = fops_pad_mmap,
180: .fo_kqfilter = fops_pad_kqfilter,
181: .fo_restart = fnullop_restart
1.57 nakayama 182: };
183:
1.62 isaki 184: CFATTACH_DECL2_NEW(pad, sizeof(struct pad_softc),
185: pad_match, pad_attach, pad_detach,
1.5 dyoung 186: NULL, NULL, pad_childdet);
1.1 jmcneill 187:
188: void
189: padattach(int n)
190: {
1.57 nakayama 191: int error;
1.1 jmcneill 192:
1.57 nakayama 193: error = config_cfattach_attach(pad_cd.cd_name, &pad_ca);
194: if (error) {
1.1 jmcneill 195: aprint_error("%s: couldn't register cfattach: %d\n",
1.57 nakayama 196: pad_cd.cd_name, error);
1.1 jmcneill 197: config_cfdriver_detach(&pad_cd);
198: return;
199: }
200: }
201:
202: static int
1.62 isaki 203: pad_match(device_t parent, cfdata_t data, void *opaque)
204: {
205:
206: return 1;
207: }
208:
209: static void
210: pad_attach(device_t parent, device_t self, void *opaque)
211: {
1.68 riastrad 212: struct pad_softc *sc = device_private(self);
1.62 isaki 213:
1.71 riastrad 214: KASSERT(KERNEL_LOCKED_P());
215:
1.62 isaki 216: aprint_normal_dev(self, "outputs: 44100Hz, 16-bit, stereo\n");
1.68 riastrad 217:
218: sc->sc_dev = self;
219:
220: cv_init(&sc->sc_condvar, device_xname(sc->sc_dev));
221: mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
1.69 riastrad 222: mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SOFTCLOCK);
223: callout_init(&sc->sc_pcallout, CALLOUT_MPSAFE);
224: callout_setfunc(&sc->sc_pcallout, pad_done_output, sc);
1.68 riastrad 225:
226: sc->sc_swvol = 255;
227: sc->sc_buflen = 0;
228: sc->sc_rpos = sc->sc_wpos = 0;
229: sc->sc_audiodev = audio_attach_mi(&pad_hw_if, sc, sc->sc_dev);
230:
231: if (!pmf_device_register(sc->sc_dev, NULL, NULL))
232: aprint_error_dev(sc->sc_dev,
233: "couldn't establish power handler\n");
1.71 riastrad 234:
235: sc->sc_open = 1;
1.62 isaki 236: }
237:
238: static int
239: pad_detach(device_t self, int flags)
240: {
1.68 riastrad 241: struct pad_softc *sc = device_private(self);
1.62 isaki 242: int cmaj, mn;
1.68 riastrad 243: int error;
244:
1.71 riastrad 245: KASSERT(KERNEL_LOCKED_P());
246:
247: /* Prevent detach without going through close -- e.g., drvctl. */
248: if (sc->sc_open)
249: return EBUSY;
250:
1.68 riastrad 251: error = config_detach_children(self, flags);
252: if (error)
253: return error;
1.62 isaki 254:
255: cmaj = cdevsw_lookup_major(&pad_cdevsw);
256: mn = device_unit(sc->sc_dev);
1.68 riastrad 257: vdevgone(cmaj, mn, mn, VCHR);
258:
259: pmf_device_deregister(sc->sc_dev);
260:
1.72 ! riastrad 261: callout_destroy(&sc->sc_pcallout);
1.68 riastrad 262: mutex_destroy(&sc->sc_lock);
263: mutex_destroy(&sc->sc_intr_lock);
264: cv_destroy(&sc->sc_condvar);
1.62 isaki 265:
266: return 0;
267: }
268:
269: static void
270: pad_childdet(device_t self, device_t child)
271: {
272: struct pad_softc *sc = device_private(self);
273:
1.68 riastrad 274: if (child == sc->sc_audiodev)
275: sc->sc_audiodev = NULL;
1.62 isaki 276: }
277:
278: static int
279: pad_add_block(struct pad_softc *sc, uint8_t *blk, int blksize)
1.1 jmcneill 280: {
281: int l;
282:
283: if (sc->sc_buflen + blksize > PAD_BUFSIZE)
284: return ENOBUFS;
285:
286: if (sc->sc_wpos + blksize <= PAD_BUFSIZE)
287: memcpy(sc->sc_audiobuf + sc->sc_wpos, blk, blksize);
288: else {
289: l = PAD_BUFSIZE - sc->sc_wpos;
290: memcpy(sc->sc_audiobuf + sc->sc_wpos, blk, l);
291: memcpy(sc->sc_audiobuf, blk + l, blksize - l);
292: }
293:
294: sc->sc_wpos += blksize;
1.59 isaki 295: if (sc->sc_wpos >= PAD_BUFSIZE)
1.1 jmcneill 296: sc->sc_wpos -= PAD_BUFSIZE;
297:
298: sc->sc_buflen += blksize;
299:
300: return 0;
301: }
302:
303: static int
1.62 isaki 304: pad_get_block(struct pad_softc *sc, pad_block_t *pb, int blksize)
1.1 jmcneill 305: {
306: int l;
307:
308: KASSERT(pb != NULL);
309:
310: pb->pb_ptr = (sc->sc_audiobuf + sc->sc_rpos);
311: if (sc->sc_rpos + blksize < PAD_BUFSIZE) {
312: pb->pb_len = blksize;
313: sc->sc_rpos += blksize;
314: } else {
315: l = PAD_BUFSIZE - sc->sc_rpos;
316: pb->pb_len = l;
317: sc->sc_rpos = 0;
318: }
319: sc->sc_buflen -= pb->pb_len;
320:
321: return 0;
322: }
323:
1.71 riastrad 324: static int
325: pad_open(dev_t dev, int flags, int fmt, struct lwp *l)
1.57 nakayama 326: {
1.71 riastrad 327: struct file *fp = NULL;
328: device_t self;
329: struct pad_softc *sc = NULL;
330: cfdata_t cf = NULL;
331: int error, fd;
332:
333: error = fd_allocfile(&fp, &fd);
334: if (error)
335: goto out;
1.57 nakayama 336:
1.71 riastrad 337: cf = kmem_alloc(sizeof(*cf), KM_SLEEP);
1.57 nakayama 338: cf->cf_name = pad_cd.cd_name;
339: cf->cf_atname = pad_cd.cd_name;
1.71 riastrad 340: cf->cf_unit = 0;
1.57 nakayama 341: cf->cf_fstate = FSTATE_STAR;
342:
1.71 riastrad 343: self = config_attach_pseudo(cf);
344: if (self == NULL) {
345: error = ENXIO;
346: goto out;
347: }
348: sc = device_private(self);
349: KASSERT(sc->sc_dev == self);
350: cf = NULL;
351:
352: error = fd_clone(fp, fd, flags, &pad_fileops, sc);
353: KASSERT(error == EMOVEFD);
354: fp = NULL;
355: sc = NULL;
356:
357: out: if (sc)
358: pad_close(sc);
359: if (cf)
360: kmem_free(cf, sizeof(*cf));
361: if (fp)
362: fd_abort(curproc, fp, fd);
1.57 nakayama 363: return error;
1.1 jmcneill 364: }
365:
1.71 riastrad 366: static void
1.57 nakayama 367: pad_close(struct pad_softc *sc)
1.41 nat 368: {
1.71 riastrad 369: device_t self = sc->sc_dev;
370: cfdata_t cf = device_cfdata(self);
1.50 nat 371:
1.71 riastrad 372: KERNEL_LOCK(1, NULL);
373: KASSERT(sc->sc_open);
374: sc->sc_open = 0;
375: (void)config_detach(self, DETACH_FORCE);
376: KERNEL_UNLOCK_ONE(NULL);
1.41 nat 377:
1.71 riastrad 378: kmem_free(cf, sizeof(*cf));
1.57 nakayama 379: }
380:
381: static int
382: fops_pad_close(struct file *fp)
383: {
1.68 riastrad 384: struct pad_softc *sc = fp->f_pad;
1.57 nakayama 385:
1.68 riastrad 386: pad_close(sc);
387:
388: return 0;
1.57 nakayama 389: }
1.1 jmcneill 390:
1.57 nakayama 391: static int
1.62 isaki 392: fops_pad_poll(struct file *fp, int events)
1.57 nakayama 393: {
1.62 isaki 394:
1.63 isaki 395: return POLLERR;
1.57 nakayama 396: }
397:
398: static int
1.62 isaki 399: fops_pad_kqfilter(struct file *fp, struct knote *kn)
1.57 nakayama 400: {
1.68 riastrad 401: struct pad_softc *sc = fp->f_pad;
1.57 nakayama 402: dev_t dev;
403:
1.62 isaki 404: dev = makedev(cdevsw_lookup_major(&pad_cdevsw),
405: device_unit(sc->sc_dev));
1.57 nakayama 406:
407: return seltrue_kqfilter(dev, kn);
408: }
409:
410: static int
1.62 isaki 411: fops_pad_ioctl(struct file *fp, u_long cmd, void *data)
1.57 nakayama 412: {
1.62 isaki 413:
1.57 nakayama 414: return ENODEV;
415: }
1.1 jmcneill 416:
1.57 nakayama 417: static int
1.62 isaki 418: fops_pad_stat(struct file *fp, struct stat *st)
1.57 nakayama 419: {
1.68 riastrad 420: struct pad_softc *sc = fp->f_pad;
1.57 nakayama 421:
422: memset(st, 0, sizeof(*st));
423:
1.62 isaki 424: st->st_dev = makedev(cdevsw_lookup_major(&pad_cdevsw),
425: device_unit(sc->sc_dev));
1.57 nakayama 426:
427: st->st_uid = kauth_cred_geteuid(fp->f_cred);
428: st->st_gid = kauth_cred_getegid(fp->f_cred);
429: st->st_mode = S_IFCHR;
430:
1.54 nakayama 431: return 0;
1.41 nat 432: }
1.39 nat 433:
1.57 nakayama 434: static int
1.62 isaki 435: fops_pad_mmap(struct file *fp, off_t *offp, size_t len, int prot, int *flagsp,
436: int *advicep, struct uvm_object **uobjp, int *maxprotp)
1.57 nakayama 437: {
1.62 isaki 438:
1.57 nakayama 439: return 1;
440: }
441:
442: static int
443: fops_pad_read(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred,
1.62 isaki 444: int ioflag)
1.57 nakayama 445: {
1.68 riastrad 446: struct pad_softc *sc = fp->f_pad;
1.39 nat 447:
1.57 nakayama 448: return pad_read(sc, offp, uio, cred, ioflag);
1.1 jmcneill 449: }
450:
1.57 nakayama 451: static int
452: pad_read(struct pad_softc *sc, off_t *offp, struct uio *uio, kauth_cred_t cred,
1.62 isaki 453: int ioflag)
1.1 jmcneill 454: {
455: pad_block_t pb;
1.59 isaki 456: int len;
457: int err;
1.1 jmcneill 458:
459: err = 0;
1.59 isaki 460: DPRINTF("%s: resid=%zu\n", __func__, uio->uio_resid);
1.27 nat 461: while (uio->uio_resid > 0 && !err) {
1.69 riastrad 462: mutex_enter(&sc->sc_intr_lock);
1.59 isaki 463: if (sc->sc_buflen == 0) {
464: DPRINTF("%s: wait\n", __func__);
1.69 riastrad 465: err = cv_wait_sig(&sc->sc_condvar, &sc->sc_intr_lock);
1.59 isaki 466: DPRINTF("%s: wake up %d\n", __func__, err);
1.69 riastrad 467: mutex_exit(&sc->sc_intr_lock);
1.59 isaki 468: if (err) {
469: if (err == ERESTART)
470: err = EINTR;
471: break;
1.35 nat 472: }
1.59 isaki 473: if (sc->sc_buflen == 0)
474: break;
1.17 jmcneill 475: continue;
476: }
1.1 jmcneill 477:
1.59 isaki 478: len = uimin(uio->uio_resid, sc->sc_buflen);
479: err = pad_get_block(sc, &pb, len);
1.69 riastrad 480: mutex_exit(&sc->sc_intr_lock);
1.59 isaki 481: if (err)
1.24 nat 482: break;
1.59 isaki 483: DPRINTF("%s: move %d\n", __func__, pb.pb_len);
484: uiomove(pb.pb_ptr, pb.pb_len, uio);
1.1 jmcneill 485: }
486:
487: return err;
488: }
489:
490: static int
1.62 isaki 491: fops_pad_write(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred,
492: int ioflag)
1.57 nakayama 493: {
1.62 isaki 494:
1.57 nakayama 495: return EOPNOTSUPP;
496: }
497:
498: static int
1.59 isaki 499: pad_query_format(void *opaque, audio_format_query_t *afp)
1.26 nat 500: {
501:
1.59 isaki 502: return audio_query_format(pad_formats, PAD_NFORMATS, afp);
1.26 nat 503: }
504:
505: static int
1.59 isaki 506: pad_set_format(void *opaque, int setmode,
507: const audio_params_t *play, const audio_params_t *rec,
508: audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
1.1 jmcneill 509: {
1.69 riastrad 510: struct pad_softc *sc = opaque;
1.1 jmcneill 511:
1.17 jmcneill 512: KASSERT(mutex_owned(&sc->sc_lock));
513:
1.59 isaki 514: /* XXX playback only */
515: pfil->codec = pad_swvol_codec;
516: pfil->context = sc;
1.2 jmcneill 517:
1.1 jmcneill 518: return 0;
519: }
520:
521: static int
522: pad_start_output(void *opaque, void *block, int blksize,
523: void (*intr)(void *), void *intrarg)
524: {
1.69 riastrad 525: struct pad_softc *sc = opaque;
1.1 jmcneill 526: int err;
1.59 isaki 527: int ms;
1.1 jmcneill 528:
1.59 isaki 529: KASSERT(mutex_owned(&sc->sc_intr_lock));
1.1 jmcneill 530:
531: sc->sc_intr = intr;
532: sc->sc_intrarg = intrarg;
533: sc->sc_blksize = blksize;
534:
1.59 isaki 535: DPRINTF("%s: blksize=%d\n", __func__, blksize);
1.1 jmcneill 536: err = pad_add_block(sc, block, blksize);
1.59 isaki 537: cv_broadcast(&sc->sc_condvar);
1.1 jmcneill 538:
1.59 isaki 539: ms = blksize * 1000 / PADCHAN / (PADPREC / NBBY) / PADFREQ;
540: DPRINTF("%s: callout ms=%d\n", __func__, ms);
1.69 riastrad 541: callout_schedule(&sc->sc_pcallout, mstohz(ms));
1.1 jmcneill 542:
1.66 nia 543: return err;
1.1 jmcneill 544: }
545:
546: static int
547: pad_halt_output(void *opaque)
548: {
1.69 riastrad 549: struct pad_softc *sc = opaque;
1.17 jmcneill 550:
1.59 isaki 551: DPRINTF("%s\n", __func__);
552: KASSERT(mutex_owned(&sc->sc_intr_lock));
1.17 jmcneill 553:
1.69 riastrad 554: callout_halt(&sc->sc_pcallout, &sc->sc_intr_lock);
555:
1.1 jmcneill 556: sc->sc_intr = NULL;
557: sc->sc_intrarg = NULL;
558: sc->sc_buflen = 0;
559: sc->sc_rpos = sc->sc_wpos = 0;
1.69 riastrad 560: cv_broadcast(&sc->sc_condvar);
1.1 jmcneill 561:
562: return 0;
563: }
564:
1.59 isaki 565: static void
566: pad_done_output(void *arg)
567: {
1.69 riastrad 568: struct pad_softc *sc = arg;
1.59 isaki 569:
570: DPRINTF("%s\n", __func__);
571:
572: mutex_enter(&sc->sc_intr_lock);
573: (*sc->sc_intr)(sc->sc_intrarg);
574: mutex_exit(&sc->sc_intr_lock);
575: }
576:
1.1 jmcneill 577: static int
578: pad_getdev(void *opaque, struct audio_device *ret)
579: {
1.62 isaki 580:
1.16 jmcneill 581: strlcpy(ret->name, "Virtual Audio", sizeof(ret->name));
582: strlcpy(ret->version, osrelease, sizeof(ret->version));
583: strlcpy(ret->config, "pad", sizeof(ret->config));
1.1 jmcneill 584:
585: return 0;
586: }
587:
588: static int
589: pad_set_port(void *opaque, mixer_ctrl_t *mc)
590: {
1.69 riastrad 591: struct pad_softc *sc = opaque;
1.2 jmcneill 592:
1.17 jmcneill 593: KASSERT(mutex_owned(&sc->sc_lock));
594:
1.2 jmcneill 595: switch (mc->dev) {
596: case PAD_OUTPUT_MASTER_VOLUME:
597: case PAD_INPUT_DAC_VOLUME:
1.58 nakayama 598: if (mc->un.value.num_channels != 1)
599: return EINVAL;
1.2 jmcneill 600: sc->sc_swvol = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO];
601: return 0;
602: }
603:
1.1 jmcneill 604: return ENXIO;
605: }
606:
607: static int
608: pad_get_port(void *opaque, mixer_ctrl_t *mc)
609: {
1.69 riastrad 610: struct pad_softc *sc = opaque;
1.2 jmcneill 611:
1.17 jmcneill 612: KASSERT(mutex_owned(&sc->sc_lock));
613:
1.2 jmcneill 614: switch (mc->dev) {
615: case PAD_OUTPUT_MASTER_VOLUME:
616: case PAD_INPUT_DAC_VOLUME:
1.58 nakayama 617: if (mc->un.value.num_channels != 1)
618: return EINVAL;
1.2 jmcneill 619: mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_swvol;
620: return 0;
621: }
622:
1.1 jmcneill 623: return ENXIO;
624: }
625:
626: static int
627: pad_query_devinfo(void *opaque, mixer_devinfo_t *di)
628: {
1.69 riastrad 629: struct pad_softc *sc __diagused = opaque;
1.2 jmcneill 630:
1.17 jmcneill 631: KASSERT(mutex_owned(&sc->sc_lock));
632:
1.2 jmcneill 633: switch (di->index) {
634: case PAD_OUTPUT_CLASS:
635: di->mixer_class = PAD_OUTPUT_CLASS;
636: strcpy(di->label.name, AudioCoutputs);
637: di->type = AUDIO_MIXER_CLASS;
638: di->next = di->prev = AUDIO_MIXER_LAST;
639: return 0;
640: case PAD_INPUT_CLASS:
641: di->mixer_class = PAD_INPUT_CLASS;
642: strcpy(di->label.name, AudioCinputs);
643: di->type = AUDIO_MIXER_CLASS;
644: di->next = di->prev = AUDIO_MIXER_LAST;
645: return 0;
646: case PAD_OUTPUT_MASTER_VOLUME:
647: di->mixer_class = PAD_OUTPUT_CLASS;
648: strcpy(di->label.name, AudioNmaster);
649: di->type = AUDIO_MIXER_VALUE;
650: di->next = di->prev = AUDIO_MIXER_LAST;
651: di->un.v.num_channels = 1;
652: strcpy(di->un.v.units.name, AudioNvolume);
653: return 0;
654: case PAD_INPUT_DAC_VOLUME:
655: di->mixer_class = PAD_INPUT_CLASS;
656: strcpy(di->label.name, AudioNdac);
657: di->type = AUDIO_MIXER_VALUE;
658: di->next = di->prev = AUDIO_MIXER_LAST;
659: di->un.v.num_channels = 1;
660: strcpy(di->un.v.units.name, AudioNvolume);
661: return 0;
662: }
663:
1.1 jmcneill 664: return ENXIO;
665: }
666:
667: static int
668: pad_get_props(void *opaque)
669: {
1.17 jmcneill 670:
1.59 isaki 671: return AUDIO_PROP_PLAYBACK;
1.1 jmcneill 672: }
1.13 ahoka 673:
1.17 jmcneill 674: static void
675: pad_get_locks(void *opaque, kmutex_t **intr, kmutex_t **thread)
676: {
1.69 riastrad 677: struct pad_softc *sc = opaque;
1.17 jmcneill 678:
679: *intr = &sc->sc_intr_lock;
680: *thread = &sc->sc_lock;
681: }
682:
1.22 jmcneill 683: static void
1.59 isaki 684: pad_swvol_codec(audio_filter_arg_t *arg)
1.22 jmcneill 685: {
1.59 isaki 686: struct pad_softc *sc = arg->context;
687: const aint_t *src;
688: aint_t *dst;
689: u_int sample_count;
690: u_int i;
691:
692: src = arg->src;
693: dst = arg->dst;
694: sample_count = arg->count * arg->srcfmt->channels;
695: for (i = 0; i < sample_count; i++) {
696: aint2_t v = (aint2_t)(*src++);
697: v = v * sc->sc_swvol / 255;
698: *dst++ = (aint_t)v;
699: }
1.22 jmcneill 700: }
701:
1.44 pgoyette 702: MODULE(MODULE_CLASS_DRIVER, pad, "audio");
703:
1.13 ahoka 704: #ifdef _MODULE
705:
1.57 nakayama 706: #include "ioconf.c"
707:
708: devmajor_t cmajor = NODEVMAJOR, bmajor = NODEVMAJOR;
709:
710: /*
711: * We need our own version of cfattach since config(1)'s ioconf does not
712: * generate what we need
713: */
714:
715: static struct cfattach *pad_cfattachinit[] = { &pad_ca, NULL };
1.13 ahoka 716:
1.57 nakayama 717: static struct cfattachinit pad_cfattach[] = {
718: { "pad", pad_cfattachinit },
719: { NULL, NULL }
1.45 pgoyette 720: };
1.47 pgoyette 721: #endif
1.45 pgoyette 722:
1.13 ahoka 723: static int
724: pad_modcmd(modcmd_t cmd, void *arg)
725: {
1.44 pgoyette 726: int error = 0;
1.13 ahoka 727:
728: switch (cmd) {
729: case MODULE_CMD_INIT:
1.44 pgoyette 730: #ifdef _MODULE
1.57 nakayama 731: pad_cfattach[1] = cfattach_ioconf_pad[0];
732: error = config_init_component(cfdriver_ioconf_pad,
733: pad_cfattach, cfdata_ioconf_pad);
734: if (error)
1.44 pgoyette 735: break;
1.13 ahoka 736:
1.25 msaitoh 737: error = devsw_attach(pad_cd.cd_name, NULL, &bmajor,
1.57 nakayama 738: &pad_cdevsw, &cmajor);
1.13 ahoka 739: if (error) {
1.57 nakayama 740: config_fini_component(cfdriver_ioconf_pad,
741: pad_cfattach, cfdata_ioconf_pad);
1.44 pgoyette 742: break;
1.13 ahoka 743: }
744:
1.44 pgoyette 745: #endif
1.57 nakayama 746: break;
1.54 nakayama 747:
1.13 ahoka 748: case MODULE_CMD_FINI:
1.44 pgoyette 749: #ifdef _MODULE
1.57 nakayama 750: error = devsw_detach(NULL, &pad_cdevsw);
751: if (error)
752: break;
753:
754: error = config_fini_component(cfdriver_ioconf_pad,
755: pad_cfattach, cfdata_ioconf_pad);
1.13 ahoka 756: if (error) {
1.57 nakayama 757: devsw_attach(pad_cd.cd_name, NULL, &bmajor,
758: &pad_cdevsw, &cmajor);
1.44 pgoyette 759: break;
1.13 ahoka 760: }
1.44 pgoyette 761: #endif
1.57 nakayama 762: break;
1.54 nakayama 763:
1.13 ahoka 764: default:
1.44 pgoyette 765: error = ENOTTY;
1.13 ahoka 766: }
1.44 pgoyette 767:
768: return error;
1.13 ahoka 769: }
CVSweb <webmaster@jp.NetBSD.org>