diff --git a/sys/i386/isa/snd/doc/Makefile b/sys/i386/isa/snd/doc/Makefile deleted file mode 100644 index 355a77f53af2..000000000000 --- 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 deleted file mode 100644 index 12beb0ad4dce..000000000000 Binary files a/sys/i386/isa/snd/doc/sound.ps.gz and /dev/null differ diff --git a/sys/i386/isa/snd/doc/sound.tex b/sys/i386/isa/snd/doc/sound.tex deleted file mode 100644 index d8e70591164c..000000000000 --- 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 -#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 e50b0418ccd0..000000000000 --- 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 16feb46269c3..000000000000 --- 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 -#include -#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 1ae931689961..000000000000 --- 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 -#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 -#include "dixstruct.h" /* for RESTYPE */ -#include "os.h" /* for xalloc/xfree and NULL */ -#include -#include -#include -#include - -#ifdef __FreeBSD__ -#include -#include -#else -#include -#endif - -#include