]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/i386/isa/sound/soundcard.c
Remove five now unused fields from struct cdevsw. They should never
[FreeBSD/FreeBSD.git] / sys / i386 / isa / sound / soundcard.c
1 /*
2  * sound/386bsd/soundcard.c
3  * 
4  * Soundcard driver for 386BSD.
5  * 
6  * Copyright by Hannu Savolainen 1993
7  * 
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are
10  * met: 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer. 2.
12  * Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  * 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23  * 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$
29  *
30  */
31 #include <i386/isa/sound/sound_config.h>
32 #if NSND > 0    /* from "snd.h" */
33 #include "uart.h"
34
35 #include <sys/select.h>
36 #include <vm/vm.h>
37 #include <vm/pmap.h>
38 #include <sys/mman.h>
39
40 #include <i386/isa/isa_device.h>
41
42
43 /*
44 **  Register definitions for DMA controller 1 (channels 0..3):
45 */
46 #define DMA1_CHN(c)     (IO_DMA1 + 1*(2*(c)))   /* addr reg for channel c */
47 #define DMA1_SMSK       (IO_DMA1 + 1*10)        /* single mask register */
48 #define DMA1_MODE       (IO_DMA1 + 1*11)        /* mode register */
49 #define DMA1_FFC        (IO_DMA1 + 1*12)        /* clear first/last FF */
50
51 /*
52 **  Register definitions for DMA controller 2 (channels 4..7):
53 */
54 #define DMA2_CHN(c)     (IO_DMA2 + 2*(2*(c)))   /* addr reg for channel c */
55 #define DMA2_SMSK       (IO_DMA2 + 2*10)        /* single mask register */
56 #define DMA2_MODE       (IO_DMA2 + 2*11)        /* mode register */
57 #define DMA2_FFC        (IO_DMA2 + 2*12)        /* clear first/last FF */
58
59
60 #define FIX_RETURN(ret) {if ((ret)<0) return -(ret); else return 0;}
61
62 static int      soundcards_installed = 0; /* Number of installed soundcards */
63 static int      soundcard_configured = 0;
64
65 static struct fileinfo files[SND_NDEVS];
66 struct selinfo  selinfo[SND_NDEVS >> 4];
67
68 int
69 MIDIbuf_poll (int dev, struct fileinfo *file, int events, select_table * wait);
70
71 int
72 audio_poll(int dev, struct fileinfo * file, int events, select_table * wait);
73
74 int
75 sequencer_poll (int dev, struct fileinfo *file, int events, select_table * wait);
76
77 static int sndprobe    __P((struct isa_device *));
78 static int sndattach   __P((struct isa_device *));
79
80 static d_open_t sndopen;
81 static d_close_t sndclose;
82 static d_ioctl_t sndioctl;
83 static d_read_t sndread;
84 static d_write_t sndwrite;
85 static d_poll_t sndpoll;
86 static d_mmap_t sndmmap;
87
88 static char     driver_name[] = "snd";
89
90 #define CDEV_MAJOR 30
91 static struct cdevsw snd_cdevsw = {
92         /* open */      sndopen,
93         /* close */     sndclose,
94         /* read */      sndread,
95         /* write */     sndwrite,
96         /* ioctl */     sndioctl,
97         /* poll */      sndpoll,
98         /* mmap */      sndmmap,
99         /* strategy */  nostrategy,
100         /* name */      driver_name,
101         /* maj */       CDEV_MAJOR,
102         /* dump */      nodump,
103         /* psize */     nopsize,
104         /* flags */     0,
105         /* bmaj */      -1
106 };
107
108
109
110
111 static void     sound_mem_init(void);
112
113 /*
114  * for each "device XXX" entry in the config file, we have
115  * a struct isa_driver which is linked into isa_devtab_null[]
116  *
117  * XXX It is a bit stupid to call the generic routine so many times and
118  * switch then to the specific one, but the alternative way would be
119  * to replicate some code in the probe/attach routines.
120  */
121
122 struct isa_driver opldriver = {sndprobe, sndattach, "opl"};
123 struct isa_driver trixdriver = {sndprobe, sndattach, "trix"};
124 struct isa_driver trixsbdriver = {sndprobe, sndattach, "trixsb"};
125 struct isa_driver sbdriver = {sndprobe, sndattach, "sb"};
126 struct isa_driver sbxvidriver = {sndprobe, sndattach, "sbxvi"};
127 struct isa_driver sbmididriver = {sndprobe, sndattach, "sbmidi"};
128 struct isa_driver awedriver    = {sndprobe, sndattach, "awe"};
129 struct isa_driver pasdriver = {sndprobe, sndattach, "pas"};
130 struct isa_driver mpudriver = {sndprobe, sndattach, "mpu"};
131 struct isa_driver gusdriver = {sndprobe, sndattach, "gus"};
132 struct isa_driver gusxvidriver = {sndprobe, sndattach, "gusxvi"};
133 struct isa_driver gusmaxdriver = {sndprobe, sndattach, "gusmax"};
134 struct isa_driver uartdriver = {sndprobe, sndattach, "uart"};
135 struct isa_driver mssdriver = {sndprobe, sndattach, "mss"};
136 struct isa_driver cssdriver = {sndprobe, sndattach, "css"};
137 struct isa_driver sscapedriver = {sndprobe, sndattach, "sscape"};
138 struct isa_driver sscape_mssdriver = {sndprobe, sndattach, "sscape_mss"};
139 struct isa_driver nssdriver = {sndprobe, sndattach, "nss"};
140
141 short ipri_to_irq(u_short ipri);
142
143 static ointhand2_t sndintr;
144
145 u_long
146 get_time(void)
147 {
148     struct timeval  timecopy;
149
150     getmicrotime(&timecopy);
151     return timecopy.tv_usec / (1000000 / hz) +
152                 (u_long) timecopy.tv_sec * hz;
153 }
154
155 static int
156 sndmmap( dev_t dev, vm_offset_t offset, int nprot )
157 {
158         struct dma_buffparms * dmap;
159         u_int min = minor(dev) >> 4;
160
161         if (min > 0 ) return (-1);
162
163         dmap =  audio_devs[min]->dmap_out;
164
165         if (nprot & PROT_EXEC)
166                 return( -1 );
167         dmap->mapping_flags |= DMA_MAP_MAPPED ;
168         return( i386_btop(vtophys(dmap->raw_buf) + offset) );
169 }
170
171
172 static int
173 sndread(dev_t dev, struct uio * buf, int flag)
174 {
175     int             count = buf->uio_resid;
176     u_int min = minor(dev);
177
178     FIX_RETURN(sound_read_sw(min, &files[min], buf, count));
179 }
180
181
182 static int
183 sndwrite(dev_t dev, struct uio * buf, int flag)
184 {
185     int             count = buf->uio_resid;
186     u_int min = minor(dev);
187
188     FIX_RETURN(sound_write_sw(min, &files[min], buf, count));
189 }
190
191 static int
192 sndopen(dev_t dev, int flags, int mode, struct proc * p)
193 {
194     int             retval;
195     struct fileinfo tmp_file;
196     u_int min = minor(dev);
197
198     if (!soundcard_configured && min) {
199         printf("SoundCard Error: soundcard system has not been configured\n");
200         return ENODEV ;
201     }
202     tmp_file.mode = 0;
203
204     if (flags & FREAD && flags & FWRITE)
205         tmp_file.mode = OPEN_READWRITE;
206     else if (flags & FREAD)
207         tmp_file.mode = OPEN_READ;
208     else if (flags & FWRITE)
209         tmp_file.mode = OPEN_WRITE;
210
211     selinfo[min >> 4].si_pid = 0;
212     selinfo[min >> 4].si_flags = 0;
213     if ((retval = sound_open_sw(min, &tmp_file)) < 0)
214         FIX_RETURN(retval);
215
216     bcopy((char *) &tmp_file, (char *) &files[min], sizeof(tmp_file));
217
218     FIX_RETURN(retval);
219 }
220
221
222 static int
223 sndclose(dev_t dev, int flags, int mode, struct proc * p)
224 {
225     u_int min = minor(dev);
226
227     sound_release_sw(min, &files[min]);
228     return 0 ;
229 }
230
231 static int
232 sndioctl(dev_t dev, u_long cmd, caddr_t arg, int mode, struct proc * p)
233 {
234     u_int min = minor(dev);
235     FIX_RETURN(sound_ioctl_sw(min, &files[min], cmd, arg));
236 }
237
238 int
239 sndpoll(dev_t dev, int events, struct proc * p)
240 {
241     u_int min = minor(dev);
242
243     /* printf ("snd_select(dev=%d, rw=%d, pid=%d)\n", min, rw, p->p_pid); */
244 #ifdef ALLOW_POLL
245     switch (min & 0x0f) {
246 #ifdef CONFIG_SEQUENCER
247     case SND_DEV_SEQ:
248     case SND_DEV_SEQ2:
249         return sequencer_poll(min, &files[min], events, p);
250         break;
251 #endif
252
253 #ifdef CONFIG_MIDI
254     case SND_DEV_MIDIN:
255         return MIDIbuf_poll(min, &files[min], events, p);
256         break;
257 #endif
258
259 #ifdef CONFIG_AUDIO
260     case SND_DEV_DSP:
261     case SND_DEV_DSP16:
262     case SND_DEV_AUDIO:
263
264         return audio_poll(min, &files[min], events, p);
265         break;
266 #endif
267
268     default:
269         return 0;
270     }
271
272 #endif  /* ALLOW_POLL */
273     DEB(printf("sound_ioctl(min=%d, cmd=0x%x, arg=0x%x)\n", min, cmd, arg));
274
275     return 0 ;
276 }
277
278 /* XXX this should become ffs(ipri), perhaps -1 lr 970705 */
279 short
280 ipri_to_irq(u_short ipri)
281 {
282     /*
283      * Converts the ipri (bitmask) to the corresponding irq number
284      */
285     int             irq;
286
287     for (irq = 0; irq < 16; irq++)
288         if (ipri == (1 << irq))
289             return irq;
290
291     return -1;          /* Invalid argument */
292 }
293
294 static int
295 driver_to_voxunit(struct isa_driver * driver)
296 {
297     /*
298      * converts a sound driver pointer into the equivalent VoxWare device
299      * unit number
300      */
301     if (driver == &opldriver)
302         return (SNDCARD_ADLIB);
303     else if (driver == &sbdriver)
304         return (SNDCARD_SB);
305     else if (driver == &pasdriver)
306         return (SNDCARD_PAS);
307     else if (driver == &gusdriver)
308         return (SNDCARD_GUS);
309     else if (driver == &mpudriver)
310         return (SNDCARD_MPU401);
311     else if (driver == &sbxvidriver)
312         return (SNDCARD_SB16);
313     else if (driver == &sbmididriver)
314         return (SNDCARD_SB16MIDI);
315     else if(driver == &awedriver)
316         return(SNDCARD_AWE32);
317     else if (driver == &uartdriver)
318         return (SNDCARD_UART6850);
319     else if (driver == &gusdriver)
320         return (SNDCARD_GUS16);
321     else if (driver == &mssdriver)
322         return (SNDCARD_MSS);
323     else if (driver == &cssdriver)
324         return (SNDCARD_CS4232);
325     else if (driver == &sscapedriver)
326         return(SNDCARD_SSCAPE);
327     else if (driver == &sscape_mssdriver)
328         return(SNDCARD_SSCAPE_MSS);
329     else if (driver == &trixdriver)
330         return (SNDCARD_TRXPRO);
331     else if (driver == &trixsbdriver)
332         return (SNDCARD_TRXPRO_SB);
333     else if (driver == &nssdriver)
334         return (SNDCARD_NSS);
335     else
336         return (0);
337 }
338
339 /*
340  * very dirty: tmp_osp is allocated in sndprobe, and used at the next
341  * call in sndattach
342  */
343
344 static sound_os_info *temp_osp;
345
346 /*
347  * sndprobe is called for each isa_device. From here, a voxware unit
348  * number is determined, and the appropriate probe routine is selected.
349  * The parameters from the config line are passed to the hw_config struct.
350  */
351
352 static int
353 sndprobe(struct isa_device * dev)
354 {
355     struct address_info hw_config;
356     int             unit;
357
358     temp_osp = (sound_os_info *)malloc(sizeof(sound_os_info),
359             M_DEVBUF, M_NOWAIT);
360     if (!temp_osp)
361         panic("SOUND: Cannot allocate memory\n");
362
363     /*
364      * get config info from the kernel config. These may be overridden
365      * by the local autoconfiguration routines though (e.g. pnp stuff).
366      */
367
368     hw_config.io_base = dev->id_iobase;
369     hw_config.irq = ipri_to_irq(dev->id_irq);
370     hw_config.dma = dev->id_drq;
371
372     /*
373      * misuse the flags field for read dma. Note that, to use 0 as
374      * read dma channel, one of the high bits should be set.  lr970705 XXX
375      */
376
377     if (dev->id_flags != 0)
378         hw_config.dma2 = dev->id_flags & 0x7;
379     else
380         hw_config.dma2 = -1;
381
382     hw_config.always_detect = 0;
383     hw_config.name = NULL;
384     hw_config.card_subtype = 0;
385
386     temp_osp->unit = dev->id_unit;
387     hw_config.osp = temp_osp;
388     unit = driver_to_voxunit(dev->id_driver);
389
390     if (sndtable_probe(unit, &hw_config)) {
391         dev->id_iobase = hw_config.io_base;
392         dev->id_irq =  hw_config.irq == -1 ? 0 : (1 << hw_config.irq);
393         dev->id_drq = hw_config.dma;
394
395         if (hw_config.dma != hw_config.dma2 && ( hw_config.dma2 != -1))
396             dev->id_flags = hw_config.dma2 | 0x100; /* XXX lr */
397         else
398             dev->id_flags = 0;
399         return TRUE;
400     }
401     return 0;
402 }
403
404 static int
405 sndattach(struct isa_device * dev)
406 {
407     int             unit;
408     static int      midi_initialized = 0;
409     static int      seq_initialized = 0;
410     struct address_info hw_config;
411     char   *dname;
412     void   *tmp;
413
414     /*
415      * Associate interrupt handlers with devices.  XXX this may be incomplete.
416      */
417     dname = dev->id_driver->name;
418 #if defined(CONFIG_AD1848)
419     if (strcmp(dname, "css") == 0 || strcmp(dname, "gusxvi") == 0 ||
420         strcmp(dname, "mss") == 0)
421         dev->id_ointr = adintr;
422 #endif
423 #ifdef CONFIG_GUS
424     if (strcmp(dname, "gus") == 0)
425         dev->id_ointr = gusintr;
426 #endif
427 #ifdef CONFIG_PAS
428     if (strcmp(dname, "pas") == 0)
429         dev->id_ointr = pasintr;
430 #endif
431 #if NSB > 0 && (defined(CONFIG_MIDI) || defined(CONFIG_AUDIO))
432     if (strcmp(dname, "sb") == 0)
433         dev->id_ointr = sbintr;
434 #endif
435     if (strcmp(dname, "sscape_mss") == 0)
436         dev->id_ointr = sndintr;
437 #if NSSCAPE > 0
438     if (strcmp(dname, "sscape") == 0 || strcmp(dname, "trix") == 0)
439         dev->id_ointr = sscapeintr;
440 #endif
441 #if NUART > 0
442     if (strcmp(dname, "uart0") == 0)
443         dev->id_ointr = m6850intr;
444 #endif
445 #if NMPU > 0 && defined(CONFIG_MIDI)
446     if (strcmp(dname, "mpu") == 0)
447         dev->id_ointr = mpuintr;
448 #endif
449 #if NNSS > 0
450     if (strcmp(dname, "nss") == 0)
451         dev->id_ointr = nssintr;
452 #endif
453
454     unit = driver_to_voxunit(dev->id_driver);
455     hw_config.io_base = dev->id_iobase;
456     hw_config.irq = ipri_to_irq(dev->id_irq);
457     hw_config.dma = dev->id_drq;
458
459     /* misuse the flags field for read dma */
460     if (dev->id_flags != 0)
461         hw_config.dma2 = dev->id_flags & 0x7;
462     else
463         hw_config.dma2 = -1;
464
465     hw_config.card_subtype = 0;
466     hw_config.osp = temp_osp;
467
468     if (!unit)
469         return FALSE;
470
471     if (!(sndtable_init_card(unit, &hw_config))) {      /* init card */
472         printf(" <Driver not configured>");
473         return FALSE;
474     }
475     /*
476      * Init the high level sound driver
477      */
478
479     if (!(soundcards_installed = sndtable_get_cardcount())) {
480         DDB(printf("No drivers actually installed\n"));
481         return FALSE;   /* No cards detected */
482     }
483     printf("\n");
484
485 #ifdef CONFIG_AUDIO
486     if (num_audiodevs) {        /* Audio devices present */
487         DMAbuf_init();
488         sound_mem_init();
489     }
490     soundcard_configured = 1;
491 #endif
492
493     if (num_midis && !midi_initialized)
494         midi_initialized = 1;
495
496     if ((num_midis + num_synths) && !seq_initialized) {
497         seq_initialized = 1;
498         sequencer_init();
499     }
500
501     cdevsw_add(&snd_cdevsw);
502 #define GID_SND GID_GAMES
503 #define UID_SND UID_ROOT
504 #define PERM_SND 0660
505     /*
506      *  make links to first successfully probed device, don't do it if
507      *  duplicate creation of same node failed (ie. bad cookie returned)
508      */
509     if (dev->id_driver == &opldriver){
510         make_dev(&snd_cdevsw, (dev->id_unit << 4) | SND_DEV_SEQ,
511             UID_SND, GID_SND, PERM_SND, "sequencer%r", dev->id_unit);
512     } else if (dev->id_driver == &mpudriver || 
513                dev->id_driver == &sbmididriver ||
514                dev->id_driver == &uartdriver){
515         make_dev(&snd_cdevsw, (dev->id_unit << 4) | SND_DEV_MIDIN,
516             UID_SND, GID_SND, PERM_SND, "midi%r", dev->id_unit);
517     } else {
518         make_dev(&snd_cdevsw, (dev->id_unit << 4) | SND_DEV_DSP,
519             UID_SND, GID_SND, PERM_SND, "dsp%r", dev->id_unit);
520         make_dev(&snd_cdevsw, (dev->id_unit << 4) | SND_DEV_DSP16,
521             UID_SND, GID_SND, PERM_SND, "dspW%r", dev->id_unit);
522         make_dev(&snd_cdevsw, (dev->id_unit << 4) | SND_DEV_AUDIO,
523             UID_SND, GID_SND, PERM_SND, "audio%r", dev->id_unit);
524         make_dev(&snd_cdevsw, (dev->id_unit << 4) | SND_DEV_CTL,
525             UID_SND, GID_SND, PERM_SND, "mixer%r", dev->id_unit);
526         make_dev(&snd_cdevsw, (dev->id_unit << 4) | SND_DEV_STATUS,
527             UID_SND, GID_SND, PERM_SND, "sndstat%r", dev->id_unit);
528     }
529     return TRUE;
530 }
531
532
533 #ifdef CONFIG_AUDIO
534
535 static void
536 alloc_dmap(int dev, int chan, struct dma_buffparms * dmap)
537 {
538     char           *tmpbuf;
539     int            i;
540
541     tmpbuf = contigmalloc(audio_devs[dev]->buffsize, M_DEVBUF, M_NOWAIT,
542                 0ul, 0xfffffful, 1ul, chan & 4 ? 0x20000ul : 0x10000ul);
543     if (tmpbuf == NULL)
544         printf("soundcard buffer alloc failed \n");
545
546     if (tmpbuf == NULL) {
547         printf("snd: Unable to allocate %d bytes of buffer\n",
548                2 * (int) audio_devs[dev]->buffsize);
549         return;
550     }
551     dmap->raw_buf = tmpbuf;
552     /*
553      * Use virtual address as the physical address, since isa_dmastart
554      * performs the phys address computation.
555      */
556
557     dmap->raw_buf_phys = (uintptr_t) tmpbuf;
558     for (i = 0; i < audio_devs[dev]->buffsize; i++)   *tmpbuf++ = 0x80; 
559
560 }
561
562 static void
563 sound_mem_init(void)
564 {
565     int             dev;
566     static u_long dsp_init_mask = 0;
567
568     for (dev = 0; dev < num_audiodevs; dev++)   /* Enumerate devices */
569         if (!(dsp_init_mask & (1 << dev)))      /* Not already done */
570             if (audio_devs[dev]->dmachan1 >= 0) {
571                 dsp_init_mask |= (1 << dev);
572                 audio_devs[dev]->buffsize = DSP_BUFFSIZE;
573                 /* Now allocate the buffers */
574                 alloc_dmap(dev, audio_devs[dev]->dmachan1,
575                         audio_devs[dev]->dmap_out);
576                 if (audio_devs[dev]->flags & DMA_DUPLEX)
577                     alloc_dmap(dev, audio_devs[dev]->dmachan2,
578                             audio_devs[dev]->dmap_in);
579             }   /* for dev */
580 }
581
582 #endif
583
584
585 int
586 snd_ioctl_return(int *addr, int value)
587 {
588     if (value < 0)
589         return value;   /* Error */
590     suword(addr, value);
591     return 0;
592 }
593
594 #define MAX_UNIT 50
595 typedef void    (*irq_proc_t) (int irq);
596 static irq_proc_t irq_proc[MAX_UNIT] = {NULL};
597 static int      irq_irq[MAX_UNIT] = {0};
598
599 int
600 snd_set_irq_handler(int int_lvl, void (*hndlr) (int), sound_os_info * osp)
601 {
602     if (osp->unit >= MAX_UNIT) {
603         printf("Sound error: Unit number too high (%d)\n", osp->unit);
604         return 0;
605     }
606     irq_proc[osp->unit] = hndlr;
607     irq_irq[osp->unit] = int_lvl;
608     return 1;
609 }
610
611 static void
612 sndintr(int unit)
613 {
614     if ( (unit >= MAX_UNIT) || (irq_proc[unit] == NULL) )
615         return;
616
617     irq_proc[unit] (irq_irq[unit]);     /* Call the installed handler */
618 }
619
620 void
621 conf_printf(char *name, struct address_info * hw_config)
622 {
623     if (!trace_init)
624         return;
625
626     printf("snd0: <%s> ", name);
627 #if 0
628     if (hw_config->io_base != -1 ) 
629     printf("at 0x%03x", hw_config->io_base);
630
631     if (hw_config->irq != -1 )
632         printf(" irq %d", hw_config->irq);
633
634     if (hw_config->dma != -1 || hw_config->dma2 != -1) {
635         printf(" dma %d", hw_config->dma);
636         if (hw_config->dma2 != -1)
637             printf(",%d", hw_config->dma2);
638     }
639 #endif
640
641 }
642
643 void
644 conf_printf2(char *name, int base, int irq, int dma, int dma2)
645 {
646     if (!trace_init)
647         return;
648
649     printf("snd0: <%s> ", name);
650 #if 0
651     if (hw_config->io_base != -1 ) 
652     printf("at 0x%03x", hw_config->io_base);
653
654     if (irq)
655         printf(" irq %d", irq);
656
657     if (dma != -1 || dma2 != -1) {
658         printf(" dma %d", dma);
659         if (dma2 != -1)
660             printf(",%d", dma2);
661     }
662 #endif
663
664 }
665
666
667 void tenmicrosec (int j)
668 {
669   int             i, k;
670   for (k = 0; k < j/10 ; k++) {
671       for (i = 0; i < 16; i++)
672           inb (0x80);
673   }
674 }
675
676 #endif  /* NSND > 0 */
677
678
679
680