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