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.2 2003/06/17 04:28:37 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 <isa/isareg.h>
46 #include <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 /* close */ pcaclose,
163 /* write */ pcawrite,
164 /* ioctl */ pcaioctl,
167 /* strategy */ nostrategy,
169 /* maj */ CDEV_MAJOR,
176 static void pca_continue __P((void));
177 static void pca_init __P((void));
178 static void pca_pause __P((void));
181 conv(const unsigned char *table, unsigned char *buff, unsigned n)
185 for (i = 0; i < n; i++)
186 buff[i] = table[buff[i]];
191 pca_volume(int volume)
195 for (i=0; i<256; i++) {
196 j = ((i-128)*volume)/25;
198 j = ((i-128)*volume)/100;
204 volume_table[i] = (((255-(j + 128))/4)+1);
213 pca_status.queries = 0;
214 pca_status.timer_on = 0;
215 pca_status.buf[0] = (unsigned char *)&buffer1[0];
216 pca_status.buf[1] = (unsigned char *)&buffer2[0];
217 pca_status.buf[2] = (unsigned char *)&buffer3[0];
218 pca_status.buffer = pca_status.buf[0];
219 pca_status.in_use[0] = pca_status.in_use[1] = pca_status.in_use[2] = 0;
220 pca_status.current = 0;
221 pca_status.sample_rate = SAMPLE_RATE;
222 pca_status.scale = (pca_status.sample_rate << 8) / INTERRUPT_RATE;
223 pca_status.encoding = AUDIO_ENCODING_ULAW;
224 pca_status.volume = 100;
226 pca_volume(pca_status.volume);
236 /* use the first buffer */
237 pca_status.current = 0;
238 pca_status.index = 0;
239 pca_status.counter = 0;
240 pca_status.buffer = pca_status.buf[pca_status.current];
241 pca_status.oldval = inb(IO_PPI) | 0x03;
242 /* acquire the timers */
243 if (acquire_timer2(TIMER_LSB|TIMER_ONESHOT))
245 else if (acquire_timer0(INTERRUPT_RATE, pcaintr)) {
249 pca_status.timer_on = 1;
261 /* release the timers */
264 /* reset the buffer */
265 pca_status.in_use[0] = pca_status.in_use[1] = pca_status.in_use[2] = 0;
266 pca_status.index = 0;
267 pca_status.counter = 0;
268 pca_status.current = 0;
269 pca_status.buffer = pca_status.buf[pca_status.current];
270 pca_status.timer_on = 0;
282 pca_status.timer_on = 0;
292 pca_status.oldval = inb(IO_PPI) | 0x03;
293 acquire_timer2(TIMER_LSB|TIMER_ONESHOT);
294 acquire_timer0(INTERRUPT_RATE, pcaintr);
295 pca_status.timer_on = 1;
305 if (!pca_status.timer_on)
308 while (pca_status.in_use[0] || pca_status.in_use[1] ||
309 pca_status.in_use[2]) {
312 error = tsleep(&pca_sleep, PZERO|PCATCH, "pca_drain", 0);
315 if (error != 0 && error != ERESTART) {
324 static struct isa_pnp_id pca_ids[] = {
325 {0x0008d041, "AT-style speaker sound"}, /* PNP0800 */
330 pcaprobe(device_t dev)
334 /* Check isapnp ids */
335 error = ISA_PNP_PROBE(device_get_parent(dev), dev, pca_ids);
343 pcaattach(device_t dev)
346 make_dev(&pca_cdevsw, 0, 0, 0, 0600, "pcaudio");
347 make_dev(&pca_cdevsw, 128, 0, 0, 0600, "pcaudioctl");
351 static device_method_t pca_methods[] = {
352 DEVMETHOD(device_probe, pcaprobe),
353 DEVMETHOD(device_attach, pcaattach),
357 static driver_t pca_driver = {
363 static devclass_t pca_devclass;
365 DRIVER_MODULE(pca, isa, pca_driver, pca_devclass, 0, 0);
369 pcaopen(dev_t dev, int flags, int fmt, struct proc *p)
371 /* audioctl device can always be opened */
372 if (minor(dev) == 128)
377 if (!pca_initialized) {
382 /* audio device can only be open by one process */
383 if (pca_status.open) {
384 pca_status.queries = 1;
387 pca_status.buffer = pca_status.buf[0];
388 pca_status.in_use[0] = pca_status.in_use[1] = pca_status.in_use[2] = 0;
389 pca_status.timer_on = 0;
391 pca_status.processed = 0;
397 pcaclose(dev_t dev, int flags, int fmt, struct proc *p)
399 /* audioctl device can always be closed */
400 if (minor(dev) == 128)
404 /* audio device close drains all output and restores timers */
413 pcawrite(dev_t dev, struct uio *uio, int flag)
415 int count, error, which, x;
417 /* only audio device can be written */
421 while ((count = min(BUF_SIZE, uio->uio_resid)) > 0) {
422 if (pca_status.in_use[0] && pca_status.in_use[1] &&
423 pca_status.in_use[2]) {
424 if (flag & IO_NDELAY)
428 error = tsleep(&pca_sleep, PZERO|PCATCH, "pca_wait", 0);
431 if (error != 0 && error != ERESTART) {
436 if (!pca_status.in_use[0])
438 else if (!pca_status.in_use[1])
442 if (count && !pca_status.in_use[which]) {
443 uiomove(pca_status.buf[which], count, uio);
444 pca_status.processed += count;
445 switch (pca_status.encoding) {
446 case AUDIO_ENCODING_ULAW:
447 conv(ulaw_dsp, pca_status.buf[which], count);
450 case AUDIO_ENCODING_ALAW:
451 conv(alaw_linear, pca_status.buf[which], count);
454 case AUDIO_ENCODING_RAW:
457 pca_status.in_use[which] = count;
458 if (!pca_status.timer_on)
468 pcaioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
475 auptr = (audio_info_t *)data;
476 auptr->play.sample_rate = pca_status.sample_rate;
477 auptr->play.channels = 1;
478 auptr->play.precision = 8;
479 auptr->play.encoding = pca_status.encoding;
481 auptr->play.gain = pca_status.volume;
482 auptr->play.port = 0;
484 auptr->play.samples = pca_status.processed;
486 auptr->play.pause = !pca_status.timer_on;
487 auptr->play.error = 0;
488 auptr->play.waiting = pca_status.queries;
490 auptr->play.open = pca_status.open;
491 auptr->play.active = pca_status.timer_on;
495 auptr = (audio_info_t *)data;
496 if (auptr->play.sample_rate != (unsigned int)~0) {
497 pca_status.sample_rate = auptr->play.sample_rate;
499 (pca_status.sample_rate << 8) / INTERRUPT_RATE;
501 if (auptr->play.encoding != (unsigned int)~0) {
502 pca_status.encoding = auptr->play.encoding;
504 if (auptr->play.gain != (unsigned int)~0) {
505 pca_status.volume = auptr->play.gain;
506 pca_volume(pca_status.volume);
508 if (auptr->play.pause != (unsigned char)~0) {
509 if (auptr->play.pause)
518 case AUDIO_COMPAT_DRAIN:
522 case AUDIO_COMPAT_FLUSH:
533 pcaintr(struct clockframe *frame)
535 if (pca_status.index < pca_status.in_use[pca_status.current]) {
537 __asm__("outb %0,$0x61\n"
540 : : "a" ((char)pca_status.oldval) );
543 : : "a" ((char)pca_status.buffer[pca_status.index]),
544 "b" (volume_table) );
546 pca_status.counter += pca_status.scale;
547 pca_status.index = (pca_status.counter >> 8);
549 if (pca_status.index >= pca_status.in_use[pca_status.current]) {
550 pca_status.index = pca_status.counter = 0;
551 pca_status.in_use[pca_status.current] = 0;
552 pca_status.current++;
553 if (pca_status.current > 2)
554 pca_status.current = 0;
555 pca_status.buffer = pca_status.buf[pca_status.current];
558 if (pca_status.wsel.si_pid) {
559 selwakeup((struct selinfo *)&pca_status.wsel.si_pid);
560 pca_status.wsel.si_pid = 0;
561 pca_status.wsel.si_flags = 0;
568 pcapoll(dev_t dev, int events, struct proc *p)
576 if (events & (POLLOUT | POLLWRNORM)) {
577 if (!pca_status.in_use[0] || !pca_status.in_use[1] ||
578 !pca_status.in_use[2])
579 revents |= events & (POLLOUT | POLLWRNORM);
581 if (pca_status.wsel.si_pid &&
582 (p1=pfind(pca_status.wsel.si_pid))
583 && p1->p_wchan == (caddr_t)&selwait)
584 pca_status.wsel.si_flags = SI_COLL;
586 pca_status.wsel.si_pid = p->p_pid;