VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 1
-EXTRAVERSION =-pre10
+EXTRAVERSION =-pre11
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
# FIXME!
# These should be made conditional on the stuff that needs them!
#
-obj-y += irq_i8259.o irq_srm.o irq_pyxis.o \
+obj-y += irq_i8259.o irq_srm.o \
es1888.o smc37c669.o smc37c93x.o ns87312.o
ifdef CONFIG_VGA_HOSE
sys_jensen.o sys_miata.o sys_mikasa.o sys_nautilus.o sys_titan.o \
sys_noritake.o sys_rawhide.o sys_ruffian.o sys_rx164.o \
sys_sable.o sys_sio.o sys_sx164.o sys_takara.o sys_rx164.o \
- sys_wildfire.o core_wildfire.o
+ sys_wildfire.o core_wildfire.o irq_pyxis.o
else
obj-$(CONFIG_ALPHA_TAKARA) += sys_takara.o
obj-$(CONFIG_ALPHA_WILDFIRE) += sys_wildfire.o
+ifneq ($(CONFIG_ALPHA_MIATA)$(CONFIG_ALPHA_RUFFIAN)$(CONFIG_ALPHA_SX164),)
+obj-y += irq_pyxis.o
+endif
+
endif # GENERIC
all: kernel.o head.o
extern int do_getitimer(int which, struct itimerval *value);
extern int do_setitimer(int which, struct itimerval *, struct itimerval *);
asmlinkage int sys_utimes(char *, struct timeval *);
-extern int sys_wait4(pid_t, int *, int, struct rusage *);
extern int do_adjtimex(struct timex *);
struct timeval32
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-asmlinkage int sys_wait4(int, int *, int, struct rusage *);
asmlinkage void ret_from_sys_call(void);
asmlinkage int do_signal(sigset_t *, struct pt_regs *,
struct switch_stack *, unsigned long, unsigned long);
cabriolet_update_irq_hw(unsigned int irq, unsigned long mask)
{
int ofs = (irq - 16) / 8;
- outb(mask >> (16 + ofs*3), 0x804 + ofs);
+ outb(mask >> (16 + ofs * 8), 0x804 + ofs);
}
static inline void
#define SWI_SYS_SIGRETURN (0xef000000|(__NR_sigreturn))
#define SWI_SYS_RT_SIGRETURN (0xef000000|(__NR_rt_sigreturn))
-asmlinkage int sys_wait4(pid_t pid, unsigned long * stat_addr,
- int options, unsigned long *ru);
asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall);
int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
return err;
}
-extern asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr,
- int options, struct rusage * ru);
-
asmlinkage long
sys32_wait4(__kernel_pid_t32 pid, unsigned int *stat_addr, int options,
struct rusage32 *ru)
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
- int options, unsigned long *ru);
asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);
const int frame_extra_sizes[16] = {
#include <asm/ptrace.h>
#include <asm/uaccess.h>
-asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
- int options, unsigned long *ru);
extern asmlinkage void syscall_trace(void);
#undef DEBUG_SIG
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-extern asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
- int options, unsigned long *ru);
extern asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);
extern asmlinkage int save_fp_context(struct sigcontext *sc);
extern asmlinkage int restore_fp_context(struct sigcontext *sc);
return err;
}
-extern asmlinkage int sys_wait4(pid_t pid, unsigned int * stat_addr,
- int options, struct rusage * ru);
-
asmlinkage int
sys32_wait4(__kernel_pid_t32 pid, unsigned int * stat_addr, int options,
struct rusage32 * ru)
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-extern asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
- int options, unsigned long *ru);
extern asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);
extern asmlinkage int save_fp_context(struct sigcontext *sc);
extern asmlinkage int restore_fp_context(struct sigcontext *sc);
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-extern asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
- int options, unsigned long *ru);
extern asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs *regs);
extern asmlinkage int save_fp_context(struct sigcontext *sc);
extern asmlinkage int restore_fp_context(struct sigcontext *sc);
#ifndef _PPC_KERNEL_OPEN_PIC_H
#define _PPC_KERNEL_OPEN_PIC_H
+#include <linux/config.h>
+
#define OPENPIC_SIZE 0x40000
/* OpenPIC IRQ controller structure */
* Common pmac/prep/chrp pci routines. -- Cort
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/delay.h>
* The motherboard routes/maps will disappear shortly. -- Cort
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#define MSR_USERCHANGE (MSR_FE0 | MSR_FE1)
int do_signal(sigset_t *oldset, struct pt_regs *regs);
-extern int sys_wait4(pid_t pid, unsigned long *stat_addr,
- int options, unsigned long *ru);
int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
{
struct ucontext uc;
} rt_sigframe;
-asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
- int options, unsigned long *ru);
asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
/*
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
- int options, unsigned long *ru);
asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
-/* $Id: signal.c,v 1.107 2000/09/05 21:44:54 davem Exp $
+/* $Id: signal.c,v 1.108 2001/01/24 21:05:12 davem Exp $
* linux/arch/sparc/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
- int options, unsigned long *ru);
-
extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
void *fpqueue, unsigned long *fpqdepth);
extern void fpload(unsigned long *fpregs, unsigned long *fsr);
-/* $Id: sys_sunos.c,v 1.130 2000/08/12 13:25:41 davem Exp $
+/* $Id: sys_sunos.c,v 1.131 2001/01/24 21:05:12 davem Exp $
* sys_sunos.c: SunOS specific syscall compatibility support.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
}
/* So stupid... */
-extern asmlinkage int sys_wait4(pid_t, unsigned int *, int, struct rusage *);
asmlinkage int sunos_wait4(pid_t pid, unsigned int *stat_addr, int options, struct rusage *ru)
{
int ret;
-/* $Id: signal.c,v 1.54 2000/09/05 21:44:54 davem Exp $
+/* $Id: signal.c,v 1.55 2001/01/24 21:05:13 davem Exp $
* arch/sparc64/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
- int options, unsigned long *ru);
-
asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
unsigned long orig_o0, int ret_from_syscall);
-/* $Id: signal32.c,v 1.67 2000/09/05 21:44:54 davem Exp $
+/* $Id: signal32.c,v 1.68 2001/01/24 21:05:13 davem Exp $
* arch/sparc64/kernel/signal32.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
- int options, unsigned long *ru);
-
asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs *regs,
unsigned long orig_o0, int ret_from_syscall);
-/* $Id: sys_sparc32.c,v 1.171 2000/12/13 16:34:55 davem Exp $
+/* $Id: sys_sparc32.c,v 1.172 2001/01/24 21:05:13 davem Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
return err;
}
-extern asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr,
- int options, struct rusage * ru);
-
asmlinkage int sys32_wait4(__kernel_pid_t32 pid, unsigned int *stat_addr, int options, struct rusage32 *ru)
{
if (!ru)
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#define ACPI_OS_NAME "Linux"
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/ctype.h>
&& atomic_read(&queued_sectors) < low_queued_sectors)
wake_up(&blk_buffers_wait);
- if (!list_empty(&q->request_freelist[rw])) {
- blk_refill_freelist(q, rw);
- list_add(&req->table, &q->request_freelist[rw]);
- return;
- }
-
/*
- * free list is empty, add to pending free list and
- * batch wakeups
+ * Add to pending free list and batch wakeups
*/
list_add(&req->table, &q->pending_freelist[rw]);
radeon_update_ring_snapshot( dev_priv );
- if ( 1 )
+ if ( 0 )
radeon_print_dirty( "dispatch_vertex", sarea_priv->dirty );
if ( buf->used ) {
};
const char *bad_ata66_4[] = {
+ "IBM-DTLA-307075",
+ "IBM-DTLA-307060",
+ "IBM-DTLA-307045",
+ "IBM-DTLA-307030",
+ "IBM-DTLA-307020",
+ "IBM-DTLA-307015",
+ "IBM-DTLA-305040",
+ "IBM-DTLA-305030",
+ "IBM-DTLA-305020",
"WDC AC310200R",
NULL
};
#ifdef CONFIG_BLK_DEV_IDEDMA
if (hwif->dma_base) {
hwif->dmaproc = &via82cxxx_dmaproc;
+#ifdef CONFIG_IDEDMA_AUTO
hwif->autodma = 1;
+#endif
}
#endif /* CONFIG_BLK_DEV_IDEDMA */
}
static const char *version =
"eepro100.c:v1.09j-t 9/29/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n"
-"eepro100.c: $Revision: 1.35 $ 2000/11/17 Modified by Andrey V. Savochkin <saw@saw.sw.com.sg> and others\n";
+"eepro100.c: $Revision: 1.36 $ 2000/11/17 Modified by Andrey V. Savochkin <saw@saw.sw.com.sg> and others\n";
/* A few user-configurable values that apply to all boards.
First set is undocumented and spelled per Intel recommendations. */
This takes less than 10usec and will easily finish before the next
action. */
outl(PortReset, ioaddr + SCBPort);
+ inl(ioaddr + SCBPort);
udelay(10);
if (eeprom[3] & 0x0100)
#endif /* kernel_bloat */
outl(PortReset, ioaddr + SCBPort);
+ inl(ioaddr + SCBPort);
udelay(10);
/* Return the chip to its original power state. */
sp->tx_ring = tx_ring_space;
sp->tx_ring_dma = tx_ring_dma;
sp->lstats = (struct speedo_stats *)(sp->tx_ring + TX_RING_SIZE);
- sp->lstats_dma = cpu_to_le32(TX_RING_ELEM_DMA(sp, TX_RING_SIZE));
+ sp->lstats_dma = TX_RING_ELEM_DMA(sp, TX_RING_SIZE);
init_timer(&sp->timer); /* used in ioctl() */
sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0;
/* Set the segment registers to '0'. */
wait_for_cmd_done(ioaddr + SCBCmd);
outl(0, ioaddr + SCBPointer);
- inl(ioaddr + SCBPointer); /* XXX */
+ /* impose a delay to avoid a bug */
+ inl(ioaddr + SCBPointer);
+ udelay(10);
outb(RxAddrLoad, ioaddr + SCBCmd);
wait_for_cmd_done(ioaddr + SCBCmd);
outb(CUCmdBase, ioaddr + SCBCmd);
/* Load the statistics block and rx ring addresses. */
wait_for_cmd_done(ioaddr + SCBCmd);
outl(sp->lstats_dma, ioaddr + SCBPointer);
- inl(ioaddr + SCBPointer); /* XXX */
outb(CUStatsAddr, ioaddr + SCBCmd);
sp->lstats->done_marker = 0;
/* Start the chip's Tx process and unmask interrupts. */
wait_for_cmd_done(ioaddr + SCBCmd);
- outl(cpu_to_le32(TX_RING_ELEM_DMA(sp, sp->dirty_tx % TX_RING_SIZE)),
+ outl(TX_RING_ELEM_DMA(sp, sp->dirty_tx % TX_RING_SIZE),
ioaddr + SCBPointer);
/* We are not ACK-ing FCP and ER in the interrupt handler yet so they should
remain masked --Dragan */
/* Only the command unit has stopped. */
printk(KERN_WARNING "%s: Trying to restart the transmitter...\n",
dev->name);
- outl(cpu_to_le32(TX_RING_ELEM_DMA(sp, dirty_tx % TX_RING_SIZE])),
+ outl(TX_RING_ELEM_DMA(sp, dirty_tx % TX_RING_SIZE]),
ioaddr + SCBPointer);
outw(CUStart, ioaddr + SCBCmd);
reset_mii(dev);
dep_tristate ' Yamaha FM synthesizer (YM3812/OPL-3) support' CONFIG_SOUND_YM3812 $CONFIG_SOUND_OSS
dep_tristate ' Yamaha OPL3-SA1 audio controller' CONFIG_SOUND_OPL3SA1 $CONFIG_SOUND_OSS
dep_tristate ' Yamaha OPL3-SA2, SA3, and SAx based PnP cards' CONFIG_SOUND_OPL3SA2 $CONFIG_SOUND_OSS
- dep_tristate ' Yamaha YMF7xx PCI audio (legacy mode)' CONFIG_SOUND_YMPCI $CONFIG_SOUND_OSS $CONFIG_PCI
- if [ "$CONFIG_SOUND_YMPCI" = "n" ]; then
- dep_tristate ' Yamaha YMF7xx PCI audio (native mode) (EXPERIMENTAL)' CONFIG_SOUND_YMFPCI $CONFIG_SOUND_OSS $CONFIG_PCI $CONFIG_EXPERIMENTAL
+ dep_tristate ' Yamaha YMF7xx PCI audio (native mode)' CONFIG_SOUND_YMFPCI $CONFIG_SOUND_OSS $CONFIG_PCI
+ if [ "$CONFIG_SOUND_YMFPCI" != "n" ]; then
+ bool ' Yamaha PCI legacy ports support' CONFIG_SOUND_YMFPCI_LEGACY
fi
dep_tristate ' 6850 UART support' CONFIG_SOUND_UART6850 $CONFIG_SOUND_OSS
obj-$(CONFIG_SOUND_AWE32_SYNTH) += awe_wave.o
obj-$(CONFIG_SOUND_VIA82CXXX) += via82cxxx_audio.o ac97_codec.o
-obj-$(CONFIG_SOUND_YMPCI) += ymf_sb.o sb_lib.o uart401.o
obj-$(CONFIG_SOUND_YMFPCI) += ymfpci.o ac97_codec.o
+ifeq ($(CONFIG_SOUND_YMFPCI_LEGACY),y)
+ obj-$(CONFIG_SOUND_YMFPCI) += opl3.o uart401.o
+endif
obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o
obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o
obj-$(CONFIG_SOUND_VWSND) += vwsnd.o
*/
-#define VIA_VERSION "1.1.14"
+#define VIA_VERSION "1.1.14a"
#include <linux/config.h>
#define VIA_COUNTER_LIMIT 100000
/* size of DMA buffers */
-#define VIA_DMA_BUFFERS 16
-#define VIA_DMA_BUF_SIZE PAGE_SIZE
+#define VIA_MAX_BUFFER_DMA_PAGES 32
+
+/* buffering default values in ms */
+#define VIA_DEFAULT_FRAG_TIME 20
+#define VIA_DEFAULT_BUFFER_TIME 500
+
+#define VIA_MAX_FRAG_SIZE PAGE_SIZE
+#define VIA_MIN_FRAG_SIZE 64
+
+#define VIA_MIN_FRAG_NUMBER 2
#ifndef AC97_PCM_LR_ADC_RATE
# define AC97_PCM_LR_ADC_RATE AC97_PCM_LR_DAC_RATE
#define VIA_BASE0_PCM_OUT_CHAN_STATUS 0x00
#define VIA_BASE0_PCM_OUT_CHAN_CTRL 0x01
#define VIA_BASE0_PCM_OUT_CHAN_TYPE 0x02
-#define VIA_BASE0_PCM_OUT_BLOCK_COUNT 0x0C
#define VIA_BASE0_PCM_IN_CHAN 0x10 /* input PCM from user */
#define VIA_BASE0_PCM_IN_CHAN_STATUS 0x10
#define VIA_PCM_CONTROL 0x01
#define VIA_PCM_TYPE 0x02
#define VIA_PCM_TABLE_ADDR 0x04
+#define VIA_PCM_BLOCK_COUNT 0x0C
/* XXX unused DMA channel for FM PCM data */
#define VIA_BASE0_FM_OUT_CHAN 0x20
};
-struct via_sgd_data {
+struct via_buffer_pgtbl {
dma_addr_t handle;
void *cpuaddr;
};
struct via_channel {
- atomic_t n_bufs;
+ atomic_t n_frags;
atomic_t hw_ptr;
wait_queue_head_t wait;
u8 pcm_fmt; /* VIA_PCM_FMT_xxx */
unsigned rate; /* sample rate */
+ unsigned int frag_size;
+ unsigned int frag_number;
volatile struct via_sgd_table *sgtable;
dma_addr_t sgt_handle;
- struct via_sgd_data sgbuf [VIA_DMA_BUFFERS];
+ unsigned int page_number;
+ struct via_buffer_pgtbl pgtbl[VIA_MAX_BUFFER_DMA_PAGES];
long iobase;
static int via_dsp_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
static int via_dsp_open (struct inode *inode, struct file *file);
static int via_dsp_release(struct inode *inode, struct file *file);
-#ifdef VIA_SUPPORT_MMAP
static int via_dsp_mmap(struct file *file, struct vm_area_struct *vma);
-#endif
static u16 via_ac97_read_reg (struct ac97_codec *codec, u8 reg);
static void via_ac97_write_reg (struct ac97_codec *codec, u8 reg, u16 value);
static u8 via_ac97_wait_idle (struct via_info *card);
static void via_chan_free (struct via_info *card, struct via_channel *chan);
-static void via_chan_clear (struct via_channel *chan);
+static void via_chan_clear (struct via_info *card, struct via_channel *chan);
static void via_chan_pcm_fmt (struct via_channel *chan, int reset);
+static void via_chan_buffer_free (struct via_info *card, struct via_channel *chan);
#ifdef VIA_PROC_FS
static int via_init_proc (void);
chan->pcm_fmt = VIA_PCM_FMT_MASK;
chan->is_enabled = 1;
- if (chan->is_record)
- atomic_set (&chan->n_bufs, 0);
- else
- atomic_set (&chan->n_bufs, VIA_DMA_BUFFERS);
+ chan->frag_number = 0;
+ chan->frag_size = 0;
+ atomic_set(&chan->n_frags, 0);
atomic_set (&chan->hw_ptr, 0);
}
+/**
+ * via_chan_init - Initialize PCM channel
+ * @card: Private audio chip info
+ * @chan: Channel to be initialized
+ *
+ * Performs some of the preparations necessary to begin
+ * using a PCM channel.
+ *
+ * Currently the preparations consist in
+ * setting the
+ * PCM channel to a known state.
+ */
+
+
+static void via_chan_init (struct via_info *card, struct via_channel *chan)
+{
+
+ DPRINTK ("ENTER\n");
+
+ /* bzero channel structure, and init members to defaults */
+ via_chan_init_defaults (card, chan);
+
+ /* stop any existing channel output */
+ via_chan_clear (card, chan);
+ via_chan_status_clear (chan->iobase);
+ via_chan_pcm_fmt (chan, 1);
+
+ DPRINTK ("EXIT\n");
+}
/**
- * via_chan_init - Initialize PCM channel
+ * via_chan_buffer_init - Initialize PCM channel buffer
* @card: Private audio chip info
* @chan: Channel to be initialized
*
- * Performs all the preparations necessary to begin
+ * Performs some of the preparations necessary to begin
* using a PCM channel.
*
* Currently the preparations include allocating the
- * scatter-gather DMA table and buffers, setting the
- * PCM channel to a known state, and passing the
+ * scatter-gather DMA table and buffers,
+ * and passing the
* address of the DMA table to the hardware.
*
* Note that special care is taken when passing the
* always "take" the address.
*/
-static int via_chan_init (struct via_info *card, struct via_channel *chan)
+static int via_chan_buffer_init (struct via_info *card, struct via_channel *chan)
{
+ int page, offset;
int i;
DPRINTK ("ENTER\n");
- /* bzero channel structure, and init members to defaults */
- via_chan_init_defaults (card, chan);
+ if (chan->sgtable != NULL) {
+ DPRINTK ("EXIT\n");
+ return 0;
+ }
/* alloc DMA-able memory for scatter-gather table */
chan->sgtable = pci_alloc_consistent (card->pdev,
- (sizeof (struct via_sgd_table) * VIA_DMA_BUFFERS),
+ (sizeof (struct via_sgd_table) * chan->frag_number),
&chan->sgt_handle);
if (!chan->sgtable) {
printk (KERN_ERR PFX "DMA table alloc fail, aborting\n");
}
memset ((void*)chan->sgtable, 0,
- (sizeof (struct via_sgd_table) * VIA_DMA_BUFFERS));
+ (sizeof (struct via_sgd_table) * chan->frag_number));
/* alloc DMA-able memory for scatter-gather buffers */
- for (i = 0; i < VIA_DMA_BUFFERS; i++) {
- chan->sgbuf[i].cpuaddr =
- pci_alloc_consistent (card->pdev, VIA_DMA_BUF_SIZE,
- &chan->sgbuf[i].handle);
- if (!chan->sgbuf[i].cpuaddr)
- goto err_out_nomem;
+ chan->page_number = (chan->frag_number * chan->frag_size) / PAGE_SIZE +
+ (((chan->frag_number * chan->frag_size) % PAGE_SIZE) ? 1 : 0);
+
+ for (i = 0; i < chan->page_number; i++) {
+ chan->pgtbl[i].cpuaddr = pci_alloc_consistent (card->pdev, PAGE_SIZE,
+ &chan->pgtbl[i].handle);
- if (i < (VIA_DMA_BUFFERS - 1))
- chan->sgtable[i].count = cpu_to_le32 (VIA_DMA_BUF_SIZE | VIA_FLAG);
- else
- chan->sgtable[i].count = cpu_to_le32 (VIA_DMA_BUF_SIZE | VIA_EOL);
- chan->sgtable[i].addr = cpu_to_le32 (chan->sgbuf[i].handle);
+ if (!chan->pgtbl[i].cpuaddr) {
+ chan->page_number = i;
+ goto err_out_nomem;
+ }
#ifndef VIA_NDEBUG
- memset (chan->sgbuf[i].cpuaddr, 0xBC, VIA_DMA_BUF_SIZE);
+ memset (chan->pgtbl[i].cpuaddr, 0xBC, chan->frag_size);
#endif
#if 1
- DPRINTK ("dmabuf #%d (h=%lx, 32(h)=%lx, v2p=%lx, a=%p)\n",
- i, (long)chan->sgbuf[i].handle,
- (long)chan->sgtable[i].addr,
- virt_to_phys(chan->sgbuf[i].cpuaddr),
- chan->sgbuf[i].cpuaddr);
+ DPRINTK ("dmabuf_pg #%d (h=%lx, v2p=%lx, a=%p)\n",
+ i, (long)chan->pgtbl[i].handle,
+ virt_to_phys(chan->pgtbl[i].cpuaddr),
+ chan->pgtbl[i].cpuaddr);
#endif
-
- assert ((VIA_DMA_BUF_SIZE % PAGE_SIZE) == 0);
}
- /* stop any existing channel output */
- via_chan_clear (chan);
- via_chan_status_clear (chan->iobase);
- via_chan_pcm_fmt (chan, 1);
+ for (i = 0; i < chan->frag_number; i++) {
+
+ page = i / (PAGE_SIZE / chan->frag_size);
+ offset = (i % (PAGE_SIZE / chan->frag_size)) * chan->frag_size;
+
+ chan->sgtable[i].count = cpu_to_le32 (chan->frag_size | VIA_FLAG);
+ chan->sgtable[i].addr = cpu_to_le32 (chan->pgtbl[page].handle + offset);
+
+#if 1
+ DPRINTK ("dmabuf #%d (32(h)=%lx)\n",
+ i,
+ (long)chan->sgtable[i].addr);
+#endif
+ }
+
+ /* overwrite the last buffer information */
+ chan->sgtable[chan->frag_number - 1].count = cpu_to_le32 (chan->frag_size | VIA_EOL);
/* set location of DMA-able scatter-gather info table */
- DPRINTK("outl (0x%X, 0x%04lX)\n",
+ DPRINTK ("outl (0x%X, 0x%04lX)\n",
cpu_to_le32 (chan->sgt_handle),
chan->iobase + VIA_PCM_TABLE_ADDR);
udelay (20);
via_ac97_wait_idle (card);
- DPRINTK("inl (0x%lX) = %x\n",
+ DPRINTK ("inl (0x%lX) = %x\n",
chan->iobase + VIA_PCM_TABLE_ADDR,
inl(chan->iobase + VIA_PCM_TABLE_ADDR));
err_out_nomem:
printk (KERN_ERR PFX "DMA buffer alloc fail, aborting\n");
- via_chan_free (card, chan);
+ via_chan_buffer_free (card, chan);
DPRINTK ("EXIT\n");
return -ENOMEM;
}
static void via_chan_free (struct via_info *card, struct via_channel *chan)
{
- int i;
-
DPRINTK ("ENTER\n");
synchronize_irq();
spin_unlock_irq (&card->lock);
+ DPRINTK ("EXIT\n");
+}
+
+static void via_chan_buffer_free (struct via_info *card, struct via_channel *chan)
+{
+ int i;
+
+ DPRINTK ("ENTER\n");
+
/* zero location of DMA-able scatter-gather info table */
via_ac97_wait_idle(card);
outl (0, chan->iobase + VIA_PCM_TABLE_ADDR);
- for (i = 0; i < VIA_DMA_BUFFERS; i++)
- if (chan->sgbuf[i].cpuaddr) {
- assert ((VIA_DMA_BUF_SIZE % PAGE_SIZE) == 0);
- pci_free_consistent (card->pdev, VIA_DMA_BUF_SIZE,
- chan->sgbuf[i].cpuaddr,
- chan->sgbuf[i].handle);
- chan->sgbuf[i].cpuaddr = NULL;
- chan->sgbuf[i].handle = 0;
+ for (i = 0; i < chan->page_number; i++)
+ if (chan->pgtbl[i].cpuaddr) {
+ pci_free_consistent (card->pdev, PAGE_SIZE,
+ chan->pgtbl[i].cpuaddr,
+ chan->pgtbl[i].handle);
+ chan->pgtbl[i].cpuaddr = NULL;
+ chan->pgtbl[i].handle = 0;
}
+ chan->page_number = 0;
+
if (chan->sgtable) {
pci_free_consistent (card->pdev,
- (sizeof (struct via_sgd_table) * VIA_DMA_BUFFERS),
+ (sizeof (struct via_sgd_table) * chan->frag_number),
(void*)chan->sgtable, chan->sgt_handle);
chan->sgtable = NULL;
}
if (!chan->is_record)
chan->pcm_fmt |= VIA_CHAN_TYPE_INT_SELECT;
- outb (chan->pcm_fmt, chan->iobase + 2);
+ outb (chan->pcm_fmt, chan->iobase + VIA_PCM_TYPE);
DPRINTK ("EXIT, pcm_fmt = 0x%02X, reg = 0x%02X\n",
chan->pcm_fmt,
- inb (chan->iobase + 2));
+ inb (chan->iobase + VIA_PCM_TYPE));
}
* all software pointers which track DMA operation.
*/
-static void via_chan_clear (struct via_channel *chan)
+static void via_chan_clear (struct via_info *card, struct via_channel *chan)
{
DPRINTK ("ENTER\n");
via_chan_stop (chan->iobase);
+ via_chan_buffer_free(card, chan);
chan->is_active = 0;
chan->is_mapped = 0;
chan->is_enabled = 1;
chan->sw_ptr = 0;
chan->n_irqs = 0;
atomic_set (&chan->hw_ptr, 0);
- if (chan->is_record)
- atomic_set (&chan->n_bufs, 0);
- else
- atomic_set (&chan->n_bufs, VIA_DMA_BUFFERS);
DPRINTK ("EXIT\n");
}
{
DPRINTK ("ENTER, requested rate = %d\n", val);
- via_chan_clear (chan);
+ via_chan_clear (card, chan);
val = via_set_rate (&card->ac97, chan, val);
val == AFMT_S16_LE ? "AFMT_S16_LE" :
"unknown");
- via_chan_clear (chan);
+ via_chan_clear (card, chan);
assert (val != AFMT_QUERY); /* this case is handled elsewhere */
{
DPRINTK ("ENTER, channels = %d\n", val);
- via_chan_clear (chan);
+ via_chan_clear (card, chan);
switch (val) {
return val;
}
+static int via_chan_set_buffering (struct via_info *card,
+ struct via_channel *chan, int val)
+{
+ int shift;
+
+ DPRINTK ("ENTER\n");
+
+ /* in both cases the buffer cannot be changed */
+ if (chan->is_active || chan->is_mapped) {
+ DPRINTK ("EXIT\n");
+ return -EINVAL;
+ }
+
+ /* called outside SETFRAGMENT */
+ /* set defaults or do nothing */
+ if (val < 0) {
+
+ if (chan->frag_size && chan->frag_number)
+ goto out;
+
+ DPRINTK ("\n");
+
+ chan->frag_size = (VIA_DEFAULT_FRAG_TIME * chan->rate *
+ ((chan->pcm_fmt & VIA_PCM_FMT_STEREO) ? 2 : 1) *
+ ((chan->pcm_fmt & VIA_PCM_FMT_16BIT) ? 2 : 1)) / 1000 - 1;
+
+ shift = 0;
+ while (chan->frag_size) {
+ chan->frag_size >>= 1;
+ shift++;
+ }
+ chan->frag_size = 1 << shift;
+
+ chan->frag_number = (VIA_DEFAULT_BUFFER_TIME / VIA_DEFAULT_FRAG_TIME);
+
+ DPRINTK ("setting default values %d %d\n", chan->frag_size, chan->frag_number);
+ } else {
+ chan->frag_size = 1 << (val & 0xFFFF);
+ chan->frag_number = (val >> 16) & 0xFFFF;
+
+ DPRINTK ("using user values %d %d\n", chan->frag_size, chan->frag_number);
+ }
+
+ /* quake3 wants frag_number to be a power of two */
+ shift = 0;
+ while (chan->frag_number) {
+ chan->frag_number >>= 1;
+ shift++;
+ }
+ chan->frag_number = 1 << shift;
+
+ if (chan->frag_size > VIA_MAX_FRAG_SIZE)
+ chan->frag_size = VIA_MAX_FRAG_SIZE;
+ else if (chan->frag_size < VIA_MIN_FRAG_SIZE)
+ chan->frag_size = VIA_MIN_FRAG_SIZE;
+
+ if (chan->frag_number < VIA_MIN_FRAG_NUMBER)
+ chan->frag_number = VIA_MIN_FRAG_NUMBER;
+
+ if ((chan->frag_number * chan->frag_size) / PAGE_SIZE > VIA_MAX_BUFFER_DMA_PAGES)
+ chan->frag_number = (VIA_MAX_BUFFER_DMA_PAGES * PAGE_SIZE) / chan->frag_size;
+
+out:
+ if (chan->is_record)
+ atomic_set (&chan->n_frags, 0);
+ else
+ atomic_set (&chan->n_frags, chan->frag_number);
+
+ DPRINTK ("EXIT\n");
+
+ return 0;
+}
#ifdef VIA_CHAN_DUMP_BUFS
/**
{
int i;
- for (i = 0; i < VIA_DMA_BUFFERS; i++) {
+ for (i = 0; i < chan->frag_number; i++) {
DPRINTK ("#%02d: addr=%x, count=%u, flag=%d, eol=%d\n",
i, chan->sgtable[i].addr,
chan->sgtable[i].count & 0x00FFFFFF,
assert (chan->slop_len > 0);
- if (chan->sw_ptr == (VIA_DMA_BUFFERS - 1))
+ if (chan->sw_ptr == (chan->frag_number - 1))
chan->sw_ptr = 0;
else
chan->sw_ptr++;
chan->slop_len = 0;
- assert (atomic_read (&chan->n_bufs) > 0);
- atomic_dec (&chan->n_bufs);
+ assert (atomic_read (&chan->n_frags) > 0);
+ atomic_dec (&chan->n_frags);
DPRINTK ("EXIT\n");
}
if (!chan->is_active && chan->is_enabled) {
chan->is_active = 1;
sg_begin (chan);
- DPRINTK("starting channel %s\n", chan->name);
+ DPRINTK ("starting channel %s\n", chan->name);
}
}
{
DPRINTK ("ENTER\n");
- DPRINTK("EXIT, returning -ESPIPE\n");
+ DPRINTK ("EXIT, returning -ESPIPE\n");
return -ESPIPE;
}
pci_read_config_byte (card->pdev, 0x43, &r43);
pci_read_config_byte (card->pdev, 0x44, &r44);
pci_read_config_byte (card->pdev, 0x48, &r48);
- DPRINTK("PCI config: %02X %02X %02X %02X %02X %02X\n",
+ DPRINTK ("PCI config: %02X %02X %02X %02X %02X %02X\n",
r40,r41,r42,r43,r44,r48);
spin_lock_irq (&card->lock);
card->ac97.dev_mixer = register_sound_mixer (&via_mixer_fops, -1);
if (card->ac97.dev_mixer < 0) {
printk (KERN_ERR PFX "unable to register AC97 mixer, aborting\n");
- DPRINTK("EXIT, returning -EIO\n");
+ DPRINTK ("EXIT, returning -EIO\n");
return -EIO;
}
err_out:
unregister_sound_mixer (card->ac97.dev_mixer);
- DPRINTK("EXIT, returning %d\n", rc);
+ DPRINTK ("EXIT, returning %d\n", rc);
return rc;
}
static void via_ac97_cleanup (struct via_info *card)
{
- DPRINTK("ENTER\n");
+ DPRINTK ("ENTER\n");
assert (card != NULL);
assert (card->ac97.dev_mixer >= 0);
unregister_sound_mixer (card->ac97.dev_mixer);
- DPRINTK("EXIT\n");
+ DPRINTK ("EXIT\n");
}
/* sanity check: make sure our h/w ptr doesn't have a weird value */
assert (n >= 0);
- assert (n < VIA_DMA_BUFFERS);
+ assert (n < chan->frag_number);
/* reset SGD data structure in memory to reflect a full buffer,
* and advance the h/w ptr, wrapping around to zero if needed
*/
- if (n == (VIA_DMA_BUFFERS - 1)) {
- chan->sgtable[n].count = (VIA_DMA_BUF_SIZE | VIA_EOL);
+ if (n == (chan->frag_number - 1)) {
+ chan->sgtable[n].count = (chan->frag_size | VIA_EOL);
atomic_set (&chan->hw_ptr, 0);
} else {
- chan->sgtable[n].count = (VIA_DMA_BUF_SIZE | VIA_FLAG);
+ chan->sgtable[n].count = (chan->frag_size | VIA_FLAG);
atomic_inc (&chan->hw_ptr);
}
/* accounting crap for SNDCTL_DSP_GETxPTR */
chan->n_irqs++;
- chan->bytes += VIA_DMA_BUF_SIZE;
+ chan->bytes += chan->frag_size;
if (chan->bytes < 0) /* handle overflow of 31-bit value */
- chan->bytes = VIA_DMA_BUF_SIZE;
+ chan->bytes = chan->frag_size;
/* wake up anyone listening to see when interrupts occur */
if (waitqueue_active (&chan->wait))
if (chan->is_mapped)
return;
- /* If we are recording, then n_bufs represents the number
- * of buffers waiting to be handled by userspace.
- * If we are playback, then n_bufs represents the number
- * of buffers remaining to be filled by userspace.
- * We increment here. If we reach max buffers (VIA_DMA_BUFFERS),
+ /* If we are recording, then n_frags represents the number
+ * of fragments waiting to be handled by userspace.
+ * If we are playback, then n_frags represents the number
+ * of fragments remaining to be filled by userspace.
+ * We increment here. If we reach max number of fragments,
* this indicates an underrun/overrun. For this case under OSS,
* we stop the record/playback process.
*/
- if (atomic_read (&chan->n_bufs) < VIA_DMA_BUFFERS)
- atomic_inc (&chan->n_bufs);
- assert (atomic_read (&chan->n_bufs) <= VIA_DMA_BUFFERS);
+ if (atomic_read (&chan->n_frags) < chan->frag_number)
+ atomic_inc (&chan->n_frags);
+ assert (atomic_read (&chan->n_frags) <= chan->frag_number);
- if (atomic_read (&chan->n_bufs) == VIA_DMA_BUFFERS) {
+ if (atomic_read (&chan->n_frags) == chan->frag_number) {
chan->is_active = 0;
via_chan_stop (chan->iobase);
}
- DPRINTK ("%s intr, channel n_bufs == %d\n", chan->name,
- atomic_read (&chan->n_bufs));
+ DPRINTK ("%s intr, channel n_frags == %d\n", chan->name,
+ atomic_read (&chan->n_frags));
}
poll: via_dsp_poll,
llseek: via_llseek,
ioctl: via_dsp_ioctl,
-#ifdef VIA_SUPPORT_MMAP
mmap: via_dsp_mmap,
-#endif
};
}
-#ifdef VIA_SUPPORT_MMAP
static struct page * via_mm_nopage (struct vm_area_struct * vma,
unsigned long address, int write_access)
{
address,
write_access);
- assert (VIA_DMA_BUF_SIZE == PAGE_SIZE);
-
if (address > vma->vm_end) {
DPRINTK ("EXIT, returning NOPAGE_SIGBUS\n");
return NOPAGE_SIGBUS; /* Disallow mremap */
#ifndef VIA_NDEBUG
{
- unsigned long max_bufs = VIA_DMA_BUFFERS;
+ unsigned long max_bufs = chan->frag_number;
if (rd && wr) max_bufs *= 2;
/* via_dsp_mmap() should ensure this */
assert (pgoff < max_bufs);
/* if full-duplex (read+write) and we have two sets of bufs,
* then the playback buffers come first, sez soundcard.c */
- if (pgoff >= VIA_DMA_BUFFERS) {
- pgoff -= VIA_DMA_BUFFERS;
+ if (pgoff >= chan->page_number) {
+ pgoff -= chan->page_number;
chan = &card->ch_in;
} else if (!wr)
chan = &card->ch_in;
- assert ((((unsigned long)chan->sgbuf[pgoff].cpuaddr) % PAGE_SIZE) == 0);
+ assert ((((unsigned long)chan->pgtbl[pgoff].cpuaddr) % PAGE_SIZE) == 0);
- dmapage = virt_to_page (chan->sgbuf[pgoff].cpuaddr);
+ dmapage = virt_to_page (chan->pgtbl[pgoff].cpuaddr);
DPRINTK ("EXIT, returning page %p for cpuaddr %lXh\n",
- dmapage, (unsigned long) chan->sgbuf[pgoff].cpuaddr);
+ dmapage, (unsigned long) chan->pgtbl[pgoff].cpuaddr);
get_page (dmapage);
return dmapage;
}
vma->vm_end - vma->vm_start,
vma->vm_pgoff);
- assert (VIA_DMA_BUF_SIZE == PAGE_SIZE);
-
max_size = 0;
- if (file->f_mode & FMODE_READ) {
+ if (vma->vm_flags & VM_READ) {
rd = 1;
- max_size += (VIA_DMA_BUFFERS * VIA_DMA_BUF_SIZE);
+ via_chan_set_buffering(card, &card->ch_in, -1);
+ via_chan_buffer_init (card, &card->ch_in);
+ max_size += card->ch_in.page_number << PAGE_SHIFT;
}
- if (file->f_mode & FMODE_WRITE) {
+ if (vma->vm_flags & VM_WRITE) {
wr = 1;
- max_size += (VIA_DMA_BUFFERS * VIA_DMA_BUF_SIZE);
+ via_chan_set_buffering(card, &card->ch_out, -1);
+ via_chan_buffer_init (card, &card->ch_out);
+ max_size += card->ch_out.page_number << PAGE_SHIFT;
}
start = vma->vm_start;
rc = 0;
out:
- DPRINTK("EXIT, returning %d\n", rc);
+ DPRINTK ("EXIT, returning %d\n", rc);
return rc;
}
-#endif /* VIA_SUPPORT_MMAP */
static ssize_t via_dsp_do_read (struct via_info *card,
*/
n = chan->sw_ptr;
- /* n_bufs represents the number of buffers waiting
+ /* n_frags represents the number of fragments waiting
* to be copied to userland. sleep until at least
* one buffer has been read from the audio hardware.
*/
- tmp = atomic_read (&chan->n_bufs);
+ tmp = atomic_read (&chan->n_frags);
assert (tmp >= 0);
- assert (tmp <= VIA_DMA_BUFFERS);
+ assert (tmp <= chan->frag_number);
while (tmp == 0) {
if (nonblock || !chan->is_active)
return -EAGAIN;
if (signal_pending (current))
return -ERESTARTSYS;
- tmp = atomic_read (&chan->n_bufs);
+ tmp = atomic_read (&chan->n_frags);
}
/* Now that we have a buffer we can read from, send
* as much as sample data possible to userspace.
*/
- while ((count > 0) && (chan->slop_len < VIA_DMA_BUF_SIZE)) {
- size_t slop_left = VIA_DMA_BUF_SIZE - chan->slop_len;
+ while ((count > 0) && (chan->slop_len < chan->frag_size)) {
+ size_t slop_left = chan->frag_size - chan->slop_len;
size = (count < slop_left) ? count : slop_left;
if (copy_to_user (userbuf,
- chan->sgbuf[n].cpuaddr + chan->slop_len,
+ chan->pgtbl[n / (PAGE_SIZE / chan->frag_size)].cpuaddr + n % (PAGE_SIZE / chan->frag_size) + chan->slop_len,
size))
return -EFAULT;
/* If we didn't copy the buffer completely to userspace,
* stop now.
*/
- if (chan->slop_len < VIA_DMA_BUF_SIZE)
+ if (chan->slop_len < chan->frag_size)
goto out;
/*
/* advance channel software pointer to point to
* the next buffer from which we will copy
*/
- if (chan->sw_ptr == (VIA_DMA_BUFFERS - 1))
+ if (chan->sw_ptr == (chan->frag_number - 1))
chan->sw_ptr = 0;
else
chan->sw_ptr++;
/* mark one less buffer waiting to be processed */
- assert (atomic_read (&chan->n_bufs) > 0);
- atomic_dec (&chan->n_bufs);
+ assert (atomic_read (&chan->n_frags) > 0);
+ atomic_dec (&chan->n_frags);
/* we are at a block boundary, there is no fragment data */
chan->slop_len = 0;
- DPRINTK("Flushed block %u, sw_ptr now %u, n_bufs now %d\n",
- n, chan->sw_ptr, atomic_read (&chan->n_bufs));
+ DPRINTK ("Flushed block %u, sw_ptr now %u, n_frags now %d\n",
+ n, chan->sw_ptr, atomic_read (&chan->n_frags));
DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
inb (card->baseaddr + 0x00),
goto out_up;
}
+ via_chan_set_buffering(card, &card->ch_in, -1);
+ rc = via_chan_buffer_init (card, &card->ch_in);
+
+ if (rc)
+ goto out_up;
+
rc = via_dsp_do_read (card, buffer, count, nonblock);
out_up:
up (&card->syscall_sem);
out:
- DPRINTK("EXIT, returning %ld\n",(long) rc);
+ DPRINTK ("EXIT, returning %ld\n",(long) rc);
return rc;
}
if (current->need_resched)
schedule ();
- /* grab current channel software pointer. In the case of
- * playback, this is pointing to the next buffer that
+ /* grab current channel fragment pointer. In the case of
+ * playback, this is pointing to the next fragment that
* should receive data from userland.
*/
n = chan->sw_ptr;
- /* n_bufs represents the number of buffers remaining
+ /* n_frags represents the number of fragments remaining
* to be filled by userspace. Sleep until
- * at least one buffer is available for our use.
+ * at least one fragment is available for our use.
*/
- tmp = atomic_read (&chan->n_bufs);
+ tmp = atomic_read (&chan->n_frags);
assert (tmp >= 0);
- assert (tmp <= VIA_DMA_BUFFERS);
+ assert (tmp <= chan->frag_number);
while (tmp == 0) {
if (nonblock || !chan->is_enabled)
return -EAGAIN;
- DPRINTK ("Sleeping on block %d, tmp==%d, ir==%d\n", n, tmp, chan->is_record);
+ DPRINTK ("Sleeping on page %d, tmp==%d, ir==%d\n", n, tmp, chan->is_record);
interruptible_sleep_on (&chan->wait);
if (signal_pending (current))
return -ERESTARTSYS;
- tmp = atomic_read (&chan->n_bufs);
+ tmp = atomic_read (&chan->n_frags);
}
- /* Now that we have a buffer we can write to, fill it up
+ /* Now that we have at least one fragment we can write to, fill the buffer
* as much as possible with data from userspace.
*/
- while ((count > 0) && (chan->slop_len < VIA_DMA_BUF_SIZE)) {
- size_t slop_left = VIA_DMA_BUF_SIZE - chan->slop_len;
+ while ((count > 0) && (chan->slop_len < chan->frag_size)) {
+ size_t slop_left = chan->frag_size - chan->slop_len;
size = (count < slop_left) ? count : slop_left;
- if (copy_from_user (chan->sgbuf[n].cpuaddr + chan->slop_len,
+ if (copy_from_user (chan->pgtbl[n / (PAGE_SIZE / chan->frag_size)].cpuaddr + (n % (PAGE_SIZE / chan->frag_size)) * chan->frag_size + chan->slop_len,
userbuf, size))
return -EFAULT;
}
/* If we didn't fill up the buffer with data, stop now.
- * Put a 'stop' marker in the DMA table too, to tell the
- * audio hardware to stop if it gets here.
- */
- if (chan->slop_len < VIA_DMA_BUF_SIZE) {
+ * Put a 'stop' marker in the DMA table too, to tell the
+ * audio hardware to stop if it gets here.
+ */
+ if (chan->slop_len < chan->frag_size) {
sgtable[n].count = cpu_to_le32 (chan->slop_len | VIA_EOL | VIA_STOP);
goto out;
}
/*
- * If we get to this point, we have filled a buffer with
- * audio data, flush the buffer to audio hardware.
- */
+ * If we get to this point, we have filled a buffer with
+ * audio data, flush the buffer to audio hardware.
+ */
/* Record the true size for the audio hardware to notice */
- if (n == (VIA_DMA_BUFFERS - 1))
- sgtable[n].count = cpu_to_le32 (VIA_DMA_BUF_SIZE | VIA_EOL);
- else
- sgtable[n].count = cpu_to_le32 (VIA_DMA_BUF_SIZE | VIA_FLAG);
+ if (n == (chan->frag_number - 1))
+ sgtable[n].count = cpu_to_le32 (chan->frag_size | VIA_EOL);
+ else
+ sgtable[n].count = cpu_to_le32 (chan->frag_size | VIA_FLAG);
/* advance channel software pointer to point to
* the next buffer we will fill with data
*/
- if (chan->sw_ptr == (VIA_DMA_BUFFERS - 1))
+ if (chan->sw_ptr == (chan->frag_number - 1))
chan->sw_ptr = 0;
else
chan->sw_ptr++;
/* mark one less buffer as being available for userspace consumption */
- assert (atomic_read (&chan->n_bufs) > 0);
- atomic_dec (&chan->n_bufs);
+ assert (atomic_read (&chan->n_frags) > 0);
+ atomic_dec (&chan->n_frags);
/* we are at a block boundary, there is no fragment data */
chan->slop_len = 0;
/* if SGD has not yet been started, start it */
via_chan_maybe_start (chan);
- DPRINTK("Flushed block %u, sw_ptr now %u, n_bufs now %d\n",
- n, chan->sw_ptr, atomic_read (&chan->n_bufs));
+ DPRINTK ("Flushed block %u, sw_ptr now %u, n_frags now %d\n",
+ n, chan->sw_ptr, atomic_read (&chan->n_frags));
DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
inb (card->baseaddr + 0x00),
goto out_up;
}
+ via_chan_set_buffering(card, &card->ch_out, -1);
+ rc = via_chan_buffer_init (card, &card->ch_out);
+
+ if (rc)
+ goto out_up;
+
rc = via_dsp_do_write (card, buffer, count, nonblock);
out_up:
up (&card->syscall_sem);
out:
- DPRINTK("EXIT, returning %ld\n",(long) rc);
+ DPRINTK ("EXIT, returning %ld\n",(long) rc);
return rc;
}
rd = (file->f_mode & FMODE_READ);
wr = (file->f_mode & FMODE_WRITE);
- if (wr && (atomic_read (&card->ch_out.n_bufs) == 0)) {
+ if (wr && (atomic_read (&card->ch_out.n_frags) == 0)) {
assert (card->ch_out.is_active);
poll_wait(file, &card->ch_out.wait, wait);
}
if (rd) {
/* XXX is it ok, spec-wise, to start DMA here? */
+ if (!card->ch_in.is_active) {
+ via_chan_set_buffering(card, &card->ch_in, -1);
+ via_chan_buffer_init(card, &card->ch_in);
+ }
via_chan_maybe_start (&card->ch_in);
- if (atomic_read (&card->ch_in.n_bufs) == 0)
+ if (atomic_read (&card->ch_in.n_frags) == 0)
poll_wait(file, &card->ch_in.wait, wait);
}
- if (wr && (atomic_read (&card->ch_out.n_bufs) > 0))
+ if (wr && ((atomic_read (&card->ch_out.n_frags) > 0) || !card->ch_out.is_active))
mask |= POLLOUT | POLLWRNORM;
- if (rd && (atomic_read (&card->ch_in.n_bufs) > 0))
+ if (rd && (atomic_read (&card->ch_in.n_frags) > 0))
mask |= POLLIN | POLLRDNORM;
- DPRINTK("EXIT, returning %u\n", mask);
+ DPRINTK ("EXIT, returning %u\n", mask);
return mask;
}
if (chan->slop_len > 0)
via_chan_flush_frag (chan);
- if (atomic_read (&chan->n_bufs) == VIA_DMA_BUFFERS)
+ if (atomic_read (&chan->n_frags) == chan->frag_number)
goto out;
via_chan_maybe_start (chan);
- while (atomic_read (&chan->n_bufs) < VIA_DMA_BUFFERS) {
+ while (atomic_read (&chan->n_frags) < chan->frag_number) {
if (nonblock) {
DPRINTK ("EXIT, returning -EAGAIN\n");
return -EAGAIN;
pci_read_config_byte (card->pdev, 0x43, &r43);
pci_read_config_byte (card->pdev, 0x44, &r44);
pci_read_config_byte (card->pdev, 0x48, &r48);
- DPRINTK("PCI config: %02X %02X %02X %02X %02X %02X\n",
+ DPRINTK ("PCI config: %02X %02X %02X %02X %02X %02X\n",
r40,r41,r42,r43,r44,r48);
DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
printk (KERN_ERR "sleeping but not active\n");
#endif
- DPRINTK ("sleeping, nbufs=%d\n", atomic_read (&chan->n_bufs));
+ DPRINTK ("sleeping, nbufs=%d\n", atomic_read (&chan->n_frags));
interruptible_sleep_on (&chan->wait);
if (signal_pending (current)) {
pci_read_config_byte (card->pdev, 0x43, &r43);
pci_read_config_byte (card->pdev, 0x44, &r44);
pci_read_config_byte (card->pdev, 0x48, &r48);
- DPRINTK("PCI config: %02X %02X %02X %02X %02X %02X\n",
+ DPRINTK ("PCI config: %02X %02X %02X %02X %02X %02X\n",
r40,r41,r42,r43,r44,r48);
DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
inl (card->baseaddr + 0x80),
inl (card->baseaddr + 0x84));
- DPRINTK ("final nbufs=%d\n", atomic_read (&chan->n_bufs));
+ DPRINTK ("final nbufs=%d\n", atomic_read (&chan->n_frags));
}
#endif
{
audio_buf_info info;
- info.fragstotal = VIA_DMA_BUFFERS;
- info.fragsize = VIA_DMA_BUF_SIZE;
+ via_chan_set_buffering(card, chan, -1);
+
+ info.fragstotal = chan->frag_number;
+ info.fragsize = chan->frag_size;
/* number of full fragments we can read/write without blocking */
- info.fragments = atomic_read (&chan->n_bufs);
+ info.fragments = atomic_read (&chan->n_frags);
- if ((chan->slop_len > 0) && (info.fragments > 0))
+ if ((chan->slop_len % chan->frag_size > 0) && (info.fragments > 0))
info.fragments--;
/* number of bytes that can be read or written immediately
* without blocking.
*/
- info.bytes = (info.fragments * VIA_DMA_BUF_SIZE);
- if (chan->slop_len > 0)
- info.bytes += VIA_DMA_BUF_SIZE - chan->slop_len;
+ info.bytes = (info.fragments * chan->frag_size);
+ if (chan->slop_len % chan->frag_size > 0)
+ info.bytes += chan->frag_size - (chan->slop_len % chan->frag_size);
DPRINTK ("EXIT, returning fragstotal=%d, fragsize=%d, fragments=%d, bytes=%d\n",
info.fragstotal,
if (chan->is_active) {
unsigned long extra;
- info.ptr = atomic_read (&chan->hw_ptr) * VIA_DMA_BUF_SIZE;
- extra = VIA_DMA_BUF_SIZE - inl (chan->iobase + VIA_BASE0_PCM_OUT_BLOCK_COUNT);
+ info.ptr = atomic_read (&chan->hw_ptr) * chan->frag_size;
+ extra = chan->frag_size - inl (chan->iobase + VIA_PCM_BLOCK_COUNT);
info.ptr += extra;
info.bytes += extra;
} else {
/* OSS API version. XXX unverified */
case OSS_GETVERSION:
- DPRINTK("ioctl OSS_GETVERSION, EXIT, returning SOUND_VERSION\n");
+ DPRINTK ("ioctl OSS_GETVERSION, EXIT, returning SOUND_VERSION\n");
rc = put_user (SOUND_VERSION, (int *)arg);
break;
/* list of supported PCM data formats */
case SNDCTL_DSP_GETFMTS:
- DPRINTK("DSP_GETFMTS, EXIT, returning AFMT U8|S16_LE\n");
+ DPRINTK ("DSP_GETFMTS, EXIT, returning AFMT U8|S16_LE\n");
rc = put_user (AFMT_U8 | AFMT_S16_LE, (int *)arg);
break;
rc = -EFAULT;
break;
}
- DPRINTK("DSP_SETFMT, val==%d\n", val);
+ DPRINTK ("DSP_SETFMT, val==%d\n", val);
if (val != AFMT_QUERY) {
rc = 0;
- if (rc == 0 && rd)
+ if (rd)
rc = via_chan_set_fmt (card, &card->ch_in, val);
- if (rc == 0 && wr)
+
+ if (rc >= 0 && wr)
rc = via_chan_set_fmt (card, &card->ch_out, val);
- if (rc <= 0) {
- if (rc == 0)
- rc = -EINVAL;
+ if (rc < 0)
break;
- }
+
val = rc;
} else {
if ((rd && (card->ch_in.pcm_fmt & VIA_PCM_FMT_16BIT)) ||
else
val = AFMT_U8;
}
- DPRINTK("SETFMT EXIT, returning %d\n", val);
+ DPRINTK ("SETFMT EXIT, returning %d\n", val);
rc = put_user (val, (int *)arg);
break;
rc = -EFAULT;
break;
}
- DPRINTK("DSP_CHANNELS, val==%d\n", val);
+ DPRINTK ("DSP_CHANNELS, val==%d\n", val);
if (val != 0) {
rc = 0;
- if (rc == 0 && rd)
+
+ if (rd)
rc = via_chan_set_stereo (card, &card->ch_in, val);
- if (rc == 0 && wr)
+
+ if (rc >= 0 && wr)
rc = via_chan_set_stereo (card, &card->ch_out, val);
- if (rc <= 0) {
- if (rc == 0)
- rc = -EINVAL;
+
+ if (rc < 0)
break;
- }
+
val = rc;
} else {
if ((rd && (card->ch_in.pcm_fmt & VIA_PCM_FMT_STEREO)) ||
else
val = 1;
}
- DPRINTK("CHANNELS EXIT, returning %d\n", val);
+ DPRINTK ("CHANNELS EXIT, returning %d\n", val);
rc = put_user (val, (int *)arg);
break;
rc = -EFAULT;
break;
}
- DPRINTK("DSP_STEREO, val==%d\n", val);
+ DPRINTK ("DSP_STEREO, val==%d\n", val);
rc = 0;
- if (rc == 0 && rd)
+ if (rd)
rc = via_chan_set_stereo (card, &card->ch_in, val ? 2 : 1);
- if (rc == 0 && wr)
+ if (rc >= 0 && wr)
rc = via_chan_set_stereo (card, &card->ch_out, val ? 2 : 1);
- if (rc <= 0) {
- if (rc == 0)
- rc = -EINVAL;
+ if (rc < 0)
break;
- }
- DPRINTK("STEREO EXIT, returning %d\n", val);
- rc = 0;
+
+ val = rc - 1;
+
+ DPRINTK ("STEREO EXIT, returning %d\n", val);
+ rc = put_user(val, (int *) arg);
break;
/* query or set sampling rate */
rc = -EFAULT;
break;
}
- DPRINTK("DSP_SPEED, val==%d\n", val);
+ DPRINTK ("DSP_SPEED, val==%d\n", val);
if (val < 0) {
rc = -EINVAL;
break;
if (val > 0) {
rc = 0;
- if (rc == 0 && rd)
+ if (rd)
rc = via_chan_set_speed (card, &card->ch_in, val);
- if (rc == 0 && wr)
+ if (rc >= 0 && wr)
rc = via_chan_set_speed (card, &card->ch_out, val);
- if (rc <= 0) {
- if (rc == 0)
- rc = -EINVAL;
+ if (rc < 0)
break;
- }
+
val = rc;
} else {
if (rd)
else
val = 0;
}
- DPRINTK("SPEED EXIT, returning %d\n", val);
+ DPRINTK ("SPEED EXIT, returning %d\n", val);
rc = put_user (val, (int *)arg);
break;
case SNDCTL_DSP_SYNC:
DPRINTK ("DSP_SYNC\n");
if (wr) {
- DPRINTK("SYNC EXIT (after calling via_dsp_drain_playback)\n");
+ DPRINTK ("SYNC EXIT (after calling via_dsp_drain_playback)\n");
rc = via_dsp_drain_playback (card, &card->ch_out, nonblock);
}
break;
case SNDCTL_DSP_RESET:
DPRINTK ("DSP_RESET\n");
if (rd) {
- via_chan_clear (&card->ch_in);
+ via_chan_clear (card, &card->ch_in);
via_chan_pcm_fmt (&card->ch_in, 1);
+ card->ch_in.frag_number = 0;
+ card->ch_in.frag_size = 0;
+ atomic_set(&card->ch_in.n_frags, 0);
}
+
if (wr) {
- via_chan_clear (&card->ch_out);
+ via_chan_clear (card, &card->ch_out);
via_chan_pcm_fmt (&card->ch_out, 1);
+ card->ch_out.frag_number = 0;
+ card->ch_out.frag_size = 0;
+ atomic_set(&card->ch_out.n_frags, 0);
}
rc = 0;
/* obtain bitmask of device capabilities, such as mmap, full duplex, etc. */
case SNDCTL_DSP_GETCAPS:
- DPRINTK("DSP_GETCAPS\n");
+ DPRINTK ("DSP_GETCAPS\n");
rc = put_user(VIA_DSP_CAP, (int *)arg);
break;
- /* obtain bitmask of device capabilities, such as mmap, full duplex, etc. */
+ /* obtain buffer fragment size */
case SNDCTL_DSP_GETBLKSIZE:
- DPRINTK("DSP_GETBLKSIZE\n");
- rc = put_user(VIA_DMA_BUF_SIZE, (int *)arg);
+ DPRINTK ("DSP_GETBLKSIZE\n");
+
+ if (rd) {
+ via_chan_set_buffering(card, &card->ch_in, -1);
+ rc = put_user(card->ch_in.frag_size, (int *)arg);
+ } else if (wr) {
+ via_chan_set_buffering(card, &card->ch_out, -1);
+ rc = put_user(card->ch_out.frag_size, (int *)arg);
+ }
break;
/* obtain information about input buffering */
case SNDCTL_DSP_GETISPACE:
- DPRINTK("DSP_GETISPACE\n");
+ DPRINTK ("DSP_GETISPACE\n");
if (rd)
rc = via_dsp_ioctl_space (card, &card->ch_in, (void*) arg);
break;
/* obtain information about output buffering */
case SNDCTL_DSP_GETOSPACE:
- DPRINTK("DSP_GETOSPACE\n");
+ DPRINTK ("DSP_GETOSPACE\n");
if (wr)
rc = via_dsp_ioctl_space (card, &card->ch_out, (void*) arg);
break;
/* obtain information about input hardware pointer */
case SNDCTL_DSP_GETIPTR:
- DPRINTK("DSP_GETIPTR\n");
+ DPRINTK ("DSP_GETIPTR\n");
if (rd)
rc = via_dsp_ioctl_ptr (card, &card->ch_in, (void*) arg);
break;
/* obtain information about output hardware pointer */
case SNDCTL_DSP_GETOPTR:
- DPRINTK("DSP_GETOPTR\n");
+ DPRINTK ("DSP_GETOPTR\n");
if (wr)
rc = via_dsp_ioctl_ptr (card, &card->ch_out, (void*) arg);
break;
/* return number of bytes remaining to be played by DMA engine */
case SNDCTL_DSP_GETODELAY:
{
- DPRINTK("DSP_GETODELAY\n");
+ DPRINTK ("DSP_GETODELAY\n");
chan = &card->ch_out;
if (!wr)
break;
- val = VIA_DMA_BUFFERS - atomic_read (&chan->n_bufs);
+ if (chan->is_active) {
- if (val > 0) {
- val *= VIA_DMA_BUF_SIZE;
- val -= VIA_DMA_BUF_SIZE -
- inl (chan->iobase + VIA_BASE0_PCM_OUT_BLOCK_COUNT);
- }
- val += chan->slop_len;
+ val = chan->frag_number - atomic_read (&chan->n_frags);
- assert (val <= (VIA_DMA_BUF_SIZE * VIA_DMA_BUFFERS));
+ if (val > 0) {
+ val *= chan->frag_size;
+ val -= chan->frag_size -
+ inl (chan->iobase + VIA_PCM_BLOCK_COUNT);
+ }
+ val += chan->slop_len % chan->frag_size;
+ } else
+ val = 0;
- DPRINTK("GETODELAY EXIT, val = %d bytes\n", val);
+ assert (val <= (chan->frag_size * chan->frag_number));
+
+ DPRINTK ("GETODELAY EXIT, val = %d bytes\n", val);
rc = put_user (val, (int *)arg);
break;
}
rc = -EFAULT;
break;
}
- DPRINTK("DSP_SETTRIGGER, rd=%d, wr=%d, act=%d/%d, en=%d/%d\n",
+ DPRINTK ("DSP_SETTRIGGER, rd=%d, wr=%d, act=%d/%d, en=%d/%d\n",
rd, wr, card->ch_in.is_active, card->ch_out.is_active,
card->ch_in.is_enabled, card->ch_out.is_enabled);
if (rd)
rc = via_dsp_ioctl_trigger (&card->ch_in, val);
+
if (!rc && wr)
rc = via_dsp_ioctl_trigger (&card->ch_out, val);
* with O_RDWR, this is mainly a no-op that always returns success.
*/
case SNDCTL_DSP_SETDUPLEX:
- DPRINTK("DSP_SETDUPLEX\n");
+ DPRINTK ("DSP_SETDUPLEX\n");
if (!rd || !wr)
break;
rc = 0;
rc = -EFAULT;
break;
}
- DPRINTK("DSP_SETFRAGMENT, val==%d\n", val);
+ DPRINTK ("DSP_SETFRAGMENT, val==%d\n", val);
+
+ if (rd)
+ rc = via_chan_set_buffering(card, &card->ch_in, val);
+
+ if (wr)
+ rc = via_chan_set_buffering(card, &card->ch_out, val);
DPRINTK ("SNDCTL_DSP_SETFRAGMENT (fragshift==0x%04X (%d), maxfrags==0x%04X (%d))\n",
val & 0xFFFF,
(val >> 16) & 0xFFFF,
(val >> 16) & 0xFFFF);
- /* just to shut up some programs */
rc = 0;
break;
/* inform device of an upcoming pause in input (or output). */
case SNDCTL_DSP_POST:
- DPRINTK("DSP_POST\n");
+ DPRINTK ("DSP_POST\n");
if (wr) {
if (card->ch_out.slop_len > 0)
via_chan_flush_frag (&card->ch_out);
}
up (&card->syscall_sem);
- DPRINTK("EXIT, returning %d\n", rc);
+ DPRINTK ("EXIT, returning %d\n", rc);
return rc;
}
static int via_dsp_open (struct inode *inode, struct file *file)
{
- int rc, minor = MINOR(inode->i_rdev);
- int got_read_chan = 0;
+ int minor = MINOR(inode->i_rdev);
struct via_info *card;
struct pci_dev *pdev;
struct via_channel *chan;
}
file->private_data = card;
- DPRINTK("file->f_mode == 0x%x\n", file->f_mode);
+ DPRINTK ("file->f_mode == 0x%x\n", file->f_mode);
/* handle input from analog source */
if (file->f_mode & FMODE_READ) {
chan = &card->ch_in;
- rc = via_chan_init (card, chan);
- if (rc)
- goto err_out;
-
- got_read_chan = 1;
+ via_chan_init (card, chan);
/* why is this forced to 16-bit stereo in all drivers? */
chan->pcm_fmt = VIA_PCM_FMT_16BIT | VIA_PCM_FMT_STEREO;
if (file->f_mode & FMODE_WRITE) {
chan = &card->ch_out;
- rc = via_chan_init (card, chan);
- if (rc)
- goto err_out_read_chan;
+ via_chan_init (card, chan);
- if ((minor & 0xf) == SND_DEV_DSP16) {
- chan->pcm_fmt |= VIA_PCM_FMT_16BIT;
- via_set_rate (&card->ac97, chan, 44100);
+ if (file->f_mode & FMODE_READ) {
+ /* if in duplex mode make the recording and playback channels
+ have the same settings */
+ chan->pcm_fmt = VIA_PCM_FMT_16BIT | VIA_PCM_FMT_STEREO;
+ via_chan_pcm_fmt (chan, 0);
+ via_set_rate (&card->ac97, chan, 44100);
} else {
- via_set_rate (&card->ac97, chan, 8000);
+ if ((minor & 0xf) == SND_DEV_DSP16) {
+ chan->pcm_fmt = VIA_PCM_FMT_16BIT;
+ via_chan_pcm_fmt (chan, 0);
+ via_set_rate (&card->ac97, chan, 44100);
+ } else {
+ via_chan_pcm_fmt (chan, 0);
+ via_set_rate (&card->ac97, chan, 8000);
+ }
}
-
- via_chan_pcm_fmt (chan, 0);
}
DPRINTK ("EXIT, returning 0\n");
return 0;
-
-err_out_read_chan:
- if (got_read_chan)
- via_chan_free (card, &card->ch_in);
-err_out:
- up (&card->open_sem);
- DPRINTK("ERROR EXIT, returning %d\n", rc);
- return rc;
}
printk (KERN_DEBUG "via_audio: ignoring drain playback error %d\n", rc);
via_chan_free (card, &card->ch_out);
+ via_chan_buffer_free(card, &card->ch_out);
}
- if (file->f_mode & FMODE_READ)
+ if (file->f_mode & FMODE_READ) {
via_chan_free (card, &card->ch_in);
+ via_chan_buffer_free (card, &card->ch_in);
+ }
up (&card->syscall_sem);
up (&card->open_sem);
- DPRINTK("EXIT, returning 0\n");
+ DPRINTK ("EXIT, returning 0\n");
return 0;
}
tmp &= 0xF0;
tmp |= pdev->irq;
pci_write_config_byte (pdev, 0x3C, tmp);
- DPRINTK("new 0x3c==0x%02x\n", tmp);
+ DPRINTK ("new 0x3c==0x%02x\n", tmp);
} else {
- DPRINTK("IRQ reg 0x3c==0x%02x, irq==%d\n",
+ DPRINTK ("IRQ reg 0x3c==0x%02x, irq==%d\n",
tmp, tmp & 0x0F);
}
static void __exit cleanup_via82cxxx_audio(void)
{
- DPRINTK("ENTER\n");
+ DPRINTK ("ENTER\n");
pci_unregister_driver (&via_driver);
via_cleanup_proc ();
- DPRINTK("EXIT\n");
+ DPRINTK ("EXIT\n");
}
);
- DPRINTK("EXIT, returning %d\n", len);
+ DPRINTK ("EXIT, returning %d\n", len);
return len;
#undef YN
*
* TODO:
* - Use P44Slot for 44.1 playback.
- * - Capture and duplex
* - 96KHz playback for DVD - use pitch of 2.0.
* - uLaw for Sun apps.
+ * : Alan says firmly "no software format conversion in kernel".
* - Retain DMA buffer on close, do not wait the end of frame.
* - Cleanup
- * ? merge ymf_pcm and state
- * ? pcm interrupt no pointer
* ? underused structure members
* - Remove remaining P3 tags (debug messages).
* - Resolve XXX tagged questions.
* - Cannot play 5133Hz.
+ * - 2001/01/07 Consider if we can remove voice_lock, like so:
+ * : Allocate/deallocate voices in open/close under semafore.
+ * : We access voices in interrupt, that only for pcms that open.
+ * voice_lock around playback_prepare closes interrupts for insane duration.
+ * - Revisit the way voice_alloc is done - too confusing, overcomplicated.
+ * Should support various channel types, however.
+ * - Remove prog_dmabuf from read/write, leave it in open.
+ * - 2001/01/07 Replace the OPL3 part of CONFIG_SOUND_YMFPCI_LEGACY code with
+ * native synthesizer through a playback slot.
+ * - Use new 2.3.x cache coherent PCI DMA routines instead of virt_to_bus.
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <asm/dma.h>
#include <asm/uaccess.h>
+#ifdef CONFIG_SOUND_YMFPCI_LEGACY
+# include "sound_config.h"
+# include "mpu401.h"
+#endif
#include "ymfpci.h"
-#define snd_magic_cast(t, p, err) ((t *)(p))
-
-/* Channels, such as play and record. I do only play a.t.m. XXX */
-#define NR_HW_CH 1
-
-static int ymf_playback_trigger(ymfpci_t *codec, ymfpci_pcm_t *ypcm, int cmd);
-static int ymfpci_voice_alloc(ymfpci_t *codec, ymfpci_voice_type_t type,
- int pair, ymfpci_voice_t **rvoice);
-static int ymfpci_voice_free(ymfpci_t *codec, ymfpci_voice_t *pvoice);
-static int ymf_playback_prepare(ymfpci_t *codec, struct ymf_state *state);
-static int ymf_state_alloc(ymfpci_t *unit, int nvirt);
+static int ymf_playback_trigger(ymfpci_t *codec, struct ymf_pcm *ypcm, int cmd);
+static void ymf_capture_trigger(ymfpci_t *unit, struct ymf_pcm *ypcm, int cmd);
+static void ymfpci_voice_free(ymfpci_t *codec, ymfpci_voice_t *pvoice);
+static int ymf_capture_alloc(struct ymf_unit *unit, int *pbank);
+static int ymf_playback_prepare(struct ymf_state *state);
+static int ymf_capture_prepare(struct ymf_state *state);
+static struct ymf_state *ymf_state_alloc(ymfpci_t *unit);
static LIST_HEAD(ymf_devs);
/*
* Mindlessly copied from cs46xx XXX
*/
-extern __inline__ unsigned ld2(unsigned int x)
+static inline unsigned ld2(unsigned int x)
{
unsigned r = 0;
f->shift++;
}
-/*
- * Whole OSS-style DMA machinery is taken from cs46xx.
- */
-
/* Are you sure 32K is not too much? See if mpg123 skips on loaded systems. */
#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT)
#define DMABUF_MINORDER 1
/* allocate DMA buffer, playback and recording buffer should be allocated seperately */
-static int alloc_dmabuf(struct ymf_state *state)
+static int alloc_dmabuf(struct ymf_dmabuf *dmabuf)
{
- struct ymf_dmabuf *dmabuf = &state->dmabuf;
void *rawbuf = NULL;
int order;
struct page * map, * mapend;
}
/* free DMA buffer */
-static void dealloc_dmabuf(struct ymf_state *state)
+static void dealloc_dmabuf(struct ymf_dmabuf *dmabuf)
{
- struct ymf_dmabuf *dmabuf = &state->dmabuf;
struct page *map, *mapend;
if (dmabuf->rawbuf) {
dmabuf->mapped = dmabuf->ready = 0;
}
-static int prog_dmabuf(struct ymf_state *state, unsigned rec)
+static int prog_dmabuf(struct ymf_state *state, int rec)
{
- struct ymf_dmabuf *dmabuf = &state->dmabuf;
+ struct ymf_dmabuf *dmabuf;
int w_16;
unsigned bytepersec;
unsigned bufsize;
int ret;
w_16 = ymf_pcm_format_width(state->format.format) == 16;
+ dmabuf = rec ? &state->rpcm.dmabuf : &state->wpcm.dmabuf;
spin_lock_irqsave(&state->unit->reg_lock, flags);
dmabuf->hwptr = dmabuf->swptr = 0;
/* allocate DMA buffer if not allocated yet */
if (!dmabuf->rawbuf)
- if ((ret = alloc_dmabuf(state)))
+ if ((ret = alloc_dmabuf(dmabuf)))
return ret;
bytepersec = state->format.rate << state->format.shift;
dmabuf->numfrag = bufsize >> dmabuf->fragshift;
}
dmabuf->fragsize = 1 << dmabuf->fragshift;
- dmabuf->fragsamples = dmabuf->fragsize >> state->format.shift;
dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift;
/*
* Now set up the ring
*/
- spin_lock_irqsave(&state->unit->reg_lock, flags);
+ /* XXX ret = rec? cap_pre(): pbk_pre(); */
+ spin_lock_irqsave(&state->unit->voice_lock, flags);
if (rec) {
- /* ymf_rec_setup(state); */
+ if ((ret = ymf_capture_prepare(state)) != 0) {
+ spin_unlock_irqrestore(&state->unit->voice_lock, flags);
+ return ret;
+ }
} else {
- if ((ret = ymf_playback_prepare(state->unit, state)) != 0) {
+ if ((ret = ymf_playback_prepare(state)) != 0) {
+ spin_unlock_irqrestore(&state->unit->voice_lock, flags);
return ret;
}
}
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+ spin_unlock_irqrestore(&state->unit->voice_lock, flags);
/* set the ready flag for the dma buffer (this comment is not stupid) */
dmabuf->ready = 1;
static void ymf_start_dac(struct ymf_state *state)
{
- ymf_playback_trigger(state->unit, &state->ypcm, 1);
+ ymf_playback_trigger(state->unit, &state->wpcm, 1);
}
+// static void ymf_start_adc(struct ymf_state *state)
+// {
+// ymf_capture_trigger(state->unit, &state->rpcm, 1);
+// }
+
/*
* Wait until output is drained.
* This does not kill the hardware for the sake of ioctls.
static void ymf_wait_dac(struct ymf_state *state)
{
struct ymf_unit *unit = state->unit;
- ymfpci_pcm_t *ypcm = &state->ypcm;
+ struct ymf_pcm *ypcm = &state->wpcm;
DECLARE_WAITQUEUE(waita, current);
unsigned long flags;
- add_wait_queue(&state->dmabuf.wait, &waita);
+ add_wait_queue(&ypcm->dmabuf.wait, &waita);
spin_lock_irqsave(&unit->reg_lock, flags);
- if (state->dmabuf.count != 0 && !state->ypcm.running) {
+ if (ypcm->dmabuf.count != 0 && !ypcm->running) {
ymf_playback_trigger(unit, ypcm, 1);
}
spin_unlock_irqrestore(&unit->reg_lock, flags);
set_current_state(TASK_RUNNING);
- remove_wait_queue(&state->dmabuf.wait, &waita);
+ remove_wait_queue(&ypcm->dmabuf.wait, &waita);
/*
* This function may take up to 4 seconds to reach this point
*/
}
+/* Can just stop, without wait. Or can we? */
+static void ymf_stop_adc(struct ymf_state *state)
+{
+ struct ymf_unit *unit = state->unit;
+ unsigned long flags;
+
+ spin_lock_irqsave(&unit->reg_lock, flags);
+ ymf_capture_trigger(unit, &state->rpcm, 0);
+ spin_unlock_irqrestore(&unit->reg_lock, flags);
+}
+
/*
* Hardware start management
*/
* Playback voice management
*/
-static int voice_alloc(ymfpci_t *codec, ymfpci_voice_type_t type, int pair, ymfpci_voice_t **rvoice)
+static int voice_alloc(ymfpci_t *codec, ymfpci_voice_type_t type, int pair, ymfpci_voice_t *rvoice[])
{
ymfpci_voice_t *voice, *voice2;
int idx;
-
- *rvoice = NULL;
+
for (idx = 0; idx < 64; idx += pair ? 2 : 1) {
voice = &codec->voices[idx];
voice2 = pair ? &codec->voices[idx+1] : NULL;
break;
}
ymfpci_hw_start(codec);
- if (voice2)
+ rvoice[0] = voice;
+ if (voice2) {
ymfpci_hw_start(codec);
- *rvoice = voice;
+ rvoice[1] = voice2;
+ }
return 0;
}
- return -ENOMEM;
+ return -EBUSY; /* Your audio channel is open by someone else. */
}
-static int ymfpci_voice_alloc(ymfpci_t *codec, ymfpci_voice_type_t type,
- int pair, ymfpci_voice_t **rvoice)
+static void ymfpci_voice_free(ymfpci_t *unit, ymfpci_voice_t *pvoice)
{
- unsigned long flags;
- int result;
-
- spin_lock_irqsave(&codec->voice_lock, flags);
- for (;;) {
- result = voice_alloc(codec, type, pair, rvoice);
- if (result == 0 || type != YMFPCI_PCM)
- break;
- /* TODO: synth/midi voice deallocation */
- break;
- }
- spin_unlock_irqrestore(&codec->voice_lock, flags);
- return result;
-}
-
-static int ymfpci_voice_free(ymfpci_t *codec, ymfpci_voice_t *pvoice)
-{
- unsigned long flags;
-
- ymfpci_hw_stop(codec);
- spin_lock_irqsave(&codec->voice_lock, flags);
+ ymfpci_hw_stop(unit);
pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = 0;
pvoice->ypcm = NULL;
- pvoice->interrupt = NULL;
- spin_unlock_irqrestore(&codec->voice_lock, flags);
- return 0;
}
/*
- * PCM part
*/
static void ymf_pcm_interrupt(ymfpci_t *codec, ymfpci_voice_t *voice)
{
- ymfpci_pcm_t *ypcm;
+ struct ymf_pcm *ypcm;
int redzone;
int pos, delta, swptr;
int played, distance;
ypcm->running = 0; // lock it
return;
}
- dmabuf = &state->dmabuf;
+ dmabuf = &ypcm->dmabuf;
spin_lock(&codec->reg_lock);
if (ypcm->running) {
/* P3 */ /** printk("ymfpci: %d, intr bank %d count %d start 0x%x:%x\n",
pos = voice->bank[codec->active_bank].start;
pos <<= state->format.shift;
if (pos < 0 || pos >= dmabuf->dmasize) { /* ucode bug */
- printk(KERN_ERR
- "ymfpci%d: %d: runaway: hwptr %d dmasize %d\n",
+ printk(KERN_ERR "ymfpci%d: runaway voice %d: hwptr %d=>%d dmasize %d\n",
codec->dev_audio, voice->number,
- dmabuf->hwptr, dmabuf->dmasize);
+ dmabuf->hwptr, pos, dmabuf->dmasize);
pos = 0;
}
if (pos < dmabuf->hwptr) {
spin_unlock(&codec->reg_lock);
}
-#if HAVE_RECORD
-static void ymfpci_pcm_capture_interrupt(snd_pcm_subchn_t *substream)
+static void ymf_cap_interrupt(ymfpci_t *unit, struct ymf_capture *cap)
{
- snd_pcm_runtime_t *runtime = substream->runtime;
- ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, );
- ymfpci_t *codec = ypcm->codec;
- u32 pos, delta;
-
- spin_lock(&codec->reg_lock);
+ struct ymf_pcm *ypcm;
+ int redzone;
+ struct ymf_state *state;
+ struct ymf_dmabuf *dmabuf;
+ int pos, delta;
+ int cnt;
+
+ if ((ypcm = cap->ypcm) == NULL) {
+ return;
+ }
+ if ((state = ypcm->state) == NULL) {
+ ypcm->running = 0; // lock it
+ return;
+ }
+ dmabuf = &ypcm->dmabuf;
+ spin_lock(&unit->reg_lock);
if (ypcm->running) {
- pos = codec->bank_capture[ypcm->capture_bank_number][codec->active_bank]->start << ypcm->shift_offset;
- if (pos < ypcm->last_pos) // <-- dmabuf->hwptr
- delta = pos + (ypcm->buffer_size - ypcm->last_pos);
- else
- delta = pos - ypcm->last_pos;
- ypcm->frag_pos += delta;
- ypcm->last_pos = pos;
- while (ypcm->frag_pos >= ypcm->frag_size) {
- ypcm->frag_pos -= ypcm->frag_size;
- // printk("done - active_bank = 0x%x, start = 0x%x\n", codec->active_bank, voice->bank[codec->active_bank].start);
- spin_unlock(&codec->reg_lock);
- snd_pcm_transfer_done(substream);
- spin_lock(&codec->reg_lock);
+ redzone = ymf_calc_lend(state->format.rate);
+ redzone <<= (state->format.shift + 1);
+
+ pos = cap->bank[unit->active_bank].start;
+ // pos <<= state->format.shift;
+ if (pos < 0 || pos >= dmabuf->dmasize) { /* ucode bug */
+ printk(KERN_ERR "ymfpci%d: runaway capture %d: hwptr %d=>%d dmasize %d\n",
+ unit->dev_audio, ypcm->capture_bank_number,
+ dmabuf->hwptr, pos, dmabuf->dmasize);
+ pos = 0;
+ }
+ if (pos < dmabuf->hwptr) {
+ delta = dmabuf->dmasize - dmabuf->hwptr;
+ delta += pos;
+ } else {
+ delta = pos - dmabuf->hwptr;
+ }
+ dmabuf->hwptr = pos;
+
+ cnt = dmabuf->count;
+ cnt += delta;
+ if (cnt + redzone > dmabuf->dmasize) {
+ /* Overflow - bump swptr */
+ dmabuf->count = dmabuf->dmasize - redzone;
+ dmabuf->swptr = dmabuf->hwptr + redzone;
+ if (dmabuf->swptr >= dmabuf->dmasize) {
+ dmabuf->swptr -= dmabuf->dmasize;
+ }
+ } else {
+ dmabuf->count = cnt;
+ }
+
+ dmabuf->total_bytes += delta;
+ if (dmabuf->count) { /* && is_sleeping XXX */
+ wake_up(&dmabuf->wait);
}
}
- spin_unlock(&codec->reg_lock);
+ spin_unlock(&unit->reg_lock);
}
-#endif
-static int ymf_playback_trigger(ymfpci_t *codec, ymfpci_pcm_t *ypcm, int cmd)
+static int ymf_playback_trigger(ymfpci_t *codec, struct ymf_pcm *ypcm, int cmd)
{
if (ypcm->voices[0] == NULL) {
return 0;
}
-#if HAVE_RECORD
-static int ymfpci_capture_trigger(void *private_data,
- snd_pcm_subchn_t * substream,
- int cmd)
+static void ymf_capture_trigger(ymfpci_t *codec, struct ymf_pcm *ypcm, int cmd)
{
- unsigned long flags;
- ymfpci_t *codec = snd_magic_cast(ymfpci_t, private_data, -ENXIO);
- ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, substream->runtime->private_data, -ENXIO);
- int result = 0;
u32 tmp;
- spin_lock_irqsave(&codec->reg_lock, flags);
- if (cmd == SND_PCM_TRIGGER_GO) {
+ if (cmd != 0) {
tmp = ymfpci_readl(codec, YDSXGR_MAPOFREC) | (1 << ypcm->capture_bank_number);
ymfpci_writel(codec, YDSXGR_MAPOFREC, tmp);
ypcm->running = 1;
- } else if (cmd == SND_PCM_TRIGGER_STOP) {
+ } else {
tmp = ymfpci_readl(codec, YDSXGR_MAPOFREC) & ~(1 << ypcm->capture_bank_number);
ymfpci_writel(codec, YDSXGR_MAPOFREC, tmp);
ypcm->running = 0;
- } else {
- result = -EINVAL;
}
- spin_unlock_irqrestore(&codec->reg_lock, flags);
- return result;
}
-#endif
-static int ymfpci_pcm_voice_alloc(ymfpci_pcm_t *ypcm, int voices)
+static int ymfpci_pcm_voice_alloc(struct ymf_pcm *ypcm, int voices)
{
+ struct ymf_unit *unit;
int err;
+ unit = ypcm->state->unit;
if (ypcm->voices[1] != NULL && voices < 2) {
- ymfpci_voice_free(ypcm->codec, ypcm->voices[1]);
+ ymfpci_voice_free(unit, ypcm->voices[1]);
ypcm->voices[1] = NULL;
}
if (voices == 1 && ypcm->voices[0] != NULL)
return 0; /* already allocated */
if (voices > 1) {
if (ypcm->voices[0] != NULL && ypcm->voices[1] == NULL) {
- ymfpci_voice_free(ypcm->codec, ypcm->voices[0]);
+ ymfpci_voice_free(unit, ypcm->voices[0]);
ypcm->voices[0] = NULL;
}
- }
- err = ymfpci_voice_alloc(ypcm->codec, YMFPCI_PCM, voices > 1, &ypcm->voices[0]);
- if (err < 0)
- return err;
- ypcm->voices[0]->ypcm = ypcm;
- ypcm->voices[0]->interrupt = ymf_pcm_interrupt;
- if (voices > 1) {
- ypcm->voices[1] = &ypcm->codec->voices[ypcm->voices[0]->number + 1];
+ if ((err = voice_alloc(unit, YMFPCI_PCM, 1, ypcm->voices)) < 0)
+ return err;
+ ypcm->voices[0]->ypcm = ypcm;
ypcm->voices[1]->ypcm = ypcm;
+ } else {
+ if ((err = voice_alloc(unit, YMFPCI_PCM, 0, ypcm->voices)) < 0)
+ return err;
+ ypcm->voices[0]->ypcm = ypcm;
}
return 0;
}
}
/*
- * XXX Use new cache coherent PCI DMA routines instead of virt_to_bus.
+ * XXX Capture channel allocation is entirely fake at the moment.
+ * We use only one channel and mark it busy as required.
*/
-static int ymf_playback_prepare(ymfpci_t *codec, struct ymf_state *state)
+static int ymf_capture_alloc(struct ymf_unit *unit, int *pbank)
{
- ymfpci_pcm_t *ypcm = &state->ypcm;
+ struct ymf_capture *cap;
+ int cbank;
+
+ cbank = 1; /* Only ADC slot is used for now. */
+ cap = &unit->capture[cbank];
+ if (cap->use)
+ return -EBUSY;
+ cap->use = 1;
+ *pbank = cbank;
+ return 0;
+}
+
+static int ymf_playback_prepare(struct ymf_state *state)
+{
+ struct ymf_pcm *ypcm = &state->wpcm;
int err, nvoice;
if ((err = ymfpci_pcm_voice_alloc(ypcm, state->format.voices)) < 0) {
- /* Cannot be unless we leak voices in ymf_release! */
- printk(KERN_ERR "ymfpci%d: cannot allocate voice!\n",
- codec->dev_audio);
+ /* Somebody started 32 mpg123's in parallel? */
+ /* P3 */ printk("ymfpci%d: cannot allocate voice\n",
+ state->unit->dev_audio);
return err;
}
ymf_pcm_init_voice(ypcm->voices[nvoice],
state->format.voices == 2, state->format.rate,
ymf_pcm_format_width(state->format.format) == 16,
- virt_to_bus(state->dmabuf.rawbuf), state->dmabuf.dmasize,
+ virt_to_bus(ypcm->dmabuf.rawbuf), ypcm->dmabuf.dmasize,
ypcm->spdif);
}
return 0;
}
-#if 0 /* old */
-static int ymfpci_capture_prepare(void *private_data,
- snd_pcm_subchn_t * substream)
+static int ymf_capture_prepare(struct ymf_state *state)
{
- ymfpci_t *codec = snd_magic_cast(ymfpci_t, private_data, -ENXIO);
- snd_pcm_runtime_t *runtime = substream->runtime;
- ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, -ENXIO);
+ ymfpci_t *unit = state->unit;
+ struct ymf_pcm *ypcm = &state->rpcm;
ymfpci_capture_bank_t * bank;
- int nbank;
+ /* XXX This is confusing, gotta rename one of them banks... */
+ int nbank; /* flip-flop bank */
+ int cbank; /* input [super-]bank */
+ struct ymf_capture *cap;
u32 rate, format;
- ypcm->frag_size = snd_pcm_lib_transfer_fragment(substream);
- ypcm->buffer_size = snd_pcm_lib_transfer_size(substream);
- ypcm->frag_pos = 0;
- ypcm->last_pos = 0;
- ypcm->shift_offset = 0;
- rate = ((48000 * 4096) / runtime->format.rate) - 1;
+ if (ypcm->capture_bank_number == -1) {
+ if (ymf_capture_alloc(unit, &cbank) != 0)
+ return -EBUSY;
+
+ ypcm->capture_bank_number = cbank;
+
+ cap = &unit->capture[cbank];
+ cap->bank = unit->bank_capture[cbank][0];
+ cap->ypcm = ypcm;
+ ymfpci_hw_start(unit);
+ }
+
+ // ypcm->frag_size = snd_pcm_lib_transfer_fragment(substream);
+ // frag_size is replaced with nonfragged byte-aligned rolling buffer
+ rate = ((48000 * 4096) / state->format.rate) - 1;
format = 0;
- if (runtime->format.voices == 2)
+ if (state->format.voices == 2)
format |= 2;
- if (snd_pcm_format_width(runtime->format.format) == 8)
+ if (ymf_pcm_format_width(state->format.format) == 8)
format |= 1;
switch (ypcm->capture_bank_number) {
case 0:
- ymfpci_writel(codec, YDSXGR_RECFORMAT, format);
- ymfpci_writel(codec, YDSXGR_RECSLOTSR, rate);
+ ymfpci_writel(unit, YDSXGR_RECFORMAT, format);
+ ymfpci_writel(unit, YDSXGR_RECSLOTSR, rate);
break;
case 1:
- ymfpci_writel(codec, YDSXGR_ADCFORMAT, format);
- ymfpci_writel(codec, YDSXGR_ADCSLOTSR, rate);
+ ymfpci_writel(unit, YDSXGR_ADCFORMAT, format);
+ ymfpci_writel(unit, YDSXGR_ADCSLOTSR, rate);
break;
}
for (nbank = 0; nbank < 2; nbank++) {
- bank = codec->bank_capture[ypcm->capture_bank_number][nbank];
- bank->base = virt_to_bus(runtime->dma_area->buf);
- bank->loop_end = ypcm->buffer_size;
+ bank = unit->bank_capture[ypcm->capture_bank_number][nbank];
+ bank->base = virt_to_bus(ypcm->dmabuf.rawbuf);
+ // bank->loop_end = ypcm->dmabuf.dmasize >> state->format.shift;
+ bank->loop_end = ypcm->dmabuf.dmasize;
bank->start = 0;
bank->num_of_loops = 0;
}
- if (runtime->digital.dig_valid)
- /*runtime->digital.type == SND_PCM_DIG_AES_IEC958*/
- ymfpci_writew(codec, YDSXGR_SPDIFOUTSTATUS, runtime->digital.dig_status[0] |
- (runtime->digital.dig_status[1] << 8));
+#if 0 /* s/pdif */
+ if (state->digital.dig_valid)
+ /*state->digital.type == SND_PCM_DIG_AES_IEC958*/
+ ymfpci_writew(codec, YDSXGR_SPDIFOUTSTATUS,
+ state->digital.dig_status[0] | (state->digital.dig_status[1] << 8));
+#endif
return 0;
}
-static unsigned int ymfpci_playback_pointer(void *private_data,
- snd_pcm_subchn_t * substream)
-{
- ymfpci_t *codec = snd_magic_cast(ymfpci_t, private_data, -ENXIO);
- snd_pcm_runtime_t *runtime = substream->runtime;
- ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, -ENXIO);
- ymfpci_voice_t *voice = ypcm->voices[0];
- unsigned long flags;
- unsigned int result;
-
- spin_lock_irqsave(&codec->reg_lock, flags);
- if (ypcm->running && voice)
- result = voice->bank[codec->active_bank].start << ypcm->shift_offset;
- else
- result = 0;
- spin_unlock_irqrestore(&codec->reg_lock, flags);
- return result;
-}
-
-static unsigned int ymfpci_capture_pointer(void *private_data,
- snd_pcm_subchn_t * substream)
-{
- ymfpci_t *codec = snd_magic_cast(ymfpci_t, private_data, -ENXIO);
- snd_pcm_runtime_t *runtime = substream->runtime;
- ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, -ENXIO);
- unsigned long flags;
- unsigned int result;
-
- spin_lock_irqsave(&codec->reg_lock, flags);
- if (ypcm->running)
- result = codec->bank_capture[ypcm->capture_bank_number][codec->active_bank]->start << ypcm->shift_offset;
- else
- result = 0;
- spin_unlock_irqrestore(&codec->reg_lock, flags);
- return result;
-}
-#endif /* old */
-
void ymf_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
ymfpci_t *codec = dev_id;
u32 status, nvoice, mode;
- ymfpci_voice_t *voice;
+ struct ymf_voice *voice;
+ struct ymf_capture *cap;
status = ymfpci_readl(codec, YDSXGR_STATUS);
if (status & 0x80000000) {
spin_lock(&codec->voice_lock);
for (nvoice = 0; nvoice < 64; nvoice++) {
voice = &codec->voices[nvoice];
- if (voice->interrupt)
- voice->interrupt(codec, voice);
+ if (voice->use)
+ ymf_pcm_interrupt(codec, voice);
+ }
+ for (nvoice = 0; nvoice < 5; nvoice++) {
+ cap = &codec->capture[nvoice];
+ if (cap->use)
+ ymf_cap_interrupt(codec, cap);
}
spin_unlock(&codec->voice_lock);
}
}
}
-static void ymf_pcm_free_substream(ymfpci_pcm_t *ypcm)
+static void ymf_pcm_free_substream(struct ymf_pcm *ypcm)
{
- ymfpci_t *codec;
+ unsigned long flags;
+ struct ymf_unit *unit;
+
+ unit = ypcm->state->unit;
- if (ypcm) {
- codec = ypcm->codec;
+ if (ypcm->type == PLAYBACK_VOICE) {
+ spin_lock_irqsave(&unit->voice_lock, flags);
if (ypcm->voices[1])
- ymfpci_voice_free(codec, ypcm->voices[1]);
+ ymfpci_voice_free(unit, ypcm->voices[1]);
if (ypcm->voices[0])
- ymfpci_voice_free(codec, ypcm->voices[0]);
+ ymfpci_voice_free(unit, ypcm->voices[0]);
+ spin_unlock_irqrestore(&unit->voice_lock, flags);
+ } else {
+ if (ypcm->capture_bank_number != -1) {
+ unit->capture[ypcm->capture_bank_number].use = 0;
+ ypcm->capture_bank_number = -1;
+ ymfpci_hw_stop(unit);
+ }
}
}
-static int ymf_state_alloc(ymfpci_t *unit, int nvirt)
+static struct ymf_state *ymf_state_alloc(ymfpci_t *unit)
{
- ymfpci_pcm_t *ypcm;
+ struct ymf_pcm *ypcm;
struct ymf_state *state;
if ((state = kmalloc(sizeof(struct ymf_state), GFP_KERNEL)) == NULL) {
}
memset(state, 0, sizeof(struct ymf_state));
- init_waitqueue_head(&state->dmabuf.wait);
-
- ypcm = &state->ypcm;
+ ypcm = &state->wpcm;
ypcm->state = state;
- ypcm->codec = unit;
ypcm->type = PLAYBACK_VOICE;
+ ypcm->capture_bank_number = -1;
+ init_waitqueue_head(&ypcm->dmabuf.wait);
+
+ ypcm = &state->rpcm;
+ ypcm->state = state;
+ ypcm->type = CAPTURE_AC97;
+ ypcm->capture_bank_number = -1;
+ init_waitqueue_head(&ypcm->dmabuf.wait);
state->unit = unit;
- state->virt = nvirt;
state->format.format = AFMT_U8;
state->format.rate = 8000;
state->format.voices = 1;
ymf_pcm_update_shift(&state->format);
- unit->states[nvirt] = state;
- return 0;
+ return state;
out0:
- return -ENOMEM;
+ return NULL;
}
-#if HAVE_RECORD
-
-static int ymfpci_capture_open(void *private_data,
- snd_pcm_subchn_t * substream,
- u32 capture_bank_number)
-{
- ymfpci_t *codec = snd_magic_cast(ymfpci_t, private_data, -ENXIO);
- snd_pcm_runtime_t *runtime = substream->runtime;
- ymfpci_pcm_t *ypcm;
- int err;
-
- if ((err = snd_pcm_dma_alloc(substream, !capture_bank_number ? codec->dma2ptr : codec->dma3ptr, "YMFPCI - ADC")) < 0)
- return err;
- ypcm = snd_magic_kcalloc(ymfpci_pcm_t, 0, GFP_KERNEL);
- if (ypcm == NULL) {
- snd_pcm_dma_free(substream);
- return -ENOMEM;
- }
- ypcm->codec = codec;
- ypcm->type = capture_bank_number + CAPTURE_REC;
- ypcm->substream = substream;
- ypcm->capture_bank_number = capture_bank_number;
- codec->capture_substream[capture_bank_number] = substream;
- runtime->hw = &ymfpci_capture;
- snd_pcm_set_mixer(substream, codec->mixer->device, codec->ac97->me_capture);
- runtime->private_data = ypcm;
- runtime->private_free = ymfpci_pcm_free_substream;
- ymfpci_hw_start(codec);
- return 0;
-}
-
-#endif /* old */
-
/* AES/IEC958 channel status bits */
#define SND_PCM_AES0_PROFESSIONAL (1<<0) /* 0 = consumer, 1 = professional */
#define SND_PCM_AES0_NONAUDIO (1<<1) /* 0 = audio, 1 = non-audio */
#define SND_PCM_AES3_CON_CLOCK_50PPM (1<<4) /* 50 ppm */
#define SND_PCM_AES3_CON_CLOCK_VARIABLE (2<<4) /* variable pitch */
-#if HAVE_RECORD /* old */
-
-static int ymfpci_capture_close(void *private_data,
- snd_pcm_subchn_t * substream)
-{
- ymfpci_t *codec = snd_magic_cast(ymfpci_t, private_data, -ENXIO);
- snd_pcm_runtime_t *runtime = substream->runtime;
- ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, -ENXIO);
-
- if (ypcm != NULL) {
- codec->capture_substream[ypcm->capture_bank_number] = NULL;
- ymfpci_hw_stop(codec);
- }
- snd_pcm_dma_free(substream);
- return 0;
-}
-#endif
-
/*
* User interface
*/
return -ESPIPE;
}
-/* in this loop, dmabuf.count signifies the amount of data that is waiting to be copied to
- the user's buffer. it is filled by the dma machine and drained by this loop. */
-static ssize_t ymf_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+/*
+ * in this loop, dmabuf.count signifies the amount of data that is
+ * waiting to be copied to the user's buffer. it is filled by the dma
+ * machine and drained by this loop.
+ */
+static ssize_t
+ymf_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
{
-#if HAVE_RECORD
- struct cs_state *state = (struct cs_state *)file->private_data;
- struct dmabuf *dmabuf = &state->dmabuf;
+ struct ymf_state *state = (struct ymf_state *)file->private_data;
+ struct ymf_dmabuf *dmabuf = &state->rpcm.dmabuf;
+ DECLARE_WAITQUEUE(waita, current);
ssize_t ret;
unsigned long flags;
- unsigned swptr;
- int cnt;
-
-#ifdef DEBUG
- printk("cs461x: cs_read called, count = %d\n", count);
-#endif
+ unsigned int swptr;
+ int cnt; /* This many to go in this revolution */
if (ppos != &file->f_pos)
return -ESPIPE;
return -EFAULT;
ret = 0;
+ add_wait_queue(&dmabuf->wait, &waita);
while (count > 0) {
- spin_lock_irqsave(&state->card->lock, flags);
- if (dmabuf->count > (signed) dmabuf->dmasize) {
- /* buffer overrun, we are recovering from sleep_on_timeout,
- resync hwptr and swptr, make process flush the buffer */
- dmabuf->count = dmabuf->dmasize;
- dmabuf->swptr = dmabuf->hwptr;
- }
+ spin_lock_irqsave(&state->unit->reg_lock, flags);
swptr = dmabuf->swptr;
cnt = dmabuf->dmasize - swptr;
if (dmabuf->count < cnt)
cnt = dmabuf->count;
- spin_unlock_irqrestore(&state->card->lock, flags);
+ spin_unlock_irqrestore(&state->unit->reg_lock, flags);
if (cnt > count)
cnt = count;
unsigned long tmo;
/* buffer is empty, start the dma machine and wait for data to be
recorded */
- start_adc(state);
+ spin_lock_irqsave(&state->unit->reg_lock, flags);
+ if (!state->rpcm.running) {
+ ymf_capture_trigger(state->unit, &state->rpcm, 1);
+ }
+ spin_unlock_irqrestore(&state->unit->reg_lock, flags);
if (file->f_flags & O_NONBLOCK) {
if (!ret) ret = -EAGAIN;
- return ret;
+ break;
}
/* This isnt strictly right for the 810 but it'll do */
- tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
- tmo >>= sample_shift[dmabuf->fmt];
+ tmo = (dmabuf->dmasize * HZ) / (state->format.rate * 2);
+ tmo >>= state->format.shift;
/* There are two situations when sleep_on_timeout returns, one is when
the interrupt is serviced correctly and the process is waked up by
ISR ON TIME. Another is when timeout is expired, which means that
is TOO LATE for the process to be scheduled to run (scheduler latency)
which results in a (potential) buffer overrun. And worse, there is
NOTHING we can do to prevent it. */
- if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {
-#ifdef DEBUG
- printk(KERN_ERR "cs461x: recording schedule timeout, "
- "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
- dmabuf->hwptr, dmabuf->swptr);
-#endif
- /* a buffer overrun, we delay the recovery untill next time the
- while loop begin and we REALLY have space to record */
+ set_current_state(TASK_INTERRUPTIBLE);
+ tmo = schedule_timeout(tmo);
+ spin_lock_irqsave(&state->unit->reg_lock, flags);
+ if (tmo == 0 && dmabuf->count == 0) {
+ printk(KERN_ERR "ymfpci%d: recording schedule timeout, "
+ "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+ state->unit->dev_audio,
+ dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
+ dmabuf->hwptr, dmabuf->swptr);
}
+ spin_unlock_irqrestore(&state->unit->reg_lock, flags);
if (signal_pending(current)) {
ret = ret ? ret : -ERESTARTSYS;
- return ret;
+ break;
}
continue;
}
if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) {
if (!ret) ret = -EFAULT;
- return ret;
+ break;
}
swptr = (swptr + cnt) % dmabuf->dmasize;
- spin_lock_irqsave(&state->card->lock, flags);
+ spin_lock_irqsave(&state->unit->reg_lock, flags);
dmabuf->swptr = swptr;
dmabuf->count -= cnt;
- spin_unlock_irqrestore(&state->card->lock, flags);
+ // spin_unlock_irqrestore(&state->unit->reg_lock, flags);
count -= cnt;
buffer += cnt;
ret += cnt;
- start_adc(state);
+ // spin_lock_irqsave(&state->unit->reg_lock, flags);
+ if (!state->rpcm.running) {
+ ymf_capture_trigger(state->unit, &state->rpcm, 1);
+ }
+ spin_unlock_irqrestore(&state->unit->reg_lock, flags);
}
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&dmabuf->wait, &waita);
+
return ret;
-#else
- return -EINVAL;
-#endif
}
-static ssize_t ymf_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+static ssize_t
+ymf_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
{
struct ymf_state *state = (struct ymf_state *)file->private_data;
- struct ymf_dmabuf *dmabuf = &state->dmabuf;
+ struct ymf_dmabuf *dmabuf = &state->wpcm.dmabuf;
DECLARE_WAITQUEUE(waita, current);
ssize_t ret;
unsigned long flags;
}
if (dmabuf->count == 0) {
swptr = dmabuf->hwptr;
- if (state->ypcm.running) {
+ if (state->wpcm.running) {
/*
* Add uncertainty reserve.
*/
* wait for data to be played
*/
spin_lock_irqsave(&state->unit->reg_lock, flags);
- if (!state->ypcm.running) {
- ymf_playback_trigger(state->unit, &state->ypcm, 1);
+ if (!state->wpcm.running) {
+ ymf_playback_trigger(state->unit, &state->wpcm, 1);
}
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
if (file->f_flags & O_NONBLOCK) {
*/
delay = state->format.rate / 20; /* 50ms */
delay <<= state->format.shift;
- if (dmabuf->count >= delay && !state->ypcm.running) {
- ymf_playback_trigger(state->unit, &state->ypcm, 1);
+ if (dmabuf->count >= delay && !state->wpcm.running) {
+ ymf_playback_trigger(state->unit, &state->wpcm, 1);
}
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
static unsigned int ymf_poll(struct file *file, struct poll_table_struct *wait)
{
struct ymf_state *state = (struct ymf_state *)file->private_data;
- struct ymf_dmabuf *dmabuf = &state->dmabuf;
+ struct ymf_dmabuf *dmabuf;
unsigned long flags;
unsigned int mask = 0;
- if (file->f_mode & (FMODE_WRITE | FMODE_READ))
- poll_wait(file, &dmabuf->wait, wait);
+ if (file->f_mode & FMODE_WRITE)
+ poll_wait(file, &state->wpcm.dmabuf.wait, wait);
+ // if (file->f_mode & FMODE_READ)
+ // poll_wait(file, &dmabuf->wait, wait);
spin_lock_irqsave(&state->unit->reg_lock, flags);
if (file->f_mode & FMODE_READ) {
+ dmabuf = &state->rpcm.dmabuf;
if (dmabuf->count >= (signed)dmabuf->fragsize)
mask |= POLLIN | POLLRDNORM;
}
if (file->f_mode & FMODE_WRITE) {
+ dmabuf = &state->wpcm.dmabuf;
if (dmabuf->mapped) {
if (dmabuf->count >= (signed)dmabuf->fragsize)
mask |= POLLOUT | POLLWRNORM;
static int ymf_mmap(struct file *file, struct vm_area_struct *vma)
{
struct ymf_state *state = (struct ymf_state *)file->private_data;
- struct ymf_dmabuf *dmabuf = &state->dmabuf;
+ struct ymf_dmabuf *dmabuf = &state->wpcm.dmabuf;
int ret;
unsigned long size;
-
if (vma->vm_flags & VM_WRITE) {
if ((ret = prog_dmabuf(state, 0)) != 0)
unsigned int cmd, unsigned long arg)
{
struct ymf_state *state = (struct ymf_state *)file->private_data;
- struct ymf_dmabuf *dmabuf = &state->dmabuf;
+ struct ymf_dmabuf *dmabuf;
unsigned long flags;
audio_buf_info abinfo;
count_info cinfo;
case SNDCTL_DSP_RESET:
if (file->f_mode & FMODE_WRITE) {
ymf_wait_dac(state);
+ dmabuf = &state->wpcm.dmabuf;
spin_lock_irqsave(&state->unit->reg_lock, flags);
dmabuf->ready = 0;
- dmabuf->swptr = dmabuf->hwptr = 0;
+ dmabuf->swptr = dmabuf->hwptr;
dmabuf->count = dmabuf->total_bytes = 0;
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
}
-#if HAVE_RECORD
if (file->f_mode & FMODE_READ) {
- stop_adc(state);
- synchronize_irq();
+ ymf_stop_adc(state);
+ dmabuf = &state->rpcm.dmabuf;
+ spin_lock_irqsave(&state->unit->reg_lock, flags);
dmabuf->ready = 0;
- dmabuf->swptr = dmabuf->hwptr = 0;
+ dmabuf->swptr = dmabuf->hwptr;
dmabuf->count = dmabuf->total_bytes = 0;
+ spin_unlock_irqrestore(&state->unit->reg_lock, flags);
}
-#endif
return 0;
case SNDCTL_DSP_SYNC:
if (file->f_mode & FMODE_WRITE) {
+ dmabuf = &state->wpcm.dmabuf;
if (file->f_flags & O_NONBLOCK) {
spin_lock_irqsave(&state->unit->reg_lock, flags);
- if (dmabuf->count != 0 && !state->ypcm.running) {
+ if (dmabuf->count != 0 && !state->wpcm.running) {
ymf_start_dac(state);
}
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
ymf_wait_dac(state);
}
}
+ /* XXX What does this do for reading? dmabuf->count=0; ? */
return 0;
case SNDCTL_DSP_SPEED: /* set smaple rate */
if (val >= 8000 && val <= 48000) {
if (file->f_mode & FMODE_WRITE) {
ymf_wait_dac(state);
+ dmabuf = &state->wpcm.dmabuf;
+ spin_lock_irqsave(&state->unit->reg_lock, flags);
+ dmabuf->ready = 0;
+ state->format.rate = val;
+ ymf_pcm_update_shift(&state->format);
+ spin_unlock_irqrestore(&state->unit->reg_lock, flags);
}
-#if HAVE_RECORD
if (file->f_mode & FMODE_READ) {
- stop_adc(state);
+ ymf_stop_adc(state);
+ dmabuf = &state->rpcm.dmabuf;
+ spin_lock_irqsave(&state->unit->reg_lock, flags);
+ dmabuf->ready = 0;
+ state->format.rate = val;
+ ymf_pcm_update_shift(&state->format);
+ spin_unlock_irqrestore(&state->unit->reg_lock, flags);
}
-#endif
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- dmabuf->ready = 0;
- state->format.rate = val;
- ymf_pcm_update_shift(&state->format);
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
}
return put_user(state->format.rate, (int *)arg);
* OSS manual does not mention SNDCTL_DSP_STEREO at all.
* All channels are mono and if you want stereo, you
* play into two channels with SNDCTL_DSP_CHANNELS.
- * However, mpg123 uses it. I wonder, why Michael Hipp uses it.
+ * However, mpg123 calls it. I wonder, why Michael Hipp used it.
*/
case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
if (get_user(val, (int *)arg))
return -EFAULT;
if (file->f_mode & FMODE_WRITE) {
ymf_wait_dac(state);
+ dmabuf = &state->wpcm.dmabuf;
spin_lock_irqsave(&state->unit->reg_lock, flags);
dmabuf->ready = 0;
state->format.voices = val ? 2 : 1;
ymf_pcm_update_shift(&state->format);
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
}
-#if HAVE_RECORD
if (file->f_mode & FMODE_READ) {
- /* stop_adc(state); */
+ ymf_stop_adc(state);
+ dmabuf = &state->rpcm.dmabuf;
+ spin_lock_irqsave(&state->unit->reg_lock, flags);
dmabuf->ready = 0;
- if(val)
- dmabuf->fmt |= CS_FMT_STEREO;
- else
- dmabuf->fmt &= ~CS_FMT_STEREO;
+ state->format.voices = val ? 2 : 1;
+ ymf_pcm_update_shift(&state->format);
+ spin_unlock_irqrestore(&state->unit->reg_lock, flags);
}
-#endif
return 0;
case SNDCTL_DSP_GETBLKSIZE:
if (file->f_mode & FMODE_WRITE) {
if ((val = prog_dmabuf(state, 0)))
return val;
- return put_user(dmabuf->fragsize, (int *)arg);
+ return put_user(state->wpcm.dmabuf.fragsize, (int *)arg);
}
if (file->f_mode & FMODE_READ) {
if ((val = prog_dmabuf(state, 1)))
return val;
- return put_user(dmabuf->fragsize, (int *)arg);
+ return put_user(state->rpcm.dmabuf.fragsize, (int *)arg);
}
return -EINVAL;
if (val == AFMT_S16_LE || val == AFMT_U8) {
if (file->f_mode & FMODE_WRITE) {
ymf_wait_dac(state);
+ dmabuf = &state->wpcm.dmabuf;
+ spin_lock_irqsave(&state->unit->reg_lock, flags);
+ dmabuf->ready = 0;
+ state->format.format = val;
+ ymf_pcm_update_shift(&state->format);
+ spin_unlock_irqrestore(&state->unit->reg_lock, flags);
}
-#if HAVE_RECORD
if (file->f_mode & FMODE_READ) {
- stop_adc(state);
+ ymf_stop_adc(state);
+ dmabuf = &state->rpcm.dmabuf;
+ spin_lock_irqsave(&state->unit->reg_lock, flags);
+ dmabuf->ready = 0;
+ state->format.format = val;
+ ymf_pcm_update_shift(&state->format);
+ spin_unlock_irqrestore(&state->unit->reg_lock, flags);
}
-#endif
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- dmabuf->ready = 0;
- state->format.format = val;
- ymf_pcm_update_shift(&state->format);
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
}
return put_user(state->format.format, (int *)arg);
ymf_wait_dac(state);
if (val == 1 || val == 2) {
spin_lock_irqsave(&state->unit->reg_lock, flags);
+ dmabuf = &state->wpcm.dmabuf;
dmabuf->ready = 0;
state->format.voices = val;
ymf_pcm_update_shift(&state->format);
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
}
}
-#if HAVE_RECORD
if (file->f_mode & FMODE_READ) {
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- stop_adc(state);
- dmabuf->ready = 0;
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+ ymf_stop_adc(state);
+ if (val == 1 || val == 2) {
+ spin_lock_irqsave(&state->unit->reg_lock, flags);
+ dmabuf = &state->rpcm.dmabuf;
+ dmabuf->ready = 0;
+ state->format.voices = val;
+ ymf_pcm_update_shift(&state->format);
+ spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+ }
}
-#endif
}
return put_user(state->format.voices, (int *)arg);
* The paragraph above is a clumsy way to say "flush ioctl".
* This ioctl is used by mpg123.
*/
- /* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_POST\n"); */
spin_lock_irqsave(&state->unit->reg_lock, flags);
- if (dmabuf->count != 0 && !state->ypcm.running) {
+ if (state->wpcm.dmabuf.count != 0 && !state->wpcm.running) {
ymf_start_dac(state);
}
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
return 0;
+#if 0 /* XXX Was dummy implementation anyways. Make sense of this. */
case SNDCTL_DSP_SUBDIVIDE:
+ dmabuf = &state->wpcm.dmabuf;
if (dmabuf->subdivision)
return -EINVAL;
if (get_user(val, (int *)arg))
return -EINVAL;
dmabuf->subdivision = val;
return 0;
+#endif
case SNDCTL_DSP_SETFRAGMENT:
if (get_user(val, (int *)arg))
/* P3: these frags are for Doom. Amasingly, it sets [2,2**11]. */
/* P3 */ // printk("ymfpci: ioctl SNDCTL_DSP_SETFRAGMENT 0x%x\n", val);
+ dmabuf = &state->wpcm.dmabuf;
dmabuf->ossfragshift = val & 0xffff;
dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
switch (dmabuf->ossmaxfrags) {
case SNDCTL_DSP_GETOSPACE:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
+ dmabuf = &state->wpcm.dmabuf;
if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
return val;
spin_lock_irqsave(&state->unit->reg_lock, flags);
- /* cs_update_ptr(state); */ /* XXX Always up to date? */
abinfo.fragsize = dmabuf->fragsize;
abinfo.bytes = dmabuf->dmasize - dmabuf->count;
abinfo.fragstotal = dmabuf->numfrag;
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-#if HAVE_RECORD
case SNDCTL_DSP_GETISPACE:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
+ dmabuf = &state->rpcm.dmabuf;
if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0)
return val;
- spin_lock_irqsave(&state->card->lock, flags);
- cs_update_ptr(state);
+ spin_lock_irqsave(&state->unit->reg_lock, flags);
abinfo.fragsize = dmabuf->fragsize;
abinfo.bytes = dmabuf->count;
abinfo.fragstotal = dmabuf->numfrag;
abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
- spin_unlock_irqrestore(&state->card->lock, flags);
+ spin_unlock_irqrestore(&state->unit->reg_lock, flags);
return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-#endif
case SNDCTL_DSP_NONBLOCK:
file->f_flags |= O_NONBLOCK;
(int *)arg); */
return put_user(0, (int *)arg);
-#if 0 /* old */
+#if 0 /* not implememnted, yet? */
case SNDCTL_DSP_GETTRIGGER:
val = 0;
+ dmabuf = &state->wpcm.dmabuf;
if (file->f_mode & FMODE_READ && dmabuf->enable)
val |= PCM_ENABLE_INPUT;
if (file->f_mode & FMODE_WRITE && dmabuf->enable)
if (get_user(val, (int *)arg))
return -EFAULT;
if (file->f_mode & FMODE_READ) {
+ dmabuf = &state->rpcm.dmabuf;
if (val & PCM_ENABLE_INPUT) {
if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
return ret;
stop_adc(state);
}
if (file->f_mode & FMODE_WRITE) {
+ dmabuf = &state->wpcm.dmabuf;
if (val & PCM_ENABLE_OUTPUT) {
if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
return ret;
stop_dac(state);
}
return 0;
-
#endif
-#if HAVE_RECORD
case SNDCTL_DSP_GETIPTR:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
+ dmabuf = &state->rpcm.dmabuf;
spin_lock_irqsave(&state->unit->reg_lock, flags);
- cs_update_ptr(state);
cinfo.bytes = dmabuf->total_bytes;
cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
cinfo.ptr = dmabuf->hwptr;
+ /* XXX fishy - breaks invariant count=hwptr-swptr */
if (dmabuf->mapped)
dmabuf->count &= dmabuf->fragsize-1;
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
-#endif
+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
case SNDCTL_DSP_GETOPTR:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
+ dmabuf = &state->wpcm.dmabuf;
spin_lock_irqsave(&state->unit->reg_lock, flags);
- /* cs_update_ptr(state); */ /* Always up to date */
cinfo.bytes = dmabuf->total_bytes;
cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
cinfo.ptr = dmabuf->hwptr;
+ /* XXX fishy - breaks invariant count=swptr-hwptr */
if (dmabuf->mapped)
dmabuf->count &= dmabuf->fragsize-1;
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
case SNDCTL_DSP_SETDUPLEX: /* XXX TODO */
return -EINVAL;
-#if 0 /* old */
+#if 0 /* XXX implement when an app found that uses it. */
case SNDCTL_DSP_GETODELAY:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
spin_lock_irqsave(&state->unit->reg_lock, flags);
cs_update_ptr(state);
+ dmabuf = &state->wpcm.dmabuf;
val = dmabuf->count;
- spin_unlock_irqrestore(&state->card->lock, flags);
+ spin_unlock_irqrestore(&state->unit->reg_lock, flags);
return put_user(val, (int *)arg);
#endif
return put_user(state->format.rate, (int *)arg);
case SOUND_PCM_READ_CHANNELS:
- return put_user(state->format.voices, (int *)arg);
+ return put_user(state->format.voices, (int *)arg);
case SOUND_PCM_READ_BITS:
return put_user(AFMT_S16_LE, (int *)arg);
return -ENOTTY;
}
+/*
+ * open(2)
+ * We use upper part of the minor to distinguish between soundcards.
+ * Channels are opened with a clone open.
+ */
static int ymf_open(struct inode *inode, struct file *file)
{
struct list_head *list;
ymfpci_t *unit;
int minor;
struct ymf_state *state;
- int nvirt;
int err;
- /*
- * This is how we do it currently: only one channel is used
- * in every board, so that we could use several boards in one machine.
- * We waste 63 out of 64 playback slots, but so what.
- * OSS model is constructed for devices with single playback channel.
- */
minor = MINOR(inode->i_rdev);
if ((minor & 0x0F) == 3) { /* /dev/dspN */
;
} else {
return -ENXIO;
}
- nvirt = 0; /* Such is the partitioning of minor */
for (list = ymf_devs.next; list != &ymf_devs; list = list->next) {
unit = list_entry(list, ymfpci_t, ymf_devs);
return -ENODEV;
down(&unit->open_sem);
- if (unit->states[nvirt] != NULL) {
- up(&unit->open_sem);
- return -EBUSY;
- }
- if ((err = ymf_state_alloc(unit, nvirt)) != 0) {
+ if ((state = ymf_state_alloc(unit)) == NULL) {
up(&unit->open_sem);
- return err;
+ return -ENOMEM;
}
- state = unit->states[nvirt];
+ list_add_tail(&state->chain, &unit->states);
file->private_data = state;
/*
- * XXX This ymf_playback_prepare is totally unneeded here.
- * The question is if we want to allow write to fail if
- * prog_dmabuf fails... Say, no memory in DMA zone?
+ * ymf_read and ymf_write that we borrowed from cs46xx
+ * allocate buffers with prog_dmabuf(). We call prog_dmabuf
+ * here so that in case of DMA memory exhaustion open
+ * fails rather than write.
+ *
+ * XXX prog_dmabuf allocates voice. Should allocate explicitly, above.
*/
- if ((err = ymf_playback_prepare(unit, state)) != 0) {
- /* XXX This recovery is ugly as hell. */
-
- ymf_pcm_free_substream(&state->ypcm);
-
- unit->states[state->virt] = NULL;
- kfree(state);
-
- up(&unit->open_sem);
- return err;
+ if (file->f_mode & FMODE_WRITE) {
+ if (!state->wpcm.dmabuf.ready) {
+ if ((err = prog_dmabuf(state, 0)) != 0) {
+ goto out_nodma;
+ }
+ }
+ }
+ if (file->f_mode & FMODE_READ) {
+ if (!state->rpcm.dmabuf.ready) {
+ if ((err = prog_dmabuf(state, 1)) != 0) {
+ goto out_nodma;
+ }
+ }
}
#if 0 /* test if interrupts work */
(YDSXGR_TIMERCTRL_TEN|YDSXGR_TIMERCTRL_TIEN));
#endif
up(&unit->open_sem);
- /* XXX Is it correct to have MOD_INC_USE_COUNT outside of sem.? */
MOD_INC_USE_COUNT;
return 0;
+
+out_nodma:
+ /*
+ * XXX Broken custom: "goto out_xxx" in other place is
+ * a nestable exception, but here it is not nestable due to semaphore.
+ * XXX Doubtful technique of self-describing objects....
+ */
+ dealloc_dmabuf(&state->wpcm.dmabuf);
+ dealloc_dmabuf(&state->rpcm.dmabuf);
+ ymf_pcm_free_substream(&state->wpcm);
+ ymf_pcm_free_substream(&state->rpcm);
+
+ list_del(&state->chain);
+ kfree(state);
+
+ up(&unit->open_sem);
+ return err;
}
static int ymf_release(struct inode *inode, struct file *file)
ymfpci_writeb(codec, YDSXGR_TIMERCTRL, 0);
#endif
- if (state != codec->states[state->virt]) {
- printk(KERN_ERR "ymfpci%d.%d: state mismatch\n",
- state->unit->dev_audio, state->virt);
- return -EIO;
- }
-
down(&codec->open_sem);
/*
* Deallocate when unloading the driver and we can wait.
*/
ymf_wait_dac(state);
- dealloc_dmabuf(state);
- ymf_pcm_free_substream(&state->ypcm);
-
- codec->states[state->virt] = NULL;
+ ymf_stop_adc(state); /* fortunately, it's immediate */
+ dealloc_dmabuf(&state->wpcm.dmabuf);
+ dealloc_dmabuf(&state->rpcm.dmabuf);
+ ymf_pcm_free_substream(&state->wpcm);
+ ymf_pcm_free_substream(&state->rpcm);
+
+ list_del(&state->chain);
+ file->private_data = NULL; /* Can you tell I programmed Solaris */
kfree(state);
up(&codec->open_sem);
* initialization routines
*/
+#ifdef CONFIG_SOUND_YMFPCI_LEGACY
+
+static int ymfpci_setup_legacy(ymfpci_t *unit, struct pci_dev *pcidev)
+{
+ int v;
+ int mpuio = -1, oplio = -1;
+
+ switch (unit->iomidi) {
+ case 0x330:
+ mpuio = 0;
+ break;
+ case 0x300:
+ mpuio = 1;
+ break;
+ case 0x332:
+ mpuio = 2;
+ break;
+ case 0x334:
+ mpuio = 3;
+ break;
+ default: ;
+ }
+
+ switch (unit->iosynth) {
+ case 0x388:
+ oplio = 0;
+ break;
+ case 0x398:
+ oplio = 1;
+ break;
+ case 0x3a0:
+ oplio = 2;
+ break;
+ case 0x3a8:
+ oplio = 3;
+ break;
+ default: ;
+ }
+
+ if (mpuio >= 0 || oplio >= 0) {
+ v = 0x003e;
+ pci_write_config_word(pcidev, PCIR_LEGCTRL, v);
+
+ switch (pcidev->device) {
+ case PCI_DEVICE_ID_YAMAHA_724:
+ case PCI_DEVICE_ID_YAMAHA_740:
+ case PCI_DEVICE_ID_YAMAHA_724F:
+ case PCI_DEVICE_ID_YAMAHA_740C:
+ v = 0x8800;
+ if (mpuio >= 0) { v |= mpuio<<4; }
+ if (oplio >= 0) { v |= oplio; }
+ pci_write_config_word(pcidev, PCIR_ELEGCTRL, v);
+ break;
+
+ case PCI_DEVICE_ID_YAMAHA_744:
+ case PCI_DEVICE_ID_YAMAHA_754:
+ v = 0x8800;
+ pci_write_config_word(pcidev, PCIR_ELEGCTRL, v);
+ if (oplio >= 0) {
+ pci_write_config_word(pcidev, PCIR_OPLADR, unit->iosynth);
+ }
+ if (mpuio >= 0) {
+ pci_write_config_word(pcidev, PCIR_MPUADR, unit->iomidi);
+ }
+ break;
+
+ default:
+ printk(KERN_ERR "ymfpci: Unknown device ID: 0x%x\n",
+ pcidev->device);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+#endif /* CONFIG_SOUND_YMFPCI_LEGACY */
+
static void ymfpci_aclink_reset(struct pci_dev * pci)
{
u8 cmd;
ptr += 0x00ff;
(long)ptr &= ~0x00ff;
+ /*
+ * Hardware requires only ptr[playback_ctrl_size] zeroed,
+ * but in our judgement it is a wrong kind of savings, so clear it all.
+ */
+ memset(ptr, 0, size);
+
codec->bank_base_playback = ptr;
codec->ctrl_playback = (u32 *)ptr;
codec->ctrl_playback[0] = YDSXG_PLAYBACK_VOICES;
kfree(codec->work_ptr);
}
-static int ymf_ac97_init(ymfpci_t *card, int num_ac97)
+static int ymf_ac97_init(ymfpci_t *unit, int num_ac97)
{
struct ac97_codec *codec;
u16 eid;
/* initialize some basic codec information, other fields will be filled
in ac97_probe_codec */
- codec->private_data = card;
+ codec->private_data = unit;
codec->id = num_ac97;
codec->codec_read = ymfpci_codec_read;
goto out_kfree;
}
- card->ac97_features = eid;
+ unit->ac97_features = eid;
if ((codec->dev_mixer = register_sound_mixer(&ymf_mixer_fops, -1)) < 0) {
printk(KERN_ERR "ymfpci: couldn't register mixer!\n");
goto out_kfree;
}
- card->ac97_codec[num_ac97] = codec;
+ unit->ac97_codec[num_ac97] = codec;
return 0;
out_kfree:
return -ENODEV;
}
+#ifdef CONFIG_SOUND_YMFPCI_LEGACY
+# ifdef MODULE
+static int mpu_io = 0;
+static int synth_io = 0;
+MODULE_PARM(mpu_io, "i");
+MODULE_PARM(synth_io, "i");
+# else
+static int mpu_io = 0x330;
+static int synth_io = 0x388;
+# endif
+static int assigned;
+#endif /* CONFIG_SOUND_YMFPCI_LEGACY */
+
static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_device_id *ent)
{
u16 ctrl;
spin_lock_init(&codec->reg_lock);
spin_lock_init(&codec->voice_lock);
init_MUTEX(&codec->open_sem);
+ INIT_LIST_HEAD(&codec->states);
codec->pci = pcidev;
pci_read_config_byte(pcidev, PCI_REVISION_ID, &codec->rev);
codec->reg_area_virt = ioremap(pci_resource_start(pcidev, 0), 0x8000);
+ if (codec->reg_area_virt == NULL) {
+ printk(KERN_ERR "ymfpci: unable to map registers\n");
+ goto out_free;
+ }
printk(KERN_INFO "ymfpci: %s at 0x%lx IRQ %d\n",
(char *)ent->driver_data, pci_resource_start(pcidev, 0), pcidev->irq);
if (ymfpci_codec_ready(codec, 0, 1) < 0)
goto out_unmap;
+#ifdef CONFIG_SOUND_YMFPCI_LEGACY
+ if (assigned == 0) {
+ codec->iomidi = mpu_io;
+ codec->iosynth = synth_io;
+ if (ymfpci_setup_legacy(codec, pcidev) < 0)
+ goto out_unmap;
+ assigned = 1;
+ }
+#endif
+
ymfpci_download_image(codec);
udelay(100); /* seems we need some delay after downloading image.. */
if (ymfpci_memalloc(codec) < 0)
goto out_disable_dsp;
- /* ymfpci_proc_init(card, codec); */
+ /* ymfpci_proc_init(unit, codec); */
if (request_irq(pcidev->irq, ymf_interrupt, SA_SHIRQ, "ymfpci", codec) != 0) {
- printk(KERN_ERR "ymfpci%d: unable to request IRQ %d\n",
- codec->dev_audio, pcidev->irq);
+ printk(KERN_ERR "ymfpci: unable to request IRQ %d\n",
+ pcidev->irq);
goto out_memfree;
}
if ((err = ymf_ac97_init(codec, 0)) != 0)
goto out_unregister_sound_dsp;
+#ifdef CONFIG_SOUND_YMFPCI_LEGACY
+ codec->opl3_data.name = "ymfpci";
+ codec->mpu_data.name = "ymfpci";
+
+ codec->opl3_data.io_base = codec->iosynth;
+ codec->opl3_data.irq = -1;
+
+ codec->mpu_data.io_base = codec->iomidi;
+ codec->mpu_data.irq = -1; /* XXX Make it ours. */
+
+ if (codec->iomidi) {
+ if (!probe_uart401(&codec->mpu_data, THIS_MODULE)) {
+ codec->iomidi = 0; /* XXX kludge */
+ }
+ }
+#endif /* CONFIG_SOUND_YMFPCI_LEGACY */
+
/* put it into driver list */
list_add_tail(&codec->ymf_devs, &ymf_devs);
pci_set_drvdata(pcidev, codec);
ymfpci_writel(codec, YDSXGR_STATUS, ~0);
out_unmap:
iounmap(codec->reg_area_virt);
+ out_free:
kfree(codec);
return -ENODEV;
}
ctrl = ymfpci_readw(codec, YDSXGR_GLOBALCTRL);
ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
iounmap(codec->reg_area_virt);
+#ifdef CONFIG_SOUND_YMFPCI_LEGACY
+ if (codec->iomidi) {
+ unload_uart401(&codec->mpu_data);
+ }
+#endif /* CONFIG_SOUND_YMFPCI_LEGACY */
kfree(codec);
}
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
+#include <linux/config.h>
/*
* Direct registers
#define YDSXG_AC97READCMD 0x8000
#define YDSXG_AC97WRITECMD 0x0000
+#define PCIR_LEGCTRL 0x40
+#define PCIR_ELEGCTRL 0x42
#define PCIR_DSXGCTRL 0x48
+#define PCIR_OPLADR 0x60
+#define PCIR_SBADR 0x62
+#define PCIR_MPUADR 0x64
#define YDSXG_DSPLENGTH 0x0080
#define YDSXG_CTRLLENGTH 0x3000
} ymfpci_playback_bank_t;
typedef struct stru_ymfpci_capture_bank {
- u32 base; /* 32-bit address */
- u32 loop_end; /* 32-bit offset */
+ u32 base; /* 32-bit address (aligned at 4) */
+ u32 loop_end; /* size in BYTES (aligned at 4) */
u32 start; /* 32-bit offset */
u32 num_of_loops; /* counter */
} ymfpci_capture_bank_t;
u32 temp;
} ymfpci_effect_bank_t;
-typedef struct stru_ymfpci_voice ymfpci_voice_t;
-typedef struct ymf_pcm ymfpci_pcm_t;
+typedef struct ymf_voice ymfpci_voice_t;
/*
* Throughout the code Yaroslav names YMF unit pointer "codec"
* even though it does not correspond to any codec. Must be historic.
YMFPCI_MIDI
} ymfpci_voice_type_t;
-struct stru_ymfpci_voice {
- ymfpci_t *codec;
+struct ymf_voice {
+ // ymfpci_t *codec;
int number;
- int use: 1,
- pcm: 1,
- synth: 1,
- midi: 1;
+ char use, pcm, synth, midi; // bool
ymfpci_playback_bank_t *bank;
- void (*interrupt)(ymfpci_t *codec, ymfpci_voice_t *voice);
- ymfpci_pcm_t *ypcm;
+ struct ymf_pcm *ypcm;
};
-typedef enum {
- PLAYBACK_VOICE,
- CAPTURE_REC,
- CAPTURE_AC97,
- EFFECT_DRY_LEFT,
- EFFECT_DRY_RIGHT,
- EFFECT_EFF1,
- EFFECT_EFF2,
- EFFECT_EFF3
-} ymfpci_pcm_type_t;
-
-struct ymf_pcm {
- ymfpci_t *codec;
- ymfpci_pcm_type_t type;
- struct ymf_state *state;
- ymfpci_voice_t *voices[2]; /* playback only */
- int running; // +
- int spdif;
+struct ymf_capture {
+ // struct ymf_unit *unit;
+ int use;
+ ymfpci_capture_bank_t *bank;
+ struct ymf_pcm *ypcm;
};
struct ymf_unit {
u8 rev; /* PCI revision */
void *reg_area_virt;
- void *work_ptr; // +
+ void *work_ptr;
unsigned int bank_size_playback;
unsigned int bank_size_capture;
unsigned int bank_size_effect;
unsigned int work_size;
- void *bank_base_playback; // +
- void *bank_base_capture; // +
- void *bank_base_effect; // +
- void *work_base; // +
+ void *bank_base_playback;
+ void *bank_base_capture;
+ void *bank_base_effect;
+ void *work_base;
u32 *ctrl_playback;
ymfpci_playback_bank_t *bank_playback[YDSXG_PLAYBACK_VOICES][2];
int start_count;
u32 active_bank;
- ymfpci_voice_t voices[64];
+ struct ymf_voice voices[64];
+ struct ymf_capture capture[5];
struct ac97_codec *ac97_codec[NR_AC97];
u16 ac97_features;
struct pci_dev *pci;
+#ifdef CONFIG_SOUND_YMFPCI_LEGACY
+ /* legacy hardware resources */
+ unsigned int iosynth, iomidi;
+ struct address_info opl3_data, mpu_data;
+#endif
+
spinlock_t reg_lock;
spinlock_t voice_lock;
struct semaphore open_sem;
struct list_head ymf_devs;
- struct ymf_state *states[1]; // *
- /* ypcm may be the same thing as state, but not for record, effects. */
+ struct list_head states; /* List of states for this unit */
+ /* For the moment we do not traverse list of states so it is
+ * entirely useless. Will be used (PM) or killed. XXX */
};
-/*
- * "Software" or virtual channel, an instance of opened /dev/dsp.
- */
-
struct ymf_dmabuf {
/* OSS buffer management stuff */
/* redundant, but makes calculations easier */
unsigned fragsize;
unsigned dmasize; /* Total rawbuf[] size */
- unsigned fragsamples;
/* OSS stuff */
unsigned mapped:1;
int shift; /* redundant, computed from the above */
};
-struct ymf_state {
- struct ymf_unit *unit; /* backpointer */
+typedef enum {
+ PLAYBACK_VOICE,
+ CAPTURE_REC,
+ CAPTURE_AC97,
+ EFFECT_DRY_LEFT,
+ EFFECT_DRY_RIGHT,
+ EFFECT_EFF1,
+ EFFECT_EFF2,
+ EFFECT_EFF3
+} ymfpci_pcm_type_t;
- /* virtual channel number */
- int virt; // * unused a.t.m.
+/* This is variant record, but we hate unions. Little waste on pointers []. */
+struct ymf_pcm {
+ ymfpci_pcm_type_t type;
+ struct ymf_state *state;
+
+ ymfpci_voice_t *voices[2];
+ int capture_bank_number;
+
+ struct ymf_dmabuf dmabuf;
+ int running;
+ int spdif;
+};
- struct ymf_pcm ypcm; // *
- struct ymf_dmabuf dmabuf; // *
- struct ymf_pcm_format format; // *
+/*
+ * "Software" or virtual channel, an instance of opened /dev/dsp.
+ * It may have two physical channels (pcms) for duplex operations.
+ */
+
+struct ymf_state {
+ struct list_head chain;
+ struct ymf_unit *unit; /* backpointer */
+ struct ymf_pcm rpcm, wpcm;
+ struct ymf_pcm_format format;
};
#endif /* __YMFPCI_H */
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/sched.h>
-#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
#include <linux/nfs.h>
#include <linux/nfs_fs.h>
*/
static struct rpc_wait_queue flushd_queue = RPC_INIT_WAITQ("nfs_flushd");
-/*
- * Spinlock
- */
-spinlock_t nfs_flushd_lock = SPIN_LOCK_UNLOCKED;
-
/*
* Local function declarations.
*/
{
struct nfs_reqlist *cache;
struct rpc_task *task;
- int status = 0;
+ int status;
dprintk("NFS: writecache_init\n");
+ lock_kernel();
+ status = -ENOMEM;
/* Create the RPC task */
if (!(task = rpc_new_task(server->client, NULL, RPC_TASK_ASYNC)))
- return -ENOMEM;
+ goto out_unlock;
- spin_lock(&nfs_flushd_lock);
cache = server->rw_requests;
+ status = 0;
if (cache->task)
goto out_unlock;
task->tk_action = nfs_flushd;
task->tk_exit = nfs_flushd_exit;
- spin_unlock(&nfs_flushd_lock);
rpc_execute(task);
+ unlock_kernel();
return 0;
out_unlock:
- spin_unlock(&nfs_flushd_lock);
- rpc_release_task(task);
+ if (task)
+ rpc_release_task(task);
+ unlock_kernel();
return status;
}
{
struct nfs_reqlist *cache;
+ lock_kernel();
cache = server->rw_requests;
if (!cache)
- return;
+ goto out;
dprintk("NFS: reqlist_exit (ptr %p rpc %p)\n", cache, cache->task);
+
while (cache->task || cache->inodes) {
- spin_lock(&nfs_flushd_lock);
if (!cache->task) {
- spin_unlock(&nfs_flushd_lock);
nfs_reqlist_init(server);
} else {
cache->task->tk_status = -ENOMEM;
rpc_wake_up_task(cache->task);
- spin_unlock(&nfs_flushd_lock);
}
interruptible_sleep_on_timeout(&cache->request_wait, 1 * HZ);
}
+ out:
+ unlock_kernel();
}
int nfs_reqlist_alloc(struct nfs_server *server)
struct nfs_reqlist *cache = NFS_REQUESTLIST(inode);
struct inode **q;
- spin_lock(&nfs_flushd_lock);
if (NFS_FLAGS(inode) & NFS_INO_FLUSH)
goto out;
inode->u.nfs_i.hash_next = NULL;
NFS_FLAGS(inode) |= NFS_INO_FLUSH;
atomic_inc(&inode->i_count);
out:
- spin_unlock(&nfs_flushd_lock);
}
void inode_remove_flushd(struct inode *inode)
struct nfs_reqlist *cache = NFS_REQUESTLIST(inode);
struct inode **q;
- spin_lock(&nfs_flushd_lock);
+ lock_kernel();
if (!(NFS_FLAGS(inode) & NFS_INO_FLUSH))
goto out;
if (*q) {
*q = inode->u.nfs_i.hash_next;
NFS_FLAGS(inode) &= ~NFS_INO_FLUSH;
- spin_unlock(&nfs_flushd_lock);
iput(inode);
- return;
}
out:
- spin_unlock(&nfs_flushd_lock);
+ unlock_kernel();
}
void inode_schedule_scan(struct inode *inode, unsigned long time)
struct rpc_task *task;
unsigned long mintimeout;
+ lock_kernel();
if (time_after(NFS_NEXTSCAN(inode), time))
NFS_NEXTSCAN(inode) = time;
mintimeout = jiffies + 1 * HZ;
mintimeout = NFS_NEXTSCAN(inode);
inode_append_flushd(inode);
- spin_lock(&nfs_flushd_lock);
task = cache->task;
if (!task) {
- spin_unlock(&nfs_flushd_lock);
nfs_reqlist_init(NFS_SERVER(inode));
} else {
if (time_after(cache->runat, mintimeout))
rpc_wake_up_task(task);
- spin_unlock(&nfs_flushd_lock);
}
+ unlock_kernel();
}
server = (struct nfs_server *) task->tk_calldata;
cache = server->rw_requests;
- spin_lock(&nfs_flushd_lock);
next = cache->inodes;
cache->inodes = NULL;
- spin_unlock(&nfs_flushd_lock);
while ((inode = next) != NULL) {
next = next->u.nfs_i.hash_next;
task->tk_timeout = delay;
cache->runat = jiffies + task->tk_timeout;
- spin_lock(&nfs_flushd_lock);
if (!atomic_read(&cache->nr_requests) && !cache->inodes) {
cache->task = NULL;
task->tk_action = NULL;
} else
rpc_sleep_on(&flushd_queue, task, NULL, NULL);
- spin_unlock(&nfs_flushd_lock);
}
static void
server = (struct nfs_server *) task->tk_calldata;
cache = server->rw_requests;
- spin_lock(&nfs_flushd_lock);
if (cache->task == task)
cache->task = NULL;
- spin_unlock(&nfs_flushd_lock);
wake_up(&cache->request_wait);
}
return sys_sync();
}
-extern long sys_wait4(int, int *, int, struct rusage *);
static inline pid_t waitpid(int pid, int * wait_stat, int flags)
{
return sys_wait4(pid, wait_stat, flags, NULL);
if (inode->i_size < offset)
goto do_expand;
inode->i_size = offset;
- truncate_inode_pages(mapping, offset);
spin_lock(&mapping->i_shared_lock);
if (!mapping->i_mmap && !mapping->i_mmap_shared)
goto out_unlock;
out_unlock:
spin_unlock(&mapping->i_shared_lock);
- /* this should go into ->truncate */
- inode->i_size = offset;
+ truncate_inode_pages(mapping, offset);
if (inode->i_op && inode->i_op->truncate)
inode->i_op->truncate(inode);
return;
info = &page->mapping->host->u.shmem_i;
swap = __get_swap_page(2);
- if (!swap.val)
- return 1;
+ if (!swap.val) {
+ set_page_dirty(page);
+ UnlockPage(page);
+ return -ENOMEM;
+ }
spin_lock(&info->lock);
shmem_recalc_inode(page->mapping->host);
dprintk("RPC: %4d holding %s cred %p\n",
task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_msg.rpc_cred);
if (task->tk_msg.rpc_cred) {
+ spin_lock(&rpc_credcache_lock);
task->tk_msg.rpc_cred->cr_count++;
task->tk_msg.rpc_cred->cr_expire = jiffies + task->tk_auth->au_expire;
+ spin_unlock(&rpc_credcache_lock);
}
}
void
rpcauth_releasecred(struct rpc_auth *auth, struct rpc_cred *cred)
{
+ spin_lock(&rpc_credcache_lock);
if (cred != NULL && cred->cr_count > 0) {
- cred->cr_count--;
- if (cred->cr_flags & RPCAUTH_CRED_DEAD) {
+ if (!--cred->cr_count && (cred->cr_flags & RPCAUTH_CRED_DEAD)) {
+ spin_unlock(&rpc_credcache_lock);
rpcauth_remove_credcache(auth, cred);
- if (!cred->cr_count)
- rpcauth_crdestroy(auth, cred);
+ rpcauth_crdestroy(auth, cred);
+ return;
}
}
+ spin_unlock(&rpc_credcache_lock);
}
void
{
dprintk("RPC: %4d invalidating %s cred %p\n",
task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_msg.rpc_cred);
+ spin_lock(&rpc_credcache_lock);
if (task->tk_msg.rpc_cred)
task->tk_msg.rpc_cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
+ spin_unlock(&rpc_credcache_lock);
}
int
rpcauth_uptodatecred(struct rpc_task *task)
{
- return !(task->tk_msg.rpc_cred) ||
+ int retval;
+ spin_lock(&rpc_credcache_lock);
+ retval = !(task->tk_msg.rpc_cred) ||
(task->tk_msg.rpc_cred->cr_flags & RPCAUTH_CRED_UPTODATE);
+ spin_unlock(&rpc_credcache_lock);
+ return retval;
}
#include <linux/mm.h>
#include <linux/sysctl.h>
-#include <linux/config.h>
extern int sysctl_unix_max_dgram_qlen;
* negotiation.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
* i-frames.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
* 2000-09-04 Henner Eisen dev_hold() / dev_put() for x25_neigh.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
* needed cleaned seq-number fields.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
* negotiation.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
* Centralised disconnection processing.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>