Commit 1343c2a8 authored by Linus Torvalds's avatar Linus Torvalds

Merge http://linux-sound.bkbits.net/linux-sound

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 90a89de4 a810a3da
......@@ -520,13 +520,19 @@ Module parameters
Module for Envy24 (ICE1712) based PCI soundcards.
* MidiMan M Audio Delta 1010
* MidiMan M Audio Delta 1010LT
* MidiMan M Audio Delta DiO 2496
* MidiMan M Audio Delta 66
* MidiMan M Audio Delta 44
* MidiMan M Audio Delta 410
* MidiMan M Audio Audiophile 2496
* TerraTec EWS 88MT
* TerraTec EWS 88D
* TerraTec EWX 24/96
* TerraTec DMX 6Fire
* Hoontech SoundTrack DSP 24
* Hoontech SoundTrack DSP 24 Value
* Hoontech SoundTrack DSP 24 Media 7.1
omni - Omni I/O support for MidiMan M-Audio Delta44/66
......@@ -534,6 +540,15 @@ Module parameters
is not used with all Envy24 based cards (for example in the MidiMan Delta
serie).
Module snd-ice1724
------------------
Module for Envy24HT (VT/ICE1724) based PCI soundcards.
* MidiMan M Audio Revolution 7.1
* AMP Ltd AUDIO2000
Module supports up to 8 cards and autoprobe.
Module snd-intel8x0
-------------------
......@@ -659,7 +674,7 @@ Module parameters
Module supports autoprobe and multiple chips (max 8).
Note: on some notebooks the buffer address cannot be detected
automatically, or causes hang-up during initialization.
In such a case, specify the buffer top address explicitly via
In such a case, specify the buffer top address explicity via
buffer_top option.
For example,
Sony F250: buffer_top=0x25a800
......@@ -968,6 +983,19 @@ Module parameters
The power-management is supported.
Configuring Non-ISAPNP Cards
============================
When the kernel is configured with ISA-PnP support, the modules
supporting the isapnp cards will have module options "isapnp".
If this option is set, *only* the ISA-PnP devices will be probed.
For probing the non ISA-PnP cards, you have to pass "isapnp=0" option
together with the proper i/o and irq configuration.
When the kernel is configured without ISA-PnP support, isapnp option
will be not built in.
modprobe/kmod support
=====================
......
......@@ -207,7 +207,7 @@ MIDI CONTROLLER
---------------
The MPU401-UART interface is enabled as default only for the first
(CMIPCI) card. You need to set module option "snd_midi_port" properly
(CMIPCI) card. You need to set module option "midi_port" properly
for the 2nd (CMIPCI) card.
There is _no_ hardware wavetable function on this chip (except for
......@@ -221,7 +221,7 @@ FM OPL/3 Synth
--------------
The FM OPL/3 is also enabled as default only for the first card.
Set "snd_fm_port" module option for more cards.
Set "fm_port" module option for more cards.
The output quality of FM OPL/3 is, however, very weird.
I don't know why..
......
......@@ -80,3 +80,5 @@ IEC958 (S/PDIF) interface:
IEC958 [...] [Playback|Capture] Con Mask /* consumer mask */
IEC958 [...] [Playback|Capture] Pro Mask /* professional mask */
IEC958 [...] [Playback|Capture] PCM Stream /* the settings assigned to a PCM stream */
IEC958 Q-subcode [Playback|Capture] Default /* Q-subcode bits */
IEC958 Preamble [Playback|Capture] Default /* burst preamble words (4*16bits) */
......@@ -48,6 +48,8 @@
<sect1><title>Memory Management Helpers</title>
!Esound/core/memory.c
!Iinclude/sound/sndmagic.h
!Esound/core/memalloc.c
!Esound/core/sgbuf.c
</sect1>
</chapter>
<chapter><title>PCM API</title>
......@@ -62,9 +64,6 @@
<sect1><title>PCM Memory Managment</title>
!Esound/core/pcm_memory.c
</sect1>
<sect1><title>SG-Buffer Helpers</title>
!Esound/core/pcm_sgbuf.c
</sect1>
</chapter>
<chapter><title>Control/Mixer API</title>
<sect1><title>General Control Interface</title>
......
......@@ -437,7 +437,7 @@
// (see "Management of Cards and Components")
static int __devinit snd_mychip_create(snd_card_t *card,
struct pci_device *pci,
mychip_t *rchip)
mychip_t **rchip)
{
mychip_t *chip;
int err;
......@@ -1377,6 +1377,8 @@
module_init(alsa_card_mychip_init)
module_exit(alsa_card_mychip_exit)
EXPORT_NO_SYMBOLS; /* for old kernels only */
]]>
</programlisting>
</example>
......@@ -1664,7 +1666,7 @@
chip->iobase_phys = pci_resource_start(pci, 0);
chip->iobase_virt = (unsigned long)
ioremap_nocache(chip->iobase_phys, 512);
if ((chip->res_port = request_mem_region(chip->port, 512,
if ((chip->res_port = request_mem_region(chip->iobase_phys, 512,
"My Chip")) == NULL) {
printk(KERN_ERR "cannot allocate the memory region\n");
snd_mychip_free(chip);
......@@ -2758,6 +2760,17 @@
</para>
</section>
<section id="pcm-interface-operators-ack">
<title>ack callback</title>
<para>
This callback is also not mandatory. This callback is called
when the appl_ptr is updated in read or write operations.
Some drivers like emu10k1-fx and cs46xx need to track the
current appl_ptr for the internal buffer, and this callback
is useful only for such a purpose.
</para>
</section>
<section id="pcm-interface-operators-page-callback">
<title>page callback</title>
......@@ -2807,7 +2820,7 @@
</para>
<para>
If you acquire a spinlock in the interrupt handler, and the
If you aquire a spinlock in the interrupt handler, and the
lock is used in other pcm callbacks, too, then you have to
release the lock before calling
<function>snd_pcm_period_elapsed()</function>, because
......@@ -4467,8 +4480,7 @@
<informalexample>
<programlisting>
<![CDATA[
snd_pcm_sgbuf_t *sgbuf = snd_magic_cast(snd_pcm_sgbuf_t,
substream->dma_private, return -EINVAL);
snd_pcm_sgbuf_t *sgbuf = (snd_pcm_sgbuf_t*)substream->dma_private;
]]>
</programlisting>
</informalexample>
......
......@@ -2,7 +2,7 @@
Serial UART 16450/16550 MIDI driver
===================================
The snd_adaptor module parameter allows you to select either:
The adaptor module parameter allows you to select either:
0 - Roland Soundcanvas support (default)
1 - Midiator MS-124T support (1)
......@@ -24,37 +24,35 @@ send the F5 NN command sequence at all; perhaps it ought to.
Usage example for simple serial converter:
/sbin/setserial /dev/ttyS0 none
/sbin/modprobe snd-serial-u16550 snd_port=0x3f8 snd_irq=4 \
snd_speed=115200
/sbin/modprobe snd-serial-u16550 port=0x3f8 irq=4 speed=115200
Usage example for Roland SoundCanvas with 4 MIDI ports:
/sbin/setserial /dev/ttyS0 none
/sbin/modprobe snd-serial-u16550 snd_port=0x3f8 snd_irq=4 snd_outs=4
/sbin/modprobe snd-serial-u16550 port=0x3f8 irq=4 outs=4
In MS-124T mode, one raw MIDI substream is supported (midiCnD0); the snd_outs
In MS-124T mode, one raw MIDI substream is supported (midiCnD0); the outs
module parameter is automatically set to 1. The driver sends the same data to
all four MIDI Out connectors. Set the A-B switch and the snd_speed module
all four MIDI Out connectors. Set the A-B switch and the speed module
parameter to match (A=19200, B=9600).
Usage example for MS-124T, with A-B switch in A position:
/sbin/setserial /dev/ttyS0 none
/sbin/modprobe snd-serial-u16550 snd_port=0x3f8 snd_irq=4 \
snd_adaptor=1 snd_speed=19200
/sbin/modprobe snd-serial-u16550 port=0x3f8 irq=4 adaptor=1 \
speed=19200
In MS-124W S/A mode, one raw MIDI substream is supported (midiCnD0);
the snd_outs module parameter is automatically set to 1. The driver sends
the outs module parameter is automatically set to 1. The driver sends
the same data to all four MIDI Out connectors at full MIDI speed.
Usage example for S/A mode:
/sbin/setserial /dev/ttyS0 none
/sbin/modprobe snd-serial-u16550 snd_port=0x3f8 snd_irq=4 \
snd_adaptor=2
/sbin/modprobe snd-serial-u16550 port=0x3f8 irq=4 adaptor=2
In MS-124W M/B mode, the driver supports 16 ALSA raw MIDI substreams;
the snd_outs module parameter is automatically set to 16. The substream
the outs module parameter is automatically set to 16. The substream
number gives a bitmask of which MIDI Out connectors the data should be
sent to, with midiCnD1 sending to Out 1, midiCnD2 to Out 2, midiCnD4 to
Out 3, and midiCnD8 to Out 4. Thus midiCnD15 sends the data to all 4 ports.
......@@ -67,8 +65,7 @@ one byte every 320 us per port.
Usage example for M/B mode:
/sbin/setserial /dev/ttyS0 none
/sbin/modprobe snd-serial-u16550 snd_port=0x3f8 snd_irq=4 \
snd_adaptor=3
/sbin/modprobe snd-serial-u16550 port=0x3f8 irq=4 adaptor=3
The MS-124W hardware's M/A mode is currently not supported. This mode allows
the MIDI Outs to act independently at double the aggregate throughput of M/B,
......@@ -88,4 +85,4 @@ The Generic driver supports multiple input and output substreams over a single
serial port. Similar to Roland Soundcanvas mode, F5 NN is used to select the
appropriate input or output stream (depending on the data direction).
Additionally, the CTS signal is used to regulate the data flow. The number of
inputs is specified by the snd_ins parameter.
inputs is specified by the ins parameter.
......@@ -156,12 +156,30 @@
/* extended modem ID bit defines */
#define AC97_MEI_LINE1 0x0001 /* Line1 present */
#define AC97_MEI_LINE2 0x0002 /* Line2 present */
#define AC97_MEI_HEADSET 0x0004 /* Headset present */
#define AC97_MEI_HANDSET 0x0004 /* Handset present */
#define AC97_MEI_CID1 0x0008 /* caller ID decode for Line1 is supported */
#define AC97_MEI_CID2 0x0010 /* caller ID decode for Line2 is supported */
#define AC97_MEI_ADDR_MASK 0xc000 /* physical codec ID (address) */
#define AC97_MEI_ADDR_SHIFT 14
/* extended modem status and control bit defines */
#define AC97_MEA_GPIO 0x0001 /* GPIO is ready (ro) */
#define AC97_MEA_MREF 0x0002 /* Vref is up to nominal level (ro) */
#define AC97_MEA_ADC1 0x0004 /* ADC1 operational (ro) */
#define AC97_MEA_DAC1 0x0008 /* DAC1 operational (ro) */
#define AC97_MEA_ADC2 0x0010 /* ADC2 operational (ro) */
#define AC97_MEA_DAC2 0x0020 /* DAC2 operational (ro) */
#define AC97_MEA_HADC 0x0040 /* HADC operational (ro) */
#define AC97_MEA_HDAC 0x0080 /* HDAC operational (ro) */
#define AC97_MEA_PRA 0x0100 /* GPIO power down (high) */
#define AC97_MEA_PRB 0x0200 /* reserved */
#define AC97_MEA_PRC 0x0400 /* ADC1 power down (high) */
#define AC97_MEA_PRD 0x0800 /* DAC1 power down (high) */
#define AC97_MEA_PRE 0x1000 /* ADC2 power down (high) */
#define AC97_MEA_PRF 0x2000 /* DAC2 power down (high) */
#define AC97_MEA_PRG 0x4000 /* HADC power down (high) */
#define AC97_MEA_PRH 0x8000 /* HDAC power down (high) */
/* specific - SigmaTel */
#define AC97_SIGMATEL_ANALOG 0x6c /* Analog Special */
#define AC97_SIGMATEL_DAC2INVERT 0x6e
......@@ -268,6 +286,14 @@ struct _snd_ac97 {
};
/* conditions */
static inline int ac97_is_audio(ac97_t * ac97)
{
return (ac97->scaps & AC97_SCAP_AUDIO);
}
static inline int ac97_is_modem(ac97_t * ac97)
{
return (ac97->scaps & AC97_SCAP_MODEM);
}
static inline int ac97_is_rev22(ac97_t * ac97)
{
return (ac97->ext_id & AC97_EI_REV_MASK) == AC97_EI_REV_22;
......@@ -278,7 +304,8 @@ static inline int ac97_can_amap(ac97_t * ac97)
}
/* functions */
int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97);
int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97); /* create mixer controls */
int snd_ac97_modem(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97); /* create modem controls */
void snd_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short value);
unsigned short snd_ac97_read(ac97_t *ac97, unsigned short reg);
......@@ -296,6 +323,7 @@ enum { AC97_TUNE_HP_ONLY, AC97_TUNE_SWAP_HP };
struct ac97_quirk {
unsigned short vendor;
unsigned short device;
const char *name;
int type;
};
......
This diff is collapsed.
......@@ -27,7 +27,7 @@
#include <linux/rwsem.h> /* struct rw_semaphore */
/* Typedef's */
typedef struct timeval snd_timestamp_t;
typedef struct timespec snd_timestamp_t;
typedef struct sndrv_interval snd_interval_t;
typedef enum sndrv_card_type snd_card_type;
typedef struct sndrv_xferi snd_xferi_t;
......@@ -275,32 +275,6 @@ void snd_hidden_vfree(void *obj);
#endif
void *snd_kcalloc(size_t size, int flags);
char *snd_kmalloc_strdup(const char *string, int flags);
void *snd_malloc_pages(unsigned long size, unsigned int dma_flags);
void *snd_malloc_pages_fallback(unsigned long size, unsigned int dma_flags, unsigned long *res_size);
void snd_free_pages(void *ptr, unsigned long size);
#ifdef CONFIG_PCI
void *snd_malloc_pci_pages(struct pci_dev *pci, unsigned long size, dma_addr_t *dma_addr);
void *snd_malloc_pci_pages_fallback(struct pci_dev *pci, unsigned long size, dma_addr_t *dma_addr, unsigned long *res_size);
void snd_free_pci_pages(struct pci_dev *pci, unsigned long size, void *ptr, dma_addr_t dma_addr);
void *snd_malloc_pci_page(struct pci_dev *pci, dma_addr_t *dma_addr);
#define snd_free_pci_page(pci,ptr,addr) snd_free_pci_pages(pci,PAGE_SIZE,ptr,addr)
#endif
#ifdef CONFIG_SBUS
void *snd_malloc_sbus_pages(struct sbus_dev *sdev, unsigned long size, dma_addr_t *dma_addr);
void *snd_malloc_sbus_pages_fallback(struct sbus_dev *sdev, unsigned long size, dma_addr_t *dma_addr, unsigned long *res_size);
void snd_free_sbus_pages(struct sbus_dev *sdev, unsigned long size, void *ptr, dma_addr_t dma_addr);
#endif
#ifdef CONFIG_ISA
#ifdef CONFIG_PCI
#define snd_malloc_isa_pages(size, dma_addr) snd_malloc_pci_pages(NULL, size, dma_addr)
#define snd_malloc_isa_pages_fallback(size, dma_addr, res_size) snd_malloc_pci_pages_fallback(NULL, size, dma_addr, res_size)
#define snd_free_isa_pages(size, ptr, dma_addr) snd_free_pci_pages(NULL, size, ptr, dma_addr)
#else /* !CONFIG_PCI */
void *snd_malloc_isa_pages(unsigned long size, dma_addr_t *dma_addr);
void *snd_malloc_isa_pages_fallback(unsigned long size, dma_addr_t *dma_addr, unsigned long *res_size);
#define snd_free_isa_pages(size, ptr, dma_addr) snd_free_pages(ptr, size)
#endif /* CONFIG_PCI */
#endif /* CONFIG_ISA */
int copy_to_user_fromio(void *dst, unsigned long src, size_t count);
int copy_from_user_toio(unsigned long dst, const void *src, size_t count);
......@@ -450,9 +424,27 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...);
#define snd_BUG() snd_assert(0, )
#define snd_timestamp_now(tstamp) do_gettimeofday(tstamp)
#define snd_timestamp_zero(tstamp) do { (tstamp)->tv_sec = 0; (tstamp)->tv_usec = 0; } while (0)
#define snd_timestamp_null(tstamp) ((tstamp)->tv_sec == 0 && (tstamp)->tv_usec ==0)
static inline void snd_timestamp_now(struct timespec *tstamp, int timespec)
{
struct timeval val;
/* FIXME: use a linear time source */
do_gettimeofday(&val);
tstamp->tv_sec = val.tv_sec;
tstamp->tv_nsec = val.tv_usec;
if (timespec)
tstamp->tv_nsec *= 1000L;
}
static inline void snd_timestamp_zero(struct timespec *tstamp)
{
tstamp->tv_sec = 0;
tstamp->tv_nsec = 0;
}
static inline int snd_timestamp_null(struct timespec *tstamp)
{
return tstamp->tv_sec == 0 && tstamp->tv_nsec == 0;
}
#define SNDRV_OSS_VERSION ((3<<16)|(8<<8)|(1<<4)|(0)) /* 3.8.1a */
......
......@@ -49,20 +49,6 @@
* ==========================================================================
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)
#if defined(__i386__) || defined(__ppc__) || defined(__x86_64__)
/*
* Here a dirty hack for 2.4 kernels.. See sound/core/memory.c.
*/
#define HACK_PCI_ALLOC_CONSISTENT
#include <linux/pci.h>
void *snd_pci_hack_alloc_consistent(struct pci_dev *hwdev, size_t size,
dma_addr_t *dma_handle);
#undef pci_alloc_consistent
#define pci_alloc_consistent snd_pci_hack_alloc_consistent
#endif /* i386 or ppc */
#endif /* 2.4.0 */
#ifdef CONFIG_SND_DEBUG_MEMORY
#include <linux/slab.h>
#include <linux/vmalloc.h>
......
......@@ -49,6 +49,8 @@
#define NUM_G 64 /* use all channels */
#define NUM_FXSENDS 4
#define EMU10K1_DMA_MASK 0x1fffffffUL
#define AUDIGY_DMA_MASK 0xffffffffUL
#define TMEMSIZE 256*1024
#define TMEMSIZEREG 4
......@@ -232,6 +234,8 @@
#define A_GPINPUT_MASK 0xff00
#define A_GPOUTPUT_MASK 0x00ff
#define A_IOCFG_GPOUT0 0x0044 /* analog/digital? */
#define A_IOCFG_GPOUT1 0x0002 /* IR */
#define A_IOCFG_GPOUT2 0x0001 /* IR */
#define TIMER 0x1a /* Timer terminal count register */
/* NOTE: After the rate is changed, a maximum */
......@@ -936,6 +940,7 @@ struct _snd_emu10k1 {
unsigned short model; /* subsystem id */
unsigned int card_type; /* EMU10K1_CARD_* */
unsigned int ecard_ctrl; /* ecard control bits */
unsigned long dma_mask; /* PCI DMA mask */
int max_cache_pages; /* max memory size / PAGE_SIZE */
void *silent_page; /* silent page */
dma_addr_t silent_page_dmaaddr;
......
......@@ -27,6 +27,8 @@
typedef enum sndrv_hwdep_iface snd_hwdep_iface_t;
typedef struct sndrv_hwdep_info snd_hwdep_info_t;
typedef struct sndrv_hwdep_dsp_status snd_hwdep_dsp_status_t;
typedef struct sndrv_hwdep_dsp_image snd_hwdep_dsp_image_t;
typedef struct _snd_hwdep_ops {
long long (*llseek) (snd_hwdep_t *hw, struct file * file, long long offset, int orig);
......@@ -37,6 +39,8 @@ typedef struct _snd_hwdep_ops {
unsigned int (*poll) (snd_hwdep_t * hw, struct file * file, poll_table * wait);
int (*ioctl) (snd_hwdep_t * hw, struct file * file, unsigned int cmd, unsigned long arg);
int (*mmap) (snd_hwdep_t * hw, struct file * file, struct vm_area_struct * vma);
int (*dsp_status) (snd_hwdep_t * hw, snd_hwdep_dsp_status_t * status);
int (*dsp_load) (snd_hwdep_t * hw, snd_hwdep_dsp_image_t * image);
} snd_hwdep_ops_t;
struct _snd_hwdep {
......@@ -56,6 +60,11 @@ struct _snd_hwdep {
wait_queue_head_t open_wait;
void *private_data;
void (*private_free) (snd_hwdep_t *hwdep);
struct semaphore open_mutex;
int used;
unsigned int dsp_loaded;
unsigned int exclusive: 1;
};
extern int snd_hwdep_new(snd_card_t * card, char *id, int device, snd_hwdep_t ** rhwdep);
......
......@@ -67,7 +67,7 @@ static const char __module_generic_string_##name [] \
#define SNDRV_BOOLEAN_TRUE_DESC "allows:{{0,Disabled},{1,Enabled}},default:1,dialog:check"
#define SNDRV_BOOLEAN_FALSE_DESC "allows:{{0,Disabled},{1,Enabled}},default:0,dialog:check"
#define SNDRV_ENABLED "enable:(snd_enable)"
#define SNDRV_ENABLED "enable:(enable)"
#define SNDRV_INDEX_DESC SNDRV_ENABLED ",allows:{{0,7}},unique,skill:required,dialog:list"
#define SNDRV_ID_DESC SNDRV_ENABLED ",unique"
......
/*
* Copyright (c) by Jaroslav Kysela <perex@suse.cz>
* Takashi Iwai <tiwai@suse.de>
*
* Generic memory allocators
*
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef __SOUND_MEMALLOC_H
#define __SOUND_MEMALLOC_H
#include <linux/pci.h>
#ifdef CONFIG_SBUS
#include <asm/sbus.h>
#endif
/*
* buffer device info
*/
struct snd_dma_device {
int type; /* SNDRV_MEM_TYPE_XXX */
union {
struct pci_dev *pci; /* for PCI and PCI-SG types */
unsigned int flags; /* GFP_XXX for continous and ISA types */
#ifdef CONFIG_SBUS
struct sbus_dev *sbus; /* for SBUS type */
#endif
} dev;
unsigned int id; /* a unique ID */
};
/*
* buffer types
*/
#define SNDRV_DMA_TYPE_UNKNOWN 0 /* not defined */
#define SNDRV_DMA_TYPE_CONTINUOUS 1 /* continuous no-DMA memory */
#define SNDRV_DMA_TYPE_ISA 2 /* ISA continuous */
#define SNDRV_DMA_TYPE_PCI 3 /* PCI continuous */
#define SNDRV_DMA_TYPE_SBUS 4 /* SBUS continuous */
#define SNDRV_DMA_TYPE_PCI_SG 5 /* PCI SG-buffer */
#ifdef CONFIG_PCI
/*
* compose a snd_dma_device struct for the PCI device
*/
static inline void snd_dma_device_pci(struct snd_dma_device *dev, struct pci_dev *pci, unsigned int id)
{
memset(dev, 0, sizeof(*dev));
dev->type = SNDRV_DMA_TYPE_PCI;
dev->dev.pci = pci;
dev->id = id;
}
#endif
/*
* info for buffer allocation
*/
struct snd_dma_buffer {
unsigned char *area; /* virtual pointer */
dma_addr_t addr; /* physical address */
size_t bytes; /* buffer size in bytes */
void *private_data; /* private for allocator; don't touch */
};
/* allocate/release a buffer */
int snd_dma_alloc_pages(const struct snd_dma_device *dev, size_t size, struct snd_dma_buffer *dmab);
void snd_dma_free_pages(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab);
/* buffer-preservation managements */
size_t snd_dma_get_reserved(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab);
int snd_dma_free_reserved(const struct snd_dma_device *dev);
int snd_dma_set_reserved(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab);
/*
* Generic memory allocators
*/
/*
* continuous pages
*/
void *snd_malloc_pages(size_t size, unsigned int gfp_flags);
void *snd_malloc_pages_fallback(size_t size, unsigned int gfp_flags, size_t *res_size);
void snd_free_pages(void *ptr, size_t size);
#ifdef CONFIG_PCI
/*
* PCI continuous pages
*/
void *snd_malloc_pci_pages(struct pci_dev *pci, size_t size, dma_addr_t *dma_addr);
void *snd_malloc_pci_pages_fallback(struct pci_dev *pci, size_t size, dma_addr_t *dma_addr, size_t *res_size);
void snd_free_pci_pages(struct pci_dev *pci, size_t size, void *ptr, dma_addr_t dma_addr);
/* one page allocation */
void *snd_malloc_pci_page(struct pci_dev *pci, dma_addr_t *dma_addr);
#define snd_free_pci_page(pci,ptr,addr) snd_free_pci_pages(pci,PAGE_SIZE,ptr,addr)
#endif
#ifdef CONFIG_SBUS
/*
* SBUS continuous pages
*/
void *snd_malloc_sbus_pages(struct sbus_dev *sdev, size_t size, dma_addr_t *dma_addr);
void *snd_malloc_sbus_pages_fallback(struct sbus_dev *sdev, size_t size, dma_addr_t *dma_addr, size_t *res_size);
void snd_free_sbus_pages(struct sbus_dev *sdev, size_t size, void *ptr, dma_addr_t dma_addr);
#endif
#ifdef CONFIG_ISA
/*
* ISA continuous pages
*/
void *snd_malloc_isa_pages(size_t size, dma_addr_t *dma_addr);
void *snd_malloc_isa_pages_fallback(size_t size, dma_addr_t *dma_addr, size_t *res_size);
void snd_free_isa_pages(size_t size, void *ptr, dma_addr_t addr);
#ifdef CONFIG_PCI
#define snd_malloc_isa_pages(size, dma_addr) snd_malloc_pci_pages(NULL, size, dma_addr)
#define snd_malloc_isa_pages_fallback(size, dma_addr, res_size) snd_malloc_pci_pages_fallback(NULL, size, dma_addr, res_size)
#define snd_free_isa_pages(size, ptr, dma_addr) snd_free_pci_pages(NULL, size, ptr, dma_addr)
#else /* !CONFIG_PCI */
#define snd_free_isa_pages(size, ptr, dma_addr) snd_free_pages(ptr, size)
#endif /* CONFIG_PCI */
#endif /* CONFIG_ISA */
#ifdef CONFIG_PCI
/*
* Scatter-Gather PCI pages
*/
struct snd_sg_page {
void *buf;
dma_addr_t addr;
};
struct snd_sg_buf {
int size; /* allocated byte size */
int pages; /* allocated pages */
int tblsize; /* allocated table size */
struct snd_sg_page *table; /* address table */
struct page **page_table; /* page table (for vmap/vunmap) */
struct pci_dev *pci;
};
void *snd_malloc_sgbuf_pages(struct pci_dev *pci, size_t size, struct snd_dma_buffer *dmab);
int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab);
/*
* return the pages matching with the given byte size
*/
static inline unsigned int snd_sgbuf_aligned_pages(size_t size)
{
return (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
}
/*
* return the physical address at the corresponding offset
*/
static inline dma_addr_t snd_sgbuf_get_addr(struct snd_sg_buf *sgbuf, size_t offset)
{
return sgbuf->table[offset >> PAGE_SHIFT].addr + offset % PAGE_SIZE;
}
#endif /* CONFIG_PCI */
/*
* wrappers
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)
#ifdef CONFIG_PCI
#if defined(__i386__) || defined(__ppc__) || defined(__x86_64__)
#define HACK_PCI_ALLOC_CONSISTENT
/* a hack for 2.4/5 kernels for better allocation of large buffers */
void *snd_pci_hack_alloc_consistent(struct pci_dev *hwdev, size_t size,
dma_addr_t *dma_handle);
#endif /* arch */
#endif /* CONFIG_PCI */
#endif /* LINUX >= 2.4.0 */
#endif /* __SOUND_MEMALLOC_H */
......@@ -42,6 +42,7 @@
#define MPU401_HW_ALS4000 16 /* Avance Logic ALS4000 */
#define MPU401_HW_INTEL8X0 17 /* Intel8x0 driver */
#define MPU401_HW_PC98II 18 /* Roland PC98II */
#define MPU401_HW_AUREAL 19 /* Aureal Vortex */
#define MPU401_MODE_BIT_INPUT 0
#define MPU401_MODE_BIT_OUTPUT 1
......@@ -87,6 +88,9 @@ struct _snd_mpu401 {
spinlock_t timer_lock;
struct timer_list timer;
void (*write) (mpu401_t * mpu, unsigned char data, unsigned long addr);
unsigned char (*read) (mpu401_t * mpu, unsigned long addr);
};
/* I/O ports */
......
......@@ -24,6 +24,7 @@
*/
#include <sound/asound.h>
#include <sound/memalloc.h>
#include <linux/poll.h>
#include <linux/bitops.h>
......@@ -49,6 +50,7 @@ typedef struct sndrv_pcm_status snd_pcm_status_t;
typedef struct sndrv_pcm_mmap_status snd_pcm_mmap_status_t;
typedef struct sndrv_pcm_mmap_control snd_pcm_mmap_control_t;
typedef struct sndrv_mask snd_mask_t;
typedef struct snd_sg_buf snd_pcm_sgbuf_t;
#define _snd_pcm_substream_chip(substream) ((substream)->private_data)
#define snd_pcm_substream_chip(substream) snd_magic_cast1(chip_t, _snd_pcm_substream_chip(substream), return -ENXIO)
......@@ -97,6 +99,7 @@ typedef struct _snd_pcm_ops {
int (*silence)(snd_pcm_substream_t *substream, int channel,
snd_pcm_uframes_t pos, snd_pcm_uframes_t count);
struct page *(*page)(snd_pcm_substream_t *substream, unsigned long offset);
int (*ack)(snd_pcm_substream_t *substream);
} snd_pcm_ops_t;
/*
......@@ -120,13 +123,6 @@ typedef struct _snd_pcm_ops {
#define SNDRV_PCM_TRIGGER_SUSPEND 5
#define SNDRV_PCM_TRIGGER_RESUME 6
#define SNDRV_PCM_DMA_TYPE_UNKNOWN 0 /* not defined */
#define SNDRV_PCM_DMA_TYPE_CONTINUOUS 1 /* continuous no-DMA memory */
#define SNDRV_PCM_DMA_TYPE_ISA 2 /* ISA continuous */
#define SNDRV_PCM_DMA_TYPE_PCI 3 /* PCI continuous */
#define SNDRV_PCM_DMA_TYPE_SBUS 4 /* SBUS continuous */
#define SNDRV_PCM_DMA_TYPE_PCI_SG 5 /* PCI SG-buffer */
/* If you change this don't forget to change rates[] table in pcm_native.c */
#define SNDRV_PCM_RATE_5512 (1<<0) /* 5512Hz */
#define SNDRV_PCM_RATE_8000 (1<<1) /* 8000Hz */
......@@ -281,13 +277,6 @@ typedef struct {
unsigned int mask;
} snd_pcm_hw_constraint_list_t;
struct snd_pcm_dma_buffer {
unsigned char *area;
dma_addr_t addr;
unsigned long bytes;
void *private_data; /* for allocator */
};
struct _snd_pcm_runtime {
/* -- Status -- */
snd_pcm_substream_t *trigger_master;
......@@ -316,6 +305,7 @@ struct _snd_pcm_runtime {
unsigned int rate_den;
/* -- SW params -- */
int tstamp_timespec; /* use timeval (0) or timespec (1) */
snd_pcm_tstamp_t tstamp_mode; /* mmap timestamp is updated */
unsigned int period_step;
unsigned int sleep_min; /* min ticks to sleep */
......@@ -361,7 +351,7 @@ struct _snd_pcm_runtime {
/* -- DMA -- */
unsigned char *dma_area; /* DMA area */
dma_addr_t dma_addr; /* physical bus address (not accessible from main CPU) */
unsigned long dma_bytes; /* size of DMA area */
size_t dma_bytes; /* size of DMA area */
void *dma_private; /* private DMA data for the memory allocator */
#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
......@@ -378,17 +368,17 @@ struct _snd_pcm_substream {
char name[32]; /* substream name */
int stream; /* stream (direction) */
size_t buffer_bytes_max; /* limit ring buffer size */
int dma_type;
struct snd_pcm_dma_buffer dma_buffer;
struct snd_dma_device dma_device;
struct snd_dma_buffer dma_buffer;
size_t dma_max;
void *dma_private;
/* -- hardware operations -- */
unsigned int open_flag: 1; /* lowlevel device has been opened */
snd_pcm_ops_t *ops;
/* -- runtime information -- */
snd_pcm_runtime_t *runtime;
/* -- timer section -- */
snd_timer_t *timer; /* timer */
int timer_running; /* time is running */
int timer_running: 1; /* time is running */
spinlock_t timer_lock;
/* -- next substream -- */
snd_pcm_substream_t *next;
......@@ -879,7 +869,18 @@ int snd_pcm_lib_preallocate_pci_pages_for_all(struct pci_dev *pci,
snd_pcm_t *pcm,
size_t size,
size_t max);
int snd_pcm_lib_preallocate_sg_pages(struct pci_dev *pci,
snd_pcm_substream_t *substream,
size_t size, size_t max);
int snd_pcm_lib_preallocate_sg_pages_for_all(struct pci_dev *pci,
snd_pcm_t *pcm,
size_t size, size_t max);
#define snd_pcm_substream_sgbuf(substream) ((substream)->runtime->dma_private)
#define snd_pcm_sgbuf_pages(size) snd_sgbuf_aligned_pages(size)
#define snd_pcm_sgbuf_get_addr(sgbuf,ofs) snd_sgbuf_get_addr(sgbuf,ofs)
struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset);
#endif
#ifdef CONFIG_SBUS
int snd_pcm_lib_preallocate_sbus_pages(struct sbus_dev *sdev,
snd_pcm_substream_t *substream,
......
#ifndef __SOUND_PCM_SGBUF_H
#define __SOUND_PCM_SGBUF_H
/*
* Scatter-Gather PCM access
*
* Copyright (c) by Takashi Iwai <tiwai@suse.de>
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
struct snd_sg_page {
void *buf;
dma_addr_t addr;
};
struct snd_sg_buf {
int size; /* allocated byte size (= runtime->dma_bytes) */
int pages; /* allocated pages */
int tblsize; /* allocated table size */
struct snd_sg_page *table;
struct page **page_table;
struct pci_dev *pci;
};
typedef struct snd_sg_buf snd_pcm_sgbuf_t; /* for magic cast */
/*
* return the pages matching with the given byte size
*/
static inline unsigned int snd_pcm_sgbuf_pages(size_t size)
{
return (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
}
/*
* return the physical address at the corresponding offset
*/
static inline dma_addr_t snd_pcm_sgbuf_get_addr(struct snd_sg_buf *sgbuf, size_t offset)
{
return sgbuf->table[offset >> PAGE_SHIFT].addr + offset % PAGE_SIZE;
}
void *snd_pcm_sgbuf_alloc_pages(struct pci_dev *pci, size_t size, struct snd_pcm_dma_buffer *dmab);
int snd_pcm_sgbuf_free_pages(struct snd_pcm_dma_buffer *dmab);
int snd_pcm_lib_preallocate_sg_pages(struct pci_dev *pci, snd_pcm_substream_t *substream, size_t size, size_t max);
int snd_pcm_lib_preallocate_sg_pages_for_all(struct pci_dev *pci, snd_pcm_t *pcm, size_t size, size_t max);
#define _snd_pcm_substream_sgbuf(substream) ((substream)->runtime->dma_private)
#define snd_pcm_substream_sgbuf(substream) snd_magic_cast(snd_pcm_sgbuf_t, _snd_pcm_substream_sgbuf(substream), return -ENXIO)
struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset);
#endif /* __SOUND_PCM_SGBUF_H */
......@@ -174,7 +174,7 @@ snd_seq_port_callback_t *snd_port_alloc_callback(void);
/* port attach/detach */
int snd_seq_event_port_attach(int client, snd_seq_port_callback_t *pcbp,
int cap, int type, int midi_channels, char *portname);
int cap, int type, int midi_channels, int midi_voices, char *portname);
int snd_seq_event_port_detach(int client, int port);
#endif /* __SOUND_SEQ_KERNEL_H */
......@@ -108,7 +108,7 @@ static inline int _snd_magic_bad(void *obj, unsigned long magic)
#define snd_pcm_proc_private_t_magic 0xa15a0104
#define snd_pcm_oss_file_t_magic 0xa15a0105
#define snd_mixer_oss_t_magic 0xa15a0106
#define snd_pcm_sgbuf_t_magic 0xa15a0107
// #define snd_pcm_sgbuf_t_magic 0xa15a0107
#define snd_info_private_data_t_magic 0xa15a0201
#define snd_info_entry_t_magic 0xa15a0202
......@@ -174,6 +174,7 @@ static inline int _snd_magic_bad(void *obj, unsigned long magic)
#define m3_dma_t_magic 0xa15a3202
#define nm256_t_magic 0xa15a3301
#define nm256_dma_t_magic 0xa15a3302
#define sam9407_t_magic 0xa15a3401
#define pmac_t_magic 0xa15a3501
#define ali_t_magic 0xa15a3601
#define mtpav_t_magic 0xa15a3701
......@@ -190,6 +191,8 @@ static inline int _snd_magic_bad(void *obj, unsigned long magic)
#define snd_usb_midi_t_magic 0xa15a3f01
#define snd_usb_midi_out_endpoint_t_magic 0xa15a3f02
#define snd_usb_midi_in_endpoint_t_magic 0xa15a3f03
#define ak4117_t_magic 0xa15a4000
#define psic_t_magic 0xa15a4100
#else
......
......@@ -3,7 +3,8 @@
/*
* Timer abstract layer
* Copyright (c) by Jaroslav Kysela <perex@suse.cz>
* Copyright (c) by Jaroslav Kysela <perex@suse.cz>,
* Abramo Bagnara <abramo@alsa-project.org>
*
*
* This program is free software; you can redistribute it and/or modify
......@@ -29,11 +30,15 @@ typedef enum sndrv_timer_class snd_timer_class_t;
typedef enum sndrv_timer_slave_class snd_timer_slave_class_t;
typedef enum sndrv_timer_global snd_timer_global_t;
typedef struct sndrv_timer_id snd_timer_id_t;
typedef struct sndrv_timer_ginfo snd_timer_ginfo_t;
typedef struct sndrv_timer_gparams snd_timer_gparams_t;
typedef struct sndrv_timer_gstatus snd_timer_gstatus_t;
typedef struct sndrv_timer_select snd_timer_select_t;
typedef struct sndrv_timer_info snd_timer_info_t;
typedef struct sndrv_timer_params snd_timer_params_t;
typedef struct sndrv_timer_status snd_timer_status_t;
typedef struct sndrv_timer_read snd_timer_read_t;
typedef struct sndrv_timer_tread snd_timer_tread_t;
#define _snd_timer_chip(timer) ((timer)->private_data)
#define snd_timer_chip(timer) snd_magic_cast1(chip_t, _snd_timer_chip(timer), return -ENXIO)
......@@ -54,16 +59,21 @@ typedef struct sndrv_timer_read snd_timer_read_t;
#define SNDRV_TIMER_IFLG_AUTO 0x00000008 /* auto restart */
#define SNDRV_TIMER_IFLG_FAST 0x00000010 /* fast callback (do not use tasklet) */
#define SNDRV_TIMER_IFLG_CALLBACK 0x00000020 /* timer callback is active */
#define SNDRV_TIMER_IFLG_EXCLUSIVE 0x00000040 /* exclusive owner - no more instances */
#define SNDRV_TIMER_FLG_CHANGE 0x00000001
#define SNDRV_TIMER_FLG_RESCHED 0x00000002 /* need reschedule */
typedef void (*snd_timer_callback_t) (snd_timer_instance_t * timeri, unsigned long ticks, unsigned long resolution);
typedef void (*snd_timer_ccallback_t) (snd_timer_instance_t * timeri, enum sndrv_timer_event event,
struct timespec * tstamp, unsigned long resolution);
struct _snd_timer_hardware {
/* -- must be filled with low-level driver */
unsigned int flags; /* various flags */
unsigned long resolution; /* average timer resolution for one tick in nsec */
unsigned long resolution_min; /* minimal resolution */
unsigned long resolution_max; /* maximal resolution */
unsigned long ticks; /* max timer ticks per interrupt */
/* -- low-level functions -- */
int (*open) (snd_timer_t * timer);
......@@ -71,6 +81,8 @@ struct _snd_timer_hardware {
unsigned long (*c_resolution) (snd_timer_t * timer);
int (*start) (snd_timer_t * timer);
int (*stop) (snd_timer_t * timer);
int (*set_period) (snd_timer_t * timer, unsigned long period_num, unsigned long period_den);
int (*precise_resolution) (snd_timer_t * timer, unsigned long *num, unsigned long *den);
};
struct _snd_timer {
......@@ -102,6 +114,7 @@ struct _snd_timer_instance {
void *private_data;
void (*private_free) (snd_timer_instance_t *ti);
snd_timer_callback_t callback;
snd_timer_ccallback_t ccallback;
void *callback_data;
unsigned long ticks; /* auto-load ticks when expired */
unsigned long cticks; /* current ticks */
......@@ -123,20 +136,19 @@ struct _snd_timer_instance {
*/
extern int snd_timer_new(snd_card_t *card, char *id, snd_timer_id_t *tid, snd_timer_t ** rtimer);
extern void snd_timer_notify(snd_timer_t *timer, enum sndrv_timer_event event, struct timespec *tstamp);
extern int snd_timer_global_new(char *id, int device, snd_timer_t **rtimer);
extern int snd_timer_global_free(snd_timer_t *timer);
extern int snd_timer_global_register(snd_timer_t *timer);
extern int snd_timer_global_unregister(snd_timer_t *timer);
extern snd_timer_instance_t *snd_timer_open(char *owner, snd_timer_id_t *tid, unsigned int slave_id);
extern int snd_timer_open(snd_timer_instance_t ** ti, char *owner, snd_timer_id_t *tid, unsigned int slave_id);
extern int snd_timer_close(snd_timer_instance_t * timeri);
extern int snd_timer_set_owner(snd_timer_instance_t * timeri, pid_t pid, gid_t gid);
extern int snd_timer_reset_owner(snd_timer_instance_t * timeri);
extern int snd_timer_set_resolution(snd_timer_instance_t * timeri, unsigned long resolution);
extern unsigned long snd_timer_resolution(snd_timer_instance_t * timeri);
extern int snd_timer_start(snd_timer_instance_t * timeri, unsigned int ticks);
extern int snd_timer_stop(snd_timer_instance_t * timeri);
extern int snd_timer_continue(snd_timer_instance_t * timeri);
extern int snd_timer_pause(snd_timer_instance_t * timeri);
extern void snd_timer_interrupt(snd_timer_t * timer, unsigned long ticks_left);
......
......@@ -365,10 +365,16 @@ struct _snd_trident_voice {
int running: 1,
capture: 1,
spdif: 1,
foldback: 1;
foldback: 1,
isync: 1,
isync2: 1,
isync3: 1;
int foldback_chan; /* foldback subdevice number */
unsigned int stimer; /* global sample timer (to detect spurious interrupts) */
unsigned int spurious_threshold; /* spurious threshold */
unsigned int isync_mark;
unsigned int isync_max;
unsigned int isync_ESO;
/* --- */
......@@ -448,6 +454,7 @@ struct _snd_trident {
snd_seq_device_t *seq_dev;
ac97_t *ac97;
ac97_t *ac97_sec;
unsigned int musicvol_wavevol;
snd_trident_pcm_mixer_t pcm_mixer[32];
......
......@@ -15,10 +15,15 @@
* features support
*/
/* $Id: uda1341.h,v 1.2 2002/04/17 07:53:22 perex Exp $ */
/* $Id: uda1341.h,v 1.4 2003/02/25 12:48:16 perex Exp $ */
#define UDA1341_ALSA_NAME "snd-uda1341"
/*
* Default rate set after inicialization
*/
#define AUDIO_RATE_DEFAULT 44100
/*
* UDA1341 L3 address and command types
*/
......
/* include/version.h. Generated by configure. */
#define CONFIG_SND_VERSION "0.9.0rc7"
#define CONFIG_SND_DATE " (Sat Feb 15 15:01:21 2003 UTC)"
#define CONFIG_SND_VERSION "0.9.2"
#define CONFIG_SND_DATE " (Thu Mar 20 13:31:57 2003 UTC)"
This diff is collapsed.
......@@ -14,8 +14,10 @@ endif
snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
pcm_memory.o
snd-page-alloc-objs := memalloc.o
ifeq ($(CONFIG_PCI),y)
snd-pcm-objs += pcm_sgbuf.o
snd-page-alloc-objs += sgbuf.o memory_wrapper.o
endif
snd-rawmidi-objs := rawmidi.o
......@@ -31,72 +33,72 @@ endif
obj-$(CONFIG_SND_HWDEP) += snd-hwdep.o
obj-$(CONFIG_SND_MIXER_OSS) += oss/
obj-$(CONFIG_SND_PCM_OSS) += snd-pcm.o snd-timer.o oss/
obj-$(CONFIG_SND_PCM_OSS) += snd-pcm.o snd-timer.o snd-page-alloc.o oss/
obj-$(CONFIG_SND_SEQUENCER) += snd-timer.o seq/
obj-$(CONFIG_SND_BIT32_EMUL) += ioctl32/
# Toplevel Module Dependency
obj-$(CONFIG_SND_DUMMY) += snd-pcm.o snd-timer.o snd.o
obj-$(CONFIG_SND_DUMMY) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
obj-$(CONFIG_SND_VIRMIDI) += snd-rawmidi.o snd.o snd-timer.o
obj-$(CONFIG_SND_SERIAL_U16550) += snd-rawmidi.o snd.o snd-timer.o
obj-$(CONFIG_SND_MTPAV) += snd-rawmidi.o snd.o snd-timer.o
obj-$(CONFIG_SND_MPU401) += snd-rawmidi.o snd.o snd-timer.o
obj-$(CONFIG_SND_ALS100) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_AZT2320) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_CMI8330) += snd-pcm.o snd-timer.o snd.o
obj-$(CONFIG_SND_DT019X) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_ES18XX) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_OPL3SA2) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_SGALAXY) += snd-pcm.o snd-timer.o snd.o
obj-$(CONFIG_SND_AD1816A) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_AD1848) += snd-pcm.o snd-timer.o snd.o
obj-$(CONFIG_SND_CS4231) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_CS4232) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_CS4236) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_ES1688) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_GUSCLASSIC) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_GUSMAX) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_GUSEXTREME) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_INTERWAVE) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_INTERWAVE_STB) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_OPTI93X) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_SB8) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_SB16) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_SBAWE) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_ES968) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_WAVEFRONT) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_ALS4000) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_CMIPCI) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_CS4281) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_ENS1370) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_ENS1371) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_ES1938) += snd-pcm.o snd-timer.o snd.o snd-hwdep.o snd-rawmidi.o
obj-$(CONFIG_SND_ES1968) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_FM801) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_ICE1712) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_INTEL8X0) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_MAESTRO3) += snd-pcm.o snd-timer.o snd.o
obj-$(CONFIG_SND_RME32) += snd-pcm.o snd-timer.o snd.o
obj-$(CONFIG_SND_RME96) += snd-pcm.o snd-timer.o snd.o
obj-$(CONFIG_SND_SONICVIBES) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_VIA82XX) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_ALI5451) += snd.o snd-rawmidi.o snd-timer.o snd-pcm.o
obj-$(CONFIG_SND_CS46XX) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_EMU10K1) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_KORG1212) += snd-pcm.o snd-timer.o snd.o
obj-$(CONFIG_SND_NM256) += snd-pcm.o snd-timer.o snd.o
obj-$(CONFIG_SND_RME9652) += snd-pcm.o snd-timer.o snd.o
obj-$(CONFIG_SND_HDSP) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_TRIDENT) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_YMFPCI) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_POWERMAC) += snd-pcm.o snd-timer.o snd.o
obj-$(CONFIG_SND_SA11XX_UDA1341) += snd-pcm.o snd-timer.o snd.o
obj-$(CONFIG_SND_ALS100) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_AZT2320) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_CMI8330) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
obj-$(CONFIG_SND_DT019X) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_ES18XX) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_OPL3SA2) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_SGALAXY) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
obj-$(CONFIG_SND_AD1816A) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_AD1848) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
obj-$(CONFIG_SND_CS4231) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_CS4232) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_CS4236) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_ES1688) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_GUSCLASSIC) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_GUSMAX) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_GUSEXTREME) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_INTERWAVE) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_INTERWAVE_STB) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_OPTI93X) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_SB8) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_SB16) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_SBAWE) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_ES968) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_WAVEFRONT) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_ALS4000) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_CMIPCI) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_CS4281) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_ENS1370) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_ENS1371) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_ES1938) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-hwdep.o snd-rawmidi.o
obj-$(CONFIG_SND_ES1968) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_FM801) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_ICE1712) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_INTEL8X0) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_MAESTRO3) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
obj-$(CONFIG_SND_RME32) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
obj-$(CONFIG_SND_RME96) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
obj-$(CONFIG_SND_SONICVIBES) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_VIA82XX) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_ALI5451) += snd.o snd-rawmidi.o snd-timer.o snd-page-alloc.o snd-pcm.o
obj-$(CONFIG_SND_CS46XX) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_EMU10K1) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_KORG1212) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
obj-$(CONFIG_SND_NM256) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
obj-$(CONFIG_SND_RME9652) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
obj-$(CONFIG_SND_HDSP) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_TRIDENT) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_YMFPCI) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_POWERMAC) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
obj-$(CONFIG_SND_SA11XX_UDA1341) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
ifeq ($(CONFIG_SND_SB16_CSP),y)
obj-$(CONFIG_SND_SB16) += snd-hwdep.o
obj-$(CONFIG_SND_SBAWE) += snd-hwdep.o
endif
obj-$(CONFIG_SND_USB_AUDIO) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_USB_AUDIO) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o
obj-m := $(sort $(obj-m))
......@@ -714,14 +714,14 @@ static int snd_ctl_ioctl(struct inode *inode, struct file *file,
return -EFAULT;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
err = -ENOPROTOOPT;
#ifdef CONFIG_PM
if (card->set_power_state) {
snd_power_lock(card);
err = card->set_power_state(card, err);
snd_power_unlock(card);
}
} else
#endif
err = -ENOPROTOOPT;
return err;
case SNDRV_CTL_IOCTL_POWER_STATE:
#ifdef CONFIG_PM
......
......@@ -107,7 +107,12 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
#endif
init_waitqueue_entry(&wait, current);
add_wait_queue(&hw->open_wait, &wait);
down(&hw->open_mutex);
while (1) {
if (hw->exclusive && hw->used > 0) {
err = -EBUSY;
break;
}
err = hw->ops.open(hw, file);
if (err >= 0)
break;
......@@ -127,20 +132,26 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&hw->open_wait, &wait);
if (err >= 0)
if (err >= 0) {
file->private_data = hw;
hw->used++;
}
up(&hw->open_mutex);
return err;
}
static int snd_hwdep_release(struct inode *inode, struct file * file)
{
int err;
int err = -ENXIO;
snd_hwdep_t *hw = snd_magic_cast(snd_hwdep_t, file->private_data, return -ENXIO);
down(&hw->open_mutex);
if (hw->ops.release) {
err = hw->ops.release(hw, file);
wake_up(&hw->open_wait);
return err;
}
if (hw->used > 0)
hw->used--;
up(&hw->open_mutex);
return -ENXIO;
}
......@@ -166,14 +177,58 @@ static int snd_hwdep_info(snd_hwdep_t *hw, snd_hwdep_info_t *_info)
return 0;
}
static int snd_hwdep_dsp_status(snd_hwdep_t *hw, snd_hwdep_dsp_status_t *_info)
{
snd_hwdep_dsp_status_t info;
int err;
if (! hw->ops.dsp_status)
return -ENXIO;
memset(&info, 0, sizeof(info));
info.dsp_loaded = hw->dsp_loaded;
if ((err = hw->ops.dsp_status(hw, &info)) < 0)
return err;
if (copy_to_user(_info, &info, sizeof(info)))
return -EFAULT;
return 0;
}
static int snd_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *_info)
{
snd_hwdep_dsp_image_t info;
int err;
if (! hw->ops.dsp_load || ! hw->ops.dsp_status)
return -ENXIO;
memset(&info, 0, sizeof(info));
if (copy_from_user(&info, _info, sizeof(info)))
return -EFAULT;
/* check whether the dsp was already loaded */
if (hw->dsp_loaded & (1 << info.index))
return -EBUSY;
if (verify_area(VERIFY_READ, info.image, info.length))
return -EFAULT;
err = hw->ops.dsp_load(hw, &info);
if (err < 0)
return err;
hw->dsp_loaded |= (1 << info.index);
return 0;
}
static int snd_hwdep_ioctl(struct inode *inode, struct file * file,
unsigned int cmd, unsigned long arg)
{
snd_hwdep_t *hw = snd_magic_cast(snd_hwdep_t, file->private_data, return -ENXIO);
if (cmd == SNDRV_HWDEP_IOCTL_PVERSION)
switch (cmd) {
case SNDRV_HWDEP_IOCTL_PVERSION:
return put_user(SNDRV_HWDEP_VERSION, (int *)arg);
if (cmd == SNDRV_HWDEP_IOCTL_INFO)
case SNDRV_HWDEP_IOCTL_INFO:
return snd_hwdep_info(hw, (snd_hwdep_info_t *)arg);
case SNDRV_HWDEP_IOCTL_DSP_STATUS:
return snd_hwdep_dsp_status(hw, (snd_hwdep_dsp_status_t *)arg);
case SNDRV_HWDEP_IOCTL_DSP_LOAD:
return snd_hwdep_dsp_load(hw, (snd_hwdep_dsp_image_t *)arg);
}
if (hw->ops.ioctl)
return hw->ops.ioctl(hw, file, cmd, arg);
return -ENOTTY;
......@@ -298,6 +353,7 @@ int snd_hwdep_new(snd_card_t * card, char *id, int device, snd_hwdep_t ** rhwdep
return err;
}
init_waitqueue_head(&hwdep->open_wait);
init_MUTEX(&hwdep->open_mutex);
*rhwdep = hwdep;
return 0;
}
......
......@@ -220,7 +220,7 @@ static ssize_t snd_info_entry_read(struct file *file, char *buffer,
buf = data->rbuffer;
if (buf == NULL)
return -EIO;
if (file->f_pos >= buf->size)
if (file->f_pos >= (long)buf->size)
return 0;
size = buf->size < count ? buf->size : count;
size1 = buf->size - file->f_pos;
......@@ -260,7 +260,7 @@ static ssize_t snd_info_entry_write(struct file *file, const char *buffer,
return -EIO;
if (file->f_pos < 0)
return -EINVAL;
if (file->f_pos >= buf->len)
if (file->f_pos >= (long)buf->len)
return -ENOMEM;
size = buf->len < count ? buf->len : count;
size1 = buf->len - file->f_pos;
......@@ -268,7 +268,7 @@ static ssize_t snd_info_entry_write(struct file *file, const char *buffer,
size = size1;
if (copy_from_user(buf->buffer + file->f_pos, buffer, size))
return -EFAULT;
if (buf->size < file->f_pos + size)
if ((long)buf->size < file->f_pos + size)
buf->size = file->f_pos + size;
file->f_pos += size;
break;
......
......@@ -495,6 +495,22 @@ void snd_card_info_read_oss(snd_info_buffer_t * buffer)
#endif
#ifdef MODULE
static snd_info_entry_t *snd_card_module_info_entry;
static void snd_card_module_info_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
{
int idx;
snd_card_t *card;
for (idx = 0; idx < SNDRV_CARDS; idx++) {
read_lock(&snd_card_rwlock);
if ((card = snd_cards[idx]) != NULL)
snd_iprintf(buffer, "%i %s\n", idx, card->module->name);
read_unlock(&snd_card_rwlock);
}
}
#endif
int __init snd_card_info_init(void)
{
snd_info_entry_t *entry;
......@@ -509,6 +525,20 @@ int __init snd_card_info_init(void)
return -ENOMEM;
}
snd_card_info_entry = entry;
#ifdef MODULE
entry = snd_info_create_module_entry(THIS_MODULE, "modules", NULL);
if (entry) {
entry->content = SNDRV_INFO_CONTENT_TEXT;
entry->c.text.read_size = PAGE_SIZE;
entry->c.text.read = snd_card_module_info_read;
if (snd_info_register(entry) < 0)
snd_info_free_entry(entry);
else
snd_card_module_info_entry = entry;
}
#endif
return 0;
}
......@@ -516,6 +546,10 @@ int __exit snd_card_info_done(void)
{
if (snd_card_info_entry)
snd_info_unregister(snd_card_info_entry);
#ifdef MODULE
if (snd_card_module_info_entry)
snd_info_unregister(snd_card_module_info_entry);
#endif
return 0;
}
......
......@@ -20,13 +20,54 @@
#include <sound/driver.h>
#include <linux/time.h>
#include <linux/fs.h>
#include <sound/core.h>
#include <sound/timer.h>
#include <sound/hwdep.h>
#include <asm/uaccess.h>
#include "ioctl32.h"
struct sndrv_hwdep_dsp_image32 {
u32 index;
unsigned char name[64];
u32 image; /* pointer */
u32 length;
u32 driver_data;
} /* don't set packed attribute here */;
static int _snd_ioctl32_hwdep_dsp_image(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
{
struct sndrv_hwdep_dsp_image data;
struct sndrv_hwdep_dsp_image data32;
mm_segment_t oldseg;
int err;
if (copy_from_user(&data32, (void*)arg, sizeof(data32)))
return -EFAULT;
memset(&data, 0, sizeof(data));
data.index = data32.index;
memcpy(data.name, data32.name, sizeof(data.name));
data.image = A(data32.image);
data.length = data32.length;
data.driver_data = data32.driver_data;
oldseg = get_fs();
set_fs(KERNEL_DS);
err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);
set_fs(oldseg);
return err;
}
DEFINE_ALSA_IOCTL_ENTRY(hwdep_dsp_image, hwdep_dsp_image, SNDRV_HWDEP_IOCTL_DSP_LOAD);
#define AP(x) snd_ioctl32_##x
enum {
SNDRV_HWDEP_IOCTL_DSP_LOAD32 = _IOW('H', 0x03, struct sndrv_hwdep_dsp_image32)
};
struct ioctl32_mapper hwdep_mappers[] = {
{ SNDRV_HWDEP_IOCTL_PVERSION, NULL },
{ SNDRV_HWDEP_IOCTL_INFO, NULL },
MAP_COMPAT(SNDRV_HWDEP_IOCTL_PVERSION),
MAP_COMPAT(SNDRV_HWDEP_IOCTL_INFO),
MAP_COMPAT(SNDRV_HWDEP_IOCTL_DSP_STATUS),
{ SNDRV_HWDEP_IOCTL_DSP_LOAD32, AP(hwdep_dsp_image) },
{ 0 },
};
......@@ -96,5 +96,8 @@ unsigned int snd_dma_pointer(unsigned long dma, unsigned int size)
if (result > size)
snd_printk(KERN_ERR "pointer (0x%x) for DMA #%ld is greater than transfer size (0x%x)\n", result, dma, size);
#endif
return result >= size ? 0 : size - result;
if (result >= size || result == 0)
return 0;
else
return size - result;
}
This diff is collapsed.
This diff is collapsed.
/*
* Copyright (c) by Jaroslav Kysela <perex@suse.cz>
* Takashi Iwai <tiwai@suse.de>
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/config.h>
#include <linux/version.h>
#include <linux/pci.h>
#include <sound/memalloc.h>
#ifdef HACK_PCI_ALLOC_CONSISTENT
/*
* A dirty hack... when the kernel code is fixed this should be removed.
*
* since pci_alloc_consistent always tries GFP_DMA when the requested
* pci memory region is below 32bit, it happens quite often that even
* 2 order of pages cannot be allocated.
*
* so in the following, we allocate at first without dma_mask, so that
* allocation will be done without GFP_DMA. if the area doesn't match
* with the requested region, then realloate with the original dma_mask
* again.
*/
void *snd_pci_hack_alloc_consistent(struct pci_dev *hwdev, size_t size,
dma_addr_t *dma_handle)
{
void *ret;
u64 dma_mask;
unsigned long rmask;
if (hwdev == NULL)
return pci_alloc_consistent(hwdev, size, dma_handle);
dma_mask = hwdev->dma_mask;
rmask = ~((unsigned long)dma_mask);
hwdev->dma_mask = 0xffffffff; /* do without masking */
ret = pci_alloc_consistent(hwdev, size, dma_handle);
hwdev->dma_mask = dma_mask; /* restore */
if (ret) {
/* obtained address is out of range? */
if (((unsigned long)*dma_handle + size - 1) & rmask) {
/* reallocate with the proper mask */
pci_free_consistent(hwdev, size, ret, *dma_handle);
ret = pci_alloc_consistent(hwdev, size, dma_handle);
}
} else {
/* wish to success now with the proper mask... */
if (dma_mask != 0xffffffff)
ret = pci_alloc_consistent(hwdev, size, dma_handle);
}
return ret;
}
#endif /* HACK_PCI_ALLOC_CONSISTENT */
......@@ -77,27 +77,6 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...)
va_end(args);
tmpbuf[sizeof(tmpbuf)-1] = '\0';
printk(tmpbuf);
}
#endif
#if defined(CONFIG_SND_DEBUG) && !defined(CONFIG_SND_VERBOSE_PRINTK)
void snd_printd(const char *format, ...)
{
va_list args;
char tmpbuf[512];
if (format[0] == '<' && format[1] >= '0' && format[1] <= '9' && format[2] == '>') {
char tmp[] = "<0>";
tmp[1] = format[1];
printk("%sALSA: ", tmp);
format += 3;
} else {
printk(KERN_DEBUG "ALSA: ");
}
va_start(args, format);
vsnprintf(tmpbuf, sizeof(tmpbuf)-1, format, args);
va_end(args);
tmpbuf[sizeof(tmpbuf)-1] = '\0';
printk(tmpbuf);
}
#endif
This diff is collapsed.
......@@ -386,10 +386,10 @@ static void snd_pcm_substream_proc_status_read(snd_info_entry_t *entry, snd_info
return;
}
snd_iprintf(buffer, "state: %s\n", snd_pcm_state_name(status.state));
snd_iprintf(buffer, "trigger_time: %ld.%06ld\n",
status.trigger_tstamp.tv_sec, status.trigger_tstamp.tv_usec);
snd_iprintf(buffer, "tstamp : %ld.%06ld\n",
status.tstamp.tv_sec, status.tstamp.tv_usec);
snd_iprintf(buffer, "trigger_time: %ld.%09ld\n",
status.trigger_tstamp.tv_sec, status.trigger_tstamp.tv_nsec);
snd_iprintf(buffer, "tstamp : %ld.%09ld\n",
status.tstamp.tv_sec, status.tstamp.tv_nsec);
snd_iprintf(buffer, "delay : %ld\n", status.delay);
snd_iprintf(buffer, "avail : %ld\n", status.avail);
snd_iprintf(buffer, "avail_max : %ld\n", status.avail_max);
......@@ -595,8 +595,6 @@ int snd_pcm_new_stream(snd_pcm_t *pcm, int stream, int substream_count)
snd_magic_kfree(substream);
return err;
}
substream->dma_type = SNDRV_PCM_DMA_TYPE_UNKNOWN;
substream->dma_private = NULL;
spin_lock_init(&substream->timer_lock);
prev = substream;
}
......
......@@ -137,7 +137,7 @@ int snd_pcm_update_hw_ptr_interrupt(snd_pcm_substream_t *substream)
old_hw_ptr = runtime->status->hw_ptr;
pos = substream->ops->pointer(substream);
if (runtime->tstamp_mode & SNDRV_PCM_TSTAMP_MMAP)
snd_timestamp_now((snd_timestamp_t*)&runtime->status->tstamp);
snd_timestamp_now((snd_timestamp_t*)&runtime->status->tstamp, runtime->tstamp_timespec);
#ifdef CONFIG_SND_DEBUG
if (pos >= runtime->buffer_size) {
snd_printk(KERN_ERR "BUG: stream = %i, pos = 0x%lx, buffer size = 0x%lx, period size = 0x%lx\n", substream->stream, pos, runtime->buffer_size, runtime->period_size);
......@@ -198,7 +198,7 @@ int snd_pcm_update_hw_ptr(snd_pcm_substream_t *substream)
old_hw_ptr = runtime->status->hw_ptr;
pos = substream->ops->pointer(substream);
if (runtime->tstamp_mode & SNDRV_PCM_TSTAMP_MMAP)
snd_timestamp_now((snd_timestamp_t*)&runtime->status->tstamp);
snd_timestamp_now((snd_timestamp_t*)&runtime->status->tstamp, runtime->tstamp_timespec);
#ifdef CONFIG_SND_DEBUG
if (pos >= runtime->buffer_size) {
snd_printk(KERN_ERR "BUG: stream = %i, pos = 0x%lx, buffer size = 0x%lx, period size = 0x%lx\n", substream->stream, pos, runtime->buffer_size, runtime->period_size);
......@@ -2186,6 +2186,8 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(snd_pcm_substream_t *substream,
} else {
runtime->control->appl_ptr = appl_ptr;
}
if (substream->ops->ack)
substream->ops->ack(substream);
offset += frames;
size -= frames;
......@@ -2478,6 +2480,8 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(snd_pcm_substream_t *substream, void
} else {
runtime->control->appl_ptr = appl_ptr;
}
if (substream->ops->ack)
substream->ops->ack(substream);
offset += frames;
size -= frames;
......@@ -2654,6 +2658,9 @@ EXPORT_SYMBOL(snd_pcm_lib_preallocate_isa_pages_for_all);
#ifdef CONFIG_PCI
EXPORT_SYMBOL(snd_pcm_lib_preallocate_pci_pages);
EXPORT_SYMBOL(snd_pcm_lib_preallocate_pci_pages_for_all);
EXPORT_SYMBOL(snd_pcm_lib_preallocate_sg_pages);
EXPORT_SYMBOL(snd_pcm_lib_preallocate_sg_pages_for_all);
EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
#endif
#ifdef CONFIG_SBUS
EXPORT_SYMBOL(snd_pcm_lib_preallocate_sbus_pages);
......
This diff is collapsed.
......@@ -527,7 +527,7 @@ u_int8_t snd_pcm_format_silence(snd_pcm_format_t format)
*
* Sets the silence data on the buffer for the given samples.
*
* Returns zero if sucessful, or a negative error code on failure.
* Returns zero if successful, or a negative error code on failure.
*/
int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples)
{
......
......@@ -30,6 +30,7 @@
#include <sound/info.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/timer.h>
#include <sound/minors.h>
/*
......@@ -514,9 +515,9 @@ int snd_pcm_status(snd_pcm_substream_t *substream,
if (runtime->tstamp_mode & SNDRV_PCM_TSTAMP_MMAP)
status->tstamp = runtime->status->tstamp;
else
snd_timestamp_now(&status->tstamp);
snd_timestamp_now(&status->tstamp, runtime->tstamp_timespec);
} else
snd_timestamp_now(&status->tstamp);
snd_timestamp_now(&status->tstamp, runtime->tstamp_timespec);
status->appl_ptr = runtime->control->appl_ptr;
status->hw_ptr = runtime->status->hw_ptr;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
......@@ -585,15 +586,15 @@ static int snd_pcm_channel_info(snd_pcm_substream_t * substream, snd_pcm_channel
return 0;
}
static void snd_pcm_trigger_time(snd_pcm_substream_t *substream)
static void snd_pcm_trigger_tstamp(snd_pcm_substream_t *substream)
{
snd_pcm_runtime_t *runtime = substream->runtime;
if (runtime->trigger_master == NULL)
return;
if (runtime->trigger_master == substream) {
snd_timestamp_now(&runtime->trigger_tstamp);
snd_timestamp_now(&runtime->trigger_tstamp, runtime->tstamp_timespec);
} else {
snd_pcm_trigger_time(runtime->trigger_master);
snd_pcm_trigger_tstamp(runtime->trigger_master);
runtime->trigger_tstamp = runtime->trigger_master->runtime->trigger_tstamp;
}
runtime->trigger_master = NULL;
......@@ -668,13 +669,15 @@ static inline int snd_pcm_do_start(snd_pcm_substream_t *substream, int state)
static inline void snd_pcm_post_start(snd_pcm_substream_t *substream, int state)
{
snd_pcm_runtime_t *runtime = substream->runtime;
snd_pcm_trigger_time(substream);
snd_pcm_trigger_tstamp(substream);
runtime->status->state = SNDRV_PCM_STATE_RUNNING;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
runtime->silence_size > 0)
snd_pcm_playback_silence(substream, ULONG_MAX);
if (runtime->sleep_min)
snd_pcm_tick_prepare(substream);
if (substream->timer)
snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTART, &runtime->trigger_tstamp);
}
/**
......@@ -703,7 +706,9 @@ static inline int snd_pcm_do_stop(snd_pcm_substream_t *substream, int state)
static inline void snd_pcm_post_stop(snd_pcm_substream_t *substream, int state)
{
snd_pcm_runtime_t *runtime = substream->runtime;
snd_pcm_trigger_time(substream);
snd_pcm_trigger_tstamp(substream);
if (substream->timer)
snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTOP, &runtime->trigger_tstamp);
runtime->status->state = state;
snd_pcm_tick_set(substream, 0);
wake_up(&runtime->sleep);
......@@ -741,15 +746,19 @@ static inline int snd_pcm_do_pause(snd_pcm_substream_t *substream, int push)
static inline void snd_pcm_post_pause(snd_pcm_substream_t *substream, int push)
{
snd_pcm_runtime_t *runtime = substream->runtime;
snd_pcm_trigger_time(substream);
snd_pcm_trigger_tstamp(substream);
if (push) {
runtime->status->state = SNDRV_PCM_STATE_PAUSED;
if (substream->timer)
snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MPAUSE, &runtime->trigger_tstamp);
snd_pcm_tick_set(substream, 0);
wake_up(&runtime->sleep);
} else {
runtime->status->state = SNDRV_PCM_STATE_RUNNING;
if (runtime->sleep_min)
snd_pcm_tick_prepare(substream);
if (substream->timer)
snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MCONTINUE, &runtime->trigger_tstamp);
}
}
......@@ -782,7 +791,9 @@ static inline int snd_pcm_do_suspend(snd_pcm_substream_t *substream, int state)
static inline void snd_pcm_post_suspend(snd_pcm_substream_t *substream, int state)
{
snd_pcm_runtime_t *runtime = substream->runtime;
snd_pcm_trigger_time(substream);
snd_pcm_trigger_tstamp(substream);
if (substream->timer)
snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MPAUSE, &runtime->trigger_tstamp);
runtime->status->state = SNDRV_PCM_STATE_SUSPENDED;
snd_pcm_tick_set(substream, 0);
wake_up(&runtime->sleep);
......@@ -847,7 +858,9 @@ static inline int snd_pcm_do_resume(snd_pcm_substream_t *substream, int state)
static inline void snd_pcm_post_resume(snd_pcm_substream_t *substream, int state)
{
snd_pcm_runtime_t *runtime = substream->runtime;
snd_pcm_trigger_time(substream);
snd_pcm_trigger_tstamp(substream);
if (substream->timer)
snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MCONTINUE, &runtime->trigger_tstamp);
runtime->status->state = runtime->status->suspended_state;
if (runtime->sleep_min)
snd_pcm_tick_prepare(substream);
......@@ -1733,9 +1746,12 @@ static int snd_pcm_release_file(snd_pcm_file_t * pcm_file)
runtime = substream->runtime;
str = substream->pstr;
snd_pcm_unlink(substream);
if (substream->ops->hw_free != NULL)
substream->ops->hw_free(substream);
substream->ops->close(substream);
if (substream->open_flag) {
if (substream->ops->hw_free != NULL)
substream->ops->hw_free(substream);
substream->ops->close(substream);
substream->open_flag = 0;
}
substream->ffile = NULL;
snd_pcm_remove_file(str, pcm_file);
snd_pcm_release_substream(substream);
......@@ -1784,6 +1800,7 @@ static int snd_pcm_open_file(struct file *file,
snd_pcm_release_file(pcm_file);
return err;
}
substream->open_flag = 1;
err = snd_pcm_hw_constraints_complete(substream);
if (err < 0) {
......@@ -1982,6 +1999,106 @@ snd_pcm_sframes_t snd_pcm_capture_rewind(snd_pcm_substream_t *substream, snd_pcm
return ret;
}
snd_pcm_sframes_t snd_pcm_playback_forward(snd_pcm_substream_t *substream, snd_pcm_uframes_t frames)
{
snd_pcm_runtime_t *runtime = substream->runtime;
snd_pcm_sframes_t appl_ptr;
snd_pcm_sframes_t ret;
snd_pcm_sframes_t avail;
if (frames == 0)
return 0;
spin_lock_irq(&runtime->lock);
switch (runtime->status->state) {
case SNDRV_PCM_STATE_PREPARED:
case SNDRV_PCM_STATE_PAUSED:
break;
case SNDRV_PCM_STATE_DRAINING:
case SNDRV_PCM_STATE_RUNNING:
if (snd_pcm_update_hw_ptr(substream) >= 0)
break;
/* Fall through */
case SNDRV_PCM_STATE_XRUN:
ret = -EPIPE;
goto __end;
default:
ret = -EBADFD;
goto __end;
}
avail = snd_pcm_playback_avail(runtime);
if (avail <= 0) {
ret = 0;
goto __end;
}
if (frames > (snd_pcm_uframes_t)avail)
frames = avail;
else
frames -= frames % runtime->xfer_align;
appl_ptr = runtime->control->appl_ptr + frames;
if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary)
appl_ptr -= runtime->boundary;
runtime->control->appl_ptr = appl_ptr;
if (runtime->status->state == SNDRV_PCM_STATE_RUNNING &&
runtime->sleep_min)
snd_pcm_tick_prepare(substream);
ret = frames;
__end:
spin_unlock_irq(&runtime->lock);
return ret;
}
snd_pcm_sframes_t snd_pcm_capture_forward(snd_pcm_substream_t *substream, snd_pcm_uframes_t frames)
{
snd_pcm_runtime_t *runtime = substream->runtime;
snd_pcm_sframes_t appl_ptr;
snd_pcm_sframes_t ret;
snd_pcm_sframes_t avail;
if (frames == 0)
return 0;
spin_lock_irq(&runtime->lock);
switch (runtime->status->state) {
case SNDRV_PCM_STATE_PREPARED:
case SNDRV_PCM_STATE_DRAINING:
case SNDRV_PCM_STATE_PAUSED:
break;
case SNDRV_PCM_STATE_RUNNING:
if (snd_pcm_update_hw_ptr(substream) >= 0)
break;
/* Fall through */
case SNDRV_PCM_STATE_XRUN:
ret = -EPIPE;
goto __end;
default:
ret = -EBADFD;
goto __end;
}
avail = snd_pcm_capture_avail(runtime);
if (avail <= 0) {
ret = 0;
goto __end;
}
if (frames > (snd_pcm_uframes_t)avail)
frames = avail;
else
frames -= frames % runtime->xfer_align;
appl_ptr = runtime->control->appl_ptr + frames;
if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary)
appl_ptr -= runtime->boundary;
runtime->control->appl_ptr = appl_ptr;
if (runtime->status->state == SNDRV_PCM_STATE_RUNNING &&
runtime->sleep_min)
snd_pcm_tick_prepare(substream);
ret = frames;
__end:
spin_unlock_irq(&runtime->lock);
return ret;
}
static int snd_pcm_hwsync(snd_pcm_substream_t *substream)
{
snd_pcm_runtime_t *runtime = substream->runtime;
......@@ -2065,6 +2182,14 @@ static int snd_pcm_common_ioctl1(snd_pcm_substream_t *substream,
return put_user(SNDRV_PCM_VERSION, (int *)arg) ? -EFAULT : 0;
case SNDRV_PCM_IOCTL_INFO:
return snd_pcm_info_user(substream, (snd_pcm_info_t *) arg);
case SNDRV_PCM_IOCTL_TSTAMP:
{
int xarg;
if (get_user(xarg, (int *) arg))
return -EFAULT;
substream->runtime->tstamp_timespec = xarg ? 1 : 0;
return 0;
}
case SNDRV_PCM_IOCTL_HW_REFINE:
return snd_pcm_hw_refine_user(substream, (snd_pcm_hw_params_t *) arg);
case SNDRV_PCM_IOCTL_HW_PARAMS:
......@@ -2169,6 +2294,18 @@ static int snd_pcm_playback_ioctl1(snd_pcm_substream_t *substream,
__put_user(result, _frames);
return result < 0 ? result : 0;
}
case SNDRV_PCM_IOCTL_FORWARD:
{
snd_pcm_uframes_t frames, *_frames = arg;
snd_pcm_sframes_t result;
if (get_user(frames, _frames))
return -EFAULT;
if (put_user(0, _frames))
return -EFAULT;
result = snd_pcm_playback_forward(substream, frames);
__put_user(result, _frames);
return result < 0 ? result : 0;
}
case SNDRV_PCM_IOCTL_PAUSE:
{
int res;
......@@ -2244,6 +2381,18 @@ static int snd_pcm_capture_ioctl1(snd_pcm_substream_t *substream,
__put_user(result, _frames);
return result < 0 ? result : 0;
}
case SNDRV_PCM_IOCTL_FORWARD:
{
snd_pcm_uframes_t frames, *_frames = arg;
snd_pcm_sframes_t result;
if (get_user(frames, _frames))
return -EFAULT;
if (put_user(0, _frames))
return -EFAULT;
result = snd_pcm_capture_forward(substream, frames);
__put_user(result, _frames);
return result < 0 ? result : 0;
}
case SNDRV_PCM_IOCTL_DRAIN:
return snd_pcm_capture_drain(substream);
case SNDRV_PCM_IOCTL_DROP:
......
/*
* Scatter-Gather PCM access
*
* Copyright (c) by Takashi Iwai <tiwai@suse.de>
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <sound/driver.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_sgbuf.h>
/* table entries are align to 32 */
#define SGBUF_TBL_ALIGN 32
#define sgbuf_align_table(tbl) ((((tbl) + SGBUF_TBL_ALIGN - 1) / SGBUF_TBL_ALIGN) * SGBUF_TBL_ALIGN)
/**
* snd_pcm_sgbuf_alloc_pages - allocate the pages for the SG buffer
* @pci: the pci device pointer
* @size: the requested buffer size in bytes
* @dmab: the dma-buffer record to store
*
* Initializes the SG-buffer table and allocates the buffer pages
* for the given size.
* The pages are mapped to the virtually continuous memory.
*
* This function is usually called from snd_pcm_lib_malloc_pages().
*
* Returns the mapped virtual address of the buffer if allocation was
* successful, or NULL at error.
*/
void *snd_pcm_sgbuf_alloc_pages(struct pci_dev *pci, size_t size, struct snd_pcm_dma_buffer *dmab)
{
struct snd_sg_buf *sgbuf;
unsigned int i, pages;
dmab->area = NULL;
dmab->addr = 0;
dmab->private_data = sgbuf = snd_magic_kcalloc(snd_pcm_sgbuf_t, 0, GFP_KERNEL);
if (! sgbuf)
return NULL;
sgbuf->pci = pci;
pages = snd_pcm_sgbuf_pages(size);
sgbuf->tblsize = sgbuf_align_table(pages);
sgbuf->table = snd_kcalloc(sizeof(*sgbuf->table) * sgbuf->tblsize, GFP_KERNEL);
if (! sgbuf->table)
goto _failed;
sgbuf->page_table = snd_kcalloc(sizeof(*sgbuf->page_table) * sgbuf->tblsize, GFP_KERNEL);
if (! sgbuf->page_table)
goto _failed;
/* allocate each page */
for (i = 0; i < pages; i++) {
void *ptr;
dma_addr_t addr;
ptr = snd_malloc_pci_page(sgbuf->pci, &addr);
if (! ptr)
goto _failed;
sgbuf->table[i].buf = ptr;
sgbuf->table[i].addr = addr;
sgbuf->page_table[i] = virt_to_page(ptr);
sgbuf->pages++;
}
sgbuf->size = size;
dmab->area = vmap(sgbuf->page_table, sgbuf->pages);
if (! dmab->area)
goto _failed;
return dmab->area;
_failed:
snd_pcm_sgbuf_free_pages(dmab); /* free the table */
return NULL;
}
/**
* snd_pcm_sgbuf_free_pages - free the sg buffer
* @dmab: dma buffer record
*
* Releases the pages and the SG-buffer table.
*
* This function is called usually from snd_pcm_lib_free_pages().
*
* Returns zero if successful, or a negative error code on failure.
*/
int snd_pcm_sgbuf_free_pages(struct snd_pcm_dma_buffer *dmab)
{
struct snd_sg_buf *sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, dmab->private_data, return -EINVAL);
int i;
for (i = 0; i < sgbuf->pages; i++)
snd_free_pci_page(sgbuf->pci, sgbuf->table[i].buf, sgbuf->table[i].addr);
if (dmab->area)
vunmap(dmab->area);
dmab->area = NULL;
if (sgbuf->table)
kfree(sgbuf->table);
if (sgbuf->page_table)
kfree(sgbuf->page_table);
snd_magic_kfree(sgbuf);
dmab->private_data = NULL;
return 0;
}
/**
* snd_pcm_sgbuf_ops_page - get the page struct at the given offset
* @substream: the pcm substream instance
* @offset: the buffer offset
*
* Returns the page struct at the given buffer offset.
* Used as the page callback of PCM ops.
*/
struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset)
{
struct snd_sg_buf *sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, _snd_pcm_substream_sgbuf(substream), return NULL);
unsigned int idx = offset >> PAGE_SHIFT;
if (idx >= (unsigned int)sgbuf->pages)
return NULL;
return sgbuf->page_table[idx];
}
/*
* Exported symbols
*/
EXPORT_SYMBOL(snd_pcm_lib_preallocate_sg_pages);
EXPORT_SYMBOL(snd_pcm_lib_preallocate_sg_pages_for_all);
EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
......@@ -79,7 +79,8 @@ static inline int snd_rawmidi_ready(snd_rawmidi_substream_t * substream)
static inline int snd_rawmidi_ready_append(snd_rawmidi_substream_t * substream, size_t count)
{
snd_rawmidi_runtime_t *runtime = substream->runtime;
return runtime->avail >= runtime->avail_min && runtime->avail >= count;
return runtime->avail >= runtime->avail_min &&
(!substream->append || runtime->avail >= count);
}
static int snd_rawmidi_init(snd_rawmidi_substream_t *substream)
......
......@@ -51,7 +51,7 @@ static int translate_mode(struct file *file);
static int create_port(seq_oss_devinfo_t *dp);
static int delete_port(seq_oss_devinfo_t *dp);
static int alloc_seq_queue(seq_oss_devinfo_t *dp);
static int delete_seq_queue(seq_oss_devinfo_t *dp);
static int delete_seq_queue(int queue);
static void free_devinfo(void *private);
#define call_ctl(type,rec) snd_seq_kernel_client_ctl(system_client, type, rec)
......@@ -186,6 +186,7 @@ snd_seq_oss_open(struct file *file, int level)
snd_printk(KERN_ERR "can't malloc device info\n");
return -ENOMEM;
}
debug_printk(("oss_open: dp = %p\n", dp));
for (i = 0; i < SNDRV_SEQ_OSS_MAX_CLIENTS; i++) {
if (client_table[i] == NULL)
......@@ -193,6 +194,7 @@ snd_seq_oss_open(struct file *file, int level)
}
if (i >= SNDRV_SEQ_OSS_MAX_CLIENTS) {
snd_printk(KERN_ERR "too many applications\n");
kfree(dp);
return -ENOMEM;
}
......@@ -209,22 +211,21 @@ snd_seq_oss_open(struct file *file, int level)
if (dp->synth_opened == 0 && dp->max_mididev == 0) {
snd_printk(KERN_ERR "no device found\n");
kfree(dp);
return -ENODEV;
rc = -ENODEV;
goto _error;
}
/* create port */
debug_printk(("create new port\n"));
if ((rc = create_port(dp)) < 0) {
snd_printk(KERN_ERR "can't create port\n");
free_devinfo(dp);
return rc;
goto _error;
}
/* allocate queue */
if ((rc = alloc_seq_queue(dp)) < 0) {
delete_port(dp);
return rc;
}
debug_printk(("allocate queue\n"));
if ((rc = alloc_seq_queue(dp)) < 0)
goto _error;
/* set address */
dp->addr.client = dp->cseq;
......@@ -238,31 +239,32 @@ snd_seq_oss_open(struct file *file, int level)
dp->file_mode = translate_mode(file);
/* initialize read queue */
debug_printk(("initialize read queue\n"));
if (is_read_mode(dp->file_mode)) {
if ((dp->readq = snd_seq_oss_readq_new(dp, maxqlen)) == NULL) {
delete_seq_queue(dp);
delete_port(dp);
return -ENOMEM;
rc = -ENOMEM;
goto _error;
}
}
/* initialize write queue */
debug_printk(("initialize write queue\n"));
if (is_write_mode(dp->file_mode)) {
dp->writeq = snd_seq_oss_writeq_new(dp, maxqlen);
if (dp->writeq == NULL) {
delete_seq_queue(dp);
delete_port(dp);
return -ENOMEM;
rc = -ENOMEM;
goto _error;
}
}
/* initialize timer */
debug_printk(("initialize timer\n"));
if ((dp->timer = snd_seq_oss_timer_new(dp)) == NULL) {
snd_printk(KERN_ERR "can't alloc timer\n");
delete_seq_queue(dp);
delete_port(dp);
return -ENOMEM;
rc = -ENOMEM;
goto _error;
}
debug_printk(("timer initialized\n"));
/* set private data pointer */
file->private_data = dp;
......@@ -277,8 +279,16 @@ snd_seq_oss_open(struct file *file, int level)
num_clients++;
debug_printk(("open done\n"));
return 0;
_error:
snd_seq_oss_synth_cleanup(dp);
snd_seq_oss_midi_cleanup(dp);
i = dp->queue;
delete_port(dp);
delete_seq_queue(i);
return rc;
}
/*
......@@ -344,6 +354,7 @@ delete_port(seq_oss_devinfo_t *dp)
if (dp->port < 0)
return 0;
debug_printk(("delete_port %i\n", dp->port));
memset(&port_info, 0, sizeof(port_info));
port_info.addr.client = dp->cseq;
port_info.addr.port = dp->port;
......@@ -375,15 +386,19 @@ alloc_seq_queue(seq_oss_devinfo_t *dp)
* release queue
*/
static int
delete_seq_queue(seq_oss_devinfo_t *dp)
delete_seq_queue(int queue)
{
snd_seq_queue_info_t qinfo;
int rc;
if (dp->queue < 0)
if (queue < 0)
return 0;
memset(&qinfo, 0, sizeof(qinfo));
qinfo.queue = dp->queue;
return call_ctl(SNDRV_SEQ_IOCTL_DELETE_QUEUE, &qinfo);
qinfo.queue = queue;
rc = call_ctl(SNDRV_SEQ_IOCTL_DELETE_QUEUE, &qinfo);
if (rc < 0)
printk(KERN_ERR "seq-oss: unable to delete queue %d (%d)\n", queue, rc);
return rc;
}
......@@ -414,6 +429,8 @@ free_devinfo(void *private)
void
snd_seq_oss_release(seq_oss_devinfo_t *dp)
{
int queue;
client_table[dp->index] = NULL;
num_clients--;
......@@ -426,10 +443,10 @@ snd_seq_oss_release(seq_oss_devinfo_t *dp)
/* clear slot */
debug_printk(("releasing resource..\n"));
queue = dp->queue;
if (dp->port >= 0)
delete_port(dp);
if (dp->queue >= 0)
delete_seq_queue(dp);
delete_seq_queue(queue);
debug_printk(("release done\n"));
}
......
......@@ -206,9 +206,9 @@ snd_seq_oss_midi_check_new_port(snd_seq_port_info_t *pinfo)
}
if (i >= max_midi_devs) {
if (max_midi_devs >= SNDRV_SEQ_OSS_MAX_MIDI_DEVS) {
spin_unlock_irqrestore(&register_lock, flags);
snd_midi_event_free(mdev->coder);
kfree(mdev);
spin_unlock_irqrestore(&register_lock, flags);
return -ENOMEM;
}
max_midi_devs++;
......@@ -372,6 +372,8 @@ snd_seq_oss_midi_open(seq_oss_devinfo_t *dp, int dev, int fmode)
subs.sender.client = mdev->client;
subs.sender.port = mdev->port;
subs.dest = dp->addr;
subs.flags = SNDRV_SEQ_PORT_SUBS_TIMESTAMP;
subs.queue = dp->queue; /* queue for timestamps */
if (snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs) >= 0)
mdev->opened |= PERM_READ;
}
......@@ -462,8 +464,7 @@ snd_seq_oss_midi_reset(seq_oss_devinfo_t *dp, int dev)
return;
}
if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC &&
(mdev->opened & PERM_WRITE)) {
if (mdev->opened & PERM_WRITE) {
snd_seq_event_t ev;
int c;
......@@ -473,16 +474,22 @@ snd_seq_oss_midi_reset(seq_oss_devinfo_t *dp, int dev)
ev.dest.port = mdev->port;
ev.queue = dp->queue;
ev.source.port = dp->port;
if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_SYNTH) {
ev.type = SNDRV_SEQ_EVENT_SENSING;
snd_seq_oss_dispatch(dp, &ev, 0, 0); /* active sensing */
}
for (c = 0; c < 16; c++) {
ev.type = SNDRV_SEQ_EVENT_CONTROLLER;
ev.data.control.channel = c;
ev.data.control.param = 123;
snd_seq_oss_dispatch(dp, &ev, 0, 0); /* all notes off */
ev.data.control.param = 121;
snd_seq_oss_dispatch(dp, &ev, 0, 0); /* reset all controllers */
ev.type = SNDRV_SEQ_EVENT_PITCHBEND;
ev.data.control.value = 0;
snd_seq_oss_dispatch(dp, &ev, 0, 0); /* bender off */
if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) {
ev.data.control.param = 121;
snd_seq_oss_dispatch(dp, &ev, 0, 0); /* reset all controllers */
ev.type = SNDRV_SEQ_EVENT_PITCHBEND;
ev.data.control.value = 0;
snd_seq_oss_dispatch(dp, &ev, 0, 0); /* bender off */
}
}
}
snd_seq_oss_midi_close(dp, dev);
......@@ -597,10 +604,12 @@ send_synth_event(seq_oss_devinfo_t *dp, snd_seq_event_t *ev, int dev)
static int
send_midi_event(seq_oss_devinfo_t *dp, snd_seq_event_t *ev, seq_oss_midi_t *mdev)
{
char msg[32]; /* enough except for sysex? */
char msg[32];
int len;
snd_seq_oss_readq_put_timestamp(dp->readq, snd_seq_oss_timer_cur_tick(dp->timer), dp->seq_mode);
snd_seq_oss_readq_put_timestamp(dp->readq, ev->time.tick, dp->seq_mode);
if (!dp->timer->running)
len = snd_seq_oss_timer_start(dp->timer);
if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {
if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) == SNDRV_SEQ_EVENT_LENGTH_VARIABLE)
snd_seq_oss_readq_puts(dp->readq, mdev->seq_device,
......
......@@ -302,29 +302,36 @@ snd_seq_oss_synth_cleanup(seq_oss_devinfo_t *dp)
seq_oss_synth_t *rec;
seq_oss_synthinfo_t *info;
snd_assert(dp->max_synthdev <= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS, return);
for (i = 0; i < dp->max_synthdev; i++) {
info = &dp->synths[i];
if (! info->opened)
continue;
if (info->is_midi) {
snd_seq_oss_midi_close(dp, info->midi_mapped);
midi_synth_dev.opened--;
if (midi_synth_dev.opened > 0) {
snd_seq_oss_midi_close(dp, info->midi_mapped);
midi_synth_dev.opened--;
}
} else {
rec = get_sdev(i);
if (rec == NULL)
continue;
if (rec->opened) {
if (rec->opened > 0) {
debug_printk(("synth %d closed\n", i));
rec->oper.close(&info->arg);
module_put(rec->oper.owner);
rec->opened--;
rec->opened = 0;
}
snd_use_lock_free(&rec->use_lock);
}
if (info->sysex)
if (info->sysex) {
kfree(info->sysex);
if (info->ch)
info->sysex = NULL;
}
if (info->ch) {
kfree(info->ch);
info->ch = NULL;
}
}
dp->synth_opened = 0;
dp->max_synthdev = 0;
......@@ -401,15 +408,21 @@ snd_seq_oss_synth_reset(seq_oss_devinfo_t *dp, int dev)
info->sysex->len = 0; /* reset sysex */
reset_channels(info);
if (info->is_midi) {
if (midi_synth_dev.opened <= 0)
return;
snd_seq_oss_midi_reset(dp, info->midi_mapped);
if (snd_seq_oss_midi_open(dp, info->midi_mapped,
dp->file_mode) < 0) {
midi_synth_dev.opened--;
info->opened = 0;
if (info->sysex)
if (info->sysex) {
kfree(info->sysex);
if (info->ch)
info->sysex = NULL;
}
if (info->ch) {
kfree(info->ch);
info->ch = NULL;
}
}
return;
}
......
......@@ -272,6 +272,21 @@ static void snd_seq_midisynth_delete(seq_midisynth_t *msynth)
snd_midi_event_free(msynth->parser);
}
/* set our client name */
static int set_client_name(seq_midisynth_client_t *client, snd_card_t *card,
snd_rawmidi_info_t *rmidi)
{
snd_seq_client_info_t cinfo;
const char *name;
memset(&cinfo, 0, sizeof(cinfo));
cinfo.client = client->seq_client;
cinfo.type = KERNEL_CLIENT;
name = rmidi->name[0] ? (const char *)rmidi->name : "External MIDI";
snprintf(cinfo.name, sizeof(cinfo.name), "Rawmidi %d - %s", card->number, name);
return snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &cinfo);
}
/* register new midi synth port */
int
snd_seq_midisynth_register_port(snd_seq_device_t *dev)
......@@ -284,7 +299,6 @@ snd_seq_midisynth_register_port(snd_seq_device_t *dev)
unsigned int p, ports;
snd_seq_client_callback_t callbacks;
snd_seq_port_callback_t pcallbacks;
snd_seq_client_info_t inf;
snd_card_t *card = dev->card;
int device = dev->device;
unsigned int input_count = 0, output_count = 0;
......@@ -325,13 +339,9 @@ snd_seq_midisynth_register_port(snd_seq_device_t *dev)
up(&register_mutex);
return -ENOMEM;
}
/* set our client name */
memset(&inf,0,sizeof(snd_seq_client_info_t));
inf.client = client->seq_client;
inf.type = KERNEL_CLIENT;
sprintf(inf.name, "External MIDI %i", card->number);
snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &inf);
}
set_client_name(client, card, &info);
} else if (device == 0)
set_client_name(client, card, &info); /* use the first device's name */
msynth = snd_kcalloc(sizeof(seq_midisynth_t) * ports, GFP_KERNEL);
if (msynth == NULL)
......@@ -358,10 +368,18 @@ snd_seq_midisynth_register_port(snd_seq_device_t *dev)
if (snd_rawmidi_info_select(card, &info) >= 0)
strcpy(port.name, info.subname);
if (! port.name[0]) {
if (ports > 1)
sprintf(port.name, "MIDI %d-%d-%d", card->number, device, p);
else
sprintf(port.name, "MIDI %d-%d", card->number, device);
if (info.name[0]) {
if (ports > 1)
snprintf(port.name, sizeof(port.name), "%s-%d", info.name, p);
else
snprintf(port.name, sizeof(port.name), "%s", info.name);
} else {
/* last resort */
if (ports > 1)
sprintf(port.name, "MIDI %d-%d-%d", card->number, device, p);
else
sprintf(port.name, "MIDI %d-%d", card->number, device);
}
}
if ((info.flags & SNDRV_RAWMIDI_INFO_OUTPUT) && p < output_count)
port.capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
......
This diff is collapsed.
......@@ -81,6 +81,7 @@ typedef struct client_port_t {
/* supported channels */
int midi_channels;
int midi_voices;
int synth_voices;
} client_port_t;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -54,6 +54,15 @@ MODULE_DEVICES("{{ALSA,Dummy soundcard}}");
#define USE_PERIODS_MAX 2
#endif
#if 0 /* ICE1712 emulation */
#define MAX_BUFFER_SIZE (256 * 1024)
#define USE_FORMATS SNDRV_PCM_FMTBIT_S32_LE
#define USE_CHANNELS_MIN 12
#define USE_CHANNELS_MAX 12
#define USE_PERIODS_MIN 1
#define USE_PERIODS_MAX 1024
#endif
#if 0 /* UDA1341 emulation */
#define MAX_BUFFER_SIZE (16380)
#define USE_FORMATS SNDRV_PCM_FMTBIT_S16_LE
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment