2 * Copyright (c) 1994-1998 Søren Schmidt
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
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.6 2003/08/07 21:17:12 dillon Exp $
32 #include <sys/param.h>
33 #include <sys/systm.h>
36 #include <sys/kernel.h>
38 #include <sys/filio.h>
40 #include <sys/vnode.h>
42 #include <machine/clock.h>
43 #include <machine/pcaudioio.h>
45 #include <bus/isa/isareg.h>
46 #include <bus/isa/isavar.h>
47 #include <i386/isa/timerreg.h>
50 #define SAMPLE_RATE 8000
51 #define INTERRUPT_RATE 16000
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 */
72 static char buffer1[BUF_SIZE];
73 static char buffer2[BUF_SIZE];
74 static char buffer3[BUF_SIZE];
75 static char volume_table[256];
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,
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,
147 static int pca_sleep = 0;
148 static int pca_initialized = 0;
150 static void pcaintr(struct clockframe *frame);
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;
158 #define CDEV_MAJOR 24
159 static struct cdevsw pca_cdevsw = {
161 /* maj */ CDEV_MAJOR,
167 /* close */ pcaclose,
169 /* write */ pcawrite,
170 /* ioctl */ pcaioctl,
173 /* strategy */ nostrategy,
178 static void pca_continue __P((void));
179 static void pca_init __P((void));
180 static void pca_pause __P((void));
183 conv(const unsigned char *table, unsigned char *buff, unsigned n)
187 for (i = 0; i < n; i++)
188 buff[i] = table[buff[i]];
193 pca_volume(int volume)
197 for (i=0; i<256; i++) {
198 j = ((i-128)*volume)/25;
200 j = ((i-128)*volume)/100;
206 volume_table[i] = (((255-(j + 128))/4)+1);
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;
228 pca_volume(pca_status.volume);
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))
247 else if (acquire_timer0(INTERRUPT_RATE, pcaintr)) {
251 pca_status.timer_on = 1;
263 /* release the timers */
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;
284 pca_status.timer_on = 0;
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;
307 if (!pca_status.timer_on)
310 while (pca_status.in_use[0] || pca_status.in_use[1] ||
311 pca_status.in_use[2]) {
314 error = tsleep(&pca_sleep, PCATCH, "pca_drain", 0);
317 if (error != 0 && error != ERESTART) {
326 static struct isa_pnp_id pca_ids[] = {
327 {0x0008d041, "AT-style speaker sound"}, /* PNP0800 */
332 pcaprobe(device_t dev)
336 /* Check isapnp ids */
337 error = ISA_PNP_PROBE(device_get_parent(dev), dev, pca_ids);
345 pcaattach(device_t dev)
348 make_dev(&pca_cdevsw, 0, 0, 0, 0600, "pcaudio");
349 make_dev(&pca_cdevsw, 128, 0, 0, 0600, "pcaudioctl");
353 static device_method_t pca_methods[] = {
354 DEVMETHOD(device_probe, pcaprobe),
355 DEVMETHOD(device_attach, pcaattach),
359 static driver_t pca_driver = {
365 static devclass_t pca_devclass;
367 DRIVER_MODULE(pca, isa, pca_driver, pca_devclass, 0, 0);
371 pcaopen(dev_t dev, int flags, int fmt, struct thread *td)
373 /* audioctl device can always be opened */
374 if (minor(dev) == 128)
379 if (!pca_initialized) {
384 /* audio device can only be open by one process */
385 if (pca_status.open) {
386 pca_status.queries = 1;
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;
393 pca_status.processed = 0;
399 pcaclose(dev_t dev, int flags, int fmt, struct thread *td)
401 /* audioctl device can always be closed */
402 if (minor(dev) == 128)
406 /* audio device close drains all output and restores timers */
415 pcawrite(dev_t dev, struct uio *uio, int flag)
417 int count, error, which, x;
419 /* only audio device can be written */
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)
430 error = tsleep(&pca_sleep, PCATCH, "pca_wait", 0);
433 if (error != 0 && error != ERESTART) {
438 if (!pca_status.in_use[0])
440 else if (!pca_status.in_use[1])
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);
452 case AUDIO_ENCODING_ALAW:
453 conv(alaw_linear, pca_status.buf[which], count);
456 case AUDIO_ENCODING_RAW:
459 pca_status.in_use[which] = count;
460 if (!pca_status.timer_on)
470 pcaioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
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;
483 auptr->play.gain = pca_status.volume;
484 auptr->play.port = 0;
486 auptr->play.samples = pca_status.processed;
488 auptr->play.pause = !pca_status.timer_on;
489 auptr->play.error = 0;
490 auptr->play.waiting = pca_status.queries;
492 auptr->play.open = pca_status.open;
493 auptr->play.active = pca_status.timer_on;
497 auptr = (audio_info_t *)data;
498 if (auptr->play.sample_rate != (unsigned int)~0) {
499 pca_status.sample_rate = auptr->play.sample_rate;
501 (pca_status.sample_rate << 8) / INTERRUPT_RATE;
503 if (auptr->play.encoding != (unsigned int)~0) {
504 pca_status.encoding = auptr->play.encoding;
506 if (auptr->play.gain != (unsigned int)~0) {
507 pca_status.volume = auptr->play.gain;
508 pca_volume(pca_status.volume);
510 if (auptr->play.pause != (unsigned char)~0) {
511 if (auptr->play.pause)
520 case AUDIO_COMPAT_DRAIN:
524 case AUDIO_COMPAT_FLUSH:
535 pcaintr(struct clockframe *frame)
537 if (pca_status.index < pca_status.in_use[pca_status.current]) {
539 __asm__("outb %0,$0x61\n"
542 : : "a" ((char)pca_status.oldval) );
545 : : "a" ((char)pca_status.buffer[pca_status.index]),
546 "b" (volume_table) );
548 pca_status.counter += pca_status.scale;
549 pca_status.index = (pca_status.counter >> 8);
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];
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;
570 pcapoll(dev_t dev, int events, struct thread *td)
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);
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;
592 pca_status.wsel.si_pid = p->p_pid;