Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  *  linux/sound/oss/dmasound/dmasound_q40.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  *  Q40 DMA Sound Driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  *  See linux/sound/oss/dmasound/dmasound_core.c for copyright and credits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  *  prior to 28/01/2001
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  *  28/01/2001 [0.1] Iain Sandoe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  *		     - added versioning
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12)  *		     - put in and populated the hardware_afmts field.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13)  *             [0.2] - put in SNDCTL_DSP_GETCAPS value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14)  *	       [0.3] - put in default hard/soft settings.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) #include <linux/soundcard.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) #include <asm/q40ints.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) #include <asm/q40_master.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) #include "dmasound.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) #define DMASOUND_Q40_REVISION 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) #define DMASOUND_Q40_EDITION 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) static int expand_bal;	/* Balance factor for expanding (not volume!) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) static int expand_data;	/* Data for expanding */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) /*** Low level stuff *********************************************************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) static void *Q40Alloc(unsigned int size, gfp_t flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) static void Q40Free(void *, unsigned int);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) static int Q40IrqInit(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) #ifdef MODULE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) static void Q40IrqCleanUp(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) static void Q40Silence(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) static void Q40Init(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) static int Q40SetFormat(int format);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) static int Q40SetVolume(int volume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) static void Q40PlayNextFrame(int index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) static void Q40Play(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) static irqreturn_t Q40StereoInterrupt(int irq, void *dummy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) static irqreturn_t Q40MonoInterrupt(int irq, void *dummy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) static void Q40Interrupt(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) /*** Mid level stuff *********************************************************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) /* userCount, frameUsed, frameLeft == byte counts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) static ssize_t q40_ct_law(const u_char __user *userPtr, size_t userCount,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 			   u_char frame[], ssize_t *frameUsed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 			   ssize_t frameLeft)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 	char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8: dmasound_alaw2dma8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 	ssize_t count, used;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 	u_char *p = (u_char *) &frame[*frameUsed];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 	used = count = min_t(size_t, userCount, frameLeft);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 	if (copy_from_user(p,userPtr,count))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 	  return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	while (count > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 		*p = table[*p]+128;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 		p++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 		count--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 	*frameUsed += used ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 	return used;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) static ssize_t q40_ct_s8(const u_char __user *userPtr, size_t userCount,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 			  u_char frame[], ssize_t *frameUsed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 			  ssize_t frameLeft)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 	ssize_t count, used;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 	u_char *p = (u_char *) &frame[*frameUsed];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 	used = count = min_t(size_t, userCount, frameLeft);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 	if (copy_from_user(p,userPtr,count))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 	  return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 	while (count > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 		*p = *p + 128;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 		p++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 		count--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 	*frameUsed += used;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 	return used;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) static ssize_t q40_ct_u8(const u_char __user *userPtr, size_t userCount,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 			  u_char frame[], ssize_t *frameUsed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 			  ssize_t frameLeft)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 	ssize_t count, used;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 	u_char *p = (u_char *) &frame[*frameUsed];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 	used = count = min_t(size_t, userCount, frameLeft);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 	if (copy_from_user(p,userPtr,count))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	  return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 	*frameUsed += used;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 	return used;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) /* a bit too complicated to optimise right now ..*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) static ssize_t q40_ctx_law(const u_char __user *userPtr, size_t userCount,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 			    u_char frame[], ssize_t *frameUsed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 			    ssize_t frameLeft)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 	unsigned char *table = (unsigned char *)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 		(dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8: dmasound_alaw2dma8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 	unsigned int data = expand_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 	u_char *p = (u_char *) &frame[*frameUsed];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 	int bal = expand_bal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 	int utotal, ftotal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	ftotal = frameLeft;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 	utotal = userCount;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 	while (frameLeft) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 		u_char c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 		if (bal < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 			if (userCount == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 				break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 			if (get_user(c, userPtr++))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 				return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 			data = table[c];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 			data += 0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 			userCount--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 			bal += hSpeed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 		*p++ = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 		frameLeft--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 		bal -= sSpeed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 	expand_bal = bal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	expand_data = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 	*frameUsed += (ftotal - frameLeft);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 	utotal -= userCount;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 	return utotal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) static ssize_t q40_ctx_s8(const u_char __user *userPtr, size_t userCount,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 			   u_char frame[], ssize_t *frameUsed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 			   ssize_t frameLeft)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 	u_char *p = (u_char *) &frame[*frameUsed];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 	unsigned int data = expand_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 	int bal = expand_bal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 	int utotal, ftotal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	ftotal = frameLeft;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 	utotal = userCount;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 	while (frameLeft) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 		u_char c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 		if (bal < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 			if (userCount == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 				break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 			if (get_user(c, userPtr++))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 				return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 			data = c ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 			data += 0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 			userCount--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 			bal += hSpeed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 		*p++ = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 		frameLeft--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 		bal -= sSpeed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 	expand_bal = bal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 	expand_data = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 	*frameUsed += (ftotal - frameLeft);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 	utotal -= userCount;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 	return utotal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) static ssize_t q40_ctx_u8(const u_char __user *userPtr, size_t userCount,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 			   u_char frame[], ssize_t *frameUsed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 			   ssize_t frameLeft)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 	u_char *p = (u_char *) &frame[*frameUsed];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 	unsigned int data = expand_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 	int bal = expand_bal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 	int utotal, ftotal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 	ftotal = frameLeft;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 	utotal = userCount;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 	while (frameLeft) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 		u_char c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 		if (bal < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 			if (userCount == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 				break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 			if (get_user(c, userPtr++))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 				return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 			data = c ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 			userCount--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 			bal += hSpeed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 		*p++ = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 		frameLeft--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 		bal -= sSpeed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 	expand_bal = bal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 	expand_data = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 	*frameUsed += (ftotal - frameLeft) ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 	utotal -= userCount;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 	return utotal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) /* compressing versions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) static ssize_t q40_ctc_law(const u_char __user *userPtr, size_t userCount,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 			    u_char frame[], ssize_t *frameUsed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 			    ssize_t frameLeft)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 	unsigned char *table = (unsigned char *)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 		(dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8: dmasound_alaw2dma8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 	unsigned int data = expand_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 	u_char *p = (u_char *) &frame[*frameUsed];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 	int bal = expand_bal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 	int utotal, ftotal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)  
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 	ftotal = frameLeft;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 	utotal = userCount;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 	while (frameLeft) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 		u_char c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 		while(bal<0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 			if (userCount == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 				goto lout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 			if (!(bal<(-hSpeed))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 				if (get_user(c, userPtr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 					return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 				data = 0x80 + table[c];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 			userPtr++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 			userCount--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 			bal += hSpeed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 		*p++ = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 		frameLeft--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 		bal -= sSpeed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)  lout:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 	expand_bal = bal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 	expand_data = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 	*frameUsed += (ftotal - frameLeft);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 	utotal -= userCount;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 	return utotal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) static ssize_t q40_ctc_s8(const u_char __user *userPtr, size_t userCount,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 			   u_char frame[], ssize_t *frameUsed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 			   ssize_t frameLeft)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 	u_char *p = (u_char *) &frame[*frameUsed];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 	unsigned int data = expand_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 	int bal = expand_bal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 	int utotal, ftotal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 	ftotal = frameLeft;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 	utotal = userCount;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 	while (frameLeft) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 		u_char c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 		while (bal < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 			if (userCount == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 				goto lout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 			if (!(bal<(-hSpeed))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 				if (get_user(c, userPtr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 					return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 				data = c + 0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 			userPtr++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 			userCount--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 			bal += hSpeed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 		*p++ = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 		frameLeft--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 		bal -= sSpeed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)  lout:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 	expand_bal = bal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 	expand_data = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 	*frameUsed += (ftotal - frameLeft);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 	utotal -= userCount;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 	return utotal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) static ssize_t q40_ctc_u8(const u_char __user *userPtr, size_t userCount,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 			   u_char frame[], ssize_t *frameUsed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 			   ssize_t frameLeft)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 	u_char *p = (u_char *) &frame[*frameUsed];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 	unsigned int data = expand_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 	int bal = expand_bal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 	int utotal, ftotal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 	ftotal = frameLeft;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 	utotal = userCount;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 	while (frameLeft) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 		u_char c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) 		while (bal < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 			if (userCount == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 				goto lout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 			if (!(bal<(-hSpeed))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 				if (get_user(c, userPtr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 					return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 				data = c ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 			userPtr++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 			userCount--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 			bal += hSpeed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 		*p++ = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 		frameLeft--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 		bal -= sSpeed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)  lout:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 	expand_bal = bal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 	expand_data = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) 	*frameUsed += (ftotal - frameLeft) ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) 	utotal -= userCount;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) 	return utotal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) static TRANS transQ40Normal = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 	q40_ct_law, q40_ct_law, q40_ct_s8, q40_ct_u8, NULL, NULL, NULL, NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) static TRANS transQ40Expanding = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 	q40_ctx_law, q40_ctx_law, q40_ctx_s8, q40_ctx_u8, NULL, NULL, NULL, NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) static TRANS transQ40Compressing = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 	q40_ctc_law, q40_ctc_law, q40_ctc_s8, q40_ctc_u8, NULL, NULL, NULL, NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) /*** Low level stuff *********************************************************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) static void *Q40Alloc(unsigned int size, gfp_t flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)          return kmalloc(size, flags); /* change to vmalloc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) static void Q40Free(void *ptr, unsigned int size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) 	kfree(ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) static int __init Q40IrqInit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 	/* Register interrupt handler. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) 	if (request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 		    "DMA sound", Q40Interrupt))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 	return(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) #ifdef MODULE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) static void Q40IrqCleanUp(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)         master_outb(0,SAMPLE_ENABLE_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 	free_irq(Q40_IRQ_SAMPLE, Q40Interrupt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) #endif /* MODULE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) static void Q40Silence(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)         master_outb(0,SAMPLE_ENABLE_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) 	*DAC_LEFT=*DAC_RIGHT=127;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) static char *q40_pp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) static unsigned int q40_sc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) static void Q40PlayNextFrame(int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) 	u_char *start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) 	u_long size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) 	u_char speed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) 	int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) 	/* used by Q40Play() if all doubts whether there really is something
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 	 * to be played are already wiped out.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) 	start = write_sq.buffers[write_sq.front];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) 	size = (write_sq.count == index ? write_sq.rear_size : write_sq.block_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) 	q40_pp=start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 	q40_sc=size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) 	write_sq.front = (write_sq.front+1) % write_sq.max_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 	write_sq.active++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) 	speed=(dmasound.hard.speed==10000 ? 0 : 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) 	master_outb( 0,SAMPLE_ENABLE_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) 	free_irq(Q40_IRQ_SAMPLE, Q40Interrupt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) 	if (dmasound.soft.stereo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) 		error = request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) 				    "Q40 sound", Q40Interrupt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) 	  else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) 		error = request_irq(Q40_IRQ_SAMPLE, Q40MonoInterrupt, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) 				    "Q40 sound", Q40Interrupt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) 	if (error && printk_ratelimit())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) 		pr_err("Couldn't register sound interrupt\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) 	master_outb( speed, SAMPLE_RATE_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) 	master_outb( 1,SAMPLE_CLEAR_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) 	master_outb( 1,SAMPLE_ENABLE_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) static void Q40Play(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)         unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) 	if (write_sq.active || write_sq.count<=0 ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) 		/* There's already a frame loaded */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) 	/* nothing in the queue */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) 	if (write_sq.count <= 1 && write_sq.rear_size < write_sq.block_size && !write_sq.syncing) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) 	         /* hmmm, the only existing frame is not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) 		  * yet filled and we're not syncing?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) 		  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) 	         return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) 	spin_lock_irqsave(&dmasound.lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) 	Q40PlayNextFrame(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) 	spin_unlock_irqrestore(&dmasound.lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) static irqreturn_t Q40StereoInterrupt(int irq, void *dummy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) 	spin_lock(&dmasound.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462)         if (q40_sc>1){
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)             *DAC_LEFT=*q40_pp++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) 	    *DAC_RIGHT=*q40_pp++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) 	    q40_sc -=2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) 	    master_outb(1,SAMPLE_CLEAR_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) 	}else Q40Interrupt();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) 	spin_unlock(&dmasound.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) 	return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) static irqreturn_t Q40MonoInterrupt(int irq, void *dummy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) 	spin_lock(&dmasound.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474)         if (q40_sc>0){
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)             *DAC_LEFT=*q40_pp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) 	    *DAC_RIGHT=*q40_pp++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) 	    q40_sc --;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) 	    master_outb(1,SAMPLE_CLEAR_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) 	}else Q40Interrupt();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) 	spin_unlock(&dmasound.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) 	return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) static void Q40Interrupt(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) 	if (!write_sq.active) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) 	          /* playing was interrupted and sq_reset() has already cleared
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) 		   * the sq variables, so better don't do anything here.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) 		   */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) 	           WAKE_UP(write_sq.sync_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) 		   master_outb(0,SAMPLE_ENABLE_REG); /* better safe */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) 		   goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) 	} else write_sq.active=0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) 	write_sq.count--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) 	Q40Play();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) 	if (q40_sc<2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) 	      { /* there was nothing to play, disable irq */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) 		master_outb(0,SAMPLE_ENABLE_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) 		*DAC_LEFT=*DAC_RIGHT=127;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) 	      }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) 	WAKE_UP(write_sq.action_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503)  exit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) 	master_outb(1,SAMPLE_CLEAR_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) static void Q40Init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) 	int i, idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) 	const int freq[] = {10000, 20000};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) 	/* search a frequency that fits into the allowed error range */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) 	idx = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) 	for (i = 0; i < 2; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) 		if ((100 * abs(dmasound.soft.speed - freq[i]) / freq[i]) <= catchRadius)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) 			idx = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) 	dmasound.hard = dmasound.soft;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) 	/*sound.hard.stereo=1;*/ /* no longer true */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) 	dmasound.hard.size=8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) 	if (idx > -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) 		dmasound.soft.speed = freq[idx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) 		dmasound.trans_write = &transQ40Normal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) 	} else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) 		dmasound.trans_write = &transQ40Expanding;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) 	Q40Silence();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) 	if (dmasound.hard.speed > 20200) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) 		/* squeeze the sound, we do that */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) 		dmasound.hard.speed = 20000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) 		dmasound.trans_write = &transQ40Compressing;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) 	} else if (dmasound.hard.speed > 10000) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) 		dmasound.hard.speed = 20000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) 		dmasound.hard.speed = 10000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) 	expand_bal = -dmasound.soft.speed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) static int Q40SetFormat(int format)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) 	/* Q40 sound supports only 8bit modes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) 	switch (format) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) 	case AFMT_QUERY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) 		return(dmasound.soft.format);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) 	case AFMT_MU_LAW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) 	case AFMT_A_LAW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) 	case AFMT_S8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) 	case AFMT_U8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) 		format = AFMT_S8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) 	dmasound.soft.format = format;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) 	dmasound.soft.size = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) 	if (dmasound.minDev == SND_DEV_DSP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) 		dmasound.dsp.format = format;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) 		dmasound.dsp.size = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) 	Q40Init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) 	return(format);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) static int Q40SetVolume(int volume)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)     return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) /*** Machine definitions *****************************************************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) static SETTINGS def_hard = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) 	.format	= AFMT_U8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) 	.stereo	= 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) 	.size	= 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) 	.speed	= 10000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) } ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) static SETTINGS def_soft = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) 	.format	= AFMT_U8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) 	.stereo	= 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) 	.size	= 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) 	.speed	= 8000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) } ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) static MACHINE machQ40 = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) 	.name		= "Q40",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) 	.name2		= "Q40",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) 	.owner		= THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) 	.dma_alloc	= Q40Alloc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) 	.dma_free	= Q40Free,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) 	.irqinit	= Q40IrqInit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) #ifdef MODULE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) 	.irqcleanup	= Q40IrqCleanUp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) #endif /* MODULE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) 	.init		= Q40Init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) 	.silence	= Q40Silence,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) 	.setFormat	= Q40SetFormat,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) 	.setVolume	= Q40SetVolume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) 	.play		= Q40Play,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609)  	.min_dsp_speed	= 10000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) 	.version	= ((DMASOUND_Q40_REVISION<<8) | DMASOUND_Q40_EDITION),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) 	.hardware_afmts	= AFMT_U8, /* h'ware-supported formats *only* here */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) 	.capabilities	= DSP_CAP_BATCH  /* As per SNDCTL_DSP_GETCAPS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) /*** Config & Setup **********************************************************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) static int __init dmasound_q40_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) 	if (MACH_IS_Q40) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) 	    dmasound.mach = machQ40;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) 	    dmasound.mach.default_hard = def_hard ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) 	    dmasound.mach.default_soft = def_soft ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) 	    return dmasound_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) 	} else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) 	    return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) static void __exit dmasound_q40_cleanup(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) 	dmasound_deinit();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) module_init(dmasound_q40_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) module_exit(dmasound_q40_cleanup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) MODULE_DESCRIPTION("Q40/Q60 sound driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) MODULE_LICENSE("GPL");