Linux Audio

Check our new training course

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