device switch 1/many: Remove d_autoq, add d_clone (where d_autoq was).
[dragonfly.git] / sys / dev / sound / isa / i386 / pca / pcaudio.c
1 /*-
2  * Copyright (c) 1994-1998 Søren Schmidt
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer,
10  *    without modification, immediately at the beginning of the file.
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  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD: src/sys/i386/isa/pcaudio.c,v 1.58 2000/01/25 21:58:43 dfr Exp $
29  * $DragonFly: src/sys/dev/sound/isa/i386/pca/Attic/pcaudio.c,v 1.9 2004/05/13 23:49:21 dillon Exp $
30  */
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/conf.h>
35 #include <sys/proc.h>
36 #include <sys/kernel.h>
37 #include <sys/bus.h>
38 #include <sys/filio.h>
39 #include <sys/poll.h>
40 #include <sys/vnode.h>
41
42 #include <machine/clock.h>
43 #include <machine/pcaudioio.h>
44
45 #include <bus/isa/isareg.h>
46 #include <bus/isa/isavar.h>
47 #include <i386/isa/timerreg.h>
48
49 #define BUF_SIZE        8192
50 #define SAMPLE_RATE     8000
51 #define INTERRUPT_RATE  16000
52
53 static struct pca_status {
54         char            open;           /* device open */
55         char            queries;        /* did others try opening */
56         unsigned char   *buf[3];        /* triple buffering */
57         unsigned char   *buffer;        /* current buffer ptr */
58         unsigned        in_use[3];      /* buffers fill */
59         unsigned        index;          /* index in current buffer */
60         unsigned        counter;        /* sample counter */
61         unsigned        scale;          /* sample counter scale */
62         unsigned        sample_rate;    /* sample rate */
63         unsigned        processed;      /* samples processed */
64         unsigned        volume;         /* volume for pc-speaker */
65         char            encoding;       /* Ulaw, Alaw or linear */
66         u_char          current;        /* current buffer */
67         unsigned char   oldval;         /* old timer port value */
68         char            timer_on;       /* is playback running */
69         struct selinfo  wsel;           /* select/poll status */
70 } pca_status;
71
72 static char buffer1[BUF_SIZE];
73 static char buffer2[BUF_SIZE];
74 static char buffer3[BUF_SIZE];
75 static char volume_table[256];
76
77 static unsigned char ulaw_dsp[] = {
78      3,    7,   11,   15,   19,   23,   27,   31,
79     35,   39,   43,   47,   51,   55,   59,   63,
80     66,   68,   70,   72,   74,   76,   78,   80,
81     82,   84,   86,   88,   90,   92,   94,   96,
82     98,   99,  100,  101,  102,  103,  104,  105,
83    106,  107,  108,  109,  110,  111,  112,  113,
84    113,  114,  114,  115,  115,  116,  116,  117,
85    117,  118,  118,  119,  119,  120,  120,  121,
86    121,  121,  122,  122,  122,  122,  123,  123,
87    123,  123,  124,  124,  124,  124,  125,  125,
88    125,  125,  125,  125,  126,  126,  126,  126,
89    126,  126,  126,  126,  127,  127,  127,  127,
90    127,  127,  127,  127,  127,  127,  127,  127,
91    128,  128,  128,  128,  128,  128,  128,  128,
92    128,  128,  128,  128,  128,  128,  128,  128,
93    128,  128,  128,  128,  128,  128,  128,  128,
94    253,  249,  245,  241,  237,  233,  229,  225,
95    221,  217,  213,  209,  205,  201,  197,  193,
96    190,  188,  186,  184,  182,  180,  178,  176,
97    174,  172,  170,  168,  166,  164,  162,  160,
98    158,  157,  156,  155,  154,  153,  152,  151,
99    150,  149,  148,  147,  146,  145,  144,  143,
100    143,  142,  142,  141,  141,  140,  140,  139,
101    139,  138,  138,  137,  137,  136,  136,  135,
102    135,  135,  134,  134,  134,  134,  133,  133,
103    133,  133,  132,  132,  132,  132,  131,  131,
104    131,  131,  131,  131,  130,  130,  130,  130,
105    130,  130,  130,  130,  129,  129,  129,  129,
106    129,  129,  129,  129,  129,  129,  129,  129,
107    128,  128,  128,  128,  128,  128,  128,  128,
108    128,  128,  128,  128,  128,  128,  128,  128,
109    128,  128,  128,  128,  128,  128,  128,  128,
110 };
111
112 static unsigned char alaw_linear[] = {
113         45,     214,    122,    133,    0,              255,    107,    149, 
114         86,     171,    126,    129,    0,              255,    117,    138, 
115         13,     246,    120,    135,    0,              255,    99,     157, 
116         70,     187,    124,    131,    0,              255,    113,    142, 
117         61,     198,    123,    132,    0,              255,    111,    145, 
118         94,     163,    127,    128,    0,              255,    119,    136, 
119         29,     230,    121,    134,    0,              255,    103,    153, 
120         78,     179,    125,    130,    0,              255,    115,    140, 
121         37,     222,    122,    133,    0,              255,    105,    151, 
122         82,     175,    126,    129,    0,              255,    116,    139, 
123         5,      254,    120,    135,    0,              255,    97,     159, 
124         66,     191,    124,    131,    0,              255,    112,    143, 
125         53,     206,    123,    132,    0,              255,    109,    147, 
126         90,     167,    127,    128,    0,              255,    118,    137, 
127         21,     238,    121,    134,    0,              255,    101,    155, 
128         74,     183,    125,    130,    0,              255,    114,    141, 
129         49,     210,    123,    133,    0,              255,    108,    148, 
130         88,     169,    127,    129,    0,              255,    118,    138, 
131         17,     242,    121,    135,    0,              255,    100,    156, 
132         72,     185,    125,    131,    0,              255,    114,    142, 
133         64,     194,    124,    132,    0,              255,    112,    144, 
134         96,     161,    128,    128,    1,              255,    120,    136, 
135         33,     226,    122,    134,    0,              255,    104,    152, 
136         80,     177,    126,    130,    0,              255,    116,    140, 
137         41,     218,    122,    133,    0,              255,    106,    150, 
138         84,     173,    126,    129,    0,              255,    117,    139, 
139         9,      250,    120,    135,    0,              255,    98,     158, 
140         68,     189,    124,    131,    0,              255,    113,    143, 
141         57,     202,    123,    132,    0,              255,    110,    146, 
142         92,     165,    127,    128,    0,              255,    119,    137, 
143         25,     234,    121,    134,    0,              255,    102,    154, 
144         76,     181,    125,    130,    0,              255,    115,    141, 
145 };
146
147 static int pca_sleep = 0;
148 static int pca_initialized = 0;
149
150 static void pcaintr(struct intrframe *frame);
151
152 static  d_open_t        pcaopen;
153 static  d_close_t       pcaclose;
154 static  d_write_t       pcawrite;
155 static  d_ioctl_t       pcaioctl;
156 static  d_poll_t        pcapoll;
157
158 #define CDEV_MAJOR 24
159 static struct cdevsw pca_cdevsw = {
160         /* name */      "pca",
161         /* maj */       CDEV_MAJOR,
162         /* flags */     0,
163         /* port */      NULL,
164         /* clone */     NULL,
165
166         /* open */      pcaopen,
167         /* close */     pcaclose,
168         /* read */      noread,
169         /* write */     pcawrite,
170         /* ioctl */     pcaioctl,
171         /* poll */      pcapoll,
172         /* mmap */      nommap,
173         /* strategy */  nostrategy,
174         /* dump */      nodump,
175         /* psize */     nopsize
176 };
177
178 static void pca_continue (void);
179 static void pca_init (void);
180 static void pca_pause (void);
181
182 static void
183 conv(const unsigned char *table, unsigned char *buff, unsigned n)
184 {
185         unsigned i;
186
187         for (i = 0; i < n; i++)
188                 buff[i] = table[buff[i]];
189 }
190
191
192 static void
193 pca_volume(int volume)
194 {
195         int i, j;
196
197         for (i=0; i<256; i++) {
198                 j = ((i-128)*volume)/25;
199 /* XXX
200                 j = ((i-128)*volume)/100;
201 */
202                 if (j<-128)
203                         j = -128;
204                 if (j>127)
205                         j = 127;
206                 volume_table[i] = (((255-(j + 128))/4)+1);
207         }
208 }
209
210
211 static void
212 pca_init(void)
213 {
214         pca_status.open = 0;
215         pca_status.queries = 0;
216         pca_status.timer_on = 0;
217         pca_status.buf[0] = (unsigned char *)&buffer1[0];
218         pca_status.buf[1] = (unsigned char *)&buffer2[0];
219         pca_status.buf[2] = (unsigned char *)&buffer3[0];
220         pca_status.buffer = pca_status.buf[0];
221         pca_status.in_use[0] = pca_status.in_use[1] = pca_status.in_use[2] = 0;
222         pca_status.current = 0;
223         pca_status.sample_rate = SAMPLE_RATE;
224         pca_status.scale = (pca_status.sample_rate << 8) / INTERRUPT_RATE;
225         pca_status.encoding = AUDIO_ENCODING_ULAW;
226         pca_status.volume = 100;
227
228         pca_volume(pca_status.volume);
229 }
230
231
232 static int
233 pca_start(void)
234 {
235         int x = splhigh();
236         int rv = 0;
237
238         /* use the first buffer */
239         pca_status.current  = 0;
240         pca_status.index = 0;
241         pca_status.counter = 0;
242         pca_status.buffer  = pca_status.buf[pca_status.current];
243         pca_status.oldval = inb(IO_PPI) | 0x03;
244         /* acquire the timers */
245         if (acquire_timer2(TIMER_LSB|TIMER_ONESHOT))
246                 rv = -1;
247         else if (acquire_timer0(INTERRUPT_RATE, pcaintr)) {
248                 release_timer2();
249                 rv =  -1;
250         } else
251                 pca_status.timer_on = 1;
252
253         splx(x);
254         return rv;
255 }
256
257
258 static void
259 pca_stop(void)
260 {
261         int x = splhigh();
262
263         /* release the timers */
264         release_timer0();
265         release_timer2();
266         /* reset the buffer */
267         pca_status.in_use[0] = pca_status.in_use[1] = pca_status.in_use[2] = 0;
268         pca_status.index = 0;
269         pca_status.counter = 0;
270         pca_status.current = 0;
271         pca_status.buffer = pca_status.buf[pca_status.current];
272         pca_status.timer_on = 0;
273         splx(x);
274 }
275
276
277 static void
278 pca_pause(void)
279 {
280         int x = splhigh();
281
282         release_timer0();
283         release_timer2();
284         pca_status.timer_on = 0;
285         splx(x);
286 }
287
288
289 static void
290 pca_continue(void)
291 {
292         int x = splhigh();
293
294         pca_status.oldval = inb(IO_PPI) | 0x03;
295         acquire_timer2(TIMER_LSB|TIMER_ONESHOT);
296         acquire_timer0(INTERRUPT_RATE, pcaintr);
297         pca_status.timer_on = 1;
298         splx(x);
299 }
300
301
302 static int
303 pca_wait(void)
304 {
305         int error, x;
306
307         if (!pca_status.timer_on)
308                 return 0;
309
310         while (pca_status.in_use[0] || pca_status.in_use[1] ||
311             pca_status.in_use[2]) {
312                 x = spltty();
313                 pca_sleep = 1;
314                 error = tsleep(&pca_sleep, PCATCH, "pca_drain", 0);
315                 pca_sleep = 0;
316                 splx(x);
317                 if (error != 0 && error != ERESTART) {
318                         pca_stop();
319                         return error;
320                 }
321         }
322         return 0;
323 }
324
325
326 static struct isa_pnp_id pca_ids[] = {
327         {0x0008d041, "AT-style speaker sound"}, /* PNP0800 */
328         {0}
329 };
330
331 static int
332 pcaprobe(device_t dev)
333 {
334         int error;
335
336         /* Check isapnp ids */
337         error = ISA_PNP_PROBE(device_get_parent(dev), dev, pca_ids);
338         if (error == ENXIO)
339                 return ENXIO;
340         return 0;
341 }
342
343
344 static int
345 pcaattach(device_t dev)
346 {
347         pca_init();
348         make_dev(&pca_cdevsw, 0, 0, 0, 0600, "pcaudio");
349         make_dev(&pca_cdevsw, 128, 0, 0, 0600, "pcaudioctl");
350         return 0;
351 }
352
353 static device_method_t pca_methods[] = {
354         DEVMETHOD(device_probe,         pcaprobe),
355         DEVMETHOD(device_attach,        pcaattach),
356         { 0, 0 }
357 };
358
359 static driver_t pca_driver = {
360         "pca",
361         pca_methods,
362         1
363 };
364
365 static devclass_t pca_devclass;
366
367 DRIVER_MODULE(pca, isa, pca_driver, pca_devclass, 0, 0);
368
369
370 static int
371 pcaopen(dev_t dev, int flags, int fmt, struct thread *td)
372 {
373         /* audioctl device can always be opened */
374         if (minor(dev) == 128)
375                 return 0;
376         if (minor(dev) > 0)
377                 return ENXIO;
378
379         if (!pca_initialized) {
380                 pca_init();
381                 pca_initialized = 1;
382         }
383
384         /* audio device can only be open by one process */
385         if (pca_status.open) {
386                 pca_status.queries = 1;
387                 return EBUSY;
388         }
389         pca_status.buffer = pca_status.buf[0];
390         pca_status.in_use[0] = pca_status.in_use[1] = pca_status.in_use[2] = 0;
391         pca_status.timer_on = 0;
392         pca_status.open = 1;
393         pca_status.processed = 0;
394         return 0;
395 }
396
397
398 static int
399 pcaclose(dev_t dev, int flags, int fmt, struct thread *td)
400 {
401         /* audioctl device can always be closed */
402         if (minor(dev) == 128)
403                 return 0;
404         if (minor(dev) > 0)
405                 return ENXIO;
406         /* audio device close drains all output and restores timers */
407         pca_wait();
408         pca_stop();
409         pca_status.open = 0;
410         return 0;
411 }
412
413
414 static int
415 pcawrite(dev_t dev, struct uio *uio, int flag)
416 {
417         int count, error, which, x;
418
419         /* only audio device can be written */
420         if (minor(dev) > 0)
421                 return ENXIO;
422
423         while ((count = min(BUF_SIZE, uio->uio_resid)) > 0) {
424                 if (pca_status.in_use[0] && pca_status.in_use[1] &&
425                     pca_status.in_use[2]) {
426                         if (flag & IO_NDELAY)
427                                 return EWOULDBLOCK;
428                         x = spltty();
429                         pca_sleep = 1;
430                         error = tsleep(&pca_sleep, PCATCH, "pca_wait", 0);
431                         pca_sleep = 0;
432                         splx(x);
433                         if (error != 0 && error != ERESTART) {
434                                 pca_stop();
435                                 return error;
436                         }
437                 }
438                 if (!pca_status.in_use[0])
439                         which = 0;
440                 else if (!pca_status.in_use[1])
441                         which = 1;
442                 else
443                         which = 2;
444                 if (count && !pca_status.in_use[which]) {
445                         uiomove(pca_status.buf[which], count, uio);
446                         pca_status.processed += count;
447                         switch (pca_status.encoding) {
448                         case AUDIO_ENCODING_ULAW:
449                                 conv(ulaw_dsp, pca_status.buf[which], count);
450                                 break;
451
452                         case AUDIO_ENCODING_ALAW:
453                                 conv(alaw_linear, pca_status.buf[which], count);
454                                 break;
455
456                         case AUDIO_ENCODING_RAW:
457                                 break;
458                         }
459                         pca_status.in_use[which] = count;
460                         if (!pca_status.timer_on)
461                                 if (pca_start())
462                                         return EBUSY;
463                 }
464         }
465         return 0;
466 }
467
468
469 static int
470 pcaioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
471 {
472         audio_info_t *auptr;
473
474         switch(cmd) {
475
476         case AUDIO_GETINFO:
477                 auptr = (audio_info_t *)data;
478                 auptr->play.sample_rate = pca_status.sample_rate;
479                 auptr->play.channels = 1;
480                 auptr->play.precision = 8;
481                 auptr->play.encoding = pca_status.encoding;
482
483                 auptr->play.gain = pca_status.volume;
484                 auptr->play.port = 0;
485
486                 auptr->play.samples = pca_status.processed;
487                 auptr->play.eof = 0;
488                 auptr->play.pause = !pca_status.timer_on;
489                 auptr->play.error = 0;
490                 auptr->play.waiting = pca_status.queries;
491
492                 auptr->play.open = pca_status.open;
493                 auptr->play.active = pca_status.timer_on;
494                 return 0;
495
496         case AUDIO_SETINFO:
497                 auptr = (audio_info_t *)data;
498                 if (auptr->play.sample_rate != (unsigned int)~0) {
499                         pca_status.sample_rate = auptr->play.sample_rate;
500                         pca_status.scale =
501                                 (pca_status.sample_rate << 8) / INTERRUPT_RATE;
502                 }
503                 if (auptr->play.encoding != (unsigned int)~0) {
504                         pca_status.encoding = auptr->play.encoding;
505                 }
506                 if (auptr->play.gain != (unsigned int)~0) {
507                         pca_status.volume = auptr->play.gain;
508                         pca_volume(pca_status.volume);
509                 }
510                 if (auptr->play.pause != (unsigned char)~0) {
511                         if (auptr->play.pause)
512                                 pca_pause();
513                         else
514                                 pca_continue();
515                 }
516
517                 return 0;
518
519         case AUDIO_DRAIN:
520         case AUDIO_COMPAT_DRAIN:
521                 return pca_wait();
522
523         case AUDIO_FLUSH:
524         case AUDIO_COMPAT_FLUSH:
525                 pca_stop();
526                 return 0;
527         case FIONBIO:
528                 return 0;
529         }
530         return ENXIO;
531 }
532
533
534 static void
535 pcaintr(struct intrframe *frame)
536 {
537         if (pca_status.index < pca_status.in_use[pca_status.current]) {
538                 cpu_disable_intr();
539                 __asm__("outb %0,$0x61\n"
540                         "andb $0xFE,%0\n"
541                         "outb %0,$0x61"
542                         : : "a" ((char)pca_status.oldval) );
543                 __asm__("xlatb\n"
544                         "outb %0,$0x42"
545                         : : "a" ((char)pca_status.buffer[pca_status.index]),
546                             "b" (volume_table) );
547                 cpu_enable_intr();
548                 pca_status.counter += pca_status.scale;
549                 pca_status.index = (pca_status.counter >> 8);
550         }
551         if (pca_status.index >= pca_status.in_use[pca_status.current]) {
552                 pca_status.index = pca_status.counter = 0;
553                 pca_status.in_use[pca_status.current] = 0;
554                 pca_status.current++;
555                 if (pca_status.current > 2)
556                         pca_status.current = 0;
557                 pca_status.buffer = pca_status.buf[pca_status.current];
558                 if (pca_sleep)
559                         wakeup(&pca_sleep);
560                 if (pca_status.wsel.si_pid) {
561                         selwakeup((struct selinfo *)&pca_status.wsel.si_pid);
562                         pca_status.wsel.si_pid = 0;
563                         pca_status.wsel.si_flags = 0;
564                 }
565         }
566 }
567
568
569 static int
570 pcapoll(dev_t dev, int events, struct thread *td)
571 {
572         int s;
573         struct proc *p;
574         struct proc *p1;
575         int revents = 0;
576
577         p = td->td_proc;
578         KKASSERT(p);
579
580         s = spltty();
581
582         if (events & (POLLOUT | POLLWRNORM)) {
583                 if (!pca_status.in_use[0] || !pca_status.in_use[1] ||
584                     !pca_status.in_use[2])
585                         revents |= events & (POLLOUT | POLLWRNORM);
586                 else {
587                         if (pca_status.wsel.si_pid &&
588                             (p1=pfind(pca_status.wsel.si_pid))
589                             && p1->p_wchan == (caddr_t)&selwait)
590                                 pca_status.wsel.si_flags = SI_COLL;
591                         else
592                                 pca_status.wsel.si_pid = p->p_pid;
593                 }
594         }
595         splx(s);
596         return (revents);
597 }