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