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