| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  *  linux/sound/oss/dmasound/dmasound_atari.c | 
 | 3 |  * | 
 | 4 |  *  Atari TT and Falcon DMA Sound Driver | 
 | 5 |  * | 
 | 6 |  *  See linux/sound/oss/dmasound/dmasound_core.c for copyright and credits | 
 | 7 |  *  prior to 28/01/2001 | 
 | 8 |  * | 
 | 9 |  *  28/01/2001 [0.1] Iain Sandoe | 
 | 10 |  *		     - added versioning | 
 | 11 |  *		     - put in and populated the hardware_afmts field. | 
 | 12 |  *             [0.2] - put in SNDCTL_DSP_GETCAPS value. | 
 | 13 |  *  01/02/2001 [0.3] - put in default hard/soft settings. | 
 | 14 |  */ | 
 | 15 |  | 
 | 16 |  | 
 | 17 | #include <linux/module.h> | 
 | 18 | #include <linux/kernel.h> | 
 | 19 | #include <linux/init.h> | 
 | 20 | #include <linux/soundcard.h> | 
 | 21 | #include <linux/mm.h> | 
 | 22 | #include <linux/spinlock.h> | 
 | 23 | #include <linux/interrupt.h> | 
 | 24 |  | 
 | 25 | #include <asm/uaccess.h> | 
 | 26 | #include <asm/atariints.h> | 
 | 27 | #include <asm/atari_stram.h> | 
 | 28 |  | 
 | 29 | #include "dmasound.h" | 
 | 30 |  | 
 | 31 | #define DMASOUND_ATARI_REVISION 0 | 
 | 32 | #define DMASOUND_ATARI_EDITION 3 | 
 | 33 |  | 
 | 34 | extern void atari_microwire_cmd(int cmd); | 
 | 35 |  | 
 | 36 | static int is_falcon; | 
 | 37 | static int write_sq_ignore_int;	/* ++TeSche: used for Falcon */ | 
 | 38 |  | 
 | 39 | static int expand_bal;	/* Balance factor for expanding (not volume!) */ | 
 | 40 | static int expand_data;	/* Data for expanding */ | 
 | 41 |  | 
 | 42 |  | 
 | 43 | /*** Translations ************************************************************/ | 
 | 44 |  | 
 | 45 |  | 
 | 46 | /* ++TeSche: radically changed for new expanding purposes... | 
 | 47 |  * | 
 | 48 |  * These two routines now deal with copying/expanding/translating the samples | 
 | 49 |  * from user space into our buffer at the right frequency. They take care about | 
 | 50 |  * how much data there's actually to read, how much buffer space there is and | 
 | 51 |  * to convert samples into the right frequency/encoding. They will only work on | 
 | 52 |  * complete samples so it may happen they leave some bytes in the input stream | 
 | 53 |  * if the user didn't write a multiple of the current sample size. They both | 
 | 54 |  * return the number of bytes they've used from both streams so you may detect | 
 | 55 |  * such a situation. Luckily all programs should be able to cope with that. | 
 | 56 |  * | 
 | 57 |  * I think I've optimized anything as far as one can do in plain C, all | 
 | 58 |  * variables should fit in registers and the loops are really short. There's | 
 | 59 |  * one loop for every possible situation. Writing a more generalized and thus | 
 | 60 |  * parameterized loop would only produce slower code. Feel free to optimize | 
 | 61 |  * this in assembler if you like. :) | 
 | 62 |  * | 
 | 63 |  * I think these routines belong here because they're not yet really hardware | 
 | 64 |  * independent, especially the fact that the Falcon can play 16bit samples | 
 | 65 |  * only in stereo is hardcoded in both of them! | 
 | 66 |  * | 
 | 67 |  * ++geert: split in even more functions (one per format) | 
 | 68 |  */ | 
 | 69 |  | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 70 | static ssize_t ata_ct_law(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 71 | 			  u_char frame[], ssize_t *frameUsed, | 
 | 72 | 			  ssize_t frameLeft); | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 73 | static ssize_t ata_ct_s8(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 74 | 			 u_char frame[], ssize_t *frameUsed, | 
 | 75 | 			 ssize_t frameLeft); | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 76 | static ssize_t ata_ct_u8(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 77 | 			 u_char frame[], ssize_t *frameUsed, | 
 | 78 | 			 ssize_t frameLeft); | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 79 | static ssize_t ata_ct_s16be(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 80 | 			    u_char frame[], ssize_t *frameUsed, | 
 | 81 | 			    ssize_t frameLeft); | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 82 | static ssize_t ata_ct_u16be(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 83 | 			    u_char frame[], ssize_t *frameUsed, | 
 | 84 | 			    ssize_t frameLeft); | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 85 | static ssize_t ata_ct_s16le(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 86 | 			    u_char frame[], ssize_t *frameUsed, | 
 | 87 | 			    ssize_t frameLeft); | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 88 | static ssize_t ata_ct_u16le(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 89 | 			    u_char frame[], ssize_t *frameUsed, | 
 | 90 | 			    ssize_t frameLeft); | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 91 | static ssize_t ata_ctx_law(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 92 | 			   u_char frame[], ssize_t *frameUsed, | 
 | 93 | 			   ssize_t frameLeft); | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 94 | static ssize_t ata_ctx_s8(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 95 | 			  u_char frame[], ssize_t *frameUsed, | 
 | 96 | 			  ssize_t frameLeft); | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 97 | static ssize_t ata_ctx_u8(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 98 | 			  u_char frame[], ssize_t *frameUsed, | 
 | 99 | 			  ssize_t frameLeft); | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 100 | static ssize_t ata_ctx_s16be(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 101 | 			     u_char frame[], ssize_t *frameUsed, | 
 | 102 | 			     ssize_t frameLeft); | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 103 | static ssize_t ata_ctx_u16be(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 104 | 			     u_char frame[], ssize_t *frameUsed, | 
 | 105 | 			     ssize_t frameLeft); | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 106 | static ssize_t ata_ctx_s16le(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 107 | 			     u_char frame[], ssize_t *frameUsed, | 
 | 108 | 			     ssize_t frameLeft); | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 109 | static ssize_t ata_ctx_u16le(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 110 | 			     u_char frame[], ssize_t *frameUsed, | 
 | 111 | 			     ssize_t frameLeft); | 
 | 112 |  | 
 | 113 |  | 
 | 114 | /*** Low level stuff *********************************************************/ | 
 | 115 |  | 
 | 116 |  | 
| Al Viro | 1ef64e6 | 2005-10-21 03:22:18 -0400 | [diff] [blame] | 117 | static void *AtaAlloc(unsigned int size, gfp_t flags); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 118 | static void AtaFree(void *, unsigned int size); | 
 | 119 | static int AtaIrqInit(void); | 
 | 120 | #ifdef MODULE | 
 | 121 | static void AtaIrqCleanUp(void); | 
 | 122 | #endif /* MODULE */ | 
 | 123 | static int AtaSetBass(int bass); | 
 | 124 | static int AtaSetTreble(int treble); | 
 | 125 | static void TTSilence(void); | 
 | 126 | static void TTInit(void); | 
 | 127 | static int TTSetFormat(int format); | 
 | 128 | static int TTSetVolume(int volume); | 
 | 129 | static int TTSetGain(int gain); | 
 | 130 | static void FalconSilence(void); | 
 | 131 | static void FalconInit(void); | 
 | 132 | static int FalconSetFormat(int format); | 
 | 133 | static int FalconSetVolume(int volume); | 
 | 134 | static void AtaPlayNextFrame(int index); | 
 | 135 | static void AtaPlay(void); | 
| David Howells | 7d12e78 | 2006-10-05 14:55:46 +0100 | [diff] [blame] | 136 | static irqreturn_t AtaInterrupt(int irq, void *dummy); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 137 |  | 
 | 138 | /*** Mid level stuff *********************************************************/ | 
 | 139 |  | 
 | 140 | static void TTMixerInit(void); | 
 | 141 | static void FalconMixerInit(void); | 
 | 142 | static int AtaMixerIoctl(u_int cmd, u_long arg); | 
 | 143 | static int TTMixerIoctl(u_int cmd, u_long arg); | 
 | 144 | static int FalconMixerIoctl(u_int cmd, u_long arg); | 
 | 145 | static int AtaWriteSqSetup(void); | 
| Al Viro | aeb5d72 | 2008-09-02 15:28:45 -0400 | [diff] [blame] | 146 | static int AtaSqOpen(fmode_t mode); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 147 | static int TTStateInfo(char *buffer, size_t space); | 
 | 148 | static int FalconStateInfo(char *buffer, size_t space); | 
 | 149 |  | 
 | 150 |  | 
 | 151 | /*** Translations ************************************************************/ | 
 | 152 |  | 
 | 153 |  | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 154 | static ssize_t ata_ct_law(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 155 | 			  u_char frame[], ssize_t *frameUsed, | 
 | 156 | 			  ssize_t frameLeft) | 
 | 157 | { | 
 | 158 | 	char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8 | 
 | 159 | 							  : dmasound_alaw2dma8; | 
 | 160 | 	ssize_t count, used; | 
 | 161 | 	u_char *p = &frame[*frameUsed]; | 
 | 162 |  | 
 | 163 | 	count = min_t(unsigned long, userCount, frameLeft); | 
 | 164 | 	if (dmasound.soft.stereo) | 
 | 165 | 		count &= ~1; | 
 | 166 | 	used = count; | 
 | 167 | 	while (count > 0) { | 
 | 168 | 		u_char data; | 
 | 169 | 		if (get_user(data, userPtr++)) | 
 | 170 | 			return -EFAULT; | 
 | 171 | 		*p++ = table[data]; | 
 | 172 | 		count--; | 
 | 173 | 	} | 
 | 174 | 	*frameUsed += used; | 
 | 175 | 	return used; | 
 | 176 | } | 
 | 177 |  | 
 | 178 |  | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 179 | static ssize_t ata_ct_s8(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 180 | 			 u_char frame[], ssize_t *frameUsed, | 
 | 181 | 			 ssize_t frameLeft) | 
 | 182 | { | 
 | 183 | 	ssize_t count, used; | 
 | 184 | 	void *p = &frame[*frameUsed]; | 
 | 185 |  | 
 | 186 | 	count = min_t(unsigned long, userCount, frameLeft); | 
 | 187 | 	if (dmasound.soft.stereo) | 
 | 188 | 		count &= ~1; | 
 | 189 | 	used = count; | 
 | 190 | 	if (copy_from_user(p, userPtr, count)) | 
 | 191 | 		return -EFAULT; | 
 | 192 | 	*frameUsed += used; | 
 | 193 | 	return used; | 
 | 194 | } | 
 | 195 |  | 
 | 196 |  | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 197 | static ssize_t ata_ct_u8(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 198 | 			 u_char frame[], ssize_t *frameUsed, | 
 | 199 | 			 ssize_t frameLeft) | 
 | 200 | { | 
 | 201 | 	ssize_t count, used; | 
 | 202 |  | 
 | 203 | 	if (!dmasound.soft.stereo) { | 
 | 204 | 		u_char *p = &frame[*frameUsed]; | 
 | 205 | 		count = min_t(unsigned long, userCount, frameLeft); | 
 | 206 | 		used = count; | 
 | 207 | 		while (count > 0) { | 
 | 208 | 			u_char data; | 
 | 209 | 			if (get_user(data, userPtr++)) | 
 | 210 | 				return -EFAULT; | 
 | 211 | 			*p++ = data ^ 0x80; | 
 | 212 | 			count--; | 
 | 213 | 		} | 
 | 214 | 	} else { | 
 | 215 | 		u_short *p = (u_short *)&frame[*frameUsed]; | 
 | 216 | 		count = min_t(unsigned long, userCount, frameLeft)>>1; | 
 | 217 | 		used = count*2; | 
 | 218 | 		while (count > 0) { | 
 | 219 | 			u_short data; | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 220 | 			if (get_user(data, (u_short __user *)userPtr)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 221 | 				return -EFAULT; | 
| Al Viro | 3756513 | 2006-01-12 01:06:22 -0800 | [diff] [blame] | 222 | 			userPtr += 2; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 223 | 			*p++ = data ^ 0x8080; | 
 | 224 | 			count--; | 
 | 225 | 		} | 
 | 226 | 	} | 
 | 227 | 	*frameUsed += used; | 
 | 228 | 	return used; | 
 | 229 | } | 
 | 230 |  | 
 | 231 |  | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 232 | static ssize_t ata_ct_s16be(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 233 | 			    u_char frame[], ssize_t *frameUsed, | 
 | 234 | 			    ssize_t frameLeft) | 
 | 235 | { | 
 | 236 | 	ssize_t count, used; | 
 | 237 |  | 
 | 238 | 	if (!dmasound.soft.stereo) { | 
 | 239 | 		u_short *p = (u_short *)&frame[*frameUsed]; | 
 | 240 | 		count = min_t(unsigned long, userCount, frameLeft)>>1; | 
 | 241 | 		used = count*2; | 
 | 242 | 		while (count > 0) { | 
 | 243 | 			u_short data; | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 244 | 			if (get_user(data, (u_short __user *)userPtr)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 245 | 				return -EFAULT; | 
| Al Viro | 3756513 | 2006-01-12 01:06:22 -0800 | [diff] [blame] | 246 | 			userPtr += 2; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 247 | 			*p++ = data; | 
 | 248 | 			*p++ = data; | 
 | 249 | 			count--; | 
 | 250 | 		} | 
 | 251 | 		*frameUsed += used*2; | 
 | 252 | 	} else { | 
 | 253 | 		void *p = (u_short *)&frame[*frameUsed]; | 
 | 254 | 		count = min_t(unsigned long, userCount, frameLeft) & ~3; | 
 | 255 | 		used = count; | 
 | 256 | 		if (copy_from_user(p, userPtr, count)) | 
 | 257 | 			return -EFAULT; | 
 | 258 | 		*frameUsed += used; | 
 | 259 | 	} | 
 | 260 | 	return used; | 
 | 261 | } | 
 | 262 |  | 
 | 263 |  | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 264 | static ssize_t ata_ct_u16be(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 265 | 			    u_char frame[], ssize_t *frameUsed, | 
 | 266 | 			    ssize_t frameLeft) | 
 | 267 | { | 
 | 268 | 	ssize_t count, used; | 
 | 269 |  | 
 | 270 | 	if (!dmasound.soft.stereo) { | 
 | 271 | 		u_short *p = (u_short *)&frame[*frameUsed]; | 
 | 272 | 		count = min_t(unsigned long, userCount, frameLeft)>>1; | 
 | 273 | 		used = count*2; | 
 | 274 | 		while (count > 0) { | 
 | 275 | 			u_short data; | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 276 | 			if (get_user(data, (u_short __user *)userPtr)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 277 | 				return -EFAULT; | 
| Al Viro | 3756513 | 2006-01-12 01:06:22 -0800 | [diff] [blame] | 278 | 			userPtr += 2; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 279 | 			data ^= 0x8000; | 
 | 280 | 			*p++ = data; | 
 | 281 | 			*p++ = data; | 
 | 282 | 			count--; | 
 | 283 | 		} | 
 | 284 | 		*frameUsed += used*2; | 
 | 285 | 	} else { | 
 | 286 | 		u_long *p = (u_long *)&frame[*frameUsed]; | 
 | 287 | 		count = min_t(unsigned long, userCount, frameLeft)>>2; | 
 | 288 | 		used = count*4; | 
 | 289 | 		while (count > 0) { | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 290 | 			u_int data; | 
 | 291 | 			if (get_user(data, (u_int __user *)userPtr)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 292 | 				return -EFAULT; | 
| Al Viro | 3756513 | 2006-01-12 01:06:22 -0800 | [diff] [blame] | 293 | 			userPtr += 4; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 294 | 			*p++ = data ^ 0x80008000; | 
 | 295 | 			count--; | 
 | 296 | 		} | 
 | 297 | 		*frameUsed += used; | 
 | 298 | 	} | 
 | 299 | 	return used; | 
 | 300 | } | 
 | 301 |  | 
 | 302 |  | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 303 | static ssize_t ata_ct_s16le(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 304 | 			    u_char frame[], ssize_t *frameUsed, | 
 | 305 | 			    ssize_t frameLeft) | 
 | 306 | { | 
 | 307 | 	ssize_t count, used; | 
 | 308 |  | 
 | 309 | 	count = frameLeft; | 
 | 310 | 	if (!dmasound.soft.stereo) { | 
 | 311 | 		u_short *p = (u_short *)&frame[*frameUsed]; | 
 | 312 | 		count = min_t(unsigned long, userCount, frameLeft)>>1; | 
 | 313 | 		used = count*2; | 
 | 314 | 		while (count > 0) { | 
 | 315 | 			u_short data; | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 316 | 			if (get_user(data, (u_short __user *)userPtr)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 317 | 				return -EFAULT; | 
| Al Viro | 3756513 | 2006-01-12 01:06:22 -0800 | [diff] [blame] | 318 | 			userPtr += 2; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 319 | 			data = le2be16(data); | 
 | 320 | 			*p++ = data; | 
 | 321 | 			*p++ = data; | 
 | 322 | 			count--; | 
 | 323 | 		} | 
 | 324 | 		*frameUsed += used*2; | 
 | 325 | 	} else { | 
 | 326 | 		u_long *p = (u_long *)&frame[*frameUsed]; | 
 | 327 | 		count = min_t(unsigned long, userCount, frameLeft)>>2; | 
 | 328 | 		used = count*4; | 
 | 329 | 		while (count > 0) { | 
 | 330 | 			u_long data; | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 331 | 			if (get_user(data, (u_int __user *)userPtr)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 332 | 				return -EFAULT; | 
| Al Viro | 3756513 | 2006-01-12 01:06:22 -0800 | [diff] [blame] | 333 | 			userPtr += 4; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 334 | 			data = le2be16dbl(data); | 
 | 335 | 			*p++ = data; | 
 | 336 | 			count--; | 
 | 337 | 		} | 
 | 338 | 		*frameUsed += used; | 
 | 339 | 	} | 
 | 340 | 	return used; | 
 | 341 | } | 
 | 342 |  | 
 | 343 |  | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 344 | static ssize_t ata_ct_u16le(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 345 | 			    u_char frame[], ssize_t *frameUsed, | 
 | 346 | 			    ssize_t frameLeft) | 
 | 347 | { | 
 | 348 | 	ssize_t count, used; | 
 | 349 |  | 
 | 350 | 	count = frameLeft; | 
 | 351 | 	if (!dmasound.soft.stereo) { | 
 | 352 | 		u_short *p = (u_short *)&frame[*frameUsed]; | 
 | 353 | 		count = min_t(unsigned long, userCount, frameLeft)>>1; | 
 | 354 | 		used = count*2; | 
 | 355 | 		while (count > 0) { | 
 | 356 | 			u_short data; | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 357 | 			if (get_user(data, (u_short __user *)userPtr)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 358 | 				return -EFAULT; | 
| Al Viro | 3756513 | 2006-01-12 01:06:22 -0800 | [diff] [blame] | 359 | 			userPtr += 2; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 360 | 			data = le2be16(data) ^ 0x8000; | 
 | 361 | 			*p++ = data; | 
 | 362 | 			*p++ = data; | 
 | 363 | 		} | 
 | 364 | 		*frameUsed += used*2; | 
 | 365 | 	} else { | 
 | 366 | 		u_long *p = (u_long *)&frame[*frameUsed]; | 
 | 367 | 		count = min_t(unsigned long, userCount, frameLeft)>>2; | 
 | 368 | 		used = count; | 
 | 369 | 		while (count > 0) { | 
 | 370 | 			u_long data; | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 371 | 			if (get_user(data, (u_int __user *)userPtr)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 372 | 				return -EFAULT; | 
| Al Viro | 3756513 | 2006-01-12 01:06:22 -0800 | [diff] [blame] | 373 | 			userPtr += 4; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 374 | 			data = le2be16dbl(data) ^ 0x80008000; | 
 | 375 | 			*p++ = data; | 
 | 376 | 			count--; | 
 | 377 | 		} | 
 | 378 | 		*frameUsed += used; | 
 | 379 | 	} | 
 | 380 | 	return used; | 
 | 381 | } | 
 | 382 |  | 
 | 383 |  | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 384 | static ssize_t ata_ctx_law(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 385 | 			   u_char frame[], ssize_t *frameUsed, | 
 | 386 | 			   ssize_t frameLeft) | 
 | 387 | { | 
 | 388 | 	char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8 | 
 | 389 | 							  : dmasound_alaw2dma8; | 
 | 390 | 	/* this should help gcc to stuff everything into registers */ | 
 | 391 | 	long bal = expand_bal; | 
 | 392 | 	long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; | 
 | 393 | 	ssize_t used, usedf; | 
 | 394 |  | 
 | 395 | 	used = userCount; | 
 | 396 | 	usedf = frameLeft; | 
 | 397 | 	if (!dmasound.soft.stereo) { | 
 | 398 | 		u_char *p = &frame[*frameUsed]; | 
 | 399 | 		u_char data = expand_data; | 
 | 400 | 		while (frameLeft) { | 
 | 401 | 			u_char c; | 
 | 402 | 			if (bal < 0) { | 
 | 403 | 				if (!userCount) | 
 | 404 | 					break; | 
 | 405 | 				if (get_user(c, userPtr++)) | 
 | 406 | 					return -EFAULT; | 
 | 407 | 				data = table[c]; | 
 | 408 | 				userCount--; | 
 | 409 | 				bal += hSpeed; | 
 | 410 | 			} | 
 | 411 | 			*p++ = data; | 
 | 412 | 			frameLeft--; | 
 | 413 | 			bal -= sSpeed; | 
 | 414 | 		} | 
 | 415 | 		expand_data = data; | 
 | 416 | 	} else { | 
 | 417 | 		u_short *p = (u_short *)&frame[*frameUsed]; | 
 | 418 | 		u_short data = expand_data; | 
 | 419 | 		while (frameLeft >= 2) { | 
 | 420 | 			u_char c; | 
 | 421 | 			if (bal < 0) { | 
 | 422 | 				if (userCount < 2) | 
 | 423 | 					break; | 
 | 424 | 				if (get_user(c, userPtr++)) | 
 | 425 | 					return -EFAULT; | 
 | 426 | 				data = table[c] << 8; | 
 | 427 | 				if (get_user(c, userPtr++)) | 
 | 428 | 					return -EFAULT; | 
 | 429 | 				data |= table[c]; | 
 | 430 | 				userCount -= 2; | 
 | 431 | 				bal += hSpeed; | 
 | 432 | 			} | 
 | 433 | 			*p++ = data; | 
 | 434 | 			frameLeft -= 2; | 
 | 435 | 			bal -= sSpeed; | 
 | 436 | 		} | 
 | 437 | 		expand_data = data; | 
 | 438 | 	} | 
 | 439 | 	expand_bal = bal; | 
 | 440 | 	used -= userCount; | 
 | 441 | 	*frameUsed += usedf-frameLeft; | 
 | 442 | 	return used; | 
 | 443 | } | 
 | 444 |  | 
 | 445 |  | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 446 | static ssize_t ata_ctx_s8(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 447 | 			  u_char frame[], ssize_t *frameUsed, | 
 | 448 | 			  ssize_t frameLeft) | 
 | 449 | { | 
 | 450 | 	/* this should help gcc to stuff everything into registers */ | 
 | 451 | 	long bal = expand_bal; | 
 | 452 | 	long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; | 
 | 453 | 	ssize_t used, usedf; | 
 | 454 |  | 
 | 455 | 	used = userCount; | 
 | 456 | 	usedf = frameLeft; | 
 | 457 | 	if (!dmasound.soft.stereo) { | 
 | 458 | 		u_char *p = &frame[*frameUsed]; | 
 | 459 | 		u_char data = expand_data; | 
 | 460 | 		while (frameLeft) { | 
 | 461 | 			if (bal < 0) { | 
 | 462 | 				if (!userCount) | 
 | 463 | 					break; | 
 | 464 | 				if (get_user(data, userPtr++)) | 
 | 465 | 					return -EFAULT; | 
 | 466 | 				userCount--; | 
 | 467 | 				bal += hSpeed; | 
 | 468 | 			} | 
 | 469 | 			*p++ = data; | 
 | 470 | 			frameLeft--; | 
 | 471 | 			bal -= sSpeed; | 
 | 472 | 		} | 
 | 473 | 		expand_data = data; | 
 | 474 | 	} else { | 
 | 475 | 		u_short *p = (u_short *)&frame[*frameUsed]; | 
 | 476 | 		u_short data = expand_data; | 
 | 477 | 		while (frameLeft >= 2) { | 
 | 478 | 			if (bal < 0) { | 
 | 479 | 				if (userCount < 2) | 
 | 480 | 					break; | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 481 | 				if (get_user(data, (u_short __user *)userPtr)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 482 | 					return -EFAULT; | 
| Al Viro | 3756513 | 2006-01-12 01:06:22 -0800 | [diff] [blame] | 483 | 				userPtr += 2; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 484 | 				userCount -= 2; | 
 | 485 | 				bal += hSpeed; | 
 | 486 | 			} | 
 | 487 | 			*p++ = data; | 
 | 488 | 			frameLeft -= 2; | 
 | 489 | 			bal -= sSpeed; | 
 | 490 | 		} | 
 | 491 | 		expand_data = data; | 
 | 492 | 	} | 
 | 493 | 	expand_bal = bal; | 
 | 494 | 	used -= userCount; | 
 | 495 | 	*frameUsed += usedf-frameLeft; | 
 | 496 | 	return used; | 
 | 497 | } | 
 | 498 |  | 
 | 499 |  | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 500 | static ssize_t ata_ctx_u8(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 501 | 			  u_char frame[], ssize_t *frameUsed, | 
 | 502 | 			  ssize_t frameLeft) | 
 | 503 | { | 
 | 504 | 	/* this should help gcc to stuff everything into registers */ | 
 | 505 | 	long bal = expand_bal; | 
 | 506 | 	long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; | 
 | 507 | 	ssize_t used, usedf; | 
 | 508 |  | 
 | 509 | 	used = userCount; | 
 | 510 | 	usedf = frameLeft; | 
 | 511 | 	if (!dmasound.soft.stereo) { | 
 | 512 | 		u_char *p = &frame[*frameUsed]; | 
 | 513 | 		u_char data = expand_data; | 
 | 514 | 		while (frameLeft) { | 
 | 515 | 			if (bal < 0) { | 
 | 516 | 				if (!userCount) | 
 | 517 | 					break; | 
 | 518 | 				if (get_user(data, userPtr++)) | 
 | 519 | 					return -EFAULT; | 
 | 520 | 				data ^= 0x80; | 
 | 521 | 				userCount--; | 
 | 522 | 				bal += hSpeed; | 
 | 523 | 			} | 
 | 524 | 			*p++ = data; | 
 | 525 | 			frameLeft--; | 
 | 526 | 			bal -= sSpeed; | 
 | 527 | 		} | 
 | 528 | 		expand_data = data; | 
 | 529 | 	} else { | 
 | 530 | 		u_short *p = (u_short *)&frame[*frameUsed]; | 
 | 531 | 		u_short data = expand_data; | 
 | 532 | 		while (frameLeft >= 2) { | 
 | 533 | 			if (bal < 0) { | 
 | 534 | 				if (userCount < 2) | 
 | 535 | 					break; | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 536 | 				if (get_user(data, (u_short __user *)userPtr)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 537 | 					return -EFAULT; | 
| Al Viro | 3756513 | 2006-01-12 01:06:22 -0800 | [diff] [blame] | 538 | 				userPtr += 2; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 539 | 				data ^= 0x8080; | 
 | 540 | 				userCount -= 2; | 
 | 541 | 				bal += hSpeed; | 
 | 542 | 			} | 
 | 543 | 			*p++ = data; | 
 | 544 | 			frameLeft -= 2; | 
 | 545 | 			bal -= sSpeed; | 
 | 546 | 		} | 
 | 547 | 		expand_data = data; | 
 | 548 | 	} | 
 | 549 | 	expand_bal = bal; | 
 | 550 | 	used -= userCount; | 
 | 551 | 	*frameUsed += usedf-frameLeft; | 
 | 552 | 	return used; | 
 | 553 | } | 
 | 554 |  | 
 | 555 |  | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 556 | static ssize_t ata_ctx_s16be(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 557 | 			     u_char frame[], ssize_t *frameUsed, | 
 | 558 | 			     ssize_t frameLeft) | 
 | 559 | { | 
 | 560 | 	/* this should help gcc to stuff everything into registers */ | 
 | 561 | 	long bal = expand_bal; | 
 | 562 | 	long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; | 
 | 563 | 	ssize_t used, usedf; | 
 | 564 |  | 
 | 565 | 	used = userCount; | 
 | 566 | 	usedf = frameLeft; | 
 | 567 | 	if (!dmasound.soft.stereo) { | 
 | 568 | 		u_short *p = (u_short *)&frame[*frameUsed]; | 
 | 569 | 		u_short data = expand_data; | 
 | 570 | 		while (frameLeft >= 4) { | 
 | 571 | 			if (bal < 0) { | 
 | 572 | 				if (userCount < 2) | 
 | 573 | 					break; | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 574 | 				if (get_user(data, (u_short __user *)userPtr)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 575 | 					return -EFAULT; | 
| Al Viro | 3756513 | 2006-01-12 01:06:22 -0800 | [diff] [blame] | 576 | 				userPtr += 2; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 577 | 				userCount -= 2; | 
 | 578 | 				bal += hSpeed; | 
 | 579 | 			} | 
 | 580 | 			*p++ = data; | 
 | 581 | 			*p++ = data; | 
 | 582 | 			frameLeft -= 4; | 
 | 583 | 			bal -= sSpeed; | 
 | 584 | 		} | 
 | 585 | 		expand_data = data; | 
 | 586 | 	} else { | 
 | 587 | 		u_long *p = (u_long *)&frame[*frameUsed]; | 
 | 588 | 		u_long data = expand_data; | 
 | 589 | 		while (frameLeft >= 4) { | 
 | 590 | 			if (bal < 0) { | 
 | 591 | 				if (userCount < 4) | 
 | 592 | 					break; | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 593 | 				if (get_user(data, (u_int __user *)userPtr)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 594 | 					return -EFAULT; | 
| Al Viro | 3756513 | 2006-01-12 01:06:22 -0800 | [diff] [blame] | 595 | 				userPtr += 4; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 596 | 				userCount -= 4; | 
 | 597 | 				bal += hSpeed; | 
 | 598 | 			} | 
 | 599 | 			*p++ = data; | 
 | 600 | 			frameLeft -= 4; | 
 | 601 | 			bal -= sSpeed; | 
 | 602 | 		} | 
 | 603 | 		expand_data = data; | 
 | 604 | 	} | 
 | 605 | 	expand_bal = bal; | 
 | 606 | 	used -= userCount; | 
 | 607 | 	*frameUsed += usedf-frameLeft; | 
 | 608 | 	return used; | 
 | 609 | } | 
 | 610 |  | 
 | 611 |  | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 612 | static ssize_t ata_ctx_u16be(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 613 | 			     u_char frame[], ssize_t *frameUsed, | 
 | 614 | 			     ssize_t frameLeft) | 
 | 615 | { | 
 | 616 | 	/* this should help gcc to stuff everything into registers */ | 
 | 617 | 	long bal = expand_bal; | 
 | 618 | 	long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; | 
 | 619 | 	ssize_t used, usedf; | 
 | 620 |  | 
 | 621 | 	used = userCount; | 
 | 622 | 	usedf = frameLeft; | 
 | 623 | 	if (!dmasound.soft.stereo) { | 
 | 624 | 		u_short *p = (u_short *)&frame[*frameUsed]; | 
 | 625 | 		u_short data = expand_data; | 
 | 626 | 		while (frameLeft >= 4) { | 
 | 627 | 			if (bal < 0) { | 
 | 628 | 				if (userCount < 2) | 
 | 629 | 					break; | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 630 | 				if (get_user(data, (u_short __user *)userPtr)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 631 | 					return -EFAULT; | 
| Al Viro | 3756513 | 2006-01-12 01:06:22 -0800 | [diff] [blame] | 632 | 				userPtr += 2; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 633 | 				data ^= 0x8000; | 
 | 634 | 				userCount -= 2; | 
 | 635 | 				bal += hSpeed; | 
 | 636 | 			} | 
 | 637 | 			*p++ = data; | 
 | 638 | 			*p++ = data; | 
 | 639 | 			frameLeft -= 4; | 
 | 640 | 			bal -= sSpeed; | 
 | 641 | 		} | 
 | 642 | 		expand_data = data; | 
 | 643 | 	} else { | 
 | 644 | 		u_long *p = (u_long *)&frame[*frameUsed]; | 
 | 645 | 		u_long data = expand_data; | 
 | 646 | 		while (frameLeft >= 4) { | 
 | 647 | 			if (bal < 0) { | 
 | 648 | 				if (userCount < 4) | 
 | 649 | 					break; | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 650 | 				if (get_user(data, (u_int __user *)userPtr)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 651 | 					return -EFAULT; | 
| Al Viro | 3756513 | 2006-01-12 01:06:22 -0800 | [diff] [blame] | 652 | 				userPtr += 4; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 653 | 				data ^= 0x80008000; | 
 | 654 | 				userCount -= 4; | 
 | 655 | 				bal += hSpeed; | 
 | 656 | 			} | 
 | 657 | 			*p++ = data; | 
 | 658 | 			frameLeft -= 4; | 
 | 659 | 			bal -= sSpeed; | 
 | 660 | 		} | 
 | 661 | 		expand_data = data; | 
 | 662 | 	} | 
 | 663 | 	expand_bal = bal; | 
 | 664 | 	used -= userCount; | 
 | 665 | 	*frameUsed += usedf-frameLeft; | 
 | 666 | 	return used; | 
 | 667 | } | 
 | 668 |  | 
 | 669 |  | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 670 | static ssize_t ata_ctx_s16le(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 671 | 			     u_char frame[], ssize_t *frameUsed, | 
 | 672 | 			     ssize_t frameLeft) | 
 | 673 | { | 
 | 674 | 	/* this should help gcc to stuff everything into registers */ | 
 | 675 | 	long bal = expand_bal; | 
 | 676 | 	long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; | 
 | 677 | 	ssize_t used, usedf; | 
 | 678 |  | 
 | 679 | 	used = userCount; | 
 | 680 | 	usedf = frameLeft; | 
 | 681 | 	if (!dmasound.soft.stereo) { | 
 | 682 | 		u_short *p = (u_short *)&frame[*frameUsed]; | 
 | 683 | 		u_short data = expand_data; | 
 | 684 | 		while (frameLeft >= 4) { | 
 | 685 | 			if (bal < 0) { | 
 | 686 | 				if (userCount < 2) | 
 | 687 | 					break; | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 688 | 				if (get_user(data, (u_short __user *)userPtr)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 689 | 					return -EFAULT; | 
| Al Viro | 3756513 | 2006-01-12 01:06:22 -0800 | [diff] [blame] | 690 | 				userPtr += 2; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 691 | 				data = le2be16(data); | 
 | 692 | 				userCount -= 2; | 
 | 693 | 				bal += hSpeed; | 
 | 694 | 			} | 
 | 695 | 			*p++ = data; | 
 | 696 | 			*p++ = data; | 
 | 697 | 			frameLeft -= 4; | 
 | 698 | 			bal -= sSpeed; | 
 | 699 | 		} | 
 | 700 | 		expand_data = data; | 
 | 701 | 	} else { | 
 | 702 | 		u_long *p = (u_long *)&frame[*frameUsed]; | 
 | 703 | 		u_long data = expand_data; | 
 | 704 | 		while (frameLeft >= 4) { | 
 | 705 | 			if (bal < 0) { | 
 | 706 | 				if (userCount < 4) | 
 | 707 | 					break; | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 708 | 				if (get_user(data, (u_int __user *)userPtr)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 709 | 					return -EFAULT; | 
| Al Viro | 3756513 | 2006-01-12 01:06:22 -0800 | [diff] [blame] | 710 | 				userPtr += 4; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 711 | 				data = le2be16dbl(data); | 
 | 712 | 				userCount -= 4; | 
 | 713 | 				bal += hSpeed; | 
 | 714 | 			} | 
 | 715 | 			*p++ = data; | 
 | 716 | 			frameLeft -= 4; | 
 | 717 | 			bal -= sSpeed; | 
 | 718 | 		} | 
 | 719 | 		expand_data = data; | 
 | 720 | 	} | 
 | 721 | 	expand_bal = bal; | 
 | 722 | 	used -= userCount; | 
 | 723 | 	*frameUsed += usedf-frameLeft; | 
 | 724 | 	return used; | 
 | 725 | } | 
 | 726 |  | 
 | 727 |  | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 728 | static ssize_t ata_ctx_u16le(const u_char __user *userPtr, size_t userCount, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 729 | 			     u_char frame[], ssize_t *frameUsed, | 
 | 730 | 			     ssize_t frameLeft) | 
 | 731 | { | 
 | 732 | 	/* this should help gcc to stuff everything into registers */ | 
 | 733 | 	long bal = expand_bal; | 
 | 734 | 	long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; | 
 | 735 | 	ssize_t used, usedf; | 
 | 736 |  | 
 | 737 | 	used = userCount; | 
 | 738 | 	usedf = frameLeft; | 
 | 739 | 	if (!dmasound.soft.stereo) { | 
 | 740 | 		u_short *p = (u_short *)&frame[*frameUsed]; | 
 | 741 | 		u_short data = expand_data; | 
 | 742 | 		while (frameLeft >= 4) { | 
 | 743 | 			if (bal < 0) { | 
 | 744 | 				if (userCount < 2) | 
 | 745 | 					break; | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 746 | 				if (get_user(data, (u_short __user *)userPtr)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 747 | 					return -EFAULT; | 
| Al Viro | 3756513 | 2006-01-12 01:06:22 -0800 | [diff] [blame] | 748 | 				userPtr += 2; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 749 | 				data = le2be16(data) ^ 0x8000; | 
 | 750 | 				userCount -= 2; | 
 | 751 | 				bal += hSpeed; | 
 | 752 | 			} | 
 | 753 | 			*p++ = data; | 
 | 754 | 			*p++ = data; | 
 | 755 | 			frameLeft -= 4; | 
 | 756 | 			bal -= sSpeed; | 
 | 757 | 		} | 
 | 758 | 		expand_data = data; | 
 | 759 | 	} else { | 
 | 760 | 		u_long *p = (u_long *)&frame[*frameUsed]; | 
 | 761 | 		u_long data = expand_data; | 
 | 762 | 		while (frameLeft >= 4) { | 
 | 763 | 			if (bal < 0) { | 
 | 764 | 				if (userCount < 4) | 
 | 765 | 					break; | 
| Al Viro | 031eb4c | 2006-01-12 01:06:33 -0800 | [diff] [blame] | 766 | 				if (get_user(data, (u_int __user *)userPtr)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 767 | 					return -EFAULT; | 
| Al Viro | 3756513 | 2006-01-12 01:06:22 -0800 | [diff] [blame] | 768 | 				userPtr += 4; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 769 | 				data = le2be16dbl(data) ^ 0x80008000; | 
 | 770 | 				userCount -= 4; | 
 | 771 | 				bal += hSpeed; | 
 | 772 | 			} | 
 | 773 | 			*p++ = data; | 
 | 774 | 			frameLeft -= 4; | 
 | 775 | 			bal -= sSpeed; | 
 | 776 | 		} | 
 | 777 | 		expand_data = data; | 
 | 778 | 	} | 
 | 779 | 	expand_bal = bal; | 
 | 780 | 	used -= userCount; | 
 | 781 | 	*frameUsed += usedf-frameLeft; | 
 | 782 | 	return used; | 
 | 783 | } | 
 | 784 |  | 
 | 785 |  | 
 | 786 | static TRANS transTTNormal = { | 
 | 787 | 	.ct_ulaw	= ata_ct_law, | 
 | 788 | 	.ct_alaw	= ata_ct_law, | 
 | 789 | 	.ct_s8		= ata_ct_s8, | 
 | 790 | 	.ct_u8		= ata_ct_u8, | 
 | 791 | }; | 
 | 792 |  | 
 | 793 | static TRANS transTTExpanding = { | 
 | 794 | 	.ct_ulaw	= ata_ctx_law, | 
 | 795 | 	.ct_alaw	= ata_ctx_law, | 
 | 796 | 	.ct_s8		= ata_ctx_s8, | 
 | 797 | 	.ct_u8		= ata_ctx_u8, | 
 | 798 | }; | 
 | 799 |  | 
 | 800 | static TRANS transFalconNormal = { | 
 | 801 | 	.ct_ulaw	= ata_ct_law, | 
 | 802 | 	.ct_alaw	= ata_ct_law, | 
 | 803 | 	.ct_s8		= ata_ct_s8, | 
 | 804 | 	.ct_u8		= ata_ct_u8, | 
 | 805 | 	.ct_s16be	= ata_ct_s16be, | 
 | 806 | 	.ct_u16be	= ata_ct_u16be, | 
 | 807 | 	.ct_s16le	= ata_ct_s16le, | 
 | 808 | 	.ct_u16le	= ata_ct_u16le | 
 | 809 | }; | 
 | 810 |  | 
 | 811 | static TRANS transFalconExpanding = { | 
 | 812 | 	.ct_ulaw	= ata_ctx_law, | 
 | 813 | 	.ct_alaw	= ata_ctx_law, | 
 | 814 | 	.ct_s8		= ata_ctx_s8, | 
 | 815 | 	.ct_u8		= ata_ctx_u8, | 
 | 816 | 	.ct_s16be	= ata_ctx_s16be, | 
 | 817 | 	.ct_u16be	= ata_ctx_u16be, | 
 | 818 | 	.ct_s16le	= ata_ctx_s16le, | 
 | 819 | 	.ct_u16le	= ata_ctx_u16le, | 
 | 820 | }; | 
 | 821 |  | 
 | 822 |  | 
 | 823 | /*** Low level stuff *********************************************************/ | 
 | 824 |  | 
 | 825 |  | 
 | 826 |  | 
 | 827 | /* | 
 | 828 |  * Atari (TT/Falcon) | 
 | 829 |  */ | 
 | 830 |  | 
| Al Viro | 1ef64e6 | 2005-10-21 03:22:18 -0400 | [diff] [blame] | 831 | static void *AtaAlloc(unsigned int size, gfp_t flags) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 832 | { | 
 | 833 | 	return atari_stram_alloc(size, "dmasound"); | 
 | 834 | } | 
 | 835 |  | 
 | 836 | static void AtaFree(void *obj, unsigned int size) | 
 | 837 | { | 
 | 838 | 	atari_stram_free( obj ); | 
 | 839 | } | 
 | 840 |  | 
 | 841 | static int __init AtaIrqInit(void) | 
 | 842 | { | 
 | 843 | 	/* Set up timer A. Timer A | 
 | 844 | 	   will receive a signal upon end of playing from the sound | 
 | 845 | 	   hardware. Furthermore Timer A is able to count events | 
 | 846 | 	   and will cause an interrupt after a programmed number | 
 | 847 | 	   of events. So all we need to keep the music playing is | 
 | 848 | 	   to provide the sound hardware with new data upon | 
 | 849 | 	   an interrupt from timer A. */ | 
| Geert Uytterhoeven | 3d92e8f | 2009-02-22 09:38:47 +0100 | [diff] [blame] | 850 | 	st_mfp.tim_ct_a = 0;	/* ++roman: Stop timer before programming! */ | 
 | 851 | 	st_mfp.tim_dt_a = 1;	/* Cause interrupt after first event. */ | 
 | 852 | 	st_mfp.tim_ct_a = 8;	/* Turn on event counting. */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 853 | 	/* Register interrupt handler. */ | 
| Geert Uytterhoeven | 89bde7b | 2008-12-30 14:25:31 +0100 | [diff] [blame] | 854 | 	if (request_irq(IRQ_MFP_TIMA, AtaInterrupt, IRQ_TYPE_SLOW, "DMA sound", | 
 | 855 | 			AtaInterrupt)) | 
 | 856 | 		return 0; | 
| Geert Uytterhoeven | 3d92e8f | 2009-02-22 09:38:47 +0100 | [diff] [blame] | 857 | 	st_mfp.int_en_a |= 0x20;	/* Turn interrupt on. */ | 
 | 858 | 	st_mfp.int_mk_a |= 0x20; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 859 | 	return 1; | 
 | 860 | } | 
 | 861 |  | 
 | 862 | #ifdef MODULE | 
 | 863 | static void AtaIrqCleanUp(void) | 
 | 864 | { | 
| Geert Uytterhoeven | 3d92e8f | 2009-02-22 09:38:47 +0100 | [diff] [blame] | 865 | 	st_mfp.tim_ct_a = 0;		/* stop timer */ | 
 | 866 | 	st_mfp.int_en_a &= ~0x20;	/* turn interrupt off */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 867 | 	free_irq(IRQ_MFP_TIMA, AtaInterrupt); | 
 | 868 | } | 
 | 869 | #endif /* MODULE */ | 
 | 870 |  | 
 | 871 |  | 
 | 872 | #define TONE_VOXWARE_TO_DB(v) \ | 
 | 873 | 	(((v) < 0) ? -12 : ((v) > 100) ? 12 : ((v) - 50) * 6 / 25) | 
 | 874 | #define TONE_DB_TO_VOXWARE(v) (((v) * 25 + ((v) > 0 ? 5 : -5)) / 6 + 50) | 
 | 875 |  | 
 | 876 |  | 
 | 877 | static int AtaSetBass(int bass) | 
 | 878 | { | 
 | 879 | 	dmasound.bass = TONE_VOXWARE_TO_DB(bass); | 
 | 880 | 	atari_microwire_cmd(MW_LM1992_BASS(dmasound.bass)); | 
 | 881 | 	return TONE_DB_TO_VOXWARE(dmasound.bass); | 
 | 882 | } | 
 | 883 |  | 
 | 884 |  | 
 | 885 | static int AtaSetTreble(int treble) | 
 | 886 | { | 
 | 887 | 	dmasound.treble = TONE_VOXWARE_TO_DB(treble); | 
 | 888 | 	atari_microwire_cmd(MW_LM1992_TREBLE(dmasound.treble)); | 
 | 889 | 	return TONE_DB_TO_VOXWARE(dmasound.treble); | 
 | 890 | } | 
 | 891 |  | 
 | 892 |  | 
 | 893 |  | 
 | 894 | /* | 
 | 895 |  * TT | 
 | 896 |  */ | 
 | 897 |  | 
 | 898 |  | 
 | 899 | static void TTSilence(void) | 
 | 900 | { | 
 | 901 | 	tt_dmasnd.ctrl = DMASND_CTRL_OFF; | 
 | 902 | 	atari_microwire_cmd(MW_LM1992_PSG_HIGH); /* mix in PSG signal 1:1 */ | 
 | 903 | } | 
 | 904 |  | 
 | 905 |  | 
 | 906 | static void TTInit(void) | 
 | 907 | { | 
 | 908 | 	int mode, i, idx; | 
 | 909 | 	const int freq[4] = {50066, 25033, 12517, 6258}; | 
 | 910 |  | 
 | 911 | 	/* search a frequency that fits into the allowed error range */ | 
 | 912 |  | 
 | 913 | 	idx = -1; | 
 | 914 | 	for (i = 0; i < ARRAY_SIZE(freq); i++) | 
 | 915 | 		/* this isn't as much useful for a TT than for a Falcon, but | 
 | 916 | 		 * then it doesn't hurt very much to implement it for a TT too. | 
 | 917 | 		 */ | 
 | 918 | 		if ((100 * abs(dmasound.soft.speed - freq[i]) / freq[i]) < catchRadius) | 
 | 919 | 			idx = i; | 
 | 920 | 	if (idx > -1) { | 
 | 921 | 		dmasound.soft.speed = freq[idx]; | 
 | 922 | 		dmasound.trans_write = &transTTNormal; | 
 | 923 | 	} else | 
 | 924 | 		dmasound.trans_write = &transTTExpanding; | 
 | 925 |  | 
 | 926 | 	TTSilence(); | 
 | 927 | 	dmasound.hard = dmasound.soft; | 
 | 928 |  | 
 | 929 | 	if (dmasound.hard.speed > 50066) { | 
 | 930 | 		/* we would need to squeeze the sound, but we won't do that */ | 
 | 931 | 		dmasound.hard.speed = 50066; | 
 | 932 | 		mode = DMASND_MODE_50KHZ; | 
 | 933 | 		dmasound.trans_write = &transTTNormal; | 
 | 934 | 	} else if (dmasound.hard.speed > 25033) { | 
 | 935 | 		dmasound.hard.speed = 50066; | 
 | 936 | 		mode = DMASND_MODE_50KHZ; | 
 | 937 | 	} else if (dmasound.hard.speed > 12517) { | 
 | 938 | 		dmasound.hard.speed = 25033; | 
 | 939 | 		mode = DMASND_MODE_25KHZ; | 
 | 940 | 	} else if (dmasound.hard.speed > 6258) { | 
 | 941 | 		dmasound.hard.speed = 12517; | 
 | 942 | 		mode = DMASND_MODE_12KHZ; | 
 | 943 | 	} else { | 
 | 944 | 		dmasound.hard.speed = 6258; | 
 | 945 | 		mode = DMASND_MODE_6KHZ; | 
 | 946 | 	} | 
 | 947 |  | 
 | 948 | 	tt_dmasnd.mode = (dmasound.hard.stereo ? | 
 | 949 | 			  DMASND_MODE_STEREO : DMASND_MODE_MONO) | | 
 | 950 | 		DMASND_MODE_8BIT | mode; | 
 | 951 |  | 
 | 952 | 	expand_bal = -dmasound.soft.speed; | 
 | 953 | } | 
 | 954 |  | 
 | 955 |  | 
 | 956 | static int TTSetFormat(int format) | 
 | 957 | { | 
 | 958 | 	/* TT sound DMA supports only 8bit modes */ | 
 | 959 |  | 
 | 960 | 	switch (format) { | 
 | 961 | 	case AFMT_QUERY: | 
 | 962 | 		return dmasound.soft.format; | 
 | 963 | 	case AFMT_MU_LAW: | 
 | 964 | 	case AFMT_A_LAW: | 
 | 965 | 	case AFMT_S8: | 
 | 966 | 	case AFMT_U8: | 
 | 967 | 		break; | 
 | 968 | 	default: | 
 | 969 | 		format = AFMT_S8; | 
 | 970 | 	} | 
 | 971 |  | 
 | 972 | 	dmasound.soft.format = format; | 
 | 973 | 	dmasound.soft.size = 8; | 
 | 974 | 	if (dmasound.minDev == SND_DEV_DSP) { | 
 | 975 | 		dmasound.dsp.format = format; | 
 | 976 | 		dmasound.dsp.size = 8; | 
 | 977 | 	} | 
 | 978 | 	TTInit(); | 
 | 979 |  | 
 | 980 | 	return format; | 
 | 981 | } | 
 | 982 |  | 
 | 983 |  | 
 | 984 | #define VOLUME_VOXWARE_TO_DB(v) \ | 
 | 985 | 	(((v) < 0) ? -40 : ((v) > 100) ? 0 : ((v) * 2) / 5 - 40) | 
 | 986 | #define VOLUME_DB_TO_VOXWARE(v) ((((v) + 40) * 5 + 1) / 2) | 
 | 987 |  | 
 | 988 |  | 
 | 989 | static int TTSetVolume(int volume) | 
 | 990 | { | 
 | 991 | 	dmasound.volume_left = VOLUME_VOXWARE_TO_DB(volume & 0xff); | 
 | 992 | 	atari_microwire_cmd(MW_LM1992_BALLEFT(dmasound.volume_left)); | 
 | 993 | 	dmasound.volume_right = VOLUME_VOXWARE_TO_DB((volume & 0xff00) >> 8); | 
 | 994 | 	atari_microwire_cmd(MW_LM1992_BALRIGHT(dmasound.volume_right)); | 
 | 995 | 	return VOLUME_DB_TO_VOXWARE(dmasound.volume_left) | | 
 | 996 | 	       (VOLUME_DB_TO_VOXWARE(dmasound.volume_right) << 8); | 
 | 997 | } | 
 | 998 |  | 
 | 999 |  | 
 | 1000 | #define GAIN_VOXWARE_TO_DB(v) \ | 
 | 1001 | 	(((v) < 0) ? -80 : ((v) > 100) ? 0 : ((v) * 4) / 5 - 80) | 
 | 1002 | #define GAIN_DB_TO_VOXWARE(v) ((((v) + 80) * 5 + 1) / 4) | 
 | 1003 |  | 
 | 1004 | static int TTSetGain(int gain) | 
 | 1005 | { | 
 | 1006 | 	dmasound.gain = GAIN_VOXWARE_TO_DB(gain); | 
 | 1007 | 	atari_microwire_cmd(MW_LM1992_VOLUME(dmasound.gain)); | 
 | 1008 | 	return GAIN_DB_TO_VOXWARE(dmasound.gain); | 
 | 1009 | } | 
 | 1010 |  | 
 | 1011 |  | 
 | 1012 |  | 
 | 1013 | /* | 
 | 1014 |  * Falcon | 
 | 1015 |  */ | 
 | 1016 |  | 
 | 1017 |  | 
 | 1018 | static void FalconSilence(void) | 
 | 1019 | { | 
 | 1020 | 	/* stop playback, set sample rate 50kHz for PSG sound */ | 
 | 1021 | 	tt_dmasnd.ctrl = DMASND_CTRL_OFF; | 
 | 1022 | 	tt_dmasnd.mode = DMASND_MODE_50KHZ | DMASND_MODE_STEREO | DMASND_MODE_8BIT; | 
 | 1023 | 	tt_dmasnd.int_div = 0; /* STE compatible divider */ | 
 | 1024 | 	tt_dmasnd.int_ctrl = 0x0; | 
 | 1025 | 	tt_dmasnd.cbar_src = 0x0000; /* no matrix inputs */ | 
 | 1026 | 	tt_dmasnd.cbar_dst = 0x0000; /* no matrix outputs */ | 
 | 1027 | 	tt_dmasnd.dac_src = 1; /* connect ADC to DAC, disconnect matrix */ | 
 | 1028 | 	tt_dmasnd.adc_src = 3; /* ADC Input = PSG */ | 
 | 1029 | } | 
 | 1030 |  | 
 | 1031 |  | 
 | 1032 | static void FalconInit(void) | 
 | 1033 | { | 
 | 1034 | 	int divider, i, idx; | 
 | 1035 | 	const int freq[8] = {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195}; | 
 | 1036 |  | 
 | 1037 | 	/* search a frequency that fits into the allowed error range */ | 
 | 1038 |  | 
 | 1039 | 	idx = -1; | 
 | 1040 | 	for (i = 0; i < ARRAY_SIZE(freq); i++) | 
 | 1041 | 		/* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would | 
 | 1042 | 		 * be playable without expanding, but that now a kernel runtime | 
 | 1043 | 		 * option | 
 | 1044 | 		 */ | 
 | 1045 | 		if ((100 * abs(dmasound.soft.speed - freq[i]) / freq[i]) < catchRadius) | 
 | 1046 | 			idx = i; | 
 | 1047 | 	if (idx > -1) { | 
 | 1048 | 		dmasound.soft.speed = freq[idx]; | 
 | 1049 | 		dmasound.trans_write = &transFalconNormal; | 
 | 1050 | 	} else | 
 | 1051 | 		dmasound.trans_write = &transFalconExpanding; | 
 | 1052 |  | 
 | 1053 | 	FalconSilence(); | 
 | 1054 | 	dmasound.hard = dmasound.soft; | 
 | 1055 |  | 
 | 1056 | 	if (dmasound.hard.size == 16) { | 
 | 1057 | 		/* the Falcon can play 16bit samples only in stereo */ | 
 | 1058 | 		dmasound.hard.stereo = 1; | 
 | 1059 | 	} | 
 | 1060 |  | 
 | 1061 | 	if (dmasound.hard.speed > 49170) { | 
 | 1062 | 		/* we would need to squeeze the sound, but we won't do that */ | 
 | 1063 | 		dmasound.hard.speed = 49170; | 
 | 1064 | 		divider = 1; | 
 | 1065 | 		dmasound.trans_write = &transFalconNormal; | 
 | 1066 | 	} else if (dmasound.hard.speed > 32780) { | 
 | 1067 | 		dmasound.hard.speed = 49170; | 
 | 1068 | 		divider = 1; | 
 | 1069 | 	} else if (dmasound.hard.speed > 24585) { | 
 | 1070 | 		dmasound.hard.speed = 32780; | 
 | 1071 | 		divider = 2; | 
 | 1072 | 	} else if (dmasound.hard.speed > 19668) { | 
 | 1073 | 		dmasound.hard.speed = 24585; | 
 | 1074 | 		divider = 3; | 
 | 1075 | 	} else if (dmasound.hard.speed > 16390) { | 
 | 1076 | 		dmasound.hard.speed = 19668; | 
 | 1077 | 		divider = 4; | 
 | 1078 | 	} else if (dmasound.hard.speed > 12292) { | 
 | 1079 | 		dmasound.hard.speed = 16390; | 
 | 1080 | 		divider = 5; | 
 | 1081 | 	} else if (dmasound.hard.speed > 9834) { | 
 | 1082 | 		dmasound.hard.speed = 12292; | 
 | 1083 | 		divider = 7; | 
 | 1084 | 	} else if (dmasound.hard.speed > 8195) { | 
 | 1085 | 		dmasound.hard.speed = 9834; | 
 | 1086 | 		divider = 9; | 
 | 1087 | 	} else { | 
 | 1088 | 		dmasound.hard.speed = 8195; | 
 | 1089 | 		divider = 11; | 
 | 1090 | 	} | 
 | 1091 | 	tt_dmasnd.int_div = divider; | 
 | 1092 |  | 
 | 1093 | 	/* Setup Falcon sound DMA for playback */ | 
 | 1094 | 	tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */ | 
 | 1095 | 	tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */ | 
 | 1096 | 	tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */ | 
 | 1097 | 	tt_dmasnd.cbar_dst = 0x0000; | 
 | 1098 | 	tt_dmasnd.rec_track_select = 0; | 
 | 1099 | 	tt_dmasnd.dac_src = 2; /* connect matrix to DAC */ | 
 | 1100 | 	tt_dmasnd.adc_src = 0; /* ADC Input = Mic */ | 
 | 1101 |  | 
 | 1102 | 	tt_dmasnd.mode = (dmasound.hard.stereo ? | 
 | 1103 | 			  DMASND_MODE_STEREO : DMASND_MODE_MONO) | | 
 | 1104 | 		((dmasound.hard.size == 8) ? | 
 | 1105 | 		 DMASND_MODE_8BIT : DMASND_MODE_16BIT) | | 
 | 1106 | 		DMASND_MODE_6KHZ; | 
 | 1107 |  | 
 | 1108 | 	expand_bal = -dmasound.soft.speed; | 
 | 1109 | } | 
 | 1110 |  | 
 | 1111 |  | 
 | 1112 | static int FalconSetFormat(int format) | 
 | 1113 | { | 
 | 1114 | 	int size; | 
 | 1115 | 	/* Falcon sound DMA supports 8bit and 16bit modes */ | 
 | 1116 |  | 
 | 1117 | 	switch (format) { | 
 | 1118 | 	case AFMT_QUERY: | 
 | 1119 | 		return dmasound.soft.format; | 
 | 1120 | 	case AFMT_MU_LAW: | 
 | 1121 | 	case AFMT_A_LAW: | 
 | 1122 | 	case AFMT_U8: | 
 | 1123 | 	case AFMT_S8: | 
 | 1124 | 		size = 8; | 
 | 1125 | 		break; | 
 | 1126 | 	case AFMT_S16_BE: | 
 | 1127 | 	case AFMT_U16_BE: | 
 | 1128 | 	case AFMT_S16_LE: | 
 | 1129 | 	case AFMT_U16_LE: | 
 | 1130 | 		size = 16; | 
 | 1131 | 		break; | 
 | 1132 | 	default: /* :-) */ | 
 | 1133 | 		size = 8; | 
 | 1134 | 		format = AFMT_S8; | 
 | 1135 | 	} | 
 | 1136 |  | 
 | 1137 | 	dmasound.soft.format = format; | 
 | 1138 | 	dmasound.soft.size = size; | 
 | 1139 | 	if (dmasound.minDev == SND_DEV_DSP) { | 
 | 1140 | 		dmasound.dsp.format = format; | 
 | 1141 | 		dmasound.dsp.size = dmasound.soft.size; | 
 | 1142 | 	} | 
 | 1143 |  | 
 | 1144 | 	FalconInit(); | 
 | 1145 |  | 
 | 1146 | 	return format; | 
 | 1147 | } | 
 | 1148 |  | 
 | 1149 |  | 
 | 1150 | /* This is for the Falcon output *attenuation* in 1.5dB steps, | 
 | 1151 |  * i.e. output level from 0 to -22.5dB in -1.5dB steps. | 
 | 1152 |  */ | 
 | 1153 | #define VOLUME_VOXWARE_TO_ATT(v) \ | 
 | 1154 | 	((v) < 0 ? 15 : (v) > 100 ? 0 : 15 - (v) * 3 / 20) | 
 | 1155 | #define VOLUME_ATT_TO_VOXWARE(v) (100 - (v) * 20 / 3) | 
 | 1156 |  | 
 | 1157 |  | 
 | 1158 | static int FalconSetVolume(int volume) | 
 | 1159 | { | 
 | 1160 | 	dmasound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff); | 
 | 1161 | 	dmasound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8); | 
 | 1162 | 	tt_dmasnd.output_atten = dmasound.volume_left << 8 | dmasound.volume_right << 4; | 
 | 1163 | 	return VOLUME_ATT_TO_VOXWARE(dmasound.volume_left) | | 
 | 1164 | 	       VOLUME_ATT_TO_VOXWARE(dmasound.volume_right) << 8; | 
 | 1165 | } | 
 | 1166 |  | 
 | 1167 |  | 
 | 1168 | static void AtaPlayNextFrame(int index) | 
 | 1169 | { | 
 | 1170 | 	char *start, *end; | 
 | 1171 |  | 
 | 1172 | 	/* used by AtaPlay() if all doubts whether there really is something | 
 | 1173 | 	 * to be played are already wiped out. | 
 | 1174 | 	 */ | 
 | 1175 | 	start = write_sq.buffers[write_sq.front]; | 
 | 1176 | 	end = start+((write_sq.count == index) ? write_sq.rear_size | 
 | 1177 | 					       : write_sq.block_size); | 
 | 1178 | 	/* end might not be a legal virtual address. */ | 
 | 1179 | 	DMASNDSetEnd(virt_to_phys(end - 1) + 1); | 
 | 1180 | 	DMASNDSetBase(virt_to_phys(start)); | 
 | 1181 | 	/* Since only an even number of samples per frame can | 
 | 1182 | 	   be played, we might lose one byte here. (TO DO) */ | 
 | 1183 | 	write_sq.front = (write_sq.front+1) % write_sq.max_count; | 
 | 1184 | 	write_sq.active++; | 
 | 1185 | 	tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT; | 
 | 1186 | } | 
 | 1187 |  | 
 | 1188 |  | 
 | 1189 | static void AtaPlay(void) | 
 | 1190 | { | 
 | 1191 | 	/* ++TeSche: Note that write_sq.active is no longer just a flag but | 
 | 1192 | 	 * holds the number of frames the DMA is currently programmed for | 
 | 1193 | 	 * instead, may be 0, 1 (currently being played) or 2 (pre-programmed). | 
 | 1194 | 	 * | 
 | 1195 | 	 * Changes done to write_sq.count and write_sq.active are a bit more | 
 | 1196 | 	 * subtle again so now I must admit I also prefer disabling the irq | 
 | 1197 | 	 * here rather than considering all possible situations. But the point | 
 | 1198 | 	 * is that disabling the irq doesn't have any bad influence on this | 
 | 1199 | 	 * version of the driver as we benefit from having pre-programmed the | 
 | 1200 | 	 * DMA wherever possible: There's no need to reload the DMA at the | 
 | 1201 | 	 * exact time of an interrupt but only at some time while the | 
 | 1202 | 	 * pre-programmed frame is playing! | 
 | 1203 | 	 */ | 
 | 1204 | 	atari_disable_irq(IRQ_MFP_TIMA); | 
 | 1205 |  | 
 | 1206 | 	if (write_sq.active == 2 ||	/* DMA is 'full' */ | 
 | 1207 | 	    write_sq.count <= 0) {	/* nothing to do */ | 
 | 1208 | 		atari_enable_irq(IRQ_MFP_TIMA); | 
 | 1209 | 		return; | 
 | 1210 | 	} | 
 | 1211 |  | 
 | 1212 | 	if (write_sq.active == 0) { | 
 | 1213 | 		/* looks like there's nothing 'in' the DMA yet, so try | 
 | 1214 | 		 * to put two frames into it (at least one is available). | 
 | 1215 | 		 */ | 
 | 1216 | 		if (write_sq.count == 1 && | 
 | 1217 | 		    write_sq.rear_size < write_sq.block_size && | 
 | 1218 | 		    !write_sq.syncing) { | 
 | 1219 | 			/* hmmm, the only existing frame is not | 
 | 1220 | 			 * yet filled and we're not syncing? | 
 | 1221 | 			 */ | 
 | 1222 | 			atari_enable_irq(IRQ_MFP_TIMA); | 
 | 1223 | 			return; | 
 | 1224 | 		} | 
 | 1225 | 		AtaPlayNextFrame(1); | 
 | 1226 | 		if (write_sq.count == 1) { | 
 | 1227 | 			/* no more frames */ | 
 | 1228 | 			atari_enable_irq(IRQ_MFP_TIMA); | 
 | 1229 | 			return; | 
 | 1230 | 		} | 
 | 1231 | 		if (write_sq.count == 2 && | 
 | 1232 | 		    write_sq.rear_size < write_sq.block_size && | 
 | 1233 | 		    !write_sq.syncing) { | 
 | 1234 | 			/* hmmm, there were two frames, but the second | 
 | 1235 | 			 * one is not yet filled and we're not syncing? | 
 | 1236 | 			 */ | 
 | 1237 | 			atari_enable_irq(IRQ_MFP_TIMA); | 
 | 1238 | 			return; | 
 | 1239 | 		} | 
 | 1240 | 		AtaPlayNextFrame(2); | 
 | 1241 | 	} else { | 
 | 1242 | 		/* there's already a frame being played so we may only stuff | 
 | 1243 | 		 * one new into the DMA, but even if this may be the last | 
 | 1244 | 		 * frame existing the previous one is still on write_sq.count. | 
 | 1245 | 		 */ | 
 | 1246 | 		if (write_sq.count == 2 && | 
 | 1247 | 		    write_sq.rear_size < write_sq.block_size && | 
 | 1248 | 		    !write_sq.syncing) { | 
 | 1249 | 			/* hmmm, the only existing frame is not | 
 | 1250 | 			 * yet filled and we're not syncing? | 
 | 1251 | 			 */ | 
 | 1252 | 			atari_enable_irq(IRQ_MFP_TIMA); | 
 | 1253 | 			return; | 
 | 1254 | 		} | 
 | 1255 | 		AtaPlayNextFrame(2); | 
 | 1256 | 	} | 
 | 1257 | 	atari_enable_irq(IRQ_MFP_TIMA); | 
 | 1258 | } | 
 | 1259 |  | 
 | 1260 |  | 
| David Howells | 7d12e78 | 2006-10-05 14:55:46 +0100 | [diff] [blame] | 1261 | static irqreturn_t AtaInterrupt(int irq, void *dummy) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1262 | { | 
 | 1263 | #if 0 | 
 | 1264 | 	/* ++TeSche: if you should want to test this... */ | 
 | 1265 | 	static int cnt; | 
 | 1266 | 	if (write_sq.active == 2) | 
 | 1267 | 		if (++cnt == 10) { | 
 | 1268 | 			/* simulate losing an interrupt */ | 
 | 1269 | 			cnt = 0; | 
 | 1270 | 			return IRQ_HANDLED; | 
 | 1271 | 		} | 
 | 1272 | #endif | 
 | 1273 | 	spin_lock(&dmasound.lock); | 
 | 1274 | 	if (write_sq_ignore_int && is_falcon) { | 
 | 1275 | 		/* ++TeSche: Falcon only: ignore first irq because it comes | 
 | 1276 | 		 * immediately after starting a frame. after that, irqs come | 
 | 1277 | 		 * (almost) like on the TT. | 
 | 1278 | 		 */ | 
 | 1279 | 		write_sq_ignore_int = 0; | 
 | 1280 | 		return IRQ_HANDLED; | 
 | 1281 | 	} | 
 | 1282 |  | 
 | 1283 | 	if (!write_sq.active) { | 
 | 1284 | 		/* playing was interrupted and sq_reset() has already cleared | 
 | 1285 | 		 * the sq variables, so better don't do anything here. | 
 | 1286 | 		 */ | 
 | 1287 | 		WAKE_UP(write_sq.sync_queue); | 
 | 1288 | 		return IRQ_HANDLED; | 
 | 1289 | 	} | 
 | 1290 |  | 
 | 1291 | 	/* Probably ;) one frame is finished. Well, in fact it may be that a | 
 | 1292 | 	 * pre-programmed one is also finished because there has been a long | 
 | 1293 | 	 * delay in interrupt delivery and we've completely lost one, but | 
 | 1294 | 	 * there's no way to detect such a situation. In such a case the last | 
 | 1295 | 	 * frame will be played more than once and the situation will recover | 
 | 1296 | 	 * as soon as the irq gets through. | 
 | 1297 | 	 */ | 
 | 1298 | 	write_sq.count--; | 
 | 1299 | 	write_sq.active--; | 
 | 1300 |  | 
 | 1301 | 	if (!write_sq.active) { | 
 | 1302 | 		tt_dmasnd.ctrl = DMASND_CTRL_OFF; | 
 | 1303 | 		write_sq_ignore_int = 1; | 
 | 1304 | 	} | 
 | 1305 |  | 
 | 1306 | 	WAKE_UP(write_sq.action_queue); | 
 | 1307 | 	/* At least one block of the queue is free now | 
 | 1308 | 	   so wake up a writing process blocked because | 
 | 1309 | 	   of a full queue. */ | 
 | 1310 |  | 
 | 1311 | 	if ((write_sq.active != 1) || (write_sq.count != 1)) | 
 | 1312 | 		/* We must be a bit carefully here: write_sq.count indicates the | 
 | 1313 | 		 * number of buffers used and not the number of frames to be | 
 | 1314 | 		 * played. If write_sq.count==1 and write_sq.active==1 that | 
 | 1315 | 		 * means the only remaining frame was already programmed | 
 | 1316 | 		 * earlier (and is currently running) so we mustn't call | 
 | 1317 | 		 * AtaPlay() here, otherwise we'll play one frame too much. | 
 | 1318 | 		 */ | 
 | 1319 | 		AtaPlay(); | 
 | 1320 |  | 
 | 1321 | 	if (!write_sq.active) WAKE_UP(write_sq.sync_queue); | 
 | 1322 | 	/* We are not playing after AtaPlay(), so there | 
 | 1323 | 	   is nothing to play any more. Wake up a process | 
 | 1324 | 	   waiting for audio output to drain. */ | 
 | 1325 | 	spin_unlock(&dmasound.lock); | 
 | 1326 | 	return IRQ_HANDLED; | 
 | 1327 | } | 
 | 1328 |  | 
 | 1329 |  | 
 | 1330 | /*** Mid level stuff *********************************************************/ | 
 | 1331 |  | 
 | 1332 |  | 
 | 1333 | /* | 
 | 1334 |  * /dev/mixer abstraction | 
 | 1335 |  */ | 
 | 1336 |  | 
 | 1337 | #define RECLEVEL_VOXWARE_TO_GAIN(v)	\ | 
 | 1338 | 	((v) < 0 ? 0 : (v) > 100 ? 15 : (v) * 3 / 20) | 
 | 1339 | #define RECLEVEL_GAIN_TO_VOXWARE(v)	(((v) * 20 + 2) / 3) | 
 | 1340 |  | 
 | 1341 |  | 
 | 1342 | static void __init TTMixerInit(void) | 
 | 1343 | { | 
 | 1344 | 	atari_microwire_cmd(MW_LM1992_VOLUME(0)); | 
 | 1345 | 	dmasound.volume_left = 0; | 
 | 1346 | 	atari_microwire_cmd(MW_LM1992_BALLEFT(0)); | 
 | 1347 | 	dmasound.volume_right = 0; | 
 | 1348 | 	atari_microwire_cmd(MW_LM1992_BALRIGHT(0)); | 
 | 1349 | 	atari_microwire_cmd(MW_LM1992_TREBLE(0)); | 
 | 1350 | 	atari_microwire_cmd(MW_LM1992_BASS(0)); | 
 | 1351 | } | 
 | 1352 |  | 
 | 1353 | static void __init FalconMixerInit(void) | 
 | 1354 | { | 
 | 1355 | 	dmasound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8; | 
 | 1356 | 	dmasound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4; | 
 | 1357 | } | 
 | 1358 |  | 
 | 1359 | static int AtaMixerIoctl(u_int cmd, u_long arg) | 
 | 1360 | { | 
 | 1361 | 	int data; | 
 | 1362 | 	unsigned long flags; | 
 | 1363 | 	switch (cmd) { | 
 | 1364 | 	    case SOUND_MIXER_READ_SPEAKER: | 
 | 1365 | 		    if (is_falcon || MACH_IS_TT) { | 
 | 1366 | 			    int porta; | 
 | 1367 | 			    spin_lock_irqsave(&dmasound.lock, flags); | 
 | 1368 | 			    sound_ym.rd_data_reg_sel = 14; | 
 | 1369 | 			    porta = sound_ym.rd_data_reg_sel; | 
 | 1370 | 			    spin_unlock_irqrestore(&dmasound.lock, flags); | 
 | 1371 | 			    return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100); | 
 | 1372 | 		    } | 
 | 1373 | 		    break; | 
 | 1374 | 	    case SOUND_MIXER_WRITE_VOLUME: | 
 | 1375 | 		    IOCTL_IN(arg, data); | 
 | 1376 | 		    return IOCTL_OUT(arg, dmasound_set_volume(data)); | 
 | 1377 | 	    case SOUND_MIXER_WRITE_SPEAKER: | 
 | 1378 | 		    if (is_falcon || MACH_IS_TT) { | 
 | 1379 | 			    int porta; | 
 | 1380 | 			    IOCTL_IN(arg, data); | 
 | 1381 | 			    spin_lock_irqsave(&dmasound.lock, flags); | 
 | 1382 | 			    sound_ym.rd_data_reg_sel = 14; | 
 | 1383 | 			    porta = (sound_ym.rd_data_reg_sel & ~0x40) | | 
 | 1384 | 				    (data < 50 ? 0x40 : 0); | 
 | 1385 | 			    sound_ym.wd_data = porta; | 
 | 1386 | 			    spin_unlock_irqrestore(&dmasound.lock, flags); | 
 | 1387 | 			    return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100); | 
 | 1388 | 		    } | 
 | 1389 | 	} | 
 | 1390 | 	return -EINVAL; | 
 | 1391 | } | 
 | 1392 |  | 
 | 1393 |  | 
 | 1394 | static int TTMixerIoctl(u_int cmd, u_long arg) | 
 | 1395 | { | 
 | 1396 | 	int data; | 
 | 1397 | 	switch (cmd) { | 
 | 1398 | 	    case SOUND_MIXER_READ_RECMASK: | 
 | 1399 | 		return IOCTL_OUT(arg, 0); | 
 | 1400 | 	    case SOUND_MIXER_READ_DEVMASK: | 
 | 1401 | 		return IOCTL_OUT(arg, | 
 | 1402 | 				 SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS | | 
 | 1403 | 				 (MACH_IS_TT ? SOUND_MASK_SPEAKER : 0)); | 
 | 1404 | 	    case SOUND_MIXER_READ_STEREODEVS: | 
 | 1405 | 		return IOCTL_OUT(arg, SOUND_MASK_VOLUME); | 
 | 1406 | 	    case SOUND_MIXER_READ_VOLUME: | 
 | 1407 | 		return IOCTL_OUT(arg, | 
 | 1408 | 				 VOLUME_DB_TO_VOXWARE(dmasound.volume_left) | | 
 | 1409 | 				 (VOLUME_DB_TO_VOXWARE(dmasound.volume_right) << 8)); | 
 | 1410 | 	    case SOUND_MIXER_READ_BASS: | 
 | 1411 | 		return IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(dmasound.bass)); | 
 | 1412 | 	    case SOUND_MIXER_READ_TREBLE: | 
 | 1413 | 		return IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(dmasound.treble)); | 
 | 1414 | 	    case SOUND_MIXER_READ_OGAIN: | 
 | 1415 | 		return IOCTL_OUT(arg, GAIN_DB_TO_VOXWARE(dmasound.gain)); | 
 | 1416 | 	    case SOUND_MIXER_WRITE_BASS: | 
 | 1417 | 		IOCTL_IN(arg, data); | 
 | 1418 | 		return IOCTL_OUT(arg, dmasound_set_bass(data)); | 
 | 1419 | 	    case SOUND_MIXER_WRITE_TREBLE: | 
 | 1420 | 		IOCTL_IN(arg, data); | 
 | 1421 | 		return IOCTL_OUT(arg, dmasound_set_treble(data)); | 
 | 1422 | 	    case SOUND_MIXER_WRITE_OGAIN: | 
 | 1423 | 		IOCTL_IN(arg, data); | 
 | 1424 | 		return IOCTL_OUT(arg, dmasound_set_gain(data)); | 
 | 1425 | 	} | 
 | 1426 | 	return AtaMixerIoctl(cmd, arg); | 
 | 1427 | } | 
 | 1428 |  | 
 | 1429 | static int FalconMixerIoctl(u_int cmd, u_long arg) | 
 | 1430 | { | 
 | 1431 | 	int data; | 
 | 1432 | 	switch (cmd) { | 
 | 1433 | 	    case SOUND_MIXER_READ_RECMASK: | 
 | 1434 | 		return IOCTL_OUT(arg, SOUND_MASK_MIC); | 
 | 1435 | 	    case SOUND_MIXER_READ_DEVMASK: | 
 | 1436 | 		return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER); | 
 | 1437 | 	    case SOUND_MIXER_READ_STEREODEVS: | 
 | 1438 | 		return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC); | 
 | 1439 | 	    case SOUND_MIXER_READ_VOLUME: | 
 | 1440 | 		return IOCTL_OUT(arg, | 
 | 1441 | 			VOLUME_ATT_TO_VOXWARE(dmasound.volume_left) | | 
 | 1442 | 			VOLUME_ATT_TO_VOXWARE(dmasound.volume_right) << 8); | 
 | 1443 | 	    case SOUND_MIXER_READ_CAPS: | 
 | 1444 | 		return IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT); | 
 | 1445 | 	    case SOUND_MIXER_WRITE_MIC: | 
 | 1446 | 		IOCTL_IN(arg, data); | 
 | 1447 | 		tt_dmasnd.input_gain = | 
 | 1448 | 			RECLEVEL_VOXWARE_TO_GAIN(data & 0xff) << 4 | | 
 | 1449 | 			RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff); | 
 | 1450 | 		/* fall thru, return set value */ | 
 | 1451 | 	    case SOUND_MIXER_READ_MIC: | 
 | 1452 | 		return IOCTL_OUT(arg, | 
 | 1453 | 			RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) | | 
 | 1454 | 			RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8); | 
 | 1455 | 	} | 
 | 1456 | 	return AtaMixerIoctl(cmd, arg); | 
 | 1457 | } | 
 | 1458 |  | 
 | 1459 | static int AtaWriteSqSetup(void) | 
 | 1460 | { | 
 | 1461 | 	write_sq_ignore_int = 0; | 
 | 1462 | 	return 0 ; | 
 | 1463 | } | 
 | 1464 |  | 
| Al Viro | aeb5d72 | 2008-09-02 15:28:45 -0400 | [diff] [blame] | 1465 | static int AtaSqOpen(fmode_t mode) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1466 | { | 
 | 1467 | 	write_sq_ignore_int = 1; | 
 | 1468 | 	return 0 ; | 
 | 1469 | } | 
 | 1470 |  | 
 | 1471 | static int TTStateInfo(char *buffer, size_t space) | 
 | 1472 | { | 
 | 1473 | 	int len = 0; | 
 | 1474 | 	len += sprintf(buffer+len, "\tvol left  %ddB [-40...  0]\n", | 
 | 1475 | 		       dmasound.volume_left); | 
 | 1476 | 	len += sprintf(buffer+len, "\tvol right %ddB [-40...  0]\n", | 
 | 1477 | 		       dmasound.volume_right); | 
 | 1478 | 	len += sprintf(buffer+len, "\tbass      %ddB [-12...+12]\n", | 
 | 1479 | 		       dmasound.bass); | 
 | 1480 | 	len += sprintf(buffer+len, "\ttreble    %ddB [-12...+12]\n", | 
 | 1481 | 		       dmasound.treble); | 
 | 1482 | 	if (len >= space) { | 
 | 1483 | 		printk(KERN_ERR "dmasound_atari: overflowed state buffer alloc.\n") ; | 
 | 1484 | 		len = space ; | 
 | 1485 | 	} | 
 | 1486 | 	return len; | 
 | 1487 | } | 
 | 1488 |  | 
 | 1489 | static int FalconStateInfo(char *buffer, size_t space) | 
 | 1490 | { | 
 | 1491 | 	int len = 0; | 
 | 1492 | 	len += sprintf(buffer+len, "\tvol left  %ddB [-22.5 ... 0]\n", | 
 | 1493 | 		       dmasound.volume_left); | 
 | 1494 | 	len += sprintf(buffer+len, "\tvol right %ddB [-22.5 ... 0]\n", | 
 | 1495 | 		       dmasound.volume_right); | 
 | 1496 | 	if (len >= space) { | 
 | 1497 | 		printk(KERN_ERR "dmasound_atari: overflowed state buffer alloc.\n") ; | 
 | 1498 | 		len = space ; | 
 | 1499 | 	} | 
 | 1500 | 	return len; | 
 | 1501 | } | 
 | 1502 |  | 
 | 1503 |  | 
 | 1504 | /*** Machine definitions *****************************************************/ | 
 | 1505 |  | 
 | 1506 | static SETTINGS def_hard_falcon = { | 
 | 1507 | 	.format		= AFMT_S8, | 
 | 1508 | 	.stereo		= 0, | 
 | 1509 | 	.size		= 8, | 
 | 1510 | 	.speed		= 8195 | 
 | 1511 | } ; | 
 | 1512 |  | 
 | 1513 | static SETTINGS def_hard_tt = { | 
 | 1514 | 	.format	= AFMT_S8, | 
 | 1515 | 	.stereo	= 0, | 
 | 1516 | 	.size	= 8, | 
 | 1517 | 	.speed	= 12517 | 
 | 1518 | } ; | 
 | 1519 |  | 
 | 1520 | static SETTINGS def_soft = { | 
 | 1521 | 	.format	= AFMT_U8, | 
 | 1522 | 	.stereo	= 0, | 
 | 1523 | 	.size	= 8, | 
 | 1524 | 	.speed	= 8000 | 
 | 1525 | } ; | 
 | 1526 |  | 
| Michael Schmitz | d497e3a | 2009-01-18 03:17:33 +0100 | [diff] [blame] | 1527 | static __initdata MACHINE machTT = { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1528 | 	.name		= "Atari", | 
 | 1529 | 	.name2		= "TT", | 
 | 1530 | 	.owner		= THIS_MODULE, | 
 | 1531 | 	.dma_alloc	= AtaAlloc, | 
 | 1532 | 	.dma_free	= AtaFree, | 
 | 1533 | 	.irqinit	= AtaIrqInit, | 
 | 1534 | #ifdef MODULE | 
 | 1535 | 	.irqcleanup	= AtaIrqCleanUp, | 
 | 1536 | #endif /* MODULE */ | 
 | 1537 | 	.init		= TTInit, | 
 | 1538 | 	.silence	= TTSilence, | 
 | 1539 | 	.setFormat	= TTSetFormat, | 
 | 1540 | 	.setVolume	= TTSetVolume, | 
 | 1541 | 	.setBass	= AtaSetBass, | 
 | 1542 | 	.setTreble	= AtaSetTreble, | 
 | 1543 | 	.setGain	= TTSetGain, | 
 | 1544 | 	.play		= AtaPlay, | 
 | 1545 | 	.mixer_init	= TTMixerInit, | 
 | 1546 | 	.mixer_ioctl	= TTMixerIoctl, | 
 | 1547 | 	.write_sq_setup	= AtaWriteSqSetup, | 
 | 1548 | 	.sq_open	= AtaSqOpen, | 
 | 1549 | 	.state_info	= TTStateInfo, | 
 | 1550 | 	.min_dsp_speed	= 6258, | 
 | 1551 | 	.version	= ((DMASOUND_ATARI_REVISION<<8) | DMASOUND_ATARI_EDITION), | 
 | 1552 | 	.hardware_afmts	= AFMT_S8,  /* h'ware-supported formats *only* here */ | 
 | 1553 | 	.capabilities	=  DSP_CAP_BATCH	/* As per SNDCTL_DSP_GETCAPS */ | 
 | 1554 | }; | 
 | 1555 |  | 
| Michael Schmitz | d497e3a | 2009-01-18 03:17:33 +0100 | [diff] [blame] | 1556 | static __initdata MACHINE machFalcon = { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1557 | 	.name		= "Atari", | 
 | 1558 | 	.name2		= "FALCON", | 
 | 1559 | 	.dma_alloc	= AtaAlloc, | 
 | 1560 | 	.dma_free	= AtaFree, | 
 | 1561 | 	.irqinit	= AtaIrqInit, | 
 | 1562 | #ifdef MODULE | 
 | 1563 | 	.irqcleanup	= AtaIrqCleanUp, | 
 | 1564 | #endif /* MODULE */ | 
 | 1565 | 	.init		= FalconInit, | 
 | 1566 | 	.silence	= FalconSilence, | 
 | 1567 | 	.setFormat	= FalconSetFormat, | 
 | 1568 | 	.setVolume	= FalconSetVolume, | 
 | 1569 | 	.setBass	= AtaSetBass, | 
 | 1570 | 	.setTreble	= AtaSetTreble, | 
 | 1571 | 	.play		= AtaPlay, | 
 | 1572 | 	.mixer_init	= FalconMixerInit, | 
 | 1573 | 	.mixer_ioctl	= FalconMixerIoctl, | 
 | 1574 | 	.write_sq_setup	= AtaWriteSqSetup, | 
 | 1575 | 	.sq_open	= AtaSqOpen, | 
 | 1576 | 	.state_info	= FalconStateInfo, | 
 | 1577 | 	.min_dsp_speed	= 8195, | 
 | 1578 | 	.version	= ((DMASOUND_ATARI_REVISION<<8) | DMASOUND_ATARI_EDITION), | 
 | 1579 | 	.hardware_afmts	= (AFMT_S8 | AFMT_S16_BE), /* h'ware-supported formats *only* here */ | 
 | 1580 | 	.capabilities	=  DSP_CAP_BATCH	/* As per SNDCTL_DSP_GETCAPS */ | 
 | 1581 | }; | 
 | 1582 |  | 
 | 1583 |  | 
 | 1584 | /*** Config & Setup **********************************************************/ | 
 | 1585 |  | 
 | 1586 |  | 
 | 1587 | static int __init dmasound_atari_init(void) | 
 | 1588 | { | 
 | 1589 | 	if (MACH_IS_ATARI && ATARIHW_PRESENT(PCM_8BIT)) { | 
 | 1590 | 	    if (ATARIHW_PRESENT(CODEC)) { | 
 | 1591 | 		dmasound.mach = machFalcon; | 
 | 1592 | 		dmasound.mach.default_soft = def_soft ; | 
 | 1593 | 		dmasound.mach.default_hard = def_hard_falcon ; | 
 | 1594 | 		is_falcon = 1; | 
 | 1595 | 	    } else if (ATARIHW_PRESENT(MICROWIRE)) { | 
 | 1596 | 		dmasound.mach = machTT; | 
 | 1597 | 		dmasound.mach.default_soft = def_soft ; | 
 | 1598 | 		dmasound.mach.default_hard = def_hard_tt ; | 
 | 1599 | 		is_falcon = 0; | 
 | 1600 | 	    } else | 
 | 1601 | 		return -ENODEV; | 
| Geert Uytterhoeven | 3d92e8f | 2009-02-22 09:38:47 +0100 | [diff] [blame] | 1602 | 	    if ((st_mfp.int_en_a & st_mfp.int_mk_a & 0x20) == 0) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1603 | 		return dmasound_init(); | 
 | 1604 | 	    else { | 
 | 1605 | 		printk("DMA sound driver: Timer A interrupt already in use\n"); | 
 | 1606 | 		return -EBUSY; | 
 | 1607 | 	    } | 
 | 1608 | 	} | 
 | 1609 | 	return -ENODEV; | 
 | 1610 | } | 
 | 1611 |  | 
 | 1612 | static void __exit dmasound_atari_cleanup(void) | 
 | 1613 | { | 
 | 1614 | 	dmasound_deinit(); | 
 | 1615 | } | 
 | 1616 |  | 
 | 1617 | module_init(dmasound_atari_init); | 
 | 1618 | module_exit(dmasound_atari_cleanup); | 
 | 1619 | MODULE_LICENSE("GPL"); |