2 * Copyright (c) 1994-1998 S
\ fen 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.
31 #include <sys/param.h>
32 #include <sys/systm.h>
35 #include <sys/kernel.h>
37 #include <sys/filio.h>
39 #include <sys/vnode.h>
41 #include <machine/clock.h>
42 #include <machine/pcaudioio.h>
44 #include <isa/isareg.h>
45 #include <isa/isavar.h>
46 #include <i386/isa/timerreg.h>
49 #define SAMPLE_RATE 8000
50 #define INTERRUPT_RATE 16000
52 static struct pca_status {
53 char open; /* device open */
54 char queries; /* did others try opening */
55 unsigned char *buf[3]; /* triple buffering */
56 unsigned char *buffer; /* current buffer ptr */
57 unsigned in_use[3]; /* buffers fill */
58 unsigned index; /* index in current buffer */
59 unsigned counter; /* sample counter */
60 unsigned scale; /* sample counter scale */
61 unsigned sample_rate; /* sample rate */
62 unsigned processed; /* samples processed */
63 unsigned volume; /* volume for pc-speaker */
64 char encoding; /* Ulaw, Alaw or linear */
65 u_char current; /* current buffer */
66 unsigned char oldval; /* old timer port value */
67 char timer_on; /* is playback running */
68 struct selinfo wsel; /* select/poll status */
71 static char buffer1[BUF_SIZE];
72 static char buffer2[BUF_SIZE];
73 static char buffer3[BUF_SIZE];
74 static char volume_table[256];
76 static unsigned char ulaw_dsp[] = {
77 3, 7, 11, 15, 19, 23, 27, 31,
78 35, 39, 43, 47, 51, 55, 59, 63,
79 66, 68, 70, 72, 74, 76, 78, 80,
80 82, 84, 86, 88, 90, 92, 94, 96,
81 98, 99, 100, 101, 102, 103, 104, 105,
82 106, 107, 108, 109, 110, 111, 112, 113,
83 113, 114, 114, 115, 115, 116, 116, 117,
84 117, 118, 118, 119, 119, 120, 120, 121,
85 121, 121, 122, 122, 122, 122, 123, 123,
86 123, 123, 124, 124, 124, 124, 125, 125,
87 125, 125, 125, 125, 126, 126, 126, 126,
88 126, 126, 126, 126, 127, 127, 127, 127,
89 127, 127, 127, 127, 127, 127, 127, 127,
90 128, 128, 128, 128, 128, 128, 128, 128,
91 128, 128, 128, 128, 128, 128, 128, 128,
92 128, 128, 128, 128, 128, 128, 128, 128,
93 253, 249, 245, 241, 237, 233, 229, 225,
94 221, 217, 213, 209, 205, 201, 197, 193,
95 190, 188, 186, 184, 182, 180, 178, 176,
96 174, 172, 170, 168, 166, 164, 162, 160,
97 158, 157, 156, 155, 154, 153, 152, 151,
98 150, 149, 148, 147, 146, 145, 144, 143,
99 143, 142, 142, 141, 141, 140, 140, 139,
100 139, 138, 138, 137, 137, 136, 136, 135,
101 135, 135, 134, 134, 134, 134, 133, 133,
102 133, 133, 132, 132, 132, 132, 131, 131,
103 131, 131, 131, 131, 130, 130, 130, 130,
104 130, 130, 130, 130, 129, 129, 129, 129,
105 129, 129, 129, 129, 129, 129, 129, 129,
106 128, 128, 128, 128, 128, 128, 128, 128,
107 128, 128, 128, 128, 128, 128, 128, 128,
108 128, 128, 128, 128, 128, 128, 128, 128,
111 static unsigned char alaw_linear[] = {
112 45, 214, 122, 133, 0, 255, 107, 149,
113 86, 171, 126, 129, 0, 255, 117, 138,
114 13, 246, 120, 135, 0, 255, 99, 157,
115 70, 187, 124, 131, 0, 255, 113, 142,
116 61, 198, 123, 132, 0, 255, 111, 145,
117 94, 163, 127, 128, 0, 255, 119, 136,
118 29, 230, 121, 134, 0, 255, 103, 153,
119 78, 179, 125, 130, 0, 255, 115, 140,
120 37, 222, 122, 133, 0, 255, 105, 151,
121 82, 175, 126, 129, 0, 255, 116, 139,
122 5, 254, 120, 135, 0, 255, 97, 159,
123 66, 191, 124, 131, 0, 255, 112, 143,
124 53, 206, 123, 132, 0, 255, 109, 147,
125 90, 167, 127, 128, 0, 255, 118, 137,
126 21, 238, 121, 134, 0, 255, 101, 155,
127 74, 183, 125, 130, 0, 255, 114, 141,
128 49, 210, 123, 133, 0, 255, 108, 148,
129 88, 169, 127, 129, 0, 255, 118, 138,
130 17, 242, 121, 135, 0, 255, 100, 156,
131 72, 185, 125, 131, 0, 255, 114, 142,
132 64, 194, 124, 132, 0, 255, 112, 144,
133 96, 161, 128, 128, 1, 255, 120, 136,
134 33, 226, 122, 134, 0, 255, 104, 152,
135 80, 177, 126, 130, 0, 255, 116, 140,
136 41, 218, 122, 133, 0, 255, 106, 150,
137 84, 173, 126, 129, 0, 255, 117, 139,
138 9, 250, 120, 135, 0, 255, 98, 158,
139 68, 189, 124, 131, 0, 255, 113, 143,
140 57, 202, 123, 132, 0, 255, 110, 146,
141 92, 165, 127, 128, 0, 255, 119, 137,
142 25, 234, 121, 134, 0, 255, 102, 154,
143 76, 181, 125, 130, 0, 255, 115, 141,
146 static int pca_sleep = 0;
147 static int pca_initialized = 0;
149 static void pcaintr(struct clockframe *frame);
151 static d_open_t pcaopen;
152 static d_close_t pcaclose;
153 static d_write_t pcawrite;
154 static d_ioctl_t pcaioctl;
155 static d_poll_t pcapoll;
157 #define CDEV_MAJOR 24
158 static struct cdevsw pca_cdevsw = {
160 /* close */ pcaclose,
162 /* write */ pcawrite,
163 /* ioctl */ pcaioctl,
166 /* strategy */ nostrategy,
168 /* maj */ CDEV_MAJOR,
175 static void pca_continue __P((void));
176 static void pca_init __P((void));
177 static void pca_pause __P((void));
180 conv(const unsigned char *table, unsigned char *buff, unsigned n)
184 for (i = 0; i < n; i++)
185 buff[i] = table[buff[i]];
190 pca_volume(int volume)
194 for (i=0; i<256; i++) {
195 j = ((i-128)*volume)/25;
197 j = ((i-128)*volume)/100;
203 volume_table[i] = (((255-(j + 128))/4)+1);
212 pca_status.queries = 0;
213 pca_status.timer_on = 0;
214 pca_status.buf[0] = (unsigned char *)&buffer1[0];
215 pca_status.buf[1] = (unsigned char *)&buffer2[0];
216 pca_status.buf[2] = (unsigned char *)&buffer3[0];
217 pca_status.buffer = pca_status.buf[0];
218 pca_status.in_use[0] = pca_status.in_use[1] = pca_status.in_use[2] = 0;
219 pca_status.current = 0;
220 pca_status.sample_rate = SAMPLE_RATE;
221 pca_status.scale = (pca_status.sample_rate << 8) / INTERRUPT_RATE;
222 pca_status.encoding = AUDIO_ENCODING_ULAW;
223 pca_status.volume = 100;
225 pca_volume(pca_status.volume);
235 /* use the first buffer */
236 pca_status.current = 0;
237 pca_status.index = 0;
238 pca_status.counter = 0;
239 pca_status.buffer = pca_status.buf[pca_status.current];
241 pca_status.oldval = inb(IO_PPI) & ~0x08;
243 pca_status.oldval = inb(IO_PPI) | 0x03;
245 /* acquire the timers */
247 if (acquire_timer1(TIMER_LSB|TIMER_ONESHOT))
249 if (acquire_timer2(TIMER_LSB|TIMER_ONESHOT))
252 else if (acquire_timer0(INTERRUPT_RATE, pcaintr)) {
260 pca_status.timer_on = 1;
272 /* release the timers */
279 /* reset the buffer */
280 pca_status.in_use[0] = pca_status.in_use[1] = pca_status.in_use[2] = 0;
281 pca_status.index = 0;
282 pca_status.counter = 0;
283 pca_status.current = 0;
284 pca_status.buffer = pca_status.buf[pca_status.current];
285 pca_status.timer_on = 0;
301 pca_status.timer_on = 0;
312 pca_status.oldval = inb(IO_PPI) & ~0x08;
314 pca_status.oldval = inb(IO_PPI) | 0x03;
316 acquire_timer2(TIMER_LSB|TIMER_ONESHOT);
317 acquire_timer0(INTERRUPT_RATE, pcaintr);
318 pca_status.timer_on = 1;
328 if (!pca_status.timer_on)
331 while (pca_status.in_use[0] || pca_status.in_use[1] ||
332 pca_status.in_use[2]) {
335 error = tsleep(&pca_sleep, PZERO|PCATCH, "pca_drain", 0);
338 if (error != 0 && error != ERESTART) {
347 static struct isa_pnp_id pca_ids[] = {
348 {0x0008d041, "AT-style speaker sound"}, /* PNP0800 */
353 pcaprobe(device_t dev)
357 /* Check isapnp ids */
358 error = ISA_PNP_PROBE(device_get_parent(dev), dev, pca_ids);
366 pcaattach(device_t dev)
369 make_dev(&pca_cdevsw, 0, 0, 0, 0600, "pcaudio");
370 make_dev(&pca_cdevsw, 128, 0, 0, 0600, "pcaudioctl");
374 static device_method_t pca_methods[] = {
375 DEVMETHOD(device_probe, pcaprobe),
376 DEVMETHOD(device_attach, pcaattach),
380 static driver_t pca_driver = {
386 static devclass_t pca_devclass;
388 DRIVER_MODULE(pca, isa, pca_driver, pca_devclass, 0, 0);
392 pcaopen(dev_t dev, int flags, int fmt, struct proc *p)
394 /* audioctl device can always be opened */
395 if (minor(dev) == 128)
400 if (!pca_initialized) {
405 /* audio device can only be open by one process */
406 if (pca_status.open) {
407 pca_status.queries = 1;
410 pca_status.buffer = pca_status.buf[0];
411 pca_status.in_use[0] = pca_status.in_use[1] = pca_status.in_use[2] = 0;
412 pca_status.timer_on = 0;
414 pca_status.processed = 0;
420 pcaclose(dev_t dev, int flags, int fmt, struct proc *p)
422 /* audioctl device can always be closed */
423 if (minor(dev) == 128)
427 /* audio device close drains all output and restores timers */
436 pcawrite(dev_t dev, struct uio *uio, int flag)
438 int count, error, which, x;
440 /* only audio device can be written */
444 while ((count = min(BUF_SIZE, uio->uio_resid)) > 0) {
445 if (pca_status.in_use[0] && pca_status.in_use[1] &&
446 pca_status.in_use[2]) {
447 if (flag & IO_NDELAY)
451 error = tsleep(&pca_sleep, PZERO|PCATCH, "pca_wait", 0);
454 if (error != 0 && error != ERESTART) {
459 if (!pca_status.in_use[0])
461 else if (!pca_status.in_use[1])
465 if (count && !pca_status.in_use[which]) {
466 uiomove(pca_status.buf[which], count, uio);
467 pca_status.processed += count;
468 switch (pca_status.encoding) {
469 case AUDIO_ENCODING_ULAW:
470 conv(ulaw_dsp, pca_status.buf[which], count);
473 case AUDIO_ENCODING_ALAW:
474 conv(alaw_linear, pca_status.buf[which], count);
477 case AUDIO_ENCODING_RAW:
480 pca_status.in_use[which] = count;
481 if (!pca_status.timer_on)
491 pcaioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
498 auptr = (audio_info_t *)data;
499 auptr->play.sample_rate = pca_status.sample_rate;
500 auptr->play.channels = 1;
501 auptr->play.precision = 8;
502 auptr->play.encoding = pca_status.encoding;
504 auptr->play.gain = pca_status.volume;
505 auptr->play.port = 0;
507 auptr->play.samples = pca_status.processed;
509 auptr->play.pause = !pca_status.timer_on;
510 auptr->play.error = 0;
511 auptr->play.waiting = pca_status.queries;
513 auptr->play.open = pca_status.open;
514 auptr->play.active = pca_status.timer_on;
518 auptr = (audio_info_t *)data;
519 if (auptr->play.sample_rate != (unsigned int)~0) {
520 pca_status.sample_rate = auptr->play.sample_rate;
522 (pca_status.sample_rate << 8) / INTERRUPT_RATE;
524 if (auptr->play.encoding != (unsigned int)~0) {
525 pca_status.encoding = auptr->play.encoding;
527 if (auptr->play.gain != (unsigned int)~0) {
528 pca_status.volume = auptr->play.gain;
529 pca_volume(pca_status.volume);
531 if (auptr->play.pause != (unsigned char)~0) {
532 if (auptr->play.pause)
541 case AUDIO_COMPAT_DRAIN:
545 case AUDIO_COMPAT_FLUSH:
556 pcaintr(struct clockframe *frame)
558 if (pca_status.index < pca_status.in_use[pca_status.current]) {
561 __asm__("outb %0,$0x35\n"
565 __asm__("outb %0,$0x61\n"
569 : : "a" ((char)pca_status.oldval) );
576 : : "a" ((char)pca_status.buffer[pca_status.index]),
577 "b" (volume_table) );
579 pca_status.counter += pca_status.scale;
580 pca_status.index = (pca_status.counter >> 8);
582 if (pca_status.index >= pca_status.in_use[pca_status.current]) {
583 pca_status.index = pca_status.counter = 0;
584 pca_status.in_use[pca_status.current] = 0;
585 pca_status.current++;
586 if (pca_status.current > 2)
587 pca_status.current = 0;
588 pca_status.buffer = pca_status.buf[pca_status.current];
591 if (pca_status.wsel.si_pid) {
592 selwakeup((struct selinfo *)&pca_status.wsel.si_pid);
593 pca_status.wsel.si_pid = 0;
594 pca_status.wsel.si_flags = 0;
601 pcapoll(dev_t dev, int events, struct proc *p)
609 if (events & (POLLOUT | POLLWRNORM)) {
610 if (!pca_status.in_use[0] || !pca_status.in_use[1] ||
611 !pca_status.in_use[2])
612 revents |= events & (POLLOUT | POLLWRNORM);
614 if (pca_status.wsel.si_pid &&
615 (p1=pfind(pca_status.wsel.si_pid))
616 && p1->p_wchan == (caddr_t)&selwait)
617 pca_status.wsel.si_flags = SI_COLL;
619 pca_status.wsel.si_pid = p->p_pid;