^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");