xref: /freebsd/sys/dev/sound/pcm/sound.c (revision a14a0223ae1b172e96dd2a1d849e22026a98b692)
1 /*
2  * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
3  * (C) 1997 Luigi Rizzo (luigi@iet.unipi.it)
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD$
28  */
29 
30 #include "opt_devfs.h"
31 
32 #include <dev/pcm/sound.h>
33 #ifdef DEVFS
34 #include <sys/devfsext.h>
35 #endif /* DEVFS */
36 
37 #if NPCM > 0	/* from "pcm.h" via disgusting #include in snd/sound.h */
38 
39 extern struct isa_driver pcmdriver;
40 
41 static int 	status_isopen = 0;
42 static int 	status_init(char *buf, int size);
43 static int 	status_read(struct uio *buf);
44 
45 static d_open_t sndopen;
46 static d_close_t sndclose;
47 static d_ioctl_t sndioctl;
48 static d_read_t sndread;
49 static d_write_t sndwrite;
50 static d_mmap_t sndmmap;
51 static d_poll_t sndpoll;
52 
53 #define CDEV_MAJOR 30
54 static struct cdevsw snd_cdevsw = {
55 	/* open */	sndopen,
56 	/* close */	sndclose,
57 	/* read */	sndread,
58 	/* write */	sndwrite,
59 	/* ioctl */	sndioctl,
60 	/* poll */	sndpoll,
61 	/* mmap */	sndmmap,
62 	/* strategy */	nostrategy,
63 	/* name */	"snd",
64 	/* maj */	CDEV_MAJOR,
65 	/* dump */	nodump,
66 	/* psize */	nopsize,
67 	/* flags */	0,
68 	/* bmaj */	-1
69 };
70 
71 /* PROPOSAL:
72 each unit needs:
73 status, mixer, dsp, dspW, audio, sequencer, midi-in, seq2, sndproc = 9 devices
74 dspW and audio are deprecated.
75 dsp needs min 64 channels, will give it 256
76 
77 minor = (unit << 12) + (dev << 8) + channel
78 currently minor = (channel << 8) + (unit << 4) + dev
79 
80 nomenclature:
81 	/dev/pcmX/dsp.(0..255)
82 	/dev/pcmX/dspW
83 	/dev/pcmX/audio
84 	/dev/pcmX/status
85 	/dev/pcmX/mixer
86 	[etc.]
87 
88 currently:
89 minor = (channel << 8) + (unit << 4) + dev
90 */
91 
92 #define PCMMINOR(x) (minor(x))
93 #define PCMCHAN(x) ((PCMMINOR(x) & 0x0000ff00) >> 8)
94 #define PCMUNIT(x) ((PCMMINOR(x) & 0x000000f0) >> 4)
95 #define PCMDEV(x)   (PCMMINOR(x) & 0x0000000f)
96 #define PCMMKMINOR(u, d) (((u) & 0x0f) << 4 | ((d) & 0x0f))
97 
98 static devclass_t pcm_devclass;
99 
100 static snddev_info *
101 gsd(int unit)
102 {
103 	return devclass_get_softc(pcm_devclass, unit);
104 }
105 
106 int
107 pcm_addchan(device_t dev, int dir, pcm_channel *templ, void *devinfo)
108 {
109     	snddev_info *d = device_get_softc(dev);
110 	pcm_channel *ch;
111 
112 	ch = (dir == PCMDIR_PLAY)? &d->play[d->playcount++] : &d->rec[d->reccount++];
113 	*ch = *templ;
114 	chn_init(ch, devinfo, dir);
115 	d->chancount++;
116 	return 0;
117 }
118 
119 int
120 pcm_setstatus(device_t dev, char *str)
121 {
122     	snddev_info *d = device_get_softc(dev);
123 	strncpy(d->status, str, SND_STATUSLEN);
124 	return 0;
125 }
126 
127 u_int32_t
128 pcm_getflags(device_t dev)
129 {
130     	snddev_info *d = device_get_softc(dev);
131 	return d->flags;
132 }
133 
134 void
135 pcm_setflags(device_t dev, u_int32_t val)
136 {
137     	snddev_info *d = device_get_softc(dev);
138 	d->flags = val;
139 }
140 
141 /* This is the generic init routine */
142 int
143 pcm_register(device_t dev, void *devinfo, int numplay, int numrec)
144 {
145     	int sz, unit = device_get_unit(dev);
146     	snddev_info *d = device_get_softc(dev);
147 
148     	if (!pcm_devclass) {
149     		pcm_devclass = device_get_devclass(dev);
150 		make_dev(&snd_cdevsw, PCMMKMINOR(0, SND_DEV_STATUS),
151 			 UID_ROOT, GID_WHEEL, 0444, "sndstat");
152 	}
153 	make_dev(&snd_cdevsw, PCMMKMINOR(unit, SND_DEV_CTL),
154 		 UID_ROOT, GID_WHEEL, 0666, "mixer%d", unit);
155 	make_dev(&snd_cdevsw, PCMMKMINOR(unit, SND_DEV_DSP),
156 		 UID_ROOT, GID_WHEEL, 0666, "dsp%d", unit);
157 	make_dev(&snd_cdevsw, PCMMKMINOR(unit, SND_DEV_AUDIO),
158 		 UID_ROOT, GID_WHEEL, 0666, "audio%d", unit);
159 	make_dev(&snd_cdevsw, PCMMKMINOR(unit, SND_DEV_DSP16),
160 		 UID_ROOT, GID_WHEEL, 0666, "dspW%d", unit);
161 	/* XXX SND_DEV_NORESET? */
162 	d->devinfo = devinfo;
163 	d->chancount = d->playcount = d->reccount = 0;
164     	sz = (numplay + numrec) * sizeof(pcm_channel *);
165     	d->aplay = (pcm_channel **)malloc(sz, M_DEVBUF, M_NOWAIT);
166     	if (!d->aplay) goto no;
167     	d->arec = (pcm_channel **)malloc(sz, M_DEVBUF, M_NOWAIT);
168     	if (!d->arec) goto no;
169     	bzero(d->aplay, sz);
170     	bzero(d->arec, sz);
171 
172     	d->play = (pcm_channel *)malloc(numplay * sizeof(pcm_channel),
173 					M_DEVBUF, M_NOWAIT);
174     	if (!d->play) goto no;
175     	d->rec = (pcm_channel *)malloc(numrec * sizeof(pcm_channel),
176 				       M_DEVBUF, M_NOWAIT);
177     	if (!d->rec) goto no;
178     	bzero(d->play, numplay * sizeof(pcm_channel));
179     	bzero(d->rec, numrec * sizeof(pcm_channel));
180 
181 	fkchan_setup(&d->fakechan);
182 	chn_init(&d->fakechan, NULL, 0);
183 	d->magic = MAGIC(unit); /* debugging... */
184 
185     	return 0;
186 no:
187 	if (d->aplay) free(d->aplay, M_DEVBUF);
188 	if (d->play) free(d->play, M_DEVBUF);
189 	if (d->arec) free(d->arec, M_DEVBUF);
190 	if (d->rec) free(d->rec, M_DEVBUF);
191 	return ENXIO;
192 }
193 
194 /*
195  * a small utility function which, given a device number, returns
196  * a pointer to the associated snddev_info struct, and sets the unit
197  * number.
198  */
199 static snddev_info *
200 get_snddev_info(dev_t i_dev, int *unit, int *dev, int *chan)
201 {
202     	int u, d, c;
203 
204     	u = PCMUNIT(i_dev);
205     	d = PCMDEV(i_dev);
206     	c = PCMCHAN(i_dev);
207     	if (u > devclass_get_maxunit(pcm_devclass)) u = -1;
208     	if (unit) *unit = u;
209     	if (dev) *dev = d;
210     	if (chan) *chan = c;
211     	if (u < 0) return NULL;
212 
213     	switch(d) {
214     	case SND_DEV_CTL:	/* /dev/mixer handled by pcm */
215     	case SND_DEV_STATUS: /* /dev/sndstat handled by pcm */
216     	case SND_DEV_DSP:
217     	case SND_DEV_DSP16:
218     	case SND_DEV_AUDIO:
219 		return gsd(u);
220 
221     	case SND_DEV_SEQ: /* XXX when enabled... */
222     	case SND_DEV_SEQ2:
223     	case SND_DEV_MIDIN:
224     	case SND_DEV_SNDPROC:	/* /dev/sndproc handled by pcm */
225     	default:
226 		printf("unsupported subdevice %d\n", d);
227 		return NULL;
228     	}
229 }
230 
231 static int
232 sndopen(dev_t i_dev, int flags, int mode, struct proc *p)
233 {
234     	int dev, unit, chan;
235     	snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan);
236 
237     	DEB(printf("open snd%d subdev %d flags 0x%08x mode 0x%08x\n",
238 		unit, dev, flags, mode));
239 
240     	switch(dev) {
241     	case SND_DEV_STATUS:
242 		if (status_isopen) return EBUSY;
243 		status_isopen = 1;
244 		return 0;
245 
246     	case SND_DEV_CTL:
247 		return d? 0 : ENXIO;
248 
249     	case SND_DEV_AUDIO:
250     	case SND_DEV_DSP:
251     	case SND_DEV_DSP16:
252 	case SND_DEV_NORESET:
253 		return d? dsp_open(d, chan, flags, dev) : ENXIO;
254 
255     	default:
256     		return ENXIO;
257     	}
258 }
259 
260 static int
261 sndclose(dev_t i_dev, int flags, int mode, struct proc *p)
262 {
263     	int dev, unit, chan;
264     	snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan);
265 
266     	DEB(printf("close snd%d subdev %d\n", unit, dev));
267 
268     	switch(dev) { /* only those for which close makes sense */
269     	case SND_DEV_STATUS:
270 		if (!status_isopen) return EBADF;
271 		status_isopen = 0;
272 		return 0;
273 
274     	case SND_DEV_CTL:
275 		return d? 0 : ENXIO;
276 
277     	case SND_DEV_AUDIO:
278     	case SND_DEV_DSP:
279     	case SND_DEV_DSP16:
280 		return d? dsp_close(d, chan, dev) : ENXIO;
281 
282     	default:
283 		return ENXIO;
284     	}
285 }
286 
287 static int
288 sndread(dev_t i_dev, struct uio *buf, int flag)
289 {
290     	int dev, unit, chan;
291     	snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan);
292     	DEB(printf("read snd%d subdev %d flag 0x%08x\n", unit, dev, flag));
293 
294     	switch(dev) {
295     	case SND_DEV_STATUS:
296 		return status_isopen? status_read(buf) : EBADF;
297 
298     	case SND_DEV_AUDIO:
299     	case SND_DEV_DSP:
300     	case SND_DEV_DSP16:
301         	return d? dsp_read(d, chan, buf, flag) : EBADF;
302 
303     	default:
304     		return ENXIO;
305     	}
306 }
307 
308 static int
309 sndwrite(dev_t i_dev, struct uio *buf, int flag)
310 {
311     	int dev, unit, chan;
312     	snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan);
313 
314     	DEB(printf("write snd%d subdev %d flag 0x%08x\n", unit, dev & 0xf, flag));
315 
316     	switch(dev) {	/* only writeable devices */
317     	case SND_DEV_DSP:
318     	case SND_DEV_DSP16:
319     	case SND_DEV_AUDIO:
320 		return d? dsp_write(d, chan, buf, flag) : EBADF;
321 
322     	default:
323 		return EPERM; /* for non-writeable devices ; */
324     	}
325 }
326 
327 static int
328 sndioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p)
329 {
330     	int dev, chan;
331     	snddev_info *d = get_snddev_info(i_dev, NULL, &dev, &chan);
332 
333     	if (d == NULL) return ENXIO;
334 
335     	switch(dev) {
336     	case SND_DEV_CTL:
337 		return mixer_ioctl(d, cmd, arg);
338 
339     	case SND_DEV_AUDIO:
340     	case SND_DEV_DSP:
341     	case SND_DEV_DSP16:
342 		return dsp_ioctl(d, chan, cmd, arg);
343 
344     	default:
345     		return ENXIO;
346     	}
347 }
348 
349 static int
350 sndpoll(dev_t i_dev, int events, struct proc *p)
351 {
352     	int dev, chan;
353     	snddev_info *d = get_snddev_info(i_dev, NULL, &dev, &chan);
354 
355     	DEB(printf("sndpoll dev 0x%04x events 0x%08x\n", i_dev, events));
356 
357     	if (d == NULL) return ENXIO;
358 
359     	switch(dev) {
360     	case SND_DEV_AUDIO:
361     	case SND_DEV_DSP:
362     	case SND_DEV_DSP16:
363 		return dsp_poll(d, chan, events, p);
364 
365     	default:
366     		return (events &
367        		       (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)) | POLLHUP;
368     	}
369 }
370 
371 /*
372  * The mmap interface allows access to the play and read buffer,
373  * plus the device descriptor.
374  * The various blocks are accessible at the following offsets:
375  *
376  * 0x00000000 ( 0   ) : write buffer ;
377  * 0x01000000 (16 MB) : read buffer ;
378  * 0x02000000 (32 MB) : device descriptor (dangerous!)
379  *
380  * WARNING: the mmap routines assume memory areas are aligned. This
381  * is true (probably) for the dma buffers, but likely false for the
382  * device descriptor. As a consequence, we do not know where it is
383  * located in the requested area.
384  */
385 static int
386 sndmmap(dev_t i_dev, vm_offset_t offset, int nprot)
387 {
388     	int unit, dev, chan;
389     	snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan);
390 
391     	DEB(printf("sndmmap d 0x%p dev 0x%04x ofs 0x%08x nprot 0x%08x\n",
392 		   d, dev, offset, nprot));
393 
394     	if (d == NULL || nprot & PROT_EXEC)	return -1; /* forbidden */
395 
396     	switch(dev) {
397     	case SND_DEV_AUDIO:
398     	case SND_DEV_DSP:
399     	case SND_DEV_DSP16:
400 		return dsp_mmap(d, chan, offset, nprot);
401 
402     	default:
403     		return -1;
404     	}
405 }
406 
407 static int
408 status_init(char *buf, int size)
409 {
410     	int             i;
411     	device_t	    dev;
412     	snddev_info     *d;
413 
414     	snprintf(buf, size, "FreeBSD Audio Driver (newpcm) %s %s\n"
415 		 "Installed devices:\n", __DATE__, __TIME__);
416 
417     	for (i = 0; i <= devclass_get_maxunit(pcm_devclass); i++) {
418 		d = gsd(i);
419 		if (!d) continue;
420 		dev = devclass_get_device(pcm_devclass, i);
421         	if (1) snprintf(buf + strlen(buf), size - strlen(buf),
422 		            	"pcm%d: <%s> %s (%d/%d channels%s)\n",
423 		            	i, device_get_desc(dev), d->status,
424 		            	d->playcount, d->reccount,
425 			    	(!(d->flags & SD_F_SIMPLEX))? " duplex" : "");
426     	}
427     	return strlen(buf);
428 }
429 
430 static int
431 status_read(struct uio *buf)
432 {
433     	static char	status_buf[4096];
434     	static int 	bufptr = 0, buflen = 0;
435     	int l;
436 
437     	if (status_isopen == 1) {
438 		status_isopen++;
439 		bufptr = 0;
440 		buflen = status_init(status_buf, sizeof status_buf);
441     	}
442 
443     	l = min(buf->uio_resid, buflen - bufptr);
444     	bufptr += l;
445     	return (l > 0)? uiomove(status_buf + bufptr - l, l, buf) : 0;
446 }
447 
448 #endif	/* NPCM > 0 */
449