1 /*-
2 * Copyright (c) 1994-1998 Sen 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: releng/5.0/sys/pc98/pc98/pcaudio.c 104676 2002-10-08 12:54:56Z nyan $
29 */
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/conf.h>
34 #include <sys/proc.h>
35 #include <sys/kernel.h>
36 #include <sys/bus.h>
37 #include <sys/filio.h>
38 #include <sys/poll.h>
39 #include <sys/vnode.h>
40
41 #include <machine/clock.h>
42 #include <machine/pcaudioio.h>
43
44 #ifdef PC98
45 #include <pc98/pc98/pc98.h>
46 #else
47 #include <isa/isareg.h>
48 #endif
49 #include <isa/isavar.h>
50 #include <i386/isa/timerreg.h>
51
52 #define BUF_SIZE 8192
53 #define SAMPLE_RATE 8000
54 #define INTERRUPT_RATE 16000
55
56 static struct pca_status {
57 char open; /* device open */
58 char queries; /* did others try opening */
59 unsigned char *buf[3]; /* triple buffering */
60 unsigned char *buffer; /* current buffer ptr */
61 unsigned in_use[3]; /* buffers fill */
62 unsigned index; /* index in current buffer */
63 unsigned counter; /* sample counter */
64 unsigned scale; /* sample counter scale */
65 unsigned sample_rate; /* sample rate */
66 unsigned processed; /* samples processed */
67 unsigned volume; /* volume for pc-speaker */
68 char encoding; /* Ulaw, Alaw or linear */
69 u_char current; /* current buffer */
70 unsigned char oldval; /* old timer port value */
71 char timer_on; /* is playback running */
72 struct selinfo wsel; /* select/poll status */
73 } pca_status;
74
75 static char buffer1[BUF_SIZE];
76 static char buffer2[BUF_SIZE];
77 static char buffer3[BUF_SIZE];
78 static char volume_table[256];
79
80 static unsigned char ulaw_dsp[] = {
81 3, 7, 11, 15, 19, 23, 27, 31,
82 35, 39, 43, 47, 51, 55, 59, 63,
83 66, 68, 70, 72, 74, 76, 78, 80,
84 82, 84, 86, 88, 90, 92, 94, 96,
85 98, 99, 100, 101, 102, 103, 104, 105,
86 106, 107, 108, 109, 110, 111, 112, 113,
87 113, 114, 114, 115, 115, 116, 116, 117,
88 117, 118, 118, 119, 119, 120, 120, 121,
89 121, 121, 122, 122, 122, 122, 123, 123,
90 123, 123, 124, 124, 124, 124, 125, 125,
91 125, 125, 125, 125, 126, 126, 126, 126,
92 126, 126, 126, 126, 127, 127, 127, 127,
93 127, 127, 127, 127, 127, 127, 127, 127,
94 128, 128, 128, 128, 128, 128, 128, 128,
95 128, 128, 128, 128, 128, 128, 128, 128,
96 128, 128, 128, 128, 128, 128, 128, 128,
97 253, 249, 245, 241, 237, 233, 229, 225,
98 221, 217, 213, 209, 205, 201, 197, 193,
99 190, 188, 186, 184, 182, 180, 178, 176,
100 174, 172, 170, 168, 166, 164, 162, 160,
101 158, 157, 156, 155, 154, 153, 152, 151,
102 150, 149, 148, 147, 146, 145, 144, 143,
103 143, 142, 142, 141, 141, 140, 140, 139,
104 139, 138, 138, 137, 137, 136, 136, 135,
105 135, 135, 134, 134, 134, 134, 133, 133,
106 133, 133, 132, 132, 132, 132, 131, 131,
107 131, 131, 131, 131, 130, 130, 130, 130,
108 130, 130, 130, 130, 129, 129, 129, 129,
109 129, 129, 129, 129, 129, 129, 129, 129,
110 128, 128, 128, 128, 128, 128, 128, 128,
111 128, 128, 128, 128, 128, 128, 128, 128,
112 128, 128, 128, 128, 128, 128, 128, 128,
113 };
114
115 static unsigned char alaw_linear[] = {
116 45, 214, 122, 133, 0, 255, 107, 149,
117 86, 171, 126, 129, 0, 255, 117, 138,
118 13, 246, 120, 135, 0, 255, 99, 157,
119 70, 187, 124, 131, 0, 255, 113, 142,
120 61, 198, 123, 132, 0, 255, 111, 145,
121 94, 163, 127, 128, 0, 255, 119, 136,
122 29, 230, 121, 134, 0, 255, 103, 153,
123 78, 179, 125, 130, 0, 255, 115, 140,
124 37, 222, 122, 133, 0, 255, 105, 151,
125 82, 175, 126, 129, 0, 255, 116, 139,
126 5, 254, 120, 135, 0, 255, 97, 159,
127 66, 191, 124, 131, 0, 255, 112, 143,
128 53, 206, 123, 132, 0, 255, 109, 147,
129 90, 167, 127, 128, 0, 255, 118, 137,
130 21, 238, 121, 134, 0, 255, 101, 155,
131 74, 183, 125, 130, 0, 255, 114, 141,
132 49, 210, 123, 133, 0, 255, 108, 148,
133 88, 169, 127, 129, 0, 255, 118, 138,
134 17, 242, 121, 135, 0, 255, 100, 156,
135 72, 185, 125, 131, 0, 255, 114, 142,
136 64, 194, 124, 132, 0, 255, 112, 144,
137 96, 161, 128, 128, 1, 255, 120, 136,
138 33, 226, 122, 134, 0, 255, 104, 152,
139 80, 177, 126, 130, 0, 255, 116, 140,
140 41, 218, 122, 133, 0, 255, 106, 150,
141 84, 173, 126, 129, 0, 255, 117, 139,
142 9, 250, 120, 135, 0, 255, 98, 158,
143 68, 189, 124, 131, 0, 255, 113, 143,
144 57, 202, 123, 132, 0, 255, 110, 146,
145 92, 165, 127, 128, 0, 255, 119, 137,
146 25, 234, 121, 134, 0, 255, 102, 154,
147 76, 181, 125, 130, 0, 255, 115, 141,
148 };
149
150 static int pca_sleep = 0;
151
152 static void pcaintr(struct clockframe *frame);
153
154 static d_open_t pcaopen;
155 static d_close_t pcaclose;
156 static d_write_t pcawrite;
157 static d_ioctl_t pcaioctl;
158 static d_poll_t pcapoll;
159
160 #define CDEV_MAJOR 24
161 static struct cdevsw pca_cdevsw = {
162 /* open */ pcaopen,
163 /* close */ pcaclose,
164 /* read */ noread,
165 /* write */ pcawrite,
166 /* ioctl */ pcaioctl,
167 /* poll */ pcapoll,
168 /* mmap */ nommap,
169 /* strategy */ nostrategy,
170 /* name */ "pca",
171 /* maj */ CDEV_MAJOR,
172 /* dump */ nodump,
173 /* psize */ nopsize,
174 /* flags */ 0,
175 };
176
177 static void pca_continue(void);
178 static void pca_init(void);
179 static void pca_pause(void);
180
181 static void
182 conv(const unsigned char *table, unsigned char *buff, unsigned n)
183 {
184 unsigned i;
185
186 for (i = 0; i < n; i++)
187 buff[i] = table[buff[i]];
188 }
189
190
191 static void
192 pca_volume(int volume)
193 {
194 int i, j;
195
196 for (i=0; i<256; i++) {
197 j = ((i-128)*volume)/25;
198 /* XXX
199 j = ((i-128)*volume)/100;
200 */
201 if (j<-128)
202 j = -128;
203 if (j>127)
204 j = 127;
205 volume_table[i] = (((255-(j + 128))/4)+1);
206 }
207 }
208
209
210 static void
211 pca_init(void)
212 {
213 pca_status.open = 0;
214 pca_status.queries = 0;
215 pca_status.timer_on = 0;
216 pca_status.buf[0] = (unsigned char *)&buffer1[0];
217 pca_status.buf[1] = (unsigned char *)&buffer2[0];
218 pca_status.buf[2] = (unsigned char *)&buffer3[0];
219 pca_status.buffer = pca_status.buf[0];
220 pca_status.in_use[0] = pca_status.in_use[1] = pca_status.in_use[2] = 0;
221 pca_status.current = 0;
222 pca_status.sample_rate = SAMPLE_RATE;
223 pca_status.scale = (pca_status.sample_rate << 8) / INTERRUPT_RATE;
224 pca_status.encoding = AUDIO_ENCODING_ULAW;
225 pca_status.volume = 100;
226
227 pca_volume(pca_status.volume);
228 }
229
230
231 static int
232 pca_start(void)
233 {
234 int x = splhigh();
235 int rv = 0;
236
237 /* use the first buffer */
238 pca_status.current = 0;
239 pca_status.index = 0;
240 pca_status.counter = 0;
241 pca_status.buffer = pca_status.buf[pca_status.current];
242 #ifdef PC98
243 pca_status.oldval = inb(IO_PPI) & ~0x08;
244 #else
245 pca_status.oldval = inb(IO_PPI) | 0x03;
246 #endif
247 /* acquire the timers */
248 #ifdef PC98
249 if (acquire_timer1(TIMER_LSB|TIMER_ONESHOT))
250 #else
251 if (acquire_timer2(TIMER_LSB|TIMER_ONESHOT))
252 #endif
253 rv = -1;
254 else if (acquire_timer0(INTERRUPT_RATE, pcaintr)) {
255 #ifdef PC98
256 release_timer1();
257 #else
258 release_timer2();
259 #endif
260 rv = -1;
261 } else
262 pca_status.timer_on = 1;
263
264 splx(x);
265 return rv;
266 }
267
268
269 static void
270 pca_stop(void)
271 {
272 int x = splhigh();
273
274 /* release the timers */
275 release_timer0();
276 #ifdef PC98
277 release_timer1();
278 #else
279 release_timer2();
280 #endif
281 /* reset the buffer */
282 pca_status.in_use[0] = pca_status.in_use[1] = pca_status.in_use[2] = 0;
283 pca_status.index = 0;
284 pca_status.counter = 0;
285 pca_status.current = 0;
286 pca_status.buffer = pca_status.buf[pca_status.current];
287 pca_status.timer_on = 0;
288 splx(x);
289 }
290
291
292 static void
293 pca_pause(void)
294 {
295 int x = splhigh();
296
297 release_timer0();
298 #ifdef PC98
299 release_timer1();
300 #else
301 release_timer2();
302 #endif
303 pca_status.timer_on = 0;
304 splx(x);
305 }
306
307
308 static void
309 pca_continue(void)
310 {
311 int x = splhigh();
312
313 #ifdef PC98
314 pca_status.oldval = inb(IO_PPI) & ~0x08;
315 acquire_timer1(TIMER_LSB|TIMER_ONESHOT);
316 #else
317 pca_status.oldval = inb(IO_PPI) | 0x03;
318 acquire_timer2(TIMER_LSB|TIMER_ONESHOT);
319 #endif
320 acquire_timer0(INTERRUPT_RATE, pcaintr);
321 pca_status.timer_on = 1;
322 splx(x);
323 }
324
325
326 static int
327 pca_wait(void)
328 {
329 int error, x;
330
331 if (!pca_status.timer_on)
332 return 0;
333
334 while (pca_status.in_use[0] || pca_status.in_use[1] ||
335 pca_status.in_use[2]) {
336 x = spltty();
337 pca_sleep = 1;
338 error = tsleep(&pca_sleep, PZERO|PCATCH, "pca_drain", 0);
339 pca_sleep = 0;
340 splx(x);
341 if (error != 0 && error != ERESTART) {
342 pca_stop();
343 return error;
344 }
345 }
346 return 0;
347 }
348
349
350 static struct isa_pnp_id pca_ids[] = {
351 {0x0008d041, "AT-style speaker sound"}, /* PNP0800 */
352 {0}
353 };
354
355 static int
356 pcaprobe(device_t dev)
357 {
358 /* Check isapnp ids */
359 return ISA_PNP_PROBE(device_get_parent(dev), dev, pca_ids);
360 }
361
362
363 static int
364 pcaattach(device_t dev)
365 {
366 pca_init();
367 make_dev(&pca_cdevsw, 0, 0, 0, 0600, "pcaudio");
368 make_dev(&pca_cdevsw, 128, 0, 0, 0600, "pcaudioctl");
369 return 0;
370 }
371
372 static device_method_t pca_methods[] = {
373 DEVMETHOD(device_probe, pcaprobe),
374 DEVMETHOD(device_attach, pcaattach),
375 { 0, 0 }
376 };
377
378 static driver_t pca_driver = {
379 "pca",
380 pca_methods,
381 1
382 };
383
384 static devclass_t pca_devclass;
385
386 DRIVER_MODULE(pca, isa, pca_driver, pca_devclass, 0, 0);
387
388
389 static int
390 pcaopen(dev_t dev, int flags, int fmt, struct thread *td)
391 {
392 /* audioctl device can always be opened */
393 if (minor(dev) == 128)
394 return 0;
395 if (minor(dev) > 0)
396 return ENXIO;
397
398 /* audio device can only be open by one process */
399 if (pca_status.open) {
400 pca_status.queries = 1;
401 return EBUSY;
402 }
403 pca_status.buffer = pca_status.buf[0];
404 pca_status.in_use[0] = pca_status.in_use[1] = pca_status.in_use[2] = 0;
405 pca_status.timer_on = 0;
406 pca_status.open = 1;
407 pca_status.processed = 0;
408 return 0;
409 }
410
411
412 static int
413 pcaclose(dev_t dev, int flags, int fmt, struct thread *td)
414 {
415 /* audioctl device can always be closed */
416 if (minor(dev) == 128)
417 return 0;
418 if (minor(dev) > 0)
419 return ENXIO;
420 /* audio device close drains all output and restores timers */
421 pca_wait();
422 pca_stop();
423 pca_status.open = 0;
424 return 0;
425 }
426
427
428 static int
429 pcawrite(dev_t dev, struct uio *uio, int flag)
430 {
431 int count, error, which, x;
432
433 /* only audio device can be written */
434 if (minor(dev) > 0)
435 return ENXIO;
436
437 while ((count = min(BUF_SIZE, uio->uio_resid)) > 0) {
438 if (pca_status.in_use[0] && pca_status.in_use[1] &&
439 pca_status.in_use[2]) {
440 if (flag & IO_NDELAY)
441 return EWOULDBLOCK;
442 x = spltty();
443 pca_sleep = 1;
444 error = tsleep(&pca_sleep, PZERO|PCATCH, "pca_wait", 0);
445 pca_sleep = 0;
446 splx(x);
447 if (error != 0 && error != ERESTART) {
448 pca_stop();
449 return error;
450 }
451 }
452 if (!pca_status.in_use[0])
453 which = 0;
454 else if (!pca_status.in_use[1])
455 which = 1;
456 else
457 which = 2;
458 if (count && !pca_status.in_use[which]) {
459 uiomove(pca_status.buf[which], count, uio);
460 pca_status.processed += count;
461 switch (pca_status.encoding) {
462 case AUDIO_ENCODING_ULAW:
463 conv(ulaw_dsp, pca_status.buf[which], count);
464 break;
465
466 case AUDIO_ENCODING_ALAW:
467 conv(alaw_linear, pca_status.buf[which], count);
468 break;
469
470 case AUDIO_ENCODING_RAW:
471 break;
472 }
473 pca_status.in_use[which] = count;
474 if (!pca_status.timer_on)
475 if (pca_start())
476 return EBUSY;
477 }
478 }
479 return 0;
480 }
481
482
483 static int
484 pcaioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
485 {
486 audio_info_t *auptr;
487
488 switch(cmd) {
489
490 case AUDIO_GETINFO:
491 auptr = (audio_info_t *)data;
492 auptr->play.sample_rate = pca_status.sample_rate;
493 auptr->play.channels = 1;
494 auptr->play.precision = 8;
495 auptr->play.encoding = pca_status.encoding;
496
497 auptr->play.gain = pca_status.volume;
498 auptr->play.port = 0;
499
500 auptr->play.samples = pca_status.processed;
501 auptr->play.eof = 0;
502 auptr->play.pause = !pca_status.timer_on;
503 auptr->play.error = 0;
504 auptr->play.waiting = pca_status.queries;
505
506 auptr->play.open = pca_status.open;
507 auptr->play.active = pca_status.timer_on;
508 return 0;
509
510 case AUDIO_SETINFO:
511 auptr = (audio_info_t *)data;
512 if (auptr->play.sample_rate != (unsigned int)~0) {
513 pca_status.sample_rate = auptr->play.sample_rate;
514 pca_status.scale =
515 (pca_status.sample_rate << 8) / INTERRUPT_RATE;
516 }
517 if (auptr->play.encoding != (unsigned int)~0) {
518 pca_status.encoding = auptr->play.encoding;
519 }
520 if (auptr->play.gain != (unsigned int)~0) {
521 pca_status.volume = auptr->play.gain;
522 pca_volume(pca_status.volume);
523 }
524 if (auptr->play.pause != (unsigned char)~0) {
525 if (auptr->play.pause)
526 pca_pause();
527 else
528 pca_continue();
529 }
530
531 return 0;
532
533 case AUDIO_DRAIN:
534 case AUDIO_COMPAT_DRAIN:
535 return pca_wait();
536
537 case AUDIO_FLUSH:
538 case AUDIO_COMPAT_FLUSH:
539 pca_stop();
540 return 0;
541 case FIONBIO:
542 return 0;
543 }
544 return ENXIO;
545 }
546
547
548 static void
549 pcaintr(struct clockframe *frame)
550 {
551 if (pca_status.index < pca_status.in_use[pca_status.current]) {
552 disable_intr();
553 #ifdef PC98
554 __asm__("outb %0,$0x35\n"
555 "orb $0x08,%0\n"
556 "outb %0,$0x35"
557 #else
558 __asm__("outb %0,$0x61\n"
559 "andb $0xFE,%0\n"
560 "outb %0,$0x61"
561 #endif
562 : : "a" ((char)pca_status.oldval) );
563 __asm__("xlatb\n"
564 #ifdef PC98
565 "outb %0,%%dx"
566 : : "a" ((char)pca_status.buffer[pca_status.index]),
567 "b" (volume_table),
568 "d" ((u_short)0x3fdb) );
569 #else
570 "outb %0,$0x42"
571 : : "a" ((char)pca_status.buffer[pca_status.index]),
572 "b" (volume_table) );
573 #endif
574 enable_intr();
575 pca_status.counter += pca_status.scale;
576 pca_status.index = (pca_status.counter >> 8);
577 }
578 if (pca_status.index >= pca_status.in_use[pca_status.current]) {
579 pca_status.index = pca_status.counter = 0;
580 pca_status.in_use[pca_status.current] = 0;
581 pca_status.current++;
582 if (pca_status.current > 2)
583 pca_status.current = 0;
584 pca_status.buffer = pca_status.buf[pca_status.current];
585 if (pca_sleep)
586 wakeup(&pca_sleep);
587 if (SEL_WAITING(&pca_status.wsel))
588 selwakeup(&pca_status.wsel);
589 }
590 }
591
592
593 static int
594 pcapoll(dev_t dev, int events, struct thread *td)
595 {
596 int s;
597 int revents = 0;
598
599 s = spltty();
600
601 if (events & (POLLOUT | POLLWRNORM)) {
602 if (!pca_status.in_use[0] || !pca_status.in_use[1] ||
603 !pca_status.in_use[2])
604 revents |= events & (POLLOUT | POLLWRNORM);
605 else
606 selrecord(td, &pca_status.wsel);
607 }
608 splx(s);
609 return (revents);
610 }
Cache object: 5c1bd05953b2ef6b76b5cdf5a95259b3
|