Device layer rollup commit.
[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.10 2004/05/19 22:52:50 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         cdevsw_add(&pca_cdevsw, 0, 0);
349         make_dev(&pca_cdevsw, 0, 0, 0, 0600, "pcaudio");
350         make_dev(&pca_cdevsw, 128, 0, 0, 0600, "pcaudioctl");
351         return 0;
352 }
353
354 static device_method_t pca_methods[] = {
355         DEVMETHOD(device_probe,         pcaprobe),
356         DEVMETHOD(device_attach,        pcaattach),
357         { 0, 0 }
358 };
359
360 static driver_t pca_driver = {
361         "pca",
362         pca_methods,
363         1
364 };
365
366 static devclass_t pca_devclass;
367
368 DRIVER_MODULE(pca, isa, pca_driver, pca_devclass, 0, 0);
369
370
371 static int
372 pcaopen(dev_t dev, int flags, int fmt, struct thread *td)
373 {
374         /* audioctl device can always be opened */
375         if (minor(dev) == 128)
376                 return 0;
377         if (minor(dev) > 0)
378                 return ENXIO;
379
380         if (!pca_initialized) {
381                 pca_init();
382                 pca_initialized = 1;
383         }
384
385         /* audio device can only be open by one process */
386         if (pca_status.open) {
387                 pca_status.queries = 1;
388                 return EBUSY;
389         }
390         pca_status.buffer = pca_status.buf[0];
391         pca_status.in_use[0] = pca_status.in_use[1] = pca_status.in_use[2] = 0;
392         pca_status.timer_on = 0;
393         pca_status.open = 1;
394         pca_status.processed = 0;
395         return 0;
396 }
397
398
399 static int
400 pcaclose(dev_t dev, int flags, int fmt, struct thread *td)
401 {
402         /* audioctl device can always be closed */
403         if (minor(dev) == 128)
404                 return 0;
405         if (minor(dev) > 0)
406                 return ENXIO;
407         /* audio device close drains all output and restores timers */
408         pca_wait();
409         pca_stop();
410         pca_status.open = 0;
411         return 0;
412 }
413
414
415 static int
416 pcawrite(dev_t dev, struct uio *uio, int flag)
417 {
418         int count, error, which, x;
419
420         /* only audio device can be written */
421         if (minor(dev) > 0)
422                 return ENXIO;
423
424         while ((count = min(BUF_SIZE, uio->uio_resid)) > 0) {
425                 if (pca_status.in_use[0] && pca_status.in_use[1] &&
426                     pca_status.in_use[2]) {
427                         if (flag & IO_NDELAY)
428                                 return EWOULDBLOCK;
429                         x = spltty();
430                         pca_sleep = 1;
431                         error = tsleep(&pca_sleep, PCATCH, "pca_wait", 0);
432                         pca_sleep = 0;
433                         splx(x);
434                         if (error != 0 && error != ERESTART) {
435                                 pca_stop();
436                                 return error;
437                         }
438                 }
439                 if (!pca_status.in_use[0])
440                         which = 0;
441                 else if (!pca_status.in_use[1])
442                         which = 1;
443                 else
444                         which = 2;
445                 if (count && !pca_status.in_use[which]) {
446                         uiomove(pca_status.buf[which], count, uio);
447                         pca_status.processed += count;
448                         switch (pca_status.encoding) {
449                         case AUDIO_ENCODING_ULAW:
450                                 conv(ulaw_dsp, pca_status.buf[which], count);
451                                 break;
452
453                         case AUDIO_ENCODING_ALAW:
454                                 conv(alaw_linear, pca_status.buf[which], count);
455                                 break;
456
457                         case AUDIO_ENCODING_RAW:
458                                 break;
459                         }
460                         pca_status.in_use[which] = count;
461                         if (!pca_status.timer_on)
462                                 if (pca_start())
463                                         return EBUSY;
464                 }
465         }
466         return 0;
467 }
468
469
470 static int
471 pcaioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
472 {
473         audio_info_t *auptr;
474
475         switch(cmd) {
476
477         case AUDIO_GETINFO:
478                 auptr = (audio_info_t *)data;
479                 auptr->play.sample_rate = pca_status.sample_rate;
480                 auptr->play.channels = 1;
481                 auptr->play.precision = 8;
482                 auptr->play.encoding = pca_status.encoding;
483
484                 auptr->play.gain = pca_status.volume;
485                 auptr->play.port = 0;
486
487                 auptr->play.samples = pca_status.processed;
488                 auptr->play.eof = 0;
489                 auptr->play.pause = !pca_status.timer_on;
490                 auptr->play.error = 0;
491                 auptr->play.waiting = pca_status.queries;
492
493                 auptr->play.open = pca_status.open;
494                 auptr->play.active = pca_status.timer_on;
495                 return 0;
496
497         case AUDIO_SETINFO:
498                 auptr = (audio_info_t *)data;
499                 if (auptr->play.sample_rate != (unsigned int)~0) {
500                         pca_status.sample_rate = auptr->play.sample_rate;
501                         pca_status.scale =
502                                 (pca_status.sample_rate << 8) / INTERRUPT_RATE;
503                 }
504                 if (auptr->play.encoding != (unsigned int)~0) {
505                         pca_status.encoding = auptr->play.encoding;
506                 }
507                 if (auptr->play.gain != (unsigned int)~0) {
508                         pca_status.volume = auptr->play.gain;
509                         pca_volume(pca_status.volume);
510                 }
511                 if (auptr->play.pause != (unsigned char)~0) {
512                         if (auptr->play.pause)
513                                 pca_pause();
514                         else
515                                 pca_continue();
516                 }
517
518                 return 0;
519
520         case AUDIO_DRAIN:
521         case AUDIO_COMPAT_DRAIN:
522                 return pca_wait();
523
524         case AUDIO_FLUSH:
525         case AUDIO_COMPAT_FLUSH:
526                 pca_stop();
527                 return 0;
528         case FIONBIO:
529                 return 0;
530         }
531         return ENXIO;
532 }
533
534
535 static void
536 pcaintr(struct intrframe *frame)
537 {
538         if (pca_status.index < pca_status.in_use[pca_status.current]) {
539                 cpu_disable_intr();
540                 __asm__("outb %0,$0x61\n"
541                         "andb $0xFE,%0\n"
542                         "outb %0,$0x61"
543                         : : "a" ((char)pca_status.oldval) );
544                 __asm__("xlatb\n"
545                         "outb %0,$0x42"
546                         : : "a" ((char)pca_status.buffer[pca_status.index]),
547                             "b" (volume_table) );
548                 cpu_enable_intr();
549                 pca_status.counter += pca_status.scale;
550                 pca_status.index = (pca_status.counter >> 8);
551         }
552         if (pca_status.index >= pca_status.in_use[pca_status.current]) {
553                 pca_status.index = pca_status.counter = 0;
554                 pca_status.in_use[pca_status.current] = 0;
555                 pca_status.current++;
556                 if (pca_status.current > 2)
557                         pca_status.current = 0;
558                 pca_status.buffer = pca_status.buf[pca_status.current];
559                 if (pca_sleep)
560                         wakeup(&pca_sleep);
561                 if (pca_status.wsel.si_pid) {
562                         selwakeup((struct selinfo *)&pca_status.wsel.si_pid);
563                         pca_status.wsel.si_pid = 0;
564                         pca_status.wsel.si_flags = 0;
565                 }
566         }
567 }
568
569
570 static int
571 pcapoll(dev_t dev, int events, struct thread *td)
572 {
573         int s;
574         struct proc *p;
575         struct proc *p1;
576         int revents = 0;
577
578         p = td->td_proc;
579         KKASSERT(p);
580
581         s = spltty();
582
583         if (events & (POLLOUT | POLLWRNORM)) {
584                 if (!pca_status.in_use[0] || !pca_status.in_use[1] ||
585                     !pca_status.in_use[2])
586                         revents |= events & (POLLOUT | POLLWRNORM);
587                 else {
588                         if (pca_status.wsel.si_pid &&
589                             (p1=pfind(pca_status.wsel.si_pid))
590                             && p1->p_wchan == (caddr_t)&selwait)
591                                 pca_status.wsel.si_flags = SI_COLL;
592                         else
593                                 pca_status.wsel.si_pid = p->p_pid;
594                 }
595         }
596         splx(s);
597         return (revents);
598 }