brintos

brintos / linux-shallow public Read only

0
0
Text · 19.0 KiB · 11272d6 Raw
704 lines · c
1/*2*3* mwavedd.c -- mwave device driver4*5*6* Written By: Mike Sullivan IBM Corporation7*8* Copyright (C) 1999 IBM Corporation9*10* This program is free software; you can redistribute it and/or modify11* it under the terms of the GNU General Public License as published by12* the Free Software Foundation; either version 2 of the License, or13* (at your option) any later version.14*15* This program is distributed in the hope that it will be useful,16* but WITHOUT ANY WARRANTY; without even the implied warranty of17* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the18* GNU General Public License for more details.19*20* NO WARRANTY21* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR22* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT23* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,24* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is25* solely responsible for determining the appropriateness of using and26* distributing the Program and assumes all risks associated with its27* exercise of rights under this Agreement, including but not limited to28* the risks and costs of program errors, damage to or loss of data,29* programs or equipment, and unavailability or interruption of operations.30*31* DISCLAIMER OF LIABILITY32* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY33* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL34* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND35* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR36* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE37* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED38* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES39*40* You should have received a copy of the GNU General Public License41* along with this program; if not, write to the Free Software42* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA43*44*45* 10/23/2000 - Alpha Release46*	First release to the public47*/48 49#include <linux/module.h>50#include <linux/kernel.h>51#include <linux/fs.h>52#include <linux/init.h>53#include <linux/major.h>54#include <linux/miscdevice.h>55#include <linux/device.h>56#include <linux/serial.h>57#include <linux/sched.h>58#include <linux/spinlock.h>59#include <linux/mutex.h>60#include <linux/delay.h>61#include <linux/serial_8250.h>62#include <linux/nospec.h>63#include "smapi.h"64#include "mwavedd.h"65#include "3780i.h"66#include "tp3780i.h"67 68MODULE_DESCRIPTION("3780i Advanced Communications Processor (Mwave) driver");69MODULE_AUTHOR("Mike Sullivan and Paul Schroeder");70MODULE_LICENSE("GPL");71 72/*73* These parameters support the setting of MWave resources. Note that no74* checks are made against other devices (ie. superio) for conflicts.75* We'll depend on users using the tpctl utility to do that for now76*/77static DEFINE_MUTEX(mwave_mutex);78int mwave_debug = 0;79int mwave_3780i_irq = 0;80int mwave_3780i_io = 0;81int mwave_uart_irq = 0;82int mwave_uart_io = 0;83module_param(mwave_debug, int, 0);84module_param_hw(mwave_3780i_irq, int, irq, 0);85module_param_hw(mwave_3780i_io, int, ioport, 0);86module_param_hw(mwave_uart_irq, int, irq, 0);87module_param_hw(mwave_uart_io, int, ioport, 0);88 89static int mwave_open(struct inode *inode, struct file *file);90static int mwave_close(struct inode *inode, struct file *file);91static long mwave_ioctl(struct file *filp, unsigned int iocmd,92							unsigned long ioarg);93 94MWAVE_DEVICE_DATA mwave_s_mdd;95 96static int mwave_open(struct inode *inode, struct file *file)97{98	unsigned int retval = 0;99 100	PRINTK_3(TRACE_MWAVE,101		"mwavedd::mwave_open, entry inode %p file %p\n",102		 inode, file);103	PRINTK_2(TRACE_MWAVE,104		"mwavedd::mwave_open, exit return retval %x\n", retval);105 106	return retval;107}108 109static int mwave_close(struct inode *inode, struct file *file)110{111	unsigned int retval = 0;112 113	PRINTK_3(TRACE_MWAVE,114		"mwavedd::mwave_close, entry inode %p file %p\n",115		 inode,  file);116 117	PRINTK_2(TRACE_MWAVE, "mwavedd::mwave_close, exit retval %x\n",118		retval);119 120	return retval;121}122 123static long mwave_ioctl(struct file *file, unsigned int iocmd,124							unsigned long ioarg)125{126	unsigned int retval = 0;127	pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;128	void __user *arg = (void __user *)ioarg;129 130	PRINTK_4(TRACE_MWAVE,131		"mwavedd::mwave_ioctl, entry file %p cmd %x arg %x\n",132		file, iocmd, (int) ioarg);133 134	switch (iocmd) {135 136		case IOCTL_MW_RESET:137			PRINTK_1(TRACE_MWAVE,138				"mwavedd::mwave_ioctl, IOCTL_MW_RESET"139				" calling tp3780I_ResetDSP\n");140			mutex_lock(&mwave_mutex);141			retval = tp3780I_ResetDSP(&pDrvData->rBDData);142			mutex_unlock(&mwave_mutex);143			PRINTK_2(TRACE_MWAVE,144				"mwavedd::mwave_ioctl, IOCTL_MW_RESET"145				" retval %x from tp3780I_ResetDSP\n",146				retval);147			break;148	149		case IOCTL_MW_RUN:150			PRINTK_1(TRACE_MWAVE,151				"mwavedd::mwave_ioctl, IOCTL_MW_RUN"152				" calling tp3780I_StartDSP\n");153			mutex_lock(&mwave_mutex);154			retval = tp3780I_StartDSP(&pDrvData->rBDData);155			mutex_unlock(&mwave_mutex);156			PRINTK_2(TRACE_MWAVE,157				"mwavedd::mwave_ioctl, IOCTL_MW_RUN"158				" retval %x from tp3780I_StartDSP\n",159				retval);160			break;161	162		case IOCTL_MW_DSP_ABILITIES: {163			MW_ABILITIES rAbilities;164	165			PRINTK_1(TRACE_MWAVE,166				"mwavedd::mwave_ioctl,"167				" IOCTL_MW_DSP_ABILITIES calling"168				" tp3780I_QueryAbilities\n");169			mutex_lock(&mwave_mutex);170			retval = tp3780I_QueryAbilities(&pDrvData->rBDData,171					&rAbilities);172			mutex_unlock(&mwave_mutex);173			PRINTK_2(TRACE_MWAVE,174				"mwavedd::mwave_ioctl, IOCTL_MW_DSP_ABILITIES"175				" retval %x from tp3780I_QueryAbilities\n",176				retval);177			if (retval == 0) {178				if( copy_to_user(arg, &rAbilities,179							sizeof(MW_ABILITIES)) )180					return -EFAULT;181			}182			PRINTK_2(TRACE_MWAVE,183				"mwavedd::mwave_ioctl, IOCTL_MW_DSP_ABILITIES"184				" exit retval %x\n",185				retval);186		}187			break;188	189		case IOCTL_MW_READ_DATA:190		case IOCTL_MW_READCLEAR_DATA: {191			MW_READWRITE rReadData;192			unsigned short __user *pusBuffer = NULL;193	194			if( copy_from_user(&rReadData, arg,195						sizeof(MW_READWRITE)) )196				return -EFAULT;197			pusBuffer = (unsigned short __user *) (rReadData.pBuf);198	199			PRINTK_4(TRACE_MWAVE,200				"mwavedd::mwave_ioctl IOCTL_MW_READ_DATA,"201				" size %lx, ioarg %lx pusBuffer %p\n",202				rReadData.ulDataLength, ioarg, pusBuffer);203			mutex_lock(&mwave_mutex);204			retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData,205					iocmd,206					pusBuffer,207					rReadData.ulDataLength,208					rReadData.usDspAddress);209			mutex_unlock(&mwave_mutex);210		}211			break;212	213		case IOCTL_MW_READ_INST: {214			MW_READWRITE rReadData;215			unsigned short __user *pusBuffer = NULL;216	217			if( copy_from_user(&rReadData, arg,218						sizeof(MW_READWRITE)) )219				return -EFAULT;220			pusBuffer = (unsigned short __user *) (rReadData.pBuf);221	222			PRINTK_4(TRACE_MWAVE,223				"mwavedd::mwave_ioctl IOCTL_MW_READ_INST,"224				" size %lx, ioarg %lx pusBuffer %p\n",225				rReadData.ulDataLength / 2, ioarg,226				pusBuffer);227			mutex_lock(&mwave_mutex);228			retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData,229				iocmd, pusBuffer,230				rReadData.ulDataLength / 2,231				rReadData.usDspAddress);232			mutex_unlock(&mwave_mutex);233		}234			break;235	236		case IOCTL_MW_WRITE_DATA: {237			MW_READWRITE rWriteData;238			unsigned short __user *pusBuffer = NULL;239	240			if( copy_from_user(&rWriteData, arg,241						sizeof(MW_READWRITE)) )242				return -EFAULT;243			pusBuffer = (unsigned short __user *) (rWriteData.pBuf);244	245			PRINTK_4(TRACE_MWAVE,246				"mwavedd::mwave_ioctl IOCTL_MW_WRITE_DATA,"247				" size %lx, ioarg %lx pusBuffer %p\n",248				rWriteData.ulDataLength, ioarg,249				pusBuffer);250			mutex_lock(&mwave_mutex);251			retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData,252					iocmd, pusBuffer,253					rWriteData.ulDataLength,254					rWriteData.usDspAddress);255			mutex_unlock(&mwave_mutex);256		}257			break;258	259		case IOCTL_MW_WRITE_INST: {260			MW_READWRITE rWriteData;261			unsigned short __user *pusBuffer = NULL;262	263			if( copy_from_user(&rWriteData, arg,264						sizeof(MW_READWRITE)) )265				return -EFAULT;266			pusBuffer = (unsigned short __user *)(rWriteData.pBuf);267	268			PRINTK_4(TRACE_MWAVE,269				"mwavedd::mwave_ioctl IOCTL_MW_WRITE_INST,"270				" size %lx, ioarg %lx pusBuffer %p\n",271				rWriteData.ulDataLength, ioarg,272				pusBuffer);273			mutex_lock(&mwave_mutex);274			retval = tp3780I_ReadWriteDspIStore(&pDrvData->rBDData,275					iocmd, pusBuffer,276					rWriteData.ulDataLength,277					rWriteData.usDspAddress);278			mutex_unlock(&mwave_mutex);279		}280			break;281	282		case IOCTL_MW_REGISTER_IPC: {283			unsigned int ipcnum = (unsigned int) ioarg;284	285			if (ipcnum >= ARRAY_SIZE(pDrvData->IPCs)) {286				PRINTK_ERROR(KERN_ERR_MWAVE287						"mwavedd::mwave_ioctl:"288						" IOCTL_MW_REGISTER_IPC:"289						" Error: Invalid ipcnum %x\n",290						ipcnum);291				return -EINVAL;292			}293			ipcnum = array_index_nospec(ipcnum,294						    ARRAY_SIZE(pDrvData->IPCs));295			PRINTK_3(TRACE_MWAVE,296				"mwavedd::mwave_ioctl IOCTL_MW_REGISTER_IPC"297				" ipcnum %x entry usIntCount %x\n",298				ipcnum,299				pDrvData->IPCs[ipcnum].usIntCount);300 301			mutex_lock(&mwave_mutex);302			pDrvData->IPCs[ipcnum].bIsHere = false;303			pDrvData->IPCs[ipcnum].bIsEnabled = true;304			mutex_unlock(&mwave_mutex);305	306			PRINTK_2(TRACE_MWAVE,307				"mwavedd::mwave_ioctl IOCTL_MW_REGISTER_IPC"308				" ipcnum %x exit\n",309				ipcnum);310		}311			break;312	313		case IOCTL_MW_GET_IPC: {314			unsigned int ipcnum = (unsigned int) ioarg;315	316			if (ipcnum >= ARRAY_SIZE(pDrvData->IPCs)) {317				PRINTK_ERROR(KERN_ERR_MWAVE318						"mwavedd::mwave_ioctl:"319						" IOCTL_MW_GET_IPC: Error:"320						" Invalid ipcnum %x\n", ipcnum);321				return -EINVAL;322			}323			ipcnum = array_index_nospec(ipcnum,324						    ARRAY_SIZE(pDrvData->IPCs));325			PRINTK_3(TRACE_MWAVE,326				"mwavedd::mwave_ioctl IOCTL_MW_GET_IPC"327				" ipcnum %x, usIntCount %x\n",328				ipcnum,329				pDrvData->IPCs[ipcnum].usIntCount);330	331			mutex_lock(&mwave_mutex);332			if (pDrvData->IPCs[ipcnum].bIsEnabled == true) {333				DECLARE_WAITQUEUE(wait, current);334 335				PRINTK_2(TRACE_MWAVE,336					"mwavedd::mwave_ioctl, thread for"337					" ipc %x going to sleep\n",338					ipcnum);339				add_wait_queue(&pDrvData->IPCs[ipcnum].ipc_wait_queue, &wait);340				pDrvData->IPCs[ipcnum].bIsHere = true;341				set_current_state(TASK_INTERRUPTIBLE);342				/* check whether an event was signalled by */343				/* the interrupt handler while we were gone */344				if (pDrvData->IPCs[ipcnum].usIntCount == 1) {	/* first int has occurred (race condition) */345					pDrvData->IPCs[ipcnum].usIntCount = 2;	/* first int has been handled */346					PRINTK_2(TRACE_MWAVE,347						"mwavedd::mwave_ioctl"348						" IOCTL_MW_GET_IPC ipcnum %x"349						" handling first int\n",350						ipcnum);351				} else {	/* either 1st int has not yet occurred, or we have already handled the first int */352					schedule();353					if (pDrvData->IPCs[ipcnum].usIntCount == 1) {354						pDrvData->IPCs[ipcnum].usIntCount = 2;355					}356					PRINTK_2(TRACE_MWAVE,357						"mwavedd::mwave_ioctl"358						" IOCTL_MW_GET_IPC ipcnum %x"359						" woke up and returning to"360						" application\n",361						ipcnum);362				}363				pDrvData->IPCs[ipcnum].bIsHere = false;364				remove_wait_queue(&pDrvData->IPCs[ipcnum].ipc_wait_queue, &wait);365				set_current_state(TASK_RUNNING);366				PRINTK_2(TRACE_MWAVE,367					"mwavedd::mwave_ioctl IOCTL_MW_GET_IPC,"368					" returning thread for ipc %x"369					" processing\n",370					ipcnum);371			}372			mutex_unlock(&mwave_mutex);373		}374			break;375	376		case IOCTL_MW_UNREGISTER_IPC: {377			unsigned int ipcnum = (unsigned int) ioarg;378	379			PRINTK_2(TRACE_MWAVE,380				"mwavedd::mwave_ioctl IOCTL_MW_UNREGISTER_IPC"381				" ipcnum %x\n",382				ipcnum);383			if (ipcnum >= ARRAY_SIZE(pDrvData->IPCs)) {384				PRINTK_ERROR(KERN_ERR_MWAVE385						"mwavedd::mwave_ioctl:"386						" IOCTL_MW_UNREGISTER_IPC:"387						" Error: Invalid ipcnum %x\n",388						ipcnum);389				return -EINVAL;390			}391			ipcnum = array_index_nospec(ipcnum,392						    ARRAY_SIZE(pDrvData->IPCs));393			mutex_lock(&mwave_mutex);394			if (pDrvData->IPCs[ipcnum].bIsEnabled == true) {395				pDrvData->IPCs[ipcnum].bIsEnabled = false;396				if (pDrvData->IPCs[ipcnum].bIsHere == true) {397					wake_up_interruptible(&pDrvData->IPCs[ipcnum].ipc_wait_queue);398				}399			}400			mutex_unlock(&mwave_mutex);401		}402			break;403	404		default:405			return -ENOTTY;406	} /* switch */407 408	PRINTK_2(TRACE_MWAVE, "mwavedd::mwave_ioctl, exit retval %x\n", retval);409 410	return retval;411}412 413 414static ssize_t mwave_read(struct file *file, char __user *buf, size_t count,415                          loff_t * ppos)416{417	PRINTK_5(TRACE_MWAVE,418		"mwavedd::mwave_read entry file %p, buf %p, count %zx ppos %p\n",419		file, buf, count, ppos);420 421	return -EINVAL;422}423 424 425static ssize_t mwave_write(struct file *file, const char __user *buf,426                           size_t count, loff_t * ppos)427{428	PRINTK_5(TRACE_MWAVE,429		"mwavedd::mwave_write entry file %p, buf %p,"430		" count %zx ppos %p\n",431		file, buf, count, ppos);432 433	return -EINVAL;434}435 436 437static int register_serial_portandirq(unsigned int port, int irq)438{439	struct uart_8250_port uart;440	441	switch ( port ) {442		case 0x3f8:443		case 0x2f8:444		case 0x3e8:445		case 0x2e8:446			/* OK */447			break;448		default:449			PRINTK_ERROR(KERN_ERR_MWAVE450					"mwavedd::register_serial_portandirq:"451					" Error: Illegal port %x\n", port );452			return -1;453	} /* switch */454	/* port is okay */455 456	switch ( irq ) {457		case 3:458		case 4:459		case 5:460		case 7:461			/* OK */462			break;463		default:464			PRINTK_ERROR(KERN_ERR_MWAVE465					"mwavedd::register_serial_portandirq:"466					" Error: Illegal irq %x\n", irq );467			return -1;468	} /* switch */469	/* irq is okay */470 471	memset(&uart, 0, sizeof(uart));472	473	uart.port.uartclk =  1843200;474	uart.port.iobase = port;475	uart.port.irq = irq;476	uart.port.iotype = UPIO_PORT;477	uart.port.flags =  UPF_SHARE_IRQ;478	return serial8250_register_8250_port(&uart);479}480 481 482static const struct file_operations mwave_fops = {483	.owner		= THIS_MODULE,484	.read		= mwave_read,485	.write		= mwave_write,486	.unlocked_ioctl	= mwave_ioctl,487	.open		= mwave_open,488	.release	= mwave_close,489	.llseek		= default_llseek,490};491 492 493static struct miscdevice mwave_misc_dev = { MWAVE_MINOR, "mwave", &mwave_fops };494 495#if 0 /* totally b0rked */496/*497 * sysfs support <paulsch@us.ibm.com>498 */499 500struct device mwave_device;501 502/* Prevent code redundancy, create a macro for mwave_show_* functions. */503#define mwave_show_function(attr_name, format_string, field)		\504static ssize_t mwave_show_##attr_name(struct device *dev, struct device_attribute *attr, char *buf)	\505{									\506	DSP_3780I_CONFIG_SETTINGS *pSettings =				\507		&mwave_s_mdd.rBDData.rDspSettings;			\508        return sprintf(buf, format_string, pSettings->field);		\509}510 511/* All of our attributes are read attributes. */512#define mwave_dev_rd_attr(attr_name, format_string, field)		\513	mwave_show_function(attr_name, format_string, field)		\514static DEVICE_ATTR(attr_name, S_IRUGO, mwave_show_##attr_name, NULL)515 516mwave_dev_rd_attr (3780i_dma, "%i\n", usDspDma);517mwave_dev_rd_attr (3780i_irq, "%i\n", usDspIrq);518mwave_dev_rd_attr (3780i_io, "%#.4x\n", usDspBaseIO);519mwave_dev_rd_attr (uart_irq, "%i\n", usUartIrq);520mwave_dev_rd_attr (uart_io, "%#.4x\n", usUartBaseIO);521 522static struct device_attribute * const mwave_dev_attrs[] = {523	&dev_attr_3780i_dma,524	&dev_attr_3780i_irq,525	&dev_attr_3780i_io,526	&dev_attr_uart_irq,527	&dev_attr_uart_io,528};529#endif530 531/*532* mwave_init is called on module load533*534* mwave_exit is called on module unload535* mwave_exit is also used to clean up after an aborted mwave_init536*/537static void mwave_exit(void)538{539	pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;540 541	PRINTK_1(TRACE_MWAVE, "mwavedd::mwave_exit entry\n");542 543#if 0544	for (i = 0; i < pDrvData->nr_registered_attrs; i++)545		device_remove_file(&mwave_device, mwave_dev_attrs[i]);546	pDrvData->nr_registered_attrs = 0;547 548	if (pDrvData->device_registered) {549		device_unregister(&mwave_device);550		pDrvData->device_registered = false;551	}552#endif553 554	if ( pDrvData->sLine >= 0 ) {555		serial8250_unregister_port(pDrvData->sLine);556	}557	if (pDrvData->bMwaveDevRegistered) {558		misc_deregister(&mwave_misc_dev);559	}560	if (pDrvData->bDSPEnabled) {561		tp3780I_DisableDSP(&pDrvData->rBDData);562	}563	if (pDrvData->bResourcesClaimed) {564		tp3780I_ReleaseResources(&pDrvData->rBDData);565	}566	if (pDrvData->bBDInitialized) {567		tp3780I_Cleanup(&pDrvData->rBDData);568	}569 570	PRINTK_1(TRACE_MWAVE, "mwavedd::mwave_exit exit\n");571}572 573module_exit(mwave_exit);574 575static int __init mwave_init(void)576{577	int i;578	int retval = 0;579	pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;580 581	PRINTK_1(TRACE_MWAVE, "mwavedd::mwave_init entry\n");582 583	memset(&mwave_s_mdd, 0, sizeof(MWAVE_DEVICE_DATA));584 585	pDrvData->bBDInitialized = false;586	pDrvData->bResourcesClaimed = false;587	pDrvData->bDSPEnabled = false;588	pDrvData->bDSPReset = false;589	pDrvData->bMwaveDevRegistered = false;590	pDrvData->sLine = -1;591 592	for (i = 0; i < ARRAY_SIZE(pDrvData->IPCs); i++) {593		pDrvData->IPCs[i].bIsEnabled = false;594		pDrvData->IPCs[i].bIsHere = false;595		pDrvData->IPCs[i].usIntCount = 0;	/* no ints received yet */596		init_waitqueue_head(&pDrvData->IPCs[i].ipc_wait_queue);597	}598 599	retval = tp3780I_InitializeBoardData(&pDrvData->rBDData);600	PRINTK_2(TRACE_MWAVE,601		"mwavedd::mwave_init, return from tp3780I_InitializeBoardData"602		" retval %x\n",603		retval);604	if (retval) {605		PRINTK_ERROR(KERN_ERR_MWAVE606				"mwavedd::mwave_init: Error:"607				" Failed to initialize board data\n");608		goto cleanup_error;609	}610	pDrvData->bBDInitialized = true;611 612	retval = tp3780I_CalcResources(&pDrvData->rBDData);613	PRINTK_2(TRACE_MWAVE,614		"mwavedd::mwave_init, return from tp3780I_CalcResources"615		" retval %x\n",616		retval);617	if (retval) {618		PRINTK_ERROR(KERN_ERR_MWAVE619				"mwavedd:mwave_init: Error:"620				" Failed to calculate resources\n");621		goto cleanup_error;622	}623 624	retval = tp3780I_ClaimResources(&pDrvData->rBDData);625	PRINTK_2(TRACE_MWAVE,626		"mwavedd::mwave_init, return from tp3780I_ClaimResources"627		" retval %x\n",628		retval);629	if (retval) {630		PRINTK_ERROR(KERN_ERR_MWAVE631				"mwavedd:mwave_init: Error:"632				" Failed to claim resources\n");633		goto cleanup_error;634	}635	pDrvData->bResourcesClaimed = true;636 637	retval = tp3780I_EnableDSP(&pDrvData->rBDData);638	PRINTK_2(TRACE_MWAVE,639		"mwavedd::mwave_init, return from tp3780I_EnableDSP"640		" retval %x\n",641		retval);642	if (retval) {643		PRINTK_ERROR(KERN_ERR_MWAVE644				"mwavedd:mwave_init: Error:"645				" Failed to enable DSP\n");646		goto cleanup_error;647	}648	pDrvData->bDSPEnabled = true;649 650	if (misc_register(&mwave_misc_dev) < 0) {651		PRINTK_ERROR(KERN_ERR_MWAVE652				"mwavedd:mwave_init: Error:"653				" Failed to register misc device\n");654		goto cleanup_error;655	}656	pDrvData->bMwaveDevRegistered = true;657 658	pDrvData->sLine = register_serial_portandirq(659		pDrvData->rBDData.rDspSettings.usUartBaseIO,660		pDrvData->rBDData.rDspSettings.usUartIrq661	);662	if (pDrvData->sLine < 0) {663		PRINTK_ERROR(KERN_ERR_MWAVE664				"mwavedd:mwave_init: Error:"665				" Failed to register serial driver\n");666		goto cleanup_error;667	}668	/* uart is registered */669 670#if 0671	/* sysfs */672	memset(&mwave_device, 0, sizeof (struct device));673	dev_set_name(&mwave_device, "mwave");674 675	if (device_register(&mwave_device))676		goto cleanup_error;677	pDrvData->device_registered = true;678	for (i = 0; i < ARRAY_SIZE(mwave_dev_attrs); i++) {679		if(device_create_file(&mwave_device, mwave_dev_attrs[i])) {680			PRINTK_ERROR(KERN_ERR_MWAVE681					"mwavedd:mwave_init: Error:"682					" Failed to create sysfs file %s\n",683					mwave_dev_attrs[i]->attr.name);684			goto cleanup_error;685		}686		pDrvData->nr_registered_attrs++;687	}688#endif689 690	/* SUCCESS! */691	return 0;692 693cleanup_error:694	PRINTK_ERROR(KERN_ERR_MWAVE695			"mwavedd::mwave_init: Error:"696			" Failed to initialize\n");697	mwave_exit(); /* clean up */698 699	return -EIO;700}701 702module_init(mwave_init);703 704