Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / platform / pc32 / isa / sound / pcm86.c
1 /*
2  * PC-9801-86 PCM driver for FreeBSD(98).
3  *
4  * Copyright (c) 1995  NAGAO Tadaaki (ABTK)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
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.
15  *
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
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD: src/sys/i386/isa/sound/pcm86.c,v 1.9 1999/08/28 00:45:19 peter Exp $
29  */
30
31 /*
32  * !! NOTE !! :
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)
36  */
37
38
39 #include <i386/isa/sound/sound_config.h>
40
41 #ifdef CONFIGURE_SOUNDCARD
42
43 #if !defined(EXCLUDE_NSS) && !defined(EXCLUDE_AUDIO)
44
45
46 /*
47  * Constants
48  */
49
50 #define YES             1
51 #define NO              0
52
53 #define IMODE_NONE      0
54 #define IMODE_INPUT     1
55 #define IMODE_OUTPUT    2
56
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 */
60
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) */
65
66
67 /*
68  * Switches for debugging and experiments
69  */
70
71 /* #define NSS_DEBUG */
72
73 #ifdef NSS_DEBUG
74 # ifdef DEB
75 #  undef DEB
76 # endif
77 # define DEB(x) x
78 #endif
79
80
81 /*
82  * Private variables and types
83  */
84
85 typedef unsigned char pcm_data;
86
87 enum board_type {
88     NO_SUPPORTED_BOARD = 0,
89     PC980186_FAMILY = 1,
90     PC980173_FAMILY = 2
91 };
92
93 static char *board_name[] = {
94     /* Each must be of the length less than 32 bytes. */
95     "No supported board",
96     "PC-9801-86 soundboard",
97     "PC-9801-73 soundboard"
98 };
99
100 /* Current status of the driver */
101 static struct {
102     int                 iobase;
103     int                 irq;
104     enum board_type     board_type;
105     int                 opened;
106     int                 format;
107     int                 bytes;
108     int                 chipspeedno;
109     int                 chipspeed;
110     int                 speed;
111     int                 stereo;
112     int                 volume;
113     int                 intr_busy;
114     int                 intr_size;
115     int                 intr_mode;
116     int                 intr_last;
117     int                 intr_trailer;
118     pcm_data *          pdma_buf;
119     int                 pdma_count;
120     int                 pdma_chunkcount;
121     int                 acc;
122     int                 last_l;
123     int                 last_r;
124     sound_os_info       *osp;
125 } pcm_s;
126
127 static struct {
128     pcm_data            buff[4];
129     int                 size;
130 } tmpbuf;
131
132 static int my_dev = 0;
133 static char nss_initialized = NO;
134
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
139 #else
140     /*
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
144      * 4000Hz.
145      */
146     44100, 33075, 22050, 16000, 11025, 8000, 5510, 4000
147 #endif
148 };
149
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
184 };
185
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
220 };
221
222
223 /*
224  * Prototypes
225  */
226
227 static int nss_detect(struct address_info *);
228
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);
238
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);
276
277
278 /*
279  * Identity
280  */
281
282 static struct audio_operations nss_operations =
283 {
284     "PC-9801-86 SoundBoard", /* filled in properly by auto configuration */
285     DMA_DISABLE,
286     ( AFMT_MU_LAW |
287       AFMT_U8 | AFMT_S16_LE | AFMT_S16_BE |
288       AFMT_S8 | AFMT_U16_LE | AFMT_U16_BE ),
289     NULL,
290     nss_open,
291     nss_close,
292     nss_output_block,
293     nss_start_input,
294     nss_ioctl,
295     nss_prepare_for_input,
296     nss_prepare_for_output,
297     nss_reset,
298     nss_halt_xfer,
299     NULL,
300     NULL
301 };
302
303
304 /*
305  * Codes for internal use
306  */
307
308 static void
309 dsp73_send_command(unsigned char command)
310 {
311     /* wait for RDY */
312     while ((inb(pcm_s.iobase + 2) & 0x48) != 8);
313
314     /* command mode */
315     outb(pcm_s.iobase + 2, (inb(pcm_s.iobase + 2) & 0x20) | 3);
316
317     /* wait for RDY */
318     while ((inb(pcm_s.iobase + 2) & 0x48) != 8);
319
320     /* send command */
321     outb(pcm_s.iobase + 4, command);
322 }
323
324
325 static void
326 dsp73_send_data(unsigned char data)
327 {
328     /* wait for RDY */
329     while ((inb(pcm_s.iobase + 2) & 0x48) != 8);
330
331     /* data mode */
332     outb(pcm_s.iobase + 2, (inb(pcm_s.iobase + 2) & 0x20) | 0x83);
333
334     /* wait for RDY */
335     while ((inb(pcm_s.iobase + 2) & 0x48) != 8);
336
337     /* send command */
338     outb(pcm_s.iobase + 4, data);
339 }
340
341
342 static void
343 dsp73_init(void)
344 {
345     const unsigned char dspinst[15] = {
346         0x00, 0x00, 0x27,
347         0x3f, 0xe0, 0x01,
348         0x00, 0x00, 0x27,
349         0x36, 0x5a, 0x0d,
350         0x3e, 0x60, 0x04
351     };
352     unsigned char t;
353     int i;
354
355     /* reset DSP */
356     t = inb(pcm_s.iobase + 2);
357     outb(pcm_s.iobase + 2, (t & 0x80) | 0x23);
358
359     /* mute on */
360     dsp73_send_command(0x04);
361     dsp73_send_data(0x6f);
362     dsp73_send_data(0x3c);
363
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]);
369
370     /* mute off */
371     dsp73_send_command(0x04);
372     dsp73_send_data(0x6f);
373     dsp73_send_data(0x30);
374
375     /* wait for RDY */
376     while ((inb(pcm_s.iobase + 2) & 0x48) != 8);
377
378     outb(pcm_s.iobase + 2, 3);
379 }
380
381
382 static int
383 set_format(int format)
384 {
385     switch (format) {
386     case AFMT_MU_LAW:
387     case AFMT_S8:
388     case AFMT_U8:
389         pcm_s.format = format;
390         pcm_s.bytes = 1;        /* 8bit */
391         break;
392     case AFMT_S16_LE:
393     case AFMT_U16_LE:
394     case AFMT_S16_BE:
395     case AFMT_U16_BE:
396         pcm_s.format = format;
397         pcm_s.bytes = 2;        /* 16bit */
398         break;
399     case AFMT_QUERY:
400         break;
401     default:
402         return -1;
403     }
404
405     return pcm_s.format;
406 }
407
408
409 static int
410 set_speed(int speed)
411 {
412     int i;
413
414     if (speed < 4000)   /* Minimum 4000Hz */
415         speed = 4000;
416     if (speed > 44100)  /* Maximum 44100Hz */
417         speed = 44100;
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];
422             break;
423         }
424     }
425     pcm_s.speed = speed;
426
427     return speed;
428 }
429
430
431 static int
432 set_stereo(int stereo)
433 {
434     pcm_s.stereo = stereo ? YES : NO;
435
436     return pcm_s.stereo;
437 }
438
439
440 static void
441 set_volume(int volume)
442 {
443     if (volume < 0)
444         volume = 0;
445     if (volume > 15)
446         volume = 15;
447     pcm_s.volume = volume;
448
449     outb(pcm_s.iobase + 6, 0xaf - volume);      /* D/A -> LINE OUT */
450     outb(0x5f,0);
451     outb(0x5f,0);
452     outb(0x5f,0);
453     outb(0x5f,0);
454     outb(pcm_s.iobase + 6, 0x20);               /* FM -> A/D */
455     outb(0x5f,0);
456     outb(0x5f,0);
457     outb(0x5f,0);
458     outb(0x5f,0);
459     outb(pcm_s.iobase + 6, 0x60);               /* LINE IN -> A/D */
460     outb(0x5f,0);
461     outb(0x5f,0);
462     outb(0x5f,0);
463     outb(0x5f,0);
464 }
465
466
467 static void
468 fifo_start(int mode)
469 {
470     unsigned char tmp;
471
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));
475
476     tmp = pcm_s.chipspeedno;
477     if (mode == IMODE_INPUT)
478         tmp |= 0x40;
479
480     /* Reset intr. flag. */
481     outb(pcm_s.iobase + 8, tmp);
482     outb(pcm_s.iobase + 8, tmp | 0x10);
483
484     /* Enable FIFO intr. */
485     outb(pcm_s.iobase + 8, tmp | 0x30);
486
487     /* Set intr. interval. */
488     outb(pcm_s.iobase + 10, pcm_s.intr_size / 128 - 1);
489
490     /* Start intr. */
491     outb(pcm_s.iobase + 8, tmp | 0xb0);
492 }
493
494
495 static void
496 fifo_stop(void)
497 {
498     unsigned char tmp;
499
500     /* Reset intr. flag, and disable FIFO intr. */
501     tmp = inb(pcm_s.iobase + 8) & 0x0f;
502     outb(pcm_s.iobase + 8, tmp);
503 }
504
505
506 static void
507 fifo_reset(void)
508 {
509     unsigned char tmp;
510
511     /* Reset FIFO. */
512     tmp = inb(pcm_s.iobase + 8) & 0x77;
513     outb(pcm_s.iobase + 8, tmp | 0x8);
514     outb(pcm_s.iobase + 8, tmp);
515 }
516
517
518 static void
519 fifo_output_block(void)
520 {
521     int chunksize, count;
522
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);
527     } else {
528         /* ??? something wrong... */
529         printf("nss0: chunkcount overrun\n");
530         chunksize = count = 0;
531     }
532
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;
538     }
539
540     pcm_s.pdma_buf += chunksize;
541     pcm_s.pdma_count -= chunksize;
542 }
543
544
545 static int
546 fifo_send(pcm_data *buf, int count)
547 {
548     int i, length, r, cnt, rslt;
549     pcm_data *p;
550
551     /* Calculate the length of PCM frames. */
552     cnt = count + tmpbuf.size;
553     length = pcm_s.bytes << pcm_s.stereo;
554     r = cnt % length;
555     cnt -= r;
556
557     if (cnt > 0) {
558         if (pcm_s.stereo)
559             fifo_send_stereo(buf, cnt);
560         else
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++;
566     } else {
567         /* Carry over extra data which doesn't seem to be a full PCM frame. */
568         p = (pcm_data *)buf;
569         for (i = tmpbuf.size; i < r; i++)
570             tmpbuf.buff[i] = *p++;
571     }
572     tmpbuf.size = r;
573
574     rslt = ((cnt / length) * pcm_s.chipspeed / pcm_s.speed) * pcm_s.bytes * 2;
575 #ifdef NSS_DEBUG
576     printf("fifo_send(): %d bytes sent\n", rslt);
577 #endif
578     return rslt;
579 }
580
581
582 static void
583 fifo_sendtrailer(int count)
584 {
585     /* Send trailing zeros to the FIFO buffer. */
586     int i;
587
588     for (i = 0; i < count; i++)
589         outb(pcm_s.iobase + 12, 0);
590     pcm_s.intr_trailer = YES;
591
592 #ifdef NSS_DEBUG
593     printf("fifo_sendtrailer(): %d bytes sent\n", count);
594 #endif
595 }
596
597
598 static void
599 fifo_send_stereo(pcm_data *buf, int count)
600 {
601     /* Convert format and sampling speed. */
602     switch (pcm_s.format) {
603     case AFMT_MU_LAW:
604         fifo_send_stereo_ulaw(buf, count);
605         break;
606     case AFMT_S8:
607         fifo_send_stereo_8(buf, count, NO);
608         break;
609     case AFMT_U8:
610         fifo_send_stereo_8(buf, count, YES);
611         break;
612     case AFMT_S16_LE:
613         fifo_send_stereo_16le(buf, count, NO);
614         break;
615     case AFMT_U16_LE:
616         fifo_send_stereo_16le(buf, count, YES);
617         break;
618     case AFMT_S16_BE:
619         fifo_send_stereo_16be(buf, count, NO);
620         break;
621     case AFMT_U16_BE:
622         fifo_send_stereo_16be(buf, count, YES);
623         break;
624     }
625 }
626
627
628 static void
629 fifo_send_monoral(pcm_data *buf, int count)
630 {
631     /* Convert format and sampling speed. */
632     switch (pcm_s.format) {
633     case AFMT_MU_LAW:
634         fifo_send_mono_ulaw(buf, count);
635         break;
636     case AFMT_S8:
637         fifo_send_mono_8(buf, count, NO);
638         break;
639     case AFMT_U8:
640         fifo_send_mono_8(buf, count, YES);
641         break;
642     case AFMT_S16_LE:
643         fifo_send_mono_16le(buf, count, NO);
644         break;
645     case AFMT_U16_LE:
646         fifo_send_mono_16le(buf, count, YES);
647         break;
648     case AFMT_S16_BE:
649         fifo_send_mono_16be(buf, count, NO);
650         break;
651     case AFMT_U16_BE:
652         fifo_send_mono_16be(buf, count, YES);
653         break;
654     }
655 }
656
657
658 static void
659 fifo_send_stereo_ulaw(pcm_data *buf, int count)
660 {
661     int i;
662     signed char dl, dl0, dl1, dr, dr0, dr1;
663     pcm_data t[2];
664
665     if (tmpbuf.size > 0)
666         t[0] = ulaw2linear[tmpbuf.buff[0]];
667     else
668         t[0] = ulaw2linear[*buf++];
669     t[1] = ulaw2linear[*buf++];
670
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]);
675         count -= 2;
676         for (i = 0; i < count; i++)
677             outb(pcm_s.iobase + 12, ulaw2linear[*buf++]);
678     } else {
679         /* Speed conversion with linear interpolation method. */
680         dl0 = pcm_s.last_l;
681         dr0 = pcm_s.last_r;
682         dl1 = t[0];
683         dr1 = t[1];
684         i = 0;
685         count /= 2;
686         while (i < count) {
687             while (pcm_s.acc >= pcm_s.chipspeed) {
688                 pcm_s.acc -= pcm_s.chipspeed;
689                 i++;
690                 dl0 = dl1;
691                 dr0 = dr1;
692                 if (i < count) {
693                     dl1 = ulaw2linear[*buf++];
694                     dr1 = ulaw2linear[*buf++];
695                 } else
696                     dl1 = dr1 = 0;
697             }
698             dl = ((dl0 * (pcm_s.chipspeed - pcm_s.acc)) + (dl1 * pcm_s.acc))
699                 / pcm_s.chipspeed;
700             dr = ((dr0 * (pcm_s.chipspeed - pcm_s.acc)) + (dr1 * pcm_s.acc))
701                 / pcm_s.chipspeed;
702             outb(pcm_s.iobase + 12, dl);
703             outb(pcm_s.iobase + 12, dr);
704             pcm_s.acc += pcm_s.speed;
705         }
706
707         pcm_s.last_l = dl0;
708         pcm_s.last_r = dr0;
709     }
710 }
711
712
713 static void
714 fifo_send_stereo_8(pcm_data *buf, int count, int uflag)
715 {
716     int i;
717     signed char dl, dl0, dl1, dr, dr0, dr1, zlev;
718     pcm_data t[2];
719
720     zlev = uflag ? -128 : 0;
721
722     if (tmpbuf.size > 0)
723         t[0] = tmpbuf.buff[0] + zlev;
724     else
725         t[0] = *buf++ + zlev;
726     t[1] = *buf++ + zlev;
727
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]);
732         count -= 2;
733         for (i = 0; i < count; i++)
734             outb(pcm_s.iobase + 12, *buf++ + zlev);
735     } else {
736         /* Speed conversion with linear interpolation method. */
737         dl0 = pcm_s.last_l;
738         dr0 = pcm_s.last_r;
739         dl1 = t[0];
740         dr1 = t[1];
741         i = 0;
742         count /= 2;
743         while (i < count) {
744             while (pcm_s.acc >= pcm_s.chipspeed) {
745                 pcm_s.acc -= pcm_s.chipspeed;
746                 i++;
747                 dl0 = dl1;
748                 dr0 = dr1;
749                 if (i < count) {
750                     dl1 = *buf++ + zlev;
751                     dr1 = *buf++ + zlev;
752                 } else
753                     dl1 = dr1 = 0;
754             }
755             dl = ((dl0 * (pcm_s.chipspeed - pcm_s.acc)) + (dl1 * pcm_s.acc))
756                 / pcm_s.chipspeed;
757             dr = ((dr0 * (pcm_s.chipspeed - pcm_s.acc)) + (dr1 * pcm_s.acc))
758                 / pcm_s.chipspeed;
759             outb(pcm_s.iobase + 12, dl);
760             outb(pcm_s.iobase + 12, dr);
761             pcm_s.acc += pcm_s.speed;
762         }
763
764         pcm_s.last_l = dl0;
765         pcm_s.last_r = dr0;
766     }
767 }
768
769
770 static void
771 fifo_send_stereo_16le(pcm_data *buf, int count, int uflag)
772 {
773     int i;
774     short dl, dl0, dl1, dr, dr0, dr1, zlev;
775     pcm_data t[4];
776
777     zlev = uflag ? -128 : 0;
778
779     for (i = 0; i < 4; i++)
780         t[i] = (tmpbuf.size > i) ? tmpbuf.buff[i] : *buf++;
781
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);
792             buf += 2;
793         }
794     } else {
795         /* Speed conversion with linear interpolation method. */
796         dl0 = pcm_s.last_l;
797         dr0 = pcm_s.last_r;
798         dl1 = t[0] + ((t[1] + zlev) << 8);
799         dr1 = t[2] + ((t[3] + zlev) << 8);
800         i = 0;
801         count /= 4;
802         while (i < count) {
803             while (pcm_s.acc >= pcm_s.chipspeed) {
804                 pcm_s.acc -= pcm_s.chipspeed;
805                 i++;
806                 dl0 = dl1;
807                 dr0 = dr1;
808                 if (i < count) {
809                     dl1 = *buf + ((*(buf + 1) + zlev) << 8);
810                     buf += 2;
811                     dr1 = *buf + ((*(buf + 1) + zlev) << 8);
812                     buf += 2;
813                 } else
814                     dl1 = dr1 = 0;
815             }
816             dl = ((dl0 * (pcm_s.chipspeed - pcm_s.acc)) + (dl1 * pcm_s.acc))
817                 / pcm_s.chipspeed;
818             dr = ((dr0 * (pcm_s.chipspeed - pcm_s.acc)) + (dr1 * pcm_s.acc))
819                 / pcm_s.chipspeed;
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;
825         }
826
827         pcm_s.last_l = dl0;
828         pcm_s.last_r = dr0;
829     }
830 }
831
832
833 static void
834 fifo_send_stereo_16be(pcm_data *buf, int count, int uflag)
835 {
836     int i;
837     short dl, dl0, dl1, dr, dr0, dr1, zlev;
838     pcm_data t[4];
839
840     zlev = uflag ? -128 : 0;
841
842     for (i = 0; i < 4; i++)
843         t[i] = (tmpbuf.size > i) ? tmpbuf.buff[i] : *buf++;
844
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));
855             buf += 2;
856         }
857     } else {
858         /* Speed conversion with linear interpolation method. */
859         dl0 = pcm_s.last_l;
860         dr0 = pcm_s.last_r;
861         dl1 = ((t[0] + zlev) << 8) + t[1];
862         dr1 = ((t[2] + zlev) << 8) + t[3];
863         i = 0;
864         count /= 4;
865         while (i < count) {
866             while (pcm_s.acc >= pcm_s.chipspeed) {
867                 pcm_s.acc -= pcm_s.chipspeed;
868                 i++;
869                 dl0 = dl1;
870                 dr0 = dr1;
871                 if (i < count) {
872                     dl1 = ((*buf + zlev) << 8) + *(buf + 1);
873                     buf += 2;
874                     dr1 = ((*buf + zlev) << 8) + *(buf + 1);
875                     buf += 2;
876                 } else
877                     dl1 = dr1 = 0;
878             }
879             dl = ((dl0 * (pcm_s.chipspeed - pcm_s.acc)) + (dl1 * pcm_s.acc))
880                 / pcm_s.chipspeed;
881             dr = ((dr0 * (pcm_s.chipspeed - pcm_s.acc)) + (dr1 * pcm_s.acc))
882                 / pcm_s.chipspeed;
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;
888         }
889
890         pcm_s.last_l = dl0;
891         pcm_s.last_r = dr0;
892     }
893 }
894
895
896 static void
897 fifo_send_mono_ulaw(pcm_data *buf, int count)
898 {
899     int i;
900     signed char d, d0, d1;
901
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);
908         }
909     else {
910         /* Speed conversion with linear interpolation method. */
911         d0 = pcm_s.last_l;
912         d1 = ulaw2linear[*buf++];
913         i = 0;
914         while (i < count) {
915             while (pcm_s.acc >= pcm_s.chipspeed) {
916                 pcm_s.acc -= pcm_s.chipspeed;
917                 i++;
918                 d0 = d1;
919                 d1 = (i < count) ? ulaw2linear[*buf++] : 0;
920             }
921             d = ((d0 * (pcm_s.chipspeed - pcm_s.acc)) + (d1 * pcm_s.acc))
922                 / pcm_s.chipspeed;
923             outb(pcm_s.iobase + 12, d);
924             outb(pcm_s.iobase + 12, d);
925             pcm_s.acc += pcm_s.speed;
926         }
927
928         pcm_s.last_l = d0;
929     }
930 }
931
932
933 static void
934 fifo_send_mono_8(pcm_data *buf, int count, int uflag)
935 {
936     int i;
937     signed char d, d0, d1, zlev;
938
939     zlev = uflag ? -128 : 0;
940
941     if (pcm_s.speed == pcm_s.chipspeed)
942         /* No reason to convert the pcm speed. */
943         for (i = 0; i < count; i++) {
944             d = *buf++ + zlev;
945             outb(pcm_s.iobase + 12, d);
946             outb(pcm_s.iobase + 12, d);
947         }
948     else {
949         /* Speed conversion with linear interpolation method. */
950         d0 = pcm_s.last_l;
951         d1 = *buf++ + zlev;
952         i = 0;
953         while (i < count) {
954             while (pcm_s.acc >= pcm_s.chipspeed) {
955                 pcm_s.acc -= pcm_s.chipspeed;
956                 i++;
957                 d0 = d1;
958                 d1 = (i < count) ? *buf++ + zlev : 0;
959             }
960             d = ((d0 * (pcm_s.chipspeed - pcm_s.acc)) + (d1 * pcm_s.acc))
961                 / pcm_s.chipspeed;
962             outb(pcm_s.iobase + 12, d);
963             outb(pcm_s.iobase + 12, d);
964             pcm_s.acc += pcm_s.speed;
965         }
966
967         pcm_s.last_l = d0;
968     }
969 }
970
971
972 static void
973 fifo_send_mono_16le(pcm_data *buf, int count, int uflag)
974 {
975     int i;
976     short d, d0, d1, zlev;
977     pcm_data t[2];
978
979     zlev = uflag ? -128 : 0;
980
981     for (i = 0; i < 2; i++)
982         t[i] = (tmpbuf.size > i) ? tmpbuf.buff[i] : *buf++;
983
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);
996             buf += 2;
997         }
998     } else {
999         /* Speed conversion with linear interpolation method. */
1000         d0 = pcm_s.last_l;
1001         d1 = t[0] + ((t[1] + zlev) << 8);
1002         i = 0;
1003         count /= 2;
1004         while (i < count) {
1005             while (pcm_s.acc >= pcm_s.chipspeed) {
1006                 pcm_s.acc -= pcm_s.chipspeed;
1007                 i++;
1008                 d0 = d1;
1009                 if (i < count) {
1010                     d1 = *buf + ((*(buf + 1) + zlev) << 8);
1011                     buf += 2;
1012                 } else
1013                     d1 = 0;
1014             }
1015             d = ((d0 * (pcm_s.chipspeed - pcm_s.acc)) + (d1 * pcm_s.acc))
1016                 / pcm_s.chipspeed;
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;
1022         }
1023
1024         pcm_s.last_l = d0;
1025     }
1026 }
1027
1028
1029 static void
1030 fifo_send_mono_16be(pcm_data *buf, int count, int uflag)
1031 {
1032     int i;
1033     short d, d0, d1, zlev;
1034     pcm_data t[2];
1035
1036     zlev = uflag ? -128 : 0;
1037
1038     for (i = 0; i < 2; i++)
1039         t[i] = (tmpbuf.size > i) ? tmpbuf.buff[i] : *buf++;
1040
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));
1053             buf += 2;
1054         }
1055     } else {
1056         /* Speed conversion with linear interpolation method. */
1057         d0 = pcm_s.last_l;
1058         d1 = ((t[0] + zlev) << 8) + t[1];
1059         i = 0;
1060         count /= 2;
1061         while (i < count) {
1062             while (pcm_s.acc >= pcm_s.chipspeed) {
1063                 pcm_s.acc -= pcm_s.chipspeed;
1064                 i++;
1065                 d0 = d1;
1066                 if (i < count) {
1067                     d1 = ((*buf + zlev) << 8) + *(buf + 1);
1068                     buf += 2;
1069                 } else
1070                     d1 = 0;
1071             }
1072             d = ((d0 * (pcm_s.chipspeed - pcm_s.acc)) + (d1 * pcm_s.acc))
1073                 / pcm_s.chipspeed;
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;
1083         }
1084
1085         pcm_s.last_l = d0;
1086     }
1087 }
1088
1089
1090 static void
1091 fifo_input_block(void)
1092 {
1093     int chunksize;
1094
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;
1101     } else
1102         /* ??? something wrong... */
1103         printf("nss0: chunkcount overrun\n");
1104 }
1105
1106
1107 static void
1108 fifo_recv(pcm_data *buf, int count)
1109 {
1110     int i;
1111
1112     if (count > tmpbuf.size) {
1113         for (i = 0; i < tmpbuf.size; i++)
1114             *buf++ = tmpbuf.buff[i];
1115         count -= tmpbuf.size;
1116         tmpbuf.size = 0;
1117         if (pcm_s.stereo)
1118             fifo_recv_stereo(buf, count);
1119         else
1120             fifo_recv_monoral(buf, count);
1121     } else {
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;
1127     }
1128
1129 #ifdef NSS_DEBUG
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);
1133 #endif
1134 }
1135
1136
1137 static void
1138 fifo_recv_stereo(pcm_data *buf, int count)
1139 {
1140     /* Convert format and sampling speed. */
1141     switch (pcm_s.format) {
1142     case AFMT_MU_LAW:
1143         fifo_recv_stereo_ulaw(buf, count);
1144         break;
1145     case AFMT_S8:
1146         fifo_recv_stereo_8(buf, count, NO);
1147         break;
1148     case AFMT_U8:
1149         fifo_recv_stereo_8(buf, count, YES);
1150         break;
1151     case AFMT_S16_LE:
1152         fifo_recv_stereo_16le(buf, count, NO);
1153         break;
1154     case AFMT_U16_LE:
1155         fifo_recv_stereo_16le(buf, count, YES);
1156         break;
1157     case AFMT_S16_BE:
1158         fifo_recv_stereo_16be(buf, count, NO);
1159         break;
1160     case AFMT_U16_BE:
1161         fifo_recv_stereo_16be(buf, count, YES);
1162         break;
1163     }
1164 }
1165
1166
1167 static void
1168 fifo_recv_monoral(pcm_data *buf, int count)
1169 {
1170     /* Convert format and sampling speed. */
1171     switch (pcm_s.format) {
1172     case AFMT_MU_LAW:
1173         fifo_recv_mono_ulaw(buf, count);
1174         break;
1175     case AFMT_S8:
1176         fifo_recv_mono_8(buf, count, NO);
1177         break;
1178     case AFMT_U8:
1179         fifo_recv_mono_8(buf, count, YES);
1180         break;
1181     case AFMT_S16_LE:
1182         fifo_recv_mono_16le(buf, count, NO);
1183         break;
1184     case AFMT_U16_LE:
1185         fifo_recv_mono_16le(buf, count, YES);
1186         break;
1187     case AFMT_S16_BE:
1188         fifo_recv_mono_16be(buf, count, NO);
1189         break;
1190     case AFMT_U16_BE:
1191         fifo_recv_mono_16be(buf, count, YES);
1192         break;
1193     }
1194 }
1195
1196
1197 static void
1198 fifo_recv_stereo_ulaw(pcm_data *buf, int count)
1199 {
1200     int i, cnt;
1201     signed char dl, dl0, dl1, dr, dr0, dr1;
1202
1203     cnt = count / 2;
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)];
1209         }
1210         if (count % 2) {
1211             *buf++ = linear2ulaw[inb(pcm_s.iobase + 12)];
1212             tmpbuf.buff[0] = linear2ulaw[inb(pcm_s.iobase + 12)];
1213             tmpbuf.size = 1;
1214         }
1215     } else {
1216         /* Speed conversion with linear interpolation method. */
1217         dl0 = pcm_s.last_l;
1218         dr0 = pcm_s.last_r;
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;
1224                 dl0 = dl1;
1225                 dr0 = dr1;
1226                 dl1 = inb(pcm_s.iobase + 12);
1227                 dr1 = inb(pcm_s.iobase + 12);
1228             }
1229             dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
1230                 / pcm_s.speed;
1231             dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
1232                 / pcm_s.speed;
1233             *buf++ = linear2ulaw[dl & 0xff];
1234             *buf++ = linear2ulaw[dr & 0xff];
1235             pcm_s.acc += pcm_s.chipspeed;
1236         }
1237         if (count % 2) {
1238             while (pcm_s.acc >= pcm_s.speed) {
1239                 pcm_s.acc -= pcm_s.speed;
1240                 dl0 = dl1;
1241                 dr0 = dr1;
1242                 dl1 = inb(pcm_s.iobase + 12);
1243                 dr1 = inb(pcm_s.iobase + 12);
1244             }
1245             dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
1246                 / pcm_s.speed;
1247             dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
1248                 / pcm_s.speed;
1249             *buf++ = linear2ulaw[dl & 0xff];
1250             tmpbuf.buff[0] = linear2ulaw[dr & 0xff];
1251             tmpbuf.size = 1;
1252         }
1253
1254         pcm_s.last_l = dl0;
1255         pcm_s.last_r = dr0;
1256     }
1257 }
1258
1259
1260 static void
1261 fifo_recv_stereo_8(pcm_data *buf, int count, int uflag)
1262 {
1263     int i, cnt;
1264     signed char dl, dl0, dl1, dr, dr0, dr1, zlev;
1265
1266     zlev = uflag ? -128 : 0;
1267
1268     cnt = count / 2;
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;
1274         }
1275         if (count % 2) {
1276             *buf++ = inb(pcm_s.iobase + 12) + zlev;
1277             tmpbuf.buff[0] = inb(pcm_s.iobase + 12) + zlev;
1278             tmpbuf.size = 1;
1279         }
1280     } else {
1281         /* Speed conversion with linear interpolation method. */
1282         dl0 = pcm_s.last_l;
1283         dr0 = pcm_s.last_r;
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;
1289                 dl0 = dl1;
1290                 dr0 = dr1;
1291                 dl1 = inb(pcm_s.iobase + 12);
1292                 dr1 = inb(pcm_s.iobase + 12);
1293             }
1294             dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
1295                 / pcm_s.speed;
1296             dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
1297                 / pcm_s.speed;
1298             *buf++ = dl + zlev;
1299             *buf++ = dr + zlev;
1300             pcm_s.acc += pcm_s.chipspeed;
1301         }
1302         if (count % 2) {
1303             while (pcm_s.acc >= pcm_s.speed) {
1304                 pcm_s.acc -= pcm_s.speed;
1305                 dl0 = dl1;
1306                 dr0 = dr1;
1307                 dl1 = inb(pcm_s.iobase + 12);
1308                 dr1 = inb(pcm_s.iobase + 12);
1309             }
1310             dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
1311                 / pcm_s.speed;
1312             dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
1313                 / pcm_s.speed;
1314             *buf++ = dl + zlev;
1315             tmpbuf.buff[0] = dr + zlev;
1316             tmpbuf.size = 1;
1317         }
1318
1319         pcm_s.last_l = dl0;
1320         pcm_s.last_r = dr0;
1321     }
1322 }
1323
1324
1325 static void
1326 fifo_recv_stereo_16le(pcm_data *buf, int count, int uflag)
1327 {
1328     int i, cnt;
1329     short dl, dl0, dl1, dr, dr0, dr1, zlev;
1330     pcm_data t[4];
1331
1332     zlev = uflag ? -128 : 0;
1333
1334     cnt = count / 4;
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);
1342             buf += 4;
1343         }
1344         if (count % 4) {
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);
1349             tmpbuf.size = 0;
1350             for (i = 0; i < count % 4; i++)
1351                 *buf++ = t[i];
1352             for (i = count % 4; i < 4; i++)
1353                 tmpbuf.buff[tmpbuf.size++] = t[i];
1354         }
1355     } else {
1356         /* Speed conversion with linear interpolation method. */
1357         dl0 = pcm_s.last_l;
1358         dr0 = pcm_s.last_r;
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;
1366                 dl0 = dl1;
1367                 dr0 = dr1;
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);
1372             }
1373             dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
1374                 / pcm_s.speed;
1375             dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
1376                 / pcm_s.speed;
1377             *buf++ = dl & 0xff;
1378             *buf++ = ((dl >> 8) & 0xff) + zlev;
1379             *buf++ = dr & 0xff;
1380             *buf++ = ((dr >> 8) & 0xff) + zlev;
1381             pcm_s.acc += pcm_s.chipspeed;
1382         }
1383         if (count % 4) {
1384             while (pcm_s.acc >= pcm_s.speed) {
1385                 pcm_s.acc -= pcm_s.speed;
1386                 dl0 = dl1;
1387                 dr0 = dr1;
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);
1392             }
1393             dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
1394                 / pcm_s.speed;
1395             dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
1396                 / pcm_s.speed;
1397             t[0] = dl & 0xff;
1398             t[1] = ((dl >> 8) & 0xff) + zlev;
1399             t[2] = dr & 0xff;
1400             t[3] = ((dr >> 8) & 0xff) + zlev;
1401             tmpbuf.size = 0;
1402             for (i = 0; i < count % 4; i++)
1403                 *buf++ = t[i];
1404             for (i = count % 4; i < 4; i++)
1405                 tmpbuf.buff[tmpbuf.size++] = t[i];
1406         }
1407
1408         pcm_s.last_l = dl0;
1409         pcm_s.last_r = dr0;
1410     }
1411 }
1412
1413
1414 static void
1415 fifo_recv_stereo_16be(pcm_data *buf, int count, int uflag)
1416 {
1417     int i, cnt;
1418     short dl, dl0, dl1, dr, dr0, dr1, zlev;
1419     pcm_data t[4];
1420
1421     zlev = uflag ? -128 : 0;
1422
1423     cnt = count / 4;
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);
1431         }
1432         if (count % 4) {
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);
1437             tmpbuf.size = 0;
1438             for (i = 0; i < count % 4; i++)
1439                 *buf++ = t[i];
1440             for (i = count % 4; i < 4; i++)
1441                 tmpbuf.buff[tmpbuf.size++] = t[i];
1442         }
1443     } else {
1444         /* Speed conversion with linear interpolation method. */
1445         dl0 = pcm_s.last_l;
1446         dr0 = pcm_s.last_r;
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;
1454                 dl0 = dl1;
1455                 dr0 = dr1;
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);
1460             }
1461             dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
1462                 / pcm_s.speed;
1463             dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
1464                 / pcm_s.speed;
1465             *buf++ = ((dl >> 8) & 0xff) + zlev;
1466             *buf++ = dl & 0xff;
1467             *buf++ = ((dr >> 8) & 0xff) + zlev;
1468             *buf++ = dr & 0xff;
1469             pcm_s.acc += pcm_s.chipspeed;
1470         }
1471         if (count % 4) {
1472             while (pcm_s.acc >= pcm_s.speed) {
1473                 pcm_s.acc -= pcm_s.speed;
1474                 dl0 = dl1;
1475                 dr0 = dr1;
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);
1480             }
1481             dl = ((dl0 * (pcm_s.speed - pcm_s.acc)) + (dl1 * pcm_s.acc))
1482                 / pcm_s.speed;
1483             dr = ((dr0 * (pcm_s.speed - pcm_s.acc)) + (dr1 * pcm_s.acc))
1484                 / pcm_s.speed;
1485             t[0] = ((dl >> 8) & 0xff) + zlev;
1486             t[1] = dl & 0xff;
1487             t[2] = ((dr >> 8) & 0xff) + zlev;
1488             t[3] = dr & 0xff;
1489             tmpbuf.size = 0;
1490             for (i = 0; i < count % 4; i++)
1491                 *buf++ = t[i];
1492             for (i = count % 4; i < 4; i++)
1493                 tmpbuf.buff[tmpbuf.size++] = t[i];
1494         }
1495
1496         pcm_s.last_l = dl0;
1497         pcm_s.last_r = dr0;
1498     }
1499 }
1500
1501
1502 static void
1503 fifo_recv_mono_ulaw(pcm_data *buf, int count)
1504 {
1505     int i;
1506     signed char d, d0, d1;
1507
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];
1514         }
1515     } else {
1516         /* Speed conversion with linear interpolation method. */
1517         d0 = pcm_s.last_l;
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;
1523                 d0 = d1;
1524                 d1 = ((signed char)inb(pcm_s.iobase + 12)
1525                       + (signed char)inb(pcm_s.iobase + 12)) >> 1;
1526             }
1527             d = ((d0 * (pcm_s.speed - pcm_s.acc)) + (d1 * pcm_s.acc))
1528                 / pcm_s.speed;
1529             *buf++ = linear2ulaw[d & 0xff];
1530             pcm_s.acc += pcm_s.chipspeed;
1531         }
1532
1533         pcm_s.last_l = d0;
1534     }
1535 }
1536
1537
1538 static void
1539 fifo_recv_mono_8(pcm_data *buf, int count, int uflag)
1540 {
1541     int i;
1542     signed char d, d0, d1, zlev;
1543
1544     zlev = uflag ? -128 : 0;
1545
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;
1551             *buf++ = d + zlev;
1552         }
1553     } else {
1554         /* Speed conversion with linear interpolation method. */
1555         d0 = pcm_s.last_l;
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;
1561                 d0 = d1;
1562                 d1 = ((signed char)inb(pcm_s.iobase + 12)
1563                       + (signed char)inb(pcm_s.iobase + 12)) >> 1;
1564             }
1565             d = ((d0 * (pcm_s.speed - pcm_s.acc)) + (d1 * pcm_s.acc))
1566                 / pcm_s.speed;
1567             *buf++ = d + zlev;
1568             pcm_s.acc += pcm_s.chipspeed;
1569         }
1570
1571         pcm_s.last_l = d0;
1572     }
1573 }
1574
1575
1576 static void
1577 fifo_recv_mono_16le(pcm_data *buf, int count, int uflag)
1578 {
1579     int i, cnt;
1580     short d, d0, d1, el, er, zlev;
1581
1582     zlev = uflag ? -128 : 0;
1583
1584     cnt = count / 2;
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);
1592             d = (el + er) >> 1;
1593             *buf++ = d & 0xff;
1594             *buf++ = ((d >> 8) & 0xff) + zlev;
1595         }
1596         if (count % 2) {
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);
1601             d = (el + er) >> 1;
1602             *buf++ = d & 0xff;
1603             tmpbuf.buff[0] = ((d >> 8) & 0xff) + zlev;
1604             tmpbuf.size = 1;
1605         }
1606     } else {
1607         /* Speed conversion with linear interpolation method. */
1608         d0 = pcm_s.last_l;
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;
1617                 d0 = d1;
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;
1623             }
1624             d = ((d0 * (pcm_s.speed - pcm_s.acc)) + (d1 * pcm_s.acc))
1625                 / pcm_s.speed;
1626             *buf++ = d & 0xff;
1627             *buf++ = ((d >> 8) & 0xff) + zlev;
1628             pcm_s.acc += pcm_s.chipspeed;
1629         }
1630         if (count % 2) {
1631             while (pcm_s.acc >= pcm_s.speed) {
1632                 pcm_s.acc -= pcm_s.speed;
1633                 d0 = d1;
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;
1639             }
1640             d = ((d0 * (pcm_s.speed - pcm_s.acc)) + (d1 * pcm_s.acc))
1641                 / pcm_s.speed;
1642             *buf++ = d & 0xff;
1643             tmpbuf.buff[0] = ((d >> 8) & 0xff) + zlev;
1644             tmpbuf.size = 1;
1645         }
1646
1647         pcm_s.last_l = d0;
1648     }
1649 }
1650
1651
1652 static void
1653 fifo_recv_mono_16be(pcm_data *buf, int count, int uflag)
1654 {
1655     int i, cnt;
1656     short d, d0, d1, el, er, zlev;
1657
1658     zlev = uflag ? -128 : 0;
1659
1660     cnt = count / 2;
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);
1668             d = (el + er) >> 1;
1669             *buf++ = ((d >> 8) & 0xff) + zlev;
1670             *buf++ = d & 0xff;
1671         }
1672         if (count % 2) {
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);
1677             d = (el + er) >> 1;
1678             *buf++ = ((d >> 8) & 0xff) + zlev;
1679             tmpbuf.buff[0] = d & 0xff;
1680             tmpbuf.size = 1;
1681         }
1682     } else {
1683         /* Speed conversion with linear interpolation method. */
1684         d0 = pcm_s.last_l;
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;
1693                 d0 = d1;
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;
1699             }
1700             d = ((d0 * (pcm_s.speed - pcm_s.acc)) + (d1 * pcm_s.acc))
1701                 / pcm_s.speed;
1702             *buf++ = ((d >> 8) & 0xff) + zlev;
1703             *buf++ = d & 0xff;
1704             pcm_s.acc += pcm_s.chipspeed;
1705         }
1706         if (count % 2) {
1707             while (pcm_s.acc >= pcm_s.speed) {
1708                 pcm_s.acc -= pcm_s.speed;
1709                 d0 = d1;
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;
1715             }
1716             d = ((d0 * (pcm_s.speed - pcm_s.acc)) + (d1 * pcm_s.acc))
1717                 / pcm_s.speed;
1718             *buf++ = ((d >> 8) & 0xff) + zlev;
1719             tmpbuf.buff[0] = d & 0xff;
1720             tmpbuf.size = 1;
1721         }
1722
1723         pcm_s.last_l = d0;
1724     }
1725 }
1726
1727
1728 static void
1729 nss_stop(void)
1730 {
1731     fifo_stop();                /* stop FIFO */
1732     fifo_reset();               /* reset FIFO buffer */
1733
1734     /* Reset driver's status. */
1735     pcm_s.intr_busy = NO;
1736     pcm_s.intr_last = NO;
1737     pcm_s.intr_trailer = NO;
1738     pcm_s.acc = 0;
1739     pcm_s.last_l = 0;
1740     pcm_s.last_r = 0;
1741
1742     DEB(printf("nss_stop\n"));
1743 }
1744
1745
1746 static void
1747 nss_init(void)
1748 {
1749     /* Initialize registers on the board. */
1750     nss_stop();
1751     if (pcm_s.board_type == PC980173_FAMILY)
1752         dsp73_init();
1753
1754     /* Set default volume. */
1755     set_volume(DEFAULT_VOLUME);
1756
1757     /* Initialize driver's status. */
1758     pcm_s.opened = NO;
1759     nss_initialized = YES;
1760 }
1761
1762
1763 /*
1764  * Codes for global use
1765  */
1766
1767 int
1768 probe_nss(struct address_info *hw_config)
1769 {
1770     return nss_detect(hw_config);
1771 }
1772
1773
1774 void
1775 attach_nss(struct address_info *hw_config)
1776 {
1777     if (pcm_s.board_type == NO_SUPPORTED_BOARD)
1778         return ;
1779
1780     /* Initialize the board. */
1781     nss_init();
1782
1783     conf_printf(nss_operations.name, hw_config);
1784
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;
1790 #ifdef NSS_DEBUG
1791         printf("\nbuffsize = %d", DSP_BUFFSIZE);
1792 #endif
1793     } else
1794         printf("nss0: Too many PCM devices available");
1795
1796     return ;
1797 }
1798
1799
1800 static int
1801 nss_detect(struct address_info *hw_config)
1802 {
1803     int opna_iobase = 0x188, irq = 12, i;
1804     unsigned char tmp;
1805
1806     if (hw_config->io_base == -1) {
1807         printf("nss0: iobase not specified. Assume default port(0x%x)\n",
1808                PCM86_IOBASE);
1809         hw_config->io_base = PCM86_IOBASE;
1810     }
1811     pcm_s.iobase = hw_config->io_base;
1812
1813     /* auto configuration */
1814     tmp = (inb(pcm_s.iobase) & 0xf0) >> 4;
1815     if (tmp == 0x07) {
1816       /* 
1817        * Remap MATE-X PCM Sound ID register (0xA460 -> 0xB460)
1818        * to avoid corrision with 86 Sound System.
1819        */
1820       /*
1821       printf("nss0: Found MATE-X PCM Sound ID\n");
1822       printf("nss0: Remaped 0xa460 to 0xb460\n");
1823        */
1824       outb(0xc24, 0xe1);
1825       outb(0xc2b, 0x60);
1826       outb(0xc2d, 0xb4);
1827     }
1828
1829     tmp = inb(pcm_s.iobase) & 0xfc;
1830     switch ((tmp & 0xf0) >> 4) {
1831     case 2:
1832         opna_iobase = 0x188;
1833         pcm_s.board_type = PC980173_FAMILY;
1834         break;
1835     case 3:
1836         opna_iobase = 0x288;
1837         pcm_s.board_type = PC980173_FAMILY;
1838         break;
1839     case 4:
1840         opna_iobase = 0x188;
1841         pcm_s.board_type = PC980186_FAMILY;
1842         break;
1843     case 5:
1844         opna_iobase = 0x288;
1845         pcm_s.board_type = PC980186_FAMILY;
1846         break;
1847     default:
1848         pcm_s.board_type = NO_SUPPORTED_BOARD;
1849         return NO;
1850     }
1851
1852     /* Enable OPNA(YM2608) facilities. */
1853     outb(pcm_s.iobase, tmp | 0x01);
1854
1855     /* Wait for OPNA to be ready. */
1856     i = 100000;         /* Some large value */
1857     while((inb(opna_iobase) & 0x80) && (i-- > 0));
1858
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. */
1863     outb(0x5f, 0);
1864     outb(0x5f, 0);
1865     tmp = inb(opna_iobase + 2) & 0x3f;
1866     outb(opna_iobase + 2, tmp | 0x80);
1867
1868     /* Wait for OPNA to be ready. */
1869     i = 100000;         /* Some large value */
1870     while((inb(opna_iobase) & 0x80) && (i-- > 0));
1871
1872     /* Get irq number from IOA port. */
1873     outb(opna_iobase, 0x0e);
1874     outb(0x5f, 0);
1875     outb(0x5f, 0);
1876     outb(0x5f, 0);
1877     outb(0x5f, 0);
1878     tmp = inb(opna_iobase + 2) & 0xc0;
1879     switch (tmp >> 6) {
1880     case 0:     /* INT0 (IRQ3)*/
1881         irq = 3;
1882         break;
1883     case 1:     /* INT6 (IRQ13)*/
1884         irq = 13;
1885         break;
1886     case 2:     /* INT4 (IRQ10)*/
1887         irq = 10;
1888         break;
1889     case 3:     /* INT5 (IRQ12)*/
1890         irq = 12;
1891         break;
1892     default:    /* error */
1893         return NO;
1894     }
1895
1896     /* Wait for OPNA to be ready. */
1897     i = 100000;         /* Some large value */
1898     while((inb(opna_iobase) & 0x80) && (i-- > 0));
1899
1900     /* Reset OPNA timer register. */
1901     outb(opna_iobase, 0x27);
1902     outb(0x5f, 0);
1903     outb(0x5f, 0);
1904     outb(0x5f, 0);
1905     outb(0x5f, 0);
1906     outb(opna_iobase + 2, 0x30);
1907
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;
1912     pcm_s.irq = irq;
1913
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;
1917
1918     pcm_s.osp = hw_config->osp;
1919
1920     return YES;
1921 }
1922
1923
1924 static int
1925 nss_open(int dev, int mode)
1926 {
1927     int err;
1928
1929     if (!nss_initialized)
1930         return -(ENXIO);
1931
1932     if (pcm_s.intr_busy || pcm_s.opened)
1933         return -(EBUSY);
1934
1935     if ((err = snd_set_irq_handler(pcm_s.irq, nssintr, pcm_s.osp)) < 0)
1936         return err;
1937
1938     nss_stop();
1939
1940     tmpbuf.size = 0;
1941     pcm_s.intr_mode = IMODE_NONE;
1942     pcm_s.opened = YES;
1943
1944     return 0;
1945 }
1946
1947
1948 static void
1949 nss_close(int dev)
1950 {
1951   /* snd_release_irq(pcm_s.irq); */
1952
1953     pcm_s.opened = NO;
1954 }
1955
1956
1957 static void
1958 nss_output_block(int dev, unsigned long buf, int count, int intrflag,
1959                    int dma_restart)
1960 {
1961     unsigned long flags, cnt;
1962     int maxchunksize;
1963
1964 #ifdef NSS_DEBUG
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");
1976     printf("\n");
1977 #endif
1978
1979 #if 0
1980     DISABLE_INTR(flags);
1981 #endif
1982
1983 #ifdef NSS_DEBUG
1984     printf("nss_output_block(): count = %d, intrsize= %d\n",
1985            count, pcm_s.intr_size);
1986 #endif
1987
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;
1996     /*
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.
2002      *
2003      * Lemma:
2004      *       maxchunksize / 2 <= chunksize <= maxchunksize.
2005      *   (Though pcm_s.pdma_chunkcount is obtained through the flooring
2006      *    function, this inequality holds.)
2007      * Proof) Omitted.
2008      */
2009
2010     fifo_output_block();
2011
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;
2017
2018 #if 0
2019     RESTORE_INTR(flags);
2020 #endif
2021 }
2022
2023
2024 static void
2025 nss_start_input(int dev, unsigned long buf, int count, int intrflag,
2026                   int dma_restart)
2027 {
2028     unsigned long flags, cnt;
2029     int maxchunksize;
2030
2031 #ifdef NSS_DEBUG
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");
2043     printf("\n");
2044 #endif
2045
2046 #if 0
2047     DISABLE_INTR(flags);
2048 #endif
2049
2050     pcm_s.intr_size = PCM86_INTRSIZE_IN;
2051
2052 #ifdef NSS_DEBUG
2053     printf("nss_start_input(): count = %d, intrsize= %d\n",
2054            count, pcm_s.intr_size);
2055 #endif
2056
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;
2064
2065     pcm_s.intr_mode = IMODE_INPUT;
2066     if (!pcm_s.intr_busy)
2067         fifo_start(IMODE_INPUT);
2068     pcm_s.intr_busy = YES;
2069
2070 #if 0
2071     RESTORE_INTR(flags);
2072 #endif
2073 }
2074
2075
2076 static int
2077 nss_ioctl(int dev, u_int cmd, ioctl_arg arg, int local)
2078 {
2079     switch (cmd) {
2080     case SOUND_PCM_WRITE_RATE:
2081         if (local)
2082             return set_speed((int) arg);
2083         return *(int *) arg = set_speed((*(int *) arg));
2084
2085     case SOUND_PCM_READ_RATE:
2086         if (local)
2087             return pcm_s.speed;
2088         return *(int *) arg = pcm_s.speed;
2089
2090     case SNDCTL_DSP_STEREO:
2091         if (local)
2092             return set_stereo((int) arg);
2093         return *(int *) arg = set_stereo((*(int *) arg));
2094
2095     case SOUND_PCM_WRITE_CHANNELS:
2096         if (local)
2097             return set_stereo((int) arg - 1) + 1;
2098         return *(int *) arg = set_stereo((*(int *) arg) - 1) + 1;
2099
2100     case SOUND_PCM_READ_CHANNELS:
2101         if (local)
2102             return pcm_s.stereo + 1;
2103         return *(int *) arg = pcm_s.stereo + 1;
2104
2105     case SNDCTL_DSP_SETFMT:
2106         if (local)
2107             return set_format((int) arg);
2108         return *(int *) arg = set_format((*(int *) arg));
2109
2110     case SOUND_PCM_READ_BITS:
2111         if (local)
2112             return pcm_s.bytes * 8;
2113         return *(int *) arg = pcm_s.bytes * 8;
2114     }
2115
2116     /* Invalid ioctl request */
2117     return -(EINVAL);
2118 }
2119
2120
2121 static int
2122 nss_prepare_for_input(int dev, int bufsize, int nbufs)
2123 {
2124     pcm_s.intr_size = PCM86_INTRSIZE_IN;
2125     pcm_s.intr_mode = IMODE_NONE;
2126     pcm_s.acc = 0;
2127     pcm_s.last_l = 0;
2128     pcm_s.last_r = 0;
2129
2130     DEB(printf("nss_prepare_for_input\n"));
2131
2132     return 0;
2133 }
2134
2135
2136 static int
2137 nss_prepare_for_output(int dev, int bufsize, int nbufs)
2138 {
2139     pcm_s.intr_size = PCM86_INTRSIZE_OUT;
2140     pcm_s.intr_mode = IMODE_NONE;
2141     pcm_s.acc = 0;
2142     pcm_s.last_l = 0;
2143     pcm_s.last_r = 0;
2144
2145     DEB(printf("nss_prepare_for_output\n"));
2146
2147     return 0;
2148 }
2149
2150
2151 static void
2152 nss_reset(int dev)
2153 {
2154     nss_stop();
2155 }
2156
2157
2158 static void
2159 nss_halt_xfer(int dev)
2160 {
2161     nss_stop();
2162
2163     DEB(printf("nss_halt_xfer\n"));
2164 }
2165
2166
2167 void
2168 nssintr(int unit)
2169 {
2170     unsigned char tmp;
2171
2172     if ((inb(pcm_s.iobase + 8) & 0x10) == 0)
2173         return;         /* not FIFO intr. */
2174
2175     switch(pcm_s.intr_mode) {
2176     case IMODE_OUTPUT:
2177         if (pcm_s.intr_trailer) {
2178             DEB(printf("nssintr(): fifo_reset\n"));
2179             fifo_reset();
2180             pcm_s.intr_trailer = NO;
2181             pcm_s.intr_busy = NO;
2182         }
2183         if (pcm_s.pdma_count > 0)
2184             fifo_output_block();
2185         else
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);
2191         break;
2192
2193     case IMODE_INPUT:
2194         fifo_input_block();
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);
2201         break;
2202
2203     default:
2204         nss_stop();
2205         printf("nss0: unexpected interrupt\n");
2206     }
2207 }
2208
2209
2210 #endif  /* EXCLUDE_NSS, EXCLUDE_AUDIO */
2211
2212 #endif  /* CONFIGURE_SOUNDCARD */