cregit-Linux how code gets into the kernel

Release 4.7 sound/oss/dmasound/dmasound_q40.c

/*
 *  linux/sound/oss/dmasound/dmasound_q40.c
 *
 *  Q40 DMA Sound Driver
 *
 *  See linux/sound/oss/dmasound/dmasound_core.c for copyright and credits
 *  prior to 28/01/2001
 *
 *  28/01/2001 [0.1] Iain Sandoe
 *                   - added versioning
 *                   - put in and populated the hardware_afmts field.
 *             [0.2] - put in SNDCTL_DSP_GETCAPS value.
 *             [0.3] - put in default hard/soft settings.
 */


#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/soundcard.h>
#include <linux/interrupt.h>

#include <asm/uaccess.h>
#include <asm/q40ints.h>
#include <asm/q40_master.h>

#include "dmasound.h"


#define DMASOUND_Q40_REVISION 0

#define DMASOUND_Q40_EDITION 3


static int expand_bal;	
/* Balance factor for expanding (not volume!) */

static int expand_data;	
/* Data for expanding */


/*** Low level stuff *********************************************************/


static void *Q40Alloc(unsigned int size, gfp_t flags);
static void Q40Free(void *, unsigned int);
static int Q40IrqInit(void);
#ifdef MODULE
static void Q40IrqCleanUp(void);
#endif
static void Q40Silence(void);
static void Q40Init(void);
static int Q40SetFormat(int format);
static int Q40SetVolume(int volume);
static void Q40PlayNextFrame(int index);
static void Q40Play(void);
static irqreturn_t Q40StereoInterrupt(int irq, void *dummy);
static irqreturn_t Q40MonoInterrupt(int irq, void *dummy);
static void Q40Interrupt(void);


/*** Mid level stuff *********************************************************/



/* userCount, frameUsed, frameLeft == byte counts */

static ssize_t q40_ct_law(const u_char __user *userPtr, size_t userCount, u_char frame[], ssize_t *frameUsed, ssize_t frameLeft) { char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8: dmasound_alaw2dma8; ssize_t count, used; u_char *p = (u_char *) &frame[*frameUsed]; used = count = min_t(size_t, userCount, frameLeft); if (copy_from_user(p,userPtr,count)) return -EFAULT; while (count > 0) { *p = table[*p]+128; p++; count--; } *frameUsed += used ; return used; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git11795.12%125.00%
linus torvaldslinus torvalds54.07%250.00%
al viroal viro10.81%125.00%
Total123100.00%4100.00%


static ssize_t q40_ct_s8(const u_char __user *userPtr, size_t userCount, u_char frame[], ssize_t *frameUsed, ssize_t frameLeft) { ssize_t count, used; u_char *p = (u_char *) &frame[*frameUsed]; used = count = min_t(size_t, userCount, frameLeft); if (copy_from_user(p,userPtr,count)) return -EFAULT; while (count > 0) { *p = *p + 128; p++; count--; } *frameUsed += used; return used; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git8581.73%120.00%
dave jonesdave jones1312.50%120.00%
linus torvaldslinus torvalds54.81%240.00%
al viroal viro10.96%120.00%
Total104100.00%5100.00%


static ssize_t q40_ct_u8(const u_char __user *userPtr, size_t userCount, u_char frame[], ssize_t *frameUsed, ssize_t frameLeft) { ssize_t count, used; u_char *p = (u_char *) &frame[*frameUsed]; used = count = min_t(size_t, userCount, frameLeft); if (copy_from_user(p,userPtr,count)) return -EFAULT; *frameUsed += used; return used; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git7591.46%120.00%
linus torvaldslinus torvalds56.10%240.00%
dave jonesdave jones11.22%120.00%
al viroal viro11.22%120.00%
Total82100.00%5100.00%

/* a bit too complicated to optimise right now ..*/
static ssize_t q40_ctx_law(const u_char __user *userPtr, size_t userCount, u_char frame[], ssize_t *frameUsed, ssize_t frameLeft) { unsigned char *table = (unsigned char *) (dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8: dmasound_alaw2dma8); unsigned int data = expand_data; u_char *p = (u_char *) &frame[*frameUsed]; int bal = expand_bal; int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; int utotal, ftotal; ftotal = frameLeft; utotal = userCount; while (frameLeft) { u_char c; if (bal < 0) { if (userCount == 0) break; if (get_user(c, userPtr++)) return -EFAULT; data = table[c]; data += 0x80; userCount--; bal += hSpeed; } *p++ = data; frameLeft--; bal -= sSpeed; } expand_bal = bal; expand_data = data; *frameUsed += (ftotal - frameLeft); utotal -= userCount; return utotal; }

Contributors

PersonTokensPropCommitsCommitProp
dave jonesdave jones10653.27%125.00%
pre-gitpre-git9145.73%125.00%
linus torvaldslinus torvalds10.50%125.00%
al viroal viro10.50%125.00%
Total199100.00%4100.00%


static ssize_t q40_ctx_s8(const u_char __user *userPtr, size_t userCount, u_char frame[], ssize_t *frameUsed, ssize_t frameLeft) { u_char *p = (u_char *) &frame[*frameUsed]; unsigned int data = expand_data; int bal = expand_bal; int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; int utotal, ftotal; ftotal = frameLeft; utotal = userCount; while (frameLeft) { u_char c; if (bal < 0) { if (userCount == 0) break; if (get_user(c, userPtr++)) return -EFAULT; data = c ; data += 0x80; userCount--; bal += hSpeed; } *p++ = data; frameLeft--; bal -= sSpeed; } expand_bal = bal; expand_data = data; *frameUsed += (ftotal - frameLeft); utotal -= userCount; return utotal; }

Contributors

PersonTokensPropCommitsCommitProp
dave jonesdave jones11164.53%125.00%
pre-gitpre-git5934.30%125.00%
linus torvaldslinus torvalds10.58%125.00%
al viroal viro10.58%125.00%
Total172100.00%4100.00%


static ssize_t q40_ctx_u8(const u_char __user *userPtr, size_t userCount, u_char frame[], ssize_t *frameUsed, ssize_t frameLeft) { u_char *p = (u_char *) &frame[*frameUsed]; unsigned int data = expand_data; int bal = expand_bal; int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; int utotal, ftotal; ftotal = frameLeft; utotal = userCount; while (frameLeft) { u_char c; if (bal < 0) { if (userCount == 0) break; if (get_user(c, userPtr++)) return -EFAULT; data = c ; userCount--; bal += hSpeed; } *p++ = data; frameLeft--; bal -= sSpeed; } expand_bal = bal; expand_data = data; *frameUsed += (ftotal - frameLeft) ; utotal -= userCount; return utotal; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git8651.19%133.33%
dave jonesdave jones8148.21%133.33%
al viroal viro10.60%133.33%
Total168100.00%3100.00%

/* compressing versions */
static ssize_t q40_ctc_law(const u_char __user *userPtr, size_t userCount, u_char frame[], ssize_t *frameUsed, ssize_t frameLeft) { unsigned char *table = (unsigned char *) (dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8: dmasound_alaw2dma8); unsigned int data = expand_data; u_char *p = (u_char *) &frame[*frameUsed]; int bal = expand_bal; int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; int utotal, ftotal; ftotal = frameLeft; utotal = userCount; while (frameLeft) { u_char c; while(bal<0) { if (userCount == 0) goto lout; if (!(bal<(-hSpeed))) { if (get_user(c, userPtr)) return -EFAULT; data = 0x80 + table[c]; } userPtr++; userCount--; bal += hSpeed; } *p++ = data; frameLeft--; bal -= sSpeed; } lout: expand_bal = bal; expand_data = data; *frameUsed += (ftotal - frameLeft); utotal -= userCount; return utotal; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git19188.02%133.33%
dave jonesdave jones2511.52%133.33%
al viroal viro10.46%133.33%
Total217100.00%3100.00%


static ssize_t q40_ctc_s8(const u_char __user *userPtr, size_t userCount, u_char frame[], ssize_t *frameUsed, ssize_t frameLeft) { u_char *p = (u_char *) &frame[*frameUsed]; unsigned int data = expand_data; int bal = expand_bal; int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; int utotal, ftotal; ftotal = frameLeft; utotal = userCount; while (frameLeft) { u_char c; while (bal < 0) { if (userCount == 0) goto lout; if (!(bal<(-hSpeed))) { if (get_user(c, userPtr)) return -EFAULT; data = c + 0x80; } userPtr++; userCount--; bal += hSpeed; } *p++ = data; frameLeft--; bal -= sSpeed; } lout: expand_bal = bal; expand_data = data; *frameUsed += (ftotal - frameLeft); utotal -= userCount; return utotal; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git16486.32%133.33%
dave jonesdave jones2513.16%133.33%
al viroal viro10.53%133.33%
Total190100.00%3100.00%


static ssize_t q40_ctc_u8(const u_char __user *userPtr, size_t userCount, u_char frame[], ssize_t *frameUsed, ssize_t frameLeft) { u_char *p = (u_char *) &frame[*frameUsed]; unsigned int data = expand_data; int bal = expand_bal; int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; int utotal, ftotal; ftotal = frameLeft; utotal = userCount; while (frameLeft) { u_char c; while (bal < 0) { if (userCount == 0) goto lout; if (!(bal<(-hSpeed))) { if (get_user(c, userPtr)) return -EFAULT; data = c ; } userPtr++; userCount--; bal += hSpeed; } *p++ = data; frameLeft--; bal -= sSpeed; } lout: expand_bal = bal; expand_data = data; *frameUsed += (ftotal - frameLeft) ; utotal -= userCount; return utotal; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git16386.70%133.33%
dave jonesdave jones2412.77%133.33%
al viroal viro10.53%133.33%
Total188100.00%3100.00%

static TRANS transQ40Normal = { q40_ct_law, q40_ct_law, q40_ct_s8, q40_ct_u8, NULL, NULL, NULL, NULL }; static TRANS transQ40Expanding = { q40_ctx_law, q40_ctx_law, q40_ctx_s8, q40_ctx_u8, NULL, NULL, NULL, NULL }; static TRANS transQ40Compressing = { q40_ctc_law, q40_ctc_law, q40_ctc_s8, q40_ctc_u8, NULL, NULL, NULL, NULL }; /*** Low level stuff *********************************************************/
static void *Q40Alloc(unsigned int size, gfp_t flags) { return kmalloc(size, flags); /* change to vmalloc */ }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git2295.65%150.00%
al viroal viro14.35%150.00%
Total23100.00%2100.00%


static void Q40Free(void *ptr, unsigned int size) { kfree(ptr); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git19100.00%1100.00%
Total19100.00%1100.00%


static int __init Q40IrqInit(void) { /* Register interrupt handler. */ if (request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0, "DMA sound", Q40Interrupt)) return 0; return(1); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git2781.82%150.00%
geert uytterhoevengeert uytterhoeven618.18%150.00%
Total33100.00%2100.00%

#ifdef MODULE
static void Q40IrqCleanUp(void) { master_outb(0,SAMPLE_ENABLE_REG); free_irq(Q40_IRQ_SAMPLE, Q40Interrupt); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git22100.00%1100.00%
Total22100.00%1100.00%

#endif /* MODULE */
static void Q40Silence(void) { master_outb(0,SAMPLE_ENABLE_REG); *DAC_LEFT=*DAC_RIGHT=127; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git2295.65%150.00%
dave jonesdave jones14.35%150.00%
Total23100.00%2100.00%

static char *q40_pp; static unsigned int q40_sc;
static void Q40PlayNextFrame(int index) { u_char *start; u_long size; u_char speed; int error; /* used by Q40Play() if all doubts whether there really is something * to be played are already wiped out. */ start = write_sq.buffers[write_sq.front]; size = (write_sq.count == index ? write_sq.rear_size : write_sq.block_size); q40_pp=start; q40_sc=size; write_sq.front = (write_sq.front+1) % write_sq.max_count; write_sq.active++; speed=(dmasound.hard.speed==10000 ? 0 : 1); master_outb( 0,SAMPLE_ENABLE_REG); free_irq(Q40_IRQ_SAMPLE, Q40Interrupt); if (dmasound.soft.stereo) error = request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0, "Q40 sound", Q40Interrupt); else error = request_irq(Q40_IRQ_SAMPLE, Q40MonoInterrupt, 0, "Q40 sound", Q40Interrupt); if (error && printk_ratelimit()) pr_err("Couldn't register sound interrupt\n"); master_outb( speed, SAMPLE_RATE_REG); master_outb( 1,SAMPLE_CLEAR_REG); master_outb( 1,SAMPLE_ENABLE_REG); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git16489.62%150.00%
geert uytterhoevengeert uytterhoeven1910.38%150.00%
Total183100.00%2100.00%


static void Q40Play(void) { unsigned long flags; if (write_sq.active || write_sq.count<=0 ) { /* There's already a frame loaded */ return; } /* nothing in the queue */ if (write_sq.count <= 1 && write_sq.rear_size < write_sq.block_size && !write_sq.syncing) { /* hmmm, the only existing frame is not * yet filled and we're not syncing? */ return; } spin_lock_irqsave(&dmasound.lock, flags); Q40PlayNextFrame(1); spin_unlock_irqrestore(&dmasound.lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git6784.81%133.33%
peter waechtlerpeter waechtler1113.92%133.33%
geert uytterhoevengeert uytterhoeven11.27%133.33%
Total79100.00%3100.00%


static irqreturn_t Q40StereoInterrupt(int irq, void *dummy) { spin_lock(&dmasound.lock); if (q40_sc>1){ *DAC_LEFT=*q40_pp++; *DAC_RIGHT=*q40_pp++; q40_sc -=2; master_outb(1,SAMPLE_CLEAR_REG); }else Q40Interrupt(); spin_unlock(&dmasound.lock); return IRQ_HANDLED; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git4971.01%133.33%
peter waechtlerpeter waechtler1623.19%133.33%
andrew mortonandrew morton45.80%133.33%
Total69100.00%3100.00%


static irqreturn_t Q40MonoInterrupt(int irq, void *dummy) { spin_lock(&dmasound.lock); if (q40_sc>0){ *DAC_LEFT=*q40_pp; *DAC_RIGHT=*q40_pp++; q40_sc --; master_outb(1,SAMPLE_CLEAR_REG); }else Q40Interrupt(); spin_unlock(&dmasound.lock); return IRQ_HANDLED; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git4770.15%133.33%
peter waechtlerpeter waechtler1623.88%133.33%
andrew mortonandrew morton45.97%133.33%
Total67100.00%3100.00%


static void Q40Interrupt(void) { if (!write_sq.active) { /* playing was interrupted and sq_reset() has already cleared * the sq variables, so better don't do anything here. */ WAKE_UP(write_sq.sync_queue); master_outb(0,SAMPLE_ENABLE_REG); /* better safe */ goto exit; } else write_sq.active=0; write_sq.count--; Q40Play(); if (q40_sc<2) { /* there was nothing to play, disable irq */ master_outb(0,SAMPLE_ENABLE_REG); *DAC_LEFT=*DAC_RIGHT=127; } WAKE_UP(write_sq.action_queue); exit: master_outb(1,SAMPLE_CLEAR_REG); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git9098.90%150.00%
dave jonesdave jones11.10%150.00%
Total91100.00%2100.00%


static void Q40Init(void) { int i, idx; const int freq[] = {10000, 20000}; /* search a frequency that fits into the allowed error range */ idx = -1; for (i = 0; i < 2; i++) if ((100 * abs(dmasound.soft.speed - freq[i]) / freq[i]) <= catchRadius) idx = i; dmasound.hard = dmasound.soft; /*sound.hard.stereo=1;*/ /* no longer true */ dmasound.hard.size=8; if (idx > -1) { dmasound.soft.speed = freq[idx]; dmasound.trans_write = &transQ40Normal; } else dmasound.trans_write = &transQ40Expanding; Q40Silence(); if (dmasound.hard.speed > 20200) { /* squeeze the sound, we do that */ dmasound.hard.speed = 20000; dmasound.trans_write = &transQ40Compressing; } else if (dmasound.hard.speed > 10000) { dmasound.hard.speed = 20000; } else { dmasound.hard.speed = 10000; } expand_bal = -dmasound.soft.speed; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git19698.49%150.00%
dave jonesdave jones31.51%150.00%
Total199100.00%2100.00%


static int Q40SetFormat(int format) { /* Q40 sound supports only 8bit modes */ switch (format) { case AFMT_QUERY: return(dmasound.soft.format); case AFMT_MU_LAW: case AFMT_A_LAW: case AFMT_S8: case AFMT_U8: break; default: format = AFMT_S8; } dmasound.soft.format = format; dmasound.soft.size = 8; if (dmasound.minDev == SND_DEV_DSP) { dmasound.dsp.format = format; dmasound.dsp.size = 8; } Q40Init(); return(format); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git96100.00%1100.00%
Total96100.00%1100.00%


static int Q40SetVolume(int volume) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git12100.00%1100.00%
Total12100.00%1100.00%

/*** Machine definitions *****************************************************/ static SETTINGS def_hard = { .format = AFMT_U8, .stereo = 0, .size = 8, .speed = 10000 } ; static SETTINGS def_soft = { .format = AFMT_U8, .stereo = 0, .size = 8, .speed = 8000 } ; static MACHINE machQ40 = { .name = "Q40", .name2 = "Q40", .owner = THIS_MODULE, .dma_alloc = Q40Alloc, .dma_free = Q40Free, .irqinit = Q40IrqInit, #ifdef MODULE .irqcleanup = Q40IrqCleanUp, #endif /* MODULE */ .init = Q40Init, .silence = Q40Silence, .setFormat = Q40SetFormat, .setVolume = Q40SetVolume, .play = Q40Play, .min_dsp_speed = 10000, .version = ((DMASOUND_Q40_REVISION<<8) | DMASOUND_Q40_EDITION), .hardware_afmts = AFMT_U8, /* h'ware-supported formats *only* here */ .capabilities = DSP_CAP_BATCH /* As per SNDCTL_DSP_GETCAPS */ }; /*** Config & Setup **********************************************************/
static int __init dmasound_q40_init(void) { if (MACH_IS_Q40) { dmasound.mach = machQ40; dmasound.mach.default_hard = def_hard ; dmasound.mach.default_soft = def_soft ; return dmasound_init(); } else return -ENODEV; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git2963.04%133.33%
dave jonesdave jones1634.78%133.33%
adrian bunkadrian bunk12.17%133.33%
Total46100.00%3100.00%


static void __exit dmasound_q40_cleanup(void) { dmasound_deinit(); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git12100.00%1100.00%
Total12100.00%1100.00%

module_init(dmasound_q40_init); module_exit(dmasound_q40_cleanup); MODULE_DESCRIPTION("Q40/Q60 sound driver"); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git217376.35%16.25%
dave jonesdave jones50517.74%16.25%
alan coxalan cox481.69%16.25%
peter waechtlerpeter waechtler431.51%16.25%
geert uytterhoevengeert uytterhoeven321.12%425.00%
linus torvaldslinus torvalds230.81%425.00%
al viroal viro110.39%212.50%
andrew mortonandrew morton100.35%16.25%
adrian bunkadrian bunk10.04%16.25%
Total2846100.00%16100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}