xref: /linux/drivers/char/mwave/mwavedd.c (revision cdd38c5f1ce4398ec58fec95904b75824daab7b5)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds *
31da177e4SLinus Torvalds * mwavedd.c -- mwave device driver
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds *
61da177e4SLinus Torvalds * Written By: Mike Sullivan IBM Corporation
71da177e4SLinus Torvalds *
81da177e4SLinus Torvalds * Copyright (C) 1999 IBM Corporation
91da177e4SLinus Torvalds *
101da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify
111da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by
121da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or
131da177e4SLinus Torvalds * (at your option) any later version.
141da177e4SLinus Torvalds *
151da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful,
161da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of
171da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
181da177e4SLinus Torvalds * GNU General Public License for more details.
191da177e4SLinus Torvalds *
201da177e4SLinus Torvalds * NO WARRANTY
211da177e4SLinus Torvalds * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
221da177e4SLinus Torvalds * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
231da177e4SLinus Torvalds * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
241da177e4SLinus Torvalds * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
251da177e4SLinus Torvalds * solely responsible for determining the appropriateness of using and
261da177e4SLinus Torvalds * distributing the Program and assumes all risks associated with its
271da177e4SLinus Torvalds * exercise of rights under this Agreement, including but not limited to
281da177e4SLinus Torvalds * the risks and costs of program errors, damage to or loss of data,
291da177e4SLinus Torvalds * programs or equipment, and unavailability or interruption of operations.
301da177e4SLinus Torvalds *
311da177e4SLinus Torvalds * DISCLAIMER OF LIABILITY
321da177e4SLinus Torvalds * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
331da177e4SLinus Torvalds * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
341da177e4SLinus Torvalds * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
351da177e4SLinus Torvalds * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
361da177e4SLinus Torvalds * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
371da177e4SLinus Torvalds * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
381da177e4SLinus Torvalds * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
391da177e4SLinus Torvalds *
401da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License
411da177e4SLinus Torvalds * along with this program; if not, write to the Free Software
421da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
431da177e4SLinus Torvalds *
441da177e4SLinus Torvalds *
451da177e4SLinus Torvalds * 10/23/2000 - Alpha Release
461da177e4SLinus Torvalds *	First release to the public
471da177e4SLinus Torvalds */
481da177e4SLinus Torvalds 
491da177e4SLinus Torvalds #include <linux/module.h>
501da177e4SLinus Torvalds #include <linux/kernel.h>
511da177e4SLinus Torvalds #include <linux/fs.h>
521da177e4SLinus Torvalds #include <linux/init.h>
531da177e4SLinus Torvalds #include <linux/major.h>
541da177e4SLinus Torvalds #include <linux/miscdevice.h>
551da177e4SLinus Torvalds #include <linux/device.h>
561da177e4SLinus Torvalds #include <linux/serial.h>
571da177e4SLinus Torvalds #include <linux/sched.h>
581da177e4SLinus Torvalds #include <linux/spinlock.h>
59613655faSArnd Bergmann #include <linux/mutex.h>
601da177e4SLinus Torvalds #include <linux/delay.h>
615981d644SAlan Cox #include <linux/serial_8250.h>
62*701956d4SGustavo A. R. Silva #include <linux/nospec.h>
631da177e4SLinus Torvalds #include "smapi.h"
641da177e4SLinus Torvalds #include "mwavedd.h"
651da177e4SLinus Torvalds #include "3780i.h"
661da177e4SLinus Torvalds #include "tp3780i.h"
671da177e4SLinus Torvalds 
681da177e4SLinus Torvalds MODULE_DESCRIPTION("3780i Advanced Communications Processor (Mwave) driver");
691da177e4SLinus Torvalds MODULE_AUTHOR("Mike Sullivan and Paul Schroeder");
701da177e4SLinus Torvalds MODULE_LICENSE("GPL");
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds /*
731da177e4SLinus Torvalds * These parameters support the setting of MWave resources. Note that no
741da177e4SLinus Torvalds * checks are made against other devices (ie. superio) for conflicts.
751da177e4SLinus Torvalds * We'll depend on users using the tpctl utility to do that for now
761da177e4SLinus Torvalds */
77613655faSArnd Bergmann static DEFINE_MUTEX(mwave_mutex);
781da177e4SLinus Torvalds int mwave_debug = 0;
791da177e4SLinus Torvalds int mwave_3780i_irq = 0;
801da177e4SLinus Torvalds int mwave_3780i_io = 0;
811da177e4SLinus Torvalds int mwave_uart_irq = 0;
821da177e4SLinus Torvalds int mwave_uart_io = 0;
831da177e4SLinus Torvalds module_param(mwave_debug, int, 0);
8494b599bcSDavid Howells module_param_hw(mwave_3780i_irq, int, irq, 0);
8594b599bcSDavid Howells module_param_hw(mwave_3780i_io, int, ioport, 0);
8694b599bcSDavid Howells module_param_hw(mwave_uart_irq, int, irq, 0);
8794b599bcSDavid Howells module_param_hw(mwave_uart_io, int, ioport, 0);
881da177e4SLinus Torvalds 
891da177e4SLinus Torvalds static int mwave_open(struct inode *inode, struct file *file);
901da177e4SLinus Torvalds static int mwave_close(struct inode *inode, struct file *file);
91909d145fSAlan Cox static long mwave_ioctl(struct file *filp, unsigned int iocmd,
92909d145fSAlan Cox 							unsigned long ioarg);
931da177e4SLinus Torvalds 
941da177e4SLinus Torvalds MWAVE_DEVICE_DATA mwave_s_mdd;
951da177e4SLinus Torvalds 
mwave_open(struct inode * inode,struct file * file)961da177e4SLinus Torvalds static int mwave_open(struct inode *inode, struct file *file)
971da177e4SLinus Torvalds {
981da177e4SLinus Torvalds 	unsigned int retval = 0;
991da177e4SLinus Torvalds 
1001da177e4SLinus Torvalds 	PRINTK_3(TRACE_MWAVE,
1011da177e4SLinus Torvalds 		"mwavedd::mwave_open, entry inode %p file %p\n",
1021da177e4SLinus Torvalds 		 inode, file);
1031da177e4SLinus Torvalds 	PRINTK_2(TRACE_MWAVE,
1041da177e4SLinus Torvalds 		"mwavedd::mwave_open, exit return retval %x\n", retval);
1051da177e4SLinus Torvalds 
1061da177e4SLinus Torvalds 	return retval;
1071da177e4SLinus Torvalds }
1081da177e4SLinus Torvalds 
mwave_close(struct inode * inode,struct file * file)1091da177e4SLinus Torvalds static int mwave_close(struct inode *inode, struct file *file)
1101da177e4SLinus Torvalds {
1111da177e4SLinus Torvalds 	unsigned int retval = 0;
1121da177e4SLinus Torvalds 
1131da177e4SLinus Torvalds 	PRINTK_3(TRACE_MWAVE,
1141da177e4SLinus Torvalds 		"mwavedd::mwave_close, entry inode %p file %p\n",
1151da177e4SLinus Torvalds 		 inode,  file);
1161da177e4SLinus Torvalds 
1171da177e4SLinus Torvalds 	PRINTK_2(TRACE_MWAVE, "mwavedd::mwave_close, exit retval %x\n",
1181da177e4SLinus Torvalds 		retval);
1191da177e4SLinus Torvalds 
1201da177e4SLinus Torvalds 	return retval;
1211da177e4SLinus Torvalds }
1221da177e4SLinus Torvalds 
mwave_ioctl(struct file * file,unsigned int iocmd,unsigned long ioarg)123909d145fSAlan Cox static long mwave_ioctl(struct file *file, unsigned int iocmd,
124909d145fSAlan Cox 							unsigned long ioarg)
1251da177e4SLinus Torvalds {
1261da177e4SLinus Torvalds 	unsigned int retval = 0;
1271da177e4SLinus Torvalds 	pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;
1281da177e4SLinus Torvalds 	void __user *arg = (void __user *)ioarg;
1291da177e4SLinus Torvalds 
130909d145fSAlan Cox 	PRINTK_4(TRACE_MWAVE,
131909d145fSAlan Cox 		"mwavedd::mwave_ioctl, entry file %p cmd %x arg %x\n",
132909d145fSAlan Cox 		file, iocmd, (int) ioarg);
1331da177e4SLinus Torvalds 
1341da177e4SLinus Torvalds 	switch (iocmd) {
1351da177e4SLinus Torvalds 
1361da177e4SLinus Torvalds 		case IOCTL_MW_RESET:
1371da177e4SLinus Torvalds 			PRINTK_1(TRACE_MWAVE,
1381da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl, IOCTL_MW_RESET"
1391da177e4SLinus Torvalds 				" calling tp3780I_ResetDSP\n");
140613655faSArnd Bergmann 			mutex_lock(&mwave_mutex);
1411da177e4SLinus Torvalds 			retval = tp3780I_ResetDSP(&pDrvData->rBDData);
142613655faSArnd Bergmann 			mutex_unlock(&mwave_mutex);
1431da177e4SLinus Torvalds 			PRINTK_2(TRACE_MWAVE,
1441da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl, IOCTL_MW_RESET"
1451da177e4SLinus Torvalds 				" retval %x from tp3780I_ResetDSP\n",
1461da177e4SLinus Torvalds 				retval);
1471da177e4SLinus Torvalds 			break;
1481da177e4SLinus Torvalds 
1491da177e4SLinus Torvalds 		case IOCTL_MW_RUN:
1501da177e4SLinus Torvalds 			PRINTK_1(TRACE_MWAVE,
1511da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl, IOCTL_MW_RUN"
1521da177e4SLinus Torvalds 				" calling tp3780I_StartDSP\n");
153613655faSArnd Bergmann 			mutex_lock(&mwave_mutex);
1541da177e4SLinus Torvalds 			retval = tp3780I_StartDSP(&pDrvData->rBDData);
155613655faSArnd Bergmann 			mutex_unlock(&mwave_mutex);
1561da177e4SLinus Torvalds 			PRINTK_2(TRACE_MWAVE,
1571da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl, IOCTL_MW_RUN"
1581da177e4SLinus Torvalds 				" retval %x from tp3780I_StartDSP\n",
1591da177e4SLinus Torvalds 				retval);
1601da177e4SLinus Torvalds 			break;
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds 		case IOCTL_MW_DSP_ABILITIES: {
1631da177e4SLinus Torvalds 			MW_ABILITIES rAbilities;
1641da177e4SLinus Torvalds 
1651da177e4SLinus Torvalds 			PRINTK_1(TRACE_MWAVE,
1661da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl,"
1671da177e4SLinus Torvalds 				" IOCTL_MW_DSP_ABILITIES calling"
1681da177e4SLinus Torvalds 				" tp3780I_QueryAbilities\n");
169613655faSArnd Bergmann 			mutex_lock(&mwave_mutex);
1701da177e4SLinus Torvalds 			retval = tp3780I_QueryAbilities(&pDrvData->rBDData,
1711da177e4SLinus Torvalds 					&rAbilities);
172613655faSArnd Bergmann 			mutex_unlock(&mwave_mutex);
1731da177e4SLinus Torvalds 			PRINTK_2(TRACE_MWAVE,
1741da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl, IOCTL_MW_DSP_ABILITIES"
1751da177e4SLinus Torvalds 				" retval %x from tp3780I_QueryAbilities\n",
1761da177e4SLinus Torvalds 				retval);
1771da177e4SLinus Torvalds 			if (retval == 0) {
1781da177e4SLinus Torvalds 				if( copy_to_user(arg, &rAbilities,
1791da177e4SLinus Torvalds 							sizeof(MW_ABILITIES)) )
1801da177e4SLinus Torvalds 					return -EFAULT;
1811da177e4SLinus Torvalds 			}
1821da177e4SLinus Torvalds 			PRINTK_2(TRACE_MWAVE,
1831da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl, IOCTL_MW_DSP_ABILITIES"
1841da177e4SLinus Torvalds 				" exit retval %x\n",
1851da177e4SLinus Torvalds 				retval);
1861da177e4SLinus Torvalds 		}
1871da177e4SLinus Torvalds 			break;
1881da177e4SLinus Torvalds 
1891da177e4SLinus Torvalds 		case IOCTL_MW_READ_DATA:
1901da177e4SLinus Torvalds 		case IOCTL_MW_READCLEAR_DATA: {
1911da177e4SLinus Torvalds 			MW_READWRITE rReadData;
1921da177e4SLinus Torvalds 			unsigned short __user *pusBuffer = NULL;
1931da177e4SLinus Torvalds 
1941da177e4SLinus Torvalds 			if( copy_from_user(&rReadData, arg,
1951da177e4SLinus Torvalds 						sizeof(MW_READWRITE)) )
1961da177e4SLinus Torvalds 				return -EFAULT;
1971da177e4SLinus Torvalds 			pusBuffer = (unsigned short __user *) (rReadData.pBuf);
1981da177e4SLinus Torvalds 
1991da177e4SLinus Torvalds 			PRINTK_4(TRACE_MWAVE,
2001da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl IOCTL_MW_READ_DATA,"
2011da177e4SLinus Torvalds 				" size %lx, ioarg %lx pusBuffer %p\n",
2021da177e4SLinus Torvalds 				rReadData.ulDataLength, ioarg, pusBuffer);
203613655faSArnd Bergmann 			mutex_lock(&mwave_mutex);
2041da177e4SLinus Torvalds 			retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData,
2051da177e4SLinus Torvalds 					iocmd,
2061da177e4SLinus Torvalds 					pusBuffer,
2071da177e4SLinus Torvalds 					rReadData.ulDataLength,
2081da177e4SLinus Torvalds 					rReadData.usDspAddress);
209613655faSArnd Bergmann 			mutex_unlock(&mwave_mutex);
2101da177e4SLinus Torvalds 		}
2111da177e4SLinus Torvalds 			break;
2121da177e4SLinus Torvalds 
2131da177e4SLinus Torvalds 		case IOCTL_MW_READ_INST: {
2141da177e4SLinus Torvalds 			MW_READWRITE rReadData;
2151da177e4SLinus Torvalds 			unsigned short __user *pusBuffer = NULL;
2161da177e4SLinus Torvalds 
2171da177e4SLinus Torvalds 			if( copy_from_user(&rReadData, arg,
2181da177e4SLinus Torvalds 						sizeof(MW_READWRITE)) )
2191da177e4SLinus Torvalds 				return -EFAULT;
2201da177e4SLinus Torvalds 			pusBuffer = (unsigned short __user *) (rReadData.pBuf);
2211da177e4SLinus Torvalds 
2221da177e4SLinus Torvalds 			PRINTK_4(TRACE_MWAVE,
2231da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl IOCTL_MW_READ_INST,"
2241da177e4SLinus Torvalds 				" size %lx, ioarg %lx pusBuffer %p\n",
2251da177e4SLinus Torvalds 				rReadData.ulDataLength / 2, ioarg,
2261da177e4SLinus Torvalds 				pusBuffer);
227613655faSArnd Bergmann 			mutex_lock(&mwave_mutex);
2281da177e4SLinus Torvalds 			retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData,
2291da177e4SLinus Torvalds 				iocmd, pusBuffer,
2301da177e4SLinus Torvalds 				rReadData.ulDataLength / 2,
2311da177e4SLinus Torvalds 				rReadData.usDspAddress);
232613655faSArnd Bergmann 			mutex_unlock(&mwave_mutex);
2331da177e4SLinus Torvalds 		}
2341da177e4SLinus Torvalds 			break;
2351da177e4SLinus Torvalds 
2361da177e4SLinus Torvalds 		case IOCTL_MW_WRITE_DATA: {
2371da177e4SLinus Torvalds 			MW_READWRITE rWriteData;
2381da177e4SLinus Torvalds 			unsigned short __user *pusBuffer = NULL;
2391da177e4SLinus Torvalds 
2401da177e4SLinus Torvalds 			if( copy_from_user(&rWriteData, arg,
2411da177e4SLinus Torvalds 						sizeof(MW_READWRITE)) )
2421da177e4SLinus Torvalds 				return -EFAULT;
2431da177e4SLinus Torvalds 			pusBuffer = (unsigned short __user *) (rWriteData.pBuf);
2441da177e4SLinus Torvalds 
2451da177e4SLinus Torvalds 			PRINTK_4(TRACE_MWAVE,
2461da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl IOCTL_MW_WRITE_DATA,"
2471da177e4SLinus Torvalds 				" size %lx, ioarg %lx pusBuffer %p\n",
2481da177e4SLinus Torvalds 				rWriteData.ulDataLength, ioarg,
2491da177e4SLinus Torvalds 				pusBuffer);
250613655faSArnd Bergmann 			mutex_lock(&mwave_mutex);
2511da177e4SLinus Torvalds 			retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData,
2521da177e4SLinus Torvalds 					iocmd, pusBuffer,
2531da177e4SLinus Torvalds 					rWriteData.ulDataLength,
2541da177e4SLinus Torvalds 					rWriteData.usDspAddress);
255613655faSArnd Bergmann 			mutex_unlock(&mwave_mutex);
2561da177e4SLinus Torvalds 		}
2571da177e4SLinus Torvalds 			break;
2581da177e4SLinus Torvalds 
2591da177e4SLinus Torvalds 		case IOCTL_MW_WRITE_INST: {
2601da177e4SLinus Torvalds 			MW_READWRITE rWriteData;
2611da177e4SLinus Torvalds 			unsigned short __user *pusBuffer = NULL;
2621da177e4SLinus Torvalds 
2631da177e4SLinus Torvalds 			if( copy_from_user(&rWriteData, arg,
2641da177e4SLinus Torvalds 						sizeof(MW_READWRITE)) )
2651da177e4SLinus Torvalds 				return -EFAULT;
2661da177e4SLinus Torvalds 			pusBuffer = (unsigned short __user *)(rWriteData.pBuf);
2671da177e4SLinus Torvalds 
2681da177e4SLinus Torvalds 			PRINTK_4(TRACE_MWAVE,
2691da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl IOCTL_MW_WRITE_INST,"
2701da177e4SLinus Torvalds 				" size %lx, ioarg %lx pusBuffer %p\n",
2711da177e4SLinus Torvalds 				rWriteData.ulDataLength, ioarg,
2721da177e4SLinus Torvalds 				pusBuffer);
273613655faSArnd Bergmann 			mutex_lock(&mwave_mutex);
2741da177e4SLinus Torvalds 			retval = tp3780I_ReadWriteDspIStore(&pDrvData->rBDData,
2751da177e4SLinus Torvalds 					iocmd, pusBuffer,
2761da177e4SLinus Torvalds 					rWriteData.ulDataLength,
2771da177e4SLinus Torvalds 					rWriteData.usDspAddress);
278613655faSArnd Bergmann 			mutex_unlock(&mwave_mutex);
2791da177e4SLinus Torvalds 		}
2801da177e4SLinus Torvalds 			break;
2811da177e4SLinus Torvalds 
2821da177e4SLinus Torvalds 		case IOCTL_MW_REGISTER_IPC: {
2831da177e4SLinus Torvalds 			unsigned int ipcnum = (unsigned int) ioarg;
2841da177e4SLinus Torvalds 
285d698f1c7SEric Sesterhenn 			if (ipcnum >= ARRAY_SIZE(pDrvData->IPCs)) {
2861da177e4SLinus Torvalds 				PRINTK_ERROR(KERN_ERR_MWAVE
2871da177e4SLinus Torvalds 						"mwavedd::mwave_ioctl:"
2881da177e4SLinus Torvalds 						" IOCTL_MW_REGISTER_IPC:"
2891da177e4SLinus Torvalds 						" Error: Invalid ipcnum %x\n",
2901da177e4SLinus Torvalds 						ipcnum);
2911da177e4SLinus Torvalds 				return -EINVAL;
2921da177e4SLinus Torvalds 			}
293*701956d4SGustavo A. R. Silva 			ipcnum = array_index_nospec(ipcnum,
294*701956d4SGustavo A. R. Silva 						    ARRAY_SIZE(pDrvData->IPCs));
295dc80df56SRoel Kluin 			PRINTK_3(TRACE_MWAVE,
296dc80df56SRoel Kluin 				"mwavedd::mwave_ioctl IOCTL_MW_REGISTER_IPC"
297dc80df56SRoel Kluin 				" ipcnum %x entry usIntCount %x\n",
298dc80df56SRoel Kluin 				ipcnum,
299dc80df56SRoel Kluin 				pDrvData->IPCs[ipcnum].usIntCount);
300dc80df56SRoel Kluin 
301613655faSArnd Bergmann 			mutex_lock(&mwave_mutex);
30226ec99b1SArnd Bergmann 			pDrvData->IPCs[ipcnum].bIsHere = false;
30326ec99b1SArnd Bergmann 			pDrvData->IPCs[ipcnum].bIsEnabled = true;
304613655faSArnd Bergmann 			mutex_unlock(&mwave_mutex);
3051da177e4SLinus Torvalds 
3061da177e4SLinus Torvalds 			PRINTK_2(TRACE_MWAVE,
3071da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl IOCTL_MW_REGISTER_IPC"
3081da177e4SLinus Torvalds 				" ipcnum %x exit\n",
3091da177e4SLinus Torvalds 				ipcnum);
3101da177e4SLinus Torvalds 		}
3111da177e4SLinus Torvalds 			break;
3121da177e4SLinus Torvalds 
3131da177e4SLinus Torvalds 		case IOCTL_MW_GET_IPC: {
3141da177e4SLinus Torvalds 			unsigned int ipcnum = (unsigned int) ioarg;
3151da177e4SLinus Torvalds 
316095d030cSEric Sesterhenn 			if (ipcnum >= ARRAY_SIZE(pDrvData->IPCs)) {
3171da177e4SLinus Torvalds 				PRINTK_ERROR(KERN_ERR_MWAVE
3181da177e4SLinus Torvalds 						"mwavedd::mwave_ioctl:"
3191da177e4SLinus Torvalds 						" IOCTL_MW_GET_IPC: Error:"
3201da177e4SLinus Torvalds 						" Invalid ipcnum %x\n", ipcnum);
3211da177e4SLinus Torvalds 				return -EINVAL;
3221da177e4SLinus Torvalds 			}
323*701956d4SGustavo A. R. Silva 			ipcnum = array_index_nospec(ipcnum,
324*701956d4SGustavo A. R. Silva 						    ARRAY_SIZE(pDrvData->IPCs));
325dc80df56SRoel Kluin 			PRINTK_3(TRACE_MWAVE,
326dc80df56SRoel Kluin 				"mwavedd::mwave_ioctl IOCTL_MW_GET_IPC"
327dc80df56SRoel Kluin 				" ipcnum %x, usIntCount %x\n",
328dc80df56SRoel Kluin 				ipcnum,
329dc80df56SRoel Kluin 				pDrvData->IPCs[ipcnum].usIntCount);
3301da177e4SLinus Torvalds 
331613655faSArnd Bergmann 			mutex_lock(&mwave_mutex);
33226ec99b1SArnd Bergmann 			if (pDrvData->IPCs[ipcnum].bIsEnabled == true) {
3331da177e4SLinus Torvalds 				DECLARE_WAITQUEUE(wait, current);
3341da177e4SLinus Torvalds 
3351da177e4SLinus Torvalds 				PRINTK_2(TRACE_MWAVE,
3361da177e4SLinus Torvalds 					"mwavedd::mwave_ioctl, thread for"
3371da177e4SLinus Torvalds 					" ipc %x going to sleep\n",
3381da177e4SLinus Torvalds 					ipcnum);
3391da177e4SLinus Torvalds 				add_wait_queue(&pDrvData->IPCs[ipcnum].ipc_wait_queue, &wait);
34026ec99b1SArnd Bergmann 				pDrvData->IPCs[ipcnum].bIsHere = true;
3411da177e4SLinus Torvalds 				set_current_state(TASK_INTERRUPTIBLE);
3421da177e4SLinus Torvalds 				/* check whether an event was signalled by */
3431da177e4SLinus Torvalds 				/* the interrupt handler while we were gone */
3441da177e4SLinus Torvalds 				if (pDrvData->IPCs[ipcnum].usIntCount == 1) {	/* first int has occurred (race condition) */
3451da177e4SLinus Torvalds 					pDrvData->IPCs[ipcnum].usIntCount = 2;	/* first int has been handled */
3461da177e4SLinus Torvalds 					PRINTK_2(TRACE_MWAVE,
3471da177e4SLinus Torvalds 						"mwavedd::mwave_ioctl"
3481da177e4SLinus Torvalds 						" IOCTL_MW_GET_IPC ipcnum %x"
3491da177e4SLinus Torvalds 						" handling first int\n",
3501da177e4SLinus Torvalds 						ipcnum);
3511da177e4SLinus Torvalds 				} else {	/* either 1st int has not yet occurred, or we have already handled the first int */
3521da177e4SLinus Torvalds 					schedule();
3531da177e4SLinus Torvalds 					if (pDrvData->IPCs[ipcnum].usIntCount == 1) {
3541da177e4SLinus Torvalds 						pDrvData->IPCs[ipcnum].usIntCount = 2;
3551da177e4SLinus Torvalds 					}
3561da177e4SLinus Torvalds 					PRINTK_2(TRACE_MWAVE,
3571da177e4SLinus Torvalds 						"mwavedd::mwave_ioctl"
3581da177e4SLinus Torvalds 						" IOCTL_MW_GET_IPC ipcnum %x"
3591da177e4SLinus Torvalds 						" woke up and returning to"
3601da177e4SLinus Torvalds 						" application\n",
3611da177e4SLinus Torvalds 						ipcnum);
3621da177e4SLinus Torvalds 				}
36326ec99b1SArnd Bergmann 				pDrvData->IPCs[ipcnum].bIsHere = false;
3641da177e4SLinus Torvalds 				remove_wait_queue(&pDrvData->IPCs[ipcnum].ipc_wait_queue, &wait);
3651da177e4SLinus Torvalds 				set_current_state(TASK_RUNNING);
3661da177e4SLinus Torvalds 				PRINTK_2(TRACE_MWAVE,
3671da177e4SLinus Torvalds 					"mwavedd::mwave_ioctl IOCTL_MW_GET_IPC,"
3681da177e4SLinus Torvalds 					" returning thread for ipc %x"
3691da177e4SLinus Torvalds 					" processing\n",
3701da177e4SLinus Torvalds 					ipcnum);
3711da177e4SLinus Torvalds 			}
372613655faSArnd Bergmann 			mutex_unlock(&mwave_mutex);
3731da177e4SLinus Torvalds 		}
3741da177e4SLinus Torvalds 			break;
3751da177e4SLinus Torvalds 
3761da177e4SLinus Torvalds 		case IOCTL_MW_UNREGISTER_IPC: {
3771da177e4SLinus Torvalds 			unsigned int ipcnum = (unsigned int) ioarg;
3781da177e4SLinus Torvalds 
3791da177e4SLinus Torvalds 			PRINTK_2(TRACE_MWAVE,
3801da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl IOCTL_MW_UNREGISTER_IPC"
3811da177e4SLinus Torvalds 				" ipcnum %x\n",
3821da177e4SLinus Torvalds 				ipcnum);
383095d030cSEric Sesterhenn 			if (ipcnum >= ARRAY_SIZE(pDrvData->IPCs)) {
3841da177e4SLinus Torvalds 				PRINTK_ERROR(KERN_ERR_MWAVE
3851da177e4SLinus Torvalds 						"mwavedd::mwave_ioctl:"
3861da177e4SLinus Torvalds 						" IOCTL_MW_UNREGISTER_IPC:"
3871da177e4SLinus Torvalds 						" Error: Invalid ipcnum %x\n",
3881da177e4SLinus Torvalds 						ipcnum);
3891da177e4SLinus Torvalds 				return -EINVAL;
3901da177e4SLinus Torvalds 			}
391*701956d4SGustavo A. R. Silva 			ipcnum = array_index_nospec(ipcnum,
392*701956d4SGustavo A. R. Silva 						    ARRAY_SIZE(pDrvData->IPCs));
393613655faSArnd Bergmann 			mutex_lock(&mwave_mutex);
39426ec99b1SArnd Bergmann 			if (pDrvData->IPCs[ipcnum].bIsEnabled == true) {
39526ec99b1SArnd Bergmann 				pDrvData->IPCs[ipcnum].bIsEnabled = false;
39626ec99b1SArnd Bergmann 				if (pDrvData->IPCs[ipcnum].bIsHere == true) {
3971da177e4SLinus Torvalds 					wake_up_interruptible(&pDrvData->IPCs[ipcnum].ipc_wait_queue);
3981da177e4SLinus Torvalds 				}
3991da177e4SLinus Torvalds 			}
400613655faSArnd Bergmann 			mutex_unlock(&mwave_mutex);
4011da177e4SLinus Torvalds 		}
4021da177e4SLinus Torvalds 			break;
4031da177e4SLinus Torvalds 
4041da177e4SLinus Torvalds 		default:
4051da177e4SLinus Torvalds 			return -ENOTTY;
4061da177e4SLinus Torvalds 	} /* switch */
4071da177e4SLinus Torvalds 
4081da177e4SLinus Torvalds 	PRINTK_2(TRACE_MWAVE, "mwavedd::mwave_ioctl, exit retval %x\n", retval);
4091da177e4SLinus Torvalds 
4101da177e4SLinus Torvalds 	return retval;
4111da177e4SLinus Torvalds }
4121da177e4SLinus Torvalds 
4131da177e4SLinus Torvalds 
mwave_read(struct file * file,char __user * buf,size_t count,loff_t * ppos)4141da177e4SLinus Torvalds static ssize_t mwave_read(struct file *file, char __user *buf, size_t count,
4151da177e4SLinus Torvalds                           loff_t * ppos)
4161da177e4SLinus Torvalds {
4171da177e4SLinus Torvalds 	PRINTK_5(TRACE_MWAVE,
4181da177e4SLinus Torvalds 		"mwavedd::mwave_read entry file %p, buf %p, count %zx ppos %p\n",
4191da177e4SLinus Torvalds 		file, buf, count, ppos);
4201da177e4SLinus Torvalds 
4211da177e4SLinus Torvalds 	return -EINVAL;
4221da177e4SLinus Torvalds }
4231da177e4SLinus Torvalds 
4241da177e4SLinus Torvalds 
mwave_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos)4251da177e4SLinus Torvalds static ssize_t mwave_write(struct file *file, const char __user *buf,
4261da177e4SLinus Torvalds                            size_t count, loff_t * ppos)
4271da177e4SLinus Torvalds {
4281da177e4SLinus Torvalds 	PRINTK_5(TRACE_MWAVE,
4291da177e4SLinus Torvalds 		"mwavedd::mwave_write entry file %p, buf %p,"
4301da177e4SLinus Torvalds 		" count %zx ppos %p\n",
4311da177e4SLinus Torvalds 		file, buf, count, ppos);
4321da177e4SLinus Torvalds 
4331da177e4SLinus Torvalds 	return -EINVAL;
4341da177e4SLinus Torvalds }
4351da177e4SLinus Torvalds 
4361da177e4SLinus Torvalds 
register_serial_portandirq(unsigned int port,int irq)4371da177e4SLinus Torvalds static int register_serial_portandirq(unsigned int port, int irq)
4381da177e4SLinus Torvalds {
439ce7240e4SAlan Cox 	struct uart_8250_port uart;
4401da177e4SLinus Torvalds 
4411da177e4SLinus Torvalds 	switch ( port ) {
4421da177e4SLinus Torvalds 		case 0x3f8:
4431da177e4SLinus Torvalds 		case 0x2f8:
4441da177e4SLinus Torvalds 		case 0x3e8:
4451da177e4SLinus Torvalds 		case 0x2e8:
4461da177e4SLinus Torvalds 			/* OK */
4471da177e4SLinus Torvalds 			break;
4481da177e4SLinus Torvalds 		default:
4491da177e4SLinus Torvalds 			PRINTK_ERROR(KERN_ERR_MWAVE
4501da177e4SLinus Torvalds 					"mwavedd::register_serial_portandirq:"
4511da177e4SLinus Torvalds 					" Error: Illegal port %x\n", port );
4521da177e4SLinus Torvalds 			return -1;
4531da177e4SLinus Torvalds 	} /* switch */
4541da177e4SLinus Torvalds 	/* port is okay */
4551da177e4SLinus Torvalds 
4561da177e4SLinus Torvalds 	switch ( irq ) {
4571da177e4SLinus Torvalds 		case 3:
4581da177e4SLinus Torvalds 		case 4:
4591da177e4SLinus Torvalds 		case 5:
4601da177e4SLinus Torvalds 		case 7:
4611da177e4SLinus Torvalds 			/* OK */
4621da177e4SLinus Torvalds 			break;
4631da177e4SLinus Torvalds 		default:
4641da177e4SLinus Torvalds 			PRINTK_ERROR(KERN_ERR_MWAVE
4651da177e4SLinus Torvalds 					"mwavedd::register_serial_portandirq:"
4661da177e4SLinus Torvalds 					" Error: Illegal irq %x\n", irq );
4671da177e4SLinus Torvalds 			return -1;
4681da177e4SLinus Torvalds 	} /* switch */
4691da177e4SLinus Torvalds 	/* irq is okay */
4701da177e4SLinus Torvalds 
471ce7240e4SAlan Cox 	memset(&uart, 0, sizeof(uart));
4721da177e4SLinus Torvalds 
473ce7240e4SAlan Cox 	uart.port.uartclk =  1843200;
474ce7240e4SAlan Cox 	uart.port.iobase = port;
475ce7240e4SAlan Cox 	uart.port.irq = irq;
476ce7240e4SAlan Cox 	uart.port.iotype = UPIO_PORT;
477ce7240e4SAlan Cox 	uart.port.flags =  UPF_SHARE_IRQ;
478ce7240e4SAlan Cox 	return serial8250_register_8250_port(&uart);
4791da177e4SLinus Torvalds }
4801da177e4SLinus Torvalds 
4811da177e4SLinus Torvalds 
48262322d25SArjan van de Ven static const struct file_operations mwave_fops = {
4831da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
4841da177e4SLinus Torvalds 	.read		= mwave_read,
4851da177e4SLinus Torvalds 	.write		= mwave_write,
486909d145fSAlan Cox 	.unlocked_ioctl	= mwave_ioctl,
4871da177e4SLinus Torvalds 	.open		= mwave_open,
4886038f373SArnd Bergmann 	.release	= mwave_close,
4896038f373SArnd Bergmann 	.llseek		= default_llseek,
4901da177e4SLinus Torvalds };
4911da177e4SLinus Torvalds 
4921da177e4SLinus Torvalds 
4931da177e4SLinus Torvalds static struct miscdevice mwave_misc_dev = { MWAVE_MINOR, "mwave", &mwave_fops };
4941da177e4SLinus Torvalds 
4951da177e4SLinus Torvalds #if 0 /* totally b0rked */
4961da177e4SLinus Torvalds /*
4971da177e4SLinus Torvalds  * sysfs support <paulsch@us.ibm.com>
4981da177e4SLinus Torvalds  */
4991da177e4SLinus Torvalds 
5001da177e4SLinus Torvalds struct device mwave_device;
5011da177e4SLinus Torvalds 
5021da177e4SLinus Torvalds /* Prevent code redundancy, create a macro for mwave_show_* functions. */
5031da177e4SLinus Torvalds #define mwave_show_function(attr_name, format_string, field)		\
50474880c06SYani Ioannou static ssize_t mwave_show_##attr_name(struct device *dev, struct device_attribute *attr, char *buf)	\
5051da177e4SLinus Torvalds {									\
5061da177e4SLinus Torvalds 	DSP_3780I_CONFIG_SETTINGS *pSettings =				\
5071da177e4SLinus Torvalds 		&mwave_s_mdd.rBDData.rDspSettings;			\
5081da177e4SLinus Torvalds         return sprintf(buf, format_string, pSettings->field);		\
5091da177e4SLinus Torvalds }
5101da177e4SLinus Torvalds 
5111da177e4SLinus Torvalds /* All of our attributes are read attributes. */
5121da177e4SLinus Torvalds #define mwave_dev_rd_attr(attr_name, format_string, field)		\
5131da177e4SLinus Torvalds 	mwave_show_function(attr_name, format_string, field)		\
5141da177e4SLinus Torvalds static DEVICE_ATTR(attr_name, S_IRUGO, mwave_show_##attr_name, NULL)
5151da177e4SLinus Torvalds 
5161da177e4SLinus Torvalds mwave_dev_rd_attr (3780i_dma, "%i\n", usDspDma);
5171da177e4SLinus Torvalds mwave_dev_rd_attr (3780i_irq, "%i\n", usDspIrq);
5181da177e4SLinus Torvalds mwave_dev_rd_attr (3780i_io, "%#.4x\n", usDspBaseIO);
5191da177e4SLinus Torvalds mwave_dev_rd_attr (uart_irq, "%i\n", usUartIrq);
5201da177e4SLinus Torvalds mwave_dev_rd_attr (uart_io, "%#.4x\n", usUartBaseIO);
5211da177e4SLinus Torvalds 
5221da177e4SLinus Torvalds static struct device_attribute * const mwave_dev_attrs[] = {
5231da177e4SLinus Torvalds 	&dev_attr_3780i_dma,
5241da177e4SLinus Torvalds 	&dev_attr_3780i_irq,
5251da177e4SLinus Torvalds 	&dev_attr_3780i_io,
5261da177e4SLinus Torvalds 	&dev_attr_uart_irq,
5271da177e4SLinus Torvalds 	&dev_attr_uart_io,
5281da177e4SLinus Torvalds };
5291da177e4SLinus Torvalds #endif
5301da177e4SLinus Torvalds 
5311da177e4SLinus Torvalds /*
5321da177e4SLinus Torvalds * mwave_init is called on module load
5331da177e4SLinus Torvalds *
5341da177e4SLinus Torvalds * mwave_exit is called on module unload
5351da177e4SLinus Torvalds * mwave_exit is also used to clean up after an aborted mwave_init
5361da177e4SLinus Torvalds */
mwave_exit(void)5371da177e4SLinus Torvalds static void mwave_exit(void)
5381da177e4SLinus Torvalds {
5391da177e4SLinus Torvalds 	pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;
5401da177e4SLinus Torvalds 
5411da177e4SLinus Torvalds 	PRINTK_1(TRACE_MWAVE, "mwavedd::mwave_exit entry\n");
5421da177e4SLinus Torvalds 
5431da177e4SLinus Torvalds #if 0
5441da177e4SLinus Torvalds 	for (i = 0; i < pDrvData->nr_registered_attrs; i++)
5451da177e4SLinus Torvalds 		device_remove_file(&mwave_device, mwave_dev_attrs[i]);
5461da177e4SLinus Torvalds 	pDrvData->nr_registered_attrs = 0;
5471da177e4SLinus Torvalds 
5481da177e4SLinus Torvalds 	if (pDrvData->device_registered) {
5491da177e4SLinus Torvalds 		device_unregister(&mwave_device);
55026ec99b1SArnd Bergmann 		pDrvData->device_registered = false;
5511da177e4SLinus Torvalds 	}
5521da177e4SLinus Torvalds #endif
5531da177e4SLinus Torvalds 
5541da177e4SLinus Torvalds 	if ( pDrvData->sLine >= 0 ) {
5555981d644SAlan Cox 		serial8250_unregister_port(pDrvData->sLine);
5561da177e4SLinus Torvalds 	}
5571da177e4SLinus Torvalds 	if (pDrvData->bMwaveDevRegistered) {
5581da177e4SLinus Torvalds 		misc_deregister(&mwave_misc_dev);
5591da177e4SLinus Torvalds 	}
5601da177e4SLinus Torvalds 	if (pDrvData->bDSPEnabled) {
5611da177e4SLinus Torvalds 		tp3780I_DisableDSP(&pDrvData->rBDData);
5621da177e4SLinus Torvalds 	}
5631da177e4SLinus Torvalds 	if (pDrvData->bResourcesClaimed) {
5641da177e4SLinus Torvalds 		tp3780I_ReleaseResources(&pDrvData->rBDData);
5651da177e4SLinus Torvalds 	}
5661da177e4SLinus Torvalds 	if (pDrvData->bBDInitialized) {
5671da177e4SLinus Torvalds 		tp3780I_Cleanup(&pDrvData->rBDData);
5681da177e4SLinus Torvalds 	}
5691da177e4SLinus Torvalds 
5701da177e4SLinus Torvalds 	PRINTK_1(TRACE_MWAVE, "mwavedd::mwave_exit exit\n");
5711da177e4SLinus Torvalds }
5721da177e4SLinus Torvalds 
5731da177e4SLinus Torvalds module_exit(mwave_exit);
5741da177e4SLinus Torvalds 
mwave_init(void)5751da177e4SLinus Torvalds static int __init mwave_init(void)
5761da177e4SLinus Torvalds {
5771da177e4SLinus Torvalds 	int i;
5781da177e4SLinus Torvalds 	int retval = 0;
5791da177e4SLinus Torvalds 	pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;
5801da177e4SLinus Torvalds 
5811da177e4SLinus Torvalds 	PRINTK_1(TRACE_MWAVE, "mwavedd::mwave_init entry\n");
5821da177e4SLinus Torvalds 
5831da177e4SLinus Torvalds 	memset(&mwave_s_mdd, 0, sizeof(MWAVE_DEVICE_DATA));
5841da177e4SLinus Torvalds 
58526ec99b1SArnd Bergmann 	pDrvData->bBDInitialized = false;
58626ec99b1SArnd Bergmann 	pDrvData->bResourcesClaimed = false;
58726ec99b1SArnd Bergmann 	pDrvData->bDSPEnabled = false;
58826ec99b1SArnd Bergmann 	pDrvData->bDSPReset = false;
58926ec99b1SArnd Bergmann 	pDrvData->bMwaveDevRegistered = false;
5901da177e4SLinus Torvalds 	pDrvData->sLine = -1;
5911da177e4SLinus Torvalds 
5921da177e4SLinus Torvalds 	for (i = 0; i < ARRAY_SIZE(pDrvData->IPCs); i++) {
59326ec99b1SArnd Bergmann 		pDrvData->IPCs[i].bIsEnabled = false;
59426ec99b1SArnd Bergmann 		pDrvData->IPCs[i].bIsHere = false;
5951da177e4SLinus Torvalds 		pDrvData->IPCs[i].usIntCount = 0;	/* no ints received yet */
5961da177e4SLinus Torvalds 		init_waitqueue_head(&pDrvData->IPCs[i].ipc_wait_queue);
5971da177e4SLinus Torvalds 	}
5981da177e4SLinus Torvalds 
5991da177e4SLinus Torvalds 	retval = tp3780I_InitializeBoardData(&pDrvData->rBDData);
6001da177e4SLinus Torvalds 	PRINTK_2(TRACE_MWAVE,
6011da177e4SLinus Torvalds 		"mwavedd::mwave_init, return from tp3780I_InitializeBoardData"
6021da177e4SLinus Torvalds 		" retval %x\n",
6031da177e4SLinus Torvalds 		retval);
6041da177e4SLinus Torvalds 	if (retval) {
6051da177e4SLinus Torvalds 		PRINTK_ERROR(KERN_ERR_MWAVE
6061da177e4SLinus Torvalds 				"mwavedd::mwave_init: Error:"
6071da177e4SLinus Torvalds 				" Failed to initialize board data\n");
6081da177e4SLinus Torvalds 		goto cleanup_error;
6091da177e4SLinus Torvalds 	}
61026ec99b1SArnd Bergmann 	pDrvData->bBDInitialized = true;
6111da177e4SLinus Torvalds 
6121da177e4SLinus Torvalds 	retval = tp3780I_CalcResources(&pDrvData->rBDData);
6131da177e4SLinus Torvalds 	PRINTK_2(TRACE_MWAVE,
6141da177e4SLinus Torvalds 		"mwavedd::mwave_init, return from tp3780I_CalcResources"
6151da177e4SLinus Torvalds 		" retval %x\n",
6161da177e4SLinus Torvalds 		retval);
6171da177e4SLinus Torvalds 	if (retval) {
6181da177e4SLinus Torvalds 		PRINTK_ERROR(KERN_ERR_MWAVE
6191da177e4SLinus Torvalds 				"mwavedd:mwave_init: Error:"
6201da177e4SLinus Torvalds 				" Failed to calculate resources\n");
6211da177e4SLinus Torvalds 		goto cleanup_error;
6221da177e4SLinus Torvalds 	}
6231da177e4SLinus Torvalds 
6241da177e4SLinus Torvalds 	retval = tp3780I_ClaimResources(&pDrvData->rBDData);
6251da177e4SLinus Torvalds 	PRINTK_2(TRACE_MWAVE,
6261da177e4SLinus Torvalds 		"mwavedd::mwave_init, return from tp3780I_ClaimResources"
6271da177e4SLinus Torvalds 		" retval %x\n",
6281da177e4SLinus Torvalds 		retval);
6291da177e4SLinus Torvalds 	if (retval) {
6301da177e4SLinus Torvalds 		PRINTK_ERROR(KERN_ERR_MWAVE
6311da177e4SLinus Torvalds 				"mwavedd:mwave_init: Error:"
6321da177e4SLinus Torvalds 				" Failed to claim resources\n");
6331da177e4SLinus Torvalds 		goto cleanup_error;
6341da177e4SLinus Torvalds 	}
63526ec99b1SArnd Bergmann 	pDrvData->bResourcesClaimed = true;
6361da177e4SLinus Torvalds 
6371da177e4SLinus Torvalds 	retval = tp3780I_EnableDSP(&pDrvData->rBDData);
6381da177e4SLinus Torvalds 	PRINTK_2(TRACE_MWAVE,
6391da177e4SLinus Torvalds 		"mwavedd::mwave_init, return from tp3780I_EnableDSP"
6401da177e4SLinus Torvalds 		" retval %x\n",
6411da177e4SLinus Torvalds 		retval);
6421da177e4SLinus Torvalds 	if (retval) {
6431da177e4SLinus Torvalds 		PRINTK_ERROR(KERN_ERR_MWAVE
6441da177e4SLinus Torvalds 				"mwavedd:mwave_init: Error:"
6451da177e4SLinus Torvalds 				" Failed to enable DSP\n");
6461da177e4SLinus Torvalds 		goto cleanup_error;
6471da177e4SLinus Torvalds 	}
64826ec99b1SArnd Bergmann 	pDrvData->bDSPEnabled = true;
6491da177e4SLinus Torvalds 
6501da177e4SLinus Torvalds 	if (misc_register(&mwave_misc_dev) < 0) {
6511da177e4SLinus Torvalds 		PRINTK_ERROR(KERN_ERR_MWAVE
6521da177e4SLinus Torvalds 				"mwavedd:mwave_init: Error:"
6531da177e4SLinus Torvalds 				" Failed to register misc device\n");
6541da177e4SLinus Torvalds 		goto cleanup_error;
6551da177e4SLinus Torvalds 	}
65626ec99b1SArnd Bergmann 	pDrvData->bMwaveDevRegistered = true;
6571da177e4SLinus Torvalds 
6581da177e4SLinus Torvalds 	pDrvData->sLine = register_serial_portandirq(
6591da177e4SLinus Torvalds 		pDrvData->rBDData.rDspSettings.usUartBaseIO,
6601da177e4SLinus Torvalds 		pDrvData->rBDData.rDspSettings.usUartIrq
6611da177e4SLinus Torvalds 	);
6621da177e4SLinus Torvalds 	if (pDrvData->sLine < 0) {
6631da177e4SLinus Torvalds 		PRINTK_ERROR(KERN_ERR_MWAVE
6641da177e4SLinus Torvalds 				"mwavedd:mwave_init: Error:"
6651da177e4SLinus Torvalds 				" Failed to register serial driver\n");
6661da177e4SLinus Torvalds 		goto cleanup_error;
6671da177e4SLinus Torvalds 	}
6681da177e4SLinus Torvalds 	/* uart is registered */
6691da177e4SLinus Torvalds 
6701da177e4SLinus Torvalds #if 0
6711da177e4SLinus Torvalds 	/* sysfs */
6721da177e4SLinus Torvalds 	memset(&mwave_device, 0, sizeof (struct device));
67324d25475SKay Sievers 	dev_set_name(&mwave_device, "mwave");
6741da177e4SLinus Torvalds 
6751da177e4SLinus Torvalds 	if (device_register(&mwave_device))
6761da177e4SLinus Torvalds 		goto cleanup_error;
67726ec99b1SArnd Bergmann 	pDrvData->device_registered = true;
6781da177e4SLinus Torvalds 	for (i = 0; i < ARRAY_SIZE(mwave_dev_attrs); i++) {
6791da177e4SLinus Torvalds 		if(device_create_file(&mwave_device, mwave_dev_attrs[i])) {
6801da177e4SLinus Torvalds 			PRINTK_ERROR(KERN_ERR_MWAVE
6811da177e4SLinus Torvalds 					"mwavedd:mwave_init: Error:"
6821da177e4SLinus Torvalds 					" Failed to create sysfs file %s\n",
6831da177e4SLinus Torvalds 					mwave_dev_attrs[i]->attr.name);
6841da177e4SLinus Torvalds 			goto cleanup_error;
6851da177e4SLinus Torvalds 		}
6861da177e4SLinus Torvalds 		pDrvData->nr_registered_attrs++;
6871da177e4SLinus Torvalds 	}
6881da177e4SLinus Torvalds #endif
6891da177e4SLinus Torvalds 
6901da177e4SLinus Torvalds 	/* SUCCESS! */
6911da177e4SLinus Torvalds 	return 0;
6921da177e4SLinus Torvalds 
6931da177e4SLinus Torvalds cleanup_error:
6941da177e4SLinus Torvalds 	PRINTK_ERROR(KERN_ERR_MWAVE
6951da177e4SLinus Torvalds 			"mwavedd::mwave_init: Error:"
6961da177e4SLinus Torvalds 			" Failed to initialize\n");
6971da177e4SLinus Torvalds 	mwave_exit(); /* clean up */
6981da177e4SLinus Torvalds 
6991da177e4SLinus Torvalds 	return -EIO;
7001da177e4SLinus Torvalds }
7011da177e4SLinus Torvalds 
7021da177e4SLinus Torvalds module_init(mwave_init);
7031da177e4SLinus Torvalds 
704