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
28 * $FreeBSD: src/sys/i386/isa/sound/pcm86.c,v 1.9 1999/08/28 00:45:19 peter Exp $
29 * $DragonFly: src/sys/i386/isa/sound/Attic/pcm86.c,v 1.2 2003/06/17 04:28:38 dillon Exp $
34 * This file DOES NOT belong to the VoxWare distribution though it works
35 * as part of the VoxWare drivers. It is FreeBSD(98) original.
36 * -- Nagao (nagao@cs.titech.ac.jp)
40 #include <i386/isa/sound/sound_config.h>
42 #ifdef CONFIGURE_SOUNDCARD
44 #if !defined(EXCLUDE_NSS) && !defined(EXCLUDE_AUDIO)
56 #define IMODE_OUTPUT 2
58 /* PC-9801-86 specific constants */
59 #define PCM86_IOBASE 0xa460 /* PCM I/O ports */
60 #define PCM86_FIFOSIZE 32768 /* There is a 32kB FIFO buffer on 86-board */
62 /* XXX -- These values should be chosen appropriately. */
63 #define PCM86_INTRSIZE_OUT 1024
64 #define PCM86_INTRSIZE_IN (PCM86_FIFOSIZE / 2 - 128)
65 #define DEFAULT_VOLUME 15 /* 0(min) - 15(max) */
69 * Switches for debugging and experiments
72 /* #define NSS_DEBUG */
83 * Private variables and types
86 typedef unsigned char pcm_data;
89 NO_SUPPORTED_BOARD = 0,
94 static char *board_name[] = {
95 /* Each must be of the length less than 32 bytes. */
97 "PC-9801-86 soundboard",
98 "PC-9801-73 soundboard"
101 /* Current status of the driver */
105 enum board_type board_type;
133 static int my_dev = 0;
134 static char nss_initialized = NO;
136 /* 86-board supports only the following rates. */
137 static int rates_tbl[8] = {
138 #ifndef WAVEMASTER_FREQ
139 44100, 33075, 22050, 16538, 11025, 8269, 5513, 4134
142 * It is said that Q-Vision's WaveMaster of some earlier lot(s?) has
143 * sampling rates incompatible with PC-9801-86.
144 * But I'm not sure whether the following rates are correct, especially
147 44100, 33075, 22050, 16000, 11025, 8000, 5510, 4000
151 /* u-law to linear translation table */
152 static pcm_data ulaw2linear[256] = {
153 130, 134, 138, 142, 146, 150, 154, 158,
154 162, 166, 170, 174, 178, 182, 186, 190,
155 193, 195, 197, 199, 201, 203, 205, 207,
156 209, 211, 213, 215, 217, 219, 221, 223,
157 225, 226, 227, 228, 229, 230, 231, 232,
158 233, 234, 235, 236, 237, 238, 239, 240,
159 240, 241, 241, 242, 242, 243, 243, 244,
160 244, 245, 245, 246, 246, 247, 247, 248,
161 248, 248, 249, 249, 249, 249, 250, 250,
162 250, 250, 251, 251, 251, 251, 252, 252,
163 252, 252, 252, 252, 253, 253, 253, 253,
164 253, 253, 253, 253, 254, 254, 254, 254,
165 254, 254, 254, 254, 254, 254, 254, 254,
166 255, 255, 255, 255, 255, 255, 255, 255,
167 255, 255, 255, 255, 255, 255, 255, 255,
168 255, 255, 255, 255, 255, 255, 255, 255,
169 125, 121, 117, 113, 109, 105, 101, 97,
170 93, 89, 85, 81, 77, 73, 69, 65,
171 62, 60, 58, 56, 54, 52, 50, 48,
172 46, 44, 42, 40, 38, 36, 34, 32,
173 30, 29, 28, 27, 26, 25, 24, 23,
174 22, 21, 20, 19, 18, 17, 16, 15,
175 15, 14, 14, 13, 13, 12, 12, 11,
176 11, 10, 10, 9, 9, 8, 8, 7,
177 7, 7, 6, 6, 6, 6, 5, 5,
178 5, 5, 4, 4, 4, 4, 3, 3,
179 3, 3, 3, 3, 2, 2, 2, 2,
180 2, 2, 2, 2, 1, 1, 1, 1,
181 1, 1, 1, 1, 1, 1, 1, 1,
182 0, 0, 0, 0, 0, 0, 0, 0,
183 0, 0, 0, 0, 0, 0, 0, 0,
184 0, 0, 0, 0, 0, 0, 0, 0
187 /* linear to u-law translation table */
188 static pcm_data linear2ulaw[256] = {
189 255, 231, 219, 211, 205, 201, 197, 193,
190 190, 188, 186, 184, 182, 180, 178, 176,
191 175, 174, 173, 172, 171, 170, 169, 168,
192 167, 166, 165, 164, 163, 162, 161, 160,
193 159, 159, 158, 158, 157, 157, 156, 156,
194 155, 155, 154, 154, 153, 153, 152, 152,
195 151, 151, 150, 150, 149, 149, 148, 148,
196 147, 147, 146, 146, 145, 145, 144, 144,
197 143, 143, 143, 143, 142, 142, 142, 142,
198 141, 141, 141, 141, 140, 140, 140, 140,
199 139, 139, 139, 139, 138, 138, 138, 138,
200 137, 137, 137, 137, 136, 136, 136, 136,
201 135, 135, 135, 135, 134, 134, 134, 134,
202 133, 133, 133, 133, 132, 132, 132, 132,
203 131, 131, 131, 131, 130, 130, 130, 130,
204 129, 129, 129, 129, 128, 128, 128, 128,
205 0, 0, 0, 0, 0, 1, 1, 1,
206 1, 2, 2, 2, 2, 3, 3, 3,
207 3, 4, 4, 4, 4, 5, 5, 5,
208 5, 6, 6, 6, 6, 7, 7, 7,
209 7, 8, 8, 8, 8, 9, 9, 9,
210 9, 10, 10, 10, 10, 11, 11, 11,
211 11, 12, 12, 12, 12, 13, 13, 13,
212 13, 14, 14, 14, 14, 15, 15, 15,
213 15, 16, 16, 17, 17, 18, 18, 19,
214 19, 20, 20, 21, 21, 22, 22, 23,
215 23, 24, 24, 25, 25, 26, 26, 27,
216 27, 28, 28, 29, 29, 30, 30, 31,
217 31, 32, 33, 34, 35, 36, 37, 38,
218 39, 40, 41, 42, 43, 44, 45, 46,
219 47, 48, 50, 52, 54, 56, 58, 60,
220 62, 65, 69, 73, 77, 83, 91, 103
228 static int nss_detect(struct address_info *);
230 static int nss_open(int, int);
231 static void nss_close(int);
232 static void nss_output_block(int, unsigned long, int, int, int);
233 static void nss_start_input(int, unsigned long, int, int, int);
234 static int nss_ioctl(int, u_int, ioctl_arg, int);
235 static int nss_prepare_for_input(int, int, int);
236 static int nss_prepare_for_output(int, int, int);
237 static void nss_reset(int);
238 static void nss_halt_xfer(int);
240 static void dsp73_send_command(unsigned char);
241 static void dsp73_send_data(unsigned char);
242 static void dsp73_init(void);
243 static int set_format(int);
244 static int set_speed(int);
245 static int set_stereo(int);
246 static void set_volume(int);
247 static void fifo_start(int);
248 static void fifo_stop(void);
249 static void fifo_reset(void);
250 static void fifo_output_block(void);
251 static int fifo_send(pcm_data *, int);
252 static void fifo_sendtrailer(int);
253 static void fifo_send_stereo(pcm_data *, int);
254 static void fifo_send_monoral(pcm_data *, int);
255 static void fifo_send_stereo_ulaw(pcm_data *, int);
256 static void fifo_send_stereo_8(pcm_data *, int, int);
257 static void fifo_send_stereo_16le(pcm_data *, int, int);
258 static void fifo_send_stereo_16be(pcm_data *, int, int);
259 static void fifo_send_mono_ulaw(pcm_data *, int);
260 static void fifo_send_mono_8(pcm_data *, int, int);
261 static void fifo_send_mono_16le(pcm_data *, int, int);
262 static void fifo_send_mono_16be(pcm_data *, int, int);
263 static void fifo_input_block(void);
264 static void fifo_recv(pcm_data *, int);
265 static void fifo_recv_stereo(pcm_data *, int);
266 static void fifo_recv_monoral(pcm_data *, int);
267 static void fifo_recv_stereo_ulaw(pcm_data *, int);
268 static void fifo_recv_stereo_8(pcm_data *, int, int);
269 static void fifo_recv_stereo_16le(pcm_data *, int, int);
270 static void fifo_recv_stereo_16be(pcm_data *, int, int);
271 static void fifo_recv_mono_ulaw(pcm_data *, int);
272 static void fifo_recv_mono_8(pcm_data *, int, int);
273 static void fifo_recv_mono_16le(pcm_data *, int, int);
274 static void fifo_recv_mono_16be(pcm_data *, int, int);
275 static void nss_stop(void);
276 static void nss_init(void);
283 static struct audio_operations nss_operations =
285 "PC-9801-86 SoundBoard", /* filled in properly by auto configuration */
288 AFMT_U8 | AFMT_S16_LE | AFMT_S16_BE |
289 AFMT_S8 | AFMT_U16_LE | AFMT_U16_BE ),
296 nss_prepare_for_input,
297 nss_prepare_for_output,
306 * Codes for internal use
310 dsp73_send_command(unsigned char command)
313 while ((inb(pcm_s.iobase + 2) & 0x48) != 8);
316 outb(pcm_s.iobase + 2, (inb(pcm_s.iobase + 2) & 0x20) | 3);
319 while ((inb(pcm_s.iobase + 2) & 0x48) != 8);
322 outb(pcm_s.iobase + 4, command);
327 dsp73_send_data(unsigned char data)
330 while ((inb(pcm_s.iobase + 2) & 0x48) != 8);
333 outb(pcm_s.iobase + 2, (inb(pcm_s.iobase + 2) & 0x20) | 0x83);
336 while ((inb(pcm_s.iobase + 2) & 0x48) != 8);
339 outb(pcm_s.iobase + 4, data);
346 const unsigned char dspinst[15] = {
357 t = inb(pcm_s.iobase + 2);
358 outb(pcm_s.iobase + 2, (t & 0x80) | 0x23);
361 dsp73_send_command(0x04);
362 dsp73_send_data(0x6f);
363 dsp73_send_data(0x3c);
365 /* write DSP instructions */
366 dsp73_send_command(0x01);
367 dsp73_send_data(0x00);
368 for (i = 0; i < 16; i++)
369 dsp73_send_data(dspinst[i]);
372 dsp73_send_command(0x04);
373 dsp73_send_data(0x6f);
374 dsp73_send_data(0x30);
377 while ((inb(pcm_s.iobase + 2) & 0x48) != 8);
379 outb(pcm_s.iobase + 2, 3);
384 set_format(int format)
390 pcm_s.format = format;
391 pcm_s.bytes = 1; /* 8bit */
397 pcm_s.format = format;
398 pcm_s.bytes = 2; /* 16bit */
415 if (speed < 4000) /* Minimum 4000Hz */
417 if (speed > 44100) /* Maximum 44100Hz */
419 for (i = 7; i >= 0; i--) {
420 if (speed <= rates_tbl[i]) {
421 pcm_s.chipspeedno = i;
422 pcm_s.chipspeed = rates_tbl[i];
433 set_stereo(int stereo)
435 pcm_s.stereo = stereo ? YES : NO;
442 set_volume(int volume)
448 pcm_s.volume = volume;
450 outb(pcm_s.iobase + 6, 0xaf - volume); /* D/A -> LINE OUT */
455 outb(pcm_s.iobase + 6, 0x20); /* FM -> A/D */
460 outb(pcm_s.iobase + 6, 0x60); /* LINE IN -> A/D */
473 /* Set frame length & panpot(LR). */
474 tmp = inb(pcm_s.iobase + 10) & 0x88;
475 outb(pcm_s.iobase + 10, tmp | ((pcm_s.bytes == 1) ? 0x72 : 0x32));
477 tmp = pcm_s.chipspeedno;
478 if (mode == IMODE_INPUT)
481 /* Reset intr. flag. */
482 outb(pcm_s.iobase + 8, tmp);
483 outb(pcm_s.iobase + 8, tmp | 0x10);
485 /* Enable FIFO intr. */
486 outb(pcm_s.iobase + 8, tmp | 0x30);
488 /* Set intr. interval. */
489 outb(pcm_s.iobase + 10, pcm_s.intr_size / 128 - 1);
492 outb(pcm_s.iobase + 8, tmp | 0xb0);
501 /* Reset intr. flag, and disable FIFO intr. */
502 tmp = inb(pcm_s.iobase + 8) & 0x0f;
503 outb(pcm_s.iobase + 8, tmp);
513 tmp = inb(pcm_s.iobase + 8) & 0x77;
514 outb(pcm_s.iobase + 8, tmp | 0x8);
515 outb(pcm_s.iobase + 8, tmp);
520 fifo_output_block(void)
522 int chunksize, count;
524 if (pcm_s.pdma_chunkcount) {
525 /* Update chunksize and then send the next chunk to FIFO. */
526 chunksize = pcm_s.pdma_count / pcm_s.pdma_chunkcount--;
527 count = fifo_send(pcm_s.pdma_buf, chunksize);
529 /* ??? something wrong... */
530 printf("nss0: chunkcount overrun\n");
531 chunksize = count = 0;
534 if (((audio_devs[my_dev]->dmap_out->qlen < 2) && (pcm_s.pdma_chunkcount == 0))
535 || (count < pcm_s.intr_size)) {
536 /* The sent chunk seems to be the last one. */
537 fifo_sendtrailer(pcm_s.intr_size);
538 pcm_s.intr_last = YES;
541 pcm_s.pdma_buf += chunksize;
542 pcm_s.pdma_count -= chunksize;
547 fifo_send(pcm_data *buf, int count)
549 int i, length, r, cnt, rslt;
552 /* Calculate the length of PCM frames. */
553 cnt = count + tmpbuf.size;
554 length = pcm_s.bytes << pcm_s.stereo;
560 fifo_send_stereo(buf, cnt);
562 fifo_send_monoral(buf, cnt);
563 /* Carry over extra data which doesn't seem to be a full PCM frame. */
564 p = (pcm_data *)buf + count - r;
565 for (i = 0; i < r; i++)
566 tmpbuf.buff[i] = *p++;
568 /* Carry over extra data which doesn't seem to be a full PCM frame. */
570 for (i = tmpbuf.size; i < r; i++)
571 tmpbuf.buff[i] = *p++;
575 rslt = ((cnt / length) * pcm_s.chipspeed / pcm_s.speed) * pcm_s.bytes * 2;
577 printf("fifo_send(): %d bytes sent\n", rslt);
584 fifo_sendtrailer(int count)
586 /* Send trailing zeros to the FIFO buffer. */
589 for (i = 0; i < count; i++)
590 outb(pcm_s.iobase + 12, 0);
591 pcm_s.intr_trailer = YES;
594 printf("fifo_sendtrailer(): %d bytes sent\n", count);
600 fifo_send_stereo(pcm_data *buf, int count)
602 /* Convert format and sampling speed. */
603 switch (pcm_s.format) {
605 fifo_send_stereo_ulaw(buf, count);
608 fifo_send_stereo_8(buf, count, NO);
611 fifo_send_stereo_8(buf, count, YES);
614 fifo_send_stereo_16le(buf, count, NO);
617 fifo_send_stereo_16le(buf, count, YES);
620 fifo_send_stereo_16be(buf, count, NO);
623 fifo_send_stereo_16be(buf, count, YES);
630 fifo_send_monoral(pcm_data *buf, int count)
632 /* Convert format and sampling speed. */
633 switch (pcm_s.format) {
635 fifo_send_mono_ulaw(buf, count);
638 fifo_send_mono_8(buf, count, NO);
641 fifo_send_mono_8(buf, count, YES);
644 fifo_send_mono_16le(buf, count, NO);
647 fifo_send_mono_16le(buf, count, YES);
650 fifo_send_mono_16be(buf, count, NO);
653 fifo_send_mono_16be(buf, count, YES);
660 fifo_send_stereo_ulaw(pcm_data *buf, int count)
663 signed char dl, dl0, dl1, dr, dr0, dr1;
667 t[0] = ulaw2linear[tmpbuf.buff[0]];
669 t[0] = ulaw2linear[*buf++];
670 t[1] = ulaw2linear[*buf++];
672 if (pcm_s.speed == pcm_s.chipspeed) {
673 /* No reason to convert the pcm speed. */
674 outb(pcm_s.iobase + 12, t[0]);
675 outb(pcm_s.iobase + 12, t[1]);
677 for (i = 0; i < count; i++)
678 outb(pcm_s.iobase + 12, ulaw2linear[*buf++]);
680 /* Speed conversion with linear interpolation method. */
688 while (pcm_s.acc >= pcm_s.chipspeed) {
689 pcm_s.acc -= pcm_s.chipspeed;
694 dl1 = ulaw2linear[*buf++];
695 dr1 = ulaw2linear[*buf++];
699 dl = ((dl0 * (pcm_s.chipspeed - pcm_s.acc)) + (dl1 * pcm_s.acc))
701 dr = ((dr0 * (pcm_s.chipspeed - pcm_s.acc)) + (dr1 * pcm_s.acc))
703 outb(pcm_s.iobase + 12, dl);
704 outb(pcm_s.iobase + 12, dr);
705 pcm_s.acc += pcm_s.speed;
715 fifo_send_stereo_8(pcm_data *buf, int count, int uflag)
718 signed char dl, dl0, dl1, dr, dr0, dr1, zlev;
721 zlev = uflag ? -128 : 0;
724 t[0] = tmpbuf.buff[0] + zlev;
726 t[0] = *buf++ + zlev;
727 t[1] = *buf++ + zlev;
729 if (pcm_s.speed == pcm_s.chipspeed) {
730 /* No reason to convert the pcm speed. */
731 outb(pcm_s.iobase + 12, t[0]);
732 outb(pcm_s.iobase + 12, t[1]);
734 for (i = 0; i < count; i++)
735 outb(pcm_s.iobase + 12, *buf++ + zlev);
737 /* Speed conversion with linear interpolation method. */
745 while (pcm_s.acc >= pcm_s.chipspeed) {
746 pcm_s.acc -= pcm_s.chipspeed;
756 dl = ((dl0 * (pcm_s.chipspeed - pcm_s.acc)) + (dl1 * pcm_s.acc))
758 dr = ((dr0 * (pcm_s.chipspeed - pcm_s.acc)) + (dr1 * pcm_s.acc))
760 outb(pcm_s.iobase + 12, dl);
761 outb(pcm_s.iobase + 12, dr);
762 pcm_s.acc += pcm_s.speed;
772 fifo_send_stereo_16le(pcm_data *buf, int count, int uflag)
775 short dl, dl0, dl1, dr, dr0, dr1, zlev;
778 zlev = uflag ? -128 : 0;
780 for (i = 0; i < 4; i++)
781 t[i] = (tmpbuf.size > i) ? tmpbuf.buff[i] : *buf++;
783 if (pcm_s.speed == pcm_s.chipspeed) {
784 /* No reason to convert the pcm speed. */
785 outb(pcm_s.iobase + 12, t[1] + zlev);
786 outb(pcm_s.iobase + 12, t[0]);
787 outb(pcm_s.iobase + 12, t[3] + zlev);
788 outb(pcm_s.iobase + 12, t[2]);
789 count = count / 2 - 2;
790 for (i = 0; i < count; i++) {
791 outb(pcm_s.iobase + 12, *(buf + 1) + zlev);
792 outb(pcm_s.iobase + 12, *buf);
796 /* Speed conversion with linear interpolation method. */
799 dl1 = t[0] + ((t[1] + zlev) << 8);
800 dr1 = t[2] + ((t[3] + zlev) << 8);
804 while (pcm_s.acc >= pcm_s.chipspeed) {
805 pcm_s.acc -= pcm_s.chipspeed;
810 dl1 = *buf + ((*(buf + 1) + zlev) << 8);
812 dr1 = *buf + ((*(buf + 1) + zlev) << 8);
817 dl = ((dl0 * (pcm_s.chipspeed - pcm_s.acc)) + (dl1 * pcm_s.acc))
819 dr = ((dr0 * (pcm_s.chipspeed - pcm_s.acc)) + (dr1 * pcm_s.acc))
821 outb(pcm_s.iobase + 12, (dl >> 8) & 0xff);
822 outb(pcm_s.iobase + 12, dl & 0xff);
823 outb(pcm_s.iobase + 12, (dr >> 8) & 0xff);
824 outb(pcm_s.iobase + 12, dr & 0xff);
825 pcm_s.acc += pcm_s.speed;
835 fifo_send_stereo_16be(pcm_data *buf, int count, int uflag)
838 short dl, dl0, dl1, dr, dr0, dr1, zlev;
841 zlev = uflag ? -128 : 0;
843 for (i = 0; i < 4; i++)
844 t[i] = (tmpbuf.size > i) ? tmpbuf.buff[i] : *buf++;
846 if (pcm_s.speed == pcm_s.chipspeed) {
847 /* No reason to convert the pcm speed. */
848 outb(pcm_s.iobase + 12, t[0] + zlev);
849 outb(pcm_s.iobase + 12, t[1]);
850 outb(pcm_s.iobase + 12, t[2] + zlev);
851 outb(pcm_s.iobase + 12, t[3]);
852 count = count / 2 - 2;
853 for (i = 0; i < count; i++) {
854 outb(pcm_s.iobase + 12, *buf + zlev);
855 outb(pcm_s.iobase + 12, *(buf + 1));
859 /* Speed conversion with linear interpolation method. */
862 dl1 = ((t[0] + zlev) << 8) + t[1];
863 dr1 = ((t[2] + zlev) << 8) + t[3];
867 while (pcm_s.acc >= pcm_s.chipspeed) {
868 pcm_s.acc -= pcm_s.chipspeed;
873 dl1 = ((*buf + zlev) << 8) + *(buf + 1);
875 dr1 = ((*buf + zlev) << 8) + *(buf + 1);
880 dl = ((dl0 * (pcm_s.chipspeed - pcm_s.acc)) + (dl1 * pcm_s.acc))
882 dr = ((dr0 * (pcm_s.chipspeed - pcm_s.acc)) + (dr1 * pcm_s.acc))
884 outb(pcm_s.iobase + 12, (dl >> 8) & 0xff);
885 outb(pcm_s.iobase + 12, dl & 0xff);
886 outb(pcm_s.iobase + 12, (dr >> 8) & 0xff);
887 outb(pcm_s.iobase + 12, dr & 0xff);
888 pcm_s.acc += pcm_s.speed;
898 fifo_send_mono_ulaw(pcm_data *buf, int count)
901 signed char d, d0, d1;
903 if (pcm_s.speed == pcm_s.chipspeed)
904 /* No reason to convert the pcm speed. */
905 for (i = 0; i < count; i++) {
906 d = ulaw2linear[*buf++];
907 outb(pcm_s.iobase + 12, d);
908 outb(pcm_s.iobase + 12, d);
911 /* Speed conversion with linear interpolation method. */
913 d1 = ulaw2linear[*buf++];
916 while (pcm_s.acc >= pcm_s.chipspeed) {
917 pcm_s.acc -= pcm_s.chipspeed;
920 d1 = (i < count) ? ulaw2linear[*buf++] : 0;
922 d = ((d0 * (pcm_s.chipspeed - pcm_s.acc)) + (d1 * pcm_s.acc))
924 outb(pcm_s.iobase + 12, d);
925 outb(pcm_s.iobase + 12, d);
926 pcm_s.acc += pcm_s.speed;
935 fifo_send_mono_8(pcm_data *buf, int count, int uflag)
938 signed char d, d0, d1, zlev;
940 zlev = uflag ? -128 : 0;
942 if (pcm_s.speed == pcm_s.chipspeed)
943 /* No reason to convert the pcm speed. */
944 for (i = 0; i < count; i++) {
946 outb(pcm_s.iobase + 12, d);
947 outb(pcm_s.iobase + 12, d);
950 /* Speed conversion with linear interpolation method. */
955 while (pcm_s.acc >= pcm_s.chipspeed) {
956 pcm_s.acc -= pcm_s.chipspeed;
959 d1 = (i < count) ? *buf++ + zlev : 0;
961 d = ((d0 * (pcm_s.chipspeed - pcm_s.acc)) + (d1 * pcm_s.acc))
963 outb(pcm_s.iobase + 12, d);
964 outb(pcm_s.iobase + 12, d);
965 pcm_s.acc += pcm_s.speed;
974 fifo_send_mono_16le(pcm_data *buf, int count, int uflag)
977 short d, d0, d1, zlev;
980 zlev = uflag ? -128 : 0;
982 for (i = 0; i < 2; i++)
983 t[i] = (tmpbuf.size > i) ? tmpbuf.buff[i] : *buf++;
985 if (pcm_s.speed == pcm_s.chipspeed) {
986 /* No reason to convert the pcm speed. */
987 outb(pcm_s.iobase + 12, t[1] + zlev);
988 outb(pcm_s.iobase + 12, t[0]);
989 outb(pcm_s.iobase + 12, t[1] + zlev);
990 outb(pcm_s.iobase + 12, t[0]);
991 count = count / 2 - 1;
992 for (i = 0; i < count; i++) {
993 outb(pcm_s.iobase + 12, *(buf + 1) + zlev);
994 outb(pcm_s.iobase + 12, *buf);
995 outb(pcm_s.iobase + 12, *(buf + 1) + zlev);
996 outb(pcm_s.iobase + 12, *buf);
1000 /* Speed conversion with linear interpolation method. */
1002 d1 = t[0] + ((t[1] + zlev) << 8);
1006 while (pcm_s.acc >= pcm_s.chipspeed) {
1007 pcm_s.acc -= pcm_s.chipspeed;
1011 d1 = *buf + ((*(buf + 1) + zlev) << 8);
1016 d = ((d0 * (pcm_s.chipspeed - pcm_s.acc)) + (d1 * pcm_s.acc))
1018 outb(pcm_s.iobase + 12, (d >> 8) & 0xff);
1019 outb(pcm_s.iobase + 12, d & 0xff);
1020 outb(pcm_s.iobase + 12, (d >> 8) & 0xff);
1021 outb(pcm_s.iobase + 12, d & 0xff);
1022 pcm_s.acc += pcm_s.speed;
1031 fifo_send_mono_16be(pcm_data *buf, int count, int uflag)
1034 short d, d0, d1, zlev;
1037 zlev = uflag ? -128 : 0;
1039 for (i = 0; i < 2; i++)
1040 t[i] = (tmpbuf.size > i) ? tmpbuf.buff[i] : *buf++;
1042 if (pcm_s.speed == pcm_s.chipspeed) {
1043 /* No reason to convert the pcm speed. */
1044 outb(pcm_s.iobase + 12, t[0] + zlev);
1045 outb(pcm_s.iobase + 12, t[1]);
1046 outb(pcm_s.iobase + 12, t[0] + zlev);
1047 outb(pcm_s.iobase + 12, t[1]);
1048 count = count / 2 - 1;
1049 for (i = 0; i < count; i++) {
1050 outb(pcm_s.iobase + 12, *buf + zlev);
1051 outb(pcm_s.iobase + 12, *(buf + 1));
1052 outb(pcm_s.iobase + 12, *buf + zlev);
1053 outb(pcm_s.iobase + 12, *(buf + 1));
1057 /* Speed conversion with linear interpolation method. */
1059 d1 = ((t[0] + zlev) << 8) + t[1];
1063 while (pcm_s.acc >= pcm_s.chipspeed) {
1064 pcm_s.acc -= pcm_s.chipspeed;
1068 d1 = ((*buf + zlev) << 8) + *(buf + 1);
1073 d = ((d0 * (pcm_s.chipspeed - pcm_s.acc)) + (d1 * pcm_s.acc))
1075 /* outb(pcm_s.iobase + 12, d & 0xff);
1076 outb(pcm_s.iobase + 12, (d >> 8) & 0xff);
1077 outb(pcm_s.iobase + 12, d & 0xff);
1078 outb(pcm_s.iobase + 12, (d >> 8) & 0xff); */
1079 outb(pcm_s.iobase + 12, (d >> 8) & 0xff);
1080 outb(pcm_s.iobase + 12, d & 0xff);
1081 outb(pcm_s.iobase + 12, (d >> 8) & 0xff);
1082 outb(pcm_s.iobase + 12, d & 0xff);
1083 pcm_s.acc += pcm_s.speed;
1092 fifo_input_block(void)
1096 if (pcm_s.pdma_chunkcount) {
1097 /* Update chunksize and then receive the next chunk from FIFO. */
1098 chunksize = pcm_s.pdma_count / pcm_s.pdma_chunkcount--;
1099 fifo_recv(pcm_s.pdma_buf, chunksize);
1100 pcm_s.pdma_buf += chunksize;
1101 pcm_s.pdma_count -= chunksize;
1103 /* ??? something wrong... */
1104 printf("nss0: chunkcount overrun\n");
1109 fifo_recv(pcm_data *buf, int count)
1113 if (count > tmpbuf.size) {
1114 for (i = 0; i < tmpbuf.size; i++)
1115 *buf++ = tmpbuf.buff[i];
1116 count -= tmpbuf.size;
1119 fifo_recv_stereo(buf, count);
1121 fifo_recv_monoral(buf, count);
1123 for (i = 0; i < count; i++)
1124 *buf++ = tmpbuf.buff[i];
1125 for (i = 0; i < tmpbuf.size - count; i++)
1126 tmpbuf.buff[i] = tmpbuf.buff[i + count];
1127 tmpbuf.size -= count;
1131 printf("fifo_recv(): %d bytes received\n",
1132 ((count / (pcm_s.bytes << pcm_s.stereo)) * pcm_s.chipspeed
1133 / pcm_s.speed) * pcm_s.bytes * 2);
1139 fifo_recv_stereo(pcm_data *buf, int count)
1141 /* Convert format and sampling speed. */
1142 switch (pcm_s.format) {
1144 fifo_recv_stereo_ulaw(buf, count);
1147 fifo_recv_stereo_8(buf, count, NO);
1150 fifo_recv_stereo_8(buf, count, YES);
1153 fifo_recv_stereo_16le(buf, count, NO);
1156 fifo_recv_stereo_16le(buf, count, YES);
1159 fifo_recv_stereo_16be(buf, count, NO);
1162 fifo_recv_stereo_16be(buf, count, YES);
1169 fifo_recv_monoral(pcm_data *buf, int count)
1171 /* Convert format and sampling speed. */
1172 switch (pcm_s.format) {
1174 fifo_recv_mono_ulaw(buf, count);
1177 fifo_recv_mono_8(buf, count, NO);
1180 fifo_recv_mono_8(buf, count, YES);
1183 fifo_recv_mono_16le(buf, count, NO);
1186 fifo_recv_mono_16le(buf, count, YES);
1189 fifo_recv_mono_16be(buf, count, NO);
1192 fifo_recv_mono_16be(buf, count, YES);
1199 fifo_recv_stereo_ulaw(pcm_data *buf, int count)
1202 signed char dl, dl0, dl1, dr, dr0, dr1;
1205 if (pcm_s.speed == pcm_s.chipspeed) {
1206 /* No reason to convert the pcm speed. */
1207 for (i = 0; i < cnt; i++) {
1208 *buf++ = linear2ulaw[inb(pcm_s.iobase + 12)];
1209 *buf++ = linear2ulaw[inb(pcm_s.iobase + 12)];
1212 *buf++ = linear2ulaw[inb(pcm_s.iobase + 12)];
1213 tmpbuf.buff[0] = linear2ulaw[inb(pcm_s.iobase + 12)];
1217 /* Speed conversion with linear interpolation method. */
1220 dl1 = inb(pcm_s.iobase + 12);
1221 dr1 = inb(pcm_s.iobase + 12);
1222 for (i = 0; i < cnt; i++) {
1223 while (pcm_s.acc >= pcm_s.speed) {
1224 pcm_s.acc -= pcm_s.speed;
1227 dl1 = inb(pcm_s.iobase + 12);
1228 dr1 = inb(pcm_s.iobase + 12);
1230 dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
1232 dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
1234 *buf++ = linear2ulaw[dl & 0xff];
1235 *buf++ = linear2ulaw[dr & 0xff];
1236 pcm_s.acc += pcm_s.chipspeed;
1239 while (pcm_s.acc >= pcm_s.speed) {
1240 pcm_s.acc -= pcm_s.speed;
1243 dl1 = inb(pcm_s.iobase + 12);
1244 dr1 = inb(pcm_s.iobase + 12);
1246 dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
1248 dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
1250 *buf++ = linear2ulaw[dl & 0xff];
1251 tmpbuf.buff[0] = linear2ulaw[dr & 0xff];
1262 fifo_recv_stereo_8(pcm_data *buf, int count, int uflag)
1265 signed char dl, dl0, dl1, dr, dr0, dr1, zlev;
1267 zlev = uflag ? -128 : 0;
1270 if (pcm_s.speed == pcm_s.chipspeed) {
1271 /* No reason to convert the pcm speed. */
1272 for (i = 0; i < cnt; i++) {
1273 *buf++ = inb(pcm_s.iobase + 12) + zlev;
1274 *buf++ = inb(pcm_s.iobase + 12) + zlev;
1277 *buf++ = inb(pcm_s.iobase + 12) + zlev;
1278 tmpbuf.buff[0] = inb(pcm_s.iobase + 12) + zlev;
1282 /* Speed conversion with linear interpolation method. */
1285 dl1 = inb(pcm_s.iobase + 12);
1286 dr1 = inb(pcm_s.iobase + 12);
1287 for (i = 0; i < cnt; i++) {
1288 while (pcm_s.acc >= pcm_s.speed) {
1289 pcm_s.acc -= pcm_s.speed;
1292 dl1 = inb(pcm_s.iobase + 12);
1293 dr1 = inb(pcm_s.iobase + 12);
1295 dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
1297 dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
1301 pcm_s.acc += pcm_s.chipspeed;
1304 while (pcm_s.acc >= pcm_s.speed) {
1305 pcm_s.acc -= pcm_s.speed;
1308 dl1 = inb(pcm_s.iobase + 12);
1309 dr1 = inb(pcm_s.iobase + 12);
1311 dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
1313 dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
1316 tmpbuf.buff[0] = dr + zlev;
1327 fifo_recv_stereo_16le(pcm_data *buf, int count, int uflag)
1330 short dl, dl0, dl1, dr, dr0, dr1, zlev;
1333 zlev = uflag ? -128 : 0;
1336 if (pcm_s.speed == pcm_s.chipspeed) {
1337 /* No reason to convert the pcm speed. */
1338 for (i = 0; i < cnt; i++) {
1339 *(buf + 1) = inb(pcm_s.iobase + 12) + zlev;
1340 *buf = inb(pcm_s.iobase + 12);
1341 *(buf + 3) = inb(pcm_s.iobase + 12) + zlev;
1342 *(buf + 2) = inb(pcm_s.iobase + 12);
1346 t[1] = inb(pcm_s.iobase + 12) + zlev;
1347 t[0] = inb(pcm_s.iobase + 12);
1348 t[3] = inb(pcm_s.iobase + 12) + zlev;
1349 t[2] = inb(pcm_s.iobase + 12);
1351 for (i = 0; i < count % 4; i++)
1353 for (i = count % 4; i < 4; i++)
1354 tmpbuf.buff[tmpbuf.size++] = t[i];
1357 /* Speed conversion with linear interpolation method. */
1360 dl1 = inb(pcm_s.iobase + 12) << 8;
1361 dl1 |= inb(pcm_s.iobase + 12);
1362 dr1 = inb(pcm_s.iobase + 12) << 8;
1363 dr1 |= inb(pcm_s.iobase + 12);
1364 for (i = 0; i < cnt; i++) {
1365 while (pcm_s.acc >= pcm_s.speed) {
1366 pcm_s.acc -= pcm_s.speed;
1369 dl1 = inb(pcm_s.iobase + 12) << 8;
1370 dl1 |= inb(pcm_s.iobase + 12);
1371 dr1 = inb(pcm_s.iobase + 12) << 8;
1372 dr1 |= inb(pcm_s.iobase + 12);
1374 dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
1376 dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
1379 *buf++ = ((dl >> 8) & 0xff) + zlev;
1381 *buf++ = ((dr >> 8) & 0xff) + zlev;
1382 pcm_s.acc += pcm_s.chipspeed;
1385 while (pcm_s.acc >= pcm_s.speed) {
1386 pcm_s.acc -= pcm_s.speed;
1389 dl1 = inb(pcm_s.iobase + 12) << 8;
1390 dl1 |= inb(pcm_s.iobase + 12);
1391 dr1 = inb(pcm_s.iobase + 12) << 8;
1392 dr1 |= inb(pcm_s.iobase + 12);
1394 dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
1396 dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
1399 t[1] = ((dl >> 8) & 0xff) + zlev;
1401 t[3] = ((dr >> 8) & 0xff) + zlev;
1403 for (i = 0; i < count % 4; i++)
1405 for (i = count % 4; i < 4; i++)
1406 tmpbuf.buff[tmpbuf.size++] = t[i];
1416 fifo_recv_stereo_16be(pcm_data *buf, int count, int uflag)
1419 short dl, dl0, dl1, dr, dr0, dr1, zlev;
1422 zlev = uflag ? -128 : 0;
1425 if (pcm_s.speed == pcm_s.chipspeed) {
1426 /* No reason to convert the pcm speed. */
1427 for (i = 0; i < cnt; i++) {
1428 *buf++ = inb(pcm_s.iobase + 12) + zlev;
1429 *buf++ = inb(pcm_s.iobase + 12);
1430 *buf++ = inb(pcm_s.iobase + 12) + zlev;
1431 *buf++ = inb(pcm_s.iobase + 12);
1434 t[0] = inb(pcm_s.iobase + 12) + zlev;
1435 t[1] = inb(pcm_s.iobase + 12);
1436 t[2] = inb(pcm_s.iobase + 12) + zlev;
1437 t[3] = inb(pcm_s.iobase + 12);
1439 for (i = 0; i < count % 4; i++)
1441 for (i = count % 4; i < 4; i++)
1442 tmpbuf.buff[tmpbuf.size++] = t[i];
1445 /* Speed conversion with linear interpolation method. */
1448 dl1 = inb(pcm_s.iobase + 12) << 8;
1449 dl1 |= inb(pcm_s.iobase + 12);
1450 dr1 = inb(pcm_s.iobase + 12) << 8;
1451 dr1 |= inb(pcm_s.iobase + 12);
1452 for (i = 0; i < cnt; i++) {
1453 while (pcm_s.acc >= pcm_s.speed) {
1454 pcm_s.acc -= pcm_s.speed;
1457 dl1 = inb(pcm_s.iobase + 12) << 8;
1458 dl1 |= inb(pcm_s.iobase + 12);
1459 dr1 = inb(pcm_s.iobase + 12) << 8;
1460 dr1 |= inb(pcm_s.iobase + 12);
1462 dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
1464 dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
1466 *buf++ = ((dl >> 8) & 0xff) + zlev;
1468 *buf++ = ((dr >> 8) & 0xff) + zlev;
1470 pcm_s.acc += pcm_s.chipspeed;
1473 while (pcm_s.acc >= pcm_s.speed) {
1474 pcm_s.acc -= pcm_s.speed;
1477 dl1 = inb(pcm_s.iobase + 12) << 8;
1478 dl1 |= inb(pcm_s.iobase + 12);
1479 dr1 = inb(pcm_s.iobase + 12) << 8;
1480 dr1 |= inb(pcm_s.iobase + 12);
1482 dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
1484 dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
1486 t[0] = ((dl >> 8) & 0xff) + zlev;
1488 t[2] = ((dr >> 8) & 0xff) + zlev;
1491 for (i = 0; i < count % 4; i++)
1493 for (i = count % 4; i < 4; i++)
1494 tmpbuf.buff[tmpbuf.size++] = t[i];
1504 fifo_recv_mono_ulaw(pcm_data *buf, int count)
1507 signed char d, d0, d1;
1509 if (pcm_s.speed == pcm_s.chipspeed) {
1510 /* No reason to convert the pcm speed. */
1511 for (i = 0; i < count; i++) {
1512 d = ((signed char)inb(pcm_s.iobase + 12)
1513 + (signed char)inb(pcm_s.iobase + 12)) >> 1;
1514 *buf++ = linear2ulaw[d & 0xff];
1517 /* Speed conversion with linear interpolation method. */
1519 d1 = ((signed char)inb(pcm_s.iobase + 12)
1520 + (signed char)inb(pcm_s.iobase + 12)) >> 1;
1521 for (i = 0; i < count; i++) {
1522 while (pcm_s.acc >= pcm_s.speed) {
1523 pcm_s.acc -= pcm_s.speed;
1525 d1 = ((signed char)inb(pcm_s.iobase + 12)
1526 + (signed char)inb(pcm_s.iobase + 12)) >> 1;
1528 d = ((d0 * (pcm_s.speed - pcm_s.acc)) + (d1 * pcm_s.acc))
1530 *buf++ = linear2ulaw[d & 0xff];
1531 pcm_s.acc += pcm_s.chipspeed;
1540 fifo_recv_mono_8(pcm_data *buf, int count, int uflag)
1543 signed char d, d0, d1, zlev;
1545 zlev = uflag ? -128 : 0;
1547 if (pcm_s.speed == pcm_s.chipspeed) {
1548 /* No reason to convert the pcm speed. */
1549 for (i = 0; i < count; i++) {
1550 d = ((signed char)inb(pcm_s.iobase + 12)
1551 + (signed char)inb(pcm_s.iobase + 12)) >> 1;
1555 /* Speed conversion with linear interpolation method. */
1557 d1 = ((signed char)inb(pcm_s.iobase + 12)
1558 + (signed char)inb(pcm_s.iobase + 12)) >> 1;
1559 for (i = 0; i < count; i++) {
1560 while (pcm_s.acc >= pcm_s.speed) {
1561 pcm_s.acc -= pcm_s.speed;
1563 d1 = ((signed char)inb(pcm_s.iobase + 12)
1564 + (signed char)inb(pcm_s.iobase + 12)) >> 1;
1566 d = ((d0 * (pcm_s.speed - pcm_s.acc)) + (d1 * pcm_s.acc))
1569 pcm_s.acc += pcm_s.chipspeed;
1578 fifo_recv_mono_16le(pcm_data *buf, int count, int uflag)
1581 short d, d0, d1, el, er, zlev;
1583 zlev = uflag ? -128 : 0;
1586 if (pcm_s.speed == pcm_s.chipspeed) {
1587 /* No reason to convert the pcm speed. */
1588 for (i = 0; i < cnt; i++) {
1589 el = inb(pcm_s.iobase + 12) << 8;
1590 el |= inb(pcm_s.iobase + 12);
1591 er = inb(pcm_s.iobase + 12) << 8;
1592 er |= inb(pcm_s.iobase + 12);
1595 *buf++ = ((d >> 8) & 0xff) + zlev;
1598 el = inb(pcm_s.iobase + 12) << 8;
1599 el |= inb(pcm_s.iobase + 12);
1600 er = inb(pcm_s.iobase + 12) << 8;
1601 er |= inb(pcm_s.iobase + 12);
1604 tmpbuf.buff[0] = ((d >> 8) & 0xff) + zlev;
1608 /* Speed conversion with linear interpolation method. */
1610 el = inb(pcm_s.iobase + 12) << 8;
1611 el |= inb(pcm_s.iobase + 12);
1612 er = inb(pcm_s.iobase + 12) << 8;
1613 er |= inb(pcm_s.iobase + 12);
1614 d1 = (el + er) >> 1;
1615 for (i = 0; i < cnt; i++) {
1616 while (pcm_s.acc >= pcm_s.speed) {
1617 pcm_s.acc -= pcm_s.speed;
1619 el = inb(pcm_s.iobase + 12) << 8;
1620 el |= inb(pcm_s.iobase + 12);
1621 er = inb(pcm_s.iobase + 12) << 8;
1622 er |= inb(pcm_s.iobase + 12);
1623 d1 = (el + er) >> 1;
1625 d = ((d0 * (pcm_s.speed - pcm_s.acc)) + (d1 * pcm_s.acc))
1628 *buf++ = ((d >> 8) & 0xff) + zlev;
1629 pcm_s.acc += pcm_s.chipspeed;
1632 while (pcm_s.acc >= pcm_s.speed) {
1633 pcm_s.acc -= pcm_s.speed;
1635 el = inb(pcm_s.iobase + 12) << 8;
1636 el |= inb(pcm_s.iobase + 12);
1637 er = inb(pcm_s.iobase + 12) << 8;
1638 er |= inb(pcm_s.iobase + 12);
1639 d1 = (el + er) >> 1;
1641 d = ((d0 * (pcm_s.speed - pcm_s.acc)) + (d1 * pcm_s.acc))
1644 tmpbuf.buff[0] = ((d >> 8) & 0xff) + zlev;
1654 fifo_recv_mono_16be(pcm_data *buf, int count, int uflag)
1657 short d, d0, d1, el, er, zlev;
1659 zlev = uflag ? -128 : 0;
1662 if (pcm_s.speed == pcm_s.chipspeed) {
1663 /* No reason to convert the pcm speed. */
1664 for (i = 0; i < cnt; i++) {
1665 el = inb(pcm_s.iobase + 12) << 8;
1666 el |= inb(pcm_s.iobase + 12);
1667 er = inb(pcm_s.iobase + 12) << 8;
1668 er |= inb(pcm_s.iobase + 12);
1670 *buf++ = ((d >> 8) & 0xff) + zlev;
1674 el = inb(pcm_s.iobase + 12) << 8;
1675 el |= inb(pcm_s.iobase + 12);
1676 er = inb(pcm_s.iobase + 12) << 8;
1677 er |= inb(pcm_s.iobase + 12);
1679 *buf++ = ((d >> 8) & 0xff) + zlev;
1680 tmpbuf.buff[0] = d & 0xff;
1684 /* Speed conversion with linear interpolation method. */
1686 el = inb(pcm_s.iobase + 12) << 8;
1687 el |= inb(pcm_s.iobase + 12);
1688 er = inb(pcm_s.iobase + 12) << 8;
1689 er |= inb(pcm_s.iobase + 12);
1690 d1 = (el + er) >> 1;
1691 for (i = 0; i < cnt; i++) {
1692 while (pcm_s.acc >= pcm_s.speed) {
1693 pcm_s.acc -= pcm_s.speed;
1695 el = inb(pcm_s.iobase + 12) << 8;
1696 el |= inb(pcm_s.iobase + 12);
1697 er = inb(pcm_s.iobase + 12) << 8;
1698 er |= inb(pcm_s.iobase + 12);
1699 d1 = (el + er) >> 1;
1701 d = ((d0 * (pcm_s.speed - pcm_s.acc)) + (d1 * pcm_s.acc))
1703 *buf++ = ((d >> 8) & 0xff) + zlev;
1705 pcm_s.acc += pcm_s.chipspeed;
1708 while (pcm_s.acc >= pcm_s.speed) {
1709 pcm_s.acc -= pcm_s.speed;
1711 el = inb(pcm_s.iobase + 12) << 8;
1712 el |= inb(pcm_s.iobase + 12);
1713 er = inb(pcm_s.iobase + 12) << 8;
1714 er |= inb(pcm_s.iobase + 12);
1715 d1 = (el + er) >> 1;
1717 d = ((d0 * (pcm_s.speed - pcm_s.acc)) + (d1 * pcm_s.acc))
1719 *buf++ = ((d >> 8) & 0xff) + zlev;
1720 tmpbuf.buff[0] = d & 0xff;
1732 fifo_stop(); /* stop FIFO */
1733 fifo_reset(); /* reset FIFO buffer */
1735 /* Reset driver's status. */
1736 pcm_s.intr_busy = NO;
1737 pcm_s.intr_last = NO;
1738 pcm_s.intr_trailer = NO;
1743 DEB(printf("nss_stop\n"));
1750 /* Initialize registers on the board. */
1752 if (pcm_s.board_type == PC980173_FAMILY)
1755 /* Set default volume. */
1756 set_volume(DEFAULT_VOLUME);
1758 /* Initialize driver's status. */
1760 nss_initialized = YES;
1765 * Codes for global use
1769 probe_nss(struct address_info *hw_config)
1771 return nss_detect(hw_config);
1776 attach_nss(struct address_info *hw_config)
1778 if (pcm_s.board_type == NO_SUPPORTED_BOARD)
1781 /* Initialize the board. */
1784 conf_printf(nss_operations.name, hw_config);
1786 if (num_audiodevs < MAX_AUDIO_DEV) {
1787 my_dev = num_audiodevs++;
1788 audio_devs[my_dev] = &nss_operations;
1789 /* audio_devs[my_dev]->buffcount = DSP_BUFFCOUNT; */
1790 audio_devs[my_dev]->buffsize = DSP_BUFFSIZE;
1792 printf("\nbuffsize = %d", DSP_BUFFSIZE);
1795 printf("nss0: Too many PCM devices available");
1802 nss_detect(struct address_info *hw_config)
1804 int opna_iobase = 0x188, irq = 12, i;
1807 if (hw_config->io_base == -1) {
1808 printf("nss0: iobase not specified. Assume default port(0x%x)\n",
1810 hw_config->io_base = PCM86_IOBASE;
1812 pcm_s.iobase = hw_config->io_base;
1814 /* auto configuration */
1815 tmp = (inb(pcm_s.iobase) & 0xf0) >> 4;
1818 * Remap MATE-X PCM Sound ID register (0xA460 -> 0xB460)
1819 * to avoid corrision with 86 Sound System.
1822 printf("nss0: Found MATE-X PCM Sound ID\n");
1823 printf("nss0: Remaped 0xa460 to 0xb460\n");
1830 tmp = inb(pcm_s.iobase) & 0xfc;
1831 switch ((tmp & 0xf0) >> 4) {
1833 opna_iobase = 0x188;
1834 pcm_s.board_type = PC980173_FAMILY;
1837 opna_iobase = 0x288;
1838 pcm_s.board_type = PC980173_FAMILY;
1841 opna_iobase = 0x188;
1842 pcm_s.board_type = PC980186_FAMILY;
1845 opna_iobase = 0x288;
1846 pcm_s.board_type = PC980186_FAMILY;
1849 pcm_s.board_type = NO_SUPPORTED_BOARD;
1853 /* Enable OPNA(YM2608) facilities. */
1854 outb(pcm_s.iobase, tmp | 0x01);
1856 /* Wait for OPNA to be ready. */
1857 i = 100000; /* Some large value */
1858 while((inb(opna_iobase) & 0x80) && (i-- > 0));
1860 /* Make IOA/IOB port ready (IOA:input, IOB:output) */
1861 outb(opna_iobase, 0x07);
1862 outb(0x5f, 0); /* Because OPNA ports are comparatively slow(?), */
1863 outb(0x5f, 0); /* we'd better wait a moment. */
1866 tmp = inb(opna_iobase + 2) & 0x3f;
1867 outb(opna_iobase + 2, tmp | 0x80);
1869 /* Wait for OPNA to be ready. */
1870 i = 100000; /* Some large value */
1871 while((inb(opna_iobase) & 0x80) && (i-- > 0));
1873 /* Get irq number from IOA port. */
1874 outb(opna_iobase, 0x0e);
1879 tmp = inb(opna_iobase + 2) & 0xc0;
1881 case 0: /* INT0 (IRQ3)*/
1884 case 1: /* INT6 (IRQ13)*/
1887 case 2: /* INT4 (IRQ10)*/
1890 case 3: /* INT5 (IRQ12)*/
1893 default: /* error */
1897 /* Wait for OPNA to be ready. */
1898 i = 100000; /* Some large value */
1899 while((inb(opna_iobase) & 0x80) && (i-- > 0));
1901 /* Reset OPNA timer register. */
1902 outb(opna_iobase, 0x27);
1907 outb(opna_iobase + 2, 0x30);
1909 /* Ok. Detection finished. */
1910 snprintf(nss_operations.name, sizeof(nss_operations.name),
1911 "%s", board_name[pcm_s.board_type]);
1912 nss_initialized = NO;
1915 if ((hw_config->irq > 0) && (hw_config->irq != irq))
1916 printf("nss0: change irq %d -> %d\n", hw_config->irq, irq);
1917 hw_config->irq = irq;
1919 pcm_s.osp = hw_config->osp;
1926 nss_open(int dev, int mode)
1930 if (!nss_initialized)
1933 if (pcm_s.intr_busy || pcm_s.opened)
1936 if ((err = snd_set_irq_handler(pcm_s.irq, nssintr, pcm_s.osp)) < 0)
1942 pcm_s.intr_mode = IMODE_NONE;
1952 /* snd_release_irq(pcm_s.irq); */
1959 nss_output_block(int dev, unsigned long buf, int count, int intrflag,
1962 unsigned long flags, cnt;
1966 printf("nss_output_block():");
1967 if (audio_devs[dev]->dmap_out->flags & DMA_BUSY)
1968 printf(" DMA_BUSY");
1969 if (audio_devs[dev]->dmap_out->flags & DMA_RESTART)
1970 printf(" DMA_RESTART");
1971 if (audio_devs[dev]->dmap_out->flags & DMA_ACTIVE)
1972 printf(" DMA_ACTIVE");
1973 if (audio_devs[dev]->dmap_out->flags & DMA_STARTED)
1974 printf(" DMA_STARTED");
1975 if (audio_devs[dev]->dmap_out->flags & DMA_ALLOC_DONE)
1976 printf(" DMA_ALLOC_DONE");
1981 DISABLE_INTR(flags);
1985 printf("nss_output_block(): count = %d, intrsize= %d\n",
1986 count, pcm_s.intr_size);
1989 pcm_s.pdma_buf = (pcm_data *)buf;
1990 pcm_s.pdma_count = count;
1991 pcm_s.pdma_chunkcount = 1;
1992 maxchunksize = (((PCM86_FIFOSIZE - pcm_s.intr_size * 2)
1993 / (pcm_s.bytes * 2)) * pcm_s.speed
1994 / pcm_s.chipspeed) * (pcm_s.bytes << pcm_s.stereo);
1995 if (count > maxchunksize)
1996 pcm_s.pdma_chunkcount = 2 * count / maxchunksize;
1998 * Let chunksize = (float)count / (float)pcm_s.pdma_chunkcount.
1999 * Data of size chunksize is sent to the FIFO buffer on the 86-board
2000 * on every occuring of interrupt.
2001 * By assuming that pcm_s.intr_size < PCM86_FIFOSIZE / 2, we can conclude
2002 * that the FIFO buffer never overflows from the following lemma.
2005 * maxchunksize / 2 <= chunksize <= maxchunksize.
2006 * (Though pcm_s.pdma_chunkcount is obtained through the flooring
2007 * function, this inequality holds.)
2011 fifo_output_block();
2013 pcm_s.intr_last = NO;
2014 pcm_s.intr_mode = IMODE_OUTPUT;
2015 if (!pcm_s.intr_busy)
2016 fifo_start(IMODE_OUTPUT);
2017 pcm_s.intr_busy = YES;
2020 RESTORE_INTR(flags);
2026 nss_start_input(int dev, unsigned long buf, int count, int intrflag,
2029 unsigned long flags, cnt;
2033 printf("nss_start_input():");
2034 if (audio_devs[dev]->dmap_in->flags & DMA_BUSY)
2035 printf(" DMA_BUSY");
2036 if (audio_devs[dev]->dmap_in->flags & DMA_RESTART)
2037 printf(" DMA_RESTART");
2038 if (audio_devs[dev]->dmap_in->flags & DMA_ACTIVE)
2039 printf(" DMA_ACTIVE");
2040 if (audio_devs[dev]->dmap_in->flags & DMA_STARTED)
2041 printf(" DMA_STARTED");
2042 if (audio_devs[dev]->dmap_in->flags & DMA_ALLOC_DONE)
2043 printf(" DMA_ALLOC_DONE");
2048 DISABLE_INTR(flags);
2051 pcm_s.intr_size = PCM86_INTRSIZE_IN;
2054 printf("nss_start_input(): count = %d, intrsize= %d\n",
2055 count, pcm_s.intr_size);
2058 pcm_s.pdma_buf = (pcm_data *)buf;
2059 pcm_s.pdma_count = count;
2060 pcm_s.pdma_chunkcount = 1;
2061 maxchunksize = ((pcm_s.intr_size / (pcm_s.bytes * 2)) * pcm_s.speed
2062 / pcm_s.chipspeed) * (pcm_s.bytes << pcm_s.stereo);
2063 if (count > maxchunksize)
2064 pcm_s.pdma_chunkcount = 2 * count / maxchunksize;
2066 pcm_s.intr_mode = IMODE_INPUT;
2067 if (!pcm_s.intr_busy)
2068 fifo_start(IMODE_INPUT);
2069 pcm_s.intr_busy = YES;
2072 RESTORE_INTR(flags);
2078 nss_ioctl(int dev, u_int cmd, ioctl_arg arg, int local)
2081 case SOUND_PCM_WRITE_RATE:
2083 return set_speed((int) arg);
2084 return *(int *) arg = set_speed((*(int *) arg));
2086 case SOUND_PCM_READ_RATE:
2089 return *(int *) arg = pcm_s.speed;
2091 case SNDCTL_DSP_STEREO:
2093 return set_stereo((int) arg);
2094 return *(int *) arg = set_stereo((*(int *) arg));
2096 case SOUND_PCM_WRITE_CHANNELS:
2098 return set_stereo((int) arg - 1) + 1;
2099 return *(int *) arg = set_stereo((*(int *) arg) - 1) + 1;
2101 case SOUND_PCM_READ_CHANNELS:
2103 return pcm_s.stereo + 1;
2104 return *(int *) arg = pcm_s.stereo + 1;
2106 case SNDCTL_DSP_SETFMT:
2108 return set_format((int) arg);
2109 return *(int *) arg = set_format((*(int *) arg));
2111 case SOUND_PCM_READ_BITS:
2113 return pcm_s.bytes * 8;
2114 return *(int *) arg = pcm_s.bytes * 8;
2117 /* Invalid ioctl request */
2123 nss_prepare_for_input(int dev, int bufsize, int nbufs)
2125 pcm_s.intr_size = PCM86_INTRSIZE_IN;
2126 pcm_s.intr_mode = IMODE_NONE;
2131 DEB(printf("nss_prepare_for_input\n"));
2138 nss_prepare_for_output(int dev, int bufsize, int nbufs)
2140 pcm_s.intr_size = PCM86_INTRSIZE_OUT;
2141 pcm_s.intr_mode = IMODE_NONE;
2146 DEB(printf("nss_prepare_for_output\n"));
2160 nss_halt_xfer(int dev)
2164 DEB(printf("nss_halt_xfer\n"));
2173 if ((inb(pcm_s.iobase + 8) & 0x10) == 0)
2174 return; /* not FIFO intr. */
2176 switch(pcm_s.intr_mode) {
2178 if (pcm_s.intr_trailer) {
2179 DEB(printf("nssintr(): fifo_reset\n"));
2181 pcm_s.intr_trailer = NO;
2182 pcm_s.intr_busy = NO;
2184 if (pcm_s.pdma_count > 0)
2185 fifo_output_block();
2187 DMAbuf_outputintr(my_dev, 1);
2188 /* Reset intr. flag. */
2189 tmp = inb(pcm_s.iobase + 8);
2190 outb(pcm_s.iobase + 8, tmp & ~0x10);
2191 outb(pcm_s.iobase + 8, tmp | 0x10);
2196 if (pcm_s.pdma_count == 0)
2197 DMAbuf_inputintr(my_dev);
2198 /* Reset intr. flag. */
2199 tmp = inb(pcm_s.iobase + 8);
2200 outb(pcm_s.iobase + 8, tmp & ~0x10);
2201 outb(pcm_s.iobase + 8, tmp | 0x10);
2206 printf("nss0: unexpected interrupt\n");
2211 #endif /* EXCLUDE_NSS, EXCLUDE_AUDIO */
2213 #endif /* CONFIGURE_SOUNDCARD */