Commit f22951c6 authored by Jaroslav Kysela's avatar Jaroslav Kysela

Alsa sync

parents 1274fcd6 addcf6d4
......@@ -110,9 +110,9 @@
</para>
<para>
One is the the trees provided as a tarball or via cvs from the
One is the trees provided as a tarball or via cvs from the
ALSA's ftp site, and another is the 2.6 (or later) Linux kernel
tree. To synchronize both, the ALSA driver tree is split to
tree. To synchronize both, the ALSA driver tree is split into
two different trees: alsa-kernel and alsa-driver. The former
contains purely the source codes for the Linux 2.6 (or later)
tree. This tree is designed only for compilation on 2.6 or
......@@ -766,7 +766,7 @@
</para>
<para>
The ALSA interfaces like PCM or control API are define in other
The ALSA interfaces like PCM or control API are defined in other
header files as <filename>&lt;sound/xxx.h&gt;</filename>.
They have to be included after
<filename>&lt;sound/core.h&gt;</filename>.
......@@ -1103,7 +1103,7 @@
/* release the irq */
if (chip->irq >= 0)
free_irq(chip->irq, (void *)chip);
/* release the i/o ports */
/* release the i/o ports & memory */
pci_release_regions(chip->pci);
/* disable the PCI entry */
pci_disable_device(chip->pci);
......@@ -1314,6 +1314,7 @@
</para>
<para>
<!-- obsolete -->
It will reserve the i/o port region of 8 bytes of the given
PCI device. The returned value, chip-&gt;res_port, is allocated
via <function>kmalloc()</function> by
......@@ -1936,6 +1937,7 @@
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
&snd_mychip_capture_ops);
/* pre-allocation of buffers */
/* NOTE: this may fail */
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci),
64*1024, 64*1024);
......@@ -1950,7 +1952,7 @@
<section id="pcm-interface-constructor">
<title>Constructor</title>
<para>
A pcm instance is allocated <function>snd_pcm_new()</function>
A pcm instance is allocated by <function>snd_pcm_new()</function>
function. It would be better to create a constructor for pcm,
namely,
......@@ -2235,7 +2237,8 @@ struct _snd_pcm_runtime {
unsigned char *dma_area; /* DMA area */
dma_addr_t dma_addr; /* physical bus address (not accessible from main CPU) */
size_t dma_bytes; /* size of DMA area */
void *dma_private; /* private DMA data for the memory allocator */
struct snd_dma_buffer *dma_buffer_p; /* allocated buffer */
#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
/* -- OSS things -- */
......@@ -2250,7 +2253,7 @@ struct _snd_pcm_runtime {
<para>
For the operators (callbacks) of each sound driver, most of
these records are supposed to be read-only. Only the PCM
middle-layer changes / updates these info. The excpetions are
middle-layer changes / updates these info. The exceptions are
the hardware description (hw), interrupt callbacks
(transfer_ack_xxx), DMA buffer information, and the private
data. Besides, if you use the standard buffer allocation
......@@ -3250,7 +3253,7 @@ struct _snd_pcm_runtime {
<para>
There are many different constraints.
Look in <filename>sound/asound.h</filename> for a complete list.
Look in <filename>sound/pcm.h</filename> for a complete list.
You can even define your own constraint rules.
For example, let's suppose my_chip can manage a substream of 1 channel
if and only if the format is S16_LE, otherwise it supports any format
......@@ -4066,7 +4069,7 @@ struct _snd_pcm_runtime {
Both <function>snd_ac97_write()</function> and
<function>snd_ac97_update()</function> functions are used to
set a value to the given register
(<constant>AC97_XXX</constant>). The different between them is
(<constant>AC97_XXX</constant>). The difference between them is
that <function>snd_ac97_update()</function> doesn't write a
value if the given value has been already set, while
<function>snd_ac97_write()</function> always rewrites the
......@@ -4152,8 +4155,8 @@ struct _snd_pcm_runtime {
<title>Proc Files</title>
<para>
The ALSA AC97 interface will create a proc file such as
<filename>/proc/asound/card0/ac97#0</filename> and
<filename>ac97#0regs</filename>. You can refer to these files to
<filename>/proc/asound/card0/codec97#0/ac97#0-0</filename> and
<filename>ac97#0-0+regs</filename>. You can refer to these files to
see the current status and registers of the codec.
</para>
</section>
......@@ -4633,7 +4636,7 @@ struct _snd_pcm_runtime {
where <parameter>size</parameter> is the byte size to be
pre-allocated and the <parameter>max</parameter> is the maximal
size to be changed via <filename>prealloc</filename> proc file.
The allocator will try to get as the large area as possible
The allocator will try to get as large area as possible
within the given size.
</para>
......@@ -4855,7 +4858,7 @@ struct _snd_pcm_runtime {
If your hardware supports the page table like emu10k1 or the
buffer descriptors like via82xx, you can use the scatter-gather
(SG) DMA. ALSA provides an interface for handling SG-buffers.
The API is provided in <filename>&lt;sound/pcm_sgbuf.h&gt;</filename>.
The API is provided in <filename>&lt;sound/pcm.h&gt;</filename>.
</para>
<para>
......@@ -5159,12 +5162,12 @@ struct _snd_pcm_runtime {
<programlisting>
<![CDATA[
#ifdef CONFIG_PM
static int snd_my_suspend(snd_card_t *card, unsigned int state)
static int snd_my_suspend(snd_card_t *card, pm_message_t state)
{
.... // do things for suspsend
return 0;
}
static int snd_my_resume(snd_card_t *card, unsigned int state)
static int snd_my_resume(snd_card_t *card)
{
.... // do things for suspsend
return 0;
......@@ -5193,7 +5196,7 @@ struct _snd_pcm_runtime {
<informalexample>
<programlisting>
<![CDATA[
static int mychip_suspend(snd_card_t *card, unsigned int state)
static int mychip_suspend(snd_card_t *card, pm_message_t state)
{
/* (1) */
mychip_t *chip = card->pm_private_data;
......
VIA82xx mixer
=============
On many VIA82xx boards, the 'Input Source Select' mixer control does not work.
Setting it to 'Input2' on such boards will cause recording to hang, or fail
with EIO (input/output error) via OSS emulation. This control should be left
at 'Input1' for such cards.
This diff is collapsed.
This diff is collapsed.
......@@ -106,7 +106,7 @@
#define AK4117_DIF_24L (AK4117_DIF2) /* STDO: 24-bit, left justified */
#define AK4117_DIF_24I2S (AK4117_DIF2|AK4117_DIF0) /* STDO: I2S */
/* AK4117_REG_INT0_MASK & AK4117_INT1_MASK */
/* AK4117_REG_INT0_MASK & AK4117_REG_INT1_MASK */
#define AK4117_MULK (1<<7) /* mask enable for UNLOCK bit */
#define AK4117_MPAR (1<<6) /* mask enable for PAR bit */
#define AK4117_MAUTO (1<<5) /* mask enable for AUTO bit */
......@@ -181,8 +181,8 @@ struct ak4117 {
int snd_ak4117_create(snd_card_t *card, ak4117_read_t *read, ak4117_write_t *write,
unsigned char pgm[5], void *private_data, ak4117_t **r_ak4117);
void snd_ak4117_reg_write(ak4117_t *chip, unsigned char reg, unsigned char mask, unsigned char val);
void snd_ak4117_reinit(ak4117_t *chip);
void snd_ak4117_reg_write(ak4117_t *ak4117, unsigned char reg, unsigned char mask, unsigned char val);
void snd_ak4117_reinit(ak4117_t *ak4117);
int snd_ak4117_build(ak4117_t *ak4117, snd_pcm_substream_t *capture_substream);
int snd_ak4117_external_rate(ak4117_t *ak4117);
int snd_ak4117_check_rate_and_errors(ak4117_t *ak4117, unsigned int flags);
......
......@@ -50,7 +50,8 @@ struct snd_akm4xxx {
/* template should fill the following fields */
unsigned int idx_offset; /* control index offset */
enum {
SND_AK4524, SND_AK4528, SND_AK4529, SND_AK4355, SND_AK4381
SND_AK4524, SND_AK4528, SND_AK4529,
SND_AK4355, SND_AK4358, SND_AK4381
} type;
struct snd_ak4xxx_ops ops;
};
......
......@@ -119,6 +119,13 @@ int snd_ctl_create(snd_card_t *card);
int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn);
int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn);
#ifdef CONFIG_COMPAT
int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn);
int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn);
#else
#define snd_ctl_register_ioctl_compat(fcn)
#define snd_ctl_unregister_ioctl_compat(fcn)
#endif
int snd_ctl_elem_read(snd_card_t *card, snd_ctl_elem_value_t *control);
int snd_ctl_elem_write(snd_card_t *card, snd_ctl_file_t *file, snd_ctl_elem_value_t *control);
......
......@@ -26,6 +26,7 @@
#include <asm/semaphore.h> /* struct semaphore */
#include <linux/rwsem.h> /* struct rw_semaphore */
#include <linux/workqueue.h> /* struct workqueue_struct */
#include <linux/pm.h> /* pm_message_t */
/* Typedef's */
typedef struct timespec snd_timestamp_t;
......@@ -167,13 +168,15 @@ struct _snd_card {
struct device *dev;
#ifdef CONFIG_PM
int (*pm_suspend)(snd_card_t *card, unsigned int state);
int (*pm_resume)(snd_card_t *card, unsigned int state);
struct pm_dev *pm_dev; /* for ISA */
int (*pm_suspend)(snd_card_t *card, pm_message_t state);
int (*pm_resume)(snd_card_t *card);
void *pm_private_data;
unsigned int power_state; /* power state */
struct semaphore power_lock; /* power lock */
wait_queue_head_t power_sleep;
#ifdef CONFIG_SND_GENERIC_PM
struct snd_generic_device *pm_dev; /* for ISA */
#endif
#endif
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
......@@ -206,36 +209,34 @@ static inline void snd_power_change_state(snd_card_t *card, unsigned int state)
wake_up(&card->power_sleep);
}
int snd_card_set_pm_callback(snd_card_t *card,
int (*suspend)(snd_card_t *, unsigned int),
int (*resume)(snd_card_t *, unsigned int),
int (*suspend)(snd_card_t *, pm_message_t),
int (*resume)(snd_card_t *),
void *private_data);
int snd_card_set_dev_pm_callback(snd_card_t *card, int type,
int (*suspend)(snd_card_t *, unsigned int),
int (*resume)(snd_card_t *, unsigned int),
void *private_data);
int snd_card_set_generic_pm_callback(snd_card_t *card,
int (*suspend)(snd_card_t *, pm_message_t),
int (*resume)(snd_card_t *),
void *private_data);
#define snd_card_set_isa_pm_callback(card,suspend,resume,data) \
snd_card_set_dev_pm_callback(card, PM_ISA_DEV, suspend, resume, data)
#ifdef CONFIG_PCI
#ifndef SND_PCI_PM_CALLBACKS
int snd_card_pci_suspend(struct pci_dev *dev, u32 state);
snd_card_set_generic_pm_callback(card, suspend, resume, data)
struct pci_dev;
int snd_card_pci_suspend(struct pci_dev *dev, pm_message_t state);
int snd_card_pci_resume(struct pci_dev *dev);
#define SND_PCI_PM_CALLBACKS \
.suspend = snd_card_pci_suspend, .resume = snd_card_pci_resume
#endif
#endif
#else
#else /* ! CONFIG_PM */
#define snd_power_lock(card) do { (void)(card); } while (0)
#define snd_power_unlock(card) do { (void)(card); } while (0)
static inline int snd_power_wait(snd_card_t *card, unsigned int state, struct file *file) { return 0; }
#define snd_power_get_state(card) SNDRV_CTL_POWER_D0
#define snd_power_change_state(card, state) do { (void)(card); } while (0)
#define snd_card_set_pm_callback(card,suspend,resume,data)
#define snd_card_set_dev_pm_callback(card,suspend,resume,data)
#define snd_card_set_generic_pm_callback(card,suspend,resume,data)
#define snd_card_set_isa_pm_callback(card,suspend,resume,data)
#ifdef CONFIG_PCI
#define SND_PCI_PM_CALLBACKS
#endif
#endif
#endif /* CONFIG_PM */
/* device.c */
......
......@@ -710,9 +710,10 @@
#define A_FXWC2 0x75 /* Selects 0x9f-0x80 for FX recording */
#define A_SPDIF_SAMPLERATE 0x76 /* Set the sample rate of SPDIF output */
#define A_SPDIF_48000 0x00000080
#define A_SPDIF_44100 0x00000000
#define A_SPDIF_96000 0x00000040
#define A_SPDIF_RATE_MASK 0x000000c0
#define A_SPDIF_48000 0x00000000
#define A_SPDIF_44100 0x00000040
#define A_SPDIF_96000 0x00000080
#define A_FXRT2 0x7c
#define A_FXRT_CHANNELE 0x0000003f /* Effects send bus number for channel's effects send E */
......@@ -1112,7 +1113,10 @@ int snd_emu10k1_fx8010_unregister_irq_handler(emu10k1_t *emu,
/* GPRs */
#define FXBUS(x) (0x00 + (x)) /* x = 0x00 - 0x0f */
#define EXTIN(x) (0x10 + (x)) /* x = 0x00 - 0x0f */
#define EXTOUT(x) (0x20 + (x)) /* x = 0x00 - 0x0f */
#define EXTOUT(x) (0x20 + (x)) /* x = 0x00 - 0x0f physical outs -> FXWC low 16 bits */
#define FXBUS2(x) (0x30 + (x)) /* x = 0x00 - 0x0f copies of fx buses for capture -> FXWC high 16 bits */
/* NB: 0x31 and 0x32 are shared with Center/LFE on SB live 5.1 */
#define C_00000000 0x40
#define C_00000001 0x41
#define C_00000002 0x42
......@@ -1154,9 +1158,13 @@ int snd_emu10k1_fx8010_unregister_irq_handler(emu10k1_t *emu,
#define A_ITRAM_CTL(x) (A_TANKMEMCTLREGBASE + 0x00 + (x)) /* x = 0x00 - 0xbf */
#define A_ETRAM_CTL(x) (A_TANKMEMCTLREGBASE + 0xc0 + (x)) /* x = 0x00 - 0x3f */
#define A_FXBUS(x) (0x00 + (x)) /* x = 0x00 - 0x3f? */
#define A_EXTIN(x) (0x40 + (x)) /* x = 0x00 - 0x1f? */
#define A_EXTOUT(x) (0x60 + (x)) /* x = 0x00 - 0x1f? */
#define A_FXBUS(x) (0x00 + (x)) /* x = 0x00 - 0x3f FX buses */
#define A_EXTIN(x) (0x40 + (x)) /* x = 0x00 - 0x0f physical ins */
#define A_P16VIN(x) (0x50 + (x)) /* x = 0x00 - 0x0f p16v ins (A2 only) "EMU32 inputs" */
#define A_EXTOUT(x) (0x60 + (x)) /* x = 0x00 - 0x1f physical outs -> A_FXWC1 0x79-7f unknown */
#define A_FXBUS2(x) (0x80 + (x)) /* x = 0x00 - 0x1f extra outs used for EFX capture -> A_FXWC2 */
#define A_EMU32OUTH(x) (0xa0 + (x)) /* x = 0x00 - 0x0f "EMU32_OUT_10 - _1F" - ??? */
#define A_EMU32OUTL(x) (0xb0 + (x)) /* x = 0x00 - 0x0f "EMU32_OUT_1 - _F" - ??? */
#define A_GPR(x) (A_FXGPREGBASE + (x))
/* cc_reg constants */
......
......@@ -38,6 +38,7 @@ typedef struct _snd_hwdep_ops {
int (*release) (snd_hwdep_t * hw, struct file * file);
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 (*ioctl_compat) (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);
......
#ifndef __SOUND_YSS225_H
#define __SOUND_YSS225_H
extern unsigned char page_zero[256];
extern unsigned char page_one[256];
extern unsigned char page_two[128];
extern unsigned char page_three[128];
extern unsigned char page_four[128];
extern unsigned char page_six[192];
extern unsigned char page_seven[256];
extern unsigned char page_zero_v2[96];
extern unsigned char page_one_v2[96];
extern unsigned char page_two_v2[48];
extern unsigned char page_three_v2[48];
extern unsigned char page_four_v2[48];
extern unsigned char page_seven_v2[96];
extern unsigned char mod_v2[304];
extern unsigned char coefficients[364];
extern unsigned char coefficients2[56];
extern unsigned char coefficients3[404];
#endif /* __SOUND_YSS225_H */
......@@ -21,7 +21,7 @@
* merged HAL layer (patches from Brian)
*/
/* $Id: sa11xx-uda1341.c,v 1.19 2004/12/15 15:26:10 tiwai Exp $ */
/* $Id: sa11xx-uda1341.c,v 1.21 2005/01/28 19:34:04 tiwai Exp $ */
/***************************************************************************************************
*
......@@ -862,7 +862,7 @@ static int __init snd_card_sa11xx_uda1341_pcm(sa11xx_uda1341_t *sa11xx_uda1341,
#ifdef CONFIG_PM
static int snd_sa11xx_uda1341_suspend(snd_card_t *card, unsigned int state)
static int snd_sa11xx_uda1341_suspend(snd_card_t *card, pm_message_t state)
{
sa11xx_uda1341_t *chip = card->pm_private_data;
......@@ -878,7 +878,7 @@ static int snd_sa11xx_uda1341_suspend(snd_card_t *card, unsigned int state)
return 0;
}
static int snd_sa11xx_uda1341_resume(snd_card_t *card, unsigned int state)
static int snd_sa11xx_uda1341_resume(snd_card_t *card)
{
sa11xx_uda1341_t *chip = card->pm_private_data;
......@@ -938,7 +938,7 @@ static int __init sa11xx_uda1341_init(void)
if ((err = snd_card_sa11xx_uda1341_pcm(sa11xx_uda1341, 0)) < 0)
goto nodev;
snd_card_set_dev_pm_callback(card, PM_SYS_DEV,
snd_card_set_generic_pm_callback(card,
snd_sa11xx_uda1341_suspend, snd_sa11_uda1341_resume,
sa11xx_uda1341);
......
# ALSA soundcard-configuration
config SND_TIMER
tristate
depends on SND
config SND_PCM
tristate
select SND_TIMER
depends on SND
config SND_HWDEP
tristate
depends on SND
config SND_RAWMIDI
tristate
depends on SND
config SND_SEQUENCER
tristate "Sequencer support"
......@@ -40,6 +44,7 @@ config SND_SEQ_DUMMY
config SND_OSSEMUL
bool
depends on SND
config SND_MIXER_OSS
tristate "OSS Mixer API"
......@@ -70,7 +75,7 @@ config SND_PCM_OSS
config SND_SEQUENCER_OSS
bool "OSS Sequencer API"
depends on SND_SEQUENCER
depends on SND && SND_SEQUENCER
select SND_OSSEMUL
help
Say Y here to enable OSS sequencer emulation (both
......@@ -81,20 +86,6 @@ config SND_SEQUENCER_OSS
To compile this driver as a module, choose M here: the module
will be called snd-seq-oss.
config SND_BIT32_EMUL
tristate "Emulation for 32-bit applications"
depends on SND && COMPAT
select SND_PCM
select SND_RAWMIDI
select SND_TIMER
select SND_HWDEP
help
Say Y here to enable the emulation for 32-bit ALSA-native
applications.
To compile this driver as a module, choose M here: the module
will be called snd-ioctl32.
config SND_RTCTIMER
tristate "RTC Timer support"
depends on SND && RTC
......@@ -137,3 +128,6 @@ config SND_DEBUG_DETECT
Say Y here to enable extra-verbose log messages printed when
detecting devices.
config SND_GENERIC_PM
bool
depends on SND
......@@ -31,4 +31,3 @@ obj-$(CONFIG_SND_RAWMIDI) += snd-rawmidi.o
obj-$(CONFIG_SND_OSSEMUL) += oss/
obj-$(CONFIG_SND_SEQUENCER) += seq/
obj-$(CONFIG_SND_BIT32_EMUL) += ioctl32/
This diff is collapsed.
......@@ -232,8 +232,7 @@ static int snd_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t __user *_in
return 0;
}
static inline int _snd_hwdep_ioctl(struct inode *inode, struct file * file,
unsigned int cmd, unsigned long arg)
static long snd_hwdep_ioctl(struct file * file, unsigned int cmd, unsigned long arg)
{
snd_hwdep_t *hw = file->private_data;
void __user *argp = (void __user *)arg;
......@@ -252,17 +251,6 @@ static inline int _snd_hwdep_ioctl(struct inode *inode, struct file * file,
return -ENOTTY;
}
/* FIXME: need to unlock BKL to allow preemption */
static int snd_hwdep_ioctl(struct inode *inode, struct file * file,
unsigned int cmd, unsigned long arg)
{
int err;
unlock_kernel();
err = _snd_hwdep_ioctl(inode, file, cmd, arg);
lock_kernel();
return err;
}
static int snd_hwdep_mmap(struct file * file, struct vm_area_struct * vma)
{
snd_hwdep_t *hw = file->private_data;
......@@ -315,6 +303,12 @@ static int snd_hwdep_control_ioctl(snd_card_t * card, snd_ctl_file_t * control,
return -ENOIOCTLCMD;
}
#ifdef CONFIG_COMPAT
#include "hwdep_compat.c"
#else
#define snd_hwdep_ioctl_compat NULL
#endif
/*
*/
......@@ -328,7 +322,8 @@ static struct file_operations snd_hwdep_f_ops =
.open = snd_hwdep_open,
.release = snd_hwdep_release,
.poll = snd_hwdep_poll,
.ioctl = snd_hwdep_ioctl,
.unlocked_ioctl = snd_hwdep_ioctl,
.compat_ioctl = snd_hwdep_ioctl_compat,
.mmap = snd_hwdep_mmap,
};
......@@ -509,12 +504,14 @@ static int __init alsa_hwdep_init(void)
}
snd_hwdep_proc_entry = entry;
snd_ctl_register_ioctl(snd_hwdep_control_ioctl);
snd_ctl_register_ioctl_compat(snd_hwdep_control_ioctl);
return 0;
}
static void __exit alsa_hwdep_exit(void)
{
snd_ctl_unregister_ioctl(snd_hwdep_control_ioctl);
snd_ctl_unregister_ioctl_compat(snd_hwdep_control_ioctl);
if (snd_hwdep_proc_entry) {
snd_info_unregister(snd_hwdep_proc_entry);
snd_hwdep_proc_entry = NULL;
......
......@@ -18,13 +18,9 @@
*
*/
#include <sound/driver.h>
#include <linux/time.h>
#include <linux/fs.h>
#include <sound/core.h>
#include <sound/hwdep.h>
#include <asm/uaccess.h>
#include "ioctl32.h"
/* This file is included from hwdep.c */
#include <linux/compat.h>
struct sndrv_hwdep_dsp_image32 {
u32 index;
......@@ -34,40 +30,48 @@ struct sndrv_hwdep_dsp_image32 {
u32 driver_data;
} /* don't set packed attribute here */;
static inline int _snd_ioctl32_hwdep_dsp_image(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
static int snd_hwdep_dsp_load_compat(snd_hwdep_t *hw,
struct sndrv_hwdep_dsp_image32 __user *src)
{
struct sndrv_hwdep_dsp_image __user *data, *dst;
struct sndrv_hwdep_dsp_image32 __user *data32, *src;
struct sndrv_hwdep_dsp_image *dst;
compat_caddr_t ptr;
u32 val;
data32 = compat_ptr(arg);
data = compat_alloc_user_space(sizeof(*data));
dst = compat_alloc_user_space(sizeof(*dst));
/* index and name */
if (copy_in_user(data, data32, 4 + 64))
if (copy_in_user(dst, src, 4 + 64))
return -EFAULT;
if (__get_user(ptr, &data32->image) ||
__put_user(compat_ptr(ptr), &data->image))
if (get_user(ptr, &src->image) ||
put_user(compat_ptr(ptr), &dst->image))
return -EFAULT;
if (get_user(val, &src->length) ||
put_user(val, &dst->length))
return -EFAULT;
if (get_user(val, &src->driver_data) ||
put_user(val, &dst->driver_data))
return -EFAULT;
src = data32;
dst = data;
COPY_CVT(length);
COPY_CVT(driver_data);
return file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data);
}
DEFINE_ALSA_IOCTL_ENTRY(hwdep_dsp_image, hwdep_dsp_image, SNDRV_HWDEP_IOCTL_DSP_LOAD);
#define AP(x) snd_ioctl32_##x
return snd_hwdep_dsp_load(hw, dst);
}
enum {
SNDRV_HWDEP_IOCTL_DSP_LOAD32 = _IOW('H', 0x03, struct sndrv_hwdep_dsp_image32)
};
struct ioctl32_mapper hwdep_mappers[] = {
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 },
};
static long snd_hwdep_ioctl_compat(struct file * file, unsigned int cmd, unsigned long arg)
{
snd_hwdep_t *hw = file->private_data;
void __user *argp = compat_ptr(arg);
switch (cmd) {
case SNDRV_HWDEP_IOCTL_PVERSION:
case SNDRV_HWDEP_IOCTL_INFO:
case SNDRV_HWDEP_IOCTL_DSP_STATUS:
return snd_hwdep_ioctl(file, cmd, (unsigned long)argp);
case SNDRV_HWDEP_IOCTL_DSP_LOAD32:
return snd_hwdep_dsp_load_compat(hw, argp);
}
if (hw->ops.ioctl_compat)
return hw->ops.ioctl_compat(hw, file, cmd, arg);
return -ENOIOCTLCMD;
}
......@@ -39,7 +39,7 @@ struct snd_shutdown_f_ops {
unsigned int snd_cards_lock = 0; /* locked for registering/using */
snd_card_t *snd_cards[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = NULL};
rwlock_t snd_card_rwlock = RW_LOCK_UNLOCKED;
DEFINE_RWLOCK(snd_card_rwlock);
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
int (*snd_mixer_oss_notify_callback)(snd_card_t *card, int free_flag);
......@@ -84,16 +84,13 @@ snd_card_t *snd_card_new(int idx, const char *xid,
write_lock(&snd_card_rwlock);
if (idx < 0) {
int idx2;
for (idx2 = 0; idx2 < snd_ecards_limit; idx2++)
if (!(snd_cards_lock & (1 << idx2))) {
for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)
if (~snd_cards_lock & idx & 1<<idx2) {
idx = idx2;
if (idx >= snd_ecards_limit)
snd_ecards_limit = idx + 1;
break;
}
if (idx < 0 && snd_ecards_limit < SNDRV_CARDS)
/* for dynamically additional devices like hotplug:
* increment the limit if still free slot exists.
*/
idx = snd_ecards_limit++;
} else if (idx < snd_ecards_limit) {
if (snd_cards_lock & (1 << idx))
err = -ENODEV; /* invalid */
......@@ -229,6 +226,10 @@ int snd_card_disconnect(snd_card_t * card)
return 0;
}
#if defined(CONFIG_PM) && defined(CONFIG_SND_GENERIC_PM)
static void snd_generic_device_unregister(struct snd_generic_device *dev);
#endif
/**
* snd_card_free - frees given soundcard structure
* @card: soundcard structure
......@@ -252,9 +253,9 @@ int snd_card_free(snd_card_t * card)
#ifdef CONFIG_PM
wake_up(&card->power_sleep);
#ifdef CONFIG_ISA
#ifdef CONFIG_SND_GENERIC_PM
if (card->pm_dev) {
pm_unregister(card->pm_dev);
snd_generic_device_unregister(card->pm_dev);
card->pm_dev = NULL;
}
#endif
......@@ -374,7 +375,7 @@ static void choose_default_id(snd_card_t * card)
while (1) {
if (loops-- == 0) {
snd_printk(KERN_ERR "unable to choose default card id (%s)", id);
snd_printk(KERN_ERR "unable to choose default card id (%s)\n", id);
strcpy(card->id, card->proc_root->name);
return;
}
......@@ -719,8 +720,8 @@ int snd_power_wait(snd_card_t *card, unsigned int power_state, struct file *file
* handler and from the control API.
*/
int snd_card_set_pm_callback(snd_card_t *card,
int (*suspend)(snd_card_t *, unsigned int),
int (*resume)(snd_card_t *, unsigned int),
int (*suspend)(snd_card_t *, pm_message_t),
int (*resume)(snd_card_t *),
void *private_data)
{
card->pm_suspend = suspend;
......@@ -729,56 +730,132 @@ int snd_card_set_pm_callback(snd_card_t *card,
return 0;
}
static int snd_generic_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
#ifdef CONFIG_SND_GENERIC_PM
/*
* use platform_device for generic power-management without a proper bus
* (e.g. ISA)
*/
struct snd_generic_device {
struct platform_device pdev;
snd_card_t *card;
};
#define get_snd_generic_card(dev) container_of(to_platform_device(dev), struct snd_generic_device, pdev)->card
#define SND_GENERIC_NAME "snd_generic_pm"
static int snd_generic_suspend(struct device *dev, u32 state, u32 level);
static int snd_generic_resume(struct device *dev, u32 level);
static struct device_driver snd_generic_driver = {
.name = SND_GENERIC_NAME,
.bus = &platform_bus_type,
.suspend = snd_generic_suspend,
.resume = snd_generic_resume,
};
static int generic_driver_registered;
static void generic_driver_unregister(void)
{
if (generic_driver_registered) {
generic_driver_registered--;
if (! generic_driver_registered)
driver_unregister(&snd_generic_driver);
}
}
static struct snd_generic_device *snd_generic_device_register(snd_card_t *card)
{
snd_card_t *card = dev->data;
struct snd_generic_device *dev;
switch (rqst) {
case PM_SUSPEND:
if (card->power_state == SNDRV_CTL_POWER_D3hot)
break;
/* FIXME: the correct state value? */
card->pm_suspend(card, 0);
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
break;
case PM_RESUME:
if (card->power_state == SNDRV_CTL_POWER_D0)
break;
/* FIXME: the correct state value? */
card->pm_resume(card, 0);
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
break;
if (! generic_driver_registered) {
if (driver_register(&snd_generic_driver) < 0)
return NULL;
}
generic_driver_registered++;
dev = kcalloc(1, sizeof(*dev), GFP_KERNEL);
if (! dev) {
generic_driver_unregister();
return NULL;
}
dev->pdev.name = SND_GENERIC_NAME;
dev->pdev.id = card->number;
dev->card = card;
if (platform_device_register(&dev->pdev) < 0) {
kfree(dev);
generic_driver_unregister();
return NULL;
}
return dev;
}
static void snd_generic_device_unregister(struct snd_generic_device *dev)
{
platform_device_unregister(&dev->pdev);
kfree(dev);
generic_driver_unregister();
}
/* suspend/resume callbacks for snd_generic platform device */
static int snd_generic_suspend(struct device *dev, u32 state, u32 level)
{
snd_card_t *card;
if (level != SUSPEND_DISABLE)
return 0;
card = get_snd_generic_card(dev);
if (card->power_state == SNDRV_CTL_POWER_D3hot)
return 0;
card->pm_suspend(card, PMSG_SUSPEND);
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
return 0;
}
static int snd_generic_resume(struct device *dev, u32 level)
{
snd_card_t *card;
if (level != RESUME_ENABLE)
return 0;
card = get_snd_generic_card(dev);
if (card->power_state == SNDRV_CTL_POWER_D0)
return 0;
card->pm_resume(card);
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
return 0;
}
/**
* snd_card_set_dev_pm_callback - set the generic power-management callbacks
* snd_card_set_generic_pm_callback - set the generic power-management callbacks
* @card: soundcard structure
* @type: PM device type (PM_XXX)
* @suspend: suspend callback function
* @resume: resume callback function
* @private_data: private data to pass to the callback functions
*
* Registers the power-management and sets the lowlevel callbacks for
* the given card with the given PM type. These callbacks are called
* from the ALSA's common PM handler and from the control API.
* the given card. These callbacks are called from the ALSA's common
* PM handler and from the control API.
*/
int snd_card_set_dev_pm_callback(snd_card_t *card, int type,
int (*suspend)(snd_card_t *, unsigned int),
int (*resume)(snd_card_t *, unsigned int),
int snd_card_set_generic_pm_callback(snd_card_t *card,
int (*suspend)(snd_card_t *, pm_message_t),
int (*resume)(snd_card_t *),
void *private_data)
{
card->pm_dev = pm_register(type, 0, snd_generic_pm_callback);
card->pm_dev = snd_generic_device_register(card);
if (! card->pm_dev)
return -ENOMEM;
card->pm_dev->data = card;
snd_card_set_pm_callback(card, suspend, resume, private_data);
return 0;
}
#endif /* CONFIG_SND_GENERIC_PM */
#ifdef CONFIG_PCI
int snd_card_pci_suspend(struct pci_dev *dev, u32 state)
int snd_card_pci_suspend(struct pci_dev *dev, pm_message_t state)
{
snd_card_t *card = pci_get_drvdata(dev);
int err;
......@@ -786,8 +863,7 @@ int snd_card_pci_suspend(struct pci_dev *dev, u32 state)
return 0;
if (card->power_state == SNDRV_CTL_POWER_D3hot)
return 0;
/* FIXME: correct state value? */
err = card->pm_suspend(card, 0);
err = card->pm_suspend(card, PMSG_SUSPEND);
pci_save_state(dev);
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
return err;
......@@ -802,8 +878,7 @@ int snd_card_pci_resume(struct pci_dev *dev)
return 0;
/* restore the PCI config space */
pci_restore_state(dev);
/* FIXME: correct state value? */
card->pm_resume(card, 0);
card->pm_resume(card);
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
return 0;
}
......
#
# Makefile for ALSA
# Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
#
snd-ioctl32-objs := ioctl32.o pcm32.o rawmidi32.o timer32.o hwdep32.o
ifneq ($(CONFIG_SND_SEQUENCER),n)
snd-ioctl32-objs += seq32.o
endif
obj-$(CONFIG_SND_BIT32_EMUL) += snd-ioctl32.o
/*
* 32bit -> 64bit ioctl helpers
* 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
*
*
* This file registers the converters from 32-bit ioctls to 64-bit ones.
* The converter assumes that a 32-bit user-pointer can be casted by compat_ptr(x)
* macro to a valid 64-bit pointer which is accessible via copy_from/to_user.
*
*/
#ifndef __ALSA_IOCTL32_H
#define __ALSA_IOCTL32_H
#include <linux/compat.h>
#define COPY(x) \
do { \
if (copy_in_user(&dst->x, &src->x, sizeof(dst->x))) \
return -EFAULT; \
} while (0)
#define COPY_ARRAY(x) \
do { \
if (copy_in_user(dst->x, src->x, sizeof(dst->x))) \
return -EFAULT; \
} while (0)
#define COPY_CVT(x) \
do { \
__typeof__(src->x) __val_tmp; \
if (get_user(__val_tmp, &src->x) || \
put_user(__val_tmp, &dst->x))\
return -EFAULT; \
} while (0)
#define convert_from_32(type, dstp, srcp)\
{\
struct sndrv_##type __user *dst = dstp;\
struct sndrv_##type##32 __user *src = srcp;\
CVT_##sndrv_##type();\
}
#define convert_to_32(type, dstp, srcp)\
{\
struct sndrv_##type __user *src = srcp;\
struct sndrv_##type##32 __user *dst = dstp;\
CVT_##sndrv_##type();\
}
#define DEFINE_ALSA_IOCTL(type) \
static inline int _snd_ioctl32_##type(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)\
{\
struct sndrv_##type##32 __user *data32;\
struct sndrv_##type __user *data;\
int err;\
data32 = compat_ptr(arg);\
data = compat_alloc_user_space(sizeof(*data));\
convert_from_32(type, data, data32);\
err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data);\
if (err < 0) \
return err;\
if (native_ctl & (_IOC_READ << _IOC_DIRSHIFT)) {\
convert_to_32(type, data32, data);\
}\
return 0;\
}
#define DEFINE_ALSA_IOCTL_ENTRY(name,type,native_ctl) \
static int snd_ioctl32_##name(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file) {\
return _snd_ioctl32_##type(fd, cmd, arg, file, native_ctl);\
}
#define MAP_COMPAT(ctl) { ctl, snd_ioctl32_compat }
struct ioctl32_mapper {
unsigned int cmd;
int (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp);
int registered;
};
int snd_ioctl32_compat(unsigned int, unsigned int, unsigned long, struct file *);
int snd_ioctl32_register(struct ioctl32_mapper *mappers);
void snd_ioctl32_unregister(struct ioctl32_mapper *mappers);
#endif /* __ALSA_IOCTL32_H */
......@@ -50,8 +50,8 @@ static long snd_alloc_kmalloc;
static long snd_alloc_vmalloc;
static LIST_HEAD(snd_alloc_kmalloc_list);
static LIST_HEAD(snd_alloc_vmalloc_list);
static spinlock_t snd_alloc_kmalloc_lock = SPIN_LOCK_UNLOCKED;
static spinlock_t snd_alloc_vmalloc_lock = SPIN_LOCK_UNLOCKED;
static DEFINE_SPINLOCK(snd_alloc_kmalloc_lock);
static DEFINE_SPINLOCK(snd_alloc_vmalloc_lock);
#define KMALLOC_MAGIC 0x87654321
#define VMALLOC_MAGIC 0x87654320
static snd_info_entry_t *snd_memory_info_entry;
......
......@@ -359,16 +359,9 @@ static int snd_mixer_oss_ioctl1(snd_mixer_oss_file_t *fmixer, unsigned int cmd,
return -ENXIO;
}
/* FIXME: need to unlock BKL to allow preemption */
static int snd_mixer_oss_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int err;
/* FIXME: need to unlock BKL to allow preemption */
unlock_kernel();
err = snd_mixer_oss_ioctl1((snd_mixer_oss_file_t *) file->private_data, cmd, arg);
lock_kernel();
return err;
return snd_mixer_oss_ioctl1((snd_mixer_oss_file_t *) file->private_data, cmd, arg);
}
int snd_mixer_oss_ioctl_card(snd_card_t *card, unsigned int cmd, unsigned long arg)
......@@ -384,6 +377,13 @@ int snd_mixer_oss_ioctl_card(snd_card_t *card, unsigned int cmd, unsigned long a
return snd_mixer_oss_ioctl1(&fmixer, cmd, arg);
}
#ifdef CONFIG_COMPAT
/* all compatible */
#define snd_mixer_oss_ioctl_compat snd_mixer_oss_ioctl
#else
#define snd_mixer_oss_ioctl_compat NULL
#endif
/*
* REGISTRATION PART
*/
......@@ -393,7 +393,8 @@ static struct file_operations snd_mixer_oss_f_ops =
.owner = THIS_MODULE,
.open = snd_mixer_oss_open,
.release = snd_mixer_oss_release,
.ioctl = snd_mixer_oss_ioctl,
.unlocked_ioctl = snd_mixer_oss_ioctl,
.compat_ioctl = snd_mixer_oss_ioctl_compat,
};
static snd_minor_t snd_mixer_oss_reg =
......
......@@ -1913,8 +1913,7 @@ static int snd_pcm_oss_release(struct inode *inode, struct file *file)
return 0;
}
static inline int _snd_pcm_oss_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
snd_pcm_oss_file_t *pcm_oss_file;
int __user *p = (int __user *)arg;
......@@ -2073,16 +2072,12 @@ static inline int _snd_pcm_oss_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
}
/* FIXME: need to unlock BKL to allow preemption */
static int snd_pcm_oss_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
int err;
unlock_kernel();
err = _snd_pcm_oss_ioctl(inode, file, cmd, arg);
lock_kernel();
return err;
}
#ifdef CONFIG_COMPAT
/* all compatible */
#define snd_pcm_oss_ioctl_compat snd_pcm_oss_ioctl
#else
#define snd_pcm_oss_ioctl_compat NULL
#endif
static ssize_t snd_pcm_oss_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
{
......@@ -2410,7 +2405,8 @@ static struct file_operations snd_pcm_oss_f_reg =
.open = snd_pcm_oss_open,
.release = snd_pcm_oss_release,
.poll = snd_pcm_oss_poll,
.ioctl = snd_pcm_oss_ioctl,
.unlocked_ioctl = snd_pcm_oss_ioctl,
.compat_ioctl = snd_pcm_oss_ioctl_compat,
.mmap = snd_pcm_oss_mmap,
};
......
......@@ -1004,6 +1004,7 @@ static int __init alsa_pcm_init(void)
snd_info_entry_t *entry;
snd_ctl_register_ioctl(snd_pcm_control_ioctl);
snd_ctl_register_ioctl_compat(snd_pcm_control_ioctl);
if ((entry = snd_info_create_module_entry(THIS_MODULE, "pcm", NULL)) != NULL) {
snd_info_set_text_ops(entry, NULL, SNDRV_CARDS * SNDRV_PCM_DEVICES * 128, snd_pcm_proc_read);
if (snd_info_register(entry) < 0) {
......@@ -1018,6 +1019,7 @@ static int __init alsa_pcm_init(void)
static void __exit alsa_pcm_exit(void)
{
snd_ctl_unregister_ioctl(snd_pcm_control_ioctl);
snd_ctl_unregister_ioctl_compat(snd_pcm_control_ioctl);
if (snd_pcm_proc_entry) {
snd_info_unregister(snd_pcm_proc_entry);
snd_pcm_proc_entry = NULL;
......
......@@ -291,7 +291,7 @@ struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned lon
* @substream: the substream to allocate the DMA buffer to
* @size: the requested buffer size in bytes
*
* Allocates the DMA buffer on the BUS type given by
* Allocates the DMA buffer on the BUS type given earlier to
* snd_pcm_lib_preallocate_xxx_pages().
*
* Returns 1 if the buffer is changed, 0 if not changed, or a negative
......
......@@ -65,7 +65,7 @@ static int snd_pcm_hw_params_old_user(snd_pcm_substream_t * substream, struct sn
*
*/
rwlock_t snd_pcm_link_rwlock = RW_LOCK_UNLOCKED;
DEFINE_RWLOCK(snd_pcm_link_rwlock);
static DECLARE_RWSEM(snd_pcm_link_rwsem);
......@@ -602,17 +602,13 @@ static int snd_pcm_status_user(snd_pcm_substream_t * substream, snd_pcm_status_t
return 0;
}
static int snd_pcm_channel_info(snd_pcm_substream_t * substream, snd_pcm_channel_info_t __user * _info)
static int snd_pcm_channel_info(snd_pcm_substream_t * substream, snd_pcm_channel_info_t * info)
{
snd_pcm_channel_info_t info;
snd_pcm_runtime_t *runtime;
int res;
unsigned int channel;
snd_assert(substream != NULL, return -ENXIO);
if (copy_from_user(&info, _info, sizeof(info)))
return -EFAULT;
channel = info.channel;
channel = info->channel;
runtime = substream->runtime;
snd_pcm_stream_lock_irq(substream);
if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
......@@ -622,9 +618,19 @@ static int snd_pcm_channel_info(snd_pcm_substream_t * substream, snd_pcm_channel
snd_pcm_stream_unlock_irq(substream);
if (channel >= runtime->channels)
return -EINVAL;
memset(&info, 0, sizeof(info));
info.channel = channel;
res = substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_CHANNEL_INFO, &info);
memset(info, 0, sizeof(*info));
info->channel = channel;
return substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_CHANNEL_INFO, info);
}
static int snd_pcm_channel_info_user(snd_pcm_substream_t * substream, snd_pcm_channel_info_t __user * _info)
{
snd_pcm_channel_info_t info;
int res;
if (copy_from_user(&info, _info, sizeof(info)))
return -EFAULT;
res = snd_pcm_channel_info(substream, &info);
if (res < 0)
return res;
if (copy_to_user(_info, &info, sizeof(info)))
......@@ -2440,7 +2446,7 @@ static int snd_pcm_common_ioctl1(snd_pcm_substream_t *substream,
case SNDRV_PCM_IOCTL_STATUS:
return snd_pcm_status_user(substream, arg);
case SNDRV_PCM_IOCTL_CHANNEL_INFO:
return snd_pcm_channel_info(substream, arg);
return snd_pcm_channel_info_user(substream, arg);
case SNDRV_PCM_IOCTL_PREPARE:
return snd_pcm_prepare(substream);
case SNDRV_PCM_IOCTL_RESET:
......@@ -2640,40 +2646,28 @@ static int snd_pcm_capture_ioctl1(snd_pcm_substream_t *substream,
return snd_pcm_common_ioctl1(substream, cmd, arg);
}
static int snd_pcm_playback_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
snd_pcm_file_t *pcm_file;
int err;
pcm_file = file->private_data;
if (((cmd >> 8) & 0xff) != 'A')
return -ENOTTY;
/* FIXME: need to unlock BKL to allow preemption */
unlock_kernel();
err = snd_pcm_playback_ioctl1(pcm_file->substream, cmd, (void __user *)arg);
lock_kernel();
return err;
return snd_pcm_playback_ioctl1(pcm_file->substream, cmd, (void __user *)arg);
}
static int snd_pcm_capture_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
snd_pcm_file_t *pcm_file;
int err;
pcm_file = file->private_data;
if (((cmd >> 8) & 0xff) != 'A')
return -ENOTTY;
/* FIXME: need to unlock BKL to allow preemption */
unlock_kernel();
err = snd_pcm_capture_ioctl1(pcm_file->substream, cmd, (void __user *)arg);
lock_kernel();
return err;
return snd_pcm_capture_ioctl1(pcm_file->substream, cmd, (void __user *)arg);
}
int snd_pcm_kernel_playback_ioctl(snd_pcm_substream_t *substream,
......@@ -3197,6 +3191,15 @@ static int snd_pcm_fasync(int fd, struct file * file, int on)
return 0;
}
/*
* ioctl32 compat
*/
#ifdef CONFIG_COMPAT
#include "pcm_compat.c"
#else
#define snd_pcm_ioctl_compat NULL
#endif
/*
* To be removed helpers to keep binary compatibility
*/
......@@ -3318,7 +3321,8 @@ static struct file_operations snd_pcm_f_ops_playback = {
.open = snd_pcm_open,
.release = snd_pcm_release,
.poll = snd_pcm_playback_poll,
.ioctl = snd_pcm_playback_ioctl,
.unlocked_ioctl = snd_pcm_playback_ioctl,
.compat_ioctl = snd_pcm_ioctl_compat,
.mmap = snd_pcm_mmap,
.fasync = snd_pcm_fasync,
};
......@@ -3330,7 +3334,8 @@ static struct file_operations snd_pcm_f_ops_capture = {
.open = snd_pcm_open,
.release = snd_pcm_release,
.poll = snd_pcm_capture_poll,
.ioctl = snd_pcm_capture_ioctl,
.unlocked_ioctl = snd_pcm_capture_ioctl,
.compat_ioctl = snd_pcm_ioctl_compat,
.mmap = snd_pcm_mmap,
.fasync = snd_pcm_fasync,
};
......
......@@ -29,6 +29,8 @@
#include <linux/time.h>
#include <linux/wait.h>
#include <linux/moduleparam.h>
#include <linux/delay.h>
#include <linux/wait.h>
#include <sound/rawmidi.h>
#include <sound/info.h>
#include <sound/control.h>
......@@ -132,27 +134,22 @@ int snd_rawmidi_drain_output(snd_rawmidi_substream_t * substream)
err = 0;
runtime->drain = 1;
while (runtime->avail < runtime->buffer_size) {
timeout = interruptible_sleep_on_timeout(&runtime->sleep, 10 * HZ);
if (signal_pending(current)) {
err = -ERESTARTSYS;
break;
}
if (runtime->avail < runtime->buffer_size && !timeout) {
snd_printk(KERN_WARNING "rawmidi drain error (avail = %li, buffer_size = %li)\n", (long)runtime->avail, (long)runtime->buffer_size);
err = -EIO;
break;
}
timeout = wait_event_interruptible_timeout(runtime->sleep,
(runtime->avail >= runtime->buffer_size),
10*HZ);
if (signal_pending(current))
err = -ERESTARTSYS;
if (runtime->avail < runtime->buffer_size && !timeout) {
snd_printk(KERN_WARNING "rawmidi drain error (avail = %li, buffer_size = %li)\n", (long)runtime->avail, (long)runtime->buffer_size);
err = -EIO;
}
runtime->drain = 0;
if (err != -ERESTARTSYS) {
/* we need wait a while to make sure that Tx FIFOs are empty */
if (substream->ops->drain)
substream->ops->drain(substream);
else {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ / 20);
}
else
msleep(50);
snd_rawmidi_drop_output(substream);
}
return err;
......@@ -673,8 +670,7 @@ static int snd_rawmidi_input_status(snd_rawmidi_substream_t * substream,
return 0;
}
static inline int _snd_rawmidi_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
snd_rawmidi_file_t *rfile;
void __user *argp = (void __user *)arg;
......@@ -784,17 +780,6 @@ static inline int _snd_rawmidi_ioctl(struct inode *inode, struct file *file,
return -ENOTTY;
}
/* FIXME: need to unlock BKL to allow preemption */
static int snd_rawmidi_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
int err;
unlock_kernel();
err = _snd_rawmidi_ioctl(inode, file, cmd, arg);
lock_kernel();
return err;
}
static int snd_rawmidi_control_ioctl(snd_card_t * card,
snd_ctl_file_t * control,
unsigned int cmd,
......@@ -1277,6 +1262,14 @@ static unsigned int snd_rawmidi_poll(struct file *file, poll_table * wait)
return mask;
}
/*
*/
#ifdef CONFIG_COMPAT
#include "rawmidi_compat.c"
#else
#define snd_rawmidi_ioctl_compat NULL
#endif
/*
*/
......@@ -1347,7 +1340,8 @@ static struct file_operations snd_rawmidi_f_ops =
.open = snd_rawmidi_open,
.release = snd_rawmidi_release,
.poll = snd_rawmidi_poll,
.ioctl = snd_rawmidi_ioctl,
.unlocked_ioctl = snd_rawmidi_ioctl,
.compat_ioctl = snd_rawmidi_ioctl_compat,
};
static snd_minor_t snd_rawmidi_reg =
......@@ -1628,6 +1622,7 @@ static int __init alsa_rawmidi_init(void)
{
snd_ctl_register_ioctl(snd_rawmidi_control_ioctl);
snd_ctl_register_ioctl_compat(snd_rawmidi_control_ioctl);
#ifdef CONFIG_SND_OSSEMUL
{ int i;
/* check device map table */
......@@ -1649,6 +1644,7 @@ static int __init alsa_rawmidi_init(void)
static void __exit alsa_rawmidi_exit(void)
{
snd_ctl_unregister_ioctl(snd_rawmidi_control_ioctl);
snd_ctl_unregister_ioctl_compat(snd_rawmidi_control_ioctl);
}
module_init(alsa_rawmidi_init)
......
......@@ -18,14 +18,9 @@
*
*/
#include <sound/driver.h>
#include <linux/time.h>
#include <linux/fs.h>
/* This file included from rawmidi.c */
#include <linux/compat.h>
#include <sound/core.h>
#include <sound/rawmidi.h>
#include <asm/uaccess.h>
#include "ioctl32.h"
struct sndrv_rawmidi_params32 {
s32 stream;
......@@ -35,14 +30,27 @@ struct sndrv_rawmidi_params32 {
unsigned char reserved[16];
} __attribute__((packed));
#define CVT_sndrv_rawmidi_params()\
{\
COPY(stream);\
COPY_CVT(buffer_size);\
COPY_CVT(avail_min);\
if (copy_in_user(((size_t __user *)&dst->avail_min + 1),\
((size_t __user *)&src->avail_min + 1), 4)) \
return -EFAULT;\
static int snd_rawmidi_ioctl_params_compat(snd_rawmidi_file_t *rfile,
struct sndrv_rawmidi_params32 __user *src)
{
snd_rawmidi_params_t params;
unsigned int val;
if (rfile->output == NULL)
return -EINVAL;
if (get_user(params.stream, &src->stream) ||
get_user(params.buffer_size, &src->buffer_size) ||
get_user(params.avail_min, &src->avail_min) ||
get_user(val, &src->no_active_sensing))
return -EFAULT;
params.no_active_sensing = val;
switch (params.stream) {
case SNDRV_RAWMIDI_STREAM_OUTPUT:
return snd_rawmidi_output_params(rfile->output, &params);
case SNDRV_RAWMIDI_STREAM_INPUT:
return snd_rawmidi_input_params(rfile->input, &params);
}
return -EINVAL;
}
struct sndrv_rawmidi_status32 {
......@@ -53,39 +61,60 @@ struct sndrv_rawmidi_status32 {
unsigned char reserved[16];
} __attribute__((packed));
#define CVT_sndrv_rawmidi_status()\
{\
COPY(stream);\
COPY_CVT(tstamp.tv_sec);\
COPY_CVT(tstamp.tv_nsec);\
COPY_CVT(avail);\
COPY_CVT(xruns);\
}
static int snd_rawmidi_ioctl_status_compat(snd_rawmidi_file_t *rfile,
struct sndrv_rawmidi_status32 __user *src)
{
int err;
snd_rawmidi_status_t status;
if (rfile->output == NULL)
return -EINVAL;
if (get_user(status.stream, &src->stream))
return -EFAULT;
DEFINE_ALSA_IOCTL(rawmidi_params);
DEFINE_ALSA_IOCTL(rawmidi_status);
switch (status.stream) {
case SNDRV_RAWMIDI_STREAM_OUTPUT:
err = snd_rawmidi_output_status(rfile->output, &status);
break;
case SNDRV_RAWMIDI_STREAM_INPUT:
err = snd_rawmidi_input_status(rfile->input, &status);
break;
default:
return -EINVAL;
}
if (err < 0)
return err;
DEFINE_ALSA_IOCTL_ENTRY(rawmidi_params, rawmidi_params, SNDRV_RAWMIDI_IOCTL_PARAMS);
DEFINE_ALSA_IOCTL_ENTRY(rawmidi_status, rawmidi_status, SNDRV_RAWMIDI_IOCTL_STATUS);
if (put_user(status.tstamp.tv_sec, &src->tstamp.tv_sec) ||
put_user(status.tstamp.tv_nsec, &src->tstamp.tv_nsec) ||
put_user(status.avail, &src->avail) ||
put_user(status.xruns, &src->xruns))
return -EFAULT;
#define AP(x) snd_ioctl32_##x
return 0;
}
enum {
SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct sndrv_rawmidi_params32),
SNDRV_RAWMIDI_IOCTL_STATUS32 = _IOWR('W', 0x20, struct sndrv_rawmidi_status32),
};
struct ioctl32_mapper rawmidi_mappers[] = {
MAP_COMPAT(SNDRV_RAWMIDI_IOCTL_PVERSION),
MAP_COMPAT(SNDRV_RAWMIDI_IOCTL_INFO),
{ SNDRV_RAWMIDI_IOCTL_PARAMS32, AP(rawmidi_params) },
{ SNDRV_RAWMIDI_IOCTL_STATUS32, AP(rawmidi_status) },
MAP_COMPAT(SNDRV_RAWMIDI_IOCTL_DROP),
MAP_COMPAT(SNDRV_RAWMIDI_IOCTL_DRAIN),
MAP_COMPAT(SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE),
MAP_COMPAT(SNDRV_CTL_IOCTL_RAWMIDI_INFO),
MAP_COMPAT(SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE),
static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
{
snd_rawmidi_file_t *rfile;
void __user *argp = compat_ptr(arg);
{ 0 },
};
rfile = file->private_data;
switch (cmd) {
case SNDRV_RAWMIDI_IOCTL_PVERSION:
case SNDRV_RAWMIDI_IOCTL_INFO:
case SNDRV_RAWMIDI_IOCTL_DROP:
case SNDRV_RAWMIDI_IOCTL_DRAIN:
return snd_rawmidi_ioctl(file, cmd, (unsigned long)argp);
case SNDRV_RAWMIDI_IOCTL_PARAMS32:
return snd_rawmidi_ioctl_params_compat(rfile, argp);
case SNDRV_RAWMIDI_IOCTL_STATUS32:
return snd_rawmidi_ioctl_status_compat(rfile, argp);
}
return -ENOIOCTLCMD;
}
......@@ -59,7 +59,7 @@ static int odev_open(struct inode *inode, struct file *file);
static int odev_release(struct inode *inode, struct file *file);
static ssize_t odev_read(struct file *file, char __user *buf, size_t count, loff_t *offset);
static ssize_t odev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset);
static int odev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
static long odev_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
static unsigned int odev_poll(struct file *file, poll_table * wait);
#ifdef CONFIG_PROC_FS
static void info_read(snd_info_entry_t *entry, snd_info_buffer_t *buf);
......@@ -177,20 +177,20 @@ odev_write(struct file *file, const char __user *buf, size_t count, loff_t *offs
return snd_seq_oss_write(dp, buf, count, file);
}
static int
odev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
static long
odev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
seq_oss_devinfo_t *dp;
int err;
dp = file->private_data;
snd_assert(dp != NULL, return -EIO);
/* FIXME: need to unlock BKL to allow preemption */
unlock_kernel();
err = snd_seq_oss_ioctl(dp, cmd, arg);
lock_kernel();
return err;
return snd_seq_oss_ioctl(dp, cmd, arg);
}
#ifdef CONFIG_COMPAT
#define odev_ioctl_compat odev_ioctl
#else
#define odev_ioctl_compat NULL
#endif
static unsigned int
odev_poll(struct file *file, poll_table * wait)
......@@ -213,7 +213,8 @@ static struct file_operations seq_oss_f_ops =
.open = odev_open,
.release = odev_release,
.poll = odev_poll,
.ioctl = odev_ioctl,
.unlocked_ioctl = odev_ioctl,
.compat_ioctl = odev_ioctl_compat,
};
static snd_minor_t seq_oss_reg = {
......
......@@ -56,7 +56,7 @@ struct seq_oss_midi_t {
static int max_midi_devs;
static seq_oss_midi_t *midi_devs[SNDRV_SEQ_OSS_MAX_MIDI_DEVS];
static spinlock_t register_lock = SPIN_LOCK_UNLOCKED;
static DEFINE_SPINLOCK(register_lock);
/*
* prototypes
......
......@@ -24,6 +24,7 @@
#include "seq_oss_event.h"
#include <sound/seq_oss_legacy.h>
#include "../seq_lock.h"
#include <linux/wait.h>
/*
* constants
......@@ -165,7 +166,9 @@ snd_seq_oss_readq_pick(seq_oss_readq_t *q, evrec_t *rec)
void
snd_seq_oss_readq_wait(seq_oss_readq_t *q)
{
interruptible_sleep_on_timeout(&q->midi_sleep, q->pre_event_timeout);
wait_event_interruptible_timeout(q->midi_sleep,
(q->qlen > 0 || q->head == q->tail),
q->pre_event_timeout);
}
/*
......
......@@ -75,7 +75,7 @@ static seq_oss_synth_t midi_synth_dev = {
"MIDI", /* name */
};
static spinlock_t register_lock = SPIN_LOCK_UNLOCKED;
static DEFINE_SPINLOCK(register_lock);
/*
* prototypes
......
......@@ -26,6 +26,7 @@
#include <sound/seq_oss_legacy.h>
#include "../seq_lock.h"
#include "../seq_clientmgr.h"
#include <linux/wait.h>
/*
......@@ -91,7 +92,6 @@ snd_seq_oss_writeq_sync(seq_oss_writeq_t *q)
{
seq_oss_devinfo_t *dp = q->dp;
abstime_t time;
unsigned long flags;
time = snd_seq_oss_timer_cur_tick(dp->timer);
if (q->sync_time >= time)
......@@ -115,27 +115,13 @@ snd_seq_oss_writeq_sync(seq_oss_writeq_t *q)
snd_seq_kernel_client_enqueue_blocking(dp->cseq, &ev, NULL, 0, 0);
}
spin_lock_irqsave(&q->sync_lock, flags);
if (! q->sync_event_put) { /* echoback event has been received */
spin_unlock_irqrestore(&q->sync_lock, flags);
return 0;
}
/* wait for echo event */
spin_unlock(&q->sync_lock);
interruptible_sleep_on_timeout(&q->sync_sleep, HZ);
spin_lock(&q->sync_lock);
if (signal_pending(current)) {
wait_event_interruptible_timeout(q->sync_sleep, ! q->sync_event_put, HZ);
if (signal_pending(current))
/* interrupted - return 0 to finish sync */
q->sync_event_put = 0;
spin_unlock_irqrestore(&q->sync_lock, flags);
return 0;
}
spin_unlock_irqrestore(&q->sync_lock, flags);
if (q->sync_time >= time)
if (! q->sync_event_put || q->sync_time >= time)
return 0;
else
return 1;
return 1;
}
/*
......
......@@ -51,7 +51,7 @@
#define SNDRV_SEQ_LFLG_OUTPUT 0x0002
#define SNDRV_SEQ_LFLG_OPEN (SNDRV_SEQ_LFLG_INPUT|SNDRV_SEQ_LFLG_OUTPUT)
static spinlock_t clients_lock = SPIN_LOCK_UNLOCKED;
static DEFINE_SPINLOCK(clients_lock);
static DECLARE_MUTEX(register_mutex);
/*
......@@ -2131,21 +2131,20 @@ static int snd_seq_do_ioctl(client_t *client, unsigned int cmd, void __user *arg
}
static int snd_seq_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long snd_seq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
client_t *client = (client_t *) file->private_data;
int err;
snd_assert(client != NULL, return -ENXIO);
/* FIXME: need to unlock BKL to allow preemption */
unlock_kernel();
err = snd_seq_do_ioctl(client, cmd, (void __user *) arg);
lock_kernel();
return err;
return snd_seq_do_ioctl(client, cmd, (void __user *) arg);
}
#ifdef CONFIG_COMPAT
#include "seq_compat.c"
#else
#define snd_seq_ioctl_compat NULL
#endif
/* -------------------------------------------------------- */
......@@ -2462,7 +2461,8 @@ static struct file_operations snd_seq_f_ops =
.open = snd_seq_open,
.release = snd_seq_release,
.poll = snd_seq_poll,
.ioctl = snd_seq_ioctl,
.unlocked_ioctl = snd_seq_ioctl,
.compat_ioctl = snd_seq_ioctl_compat,
};
static snd_minor_t snd_seq_reg =
......
......@@ -18,14 +18,9 @@
*
*/
#include <sound/driver.h>
#include <linux/time.h>
#include <linux/fs.h>
#include <sound/core.h>
#include <sound/timer.h>
#include <asm/uaccess.h>
#include <sound/asequencer.h>
#include "ioctl32.h"
/* This file included from seq.c */
#include <linux/compat.h>
struct sndrv_seq_port_info32 {
struct sndrv_seq_addr addr; /* client/port numbers */
......@@ -46,71 +41,97 @@ struct sndrv_seq_port_info32 {
char reserved[59]; /* for future use */
};
#define CVT_sndrv_seq_port_info()\
{\
COPY(addr);\
COPY_ARRAY(name);\
COPY(capability);\
COPY(type);\
COPY(midi_channels);\
COPY(midi_voices);\
COPY(synth_voices);\
COPY(read_use);\
COPY(write_use);\
COPY(flags);\
COPY(time_queue);\
static int snd_seq_call_port_info_ioctl(client_t *client, unsigned int cmd,
struct sndrv_seq_port_info32 __user *data32)
{
int err = -EFAULT;
snd_seq_port_info_t *data;
mm_segment_t fs;
data = kmalloc(sizeof(*data), GFP_KERNEL);
if (! data)
return -ENOMEM;
if (copy_from_user(data, data32, sizeof(*data32)) ||
get_user(data->flags, &data32->flags) ||
get_user(data->time_queue, &data32->time_queue))
goto error;
data->kernel = NULL;
fs = snd_enter_user();
err = snd_seq_do_ioctl(client, cmd, data);
snd_leave_user(fs);
if (err < 0)
goto error;
if (copy_to_user(data32, data, sizeof(*data32)) ||
put_user(data->flags, &data32->flags) ||
put_user(data->time_queue, &data32->time_queue))
err = -EFAULT;
error:
kfree(data);
return err;
}
DEFINE_ALSA_IOCTL(seq_port_info);
DEFINE_ALSA_IOCTL_ENTRY(create_port, seq_port_info, SNDRV_SEQ_IOCTL_CREATE_PORT);
DEFINE_ALSA_IOCTL_ENTRY(delete_port, seq_port_info, SNDRV_SEQ_IOCTL_DELETE_PORT);
DEFINE_ALSA_IOCTL_ENTRY(get_port_info, seq_port_info, SNDRV_SEQ_IOCTL_GET_PORT_INFO);
DEFINE_ALSA_IOCTL_ENTRY(set_port_info, seq_port_info, SNDRV_SEQ_IOCTL_SET_PORT_INFO);
DEFINE_ALSA_IOCTL_ENTRY(query_next_port, seq_port_info, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT);
/*
*/
#define AP(x) snd_ioctl32_##x
enum {
SNDRV_SEQ_IOCTL_CREATE_PORT32 = _IOWR('S', 0x20, struct sndrv_seq_port_info32),
SNDRV_SEQ_IOCTL_DELETE_PORT32 = _IOW ('S', 0x21, struct sndrv_seq_port_info32),
SNDRV_SEQ_IOCTL_GET_PORT_INFO32 = _IOWR('S', 0x22, struct sndrv_seq_port_info32),
SNDRV_SEQ_IOCTL_SET_PORT_INFO32 = _IOW ('S', 0x23, struct sndrv_seq_port_info32),
SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32 = _IOWR('S', 0x52, struct sndrv_seq_port_info32),
SNDRV_SEQ_IOCTL_CREATE_PORT32 = _IOWR('S', 0x20, struct sndrv_seq_port_info32),
SNDRV_SEQ_IOCTL_DELETE_PORT32 = _IOW ('S', 0x21, struct sndrv_seq_port_info32),
SNDRV_SEQ_IOCTL_GET_PORT_INFO32 = _IOWR('S', 0x22, struct sndrv_seq_port_info32),
SNDRV_SEQ_IOCTL_SET_PORT_INFO32 = _IOW ('S', 0x23, struct sndrv_seq_port_info32),
SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32 = _IOWR('S', 0x52, struct sndrv_seq_port_info32),
};
struct ioctl32_mapper seq_mappers[] = {
MAP_COMPAT(SNDRV_SEQ_IOCTL_PVERSION),
MAP_COMPAT(SNDRV_SEQ_IOCTL_CLIENT_ID),
MAP_COMPAT(SNDRV_SEQ_IOCTL_SYSTEM_INFO),
MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_CLIENT_INFO),
MAP_COMPAT(SNDRV_SEQ_IOCTL_SET_CLIENT_INFO),
{ SNDRV_SEQ_IOCTL_CREATE_PORT32, AP(create_port) },
{ SNDRV_SEQ_IOCTL_DELETE_PORT32, AP(delete_port) },
{ SNDRV_SEQ_IOCTL_GET_PORT_INFO32, AP(get_port_info) },
{ SNDRV_SEQ_IOCTL_SET_PORT_INFO32, AP(set_port_info) },
MAP_COMPAT(SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT),
MAP_COMPAT(SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT),
MAP_COMPAT(SNDRV_SEQ_IOCTL_CREATE_QUEUE),
MAP_COMPAT(SNDRV_SEQ_IOCTL_DELETE_QUEUE),
MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_QUEUE_INFO),
MAP_COMPAT(SNDRV_SEQ_IOCTL_SET_QUEUE_INFO),
MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE),
MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS),
MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO),
MAP_COMPAT(SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO),
MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER),
MAP_COMPAT(SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER),
MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT),
MAP_COMPAT(SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT),
MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_CLIENT_POOL),
MAP_COMPAT(SNDRV_SEQ_IOCTL_SET_CLIENT_POOL),
MAP_COMPAT(SNDRV_SEQ_IOCTL_REMOVE_EVENTS),
MAP_COMPAT(SNDRV_SEQ_IOCTL_QUERY_SUBS),
MAP_COMPAT(SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION),
MAP_COMPAT(SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT),
{ SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32, AP(query_next_port) },
MAP_COMPAT(SNDRV_SEQ_IOCTL_RUNNING_MODE),
{ 0 },
};
static long snd_seq_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
{
client_t *client = (client_t *) file->private_data;
void __user *argp = compat_ptr(arg);
snd_assert(client != NULL, return -ENXIO);
switch (cmd) {
case SNDRV_SEQ_IOCTL_PVERSION:
case SNDRV_SEQ_IOCTL_CLIENT_ID:
case SNDRV_SEQ_IOCTL_SYSTEM_INFO:
case SNDRV_SEQ_IOCTL_GET_CLIENT_INFO:
case SNDRV_SEQ_IOCTL_SET_CLIENT_INFO:
case SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT:
case SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT:
case SNDRV_SEQ_IOCTL_CREATE_QUEUE:
case SNDRV_SEQ_IOCTL_DELETE_QUEUE:
case SNDRV_SEQ_IOCTL_GET_QUEUE_INFO:
case SNDRV_SEQ_IOCTL_SET_QUEUE_INFO:
case SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE:
case SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS:
case SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO:
case SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO:
case SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER:
case SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER:
case SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT:
case SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT:
case SNDRV_SEQ_IOCTL_GET_CLIENT_POOL:
case SNDRV_SEQ_IOCTL_SET_CLIENT_POOL:
case SNDRV_SEQ_IOCTL_REMOVE_EVENTS:
case SNDRV_SEQ_IOCTL_QUERY_SUBS:
case SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION:
case SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT:
case SNDRV_SEQ_IOCTL_RUNNING_MODE:
return snd_seq_do_ioctl(client, cmd, argp);
case SNDRV_SEQ_IOCTL_CREATE_PORT32:
return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_CREATE_PORT, argp);
case SNDRV_SEQ_IOCTL_DELETE_PORT32:
return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_DELETE_PORT, argp);
case SNDRV_SEQ_IOCTL_GET_PORT_INFO32:
return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_GET_PORT_INFO, argp);
case SNDRV_SEQ_IOCTL_SET_PORT_INFO32:
return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_SET_PORT_INFO, argp);
case SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32:
return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, argp);
}
return -ENOIOCTLCMD;
}
......@@ -49,7 +49,7 @@
/* list of allocated queues */
static queue_t *queue_list[SNDRV_SEQ_MAX_QUEUES];
static spinlock_t queue_list_lock = SPIN_LOCK_UNLOCKED;
static DEFINE_SPINLOCK(queue_list_lock);
/* number of queues allocated */
static int num_queues;
......
......@@ -420,7 +420,9 @@ EXPORT_SYMBOL(snd_card_file_remove);
#ifdef CONFIG_PM
EXPORT_SYMBOL(snd_power_wait);
EXPORT_SYMBOL(snd_card_set_pm_callback);
EXPORT_SYMBOL(snd_card_set_dev_pm_callback);
#if defined(CONFIG_PM) && defined(CONFIG_SND_GENERIC_PM)
EXPORT_SYMBOL(snd_card_set_generic_pm_callback);
#endif
#ifdef CONFIG_PCI
EXPORT_SYMBOL(snd_card_pci_suspend);
EXPORT_SYMBOL(snd_card_pci_resume);
......@@ -467,6 +469,10 @@ EXPORT_SYMBOL(snd_ctl_find_id);
EXPORT_SYMBOL(snd_ctl_notify);
EXPORT_SYMBOL(snd_ctl_register_ioctl);
EXPORT_SYMBOL(snd_ctl_unregister_ioctl);
#ifdef CONFIG_COMPAT
EXPORT_SYMBOL(snd_ctl_register_ioctl_compat);
EXPORT_SYMBOL(snd_ctl_unregister_ioctl_compat);
#endif
EXPORT_SYMBOL(snd_ctl_elem_read);
EXPORT_SYMBOL(snd_ctl_elem_write);
/* misc.c */
......
......@@ -76,7 +76,7 @@ static LIST_HEAD(snd_timer_list);
static LIST_HEAD(snd_timer_slave_list);
/* lock for slave active lists */
static spinlock_t slave_active_lock = SPIN_LOCK_UNLOCKED;
static DEFINE_SPINLOCK(slave_active_lock);
static DECLARE_MUTEX(register_mutex);
......@@ -1653,8 +1653,7 @@ static int snd_timer_user_continue(struct file *file)
return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0;
}
static inline int _snd_timer_user_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
snd_timer_user_t *tu;
void __user *argp = (void __user *)arg;
......@@ -1701,17 +1700,6 @@ static inline int _snd_timer_user_ioctl(struct inode *inode, struct file *file,
return -ENOTTY;
}
/* FIXME: need to unlock BKL to allow preemption */
static int snd_timer_user_ioctl(struct inode *inode, struct file * file,
unsigned int cmd, unsigned long arg)
{
int err;
unlock_kernel();
err = _snd_timer_user_ioctl(inode, file, cmd, arg);
lock_kernel();
return err;
}
static int snd_timer_user_fasync(int fd, struct file * file, int on)
{
snd_timer_user_t *tu;
......@@ -1803,6 +1791,12 @@ static unsigned int snd_timer_user_poll(struct file *file, poll_table * wait)
return mask;
}
#ifdef CONFIG_COMPAT
#include "timer_compat.c"
#else
#define snd_timer_user_ioctl_compat NULL
#endif
static struct file_operations snd_timer_f_ops =
{
.owner = THIS_MODULE,
......@@ -1810,7 +1804,8 @@ static struct file_operations snd_timer_f_ops =
.open = snd_timer_user_open,
.release = snd_timer_user_release,
.poll = snd_timer_user_poll,
.ioctl = snd_timer_user_ioctl,
.unlocked_ioctl = snd_timer_user_ioctl,
.compat_ioctl = snd_timer_user_ioctl_compat,
.fasync = snd_timer_user_fasync,
};
......
......@@ -18,14 +18,9 @@
*
*/
#include <sound/driver.h>
#include <linux/time.h>
#include <linux/fs.h>
/* This file included from timer.c */
#include <linux/compat.h>
#include <sound/core.h>
#include <sound/timer.h>
#include <asm/uaccess.h>
#include "ioctl32.h"
struct sndrv_timer_info32 {
u32 flags;
......@@ -37,13 +32,27 @@ struct sndrv_timer_info32 {
unsigned char reserved[64];
};
#define CVT_sndrv_timer_info()\
{\
COPY(flags);\
COPY(card);\
COPY_ARRAY(id);\
COPY_ARRAY(name);\
COPY_CVT(resolution);\
static int snd_timer_user_info_compat(struct file *file,
struct sndrv_timer_info32 __user *_info)
{
snd_timer_user_t *tu;
struct sndrv_timer_info32 info;
snd_timer_t *t;
tu = file->private_data;
snd_assert(tu->timeri != NULL, return -ENXIO);
t = tu->timeri->timer;
snd_assert(t != NULL, return -ENXIO);
memset(&info, 0, sizeof(info));
info.card = t->card ? t->card->number : -1;
if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
info.flags |= SNDRV_TIMER_FLG_SLAVE;
strlcpy(info.id, t->id, sizeof(info.id));
strlcpy(info.name, t->name, sizeof(info.name));
info.resolution = t->hw.resolution;
if (copy_to_user(_info, &info, sizeof(*_info)))
return -EFAULT;
return 0;
}
struct sndrv_timer_status32 {
......@@ -55,51 +64,56 @@ struct sndrv_timer_status32 {
unsigned char reserved[64];
};
#define CVT_sndrv_timer_status()\
{\
COPY_CVT(tstamp.tv_sec);\
COPY_CVT(tstamp.tv_nsec);\
COPY(resolution);\
COPY(lost);\
COPY(overrun);\
COPY(queue);\
static int snd_timer_user_status_compat(struct file *file,
struct sndrv_timer_status32 __user *_status)
{
snd_timer_user_t *tu;
snd_timer_status_t status;
tu = file->private_data;
snd_assert(tu->timeri != NULL, return -ENXIO);
memset(&status, 0, sizeof(status));
status.tstamp = tu->tstamp;
status.resolution = snd_timer_resolution(tu->timeri);
status.lost = tu->timeri->lost;
status.overrun = tu->overrun;
spin_lock_irq(&tu->qlock);
status.queue = tu->qused;
spin_unlock_irq(&tu->qlock);
if (copy_to_user(_status, &status, sizeof(status)))
return -EFAULT;
return 0;
}
DEFINE_ALSA_IOCTL(timer_info);
DEFINE_ALSA_IOCTL(timer_status);
DEFINE_ALSA_IOCTL_ENTRY(timer_info, timer_info, SNDRV_TIMER_IOCTL_INFO);
DEFINE_ALSA_IOCTL_ENTRY(timer_status, timer_status, SNDRV_TIMER_IOCTL_STATUS);
/*
*/
#define AP(x) snd_ioctl32_##x
enum {
SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct sndrv_timer_info32),
SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct sndrv_timer_status32),
};
struct ioctl32_mapper timer_mappers[] = {
MAP_COMPAT(SNDRV_TIMER_IOCTL_PVERSION),
MAP_COMPAT(SNDRV_TIMER_IOCTL_NEXT_DEVICE),
MAP_COMPAT(SNDRV_TIMER_IOCTL_SELECT),
{ SNDRV_TIMER_IOCTL_INFO32, AP(timer_info) },
MAP_COMPAT(SNDRV_TIMER_IOCTL_PARAMS),
{ SNDRV_TIMER_IOCTL_STATUS32, AP(timer_status) },
#if 0
/* ** FIXME **
* The following four entries are disabled because they conflict
* with the TCOC* definitions.
* Unfortunately, the current ioctl32 wrapper uses a single
* hash table for all devices. Once when the wrapper is fixed
* with the table based on devices, they'll be back again.
*/
MAP_COMPAT(SNDRV_TIMER_IOCTL_START),
MAP_COMPAT(SNDRV_TIMER_IOCTL_STOP),
MAP_COMPAT(SNDRV_TIMER_IOCTL_CONTINUE),
MAP_COMPAT(SNDRV_TIMER_IOCTL_PAUSE),
#endif
{ 0 },
};
static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
{
void __user *argp = compat_ptr(arg);
switch (cmd) {
case SNDRV_TIMER_IOCTL_PVERSION:
case SNDRV_TIMER_IOCTL_TREAD:
case SNDRV_TIMER_IOCTL_GINFO:
case SNDRV_TIMER_IOCTL_GPARAMS:
case SNDRV_TIMER_IOCTL_GSTATUS:
case SNDRV_TIMER_IOCTL_SELECT:
case SNDRV_TIMER_IOCTL_PARAMS:
case SNDRV_TIMER_IOCTL_START:
case SNDRV_TIMER_IOCTL_STOP:
case SNDRV_TIMER_IOCTL_CONTINUE:
case SNDRV_TIMER_IOCTL_NEXT_DEVICE:
return snd_timer_user_ioctl(file, cmd, (unsigned long)argp);
case SNDRV_TIMER_IOCTL_INFO32:
return snd_timer_user_info_compat(file, argp);
case SNDRV_TIMER_IOCTL_STATUS32:
return snd_timer_user_status_compat(file, argp);
}
return -ENOIOCTLCMD;
}
This diff is collapsed.
......@@ -25,6 +25,7 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include <sound/core.h>
#include <sound/pcm.h>
......@@ -45,12 +46,10 @@ MODULE_LICENSE("GPL");
*/
void snd_vx_delay(vx_core_t *chip, int xmsec)
{
if (! in_interrupt() && xmsec >= 1000 / HZ) {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((xmsec * HZ + 999) / 1000);
} else {
if (! in_interrupt() && xmsec >= 1000 / HZ)
msleep(xmsec);
else
mdelay(xmsec);
}
}
/*
......@@ -610,6 +609,10 @@ static void vx_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
static char *uer_type[] = { "Consumer", "Professional", "Not Present" };
snd_iprintf(buffer, "%s\n", chip->card->longname);
snd_iprintf(buffer, "Xilinx Firmware: %s\n",
chip->chip_status & VX_STAT_XILINX_LOADED ? "Loaded" : "No");
snd_iprintf(buffer, "Device Initialized: %s\n",
chip->chip_status & VX_STAT_DEVICE_INIT ? "Yes" : "No");
snd_iprintf(buffer, "DSP audio info:");
if (chip->audio_info & VX_AUDIO_INFO_REAL_TIME)
snd_iprintf(buffer, " realtime");
......@@ -718,7 +721,7 @@ int snd_vx_dsp_load(vx_core_t *chip, const struct firmware *dsp)
/*
* suspend
*/
static int snd_vx_suspend(snd_card_t *card, unsigned int state)
static int snd_vx_suspend(snd_card_t *card, pm_message_t state)
{
vx_core_t *chip = card->pm_private_data;
unsigned int i;
......@@ -735,7 +738,7 @@ static int snd_vx_suspend(snd_card_t *card, unsigned int state)
/*
* resume
*/
static int snd_vx_resume(snd_card_t *card, unsigned int state)
static int snd_vx_resume(snd_card_t *card)
{
vx_core_t *chip = card->pm_private_data;
int i, err;
......
......@@ -21,6 +21,7 @@
*/
#include <sound/driver.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include <sound/core.h>
#include <sound/hwdep.h>
......
......@@ -3,6 +3,7 @@
# Copyright (c) 2003 by Jaroslav Kysela <perex@suse.cz>
#
snd-ak4114-objs := ak4114.o
snd-ak4117-objs := ak4117.o
snd-ak4xxx-adda-objs := ak4xxx-adda.o
snd-tea575x-tuner-objs := tea575x-tuner.o
......@@ -11,4 +12,5 @@ snd-tea575x-tuner-objs := tea575x-tuner.o
obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o
obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o
obj-$(CONFIG_SND_ICE1724) += snd-ak4xxx-adda.o
obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o
obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o
This diff is collapsed.
/*
* ALSA driver for AK4524 / AK4528 / AK4529 / AK4355 / AK4381
* ALSA driver for AK4524 / AK4528 / AK4529 / AK4355 / AK4358 / AK4381
* AD and DA converters
*
* Copyright (c) 2000-2003 Jaroslav Kysela <perex@suse.cz>,
* Copyright (c) 2000-2004 Jaroslav Kysela <perex@suse.cz>,
* Takashi Iwai <tiwai@suse.de>
*
* This program is free software; you can redistribute it and/or modify
......@@ -84,6 +84,7 @@ void snd_akm4xxx_reset(akm4xxx_t *ak, int state)
/* FIXME: needed for ak4529? */
break;
case SND_AK4355:
case SND_AK4358:
if (state) {
snd_akm4xxx_write(ak, 0, 0x01, 0x02); /* reset and soft-mute */
return;
......@@ -166,6 +167,24 @@ void snd_akm4xxx_init(akm4xxx_t *ak)
0x01, 0x01, /* 1: un-reset, unmute */
0xff, 0xff
};
static unsigned char inits_ak4358[] = {
0x01, 0x02, /* 1: reset and soft-mute */
0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect, disable DZF, sharp roll-off, RSTN#=0 */
0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */
// 0x02, 0x2e, /* quad speed */
0x03, 0x01, /* 3: de-emphasis off */
0x04, 0x00, /* 4: LOUT1 volume muted */
0x05, 0x00, /* 5: ROUT1 volume muted */
0x06, 0x00, /* 6: LOUT2 volume muted */
0x07, 0x00, /* 7: ROUT2 volume muted */
0x08, 0x00, /* 8: LOUT3 volume muted */
0x09, 0x00, /* 9: ROUT3 volume muted */
0x0b, 0x00, /* b: LOUT4 volume muted */
0x0c, 0x00, /* c: ROUT4 volume muted */
0x0a, 0x00, /* a: DATT speed=0, ignore DZF */
0x01, 0x01, /* 1: un-reset, unmute */
0xff, 0xff
};
static unsigned char inits_ak4381[] = {
0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */
0x01, 0x02, /* 1: de-emphasis off, normal speed, sharp roll-off, DZF off */
......@@ -197,6 +216,10 @@ void snd_akm4xxx_init(akm4xxx_t *ak)
inits = inits_ak4355;
num_chips = 1;
break;
case SND_AK4358:
inits = inits_ak4358;
num_chips = 1;
break;
case SND_AK4381:
inits = inits_ak4381;
num_chips = ak->num_dacs / 2;
......@@ -370,6 +393,12 @@ int snd_akm4xxx_build_controls(akm4xxx_t *ak)
case SND_AK4355:
ctl.private_value = AK_COMPOSE(0, idx + 4, 0, 255); /* register 4-9, chip #0 only */
break;
case SND_AK4358:
if (idx >= 6)
ctl.private_value = AK_COMPOSE(0, idx + 5, 0, 255); /* register 4-9, chip #0 only */
else
ctl.private_value = AK_COMPOSE(0, idx + 4, 0, 255); /* register 4-9, chip #0 only */
break;
case SND_AK4381:
ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255); /* register 3 & 4 */
break;
......@@ -407,7 +436,7 @@ int snd_akm4xxx_build_controls(akm4xxx_t *ak)
if ((err = snd_ctl_add(ak->card, snd_ctl_new(&ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0)
return err;
}
if (ak->type == SND_AK4355)
if (ak->type == SND_AK4355 || ak->type == SND_AK4358)
num_emphs = 1;
else
num_emphs = ak->num_dacs / 2;
......@@ -432,6 +461,7 @@ int snd_akm4xxx_build_controls(akm4xxx_t *ak)
break;
}
case SND_AK4355:
case SND_AK4358:
ctl.private_value = AK_COMPOSE(idx, 3, 0, 0);
break;
case SND_AK4381:
......
This diff is collapsed.
......@@ -644,7 +644,7 @@ static void snd_ad1848_thinkpad_twiddle(ad1848_t *chip, int on) {
}
#ifdef CONFIG_PM
static int snd_ad1848_suspend(snd_card_t *card, unsigned int state)
static int snd_ad1848_suspend(snd_card_t *card, pm_message_t state)
{
ad1848_t *chip = card->pm_private_data;
......@@ -657,7 +657,7 @@ static int snd_ad1848_suspend(snd_card_t *card, unsigned int state)
return 0;
}
static int snd_ad1848_resume(snd_card_t *card, unsigned int state)
static int snd_ad1848_resume(snd_card_t *card)
{
ad1848_t *chip = card->pm_private_data;
......
......@@ -121,7 +121,7 @@ static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard,
return -ENODEV;
}
acard->devmpu = pnp_request_card_device(card, id->devs[1].id, acard->dev);
acard->devopl = pnp_request_card_device(card, id->devs[2].id, acard->devmpu);
acard->devopl = pnp_request_card_device(card, id->devs[2].id, acard->dev);
pdev = acard->dev;
......
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.
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