Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / i386 / isa / sound / audio.c
1 /*
2  * sound/audio.c
3  * 
4  * Device file manager for /dev/audio
5  * 
6  * Copyright by Hannu Savolainen 1993
7  * 
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are
10  * met: 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer. 2.
12  * Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  * 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  * 
28  */
29
30 #include <i386/isa/sound/sound_config.h>
31
32 #ifdef CONFIG_AUDIO
33
34 #include <i386/isa/sound/ulaw.h>
35 #include <i386/isa/sound/coproc.h>
36
37 #define ON              1
38 #define OFF             0
39 int
40 DMAbuf_poll(int dev, struct fileinfo * file, int events, select_table * wait);
41
42 int
43 audio_poll(int dev, struct fileinfo * file, int events, select_table * wait);
44
45 static int      wr_buff_no[MAX_AUDIO_DEV];
46         /* != -1, if there is a incomplete output block in the queue. */
47 static int      wr_buff_size[MAX_AUDIO_DEV], wr_buff_ptr[MAX_AUDIO_DEV];
48
49 static int      audio_mode[MAX_AUDIO_DEV];
50 static int      dev_nblock[MAX_AUDIO_DEV];      /* 1 if in noblocking mode */
51
52 #define         AM_NONE         0
53 #define         AM_WRITE        1
54 #define         AM_READ         2
55
56 static char    *wr_dma_buf[MAX_AUDIO_DEV];
57 static int      audio_format[MAX_AUDIO_DEV];
58 static int      local_conversion[MAX_AUDIO_DEV];
59
60 static int
61 set_format(int dev, int fmt)
62 {
63     if (fmt != AFMT_QUERY) {
64
65         local_conversion[dev] = 0;
66
67         if (!(audio_devs[dev]->format_mask & fmt)) { /* Not supported */
68             if (fmt == AFMT_MU_LAW) {
69                 fmt = AFMT_U8;
70                 local_conversion[dev] = AFMT_MU_LAW;
71             } else
72                 fmt = AFMT_U8;  /* This is always supported */
73         }
74         audio_format[dev] = DMAbuf_ioctl(dev, SNDCTL_DSP_SETFMT,
75                     (ioctl_arg) fmt, 1);
76     }
77     if (local_conversion[dev])  /* This shadows the HW format */
78         return local_conversion[dev];
79
80     return audio_format[dev];
81 }
82
83 int
84 audio_open(int dev, struct fileinfo * file)
85 {
86     int             ret;
87     int             bits;
88     int             dev_type = dev & 0x0f;
89     int             mode = file->mode & O_ACCMODE;
90
91     dev = dev >> 4;
92
93     bits = (dev_type == SND_DEV_DSP16) ? 16 : 8 ;
94
95     if ((ret = DMAbuf_open(dev, mode)) < 0)
96         return ret;
97
98     if (audio_devs[dev]->coproc)
99         if ((ret = audio_devs[dev]->coproc->
100                  open(audio_devs[dev]->coproc->devc, COPR_PCM)) < 0) {
101             audio_release(dev, file);
102             printf("Sound: Can't access coprocessor device\n");
103
104             return ret;
105         }
106     local_conversion[dev] = 0;
107
108     if (DMAbuf_ioctl(dev, SNDCTL_DSP_SETFMT, (ioctl_arg) bits, 1) != bits) {
109         audio_release(dev, file);
110         return -(ENXIO);
111     }
112
113     set_format(dev,  (dev_type == SND_DEV_AUDIO) ? AFMT_MU_LAW : bits ) ;
114
115     wr_buff_no[dev] = -1;
116     audio_mode[dev] = AM_NONE;
117     wr_buff_size[dev] = wr_buff_ptr[dev] = 0;
118     dev_nblock[dev] = 0;
119
120     return ret;
121 }
122
123 void
124 audio_release(int dev, struct fileinfo * file)
125 {
126     int             mode;
127
128     dev = dev >> 4;
129     mode = file->mode & O_ACCMODE;
130
131     if (wr_buff_no[dev] >= 0) {
132         DMAbuf_start_output(dev, wr_buff_no[dev], wr_buff_ptr[dev]);
133         wr_buff_no[dev] = -1;
134     }
135     if (audio_devs[dev]->coproc)
136         audio_devs[dev]->coproc->close(audio_devs[dev]->coproc->devc,COPR_PCM);
137     DMAbuf_release(dev, mode);
138     audio_devs[dev]->dmap_out->mapping_flags &= ~DMA_MAP_MAPPED ;
139
140 }
141
142 static void
143 translate_bytes(const u_char *table, u_char *buff, int n)
144 {
145     u_long   i;
146
147     if (n <= 0)
148         return;
149
150     for (i = 0; i < n; ++i)
151         buff[i] = table[buff[i]];
152 }
153
154 int
155 audio_write(int dev, struct fileinfo * file, snd_rw_buf * buf, int count)
156 {
157     int             c, p, l;
158     int             err;
159
160     dev = dev >> 4;
161
162     p = 0;
163     c = count;
164     if ((audio_mode[dev] & AM_READ) &&
165         !(audio_devs[dev]->flags & DMA_DUPLEX)) {       /* Direction change */
166         wr_buff_no[dev] = -1;
167     }
168     if (audio_devs[dev]->flags & DMA_DUPLEX)
169         audio_mode[dev] |= AM_WRITE;
170     else
171         audio_mode[dev] = AM_WRITE;
172
173     if (!count) {               /* Flush output */
174         if (wr_buff_no[dev] >= 0) {
175             DMAbuf_start_output(dev, wr_buff_no[dev], wr_buff_ptr[dev]);
176             wr_buff_no[dev] = -1;
177         }
178         return 0;
179     }
180     while (c) {         /* Perform output blocking */
181         if (wr_buff_no[dev] < 0) {
182             /* There is no incomplete buffers */
183             if ((wr_buff_no[dev] = DMAbuf_getwrbuffer(dev,
184                     &wr_dma_buf[dev], &wr_buff_size[dev],
185                     dev_nblock[dev])) < 0) {
186                 /* Handle nonblocking mode */
187                 if (dev_nblock[dev] && wr_buff_no[dev] == -(EAGAIN))
188                     return p; /* No more space. Return # of accepted bytes */
189                 return wr_buff_no[dev];
190             }
191             wr_buff_ptr[dev] = 0;
192         }
193         l = c;
194         if (l > (wr_buff_size[dev] - wr_buff_ptr[dev]))
195             l = (wr_buff_size[dev] - wr_buff_ptr[dev]);
196
197         if (!audio_devs[dev]->copy_from_user) { /* No device specific
198                                                  * copy routine */
199
200             if (uiomove(&wr_dma_buf[dev][wr_buff_ptr[dev]], l, buf)) {
201                 printf("sb: Bad copyin()!\n");
202             };
203         } else
204             audio_devs[dev]->copy_from_user(dev,
205                           wr_dma_buf[dev], wr_buff_ptr[dev], buf, p, l);
206
207
208         /*
209          * Insert local processing here
210          */
211
212         if (local_conversion[dev] == AFMT_MU_LAW) {
213             translate_bytes(ulaw_dsp,
214                     (u_char *) &wr_dma_buf[dev][wr_buff_ptr[dev]], l);
215         }
216         c -= l;
217         p += l;
218         wr_buff_ptr[dev] += l;
219
220         if (wr_buff_ptr[dev] >= wr_buff_size[dev]) {
221             if ((err = DMAbuf_start_output(dev, wr_buff_no[dev],
222                     wr_buff_ptr[dev])) < 0) {
223                 return err;
224             }
225             wr_buff_no[dev] = -1;
226         }
227     }
228     return count;
229 }
230
231 int
232 audio_read(int dev, struct fileinfo * file, snd_rw_buf * buf, int count)
233 {
234     int             c, p, l;
235     char           *dmabuf;
236     int             buff_no;
237
238     dev = dev >> 4;
239     p = 0;
240     c = count;
241     if ((audio_mode[dev] & AM_WRITE) &&
242             !(audio_devs[dev]->flags & DMA_DUPLEX)) {
243         if (wr_buff_no[dev] >= 0) {
244             DMAbuf_start_output(dev, wr_buff_no[dev], wr_buff_ptr[dev]);
245
246             if (!(audio_devs[dev]->flags & DMA_DUPLEX))
247                 wr_buff_no[dev] = -1;
248         }
249     }
250     if (audio_devs[dev]->flags & DMA_DUPLEX)
251         audio_mode[dev] |= AM_READ;
252     else
253         audio_mode[dev] = AM_READ;
254
255     while (c) {
256         if ((buff_no = DMAbuf_getrdbuffer(dev, &dmabuf, &l,
257                                           dev_nblock[dev])) < 0) {
258             /*
259              * Nonblocking mode handling. Return current # of bytes
260              */
261
262             if (dev_nblock[dev] && buff_no == -(EAGAIN))
263                 return p;
264
265             return buff_no;
266         }
267         if (l > c)
268             l = c;
269
270         /*
271          * Insert any local processing here.
272          */
273
274         if (local_conversion[dev] == AFMT_MU_LAW) {
275             translate_bytes(dsp_ulaw, (u_char *) dmabuf, l);
276         }
277         if (uiomove(dmabuf, l, buf)) {
278             printf("sb: Bad copyout()!\n");
279         };
280
281         DMAbuf_rmchars(dev, buff_no, l);
282
283         p += l;
284         c -= l;
285     }
286     return count - c;
287 }
288
289 int
290 audio_ioctl(int dev, struct fileinfo * file, u_int cmd, ioctl_arg arg)
291 {
292     dev = dev >> 4;
293     if (((cmd >> 8) & 0xff) == 'C') {
294         if (audio_devs[dev]->coproc)    /* Coprocessor ioctl */
295             return audio_devs[dev]->coproc->ioctl(audio_devs[dev]->coproc->devc, cmd, arg, 0);
296         else
297             printf("/dev/dsp%d: No coprocessor for this device\n", dev);
298
299         return -(ENXIO);
300     } else
301         switch (cmd) {
302
303         case SNDCTL_DSP_SYNC:
304             if (wr_buff_no[dev] >= 0) {
305                 DMAbuf_start_output(dev, wr_buff_no[dev], wr_buff_ptr[dev]);
306                 wr_buff_no[dev] = -1;
307             }
308             return DMAbuf_ioctl(dev, cmd, arg, 0);
309             break;
310
311         case SNDCTL_DSP_POST:
312             if (wr_buff_no[dev] >= 0) {
313                 DMAbuf_start_output(dev, wr_buff_no[dev], wr_buff_ptr[dev]);
314                 wr_buff_no[dev] = -1;
315             }
316             return 0;
317             break;
318
319         case SNDCTL_DSP_RESET:
320             wr_buff_no[dev] = -1;
321             audio_mode[dev] = AM_NONE;
322             return DMAbuf_ioctl(dev, cmd, arg, 0);
323             break;
324
325         case SNDCTL_DSP_GETFMTS:
326             return *(int *) arg = audio_devs[dev]->format_mask;
327             break;
328
329         case SNDCTL_DSP_SETFMT:
330             return *(int *) arg = set_format(dev, (*(int *) arg));
331
332         case SNDCTL_DSP_GETISPACE:
333             if ((audio_mode[dev] & AM_WRITE) &&
334                     !(audio_devs[dev]->flags & DMA_DUPLEX))
335                 return -(EBUSY);
336
337             else {
338                 audio_buf_info  info;
339                 int err = DMAbuf_ioctl(dev, cmd, (ioctl_arg) & info, 1);
340
341                 if (err < 0)
342                     return err;
343
344                 bcopy((char *) &info, &(((char *) arg)[0]), sizeof(info));
345                 return 0;
346             }
347
348         case SNDCTL_DSP_GETOSPACE:
349             if ((audio_mode[dev] & AM_READ) &&
350                     !(audio_devs[dev]->flags & DMA_DUPLEX))
351                 return -(EBUSY);
352             else {
353                 audio_buf_info  info;
354                 int err = DMAbuf_ioctl(dev, cmd, (ioctl_arg) & info, 1);
355
356                 if (err < 0)
357                     return err;
358
359                 if (wr_buff_no[dev] != -1)
360                     info.bytes += wr_buff_size[dev] - wr_buff_ptr[dev];
361
362                 bcopy((char *) &info, &(((char *) arg)[0]), sizeof(info));
363                 return 0;
364             }
365
366         case SNDCTL_DSP_NONBLOCK:
367             dev_nblock[dev] = 1;
368             return 0;
369             break;
370
371         case SNDCTL_DSP_GETCAPS:
372             {
373                 int   info = 1; /* Revision level of this ioctl() */
374
375                 if (audio_devs[dev]->flags & DMA_DUPLEX)
376                     info |= DSP_CAP_DUPLEX;
377
378                 if (audio_devs[dev]->coproc)
379                     info |= DSP_CAP_COPROC;
380
381                 if (audio_devs[dev]->local_qlen) /* Dev. has hidden buffs */
382                     info |= DSP_CAP_BATCH;
383
384                 if (audio_devs[dev]->trigger) /* Supports SETTRIGGER */
385                     info |= DSP_CAP_TRIGGER;
386
387                 info |= DSP_CAP_MMAP;
388                 bcopy((char *) &info, &(((char *) arg)[0]), sizeof(info));
389                     return 0;
390             }
391             break;
392
393
394         case FIOASYNC:
395             return *(int *) arg = 1;
396
397         case FIONBIO:
398             return *(int *) arg = 1;
399
400         default:
401             return DMAbuf_ioctl(dev, cmd, arg, 0);
402         }
403 }
404
405 #ifdef ALLOW_POLL
406 /*
407  * XXX should we use spltty() in the select calls ? - lr970714
408  *
409  */
410
411 int
412 audio_poll(int dev, struct fileinfo * file, int events, select_table * wait)
413 {
414     dev = dev >> 4;
415
416  if (events & (POLLIN | POLLRDNORM)) {
417         if ((audio_mode[dev] & AM_WRITE) &&
418                 !(audio_devs[dev]->flags & DMA_DUPLEX))
419             return 0;   /* Not recording */
420
421
422         return (DMAbuf_poll(dev, file, events, wait));
423  }
424
425  if (events & (POLLOUT | POLLWRNORM)) {
426         if ((audio_mode[dev] & AM_READ) &&
427                 !(audio_devs[dev]->flags & DMA_DUPLEX))
428             return 0;   /* Wrong direction */
429
430         if (wr_buff_no[dev] != -1)
431             return 1;   /* There is space in the current buffer */
432
433         return ( DMAbuf_poll(dev, file, events, wait) );
434
435  }
436     return 0;
437 }
438 #endif                          /* ALLOW_POLL */
439
440 #endif