* sound/386bsd/soundcard.c
* Soundcard driver for FreeBSD.
* Copyright by Hannu Savolainen 1993
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
#include "sound_config.h"
#ifdef CONFIGURE_SOUNDCARD
#define FIX_RETURN(ret) {if ((ret)<0) return -(ret); else return 0;}
static int timer_running
= 0;
static int soundcards_installed
= 0; /* Number of installed
static int soundcard_configured
= 0;
extern char *snd_raw_buf
[MAX_DSP_DEV
][DSP_BUFFCOUNT
];
extern unsigned long snd_raw_buf_phys
[MAX_DSP_DEV
][DSP_BUFFCOUNT
];
extern int snd_raw_count
[MAX_DSP_DEV
];
static struct fileinfo files
[SND_NDEVS
];
int sndprobe (struct isa_device
*dev
);
int sndattach (struct isa_device
*dev
);
int sndopen (dev_t dev
, int flags
);
int sndclose (dev_t dev
, int flags
);
int sndioctl (dev_t dev
, int cmd
, caddr_t arg
, int mode
);
int sndread (int dev
, struct uio
*uio
);
int sndwrite (int dev
, struct uio
*uio
);
int sndselect (int dev
, int rw
);
static void sound_mem_init(void);
extern struct timeval time
;
return timecopy
.tv_usec
/(1000000/HZ
) +
(unsigned long)timecopy
.tv_sec
*HZ
;
sndread (int dev
, struct uio
*buf
)
int count
= buf
->uio_resid
;
FIX_RETURN (sound_read_sw (dev
, &files
[dev
], buf
, count
));
sndwrite (int dev
, struct uio
*buf
)
int count
= buf
->uio_resid
;
FIX_RETURN (sound_write_sw (dev
, &files
[dev
], buf
, count
));
sndopen (dev_t dev
, int flags
)
if (!soundcard_configured
&& dev
)
printk ("SoundCard Error: The soundcard system has not been configured\n");
if (flags
& FREAD
&& flags
& FWRITE
)
files
[dev
].mode
= OPEN_READWRITE
;
files
[dev
].mode
= OPEN_READ
;
files
[dev
].mode
= OPEN_WRITE
;
FIX_RETURN(sound_open_sw (dev
, &files
[dev
]));
sndclose (dev_t dev
, int flags
)
sound_release_sw(dev
, &files
[dev
]);
sndioctl (dev_t dev
, int cmd
, caddr_t arg
, int mode
)
FIX_RETURN (sound_ioctl_sw (dev
, &files
[dev
], cmd
, (unsigned int) arg
));
sndselect (int dev
, int rw
)
DEB (printk ("sound_ioctl(dev=%d, cmd=0x%x, arg=0x%x)\n", dev
, cmd
, arg
));
ipri_to_irq (unsigned short ipri
)
* Converts the ipri (bitmask) to the corresponding irq number
for (irq
= 0; irq
< 16; irq
++)
return -1; /* Invalid argument */
sndprobe (struct isa_device
*dev
)
struct address_info hw_config
;
hw_config
.io_base
= dev
->id_iobase
;
hw_config
.irq
= ipri_to_irq (dev
->id_irq
);
hw_config
.dma
= dev
->id_drq
;
return sndtable_probe (dev
->id_unit
, &hw_config
);
sndattach (struct isa_device
*dev
)
static int dsp_initialized
= 0;
static int midi_initialized
= 0;
static int seq_initialized
= 0;
static int generic_midi_initialized
= 0;
unsigned long mem_start
= 0xefffffffUL
;
struct address_info hw_config
;
hw_config
.io_base
= dev
->id_iobase
;
hw_config
.irq
= ipri_to_irq (dev
->id_irq
);
hw_config
.dma
= dev
->id_drq
;
if (dev
->id_unit
) /* Card init */
if (!sndtable_init_card (dev
->id_unit
, &hw_config
))
printf (" <Driver not configured>");
* Init the high level sound driver
if (!(soundcards_installed
= sndtable_get_cardcount ()))
printf (" <No such hardware>");
return FALSE
; /* No cards detected */
soundcard_configured
= 1;
if (num_dspdevs
&& !dsp_initialized
) /* Audio devices present */
mem_start
= DMAbuf_init (mem_start
);
mem_start
= audio_init (mem_start
);
#ifndef EXCLUDE_CHIP_MIDI
if (!generic_midi_initialized
)
generic_midi_initialized
= 1;
mem_start
= CMIDI_init (mem_start
);
if (num_midis
&& !midi_initialized
)
mem_start
= MIDIbuf_init (mem_start
);
if ((num_midis
+ num_synths
) && !seq_initialized
)
mem_start
= sequencer_init (mem_start
);
request_sound_timer (int count
)
timeout ((timeout_func_t
)sequencer_timer
, 0, -count
);
current
= 0; /* Timer restarted */
timeout ((timeout_func_t
)sequencer_timer
, 0, count
);
untimeout ((timeout_func_t
)sequencer_timer
, 0);
unsigned long dma_pagesize
;
static unsigned long dsp_init_mask
= 0;
for (dev
= 0; dev
< num_dspdevs
; dev
++) /* Enumerate devices */
if (!(dsp_init_mask
& (1 << dev
))) /* Not already done */
if (sound_buffcounts
[dev
] > 0 && sound_dsp_dmachan
[dev
] > 0)
dsp_init_mask
|= (1 << dev
);
if (sound_dma_automode
[dev
])
sound_dma_automode
[dev
] = 0; /* Not possible with FreeBSD */
if (sound_buffcounts
[dev
] == 1)
sound_buffcounts
[dev
] = 2;
sound_buffsizes
[dev
] /= 2;
if (sound_buffsizes
[dev
] > 65536) /* Larger is not possible (yet) */
sound_buffsizes
[dev
] = 65536;
if (sound_dsp_dmachan
[dev
] > 3 && sound_buffsizes
[dev
] > 65536)
dma_pagesize
= 131072; /* 128k */
dma_pagesize
= 4096; /* use bounce buffer */
if (sound_buffsizes
[dev
] > dma_pagesize
)
sound_buffsizes
[dev
] = dma_pagesize
;
sound_buffsizes
[dev
] &= ~0xfff; /* Truncate to n*4k */
if (sound_buffsizes
[dev
] < 4096)
sound_buffsizes
[dev
] = 4096;
sound_buffsizes
[dev
] = 4096;
sound_buffcounts
[dev
] = 16; /* -> 64k */
/* Now allocate the buffers */
for (snd_raw_count
[dev
] = 0; snd_raw_count
[dev
] < sound_buffcounts
[dev
]; snd_raw_count
[dev
]++)
* The DMA buffer allocation algorithm hogs memory. We allocate
* a memory area which is two times the requires size. This
* guarantees that it contains at least one valid DMA buffer.
* This really needs some kind of finetuning.
char *tmpbuf
= malloc (2*sound_buffsizes
[dev
], M_DEVBUF
, M_NOWAIT
);
unsigned long addr
, rounded
;
printk ("snd: Unable to allocate %d bytes of buffer\n",
2 * sound_buffsizes
[dev
]);
* Align the start address
rounded
= (addr
& ~(dma_pagesize
- 1)) + dma_pagesize
;
snd_raw_buf
[dev
][snd_raw_count
[dev
]] =
&tmpbuf
[rounded
- addr
]; /* Compute offset */
* Use virtual address as the physical address, since
* isa_dmastart performs the phys address computation.
snd_raw_buf_phys
[dev
][snd_raw_count
[dev
]] =
(unsigned long) snd_raw_buf
[dev
][snd_raw_count
[dev
]];
struct isa_driver snddriver
=
{sndprobe
, sndattach
, "snd"};
snd_ioctl_return (int *addr
, int value
)
return value
; /* Error */
snd_set_irq_handler (int interrupt_level
, void(*hndlr
)(int))
snd_release_irq(int vect
)