1 /* 2 * Driver for Sound Core PDAudioCF soundcard 3 * 4 * Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 */ 20 21 #include <sound/core.h> 22 #include "pdaudiocf.h" 23 #include <sound/initval.h> 24 #include <asm/irq_regs.h> 25 26 /* 27 * 28 */ 29 irqreturn_t pdacf_interrupt(int irq, void *dev) 30 { 31 struct snd_pdacf *chip = dev; 32 unsigned short stat; 33 34 if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE| 35 PDAUDIOCF_STAT_IS_CONFIGURED| 36 PDAUDIOCF_STAT_IS_SUSPENDED)) != PDAUDIOCF_STAT_IS_CONFIGURED) 37 return IRQ_HANDLED; /* IRQ_NONE here? */ 38 39 stat = inw(chip->port + PDAUDIOCF_REG_ISR); 40 if (stat & (PDAUDIOCF_IRQLVL|PDAUDIOCF_IRQOVR)) { 41 if (stat & PDAUDIOCF_IRQOVR) /* should never happen */ 42 snd_printk(KERN_ERR "PDAUDIOCF SRAM buffer overrun detected!\n"); 43 if (chip->pcm_substream) 44 tasklet_schedule(&chip->tq); 45 if (!(stat & PDAUDIOCF_IRQAKM)) 46 stat |= PDAUDIOCF_IRQAKM; /* check rate */ 47 } 48 if (get_irq_regs() != NULL) 49 snd_ak4117_check_rate_and_errors(chip->ak4117, 0); 50 return IRQ_HANDLED; 51 } 52 53 static inline void pdacf_transfer_mono16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port) 54 { 55 while (size-- > 0) { 56 *dst++ = inw(rdp_port) ^ xor; 57 inw(rdp_port); 58 } 59 } 60 61 static inline void pdacf_transfer_mono32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port) 62 { 63 register u16 val1, val2; 64 65 while (size-- > 0) { 66 val1 = inw(rdp_port); 67 val2 = inw(rdp_port); 68 inw(rdp_port); 69 *dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor; 70 } 71 } 72 73 static inline void pdacf_transfer_stereo16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port) 74 { 75 while (size-- > 0) { 76 *dst++ = inw(rdp_port) ^ xor; 77 *dst++ = inw(rdp_port) ^ xor; 78 } 79 } 80 81 static inline void pdacf_transfer_stereo32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port) 82 { 83 register u16 val1, val2, val3; 84 85 while (size-- > 0) { 86 val1 = inw(rdp_port); 87 val2 = inw(rdp_port); 88 val3 = inw(rdp_port); 89 *dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor; 90 *dst++ = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor; 91 } 92 } 93 94 static inline void pdacf_transfer_mono16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port) 95 { 96 while (size-- > 0) { 97 *dst++ = swab16(inw(rdp_port) ^ xor); 98 inw(rdp_port); 99 } 100 } 101 102 static inline void pdacf_transfer_mono32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port) 103 { 104 register u16 val1, val2; 105 106 while (size-- > 0) { 107 val1 = inw(rdp_port); 108 val2 = inw(rdp_port); 109 inw(rdp_port); 110 *dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor); 111 } 112 } 113 114 static inline void pdacf_transfer_stereo16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port) 115 { 116 while (size-- > 0) { 117 *dst++ = swab16(inw(rdp_port) ^ xor); 118 *dst++ = swab16(inw(rdp_port) ^ xor); 119 } 120 } 121 122 static inline void pdacf_transfer_stereo32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port) 123 { 124 register u16 val1, val2, val3; 125 126 while (size-- > 0) { 127 val1 = inw(rdp_port); 128 val2 = inw(rdp_port); 129 val3 = inw(rdp_port); 130 *dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor); 131 *dst++ = swab32((((u32)val3 << 16) | (val2 & 0xff00)) ^ xor); 132 } 133 } 134 135 static inline void pdacf_transfer_mono24le(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port) 136 { 137 register u16 val1, val2; 138 register u32 xval1; 139 140 while (size-- > 0) { 141 val1 = inw(rdp_port); 142 val2 = inw(rdp_port); 143 inw(rdp_port); 144 xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor; 145 *dst++ = (u8)(xval1 >> 8); 146 *dst++ = (u8)(xval1 >> 16); 147 *dst++ = (u8)(xval1 >> 24); 148 } 149 } 150 151 static inline void pdacf_transfer_mono24be(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port) 152 { 153 register u16 val1, val2; 154 register u32 xval1; 155 156 while (size-- > 0) { 157 val1 = inw(rdp_port); 158 val2 = inw(rdp_port); 159 inw(rdp_port); 160 xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor; 161 *dst++ = (u8)(xval1 >> 24); 162 *dst++ = (u8)(xval1 >> 16); 163 *dst++ = (u8)(xval1 >> 8); 164 } 165 } 166 167 static inline void pdacf_transfer_stereo24le(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port) 168 { 169 register u16 val1, val2, val3; 170 register u32 xval1, xval2; 171 172 while (size-- > 0) { 173 val1 = inw(rdp_port); 174 val2 = inw(rdp_port); 175 val3 = inw(rdp_port); 176 xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor; 177 xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor; 178 *dst++ = (u8)(xval1 >> 8); 179 *dst++ = (u8)(xval1 >> 16); 180 *dst++ = (u8)(xval1 >> 24); 181 *dst++ = (u8)(xval2 >> 8); 182 *dst++ = (u8)(xval2 >> 16); 183 *dst++ = (u8)(xval2 >> 24); 184 } 185 } 186 187 static inline void pdacf_transfer_stereo24be(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port) 188 { 189 register u16 val1, val2, val3; 190 register u32 xval1, xval2; 191 192 while (size-- > 0) { 193 val1 = inw(rdp_port); 194 val2 = inw(rdp_port); 195 val3 = inw(rdp_port); 196 xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor; 197 xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor; 198 *dst++ = (u8)(xval1 >> 24); 199 *dst++ = (u8)(xval1 >> 16); 200 *dst++ = (u8)(xval1 >> 8); 201 *dst++ = (u8)(xval2 >> 24); 202 *dst++ = (u8)(xval2 >> 16); 203 *dst++ = (u8)(xval2 >> 8); 204 } 205 } 206 207 static void pdacf_transfer(struct snd_pdacf *chip, unsigned int size, unsigned int off) 208 { 209 unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD; 210 unsigned int xor = chip->pcm_xor; 211 212 if (chip->pcm_sample == 3) { 213 if (chip->pcm_little) { 214 if (chip->pcm_channels == 1) { 215 pdacf_transfer_mono24le((char *)chip->pcm_area + (off * 3), xor, size, rdp_port); 216 } else { 217 pdacf_transfer_stereo24le((char *)chip->pcm_area + (off * 6), xor, size, rdp_port); 218 } 219 } else { 220 if (chip->pcm_channels == 1) { 221 pdacf_transfer_mono24be((char *)chip->pcm_area + (off * 3), xor, size, rdp_port); 222 } else { 223 pdacf_transfer_stereo24be((char *)chip->pcm_area + (off * 6), xor, size, rdp_port); 224 } 225 } 226 return; 227 } 228 if (chip->pcm_swab == 0) { 229 if (chip->pcm_channels == 1) { 230 if (chip->pcm_frame == 2) { 231 pdacf_transfer_mono16((u16 *)chip->pcm_area + off, xor, size, rdp_port); 232 } else { 233 pdacf_transfer_mono32((u32 *)chip->pcm_area + off, xor, size, rdp_port); 234 } 235 } else { 236 if (chip->pcm_frame == 2) { 237 pdacf_transfer_stereo16((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port); 238 } else { 239 pdacf_transfer_stereo32((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port); 240 } 241 } 242 } else { 243 if (chip->pcm_channels == 1) { 244 if (chip->pcm_frame == 2) { 245 pdacf_transfer_mono16sw((u16 *)chip->pcm_area + off, xor, size, rdp_port); 246 } else { 247 pdacf_transfer_mono32sw((u32 *)chip->pcm_area + off, xor, size, rdp_port); 248 } 249 } else { 250 if (chip->pcm_frame == 2) { 251 pdacf_transfer_stereo16sw((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port); 252 } else { 253 pdacf_transfer_stereo32sw((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port); 254 } 255 } 256 } 257 } 258 259 void pdacf_tasklet(unsigned long private_data) 260 { 261 struct snd_pdacf *chip = (struct snd_pdacf *) private_data; 262 int size, off, cont, rdp, wdp; 263 264 if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|PDAUDIOCF_STAT_IS_CONFIGURED)) != PDAUDIOCF_STAT_IS_CONFIGURED) 265 return; 266 267 if (chip->pcm_substream == NULL || chip->pcm_substream->runtime == NULL || !snd_pcm_running(chip->pcm_substream)) 268 return; 269 270 rdp = inw(chip->port + PDAUDIOCF_REG_RDP); 271 wdp = inw(chip->port + PDAUDIOCF_REG_WDP); 272 /* printk(KERN_DEBUG "TASKLET: rdp = %x, wdp = %x\n", rdp, wdp); */ 273 size = wdp - rdp; 274 if (size < 0) 275 size += 0x10000; 276 if (size == 0) 277 size = 0x10000; 278 size /= chip->pcm_frame; 279 if (size > 64) 280 size -= 32; 281 282 #if 0 283 chip->pcm_hwptr += size; 284 chip->pcm_hwptr %= chip->pcm_size; 285 chip->pcm_tdone += size; 286 if (chip->pcm_frame == 2) { 287 unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD; 288 while (size-- > 0) { 289 inw(rdp_port); 290 inw(rdp_port); 291 } 292 } else { 293 unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD; 294 while (size-- > 0) { 295 inw(rdp_port); 296 inw(rdp_port); 297 inw(rdp_port); 298 } 299 } 300 #else 301 off = chip->pcm_hwptr + chip->pcm_tdone; 302 off %= chip->pcm_size; 303 chip->pcm_tdone += size; 304 while (size > 0) { 305 cont = chip->pcm_size - off; 306 if (cont > size) 307 cont = size; 308 pdacf_transfer(chip, cont, off); 309 off += cont; 310 off %= chip->pcm_size; 311 size -= cont; 312 } 313 #endif 314 spin_lock(&chip->reg_lock); 315 while (chip->pcm_tdone >= chip->pcm_period) { 316 chip->pcm_hwptr += chip->pcm_period; 317 chip->pcm_hwptr %= chip->pcm_size; 318 chip->pcm_tdone -= chip->pcm_period; 319 spin_unlock(&chip->reg_lock); 320 snd_pcm_period_elapsed(chip->pcm_substream); 321 spin_lock(&chip->reg_lock); 322 } 323 spin_unlock(&chip->reg_lock); 324 /* printk(KERN_DEBUG "TASKLET: end\n"); */ 325 } 326