xref: /linux/drivers/char/mwave/mwavedd.c (revision 74880c063b06efd103c924abfe19d9d8fa4864c4)
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>
591da177e4SLinus Torvalds #include <linux/delay.h>
601da177e4SLinus Torvalds #include "smapi.h"
611da177e4SLinus Torvalds #include "mwavedd.h"
621da177e4SLinus Torvalds #include "3780i.h"
631da177e4SLinus Torvalds #include "tp3780i.h"
641da177e4SLinus Torvalds 
651da177e4SLinus Torvalds MODULE_DESCRIPTION("3780i Advanced Communications Processor (Mwave) driver");
661da177e4SLinus Torvalds MODULE_AUTHOR("Mike Sullivan and Paul Schroeder");
671da177e4SLinus Torvalds MODULE_LICENSE("GPL");
681da177e4SLinus Torvalds 
691da177e4SLinus Torvalds /*
701da177e4SLinus Torvalds * These parameters support the setting of MWave resources. Note that no
711da177e4SLinus Torvalds * checks are made against other devices (ie. superio) for conflicts.
721da177e4SLinus Torvalds * We'll depend on users using the tpctl utility to do that for now
731da177e4SLinus Torvalds */
741da177e4SLinus Torvalds int mwave_debug = 0;
751da177e4SLinus Torvalds int mwave_3780i_irq = 0;
761da177e4SLinus Torvalds int mwave_3780i_io = 0;
771da177e4SLinus Torvalds int mwave_uart_irq = 0;
781da177e4SLinus Torvalds int mwave_uart_io = 0;
791da177e4SLinus Torvalds module_param(mwave_debug, int, 0);
801da177e4SLinus Torvalds module_param(mwave_3780i_irq, int, 0);
811da177e4SLinus Torvalds module_param(mwave_3780i_io, int, 0);
821da177e4SLinus Torvalds module_param(mwave_uart_irq, int, 0);
831da177e4SLinus Torvalds module_param(mwave_uart_io, int, 0);
841da177e4SLinus Torvalds 
851da177e4SLinus Torvalds static int mwave_open(struct inode *inode, struct file *file);
861da177e4SLinus Torvalds static int mwave_close(struct inode *inode, struct file *file);
871da177e4SLinus Torvalds static int mwave_ioctl(struct inode *inode, struct file *filp,
881da177e4SLinus Torvalds                        unsigned int iocmd, unsigned long ioarg);
891da177e4SLinus Torvalds 
901da177e4SLinus Torvalds MWAVE_DEVICE_DATA mwave_s_mdd;
911da177e4SLinus Torvalds 
921da177e4SLinus Torvalds static int mwave_open(struct inode *inode, struct file *file)
931da177e4SLinus Torvalds {
941da177e4SLinus Torvalds 	unsigned int retval = 0;
951da177e4SLinus Torvalds 
961da177e4SLinus Torvalds 	PRINTK_3(TRACE_MWAVE,
971da177e4SLinus Torvalds 		"mwavedd::mwave_open, entry inode %p file %p\n",
981da177e4SLinus Torvalds 		 inode, file);
991da177e4SLinus Torvalds 	PRINTK_2(TRACE_MWAVE,
1001da177e4SLinus Torvalds 		"mwavedd::mwave_open, exit return retval %x\n", retval);
1011da177e4SLinus Torvalds 
1021da177e4SLinus Torvalds 	return retval;
1031da177e4SLinus Torvalds }
1041da177e4SLinus Torvalds 
1051da177e4SLinus Torvalds static int mwave_close(struct inode *inode, struct file *file)
1061da177e4SLinus Torvalds {
1071da177e4SLinus Torvalds 	unsigned int retval = 0;
1081da177e4SLinus Torvalds 
1091da177e4SLinus Torvalds 	PRINTK_3(TRACE_MWAVE,
1101da177e4SLinus Torvalds 		"mwavedd::mwave_close, entry inode %p file %p\n",
1111da177e4SLinus Torvalds 		 inode,  file);
1121da177e4SLinus Torvalds 
1131da177e4SLinus Torvalds 	PRINTK_2(TRACE_MWAVE, "mwavedd::mwave_close, exit retval %x\n",
1141da177e4SLinus Torvalds 		retval);
1151da177e4SLinus Torvalds 
1161da177e4SLinus Torvalds 	return retval;
1171da177e4SLinus Torvalds }
1181da177e4SLinus Torvalds 
1191da177e4SLinus Torvalds static int mwave_ioctl(struct inode *inode, struct file *file,
1201da177e4SLinus Torvalds                        unsigned int iocmd, unsigned long ioarg)
1211da177e4SLinus Torvalds {
1221da177e4SLinus Torvalds 	unsigned int retval = 0;
1231da177e4SLinus Torvalds 	pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;
1241da177e4SLinus Torvalds 	void __user *arg = (void __user *)ioarg;
1251da177e4SLinus Torvalds 
1261da177e4SLinus Torvalds 	PRINTK_5(TRACE_MWAVE,
1271da177e4SLinus Torvalds 		"mwavedd::mwave_ioctl, entry inode %p file %p cmd %x arg %x\n",
1281da177e4SLinus Torvalds 		 inode,  file, iocmd, (int) ioarg);
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds 	switch (iocmd) {
1311da177e4SLinus Torvalds 
1321da177e4SLinus Torvalds 		case IOCTL_MW_RESET:
1331da177e4SLinus Torvalds 			PRINTK_1(TRACE_MWAVE,
1341da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl, IOCTL_MW_RESET"
1351da177e4SLinus Torvalds 				" calling tp3780I_ResetDSP\n");
1361da177e4SLinus Torvalds 			retval = tp3780I_ResetDSP(&pDrvData->rBDData);
1371da177e4SLinus Torvalds 			PRINTK_2(TRACE_MWAVE,
1381da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl, IOCTL_MW_RESET"
1391da177e4SLinus Torvalds 				" retval %x from tp3780I_ResetDSP\n",
1401da177e4SLinus Torvalds 				retval);
1411da177e4SLinus Torvalds 			break;
1421da177e4SLinus Torvalds 
1431da177e4SLinus Torvalds 		case IOCTL_MW_RUN:
1441da177e4SLinus Torvalds 			PRINTK_1(TRACE_MWAVE,
1451da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl, IOCTL_MW_RUN"
1461da177e4SLinus Torvalds 				" calling tp3780I_StartDSP\n");
1471da177e4SLinus Torvalds 			retval = tp3780I_StartDSP(&pDrvData->rBDData);
1481da177e4SLinus Torvalds 			PRINTK_2(TRACE_MWAVE,
1491da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl, IOCTL_MW_RUN"
1501da177e4SLinus Torvalds 				" retval %x from tp3780I_StartDSP\n",
1511da177e4SLinus Torvalds 				retval);
1521da177e4SLinus Torvalds 			break;
1531da177e4SLinus Torvalds 
1541da177e4SLinus Torvalds 		case IOCTL_MW_DSP_ABILITIES: {
1551da177e4SLinus Torvalds 			MW_ABILITIES rAbilities;
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds 			PRINTK_1(TRACE_MWAVE,
1581da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl,"
1591da177e4SLinus Torvalds 				" IOCTL_MW_DSP_ABILITIES calling"
1601da177e4SLinus Torvalds 				" tp3780I_QueryAbilities\n");
1611da177e4SLinus Torvalds 			retval = tp3780I_QueryAbilities(&pDrvData->rBDData,
1621da177e4SLinus Torvalds 					&rAbilities);
1631da177e4SLinus Torvalds 			PRINTK_2(TRACE_MWAVE,
1641da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl, IOCTL_MW_DSP_ABILITIES"
1651da177e4SLinus Torvalds 				" retval %x from tp3780I_QueryAbilities\n",
1661da177e4SLinus Torvalds 				retval);
1671da177e4SLinus Torvalds 			if (retval == 0) {
1681da177e4SLinus Torvalds 				if( copy_to_user(arg, &rAbilities,
1691da177e4SLinus Torvalds 							sizeof(MW_ABILITIES)) )
1701da177e4SLinus Torvalds 					return -EFAULT;
1711da177e4SLinus Torvalds 			}
1721da177e4SLinus Torvalds 			PRINTK_2(TRACE_MWAVE,
1731da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl, IOCTL_MW_DSP_ABILITIES"
1741da177e4SLinus Torvalds 				" exit retval %x\n",
1751da177e4SLinus Torvalds 				retval);
1761da177e4SLinus Torvalds 		}
1771da177e4SLinus Torvalds 			break;
1781da177e4SLinus Torvalds 
1791da177e4SLinus Torvalds 		case IOCTL_MW_READ_DATA:
1801da177e4SLinus Torvalds 		case IOCTL_MW_READCLEAR_DATA: {
1811da177e4SLinus Torvalds 			MW_READWRITE rReadData;
1821da177e4SLinus Torvalds 			unsigned short __user *pusBuffer = NULL;
1831da177e4SLinus Torvalds 
1841da177e4SLinus Torvalds 			if( copy_from_user(&rReadData, arg,
1851da177e4SLinus Torvalds 						sizeof(MW_READWRITE)) )
1861da177e4SLinus Torvalds 				return -EFAULT;
1871da177e4SLinus Torvalds 			pusBuffer = (unsigned short __user *) (rReadData.pBuf);
1881da177e4SLinus Torvalds 
1891da177e4SLinus Torvalds 			PRINTK_4(TRACE_MWAVE,
1901da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl IOCTL_MW_READ_DATA,"
1911da177e4SLinus Torvalds 				" size %lx, ioarg %lx pusBuffer %p\n",
1921da177e4SLinus Torvalds 				rReadData.ulDataLength, ioarg, pusBuffer);
1931da177e4SLinus Torvalds 			retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData,
1941da177e4SLinus Torvalds 					iocmd,
1951da177e4SLinus Torvalds 					pusBuffer,
1961da177e4SLinus Torvalds 					rReadData.ulDataLength,
1971da177e4SLinus Torvalds 					rReadData.usDspAddress);
1981da177e4SLinus Torvalds 		}
1991da177e4SLinus Torvalds 			break;
2001da177e4SLinus Torvalds 
2011da177e4SLinus Torvalds 		case IOCTL_MW_READ_INST: {
2021da177e4SLinus Torvalds 			MW_READWRITE rReadData;
2031da177e4SLinus Torvalds 			unsigned short __user *pusBuffer = NULL;
2041da177e4SLinus Torvalds 
2051da177e4SLinus Torvalds 			if( copy_from_user(&rReadData, arg,
2061da177e4SLinus Torvalds 						sizeof(MW_READWRITE)) )
2071da177e4SLinus Torvalds 				return -EFAULT;
2081da177e4SLinus Torvalds 			pusBuffer = (unsigned short __user *) (rReadData.pBuf);
2091da177e4SLinus Torvalds 
2101da177e4SLinus Torvalds 			PRINTK_4(TRACE_MWAVE,
2111da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl IOCTL_MW_READ_INST,"
2121da177e4SLinus Torvalds 				" size %lx, ioarg %lx pusBuffer %p\n",
2131da177e4SLinus Torvalds 				rReadData.ulDataLength / 2, ioarg,
2141da177e4SLinus Torvalds 				pusBuffer);
2151da177e4SLinus Torvalds 			retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData,
2161da177e4SLinus Torvalds 				iocmd, pusBuffer,
2171da177e4SLinus Torvalds 				rReadData.ulDataLength / 2,
2181da177e4SLinus Torvalds 				rReadData.usDspAddress);
2191da177e4SLinus Torvalds 		}
2201da177e4SLinus Torvalds 			break;
2211da177e4SLinus Torvalds 
2221da177e4SLinus Torvalds 		case IOCTL_MW_WRITE_DATA: {
2231da177e4SLinus Torvalds 			MW_READWRITE rWriteData;
2241da177e4SLinus Torvalds 			unsigned short __user *pusBuffer = NULL;
2251da177e4SLinus Torvalds 
2261da177e4SLinus Torvalds 			if( copy_from_user(&rWriteData, arg,
2271da177e4SLinus Torvalds 						sizeof(MW_READWRITE)) )
2281da177e4SLinus Torvalds 				return -EFAULT;
2291da177e4SLinus Torvalds 			pusBuffer = (unsigned short __user *) (rWriteData.pBuf);
2301da177e4SLinus Torvalds 
2311da177e4SLinus Torvalds 			PRINTK_4(TRACE_MWAVE,
2321da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl IOCTL_MW_WRITE_DATA,"
2331da177e4SLinus Torvalds 				" size %lx, ioarg %lx pusBuffer %p\n",
2341da177e4SLinus Torvalds 				rWriteData.ulDataLength, ioarg,
2351da177e4SLinus Torvalds 				pusBuffer);
2361da177e4SLinus Torvalds 			retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData,
2371da177e4SLinus Torvalds 					iocmd, pusBuffer,
2381da177e4SLinus Torvalds 					rWriteData.ulDataLength,
2391da177e4SLinus Torvalds 					rWriteData.usDspAddress);
2401da177e4SLinus Torvalds 		}
2411da177e4SLinus Torvalds 			break;
2421da177e4SLinus Torvalds 
2431da177e4SLinus Torvalds 		case IOCTL_MW_WRITE_INST: {
2441da177e4SLinus Torvalds 			MW_READWRITE rWriteData;
2451da177e4SLinus Torvalds 			unsigned short __user *pusBuffer = NULL;
2461da177e4SLinus Torvalds 
2471da177e4SLinus Torvalds 			if( copy_from_user(&rWriteData, arg,
2481da177e4SLinus Torvalds 						sizeof(MW_READWRITE)) )
2491da177e4SLinus Torvalds 				return -EFAULT;
2501da177e4SLinus Torvalds 			pusBuffer = (unsigned short __user *)(rWriteData.pBuf);
2511da177e4SLinus Torvalds 
2521da177e4SLinus Torvalds 			PRINTK_4(TRACE_MWAVE,
2531da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl IOCTL_MW_WRITE_INST,"
2541da177e4SLinus Torvalds 				" size %lx, ioarg %lx pusBuffer %p\n",
2551da177e4SLinus Torvalds 				rWriteData.ulDataLength, ioarg,
2561da177e4SLinus Torvalds 				pusBuffer);
2571da177e4SLinus Torvalds 			retval = tp3780I_ReadWriteDspIStore(&pDrvData->rBDData,
2581da177e4SLinus Torvalds 					iocmd, pusBuffer,
2591da177e4SLinus Torvalds 					rWriteData.ulDataLength,
2601da177e4SLinus Torvalds 					rWriteData.usDspAddress);
2611da177e4SLinus Torvalds 		}
2621da177e4SLinus Torvalds 			break;
2631da177e4SLinus Torvalds 
2641da177e4SLinus Torvalds 		case IOCTL_MW_REGISTER_IPC: {
2651da177e4SLinus Torvalds 			unsigned int ipcnum = (unsigned int) ioarg;
2661da177e4SLinus Torvalds 
2671da177e4SLinus Torvalds 			PRINTK_3(TRACE_MWAVE,
2681da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl IOCTL_MW_REGISTER_IPC"
2691da177e4SLinus Torvalds 				" ipcnum %x entry usIntCount %x\n",
2701da177e4SLinus Torvalds 				ipcnum,
2711da177e4SLinus Torvalds 				pDrvData->IPCs[ipcnum].usIntCount);
2721da177e4SLinus Torvalds 
2731da177e4SLinus Torvalds 			if (ipcnum > ARRAY_SIZE(pDrvData->IPCs)) {
2741da177e4SLinus Torvalds 				PRINTK_ERROR(KERN_ERR_MWAVE
2751da177e4SLinus Torvalds 						"mwavedd::mwave_ioctl:"
2761da177e4SLinus Torvalds 						" IOCTL_MW_REGISTER_IPC:"
2771da177e4SLinus Torvalds 						" Error: Invalid ipcnum %x\n",
2781da177e4SLinus Torvalds 						ipcnum);
2791da177e4SLinus Torvalds 				return -EINVAL;
2801da177e4SLinus Torvalds 			}
2811da177e4SLinus Torvalds 			pDrvData->IPCs[ipcnum].bIsHere = FALSE;
2821da177e4SLinus Torvalds 			pDrvData->IPCs[ipcnum].bIsEnabled = TRUE;
2831da177e4SLinus Torvalds 
2841da177e4SLinus Torvalds 			PRINTK_2(TRACE_MWAVE,
2851da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl IOCTL_MW_REGISTER_IPC"
2861da177e4SLinus Torvalds 				" ipcnum %x exit\n",
2871da177e4SLinus Torvalds 				ipcnum);
2881da177e4SLinus Torvalds 		}
2891da177e4SLinus Torvalds 			break;
2901da177e4SLinus Torvalds 
2911da177e4SLinus Torvalds 		case IOCTL_MW_GET_IPC: {
2921da177e4SLinus Torvalds 			unsigned int ipcnum = (unsigned int) ioarg;
2931da177e4SLinus Torvalds 
2941da177e4SLinus Torvalds 			PRINTK_3(TRACE_MWAVE,
2951da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl IOCTL_MW_GET_IPC"
2961da177e4SLinus Torvalds 				" ipcnum %x, usIntCount %x\n",
2971da177e4SLinus Torvalds 				ipcnum,
2981da177e4SLinus Torvalds 				pDrvData->IPCs[ipcnum].usIntCount);
2991da177e4SLinus Torvalds 			if (ipcnum > ARRAY_SIZE(pDrvData->IPCs)) {
3001da177e4SLinus Torvalds 				PRINTK_ERROR(KERN_ERR_MWAVE
3011da177e4SLinus Torvalds 						"mwavedd::mwave_ioctl:"
3021da177e4SLinus Torvalds 						" IOCTL_MW_GET_IPC: Error:"
3031da177e4SLinus Torvalds 						" Invalid ipcnum %x\n", ipcnum);
3041da177e4SLinus Torvalds 				return -EINVAL;
3051da177e4SLinus Torvalds 			}
3061da177e4SLinus Torvalds 
3071da177e4SLinus Torvalds 			if (pDrvData->IPCs[ipcnum].bIsEnabled == TRUE) {
3081da177e4SLinus Torvalds 				DECLARE_WAITQUEUE(wait, current);
3091da177e4SLinus Torvalds 
3101da177e4SLinus Torvalds 				PRINTK_2(TRACE_MWAVE,
3111da177e4SLinus Torvalds 					"mwavedd::mwave_ioctl, thread for"
3121da177e4SLinus Torvalds 					" ipc %x going to sleep\n",
3131da177e4SLinus Torvalds 					ipcnum);
3141da177e4SLinus Torvalds 				add_wait_queue(&pDrvData->IPCs[ipcnum].ipc_wait_queue, &wait);
3151da177e4SLinus Torvalds 				pDrvData->IPCs[ipcnum].bIsHere = TRUE;
3161da177e4SLinus Torvalds 				set_current_state(TASK_INTERRUPTIBLE);
3171da177e4SLinus Torvalds 				/* check whether an event was signalled by */
3181da177e4SLinus Torvalds 				/* the interrupt handler while we were gone */
3191da177e4SLinus Torvalds 				if (pDrvData->IPCs[ipcnum].usIntCount == 1) {	/* first int has occurred (race condition) */
3201da177e4SLinus Torvalds 					pDrvData->IPCs[ipcnum].usIntCount = 2;	/* first int has been handled */
3211da177e4SLinus Torvalds 					PRINTK_2(TRACE_MWAVE,
3221da177e4SLinus Torvalds 						"mwavedd::mwave_ioctl"
3231da177e4SLinus Torvalds 						" IOCTL_MW_GET_IPC ipcnum %x"
3241da177e4SLinus Torvalds 						" handling first int\n",
3251da177e4SLinus Torvalds 						ipcnum);
3261da177e4SLinus Torvalds 				} else {	/* either 1st int has not yet occurred, or we have already handled the first int */
3271da177e4SLinus Torvalds 					schedule();
3281da177e4SLinus Torvalds 					if (pDrvData->IPCs[ipcnum].usIntCount == 1) {
3291da177e4SLinus Torvalds 						pDrvData->IPCs[ipcnum].usIntCount = 2;
3301da177e4SLinus Torvalds 					}
3311da177e4SLinus Torvalds 					PRINTK_2(TRACE_MWAVE,
3321da177e4SLinus Torvalds 						"mwavedd::mwave_ioctl"
3331da177e4SLinus Torvalds 						" IOCTL_MW_GET_IPC ipcnum %x"
3341da177e4SLinus Torvalds 						" woke up and returning to"
3351da177e4SLinus Torvalds 						" application\n",
3361da177e4SLinus Torvalds 						ipcnum);
3371da177e4SLinus Torvalds 				}
3381da177e4SLinus Torvalds 				pDrvData->IPCs[ipcnum].bIsHere = FALSE;
3391da177e4SLinus Torvalds 				remove_wait_queue(&pDrvData->IPCs[ipcnum].ipc_wait_queue, &wait);
3401da177e4SLinus Torvalds 				set_current_state(TASK_RUNNING);
3411da177e4SLinus Torvalds 				PRINTK_2(TRACE_MWAVE,
3421da177e4SLinus Torvalds 					"mwavedd::mwave_ioctl IOCTL_MW_GET_IPC,"
3431da177e4SLinus Torvalds 					" returning thread for ipc %x"
3441da177e4SLinus Torvalds 					" processing\n",
3451da177e4SLinus Torvalds 					ipcnum);
3461da177e4SLinus Torvalds 			}
3471da177e4SLinus Torvalds 		}
3481da177e4SLinus Torvalds 			break;
3491da177e4SLinus Torvalds 
3501da177e4SLinus Torvalds 		case IOCTL_MW_UNREGISTER_IPC: {
3511da177e4SLinus Torvalds 			unsigned int ipcnum = (unsigned int) ioarg;
3521da177e4SLinus Torvalds 
3531da177e4SLinus Torvalds 			PRINTK_2(TRACE_MWAVE,
3541da177e4SLinus Torvalds 				"mwavedd::mwave_ioctl IOCTL_MW_UNREGISTER_IPC"
3551da177e4SLinus Torvalds 				" ipcnum %x\n",
3561da177e4SLinus Torvalds 				ipcnum);
3571da177e4SLinus Torvalds 			if (ipcnum > ARRAY_SIZE(pDrvData->IPCs)) {
3581da177e4SLinus Torvalds 				PRINTK_ERROR(KERN_ERR_MWAVE
3591da177e4SLinus Torvalds 						"mwavedd::mwave_ioctl:"
3601da177e4SLinus Torvalds 						" IOCTL_MW_UNREGISTER_IPC:"
3611da177e4SLinus Torvalds 						" Error: Invalid ipcnum %x\n",
3621da177e4SLinus Torvalds 						ipcnum);
3631da177e4SLinus Torvalds 				return -EINVAL;
3641da177e4SLinus Torvalds 			}
3651da177e4SLinus Torvalds 			if (pDrvData->IPCs[ipcnum].bIsEnabled == TRUE) {
3661da177e4SLinus Torvalds 				pDrvData->IPCs[ipcnum].bIsEnabled = FALSE;
3671da177e4SLinus Torvalds 				if (pDrvData->IPCs[ipcnum].bIsHere == TRUE) {
3681da177e4SLinus Torvalds 					wake_up_interruptible(&pDrvData->IPCs[ipcnum].ipc_wait_queue);
3691da177e4SLinus Torvalds 				}
3701da177e4SLinus Torvalds 			}
3711da177e4SLinus Torvalds 		}
3721da177e4SLinus Torvalds 			break;
3731da177e4SLinus Torvalds 
3741da177e4SLinus Torvalds 		default:
3751da177e4SLinus Torvalds 			PRINTK_ERROR(KERN_ERR_MWAVE "mwavedd::mwave_ioctl:"
3761da177e4SLinus Torvalds 					" Error: Unrecognized iocmd %x\n",
3771da177e4SLinus Torvalds 					iocmd);
3781da177e4SLinus Torvalds 			return -ENOTTY;
3791da177e4SLinus Torvalds 			break;
3801da177e4SLinus Torvalds 	} /* switch */
3811da177e4SLinus Torvalds 
3821da177e4SLinus Torvalds 	PRINTK_2(TRACE_MWAVE, "mwavedd::mwave_ioctl, exit retval %x\n", retval);
3831da177e4SLinus Torvalds 
3841da177e4SLinus Torvalds 	return retval;
3851da177e4SLinus Torvalds }
3861da177e4SLinus Torvalds 
3871da177e4SLinus Torvalds 
3881da177e4SLinus Torvalds static ssize_t mwave_read(struct file *file, char __user *buf, size_t count,
3891da177e4SLinus Torvalds                           loff_t * ppos)
3901da177e4SLinus Torvalds {
3911da177e4SLinus Torvalds 	PRINTK_5(TRACE_MWAVE,
3921da177e4SLinus Torvalds 		"mwavedd::mwave_read entry file %p, buf %p, count %zx ppos %p\n",
3931da177e4SLinus Torvalds 		file, buf, count, ppos);
3941da177e4SLinus Torvalds 
3951da177e4SLinus Torvalds 	return -EINVAL;
3961da177e4SLinus Torvalds }
3971da177e4SLinus Torvalds 
3981da177e4SLinus Torvalds 
3991da177e4SLinus Torvalds static ssize_t mwave_write(struct file *file, const char __user *buf,
4001da177e4SLinus Torvalds                            size_t count, loff_t * ppos)
4011da177e4SLinus Torvalds {
4021da177e4SLinus Torvalds 	PRINTK_5(TRACE_MWAVE,
4031da177e4SLinus Torvalds 		"mwavedd::mwave_write entry file %p, buf %p,"
4041da177e4SLinus Torvalds 		" count %zx ppos %p\n",
4051da177e4SLinus Torvalds 		file, buf, count, ppos);
4061da177e4SLinus Torvalds 
4071da177e4SLinus Torvalds 	return -EINVAL;
4081da177e4SLinus Torvalds }
4091da177e4SLinus Torvalds 
4101da177e4SLinus Torvalds 
4111da177e4SLinus Torvalds static int register_serial_portandirq(unsigned int port, int irq)
4121da177e4SLinus Torvalds {
4131da177e4SLinus Torvalds 	struct serial_struct serial;
4141da177e4SLinus Torvalds 
4151da177e4SLinus Torvalds 	switch ( port ) {
4161da177e4SLinus Torvalds 		case 0x3f8:
4171da177e4SLinus Torvalds 		case 0x2f8:
4181da177e4SLinus Torvalds 		case 0x3e8:
4191da177e4SLinus Torvalds 		case 0x2e8:
4201da177e4SLinus Torvalds 			/* OK */
4211da177e4SLinus Torvalds 			break;
4221da177e4SLinus Torvalds 		default:
4231da177e4SLinus Torvalds 			PRINTK_ERROR(KERN_ERR_MWAVE
4241da177e4SLinus Torvalds 					"mwavedd::register_serial_portandirq:"
4251da177e4SLinus Torvalds 					" Error: Illegal port %x\n", port );
4261da177e4SLinus Torvalds 			return -1;
4271da177e4SLinus Torvalds 	} /* switch */
4281da177e4SLinus Torvalds 	/* port is okay */
4291da177e4SLinus Torvalds 
4301da177e4SLinus Torvalds 	switch ( irq ) {
4311da177e4SLinus Torvalds 		case 3:
4321da177e4SLinus Torvalds 		case 4:
4331da177e4SLinus Torvalds 		case 5:
4341da177e4SLinus Torvalds 		case 7:
4351da177e4SLinus Torvalds 			/* OK */
4361da177e4SLinus Torvalds 			break;
4371da177e4SLinus Torvalds 		default:
4381da177e4SLinus Torvalds 			PRINTK_ERROR(KERN_ERR_MWAVE
4391da177e4SLinus Torvalds 					"mwavedd::register_serial_portandirq:"
4401da177e4SLinus Torvalds 					" Error: Illegal irq %x\n", irq );
4411da177e4SLinus Torvalds 			return -1;
4421da177e4SLinus Torvalds 	} /* switch */
4431da177e4SLinus Torvalds 	/* irq is okay */
4441da177e4SLinus Torvalds 
4451da177e4SLinus Torvalds 	memset(&serial, 0, sizeof(serial));
4461da177e4SLinus Torvalds 	serial.port = port;
4471da177e4SLinus Torvalds 	serial.irq = irq;
4481da177e4SLinus Torvalds 	serial.flags = ASYNC_SHARE_IRQ;
4491da177e4SLinus Torvalds 
4501da177e4SLinus Torvalds 	return register_serial(&serial);
4511da177e4SLinus Torvalds }
4521da177e4SLinus Torvalds 
4531da177e4SLinus Torvalds 
4541da177e4SLinus Torvalds static struct file_operations mwave_fops = {
4551da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
4561da177e4SLinus Torvalds 	.read		= mwave_read,
4571da177e4SLinus Torvalds 	.write		= mwave_write,
4581da177e4SLinus Torvalds 	.ioctl		= mwave_ioctl,
4591da177e4SLinus Torvalds 	.open		= mwave_open,
4601da177e4SLinus Torvalds 	.release	= mwave_close
4611da177e4SLinus Torvalds };
4621da177e4SLinus Torvalds 
4631da177e4SLinus Torvalds 
4641da177e4SLinus Torvalds static struct miscdevice mwave_misc_dev = { MWAVE_MINOR, "mwave", &mwave_fops };
4651da177e4SLinus Torvalds 
4661da177e4SLinus Torvalds #if 0 /* totally b0rked */
4671da177e4SLinus Torvalds /*
4681da177e4SLinus Torvalds  * sysfs support <paulsch@us.ibm.com>
4691da177e4SLinus Torvalds  */
4701da177e4SLinus Torvalds 
4711da177e4SLinus Torvalds struct device mwave_device;
4721da177e4SLinus Torvalds 
4731da177e4SLinus Torvalds /* Prevent code redundancy, create a macro for mwave_show_* functions. */
4741da177e4SLinus Torvalds #define mwave_show_function(attr_name, format_string, field)		\
475*74880c06SYani Ioannou static ssize_t mwave_show_##attr_name(struct device *dev, struct device_attribute *attr, char *buf)	\
4761da177e4SLinus Torvalds {									\
4771da177e4SLinus Torvalds 	DSP_3780I_CONFIG_SETTINGS *pSettings =				\
4781da177e4SLinus Torvalds 		&mwave_s_mdd.rBDData.rDspSettings;			\
4791da177e4SLinus Torvalds         return sprintf(buf, format_string, pSettings->field);		\
4801da177e4SLinus Torvalds }
4811da177e4SLinus Torvalds 
4821da177e4SLinus Torvalds /* All of our attributes are read attributes. */
4831da177e4SLinus Torvalds #define mwave_dev_rd_attr(attr_name, format_string, field)		\
4841da177e4SLinus Torvalds 	mwave_show_function(attr_name, format_string, field)		\
4851da177e4SLinus Torvalds static DEVICE_ATTR(attr_name, S_IRUGO, mwave_show_##attr_name, NULL)
4861da177e4SLinus Torvalds 
4871da177e4SLinus Torvalds mwave_dev_rd_attr (3780i_dma, "%i\n", usDspDma);
4881da177e4SLinus Torvalds mwave_dev_rd_attr (3780i_irq, "%i\n", usDspIrq);
4891da177e4SLinus Torvalds mwave_dev_rd_attr (3780i_io, "%#.4x\n", usDspBaseIO);
4901da177e4SLinus Torvalds mwave_dev_rd_attr (uart_irq, "%i\n", usUartIrq);
4911da177e4SLinus Torvalds mwave_dev_rd_attr (uart_io, "%#.4x\n", usUartBaseIO);
4921da177e4SLinus Torvalds 
4931da177e4SLinus Torvalds static struct device_attribute * const mwave_dev_attrs[] = {
4941da177e4SLinus Torvalds 	&dev_attr_3780i_dma,
4951da177e4SLinus Torvalds 	&dev_attr_3780i_irq,
4961da177e4SLinus Torvalds 	&dev_attr_3780i_io,
4971da177e4SLinus Torvalds 	&dev_attr_uart_irq,
4981da177e4SLinus Torvalds 	&dev_attr_uart_io,
4991da177e4SLinus Torvalds };
5001da177e4SLinus Torvalds #endif
5011da177e4SLinus Torvalds 
5021da177e4SLinus Torvalds /*
5031da177e4SLinus Torvalds * mwave_init is called on module load
5041da177e4SLinus Torvalds *
5051da177e4SLinus Torvalds * mwave_exit is called on module unload
5061da177e4SLinus Torvalds * mwave_exit is also used to clean up after an aborted mwave_init
5071da177e4SLinus Torvalds */
5081da177e4SLinus Torvalds static void mwave_exit(void)
5091da177e4SLinus Torvalds {
5101da177e4SLinus Torvalds 	pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;
5111da177e4SLinus Torvalds 
5121da177e4SLinus Torvalds 	PRINTK_1(TRACE_MWAVE, "mwavedd::mwave_exit entry\n");
5131da177e4SLinus Torvalds 
5141da177e4SLinus Torvalds #if 0
5151da177e4SLinus Torvalds 	for (i = 0; i < pDrvData->nr_registered_attrs; i++)
5161da177e4SLinus Torvalds 		device_remove_file(&mwave_device, mwave_dev_attrs[i]);
5171da177e4SLinus Torvalds 	pDrvData->nr_registered_attrs = 0;
5181da177e4SLinus Torvalds 
5191da177e4SLinus Torvalds 	if (pDrvData->device_registered) {
5201da177e4SLinus Torvalds 		device_unregister(&mwave_device);
5211da177e4SLinus Torvalds 		pDrvData->device_registered = FALSE;
5221da177e4SLinus Torvalds 	}
5231da177e4SLinus Torvalds #endif
5241da177e4SLinus Torvalds 
5251da177e4SLinus Torvalds 	if ( pDrvData->sLine >= 0 ) {
5261da177e4SLinus Torvalds 		unregister_serial(pDrvData->sLine);
5271da177e4SLinus Torvalds 	}
5281da177e4SLinus Torvalds 	if (pDrvData->bMwaveDevRegistered) {
5291da177e4SLinus Torvalds 		misc_deregister(&mwave_misc_dev);
5301da177e4SLinus Torvalds 	}
5311da177e4SLinus Torvalds 	if (pDrvData->bDSPEnabled) {
5321da177e4SLinus Torvalds 		tp3780I_DisableDSP(&pDrvData->rBDData);
5331da177e4SLinus Torvalds 	}
5341da177e4SLinus Torvalds 	if (pDrvData->bResourcesClaimed) {
5351da177e4SLinus Torvalds 		tp3780I_ReleaseResources(&pDrvData->rBDData);
5361da177e4SLinus Torvalds 	}
5371da177e4SLinus Torvalds 	if (pDrvData->bBDInitialized) {
5381da177e4SLinus Torvalds 		tp3780I_Cleanup(&pDrvData->rBDData);
5391da177e4SLinus Torvalds 	}
5401da177e4SLinus Torvalds 
5411da177e4SLinus Torvalds 	PRINTK_1(TRACE_MWAVE, "mwavedd::mwave_exit exit\n");
5421da177e4SLinus Torvalds }
5431da177e4SLinus Torvalds 
5441da177e4SLinus Torvalds module_exit(mwave_exit);
5451da177e4SLinus Torvalds 
5461da177e4SLinus Torvalds static int __init mwave_init(void)
5471da177e4SLinus Torvalds {
5481da177e4SLinus Torvalds 	int i;
5491da177e4SLinus Torvalds 	int retval = 0;
5501da177e4SLinus Torvalds 	pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;
5511da177e4SLinus Torvalds 
5521da177e4SLinus Torvalds 	PRINTK_1(TRACE_MWAVE, "mwavedd::mwave_init entry\n");
5531da177e4SLinus Torvalds 
5541da177e4SLinus Torvalds 	memset(&mwave_s_mdd, 0, sizeof(MWAVE_DEVICE_DATA));
5551da177e4SLinus Torvalds 
5561da177e4SLinus Torvalds 	pDrvData->bBDInitialized = FALSE;
5571da177e4SLinus Torvalds 	pDrvData->bResourcesClaimed = FALSE;
5581da177e4SLinus Torvalds 	pDrvData->bDSPEnabled = FALSE;
5591da177e4SLinus Torvalds 	pDrvData->bDSPReset = FALSE;
5601da177e4SLinus Torvalds 	pDrvData->bMwaveDevRegistered = FALSE;
5611da177e4SLinus Torvalds 	pDrvData->sLine = -1;
5621da177e4SLinus Torvalds 
5631da177e4SLinus Torvalds 	for (i = 0; i < ARRAY_SIZE(pDrvData->IPCs); i++) {
5641da177e4SLinus Torvalds 		pDrvData->IPCs[i].bIsEnabled = FALSE;
5651da177e4SLinus Torvalds 		pDrvData->IPCs[i].bIsHere = FALSE;
5661da177e4SLinus Torvalds 		pDrvData->IPCs[i].usIntCount = 0;	/* no ints received yet */
5671da177e4SLinus Torvalds 		init_waitqueue_head(&pDrvData->IPCs[i].ipc_wait_queue);
5681da177e4SLinus Torvalds 	}
5691da177e4SLinus Torvalds 
5701da177e4SLinus Torvalds 	retval = tp3780I_InitializeBoardData(&pDrvData->rBDData);
5711da177e4SLinus Torvalds 	PRINTK_2(TRACE_MWAVE,
5721da177e4SLinus Torvalds 		"mwavedd::mwave_init, return from tp3780I_InitializeBoardData"
5731da177e4SLinus Torvalds 		" retval %x\n",
5741da177e4SLinus Torvalds 		retval);
5751da177e4SLinus Torvalds 	if (retval) {
5761da177e4SLinus Torvalds 		PRINTK_ERROR(KERN_ERR_MWAVE
5771da177e4SLinus Torvalds 				"mwavedd::mwave_init: Error:"
5781da177e4SLinus Torvalds 				" Failed to initialize board data\n");
5791da177e4SLinus Torvalds 		goto cleanup_error;
5801da177e4SLinus Torvalds 	}
5811da177e4SLinus Torvalds 	pDrvData->bBDInitialized = TRUE;
5821da177e4SLinus Torvalds 
5831da177e4SLinus Torvalds 	retval = tp3780I_CalcResources(&pDrvData->rBDData);
5841da177e4SLinus Torvalds 	PRINTK_2(TRACE_MWAVE,
5851da177e4SLinus Torvalds 		"mwavedd::mwave_init, return from tp3780I_CalcResources"
5861da177e4SLinus Torvalds 		" retval %x\n",
5871da177e4SLinus Torvalds 		retval);
5881da177e4SLinus Torvalds 	if (retval) {
5891da177e4SLinus Torvalds 		PRINTK_ERROR(KERN_ERR_MWAVE
5901da177e4SLinus Torvalds 				"mwavedd:mwave_init: Error:"
5911da177e4SLinus Torvalds 				" Failed to calculate resources\n");
5921da177e4SLinus Torvalds 		goto cleanup_error;
5931da177e4SLinus Torvalds 	}
5941da177e4SLinus Torvalds 
5951da177e4SLinus Torvalds 	retval = tp3780I_ClaimResources(&pDrvData->rBDData);
5961da177e4SLinus Torvalds 	PRINTK_2(TRACE_MWAVE,
5971da177e4SLinus Torvalds 		"mwavedd::mwave_init, return from tp3780I_ClaimResources"
5981da177e4SLinus Torvalds 		" retval %x\n",
5991da177e4SLinus Torvalds 		retval);
6001da177e4SLinus Torvalds 	if (retval) {
6011da177e4SLinus Torvalds 		PRINTK_ERROR(KERN_ERR_MWAVE
6021da177e4SLinus Torvalds 				"mwavedd:mwave_init: Error:"
6031da177e4SLinus Torvalds 				" Failed to claim resources\n");
6041da177e4SLinus Torvalds 		goto cleanup_error;
6051da177e4SLinus Torvalds 	}
6061da177e4SLinus Torvalds 	pDrvData->bResourcesClaimed = TRUE;
6071da177e4SLinus Torvalds 
6081da177e4SLinus Torvalds 	retval = tp3780I_EnableDSP(&pDrvData->rBDData);
6091da177e4SLinus Torvalds 	PRINTK_2(TRACE_MWAVE,
6101da177e4SLinus Torvalds 		"mwavedd::mwave_init, return from tp3780I_EnableDSP"
6111da177e4SLinus Torvalds 		" retval %x\n",
6121da177e4SLinus Torvalds 		retval);
6131da177e4SLinus Torvalds 	if (retval) {
6141da177e4SLinus Torvalds 		PRINTK_ERROR(KERN_ERR_MWAVE
6151da177e4SLinus Torvalds 				"mwavedd:mwave_init: Error:"
6161da177e4SLinus Torvalds 				" Failed to enable DSP\n");
6171da177e4SLinus Torvalds 		goto cleanup_error;
6181da177e4SLinus Torvalds 	}
6191da177e4SLinus Torvalds 	pDrvData->bDSPEnabled = TRUE;
6201da177e4SLinus Torvalds 
6211da177e4SLinus Torvalds 	if (misc_register(&mwave_misc_dev) < 0) {
6221da177e4SLinus Torvalds 		PRINTK_ERROR(KERN_ERR_MWAVE
6231da177e4SLinus Torvalds 				"mwavedd:mwave_init: Error:"
6241da177e4SLinus Torvalds 				" Failed to register misc device\n");
6251da177e4SLinus Torvalds 		goto cleanup_error;
6261da177e4SLinus Torvalds 	}
6271da177e4SLinus Torvalds 	pDrvData->bMwaveDevRegistered = TRUE;
6281da177e4SLinus Torvalds 
6291da177e4SLinus Torvalds 	pDrvData->sLine = register_serial_portandirq(
6301da177e4SLinus Torvalds 		pDrvData->rBDData.rDspSettings.usUartBaseIO,
6311da177e4SLinus Torvalds 		pDrvData->rBDData.rDspSettings.usUartIrq
6321da177e4SLinus Torvalds 	);
6331da177e4SLinus Torvalds 	if (pDrvData->sLine < 0) {
6341da177e4SLinus Torvalds 		PRINTK_ERROR(KERN_ERR_MWAVE
6351da177e4SLinus Torvalds 				"mwavedd:mwave_init: Error:"
6361da177e4SLinus Torvalds 				" Failed to register serial driver\n");
6371da177e4SLinus Torvalds 		goto cleanup_error;
6381da177e4SLinus Torvalds 	}
6391da177e4SLinus Torvalds 	/* uart is registered */
6401da177e4SLinus Torvalds 
6411da177e4SLinus Torvalds #if 0
6421da177e4SLinus Torvalds 	/* sysfs */
6431da177e4SLinus Torvalds 	memset(&mwave_device, 0, sizeof (struct device));
6441da177e4SLinus Torvalds 	snprintf(mwave_device.bus_id, BUS_ID_SIZE, "mwave");
6451da177e4SLinus Torvalds 
6461da177e4SLinus Torvalds 	if (device_register(&mwave_device))
6471da177e4SLinus Torvalds 		goto cleanup_error;
6481da177e4SLinus Torvalds 	pDrvData->device_registered = TRUE;
6491da177e4SLinus Torvalds 	for (i = 0; i < ARRAY_SIZE(mwave_dev_attrs); i++) {
6501da177e4SLinus Torvalds 		if(device_create_file(&mwave_device, mwave_dev_attrs[i])) {
6511da177e4SLinus Torvalds 			PRINTK_ERROR(KERN_ERR_MWAVE
6521da177e4SLinus Torvalds 					"mwavedd:mwave_init: Error:"
6531da177e4SLinus Torvalds 					" Failed to create sysfs file %s\n",
6541da177e4SLinus Torvalds 					mwave_dev_attrs[i]->attr.name);
6551da177e4SLinus Torvalds 			goto cleanup_error;
6561da177e4SLinus Torvalds 		}
6571da177e4SLinus Torvalds 		pDrvData->nr_registered_attrs++;
6581da177e4SLinus Torvalds 	}
6591da177e4SLinus Torvalds #endif
6601da177e4SLinus Torvalds 
6611da177e4SLinus Torvalds 	/* SUCCESS! */
6621da177e4SLinus Torvalds 	return 0;
6631da177e4SLinus Torvalds 
6641da177e4SLinus Torvalds cleanup_error:
6651da177e4SLinus Torvalds 	PRINTK_ERROR(KERN_ERR_MWAVE
6661da177e4SLinus Torvalds 			"mwavedd::mwave_init: Error:"
6671da177e4SLinus Torvalds 			" Failed to initialize\n");
6681da177e4SLinus Torvalds 	mwave_exit(); /* clean up */
6691da177e4SLinus Torvalds 
6701da177e4SLinus Torvalds 	return -EIO;
6711da177e4SLinus Torvalds }
6721da177e4SLinus Torvalds 
6731da177e4SLinus Torvalds module_init(mwave_init);
6741da177e4SLinus Torvalds 
675