Commit 1c033b99 authored by Jaroslav Kysela's avatar Jaroslav Kysela

ALSA update - small patches

  - added kmalloc_nocheck and vmalloc_nocheck macros
  - PCM
    - the page callback returns 'struct page *'
    - fixed delay function (moved put_user call outside spinlock)
  - OSS PCM emulation
    - fixed read() lock when stream was terminated and no data is available
  - EMU8000
   - added 'can schedule' condition to snd_emu8000_write_wait()
  - AC'97
   - added ALC650 support
  - ALI5451
    - removed double free
parent 7e796024
......@@ -241,11 +241,15 @@ void *snd_hidden_vmalloc(unsigned long size);
void snd_hidden_vfree(void *obj);
#define kmalloc(size, flags) snd_hidden_kmalloc(size, flags)
#define kfree(obj) snd_hidden_kfree(obj)
#define kfree_nocheck(obj) snd_wrapper_kfree(obj)
#define vmalloc(size) snd_hidden_vmalloc(size)
#define vfree(obj) snd_hidden_vfree(obj)
#define kmalloc_nocheck(size, flags) snd_wrapper_kmalloc(size, flags)
#define vmalloc_nocheck(size) snd_wrapper_vmalloc(size)
#define kfree_nocheck(obj) snd_wrapper_kfree(obj)
#define vfree_nocheck(obj) snd_wrapper_vfree(obj)
#else
#define kmalloc_nocheck(size, flags) kmalloc(size, flags)
#define vmalloc_nocheck(size) vmalloc(size)
#define kfree_nocheck(obj) kfree(obj)
#define vfree_nocheck(obj) vfree(obj)
#endif
......
......@@ -96,7 +96,7 @@ typedef struct _snd_pcm_ops {
void *buf, snd_pcm_uframes_t count);
int (*silence)(snd_pcm_substream_t *substream, int channel,
snd_pcm_uframes_t pos, snd_pcm_uframes_t count);
void *(*page)(snd_pcm_substream_t *substream, unsigned long offset);
struct page *(*page)(snd_pcm_substream_t *substream, unsigned long offset);
} snd_pcm_ops_t;
/*
......@@ -125,7 +125,7 @@ typedef struct _snd_pcm_ops {
#define SNDRV_PCM_DMA_TYPE_PCI 2 /* PCI continuous */
#define SNDRV_PCM_DMA_TYPE_SBUS 3 /* SBUS continuous */
/* If you change this don't forget to changed snd_pcm_rates table in pcm_lib.c */
/* 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 */
#define SNDRV_PCM_RATE_11025 (1<<2) /* 11025Hz */
......
......@@ -61,7 +61,7 @@ int snd_pcm_sgbuf_free(snd_pcm_substream_t *substream);
int snd_pcm_sgbuf_ops_copy_playback(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t hwoff, void *buf, snd_pcm_uframes_t count);
int snd_pcm_sgbuf_ops_copy_capture(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t hwoff, void *buf, snd_pcm_uframes_t count);
int snd_pcm_sgbuf_ops_silence(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t hwoff, snd_pcm_uframes_t count);
void *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset);
struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset);
#endif /* __SOUND_PCM_SGBUF_H */
......@@ -564,7 +564,15 @@ snd_pcm_sframes_t snd_pcm_oss_read3(snd_pcm_substream_t *substream, char *ptr, s
} else {
ret = snd_pcm_lib_read(substream, ptr, frames);
}
if (ret != -EPIPE && ret != -ESTRPIPE)
if (ret == -EPIPE) {
if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, 0);
if (ret < 0)
break;
}
continue;
}
if (ret != -ESTRPIPE)
break;
}
return ret;
......
......@@ -1996,7 +1996,7 @@ static int snd_pcm_delay(snd_pcm_substream_t *substream, snd_pcm_sframes_t *res)
{
snd_pcm_runtime_t *runtime = substream->runtime;
int err;
snd_pcm_sframes_t n;
snd_pcm_sframes_t n = 0;
spin_lock_irq(&runtime->lock);
switch (runtime->status->state) {
......@@ -2014,8 +2014,6 @@ static int snd_pcm_delay(snd_pcm_substream_t *substream, snd_pcm_sframes_t *res)
n = snd_pcm_playback_hw_avail(runtime);
else
n = snd_pcm_capture_avail(runtime);
if (put_user(n, res))
err = -EFAULT;
break;
case SNDRV_PCM_STATE_XRUN:
err = -EPIPE;
......@@ -2026,6 +2024,9 @@ static int snd_pcm_delay(snd_pcm_substream_t *substream, snd_pcm_sframes_t *res)
break;
}
spin_unlock_irq(&runtime->lock);
if (!err)
if (put_user(n, res))
err = -EFAULT;
return err;
}
......@@ -2668,12 +2669,13 @@ static unsigned long snd_pcm_mmap_data_nopage(struct vm_area_struct *area, unsig
if (offset > dma_bytes - PAGE_SIZE)
return NOPAGE_SIGBUS;
if (substream->ops->page) {
vaddr = substream->ops->page(substream, offset);
if (! vaddr)
page = substream->ops->page(substream, offset);
if (! page)
return NOPAGE_OOM;
} else
} else {
vaddr = runtime->dma_area + offset;
page = virt_to_page(vaddr);
page = virt_to_page(vaddr);
}
get_page(page);
#ifndef LINUX_2_2
return page;
......
......@@ -66,7 +66,7 @@ int snd_pcm_sgbuf_init(snd_pcm_substream_t *substream, struct pci_dev *pci, int
sgbuf->tblsize = tblsize;
sgbuf->table = kmalloc(sizeof(struct snd_sg_page) * tblsize, GFP_KERNEL);
if (! sgbuf->table) {
snd_pcm_sgbuf_free(substream);
snd_pcm_sgbuf_delete(substream);
return -ENOMEM;
}
memset(sgbuf->table, 0, sizeof(struct snd_sg_page) * tblsize);
......@@ -158,9 +158,8 @@ int snd_pcm_sgbuf_free(snd_pcm_substream_t *substream)
/*
* get the page pointer on the given offset
* used as the page callback of pcm ops
*/
void *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset)
static void *sgbuf_get_addr(snd_pcm_substream_t *substream, unsigned long offset)
{
struct snd_sg_buf *sgbuf;
unsigned int idx;
......@@ -172,6 +171,19 @@ void *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offse
return sgbuf->table[idx].buf;
}
/*
* get the page struct at the given offset
* used as the page callback of pcm ops
*/
struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset)
{
void *addr = sgbuf_get_addr(substream, offset);
if (addr)
return virt_to_page(addr);
else
return 0;
}
/*
* do copy_from_user to the sg buffer
*/
......@@ -184,7 +196,7 @@ static int copy_from_user_sg_buf(snd_pcm_substream_t *substream,
hwoff -= p;
len = PAGE_SIZE - hwoff;
for (;;) {
addr = snd_pcm_sgbuf_ops_page(substream, p);
addr = sgbuf_get_addr(substream, p);
if (! addr)
return -EFAULT;
if (len > bytes)
......@@ -214,7 +226,7 @@ static int copy_to_user_sg_buf(snd_pcm_substream_t *substream,
hwoff -= p;
len = PAGE_SIZE - hwoff;
for (;;) {
addr = snd_pcm_sgbuf_ops_page(substream, p);
addr = sgbuf_get_addr(substream, p);
if (! addr)
return -EFAULT;
if (len > bytes)
......@@ -246,7 +258,7 @@ static int set_silence_sg_buf(snd_pcm_substream_t *substream,
len = bytes_to_samples(substream->runtime, PAGE_SIZE - hwoff);
page_len = bytes_to_samples(substream->runtime, PAGE_SIZE);
for (;;) {
addr = snd_pcm_sgbuf_ops_page(substream, p);
addr = sgbuf_get_addr(substream, p);
if (! addr)
return -EFAULT;
if (len > samples)
......
......@@ -699,7 +699,6 @@ static int snd_rawmidi_ioctl(struct inode *inode, struct file *file,
case SNDRV_RAWMIDI_IOCTL_PARAMS:
{
snd_rawmidi_params_t params;
int err;
if (copy_from_user(&params, (snd_rawmidi_params_t *) arg, sizeof(snd_rawmidi_params_t)))
return -EFAULT;
switch (params.stream) {
......@@ -714,9 +713,6 @@ static int snd_rawmidi_ioctl(struct inode *inode, struct file *file,
default:
return -EINVAL;
}
if (copy_to_user((snd_rawmidi_params_t *) arg, &params, sizeof(snd_rawmidi_params_t)))
return -EFAULT;
return err;
}
case SNDRV_RAWMIDI_IOCTL_STATUS:
{
......
......@@ -25,7 +25,6 @@
#include <sound/core.h>
#include "seq_timer.h"
#include "seq_prioq.h"
#include "seq_timer.h"
/* Implementation is a simple linked list for now...
......
......@@ -16,7 +16,7 @@
* 2002-04-12 Tomas Kasparek Proc interface update, code cleanup
*/
/* $Id: uda1341.c,v 1.4 2002/08/15 12:13:06 perex Exp $ */
/* $Id: uda1341.c,v 1.5 2002/11/09 13:12:19 perex Exp $ */
#include <sound/driver.h>
#include <linux/module.h>
......@@ -341,7 +341,7 @@ static void snd_uda1341_proc_read(snd_info_entry_t *entry,
snd_iprintf(buffer, "Automatic Gain Ctrl : %s\n", uda->cfg[CMD_AGC] ? "on" : "off");
snd_iprintf(buffer, "AGC attack time : %d ms\n", AGC_atime[uda->cfg[CMD_AGC_TIME]]);
snd_iprintf(buffer, "AGC decay time : %d ns\n", AGC_dtime[uda->cfg[CMD_AGC_TIME]]);
snd_iprintf(buffer, "AGC decay time : %d ms\n", AGC_dtime[uda->cfg[CMD_AGC_TIME]]);
snd_iprintf(buffer, "AGC output level : %s dB\n\n", AGC_level[uda->cfg[CMD_AGC_LEVEL]]);
snd_iprintf(buffer, "Mute : %s\n", uda->cfg[CMD_MUTE] ? "on" : "off");
......
......@@ -115,13 +115,15 @@ emu8k_open_dram_for_pcm(emu8000_t *emu, int channels)
/*
*/
static void
snd_emu8000_write_wait(emu8000_t *emu)
snd_emu8000_write_wait(emu8000_t *emu, int can_schedule)
{
while ((EMU8000_SMALW_READ(emu) & 0x80000000) != 0) {
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1);
if (signal_pending(current))
break;
if (can_schedule) {
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1);
if (signal_pending(current))
break;
}
}
}
......@@ -457,7 +459,7 @@ static int emu8k_pcm_copy(snd_pcm_substream_t *subs,
emu8k_pcm_t *rec = subs->runtime->private_data;
emu8000_t *emu = rec->emu;
snd_emu8000_write_wait(emu);
snd_emu8000_write_wait(emu, 1);
if (voice == -1) {
unsigned short *buf = src;
int i, err;
......@@ -494,7 +496,7 @@ static int emu8k_pcm_silence(snd_pcm_substream_t *subs,
emu8k_pcm_t *rec = subs->runtime->private_data;
emu8000_t *emu = rec->emu;
snd_emu8000_write_wait(emu);
snd_emu8000_write_wait(emu, 1);
if (voice == -1 && rec->voices == 1)
voice = 0;
if (voice == -1) {
......@@ -524,7 +526,7 @@ static int emu8k_pcm_copy(snd_pcm_substream_t *subs,
emu8000_t *emu = rec->emu;
unsigned short *buf = src;
snd_emu8000_write_wait(emu);
snd_emu8000_write_wait(emu, 1);
EMU8000_SMALW_WRITE(emu, pos + rec->loop_start[0]);
if (rec->voices > 1)
EMU8000_SMARW_WRITE(emu, pos + rec->loop_start[1]);
......@@ -553,7 +555,7 @@ static int emu8k_pcm_silence(snd_pcm_substream_t *subs,
emu8k_pcm_t *rec = subs->runtime->private_data;
emu8000_t *emu = rec->emu;
snd_emu8000_write_wait(emu);
snd_emu8000_write_wait(emu, 1);
EMU8000_SMALW_WRITE(emu, rec->loop_start[0] + pos);
if (rec->voices > 1)
EMU8000_SMARW_WRITE(emu, rec->loop_start[1] + pos);
......@@ -645,7 +647,7 @@ static int emu8k_pcm_prepare(snd_pcm_substream_t *subs)
rec->dram_opened = 1;
/* clear loop blanks */
snd_emu8000_write_wait(rec->emu);
snd_emu8000_write_wait(rec->emu, 0);
EMU8000_SMALW_WRITE(rec->emu, rec->offset);
for (i = 0; i < LOOP_BLANK_SIZE; i++)
EMU8000_SMLD_WRITE(rec->emu, 0);
......
......@@ -105,7 +105,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
{ 0x414c4310, 0xfffffff0, "RL5382", NULL },
{ 0x414c4320, 0xfffffff0, "RL5383", NULL },
{ 0x414c4710, 0xfffffff0, "ALC200/200P", NULL },
{ 0x414c4720, 0xfffffff0, "ALC650", NULL },
{ 0x414c4720, 0xfffffff0, "ALC650", patch_alc650 },
{ 0x414c4730, 0xffffffff, "ALC101", NULL },
{ 0x414c4740, 0xfffffff0, "ALC202", NULL },
{ 0x414c4750, 0xfffffff0, "ALC250", NULL },
......@@ -914,6 +914,25 @@ static const snd_kcontrol_new_t snd_ac97_controls_ad18xx_lfe[1] = {
AD18XX_PCM_BITS("LFE Playback Volume", 2, 0, 31)
};
/*
* ALC650
*/
static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = {
AC97_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0),
AC97_SINGLE("Surround Down Mix", AC97_ALC650_MULTICH, 1, 1, 0),
AC97_SINGLE("Center/LFE Down Mix", AC97_ALC650_MULTICH, 2, 1, 0),
AC97_SINGLE("Exchange Center/LFE", AC97_ALC650_MULTICH, 3, 1, 0),
AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0),
AC97_SINGLE("Mic As Center/LFE", AC97_ALC650_MULTICH, 10, 1, 0),
AC97_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0),
AC97_SINGLE("Analog to IEC958 Output", AC97_ALC650_MULTICH, 12, 1, 0),
AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0),
#if 0 /* always set in patch_alc650 */
AC97_SINGLE("IEC958 Input Clock Enable", AC97_ALC650_CLOCK, 0, 1, 0),
AC97_SINGLE("IEC958 Input Pin Enable", AC97_ALC650_CLOCK, 1, 1, 0),
#endif
};
/*
*
*/
......@@ -1340,7 +1359,7 @@ static int snd_ac97_mixer_build(snd_card_t * card, ac97_t * ac97)
}
/* build S/PDIF controls */
if (ac97->ext_id & AC97_EA_SPDIF) {
if (ac97->ext_id & AC97_EI_SPDIF) {
if (ac97->flags & AC97_CS_SPDIF) {
for (idx = 0; idx < 3; idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_spdif[idx], ac97))) < 0)
......@@ -1379,7 +1398,7 @@ static int snd_ac97_mixer_build(snd_card_t * card, ac97_t * ac97)
ac97->spdif_status = SNDRV_PCM_DEFAULT_CON_SPDIF;
}
/* build Sigmatel specific controls */
/* build chip specific controls */
switch (ac97->id) {
case AC97_ID_STAC9700:
case AC97_ID_STAC9708:
......@@ -1393,6 +1412,12 @@ static int snd_ac97_mixer_build(snd_card_t * card, ac97_t * ac97)
if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_ANALOG, 0))
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_sigmatel_controls[1], ac97))) < 0)
return err;
break;
case AC97_ID_ALC650:
for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_alc650); idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_alc650[idx], ac97))) < 0)
return err;
break;
default:
/* nothing */
break;
......
......@@ -43,3 +43,4 @@
#define AC97_ID_CS4299 0x43525930
#define AC97_ID_CS4201 0x43525948
#define AC97_ID_CS4205 0x43525958
#define AC97_ID_ALC650 0x414c4720
......@@ -168,7 +168,7 @@ int patch_cirrus_spdif(ac97_t * ac97)
ac97->flags |= AC97_CS_SPDIF;
ac97->rates[AC97_RATES_SPDIF] &= ~SNDRV_PCM_RATE_32000;
ac97->ext_id |= AC97_EA_SPDIF; /* force the detection of spdif */
ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */
snd_ac97_write_cache(ac97, AC97_CSR_ACMODE, 0x0080);
return 0;
}
......@@ -184,7 +184,7 @@ int patch_cirrus_cs4299(ac97_t * ac97)
int patch_conexant(ac97_t * ac97)
{
ac97->flags |= AC97_CX_SPDIF;
ac97->ext_id |= AC97_EA_SPDIF; /* force the detection of spdif */
ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */
return 0;
}
......@@ -336,3 +336,11 @@ int patch_ad1980(ac97_t * ac97)
snd_ac97_write_cache(ac97, AC97_AD_MISC, misc | 0x0420);
return 0;
}
int patch_alc650(ac97_t * ac97)
{
/* enable spdif in */
snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK,
snd_ac97_read(ac97, AC97_ALC650_CLOCK) | 0x03);
return 0;
}
......@@ -38,3 +38,4 @@ int patch_ad1881(ac97_t * ac97);
int patch_ad1885(ac97_t * ac97);
int patch_ad1886(ac97_t * ac97);
int patch_ad1980(ac97_t * ac97);
int patch_alc650(ac97_t * ac97);
......@@ -233,6 +233,7 @@ struct snd_stru_ali {
unsigned long port;
unsigned char revision;
unsigned int hw_initialized: 1;
struct resource *res_port;
struct pci_dev *pci;
......@@ -1965,7 +1966,8 @@ static void snd_ali_resume(struct pci_dev *dev)
static int snd_ali_free(ali_t * codec)
{
snd_ali_disable_address_interrupt(codec);
if (codec->hw_initialized)
snd_ali_disable_address_interrupt(codec);
if (codec->irq >= 0) {
synchronize_irq(codec->irq);
free_irq(codec->irq, (void *)codec);
......@@ -2036,13 +2038,11 @@ static int __devinit snd_ali_resources(ali_t *codec)
{
snd_ali_printk("resouces allocation ...\n");
if ((codec->res_port = request_region(codec->port, 0x100, "ALI 5451")) == NULL) {
snd_ali_free(codec);
snd_printk("Unalbe to request io ports.\n");
return -EBUSY;
}
if (request_irq(codec->pci->irq, snd_ali_card_interrupt, SA_INTERRUPT|SA_SHIRQ, "ALI 5451", (void *)codec)) {
snd_ali_free(codec);
snd_printk("Unable to request irq.\n");
return -EBUSY;
}
......@@ -2112,6 +2112,7 @@ static int __devinit snd_ali_create(snd_card_t * card,
pci_set_master(pci);
if (snd_ali_resources(codec)) {
snd_ali_free(codec);
return -EBUSY;
}
......@@ -2156,7 +2157,6 @@ static int __devinit snd_ali_create(snd_card_t * card,
if ((err = snd_ali_chip_init(codec)) < 0) {
snd_printk("ali create: chip init error.\n");
snd_ali_free(codec);
return err;
}
......@@ -2167,6 +2167,7 @@ static int __devinit snd_ali_create(snd_card_t * card,
#endif
snd_ali_enable_address_interrupt(codec);
codec->hw_initialized = 1;
*r_ali = codec;
snd_ali_printk("created.\n");
......
......@@ -25,7 +25,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
$Id: hammerfall_mem.c,v 1.4 2002/10/21 18:28:25 perex Exp $
$Id: hammerfall_mem.c,v 1.5 2002/11/04 09:11:42 perex Exp $
Tue Oct 17 2000 Jaroslav Kysela <perex@suse.cz>
......@@ -34,7 +34,6 @@
*/
#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/pci.h>
......
......@@ -29,7 +29,6 @@
* --- End of notes from Thoamas's original driver ---
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
......
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