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.10 2004/05/19 22:52:50 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 intrframe *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 (void);
179 static void pca_init (void);
180 static void pca_pause (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 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");
354 static device_method_t pca_methods[] = {
355 DEVMETHOD(device_probe, pcaprobe),
356 DEVMETHOD(device_attach, pcaattach),
360 static driver_t pca_driver = {
366 static devclass_t pca_devclass;
368 DRIVER_MODULE(pca, isa, pca_driver, pca_devclass, 0, 0);
372 pcaopen(dev_t dev, int flags, int fmt, struct thread *td)
374 /* audioctl device can always be opened */
375 if (minor(dev) == 128)
380 if (!pca_initialized) {
385 /* audio device can only be open by one process */
386 if (pca_status.open) {
387 pca_status.queries = 1;
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;
394 pca_status.processed = 0;
400 pcaclose(dev_t dev, int flags, int fmt, struct thread *td)
402 /* audioctl device can always be closed */
403 if (minor(dev) == 128)
407 /* audio device close drains all output and restores timers */
416 pcawrite(dev_t dev, struct uio *uio, int flag)
418 int count, error, which, x;
420 /* only audio device can be written */
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)
431 error = tsleep(&pca_sleep, PCATCH, "pca_wait", 0);
434 if (error != 0 && error != ERESTART) {
439 if (!pca_status.in_use[0])
441 else if (!pca_status.in_use[1])
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);
453 case AUDIO_ENCODING_ALAW:
454 conv(alaw_linear, pca_status.buf[which], count);
457 case AUDIO_ENCODING_RAW:
460 pca_status.in_use[which] = count;
461 if (!pca_status.timer_on)
471 pcaioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
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;
484 auptr->play.gain = pca_status.volume;
485 auptr->play.port = 0;
487 auptr->play.samples = pca_status.processed;
489 auptr->play.pause = !pca_status.timer_on;
490 auptr->play.error = 0;
491 auptr->play.waiting = pca_status.queries;
493 auptr->play.open = pca_status.open;
494 auptr->play.active = pca_status.timer_on;
498 auptr = (audio_info_t *)data;
499 if (auptr->play.sample_rate != (unsigned int)~0) {
500 pca_status.sample_rate = auptr->play.sample_rate;
502 (pca_status.sample_rate << 8) / INTERRUPT_RATE;
504 if (auptr->play.encoding != (unsigned int)~0) {
505 pca_status.encoding = auptr->play.encoding;
507 if (auptr->play.gain != (unsigned int)~0) {
508 pca_status.volume = auptr->play.gain;
509 pca_volume(pca_status.volume);
511 if (auptr->play.pause != (unsigned char)~0) {
512 if (auptr->play.pause)
521 case AUDIO_COMPAT_DRAIN:
525 case AUDIO_COMPAT_FLUSH:
536 pcaintr(struct intrframe *frame)
538 if (pca_status.index < pca_status.in_use[pca_status.current]) {
540 __asm__("outb %0,$0x61\n"
543 : : "a" ((char)pca_status.oldval) );
546 : : "a" ((char)pca_status.buffer[pca_status.index]),
547 "b" (volume_table) );
549 pca_status.counter += pca_status.scale;
550 pca_status.index = (pca_status.counter >> 8);
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];
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;
571 pcapoll(dev_t dev, int events, struct thread *td)
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);
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;
593 pca_status.wsel.si_pid = p->p_pid;