162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * The DSP56001 Device Driver, saviour of the Free World(tm) 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Authors: Fredrik Noring <noring@nocrew.org> 562306a36Sopenharmony_ci * lars brinkhoff <lars@nocrew.org> 662306a36Sopenharmony_ci * Tomas Berndtsson <tomas@nocrew.org> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * First version May 1996 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * History: 1162306a36Sopenharmony_ci * 97-01-29 Tomas Berndtsson, 1262306a36Sopenharmony_ci * Integrated with Linux 2.1.21 kernel sources. 1362306a36Sopenharmony_ci * 97-02-15 Tomas Berndtsson, 1462306a36Sopenharmony_ci * Fixed for kernel 2.1.26 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * BUGS: 1762306a36Sopenharmony_ci * Hmm... there must be something here :) 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * Copyright (C) 1996,1997 Fredrik Noring, lars brinkhoff & Tomas Berndtsson 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 2262306a36Sopenharmony_ci * License. See the file COPYING in the main directory of this archive 2362306a36Sopenharmony_ci * for more details. 2462306a36Sopenharmony_ci */ 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include <linux/module.h> 2762306a36Sopenharmony_ci#include <linux/major.h> 2862306a36Sopenharmony_ci#include <linux/types.h> 2962306a36Sopenharmony_ci#include <linux/errno.h> 3062306a36Sopenharmony_ci#include <linux/delay.h> /* guess what */ 3162306a36Sopenharmony_ci#include <linux/fs.h> 3262306a36Sopenharmony_ci#include <linux/mm.h> 3362306a36Sopenharmony_ci#include <linux/init.h> 3462306a36Sopenharmony_ci#include <linux/device.h> 3562306a36Sopenharmony_ci#include <linux/mutex.h> 3662306a36Sopenharmony_ci#include <linux/firmware.h> 3762306a36Sopenharmony_ci#include <linux/platform_device.h> 3862306a36Sopenharmony_ci#include <linux/uaccess.h> /* For put_user and get_user */ 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#include <asm/atarihw.h> 4162306a36Sopenharmony_ci#include <asm/traps.h> 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#include <asm/dsp56k.h> 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* minor devices */ 4662306a36Sopenharmony_ci#define DSP56K_DEV_56001 0 /* The only device so far */ 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define TIMEOUT 10 /* Host port timeout in number of tries */ 4962306a36Sopenharmony_ci#define MAXIO 2048 /* Maximum number of words before sleep */ 5062306a36Sopenharmony_ci#define DSP56K_MAX_BINARY_LENGTH (3*64*1024) 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define DSP56K_TX_INT_ON dsp56k_host_interface.icr |= DSP56K_ICR_TREQ 5362306a36Sopenharmony_ci#define DSP56K_RX_INT_ON dsp56k_host_interface.icr |= DSP56K_ICR_RREQ 5462306a36Sopenharmony_ci#define DSP56K_TX_INT_OFF dsp56k_host_interface.icr &= ~DSP56K_ICR_TREQ 5562306a36Sopenharmony_ci#define DSP56K_RX_INT_OFF dsp56k_host_interface.icr &= ~DSP56K_ICR_RREQ 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#define DSP56K_TRANSMIT (dsp56k_host_interface.isr & DSP56K_ISR_TXDE) 5862306a36Sopenharmony_ci#define DSP56K_RECEIVE (dsp56k_host_interface.isr & DSP56K_ISR_RXDF) 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define handshake(count, maxio, timeout, ENABLE, f) \ 6162306a36Sopenharmony_ci{ \ 6262306a36Sopenharmony_ci long i, t, m; \ 6362306a36Sopenharmony_ci while (count > 0) { \ 6462306a36Sopenharmony_ci m = min_t(unsigned long, count, maxio); \ 6562306a36Sopenharmony_ci for (i = 0; i < m; i++) { \ 6662306a36Sopenharmony_ci for (t = 0; t < timeout && !ENABLE; t++) \ 6762306a36Sopenharmony_ci msleep(20); \ 6862306a36Sopenharmony_ci if(!ENABLE) \ 6962306a36Sopenharmony_ci return -EIO; \ 7062306a36Sopenharmony_ci f; \ 7162306a36Sopenharmony_ci } \ 7262306a36Sopenharmony_ci count -= m; \ 7362306a36Sopenharmony_ci if (m == maxio) msleep(20); \ 7462306a36Sopenharmony_ci } \ 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci#define tx_wait(n) \ 7862306a36Sopenharmony_ci{ \ 7962306a36Sopenharmony_ci int t; \ 8062306a36Sopenharmony_ci for(t = 0; t < n && !DSP56K_TRANSMIT; t++) \ 8162306a36Sopenharmony_ci msleep(10); \ 8262306a36Sopenharmony_ci if(!DSP56K_TRANSMIT) { \ 8362306a36Sopenharmony_ci return -EIO; \ 8462306a36Sopenharmony_ci } \ 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci#define rx_wait(n) \ 8862306a36Sopenharmony_ci{ \ 8962306a36Sopenharmony_ci int t; \ 9062306a36Sopenharmony_ci for(t = 0; t < n && !DSP56K_RECEIVE; t++) \ 9162306a36Sopenharmony_ci msleep(10); \ 9262306a36Sopenharmony_ci if(!DSP56K_RECEIVE) { \ 9362306a36Sopenharmony_ci return -EIO; \ 9462306a36Sopenharmony_ci } \ 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic DEFINE_MUTEX(dsp56k_mutex); 9862306a36Sopenharmony_cistatic struct dsp56k_device { 9962306a36Sopenharmony_ci unsigned long in_use; 10062306a36Sopenharmony_ci long maxio, timeout; 10162306a36Sopenharmony_ci int tx_wsize, rx_wsize; 10262306a36Sopenharmony_ci} dsp56k; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic const struct class dsp56k_class = { 10562306a36Sopenharmony_ci .name = "dsp56k", 10662306a36Sopenharmony_ci}; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic int dsp56k_reset(void) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci u_char status; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci /* Power down the DSP */ 11362306a36Sopenharmony_ci sound_ym.rd_data_reg_sel = 14; 11462306a36Sopenharmony_ci status = sound_ym.rd_data_reg_sel & 0xef; 11562306a36Sopenharmony_ci sound_ym.wd_data = status; 11662306a36Sopenharmony_ci sound_ym.wd_data = status | 0x10; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci udelay(10); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci /* Power up the DSP */ 12162306a36Sopenharmony_ci sound_ym.rd_data_reg_sel = 14; 12262306a36Sopenharmony_ci sound_ym.wd_data = sound_ym.rd_data_reg_sel & 0xef; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci return 0; 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic int dsp56k_upload(u_char __user *bin, int len) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci struct platform_device *pdev; 13062306a36Sopenharmony_ci const struct firmware *fw; 13162306a36Sopenharmony_ci const char fw_name[] = "dsp56k/bootstrap.bin"; 13262306a36Sopenharmony_ci int err; 13362306a36Sopenharmony_ci int i; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci dsp56k_reset(); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci pdev = platform_device_register_simple("dsp56k", 0, NULL, 0); 13862306a36Sopenharmony_ci if (IS_ERR(pdev)) { 13962306a36Sopenharmony_ci printk(KERN_ERR "Failed to register device for \"%s\"\n", 14062306a36Sopenharmony_ci fw_name); 14162306a36Sopenharmony_ci return -EINVAL; 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci err = request_firmware(&fw, fw_name, &pdev->dev); 14462306a36Sopenharmony_ci platform_device_unregister(pdev); 14562306a36Sopenharmony_ci if (err) { 14662306a36Sopenharmony_ci printk(KERN_ERR "Failed to load image \"%s\" err %d\n", 14762306a36Sopenharmony_ci fw_name, err); 14862306a36Sopenharmony_ci return err; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci if (fw->size % 3) { 15162306a36Sopenharmony_ci printk(KERN_ERR "Bogus length %d in image \"%s\"\n", 15262306a36Sopenharmony_ci fw->size, fw_name); 15362306a36Sopenharmony_ci release_firmware(fw); 15462306a36Sopenharmony_ci return -EINVAL; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci for (i = 0; i < fw->size; i = i + 3) { 15762306a36Sopenharmony_ci /* tx_wait(10); */ 15862306a36Sopenharmony_ci dsp56k_host_interface.data.b[1] = fw->data[i]; 15962306a36Sopenharmony_ci dsp56k_host_interface.data.b[2] = fw->data[i + 1]; 16062306a36Sopenharmony_ci dsp56k_host_interface.data.b[3] = fw->data[i + 2]; 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci release_firmware(fw); 16362306a36Sopenharmony_ci for (; i < 512; i++) { 16462306a36Sopenharmony_ci /* tx_wait(10); */ 16562306a36Sopenharmony_ci dsp56k_host_interface.data.b[1] = 0; 16662306a36Sopenharmony_ci dsp56k_host_interface.data.b[2] = 0; 16762306a36Sopenharmony_ci dsp56k_host_interface.data.b[3] = 0; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci for (i = 0; i < len; i++) { 17162306a36Sopenharmony_ci tx_wait(10); 17262306a36Sopenharmony_ci get_user(dsp56k_host_interface.data.b[1], bin++); 17362306a36Sopenharmony_ci get_user(dsp56k_host_interface.data.b[2], bin++); 17462306a36Sopenharmony_ci get_user(dsp56k_host_interface.data.b[3], bin++); 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci tx_wait(10); 17862306a36Sopenharmony_ci dsp56k_host_interface.data.l = 3; /* Magic execute */ 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci return 0; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic ssize_t dsp56k_read(struct file *file, char __user *buf, size_t count, 18462306a36Sopenharmony_ci loff_t *ppos) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci struct inode *inode = file_inode(file); 18762306a36Sopenharmony_ci int dev = iminor(inode) & 0x0f; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci switch(dev) 19062306a36Sopenharmony_ci { 19162306a36Sopenharmony_ci case DSP56K_DEV_56001: 19262306a36Sopenharmony_ci { 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci long n; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci /* Don't do anything if nothing is to be done */ 19762306a36Sopenharmony_ci if (!count) return 0; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci n = 0; 20062306a36Sopenharmony_ci switch (dsp56k.rx_wsize) { 20162306a36Sopenharmony_ci case 1: /* 8 bit */ 20262306a36Sopenharmony_ci { 20362306a36Sopenharmony_ci handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE, 20462306a36Sopenharmony_ci put_user(dsp56k_host_interface.data.b[3], buf+n++)); 20562306a36Sopenharmony_ci return n; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci case 2: /* 16 bit */ 20862306a36Sopenharmony_ci { 20962306a36Sopenharmony_ci short __user *data; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci count /= 2; 21262306a36Sopenharmony_ci data = (short __user *) buf; 21362306a36Sopenharmony_ci handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE, 21462306a36Sopenharmony_ci put_user(dsp56k_host_interface.data.w[1], data+n++)); 21562306a36Sopenharmony_ci return 2*n; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci case 3: /* 24 bit */ 21862306a36Sopenharmony_ci { 21962306a36Sopenharmony_ci count /= 3; 22062306a36Sopenharmony_ci handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE, 22162306a36Sopenharmony_ci put_user(dsp56k_host_interface.data.b[1], buf+n++); 22262306a36Sopenharmony_ci put_user(dsp56k_host_interface.data.b[2], buf+n++); 22362306a36Sopenharmony_ci put_user(dsp56k_host_interface.data.b[3], buf+n++)); 22462306a36Sopenharmony_ci return 3*n; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci case 4: /* 32 bit */ 22762306a36Sopenharmony_ci { 22862306a36Sopenharmony_ci long __user *data; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci count /= 4; 23162306a36Sopenharmony_ci data = (long __user *) buf; 23262306a36Sopenharmony_ci handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE, 23362306a36Sopenharmony_ci put_user(dsp56k_host_interface.data.l, data+n++)); 23462306a36Sopenharmony_ci return 4*n; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci return -EFAULT; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci default: 24162306a36Sopenharmony_ci printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev); 24262306a36Sopenharmony_ci return -ENXIO; 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic ssize_t dsp56k_write(struct file *file, const char __user *buf, size_t count, 24762306a36Sopenharmony_ci loff_t *ppos) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci struct inode *inode = file_inode(file); 25062306a36Sopenharmony_ci int dev = iminor(inode) & 0x0f; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci switch(dev) 25362306a36Sopenharmony_ci { 25462306a36Sopenharmony_ci case DSP56K_DEV_56001: 25562306a36Sopenharmony_ci { 25662306a36Sopenharmony_ci long n; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* Don't do anything if nothing is to be done */ 25962306a36Sopenharmony_ci if (!count) return 0; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci n = 0; 26262306a36Sopenharmony_ci switch (dsp56k.tx_wsize) { 26362306a36Sopenharmony_ci case 1: /* 8 bit */ 26462306a36Sopenharmony_ci { 26562306a36Sopenharmony_ci handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT, 26662306a36Sopenharmony_ci get_user(dsp56k_host_interface.data.b[3], buf+n++)); 26762306a36Sopenharmony_ci return n; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci case 2: /* 16 bit */ 27062306a36Sopenharmony_ci { 27162306a36Sopenharmony_ci const short __user *data; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci count /= 2; 27462306a36Sopenharmony_ci data = (const short __user *)buf; 27562306a36Sopenharmony_ci handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT, 27662306a36Sopenharmony_ci get_user(dsp56k_host_interface.data.w[1], data+n++)); 27762306a36Sopenharmony_ci return 2*n; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci case 3: /* 24 bit */ 28062306a36Sopenharmony_ci { 28162306a36Sopenharmony_ci count /= 3; 28262306a36Sopenharmony_ci handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT, 28362306a36Sopenharmony_ci get_user(dsp56k_host_interface.data.b[1], buf+n++); 28462306a36Sopenharmony_ci get_user(dsp56k_host_interface.data.b[2], buf+n++); 28562306a36Sopenharmony_ci get_user(dsp56k_host_interface.data.b[3], buf+n++)); 28662306a36Sopenharmony_ci return 3*n; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci case 4: /* 32 bit */ 28962306a36Sopenharmony_ci { 29062306a36Sopenharmony_ci const long __user *data; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci count /= 4; 29362306a36Sopenharmony_ci data = (const long __user *)buf; 29462306a36Sopenharmony_ci handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT, 29562306a36Sopenharmony_ci get_user(dsp56k_host_interface.data.l, data+n++)); 29662306a36Sopenharmony_ci return 4*n; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci return -EFAULT; 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci default: 30362306a36Sopenharmony_ci printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev); 30462306a36Sopenharmony_ci return -ENXIO; 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic long dsp56k_ioctl(struct file *file, unsigned int cmd, 30962306a36Sopenharmony_ci unsigned long arg) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci int dev = iminor(file_inode(file)) & 0x0f; 31262306a36Sopenharmony_ci void __user *argp = (void __user *)arg; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci switch(dev) 31562306a36Sopenharmony_ci { 31662306a36Sopenharmony_ci case DSP56K_DEV_56001: 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci switch(cmd) { 31962306a36Sopenharmony_ci case DSP56K_UPLOAD: 32062306a36Sopenharmony_ci { 32162306a36Sopenharmony_ci char __user *bin; 32262306a36Sopenharmony_ci int r, len; 32362306a36Sopenharmony_ci struct dsp56k_upload __user *binary = argp; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci if(get_user(len, &binary->len) < 0) 32662306a36Sopenharmony_ci return -EFAULT; 32762306a36Sopenharmony_ci if(get_user(bin, &binary->bin) < 0) 32862306a36Sopenharmony_ci return -EFAULT; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (len <= 0) { 33162306a36Sopenharmony_ci return -EINVAL; /* nothing to upload?!? */ 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci if (len > DSP56K_MAX_BINARY_LENGTH) { 33462306a36Sopenharmony_ci return -EINVAL; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci mutex_lock(&dsp56k_mutex); 33762306a36Sopenharmony_ci r = dsp56k_upload(bin, len); 33862306a36Sopenharmony_ci mutex_unlock(&dsp56k_mutex); 33962306a36Sopenharmony_ci if (r < 0) { 34062306a36Sopenharmony_ci return r; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci break; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci case DSP56K_SET_TX_WSIZE: 34662306a36Sopenharmony_ci if (arg > 4 || arg < 1) 34762306a36Sopenharmony_ci return -EINVAL; 34862306a36Sopenharmony_ci mutex_lock(&dsp56k_mutex); 34962306a36Sopenharmony_ci dsp56k.tx_wsize = (int) arg; 35062306a36Sopenharmony_ci mutex_unlock(&dsp56k_mutex); 35162306a36Sopenharmony_ci break; 35262306a36Sopenharmony_ci case DSP56K_SET_RX_WSIZE: 35362306a36Sopenharmony_ci if (arg > 4 || arg < 1) 35462306a36Sopenharmony_ci return -EINVAL; 35562306a36Sopenharmony_ci mutex_lock(&dsp56k_mutex); 35662306a36Sopenharmony_ci dsp56k.rx_wsize = (int) arg; 35762306a36Sopenharmony_ci mutex_unlock(&dsp56k_mutex); 35862306a36Sopenharmony_ci break; 35962306a36Sopenharmony_ci case DSP56K_HOST_FLAGS: 36062306a36Sopenharmony_ci { 36162306a36Sopenharmony_ci int dir, out, status; 36262306a36Sopenharmony_ci struct dsp56k_host_flags __user *hf = argp; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if(get_user(dir, &hf->dir) < 0) 36562306a36Sopenharmony_ci return -EFAULT; 36662306a36Sopenharmony_ci if(get_user(out, &hf->out) < 0) 36762306a36Sopenharmony_ci return -EFAULT; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci mutex_lock(&dsp56k_mutex); 37062306a36Sopenharmony_ci if ((dir & 0x1) && (out & 0x1)) 37162306a36Sopenharmony_ci dsp56k_host_interface.icr |= DSP56K_ICR_HF0; 37262306a36Sopenharmony_ci else if (dir & 0x1) 37362306a36Sopenharmony_ci dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0; 37462306a36Sopenharmony_ci if ((dir & 0x2) && (out & 0x2)) 37562306a36Sopenharmony_ci dsp56k_host_interface.icr |= DSP56K_ICR_HF1; 37662306a36Sopenharmony_ci else if (dir & 0x2) 37762306a36Sopenharmony_ci dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci status = 0; 38062306a36Sopenharmony_ci if (dsp56k_host_interface.icr & DSP56K_ICR_HF0) status |= 0x1; 38162306a36Sopenharmony_ci if (dsp56k_host_interface.icr & DSP56K_ICR_HF1) status |= 0x2; 38262306a36Sopenharmony_ci if (dsp56k_host_interface.isr & DSP56K_ISR_HF2) status |= 0x4; 38362306a36Sopenharmony_ci if (dsp56k_host_interface.isr & DSP56K_ISR_HF3) status |= 0x8; 38462306a36Sopenharmony_ci mutex_unlock(&dsp56k_mutex); 38562306a36Sopenharmony_ci return put_user(status, &hf->status); 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci case DSP56K_HOST_CMD: 38862306a36Sopenharmony_ci if (arg > 31) 38962306a36Sopenharmony_ci return -EINVAL; 39062306a36Sopenharmony_ci mutex_lock(&dsp56k_mutex); 39162306a36Sopenharmony_ci dsp56k_host_interface.cvr = (u_char)((arg & DSP56K_CVR_HV_MASK) | 39262306a36Sopenharmony_ci DSP56K_CVR_HC); 39362306a36Sopenharmony_ci mutex_unlock(&dsp56k_mutex); 39462306a36Sopenharmony_ci break; 39562306a36Sopenharmony_ci default: 39662306a36Sopenharmony_ci return -EINVAL; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci return 0; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci default: 40162306a36Sopenharmony_ci printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev); 40262306a36Sopenharmony_ci return -ENXIO; 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci/* As of 2.1.26 this should be dsp56k_poll, 40762306a36Sopenharmony_ci * but how do I then check device minor number? 40862306a36Sopenharmony_ci * Do I need this function at all??? 40962306a36Sopenharmony_ci */ 41062306a36Sopenharmony_ci#if 0 41162306a36Sopenharmony_cistatic __poll_t dsp56k_poll(struct file *file, poll_table *wait) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci int dev = iminor(file_inode(file)) & 0x0f; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci switch(dev) 41662306a36Sopenharmony_ci { 41762306a36Sopenharmony_ci case DSP56K_DEV_56001: 41862306a36Sopenharmony_ci /* poll_wait(file, ???, wait); */ 41962306a36Sopenharmony_ci return EPOLLIN | EPOLLRDNORM | EPOLLOUT; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci default: 42262306a36Sopenharmony_ci printk("DSP56k driver: Unknown minor device: %d\n", dev); 42362306a36Sopenharmony_ci return 0; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci#endif 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic int dsp56k_open(struct inode *inode, struct file *file) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci int dev = iminor(inode) & 0x0f; 43162306a36Sopenharmony_ci int ret = 0; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci mutex_lock(&dsp56k_mutex); 43462306a36Sopenharmony_ci switch(dev) 43562306a36Sopenharmony_ci { 43662306a36Sopenharmony_ci case DSP56K_DEV_56001: 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci if (test_and_set_bit(0, &dsp56k.in_use)) { 43962306a36Sopenharmony_ci ret = -EBUSY; 44062306a36Sopenharmony_ci goto out; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci dsp56k.timeout = TIMEOUT; 44462306a36Sopenharmony_ci dsp56k.maxio = MAXIO; 44562306a36Sopenharmony_ci dsp56k.rx_wsize = dsp56k.tx_wsize = 4; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci DSP56K_TX_INT_OFF; 44862306a36Sopenharmony_ci DSP56K_RX_INT_OFF; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci /* Zero host flags */ 45162306a36Sopenharmony_ci dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0; 45262306a36Sopenharmony_ci dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci break; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci default: 45762306a36Sopenharmony_ci ret = -ENODEV; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ciout: 46062306a36Sopenharmony_ci mutex_unlock(&dsp56k_mutex); 46162306a36Sopenharmony_ci return ret; 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cistatic int dsp56k_release(struct inode *inode, struct file *file) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci int dev = iminor(inode) & 0x0f; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci switch(dev) 46962306a36Sopenharmony_ci { 47062306a36Sopenharmony_ci case DSP56K_DEV_56001: 47162306a36Sopenharmony_ci clear_bit(0, &dsp56k.in_use); 47262306a36Sopenharmony_ci break; 47362306a36Sopenharmony_ci default: 47462306a36Sopenharmony_ci printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev); 47562306a36Sopenharmony_ci return -ENXIO; 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci return 0; 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_cistatic const struct file_operations dsp56k_fops = { 48262306a36Sopenharmony_ci .owner = THIS_MODULE, 48362306a36Sopenharmony_ci .read = dsp56k_read, 48462306a36Sopenharmony_ci .write = dsp56k_write, 48562306a36Sopenharmony_ci .unlocked_ioctl = dsp56k_ioctl, 48662306a36Sopenharmony_ci .open = dsp56k_open, 48762306a36Sopenharmony_ci .release = dsp56k_release, 48862306a36Sopenharmony_ci .llseek = noop_llseek, 48962306a36Sopenharmony_ci}; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci/****** Init and module functions ******/ 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_cistatic const char banner[] __initconst = KERN_INFO "DSP56k driver installed\n"; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_cistatic int __init dsp56k_init_driver(void) 49762306a36Sopenharmony_ci{ 49862306a36Sopenharmony_ci int err; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci if(!MACH_IS_ATARI || !ATARIHW_PRESENT(DSP56K)) { 50162306a36Sopenharmony_ci printk("DSP56k driver: Hardware not present\n"); 50262306a36Sopenharmony_ci return -ENODEV; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci if(register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops)) { 50662306a36Sopenharmony_ci printk("DSP56k driver: Unable to register driver\n"); 50762306a36Sopenharmony_ci return -ENODEV; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci err = class_register(&dsp56k_class); 51062306a36Sopenharmony_ci if (err) 51162306a36Sopenharmony_ci goto out_chrdev; 51262306a36Sopenharmony_ci device_create(&dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), NULL, 51362306a36Sopenharmony_ci "dsp56k"); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci printk(banner); 51662306a36Sopenharmony_ci goto out; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ciout_chrdev: 51962306a36Sopenharmony_ci unregister_chrdev(DSP56K_MAJOR, "dsp56k"); 52062306a36Sopenharmony_ciout: 52162306a36Sopenharmony_ci return err; 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_cimodule_init(dsp56k_init_driver); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_cistatic void __exit dsp56k_cleanup_driver(void) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci device_destroy(&dsp56k_class, MKDEV(DSP56K_MAJOR, 0)); 52862306a36Sopenharmony_ci class_unregister(&dsp56k_class); 52962306a36Sopenharmony_ci unregister_chrdev(DSP56K_MAJOR, "dsp56k"); 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_cimodule_exit(dsp56k_cleanup_driver); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 53462306a36Sopenharmony_ciMODULE_FIRMWARE("dsp56k/bootstrap.bin"); 535