cregit-Linux how code gets into the kernel

Release 4.7 sound/oss/pas2_pcm.c

Directory: sound/oss
/*
 * pas2_pcm.c Audio routines for PAS16
 *
 *
 * 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.
 *
 *
 * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
 * Alan Cox        : Swatted a double allocation of device bug. Made a few
 *                   more things module options.
 * Bartlomiej Zolnierkiewicz : Added __init to pas_pcm_init()
 */

#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/timex.h>
#include "sound_config.h"

#include "pas2.h"


#define PAS_PCM_INTRBITS (0x08)
/*
 * Sample buffer timer interrupt enable
 */


#define PCM_NON	0

#define PCM_DAC	1

#define PCM_ADC	2


static unsigned long pcm_speed; 	
/* sampling rate */

static unsigned char pcm_channels = 1;	
/* channels (1 or 2) */

static unsigned char pcm_bits = 8;	
/* bits/sample (8 or 16) */

static unsigned char pcm_filter;	
/* filter FLAG */

static unsigned char pcm_mode = PCM_NON;

static unsigned long pcm_count;

static unsigned short pcm_bitsok = 8;	
/* mask of OK bits */

static int      pcm_busy;

int             pas_audiodev = -1;

static int      open_mode;

extern spinlock_t pas_lock;


static int pcm_set_speed(int arg) { int foo, tmp; unsigned long flags; if (arg == 0) return pcm_speed; if (arg > 44100) arg = 44100; if (arg < 5000) arg = 5000; if (pcm_channels & 2) { foo = ((PIT_TICK_RATE / 2) + (arg / 2)) / arg; arg = ((PIT_TICK_RATE / 2) + (foo / 2)) / foo; } else { foo = (PIT_TICK_RATE + (arg / 2)) / arg; arg = (PIT_TICK_RATE + (foo / 2)) / foo; } pcm_speed = arg; tmp = pas_read(0x0B8A); /* * Set anti-aliasing filters according to sample rate. You really *NEED* * to enable this feature for all normal recording unless you want to * experiment with aliasing effects. * These filters apply to the selected "recording" source. * I (pfw) don't know the encoding of these 5 bits. The values shown * come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/. * * I cleared bit 5 of these values, since that bit controls the master * mute flag. (Olav Wölfelschneider) * */ #if !defined NO_AUTO_FILTER_SET tmp &= 0xe0; if (pcm_speed >= 2 * 17897) tmp |= 0x01; else if (pcm_speed >= 2 * 15909) tmp |= 0x02; else if (pcm_speed >= 2 * 11931) tmp |= 0x09; else if (pcm_speed >= 2 * 8948) tmp |= 0x11; else if (pcm_speed >= 2 * 5965) tmp |= 0x19; else if (pcm_speed >= 2 * 2982) tmp |= 0x04; pcm_filter = tmp; #endif spin_lock_irqsave(&pas_lock, flags); pas_write(tmp & ~(0x40 | 0x80), 0x0B8A); pas_write(0x00 | 0x30 | 0x04, 0x138B); pas_write(foo & 0xff, 0x1388); pas_write((foo >> 8) & 0xff, 0x1388); pas_write(tmp, 0x0B8A); spin_unlock_irqrestore(&pas_lock, flags); return pcm_speed; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git27892.98%758.33%
andrew mortonandrew morton82.68%18.33%
peter waechtlerpeter waechtler62.01%18.33%
deepak saxenadeepak saxena41.34%18.33%
rusty russellrusty russell20.67%18.33%
john anthony kazos jrjohn anthony kazos jr10.33%18.33%
Total299100.00%12100.00%


static int pcm_set_channels(int arg) { if ((arg != 1) && (arg != 2)) return pcm_channels; if (arg != pcm_channels) { pas_write(pas_read(0xF8A) ^ 0x20, 0xF8A); pcm_channels = arg; pcm_set_speed(pcm_speed); /* The speed must be reinitialized */ } return pcm_channels; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git59100.00%3100.00%
Total59100.00%3100.00%


static int pcm_set_bits(int arg) { if (arg == 0) return pcm_bits; if ((arg & pcm_bitsok) != arg) return pcm_bits; if (arg != pcm_bits) { pas_write(pas_read(0x8389) ^ 0x04, 0x8389); pcm_bits = arg; } return pcm_bits; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git58100.00%4100.00%
Total58100.00%4100.00%


static int pas_audio_ioctl(int dev, unsigned int cmd, void __user *arg) { int val, ret; int __user *p = arg; switch (cmd) { case SOUND_PCM_WRITE_RATE: if (get_user(val, p)) return -EFAULT; ret = pcm_set_speed(val); break; case SOUND_PCM_READ_RATE: ret = pcm_speed; break; case SNDCTL_DSP_STEREO: if (get_user(val, p)) return -EFAULT; ret = pcm_set_channels(val + 1) - 1; break; case SOUND_PCM_WRITE_CHANNELS: if (get_user(val, p)) return -EFAULT; ret = pcm_set_channels(val); break; case SOUND_PCM_READ_CHANNELS: ret = pcm_channels; break; case SNDCTL_DSP_SETFMT: if (get_user(val, p)) return -EFAULT; ret = pcm_set_bits(val); break; case SOUND_PCM_READ_BITS: ret = pcm_bits; break; default: return -EINVAL; } return put_user(ret, p); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git15891.33%888.89%
al viroal viro158.67%111.11%
Total173100.00%9100.00%


static void pas_audio_reset(int dev) { pas_write(pas_read(0xF8A) & ~0x40, 0xF8A); /* Disable PCM */ }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git23100.00%3100.00%
Total23100.00%3100.00%


static int pas_audio_open(int dev, int mode) { int err; unsigned long flags; spin_lock_irqsave(&pas_lock, flags); if (pcm_busy) { spin_unlock_irqrestore(&pas_lock, flags); return -EBUSY; } pcm_busy = 1; spin_unlock_irqrestore(&pas_lock, flags); if ((err = pas_set_intr(PAS_PCM_INTRBITS)) < 0) return err; pcm_count = 0; open_mode = mode; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git7285.71%466.67%
peter waechtlerpeter waechtler910.71%116.67%
rusty russellrusty russell33.57%116.67%
Total84100.00%6100.00%


static void pas_audio_close(int dev) { unsigned long flags; spin_lock_irqsave(&pas_lock, flags); pas_audio_reset(dev); pas_remove_intr(PAS_PCM_INTRBITS); pcm_mode = PCM_NON; pcm_busy = 0; spin_unlock_irqrestore(&pas_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git3982.98%360.00%
peter waechtlerpeter waechtler612.77%120.00%
rusty russellrusty russell24.26%120.00%
Total47100.00%5100.00%


static void pas_audio_output_block(int dev, unsigned long buf, int count, int intrflag) { unsigned long flags, cnt; cnt = count; if (audio_devs[dev]->dmap_out->dma > 3) cnt >>= 1; if (audio_devs[dev]->flags & DMA_AUTOMODE && intrflag && cnt == pcm_count) return; spin_lock_irqsave(&pas_lock, flags); pas_write(pas_read(0xF8A) & ~0x40, 0xF8A); /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ if (audio_devs[dev]->dmap_out->dma > 3) count >>= 1; if (count != pcm_count) { pas_write(pas_read(0x0B8A) & ~0x80, 0x0B8A); pas_write(0x40 | 0x30 | 0x04, 0x138B); pas_write(count & 0xff, 0x1389); pas_write((count >> 8) & 0xff, 0x1389); pas_write(pas_read(0x0B8A) | 0x80, 0x0B8A); pcm_count = count; } pas_write(pas_read(0x0B8A) | 0x80 | 0x40, 0x0B8A); #ifdef NO_TRIGGER pas_write(pas_read(0xF8A) | 0x40 | 0x10, 0xF8A); #endif pcm_mode = PCM_DAC; spin_unlock_irqrestore(&pas_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git21096.33%571.43%
peter waechtlerpeter waechtler62.75%114.29%
rusty russellrusty russell20.92%114.29%
Total218100.00%7100.00%


static void pas_audio_start_input(int dev, unsigned long buf, int count, int intrflag) { unsigned long flags; int cnt; cnt = count; if (audio_devs[dev]->dmap_out->dma > 3) cnt >>= 1; if (audio_devs[pas_audiodev]->flags & DMA_AUTOMODE && intrflag && cnt == pcm_count) return; spin_lock_irqsave(&pas_lock, flags); /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ if (audio_devs[dev]->dmap_out->dma > 3) count >>= 1; if (count != pcm_count) { pas_write(pas_read(0x0B8A) & ~0x80, 0x0B8A); pas_write(0x40 | 0x30 | 0x04, 0x138B); pas_write(count & 0xff, 0x1389); pas_write((count >> 8) & 0xff, 0x1389); pas_write(pas_read(0x0B8A) | 0x80, 0x0B8A); pcm_count = count; } pas_write(pas_read(0x0B8A) | 0x80 | 0x40, 0x0B8A); #ifdef NO_TRIGGER pas_write((pas_read(0xF8A) | 0x40) & ~0x10, 0xF8A); #endif pcm_mode = PCM_ADC; spin_unlock_irqrestore(&pas_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git20196.17%675.00%
peter waechtlerpeter waechtler62.87%112.50%
rusty russellrusty russell20.96%112.50%
Total209100.00%8100.00%

#ifndef NO_TRIGGER
static void pas_audio_trigger(int dev, int state) { unsigned long flags; spin_lock_irqsave(&pas_lock, flags); state &= open_mode; if (state & PCM_ENABLE_OUTPUT) pas_write(pas_read(0xF8A) | 0x40 | 0x10, 0xF8A); else if (state & PCM_ENABLE_INPUT) pas_write((pas_read(0xF8A) | 0x40) & ~0x10, 0xF8A); else pas_write(pas_read(0xF8A) & ~0x40, 0xF8A); spin_unlock_irqrestore(&pas_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git8691.49%360.00%
peter waechtlerpeter waechtler66.38%120.00%
rusty russellrusty russell22.13%120.00%
Total94100.00%5100.00%

#endif
static int pas_audio_prepare_for_input(int dev, int bsize, int bcount) { pas_audio_reset(dev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git23100.00%3100.00%
Total23100.00%3100.00%


static int pas_audio_prepare_for_output(int dev, int bsize, int bcount) { pas_audio_reset(dev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git23100.00%3100.00%
Total23100.00%3100.00%

static struct audio_driver pas_audio_driver = { .owner = THIS_MODULE, .open = pas_audio_open, .close = pas_audio_close, .output_block = pas_audio_output_block, .start_input = pas_audio_start_input, .ioctl = pas_audio_ioctl, .prepare_for_input = pas_audio_prepare_for_input, .prepare_for_output = pas_audio_prepare_for_output, .halt_io = pas_audio_reset, .trigger = pas_audio_trigger };
void __init pas_pcm_init(struct address_info *hw_config) { pcm_bitsok = 8; if (pas_read(0xEF8B) & 0x08) pcm_bitsok |= 16; pcm_set_speed(DSP_DEFAULT_SPEED); if ((pas_audiodev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, "Pro Audio Spectrum", &pas_audio_driver, sizeof(struct audio_driver), DMA_AUTOMODE, AFMT_U8 | AFMT_S16_LE, NULL, hw_config->dma, hw_config->dma)) < 0) printk(KERN_WARNING "PAS16: Too many PCM devices available\n"); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git79100.00%7100.00%
Total79100.00%7100.00%


void pas_pcm_interrupt(unsigned char status, int cause) { if (cause == 1) { /* * Halt the PCM first. Otherwise we don't have time to start a new * block before the PCM chip proceeds to the next sample */ if (!(audio_devs[pas_audiodev]->flags & DMA_AUTOMODE)) pas_write(pas_read(0xF8A) & ~0x40, 0xF8A); switch (pcm_mode) { case PCM_DAC: DMAbuf_outputintr(pas_audiodev, 1); break; case PCM_ADC: DMAbuf_inputintr(pas_audiodev); break; default: printk(KERN_WARNING "PAS: Unexpected PCM interrupt\n"); } } }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git81100.00%5100.00%
Total81100.00%5100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git152193.26%2172.41%
peter waechtlerpeter waechtler452.76%13.45%
alan coxalan cox201.23%13.45%
al viroal viro150.92%13.45%
rusty russellrusty russell140.86%13.45%
andrew mortonandrew morton100.61%13.45%
deepak saxenadeepak saxena40.25%13.45%
arnd bergmannarnd bergmann10.06%13.45%
john anthony kazos jrjohn anthony kazos jr10.06%13.45%
Total1631100.00%29100.00%
Directory: sound/oss
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}