Date: Wed, 29 Jan 1997 18:30:44 +0100 (MET)
From: Tomas Berndtsson <tobe@lysator.liu.se>
To: Linux-m68k List <linux-m68k@phil.uni-sb.de>
Subject: L68K: DSP56k device driver in kernel
Sender: owner-linux-m68k@phil.uni-sb.de
Reply-To: linux-m68k@phil.uni-sb.de

Hi!

I have now integrated the DSP56k driver into the linux 2.1.21 source tree.
The patches are made to my patched tree from the distributed package 
without any other patches, so there are a few places where other changes, 
others than my own that are also in this patch. I'm sorry for that.

I put it in the configuration as an experimental driver. These patches
also adds a hardware check if a DSP56k is present. I haven't tested this
more than on my Falcon. So, someone with a TT, please test it.

These are the files affected by this patch:

   drivers/char/dsp56k.c         (NEW)
   include/asm-m68k/dsp56k.h     (NEW)
   drivers/char/misc.c
   drivers/char/Makefile         (+ previous patches)
   include/linux/major.h
   include/asm-m68k/atarihw.h    (+ previous patches)
   arch/m68k/atari/config.c      (+ previous patches)
   arch/m68k/config.in
   Documentation/Configure.help


The DSP56k device has major number 55 and minor number 0. 

if you don't have it, do this:
mknod /dev/dsp56k c 55 0


Only Atari Falcon DSP56001 is supported in this driver, and only host
transfer. All matrix related communication with the DSP56001 is handled
by /dev/matrix. The matrix driver is still under development, but will
hopefully go under device major 14, soundcards.

The kernel implemented DSP56k driver has only been tested with the mp2
audio player by NoCrew, and only compiled in the kernel, not as a module.
But, it should be no problem to use as a module. If anyone wants to test
it, I'd be happy. I'm not so eager to recompile my kernel just yet. :)


If you'd like to test it with the mp2 player, you can get the rest of the 
things needed from ftp://ftp.nocrew.pp.se/pub/nocrew/linux/


- Tomas

--
Tomas Berndtsson
tobe@lysator.liu.se
http://www.lysator.liu.se/~tobe


+++ linux-2.1.21/drivers/char/dsp56k.c	Wed Jan 29 16:03:56 1997
@@ -0,0 +1,564 @@
+/*
+ * The DSP56001 Device Driver, saviour of the Free World(tm)
+ *
+ * Authors: Fredrik Noring   <noring@lysator.liu.se>
+ *          lars brinkhoff   <f93labr@dd.chalmers.se>
+ *          Tomas Berndtsson <tobe@lysator.liu.se>
+ *
+ * First version May 1996
+ *
+ * History:
+ *  97-01-29   Tomas Berndtsson,
+ *               Integrated with Linux 2.1.21 kernel sources.
+ *
+ * BUGS:
+ *  Hmm... there must be something here :)
+ *
+ * Copyright (C) 1996,1997 Fredrik Noring, lars brinkhoff & Tomas Berndtsson
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/malloc.h>	/* for kmalloc() and kfree() */
+#include <linux/sched.h>	/* for struct wait_queue etc */
+#include <linux/major.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>	/* guess what */
+#include <linux/fs.h>
+#include <linux/mm.h>
+
+#include <asm/segment.h>
+#include <asm/atarihw.h>
+#include <asm/traps.h>
+#include <asm/uaccess.h>	/* For put_user and get_user */
+
+#include <asm/dsp56k.h>
+
+/* minor devices */
+#define DSP56K_DEV_56001        0    /* The only device so far */
+
+#define TIMEOUT    10   /* Host port timeout in number of tries */
+#define MAXIO    2048   /* Maximum number of words before sleep */
+#define DSP56K_MAX_BINARY_LENGTH (3*64*1024)
+
+#define DSP56K_TX_INT_ON	dsp56k_host_interface.icr |=  DSP56K_ICR_TREQ
+#define DSP56K_RX_INT_ON	dsp56k_host_interface.icr |=  DSP56K_ICR_RREQ
+#define DSP56K_TX_INT_OFF	dsp56k_host_interface.icr &= ~DSP56K_ICR_TREQ
+#define DSP56K_RX_INT_OFF	dsp56k_host_interface.icr &= ~DSP56K_ICR_RREQ
+
+#define DSP56K_TRANSMIT		(dsp56k_host_interface.isr & DSP56K_ISR_TXDE)
+#define DSP56K_RECEIVE		(dsp56k_host_interface.isr & DSP56K_ISR_RXDF)
+
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#define min(a,b) ((a) < (b) ? (a) : (b))
+
+#define wait_some(n) \
+{ \
+	current->state = TASK_INTERRUPTIBLE; \
+	current->timeout = jiffies + n; \
+	schedule(); \
+}
+
+#define handshake(count, maxio, timeout, ENABLE, f) \
+{ \
+	long i, t, m; \
+	while (count > 0) { \
+		m = min(count, maxio); \
+		for (i = 0; i < m; i++) { \
+			for (t = 0; t < timeout && !ENABLE; t++) \
+				wait_some(2); \
+			if(!ENABLE) \
+				return -EIO; \
+			f; \
+		} \
+		count -= m; \
+		if (m == maxio) wait_some(2); \
+	} \
+}
+
+#define tx_wait(n) \
+{ \
+	int t; \
+	for(t = 0; t < n && !DSP56K_TRANSMIT; t++) \
+		wait_some(1); \
+	if(!DSP56K_TRANSMIT) { \
+		return -EIO; \
+	} \
+}
+
+#define rx_wait(n) \
+{ \
+	int t; \
+	for(t = 0; t < n && !DSP56K_RECEIVE; t++) \
+		wait_some(1); \
+	if(!DSP56K_RECEIVE) { \
+		return -EIO; \
+	} \
+}
+
+/* DSP56001 bootstrap code */
+static char bootstrap[] = {
+	0x0c, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x60, 0xf4, 0x00, 0x00, 0x00, 0x4f, 0x61, 0xf4,
+	0x00, 0x00, 0x7e, 0xa9, 0x06, 0x2e, 0x80, 0x00, 0x00, 0x47,
+	0x07, 0xd8, 0x84, 0x07, 0x59, 0x84, 0x08, 0xf4, 0xa8, 0x00,
+	0x00, 0x04, 0x08, 0xf4, 0xbf, 0x00, 0x0c, 0x00, 0x00, 0xfe,
+	0xb8, 0x0a, 0xf0, 0x80, 0x00, 0x7e, 0xa9, 0x08, 0xf4, 0xa0,
+	0x00, 0x00, 0x01, 0x08, 0xf4, 0xbe, 0x00, 0x00, 0x00, 0x0a,
+	0xa9, 0x80, 0x00, 0x7e, 0xad, 0x08, 0x4e, 0x2b, 0x44, 0xf4,
+	0x00, 0x00, 0x00, 0x03, 0x44, 0xf4, 0x45, 0x00, 0x00, 0x01,
+	0x0e, 0xa0, 0x00, 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xb5, 0x08,
+	0x50, 0x2b, 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xb8, 0x08, 0x46,
+	0x2b, 0x44, 0xf4, 0x45, 0x00, 0x00, 0x02, 0x0a, 0xf0, 0xaa,
+	0x00, 0x7e, 0xc9, 0x20, 0x00, 0x45, 0x0a, 0xf0, 0xaa, 0x00,
+	0x7e, 0xd0, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xc6, 0x0a, 0xa9,
+	0x80, 0x00, 0x7e, 0xc4, 0x08, 0x58, 0x6b, 0x0a, 0xf0, 0x80,
+	0x00, 0x7e, 0xad, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xcd, 0x0a,
+	0xa9, 0x80, 0x00, 0x7e, 0xcb, 0x08, 0x58, 0xab, 0x0a, 0xf0,
+	0x80, 0x00, 0x7e, 0xad, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xd4,
+	0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xd2, 0x08, 0x58, 0xeb, 0x0a,
+	0xf0, 0x80, 0x00, 0x7e, 0xad};
+static int sizeof_bootstrap = 375;
+
+
+static struct dsp56k_device {
+	int in_use;
+	long maxio, timeout;
+	int tx_wsize, rx_wsize;
+} dsp56k;
+
+static int dsp56k_reset(void)
+{
+	u_char status;
+	
+	/* Power down the DSP */
+	sound_ym.rd_data_reg_sel = 14;
+	status = sound_ym.rd_data_reg_sel & 0xef;
+	sound_ym.wd_data = status;
+	sound_ym.wd_data = status | 0x10;
+  
+	udelay(10);
+  
+	/* Power up the DSP */
+	sound_ym.rd_data_reg_sel = 14;
+	sound_ym.wd_data = sound_ym.rd_data_reg_sel & 0xef;
+
+	return 0;
+}
+
+static int dsp56k_upload(u_char *bin, int len)
+{
+	int i;
+	u_char *p;
+	
+	dsp56k_reset();
+  
+	p = bootstrap;
+	for (i = 0; i < sizeof_bootstrap/3; i++) {
+		/* tx_wait(10); */
+		dsp56k_host_interface.data.b[1] = *p++;
+		dsp56k_host_interface.data.b[2] = *p++;
+		dsp56k_host_interface.data.b[3] = *p++;
+	}
+	for (; i < 512; i++) {
+		/* tx_wait(10); */
+		dsp56k_host_interface.data.b[1] = 0;
+		dsp56k_host_interface.data.b[2] = 0;
+		dsp56k_host_interface.data.b[3] = 0;
+	}
+  
+	for (i = 0; i < len; i++) {
+		tx_wait(10);
+		get_user(dsp56k_host_interface.data.b[1], bin++);
+		get_user(dsp56k_host_interface.data.b[2], bin++);
+		get_user(dsp56k_host_interface.data.b[3], bin++);
+	}
+
+	tx_wait(10);
+	dsp56k_host_interface.data.l = 3;    /* Magic execute */
+
+	return 0;
+}
+
+static long dsp56k_read(struct inode *inode, struct file *file,
+			char *buf, unsigned long count)
+{
+	int dev = MINOR(inode->i_rdev) & 0x0f;
+
+	switch(dev)
+	{
+	case DSP56K_DEV_56001:
+	{
+
+		long n;
+
+		/* Don't do anything if nothing is to be done */
+		if (!count) return 0;
+
+		n = 0;
+		switch (dsp56k.rx_wsize) {
+		case 1:  /* 8 bit */
+		{
+			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
+				  put_user(dsp56k_host_interface.data.b[3], buf+n++));
+			return n;
+		}
+		case 2:  /* 16 bit */
+		{
+			short *data;
+
+			count /= 2;
+			data = (short*) buf;
+			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
+				  put_user(dsp56k_host_interface.data.w[1], data+n++));
+			return 2*n;
+		}
+		case 3:  /* 24 bit */
+		{
+			count /= 3;
+			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
+				  put_user(dsp56k_host_interface.data.b[1], buf+n++);
+				  put_user(dsp56k_host_interface.data.b[2], buf+n++);
+				  put_user(dsp56k_host_interface.data.b[3], buf+n++));
+			return 3*n;
+		}
+		case 4:  /* 32 bit */
+		{
+			long *data;
+
+			count /= 4;
+			data = (long*) buf;
+			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
+				  put_user(dsp56k_host_interface.data.l, data+n++));
+			return 4*n;
+		}
+		}
+		return -EFAULT;
+	}
+
+	default:
+		printk("DSP56k driver: Unknown minor device: %d\n", dev);
+		return -ENXIO;
+	}
+}
+
+static long dsp56k_write(struct inode *inode, struct file *file,
+			 const char *buf, unsigned long count)
+{
+	int dev = MINOR(inode->i_rdev) & 0x0f;
+
+	switch(dev)
+	{
+	case DSP56K_DEV_56001:
+	{
+		long n;
+
+		/* Don't do anything if nothing is to be done */
+		if (!count) return 0;
+
+		n = 0;
+		switch (dsp56k.tx_wsize) {
+		case 1:  /* 8 bit */
+		{
+			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
+				  get_user(dsp56k_host_interface.data.b[3], buf+n++));
+			return n;
+		}
+		case 2:  /* 16 bit */
+		{
+			short *data;
+
+			count /= 2;
+			data = (short*) buf;
+			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
+				  get_user(dsp56k_host_interface.data.w[1], data+n++));
+			return 2*n;
+		}
+		case 3:  /* 24 bit */
+		{
+			count /= 3;
+			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
+				  get_user(dsp56k_host_interface.data.b[1], buf+n++);
+				  get_user(dsp56k_host_interface.data.b[2], buf+n++);
+				  get_user(dsp56k_host_interface.data.b[3], buf+n++));
+			return 3*n;
+		}
+		case 4:  /* 32 bit */
+		{
+			long *data;
+
+			count /= 4;
+			data = (long*) buf;
+			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
+				  get_user(dsp56k_host_interface.data.l, data+n++));
+			return 4*n;
+		}
+		}
+
+		return -EFAULT;
+	}
+	default:
+		printk("DSP56k driver: Unknown minor device: %d\n", dev);
+		return -ENXIO;
+	}
+}
+
+static int dsp56k_ioctl(struct inode *inode, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	int dev = MINOR(inode->i_rdev) & 0x0f;
+
+	switch(dev)
+	{
+	case DSP56K_DEV_56001:
+
+		switch(cmd) {
+		case DSP56K_UPLOAD:
+		{
+			char *bin;
+			int r, len;
+			struct dsp56k_upload *binary = (struct dsp56k_upload *) arg;
+    
+			if(get_user(len, &binary->len) < 0)
+				return -EFAULT;
+			if(get_user(bin, &binary->bin) < 0)
+				return -EFAULT;
+		
+			if (len == 0) {
+				return -EINVAL;      /* nothing to upload?!? */
+			}
+			if (len > DSP56K_MAX_BINARY_LENGTH) {
+				return -EINVAL;
+			}
+    
+			r = dsp56k_upload(bin, len);
+			if (r < 0) {
+				return r;
+			}
+    
+			break;
+		}
+		case DSP56K_SET_TX_WSIZE:
+			if (arg > 4 || arg < 1)
+				return -EINVAL;
+			dsp56k.tx_wsize = (int) arg;
+			break;
+		case DSP56K_SET_RX_WSIZE:
+			if (arg > 4 || arg < 1)
+				return -EINVAL;
+			dsp56k.rx_wsize = (int) arg;
+			break;
+		case DSP56K_HOST_FLAGS:
+		{
+			int dir, out, status;
+			struct dsp56k_host_flags *hf = (struct dsp56k_host_flags*) arg;
+    
+			if(get_user(dir, &hf->dir) < 0)
+				return -EFAULT;
+			if(get_user(out, &hf->out) < 0)
+				return -EFAULT;
+
+			if ((dir & 0x1) && (out & 0x1))
+				dsp56k_host_interface.icr |= DSP56K_ICR_HF0;
+			else if (dir & 0x1)
+				dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0;
+			if ((dir & 0x2) && (out & 0x2))
+				dsp56k_host_interface.icr |= DSP56K_ICR_HF1;
+			else if (dir & 0x2)
+				dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1;
+
+			status = 0;
+			if (dsp56k_host_interface.icr & DSP56K_ICR_HF0) status |= 0x1;
+			if (dsp56k_host_interface.icr & DSP56K_ICR_HF1) status |= 0x2;
+			if (dsp56k_host_interface.isr & DSP56K_ISR_HF2) status |= 0x4;
+			if (dsp56k_host_interface.isr & DSP56K_ISR_HF3) status |= 0x8;
+
+			if(put_user(status, &hf->status) < 0)
+				return -EFAULT;
+			break;
+		}
+		case DSP56K_HOST_CMD:
+			if (arg > 31 || arg < 0)
+				return -EINVAL;
+			dsp56k_host_interface.cvr = (u_char)((arg & DSP56K_CVR_HV_MASK) |
+							     DSP56K_CVR_HC);
+			break;
+		default:
+			return -EINVAL;
+		}
+		return 0;
+
+	default:
+		printk("DSP56k driver: Unknown minor device: %d\n", dev);
+		return -ENXIO;
+	}
+}
+
+static int dsp56k_select(struct inode *inode, struct file *file, int sel_type,
+			 select_table *wait)
+{
+	int dev = MINOR(inode->i_rdev) & 0x0f;
+
+	switch(dev)
+	{
+	case DSP56K_DEV_56001:
+
+		switch(sel_type) {
+		case SEL_IN:		/* read */
+			return 1;
+		case SEL_OUT:		/* write */
+			return 1;
+		default:
+			return 1;
+		}
+
+	default:
+		printk("DSP56k driver: Unknown minor device: %d\n", dev);
+		return -ENXIO;
+	}
+}
+
+static int dsp56k_open(struct inode *inode, struct file *file)
+{
+	int dev = MINOR(inode->i_rdev) & 0x0f;
+
+	switch(dev)
+	{
+	case DSP56K_DEV_56001:
+
+		if (dsp56k.in_use)
+			return -EBUSY;
+
+		dsp56k.in_use = 1;
+		dsp56k.timeout = TIMEOUT;
+		dsp56k.maxio = MAXIO;
+		dsp56k.rx_wsize = dsp56k.tx_wsize = 4; 
+
+		DSP56K_TX_INT_OFF;
+		DSP56K_RX_INT_OFF;
+
+		/* Zero host flags */
+		dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0;
+		dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1;
+
+		break;
+
+	default:
+		printk("DSP56k driver: Unknown minor device: %d\n", dev);
+		return -ENXIO;
+	}
+
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif /* MODULE */
+
+	return 0;
+}
+
+static void dsp56k_release(struct inode *inode, struct file *file)
+{
+	int dev = MINOR(inode->i_rdev) & 0x0f;
+
+	switch(dev)
+	{
+	case DSP56K_DEV_56001:
+
+		dsp56k.in_use = 0;
+
+		break;
+	default:
+		printk("DSP56k driver: Unknown minor device: %d\n", dev);
+		return;
+	}
+
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif /* MODULE */
+}
+
+static struct file_operations dsp56k_fops = {
+	NULL,    /* no special dsp56k_lseek */
+	dsp56k_read,
+	dsp56k_write,
+	NULL,    /* no special dsp56k_readdir */
+	dsp56k_select,
+	dsp56k_ioctl,
+	NULL,    /* no special dsp56k_mmap */
+	dsp56k_open,
+	dsp56k_release,
+	NULL,    /* no special dsp56k_fsync */
+	NULL,    /* no special dsp56k_fasync */
+	NULL,    /* no special dsp56k_check_media_change */
+	NULL     /* no special dsp56k_revalidate */
+};
+
+
+/****** Init and module functions ******/
+
+static int init_error = 0;
+
+void dsp56k_init(void)
+{
+	if(!ATARIHW_PRESENT(DSP56K)) {
+		init_error = 1;
+		printk("DSP56k driver: Hardware not present\n");
+		return;
+	}
+
+#ifndef MODULE
+	if(register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops)) {
+		printk("DSP56k driver: Unable to register driver\n");
+		return;
+	}
+#endif /* !MODULE */
+
+	dsp56k.in_use = 0;
+
+	printk("DSP56k driver installed\n");
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	init_error = 0;
+	dsp56k_init();
+	if(init_error)
+		return -EPERM;
+
+	if(register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops)) {
+		printk("DSP56k driver: Unable to register driver\n");
+		return r;
+	}
+	
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	unregister_chrdev(DSP56K_MAJOR, "dsp56k");
+}
+#endif /* MODULE */
+++ linux-2.1.21/include/asm-m68k/dsp56k.h	Wed Jan 29 16:04:56 1997
@@ -0,0 +1,35 @@
+/*
+ * linux/include/asm-m68k/dsp56k.h - defines and declarations for
+ *                                   DSP56k device driver
+ *
+ * Copyright (C) 1996,1997 Fredrik Noring, lars brinkhoff & Tomas Berndtsson
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+
+/* Used for uploading DSP binary code */
+struct dsp56k_upload {
+	int len;
+	char *bin;
+};
+
+/* For the DSP host flags */
+struct dsp56k_host_flags {
+	int dir;     /* Bit field. 1 = write output bit, 0 = do nothing.
+		      * 0x0000 means reading only, 0x0011 means
+		      * writing the bits stored in `out' on HF0 and HF1.
+		      * Note that HF2 and HF3 can only be read.
+		      */
+	int out;     /* Bit field like above. */
+	int status;  /* Host register's current state is returned */
+};
+
+/* ioctl command codes */
+#define DSP56K_UPLOAD	        1    /* Upload DSP binary program       */
+#define DSP56K_SET_TX_WSIZE	2    /* Host transmit word size (1-4)   */
+#define DSP56K_SET_RX_WSIZE	3    /* Host receive word size (1-4)    */
+#define DSP56K_HOST_FLAGS	4    /* Host flag registers             */
+#define DSP56K_HOST_CMD         5    /* Trig Host Command (0-31)        */
--- linux-2.1.21/drivers/char/misc.c.orig	Wed Jan 29 16:11:46 1997
+++ linux-2.1.21/drivers/char/misc.c	Wed Jan 29 15:08:41 1997
@@ -72,6 +72,7 @@
 extern void wdt_init(void);
 extern void pcwatchdog_init(void);
 extern int rtc_init(void);
+extern int dsp56k_init(void);
 
 #ifdef CONFIG_PROC_FS
 static int proc_misc_read(char *buf, char **start, off_t offset, int len, int unused)
@@ -233,6 +234,9 @@
 #endif
 #ifdef CONFIG_RTC
 	rtc_init();
+#endif
+#ifdef CONFIG_ATARI_DSP56K
+	dsp56k_init();
 #endif
 #endif /* !MODULE */
 	if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
--- linux-2.1.21/arch/m68k/config.in.orig	Wed Jan 29 16:17:46 1997
+++ linux-2.1.21/arch/m68k/config.in	Tue Jan 28 16:41:15 1997
@@ -212,6 +212,9 @@
   tristate 'Atari MFP serial support' CONFIG_ATARI_MFPSER
   tristate 'Atari SCC serial support' CONFIG_ATARI_SCC
   tristate 'Atari MIDI serial support' CONFIG_ATARI_MIDI
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    tristate 'Atari DSP56k support (EXPERIMENTAL)' CONFIG_ATARI_DSP56K
+  fi
 fi
 if [ "$CONFIG_AMIGA" = "y" ]; then
   tristate 'Amiga builtin serial support' CONFIG_AMIGA_BUILTIN_SERIAL
--- linux-2.1.21/arch/m68k/atari/config.c.orig	Wed Jan 29 16:19:15 1997
+++ linux-2.1.21/arch/m68k/atari/config.c	Tue Jan 28 13:44:07 1997
@@ -57,7 +57,7 @@
 extern void atari_init_IRQ (void);
 extern int atari_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
                               unsigned long flags, const char *devname, void *dev_id);
-extern int atari_free_irq (unsigned int irq, void *dev_id);
+extern void atari_free_irq (unsigned int irq, void *dev_id);
 extern void atari_enable_irq (unsigned int);
 extern void atari_disable_irq (unsigned int);
 extern int atari_get_irq_list (char *buf);
@@ -338,10 +338,14 @@
 	ATARIHW_SET(PCM_8BIT);
         printk( "PCM " );
     }
-    if (hwreg_present( (void *)(0xffff8940) )) {
+    if (hwreg_present( &codec.unused5 )) {
 	ATARIHW_SET(CODEC);
         printk( "CODEC " );
     }
+    if (hwreg_present( &dsp56k_host_interface.icr )) {
+	ATARIHW_SET(DSP56K);
+        printk( "DSP56K " );
+    }
     if (hwreg_present( &tt_scc_dma.dma_ctrl ) &&
 #if 0
 	/* This test sucks! Who knows some better? */
@@ -1219,6 +1223,8 @@
     ATARIHW_ANNOUNCE(SCU, "System Control Unit");
     ATARIHW_ANNOUNCE(BLITTER, "Blitter");
     ATARIHW_ANNOUNCE(VME, "VME Bus");
+    ATARIHW_ANNOUNCE(DSP56K, "DSP56001 processor");
 
     return(len);
 }
+
--- linux-2.1.21/Documentation/Configure.help.orig	Wed Jan 29 16:21:43 1997
+++ linux-2.1.21/Documentation/Configure.help	Tue Jan 28 16:29:31 1997
@@ -4496,6 +4496,16 @@
   want to compile it as a module, say M here and read
   Documentation/modules.txt.
 
+Atari DSP56k Digital Signal Processor support
+CONFIG_ATARI_DSP56K
+  If you want to be able to use the DSP56001 in Falcons, say Y.
+  This driver is still experimental, and if you don't know what it is,
+  or if you don't have this processor, just say N.
+  This driver is also available as a module ( = code which can be inserted
+  in and removed from the running kernel whenever you want). If you
+  want to compile it as a module, say M here and read
+  Documentation/modules.txt.
+
 Amiga builtin serial support
 CONFIG_AMIGA_BUILTIN_SERIAL
   If you want to use your Amiga's built-in serial port in Linux, say Y.
--- linux-2.1.21/drivers/char/Makefile.orig	Wed Jan 29 16:23:51 1997
+++ linux-2.1.21/drivers/char/Makefile	Tue Jan 28 16:01:40 1997
@@ -45,26 +45,6 @@
   endif
 endif
 
-ifeq ($(CONFIG_AMIGAMOUSE),y)
-M = y
-L_OBJS += amigamouse.o
-else
-  ifeq ($(CONFIG_AMIGAMOUSE),m)
-    M_OBJS += amigamouse.o
-    MM = m
-  endif
-endif
-
-ifeq ($(CONFIG_ATARIMOUSE),y)
-M = y
-L_OBJS += atarimouse.o
-else
-  ifeq ($(CONFIG_ATARIMOUSE),m)
-    M_OBJS += atarimouse.o
-    MM = m
-  endif
-endif
-
 ifeq ($(CONFIG_ATARI_MFPSER),y)
 L_OBJS += atari_MFPser.o
 S = y
@@ -91,6 +71,16 @@
 else
   ifeq ($(CONFIG_ATARI_MIDI),m)
   M_OBJS += atari_MIDI.o
+  SM = y
+  endif
+endif
+
+ifeq ($(CONFIG_ATARI_DSP56K),y)
+L_OBJS += dsp56k.o
+S = y
+else
+  ifeq ($(CONFIG_ATARI_DSP56K),m)
+  M_OBJS += dsp56k.o
   SM = y
   endif
 endif
--- linux-2.1.21/include/asm-m68k/atarihw.h.orig	Wed Jan 29 16:27:59 1997
+++ linux-2.1.21/include/asm-m68k/atarihw.h	Tue Jan 28 17:43:23 1997
@@ -79,6 +79,7 @@
     ATARIHW_DECLARE(SCU);		/* System Control Unit */
     ATARIHW_DECLARE(BLITTER);		/* Blitter */
     ATARIHW_DECLARE(VME);		/* VME Bus */
+    ATARIHW_DECLARE(DSP56K);		/* DSP56k processor in Falcon */
 };
 
 extern struct atari_hw_present atari_hw_present;
@@ -356,8 +357,8 @@
 {
   u_char tracks;
   u_char input_source;
-#define CODEC_SOURCE_MATRIX     1
-#define CODEC_SOURCE_ADC        2
+#define CODEC_SOURCE_ADC        1
+#define CODEC_SOURCE_MATRIX     2
   u_char adc_source;
 #define ADC_SOURCE_RIGHT_PSG    1
 #define ADC_SOURCE_LEFT_PSG     2
@@ -673,17 +674,28 @@
 };
 # define tt_dmasnd ((*(volatile struct TT_DMASND *)TT_DMASND_BAS))
 
-#define	DMASND_CTRL_OFF		0x00
-#define	DMASND_CTRL_ON		0x01
-#define	DMASND_CTRL_REPEAT	0x02
-#define	DMASND_MODE_MONO	0x80
-#define	DMASND_MODE_STEREO	0x00
-#define DMASND_MODE_8BIT	0x00
-#define DMASND_MODE_16BIT	0x40	/* Falcon only */
-#define	DMASND_MODE_6KHZ	0x00	/* Falcon: mute */
-#define	DMASND_MODE_12KHZ	0x01
-#define	DMASND_MODE_25KHZ	0x02
-#define	DMASND_MODE_50KHZ	0x03
+#define DMASND_MFP_INT_REPLAY     0x01
+#define DMASND_MFP_INT_RECORD     0x02
+#define DMASND_TIMERA_INT_REPLAY  0x04
+#define DMASND_TIMERA_INT_RECORD  0x08
+
+#define	DMASND_CTRL_OFF		  0x00
+#define	DMASND_CTRL_ON		  0x01
+#define	DMASND_CTRL_REPEAT	  0x02
+#define DMASND_CTRL_RECORD_ON     0x10
+#define DMASND_CTRL_RECORD_OFF    0x00
+#define DMASND_CTRL_RECORD_REPEAT 0x20
+#define DMASND_CTRL_SELECT_REPLAY 0x00
+#define DMASND_CTRL_SELECT_RECORD 0x80
+#define	DMASND_MODE_MONO	  0x80
+#define	DMASND_MODE_STEREO	  0x00
+#define DMASND_MODE_8BIT	  0x00
+#define DMASND_MODE_16BIT	  0x40	/* Falcon only */
+#define	DMASND_MODE_6KHZ	  0x00	/* Falcon: mute */
+#define	DMASND_MODE_12KHZ	  0x01
+#define	DMASND_MODE_25KHZ	  0x02
+#define	DMASND_MODE_50KHZ	  0x03
+ 
 
 #define DMASNDSetBase(bufstart)						\
     do {								\
--- linux-2.1.21/include/linux/major.h.orig	Wed Jan 29 16:30:14 1997
+++ linux-2.1.21/include/linux/major.h	Tue Jan 28 15:41:57 1997
@@ -70,6 +70,7 @@
 #define RISCOM8_NORMAL_MAJOR 48
 #define RISCOM8_CALLOUT_MAJOR 49
 #define MKISS_MAJOR	55
+#define DSP56K_MAJOR    55   /* DSP56001 processor device */
 
 /*
  * Tests for SCSI devices.




