Device layer rollup commit.
[dragonfly.git] / sys / dev / sound / isa / i386 / soundcard.c
CommitLineData
984263bc
MD
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 $
e4c9c0c8 29 * $DragonFly: src/sys/dev/sound/isa/i386/Attic/soundcard.c,v 1.7 2004/05/19 22:52:50 dillon Exp $
984263bc
MD
30 *
31 */
1f2de5d4
MD
32#include "use_snd.h"
33#include "sound_config.h"
984263bc 34#if NSND > 0 /* from "snd.h" */
1f2de5d4 35#include "use_uart.h"
984263bc
MD
36
37#include <sys/select.h>
38#include <vm/vm.h>
39#include <vm/pmap.h>
40#include <sys/mman.h>
41
1f2de5d4 42#include <bus/isa/i386/isa_device.h>
984263bc
MD
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
64static int soundcards_installed = 0; /* Number of installed soundcards */
65static int soundcard_configured = 0;
66
67static struct fileinfo files[SND_NDEVS];
68struct selinfo selinfo[SND_NDEVS >> 4];
69
70int
71MIDIbuf_poll (int dev, struct fileinfo *file, int events, select_table * wait);
72
73int
74audio_poll(int dev, struct fileinfo * file, int events, select_table * wait);
75
76int
77sequencer_poll (int dev, struct fileinfo *file, int events, select_table * wait);
78
5ca58d54
RG
79static int sndprobe (struct isa_device *);
80static int sndattach (struct isa_device *);
984263bc
MD
81
82static d_open_t sndopen;
83static d_close_t sndclose;
84static d_ioctl_t sndioctl;
85static d_read_t sndread;
86static d_write_t sndwrite;
87static d_poll_t sndpoll;
88static d_mmap_t sndmmap;
89
90static char driver_name[] = "snd";
91
92#define CDEV_MAJOR 30
93static struct cdevsw snd_cdevsw = {
fabb8ceb
MD
94 /* name */ driver_name,
95 /* maj */ CDEV_MAJOR,
96 /* flags */ 0,
97 /* port */ NULL,
455fcd7e 98 /* clone */ NULL,
fabb8ceb 99
984263bc
MD
100 /* open */ sndopen,
101 /* close */ sndclose,
102 /* read */ sndread,
103 /* write */ sndwrite,
104 /* ioctl */ sndioctl,
105 /* poll */ sndpoll,
106 /* mmap */ sndmmap,
107 /* strategy */ nostrategy,
984263bc 108 /* dump */ nodump,
fabb8ceb 109 /* psize */ nopsize
984263bc
MD
110};
111
112
113
114
115static 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
126struct isa_driver opldriver = {sndprobe, sndattach, "opl"};
127struct isa_driver trixdriver = {sndprobe, sndattach, "trix"};
128struct isa_driver trixsbdriver = {sndprobe, sndattach, "trixsb"};
129struct isa_driver sbdriver = {sndprobe, sndattach, "sb"};
130struct isa_driver sbxvidriver = {sndprobe, sndattach, "sbxvi"};
131struct isa_driver sbmididriver = {sndprobe, sndattach, "sbmidi"};
132struct isa_driver awedriver = {sndprobe, sndattach, "awe"};
133struct isa_driver pasdriver = {sndprobe, sndattach, "pas"};
134struct isa_driver mpudriver = {sndprobe, sndattach, "mpu"};
135struct isa_driver gusdriver = {sndprobe, sndattach, "gus"};
136struct isa_driver gusxvidriver = {sndprobe, sndattach, "gusxvi"};
137struct isa_driver gusmaxdriver = {sndprobe, sndattach, "gusmax"};
138struct isa_driver uartdriver = {sndprobe, sndattach, "uart"};
139struct isa_driver mssdriver = {sndprobe, sndattach, "mss"};
140struct isa_driver cssdriver = {sndprobe, sndattach, "css"};
141struct isa_driver sscapedriver = {sndprobe, sndattach, "sscape"};
142struct isa_driver sscape_mssdriver = {sndprobe, sndattach, "sscape_mss"};
143struct isa_driver nssdriver = {sndprobe, sndattach, "nss"};
144
145short ipri_to_irq(u_short ipri);
146
147static ointhand2_t sndintr;
148
149u_long
150get_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
159static int
160sndmmap( 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
176static int
177sndread(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
186static int
187sndwrite(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
195static int
196sndopen(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
226static int
227sndclose(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
235static int
236sndioctl(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
242int
243sndpoll(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 */
283short
284ipri_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
298static int
299driver_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
348static 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
356static int
357sndprobe(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
408static int
409sndattach(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
e4c9c0c8 504 cdevsw_add(&snd_cdevsw, 0xf0, dev->id_unit << 4);
984263bc
MD
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
538static void
539alloc_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
565static void
566sound_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
588int
589snd_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
598typedef void (*irq_proc_t) (int irq);
599static irq_proc_t irq_proc[MAX_UNIT] = {NULL};
600static int irq_irq[MAX_UNIT] = {0};
601
602int
603snd_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
614static void
615sndintr(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
623void
624conf_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
646void
647conf_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
670void 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