1/* 2 * pas2_pcm.c Audio routines for PAS16 3 * 4 * 5 * Copyright (C) by Hannu Savolainen 1993-1997 6 * 7 * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) 8 * Version 2 (June 1991). See the "COPYING" file distributed with this software 9 * for more info. 10 * 11 * 12 * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) 13 * Alan Cox : Swatted a double allocation of device bug. Made a few 14 * more things module options. 15 * Bartlomiej Zolnierkiewicz : Added __init to pas_pcm_init() 16 */ 17 18#include <linux/init.h> 19#include <linux/spinlock.h> 20#include <linux/timex.h> 21#include "sound_config.h" 22 23#include "pas2.h" 24 25#ifndef DEB 26#define DEB(WHAT) 27#endif 28 29#define PAS_PCM_INTRBITS (0x08) 30/* 31 * Sample buffer timer interrupt enable 32 */ 33 34#define PCM_NON 0 35#define PCM_DAC 1 36#define PCM_ADC 2 37 38static unsigned long pcm_speed; /* sampling rate */ 39static unsigned char pcm_channels = 1; /* channels (1 or 2) */ 40static unsigned char pcm_bits = 8; /* bits/sample (8 or 16) */ 41static unsigned char pcm_filter; /* filter FLAG */ 42static unsigned char pcm_mode = PCM_NON; 43static unsigned long pcm_count; 44static unsigned short pcm_bitsok = 8; /* mask of OK bits */ 45static int pcm_busy; 46int pas_audiodev = -1; 47static int open_mode; 48 49extern spinlock_t pas_lock; 50 51static int pcm_set_speed(int arg) 52{ 53 int foo, tmp; 54 unsigned long flags; 55 56 if (arg == 0) 57 return pcm_speed; 58 59 if (arg > 44100) 60 arg = 44100; 61 if (arg < 5000) 62 arg = 5000; 63 64 if (pcm_channels & 2) 65 { 66 foo = ((CLOCK_TICK_RATE / 2) + (arg / 2)) / arg; 67 arg = ((CLOCK_TICK_RATE / 2) + (foo / 2)) / foo; 68 } 69 else 70 { 71 foo = (CLOCK_TICK_RATE + (arg / 2)) / arg; 72 arg = (CLOCK_TICK_RATE + (foo / 2)) / foo; 73 } 74 75 pcm_speed = arg; 76 77 tmp = pas_read(0x0B8A); 78 79 /* 80 * Set anti-aliasing filters according to sample rate. You really *NEED* 81 * to enable this feature for all normal recording unless you want to 82 * experiment with aliasing effects. 83 * These filters apply to the selected "recording" source. 84 * I (pfw) don't know the encoding of these 5 bits. The values shown 85 * come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/. 86 * 87 * I cleared bit 5 of these values, since that bit controls the master 88 * mute flag. (Olav W��lfelschneider) 89 * 90 */ 91#if !defined NO_AUTO_FILTER_SET 92 tmp &= 0xe0; 93 if (pcm_speed >= 2 * 17897) 94 tmp |= 0x01; 95 else if (pcm_speed >= 2 * 15909) 96 tmp |= 0x02; 97 else if (pcm_speed >= 2 * 11931) 98 tmp |= 0x09; 99 else if (pcm_speed >= 2 * 8948) 100 tmp |= 0x11; 101 else if (pcm_speed >= 2 * 5965) 102 tmp |= 0x19; 103 else if (pcm_speed >= 2 * 2982) 104 tmp |= 0x04; 105 pcm_filter = tmp; 106#endif 107 108 spin_lock_irqsave(&pas_lock, flags); 109 110 pas_write(tmp & ~(0x40 | 0x80), 0x0B8A); 111 pas_write(0x00 | 0x30 | 0x04, 0x138B); 112 pas_write(foo & 0xff, 0x1388); 113 pas_write((foo >> 8) & 0xff, 0x1388); 114 pas_write(tmp, 0x0B8A); 115 116 spin_unlock_irqrestore(&pas_lock, flags); 117 118 return pcm_speed; 119} 120 121static int pcm_set_channels(int arg) 122{ 123 124 if ((arg != 1) && (arg != 2)) 125 return pcm_channels; 126 127 if (arg != pcm_channels) 128 { 129 pas_write(pas_read(0xF8A) ^ 0x20, 0xF8A); 130 131 pcm_channels = arg; 132 pcm_set_speed(pcm_speed); /* The speed must be reinitialized */ 133 } 134 return pcm_channels; 135} 136 137static int pcm_set_bits(int arg) 138{ 139 if (arg == 0) 140 return pcm_bits; 141 142 if ((arg & pcm_bitsok) != arg) 143 return pcm_bits; 144 145 if (arg != pcm_bits) 146 { 147 pas_write(pas_read(0x8389) ^ 0x04, 0x8389); 148 149 pcm_bits = arg; 150 } 151 return pcm_bits; 152} 153 154static int pas_audio_ioctl(int dev, unsigned int cmd, void __user *arg) 155{ 156 int val, ret; 157 int __user *p = arg; 158 159 DEB(printk("pas2_pcm.c: static int pas_audio_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg)); 160 161 switch (cmd) 162 { 163 case SOUND_PCM_WRITE_RATE: 164 if (get_user(val, p)) 165 return -EFAULT; 166 ret = pcm_set_speed(val); 167 break; 168 169 case SOUND_PCM_READ_RATE: 170 ret = pcm_speed; 171 break; 172 173 case SNDCTL_DSP_STEREO: 174 if (get_user(val, p)) 175 return -EFAULT; 176 ret = pcm_set_channels(val + 1) - 1; 177 break; 178 179 case SOUND_PCM_WRITE_CHANNELS: 180 if (get_user(val, p)) 181 return -EFAULT; 182 ret = pcm_set_channels(val); 183 break; 184 185 case SOUND_PCM_READ_CHANNELS: 186 ret = pcm_channels; 187 break; 188 189 case SNDCTL_DSP_SETFMT: 190 if (get_user(val, p)) 191 return -EFAULT; 192 ret = pcm_set_bits(val); 193 break; 194 195 case SOUND_PCM_READ_BITS: 196 ret = pcm_bits; 197 break; 198 199 default: 200 return -EINVAL; 201 } 202 return put_user(ret, p); 203} 204 205static void pas_audio_reset(int dev) 206{ 207 DEB(printk("pas2_pcm.c: static void pas_audio_reset(void)\n")); 208 209 pas_write(pas_read(0xF8A) & ~0x40, 0xF8A); /* Disable PCM */ 210} 211 212static int pas_audio_open(int dev, int mode) 213{ 214 int err; 215 unsigned long flags; 216 217 DEB(printk("pas2_pcm.c: static int pas_audio_open(int mode = %X)\n", mode)); 218 219 spin_lock_irqsave(&pas_lock, flags); 220 if (pcm_busy) 221 { 222 spin_unlock_irqrestore(&pas_lock, flags); 223 return -EBUSY; 224 } 225 pcm_busy = 1; 226 spin_unlock_irqrestore(&pas_lock, flags); 227 228 if ((err = pas_set_intr(PAS_PCM_INTRBITS)) < 0) 229 return err; 230 231 232 pcm_count = 0; 233 open_mode = mode; 234 235 return 0; 236} 237 238static void pas_audio_close(int dev) 239{ 240 unsigned long flags; 241 242 DEB(printk("pas2_pcm.c: static void pas_audio_close(void)\n")); 243 244 spin_lock_irqsave(&pas_lock, flags); 245 246 pas_audio_reset(dev); 247 pas_remove_intr(PAS_PCM_INTRBITS); 248 pcm_mode = PCM_NON; 249 250 pcm_busy = 0; 251 spin_unlock_irqrestore(&pas_lock, flags); 252} 253 254static void pas_audio_output_block(int dev, unsigned long buf, int count, 255 int intrflag) 256{ 257 unsigned long flags, cnt; 258 259 DEB(printk("pas2_pcm.c: static void pas_audio_output_block(char *buf = %P, int count = %X)\n", buf, count)); 260 261 cnt = count; 262 if (audio_devs[dev]->dmap_out->dma > 3) 263 cnt >>= 1; 264 265 if (audio_devs[dev]->flags & DMA_AUTOMODE && 266 intrflag && 267 cnt == pcm_count) 268 return; 269 270 spin_lock_irqsave(&pas_lock, flags); 271 272 pas_write(pas_read(0xF8A) & ~0x40, 273 0xF8A); 274 275 /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ 276 277 if (audio_devs[dev]->dmap_out->dma > 3) 278 count >>= 1; 279 280 if (count != pcm_count) 281 { 282 pas_write(pas_read(0x0B8A) & ~0x80, 0x0B8A); 283 pas_write(0x40 | 0x30 | 0x04, 0x138B); 284 pas_write(count & 0xff, 0x1389); 285 pas_write((count >> 8) & 0xff, 0x1389); 286 pas_write(pas_read(0x0B8A) | 0x80, 0x0B8A); 287 288 pcm_count = count; 289 } 290 pas_write(pas_read(0x0B8A) | 0x80 | 0x40, 0x0B8A); 291#ifdef NO_TRIGGER 292 pas_write(pas_read(0xF8A) | 0x40 | 0x10, 0xF8A); 293#endif 294 295 pcm_mode = PCM_DAC; 296 297 spin_unlock_irqrestore(&pas_lock, flags); 298} 299 300static void pas_audio_start_input(int dev, unsigned long buf, int count, 301 int intrflag) 302{ 303 unsigned long flags; 304 int cnt; 305 306 DEB(printk("pas2_pcm.c: static void pas_audio_start_input(char *buf = %P, int count = %X)\n", buf, count)); 307 308 cnt = count; 309 if (audio_devs[dev]->dmap_out->dma > 3) 310 cnt >>= 1; 311 312 if (audio_devs[pas_audiodev]->flags & DMA_AUTOMODE && 313 intrflag && 314 cnt == pcm_count) 315 return; 316 317 spin_lock_irqsave(&pas_lock, flags); 318 319 /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ 320 321 if (audio_devs[dev]->dmap_out->dma > 3) 322 count >>= 1; 323 324 if (count != pcm_count) 325 { 326 pas_write(pas_read(0x0B8A) & ~0x80, 0x0B8A); 327 pas_write(0x40 | 0x30 | 0x04, 0x138B); 328 pas_write(count & 0xff, 0x1389); 329 pas_write((count >> 8) & 0xff, 0x1389); 330 pas_write(pas_read(0x0B8A) | 0x80, 0x0B8A); 331 332 pcm_count = count; 333 } 334 pas_write(pas_read(0x0B8A) | 0x80 | 0x40, 0x0B8A); 335#ifdef NO_TRIGGER 336 pas_write((pas_read(0xF8A) | 0x40) & ~0x10, 0xF8A); 337#endif 338 339 pcm_mode = PCM_ADC; 340 341 spin_unlock_irqrestore(&pas_lock, flags); 342} 343 344#ifndef NO_TRIGGER 345static void pas_audio_trigger(int dev, int state) 346{ 347 unsigned long flags; 348 349 spin_lock_irqsave(&pas_lock, flags); 350 state &= open_mode; 351 352 if (state & PCM_ENABLE_OUTPUT) 353 pas_write(pas_read(0xF8A) | 0x40 | 0x10, 0xF8A); 354 else if (state & PCM_ENABLE_INPUT) 355 pas_write((pas_read(0xF8A) | 0x40) & ~0x10, 0xF8A); 356 else 357 pas_write(pas_read(0xF8A) & ~0x40, 0xF8A); 358 359 spin_unlock_irqrestore(&pas_lock, flags); 360} 361#endif 362 363static int pas_audio_prepare_for_input(int dev, int bsize, int bcount) 364{ 365 pas_audio_reset(dev); 366 return 0; 367} 368 369static int pas_audio_prepare_for_output(int dev, int bsize, int bcount) 370{ 371 pas_audio_reset(dev); 372 return 0; 373} 374 375static struct audio_driver pas_audio_driver = 376{ 377 .owner = THIS_MODULE, 378 .open = pas_audio_open, 379 .close = pas_audio_close, 380 .output_block = pas_audio_output_block, 381 .start_input = pas_audio_start_input, 382 .ioctl = pas_audio_ioctl, 383 .prepare_for_input = pas_audio_prepare_for_input, 384 .prepare_for_output = pas_audio_prepare_for_output, 385 .halt_io = pas_audio_reset, 386 .trigger = pas_audio_trigger 387}; 388 389void __init pas_pcm_init(struct address_info *hw_config) 390{ 391 DEB(printk("pas2_pcm.c: long pas_pcm_init()\n")); 392 393 pcm_bitsok = 8; 394 if (pas_read(0xEF8B) & 0x08) 395 pcm_bitsok |= 16; 396 397 pcm_set_speed(DSP_DEFAULT_SPEED); 398 399 if ((pas_audiodev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, 400 "Pro Audio Spectrum", 401 &pas_audio_driver, 402 sizeof(struct audio_driver), 403 DMA_AUTOMODE, 404 AFMT_U8 | AFMT_S16_LE, 405 NULL, 406 hw_config->dma, 407 hw_config->dma)) < 0) 408 printk(KERN_WARNING "PAS16: Too many PCM devices available\n"); 409} 410 411void pas_pcm_interrupt(unsigned char status, int cause) 412{ 413 if (cause == 1) 414 { 415 /* 416 * Halt the PCM first. Otherwise we don't have time to start a new 417 * block before the PCM chip proceeds to the next sample 418 */ 419 420 if (!(audio_devs[pas_audiodev]->flags & DMA_AUTOMODE)) 421 pas_write(pas_read(0xF8A) & ~0x40, 0xF8A); 422 423 switch (pcm_mode) 424 { 425 case PCM_DAC: 426 DMAbuf_outputintr(pas_audiodev, 1); 427 break; 428 429 case PCM_ADC: 430 DMAbuf_inputintr(pas_audiodev); 431 break; 432 433 default: 434 printk(KERN_WARNING "PAS: Unexpected PCM interrupt\n"); 435 } 436 } 437} 438