Make doubly sure that timer2 is not used for speaker operation.
[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.11 2004/08/02 23:20:29 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         return(-1);
236 #if 0
237         int x = splhigh();
238         int rv = 0;
239
240         /* use the first buffer */
241         pca_status.current  = 0;
242         pca_status.index = 0;
243         pca_status.counter = 0;
244         pca_status.buffer  = pca_status.buf[pca_status.current];
245         pca_status.oldval = inb(IO_PPI) | 0x03;
246         /* acquire the timers */
247         if (acquire_timer2(TIMER_LSB|TIMER_ONESHOT))
248                 rv = -1;
249         else if (acquire_timer0(INTERRUPT_RATE, pcaintr)) {
250                 release_timer2();
251                 rv =  -1;
252         } else
253                 pca_status.timer_on = 1;
254
255         splx(x);
256         return rv;
257 #endif
258 }
259
260
261 static void
262 pca_stop(void)
263 {
264 #if 0
265         int x = splhigh();
266
267         /* release the timers */
268         release_timer0();
269         release_timer2();
270         /* reset the buffer */
271         pca_status.in_use[0] = pca_status.in_use[1] = pca_status.in_use[2] = 0;
272         pca_status.index = 0;
273         pca_status.counter = 0;
274         pca_status.current = 0;
275         pca_status.buffer = pca_status.buf[pca_status.current];
276         pca_status.timer_on = 0;
277         splx(x);
278 #endif
279 }
280
281
282 static void
283 pca_pause(void)
284 {
285 #if 0
286         int x = splhigh();
287
288         release_timer0();
289         release_timer2();
290         pca_status.timer_on = 0;
291         splx(x);
292 #endif
293 }
294
295
296 static void
297 pca_continue(void)
298 {
299 #if 0
300         int x = splhigh();
301
302         pca_status.oldval = inb(IO_PPI) | 0x03;
303         acquire_timer2(TIMER_LSB|TIMER_ONESHOT);
304         acquire_timer0(INTERRUPT_RATE, pcaintr);
305         pca_status.timer_on = 1;
306         splx(x);
307 #endif
308 }
309
310
311 static int
312 pca_wait(void)
313 {
314         int error, x;
315
316         if (!pca_status.timer_on)
317                 return 0;
318
319         while (pca_status.in_use[0] || pca_status.in_use[1] ||
320             pca_status.in_use[2]) {
321                 x = spltty();
322                 pca_sleep = 1;
323                 error = tsleep(&pca_sleep, PCATCH, "pca_drain", 0);
324                 pca_sleep = 0;
325                 splx(x);
326                 if (error != 0 && error != ERESTART) {
327                         pca_stop();
328                         return error;
329                 }
330         }
331         return 0;
332 }
333
334
335 static struct isa_pnp_id pca_ids[] = {
336         {0x0008d041, "AT-style speaker sound"}, /* PNP0800 */
337         {0}
338 };
339
340 static int
341 pcaprobe(device_t dev)
342 {
343         int error;
344
345         /* Check isapnp ids */
346         error = ISA_PNP_PROBE(device_get_parent(dev), dev, pca_ids);
347         if (error == ENXIO)
348                 return ENXIO;
349         return 0;
350 }
351
352
353 static int
354 pcaattach(device_t dev)
355 {
356         pca_init();
357         cdevsw_add(&pca_cdevsw, 0, 0);
358         make_dev(&pca_cdevsw, 0, 0, 0, 0600, "pcaudio");
359         make_dev(&pca_cdevsw, 128, 0, 0, 0600, "pcaudioctl");
360         return 0;
361 }
362
363 static device_method_t pca_methods[] = {
364         DEVMETHOD(device_probe,         pcaprobe),
365         DEVMETHOD(device_attach,        pcaattach),
366         { 0, 0 }
367 };
368
369 static driver_t pca_driver = {
370         "pca",
371         pca_methods,
372         1
373 };
374
375 static devclass_t pca_devclass;
376
377 DRIVER_MODULE(pca, isa, pca_driver, pca_devclass, 0, 0);
378
379
380 static int
381 pcaopen(dev_t dev, int flags, int fmt, struct thread *td)
382 {
383         /* audioctl device can always be opened */
384         if (minor(dev) == 128)
385                 return 0;
386         if (minor(dev) > 0)
387                 return ENXIO;
388
389         if (!pca_initialized) {
390                 pca_init();
391                 pca_initialized = 1;
392         }
393
394         /* audio device can only be open by one process */
395         if (pca_status.open) {
396                 pca_status.queries = 1;
397                 return EBUSY;
398         }
399         pca_status.buffer = pca_status.buf[0];
400         pca_status.in_use[0] = pca_status.in_use[1] = pca_status.in_use[2] = 0;
401         pca_status.timer_on = 0;
402         pca_status.open = 1;
403         pca_status.processed = 0;
404         return 0;
405 }
406
407
408 static int
409 pcaclose(dev_t dev, int flags, int fmt, struct thread *td)
410 {
411         /* audioctl device can always be closed */
412         if (minor(dev) == 128)
413                 return 0;
414         if (minor(dev) > 0)
415                 return ENXIO;
416         /* audio device close drains all output and restores timers */
417         pca_wait();
418         pca_stop();
419         pca_status.open = 0;
420         return 0;
421 }
422
423
424 static int
425 pcawrite(dev_t dev, struct uio *uio, int flag)
426 {
427         int count, error, which, x;
428
429         /* only audio device can be written */
430         if (minor(dev) > 0)
431                 return ENXIO;
432
433         while ((count = min(BUF_SIZE, uio->uio_resid)) > 0) {
434                 if (pca_status.in_use[0] && pca_status.in_use[1] &&
435                     pca_status.in_use[2]) {
436                         if (flag & IO_NDELAY)
437                                 return EWOULDBLOCK;
438                         x = spltty();
439                         pca_sleep = 1;
440                         error = tsleep(&pca_sleep, PCATCH, "pca_wait", 0);
441                         pca_sleep = 0;
442                         splx(x);
443                         if (error != 0 && error != ERESTART) {
444                                 pca_stop();
445                                 return error;
446                         }
447                 }
448                 if (!pca_status.in_use[0])
449                         which = 0;
450                 else if (!pca_status.in_use[1])
451                         which = 1;
452                 else
453                         which = 2;
454                 if (count && !pca_status.in_use[which]) {
455                         uiomove(pca_status.buf[which], count, uio);
456                         pca_status.processed += count;
457                         switch (pca_status.encoding) {
458                         case AUDIO_ENCODING_ULAW:
459                                 conv(ulaw_dsp, pca_status.buf[which], count);
460                                 break;
461
462                         case AUDIO_ENCODING_ALAW:
463                                 conv(alaw_linear, pca_status.buf[which], count);
464                                 break;
465
466                         case AUDIO_ENCODING_RAW:
467                                 break;
468                         }
469                         pca_status.in_use[which] = count;
470                         if (!pca_status.timer_on)
471                                 if (pca_start())
472                                         return EBUSY;
473                 }
474         }
475         return 0;
476 }
477
478
479 static int
480 pcaioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
481 {
482         audio_info_t *auptr;
483
484         switch(cmd) {
485
486         case AUDIO_GETINFO:
487                 auptr = (audio_info_t *)data;
488                 auptr->play.sample_rate = pca_status.sample_rate;
489                 auptr->play.channels = 1;
490                 auptr->play.precision = 8;
491                 auptr->play.encoding = pca_status.encoding;
492
493                 auptr->play.gain = pca_status.volume;
494                 auptr->play.port = 0;
495
496                 auptr->play.samples = pca_status.processed;
497                 auptr->play.eof = 0;
498                 auptr->play.pause = !pca_status.timer_on;
499                 auptr->play.error = 0;
500                 auptr->play.waiting = pca_status.queries;
501
502                 auptr->play.open = pca_status.open;
503                 auptr->play.active = pca_status.timer_on;
504                 return 0;
505
506         case AUDIO_SETINFO:
507                 auptr = (audio_info_t *)data;
508                 if (auptr->play.sample_rate != (unsigned int)~0) {
509                         pca_status.sample_rate = auptr->play.sample_rate;
510                         pca_status.scale =
511                                 (pca_status.sample_rate << 8) / INTERRUPT_RATE;
512                 }
513                 if (auptr->play.encoding != (unsigned int)~0) {
514                         pca_status.encoding = auptr->play.encoding;
515                 }
516                 if (auptr->play.gain != (unsigned int)~0) {
517                         pca_status.volume = auptr->play.gain;
518                         pca_volume(pca_status.volume);
519                 }
520                 if (auptr->play.pause != (unsigned char)~0) {
521                         if (auptr->play.pause)
522                                 pca_pause();
523                         else
524                                 pca_continue();
525                 }
526
527                 return 0;
528
529         case AUDIO_DRAIN:
530         case AUDIO_COMPAT_DRAIN:
531                 return pca_wait();
532
533         case AUDIO_FLUSH:
534         case AUDIO_COMPAT_FLUSH:
535                 pca_stop();
536                 return 0;
537         case FIONBIO:
538                 return 0;
539         }
540         return ENXIO;
541 }
542
543
544 static void
545 pcaintr(struct intrframe *frame)
546 {
547         if (pca_status.index < pca_status.in_use[pca_status.current]) {
548                 cpu_disable_intr();
549                 __asm__("outb %0,$0x61\n"
550                         "andb $0xFE,%0\n"
551                         "outb %0,$0x61"
552                         : : "a" ((char)pca_status.oldval) );
553                 __asm__("xlatb\n"
554                         "outb %0,$0x42"
555                         : : "a" ((char)pca_status.buffer[pca_status.index]),
556                             "b" (volume_table) );
557                 cpu_enable_intr();
558                 pca_status.counter += pca_status.scale;
559                 pca_status.index = (pca_status.counter >> 8);
560         }
561         if (pca_status.index >= pca_status.in_use[pca_status.current]) {
562                 pca_status.index = pca_status.counter = 0;
563                 pca_status.in_use[pca_status.current] = 0;
564                 pca_status.current++;
565                 if (pca_status.current > 2)
566                         pca_status.current = 0;
567                 pca_status.buffer = pca_status.buf[pca_status.current];
568                 if (pca_sleep)
569                         wakeup(&pca_sleep);
570                 if (pca_status.wsel.si_pid) {
571                         selwakeup((struct selinfo *)&pca_status.wsel.si_pid);
572                         pca_status.wsel.si_pid = 0;
573                         pca_status.wsel.si_flags = 0;
574                 }
575         }
576 }
577
578
579 static int
580 pcapoll(dev_t dev, int events, struct thread *td)
581 {
582         int s;
583         struct proc *p;
584         struct proc *p1;
585         int revents = 0;
586
587         p = td->td_proc;
588         KKASSERT(p);
589
590         s = spltty();
591
592         if (events & (POLLOUT | POLLWRNORM)) {
593                 if (!pca_status.in_use[0] || !pca_status.in_use[1] ||
594                     !pca_status.in_use[2])
595                         revents |= events & (POLLOUT | POLLWRNORM);
596                 else {
597                         if (pca_status.wsel.si_pid &&
598                             (p1=pfind(pca_status.wsel.si_pid))
599                             && p1->p_wchan == (caddr_t)&selwait)
600                                 pca_status.wsel.si_flags = SI_COLL;
601                         else
602                                 pca_status.wsel.si_pid = p->p_pid;
603                 }
604         }
605         splx(s);
606         return (revents);
607 }