cregit-Linux how code gets into the kernel

Release 4.14 sound/oss/waveartist.c

Directory: sound/oss
/*
 * linux/sound/oss/waveartist.c
 *
 * The low level driver for the RWA010 Rockwell Wave Artist
 * codec chip used in the Rebel.com NetWinder.
 *
 * Cleaned up and integrated into 2.1 by Russell King (rmk@arm.linux.org.uk)
 * and Pat Beirne (patb@corel.ca)
 *
 *
 * Copyright (C) by Rebel.com 1998-1999
 *
 * RWA010 specs received under NDA from Rockwell
 *
 * Copyright (C) by Hannu Savolainen 1993-1997
 *
 * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
 * Version 2 (June 1991). See the "COPYING" file distributed with this software
 * for more info.
 *
 * Changes:
 * 11-10-2000   Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
 *              Added __init to waveartist_init()
 */

/* Debugging */

#define DEBUG_CMD	1

#define DEBUG_OUT	2

#define DEBUG_IN	4

#define DEBUG_INTR	8

#define DEBUG_MIXER	16

#define DEBUG_TRIGGER	32


#define debug_flg (0)

#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/bitops.h>


#include "sound_config.h"
#include "waveartist.h"

#ifdef CONFIG_ARM
#include <mach/hardware.h>
#include <asm/mach-types.h>
#endif

#ifndef NO_DMA

#define NO_DMA	255
#endif


#define SUPPORTED_MIXER_DEVICES		(SOUND_MASK_SYNTH      |\
                                         SOUND_MASK_PCM        |\
                                         SOUND_MASK_LINE       |\
                                         SOUND_MASK_MIC        |\
                                         SOUND_MASK_LINE1      |\
                                         SOUND_MASK_RECLEV     |\
                                         SOUND_MASK_VOLUME     |\
                                         SOUND_MASK_IMIX)


static unsigned short levels[SOUND_MIXER_NRDEVICES] = {
	0x5555,		/* Master Volume         */
	0x0000,		/* Bass                  */
	0x0000,		/* Treble                */
	0x2323,		/* Synth (FM)            */
	0x4b4b,		/* PCM                   */
	0x6464,		/* PC Speaker            */
	0x0000,		/* Ext Line              */
	0x0000,		/* Mic                   */
	0x0000,		/* CD                    */
	0x6464,		/* Recording monitor     */
	0x0000,		/* SB PCM (ALT PCM)      */
	0x0000,		/* Recording level       */
	0x6464,		/* Input gain            */
	0x6464,		/* Output gain           */
	0x0000,		/* Line1 (Aux1)          */
	0x0000,		/* Line2 (Aux2)          */
	0x0000,		/* Line3 (Aux3)          */
	0x0000,		/* Digital1              */
	0x0000,		/* Digital2              */
	0x0000,		/* Digital3              */
	0x0000,		/* Phone In              */
	0x6464,		/* Phone Out             */
	0x0000,		/* Video                 */
	0x0000,		/* Radio                 */
	0x0000		/* Monitor               */
};


struct wavnc_info {
	
struct address_info  hw;	/* hardware */
	
char		*chip_name;

	
int		xfer_count;
	
int		audio_mode;
	
int		open_mode;
	
int		audio_flags;
	
int		record_dev;
	
int		playback_dev;
	
int		dev_no;

	/* Mixer parameters */
	
const struct waveartist_mixer_info *mix;

	
unsigned short	*levels;	   /* cache of volume settings   */
	
int		recmask;	   /* currently enabled recording device! */

#ifdef CONFIG_ARCH_NETWINDER
	
signed int	slider_vol;	   /* hardware slider volume     */
	
unsigned int	handset_detect	:1;
	
unsigned int	telephone_detect:1;
	
unsigned int	no_autoselect	:1;/* handset/telephone autoselects a path */
	
unsigned int	spkr_mute_state	:1;/* set by ioctl or autoselect */
	
unsigned int	line_mute_state	:1;/* set by ioctl or autoselect */
	
unsigned int	use_slider	:1;/* use slider setting for o/p vol */
#endif
};

/*
 * This is the implementation specific mixer information.
 */

struct waveartist_mixer_info {
	
unsigned int	supported_devs;	   /* Supported devices */
	
unsigned int	recording_devs;	   /* Recordable devies */
	
unsigned int	stereo_devs;	   /* Stereo devices       */

	
unsigned int	(*select_input)(struct wavnc_info *, unsigned int,
					unsigned char *, unsigned char *);
	
int		(*decode_mixer)(struct wavnc_info *, int,
					unsigned char, unsigned char);
	
int		(*get_mixer)(struct wavnc_info *, int);
};


struct wavnc_port_info {
	
int		open_mode;
	
int		speed;
	
int		channels;
	
int		audio_format;
};


static int		nr_waveartist_devs;

static struct wavnc_info	adev_info[MAX_AUDIO_DEV];
static DEFINE_SPINLOCK(waveartist_lock);

#ifndef CONFIG_ARCH_NETWINDER

#define machine_is_netwinder() 0
#else

static struct timer_list vnc_timer;
static void vnc_configure_mixer(struct wavnc_info *devc,
				unsigned int input_mask);
static int vnc_private_ioctl(int dev, unsigned int cmd, int __user *arg);
static void vnc_slider_tick(unsigned long data);
#endif


static inline void waveartist_set_ctlr(struct address_info *hw, unsigned char clear, unsigned char set) { unsigned int ctlr_port = hw->io_base + CTLR; clear = ~clear & inb(ctlr_port); outb(clear | set, ctlr_port); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)49100.00%3100.00%
Total49100.00%3100.00%

/* Toggle IRQ acknowledge line */
static inline void waveartist_iack(struct wavnc_info *devc) { unsigned int ctlr_port = devc->hw.io_base + CTLR; int old_ctlr; old_ctlr = inb(ctlr_port) & ~IRQ_ACK; outb(old_ctlr | IRQ_ACK, ctlr_port); outb(old_ctlr, ctlr_port); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5298.11%375.00%
Himangi Saraogi11.89%125.00%
Total53100.00%4100.00%


static inline int waveartist_sleep(int timeout_ms) { unsigned int timeout = msecs_to_jiffies(timeout_ms*100); return schedule_timeout_interruptible(timeout); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)2177.78%360.00%
Vasiliy Kulikov518.52%120.00%
Linus Torvalds13.70%120.00%
Total27100.00%5100.00%


static int waveartist_reset(struct wavnc_info *devc) { struct address_info *hw = &devc->hw; unsigned int timeout, res = -1; waveartist_set_ctlr(hw, -1, RESET); waveartist_sleep(2); waveartist_set_ctlr(hw, RESET, 0); timeout = 500; do { mdelay(2); if (inb(hw->io_base + STATR) & CMD_RF) { res = inw(hw->io_base + CMDR); if (res == 0x55aa) break; } } while (--timeout); if (timeout == 0) { printk(KERN_WARNING "WaveArtist: reset timeout "); if (res != (unsigned int)-1) printk("(res=%04X)", res); printk("\n"); return 1; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)14799.32%480.00%
Himangi Saraogi10.68%120.00%
Total148100.00%5100.00%

/* Helper function to send and receive words * from WaveArtist. It handles all the handshaking * and can send or receive multiple words. */
static int waveartist_cmd(struct wavnc_info *devc, int nr_cmd, unsigned int *cmd, int nr_resp, unsigned int *resp) { unsigned int io_base = devc->hw.io_base; unsigned int timed_out = 0; unsigned int i; if (debug_flg & DEBUG_CMD) { printk("waveartist_cmd: cmd="); for (i = 0; i < nr_cmd; i++) printk("%04X ", cmd[i]); printk("\n"); } if (inb(io_base + STATR) & CMD_RF) { int old_data; /* flush the port */ old_data = inw(io_base + CMDR); if (debug_flg & DEBUG_CMD) printk("flushed %04X...", old_data); udelay(10); } for (i = 0; !timed_out && i < nr_cmd; i++) { int count; for (count = 5000; count; count--) if (inb(io_base + STATR) & CMD_WE) break; if (!count) timed_out = 1; else outw(cmd[i], io_base + CMDR); } for (i = 0; !timed_out && i < nr_resp; i++) { int count; for (count = 5000; count; count--) if (inb(io_base + STATR) & CMD_RF) break; if (!count) timed_out = 1; else resp[i] = inw(io_base + CMDR); } if (debug_flg & DEBUG_CMD) { if (!timed_out) { printk("waveartist_cmd: resp="); for (i = 0; i < nr_resp; i++) printk("%04X ", resp[i]); printk("\n"); } else printk("waveartist_cmd: timed out\n"); } return timed_out ? 1 : 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)32499.69%375.00%
Himangi Saraogi10.31%125.00%
Total325100.00%4100.00%

/* * Send one command word */
static inline int waveartist_cmd1(struct wavnc_info *devc, unsigned int cmd) { return waveartist_cmd(devc, 1, &cmd, 0, NULL); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)3096.77%375.00%
Himangi Saraogi13.23%125.00%
Total31100.00%4100.00%

/* * Send one command, receive one word */
static inline unsigned int waveartist_cmd1_r(struct wavnc_info *devc, unsigned int cmd) { unsigned int ret; waveartist_cmd(devc, 1, &cmd, 1, &ret); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)3897.44%375.00%
Himangi Saraogi12.56%125.00%
Total39100.00%4100.00%

/* * Send a double command, receive one * word (and throw it away) */
static inline int waveartist_cmd2(struct wavnc_info *devc, unsigned int cmd, unsigned int arg) { unsigned int vals[2]; vals[0] = cmd; vals[1] = arg; return waveartist_cmd(devc, 2, vals, 1, vals); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5498.18%375.00%
Himangi Saraogi11.82%125.00%
Total55100.00%4100.00%

/* * Send a triple command */
static inline int waveartist_cmd3(struct wavnc_info *devc, unsigned int cmd, unsigned int arg1, unsigned int arg2) { unsigned int vals[3]; vals[0] = cmd; vals[1] = arg1; vals[2] = arg2; return waveartist_cmd(devc, 3, vals, 0, NULL); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)6598.48%375.00%
Himangi Saraogi11.52%125.00%
Total66100.00%4100.00%


static int waveartist_getrev(struct wavnc_info *devc, char *rev) { unsigned int temp[2]; unsigned int cmd = WACMD_GETREV; waveartist_cmd(devc, 1, &cmd, 2, temp); rev[0] = temp[0] >> 8; rev[1] = temp[0] & 255; rev[2] = '\0'; return temp[0]; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)7898.73%375.00%
Himangi Saraogi11.27%125.00%
Total79100.00%4100.00%

static void waveartist_halt_output(int dev); static void waveartist_halt_input(int dev); static void waveartist_halt(int dev); static void waveartist_trigger(int dev, int state);
static int waveartist_open(int dev, int mode) { struct wavnc_info *devc; struct wavnc_port_info *portc; unsigned long flags; if (dev < 0 || dev >= num_audiodevs) return -ENXIO; devc = (struct wavnc_info *) audio_devs[dev]->devc; portc = (struct wavnc_port_info *) audio_devs[dev]->portc; spin_lock_irqsave(&waveartist_lock, flags); if (portc->open_mode || (devc->open_mode & mode)) { spin_unlock_irqrestore(&waveartist_lock, flags); return -EBUSY; } devc->audio_mode = 0; devc->open_mode |= mode; portc->open_mode = mode; waveartist_trigger(dev, 0); if (mode & OPEN_READ) devc->record_dev = dev; if (mode & OPEN_WRITE) devc->playback_dev = dev; spin_unlock_irqrestore(&waveartist_lock, flags); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)16097.56%375.00%
Himangi Saraogi42.44%125.00%
Total164100.00%4100.00%


static void waveartist_close(int dev) { struct wavnc_info *devc = (struct wavnc_info *) audio_devs[dev]->devc; struct wavnc_port_info *portc = (struct wavnc_port_info *) audio_devs[dev]->portc; unsigned long flags; spin_lock_irqsave(&waveartist_lock, flags); waveartist_halt(dev); devc->audio_mode = 0; devc->open_mode &= ~portc->open_mode; portc->open_mode = 0; spin_unlock_irqrestore(&waveartist_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)8595.51%375.00%
Himangi Saraogi44.49%125.00%
Total89100.00%4100.00%


static void waveartist_output_block(int dev, unsigned long buf, int __count, int intrflag) { struct wavnc_port_info *portc = (struct wavnc_port_info *) audio_devs[dev]->portc; struct wavnc_info *devc = (struct wavnc_info *) audio_devs[dev]->devc; unsigned long flags; unsigned int count = __count; if (debug_flg & DEBUG_OUT) printk("waveartist: output block, buf=0x%lx, count=0x%x...\n", buf, count); /* * 16 bit data */ if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) count >>= 1; if (portc->channels > 1) count >>= 1; count -= 1; if (devc->audio_mode & PCM_ENABLE_OUTPUT && audio_devs[dev]->flags & DMA_AUTOMODE && intrflag && count == devc->xfer_count) { devc->audio_mode |= PCM_ENABLE_OUTPUT; return; /* * Auto DMA mode on. No need to react */ } spin_lock_irqsave(&waveartist_lock, flags); /* * set sample count */ waveartist_cmd2(devc, WACMD_OUTPUTSIZE, count); devc->xfer_count = count; devc->audio_mode |= PCM_ENABLE_OUTPUT; spin_unlock_irqrestore(&waveartist_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)18097.83%375.00%
Himangi Saraogi42.17%125.00%
Total184100.00%4100.00%


static void waveartist_start_input(int dev, unsigned long buf, int __count, int intrflag) { struct wavnc_port_info *portc = (struct wavnc_port_info *) audio_devs[dev]->portc; struct wavnc_info *devc = (struct wavnc_info *) audio_devs[dev]->devc; unsigned long flags; unsigned int count = __count; if (debug_flg & DEBUG_IN) printk("waveartist: start input, buf=0x%lx, count=0x%x...\n", buf, count); if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */ count >>= 1; if (portc->channels > 1) count >>= 1; count -= 1; if (devc->audio_mode & PCM_ENABLE_INPUT && audio_devs[dev]->flags & DMA_AUTOMODE && intrflag && count == devc->xfer_count) { devc->audio_mode |= PCM_ENABLE_INPUT; return; /* * Auto DMA mode on. No need to react */ } spin_lock_irqsave(&waveartist_lock, flags); /* * set sample count */ waveartist_cmd2(devc, WACMD_INPUTSIZE, count); devc->xfer_count = count; devc->audio_mode |= PCM_ENABLE_INPUT; spin_unlock_irqrestore(&waveartist_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)18097.83%375.00%
Himangi Saraogi42.17%125.00%
Total184100.00%4100.00%


static int waveartist_ioctl(int dev, unsigned int cmd, void __user * arg) { return -EINVAL; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)1986.36%375.00%
Al Viro313.64%125.00%
Total22100.00%4100.00%


static unsigned int waveartist_get_speed(struct wavnc_port_info *portc) { unsigned int speed; /* * program the speed, channels, bits */ if (portc->speed == 8000) speed = 0x2E71; else if (portc->speed == 11025) speed = 0x4000; else if (portc->speed == 22050) speed = 0x8000; else if (portc->speed == 44100) speed = 0x0; else { /* * non-standard - just calculate */ speed = portc->speed << 16; speed = (speed / 44100) & 65535; } return speed; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)9298.92%375.00%
Himangi Saraogi11.08%125.00%
Total93100.00%4100.00%


static unsigned int waveartist_get_bits(struct wavnc_port_info *portc) { unsigned int bits; if (portc->audio_format == AFMT_S16_LE) bits = 1; else if (portc->audio_format == AFMT_S8) bits = 0; else bits = 2; //default AFMT_U8 return bits; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)4998.00%266.67%
Himangi Saraogi12.00%133.33%
Total50100.00%3100.00%


static int waveartist_prepare_for_input(int dev, int bsize, int bcount) { unsigned long flags; struct wavnc_info *devc = (struct wavnc_info *) audio_devs[dev]->devc; struct wavnc_port_info *portc = (struct wavnc_port_info *) audio_devs[dev]->portc; unsigned int speed, bits; if (devc->audio_mode) return 0; speed = waveartist_get_speed(portc); bits = waveartist_get_bits(portc); spin_lock_irqsave(&waveartist_lock, flags); if (waveartist_cmd2(devc, WACMD_INPUTFORMAT, bits)) printk(KERN_WARNING "waveartist: error setting the " "record format to %d\n", portc->audio_format); if (waveartist_cmd2(devc, WACMD_INPUTCHANNELS, portc->channels)) printk(KERN_WARNING "waveartist: error setting record " "to %d channels\n", portc->channels); /* * write cmd SetSampleSpeedTimeConstant */ if (waveartist_cmd2(devc, WACMD_INPUTSPEED, speed)) printk(KERN_WARNING "waveartist: error setting the record " "speed to %dHz.\n", portc->speed); if (waveartist_cmd2(devc, WACMD_INPUTDMA, 1)) printk(KERN_WARNING "waveartist: error setting the record " "data path to 0x%X\n", 1); if (waveartist_cmd2(devc, WACMD_INPUTFORMAT, bits)) printk(KERN_WARNING "waveartist: error setting the record " "format to %d\n", portc->audio_format); devc->xfer_count = 0; spin_unlock_irqrestore(&waveartist_lock, flags); waveartist_halt_input(dev); if (debug_flg & DEBUG_INTR) { printk("WA CTLR reg: 0x%02X.\n", inb(devc->hw.io_base + CTLR)); printk("WA STAT reg: 0x%02X.\n", inb(devc->hw.io_base + STATR)); printk("WA IRQS reg: 0x%02X.\n", inb(devc->hw.io_base + IRQSTAT)); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)27598.57%375.00%
Himangi Saraogi41.43%125.00%
Total279100.00%4100.00%


static int waveartist_prepare_for_output(int dev, int bsize, int bcount) { unsigned long flags; struct wavnc_info *devc = (struct wavnc_info *) audio_devs[dev]->devc; struct wavnc_port_info *portc = (struct wavnc_port_info *) audio_devs[dev]->portc; unsigned int speed, bits; /* * program the speed, channels, bits */ speed = waveartist_get_speed(portc); bits = waveartist_get_bits(portc); spin_lock_irqsave(&waveartist_lock, flags); if (waveartist_cmd2(devc, WACMD_OUTPUTSPEED, speed) && waveartist_cmd2(devc, WACMD_OUTPUTSPEED, speed)) printk(KERN_WARNING "waveartist: error setting the playback " "speed to %dHz.\n", portc->speed); if (waveartist_cmd2(devc, WACMD_OUTPUTCHANNELS, portc->channels)) printk(KERN_WARNING "waveartist: error setting the playback " "to %d channels\n", portc->channels); if (waveartist_cmd2(devc, WACMD_OUTPUTDMA, 0)) printk(KERN_WARNING "waveartist: error setting the playback " "data path to 0x%X\n", 0); if (waveartist_cmd2(devc, WACMD_OUTPUTFORMAT, bits)) printk(KERN_WARNING "waveartist: error setting the playback " "format to %d\n", portc->audio_format); devc->xfer_count = 0; spin_unlock_irqrestore(&waveartist_lock, flags); waveartist_halt_output(dev); if (debug_flg & DEBUG_INTR) { printk("WA CTLR reg: 0x%02X.\n",inb(devc->hw.io_base + CTLR)); printk("WA STAT reg: 0x%02X.\n",inb(devc->hw.io_base + STATR)); printk("WA IRQS reg: 0x%02X.\n",inb(devc->hw.io_base + IRQSTAT)); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)25398.44%375.00%
Himangi Saraogi41.56%125.00%
Total257100.00%4100.00%


static void waveartist_halt(int dev) { struct wavnc_port_info *portc = (struct wavnc_port_info *) audio_devs[dev]->portc; struct wavnc_info *devc; if (portc->open_mode & OPEN_WRITE) waveartist_halt_output(dev); if (portc->open_mode & OPEN_READ) waveartist_halt_input(dev); devc = (struct wavnc_info *) audio_devs[dev]->devc; devc->audio_mode = 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)7394.81%150.00%
Himangi Saraogi45.19%150.00%
Total77100.00%2100.00%


static void waveartist_halt_input(int dev) { struct wavnc_info *devc = (struct wavnc_info *) audio_devs[dev]->devc; unsigned long flags; spin_lock_irqsave(&waveartist_lock, flags); /* * Stop capture */ waveartist_cmd1(devc, WACMD_INPUTSTOP); devc->audio_mode &= ~PCM_ENABLE_INPUT; /* * Clear interrupt by toggling * the IRQ_ACK bit in CTRL */ if (inb(devc->hw.io_base + STATR) & IRQ_REQ) waveartist_iack(devc); // devc->audio_mode &= ~PCM_ENABLE_INPUT; spin_unlock_irqrestore(&waveartist_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)8197.59%266.67%
Himangi Saraogi22.41%133.33%
Total83100.00%3100.00%


static void waveartist_halt_output(int dev) { struct wavnc_info *devc = (struct wavnc_info *) audio_devs[dev]->devc; unsigned long flags; spin_lock_irqsave(&waveartist_lock, flags); waveartist_cmd1(devc, WACMD_OUTPUTSTOP); devc->audio_mode &= ~PCM_ENABLE_OUTPUT; /* * Clear interrupt by toggling * the IRQ_ACK bit in CTRL */ if (inb(devc->hw.io_base + STATR) & IRQ_REQ) waveartist_iack(devc); // devc->audio_mode &= ~PCM_ENABLE_OUTPUT; spin_unlock_irqrestore(&waveartist_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)8097.56%266.67%
Himangi Saraogi22.44%133.33%
Total82100.00%3100.00%


static void waveartist_trigger(int dev, int state) { struct wavnc_info *devc = (struct wavnc_info *) audio_devs[dev]->devc; struct wavnc_port_info *portc = (struct wavnc_port_info *) audio_devs[dev]->portc; unsigned long flags; if (debug_flg & DEBUG_TRIGGER) { printk("wavnc: audio trigger "); if (state & PCM_ENABLE_INPUT) printk("in "); if (state & PCM_ENABLE_OUTPUT) printk("out"); printk("\n"); } spin_lock_irqsave(&waveartist_lock, flags); state &= devc->audio_mode; if (portc->open_mode & OPEN_READ && state & PCM_ENABLE_INPUT) /* * enable ADC Data Transfer to PC */ waveartist_cmd1(devc, WACMD_INPUTSTART); if (portc->open_mode & OPEN_WRITE && state & PCM_ENABLE_OUTPUT) /* * enable DAC data transfer from PC */ waveartist_cmd1(devc, WACMD_OUTPUTSTART); spin_unlock_irqrestore(&waveartist_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)14897.37%266.67%
Himangi Saraogi42.63%133.33%
Total152100.00%3100.00%


static int waveartist_set_speed(int dev, int arg) { struct wavnc_port_info *portc = (struct wavnc_port_info *) audio_devs[dev]->portc; if (arg <= 0) return portc->speed; if (arg < 5000) arg = 5000; if (arg > 44100) arg = 44100; portc->speed = arg; return portc->speed; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)6997.18%150.00%
Himangi Saraogi22.82%150.00%
Total71100.00%2100.00%


static short waveartist_set_channels(int dev, short arg) { struct wavnc_port_info *portc = (struct wavnc_port_info *) audio_devs[dev]->portc; if (arg != 1 && arg != 2) return portc->channels; portc->channels = arg; return arg; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5196.23%150.00%
Himangi Saraogi23.77%150.00%
Total53100.00%2100.00%


static unsigned int waveartist_set_bits(int dev, unsigned int arg) { struct wavnc_port_info *portc = (struct wavnc_port_info *) audio_devs[dev]->portc; if (arg == 0) return portc->audio_format; if ((arg != AFMT_U8) && (arg != AFMT_S16_LE) && (arg != AFMT_S8)) arg = AFMT_U8; portc->audio_format = arg; return arg; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)7397.33%150.00%
Himangi Saraogi22.67%150.00%
Total75100.00%2100.00%

static struct audio_driver waveartist_audio_driver = { .owner = THIS_MODULE, .open = waveartist_open, .close = waveartist_close, .output_block = waveartist_output_block, .start_input = waveartist_start_input, .ioctl = waveartist_ioctl, .prepare_for_input = waveartist_prepare_for_input, .prepare_for_output = waveartist_prepare_for_output, .halt_io = waveartist_halt, .halt_input = waveartist_halt_input, .halt_output = waveartist_halt_output, .trigger = waveartist_trigger, .set_speed = waveartist_set_speed, .set_bits = waveartist_set_bits, .set_channels = waveartist_set_channels };
static irqreturn_t waveartist_intr(int irq, void *dev_id) { struct wavnc_info *devc = dev_id; int irqstatus, status; spin_lock(&waveartist_lock); irqstatus = inb(devc->hw.io_base + IRQSTAT); status = inb(devc->hw.io_base + STATR); if (debug_flg & DEBUG_INTR) printk("waveartist_intr: stat=%02x, irqstat=%02x\n", status, irqstatus); if (status & IRQ_REQ) /* Clear interrupt */ waveartist_iack(devc); else printk(KERN_WARNING "waveartist: unexpected interrupt\n"); if (irqstatus & 0x01) { int temp = 1; /* PCM buffer done */ if ((status & DMA0) && (devc->audio_mode & PCM_ENABLE_OUTPUT)) { DMAbuf_outputintr(devc->playback_dev, 1); temp = 0; } if ((status & DMA1) && (devc->audio_mode & PCM_ENABLE_INPUT)) { DMAbuf_inputintr(devc->record_dev); temp = 0; } if (temp) //default: printk(KERN_WARNING "waveartist: Unknown interrupt\n"); } if (irqstatus & 0x2) // We do not use SB mode natively... printk(KERN_WARNING "waveartist: Unexpected SB interrupt...\n"); spin_unlock(&waveartist_lock); return IRQ_HANDLED; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)18191.41%350.00%
Peter Wächtler126.06%116.67%
Andrew Morton42.02%116.67%
Himangi Saraogi10.51%116.67%
Total198100.00%6100.00%

/* ------------------------------------------------------------------------- * Mixer stuff */ struct mix_ent { unsigned char reg_l; unsigned char reg_r; unsigned char shift; unsigned char max; }; static const struct mix_ent mix_devs[SOUND_MIXER_NRDEVICES] = { { 2, 6, 1, 7 }, /* SOUND_MIXER_VOLUME */ { 0, 0, 0, 0 }, /* SOUND_MIXER_BASS */ { 0, 0, 0, 0 }, /* SOUND_MIXER_TREBLE */ { 0, 0, 0, 0 }, /* SOUND_MIXER_SYNTH */ { 0, 0, 0, 0 }, /* SOUND_MIXER_PCM */ { 0, 0, 0, 0 }, /* SOUND_MIXER_SPEAKER */ { 0, 4, 6, 31 }, /* SOUND_MIXER_LINE */ { 2, 6, 4, 3 }, /* SOUND_MIXER_MIC */ { 0, 0, 0, 0 }, /* SOUND_MIXER_CD */ { 0, 0, 0, 0 }, /* SOUND_MIXER_IMIX */ { 0, 0, 0, 0 }, /* SOUND_MIXER_ALTPCM */ #if 0 { 3, 7, 0, 10 }, /* SOUND_MIXER_RECLEV */ { 0, 0, 0, 0 }, /* SOUND_MIXER_IGAIN */ #else { 0, 0, 0, 0 }, /* SOUND_MIXER_RECLEV */ { 3, 7, 0, 7 }, /* SOUND_MIXER_IGAIN */ #endif { 0, 0, 0, 0 }, /* SOUND_MIXER_OGAIN */ { 0, 4, 1, 31 }, /* SOUND_MIXER_LINE1 */ { 1, 5, 6, 31 }, /* SOUND_MIXER_LINE2 */ { 0, 0, 0, 0 }, /* SOUND_MIXER_LINE3 */ { 0, 0, 0, 0 }, /* SOUND_MIXER_DIGITAL1 */ { 0, 0, 0, 0 }, /* SOUND_MIXER_DIGITAL2 */ { 0, 0, 0, 0 }, /* SOUND_MIXER_DIGITAL3 */ { 0, 0, 0, 0 }, /* SOUND_MIXER_PHONEIN */ { 0, 0, 0, 0 }, /* SOUND_MIXER_PHONEOUT */ { 0, 0, 0, 0 }, /* SOUND_MIXER_VIDEO */ { 0, 0, 0, 0 }, /* SOUND_MIXER_RADIO */ { 0, 0, 0, 0 } /* SOUND_MIXER_MONITOR */ };
static void waveartist_mixer_update(struct wavnc_info *devc, int whichDev) { unsigned int lev_left, lev_right; lev_left = devc->levels[whichDev] & 0xff; lev_right = devc->levels[whichDev] >> 8; if (lev_left > 100) lev_left = 100; if (lev_right > 100) lev_right = 100; #define SCALE(lev,max) ((lev) * (max) / 100) if (machine_is_netwinder() && whichDev == SOUND_MIXER_PHONEOUT) whichDev = SOUND_MIXER_VOLUME; if (mix_devs[whichDev].reg_l || mix_devs[whichDev].reg_r) { const struct mix_ent *mix = mix_devs + whichDev; unsigned int mask, left, right; mask = mix->max << mix->shift; lev_left = SCALE(lev_left, mix->max) << mix->shift; lev_right = SCALE(lev_right, mix->max) << mix->shift; /* read left setting */ left = waveartist_cmd1_r(devc, WACMD_GET_LEVEL | mix->reg_l << 8); /* read right setting */ right = waveartist_cmd1_r(devc, WACMD_GET_LEVEL | mix->reg_r << 8); left = (left & ~mask) | (lev_left & mask); right = (right & ~mask) | (lev_right & mask); /* write left,right back */ waveartist_cmd3(devc, WACMD_SET_MIXER, left, right); } else { switch(whichDev) { case SOUND_MIXER_PCM: waveartist_cmd3(devc, WACMD_SET_LEVEL, SCALE(lev_left, 32767), SCALE(lev_right, 32767)); break; case SOUND_MIXER_SYNTH: waveartist_cmd3(devc, 0x0100 | WACMD_SET_LEVEL, SCALE(lev_left, 32767), SCALE(lev_right, 32767)); break; } } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds29499.66%150.00%
Himangi Saraogi10.34%150.00%
Total295100.00%2100.00%

/* * Set the ADC MUX to the specified values. We do NOT do any * checking of the values passed, since we assume that the * relevant *_select_input function has done that for us. */
static void waveartist_set_adc_mux(struct wavnc_info *devc, char left_dev, char right_dev) { unsigned int reg_08, reg_09; reg_08 = waveartist_cmd1_r(devc, WACMD_GET_LEVEL | 0x0800); reg_09 = waveartist_cmd1_r(devc, WACMD_GET_LEVEL | 0x0900); reg_08 = (reg_08 & ~0x3f) | right_dev << 3 | left_dev; waveartist_cmd3(devc, WACMD_SET_MIXER, reg_08, reg_09); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds7098.59%150.00%
Himangi Saraogi11.41%150.00%
Total71100.00%2100.00%

/* * Decode a recording mask into a mixer selection as follows: * * OSS Source WA Source Actual source * SOUND_MASK_IMIX Mixer Mixer output (same as AD1848) * SOUND_MASK_LINE Line Line in * SOUND_MASK_LINE1 Aux 1 Aux 1 in * SOUND_MASK_LINE2 Aux 2 Aux 2 in * SOUND_MASK_MIC Mic Microphone */
static unsigned int waveartist_select_input(struct wavnc_info *devc, unsigned int recmask, unsigned char *dev_l, unsigned char *dev_r) { unsigned int recdev = ADC_MUX_NONE; if (recmask & SOUND_MASK_IMIX) { recmask = SOUND_MASK_IMIX; recdev = ADC_MUX_MIXER; } else if (recmask & SOUND_MASK_LINE2) { recmask = SOUND_MASK_LINE2; recdev = ADC_MUX_AUX2; } else if (recmask & SOUND_MASK_LINE1) { recmask = SOUND_MASK_LINE1; recdev = ADC_MUX_AUX1; } else if (recmask & SOUND_MASK_LINE) { recmask = SOUND_MASK_LINE; recdev = ADC_MUX_LINE; } else if (recmask & SOUND_MASK_MIC) { recmask = SOUND_MASK_MIC; recdev = ADC_MUX_MIC; } *dev_l = *dev_r = recdev; return recmask; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds12699.21%150.00%
Himangi Saraogi10.79%150.00%
Total127100.00%2100.00%


static int waveartist_decode_mixer(struct wavnc_info *devc, int dev, unsigned char lev_l, unsigned char lev_r) { switch (dev) { case SOUND_MIXER_VOLUME: case SOUND_MIXER_SYNTH: case SOUND_MIXER_PCM: case SOUND_MIXER_LINE: case SOUND_MIXER_MIC: case SOUND_MIXER_IGAIN: case SOUND_MIXER_LINE1: case SOUND_MIXER_LINE2: devc->levels[dev] = lev_l | lev_r << 8; break; case SOUND_MIXER_IMIX: break; default: dev = -EINVAL; break; } return dev; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds7796.25%125.00%
Linus Torvalds (pre-git)22.50%250.00%
Himangi Saraogi11.25%125.00%
Total80100.00%4100.00%


static int waveartist_get_mixer(struct wavnc_info *devc, int dev) { return devc->levels[dev]; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds2195.45%150.00%
Himangi Saraogi14.55%150.00%
Total22100.00%2100.00%

static const struct waveartist_mixer_info waveartist_mixer = { .supported_devs = SUPPORTED_MIXER_DEVICES | SOUND_MASK_IGAIN, .recording_devs = SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_LINE1 | SOUND_MASK_LINE2 | SOUND_MASK_IMIX, .stereo_devs = (SUPPORTED_MIXER_DEVICES | SOUND_MASK_IGAIN) & ~ (SOUND_MASK_SPEAKER | SOUND_MASK_IMIX), .select_input = waveartist_select_input, .decode_mixer = waveartist_decode_mixer, .get_mixer = waveartist_get_mixer, };
static void waveartist_set_recmask(struct wavnc_info *devc, unsigned int recmask) { unsigned char dev_l, dev_r; recmask &= devc->mix->recording_devs; /* * If more than one recording device selected, * disable the device that is currently in use. */ if (hweight32(recmask) > 1) recmask &= ~devc->recmask; /* * Translate the recording device mask into * the ADC multiplexer settings. */ devc->recmask = devc->mix->select_input(devc, recmask, &dev_l, &dev_r); waveartist_set_adc_mux(devc, dev_l, dev_r); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds7698.70%150.00%
Himangi Saraogi11.30%150.00%
Total77100.00%2100.00%


static int waveartist_set_mixer(struct wavnc_info *devc, int dev, unsigned int level) { unsigned int lev_left = level & 0x00ff; unsigned int lev_right = (level & 0xff00) >> 8; if (lev_left > 100) lev_left = 100; if (lev_right > 100) lev_right = 100; /* * Mono devices have their right volume forced to their * left volume. (from ALSA driver OSS emulation). */ if (!(devc->mix->stereo_devs & (1 << dev))) lev_right = lev_left; dev = devc->mix->decode_mixer(devc, dev, lev_left, lev_right); if (dev >= 0) waveartist_mixer_update(devc, dev); return dev < 0 ? dev : 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds9882.35%120.00%
Linus Torvalds (pre-git)2016.81%360.00%
Himangi Saraogi10.84%120.00%
Total119100.00%5100.00%


static int waveartist_mixer_ioctl(int dev, unsigned int cmd, void __user * arg) { struct wavnc_info *devc = (struct wavnc_info *)audio_devs[dev]->devc; int ret = 0, val, nr; /* * All SOUND_MIXER_* ioctls use type 'M' */ if (((cmd >> 8) & 255) != 'M') return -ENOIOCTLCMD; #ifdef CONFIG_ARCH_NETWINDER if (machine_is_netwinder()) { ret = vnc_private_ioctl(dev, cmd, arg); if (ret != -ENOIOCTLCMD) return ret; else ret = 0; } #endif nr = cmd & 0xff; if (_SIOC_DIR(cmd) & _SIOC_WRITE) { if (get_user(val, (int __user *)arg)) return -EFAULT; switch (nr) { case SOUND_MIXER_RECSRC: waveartist_set_recmask(devc, val); break; default: ret = -EINVAL; if (nr < SOUND_MIXER_NRDEVICES && devc->mix->supported_devs & (1 << nr)) ret = waveartist_set_mixer(devc, nr, val); } } if (ret == 0 && _SIOC_DIR(cmd) & _SIOC_READ) { ret = -EINVAL; switch (nr) { case SOUND_MIXER_RECSRC: ret = devc->recmask; break; case SOUND_MIXER_DEVMASK: ret = devc->mix->supported_devs; break; case SOUND_MIXER_STEREODEVS: ret = devc->mix->stereo_devs; break; case SOUND_MIXER_RECMASK: ret = devc->mix->recording_devs; break; case SOUND_MIXER_CAPS: ret = SOUND_CAP_EXCL_INPUT; break; default: if (nr < SOUND_MIXER_NRDEVICES) ret = devc->mix->get_mixer(devc, nr); break; } if (ret >= 0) ret = put_user(ret, (int __user *)arg) ? -EFAULT : 0; } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds26583.60%116.67%
Linus Torvalds (pre-git)4514.20%350.00%
Al Viro51.58%116.67%
Himangi Saraogi20.63%116.67%
Total317100.00%6100.00%

static struct mixer_operations waveartist_mixer_operations = { .owner = THIS_MODULE, .id = "WaveArtist", .name = "WaveArtist", .ioctl = waveartist_mixer_ioctl };
static void waveartist_mixer_reset(struct wavnc_info *devc) { int i; if (debug_flg & DEBUG_MIXER) printk("%s: mixer_reset\n", devc->hw.name); /* * reset mixer cmd */ waveartist_cmd1(devc, WACMD_RST_MIXER); /* * set input for ADC to come from 'quiet' * turn on default modes */ waveartist_cmd3(devc, WACMD_SET_MIXER, 0x9800, 0xa836); /* * set mixer input select to none, RX filter gains 0 dB */ waveartist_cmd3(devc, WACMD_SET_MIXER, 0x4c00, 0x8c00); /* * set bit 0 reg 2 to 1 - unmute MonoOut */ waveartist_cmd3(devc, WACMD_SET_MIXER, 0x2801, 0x6800); /* set default input device = internal mic * current recording device = none */ waveartist_set_recmask(devc, 0); for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) waveartist_mixer_update(devc, i); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds6563.11%125.00%
Linus Torvalds (pre-git)3735.92%250.00%
Himangi Saraogi10.97%125.00%
Total103100.00%4100.00%


static int __init waveartist_init(struct wavnc_info *devc) { struct wavnc_port_info *portc; char rev[3], dev_name[64]; int my_dev; if (waveartist_reset(devc)) return -ENODEV; sprintf(dev_name, "%s (%s", devc->hw.name, devc->chip_name); if (waveartist_getrev(devc, rev)) { strcat(dev_name, " rev. "); strcat(dev_name, rev); } strcat(dev_name, ")"); conf_printf2(dev_name, devc->hw.io_base, devc->hw.irq, devc->hw.dma, devc->hw.dma2); portc = kzalloc(sizeof(struct wavnc_port_info), GFP_KERNEL); if (portc == NULL) goto nomem; my_dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, dev_name, &waveartist_audio_driver, sizeof(struct audio_driver), devc->audio_flags, AFMT_U8 | AFMT_S16_LE | AFMT_S8, devc, devc->hw.dma, devc->hw.dma2); if (my_dev < 0) goto free; audio_devs[my_dev]->portc = portc; waveartist_mixer_reset(devc); /* * clear any pending interrupt */ waveartist_iack(devc); if (request_irq(devc->hw.irq, waveartist_intr, 0, devc->hw.name, devc) < 0) { printk(KERN_ERR "%s: IRQ %d in use\n", devc->hw.name, devc->hw.irq); goto uninstall; } if (sound_alloc_dma(devc->hw.dma, devc->hw.name)) { printk(KERN_ERR "%s: Can't allocate DMA%d\n", devc->hw.name, devc->hw.dma); goto uninstall_irq; } if (devc->hw.dma != devc->hw.dma2 && devc->hw.dma2 != NO_DMA) if (sound_alloc_dma(devc->hw.dma2, devc->hw.name)) { printk(KERN_ERR "%s: can't allocate DMA%d\n", devc->hw.name, devc->hw.dma2); goto uninstall_dma; } waveartist_set_ctlr(&devc->hw, 0, DMA1_IE | DMA0_IE); audio_devs[my_dev]->mixer_dev = sound_install_mixer(MIXER_DRIVER_VERSION, dev_name, &waveartist_mixer_operations, sizeof(struct mixer_operations), devc); return my_dev; uninstall_dma: sound_free_dma(devc->hw.dma); uninstall_irq: free_irq(devc->hw.irq, devc); uninstall: sound_unload_audiodev(my_dev); free: kfree(portc); nomem: return -1; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds32873.05%116.67%
Linus Torvalds (pre-git)11726.06%350.00%
Himangi Saraogi30.67%116.67%
Robert P. J. Day10.22%116.67%
Total449100.00%6100.00%


static int __init probe_waveartist(struct address_info *hw_config) { struct wavnc_info *devc = &adev_info[nr_waveartist_devs]; if (nr_waveartist_devs >= MAX_AUDIO_DEV) { printk(KERN_WARNING "waveartist: too many audio devices\n"); return 0; } if (!request_region(hw_config->io_base, 15, hw_config->name)) { printk(KERN_WARNING "WaveArtist: I/O port conflict\n"); return 0; } if (hw_config->irq > 15 || hw_config->irq < 0) { release_region(hw_config->io_base, 15); printk(KERN_WARNING "WaveArtist: Bad IRQ %d\n", hw_config->irq); return 0; } if (hw_config->dma != 3) { release_region(hw_config->io_base, 15); printk(KERN_WARNING "WaveArtist: Bad DMA %d\n", hw_config->dma); return 0; } hw_config->name = "WaveArtist"; devc->hw = *hw_config; devc->open_mode = 0; devc->chip_name = "RWA-010"; return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds8853.33%116.67%
Linus Torvalds (pre-git)5231.52%350.00%
Al Viro2414.55%116.67%
Himangi Saraogi10.61%116.67%
Total165100.00%6100.00%


static void __init attach_waveartist(struct address_info *hw, const struct waveartist_mixer_info *mix) { struct wavnc_info *devc = &adev_info[nr_waveartist_devs]; /* * NOTE! If irq < 0, there is another driver which has allocated the * IRQ so that this driver doesn't need to allocate/deallocate it. * The actually used IRQ is ABS(irq). */ devc->hw = *hw; devc->hw.irq = (hw->irq > 0) ? hw->irq : 0; devc->open_mode = 0; devc->playback_dev = 0; devc->record_dev = 0; devc->audio_flags = DMA_AUTOMODE; devc->levels = levels; if (hw->dma != hw->dma2 && hw->dma2 != NO_DMA) devc->audio_flags |= DMA_DUPLEX; devc->mix = mix; devc->dev_no = waveartist_init(devc); if (devc->dev_no < 0) release_region(hw->io_base, 15); else { #ifdef CONFIG_ARCH_NETWINDER if (machine_is_netwinder()) { setup_timer(&vnc_timer, vnc_slider_tick, nr_waveartist_devs); mod_timer(&vnc_timer, jiffies); vnc_configure_mixer(devc, 0); devc->no_autoselect = 1; } #endif nr_waveartist_devs += 1; } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds13972.77%120.00%
Linus Torvalds (pre-git)4423.04%240.00%
Muhammad Falak R Wani73.66%120.00%
Himangi Saraogi10.52%120.00%
Total191100.00%5100.00%


static void __exit unload_waveartist(struct address_info *hw) { struct wavnc_info *devc = NULL; int i; for (i = 0; i < nr_waveartist_devs; i++) if (hw->io_base == adev_info[i].hw.io_base) { devc = adev_info + i; break; } if (devc != NULL) { int mixer; #ifdef CONFIG_ARCH_NETWINDER if (machine_is_netwinder()) del_timer(&vnc_timer); #endif release_region(devc->hw.io_base, 15); waveartist_set_ctlr(&devc->hw, DMA1_IE|DMA0_IE, 0); if (devc->hw.irq >= 0) free_irq(devc->hw.irq, devc); sound_free_dma(devc->hw.dma); if (devc->hw.dma != devc->hw.dma2 && devc->hw.dma2 != NO_DMA) sound_free_dma(devc->hw.dma2); mixer = audio_devs[devc->dev_no]->mixer_dev; if (mixer >= 0) sound_unload_mixerdev(mixer); if (devc->dev_no >= 0) sound_unload_audiodev(devc->dev_no); nr_waveartist_devs -= 1; for (; i < nr_waveartist_devs; i++) adev_info[i] = adev_info[i + 1]; } else printk(KERN_WARNING "waveartist: can't find device " "to unload\n"); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds15764.61%133.33%
Linus Torvalds (pre-git)8534.98%133.33%
Himangi Saraogi10.41%133.33%
Total243100.00%3100.00%

#ifdef CONFIG_ARCH_NETWINDER /* * Rebel.com Netwinder specifics... */ #include <asm/hardware/dec21285.h> #define VNC_TIMER_PERIOD (HZ/4) //check slider 4 times/sec #define MIXER_PRIVATE3_RESET 0x53570000 #define MIXER_PRIVATE3_READ 0x53570001 #define MIXER_PRIVATE3_WRITE 0x53570002 #define VNC_MUTE_INTERNAL_SPKR 0x01 //the sw mute on/off control bit #define VNC_MUTE_LINE_OUT 0x10 #define VNC_PHONE_DETECT 0x20 #define VNC_HANDSET_DETECT 0x40 #define VNC_DISABLE_AUTOSWITCH 0x80
static inline void vnc_mute_spkr(struct wavnc_info *devc) { unsigned long flags; raw_spin_lock_irqsave(&nw_gpio_lock, flags); nw_cpld_modify(CPLD_UNMUTE, devc->spkr_mute_state ? 0 : CPLD_UNMUTE); raw_spin_unlock_irqrestore(&nw_gpio_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds2351.11%120.00%
Linus Torvalds (pre-git)1635.56%120.00%
Russell King36.67%120.00%
Arnd Bergmann24.44%120.00%
Himangi Saraogi12.22%120.00%
Total45100.00%5100.00%


static void vnc_mute_lout(struct wavnc_info *devc) { unsigned int left, right; left = waveartist_cmd1_r(devc, WACMD_GET_LEVEL); right = waveartist_cmd1_r(devc, WACMD_GET_LEVEL | 0x400); if (devc->line_mute_state) { left &= ~1; right &= ~1; } else { left |= 1; right |= 1; } waveartist_cmd3(devc, WACMD_SET_MIXER, left, right); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds5064.94%125.00%
Linus Torvalds (pre-git)2633.77%250.00%
Himangi Saraogi11.30%125.00%
Total77100.00%4100.00%


static int vnc_volume_slider(struct wavnc_info *devc) { static signed int old_slider_volume; unsigned long flags; signed int volume = 255; *CSR_TIMER1_LOAD = 0x00ffffff; spin_lock_irqsave(&waveartist_lock, flags); outb(0xFF, 0x201); *CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_DIV1; while (volume && (inb(0x201) & 0x01)) volume--; *CSR_TIMER1_CNTL = 0; spin_unlock_irqrestore(&waveartist_lock,flags); volume = 0x00ffffff - *CSR_TIMER1_VALUE; #ifndef REVERSE volume = 150 - (volume >> 5); #else volume = (volume >> 6) - 25; #endif if (volume < 0) volume = 0; if (volume > 100) volume = 100; /* * slider quite often reads +-8, so debounce this random noise */ if (abs(volume - old_slider_volume) > 7) { old_slider_volume = volume; if (debug_flg & DEBUG_MIXER) printk(KERN_DEBUG "Slider volume: %d.\n", volume); } return old_slider_volume; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds12070.18%120.00%
Linus Torvalds (pre-git)4224.56%240.00%
Peter Wächtler84.68%120.00%
Himangi Saraogi10.58%120.00%
Total171100.00%5100.00%

/* * Decode a recording mask into a mixer selection on the NetWinder * as follows: * * OSS Source WA Source Actual source * SOUND_MASK_IMIX Mixer Mixer output (same as AD1848) * SOUND_MASK_LINE Line Line in * SOUND_MASK_LINE1 Left Mic Handset * SOUND_MASK_PHONEIN Left Aux Telephone microphone * SOUND_MASK_MIC Right Mic Builtin microphone */
static unsigned int netwinder_select_input(struct wavnc_info *devc, unsigned int recmask, unsigned char *dev_l, unsigned char *dev_r) { unsigned int recdev_l = ADC_MUX_NONE, recdev_r = ADC_MUX_NONE; if (recmask & SOUND_MASK_IMIX) { recmask = SOUND_MASK_IMIX; recdev_l = ADC_MUX_MIXER; recdev_r = ADC_MUX_MIXER; } else if (recmask & SOUND_MASK_LINE) { recmask = SOUND_MASK_LINE; recdev_l = ADC_MUX_LINE; recdev_r = ADC_MUX_LINE; } else if (recmask & SOUND_MASK_LINE1) { recmask = SOUND_MASK_LINE1; waveartist_cmd1(devc, WACMD_SET_MONO); /* left */ recdev_l = ADC_MUX_MIC; recdev_r = ADC_MUX_NONE; } else if (recmask & SOUND_MASK_PHONEIN) { recmask = SOUND_MASK_PHONEIN; waveartist_cmd1(devc, WACMD_SET_MONO); /* left */ recdev_l = ADC_MUX_AUX1; recdev_r = ADC_MUX_NONE; } else if (recmask & SOUND_MASK_MIC) { recmask = SOUND_MASK_MIC; waveartist_cmd1(devc, WACMD_SET_MONO | 0x100); /* right */ recdev_l = ADC_MUX_NONE; recdev_r = ADC_MUX_MIC; } *dev_l = recdev_l; *dev_r = recdev_r; return recmask; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds12770.95%125.00%
Linus Torvalds (pre-git)5128.49%250.00%
Himangi Saraogi10.56%125.00%
Total179100.00%4100.00%


static int netwinder_decode_mixer(struct wavnc_info *devc, int dev, unsigned char lev_l, unsigned char lev_r) { switch (dev) { case SOUND_MIXER_VOLUME: case SOUND_MIXER_SYNTH: case SOUND_MIXER_PCM: case SOUND_MIXER_LINE: case SOUND_MIXER_IGAIN: devc->levels[dev] = lev_l | lev_r << 8; break; case SOUND_MIXER_MIC: /* right mic only */ devc->levels[SOUND_MIXER_MIC] &= 0xff; devc->levels[SOUND_MIXER_MIC] |= lev_l << 8; break; case SOUND_MIXER_LINE1: /* left mic only */ devc->levels[SOUND_MIXER_MIC] &= 0xff00; devc->levels[SOUND_MIXER_MIC] |= lev_l; dev = SOUND_MIXER_MIC; break; case SOUND_MIXER_PHONEIN: /* left aux only */ devc->levels[SOUND_MIXER_LINE1] = lev_l; dev = SOUND_MIXER_LINE1; break; case SOUND_MIXER_IMIX: case SOUND_MIXER_PHONEOUT: break; default: dev = -EINVAL; break; } return dev; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds13090.28%120.00%
Linus Torvalds (pre-git)139.03%360.00%
Himangi Saraogi10.69%120.00%
Total144100.00%5100.00%


static int netwinder_get_mixer(struct wavnc_info *devc, int dev) { int levels; switch (dev) { case SOUND_MIXER_VOLUME: case SOUND_MIXER_SYNTH: case SOUND_MIXER_PCM: case SOUND_MIXER_LINE: case SOUND_MIXER_IGAIN: levels = devc->levels[dev]; break; case SOUND_MIXER_MIC: /* builtin mic: right mic only */ levels = devc->levels[SOUND_MIXER_MIC] >> 8; levels |= levels << 8; break; case SOUND_MIXER_LINE1: /* handset mic: left mic only */ levels = devc->levels[SOUND_MIXER_MIC] & 0xff; levels |= levels << 8; break; case SOUND_MIXER_PHONEIN: /* phone mic: left aux1 only */ levels = devc->levels[SOUND_MIXER_LINE1] & 0xff; levels |= levels << 8; break; default: levels = 0; } return levels; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds9376.23%120.00%
Linus Torvalds (pre-git)2822.95%360.00%
Himangi Saraogi10.82%120.00%
Total122100.00%5100.00%

/* * Waveartist specific mixer information. */ static const struct waveartist_mixer_info netwinder_mixer = { .supported_devs = SOUND_MASK_VOLUME | SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_IMIX | SOUND_MASK_LINE1 | SOUND_MASK_PHONEIN | SOUND_MASK_PHONEOUT| SOUND_MASK_IGAIN, .recording_devs = SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_IMIX | SOUND_MASK_LINE1 | SOUND_MASK_PHONEIN, .stereo_devs = SOUND_MASK_VOLUME | SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_IMIX | SOUND_MASK_IGAIN, .select_input = netwinder_select_input, .decode_mixer = netwinder_decode_mixer, .get_mixer = netwinder_get_mixer, };
static void vnc_configure_mixer(struct wavnc_info *devc, unsigned int recmask) { if (!devc->no_autoselect) { if (devc->handset_detect) { recmask = SOUND_MASK_LINE1; devc->spkr_mute_state = devc->line_mute_state = 1; } else if (devc->telephone_detect) { recmask = SOUND_MASK_PHONEIN; devc->spkr_mute_state = devc->line_mute_state = 1; } else { /* unless someone has asked for LINE-IN, * we default to MIC */ if ((devc->recmask & SOUND_MASK_LINE) == 0) devc->recmask = SOUND_MASK_MIC; devc->spkr_mute_state = devc->line_mute_state = 0; } vnc_mute_spkr(devc); vnc_mute_lout(devc); if (recmask != devc->recmask) waveartist_set_recmask(devc, recmask); } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)11591.27%360.00%
Linus Torvalds107.94%120.00%
Himangi Saraogi10.79%120.00%
Total126100.00%5100.00%


static int vnc_slider(struct wavnc_info *devc) { signed int slider_volume; unsigned int temp, old_hs, old_td; /* * read the "buttons" state. * Bit 4 = 0 means handset present * Bit 5 = 1 means phone offhook */ temp = inb(0x201); old_hs = devc->handset_detect; old_td = devc->telephone_detect; devc->handset_detect = !(temp & 0x10); devc->telephone_detect = !!(temp & 0x20); if (!devc->no_autoselect && (old_hs != devc->handset_detect || old_td != devc->telephone_detect)) vnc_configure_mixer(devc, devc->recmask); slider_volume = vnc_volume_slider(devc); /* * If we're using software controlled volume, and * the slider moves by more than 20%, then we * switch back to slider controlled volume. */ if (abs(devc->slider_vol - slider_volume) > 20) devc->use_slider = 1; /* * use only left channel */ temp = levels[SOUND_MIXER_VOLUME] & 0xFF; if (slider_volume != temp && devc->use_slider) { devc->slider_vol = slider_volume; waveartist_set_mixer(devc, SOUND_MIXER_VOLUME, slider_volume | slider_volume << 8); return 1; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)16395.88%360.00%
Linus Torvalds63.53%120.00%
Himangi Saraogi10.59%120.00%
Total170100.00%5100.00%


static void vnc_slider_tick(unsigned long data) { int next_timeout; if (vnc_slider(adev_info + data)) next_timeout = 5; // mixer reported change else next_timeout = VNC_TIMER_PERIOD; mod_timer(&vnc_timer, jiffies + next_timeout); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)42100.00%3100.00%
Total42100.00%3100.00%


static int vnc_private_ioctl(int dev, unsigned int cmd, int __user * arg) { struct wavnc_info *devc = (struct wavnc_info *)audio_devs[dev]->devc; int val; switch (cmd) { case SOUND_MIXER_PRIVATE1: { u_int prev_spkr_mute, prev_line_mute, prev_auto_state; int val; if (get_user(val, arg)) return -EFAULT; /* check if parameter is logical */ if (val & ~(VNC_MUTE_INTERNAL_SPKR | VNC_MUTE_LINE_OUT | VNC_DISABLE_AUTOSWITCH)) return -EINVAL; prev_auto_state = devc->no_autoselect; prev_spkr_mute = devc->spkr_mute_state; prev_line_mute = devc->line_mute_state; devc->no_autoselect = (val & VNC_DISABLE_AUTOSWITCH) ? 1 : 0; devc->spkr_mute_state = (val & VNC_MUTE_INTERNAL_SPKR) ? 1 : 0; devc->line_mute_state = (val & VNC_MUTE_LINE_OUT) ? 1 : 0; if (prev_spkr_mute != devc->spkr_mute_state) vnc_mute_spkr(devc); if (prev_line_mute != devc->line_mute_state) vnc_mute_lout(devc); if (prev_auto_state != devc->no_autoselect) vnc_configure_mixer(devc, devc->recmask); return 0; } case SOUND_MIXER_PRIVATE2: if (get_user(val, arg)) return -EFAULT; switch (val) { #define VNC_SOUND_PAUSE 0x53 //to pause the DSP #define VNC_SOUND_RESUME 0x57 //to unpause the DSP case VNC_SOUND_PAUSE: waveartist_cmd1(devc, 0x16); break; case VNC_SOUND_RESUME: waveartist_cmd1(devc, 0x18); break; default: return -EINVAL; } return 0; /* private ioctl to allow bulk access to waveartist */ case SOUND_MIXER_PRIVATE3: { unsigned long flags; int mixer_reg[15], i, val; if (get_user(val, arg)) return -EFAULT; if (copy_from_user(mixer_reg, (void *)val, sizeof(mixer_reg))) return -EFAULT; switch (mixer_reg[14]) { case MIXER_PRIVATE3_RESET: waveartist_mixer_reset(devc); break; case MIXER_PRIVATE3_WRITE: waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[0], mixer_reg[4]); waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[1], mixer_reg[5]); waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[2], mixer_reg[6]); waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[3], mixer_reg[7]); waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[8], mixer_reg[9]); waveartist_cmd3(devc, WACMD_SET_LEVEL, mixer_reg[10], mixer_reg[11]); waveartist_cmd3(devc, WACMD_SET_LEVEL, mixer_reg[12], mixer_reg[13]); break; case MIXER_PRIVATE3_READ: spin_lock_irqsave(&waveartist_lock, flags); for (i = 0x30; i < 14 << 8; i += 1 << 8) waveartist_cmd(devc, 1, &i, 1, mixer_reg + (i >> 8)); spin_unlock_irqrestore(&waveartist_lock, flags); if (copy_to_user((void *)val, mixer_reg, sizeof(mixer_reg))) return -EFAULT; break; default: return -EINVAL; } return 0; } /* read back the state from PRIVATE1 */ case SOUND_MIXER_PRIVATE4: val = (devc->spkr_mute_state ? VNC_MUTE_INTERNAL_SPKR : 0) | (devc->line_mute_state ? VNC_MUTE_LINE_OUT : 0) | (devc->handset_detect ? VNC_HANDSET_DETECT : 0) | (devc->telephone_detect ? VNC_PHONE_DETECT : 0) | (devc->no_autoselect ? VNC_DISABLE_AUTOSWITCH : 0); return put_user(val, arg) ? -EFAULT : 0; } if (_SIOC_DIR(cmd) & _SIOC_WRITE) { /* * special case for master volume: if we * received this call - switch from hw * volume control to a software volume * control, till the hw volume is modified * to signal that user wants to be back in * hardware... */ if ((cmd & 0xff) == SOUND_MIXER_VOLUME) devc->use_slider = 0; /* speaker output */ if ((cmd & 0xff) == SOUND_MIXER_SPEAKER) { unsigned int val, l, r; if (get_user(val, arg)) return -EFAULT; l = val & 0x7f; r = (val & 0x7f00) >> 8; val = (l + r) / 2; devc->levels[SOUND_MIXER_SPEAKER] = val | (val << 8); devc->spkr_mute_state = (val <= 50); vnc_mute_spkr(devc); return 0; } } return -ENOIOCTLCMD; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)65288.59%350.00%
Linus Torvalds7910.73%116.67%
Al Viro30.41%116.67%
Himangi Saraogi20.27%116.67%
Total736100.00%6100.00%

#endif static struct address_info cfg; static int attached; static int __initdata io = 0; static int __initdata irq = 0; static int __initdata dma = 0; static int __initdata dma2 = 0;
static int __init init_waveartist(void) { const struct waveartist_mixer_info *mix; if (!io && machine_is_netwinder()) { /* * The NetWinder WaveArtist is at a fixed address. * If the user does not supply an address, use the * well-known parameters. */ io = 0x250; irq = 12; dma = 3; dma2 = 7; } mix = &waveartist_mixer; #ifdef CONFIG_ARCH_NETWINDER if (machine_is_netwinder()) mix = &netwinder_mixer; #endif cfg.io_base = io; cfg.irq = irq; cfg.dma = dma; cfg.dma2 = dma2; if (!probe_waveartist(&cfg)) return -ENODEV; attach_waveartist(&cfg, mix); attached = 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)8675.44%375.00%
Linus Torvalds2824.56%125.00%
Total114100.00%4100.00%


static void __exit cleanup_waveartist(void) { if (attached) unload_waveartist(&cfg); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)19100.00%2100.00%
Total19100.00%2100.00%

module_init(init_waveartist); module_exit(cleanup_waveartist); #ifndef MODULE
static int __init setup_waveartist(char *str) { /* io, irq, dma, dma2 */ int ints[5]; str = get_options(str, ARRAY_SIZE(ints), ints); io = ints[1]; irq = ints[2]; dma = ints[3]; dma2 = ints[4]; return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)6298.41%150.00%
Linus Torvalds11.59%150.00%
Total63100.00%2100.00%

__setup("waveartist=", setup_waveartist); #endif MODULE_DESCRIPTION("Rockwell WaveArtist RWA-010 sound driver"); module_param_hw(io, int, ioport, 0); /* IO base */ module_param_hw(irq, int, irq, 0); /* IRQ */ module_param_hw(dma, int, dma, 0); /* DMA */ module_param_hw(dma2, int, dma, 0); /* DMA2 */ MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)510660.33%1136.67%
Linus Torvalds309536.57%26.67%
Himangi Saraogi871.03%13.33%
Alan Cox620.73%13.33%
Al Viro380.45%26.67%
Peter Wächtler200.24%13.33%
David Howells120.14%13.33%
Rusty Russell120.14%13.33%
Muhammad Falak R Wani70.08%13.33%
Vasiliy Kulikov50.06%13.33%
Andrew Morton40.05%13.33%
Thomas Gleixner40.05%13.33%
Russell King40.05%26.67%
Tejun Heo30.04%13.33%
Arnd Bergmann20.02%13.33%
Robert P. J. Day10.01%13.33%
Uwe Zeisberger10.01%13.33%
Total8463100.00%30100.00%
Directory: sound/oss
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.