cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dsp56k.c (12496B)


      1/*
      2 * The DSP56001 Device Driver, saviour of the Free World(tm)
      3 *
      4 * Authors: Fredrik Noring   <noring@nocrew.org>
      5 *          lars brinkhoff   <lars@nocrew.org>
      6 *          Tomas Berndtsson <tomas@nocrew.org>
      7 *
      8 * First version May 1996
      9 *
     10 * History:
     11 *  97-01-29   Tomas Berndtsson,
     12 *               Integrated with Linux 2.1.21 kernel sources.
     13 *  97-02-15   Tomas Berndtsson,
     14 *               Fixed for kernel 2.1.26
     15 *
     16 * BUGS:
     17 *  Hmm... there must be something here :)
     18 *
     19 * Copyright (C) 1996,1997 Fredrik Noring, lars brinkhoff & Tomas Berndtsson
     20 *
     21 * This file is subject to the terms and conditions of the GNU General Public
     22 * License.  See the file COPYING in the main directory of this archive
     23 * for more details.
     24 */
     25
     26#include <linux/module.h>
     27#include <linux/major.h>
     28#include <linux/types.h>
     29#include <linux/errno.h>
     30#include <linux/delay.h>	/* guess what */
     31#include <linux/fs.h>
     32#include <linux/mm.h>
     33#include <linux/init.h>
     34#include <linux/device.h>
     35#include <linux/mutex.h>
     36#include <linux/firmware.h>
     37#include <linux/platform_device.h>
     38#include <linux/uaccess.h>	/* For put_user and get_user */
     39
     40#include <asm/atarihw.h>
     41#include <asm/traps.h>
     42
     43#include <asm/dsp56k.h>
     44
     45/* minor devices */
     46#define DSP56K_DEV_56001        0    /* The only device so far */
     47
     48#define TIMEOUT    10   /* Host port timeout in number of tries */
     49#define MAXIO    2048   /* Maximum number of words before sleep */
     50#define DSP56K_MAX_BINARY_LENGTH (3*64*1024)
     51
     52#define DSP56K_TX_INT_ON	dsp56k_host_interface.icr |=  DSP56K_ICR_TREQ
     53#define DSP56K_RX_INT_ON	dsp56k_host_interface.icr |=  DSP56K_ICR_RREQ
     54#define DSP56K_TX_INT_OFF	dsp56k_host_interface.icr &= ~DSP56K_ICR_TREQ
     55#define DSP56K_RX_INT_OFF	dsp56k_host_interface.icr &= ~DSP56K_ICR_RREQ
     56
     57#define DSP56K_TRANSMIT		(dsp56k_host_interface.isr & DSP56K_ISR_TXDE)
     58#define DSP56K_RECEIVE		(dsp56k_host_interface.isr & DSP56K_ISR_RXDF)
     59
     60#define handshake(count, maxio, timeout, ENABLE, f) \
     61{ \
     62	long i, t, m; \
     63	while (count > 0) { \
     64		m = min_t(unsigned long, count, maxio); \
     65		for (i = 0; i < m; i++) { \
     66			for (t = 0; t < timeout && !ENABLE; t++) \
     67				msleep(20); \
     68			if(!ENABLE) \
     69				return -EIO; \
     70			f; \
     71		} \
     72		count -= m; \
     73		if (m == maxio) msleep(20); \
     74	} \
     75}
     76
     77#define tx_wait(n) \
     78{ \
     79	int t; \
     80	for(t = 0; t < n && !DSP56K_TRANSMIT; t++) \
     81		msleep(10); \
     82	if(!DSP56K_TRANSMIT) { \
     83		return -EIO; \
     84	} \
     85}
     86
     87#define rx_wait(n) \
     88{ \
     89	int t; \
     90	for(t = 0; t < n && !DSP56K_RECEIVE; t++) \
     91		msleep(10); \
     92	if(!DSP56K_RECEIVE) { \
     93		return -EIO; \
     94	} \
     95}
     96
     97static DEFINE_MUTEX(dsp56k_mutex);
     98static struct dsp56k_device {
     99	unsigned long in_use;
    100	long maxio, timeout;
    101	int tx_wsize, rx_wsize;
    102} dsp56k;
    103
    104static struct class *dsp56k_class;
    105
    106static int dsp56k_reset(void)
    107{
    108	u_char status;
    109	
    110	/* Power down the DSP */
    111	sound_ym.rd_data_reg_sel = 14;
    112	status = sound_ym.rd_data_reg_sel & 0xef;
    113	sound_ym.wd_data = status;
    114	sound_ym.wd_data = status | 0x10;
    115  
    116	udelay(10);
    117  
    118	/* Power up the DSP */
    119	sound_ym.rd_data_reg_sel = 14;
    120	sound_ym.wd_data = sound_ym.rd_data_reg_sel & 0xef;
    121
    122	return 0;
    123}
    124
    125static int dsp56k_upload(u_char __user *bin, int len)
    126{
    127	struct platform_device *pdev;
    128	const struct firmware *fw;
    129	const char fw_name[] = "dsp56k/bootstrap.bin";
    130	int err;
    131	int i;
    132
    133	dsp56k_reset();
    134
    135	pdev = platform_device_register_simple("dsp56k", 0, NULL, 0);
    136	if (IS_ERR(pdev)) {
    137		printk(KERN_ERR "Failed to register device for \"%s\"\n",
    138		       fw_name);
    139		return -EINVAL;
    140	}
    141	err = request_firmware(&fw, fw_name, &pdev->dev);
    142	platform_device_unregister(pdev);
    143	if (err) {
    144		printk(KERN_ERR "Failed to load image \"%s\" err %d\n",
    145		       fw_name, err);
    146		return err;
    147	}
    148	if (fw->size % 3) {
    149		printk(KERN_ERR "Bogus length %d in image \"%s\"\n",
    150		       fw->size, fw_name);
    151		release_firmware(fw);
    152		return -EINVAL;
    153	}
    154	for (i = 0; i < fw->size; i = i + 3) {
    155		/* tx_wait(10); */
    156		dsp56k_host_interface.data.b[1] = fw->data[i];
    157		dsp56k_host_interface.data.b[2] = fw->data[i + 1];
    158		dsp56k_host_interface.data.b[3] = fw->data[i + 2];
    159	}
    160	release_firmware(fw);
    161	for (; i < 512; i++) {
    162		/* tx_wait(10); */
    163		dsp56k_host_interface.data.b[1] = 0;
    164		dsp56k_host_interface.data.b[2] = 0;
    165		dsp56k_host_interface.data.b[3] = 0;
    166	}
    167  
    168	for (i = 0; i < len; i++) {
    169		tx_wait(10);
    170		get_user(dsp56k_host_interface.data.b[1], bin++);
    171		get_user(dsp56k_host_interface.data.b[2], bin++);
    172		get_user(dsp56k_host_interface.data.b[3], bin++);
    173	}
    174
    175	tx_wait(10);
    176	dsp56k_host_interface.data.l = 3;    /* Magic execute */
    177
    178	return 0;
    179}
    180
    181static ssize_t dsp56k_read(struct file *file, char __user *buf, size_t count,
    182			   loff_t *ppos)
    183{
    184	struct inode *inode = file_inode(file);
    185	int dev = iminor(inode) & 0x0f;
    186
    187	switch(dev)
    188	{
    189	case DSP56K_DEV_56001:
    190	{
    191
    192		long n;
    193
    194		/* Don't do anything if nothing is to be done */
    195		if (!count) return 0;
    196
    197		n = 0;
    198		switch (dsp56k.rx_wsize) {
    199		case 1:  /* 8 bit */
    200		{
    201			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
    202				  put_user(dsp56k_host_interface.data.b[3], buf+n++));
    203			return n;
    204		}
    205		case 2:  /* 16 bit */
    206		{
    207			short __user *data;
    208
    209			count /= 2;
    210			data = (short __user *) buf;
    211			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
    212				  put_user(dsp56k_host_interface.data.w[1], data+n++));
    213			return 2*n;
    214		}
    215		case 3:  /* 24 bit */
    216		{
    217			count /= 3;
    218			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
    219				  put_user(dsp56k_host_interface.data.b[1], buf+n++);
    220				  put_user(dsp56k_host_interface.data.b[2], buf+n++);
    221				  put_user(dsp56k_host_interface.data.b[3], buf+n++));
    222			return 3*n;
    223		}
    224		case 4:  /* 32 bit */
    225		{
    226			long __user *data;
    227
    228			count /= 4;
    229			data = (long __user *) buf;
    230			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
    231				  put_user(dsp56k_host_interface.data.l, data+n++));
    232			return 4*n;
    233		}
    234		}
    235		return -EFAULT;
    236	}
    237
    238	default:
    239		printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
    240		return -ENXIO;
    241	}
    242}
    243
    244static ssize_t dsp56k_write(struct file *file, const char __user *buf, size_t count,
    245			    loff_t *ppos)
    246{
    247	struct inode *inode = file_inode(file);
    248	int dev = iminor(inode) & 0x0f;
    249
    250	switch(dev)
    251	{
    252	case DSP56K_DEV_56001:
    253	{
    254		long n;
    255
    256		/* Don't do anything if nothing is to be done */
    257		if (!count) return 0;
    258
    259		n = 0;
    260		switch (dsp56k.tx_wsize) {
    261		case 1:  /* 8 bit */
    262		{
    263			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
    264				  get_user(dsp56k_host_interface.data.b[3], buf+n++));
    265			return n;
    266		}
    267		case 2:  /* 16 bit */
    268		{
    269			const short __user *data;
    270
    271			count /= 2;
    272			data = (const short __user *)buf;
    273			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
    274				  get_user(dsp56k_host_interface.data.w[1], data+n++));
    275			return 2*n;
    276		}
    277		case 3:  /* 24 bit */
    278		{
    279			count /= 3;
    280			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
    281				  get_user(dsp56k_host_interface.data.b[1], buf+n++);
    282				  get_user(dsp56k_host_interface.data.b[2], buf+n++);
    283				  get_user(dsp56k_host_interface.data.b[3], buf+n++));
    284			return 3*n;
    285		}
    286		case 4:  /* 32 bit */
    287		{
    288			const long __user *data;
    289
    290			count /= 4;
    291			data = (const long __user *)buf;
    292			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
    293				  get_user(dsp56k_host_interface.data.l, data+n++));
    294			return 4*n;
    295		}
    296		}
    297
    298		return -EFAULT;
    299	}
    300	default:
    301		printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
    302		return -ENXIO;
    303	}
    304}
    305
    306static long dsp56k_ioctl(struct file *file, unsigned int cmd,
    307			 unsigned long arg)
    308{
    309	int dev = iminor(file_inode(file)) & 0x0f;
    310	void __user *argp = (void __user *)arg;
    311
    312	switch(dev)
    313	{
    314	case DSP56K_DEV_56001:
    315
    316		switch(cmd) {
    317		case DSP56K_UPLOAD:
    318		{
    319			char __user *bin;
    320			int r, len;
    321			struct dsp56k_upload __user *binary = argp;
    322    
    323			if(get_user(len, &binary->len) < 0)
    324				return -EFAULT;
    325			if(get_user(bin, &binary->bin) < 0)
    326				return -EFAULT;
    327		
    328			if (len <= 0) {
    329				return -EINVAL;      /* nothing to upload?!? */
    330			}
    331			if (len > DSP56K_MAX_BINARY_LENGTH) {
    332				return -EINVAL;
    333			}
    334			mutex_lock(&dsp56k_mutex);
    335			r = dsp56k_upload(bin, len);
    336			mutex_unlock(&dsp56k_mutex);
    337			if (r < 0) {
    338				return r;
    339			}
    340    
    341			break;
    342		}
    343		case DSP56K_SET_TX_WSIZE:
    344			if (arg > 4 || arg < 1)
    345				return -EINVAL;
    346			mutex_lock(&dsp56k_mutex);
    347			dsp56k.tx_wsize = (int) arg;
    348			mutex_unlock(&dsp56k_mutex);
    349			break;
    350		case DSP56K_SET_RX_WSIZE:
    351			if (arg > 4 || arg < 1)
    352				return -EINVAL;
    353			mutex_lock(&dsp56k_mutex);
    354			dsp56k.rx_wsize = (int) arg;
    355			mutex_unlock(&dsp56k_mutex);
    356			break;
    357		case DSP56K_HOST_FLAGS:
    358		{
    359			int dir, out, status;
    360			struct dsp56k_host_flags __user *hf = argp;
    361    
    362			if(get_user(dir, &hf->dir) < 0)
    363				return -EFAULT;
    364			if(get_user(out, &hf->out) < 0)
    365				return -EFAULT;
    366
    367			mutex_lock(&dsp56k_mutex);
    368			if ((dir & 0x1) && (out & 0x1))
    369				dsp56k_host_interface.icr |= DSP56K_ICR_HF0;
    370			else if (dir & 0x1)
    371				dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0;
    372			if ((dir & 0x2) && (out & 0x2))
    373				dsp56k_host_interface.icr |= DSP56K_ICR_HF1;
    374			else if (dir & 0x2)
    375				dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1;
    376
    377			status = 0;
    378			if (dsp56k_host_interface.icr & DSP56K_ICR_HF0) status |= 0x1;
    379			if (dsp56k_host_interface.icr & DSP56K_ICR_HF1) status |= 0x2;
    380			if (dsp56k_host_interface.isr & DSP56K_ISR_HF2) status |= 0x4;
    381			if (dsp56k_host_interface.isr & DSP56K_ISR_HF3) status |= 0x8;
    382			mutex_unlock(&dsp56k_mutex);
    383			return put_user(status, &hf->status);
    384		}
    385		case DSP56K_HOST_CMD:
    386			if (arg > 31)
    387				return -EINVAL;
    388			mutex_lock(&dsp56k_mutex);
    389			dsp56k_host_interface.cvr = (u_char)((arg & DSP56K_CVR_HV_MASK) |
    390							     DSP56K_CVR_HC);
    391			mutex_unlock(&dsp56k_mutex);
    392			break;
    393		default:
    394			return -EINVAL;
    395		}
    396		return 0;
    397
    398	default:
    399		printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
    400		return -ENXIO;
    401	}
    402}
    403
    404/* As of 2.1.26 this should be dsp56k_poll,
    405 * but how do I then check device minor number?
    406 * Do I need this function at all???
    407 */
    408#if 0
    409static __poll_t dsp56k_poll(struct file *file, poll_table *wait)
    410{
    411	int dev = iminor(file_inode(file)) & 0x0f;
    412
    413	switch(dev)
    414	{
    415	case DSP56K_DEV_56001:
    416		/* poll_wait(file, ???, wait); */
    417		return EPOLLIN | EPOLLRDNORM | EPOLLOUT;
    418
    419	default:
    420		printk("DSP56k driver: Unknown minor device: %d\n", dev);
    421		return 0;
    422	}
    423}
    424#endif
    425
    426static int dsp56k_open(struct inode *inode, struct file *file)
    427{
    428	int dev = iminor(inode) & 0x0f;
    429	int ret = 0;
    430
    431	mutex_lock(&dsp56k_mutex);
    432	switch(dev)
    433	{
    434	case DSP56K_DEV_56001:
    435
    436		if (test_and_set_bit(0, &dsp56k.in_use)) {
    437			ret = -EBUSY;
    438			goto out;
    439		}
    440
    441		dsp56k.timeout = TIMEOUT;
    442		dsp56k.maxio = MAXIO;
    443		dsp56k.rx_wsize = dsp56k.tx_wsize = 4; 
    444
    445		DSP56K_TX_INT_OFF;
    446		DSP56K_RX_INT_OFF;
    447
    448		/* Zero host flags */
    449		dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0;
    450		dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1;
    451
    452		break;
    453
    454	default:
    455		ret = -ENODEV;
    456	}
    457out:
    458	mutex_unlock(&dsp56k_mutex);
    459	return ret;
    460}
    461
    462static int dsp56k_release(struct inode *inode, struct file *file)
    463{
    464	int dev = iminor(inode) & 0x0f;
    465
    466	switch(dev)
    467	{
    468	case DSP56K_DEV_56001:
    469		clear_bit(0, &dsp56k.in_use);
    470		break;
    471	default:
    472		printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
    473		return -ENXIO;
    474	}
    475
    476	return 0;
    477}
    478
    479static const struct file_operations dsp56k_fops = {
    480	.owner		= THIS_MODULE,
    481	.read		= dsp56k_read,
    482	.write		= dsp56k_write,
    483	.unlocked_ioctl	= dsp56k_ioctl,
    484	.open		= dsp56k_open,
    485	.release	= dsp56k_release,
    486	.llseek		= noop_llseek,
    487};
    488
    489
    490/****** Init and module functions ******/
    491
    492static const char banner[] __initconst = KERN_INFO "DSP56k driver installed\n";
    493
    494static int __init dsp56k_init_driver(void)
    495{
    496	int err = 0;
    497
    498	if(!MACH_IS_ATARI || !ATARIHW_PRESENT(DSP56K)) {
    499		printk("DSP56k driver: Hardware not present\n");
    500		return -ENODEV;
    501	}
    502
    503	if(register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops)) {
    504		printk("DSP56k driver: Unable to register driver\n");
    505		return -ENODEV;
    506	}
    507	dsp56k_class = class_create(THIS_MODULE, "dsp56k");
    508	if (IS_ERR(dsp56k_class)) {
    509		err = PTR_ERR(dsp56k_class);
    510		goto out_chrdev;
    511	}
    512	device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), NULL,
    513		      "dsp56k");
    514
    515	printk(banner);
    516	goto out;
    517
    518out_chrdev:
    519	unregister_chrdev(DSP56K_MAJOR, "dsp56k");
    520out:
    521	return err;
    522}
    523module_init(dsp56k_init_driver);
    524
    525static void __exit dsp56k_cleanup_driver(void)
    526{
    527	device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0));
    528	class_destroy(dsp56k_class);
    529	unregister_chrdev(DSP56K_MAJOR, "dsp56k");
    530}
    531module_exit(dsp56k_cleanup_driver);
    532
    533MODULE_LICENSE("GPL");
    534MODULE_FIRMWARE("dsp56k/bootstrap.bin");