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