warning: ignoring return value of 'request_irq', declared with attribute warn_unused_result Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
		
			
				
	
	
		
			639 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			639 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  *  linux/sound/oss/dmasound/dmasound_q40.c
 | |
|  *
 | |
|  *  Q40 DMA Sound Driver
 | |
|  *
 | |
|  *  See linux/sound/oss/dmasound/dmasound_core.c for copyright and credits
 | |
|  *  prior to 28/01/2001
 | |
|  *
 | |
|  *  28/01/2001 [0.1] Iain Sandoe
 | |
|  *		     - added versioning
 | |
|  *		     - put in and populated the hardware_afmts field.
 | |
|  *             [0.2] - put in SNDCTL_DSP_GETCAPS value.
 | |
|  *	       [0.3] - put in default hard/soft settings.
 | |
|  */
 | |
| 
 | |
| 
 | |
| #include <linux/module.h>
 | |
| #include <linux/init.h>
 | |
| #include <linux/slab.h>
 | |
| #include <linux/soundcard.h>
 | |
| #include <linux/interrupt.h>
 | |
| 
 | |
| #include <asm/uaccess.h>
 | |
| #include <asm/q40ints.h>
 | |
| #include <asm/q40_master.h>
 | |
| 
 | |
| #include "dmasound.h"
 | |
| 
 | |
| #define DMASOUND_Q40_REVISION 0
 | |
| #define DMASOUND_Q40_EDITION 3
 | |
| 
 | |
| static int expand_bal;	/* Balance factor for expanding (not volume!) */
 | |
| static int expand_data;	/* Data for expanding */
 | |
| 
 | |
| 
 | |
| /*** Low level stuff *********************************************************/
 | |
| 
 | |
| 
 | |
| static void *Q40Alloc(unsigned int size, gfp_t flags);
 | |
| static void Q40Free(void *, unsigned int);
 | |
| static int Q40IrqInit(void);
 | |
| #ifdef MODULE
 | |
| static void Q40IrqCleanUp(void);
 | |
| #endif
 | |
| static void Q40Silence(void);
 | |
| static void Q40Init(void);
 | |
| static int Q40SetFormat(int format);
 | |
| static int Q40SetVolume(int volume);
 | |
| static void Q40PlayNextFrame(int index);
 | |
| static void Q40Play(void);
 | |
| static irqreturn_t Q40StereoInterrupt(int irq, void *dummy);
 | |
| static irqreturn_t Q40MonoInterrupt(int irq, void *dummy);
 | |
| static void Q40Interrupt(void);
 | |
| 
 | |
| 
 | |
| /*** Mid level stuff *********************************************************/
 | |
| 
 | |
| 
 | |
| 
 | |
| /* userCount, frameUsed, frameLeft == byte counts */
 | |
| static ssize_t q40_ct_law(const u_char __user *userPtr, size_t userCount,
 | |
| 			   u_char frame[], ssize_t *frameUsed,
 | |
| 			   ssize_t frameLeft)
 | |
| {
 | |
| 	char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8: dmasound_alaw2dma8;
 | |
| 	ssize_t count, used;
 | |
| 	u_char *p = (u_char *) &frame[*frameUsed];
 | |
| 
 | |
| 	used = count = min_t(size_t, userCount, frameLeft);
 | |
| 	if (copy_from_user(p,userPtr,count))
 | |
| 	  return -EFAULT;
 | |
| 	while (count > 0) {
 | |
| 		*p = table[*p]+128;
 | |
| 		p++;
 | |
| 		count--;
 | |
| 	}
 | |
| 	*frameUsed += used ;
 | |
| 	return used;
 | |
| }
 | |
| 
 | |
| 
 | |
| static ssize_t q40_ct_s8(const u_char __user *userPtr, size_t userCount,
 | |
| 			  u_char frame[], ssize_t *frameUsed,
 | |
| 			  ssize_t frameLeft)
 | |
| {
 | |
| 	ssize_t count, used;
 | |
| 	u_char *p = (u_char *) &frame[*frameUsed];
 | |
| 
 | |
| 	used = count = min_t(size_t, userCount, frameLeft);
 | |
| 	if (copy_from_user(p,userPtr,count))
 | |
| 	  return -EFAULT;
 | |
| 	while (count > 0) {
 | |
| 		*p = *p + 128;
 | |
| 		p++;
 | |
| 		count--;
 | |
| 	}
 | |
| 	*frameUsed += used;
 | |
| 	return used;
 | |
| }
 | |
| 
 | |
| static ssize_t q40_ct_u8(const u_char __user *userPtr, size_t userCount,
 | |
| 			  u_char frame[], ssize_t *frameUsed,
 | |
| 			  ssize_t frameLeft)
 | |
| {
 | |
| 	ssize_t count, used;
 | |
| 	u_char *p = (u_char *) &frame[*frameUsed];
 | |
| 
 | |
| 	used = count = min_t(size_t, userCount, frameLeft);
 | |
| 	if (copy_from_user(p,userPtr,count))
 | |
| 	  return -EFAULT;
 | |
| 	*frameUsed += used;
 | |
| 	return used;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* a bit too complicated to optimise right now ..*/
 | |
| static ssize_t q40_ctx_law(const u_char __user *userPtr, size_t userCount,
 | |
| 			    u_char frame[], ssize_t *frameUsed,
 | |
| 			    ssize_t frameLeft)
 | |
| {
 | |
| 	unsigned char *table = (unsigned char *)
 | |
| 		(dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8: dmasound_alaw2dma8);
 | |
| 	unsigned int data = expand_data;
 | |
| 	u_char *p = (u_char *) &frame[*frameUsed];
 | |
| 	int bal = expand_bal;
 | |
| 	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
 | |
| 	int utotal, ftotal;
 | |
| 
 | |
| 	ftotal = frameLeft;
 | |
| 	utotal = userCount;
 | |
| 	while (frameLeft) {
 | |
| 		u_char c;
 | |
| 		if (bal < 0) {
 | |
| 			if (userCount == 0)
 | |
| 				break;
 | |
| 			if (get_user(c, userPtr++))
 | |
| 				return -EFAULT;
 | |
| 			data = table[c];
 | |
| 			data += 0x80;
 | |
| 			userCount--;
 | |
| 			bal += hSpeed;
 | |
| 		}
 | |
| 		*p++ = data;
 | |
| 		frameLeft--;
 | |
| 		bal -= sSpeed;
 | |
| 	}
 | |
| 	expand_bal = bal;
 | |
| 	expand_data = data;
 | |
| 	*frameUsed += (ftotal - frameLeft);
 | |
| 	utotal -= userCount;
 | |
| 	return utotal;
 | |
| }
 | |
| 
 | |
| 
 | |
| static ssize_t q40_ctx_s8(const u_char __user *userPtr, size_t userCount,
 | |
| 			   u_char frame[], ssize_t *frameUsed,
 | |
| 			   ssize_t frameLeft)
 | |
| {
 | |
| 	u_char *p = (u_char *) &frame[*frameUsed];
 | |
| 	unsigned int data = expand_data;
 | |
| 	int bal = expand_bal;
 | |
| 	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
 | |
| 	int utotal, ftotal;
 | |
| 
 | |
| 
 | |
| 	ftotal = frameLeft;
 | |
| 	utotal = userCount;
 | |
| 	while (frameLeft) {
 | |
| 		u_char c;
 | |
| 		if (bal < 0) {
 | |
| 			if (userCount == 0)
 | |
| 				break;
 | |
| 			if (get_user(c, userPtr++))
 | |
| 				return -EFAULT;
 | |
| 			data = c ;
 | |
| 			data += 0x80;
 | |
| 			userCount--;
 | |
| 			bal += hSpeed;
 | |
| 		}
 | |
| 		*p++ = data;
 | |
| 		frameLeft--;
 | |
| 		bal -= sSpeed;
 | |
| 	}
 | |
| 	expand_bal = bal;
 | |
| 	expand_data = data;
 | |
| 	*frameUsed += (ftotal - frameLeft);
 | |
| 	utotal -= userCount;
 | |
| 	return utotal;
 | |
| }
 | |
| 
 | |
| 
 | |
| static ssize_t q40_ctx_u8(const u_char __user *userPtr, size_t userCount,
 | |
| 			   u_char frame[], ssize_t *frameUsed,
 | |
| 			   ssize_t frameLeft)
 | |
| {
 | |
| 	u_char *p = (u_char *) &frame[*frameUsed];
 | |
| 	unsigned int data = expand_data;
 | |
| 	int bal = expand_bal;
 | |
| 	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
 | |
| 	int utotal, ftotal;
 | |
| 
 | |
| 	ftotal = frameLeft;
 | |
| 	utotal = userCount;
 | |
| 	while (frameLeft) {
 | |
| 		u_char c;
 | |
| 		if (bal < 0) {
 | |
| 			if (userCount == 0)
 | |
| 				break;
 | |
| 			if (get_user(c, userPtr++))
 | |
| 				return -EFAULT;
 | |
| 			data = c ;
 | |
| 			userCount--;
 | |
| 			bal += hSpeed;
 | |
| 		}
 | |
| 		*p++ = data;
 | |
| 		frameLeft--;
 | |
| 		bal -= sSpeed;
 | |
| 	}
 | |
| 	expand_bal = bal;
 | |
| 	expand_data = data;
 | |
| 	*frameUsed += (ftotal - frameLeft) ;
 | |
| 	utotal -= userCount;
 | |
| 	return utotal;
 | |
| }
 | |
| 
 | |
| /* compressing versions */
 | |
| static ssize_t q40_ctc_law(const u_char __user *userPtr, size_t userCount,
 | |
| 			    u_char frame[], ssize_t *frameUsed,
 | |
| 			    ssize_t frameLeft)
 | |
| {
 | |
| 	unsigned char *table = (unsigned char *)
 | |
| 		(dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8: dmasound_alaw2dma8);
 | |
| 	unsigned int data = expand_data;
 | |
| 	u_char *p = (u_char *) &frame[*frameUsed];
 | |
| 	int bal = expand_bal;
 | |
| 	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
 | |
| 	int utotal, ftotal;
 | |
|  
 | |
| 	ftotal = frameLeft;
 | |
| 	utotal = userCount;
 | |
| 	while (frameLeft) {
 | |
| 		u_char c;
 | |
| 		while(bal<0) {
 | |
| 			if (userCount == 0)
 | |
| 				goto lout;
 | |
| 			if (!(bal<(-hSpeed))) {
 | |
| 				if (get_user(c, userPtr))
 | |
| 					return -EFAULT;
 | |
| 				data = 0x80 + table[c];
 | |
| 			}
 | |
| 			userPtr++;
 | |
| 			userCount--;
 | |
| 			bal += hSpeed;
 | |
| 		}
 | |
| 		*p++ = data;
 | |
| 		frameLeft--;
 | |
| 		bal -= sSpeed;
 | |
| 	}
 | |
|  lout:
 | |
| 	expand_bal = bal;
 | |
| 	expand_data = data;
 | |
| 	*frameUsed += (ftotal - frameLeft);
 | |
| 	utotal -= userCount;
 | |
| 	return utotal;
 | |
| }
 | |
| 
 | |
| 
 | |
| static ssize_t q40_ctc_s8(const u_char __user *userPtr, size_t userCount,
 | |
| 			   u_char frame[], ssize_t *frameUsed,
 | |
| 			   ssize_t frameLeft)
 | |
| {
 | |
| 	u_char *p = (u_char *) &frame[*frameUsed];
 | |
| 	unsigned int data = expand_data;
 | |
| 	int bal = expand_bal;
 | |
| 	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
 | |
| 	int utotal, ftotal;
 | |
| 
 | |
| 	ftotal = frameLeft;
 | |
| 	utotal = userCount;
 | |
| 	while (frameLeft) {
 | |
| 		u_char c;
 | |
| 		while (bal < 0) {
 | |
| 			if (userCount == 0)
 | |
| 				goto lout;
 | |
| 			if (!(bal<(-hSpeed))) {
 | |
| 				if (get_user(c, userPtr))
 | |
| 					return -EFAULT;
 | |
| 				data = c + 0x80;
 | |
| 			}
 | |
| 			userPtr++;
 | |
| 			userCount--;
 | |
| 			bal += hSpeed;
 | |
| 		}
 | |
| 		*p++ = data;
 | |
| 		frameLeft--;
 | |
| 		bal -= sSpeed;
 | |
| 	}
 | |
|  lout:
 | |
| 	expand_bal = bal;
 | |
| 	expand_data = data;
 | |
| 	*frameUsed += (ftotal - frameLeft);
 | |
| 	utotal -= userCount;
 | |
| 	return utotal;
 | |
| }
 | |
| 
 | |
| 
 | |
| static ssize_t q40_ctc_u8(const u_char __user *userPtr, size_t userCount,
 | |
| 			   u_char frame[], ssize_t *frameUsed,
 | |
| 			   ssize_t frameLeft)
 | |
| {
 | |
| 	u_char *p = (u_char *) &frame[*frameUsed];
 | |
| 	unsigned int data = expand_data;
 | |
| 	int bal = expand_bal;
 | |
| 	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
 | |
| 	int utotal, ftotal;
 | |
| 
 | |
| 	ftotal = frameLeft;
 | |
| 	utotal = userCount;
 | |
| 	while (frameLeft) {
 | |
| 		u_char c;
 | |
| 		while (bal < 0) {
 | |
| 			if (userCount == 0)
 | |
| 				goto lout;
 | |
| 			if (!(bal<(-hSpeed))) {
 | |
| 				if (get_user(c, userPtr))
 | |
| 					return -EFAULT;
 | |
| 				data = c ;
 | |
| 			}
 | |
| 			userPtr++;
 | |
| 			userCount--;
 | |
| 			bal += hSpeed;
 | |
| 		}
 | |
| 		*p++ = data;
 | |
| 		frameLeft--;
 | |
| 		bal -= sSpeed;
 | |
| 	}
 | |
|  lout:
 | |
| 	expand_bal = bal;
 | |
| 	expand_data = data;
 | |
| 	*frameUsed += (ftotal - frameLeft) ;
 | |
| 	utotal -= userCount;
 | |
| 	return utotal;
 | |
| }
 | |
| 
 | |
| 
 | |
| static TRANS transQ40Normal = {
 | |
| 	q40_ct_law, q40_ct_law, q40_ct_s8, q40_ct_u8, NULL, NULL, NULL, NULL
 | |
| };
 | |
| 
 | |
| static TRANS transQ40Expanding = {
 | |
| 	q40_ctx_law, q40_ctx_law, q40_ctx_s8, q40_ctx_u8, NULL, NULL, NULL, NULL
 | |
| };
 | |
| 
 | |
| static TRANS transQ40Compressing = {
 | |
| 	q40_ctc_law, q40_ctc_law, q40_ctc_s8, q40_ctc_u8, NULL, NULL, NULL, NULL
 | |
| };
 | |
| 
 | |
| 
 | |
| /*** Low level stuff *********************************************************/
 | |
| 
 | |
| static void *Q40Alloc(unsigned int size, gfp_t flags)
 | |
| {
 | |
|          return kmalloc(size, flags); /* change to vmalloc */
 | |
| }
 | |
| 
 | |
| static void Q40Free(void *ptr, unsigned int size)
 | |
| {
 | |
| 	kfree(ptr);
 | |
| }
 | |
| 
 | |
| static int __init Q40IrqInit(void)
 | |
| {
 | |
| 	/* Register interrupt handler. */
 | |
| 	if (request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0,
 | |
| 		    "DMA sound", Q40Interrupt))
 | |
| 		return 0;
 | |
| 
 | |
| 	return(1);
 | |
| }
 | |
| 
 | |
| 
 | |
| #ifdef MODULE
 | |
| static void Q40IrqCleanUp(void)
 | |
| {
 | |
|         master_outb(0,SAMPLE_ENABLE_REG);
 | |
| 	free_irq(Q40_IRQ_SAMPLE, Q40Interrupt);
 | |
| }
 | |
| #endif /* MODULE */
 | |
| 
 | |
| 
 | |
| static void Q40Silence(void)
 | |
| {
 | |
|         master_outb(0,SAMPLE_ENABLE_REG);
 | |
| 	*DAC_LEFT=*DAC_RIGHT=127;
 | |
| }
 | |
| 
 | |
| static char *q40_pp;
 | |
| static unsigned int q40_sc;
 | |
| 
 | |
| static void Q40PlayNextFrame(int index)
 | |
| {
 | |
| 	u_char *start;
 | |
| 	u_long size;
 | |
| 	u_char speed;
 | |
| 	int error;
 | |
| 
 | |
| 	/* used by Q40Play() if all doubts whether there really is something
 | |
| 	 * to be played are already wiped out.
 | |
| 	 */
 | |
| 	start = write_sq.buffers[write_sq.front];
 | |
| 	size = (write_sq.count == index ? write_sq.rear_size : write_sq.block_size);
 | |
| 
 | |
| 	q40_pp=start;
 | |
| 	q40_sc=size;
 | |
| 
 | |
| 	write_sq.front = (write_sq.front+1) % write_sq.max_count;
 | |
| 	write_sq.active++;
 | |
| 
 | |
| 	speed=(dmasound.hard.speed==10000 ? 0 : 1);
 | |
| 
 | |
| 	master_outb( 0,SAMPLE_ENABLE_REG);
 | |
| 	free_irq(Q40_IRQ_SAMPLE, Q40Interrupt);
 | |
| 	if (dmasound.soft.stereo)
 | |
| 		error = request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0,
 | |
| 				    "Q40 sound", Q40Interrupt);
 | |
| 	  else
 | |
| 		error = request_irq(Q40_IRQ_SAMPLE, Q40MonoInterrupt, 0,
 | |
| 				    "Q40 sound", Q40Interrupt);
 | |
| 	if (error && printk_ratelimit())
 | |
| 		pr_err("Couldn't register sound interrupt\n");
 | |
| 
 | |
| 	master_outb( speed, SAMPLE_RATE_REG);
 | |
| 	master_outb( 1,SAMPLE_CLEAR_REG);
 | |
| 	master_outb( 1,SAMPLE_ENABLE_REG);
 | |
| }
 | |
| 
 | |
| static void Q40Play(void)
 | |
| {
 | |
|         unsigned long flags;
 | |
| 
 | |
| 	if (write_sq.active || write_sq.count<=0 ) {
 | |
| 		/* There's already a frame loaded */
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	/* nothing in the queue */
 | |
| 	if (write_sq.count <= 1 && write_sq.rear_size < write_sq.block_size && !write_sq.syncing) {
 | |
| 	         /* hmmm, the only existing frame is not
 | |
| 		  * yet filled and we're not syncing?
 | |
| 		  */
 | |
| 	         return;
 | |
| 	}
 | |
| 	spin_lock_irqsave(&dmasound.lock, flags);
 | |
| 	Q40PlayNextFrame(1);
 | |
| 	spin_unlock_irqrestore(&dmasound.lock, flags);
 | |
| }
 | |
| 
 | |
| static irqreturn_t Q40StereoInterrupt(int irq, void *dummy)
 | |
| {
 | |
| 	spin_lock(&dmasound.lock);
 | |
|         if (q40_sc>1){
 | |
|             *DAC_LEFT=*q40_pp++;
 | |
| 	    *DAC_RIGHT=*q40_pp++;
 | |
| 	    q40_sc -=2;
 | |
| 	    master_outb(1,SAMPLE_CLEAR_REG);
 | |
| 	}else Q40Interrupt();
 | |
| 	spin_unlock(&dmasound.lock);
 | |
| 	return IRQ_HANDLED;
 | |
| }
 | |
| static irqreturn_t Q40MonoInterrupt(int irq, void *dummy)
 | |
| {
 | |
| 	spin_lock(&dmasound.lock);
 | |
|         if (q40_sc>0){
 | |
|             *DAC_LEFT=*q40_pp;
 | |
| 	    *DAC_RIGHT=*q40_pp++;
 | |
| 	    q40_sc --;
 | |
| 	    master_outb(1,SAMPLE_CLEAR_REG);
 | |
| 	}else Q40Interrupt();
 | |
| 	spin_unlock(&dmasound.lock);
 | |
| 	return IRQ_HANDLED;
 | |
| }
 | |
| static void Q40Interrupt(void)
 | |
| {
 | |
| 	if (!write_sq.active) {
 | |
| 	          /* playing was interrupted and sq_reset() has already cleared
 | |
| 		   * the sq variables, so better don't do anything here.
 | |
| 		   */
 | |
| 	           WAKE_UP(write_sq.sync_queue);
 | |
| 		   master_outb(0,SAMPLE_ENABLE_REG); /* better safe */
 | |
| 		   goto exit;
 | |
| 	} else write_sq.active=0;
 | |
| 	write_sq.count--;
 | |
| 	Q40Play();
 | |
| 
 | |
| 	if (q40_sc<2)
 | |
| 	      { /* there was nothing to play, disable irq */
 | |
| 		master_outb(0,SAMPLE_ENABLE_REG);
 | |
| 		*DAC_LEFT=*DAC_RIGHT=127;
 | |
| 	      }
 | |
| 	WAKE_UP(write_sq.action_queue);
 | |
| 
 | |
|  exit:
 | |
| 	master_outb(1,SAMPLE_CLEAR_REG);
 | |
| }
 | |
| 
 | |
| 
 | |
| static void Q40Init(void)
 | |
| {
 | |
| 	int i, idx;
 | |
| 	const int freq[] = {10000, 20000};
 | |
| 
 | |
| 	/* search a frequency that fits into the allowed error range */
 | |
| 
 | |
| 	idx = -1;
 | |
| 	for (i = 0; i < 2; i++)
 | |
| 		if ((100 * abs(dmasound.soft.speed - freq[i]) / freq[i]) <= catchRadius)
 | |
| 			idx = i;
 | |
| 
 | |
| 	dmasound.hard = dmasound.soft;
 | |
| 	/*sound.hard.stereo=1;*/ /* no longer true */
 | |
| 	dmasound.hard.size=8;
 | |
| 
 | |
| 	if (idx > -1) {
 | |
| 		dmasound.soft.speed = freq[idx];
 | |
| 		dmasound.trans_write = &transQ40Normal;
 | |
| 	} else
 | |
| 		dmasound.trans_write = &transQ40Expanding;
 | |
| 
 | |
| 	Q40Silence();
 | |
| 
 | |
| 	if (dmasound.hard.speed > 20200) {
 | |
| 		/* squeeze the sound, we do that */
 | |
| 		dmasound.hard.speed = 20000;
 | |
| 		dmasound.trans_write = &transQ40Compressing;
 | |
| 	} else if (dmasound.hard.speed > 10000) {
 | |
| 		dmasound.hard.speed = 20000;
 | |
| 	} else {
 | |
| 		dmasound.hard.speed = 10000;
 | |
| 	}
 | |
| 	expand_bal = -dmasound.soft.speed;
 | |
| }
 | |
| 
 | |
| 
 | |
| static int Q40SetFormat(int format)
 | |
| {
 | |
| 	/* Q40 sound supports only 8bit modes */
 | |
| 
 | |
| 	switch (format) {
 | |
| 	case AFMT_QUERY:
 | |
| 		return(dmasound.soft.format);
 | |
| 	case AFMT_MU_LAW:
 | |
| 	case AFMT_A_LAW:
 | |
| 	case AFMT_S8:
 | |
| 	case AFMT_U8:
 | |
| 		break;
 | |
| 	default:
 | |
| 		format = AFMT_S8;
 | |
| 	}
 | |
| 
 | |
| 	dmasound.soft.format = format;
 | |
| 	dmasound.soft.size = 8;
 | |
| 	if (dmasound.minDev == SND_DEV_DSP) {
 | |
| 		dmasound.dsp.format = format;
 | |
| 		dmasound.dsp.size = 8;
 | |
| 	}
 | |
| 	Q40Init();
 | |
| 
 | |
| 	return(format);
 | |
| }
 | |
| 
 | |
| static int Q40SetVolume(int volume)
 | |
| {
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*** Machine definitions *****************************************************/
 | |
| 
 | |
| static SETTINGS def_hard = {
 | |
| 	.format	= AFMT_U8,
 | |
| 	.stereo	= 0,
 | |
| 	.size	= 8,
 | |
| 	.speed	= 10000
 | |
| } ;
 | |
| 
 | |
| static SETTINGS def_soft = {
 | |
| 	.format	= AFMT_U8,
 | |
| 	.stereo	= 0,
 | |
| 	.size	= 8,
 | |
| 	.speed	= 8000
 | |
| } ;
 | |
| 
 | |
| static MACHINE machQ40 = {
 | |
| 	.name		= "Q40",
 | |
| 	.name2		= "Q40",
 | |
| 	.owner		= THIS_MODULE,
 | |
| 	.dma_alloc	= Q40Alloc,
 | |
| 	.dma_free	= Q40Free,
 | |
| 	.irqinit	= Q40IrqInit,
 | |
| #ifdef MODULE
 | |
| 	.irqcleanup	= Q40IrqCleanUp,
 | |
| #endif /* MODULE */
 | |
| 	.init		= Q40Init,
 | |
| 	.silence	= Q40Silence,
 | |
| 	.setFormat	= Q40SetFormat,
 | |
| 	.setVolume	= Q40SetVolume,
 | |
| 	.play		= Q40Play,
 | |
|  	.min_dsp_speed	= 10000,
 | |
| 	.version	= ((DMASOUND_Q40_REVISION<<8) | DMASOUND_Q40_EDITION),
 | |
| 	.hardware_afmts	= AFMT_U8, /* h'ware-supported formats *only* here */
 | |
| 	.capabilities	= DSP_CAP_BATCH  /* As per SNDCTL_DSP_GETCAPS */
 | |
| };
 | |
| 
 | |
| 
 | |
| /*** Config & Setup **********************************************************/
 | |
| 
 | |
| 
 | |
| static int __init dmasound_q40_init(void)
 | |
| {
 | |
| 	if (MACH_IS_Q40) {
 | |
| 	    dmasound.mach = machQ40;
 | |
| 	    dmasound.mach.default_hard = def_hard ;
 | |
| 	    dmasound.mach.default_soft = def_soft ;
 | |
| 	    return dmasound_init();
 | |
| 	} else
 | |
| 	    return -ENODEV;
 | |
| }
 | |
| 
 | |
| static void __exit dmasound_q40_cleanup(void)
 | |
| {
 | |
| 	dmasound_deinit();
 | |
| }
 | |
| 
 | |
| module_init(dmasound_q40_init);
 | |
| module_exit(dmasound_q40_cleanup);
 | |
| 
 | |
| MODULE_DESCRIPTION("Q40/Q60 sound driver");
 | |
| MODULE_LICENSE("GPL");
 |