2 * PC-9801-86 PCM driver for FreeBSD(98).
4 * Copyright (c) 1995 NAGAO Tadaaki (ABTK)
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR AND CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * This file DOES NOT belong to the VoxWare distribution though it works
34 * as part of the VoxWare drivers. It is FreeBSD(98) original.
35 * -- Nagao (nagao@cs.titech.ac.jp)
39 #include <i386/isa/sound/sound_config.h>
41 #ifdef CONFIGURE_SOUNDCARD
43 #if !defined(EXCLUDE_NSS) && !defined(EXCLUDE_AUDIO)
55 #define IMODE_OUTPUT 2
57 /* PC-9801-86 specific constants */
58 #define PCM86_IOBASE 0xa460 /* PCM I/O ports */
59 #define PCM86_FIFOSIZE 32768 /* There is a 32kB FIFO buffer on 86-board */
61 /* XXX -- These values should be chosen appropriately. */
62 #define PCM86_INTRSIZE_OUT 1024
63 #define PCM86_INTRSIZE_IN (PCM86_FIFOSIZE / 2 - 128)
64 #define DEFAULT_VOLUME 15 /* 0(min) - 15(max) */
68 * Switches for debugging and experiments
71 /* #define NSS_DEBUG */
82 * Private variables and types
85 typedef unsigned char pcm_data;
88 NO_SUPPORTED_BOARD = 0,
93 static char *board_name[] = {
94 /* Each must be of the length less than 32 bytes. */
96 "PC-9801-86 soundboard",
97 "PC-9801-73 soundboard"
100 /* Current status of the driver */
104 enum board_type board_type;
132 static int my_dev = 0;
133 static char nss_initialized = NO;
135 /* 86-board supports only the following rates. */
136 static int rates_tbl[8] = {
137 #ifndef WAVEMASTER_FREQ
138 44100, 33075, 22050, 16538, 11025, 8269, 5513, 4134
141 * It is said that Q-Vision's WaveMaster of some earlier lot(s?) has
142 * sampling rates incompatible with PC-9801-86.
143 * But I'm not sure whether the following rates are correct, especially
146 44100, 33075, 22050, 16000, 11025, 8000, 5510, 4000
150 /* u-law to linear translation table */
151 static pcm_data ulaw2linear[256] = {
152 130, 134, 138, 142, 146, 150, 154, 158,
153 162, 166, 170, 174, 178, 182, 186, 190,
154 193, 195, 197, 199, 201, 203, 205, 207,
155 209, 211, 213, 215, 217, 219, 221, 223,
156 225, 226, 227, 228, 229, 230, 231, 232,
157 233, 234, 235, 236, 237, 238, 239, 240,
158 240, 241, 241, 242, 242, 243, 243, 244,
159 244, 245, 245, 246, 246, 247, 247, 248,
160 248, 248, 249, 249, 249, 249, 250, 250,
161 250, 250, 251, 251, 251, 251, 252, 252,
162 252, 252, 252, 252, 253, 253, 253, 253,
163 253, 253, 253, 253, 254, 254, 254, 254,
164 254, 254, 254, 254, 254, 254, 254, 254,
165 255, 255, 255, 255, 255, 255, 255, 255,
166 255, 255, 255, 255, 255, 255, 255, 255,
167 255, 255, 255, 255, 255, 255, 255, 255,
168 125, 121, 117, 113, 109, 105, 101, 97,
169 93, 89, 85, 81, 77, 73, 69, 65,
170 62, 60, 58, 56, 54, 52, 50, 48,
171 46, 44, 42, 40, 38, 36, 34, 32,
172 30, 29, 28, 27, 26, 25, 24, 23,
173 22, 21, 20, 19, 18, 17, 16, 15,
174 15, 14, 14, 13, 13, 12, 12, 11,
175 11, 10, 10, 9, 9, 8, 8, 7,
176 7, 7, 6, 6, 6, 6, 5, 5,
177 5, 5, 4, 4, 4, 4, 3, 3,
178 3, 3, 3, 3, 2, 2, 2, 2,
179 2, 2, 2, 2, 1, 1, 1, 1,
180 1, 1, 1, 1, 1, 1, 1, 1,
181 0, 0, 0, 0, 0, 0, 0, 0,
182 0, 0, 0, 0, 0, 0, 0, 0,
183 0, 0, 0, 0, 0, 0, 0, 0
186 /* linear to u-law translation table */
187 static pcm_data linear2ulaw[256] = {
188 255, 231, 219, 211, 205, 201, 197, 193,
189 190, 188, 186, 184, 182, 180, 178, 176,
190 175, 174, 173, 172, 171, 170, 169, 168,
191 167, 166, 165, 164, 163, 162, 161, 160,
192 159, 159, 158, 158, 157, 157, 156, 156,
193 155, 155, 154, 154, 153, 153, 152, 152,
194 151, 151, 150, 150, 149, 149, 148, 148,
195 147, 147, 146, 146, 145, 145, 144, 144,
196 143, 143, 143, 143, 142, 142, 142, 142,
197 141, 141, 141, 141, 140, 140, 140, 140,
198 139, 139, 139, 139, 138, 138, 138, 138,
199 137, 137, 137, 137, 136, 136, 136, 136,
200 135, 135, 135, 135, 134, 134, 134, 134,
201 133, 133, 133, 133, 132, 132, 132, 132,
202 131, 131, 131, 131, 130, 130, 130, 130,
203 129, 129, 129, 129, 128, 128, 128, 128,
204 0, 0, 0, 0, 0, 1, 1, 1,
205 1, 2, 2, 2, 2, 3, 3, 3,
206 3, 4, 4, 4, 4, 5, 5, 5,
207 5, 6, 6, 6, 6, 7, 7, 7,
208 7, 8, 8, 8, 8, 9, 9, 9,
209 9, 10, 10, 10, 10, 11, 11, 11,
210 11, 12, 12, 12, 12, 13, 13, 13,
211 13, 14, 14, 14, 14, 15, 15, 15,
212 15, 16, 16, 17, 17, 18, 18, 19,
213 19, 20, 20, 21, 21, 22, 22, 23,
214 23, 24, 24, 25, 25, 26, 26, 27,
215 27, 28, 28, 29, 29, 30, 30, 31,
216 31, 32, 33, 34, 35, 36, 37, 38,
217 39, 40, 41, 42, 43, 44, 45, 46,
218 47, 48, 50, 52, 54, 56, 58, 60,
219 62, 65, 69, 73, 77, 83, 91, 103
227 static int nss_detect(struct address_info *);
229 static int nss_open(int, int);
230 static void nss_close(int);
231 static void nss_output_block(int, unsigned long, int, int, int);
232 static void nss_start_input(int, unsigned long, int, int, int);
233 static int nss_ioctl(int, u_int, ioctl_arg, int);
234 static int nss_prepare_for_input(int, int, int);
235 static int nss_prepare_for_output(int, int, int);
236 static void nss_reset(int);
237 static void nss_halt_xfer(int);
239 static void dsp73_send_command(unsigned char);
240 static void dsp73_send_data(unsigned char);
241 static void dsp73_init(void);
242 static int set_format(int);
243 static int set_speed(int);
244 static int set_stereo(int);
245 static void set_volume(int);
246 static void fifo_start(int);
247 static void fifo_stop(void);
248 static void fifo_reset(void);
249 static void fifo_output_block(void);
250 static int fifo_send(pcm_data *, int);
251 static void fifo_sendtrailer(int);
252 static void fifo_send_stereo(pcm_data *, int);
253 static void fifo_send_monoral(pcm_data *, int);
254 static void fifo_send_stereo_ulaw(pcm_data *, int);
255 static void fifo_send_stereo_8(pcm_data *, int, int);
256 static void fifo_send_stereo_16le(pcm_data *, int, int);
257 static void fifo_send_stereo_16be(pcm_data *, int, int);
258 static void fifo_send_mono_ulaw(pcm_data *, int);
259 static void fifo_send_mono_8(pcm_data *, int, int);
260 static void fifo_send_mono_16le(pcm_data *, int, int);
261 static void fifo_send_mono_16be(pcm_data *, int, int);
262 static void fifo_input_block(void);
263 static void fifo_recv(pcm_data *, int);
264 static void fifo_recv_stereo(pcm_data *, int);
265 static void fifo_recv_monoral(pcm_data *, int);
266 static void fifo_recv_stereo_ulaw(pcm_data *, int);
267 static void fifo_recv_stereo_8(pcm_data *, int, int);
268 static void fifo_recv_stereo_16le(pcm_data *, int, int);
269 static void fifo_recv_stereo_16be(pcm_data *, int, int);
270 static void fifo_recv_mono_ulaw(pcm_data *, int);
271 static void fifo_recv_mono_8(pcm_data *, int, int);
272 static void fifo_recv_mono_16le(pcm_data *, int, int);
273 static void fifo_recv_mono_16be(pcm_data *, int, int);
274 static void nss_stop(void);
275 static void nss_init(void);
282 static struct audio_operations nss_operations =
284 "PC-9801-86 SoundBoard", /* filled in properly by auto configuration */
287 AFMT_U8 | AFMT_S16_LE | AFMT_S16_BE |
288 AFMT_S8 | AFMT_U16_LE | AFMT_U16_BE ),
295 nss_prepare_for_input,
296 nss_prepare_for_output,
305 * Codes for internal use
309 dsp73_send_command(unsigned char command)
312 while ((inb(pcm_s.iobase + 2) & 0x48) != 8);
315 outb(pcm_s.iobase + 2, (inb(pcm_s.iobase + 2) & 0x20) | 3);
318 while ((inb(pcm_s.iobase + 2) & 0x48) != 8);
321 outb(pcm_s.iobase + 4, command);
326 dsp73_send_data(unsigned char data)
329 while ((inb(pcm_s.iobase + 2) & 0x48) != 8);
332 outb(pcm_s.iobase + 2, (inb(pcm_s.iobase + 2) & 0x20) | 0x83);
335 while ((inb(pcm_s.iobase + 2) & 0x48) != 8);
338 outb(pcm_s.iobase + 4, data);
345 const unsigned char dspinst[15] = {
356 t = inb(pcm_s.iobase + 2);
357 outb(pcm_s.iobase + 2, (t & 0x80) | 0x23);
360 dsp73_send_command(0x04);
361 dsp73_send_data(0x6f);
362 dsp73_send_data(0x3c);
364 /* write DSP instructions */
365 dsp73_send_command(0x01);
366 dsp73_send_data(0x00);
367 for (i = 0; i < 16; i++)
368 dsp73_send_data(dspinst[i]);
371 dsp73_send_command(0x04);
372 dsp73_send_data(0x6f);
373 dsp73_send_data(0x30);
376 while ((inb(pcm_s.iobase + 2) & 0x48) != 8);
378 outb(pcm_s.iobase + 2, 3);
383 set_format(int format)
389 pcm_s.format = format;
390 pcm_s.bytes = 1; /* 8bit */
396 pcm_s.format = format;
397 pcm_s.bytes = 2; /* 16bit */
414 if (speed < 4000) /* Minimum 4000Hz */
416 if (speed > 44100) /* Maximum 44100Hz */
418 for (i = 7; i >= 0; i--) {
419 if (speed <= rates_tbl[i]) {
420 pcm_s.chipspeedno = i;
421 pcm_s.chipspeed = rates_tbl[i];
432 set_stereo(int stereo)
434 pcm_s.stereo = stereo ? YES : NO;
441 set_volume(int volume)
447 pcm_s.volume = volume;
449 outb(pcm_s.iobase + 6, 0xaf - volume); /* D/A -> LINE OUT */
454 outb(pcm_s.iobase + 6, 0x20); /* FM -> A/D */
459 outb(pcm_s.iobase + 6, 0x60); /* LINE IN -> A/D */
472 /* Set frame length & panpot(LR). */
473 tmp = inb(pcm_s.iobase + 10) & 0x88;
474 outb(pcm_s.iobase + 10, tmp | ((pcm_s.bytes == 1) ? 0x72 : 0x32));
476 tmp = pcm_s.chipspeedno;
477 if (mode == IMODE_INPUT)
480 /* Reset intr. flag. */
481 outb(pcm_s.iobase + 8, tmp);
482 outb(pcm_s.iobase + 8, tmp | 0x10);
484 /* Enable FIFO intr. */
485 outb(pcm_s.iobase + 8, tmp | 0x30);
487 /* Set intr. interval. */
488 outb(pcm_s.iobase + 10, pcm_s.intr_size / 128 - 1);
491 outb(pcm_s.iobase + 8, tmp | 0xb0);
500 /* Reset intr. flag, and disable FIFO intr. */
501 tmp = inb(pcm_s.iobase + 8) & 0x0f;
502 outb(pcm_s.iobase + 8, tmp);
512 tmp = inb(pcm_s.iobase + 8) & 0x77;
513 outb(pcm_s.iobase + 8, tmp | 0x8);
514 outb(pcm_s.iobase + 8, tmp);
519 fifo_output_block(void)
521 int chunksize, count;
523 if (pcm_s.pdma_chunkcount) {
524 /* Update chunksize and then send the next chunk to FIFO. */
525 chunksize = pcm_s.pdma_count / pcm_s.pdma_chunkcount--;
526 count = fifo_send(pcm_s.pdma_buf, chunksize);
528 /* ??? something wrong... */
529 printf("nss0: chunkcount overrun\n");
530 chunksize = count = 0;
533 if (((audio_devs[my_dev]->dmap_out->qlen < 2) && (pcm_s.pdma_chunkcount == 0))
534 || (count < pcm_s.intr_size)) {
535 /* The sent chunk seems to be the last one. */
536 fifo_sendtrailer(pcm_s.intr_size);
537 pcm_s.intr_last = YES;
540 pcm_s.pdma_buf += chunksize;
541 pcm_s.pdma_count -= chunksize;
546 fifo_send(pcm_data *buf, int count)
548 int i, length, r, cnt, rslt;
551 /* Calculate the length of PCM frames. */
552 cnt = count + tmpbuf.size;
553 length = pcm_s.bytes << pcm_s.stereo;
559 fifo_send_stereo(buf, cnt);
561 fifo_send_monoral(buf, cnt);
562 /* Carry over extra data which doesn't seem to be a full PCM frame. */
563 p = (pcm_data *)buf + count - r;
564 for (i = 0; i < r; i++)
565 tmpbuf.buff[i] = *p++;
567 /* Carry over extra data which doesn't seem to be a full PCM frame. */
569 for (i = tmpbuf.size; i < r; i++)
570 tmpbuf.buff[i] = *p++;
574 rslt = ((cnt / length) * pcm_s.chipspeed / pcm_s.speed) * pcm_s.bytes * 2;
576 printf("fifo_send(): %d bytes sent\n", rslt);
583 fifo_sendtrailer(int count)
585 /* Send trailing zeros to the FIFO buffer. */
588 for (i = 0; i < count; i++)
589 outb(pcm_s.iobase + 12, 0);
590 pcm_s.intr_trailer = YES;
593 printf("fifo_sendtrailer(): %d bytes sent\n", count);
599 fifo_send_stereo(pcm_data *buf, int count)
601 /* Convert format and sampling speed. */
602 switch (pcm_s.format) {
604 fifo_send_stereo_ulaw(buf, count);
607 fifo_send_stereo_8(buf, count, NO);
610 fifo_send_stereo_8(buf, count, YES);
613 fifo_send_stereo_16le(buf, count, NO);
616 fifo_send_stereo_16le(buf, count, YES);
619 fifo_send_stereo_16be(buf, count, NO);
622 fifo_send_stereo_16be(buf, count, YES);
629 fifo_send_monoral(pcm_data *buf, int count)
631 /* Convert format and sampling speed. */
632 switch (pcm_s.format) {
634 fifo_send_mono_ulaw(buf, count);
637 fifo_send_mono_8(buf, count, NO);
640 fifo_send_mono_8(buf, count, YES);
643 fifo_send_mono_16le(buf, count, NO);
646 fifo_send_mono_16le(buf, count, YES);
649 fifo_send_mono_16be(buf, count, NO);
652 fifo_send_mono_16be(buf, count, YES);
659 fifo_send_stereo_ulaw(pcm_data *buf, int count)
662 signed char dl, dl0, dl1, dr, dr0, dr1;
666 t[0] = ulaw2linear[tmpbuf.buff[0]];
668 t[0] = ulaw2linear[*buf++];
669 t[1] = ulaw2linear[*buf++];
671 if (pcm_s.speed == pcm_s.chipspeed) {
672 /* No reason to convert the pcm speed. */
673 outb(pcm_s.iobase + 12, t[0]);
674 outb(pcm_s.iobase + 12, t[1]);
676 for (i = 0; i < count; i++)
677 outb(pcm_s.iobase + 12, ulaw2linear[*buf++]);
679 /* Speed conversion with linear interpolation method. */
687 while (pcm_s.acc >= pcm_s.chipspeed) {
688 pcm_s.acc -= pcm_s.chipspeed;
693 dl1 = ulaw2linear[*buf++];
694 dr1 = ulaw2linear[*buf++];
698 dl = ((dl0 * (pcm_s.chipspeed - pcm_s.acc)) + (dl1 * pcm_s.acc))
700 dr = ((dr0 * (pcm_s.chipspeed - pcm_s.acc)) + (dr1 * pcm_s.acc))
702 outb(pcm_s.iobase + 12, dl);
703 outb(pcm_s.iobase + 12, dr);
704 pcm_s.acc += pcm_s.speed;
714 fifo_send_stereo_8(pcm_data *buf, int count, int uflag)
717 signed char dl, dl0, dl1, dr, dr0, dr1, zlev;
720 zlev = uflag ? -128 : 0;
723 t[0] = tmpbuf.buff[0] + zlev;
725 t[0] = *buf++ + zlev;
726 t[1] = *buf++ + zlev;
728 if (pcm_s.speed == pcm_s.chipspeed) {
729 /* No reason to convert the pcm speed. */
730 outb(pcm_s.iobase + 12, t[0]);
731 outb(pcm_s.iobase + 12, t[1]);
733 for (i = 0; i < count; i++)
734 outb(pcm_s.iobase + 12, *buf++ + zlev);
736 /* Speed conversion with linear interpolation method. */
744 while (pcm_s.acc >= pcm_s.chipspeed) {
745 pcm_s.acc -= pcm_s.chipspeed;
755 dl = ((dl0 * (pcm_s.chipspeed - pcm_s.acc)) + (dl1 * pcm_s.acc))
757 dr = ((dr0 * (pcm_s.chipspeed - pcm_s.acc)) + (dr1 * pcm_s.acc))
759 outb(pcm_s.iobase + 12, dl);
760 outb(pcm_s.iobase + 12, dr);
761 pcm_s.acc += pcm_s.speed;
771 fifo_send_stereo_16le(pcm_data *buf, int count, int uflag)
774 short dl, dl0, dl1, dr, dr0, dr1, zlev;
777 zlev = uflag ? -128 : 0;
779 for (i = 0; i < 4; i++)
780 t[i] = (tmpbuf.size > i) ? tmpbuf.buff[i] : *buf++;
782 if (pcm_s.speed == pcm_s.chipspeed) {
783 /* No reason to convert the pcm speed. */
784 outb(pcm_s.iobase + 12, t[1] + zlev);
785 outb(pcm_s.iobase + 12, t[0]);
786 outb(pcm_s.iobase + 12, t[3] + zlev);
787 outb(pcm_s.iobase + 12, t[2]);
788 count = count / 2 - 2;
789 for (i = 0; i < count; i++) {
790 outb(pcm_s.iobase + 12, *(buf + 1) + zlev);
791 outb(pcm_s.iobase + 12, *buf);
795 /* Speed conversion with linear interpolation method. */
798 dl1 = t[0] + ((t[1] + zlev) << 8);
799 dr1 = t[2] + ((t[3] + zlev) << 8);
803 while (pcm_s.acc >= pcm_s.chipspeed) {
804 pcm_s.acc -= pcm_s.chipspeed;
809 dl1 = *buf + ((*(buf + 1) + zlev) << 8);
811 dr1 = *buf + ((*(buf + 1) + zlev) << 8);
816 dl = ((dl0 * (pcm_s.chipspeed - pcm_s.acc)) + (dl1 * pcm_s.acc))
818 dr = ((dr0 * (pcm_s.chipspeed - pcm_s.acc)) + (dr1 * pcm_s.acc))
820 outb(pcm_s.iobase + 12, (dl >> 8) & 0xff);
821 outb(pcm_s.iobase + 12, dl & 0xff);
822 outb(pcm_s.iobase + 12, (dr >> 8) & 0xff);
823 outb(pcm_s.iobase + 12, dr & 0xff);
824 pcm_s.acc += pcm_s.speed;
834 fifo_send_stereo_16be(pcm_data *buf, int count, int uflag)
837 short dl, dl0, dl1, dr, dr0, dr1, zlev;
840 zlev = uflag ? -128 : 0;
842 for (i = 0; i < 4; i++)
843 t[i] = (tmpbuf.size > i) ? tmpbuf.buff[i] : *buf++;
845 if (pcm_s.speed == pcm_s.chipspeed) {
846 /* No reason to convert the pcm speed. */
847 outb(pcm_s.iobase + 12, t[0] + zlev);
848 outb(pcm_s.iobase + 12, t[1]);
849 outb(pcm_s.iobase + 12, t[2] + zlev);
850 outb(pcm_s.iobase + 12, t[3]);
851 count = count / 2 - 2;
852 for (i = 0; i < count; i++) {
853 outb(pcm_s.iobase + 12, *buf + zlev);
854 outb(pcm_s.iobase + 12, *(buf + 1));
858 /* Speed conversion with linear interpolation method. */
861 dl1 = ((t[0] + zlev) << 8) + t[1];
862 dr1 = ((t[2] + zlev) << 8) + t[3];
866 while (pcm_s.acc >= pcm_s.chipspeed) {
867 pcm_s.acc -= pcm_s.chipspeed;
872 dl1 = ((*buf + zlev) << 8) + *(buf + 1);
874 dr1 = ((*buf + zlev) << 8) + *(buf + 1);
879 dl = ((dl0 * (pcm_s.chipspeed - pcm_s.acc)) + (dl1 * pcm_s.acc))
881 dr = ((dr0 * (pcm_s.chipspeed - pcm_s.acc)) + (dr1 * pcm_s.acc))
883 outb(pcm_s.iobase + 12, (dl >> 8) & 0xff);
884 outb(pcm_s.iobase + 12, dl & 0xff);
885 outb(pcm_s.iobase + 12, (dr >> 8) & 0xff);
886 outb(pcm_s.iobase + 12, dr & 0xff);
887 pcm_s.acc += pcm_s.speed;
897 fifo_send_mono_ulaw(pcm_data *buf, int count)
900 signed char d, d0, d1;
902 if (pcm_s.speed == pcm_s.chipspeed)
903 /* No reason to convert the pcm speed. */
904 for (i = 0; i < count; i++) {
905 d = ulaw2linear[*buf++];
906 outb(pcm_s.iobase + 12, d);
907 outb(pcm_s.iobase + 12, d);
910 /* Speed conversion with linear interpolation method. */
912 d1 = ulaw2linear[*buf++];
915 while (pcm_s.acc >= pcm_s.chipspeed) {
916 pcm_s.acc -= pcm_s.chipspeed;
919 d1 = (i < count) ? ulaw2linear[*buf++] : 0;
921 d = ((d0 * (pcm_s.chipspeed - pcm_s.acc)) + (d1 * pcm_s.acc))
923 outb(pcm_s.iobase + 12, d);
924 outb(pcm_s.iobase + 12, d);
925 pcm_s.acc += pcm_s.speed;
934 fifo_send_mono_8(pcm_data *buf, int count, int uflag)
937 signed char d, d0, d1, zlev;
939 zlev = uflag ? -128 : 0;
941 if (pcm_s.speed == pcm_s.chipspeed)
942 /* No reason to convert the pcm speed. */
943 for (i = 0; i < count; i++) {
945 outb(pcm_s.iobase + 12, d);
946 outb(pcm_s.iobase + 12, d);
949 /* Speed conversion with linear interpolation method. */
954 while (pcm_s.acc >= pcm_s.chipspeed) {
955 pcm_s.acc -= pcm_s.chipspeed;
958 d1 = (i < count) ? *buf++ + zlev : 0;
960 d = ((d0 * (pcm_s.chipspeed - pcm_s.acc)) + (d1 * pcm_s.acc))
962 outb(pcm_s.iobase + 12, d);
963 outb(pcm_s.iobase + 12, d);
964 pcm_s.acc += pcm_s.speed;
973 fifo_send_mono_16le(pcm_data *buf, int count, int uflag)
976 short d, d0, d1, zlev;
979 zlev = uflag ? -128 : 0;
981 for (i = 0; i < 2; i++)
982 t[i] = (tmpbuf.size > i) ? tmpbuf.buff[i] : *buf++;
984 if (pcm_s.speed == pcm_s.chipspeed) {
985 /* No reason to convert the pcm speed. */
986 outb(pcm_s.iobase + 12, t[1] + zlev);
987 outb(pcm_s.iobase + 12, t[0]);
988 outb(pcm_s.iobase + 12, t[1] + zlev);
989 outb(pcm_s.iobase + 12, t[0]);
990 count = count / 2 - 1;
991 for (i = 0; i < count; i++) {
992 outb(pcm_s.iobase + 12, *(buf + 1) + zlev);
993 outb(pcm_s.iobase + 12, *buf);
994 outb(pcm_s.iobase + 12, *(buf + 1) + zlev);
995 outb(pcm_s.iobase + 12, *buf);
999 /* Speed conversion with linear interpolation method. */
1001 d1 = t[0] + ((t[1] + zlev) << 8);
1005 while (pcm_s.acc >= pcm_s.chipspeed) {
1006 pcm_s.acc -= pcm_s.chipspeed;
1010 d1 = *buf + ((*(buf + 1) + zlev) << 8);
1015 d = ((d0 * (pcm_s.chipspeed - pcm_s.acc)) + (d1 * pcm_s.acc))
1017 outb(pcm_s.iobase + 12, (d >> 8) & 0xff);
1018 outb(pcm_s.iobase + 12, d & 0xff);
1019 outb(pcm_s.iobase + 12, (d >> 8) & 0xff);
1020 outb(pcm_s.iobase + 12, d & 0xff);
1021 pcm_s.acc += pcm_s.speed;
1030 fifo_send_mono_16be(pcm_data *buf, int count, int uflag)
1033 short d, d0, d1, zlev;
1036 zlev = uflag ? -128 : 0;
1038 for (i = 0; i < 2; i++)
1039 t[i] = (tmpbuf.size > i) ? tmpbuf.buff[i] : *buf++;
1041 if (pcm_s.speed == pcm_s.chipspeed) {
1042 /* No reason to convert the pcm speed. */
1043 outb(pcm_s.iobase + 12, t[0] + zlev);
1044 outb(pcm_s.iobase + 12, t[1]);
1045 outb(pcm_s.iobase + 12, t[0] + zlev);
1046 outb(pcm_s.iobase + 12, t[1]);
1047 count = count / 2 - 1;
1048 for (i = 0; i < count; i++) {
1049 outb(pcm_s.iobase + 12, *buf + zlev);
1050 outb(pcm_s.iobase + 12, *(buf + 1));
1051 outb(pcm_s.iobase + 12, *buf + zlev);
1052 outb(pcm_s.iobase + 12, *(buf + 1));
1056 /* Speed conversion with linear interpolation method. */
1058 d1 = ((t[0] + zlev) << 8) + t[1];
1062 while (pcm_s.acc >= pcm_s.chipspeed) {
1063 pcm_s.acc -= pcm_s.chipspeed;
1067 d1 = ((*buf + zlev) << 8) + *(buf + 1);
1072 d = ((d0 * (pcm_s.chipspeed - pcm_s.acc)) + (d1 * pcm_s.acc))
1074 /* outb(pcm_s.iobase + 12, d & 0xff);
1075 outb(pcm_s.iobase + 12, (d >> 8) & 0xff);
1076 outb(pcm_s.iobase + 12, d & 0xff);
1077 outb(pcm_s.iobase + 12, (d >> 8) & 0xff); */
1078 outb(pcm_s.iobase + 12, (d >> 8) & 0xff);
1079 outb(pcm_s.iobase + 12, d & 0xff);
1080 outb(pcm_s.iobase + 12, (d >> 8) & 0xff);
1081 outb(pcm_s.iobase + 12, d & 0xff);
1082 pcm_s.acc += pcm_s.speed;
1091 fifo_input_block(void)
1095 if (pcm_s.pdma_chunkcount) {
1096 /* Update chunksize and then receive the next chunk from FIFO. */
1097 chunksize = pcm_s.pdma_count / pcm_s.pdma_chunkcount--;
1098 fifo_recv(pcm_s.pdma_buf, chunksize);
1099 pcm_s.pdma_buf += chunksize;
1100 pcm_s.pdma_count -= chunksize;
1102 /* ??? something wrong... */
1103 printf("nss0: chunkcount overrun\n");
1108 fifo_recv(pcm_data *buf, int count)
1112 if (count > tmpbuf.size) {
1113 for (i = 0; i < tmpbuf.size; i++)
1114 *buf++ = tmpbuf.buff[i];
1115 count -= tmpbuf.size;
1118 fifo_recv_stereo(buf, count);
1120 fifo_recv_monoral(buf, count);
1122 for (i = 0; i < count; i++)
1123 *buf++ = tmpbuf.buff[i];
1124 for (i = 0; i < tmpbuf.size - count; i++)
1125 tmpbuf.buff[i] = tmpbuf.buff[i + count];
1126 tmpbuf.size -= count;
1130 printf("fifo_recv(): %d bytes received\n",
1131 ((count / (pcm_s.bytes << pcm_s.stereo)) * pcm_s.chipspeed
1132 / pcm_s.speed) * pcm_s.bytes * 2);
1138 fifo_recv_stereo(pcm_data *buf, int count)
1140 /* Convert format and sampling speed. */
1141 switch (pcm_s.format) {
1143 fifo_recv_stereo_ulaw(buf, count);
1146 fifo_recv_stereo_8(buf, count, NO);
1149 fifo_recv_stereo_8(buf, count, YES);
1152 fifo_recv_stereo_16le(buf, count, NO);
1155 fifo_recv_stereo_16le(buf, count, YES);
1158 fifo_recv_stereo_16be(buf, count, NO);
1161 fifo_recv_stereo_16be(buf, count, YES);
1168 fifo_recv_monoral(pcm_data *buf, int count)
1170 /* Convert format and sampling speed. */
1171 switch (pcm_s.format) {
1173 fifo_recv_mono_ulaw(buf, count);
1176 fifo_recv_mono_8(buf, count, NO);
1179 fifo_recv_mono_8(buf, count, YES);
1182 fifo_recv_mono_16le(buf, count, NO);
1185 fifo_recv_mono_16le(buf, count, YES);
1188 fifo_recv_mono_16be(buf, count, NO);
1191 fifo_recv_mono_16be(buf, count, YES);
1198 fifo_recv_stereo_ulaw(pcm_data *buf, int count)
1201 signed char dl, dl0, dl1, dr, dr0, dr1;
1204 if (pcm_s.speed == pcm_s.chipspeed) {
1205 /* No reason to convert the pcm speed. */
1206 for (i = 0; i < cnt; i++) {
1207 *buf++ = linear2ulaw[inb(pcm_s.iobase + 12)];
1208 *buf++ = linear2ulaw[inb(pcm_s.iobase + 12)];
1211 *buf++ = linear2ulaw[inb(pcm_s.iobase + 12)];
1212 tmpbuf.buff[0] = linear2ulaw[inb(pcm_s.iobase + 12)];
1216 /* Speed conversion with linear interpolation method. */
1219 dl1 = inb(pcm_s.iobase + 12);
1220 dr1 = inb(pcm_s.iobase + 12);
1221 for (i = 0; i < cnt; i++) {
1222 while (pcm_s.acc >= pcm_s.speed) {
1223 pcm_s.acc -= pcm_s.speed;
1226 dl1 = inb(pcm_s.iobase + 12);
1227 dr1 = inb(pcm_s.iobase + 12);
1229 dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
1231 dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
1233 *buf++ = linear2ulaw[dl & 0xff];
1234 *buf++ = linear2ulaw[dr & 0xff];
1235 pcm_s.acc += pcm_s.chipspeed;
1238 while (pcm_s.acc >= pcm_s.speed) {
1239 pcm_s.acc -= pcm_s.speed;
1242 dl1 = inb(pcm_s.iobase + 12);
1243 dr1 = inb(pcm_s.iobase + 12);
1245 dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
1247 dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
1249 *buf++ = linear2ulaw[dl & 0xff];
1250 tmpbuf.buff[0] = linear2ulaw[dr & 0xff];
1261 fifo_recv_stereo_8(pcm_data *buf, int count, int uflag)
1264 signed char dl, dl0, dl1, dr, dr0, dr1, zlev;
1266 zlev = uflag ? -128 : 0;
1269 if (pcm_s.speed == pcm_s.chipspeed) {
1270 /* No reason to convert the pcm speed. */
1271 for (i = 0; i < cnt; i++) {
1272 *buf++ = inb(pcm_s.iobase + 12) + zlev;
1273 *buf++ = inb(pcm_s.iobase + 12) + zlev;
1276 *buf++ = inb(pcm_s.iobase + 12) + zlev;
1277 tmpbuf.buff[0] = inb(pcm_s.iobase + 12) + zlev;
1281 /* Speed conversion with linear interpolation method. */
1284 dl1 = inb(pcm_s.iobase + 12);
1285 dr1 = inb(pcm_s.iobase + 12);
1286 for (i = 0; i < cnt; i++) {
1287 while (pcm_s.acc >= pcm_s.speed) {
1288 pcm_s.acc -= pcm_s.speed;
1291 dl1 = inb(pcm_s.iobase + 12);
1292 dr1 = inb(pcm_s.iobase + 12);
1294 dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
1296 dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
1300 pcm_s.acc += pcm_s.chipspeed;
1303 while (pcm_s.acc >= pcm_s.speed) {
1304 pcm_s.acc -= pcm_s.speed;
1307 dl1 = inb(pcm_s.iobase + 12);
1308 dr1 = inb(pcm_s.iobase + 12);
1310 dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
1312 dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
1315 tmpbuf.buff[0] = dr + zlev;
1326 fifo_recv_stereo_16le(pcm_data *buf, int count, int uflag)
1329 short dl, dl0, dl1, dr, dr0, dr1, zlev;
1332 zlev = uflag ? -128 : 0;
1335 if (pcm_s.speed == pcm_s.chipspeed) {
1336 /* No reason to convert the pcm speed. */
1337 for (i = 0; i < cnt; i++) {
1338 *(buf + 1) = inb(pcm_s.iobase + 12) + zlev;
1339 *buf = inb(pcm_s.iobase + 12);
1340 *(buf + 3) = inb(pcm_s.iobase + 12) + zlev;
1341 *(buf + 2) = inb(pcm_s.iobase + 12);
1345 t[1] = inb(pcm_s.iobase + 12) + zlev;
1346 t[0] = inb(pcm_s.iobase + 12);
1347 t[3] = inb(pcm_s.iobase + 12) + zlev;
1348 t[2] = inb(pcm_s.iobase + 12);
1350 for (i = 0; i < count % 4; i++)
1352 for (i = count % 4; i < 4; i++)
1353 tmpbuf.buff[tmpbuf.size++] = t[i];
1356 /* Speed conversion with linear interpolation method. */
1359 dl1 = inb(pcm_s.iobase + 12) << 8;
1360 dl1 |= inb(pcm_s.iobase + 12);
1361 dr1 = inb(pcm_s.iobase + 12) << 8;
1362 dr1 |= inb(pcm_s.iobase + 12);
1363 for (i = 0; i < cnt; i++) {
1364 while (pcm_s.acc >= pcm_s.speed) {
1365 pcm_s.acc -= pcm_s.speed;
1368 dl1 = inb(pcm_s.iobase + 12) << 8;
1369 dl1 |= inb(pcm_s.iobase + 12);
1370 dr1 = inb(pcm_s.iobase + 12) << 8;
1371 dr1 |= inb(pcm_s.iobase + 12);
1373 dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
1375 dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
1378 *buf++ = ((dl >> 8) & 0xff) + zlev;
1380 *buf++ = ((dr >> 8) & 0xff) + zlev;
1381 pcm_s.acc += pcm_s.chipspeed;
1384 while (pcm_s.acc >= pcm_s.speed) {
1385 pcm_s.acc -= pcm_s.speed;
1388 dl1 = inb(pcm_s.iobase + 12) << 8;
1389 dl1 |= inb(pcm_s.iobase + 12);
1390 dr1 = inb(pcm_s.iobase + 12) << 8;
1391 dr1 |= inb(pcm_s.iobase + 12);
1393 dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
1395 dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
1398 t[1] = ((dl >> 8) & 0xff) + zlev;
1400 t[3] = ((dr >> 8) & 0xff) + zlev;
1402 for (i = 0; i < count % 4; i++)
1404 for (i = count % 4; i < 4; i++)
1405 tmpbuf.buff[tmpbuf.size++] = t[i];
1415 fifo_recv_stereo_16be(pcm_data *buf, int count, int uflag)
1418 short dl, dl0, dl1, dr, dr0, dr1, zlev;
1421 zlev = uflag ? -128 : 0;
1424 if (pcm_s.speed == pcm_s.chipspeed) {
1425 /* No reason to convert the pcm speed. */
1426 for (i = 0; i < cnt; i++) {
1427 *buf++ = inb(pcm_s.iobase + 12) + zlev;
1428 *buf++ = inb(pcm_s.iobase + 12);
1429 *buf++ = inb(pcm_s.iobase + 12) + zlev;
1430 *buf++ = inb(pcm_s.iobase + 12);
1433 t[0] = inb(pcm_s.iobase + 12) + zlev;
1434 t[1] = inb(pcm_s.iobase + 12);
1435 t[2] = inb(pcm_s.iobase + 12) + zlev;
1436 t[3] = inb(pcm_s.iobase + 12);
1438 for (i = 0; i < count % 4; i++)
1440 for (i = count % 4; i < 4; i++)
1441 tmpbuf.buff[tmpbuf.size++] = t[i];
1444 /* Speed conversion with linear interpolation method. */
1447 dl1 = inb(pcm_s.iobase + 12) << 8;
1448 dl1 |= inb(pcm_s.iobase + 12);
1449 dr1 = inb(pcm_s.iobase + 12) << 8;
1450 dr1 |= inb(pcm_s.iobase + 12);
1451 for (i = 0; i < cnt; i++) {
1452 while (pcm_s.acc >= pcm_s.speed) {
1453 pcm_s.acc -= pcm_s.speed;
1456 dl1 = inb(pcm_s.iobase + 12) << 8;
1457 dl1 |= inb(pcm_s.iobase + 12);
1458 dr1 = inb(pcm_s.iobase + 12) << 8;
1459 dr1 |= inb(pcm_s.iobase + 12);
1461 dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
1463 dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
1465 *buf++ = ((dl >> 8) & 0xff) + zlev;
1467 *buf++ = ((dr >> 8) & 0xff) + zlev;
1469 pcm_s.acc += pcm_s.chipspeed;
1472 while (pcm_s.acc >= pcm_s.speed) {
1473 pcm_s.acc -= pcm_s.speed;
1476 dl1 = inb(pcm_s.iobase + 12) << 8;
1477 dl1 |= inb(pcm_s.iobase + 12);
1478 dr1 = inb(pcm_s.iobase + 12) << 8;
1479 dr1 |= inb(pcm_s.iobase + 12);
1481 dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
1483 dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
1485 t[0] = ((dl >> 8) & 0xff) + zlev;
1487 t[2] = ((dr >> 8) & 0xff) + zlev;
1490 for (i = 0; i < count % 4; i++)
1492 for (i = count % 4; i < 4; i++)
1493 tmpbuf.buff[tmpbuf.size++] = t[i];
1503 fifo_recv_mono_ulaw(pcm_data *buf, int count)
1506 signed char d, d0, d1;
1508 if (pcm_s.speed == pcm_s.chipspeed) {
1509 /* No reason to convert the pcm speed. */
1510 for (i = 0; i < count; i++) {
1511 d = ((signed char)inb(pcm_s.iobase + 12)
1512 + (signed char)inb(pcm_s.iobase + 12)) >> 1;
1513 *buf++ = linear2ulaw[d & 0xff];
1516 /* Speed conversion with linear interpolation method. */
1518 d1 = ((signed char)inb(pcm_s.iobase + 12)
1519 + (signed char)inb(pcm_s.iobase + 12)) >> 1;
1520 for (i = 0; i < count; i++) {
1521 while (pcm_s.acc >= pcm_s.speed) {
1522 pcm_s.acc -= pcm_s.speed;
1524 d1 = ((signed char)inb(pcm_s.iobase + 12)
1525 + (signed char)inb(pcm_s.iobase + 12)) >> 1;
1527 d = ((d0 * (pcm_s.speed - pcm_s.acc)) + (d1 * pcm_s.acc))
1529 *buf++ = linear2ulaw[d & 0xff];
1530 pcm_s.acc += pcm_s.chipspeed;
1539 fifo_recv_mono_8(pcm_data *buf, int count, int uflag)
1542 signed char d, d0, d1, zlev;
1544 zlev = uflag ? -128 : 0;
1546 if (pcm_s.speed == pcm_s.chipspeed) {
1547 /* No reason to convert the pcm speed. */
1548 for (i = 0; i < count; i++) {
1549 d = ((signed char)inb(pcm_s.iobase + 12)
1550 + (signed char)inb(pcm_s.iobase + 12)) >> 1;
1554 /* Speed conversion with linear interpolation method. */
1556 d1 = ((signed char)inb(pcm_s.iobase + 12)
1557 + (signed char)inb(pcm_s.iobase + 12)) >> 1;
1558 for (i = 0; i < count; i++) {
1559 while (pcm_s.acc >= pcm_s.speed) {
1560 pcm_s.acc -= pcm_s.speed;
1562 d1 = ((signed char)inb(pcm_s.iobase + 12)
1563 + (signed char)inb(pcm_s.iobase + 12)) >> 1;
1565 d = ((d0 * (pcm_s.speed - pcm_s.acc)) + (d1 * pcm_s.acc))
1568 pcm_s.acc += pcm_s.chipspeed;
1577 fifo_recv_mono_16le(pcm_data *buf, int count, int uflag)
1580 short d, d0, d1, el, er, zlev;
1582 zlev = uflag ? -128 : 0;
1585 if (pcm_s.speed == pcm_s.chipspeed) {
1586 /* No reason to convert the pcm speed. */
1587 for (i = 0; i < cnt; i++) {
1588 el = inb(pcm_s.iobase + 12) << 8;
1589 el |= inb(pcm_s.iobase + 12);
1590 er = inb(pcm_s.iobase + 12) << 8;
1591 er |= inb(pcm_s.iobase + 12);
1594 *buf++ = ((d >> 8) & 0xff) + zlev;
1597 el = inb(pcm_s.iobase + 12) << 8;
1598 el |= inb(pcm_s.iobase + 12);
1599 er = inb(pcm_s.iobase + 12) << 8;
1600 er |= inb(pcm_s.iobase + 12);
1603 tmpbuf.buff[0] = ((d >> 8) & 0xff) + zlev;
1607 /* Speed conversion with linear interpolation method. */
1609 el = inb(pcm_s.iobase + 12) << 8;
1610 el |= inb(pcm_s.iobase + 12);
1611 er = inb(pcm_s.iobase + 12) << 8;
1612 er |= inb(pcm_s.iobase + 12);
1613 d1 = (el + er) >> 1;
1614 for (i = 0; i < cnt; i++) {
1615 while (pcm_s.acc >= pcm_s.speed) {
1616 pcm_s.acc -= pcm_s.speed;
1618 el = inb(pcm_s.iobase + 12) << 8;
1619 el |= inb(pcm_s.iobase + 12);
1620 er = inb(pcm_s.iobase + 12) << 8;
1621 er |= inb(pcm_s.iobase + 12);
1622 d1 = (el + er) >> 1;
1624 d = ((d0 * (pcm_s.speed - pcm_s.acc)) + (d1 * pcm_s.acc))
1627 *buf++ = ((d >> 8) & 0xff) + zlev;
1628 pcm_s.acc += pcm_s.chipspeed;
1631 while (pcm_s.acc >= pcm_s.speed) {
1632 pcm_s.acc -= pcm_s.speed;
1634 el = inb(pcm_s.iobase + 12) << 8;
1635 el |= inb(pcm_s.iobase + 12);
1636 er = inb(pcm_s.iobase + 12) << 8;
1637 er |= inb(pcm_s.iobase + 12);
1638 d1 = (el + er) >> 1;
1640 d = ((d0 * (pcm_s.speed - pcm_s.acc)) + (d1 * pcm_s.acc))
1643 tmpbuf.buff[0] = ((d >> 8) & 0xff) + zlev;
1653 fifo_recv_mono_16be(pcm_data *buf, int count, int uflag)
1656 short d, d0, d1, el, er, zlev;
1658 zlev = uflag ? -128 : 0;
1661 if (pcm_s.speed == pcm_s.chipspeed) {
1662 /* No reason to convert the pcm speed. */
1663 for (i = 0; i < cnt; i++) {
1664 el = inb(pcm_s.iobase + 12) << 8;
1665 el |= inb(pcm_s.iobase + 12);
1666 er = inb(pcm_s.iobase + 12) << 8;
1667 er |= inb(pcm_s.iobase + 12);
1669 *buf++ = ((d >> 8) & 0xff) + zlev;
1673 el = inb(pcm_s.iobase + 12) << 8;
1674 el |= inb(pcm_s.iobase + 12);
1675 er = inb(pcm_s.iobase + 12) << 8;
1676 er |= inb(pcm_s.iobase + 12);
1678 *buf++ = ((d >> 8) & 0xff) + zlev;
1679 tmpbuf.buff[0] = d & 0xff;
1683 /* Speed conversion with linear interpolation method. */
1685 el = inb(pcm_s.iobase + 12) << 8;
1686 el |= inb(pcm_s.iobase + 12);
1687 er = inb(pcm_s.iobase + 12) << 8;
1688 er |= inb(pcm_s.iobase + 12);
1689 d1 = (el + er) >> 1;
1690 for (i = 0; i < cnt; i++) {
1691 while (pcm_s.acc >= pcm_s.speed) {
1692 pcm_s.acc -= pcm_s.speed;
1694 el = inb(pcm_s.iobase + 12) << 8;
1695 el |= inb(pcm_s.iobase + 12);
1696 er = inb(pcm_s.iobase + 12) << 8;
1697 er |= inb(pcm_s.iobase + 12);
1698 d1 = (el + er) >> 1;
1700 d = ((d0 * (pcm_s.speed - pcm_s.acc)) + (d1 * pcm_s.acc))
1702 *buf++ = ((d >> 8) & 0xff) + zlev;
1704 pcm_s.acc += pcm_s.chipspeed;
1707 while (pcm_s.acc >= pcm_s.speed) {
1708 pcm_s.acc -= pcm_s.speed;
1710 el = inb(pcm_s.iobase + 12) << 8;
1711 el |= inb(pcm_s.iobase + 12);
1712 er = inb(pcm_s.iobase + 12) << 8;
1713 er |= inb(pcm_s.iobase + 12);
1714 d1 = (el + er) >> 1;
1716 d = ((d0 * (pcm_s.speed - pcm_s.acc)) + (d1 * pcm_s.acc))
1718 *buf++ = ((d >> 8) & 0xff) + zlev;
1719 tmpbuf.buff[0] = d & 0xff;
1731 fifo_stop(); /* stop FIFO */
1732 fifo_reset(); /* reset FIFO buffer */
1734 /* Reset driver's status. */
1735 pcm_s.intr_busy = NO;
1736 pcm_s.intr_last = NO;
1737 pcm_s.intr_trailer = NO;
1742 DEB(printf("nss_stop\n"));
1749 /* Initialize registers on the board. */
1751 if (pcm_s.board_type == PC980173_FAMILY)
1754 /* Set default volume. */
1755 set_volume(DEFAULT_VOLUME);
1757 /* Initialize driver's status. */
1759 nss_initialized = YES;
1764 * Codes for global use
1768 probe_nss(struct address_info *hw_config)
1770 return nss_detect(hw_config);
1775 attach_nss(struct address_info *hw_config)
1777 if (pcm_s.board_type == NO_SUPPORTED_BOARD)
1780 /* Initialize the board. */
1783 conf_printf(nss_operations.name, hw_config);
1785 if (num_audiodevs < MAX_AUDIO_DEV) {
1786 my_dev = num_audiodevs++;
1787 audio_devs[my_dev] = &nss_operations;
1788 /* audio_devs[my_dev]->buffcount = DSP_BUFFCOUNT; */
1789 audio_devs[my_dev]->buffsize = DSP_BUFFSIZE;
1791 printf("\nbuffsize = %d", DSP_BUFFSIZE);
1794 printf("nss0: Too many PCM devices available");
1801 nss_detect(struct address_info *hw_config)
1803 int opna_iobase = 0x188, irq = 12, i;
1806 if (hw_config->io_base == -1) {
1807 printf("nss0: iobase not specified. Assume default port(0x%x)\n",
1809 hw_config->io_base = PCM86_IOBASE;
1811 pcm_s.iobase = hw_config->io_base;
1813 /* auto configuration */
1814 tmp = (inb(pcm_s.iobase) & 0xf0) >> 4;
1817 * Remap MATE-X PCM Sound ID register (0xA460 -> 0xB460)
1818 * to avoid corrision with 86 Sound System.
1821 printf("nss0: Found MATE-X PCM Sound ID\n");
1822 printf("nss0: Remaped 0xa460 to 0xb460\n");
1829 tmp = inb(pcm_s.iobase) & 0xfc;
1830 switch ((tmp & 0xf0) >> 4) {
1832 opna_iobase = 0x188;
1833 pcm_s.board_type = PC980173_FAMILY;
1836 opna_iobase = 0x288;
1837 pcm_s.board_type = PC980173_FAMILY;
1840 opna_iobase = 0x188;
1841 pcm_s.board_type = PC980186_FAMILY;
1844 opna_iobase = 0x288;
1845 pcm_s.board_type = PC980186_FAMILY;
1848 pcm_s.board_type = NO_SUPPORTED_BOARD;
1852 /* Enable OPNA(YM2608) facilities. */
1853 outb(pcm_s.iobase, tmp | 0x01);
1855 /* Wait for OPNA to be ready. */
1856 i = 100000; /* Some large value */
1857 while((inb(opna_iobase) & 0x80) && (i-- > 0));
1859 /* Make IOA/IOB port ready (IOA:input, IOB:output) */
1860 outb(opna_iobase, 0x07);
1861 outb(0x5f, 0); /* Because OPNA ports are comparatively slow(?), */
1862 outb(0x5f, 0); /* we'd better wait a moment. */
1865 tmp = inb(opna_iobase + 2) & 0x3f;
1866 outb(opna_iobase + 2, tmp | 0x80);
1868 /* Wait for OPNA to be ready. */
1869 i = 100000; /* Some large value */
1870 while((inb(opna_iobase) & 0x80) && (i-- > 0));
1872 /* Get irq number from IOA port. */
1873 outb(opna_iobase, 0x0e);
1878 tmp = inb(opna_iobase + 2) & 0xc0;
1880 case 0: /* INT0 (IRQ3)*/
1883 case 1: /* INT6 (IRQ13)*/
1886 case 2: /* INT4 (IRQ10)*/
1889 case 3: /* INT5 (IRQ12)*/
1892 default: /* error */
1896 /* Wait for OPNA to be ready. */
1897 i = 100000; /* Some large value */
1898 while((inb(opna_iobase) & 0x80) && (i-- > 0));
1900 /* Reset OPNA timer register. */
1901 outb(opna_iobase, 0x27);
1906 outb(opna_iobase + 2, 0x30);
1908 /* Ok. Detection finished. */
1909 snprintf(nss_operations.name, sizeof(nss_operations.name),
1910 "%s", board_name[pcm_s.board_type]);
1911 nss_initialized = NO;
1914 if ((hw_config->irq > 0) && (hw_config->irq != irq))
1915 printf("nss0: change irq %d -> %d\n", hw_config->irq, irq);
1916 hw_config->irq = irq;
1918 pcm_s.osp = hw_config->osp;
1925 nss_open(int dev, int mode)
1929 if (!nss_initialized)
1932 if (pcm_s.intr_busy || pcm_s.opened)
1935 if ((err = snd_set_irq_handler(pcm_s.irq, nssintr, pcm_s.osp)) < 0)
1941 pcm_s.intr_mode = IMODE_NONE;
1951 /* snd_release_irq(pcm_s.irq); */
1958 nss_output_block(int dev, unsigned long buf, int count, int intrflag,
1961 unsigned long flags, cnt;
1965 printf("nss_output_block():");
1966 if (audio_devs[dev]->dmap_out->flags & DMA_BUSY)
1967 printf(" DMA_BUSY");
1968 if (audio_devs[dev]->dmap_out->flags & DMA_RESTART)
1969 printf(" DMA_RESTART");
1970 if (audio_devs[dev]->dmap_out->flags & DMA_ACTIVE)
1971 printf(" DMA_ACTIVE");
1972 if (audio_devs[dev]->dmap_out->flags & DMA_STARTED)
1973 printf(" DMA_STARTED");
1974 if (audio_devs[dev]->dmap_out->flags & DMA_ALLOC_DONE)
1975 printf(" DMA_ALLOC_DONE");
1980 DISABLE_INTR(flags);
1984 printf("nss_output_block(): count = %d, intrsize= %d\n",
1985 count, pcm_s.intr_size);
1988 pcm_s.pdma_buf = (pcm_data *)buf;
1989 pcm_s.pdma_count = count;
1990 pcm_s.pdma_chunkcount = 1;
1991 maxchunksize = (((PCM86_FIFOSIZE - pcm_s.intr_size * 2)
1992 / (pcm_s.bytes * 2)) * pcm_s.speed
1993 / pcm_s.chipspeed) * (pcm_s.bytes << pcm_s.stereo);
1994 if (count > maxchunksize)
1995 pcm_s.pdma_chunkcount = 2 * count / maxchunksize;
1997 * Let chunksize = (float)count / (float)pcm_s.pdma_chunkcount.
1998 * Data of size chunksize is sent to the FIFO buffer on the 86-board
1999 * on every occuring of interrupt.
2000 * By assuming that pcm_s.intr_size < PCM86_FIFOSIZE / 2, we can conclude
2001 * that the FIFO buffer never overflows from the following lemma.
2004 * maxchunksize / 2 <= chunksize <= maxchunksize.
2005 * (Though pcm_s.pdma_chunkcount is obtained through the flooring
2006 * function, this inequality holds.)
2010 fifo_output_block();
2012 pcm_s.intr_last = NO;
2013 pcm_s.intr_mode = IMODE_OUTPUT;
2014 if (!pcm_s.intr_busy)
2015 fifo_start(IMODE_OUTPUT);
2016 pcm_s.intr_busy = YES;
2019 RESTORE_INTR(flags);
2025 nss_start_input(int dev, unsigned long buf, int count, int intrflag,
2028 unsigned long flags, cnt;
2032 printf("nss_start_input():");
2033 if (audio_devs[dev]->dmap_in->flags & DMA_BUSY)
2034 printf(" DMA_BUSY");
2035 if (audio_devs[dev]->dmap_in->flags & DMA_RESTART)
2036 printf(" DMA_RESTART");
2037 if (audio_devs[dev]->dmap_in->flags & DMA_ACTIVE)
2038 printf(" DMA_ACTIVE");
2039 if (audio_devs[dev]->dmap_in->flags & DMA_STARTED)
2040 printf(" DMA_STARTED");
2041 if (audio_devs[dev]->dmap_in->flags & DMA_ALLOC_DONE)
2042 printf(" DMA_ALLOC_DONE");
2047 DISABLE_INTR(flags);
2050 pcm_s.intr_size = PCM86_INTRSIZE_IN;
2053 printf("nss_start_input(): count = %d, intrsize= %d\n",
2054 count, pcm_s.intr_size);
2057 pcm_s.pdma_buf = (pcm_data *)buf;
2058 pcm_s.pdma_count = count;
2059 pcm_s.pdma_chunkcount = 1;
2060 maxchunksize = ((pcm_s.intr_size / (pcm_s.bytes * 2)) * pcm_s.speed
2061 / pcm_s.chipspeed) * (pcm_s.bytes << pcm_s.stereo);
2062 if (count > maxchunksize)
2063 pcm_s.pdma_chunkcount = 2 * count / maxchunksize;
2065 pcm_s.intr_mode = IMODE_INPUT;
2066 if (!pcm_s.intr_busy)
2067 fifo_start(IMODE_INPUT);
2068 pcm_s.intr_busy = YES;
2071 RESTORE_INTR(flags);
2077 nss_ioctl(int dev, u_int cmd, ioctl_arg arg, int local)
2080 case SOUND_PCM_WRITE_RATE:
2082 return set_speed((int) arg);
2083 return *(int *) arg = set_speed((*(int *) arg));
2085 case SOUND_PCM_READ_RATE:
2088 return *(int *) arg = pcm_s.speed;
2090 case SNDCTL_DSP_STEREO:
2092 return set_stereo((int) arg);
2093 return *(int *) arg = set_stereo((*(int *) arg));
2095 case SOUND_PCM_WRITE_CHANNELS:
2097 return set_stereo((int) arg - 1) + 1;
2098 return *(int *) arg = set_stereo((*(int *) arg) - 1) + 1;
2100 case SOUND_PCM_READ_CHANNELS:
2102 return pcm_s.stereo + 1;
2103 return *(int *) arg = pcm_s.stereo + 1;
2105 case SNDCTL_DSP_SETFMT:
2107 return set_format((int) arg);
2108 return *(int *) arg = set_format((*(int *) arg));
2110 case SOUND_PCM_READ_BITS:
2112 return pcm_s.bytes * 8;
2113 return *(int *) arg = pcm_s.bytes * 8;
2116 /* Invalid ioctl request */
2122 nss_prepare_for_input(int dev, int bufsize, int nbufs)
2124 pcm_s.intr_size = PCM86_INTRSIZE_IN;
2125 pcm_s.intr_mode = IMODE_NONE;
2130 DEB(printf("nss_prepare_for_input\n"));
2137 nss_prepare_for_output(int dev, int bufsize, int nbufs)
2139 pcm_s.intr_size = PCM86_INTRSIZE_OUT;
2140 pcm_s.intr_mode = IMODE_NONE;
2145 DEB(printf("nss_prepare_for_output\n"));
2159 nss_halt_xfer(int dev)
2163 DEB(printf("nss_halt_xfer\n"));
2172 if ((inb(pcm_s.iobase + 8) & 0x10) == 0)
2173 return; /* not FIFO intr. */
2175 switch(pcm_s.intr_mode) {
2177 if (pcm_s.intr_trailer) {
2178 DEB(printf("nssintr(): fifo_reset\n"));
2180 pcm_s.intr_trailer = NO;
2181 pcm_s.intr_busy = NO;
2183 if (pcm_s.pdma_count > 0)
2184 fifo_output_block();
2186 DMAbuf_outputintr(my_dev, 1);
2187 /* Reset intr. flag. */
2188 tmp = inb(pcm_s.iobase + 8);
2189 outb(pcm_s.iobase + 8, tmp & ~0x10);
2190 outb(pcm_s.iobase + 8, tmp | 0x10);
2195 if (pcm_s.pdma_count == 0)
2196 DMAbuf_inputintr(my_dev);
2197 /* Reset intr. flag. */
2198 tmp = inb(pcm_s.iobase + 8);
2199 outb(pcm_s.iobase + 8, tmp & ~0x10);
2200 outb(pcm_s.iobase + 8, tmp | 0x10);
2205 printf("nss0: unexpected interrupt\n");
2210 #endif /* EXCLUDE_NSS, EXCLUDE_AUDIO */
2212 #endif /* CONFIGURE_SOUNDCARD */