diff options
-rw-r--r-- | sys/i386/isa/snd/doc/Makefile | 40 | ||||
-rw-r--r-- | sys/i386/isa/snd/doc/sound.ps.gz | bin | 45365 -> 0 bytes | |||
-rw-r--r-- | sys/i386/isa/snd/doc/sound.tex | 917 | ||||
-rw-r--r-- | sys/i386/isa/snd/misc/README | 82 | ||||
-rw-r--r-- | sys/i386/isa/snd/misc/audio-voxware.cc | 435 | ||||
-rw-r--r-- | sys/i386/isa/snd/misc/auvoxware.c | 1301 | ||||
-rw-r--r-- | sys/i386/isa/snd/misc/files.i386 | 240 | ||||
-rw-r--r-- | sys/i386/isa/snd/misc/linux.patch | 41 | ||||
-rw-r--r-- | sys/i386/isa/snd/misc/linux_a.c | 238 | ||||
-rw-r--r-- | sys/i386/isa/snd/misc/mmap_test.c | 278 | ||||
-rw-r--r-- | sys/i386/isa/snd/misc/pcmio.c | 236 | ||||
-rw-r--r-- | sys/i386/isa/snd/misc/soundbyte.c | 275 | ||||
-rw-r--r-- | sys/i386/isa/snd/misc/test.c | 84 |
13 files changed, 0 insertions, 4167 deletions
diff --git a/sys/i386/isa/snd/doc/Makefile b/sys/i386/isa/snd/doc/Makefile deleted file mode 100644 index 355a77f..0000000 --- a/sys/i386/isa/snd/doc/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -# Makefile for the sound documentation - -ARTICLE=sound -INPUTS= -STYLES= -.SUFFIXES: .fig .ps -OTHERSTUFF= -FIGURES= -PSS= -ALLFIG= $(FIGURES) -COMPAT= psfigps.tex - -ALLPS= $(ALLFIG:.fig=.ps) - -ALLSRCS= $(ARTICLE).tex $(STYLES) $(ALLFIG) $(PSS) $(INPUTS) \ - $(COMPAT) $(OTHERSTUFF) Makefile - -.fig.ps: - fig2dev -L ps -m 0.5 $*.fig > $*.ps - -all: $(ARTICLE).dvi pnp.dvi ioctl.dvi Makefile - -$(ARTICLE).dvi: allfig $(ARTICLE).tex $(INPUTS) $(STYLES) $(PSS) - latex $(ARTICLE).tex - -pnp.dvi: allfig pnp.tex $(INPUTS) $(STYLES) $(PSS) - latex pnp.tex - -ioctl.dvi: allfig pnp.tex $(INPUTS) $(STYLES) $(PSS) - latex ioctl.tex - -allfig: $(ALLPS) - -clean: - rm -f $(ALLPS) a c *.dvi *.aux *.log rl - -tgz: $(ALLSRCS) - tar cvf - $(ALLSRCS) | gzip -9 > $(ARTICLE).tgz - - diff --git a/sys/i386/isa/snd/doc/sound.ps.gz b/sys/i386/isa/snd/doc/sound.ps.gz Binary files differdeleted file mode 100644 index 12beb0a..0000000 --- a/sys/i386/isa/snd/doc/sound.ps.gz +++ /dev/null diff --git a/sys/i386/isa/snd/doc/sound.tex b/sys/i386/isa/snd/doc/sound.tex deleted file mode 100644 index d8e7059..0000000 --- a/sys/i386/isa/snd/doc/sound.tex +++ /dev/null @@ -1,917 +0,0 @@ -\documentclass[11pt]{article} - -\textwidth 6in -\textheight 9in -\oddsidemargin 0in -\evensidemargin 0in -\topmargin 0in - -% \input{psfigps.tex} - -\begin{document} -\author{Luigi Rizzo\\ - Dipartimento di Ingegneria dell'Informazione -- Universit\`a di Pisa\\ - via Diotisalvi 2 -- 56126 Pisa (Italy)\\ - email: {\tt l.rizzo@iet.unipi.it}} -\title{The FreeBSD audio driver} -\maketitle - -\begin{abstract} -In this paper we describe the architecture of the new FreeBSD audio -driver. We also give detailed information on the internal data -structures used by the driver, and examples on how to add support -for new devices. - -{\bf WARNING:} since the code is rapidly evolving, there might be some -minor differences between this paper and the source code. In doubt, -the source code is the ultimate reference. - -\end{abstract} - -\section{Introduction} - -The audio driver is the part of the kernel which handles audio-related -peripherals. In FreeBSD, historically, there has been not much support -for these devices. The original FreeBSD audio driver has been based on -the Voxware 3.0 release, originally developed for Linux and ported to -FreeBSD at 1.1 times. The driver in the source tree has been -essentially unsupported since then. - -In parallel, some volunteers have been using a driver derived from -Voxware 3.5, which had support for full-duplex audio cards which have -become popular in more recent times. - -Both versions of the Voxware code are extremely complex and not very -much in line with BSD device drivers. There are several motivations -for that, the main one (we believe) was that the code has evolved -through the years to support a number of boards which are sufficiently -similar to suggest not to write a completely different driver, and -sufficiently different to require the addition of state variables, new -support routines, and feature enahncements, to the existing driver. -The unfortunate result of this evolution was that the code in our hand -was extremely difficult to configure, follow, and in many cases unable to -support multiple devices. Furthermore, the complexity of the code, -prevented proper support for it. - -The desire for a functional audio driver for FreeBSD, together with -the lack of support for the code currently in the source tree, and -its complexity of the original driver, were for us sufficient -motivations to start a large rewrite of the code. - -From a user's point of view, we were especially concerned with the -complexity of the configuration process, which, to be done properly, -required a number of different devices to be compiled into the kernel, -with (at times) subtle dependencies among the modules and the options -to be used. So, one of our goal was to simplify the configuration -process, a goal which we believe to have achieved. - -From the kernel developer's point of view, the Voxware driver was hard -to understand for two reasons. First, its structure was not much in -line with BSD driver. This obviously derives from the original -development on a different system. The second reason is the evolution -of the driver during time, which, we believe, has degraded the quality of -the code from a carefully designed original version. - -We have started our work basing on Voxware 3.5. The Voxware code -served mainly as a reference on what the features of the various -boards were, and how problems had been dealt with. Our code -then evolved into a fairly complete rewrite of the main modules, -including the main configuration mechanisms, the DMA support -routines, and, in many cases, also the board-specific drivers which -could make use of many of the simplifications we have introduced. - -\section{What the audio driver does} - -The audio driver is intended to control all peripherals related to -audio handling. This includes digital audio sampling and generation -({\tt pcm}), communication with MIDI devices ({\tt midi}) and the -synthesizers ({\tt synth}) which several audio cards provide. In -addition to these devices, which have explicit entries in the kernel -configuration file, audio cards generally provide a {\em mixer} -device, which controls audio paths within the board. -Our devices currently has only support for {\tt pcm} and mixer -devices. - -\subsection{The {\tt pcm} device} - -The {\tt pcm} device is in charge of the audio sampling and -generation. Such device is generally implemented by a CODEC, a piece -of hardware containing one or two A/D and D/A converters. Depending on -the board, the minimum and maximum sampling rate, the number of bits -per sample, and the data format (e.g. the availability of compressed -audio formats) varies. At a minimum, all boards seem to be capable of -sampling mono audio with 8-bit unsigned values and 8 KHz resolutions. -Most boards (especially the Windows-Sound-System ones, known as WSS or -MSS) are also capable of full duplex stereo with 16-bit and 44.1KHz -sampling rate (corresponding to CD-quality). - -The {\tt pcm} device implements the {\tt ioctl()} calls to select the -desired data format, and {\tt read()} and {\tt write()} functions to -allow a smooth exchange of data with the codec, and {\tt select()} to -notify the application when I/O is possible. - - -\subsection{The mixer} - -The mixer controls audio data paths, i.e. which sources are directed -to the ADC input, which ones are directed to the audio output, and the -attenuation on the various channels. There is a wide variety of -features in this subsystem, as some boards do provide only on-off -control on a limited number of sources, whereas some boards provide -many sources and fine-grained volume controls. - -We believe that a sufficiently general model of the {\tt mixer} -is one actually using {\em two} mixers, one to connect sources to the -ADC part of the codec, and one to connect sources to the physical -output (usually the speakers). Some early boards often implement the -mixer leading to the ADC only as a multiplexer with one active line, -but that can be modeled by thinking of a very coarse (1 bit) volume -control, and a restriction on the volumes on the various sources. - - -\section{Kernel Configuration} - -The configuration of the driver is done through the following -statements included in the system configuration file: -\begin{verbatim} -device pcm0 at isa? port? tty irq N drq D flags F vector pcmintr -\end{verbatim} -The {\tt device pcm0} statement is in charge of bringing into the -kernel all modules related to audio support. - -The main audio subsystem is configured by using the {\tt device -pcm0} statement. This line supplies the main parameters related to the -configuration of a single sound card, which are: -\begin{itemize} -\item {\bf port} the I/O address for the codec (and generally mixer) - subsystem. If no address is supplied, the driver looks at - different addresses for the most common boards. -\item {\bf irq} the interrupt line used by the board. -\item {\bf drq} the first DMA channel used by the board. Modern - sound boards supporting full-duplex can use two DMA channels, - so we use the {\tt flags} field to specify the second channel. -\item {\bf flags} used to specify the second DMA channel, the device - type (overriding the autoconfiguration mechanism), and - other information. - In particular, the flags have the following use:\\ - \begin{center} - \begin{tabular}{|c|l|} - \hline Bits & Meaning \\ - \hline \hline - 2..0 & secondary (read) DMA channel for dual-dma boards. \\ - \hline - 4 & Enable secondary dma channel \\ - \hline - 15..8 & Specific device type/class. 0 means autoconfigure\\ - \hline - \end{tabular} - \end{center} -\end{itemize} -A sound board often has more than the codec, and uses more than one -I/O address block. Since the {\tt device} line in the config file -does not permit to -specify more than one address (except, perhaps, by abusing the {\tt -flags} field, which we have already used though), we will -use two additional {\tt device} entries to specify the i/o address -for the MIDI ({\tt midi}) and Synthesizer ({\tt synth}) devices, -respectively. These entries do not correspond to actual devices -recognized by the kernel (in the sense that their probe routine will -always fail, and their attach routine will do nothing and will never -be called); rather, the parameters specified in these lines are used -to extend the description of the board provided by the {\tt device -pcmX} line. -There is no support at the moment for {\tt midi} and {\tt synth} -devices. - -\subsection{Plug and Play support} - -As a side effect of our work on the audio driver, we have implemented -support for Plug and Play (PnP) device configuration. This was a -necessity since many modern audio boards are configured through -PnP. PnP support is described in a separate document. - -In order to support PnP boards, one device entry is still necessary -(i.e. {\tt pcm0}), to let the -configure program include all the necessary parameters. The entry must -include all fields, e.g. -\begin{verbatim} -device pcm0 at isa? port? tty irq 7 drq 1 vector pcmintr -\end{verbatim} -although -the actual configuration of PnP devices (i.e. port addresses, IRQ, -DMA, etc. will be auto detected, and unit numbers will be assigned -starting from the next free one (e.g. {\tt pcm1, pcm2, ...}). - -\section{Code structure} - -The following table details the various file which make up the code. -All files reside in the directory {\tt /sys/i386/isa/snd} . - -\begin{center} -\begin{tabular}{|l|p{4in}|} -\hline -File Name & Description \\ -\hline \hline -{\tt sound.c} & main device routines and autoconfiguration.\\ -\hline -{\tt sound.h} & generic header for all kernel files.\\ -\hline -{\tt soundcard.h} & generic header for all userland sound apps.\\ -\hline -{\tt dmabuf.c} & DMA support. \\ -\hline -{\tt sb\_dsp.c} & SoundBlaster driver \\ -\hline -{\tt ad1848.c} & MSS-compatible driver \\ -\hline -{\tt clones.c} & Miscellaneous code to enable SB/MSS emulation in - various boards. \\ -\hline -\end{tabular} -\end{center} - -\subsection{The {\tt snddev\_info} structure} - -Each known board is fully described by a {\tt snddev\_info} -structure. The structure contains information of use at initialization -time (such as board type, name, probe and attach routines), and at -runtime. The latter include all board-specific functions, and the -generic status information about the board when in use. - -{\tt snddev\_info} is made of two parts, the first one which is -generally initialized from a template which univoquely identifies the -board, the second one which contains run-time parameters. The first part -of the structure is: - -\begin{verbatim} -typedef struct _snddev_info snddev_info ; -struct _snddev_info { - char name[64]; - int type ; /* board type/class, search key during probes */ - int (*probe)(struct isa_device * dev); - int (*attach)(struct isa_device * dev) ; - d_open_t *open ; - d_close_t *close ; - d_read_t *read ; - d_write_t *write ; - d_ioctl_t *ioctl ; - d_select_t *select ; - irq_proc_t *isr ; - snd_callback_t *callback; - - int bufsize; /* DMA buffer size */ - u_long audio_fmt ; /* bitmap of supported audio formats */ -\end{verbatim} -where the names of the fields clearly identify the functions. -Board-specific code generally supplies, in the template, initializers -for all the above fields. At attach time, and before calling the -board-specific attach routines, the descriptor associated with the -device, {\tt pcm\_info[dev->id\_unit]} is bzeroed, initialized with -the template, then the fields in the second part of the structure -(shown next) are initialized with default values (partly taken from -the device config line, as in the case of i/o, irq and dma addresses), -and the required buffers are allocated. - -\begin{verbatim} - int io_base, alt_base, conf_base, - mix_base, midi_base, synth_base; - - int bd_id; /* board-specific id */ - snd_dbuf dbuf_out, dbuf_in; - int status_len, status_ptr ; /* to implement sndstat */ - - volatile u_long flags; /* generic flags */ - - u_long bd_flags; /* board-specific flags */ - int play_speed, rec_speed; - - int play_blocksize, rec_blocksize; - u_long play_fmt, rec_fmt ; - u_long mix_devs, mix_rec_devs, mix_recsrc; - u_short mix_levels[32]; - - u_long interrupts; - void *device_data; -\end{verbatim} -The structure provides all generic fields for audio support, plus a -couple of board-specific fields, {\tt bd\_id} and {\tt bd\_flags}. The -former should be used to distinguish different versions of the same -device (e.g. major/minor id in case of the SoundBlaster, codec type -for MSS-compatible boards, etc.), the latter can be used to hold -board-specific flags. Should these info not be sufficient, room is -provided for a pointer to device-specific data so that the structure -can be extended at will. - -Note that the descriptor has room for several base addresses. One of -this ({\tt io\_base}) is derived from the the kernel config line, and -corresponds to the base address for codec access. The others can be -derived using various mechanisms, e.g. hardwired info (some boards are -known to have a given subsystem at a given address), additional lines -in the config file, or PnP autoconfiguration info. These addresses are -used to access the subsystems, and to check for conflicts during the -configuration process. - -Of particular importance is the {\tt flags} fields, which holds many -flags used to determine the status of the device. Among them: -\begin{verbatim} -#define SND_F_BUSY 0x0001 /* has been opened (for write) */ -#define SND_F_BUSY_AUDIO 0x10000000 -#define SND_F_BUSY_DSP 0x20000000 -#define SND_F_BUSY_DSP16 0x40000000 -\end{verbatim} -These flags indicate the busy status of the board. They are of -exclusive use of the device-specific {\tt open()} and {\tt close()} -routines. The intended purpose is to allow only one or more opens -on the device. For the way the kernel operates, when multiple -descriptors are open on the same device (e.g. because the process -{\tt fork()}'ed after opening the device), only the last {\tt -close()} will result in the invokation of the device-specific close. -But, since in the Voxware mode, a device is accessed using three -minor numbers (corresponding to {\tt /dev/dsp, /dev/audio, /dev/dspW}), -we have to keep track of opens issued on the different devices and -only call the close routines on the very last close. - -\begin{verbatim} -#define SND_F_READING 0x0004 /* have a pending read */ -#define SND_F_WRITING 0x0008 /* have a pending write */ -\end{verbatim} -Allowing a single open does not suffice to exclude the possibility -that a process forks and then multiple calls are issued concurrently. -These two flags are used in the generic read/write routines to -prevent concurrent calls of the same type, and serialize calls of -different types for half-duplex devices. These two flags are -generally used in the generic read/write code, and there should be -no need to use them in the device-specific code, unless the read/write -routines are reimplemented. - -\begin{verbatim} -#define SND_F_CLOSING 0x0040 /* a pending close */ -#define SND_F_ABORTING 0x1000 /* a pending abort on write */ -\end{verbatim} -These flags mark special conditions, which should be known to the -DMA routines to shut down the device properly. The {\tt CLOSING} flags -are generally set by a call to {\tt close()} so that DMA transfers are -shut down at the end of the current operation. The {\tt ABORTING} -flags are set in response to user breaks or special {\tt ioctl}'s -such as {\tt PAUSE}, and cause immediate suspension of the output. - -\begin{verbatim} -#define SND_F_STEREO 0x0100 -#define SND_F_XLAT8 0x0400 /* u-law <--> 8-bit unsigned */ -#define SND_F_XLAT16 0x0800 /* u-law <--> 16-bit signed */ -\end{verbatim} -These are generic flags, marking the use of stereo audio and the -need for special translations in order to support {\tt /dev/audio} -on boards which do not have native $\mu$LAW support. In practice, -the latter flags are only used for the SoundBlaster; furthermore, -conversion between $\mu$LAW and 16-bit signed is currently not -implemented (but required to implement full-duplex through {\tt -/dev/audio} on the SB16). - -\begin{verbatim} -#define SND_F_INIT 0x4000 /* changed parameters. need init */ -\end{verbatim} -Finally, this flag marks the need for board reinitialization at the -next convenient time. This is because some parameters (e.g. speed, -channels, etc.) might be changed while an I/O operation is in progress -(e.g. a previous write is being flushed), and the board can only be -reprogrammed at the end of a transfer. This flag helps in supporting -the functionality. In the generic {\tt ioctl} handler, as an example, -all calls which set a parameter update the descriptor, set the flag, -and then invoke the callback function to apply the change. If successful, -the flag will be cleared, otherwise it will stay set for the update to -take place at the next convenient time. - -\subsection{Autoconfiguration} - -The main component of the driver is the file {\tt sound.c} which -contains the autoconfiguration stuff and the main device routines. - -The configuration process occurs as follows (see the following -diagram). - -\begin{verbatim} -pcmprobe(dev) { - foreach (p in supported devices) - if (p->probe(dev) is successful) { - snddev_last_probed = p ; - return 1 ; - } - return 0 ; /* fail */ -} - -pcmattach(dev) { - initialize pcm_info[dev->id_unit] with data from the template, - from snddev_last_probed, and from dev; - call snddev_last_probed->attach(dev); -} - -xxx_probe(dev) { - try to identify the board, possibly updating dev; can use - pcm_info[dev->id_unit] as temporary storage (reset on exit); - return 1 on success, 0 on failure. -} - -xxx_attach(dev) { - initialize board and do the necessary allocation, complete the - info in pcm_info[dev->id_unit] (initialized from the template - and dev) -} -\end{verbatim} -The kernel invokes {\tt pcmprobe()} to detect a board, passing it -the parameters from the configuration line. The routine then scans -the set of supported devices to see if the device is compatible -with the configured unit, and in case invokes the probe routine, -which is passed a pointer to the {\tt isa\_device} structure -describing the device. - -Compatibility is checked using the following rules. If a device -type is specified, only that device is checked for. If the ``device -type'' refers to a class of devices (e.g. all SoundBlaster-like -boards, all MSS-like boards), then all known devices in that class -are probed. Finally, if no device type is specified, then all -devices are probed. Internally, a {\tt snddev\_info} structure is -defined for each known board. For each board class, an array holds -pointers to the descriptors of each board. Finally, an array holds -pointers to the arrays describing each board class. - -The probe routine is not supposed to do any resource allocation, -just to check for the presence of the board. The only allowed side -effect of the probe routine is to modify the content of the {\tt -isa\_device} structure, in case a generic parameter was passed, to -instantiate it to the correct value. If the board-specific probe -routine is successful, so is {\tt pcmprobe()}. This will result in -the invokation of {\tt pcmattach()}, with a pointer to the same -{\tt isa\_device} structure that was used at probe time. - -{\tt pcmattach()} will now copy the {\tt snddev\_info} structure -describing the successfully-probed device into a permanent device -descriptor, fill it up with run-time information, and call the -board-specific attach routine. All the above is only possible -because {\tt pcmprobe()} saves a pointer ({\tt last\_probed}) to -the {\tt snddev\_info} corresponding to the successfully probed -device before returning. - -The board-specific attach routines has the task of configuring the -boards using the supplied parameters. The only parameter passed -to the attach routine is the {\tt isa\_device} pointer. This -structure includes the unit number, so the board-specific can -identify the permanent device descriptor as {\tt pcm\_info[unit]} -(use {\tt midi\_info}, {\tt synth\_info} for other devices). - -Although the return type is {\tt int}, the return value from the -board-specific attach routine is not checked, similarly to what is -done for the generic ISA attach routines. The only action that the -kernel does on a successful attach is to register an interrupt for -the device. As a consequence, a failed attach can be marked by -setting {\tt dev->id\_irq = 0 ;} which has the consequence of not -registering an interrupt for the device. - -\subsection{Main device routines} - -Upon a successful attach, {\tt pcmattach()} registers a {\tt cdevsw} -entry for the audio device. All audio devices share the same routines, -{\tt sndopen, sndclose, sndread, sndwrite, sndioctl, sndselect}, -which perform some generic actions and then invoke the board-specific -routines, if available. The board-specific routines, as well as -the probe and attach routines, have the same interface of a BSD -device driver. This was a design choice meant to simplify development: -one can, in principle, develop a driver outside the audio driver, -and then move it under the audio driver with minimal effort. -Additionally, this approach simplifies life to a kernel developer -since there are no new interfaces to be learned. - -\subsubsection{{\tt sndopen()} and {\tt sndclose()} } - -The generic open and close routines do very little, they basically -check that the unit and device number correspond to a supported -device, and then invoke the (required) open/close routines for -the specific board. There is little more the generic routines can -do, since board vary widely and the open and close actions are very -board-specific. - -\subsubsection{{\tt sndread()} and {\tt sndwrite()} } - -On the contrary, the generic read and write actions are very similar -across all boards. In all cases, checks must be done for valid unit -and device numbers. Then, concurrent operations of the same type -must be denied. Finally, operations of different types on half-duplex -devices must be properly sequenced. After these checks have been -done, the generic read/write code requires to move data between the -user buffer and the DMA buffer, in blocks of appropriate size. - -\subsection{{\tt sndioctl()}} - -The audio driver uses a very large number of {\tt ioctl}'s. Many -of these simply require to read, or set, parameters in the device -descriptor, so they can be implemented by the generic routine for -all boards. Other ioctl calls, instead, require board-specific -actions. We have devised a mechanism to allow board-specific ioctl -to handle the desired set of ioctl calls, leaving the generic -routine the task to deal with other, unhandled, calls. - -The generic routine, after checking device and unit numbers, passes -control to the board-specific routine, if existing. This can do its -own processing and return the error status. If the return value is -{\tt ENOSYS} (error number 78, ``Function not implemented''), then -the generic ioctl {\tt switch} statement is invoked which performs -the generic actions. - -The generic routine tries to implement as much as possible of the -sound calls, leaving little processing to the user code. In -particular, it is assumed that all calls which just read the status -of the device can fetch it directly from the audio descriptor. -Updates to the parameters are done in the generic ioctl by setting -the parameter in the descriptor (when possible, by checking that -values are acceptable), setting the {\tt SND\_F\_INIT} flag and -calling the device-specific {\tt callback()} function, if available. -This in turn will try to perform the necessary action or, if not -possible, leave the flag set for later operation. - - -\subsection{{\tt sndselect()}} - -A properly working select routine is fundamental for a audio device, -because often an application has to handle multiple data streams. -While it is true that an application can determine how long -a read or write call will take to complete, knowing buffer sizes and -sample rates, it is certainly more convenient and efficient to have a -working {\tt select()}. The generic select routine should cover all -needs for devices using DMA. The body of the routine is very -standard. The only noticeable thing is that, when the user specified a -preferred block size through one of the available {\tt ioctl()} calls, -then {\tt select()} will return only when at least one whole block -can be transferred. In other cases (default) one byte will suffice to -make {\tt select()} return (although the system will still choose a blocksize -for DMA transfers, corresponding to 0.25~s of data). - -\subsection{{\tt /dev/sndstat}} - -In the Voxware driver, a special, readonly, status device ({\tt -/dev/sndstat}) was defined (minor number 6) which returned information -on the audio system, including supported devices and configured -devices. In our code, {\tt /dev/sndstat} is supported directly in -the generic routines (in file {\tt sound.c}) and is defined for -every unit returning the same information. In particular, the -status device returns data from a statically allocated 4~KB buffer -({\tt status\_buf}) which is filled-up at the first open with the -function {\tt init\_status()}. - -\section{DMA support} - -DMA handling routines are an important module of the audio code. -All the DMA-related code is in file {\tt dmabuf.c} and is completely -new for this release. - -At the time of this writing, DMA support does not use AUTOMODE. - -Using DMA mode, the sound card requests the transfer of data by -issuing DMA requests to the ISA DMA controller, which in turn -satisfies the request. The ISA DMA controller can be programmed with a -count, so that a signal (TC) is generated after the required amount of data -has been transferred. In ``AUTO'' mode, the ISA DMA controller -reinitializes itself at the end of the transfer. Otherwise, requests -are not served anymore until the controller is reprogrammed. - -In principle, the codec could just forward the TC signal to the -appropriate interrupt line when enabled for DMA transfers. However, -many codec usually have a DMA count register themselves, and generate -an interrupt after the programmed number of bytes is transferred, -in many cases without looking at the value of TC. This makes it -possible to program the ISA DMA controller to use a large buffer, -while letting the codec generate interrupts on smaller (and perhaps -variable size) blocks. - -There are several problems to be dealt with by the DMA code in the -audio driver. First, and most important, we need to avoid overruns -or underruns in transferring data from/to the audio board. This is -more important for (old) boards which do not have a properly sized -on-board FIFO. The second problem is to minimize the latency in -all i/o functions, something which is especially important for -full-duplex applications. - -In the Voxware code, the DMA routines used a buffer partitioned into -a number of fixed-size fragments. The programmer should use ioctls to -select the fragment size which was best suited to his needs, -generally in terms of latency. - -In our code, we use a completely different approach. The DMA buffer -is a single memory block divided into two, variable-size, areas: -{\em READY} and {\em FREE}. Each area is identified by an -offset into the buffer and a length. The data structure describing a -DMA buffer is the following: -\begin{verbatim} -typedef struct _snd_dbuf { - char *buf; /* pointer to the data buffer */ - int bufsize ; /* total buffer size */ - volatile int rp, fp; /* pointers to the ready and free area */ - volatile int dl; /* transfer size */ - volatile int rl, fl; /* length of ready and free areas. */ - int int_count; /* how many interrupts on this channel */ - int chan; /* dma channel */ - int sample_size ; /* 1, 2, 4 */ - struct selinfo sel; /* support for select */ - u_long total; /* total bytes processed */ - u_long prev_total; /* copy of the above when GETxPTR called */ -} snd_dbuf ; -\end{verbatim} -The READY area contains -data ready to be transferred to the codec or to the user, depending -on the direction of the transfer. The FREE area is empty and -available for use. Both READY and FREE can wrap through the end of -the buffer. When the dma engine is in use, it transfers {\tt dl} bytes -from the beginning of the READY area (play) or to the beginning of the -FREE area (record). - -The status of a dma transfer can in many cases be detected from the -value of the length components of the structures. If {\tt dl == 0}, -then the DMA engine is not active. If {\em fl == 0}, a user write will -be blocking or a new DMA read cannot be started. -If {\em rl == 0}, a user read will be blocking, or a new DMA write -cannot be started. A idle dma descriptor has {\tt dl = rl = 0, fl -= bufsize}. - -\subsection{Handling block sizes} - -The purpose of the subdivision of buffers in three areas is that we -can have one pending DMA operation using the DMA area, some space for -the next DMA operation (the READY area for a write, the FREE area for -a READ), and a pending read or write on the third area. - -Obviously we should avoid each of these areas to become too large and -eat all the available buffer space, or too small and make operations -inefficient. We will analize the details in the following two -sections. - -\subsection{DMA write} - -In write operations, the boundary between READY and FREE is advanced -to make room for user data. When possible, a DMA operation is -started by advancing the boundary between DMA and READY by the -amount of data which must be transferred. At the end of the DMA -transfer, the DMA area is shrunk to zero length by extending the -FREE area. These actions occur in the user write routine {\tt -dsp\_write\_body()}, and in the write interrupt service routine -{\tt dsp\_wrintr()}. - -By using a straightforward implementation, the time required for the -user write routine to make data available to the DMA engine would be -proportional to the block size used in the write operation. This is -mainly because of the use of the {\tt uiomove} function in the -routine, possibly followed by a format conversion for translating -between $\mu$-LAW and the native format supported by the codec. -In order to minimize this latency, we do the transfer in blocks of -increasing size, doubling it at each pass. This gives us very low -latency, while at the same time enables the use of large blocks when -needed, without requesting the user to specify a block size. - - -\subsection{DMA read} - -In read operations, a DMA operation needs to be started first, by -advancing the boundary between DMA and FREE by the amount of required -data. When the DMA transfer is complete, the boundary between READY -and DMA is advanced. User reads can be served by removing data from -the READY area and advancing the boundary between FREE and READY -accordingly. These actions occur in the user read routine {\tt -dsp\_read\_body()} and in the read interrupt service routine {\tt -dsp\_rdintr()}. - -Even for DMA read, we move data to user space in blocks of increasing -size, so as to minimize latency in freeing space in the buffer. -However, implementing the read poses another difficulty in deciding -when to return data to a requesting application. Typically, -a read request should return when the requested number of bytes is -available. If data are already available, we can simply copy them -and return. If no data is available and the DMA is inactive, we -can start it with the requested amount of data, and then wait for -the request to complete. However, we are in trouble if the read -request arrives when a DMA operation is already scheduled (a normal -situation) and the transfer length is (possibly much) larger than -the requested amount of data. In this case, the interrupt will only -arrive at the end of the operation, which might take a long time. -This is not a problem with writes, since data are already buffered -for the whole operation. - -\subsection{Why this does not always work...} - -Using single DMA mode avoids that, because of slow interrupt -response, samples are played beyond the end of the buffer, or -capture overwrites some old, still unread, data at the other end -of the buffer. -Single DMA mode has the problem of requiring fast interrupt -response to ensure a smooth data transfer. If the system is not quick -to reinitialize the DMA controller, some samples might be missed. To -mitigate the problem, some controllers provide an internal FIFO which -increases the allowable interrupt response time. As an example, a -codec with 16-samples FIFO at 8~KHz gives 2~ms to reinitialize the -codec itself, which is a reasonable time. -This of course assumes that -the codec makes good use of the FIFO e.g. in the play queue generates -an interrupt when the count goes to 0 even when the FIFO is full. Some -don't. - -Another problem of using single DMA is that the same count is -programmed into the two devices. It appears that some codecs when -working in full duplex have the bad habit of forgetting to count some -cycles, resulting in interrupts not being generated. - -So, to sum up, single DMA mode works very well with well-behaved -codecs and fast systems. When the system becomes slow, late interrupt -response might cause ``clicks'' in the output, or missing samples in -the input. When the codec is buggy, there might be deadlocks because -of missing interrupts (we have only seen these in full duplex on some -cards). - -\subsection{Auto-mode DMA} - -Auto-mode DMA refers to a special operating mode of the DMA engine -which does not require the CPU to reinitialize the channel at the -end of a transfer. Auto DMA can be enabled independently in the -ISA DMA controller and in the sound card. The advantage of auto -mode is that data can be transferred continuously and do not require -the interrupt service routine to have a low latency (if AUTO DMA -is used on both the ISA DMA controller and in the sound card). - -Enabling AUTO DMA in the ISA DMA controller only saves the small time -needed to reinitialize the DMA controller, and can help preventing the -deadlock with broken codecs, since the ISA DMA controller will always -be available to serve DMA requests. A drawback of this approach is -that the codec might try to transfer data beyond the allowed space. - -Enabling AUTO DMA in the codec only does not make any sense. - -To overcome the problem of DMA transfers going beyond the allowed -space, the following strategy can be used. For playback, we must -insure that the region beyond the end of valid data contains data -which do not produce audible effects. As an example, it can be -initialized with replicas of the last sample (1, 2 or 4 bytes -depending on the operating mode). The amount of space to be -initialized in this way should correspond to the expected maximum -interrupt latency. - -For record, the whole buffer should not be used to acquire data, so -that any overrun will just fill a guard region in the buffer, and not -overwrite old data. Again the size of the guard region should be -computed depending on the expected maximum interrupt latency. - -\section{Board-specific routines} - -All board-specific routines are contained in one or more board-specific -source files, and possibly some include files. The board-specific -file(s) should provide as a minimum a template {\tt snddev\_info} -describing the board, and the various functions referenced in the -template and not defined elsewhere. This generally includes the -probe, attach, open, close, the callback, and the interrupt -dispatcher. - -In order to make board-specific files easily readable, we suggest -to use a standard structure for them. As a reference, one can -look at file {\tt sb\_dsp.c} which contains the driver for the -SoundBlaster board. - -The standard structure begins with the copyright. Then the body of the -file is enclosed in the following lines: -\begin{verbatim} -#include <i386/isa/snd/sound.h> -#if NPCM > 0 -... body of the file -#endif /* NPCM > 0 */ -\end{verbatim} -where the {\tt "sound.h"} contains all the generic include files and -definitions for kernel audio modules. It also includes the -config-generated file {\tt "snd.h"} which defines the number of -statically-configured audio devices, NPCM (note that one is required -but often suffices, since PnP devices will use additional unit numbers -up to the maximum of {\tt NPCM\_MAX} which is currently defined as 8. -The total number of audio devices, which can be used and should be -incremented when PnP devices are detected, is held in the global -variable {\tt u\_long nsnd} which is initialized with NPCM. - -Next come the {\tt \#include} for all board-specific include files, -followed by the prototype declaration for all static functions which go -into the {\tt snddev\_info}, and then prototypes for all static -functions in this module. We encourage to make functions static if not -used by other modules, to reduce pollution of the name space. - -After function prototypes, put the (initialized) descriptors for the -board(s) supported by this file, e.g. -\begin{verbatim} -snddev_info sb_op_desc = { - "SoundBlaster", SNDCARD_SB, - sb_probe, sb_attach, - sb_open, sb_close, NULL /* rd */, NULL /* wr */, - sb_dsp_ioctl, sndselect, sbintr, sb_callback, - DSP_BUFFSIZE, - AFMT_U8, -} -\end{verbatim} - -\subsection{{\tt xxx\_probe()}} - -The board-specific probe routine is passed a pointer to a {\tt struct -isa\_device} which contains all information collected from the {\tt -device pcmX} line in the kernel configuration file. The probe code -should do the minimum action to detect the board type and see if -parameters are compatible with the board's features. It returns 1 in -case of success, 0 in case of failure. - -The probe code is -not supposed to do any allocation. If some temporary storage is -necessary, the probe code can use {\tt pcm\_info[dev->id\_unit]}, -which is available, although not initialized at this stage. This -is convenient since, often, the probe and attach routine share the -same code for determining the board type, and can store the detected -information right there. Note however that {\tt -pcm\_info[dev->id\_unit]} will be reinitialized at attach time, so that -data structure should not be regarded as persistent information, but -only as a convenient storage area. - -\subsection{{\tt xxx\_attach()}} - -Same as the probe routine, the attach routine is passed a pointer -to a {\tt struct isa\_device} with info from the configuration -file. This time, however, the generic attach routine will also -initialize {\tt pcm\_info[dev->id\_unit]} copying the template -corresponding to the device identified by the probe routine; -moreover, values from the kernel config line are also copied in -the correct places (in particular, this involves the various fields -which depend on the value of {\tt flags}. - -\subsection{Interrupt dispatcher} - -All audio devices register the same interrupt service routine ({\em -ISR}), {\tt pcmintr}. This merely calls the ISR which is specified -in the device descriptor, passing it the unit number for which the -interrupt has arrived (in practice, one is not aware of the presence -of {\tt pcmintr}, which could also disappear in the future, and -should write the ISR routine as a standard ISR for BSD systems. - -The ISR mainly has to find out the interrupt reason (accessing {\tt -pcm\_info[unit]} to collect board specific parameters) and perform -whatever action is necessary. Usually, it is only necessary to call -{\tt dsp\_wrintr()} or {\tt dsp\_rdintr()}, and possibly clear the -interrupt flag in the codec. - -\subsection{Callback routine} - -The main interface between the generic audio code and the device -specific code is the callback routine which is specified in the device -descriptor. The callback routine is passed an {\tt int} argument which -describes the reason of the callback. The argument is made of a mode -(read and/or write) and a reason. Typically the callback is invoked -from the dma code, upon user writes or interrupt routines. The code in -the callback routine should typically perform codec-specific actions -to start/stop a dma transfer in the desired direction. -As an extension, the callback function can also be called by the -generic routines at open and close times. This only happens if -device-specific open and close are not implemented, and the -functionalities are implemented here. - -Again this is done for convenience, since in many cases the open and -close routines share a common part (e.g. to check for device busy -conditions, etc.) which this way need not to be replicated in -different drivers. - -\subsection{Mixer} - -Sound cards generally have a mixer device, which is in charge of -controlling signal flow, attenuation and filtering on the various -paths. We mutuate the Voxware scheme in this driver, both because it -is reasonably flexible, and for compatibility with existing -applications. In this scheme, each of the possible mixer channels is -associated to a bit in a bitmask. - -Setting levels for a mixer channel generally just requires to write a -value (associated to the level) in some location. Since the number of -bits used by various mixer devices largely differs from board to -board, the Voxware driver uses a description table to map channels -into the appropriate addresses. A table is made of an array of {\tt -mixer\_ent} entries, which are set with the {\tt PMIX\_ENT} and -{\tt MIX\_ENT} macros (all defined in {\tt sound.h}): -entries: - -\begin{verbatim} -struct mixer_def { - u_int regno:7; - u_int polarity:1; - u_int bitoffs:4; - u_int nbits:4; -}; -typedef struct mixer_def mixer_ent; -typedef struct mixer_def mixer_tab[32][2]; - -#define MIX_ENT(name, reg_l, pol_l, pos_l, len_l, reg_r, pol_r, pos_r, len_r) \ - {{reg_l, pol_l, pos_l, len_l}, {reg_r, pol_r, pos_r, len_r}} -#define PMIX_ENT(name, reg_l, pos_l, len_l, reg_r, pos_r, len_r) \ - {{reg_l, 0, pos_l, len_l}, {reg_r, 0, pos_r, len_r}} - -void -change_bits(mixer_tab *t, u_char *regval, int dev, int chn, int newval); -\end{verbatim} -The table is used by {\tt change\_bits()}, which accepts a pointer -to a table, a pointer to the old value of the register, device -(0..31), channel (left or right), and the new value to be set, in -the range 0..100. - -\end{document} diff --git a/sys/i386/isa/snd/misc/README b/sys/i386/isa/snd/misc/README deleted file mode 100644 index e50b041..0000000 --- a/sys/i386/isa/snd/misc/README +++ /dev/null @@ -1,82 +0,0 @@ -Various support files for the new sound driver for FreeBSD. - - audio-voxware.cc - - this is the driver for "vat" (tested with vat 4.0b2 in the - ports distribution) to make things work in full duplex. It - does _not_ use non-blocking i/o, otherwise vat will happily - eat most of your CPU time since select will often return true - even if less than one frame is ready. - - The environment variable AUDIODEV will let you use different - sound cards if you have more than one. It can contain the unit - number (0, 1, 2, ...) or the full pathname. - - As an additional bonus, you can select a fourth input which is - a ulaw file which is written to the network instead of the - input audio data. - - CPU usage on my p5/133 in full duplex, local feedback and - silence suppression (most demanding configuration I believe): - PCM 3.5% - DVI 4.8% - LPC 11 % - GSM 23 % - - auvoxware.c - - this is the driver for "nas" (tested with nas 1.2b5). Works - fine in full duplex. - - linux_a.c - - driver for timidity, a midi-to-pcm converter. Using this program - (and if you have spare cpu cycles) you can play midi files to - /dev/audio without the need for a synthesis device. - - linux.patch - - this is a patch for 2.2.X users for the linux emulator. The - files to correct are in /sys/i386/linux, and this patch - implements a few ioctl which are used by the realvideo player - for linux (rvplayer). In order to use these patches you have - to recompile the linux_mod.o and install it in place as follows - - cd /usr/src/lkm/linux - make - mv linux_mod.o /lkm/linux_mod.o - - pcmio.c - - a simple program to do i/o with the audio device. You can set - on the command line the device, the speed, data format, stereo - or mono... And if you use a bidirectional device, you can play - and record at the same time. - - E.g. - - pcmio -f 1 +rec,stereo,44100,s16 song - - will record from /dev/audio1 stereo,16-bit data to the file "song" - - pcmio +play,stereo,44100,s16,loop 50s:20s song - - will continuosly play 50s from "song" (skipping the first 20s) - to /dev/audio - - pcmio +rec,ulaw - | tee tapefile > /dev/audio - - will record using ulaw (mono at 8KHz, default) to stdout, and - the pipe will both dump things to "tapefile" and to /dev/audio - to listen what you are recording (you could do the same with - "cat..."). - - soundbyte.c - - the audio module for speak_freely - - test.c - - lets you monitor the status of the device (/dev/audio1) by - mmapping the descriptor and dumping to screen the interesting - fields. diff --git a/sys/i386/isa/snd/misc/audio-voxware.cc b/sys/i386/isa/snd/misc/audio-voxware.cc deleted file mode 100644 index 16feb46..0000000 --- a/sys/i386/isa/snd/misc/audio-voxware.cc +++ /dev/null @@ -1,435 +0,0 @@ -/* - * Copyright (c) 1991-1993 Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the Computer Systems - * Engineering Group at Lawrence Berkeley Laboratory. - * 4. Neither the name of the University nor of the Laboratory may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 - * SUCH DAMAGE. - */ - - -/* - * Full Duplex audio module for the new sound driver and full duplex - * cards. Luigi Rizzo, from original sources supplied by Amancio Hasty. - * - * This includes some enhancements: - * - the audio device to use can be in the AUDIODEV env. variable. - * It can be either a unit number or a full pathname; - * - use whatever format is available from the card (included split - * format e.g. for the sb16); - * - limit the maximum size of the playout queue to approx 4 frames; - * this is necessary if the write channel is slower than expected; - * the fix is based on two new ioctls, AIOGCAP and AIONWRITE, - * but the code should compile with the old driver as well. - */ - -#include <osfcn.h> -#include <machine/soundcard.h> -#include "audio.h" -#include "mulaw.h" -#include "Tcl.h" - -#define ULAW_ZERO 0x7f - -extern const u_char lintomulawX[]; - -class VoxWare : public Audio { - public: - VoxWare(); - virtual int FrameReady(); - virtual u_char* Read(); - virtual void Write(u_char *); - virtual void SetRGain(int); - virtual void SetPGain(int); - virtual void OutputPort(int); - virtual void InputPort(int); - virtual void Obtain(); - virtual void Release(); - virtual void RMute(); - virtual void RUnmute(); - virtual int HalfDuplex() const; - protected: - int ext_fd; /* source for external file */ - - u_char* readbuf; - u_short *s16_buf; - - int play_fmt ; -#if defined(AIOGCAP) /* new sound driver */ - int rec_fmt ; /* the sb16 has split format... */ - snd_capabilities soundcaps; -#endif -}; - -static class VoxWareMatcher : public Matcher { -public: - VoxWareMatcher() : Matcher("audio") {} - TclObject* match(const char* fmt) { - if (strcmp(fmt, "voxware") == 0) - return (new VoxWare); - return (0); - } -} linux_audio_matcher; - -VoxWare::VoxWare() -{ - readbuf = new u_char[blksize]; - s16_buf = new u_short[blksize]; - - memset(readbuf, ULAW_ZERO, blksize); - - ext_fd = -1 ; /* no external audio */ - iports = 4; /* number of input ports */ -} - -void -VoxWare::Obtain() -{ - char *thedev; - char buf[64]; - int d = -1; - - if (HaveAudio()) - abort(); - thedev=getenv("AUDIODEV"); - if (thedev==NULL) - thedev="/dev/audio"; - else if ( thedev[0] >= '0' && thedev[0] <= '9' ) { - d = atoi(thedev); - sprintf(buf,"/dev/audio%d", d); - thedev = buf ; - } - fd = open(thedev, O_RDWR ); - thedev=getenv("MIXERDEV"); - if (thedev == NULL) - if (d < 0) - thedev = "/dev/mixer"; - else { - sprintf(buf,"/dev/mixer%d", d); - thedev = buf ; - } - - if (fd >= 0) { - int i = -1 ; -#if defined(AIOGCAP) /* new sound driver */ - i = ioctl(fd, AIOGCAP, &soundcaps); - if (i == 0) { - snd_chan_param pa; - struct snd_size sz; - - pa.play_rate = pa.rec_rate = 8000 ; - pa.play_format = pa.rec_format = AFMT_MU_LAW ; - switch (soundcaps.formats & (AFMT_FULLDUPLEX | AFMT_WEIRD)) { - case AFMT_FULLDUPLEX : - /* - * this entry for cards with decent full duplex. Use s16 - * preferably (some are broken in ulaw) or ulaw or u8 otherwise. - */ - if (soundcaps.formats & AFMT_S16_LE) - pa.play_format = pa.rec_format = AFMT_S16_LE ; - else if (soundcaps.formats & AFMT_MU_LAW) - pa.play_format = pa.rec_format = AFMT_MU_LAW ; - else if (soundcaps.formats & AFMT_U8) - pa.play_format = pa.rec_format = AFMT_U8 ; - else { - printf("sorry, no supported formats\n"); - close(fd); - fd = -1 ; - return; - } - break ; - case AFMT_FULLDUPLEX | AFMT_WEIRD : - /* this is the sb16... */ - if (soundcaps.formats & AFMT_S16_LE) { - pa.play_format = AFMT_U8 ; - pa.rec_format = AFMT_S16_LE; - } else { - printf("sorry, no supported formats\n"); - close(fd); - fd = -1 ; - return; - } - break ; - default : - printf("sorry don't know how to deal with this card\n"); - close (fd); - fd = -1; - break; - } - ioctl(fd, AIOSFMT, &pa); - play_fmt = pa.play_format ; - rec_fmt = pa.rec_format ; - sz.play_size = (play_fmt == AFMT_S16_LE) ? 2*blksize : blksize; - sz.rec_size = (rec_fmt == AFMT_S16_LE) ? 2*blksize : blksize; - ioctl(fd, AIOSSIZE, &sz); - } else -#endif - { /* setup code for old voxware driver */ - } - Audio::Obtain(); - } -} - -/* - * note: HalfDuplex() uses a modified function of the new driver, - * which will return AFMT_FULLDUPLEX set in SNDCTL_DSP_GETFMTS - * for full-duplex devices. In the old driver this was 0 so - * the default is to use half-duplex for them. Note also that I have - * not tested half-duplex operation. - */ -int -VoxWare::HalfDuplex() const -{ - int i; - ioctl(fd, SNDCTL_DSP_GETFMTS, &i); -#if 0 - printf("SNDCTL_DSP_GETFMTS returns 0x%08x %s duplex\n", - i, i & AFMT_FULLDUPLEX ? "full":"half"); -#endif - return (i & AFMT_FULLDUPLEX) ? 0 : 1 ; -} - -void VoxWare::Release() -{ - if (HaveAudio()) { - Audio::Release(); - } -} - -void VoxWare::Write(u_char *cp) -{ - int i = blksize, l; - static int peak = 0; - - if (play_fmt == AFMT_S16_LE) { - for (i=0; i< blksize; i++) - s16_buf[i] = mulawtolin[cp[i]] ; - cp = (u_char *)s16_buf; - i = 2 *blksize ; - } - else if (play_fmt == AFMT_S8) { - for (i=0; i< blksize; i++) { - int x = mulawtolin[cp[i]] ; - x = (x >> 8 ) & 0xff; - cp[i] = (u_char)x ; - } - i = blksize ; - } else if (play_fmt == AFMT_U8) { - /* - * when translating to 8-bit formats, need to implement AGC - * to avoid loss of resolution in the conversion. - * The peak is multiplied by 2^13 - */ - for (i=0; i< blksize; i++) { - int x = mulawtolin[cp[i]] ; -#if 0 /* AGC -- still not complete... */ - if (x < 0) x = -x ; - if (x > peak) peak = ( peak*16 + x - peak ) / 16 ; - else peak = ( peak*8192 + x - peak ) / 8192 ; - if (peak < 128) peak = 128 ; - /* at this point peak is in the range 128..32k - * samples can be scaled and clipped consequently. - */ - x = x * 32768/peak ; - if (x > 32767) x = 32767; - else if (x < -32768) x = -32768; -#endif - x = (x >> 8 ) & 0xff; - x = (x ^ 0x80) & 0xff ; - cp[i] = (u_char)x ; - } - i = blksize ; - } -#if 0 && defined(AIOGCAP) - int queued; - ioctl(fd, AIONWRITE, &queued); - queued = soundcaps.bufsize - queued ; - if (play_fmt == AFMT_S16_LE) { - if (queued > 8*blksize) - i -= 8 ; - } else { - if (queued > 4*blksize) - i -= 4 ; - } -#endif - for ( ; i > 0 ; i -= l) { - l = write(fd, cp, i); - cp += l; - } -} - -u_char* VoxWare::Read() -{ - u_char* cp; - int l=0, l0 = blksize, i = blksize; - static int smean = 0 ; /* smoothed mean to remove DC */ - static int loops = 20 ; - - cp = readbuf; - - if (rec_fmt == AFMT_S16_LE) { - cp = (u_char *)s16_buf; - l0 = i = 2 *blksize ; - } - for ( ; i > 0 ; i -= l ) { - l = read(fd, cp, i); - cp += l ; - } - if (rec_fmt == AFMT_S16_LE) { - for (i=0; i< blksize; i++) { -#if 1 /* remove DC component... */ - int mean = smean >> 13; - int dif = ((short) s16_buf[i]) - mean; - smean += dif ; - readbuf[i] = lintomulawX[ dif & 0x1ffff ] ; -#else - readbuf[i] = lintomulaw[ s16_buf[i] ] ; -#endif - } - } - else if (rec_fmt == AFMT_S8) { - for (i=0; i< blksize; i++) - readbuf[i] = lintomulaw[ readbuf[i]<<8 ] ; - } - else if (rec_fmt == AFMT_U8) { - for (i=0; i< blksize; i++) - readbuf[i] = lintomulaw[ (readbuf[i]<<8) ^ 0x8000 ] ; - } - if (iport == 3) { - l = read(ext_fd, readbuf, blksize); - if (l < blksize) { - lseek(ext_fd, (off_t) 0, 0); - read(ext_fd, readbuf+l, blksize - l); - } - } - return readbuf; -} - -/* - * should check that I HaveAudio() before trying to set gain. - * - * In most mixer devices, there is only a master volume control on - * the capture channel, so the following code does not really work - * as expected. The only (partial) exception is the MIC line, where - * there is generally a 20dB boost which can be enabled or not - * depending on the type of device. - */ -void VoxWare::SetRGain(int level) -{ - double x = level; - level = (int) (x/2.56); - int foo = (level<<8) | level; - if (!HaveAudio()) - Obtain(); - switch (iport) { - case 2: - case 1: - break; - case 0: - if (ioctl(fd, MIXER_WRITE(SOUND_MIXER_MIC), &foo) == -1) - printf("failed to set mic volume \n"); - break; - } - if (ioctl(fd, MIXER_WRITE(SOUND_MIXER_IGAIN), &foo) == -1) - printf("failed set input line volume \n"); - rgain = level; -} - -void VoxWare::SetPGain(int level) -{ - float x = level; - level = (int) (x/2.56); - int foo = (level<<8) | level; - if (ioctl(fd, MIXER_WRITE(SOUND_MIXER_PCM), &foo) == -1) { - printf("failed to output level %d \n", level); - } - pgain = level; -} - -void VoxWare::OutputPort(int p) -{ - oport = p; -} - -void VoxWare::InputPort(int p) -{ - int src = 0; - - if (ext_fd >=0 && p != 3) { - close(ext_fd); - ext_fd = -1 ; - } - - switch(p) { - case 3: - fprintf(stderr,"input from file %s\n", ext_fname); - if (ext_fd == -1) - ext_fd = open(ext_fname, 0); - if (ext_fd != -1) - lseek(ext_fd, (off_t) 0, 0); - break; - case 2: - src = 1 << SOUND_MIXER_LINE; - break; - case 1: /* cd ... */ - src = 1 << SOUND_MIXER_CD; - break; - case 0 : - src = 1 << SOUND_MIXER_MIC; - break; - } - if ( ioctl(fd, SOUND_MIXER_WRITE_RECSRC, &src) == -1 ) { - printf("failed to select input \n"); - p = 0; - } - iport = p; -} - -void VoxWare::RMute() -{ - rmute |= 1; -} - -void VoxWare::RUnmute() -{ - rmute &=~ 1; -} - -/* - * FrameReady must return 0 every so often, or the system will keep - * processing mike data and not other events. - */ -int VoxWare::FrameReady() -{ - int i = 0; - int lim = blksize; - - ioctl(fd, FIONREAD, &i ); - if (rec_fmt == AFMT_S16_LE) lim = 2*blksize; - return (i >= lim) ? 1 : 0 ; -} -/*** end of file ***/ diff --git a/sys/i386/isa/snd/misc/auvoxware.c b/sys/i386/isa/snd/misc/auvoxware.c deleted file mode 100644 index 1ae9316..0000000 --- a/sys/i386/isa/snd/misc/auvoxware.c +++ /dev/null @@ -1,1301 +0,0 @@ -/* - SCCS: @(#) auvoxware.c 11.4 95/04/14 -*/ -/*------------------------------------------------------------------------- - -Copyright (C) 1995 The Santa Cruz Operation, Inc. -All Rights Reserved. - -Permission to use, copy, modify and distribute this software -for any purpose is hereby granted without fee, provided that the -above copyright notice and this notice appear in all copies -and that both the copyright notice and this notice appear in -supporting documentation. SCO makes no representations about -the suitability of this software for any purpose. It is provided -"AS IS" without express or implied warranty. - -SCO DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL SCO BE LIABLE FOR ANY SPECIAL, INDIRECT, -PUNITIVE, CONSEQUENTIAL OR INCIDENTAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, LOSS OF DATA OR LOSS OF -PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. - --------------------------------------------------------------------------*/ -/* - AUVoxConfig additions (sysseh@devetir.qld.gov.au) - 96-01-15 - Put the following keywords in - - minrate - Minimum sampling rate - maxrate - Maximum sampling rate - fragsize - The fragment size - minfrags - Minimum number of frags in queue - maxfrags - Maximum fragments in queue - wordsize - 8 or 16 bit samples - device - What device file to use - numchans - Mono (1) or stereo (2) - debug - Output messages during operation - verbose - Be chatty about config - inputsection - Next lot of specs are for input - outputsection - Next specs are for output - end - End an input or output section -*/ -/* - SCO Modification History: - S005, 24-Apr-95, shawnm@sco.com - base # of driver buffer fragments on data rate - S004, 12-Apr-95, shawnm@sco.com - finish integration of ausco.c, fix setitimer calls - S003, 28-Mar-95, shawnm@sco.com, sysseh@devetir.qld.gov.au - incorporate patch for stereo/mono mixing from Stephen Hocking - S002, 21-Mar-95, shawnm@sco.com - incorporate signal handling and audio block/unblock from ausco.c - S001, 21-Mar-95, shawnm@sco.com, sysseh@devetir.qld.gov.au - SYSSEH incorporate parts of patch from Stephen Hocking -*/ -/* - * Copyright 1993 Network Computing Devices, Inc. Copyright (C) Siemens - * Nixdorf Informationssysteme AG 1993 - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name Network Computing Devices, Inc. or - * Siemens Nixdorf Informationssysteme AG not be used in advertising or - * publicity pertaining to distribution of this software without specific, - * written prior permission. - * - * THIS SOFTWARE IS PROVIDED `AS-IS'. NETWORK COMPUTING DEVICES, INC. AND - * SIEMENS NIXDORF INFORMATIONSSYSTEME AG DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR - * NONINFRINGEMENT. IN NO EVENT SHALL NETWORK COMPUTING DEVICES, INC. NOR - * SIEMENS NIXDORF INFORMATIONSSYSTEME AG BE LIABLE FOR ANY DAMAGES - * WHATSOEVER, INCLUDING SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES, - * INCLUDING LOSS OF USE, DATA, OR PROFITS, EVEN IF ADVISED OF THE - * POSSIBILITY THEREOF, AND REGARDLESS OF WHETHER IN AN ACTION IN CONTRACT, - * TORT OR NEGLIGENCE, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - * - * $NCDId: @(#)auvoxware.c,v 1.10 1996/04/24 17:04:19 greg Exp $ - * - * Copyright (C) Siemens Nixdorf Informationssysteme AG 1993 All rights reserved - */ - -/* - * Originally from the merge of auvoxware by Amancio Hasty (hasty@netcom.com) - * & auvoxsvr4 by Stephen Hocking (sysseh@devetir.qld.gov.au). - * 16bit fixes and Linux patches supplied by Christian - * Schlichtherle (s_schli@ira.uka.de). - * - * BUGS: - * - When the soundcard can do only 8 bit recording, "aurecord" records - * twice as long as it should. Is this our fault? - * - * TODO: - * - Adapt the buffer sizes to the current sampling rate, - * so that we can record/play high quality audio samples without - * swallows/pauses. - * Note that setting the buffer size to a fixed maximum will not work, - * because it causes playing at slow sample rate to pause. :-( - * I already tried to do this, but it seems that the rest of the server - * code doesn't recognize the changed buffer sizes. Any help in doing - * this is welcome! - * [chris] - * - Support a second input channel for stereo sampling, - * so that microphone sampling is done on the mono channel - * while line sampling is done on the stereo channel. - * [chris] - * - * CHANGELOG: - * - 94/7/2: - * Completely rewrote this file. Features: - * + Makes use of two sound cards if available. - * So you can concurrently record and play samples. - * + Tested to work with all combinations of 8/16 bit, mono/stereo - * sound card sampling modes. - * + Uses a stereo input channel if hardware supports this. - * + Can play stereo samples on mono sound cards (but who cares?). - * + Always uses the highest possible audio quality, i.e. 8/16 bit and - * mono/stereo parameters are fixed while only the sampling rate is - * variable. This reduces swallows and pauses to the (currently) - * unavoidable minimum while consuming a little bit more cpu time. - * + Format conversion stuff is pushed back to the rest of the server code. - * Only mono/stereo conversion is done here. - * + Debugging output uses indentation. - * [chris] - */ - -#include <stdio.h> -#include "config.h" - -FILE *yyin; - -static char *searchpath = CONFSEARCHPATH; - -#if defined(DEBUGDSPOUT) || defined(DEBUGDSPIN) -int dspin, dspout; -#endif - -# define PRMSG(x, a, b) \ - if (doDebug) { \ - fprintf(stderr, "auvoxware.c: %*s", debug_msg_indentation, ""); \ - fprintf(stderr, (x), (a), (b)); \ - fflush(stderr); \ - } -# define IDENTMSG (debug_msg_indentation += 2) -# define UNIDENTMSG (debug_msg_indentation -= 2) - -static int doDebug = 0; -int beVerbose = 0; -static int debug_msg_indentation = 0; - -#include <errno.h> -#include "dixstruct.h" /* for RESTYPE */ -#include "os.h" /* for xalloc/xfree and NULL */ -#include <fcntl.h> -#include <sys/time.h> -#include <sys/param.h> -#include <assert.h> - -#ifdef __FreeBSD__ -#include <machine/soundcard.h> -#include <machine/pcaudioio.h> -#else -#include <sys/soundcard.h> -#endif - -#include <audio/audio.h> -#include <audio/Aproto.h> -#include "au.h" - -#ifdef sco -static AuBool scoAudioBlocked = AuFalse; -#endif /* sco */ - -static AuBool processFlowEnabled; - -#define SERVER_CLIENT 0 - -#define MIN_MINIBUF_SAMPLES 256 -#define MAX_MINIBUF_SAMPLES 1024 /* Must be a power of 2 */ - -#define auDefaultInputGain AuFixedPointFromSum(50, 0) -#define auDefaultOutputGain AuFixedPointFromSum(50, 0) - -#define PhysicalOneTrackBufferSize \ - PAD4(auMinibufSamples * auNativeBytesPerSample * 1) -#define PhysicalTwoTrackBufferSize \ - PAD4(auMinibufSamples * auNativeBytesPerSample * 2) - -/* VOXware sound driver mixer control variables */ - -static int Letsplay; -static int level[100]; -static int mixerfd; /* The mixer device */ -static int devmask = 0; /* Bitmask for supported mixer devices */ -static int recsrc = 0; /* Currently selected recording sources */ -static int recmask = 0; /* Supported recording sources */ -static int stereodevs = 0; /* Channels supporting stereo */ - -static char *labels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS; - -/* end of VOXware driver mixer control variables */ - -int ParseError = 0; /* Did we fail to parse conf. file? */ - -SndStat *confStat; - -SndStat sndStatIn = -{ - -1, - 16, - 2, - 0, - 4000, - 44100, - 256, - 3, - 32, - "/dev/dsp", - 0 -}, sndStatOut = -{ - -1, - 16, - 2, - 0, - 4000, - 44100, - 256, - 3, - 32, - "/dev/dsp", - 0 -}; - -static AuUint8 *auOutputMono, - *auOutputStereo, - *auInput; - -static ComponentPtr monoInputDevice, - stereoInputDevice, - monoOutputDevice, - stereoOutputDevice; - -extern AuInt32 auMinibufSamples; - - -#define auPhysicalOutputChangableMask AuCompDeviceGainMask - -#define auPhysicalOutputValueMask \ - (AuCompCommonAllMasks \ - | AuCompDeviceMinSampleRateMask \ - | AuCompDeviceMaxSampleRateMask \ - | AuCompDeviceGainMask \ - | AuCompDeviceLocationMask \ - | AuCompDeviceChildrenMask) - -#define auPhysicalInputChangableMask \ - (AuCompDeviceGainMask | AuCompDeviceLineModeMask) - -#define auPhysicalInputValueMask \ - (AuCompCommonAllMasks \ - | AuCompDeviceMinSampleRateMask \ - | AuCompDeviceMaxSampleRateMask \ - | AuCompDeviceLocationMask \ - | AuCompDeviceGainMask \ - | AuCompDeviceChildrenMask) - -static void setPhysicalOutputGain(); -static void setPhysicalInputGainAndLineMode(); - -void setDebugOn () -{ - doDebug = 1; -} - -void setVerboseOn () -{ - beVerbose = 1; -} - -#ifdef sco - -AuBlock -AuBlockAudio() -{ - scoAudioBlocked = AuTrue; - return 0; -} - -void -AuUnBlockAudio(AuBlock id) -{ - scoAudioBlocked = AuFalse; -} - -#endif /* sco */ - -static int createServerComponents(auServerDeviceListSize, - auServerBucketListSize, - auServerRadioListSize, - auServerMinRate, - auServerMaxRate) -AuUint32 *auServerDeviceListSize, - *auServerBucketListSize, - *auServerRadioListSize, - *auServerMinRate, - *auServerMaxRate; -{ - AuDeviceID stereo, mono; - ComponentPtr d, *p; - int i; - AuUint8 formatIn, - formatOut; - AuUint32 bytesPerSampleIn, - bytesPerSampleOut; - static AuBool initialized = AuFalse; - extern RESTYPE auComponentType; - extern ComponentPtr *auServerDevices, /* array of devices */ - *auServerBuckets, /* array of server owned buckets */ - *auServerRadios, /* array of server owned radios */ - auDevices, /* list of all devices */ - auBuckets, /* list of all buckets */ - auRadios; /* list of all radios */ - extern AuUint32 auNumServerDevices, /* number of devices */ - auNumActions, /* number of defined actions */ - auNumServerBuckets, /* number of server owned buckets */ - auNumServerRadios; /* number of server owned radios */ - - PRMSG("createServerComponents(...);\n", 0, 0); - IDENTMSG; - - *auServerMinRate = aumax(sndStatIn.minSampleRate, - sndStatOut.minSampleRate); - *auServerMaxRate = aumax(sndStatIn.maxSampleRate, - sndStatOut.maxSampleRate); - - auNumServerDevices = *auServerDeviceListSize - = *auServerBucketListSize - = *auServerRadioListSize - = 0; - - formatIn = (sndStatIn.wordSize == 16) ? AuFormatLinearSigned16LSB - : AuFormatLinearUnsigned8; - formatOut = (sndStatOut.wordSize == 16) ? AuFormatLinearSigned16LSB - : AuFormatLinearUnsigned8; - - bytesPerSampleIn = sndStatIn.wordSize / 8; - bytesPerSampleOut = sndStatOut.wordSize / 8; - - AU_ALLOC_DEVICE(d, 1, 0); - d->id = FakeClientID(SERVER_CLIENT); - d->changableMask = auPhysicalOutputChangableMask; - d->valueMask = auPhysicalOutputValueMask; - d->kind = AuComponentKindPhysicalOutput; - d->use = AuComponentUseExportMask; - d->access = AuAccessExportMask | AuAccessListMask; - d->format = formatOut; - d->numTracks = 1; - d->description.type = AuStringLatin1; - d->description.string = "Mono Channel Output"; - d->description.len = strlen(d->description.string); - d->minSampleRate = sndStatOut.minSampleRate; - d->maxSampleRate = sndStatOut.maxSampleRate; - d->location = AuDeviceLocationCenterMask | AuDeviceLocationInternalMask; - d->numChildren = 0; - d->minibuf = auOutputMono; - d->minibufSize = d->numTracks * bytesPerSampleOut * auMinibufSamples; - d->physicalDeviceMask = PhysicalOutputMono; - AU_ADD_DEVICE(d); - - monoOutputDevice = d; - - AU_ALLOC_DEVICE(d, 2, 1); - d->id = FakeClientID(SERVER_CLIENT); - d->changableMask = auPhysicalOutputChangableMask; - d->valueMask = auPhysicalOutputValueMask; - d->kind = AuComponentKindPhysicalOutput; - d->use = AuComponentUseExportMask; - d->access = AuAccessExportMask | AuAccessListMask; - d->format = formatOut; - d->numTracks = 2; - d->description.type = AuStringLatin1; - d->description.string = "Stereo Channel Output"; - d->description.len = strlen(d->description.string); - d->minSampleRate = sndStatOut.minSampleRate; - d->maxSampleRate = sndStatOut.maxSampleRate; - d->location = AuDeviceLocationCenterMask | AuDeviceLocationInternalMask; - d->numChildren = 1; - d->children = (AuID *) ((AuUint8 *) d + PAD4(sizeof(ComponentRec))); - d->childSwap = (char *) (d->children + d->numChildren); - d->children[0] = monoOutputDevice->id; - d->minibuf = auOutputStereo; - d->minibufSize = d->numTracks * bytesPerSampleOut * auMinibufSamples; - d->physicalDeviceMask = PhysicalOutputStereo; - AU_ADD_DEVICE(d); - - stereoOutputDevice = d; - - AU_ALLOC_DEVICE(d, (sndStatIn.isStereo + 1), 0); - d->id = FakeClientID(SERVER_CLIENT); - d->changableMask = auPhysicalInputChangableMask; - d->valueMask = auPhysicalInputValueMask; - d->kind = AuComponentKindPhysicalInput; - d->use = AuComponentUseImportMask; - d->access = AuAccessImportMask | AuAccessListMask; - d->format = formatIn; - d->numTracks = sndStatIn.isStereo + 1; - d->description.type = AuStringLatin1; - d->description.string = (sndStatIn.isStereo) ? "Stereo Channel Input" - : "Mono Channel Input"; - d->description.len = strlen(d->description.string); - d->minSampleRate = sndStatOut.minSampleRate; - d->maxSampleRate = sndStatOut.maxSampleRate; - d->location = AuDeviceLocationRightMask | AuDeviceLocationLeftMask - | AuDeviceLocationExternalMask; - d->numChildren = 0; - d->gain = auDefaultInputGain; - d->minibuf = auInput; - d->minibufSize = d->numTracks * bytesPerSampleIn * auMinibufSamples; - d->physicalDeviceMask = (sndStatIn.isStereo) ? PhysicalInputStereo - : PhysicalInputMono; - AU_ADD_DEVICE(d); - - monoInputDevice = d; /* Should have two input devices - FIXME */ - stereoInputDevice = d; - - /* set the array of server devices */ - if (!(auServerDevices = (ComponentPtr *) aualloc(sizeof(ComponentPtr) - * auNumServerDevices))) { - UNIDENTMSG; - return AuBadAlloc; - } - - p = auServerDevices; - d = auDevices; - - while (d) { - *p++ = d; - d = d->next; - } - - if (!initialized) { - initialized = AuTrue; - setPhysicalOutputGain(auDefaultOutputGain); - setPhysicalInputGainAndLineMode(auDefaultInputGain, 0); - } - - UNIDENTMSG; - - return AuSuccess; -} - -static AuInt32 setTimer(rate) -AuInt32 rate; -{ - AuInt16 timer_ms; - AuInt32 foo; - struct itimerval ntval, otval; - - PRMSG("setTimer(rate = %d);\n", rate, 0); - IDENTMSG; - - /* change timer according to new sample rate */ - if (rate == 0) { /* Disable timer case */ - ntval.it_value.tv_sec = ntval.it_value.tv_usec = 0; - ntval.it_interval.tv_sec = ntval.it_interval.tv_usec = 0; - timer_ms = 0x7fff; - } else { - timer_ms = (auMinibufSamples * 500) / rate; - ntval.it_interval.tv_sec = 0; - ntval.it_interval.tv_usec = timer_ms * 1000; - ntval.it_value.tv_sec = 0; - ntval.it_value.tv_usec = timer_ms *1000 / 2 ; - } - foo = setitimer(ITIMER_REAL, &ntval, &otval); - - UNIDENTMSG; - - return timer_ms; -} - - -#ifdef sco -static void -oneMoreTick() -{ - struct itimerval ntval, otval; - int foo; - - ntval.it_interval.tv_sec = 0; - ntval.it_interval.tv_usec = 0; - ntval.it_value.tv_sec = 0; - ntval.it_value.tv_usec = 10; - foo = setitimer(ITIMER_REAL, &ntval, &otval); -} -#endif /* sco */ - - -static void -setFragmentSize(sndStatPtr) -SndStat *sndStatPtr; -{ - int fragarg, i, j; - int datarate, numfrags; - - datarate = sndStatPtr->curSampleRate; - if (sndStatPtr->isStereo) - datarate *= 2; - if (sndStatPtr->wordSize == 16) - datarate *= 2; - datarate /= 2; /* half second */ - numfrags = datarate / MAX_MINIBUF_SAMPLES; - if (numfrags < sndStatPtr->minFrags) - numfrags = sndStatPtr->minFrags; - else if (numfrags > sndStatPtr->maxFrags) - numfrags = sndStatPtr->maxFrags; - - j = MAX_MINIBUF_SAMPLES; - for (i = 0; j; i++) /* figure out what power of 2 MAX_MINIBUF_SAMPLES is */ - j = j >> 1; - fragarg = (numfrags << 16) | i; /* numfrags of size MAX_MINIBUF_SAMPLES */ - ioctl(sndStatPtr->fd, SNDCTL_DSP_SETFRAGMENT, &fragarg); -} - - -static AuUint32 setSampleRate(rate) -AuUint32 rate; -{ - int numSamplesIn, numSamplesOut; - AuBlock l; - - PRMSG("setSampleRate(rate = %d);\n", rate, 0); - IDENTMSG; - - l = AuBlockAudio(); - - if (sndStatOut.curSampleRate != rate) { - sndStatOut.curSampleRate = rate; - -#if defined(SNDCTL_DSP_SETFRAGMENT) - setFragmentSize(&sndStatOut); -#endif - ioctl(sndStatOut.fd, SNDCTL_DSP_SYNC, NULL); - ioctl(sndStatOut.fd, SNDCTL_DSP_SPEED, &(sndStatOut.curSampleRate)); - } - - if (sndStatIn.fd == sndStatOut.fd) - sndStatIn = sndStatOut; - else if (sndStatIn.curSampleRate != rate) { - sndStatIn.curSampleRate = rate; - -#if defined(SNDCTL_DSP_SETFRAGMENT) - setFragmentSize(&sndStatIn); -#endif - ioctl(sndStatIn.fd, SNDCTL_DSP_SYNC, NULL); - ioctl(sndStatIn.fd, SNDCTL_DSP_SPEED, &(sndStatIn.curSampleRate)); - } - -#if defined(AUDIO_DRAIN) - if (sndStatOut.isPCSpeaker) - ioctl (sndStatOut.fd, AUDIO_DRAIN, 0); -#endif - - AuUnBlockAudio(l); - - setTimer(rate); - - UNIDENTMSG; - - return sndStatOut.curSampleRate; -} - - -static void serverReset() -{ - PRMSG("serverReset();\n", 0, 0); - IDENTMSG; - - setTimer(0); -#ifndef sco - signal(SIGALRM, SIG_IGN); -#endif /* sco */ - - PRMSG("Audio Synchronisation...", 0, 0); - -#if defined(AUDIO_DRAIN) - if (sndStatOut.isPCSpeaker) - ioctl(sndStatOut.fd,AUDIO_DRAIN,0); - else { -#endif - - ioctl(sndStatIn.fd, SNDCTL_DSP_SYNC, NULL); - if (sndStatOut.fd != sndStatIn.fd) - ioctl(sndStatOut.fd, SNDCTL_DSP_SYNC, NULL); - -#if defined(AUDIO_DRAIN) - } -#endif - - if (doDebug) { - fputs(" done.\n", stderr); - fflush(stderr); - } - UNIDENTMSG; -} - - -static void -#ifdef sco -intervalProc(int i) -#else -intervalProc() -#endif /* sco */ -{ - extern void AuProcessData(); - -#ifndef sco - signal(SIGALRM, SIG_IGN); - - if (processFlowEnabled) - { - AuProcessData(); - signal(SIGALRM, intervalProc); - } -#else - if (!scoAudioBlocked && processFlowEnabled) - AuProcessData(); -#endif /* sco */ -} - -/** - * Gains are mapped thusly: - * - * Software s 0 - 100 - * Hardware h 0 - 100 -**/ - -static void -setPhysicalOutputGain(gain) - AuFixedPoint gain; -{ - AuInt32 g = AuFixedPointIntegralAddend(gain); - AuInt32 i, gusvolume; - - - if (g > 100) - g = 100; - if (g < 0) - g = 0; - Letsplay = g; - gusvolume = g | (g << 8); - if (mixerfd != -1) - i = ioctl(mixerfd, MIXER_WRITE(SOUND_MIXER_PCM), &gusvolume); -} - -static AuFixedPoint -getPhysicalOutputGain() -{ - AuInt16 outputGain; - - outputGain = Letsplay; - - return AuFixedPointFromSum(outputGain, 0); -} - -static void -setPhysicalInputGainAndLineMode(gain, lineMode) - AuFixedPoint gain; - AuUint8 lineMode; -{ - AuInt16 g = AuFixedPointIntegralAddend(gain); - AuInt16 inputAttenuation; - AuInt16 zero = 0; - AuInt32 params[4]; - - if (g < 100) - inputAttenuation = g; - else - inputAttenuation = 100; - - inputAttenuation = inputAttenuation << 8 | inputAttenuation; - - if (lineMode == AuDeviceLineModeHigh) { - ioctl(mixerfd, MIXER_WRITE(SOUND_MIXER_MIC), &inputAttenuation); - ioctl(mixerfd, MIXER_WRITE(SOUND_MIXER_LINE), &zero); - } - - if (lineMode == AuDeviceLineModeLow) { - ioctl(mixerfd, MIXER_WRITE(SOUND_MIXER_LINE), &inputAttenuation); - ioctl(mixerfd, MIXER_WRITE(SOUND_MIXER_MIC), &zero); - } -} - -static void enableProcessFlow() -{ - AuUint8 *p; - - PRMSG("enableProcessFlow();\n", 0, 0); - -#ifdef sco - if (!processFlowEnabled) - { -#endif /* sco */ - - processFlowEnabled = AuTrue; - -#ifndef sco - signal(SIGALRM, intervalProc); -#else - setTimer(sndStatOut.curSampleRate); -#endif /* sco */ - -#ifdef sco - } -#endif /* sco */ -} - -static void disableProcessFlow() -{ - -#ifndef sco - signal(SIGALRM, SIG_IGN); -#endif /* sco */ - - PRMSG("disableProcessFlow();\n", 0, 0); - -#ifdef sco - if (processFlowEnabled) - { -#endif /* sco */ - - ioctl(sndStatOut.fd, SNDCTL_DSP_SYNC, NULL); -#ifndef sco - ioctl(sndStatOut.fd, SNDCTL_DSP_SPEED, &sndStatOut.curSampleRate); -#endif /* sco */ - - if (sndStatOut.fd != sndStatIn.fd) - { - ioctl(sndStatIn.fd, SNDCTL_DSP_SYNC, NULL); -#ifndef sco - ioctl(sndStatIn.fd, SNDCTL_DSP_SPEED, &sndStatIn.curSampleRate); -#endif /* sco */ - } - -#ifdef sco - oneMoreTick(); -#endif - - processFlowEnabled = AuFalse; - -#ifdef sco - } -#endif /* sco */ -} - - -#if defined(__GNUC__) && !defined(linux) -inline -#endif -static void monoToStereoLinearSigned16LSB(numSamples) -AuUint32 numSamples; -{ - AuInt16 *s = (AuInt16*)monoOutputDevice->minibuf; - AuInt16 *d = (AuInt16*)stereoOutputDevice->minibuf; - - while (numSamples--) { - *d++ = *s; - *d++ = *s++; - } -} - -#if defined(__GNUC__) && !defined(linux) -inline -#endif -static void monoToStereoLinearUnsigned8(numSamples) -AuUint32 numSamples; -{ - AuUint8 *s = (AuUint8*)monoOutputDevice->minibuf; - AuUint8 *d = (AuUint8*)stereoOutputDevice->minibuf; - - while (numSamples--) { - *d++ = *s; - *d++ = *s++; - } -} - -static void writePhysicalOutputsMono() -{ - AuBlock l; - void* buf; - int bufSize; - - if (sndStatOut.isStereo) { - switch (monoOutputDevice->format) { - case AuFormatLinearSigned16LSB: - monoToStereoLinearSigned16LSB(monoOutputDevice->minibufSamples); - break; - - case AuFormatLinearUnsigned8: - monoToStereoLinearUnsigned8(monoOutputDevice->minibufSamples); - break; - - default: - /* check createServerComponents(...)! */ - assert(0); - } - - buf = stereoOutputDevice->minibuf; - bufSize = stereoOutputDevice->bytesPerSample - * monoOutputDevice->minibufSamples; - } else { - buf = monoOutputDevice->minibuf; - bufSize = monoOutputDevice->bytesPerSample - * monoOutputDevice->minibufSamples; - } - - l = AuBlockAudio(); - { int b, w; - char *p = buf ; - for (b=bufSize; b>0; b -= w) { - w = write(sndStatOut.fd, p, b); - p += w ; - } - } - -#ifdef DEBUGDSPOUT - { - char tempbuf[80]; - - sprintf(tempbuf, "\nwriteMono buf: %d size: %d\n", buf, bufSize); - write(dspout, tempbuf, strlen(tempbuf)); - write(dspout, buf, bufSize); - } -#endif /* DEBUGDSPOUT */ - - AuUnBlockAudio(l); -} - -#if defined(__GNUC__) && !defined(linux) -inline -#endif -static void stereoToMonoLinearSigned16LSB(numSamples) -AuUint32 numSamples; -{ - AuInt16 *s = (AuInt16*)stereoOutputDevice->minibuf; - AuInt16 *d = (AuInt16*)monoOutputDevice->minibuf; - - while (numSamples--) { - *d++ = (s[0] + s[1]) / 2; - s += 2; - } -} - -#if defined(__GNUC__) && !defined(linux) -inline -#endif -static void stereoToMonoLinearUnsigned8(numSamples) -AuUint32 numSamples; -{ - AuUint8 *s = (AuUint8*)stereoOutputDevice->minibuf; - AuUint8 *d = (AuUint8*)monoOutputDevice->minibuf; - - while (numSamples--) { - *d++ = (s[0] + s[1]) / 2; - s += 2; - } -} - -static void writePhysicalOutputsStereo() -{ - AuBlock l; - void* buf; - int bufSize; - - if (sndStatOut.isStereo) { - buf = stereoOutputDevice->minibuf; - bufSize = stereoOutputDevice->bytesPerSample - * stereoOutputDevice->minibufSamples; - } else { - switch (stereoOutputDevice->format) { - case AuFormatLinearSigned16LSB: - stereoToMonoLinearSigned16LSB(stereoOutputDevice->minibufSamples); - break; - - case AuFormatLinearUnsigned8: - stereoToMonoLinearUnsigned8(stereoOutputDevice->minibufSamples); - break; - - default: - /* check createServerComponents(...)! */ - assert(0); - } - - buf = monoOutputDevice->minibuf; - bufSize = monoOutputDevice->bytesPerSample - * stereoOutputDevice->minibufSamples; - } - - l = AuBlockAudio(); - { int b, w; - char *p = buf ; - for (b=bufSize; b>0; b -= w) { - w = write(sndStatOut.fd, p, b); - p += w ; - } - } - -#ifdef DEBUGDSPOUT - { - char tempbuf[80]; - - sprintf(tempbuf, "\nwriteStereo buf: %d size: %d\n", buf, bufSize); - write(dspout, tempbuf, strlen(tempbuf)); - write(dspout, buf, bufSize); - } -#endif /* DEBUGDSPOUT */ - - AuUnBlockAudio(l); -} - -static void writePhysicalOutputsBoth() -{ - AuInt16 *m = (AuInt16 *) monoOutputDevice->minibuf; - AuInt16 *p, *s; - AuUint8 *m8 = (AuUint8 *) monoOutputDevice->minibuf; - AuUint8 *p8, *s8; - AuUint32 max = aumax(monoOutputDevice->minibufSamples, - stereoOutputDevice->minibufSamples); - AuUint32 i; - - switch (stereoOutputDevice->format) { - case AuFormatLinearSigned16LSB: - p = s = (AuInt16 *) stereoOutputDevice->minibuf; - - for (i = 0; i < max; i++) { - *p++ = (*m + *s++) / 2; - *p++ = (*m++ + *s++) / 2; - } - break; - - case AuFormatLinearUnsigned8: - p8 = s8 = (AuUint8 *) stereoOutputDevice->minibuf; - - for (i = 0; i < max; i++) { - *p8++ = (*m8 + *s8++) / 2; - *p8++ = (*m8++ + *s8++) / 2; - } - break; - - default: - assert(0); - } - - stereoOutputDevice->minibufSamples = max; - - writePhysicalOutputsStereo(); -} - -static void readPhysicalInputs() -{ - AuBlock l; - char *p = stereoInputDevice->minibuf ; - int b,r ; - - /* Should make use of two input devices - FIXME */ - l = AuBlockAudio(); - for (b = stereoInputDevice->bytesPerSample * auMinibufSamples; - b > 0 ; b -= r) { - r = read(sndStatIn.fd, p, b); - p += r ; - } - -#ifdef DEBUGDSPIN - { - char tempbuf[80]; - sprintf(tempbuf, "\nreadInputs buf: %d size: %d\n", - stereoInputDevice->minibuf, - stereoInputDevice->bytesPerSample * auMinibufSamples); - write(dspin, tempbuf, strlen(tempbuf)); - write(dspin, stereoInputDevice->minibuf, - stereoInputDevice->bytesPerSample * auMinibufSamples); - } -#endif /* DEBUGDSPIN */ - - AuUnBlockAudio(l); -} - -static void -noop() -{ -} - -static void -setWritePhysicalOutputFunction(flow, funct) - CompiledFlowPtr flow; - void (**funct) (); -{ - AuUint32 mask = flow->physicalDeviceMask; - - if ((mask & (PhysicalOutputMono | PhysicalOutputStereo)) == - (PhysicalOutputMono | PhysicalOutputStereo)) - *funct = writePhysicalOutputsBoth; - else if (mask & PhysicalOutputMono) - *funct = writePhysicalOutputsMono; - else if (mask & PhysicalOutputStereo) - *funct = writePhysicalOutputsStereo; - else - *funct = noop; -} - -/* - * Setup soundcard at maximum audio quality. - */ - -#ifdef __FreeBSD__ -#define NO_16_BIT_SAMPLING -#endif - -static void setupSoundcard(sndStatPtr) -SndStat* sndStatPtr; -{ - int samplesize; - - PRMSG("setupSoundcard(...);\n", 0, 0); - IDENTMSG; - - if (beVerbose) - if (sndStatPtr == &sndStatOut) - fprintf (stderr, "++ Setting up Output device\n"); - else - fprintf (stderr, "++ Setting up Input device\n"); - - if (sndStatPtr->isPCSpeaker) { - if (beVerbose) - fprintf(stderr, "+++ Device is a PC speaker\n"); - sndStatPtr->curSampleRate = sndStatPtr->maxSampleRate - = sndStatPtr->minSampleRate = 8000; - sndStatPtr->isStereo = 0; - sndStatPtr->wordSize = 8; - } - else { - if (beVerbose) - fprintf(stderr, "+++ requesting wordsize of %d, ", sndStatPtr->wordSize); - if (ioctl(sndStatPtr->fd, SNDCTL_DSP_SAMPLESIZE, &sndStatPtr->wordSize) - || sndStatPtr->wordSize != 16) { - sndStatPtr->wordSize = 8; - ioctl(sndStatPtr->fd, SNDCTL_DSP_SAMPLESIZE, &sndStatPtr->wordSize); - } - if (beVerbose) - fprintf(stderr, "got %d\n", sndStatPtr->wordSize); - - if (beVerbose) - fprintf(stderr, "+++ requesting %d channel(s), ", sndStatPtr->isStereo + 1); - if (ioctl(sndStatPtr->fd, SNDCTL_DSP_STEREO, &sndStatPtr->isStereo) == -1 - || !sndStatPtr->isStereo) { - sndStatPtr->isStereo = 0; - ioctl(sndStatPtr->fd, SNDCTL_DSP_STEREO, &sndStatPtr->isStereo); - } - if (beVerbose) - fprintf(stderr, "got %d channel(s)\n", sndStatPtr->isStereo + 1); - - if (beVerbose) - fprintf (stderr, "+++ Requesting minimum sample rate of %d, ", sndStatPtr->minSampleRate); - ioctl(sndStatPtr->fd, SNDCTL_DSP_SPEED, &sndStatPtr->minSampleRate); - if (beVerbose) - fprintf (stderr, "got %d\n", sndStatPtr->minSampleRate); - - if (beVerbose) - fprintf (stderr, "+++ Requesting maximum sample rate of %d, ", sndStatPtr->maxSampleRate); - ioctl(sndStatPtr->fd, SNDCTL_DSP_SPEED, &sndStatPtr->maxSampleRate); - if (beVerbose) - fprintf (stderr, "got %d\n", sndStatPtr->maxSampleRate); - - sndStatPtr->curSampleRate = sndStatPtr->maxSampleRate; - - } - -#if defined(SNDCTL_DSP_SETFRAGMENT) - setFragmentSize(sndStatPtr); -#endif - - UNIDENTMSG; -} - - -#ifdef sco -static AuBool -scoInterrupts() -{ - struct sigaction act; - - act.sa_handler = intervalProc; - act.sa_flags = 0; - sigemptyset(&act.sa_mask); - sigaddset(&act.sa_mask, SIGALRM); - if (sigaction(SIGALRM, &act, (struct sigaction *)NULL) == -1) - { - ErrorF("sigaction SIGALRM"); - return FALSE; - } - - return TRUE; -} -#endif /* sco */ - -/* -* Find the config file -*/ - -static FILE *openConfigFile (char *path) -{ - static char buf[1024]; - FILE *config; - - strcat (buf, path); - strcat (buf, "AUVoxConfig"); - if ((config = fopen (buf, "r")) != NULL) - return config; - else - return NULL; -} - - -AuBool AuInitPhysicalDevices() -{ - static AuBool AL_initialized = AuFalse; - static AuUint8 *physicalBuffers; - int fd; - AuUint32 physicalBuffersSize; - extern AuUint8 *auPhysicalOutputBuffers; - extern AuUint32 auPhysicalOutputBuffersSize; - extern void AuProcessData(); -#if defined(AUDIO_GETINFO) - audio_info_t spkrinf; -#endif - - PRMSG("AuInitPhysicalDevices();\n", 0, 0); - IDENTMSG; - - /* - * create the input and output ports - */ - if (!AL_initialized) { - int fd; - AuInt32 i; - - AL_initialized = AuTrue; - - if ((yyin = openConfigFile (CONFSEARCHPATH)) != NULL) - yyparse(); - - if ((fd = open(sndStatOut.device, O_RDWR, 0)) == -1) { - UNIDENTMSG; - return AuFalse; - } -#if defined(AUDIO_GETINFO) - if (sndStatOut.isPCSpeaker) { - ioctl(fd, AUDIO_GETINFO, &spkrinf); - spkrinf.play.encoding = AUDIO_ENCODING_RAW; - ioctl(fd, AUDIO_SETINFO, &spkrinf); - } -#endif - -#ifdef DEBUGDSPOUT - dspout = open("/tmp/dspout", O_RDWR | O_CREAT, 00666); -#endif -#ifdef DEBUGDSPIN - dspin = open("/tmp/dspin", O_RDWR | O_CREAT, 00666); -#endif - - sndStatOut.fd = fd; - - if ((fd = open(sndStatIn.device, O_RDONLY, 0)) != -1) - sndStatIn.fd = fd; - else - sndStatIn.fd = sndStatOut.fd; - - setupSoundcard(&sndStatOut); - if (sndStatOut.fd != sndStatIn.fd) - setupSoundcard(&sndStatIn); - - if (!sndStatOut.isPCSpeaker) { - if ((mixerfd = open("/dev/mixer", O_RDONLY, 0)) == -1) { - UNIDENTMSG; - return AuFalse; - } - - if (ioctl(mixerfd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) { - close(mixerfd); - mixerfd = -1; - } else { - if (ioctl(mixerfd, SOUND_MIXER_READ_RECMASK, &recmask) == -1) { - return AuFalse; - } - - { - /* Enable all used recording sources ( mic & line ) and - * control which is active via level setting later. There - * should be a better way to do this! - */ - int mask = SOUND_MASK_MIC | SOUND_MASK_LINE; /* enable these */ - mask &= recmask; /* if supported */ - if (ioctl(mixerfd, SOUND_MIXER_WRITE_RECSRC, &mask) == -1) { - return AuFalse; - } - } - - if (ioctl(mixerfd, SOUND_MIXER_READ_RECSRC, &recsrc) == -1) { - UNIDENTMSG; - return AuFalse; - } - - if (ioctl(mixerfd, SOUND_MIXER_READ_STEREODEVS, &stereodevs) == -1) { - UNIDENTMSG; - return AuFalse; - } - - /* get all sound levels */ - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { - if ((1 << i) & devmask) { - - if (ioctl(mixerfd, MIXER_READ(i), &level[i]) == -1) { - UNIDENTMSG; - return AuFalse; - } - } - } - - } - } - } - - if (physicalBuffers) - aufree(physicalBuffers); - - auMinibufSamples = MAX_MINIBUF_SAMPLES; - - /* the output buffers need to be twice as large for output range checking */ - physicalBuffersSize = - PhysicalTwoTrackBufferSize + /* mono/stereo input */ - PhysicalOneTrackBufferSize * 2 + /* mono output */ - PhysicalTwoTrackBufferSize * 2; /* stereo output */ - - if (!(physicalBuffers = (AuUint8 *) aualloc(physicalBuffersSize))) { - UNIDENTMSG; - return AuFalse; - } - - auInput = physicalBuffers; - auOutputMono = auInput + PhysicalTwoTrackBufferSize; - auOutputStereo = auOutputMono + 2 * PhysicalOneTrackBufferSize; - - auPhysicalOutputBuffers = auOutputMono; - auPhysicalOutputBuffersSize = physicalBuffersSize - - PhysicalTwoTrackBufferSize; - - /* - * Call AuProcessData() in signal handler often enough to drain the - * input devices and keep the output devices full at the current - * sample rate. - */ - - processFlowEnabled = AuFalse; - -#ifdef sco - if (!scoInterrupts()) - { - return AuFalse; - } -#else - signal(SIGALRM, intervalProc); -#endif /* sco */ - - setTimer(0); - - AuRegisterCallback(AuCreateServerComponentsCB, createServerComponents); - AuRegisterCallback(AuSetPhysicalOutputGainCB, setPhysicalOutputGain); - AuRegisterCallback(AuGetPhysicalOutputGainCB, getPhysicalOutputGain); - AuRegisterCallback(AuSetPhysicalInputGainAndLineModeCB, - setPhysicalInputGainAndLineMode); - AuRegisterCallback(AuEnableProcessFlowCB, enableProcessFlow); - AuRegisterCallback(AuDisableProcessFlowCB, disableProcessFlow); - AuRegisterCallback(AuReadPhysicalInputsCB, readPhysicalInputs); - AuRegisterCallback(AuSetWritePhysicalOutputFunctionCB, - setWritePhysicalOutputFunction); - - AuRegisterCallback(AuSetSampleRateCB, setSampleRate); - - /* bogus resource so we can have a cleanup function at server reset */ - AddResource(FakeClientID(SERVER_CLIENT), - CreateNewResourceType(serverReset), 0); - - UNIDENTMSG; - - return AuTrue; -} diff --git a/sys/i386/isa/snd/misc/files.i386 b/sys/i386/isa/snd/misc/files.i386 deleted file mode 100644 index bc12938..0000000 --- a/sys/i386/isa/snd/misc/files.i386 +++ /dev/null @@ -1,240 +0,0 @@ -# This file tells config what files go into building a kernel, -# files marked standard are always included. -# -# $Id: files.i386,v 1.141.2.11 1997/04/04 04:35:46 gibbs Exp $ -# -aic7xxx_asm optional ahc device-driver \ - dependency "$S/dev/aic7xxx/*.[chyl]" \ - compile-with "cd $S/dev/aic7xxx; make obj; make BINDIR=${.CURDIR} all install" \ - no-obj no-implicit-rule \ - clean "aic7xxx_asm" -# -aic7xxx_{seq,reg}.h optional ahc device-driver \ - compile-with "./aic7xxx_asm ${INCLUDES} -o aic7xxx_seq.h -r aic7xxx_reg.h $S/dev/aic7xxx/aic7xxx.seq" \ - no-obj no-implicit-rule before-depend \ - clean "aic7xxx_seq.h aic7xxx_reg.h" \ - dependency "$S/dev/aic7xxx/aic7xxx.{reg,seq} aic7xxx_asm" -# -linux_genassym optional compat_linux \ - dependency "$S/i386/linux/linux_genassym.c $S/i386/linux/linux.h" \ - compile-with "${CC} ${CFLAGS} ${PARAM} -UKERNEL -o $@ $<" \ - no-obj no-implicit-rule \ - clean "linux_genassym" -# -linux_assym.h optional compat_linux \ - dependency "linux_genassym" \ - compile-with "./linux_genassym > $@" \ - no-obj no-implicit-rule before-depend \ - clean "linux_assym.h" -# -i386/scsi/93cx6.c optional ahc device-driver -i386/apm/apm.c optional apm device-driver -i386/apm/apm_setup.s optional apm -i386/eisa/3c5x9.c optional ep device-driver -i386/eisa/aic7770.c optional ahc device-driver \ - dependency "aic7xxx_reg.h $S/i386/eisa/aic7770.c" -i386/eisa/aha1742.c optional ahb device-driver -i386/eisa/bt74x.c optional bt device-driver -i386/eisa/eisaconf.c optional eisa -i386/eisa/if_vx_eisa.c optional vx device-driver -i386/eisa/if_fea.c optional fea device-driver -i386/i386/autoconf.c standard device-driver -i386/i386/cons.c standard -i386/i386/db_disasm.c optional ddb -i386/i386/db_interface.c optional ddb -i386/i386/db_trace.c optional ddb -i386/i386/i386-gdbstub.c optional ddb -i386/i386/exception.s standard -i386/i386/identcpu.c standard -i386/i386/in_cksum.c optional inet -# locore.s needs to be handled in Makefile to put it first. Otherwise it's -# now normal. -# i386/i386/locore.s standard -i386/i386/machdep.c standard -i386/i386/math_emulate.c optional math_emulate -i386/i386/mem.c standard -i386/i386/microtime.s standard -i386/i386/perfmon.c optional perfmon profiling-routine -i386/i386/perfmon.c optional perfmon -i386/i386/pmap.c standard -i386/i386/procfs_machdep.c standard -i386/i386/support.s standard -i386/i386/swtch.s standard -i386/i386/sys_machdep.c standard -i386/i386/trap.c standard -i386/i386/userconfig.c optional userconfig -i386/i386/vm_machdep.c standard -i386/ibcs2/ibcs2_fcntl.c optional ibcs2 -i386/ibcs2/ibcs2_stat.c optional ibcs2 -i386/ibcs2/ibcs2_ipc.c optional ibcs2 -i386/ibcs2/ibcs2_msg.c optional ibcs2 -i386/ibcs2/ibcs2_misc.c optional ibcs2 -i386/ibcs2/ibcs2_other.c optional ibcs2 -i386/ibcs2/ibcs2_signal.c optional ibcs2 -i386/ibcs2/ibcs2_ioctl.c optional ibcs2 -i386/ibcs2/ibcs2_socksys.c optional ibcs2 -i386/ibcs2/ibcs2_sysi86.c optional ibcs2 -i386/ibcs2/ibcs2_util.c optional ibcs2 -i386/ibcs2/ibcs2_isc.c optional ibcs2 -i386/ibcs2/ibcs2_isc_sysent.c optional ibcs2 -i386/ibcs2/ibcs2_xenix.c optional ibcs2 -i386/ibcs2/ibcs2_xenix_sysent.c optional ibcs2 -i386/ibcs2/ibcs2_errno.c optional ibcs2 -i386/ibcs2/ibcs2_sysent.c optional ibcs2 -i386/ibcs2/ibcs2_sysvec.c optional ibcs2 -i386/ibcs2/imgact_coff.c optional ibcs2 -i386/isa/aha1542.c optional aha device-driver -i386/isa/aic6360.c optional aic device-driver -i386/isa/b004.c optional bqu device-driver -i386/isa/bt5xx-445.c optional bt device-driver -i386/isa/clock.c standard -i386/isa/cronyx.c optional cx device-driver -i386/isa/ctx.c optional ctx device-driver -i386/isa/cx.c optional cx device-driver -i386/isa/cy.c optional cy device-driver -i386/isa/diskslice_machdep.c standard -i386/isa/elink.c optional ep device-driver -i386/isa/elink.c optional ie device-driver -i386/isa/fd.c optional fd device-driver -i386/isa/ft.c optional ft device-driver -i386/isa/gpib.c optional gp device-driver -i386/isa/asc.c optional asc device-driver -i386/isa/gsc.c optional gsc device-driver -i386/isa/if_ar.c optional ar device-driver -i386/isa/if_cx.c optional cx device-driver -i386/isa/if_ed.c optional ed device-driver -i386/isa/if_eg.c optional eg device-driver -i386/isa/if_el.c optional el device-driver -i386/isa/if_ep.c optional ep device-driver -i386/isa/if_ex.c optional ex device-driver -i386/isa/if_fe.c optional fe device-driver -i386/isa/if_ie.c optional ie device-driver -i386/isa/if_ix.c optional ix device-driver -i386/isa/if_le.c optional le device-driver -i386/isa/if_lnc.c optional lnc device-driver -i386/isa/if_sr.c optional sr device-driver -i386/isa/if_ze.c optional ze device-driver -i386/isa/if_zp.c optional zp device-driver -i386/isa/isa.c optional isa device-driver -i386/isa/istallion.c optional stli device-driver -i386/isa/joy.c optional joy device-driver -i386/isa/kbdio.c optional psm device-driver -i386/isa/kbdio.c optional sc device-driver -i386/isa/kbdio.c optional vt device-driver -i386/isa/lpt.c optional lpt device-driver -i386/isa/labpc.c optional labpc device-driver -i386/isa/mcd.c optional mcd device-driver -i386/isa/mse.c optional mse device-driver -i386/isa/ncr5380.c optional nca device-driver -i386/isa/npx.c optional npx device-driver -i386/isa/pcaudio.c optional pca device-driver -i386/isa/matcd/matcd.c optional matcd device-driver -i386/isa/pcibus.c optional pci device-driver -i386/isa/pcicx.c optional ze device-driver -i386/isa/pcicx.c optional zp device-driver -i386/isa/pcvt/pcvt_drv.c optional vt device-driver -i386/isa/pcvt/pcvt_ext.c optional vt device-driver -i386/isa/pcvt/pcvt_kbd.c optional vt device-driver -i386/isa/pcvt/pcvt_out.c optional vt device-driver -i386/isa/pcvt/pcvt_sup.c optional vt device-driver -i386/isa/pcvt/pcvt_vtf.c optional vt device-driver -i386/isa/pnp.c optional pnp device-driver -i386/isa/prof_machdep.c optional profiling-routine -i386/isa/psm.c optional psm device-driver -i386/isa/qcam.c optional qcam device-driver -i386/isa/qcamio.c optional qcam device-driver -i386/isa/random_machdep.c standard -i386/isa/rc.c optional rc device-driver -i386/isa/scd.c optional scd device-driver -i386/isa/seagate.c optional sea device-driver -i386/isa/si.c optional si device-driver -i386/isa/si_code.c optional si device-driver -i386/isa/sio.c optional sio device-driver -i386/isa/snd/sound.c optional pcm device-driver -i386/isa/snd/dmabuf.c optional pcm device-driver -i386/isa/snd/ad1848.c optional pcm device-driver -i386/isa/snd/sb_dsp.c optional pcm device-driver -i386/isa/snd/clones.c optional pcm device-driver -i386/isa/spigot.c optional spigot device-driver -i386/isa/spkr.c optional speaker device-driver -i386/isa/stallion.c optional stl device-driver -i386/isa/syscons.c optional sc device-driver -i386/isa/tw.c optional tw device-driver -i386/isa/ultra14f.c optional uha device-driver -i386/isa/wd.c optional wdc device-driver -i386/isa/wd.c optional wd device-driver -i386/isa/atapi.c optional atapi device-driver -i386/isa/wcd.c optional wcd device-driver -i386/isa/wd7000.c optional wds device-driver -i386/isa/wt.c optional wt device-driver -i386/linux/imgact_linux.c optional compat_linux -i386/linux/linux_dummy.c optional compat_linux -i386/linux/linux_file.c optional compat_linux -i386/linux/linux_ioctl.c optional compat_linux -i386/linux/linux_ipc.c optional compat_linux -i386/linux/linux_locore.s optional compat_linux \ - dependency "linux_assym.h" -i386/linux/linux_misc.c optional compat_linux -i386/linux/linux_signal.c optional compat_linux -i386/linux/linux_socket.c optional compat_linux -i386/linux/linux_stats.c optional compat_linux -i386/linux/linux_sysent.c optional compat_linux -i386/linux/linux_sysvec.c optional compat_linux -i386/linux/linux_util.c optional compat_linux -i386/scsi/aic7xxx.c optional ahc device-driver \ - dependency "aic7xxx_{reg,seq}.h" -i386/scsi/bt.c optional bt device-driver -libkern/bcd.c standard -libkern/divdi3.c standard -libkern/inet_ntoa.c standard -libkern/index.c standard -libkern/mcount.c optional profiling-routine -libkern/moddi3.c standard -libkern/qdivrem.c standard -libkern/qsort.c standard -libkern/random.c standard -libkern/scanc.c standard -libkern/skpc.c standard -libkern/strcat.c standard -libkern/strcmp.c standard -libkern/strcpy.c standard -libkern/strlen.c standard -libkern/strncmp.c standard -libkern/strncpy.c standard -libkern/udivdi3.c standard -libkern/umoddi3.c standard -gnu/i386/fpemul/div_small.s optional gpl_math_emulate -gnu/i386/fpemul/errors.c optional gpl_math_emulate -gnu/i386/fpemul/fpu_arith.c optional gpl_math_emulate -gnu/i386/fpemul/fpu_aux.c optional gpl_math_emulate -gnu/i386/fpemul/fpu_entry.c optional gpl_math_emulate -gnu/i386/fpemul/fpu_etc.c optional gpl_math_emulate -gnu/i386/fpemul/fpu_trig.c optional gpl_math_emulate -gnu/i386/fpemul/get_address.c optional gpl_math_emulate -gnu/i386/fpemul/load_store.c optional gpl_math_emulate -gnu/i386/fpemul/poly_2xm1.c optional gpl_math_emulate -gnu/i386/fpemul/poly_atan.c optional gpl_math_emulate -gnu/i386/fpemul/poly_div.s optional gpl_math_emulate -gnu/i386/fpemul/poly_l2.c optional gpl_math_emulate -gnu/i386/fpemul/poly_mul64.s optional gpl_math_emulate -gnu/i386/fpemul/poly_sin.c optional gpl_math_emulate -gnu/i386/fpemul/poly_tan.c optional gpl_math_emulate -gnu/i386/fpemul/polynomial.s optional gpl_math_emulate -gnu/i386/fpemul/reg_add_sub.c optional gpl_math_emulate -gnu/i386/fpemul/reg_compare.c optional gpl_math_emulate -gnu/i386/fpemul/reg_constant.c optional gpl_math_emulate -gnu/i386/fpemul/reg_div.s optional gpl_math_emulate -gnu/i386/fpemul/reg_ld_str.c optional gpl_math_emulate -gnu/i386/fpemul/reg_mul.c optional gpl_math_emulate -gnu/i386/fpemul/reg_norm.s optional gpl_math_emulate -gnu/i386/fpemul/reg_round.s optional gpl_math_emulate -gnu/i386/fpemul/reg_u_add.s optional gpl_math_emulate -gnu/i386/fpemul/reg_u_div.s optional gpl_math_emulate -gnu/i386/fpemul/reg_u_mul.s optional gpl_math_emulate -gnu/i386/fpemul/reg_u_sub.s optional gpl_math_emulate -gnu/i386/fpemul/wm_shrx.s optional gpl_math_emulate -gnu/i386/fpemul/wm_sqrt.s optional gpl_math_emulate -gnu/i386/isa/dgb.c optional dgb device-driver -gnu/i386/isa/nic3008.c optional nic device-driver -gnu/i386/isa/nic3009.c optional nnic device-driver -pci/wd82371.c optional wd device-driver diff --git a/sys/i386/isa/snd/misc/linux.patch b/sys/i386/isa/snd/misc/linux.patch deleted file mode 100644 index aacfcbc..0000000 --- a/sys/i386/isa/snd/misc/linux.patch +++ /dev/null @@ -1,41 +0,0 @@ ---- linux.h.orig Tue Dec 3 16:47:28 1996 -+++ linux.h Mon Nov 17 00:05:29 1997 -@@ -491,6 +491,9 @@ - #define LINUX_SNDCTL_DSP_GETOSPACE 0x500C - #define LINUX_SNDCTL_DSP_GETISPACE 0x500D - #define LINUX_SNDCTL_DSP_NONBLOCK 0x500E -+#define LINUX_SNDCTL_DSP_GETCAPS 0x500F -+#define LINUX_SNDCTL_DSP_GETIPTR 0x5011 -+#define LINUX_SNDCTL_DSP_GETOPTR 0x5012 - #define LINUX_SOUND_MIXER_WRITE_VOLUME 0x4d00 - #define LINUX_SOUND_MIXER_WRITE_BASS 0x4d01 - #define LINUX_SOUND_MIXER_WRITE_TREBLE 0x4d02 ---- linux_ioctl.c.orig Sat Nov 9 22:10:15 1996 -+++ linux_ioctl.c Mon Nov 17 10:20:14 1997 -@@ -691,6 +691,26 @@ - args->cmd = SNDCTL_DSP_NONBLOCK; - return ioctl(p, (struct ioctl_args *)args, retval); - -+ case LINUX_SNDCTL_DSP_GETCAPS: -+ args->cmd = SNDCTL_DSP_GETCAPS; -+ return ioctl(p, (struct ioctl_args *)args, retval); -+ -+ case LINUX_SNDCTL_DSP_GETIPTR: -+ args->cmd = SNDCTL_DSP_GETIPTR; -+ return ioctl(p, (struct ioctl_args *)args, retval); -+ -+ case LINUX_SNDCTL_DSP_GETOPTR: -+ args->cmd = SNDCTL_DSP_GETOPTR; -+ { int a= ioctl(p, (struct ioctl_args *)args, retval); -+ struct count_info *p = (struct count_info *)(args->arg); -+#if 0 -+ p->bytes += 128 ; -+ uprintf("GETOPTR bytes %d blk %d ptr %d\n", -+ p->bytes, p->blocks, p->ptr); -+#endif -+ return a; -+ } -+ - case LINUX_SOUND_MIXER_WRITE_VOLUME: - args->cmd = SOUND_MIXER_WRITE_VOLUME; - return ioctl(p, (struct ioctl_args *)args, retval); diff --git a/sys/i386/isa/snd/misc/linux_a.c b/sys/i386/isa/snd/misc/linux_a.c deleted file mode 100644 index 3a86aad..0000000 --- a/sys/i386/isa/snd/misc/linux_a.c +++ /dev/null @@ -1,238 +0,0 @@ -/* - * TiMidity -- Experimental MIDI to WAVE converter Copyright (C) 1995 Tuukka - * Toivonen <toivonen@clinet.fi> - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 675 - * Mass Ave, Cambridge, MA 02139, USA. - * - * linux_audio.c - * - * Functions to play sound on the VoxWare audio driver (Linux or FreeBSD) - * - */ - -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> - -#ifdef linux -#include <sys/ioctl.h> /* new with 1.2.0? Didn't need this under - * 1.1.64 */ -#include <linux/soundcard.h> -#endif - -#ifdef __FreeBSD__ -#include <stdio.h> -#include <machine/soundcard.h> -#endif - -#include "config.h" -#include "output.h" -#include "controls.h" - -static int open_output(void); /* 0=success, 1=warning, -1=fatal - * error */ -static void close_output(void); -static void output_data(int32 * buf, int32 count); -static void flush_output(void); -static void purge_output(void); - -/* export the playback mode */ - -#define dpm linux_play_mode - -PlayMode dpm = { - DEFAULT_RATE, PE_16BIT | PE_SIGNED, - -1, - {0}, /* default: get all the buffer fragments you - * can */ - "Linux dsp device", 'd', - "/dev/dsp", - open_output, - close_output, - output_data, - flush_output, - purge_output -}; - - -/*************************************************************************/ -/* - * We currently only honor the PE_MONO bit, the sample rate, and the number - * of buffer fragments. We try 16-bit signed data first, and then 8-bit - * unsigned if it fails. If you have a sound device that can't handle either, - * let me know. - */ - -static int -open_output(void) -{ - int fd, tmp, i, warnings = 0; - - /* Open the audio device */ - fd = open(dpm.name, O_RDWR /* | O_NDELAY */); - if (fd < 0) { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s", - dpm.name, sys_errlist[errno]); - return -1; - } - /* They can't mean these */ - dpm.encoding &= ~(PE_ULAW | PE_BYTESWAP); - - - /* - * Set sample width to whichever the user wants. If it fails, try the - * other one. - */ - - i = tmp = (dpm.encoding & PE_16BIT) ? 16 : 8; - if (dpm.encoding & PE_16BIT) { - int fmt = AFMT_S16_LE ; - - if (ioctl(fd, SNDCTL_DSP_SETFMT, &fmt) < 0 || fmt != AFMT_S16_LE) { - fmt = AFMT_U8 ; - if (ioctl(fd, SNDCTL_DSP_SETFMT, &fmt) < 0 || fmt != AFMT_U8) { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "%s doesn't support 16- or 8-bit sample width", - dpm.name); - close(fd); - return -1; - } - ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, - "Sample width adjusted to %d bits", tmp); - dpm.encoding ^= PE_16BIT; - warnings = 1; - } - } - if (dpm.encoding & PE_16BIT) - dpm.encoding |= PE_SIGNED; - else - dpm.encoding &= ~PE_SIGNED; - - - /* - * Try stereo or mono, whichever the user wants. If it fails, try the - * other. - */ - - i = tmp = (dpm.encoding & PE_MONO) ? 0 : 1; - if ((ioctl(fd, SNDCTL_DSP_STEREO, &tmp) < 0) || tmp != i) { - i = tmp = (dpm.encoding & PE_MONO) ? 1 : 0; - - if ((ioctl(fd, SNDCTL_DSP_STEREO, &tmp) < 0) || tmp != i) { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "%s doesn't support mono or stereo samples", - dpm.name); - close(fd); - return -1; - } - if (tmp == 0) - dpm.encoding |= PE_MONO; - else - dpm.encoding &= ~PE_MONO; - ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, "Sound adjusted to %sphonic", - (tmp == 0) ? "mono" : "stereo"); - warnings = 1; - } - /* Set the sample rate */ - - tmp = dpm.rate; - if (ioctl(fd, SNDCTL_DSP_SPEED, &tmp) < 0) { - ctl->cmsg(CMSG_ERROR, VERB_NORMAL, - "%s doesn't support a %d Hz sample rate", - dpm.name, dpm.rate); - close(fd); - return -1; - } - if (tmp != dpm.rate) { - dpm.rate = tmp; - ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, - "Output rate adjusted to %d Hz", dpm.rate); - warnings = 1; - } - /* Older VoxWare drivers don't have buffer fragment capabilities */ -#ifdef SNDCTL_DSP_SETFRAGMENT - /* Set buffer fragments (in extra_param[0]) */ - - tmp = 2+ AUDIO_BUFFER_BITS ; - if (!(dpm.encoding & PE_MONO)) - tmp++; - if (dpm.encoding & PE_16BIT) - tmp++; - tmp |= (dpm.extra_param[0] << 16); - i = tmp; - if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &tmp) < 0) { - ctl->cmsg(CMSG_WARNING, VERB_NORMAL, - "%s doesn't support %d-byte buffer fragments", dpm.name, (1 << i)); - /* - * It should still work in some fashion. We should use a secondary - * buffer anyway -- 64k isn't enough. - */ - warnings = 1; - } -#else - if (dpm.extra_param[0]) { - ctl->cmsg(CMSG_WARNING, VERB_NORMAL, - "%s doesn't support buffer fragments", dpm.name); - warnings = 1; - } -#endif - - dpm.fd = fd; - - return warnings; -} - -static void -output_data(int32 * buf, int32 count) -{ - char *p; - int res, l; - - if (!(dpm.encoding & PE_MONO)) - count *= 2; /* Stereo samples */ - - if (dpm.encoding & PE_16BIT) { - /* Convert data to signed 16-bit PCM */ - s32tos16(buf, count); - res = count*2; - } else { - /* Convert to 8-bit unsigned and write out. */ - s32tou8(buf, count); - res = count ; - } - for (p = buf ; res > 0 ; res -= l ) { - l = write(dpm.fd, p, res); - if (l < 0) return ; - p += l ; - } -} - -static void -close_output(void) -{ - close(dpm.fd); -} - -static void -flush_output(void) -{ - ioctl(dpm.fd, SNDCTL_DSP_SYNC); -} - -static void -purge_output(void) -{ - ioctl(dpm.fd, SNDCTL_DSP_RESET); -} diff --git a/sys/i386/isa/snd/misc/mmap_test.c b/sys/i386/isa/snd/misc/mmap_test.c deleted file mode 100644 index f9e8b3e..0000000 --- a/sys/i386/isa/snd/misc/mmap_test.c +++ /dev/null @@ -1,278 +0,0 @@ -/* - * This is a simple program which demonstrates use of mmapped DMA buffer - * of the sound driver directly from application program. - * - * This sample program works (currently) only with Linux, FreeBSD and BSD/OS - * (FreeBSD and BSD/OS require OSS version 3.8-beta16 or later. - * - * Note! Don't use mmapped DMA buffers (direct audio) unless you have - * very good reasons to do it. Programs using this feature will not - * work with all soundcards. GUS (GF1) is one of them (GUS MAX works). - * - * This program requires version 3.5-beta7 or later of OSS - * (3.8-beta16 or later in FreeBSD and BSD/OS). - */ - -#include <stdio.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/types.h> -#include <sys/mman.h> -#include <sys/soundcard.h> -#include <sys/time.h> - -main() -{ - int fd, sz, fsz, i, tmp, n, l, have_data=0, nfrag; - int caps; - - int sd, sl=0, sp; - - unsigned char data[500000], *dp = data; - - struct buffmem_desc imemd, omemd; - caddr_t buf; - struct timeval tim; - - unsigned char *op; - - struct audio_buf_info info; - - int frag = 0xffff000c; /* Max # fragments of 2^13=8k bytes */ - - fd_set writeset; - - close(0); - if ((fd=open("/dev/dsp", O_RDWR, 0))==-1) - { - perror("/dev/dsp"); - exit(-1); - } -/* - * Then setup sampling parameters. Just sampling rate in this case. - */ - - tmp = 48000; - ioctl(fd, SNDCTL_DSP_SPEED, &tmp); - printf("Speed set to %d\n", tmp); - -/* - * Load some test data. - */ - - sl = sp = 0; - if ((sd=open("smpl", O_RDONLY, 0))!=-1) - { - sl = read(sd, data, sizeof(data)); - printf("%d bytes read from file.\n", sl); - close(sd); - } - else perror("smpl"); - - if (ioctl(fd, SNDCTL_DSP_GETCAPS, &caps)==-1) - { - perror("/dev/dsp"); - fprintf(stderr, "Sorry but your sound driver is too old\n"); - exit(-1); - } - -/* - * Check that the device has capability to do this. Currently just - * CS4231 based cards will work. - * - * The application should also check for DSP_CAP_MMAP bit but this - * version of driver doesn't have it yet. - */ -/* ioctl(fd, SNDCTL_DSP_SETSYNCRO, 0); */ - -/* - * You need version 3.5-beta7 or later of the sound driver before next - * two lines compile. There is no point to modify this program to - * compile with older driver versions since they don't have working - * mmap() support. - */ - if (!(caps & DSP_CAP_TRIGGER) || - !(caps & DSP_CAP_MMAP)) - { - fprintf(stderr, "Sorry but your soundcard can't do this\n"); - exit(-1); - } - -/* - * Select the fragment size. This is propably important only when - * the program uses select(). Fragment size defines how often - * select call returns. - */ - - ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag); - -/* - * Compute total size of the buffer. It's important to use this value - * in mmap() call. - */ - - if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info)==-1) - { - perror("GETOSPACE"); - exit(-1); - } - - sz = info.fragstotal * info.fragsize; - fsz = info.fragsize; - -/* - * Call mmap(). - * - * IMPORTANT NOTE!!!!!!!!!!! - * - * Full duplex audio devices have separate input and output buffers. - * It is not possible to map both of them at the same mmap() call. The buffer - * is selected based on the prot argument in the following way: - * - * - PROT_READ (alone) selects the input buffer. - * - PROT_WRITE (alone) selects the output buffer. - * - PROT_WRITE|PROT_READ together select the output buffer. This combination - * is required in BSD to make the buffer accessible. With just PROT_WRITE - * every attempt to access the returned buffer will result in segmentation/bus - * error. PROT_READ|PROT_WRITE is also permitted in Linux with OSS version - * 3.8-beta16 and later (earlier versions don't accept it). - * - * Non duplex devices have just one buffer. When an application wants to do both - * input and output it's recommended that the device is closed and re-opened when - * switching between modes. PROT_READ|PROT_WRITE can be used to open the buffer - * for both input and output (with OSS 3.8-beta16 and later) but the result may be - * unpredictable. - */ - - if ((buf=mmap(NULL, sz, PROT_WRITE, MAP_FILE|MAP_SHARED, fd, 0))==(caddr_t)-1) - { - perror("mmap (write)"); - exit(-1); - } - printf("mmap (out) returned %08x\n", buf); - op=buf; - -/* - * op contains now a pointer to the DMA buffer - */ - -/* - * Then it's time to start the engine. The driver doesn't allow read() and/or - * write() when the buffer is mapped. So the only way to start operation is - * to togle device's enable bits. First set them off. Setting them on enables - * recording and/or playback. - */ - - tmp = 0; - ioctl(fd, SNDCTL_DSP_SETTRIGGER, &tmp); - printf("Trigger set to %08x\n", tmp); - -/* - * It might be usefull to write some data to the buffer before starting. - */ - - tmp = PCM_ENABLE_OUTPUT; - ioctl(fd, SNDCTL_DSP_SETTRIGGER, &tmp); - printf("Trigger set to %08x\n", tmp); - -/* - * The machine is up and running now. Use SNDCTL_DSP_GETOPTR to get the - * buffer status. - * - * NOTE! The driver empties each buffer fragmen after they have been - * played. This prevents looping sound if there are some performance problems - * in the application side. For similar reasons it recommended that the - * application uses some amout of play ahead. It can rewrite the unplayed - * data later if necessary. - */ - - nfrag = 0; - while (1) - { - struct count_info count; - int p, l, extra; - - FD_ZERO(&writeset); - FD_SET(fd, &writeset); - - tim.tv_sec = 10; - tim.tv_usec= 0; - - select(fd+1, &writeset, &writeset, NULL, NULL); -/* - * SNDCTL_DSP_GETOPTR (and GETIPTR as well) return three items. The - * bytes field returns number of bytes played since start. It can be used - * as a real time clock. - * - * The blocks field returns number of fragment transitions (interrupts) since - * previous GETOPTR call. It can be used as a method to detect underrun - * situations. - * - * The ptr field is the DMA pointer inside the buffer area (in bytes from - * the beginning of total buffer area). - */ - - if (ioctl(fd, SNDCTL_DSP_GETOPTR, &count)==-1) - { - perror("GETOPTR"); - exit(-1); - } - - nfrag += count.blocks; - -#ifdef VERBOSE - - printf("\rTotal: %09d, Fragment: %03d, Ptr: %06d", - count.bytes, nfrag, count.ptr); - fflush(stdout); -#endif - -/* - * Caution! This version doesn't check for bounds of the DMA - * memory area. It's possible that the returned pointer value is not aligned - * to fragment boundaries. It may be several samples behind the boundary - * in case there was extra delay between the actual hardware interrupt and - * the time when DSP_GETOPTR was called. - * - * Don't just call memcpy() with length set to 'fragment_size' without - * first checking that the transfer really fits to the buffer area. - * A mistake of just one byte causes seg fault. It may be easiest just - * to align the returned pointer value to fragment boundary before using it. - * - * It would be very good idea to write few extra samples to next fragment - * too. Otherwise several (uninitialized) samples from next fragment - * will get played before your program gets chance to initialize them. - * Take in count the fact thaat there are other processes batling about - * the same CPU. This effect is likely to be very annoying if fragment - * size is decreased too much. - */ - -/* - * Just a minor clarification to the above. The following line alings - * the pointer to fragment boundaries. Note! Don't trust that fragment - * size is always a power of 2. It may not be so in future. - */ - count.ptr = (count.ptr/fsz)*fsz; - -#ifdef VERBOSE - printf(" memcpy(%6d, %4d)", (dp-data), fsz); - fflush(stdout); -#endif - -/* - * Set few bytes in the beginning of next fragment too. - */ - if ((count.ptr+fsz+16) < sz) /* Last fragment? */ - extra = 16; - else - extra = 0; - - memcpy(op+count.ptr, dp, fsz+extra); - - dp += fsz; - if (dp > (data+sl-fsz)) - dp = data; - } - - exit(0); -} diff --git a/sys/i386/isa/snd/misc/pcmio.c b/sys/i386/isa/snd/misc/pcmio.c deleted file mode 100644 index 5bab10e..0000000 --- a/sys/i386/isa/snd/misc/pcmio.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * pcmio.c -- a simple utility for controlling audio I/O - * (rate, channels, resolution...) - * - * (C) Luigi Rizzo 1998 - * - */ - -#include <stdio.h> -#include <stdlib.h> -#include <fcntl.h> -#include <machine/soundcard.h> - -char * usage_string = -"Usage: %s [-f device] [+parameters] [len:skip] file { file }\n" -"where device is the device to be used (default /dev/audio)\n" -"[len:skip] is the subsection of the file to be played\n" -"with a '-' indicating the default\n" -"and parameters is a comma-separated list containing one or more of\n" -" N the sampling speed\n" -" stereo|mono \n" -" cd|u8|alaw|ulaw|s16 data format\n" -" loop loop (play cyclically)\n" -; - -#define BLKSZ 32768 -int format=AFMT_MU_LAW; -int rate=8000 ; -int stereo = 0 ; -char dev[128]; -int audiodev; -int play = 1 ; /* default */ -int loop = 0 ; -int skip = 0; -int size = -1 ; - -extern char *optarg; -extern int optind, optopt, opterr, optreset; - -int -usage(char *s) -{ - printf(usage_string, s); - exit(0); -} - -int -parse_len(char *s) -{ - int par = -1; - int mul = 1; - int p = strlen(s); - - if (p == 0) - return -1 ; - - if (*s != '-') - par = atoi(s); - else - return -1 ; - switch(s[p-1]) { - case 'k': - case 'K': - mul = 1024; - break; - case 'm': - case 'M': - mul = 1024*1024; - break; - case 's': - mul = rate * (stereo+1); - if (format == AFMT_S16_LE) - mul += mul; - break; - } - return par*mul; -} - -void -parse_fmt(char *fmt) -{ - char *s; - int v, last = 0 ; - -again: - while (*fmt && (*fmt == ' ' || *fmt == '\t')) fmt++; - s = fmt; - while (*s && ! (*s == ',' || *s == ':' || *s == ';') ) s++; - if (*s) - *s='\0'; - else - last = 1 ; - v = atoi(fmt) ; - if (v > 0 && v < 1000000) - rate = v ; - else { - if (!strcmp(fmt, "ulaw")) format = AFMT_MU_LAW; - else if (!strcmp(fmt, "alaw")) format = AFMT_A_LAW; - else if (!strcmp(fmt, "u8")) format = AFMT_U8 ; - else if (!strcmp(fmt, "s16")) format = AFMT_S16_LE ; - else if (!strcmp(fmt, "mono")) stereo = 0; - else if (!strcmp(fmt, "stereo")) stereo = 1; - else if (!strcmp(fmt, "loop")) loop = 1; - else if (!strcmp(fmt, "rec")) play = 0; - else if (!strcmp(fmt, "play")) play = 1; - else if (!strcmp(fmt, "cd")) { - stereo = 1 ; - format = AFMT_S16_LE ; - rate = 44100; - } - } - if (last == 0) { - fmt = s+1; - goto again; - } -} - -char buf[BLKSZ]; - -int -main(int argc, char *argv[]) -{ - int i,c; - int ac = argc; - char *p; - - strcpy(dev, "/dev/audio"); - - while ( (c= getopt(argc, argv, "f:") ) != EOF ) { - switch (c) { - case 'f' : - if (optarg[0] >='0' && optarg[0] <='9') - sprintf(dev, "/dev/audio%s", optarg); - else - strcpy(dev, optarg); - break; - } - } - if (*argv[optind] == '+') { - parse_fmt(argv[optind]+1); - optind++; - } - /* - * assume a string with a "," and no "/" as a command - */ - if (strstr(argv[optind],",") && !strstr(argv[optind],"/") ) { - parse_fmt(argv[optind]); - optind++; - } - /* - * assume a string with a ":" and no "/" as a time limit - */ - if ( (p = strstr(argv[optind] , ":")) && !strstr(argv[optind],"/") ) { - *p = '\0'; - size = parse_len(argv[optind]); - skip = parse_len(p+1); - optind++; - } - printf("Using device %s, speed %d, mode 0x%08x, %s\n", - dev, rate, format, stereo ? "stereo":"mono"); - printf("using files: "); - for (i=optind; i< argc ; i++) - printf("[%d] %s, ",i, argv[i]); - printf("\n"); - - audiodev = open(dev, play ? 1 : 0); - if (audiodev < 0) { - printf("failed to open %d\n", dev); - exit(2); - } - ioctl(audiodev, SNDCTL_DSP_SETFMT, &format); - ioctl(audiodev, SNDCTL_DSP_STEREO, &stereo); - ioctl(audiodev, SNDCTL_DSP_SPEED, &rate); - printf("-- format %d,%s,0x%08x, len %d skip %d\n", - rate, stereo? "stereo":"mono",format, size, skip); - if (play) { - off_t ofs; - int limit; -again: - for (i=optind; i< argc ; i++) { - int l = -2; - int f = open(argv[i], O_RDONLY); - int sz ; - - printf("opened %s returns %d\n", argv[i], f); - if (f < 0) - continue; - limit = size; - if (skip > 0) { - ofs = skip; - lseek(f, ofs, 0 /* begin */ ); - } - sz = BLKSZ; - if (limit > 0 && limit < sz) - sz = limit ; - while ( (l = read(f, buf, sz) ) > 0 ) { - write(audiodev, buf, l); - if (limit > 0) { - limit -= l ; - if (limit > 0 && limit < sz) - sz = limit ; - if (limit <= 0 ) - break; - if (limit < sz) - sz = limit ; - } - } - close(f); - } - if (loop) - goto again; - } else { /* record */ - int l = -2; - int f ; - if (!strcmp(argv[optind], "-") ) - f = 1; - else - f = open(argv[optind], O_WRONLY | O_CREAT | O_TRUNC, 0664); - fprintf(stderr,"open %s returns %d\n", argv[optind], f); - - while ( size > 0 && (l = read(audiodev, buf, BLKSZ) ) > 0 ) { - if (l <= skip) { - skip -= l ; /* at most skip = 0 */ - continue; - } else { /* l > skip */ - l -= skip ; - if (l > size) - l = size ; - write(f, buf+skip, l); - skip = 0 ; - size -= l ; - } - } - close(f); - } -} diff --git a/sys/i386/isa/snd/misc/soundbyte.c b/sys/i386/isa/snd/misc/soundbyte.c deleted file mode 100644 index 2e8d8cc..0000000 --- a/sys/i386/isa/snd/misc/soundbyte.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Sound interface for Speak Freely for Unix - * - * Designed and implemented in July of 1990 by John Walker - * - * FreeBSD / voxware version - */ - -#define BUFL 8000 - -#include "speakfree.h" - -#include <sys/dir.h> -#include <sys/file.h> - -/* #include <math.h> */ -#include <errno.h> - -#include <sys/ioctl.h> -#ifdef LINUX -#include <linux/soundcard.h> -#else -#include <machine/soundcard.h> -#endif -#define AUDIO_MIN_GAIN 0 -#define AUDIO_MAX_GAIN 255 -static int abuf_size; - -#define SoundFile "/dev/audio" -#define AUDIO_CTLDEV "/dev/mixer" - -#define MAX_GAIN 100 - -struct sound_buf { - struct sound_buf *snext; /* Next sound buffer */ - int sblen; /* Length of this sound buffer */ - unsigned char sbtext[2]; /* Actual sampled sound */ -}; - -/* Local variables */ - -static int audiof = -1; /* Audio device file descriptor */ -static int Audio_fd; /* Audio control port */ -struct sound_buf *sbchain = NULL, /* Sound buffer chain links */ - *sbtail = NULL; -static int sbtotal = 0; /* Total sample bytes in memory */ -static int playing = FALSE;/* Replay in progress ? */ -/* static int playqsize; *//* Output queue size */ -static int playlen = 0; /* Length left to play */ -static unsigned char *playbuf = NULL; /* Current play pointer */ -static int squelch = 0; /* Squelch value */ - -/* Convert local gain into device parameters */ - -static unsigned -scale_gain(unsigned g) -{ - return (AUDIO_MIN_GAIN + (unsigned) - ((int) ((((double) (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN)) * - ((double) g / (double) MAX_GAIN)) + 0.5))); -} - -#ifdef HALF_DUPLEX -static int oldvol = -1; -#endif - -/* - * SOUNDINIT -- Open the sound peripheral and initialise for access. Return - * TRUE if successful, FALSE otherwise. - */ - -int -soundinit(int iomode) -{ - int attempts = 3; - - assert(audiof == -1); - while (attempts-- > 0) { - if ((audiof = open(SoundFile, iomode)) >= 0) { - - if ((Audio_fd = open(AUDIO_CTLDEV, O_RDWR)) < 0) { - perror(AUDIO_CTLDEV); - return FALSE; - } - /* fcntl(audiof, F_SETFL, O_NDELAY); */ -#ifndef AUDIO_BLOCKING - if (ioctl(audiof, SNDCTL_DSP_NONBLOCK, NULL) < 0) { - perror("SNDCTL_DSP_NONBLOCK"); - return FALSE; - } - if (ioctl(audiof, SNDCTL_DSP_GETBLKSIZE, &abuf_size) < 0) { - perror("SNDCTL_DSP_GETBLKSIZE"); - return FALSE; - } -#endif -#ifdef HALF_DUPLEX - if (iomode == O_RDONLY) { - if (oldvol == -1) - oldvol = soundgetvol(); - soundplayvol(0); - } else if (iomode == O_WRONLY && oldvol != -1 ) { - if (soundgetvol() == 0) - soundplayvol(oldvol); - oldvol = -1; - } -#endif - return TRUE; - } - if (errno != EINTR) - break; - fprintf(stderr, "Audio open: retrying EINTR attempt %d\n", attempts); - } - return FALSE; -} - -/* SOUNDTERM -- Close the sound device. chan=1 for play, 2:capture */ - -void -soundterm(int chan) -{ - if (audiof >= 0) { - int arg; -#ifdef AIOSTOP /* FreeBSD */ - if (chan == 2) { - arg = AIOSYNC_CAPTURE; - ioctl(audiof, AIOSTOP, &arg); - } -#endif -#ifdef SNDCTL_DSP_SYNC - if (chan == 1) - ioctl(audiof, SNDCTL_DSP_SYNC); -#endif -#ifdef HALF_DUPLEX - if (oldvol != -1) { - if (soundgetvol() == 0) - soundplayvol(oldvol); - oldvol = -1; - } -#endif - if (close(audiof) < 0) - perror("closing audio device"); - if (close(Audio_fd) < 0) - perror("closing audio control device"); - audiof = -1; - } -} - -/* SOUNDPLAY -- Begin playing a sound. */ - -void -soundplay(int len, unsigned char *buf) -{ - int ios; - - assert(audiof != -1); - while (TRUE) { - ios = write(audiof, buf, len); - if (ios == -1) - sf_usleep(100000); - else { - if (ios < len) { - buf += ios; - len -= ios; - } else - break; - } - } -} - -/* SOUNDPLAYVOL -- Set playback volume from 0 (silence) to 100 (full on). */ - -void -soundplayvol(int value) -{ - int arg; - - arg = (value << 8) | value; - - if (ioctl(Audio_fd, SOUND_MIXER_WRITE_PCM, &arg) < 0) - perror("SOUND_MIXER_WRITE_PCM"); -} - -#ifdef HALF_DUPLEX - -/* SOUNDGETVOL -- Get current playback volume. */ - -int -soundgetvol() -{ - int arg, v1, v2; - - if (ioctl(Audio_fd, SOUND_MIXER_READ_PCM, &arg) < 0) { - perror("SOUND_MIXER_READ_PCM"); - return -1; - } - v1 = arg & 0xFF; - v2 = (arg >> 8) & 0xFF; - return (v1 > v2) ? v1 : v2; -} -#endif - -/* SOUNDRECGAIN -- Set recording gain from 0 (minimum) to 100 (maximum). */ - -void -soundrecgain(int value) -{ - int arg; - - arg = (value << 8) | value; - - if (ioctl(Audio_fd, SOUND_MIXER_WRITE_RECLEV, &arg) < 0) - perror("SOUND_MIXER_WRITE_RECLEV"); -} - -/* - * SOUNDDEST -- Set destination for generated sound. If "where" is 0, - * sound goes to the built-in speaker; if 1, to the audio output jack. - */ - -void -sounddest(int where) -{ -} - -/* SOUNDGRAB -- Return audio information in the record queue. */ - -int -soundgrab(char *buf, int len) -{ - long read_size; - int c; - - read_size = len; -#ifndef AUDIO_BLOCKING - if (read_size > abuf_size) { - read_size = abuf_size; - } -#endif - while (TRUE) { - c = read(audiof, buf, read_size); - if (c < 0) { - if (errno == EINTR) { - continue; - } else if (errno == EAGAIN) { - c = 0; - } - } - break; - } - if (c < 0) { - perror("soundgrab"); - } - return c; -} - -/* SOUNDFLUSH -- Flush any queued sound. */ - -void -soundflush() -{ - char sb[BUFL]; - int c; - -#ifndef AUDIO_BLOCKING - while (TRUE) { - c = read(audiof, sb, BUFL < abuf_size ? BUFL : abuf_size); - if (c < 0 && errno == EAGAIN) - c = 0; - if (c < 0) - perror("soundflush"); - if (c <= 0) - break; - } -#endif -} diff --git a/sys/i386/isa/snd/misc/test.c b/sys/i386/isa/snd/misc/test.c deleted file mode 100644 index 2725dcc..0000000 --- a/sys/i386/isa/snd/misc/test.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * test.c -- a simple utility for testing audio I/O - * - * (C) Luigi Rizzo 1997 - * - * This code mmaps the io descriptor, then every second dumps the - * relevant data structures. - * - * call it as "test unit" where unit is the unit number you want - * to see displayed. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <fcntl.h> - -#include <sys/types.h> -#include <sys/mman.h> -#include <sys/select.h> - -caddr_t r, w, d; - -#include </sys/i386/isa/snd/sound.h> - -void -print_d(u_long *p, int unit) -{ - snddev_info *d; - int i; - for (i=0; i<2000; i++) { - d = (snddev_info *)&(p[i]); - if ( d->magic == MAGIC(unit) ) - break; - } - if (i == 2000) { - printf("desc not found\n"); - return; - } - printf("device type %d name %s\n", d->type, d->name); - for (i=0;;i++) { - if (i%20 == 0) - printf("flags... fmt speed .bsz. c in-rl:in-dl:in-fl.ints " - " c ou-fl:ou_dl:ou-rl.ints |\n"); - printf("%08x %3x %5d %5d %d %5d %5d %5d %4d %d %5d %5d %5d %4d |\n", - d->flags, d->play_fmt, d->play_speed, d->play_blocksize, - d->dbuf_in.chan, - d->dbuf_in.rl, - d->dbuf_in.dl, - d->dbuf_in.fl, - d->dbuf_in.int_count, - - d->dbuf_out.chan, - d->dbuf_out.fl, - d->dbuf_out.dl, - d->dbuf_out.rl, - d->dbuf_out.int_count); - sleep(1); - } -} - -main(int argc, char *argv[]) -{ - int fd ; - int unit = 0; - char devn[64]; - - if (argc>1) unit=atoi(argv[1]); - sprintf(devn,"/dev/mixer%d", unit); - fd = open (devn, O_RDWR); - printf("open returns %d\n", fd); - - w = mmap(NULL, 0x10000, PROT_READ, 0, fd, 0); /* play */ - r = mmap(NULL, 0x10000, PROT_READ, 0, fd, 1<<24); /* rec */ - d = mmap(NULL, 0x2000, PROT_READ, 0, fd, 2<<24); /* desc */ - - printf("mmap: w 0x%08lx, r 0x%08lx, d 0x%08lx\n", w, r, d); - if (d && (int)d != -1 ) { - print_d((u_long *)d, unit); - } - if (w && (int)w != -1) munmap(w, 0x10000); - if (r && (int)r != -1) munmap(r, 0x10000); - if (d && (int)d != -1) munmap(d, 0x2000); - return 0; -} |