Back to home page

OSCL-LXR

 
 

    


0001 /*
0002 *
0003 * mwavedd.c -- mwave device driver
0004 *
0005 *
0006 * Written By: Mike Sullivan IBM Corporation
0007 *
0008 * Copyright (C) 1999 IBM Corporation
0009 *
0010 * This program is free software; you can redistribute it and/or modify
0011 * it under the terms of the GNU General Public License as published by
0012 * the Free Software Foundation; either version 2 of the License, or
0013 * (at your option) any later version.
0014 *
0015 * This program is distributed in the hope that it will be useful,
0016 * but WITHOUT ANY WARRANTY; without even the implied warranty of
0017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0018 * GNU General Public License for more details.
0019 *
0020 * NO WARRANTY
0021 * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
0022 * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
0023 * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
0024 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
0025 * solely responsible for determining the appropriateness of using and
0026 * distributing the Program and assumes all risks associated with its
0027 * exercise of rights under this Agreement, including but not limited to
0028 * the risks and costs of program errors, damage to or loss of data,
0029 * programs or equipment, and unavailability or interruption of operations.
0030 *
0031 * DISCLAIMER OF LIABILITY
0032 * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
0033 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0034 * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
0035 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
0036 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
0037 * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
0038 * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
0039 *
0040 * You should have received a copy of the GNU General Public License
0041 * along with this program; if not, write to the Free Software
0042 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
0043 *
0044 *
0045 * 10/23/2000 - Alpha Release
0046 *   First release to the public
0047 */
0048 
0049 #include <linux/module.h>
0050 #include <linux/kernel.h>
0051 #include <linux/fs.h>
0052 #include <linux/init.h>
0053 #include <linux/major.h>
0054 #include <linux/miscdevice.h>
0055 #include <linux/device.h>
0056 #include <linux/serial.h>
0057 #include <linux/sched.h>
0058 #include <linux/spinlock.h>
0059 #include <linux/mutex.h>
0060 #include <linux/delay.h>
0061 #include <linux/serial_8250.h>
0062 #include <linux/nospec.h>
0063 #include "smapi.h"
0064 #include "mwavedd.h"
0065 #include "3780i.h"
0066 #include "tp3780i.h"
0067 
0068 MODULE_DESCRIPTION("3780i Advanced Communications Processor (Mwave) driver");
0069 MODULE_AUTHOR("Mike Sullivan and Paul Schroeder");
0070 MODULE_LICENSE("GPL");
0071 
0072 /*
0073 * These parameters support the setting of MWave resources. Note that no
0074 * checks are made against other devices (ie. superio) for conflicts.
0075 * We'll depend on users using the tpctl utility to do that for now
0076 */
0077 static DEFINE_MUTEX(mwave_mutex);
0078 int mwave_debug = 0;
0079 int mwave_3780i_irq = 0;
0080 int mwave_3780i_io = 0;
0081 int mwave_uart_irq = 0;
0082 int mwave_uart_io = 0;
0083 module_param(mwave_debug, int, 0);
0084 module_param_hw(mwave_3780i_irq, int, irq, 0);
0085 module_param_hw(mwave_3780i_io, int, ioport, 0);
0086 module_param_hw(mwave_uart_irq, int, irq, 0);
0087 module_param_hw(mwave_uart_io, int, ioport, 0);
0088 
0089 static int mwave_open(struct inode *inode, struct file *file);
0090 static int mwave_close(struct inode *inode, struct file *file);
0091 static long mwave_ioctl(struct file *filp, unsigned int iocmd,
0092                             unsigned long ioarg);
0093 
0094 MWAVE_DEVICE_DATA mwave_s_mdd;
0095 
0096 static int mwave_open(struct inode *inode, struct file *file)
0097 {
0098     unsigned int retval = 0;
0099 
0100     PRINTK_3(TRACE_MWAVE,
0101         "mwavedd::mwave_open, entry inode %p file %p\n",
0102          inode, file);
0103     PRINTK_2(TRACE_MWAVE,
0104         "mwavedd::mwave_open, exit return retval %x\n", retval);
0105 
0106     return retval;
0107 }
0108 
0109 static int mwave_close(struct inode *inode, struct file *file)
0110 {
0111     unsigned int retval = 0;
0112 
0113     PRINTK_3(TRACE_MWAVE,
0114         "mwavedd::mwave_close, entry inode %p file %p\n",
0115          inode,  file);
0116 
0117     PRINTK_2(TRACE_MWAVE, "mwavedd::mwave_close, exit retval %x\n",
0118         retval);
0119 
0120     return retval;
0121 }
0122 
0123 static long mwave_ioctl(struct file *file, unsigned int iocmd,
0124                             unsigned long ioarg)
0125 {
0126     unsigned int retval = 0;
0127     pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;
0128     void __user *arg = (void __user *)ioarg;
0129 
0130     PRINTK_4(TRACE_MWAVE,
0131         "mwavedd::mwave_ioctl, entry file %p cmd %x arg %x\n",
0132         file, iocmd, (int) ioarg);
0133 
0134     switch (iocmd) {
0135 
0136         case IOCTL_MW_RESET:
0137             PRINTK_1(TRACE_MWAVE,
0138                 "mwavedd::mwave_ioctl, IOCTL_MW_RESET"
0139                 " calling tp3780I_ResetDSP\n");
0140             mutex_lock(&mwave_mutex);
0141             retval = tp3780I_ResetDSP(&pDrvData->rBDData);
0142             mutex_unlock(&mwave_mutex);
0143             PRINTK_2(TRACE_MWAVE,
0144                 "mwavedd::mwave_ioctl, IOCTL_MW_RESET"
0145                 " retval %x from tp3780I_ResetDSP\n",
0146                 retval);
0147             break;
0148     
0149         case IOCTL_MW_RUN:
0150             PRINTK_1(TRACE_MWAVE,
0151                 "mwavedd::mwave_ioctl, IOCTL_MW_RUN"
0152                 " calling tp3780I_StartDSP\n");
0153             mutex_lock(&mwave_mutex);
0154             retval = tp3780I_StartDSP(&pDrvData->rBDData);
0155             mutex_unlock(&mwave_mutex);
0156             PRINTK_2(TRACE_MWAVE,
0157                 "mwavedd::mwave_ioctl, IOCTL_MW_RUN"
0158                 " retval %x from tp3780I_StartDSP\n",
0159                 retval);
0160             break;
0161     
0162         case IOCTL_MW_DSP_ABILITIES: {
0163             MW_ABILITIES rAbilities;
0164     
0165             PRINTK_1(TRACE_MWAVE,
0166                 "mwavedd::mwave_ioctl,"
0167                 " IOCTL_MW_DSP_ABILITIES calling"
0168                 " tp3780I_QueryAbilities\n");
0169             mutex_lock(&mwave_mutex);
0170             retval = tp3780I_QueryAbilities(&pDrvData->rBDData,
0171                     &rAbilities);
0172             mutex_unlock(&mwave_mutex);
0173             PRINTK_2(TRACE_MWAVE,
0174                 "mwavedd::mwave_ioctl, IOCTL_MW_DSP_ABILITIES"
0175                 " retval %x from tp3780I_QueryAbilities\n",
0176                 retval);
0177             if (retval == 0) {
0178                 if( copy_to_user(arg, &rAbilities,
0179                             sizeof(MW_ABILITIES)) )
0180                     return -EFAULT;
0181             }
0182             PRINTK_2(TRACE_MWAVE,
0183                 "mwavedd::mwave_ioctl, IOCTL_MW_DSP_ABILITIES"
0184                 " exit retval %x\n",
0185                 retval);
0186         }
0187             break;
0188     
0189         case IOCTL_MW_READ_DATA:
0190         case IOCTL_MW_READCLEAR_DATA: {
0191             MW_READWRITE rReadData;
0192             unsigned short __user *pusBuffer = NULL;
0193     
0194             if( copy_from_user(&rReadData, arg,
0195                         sizeof(MW_READWRITE)) )
0196                 return -EFAULT;
0197             pusBuffer = (unsigned short __user *) (rReadData.pBuf);
0198     
0199             PRINTK_4(TRACE_MWAVE,
0200                 "mwavedd::mwave_ioctl IOCTL_MW_READ_DATA,"
0201                 " size %lx, ioarg %lx pusBuffer %p\n",
0202                 rReadData.ulDataLength, ioarg, pusBuffer);
0203             mutex_lock(&mwave_mutex);
0204             retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData,
0205                     iocmd,
0206                     pusBuffer,
0207                     rReadData.ulDataLength,
0208                     rReadData.usDspAddress);
0209             mutex_unlock(&mwave_mutex);
0210         }
0211             break;
0212     
0213         case IOCTL_MW_READ_INST: {
0214             MW_READWRITE rReadData;
0215             unsigned short __user *pusBuffer = NULL;
0216     
0217             if( copy_from_user(&rReadData, arg,
0218                         sizeof(MW_READWRITE)) )
0219                 return -EFAULT;
0220             pusBuffer = (unsigned short __user *) (rReadData.pBuf);
0221     
0222             PRINTK_4(TRACE_MWAVE,
0223                 "mwavedd::mwave_ioctl IOCTL_MW_READ_INST,"
0224                 " size %lx, ioarg %lx pusBuffer %p\n",
0225                 rReadData.ulDataLength / 2, ioarg,
0226                 pusBuffer);
0227             mutex_lock(&mwave_mutex);
0228             retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData,
0229                 iocmd, pusBuffer,
0230                 rReadData.ulDataLength / 2,
0231                 rReadData.usDspAddress);
0232             mutex_unlock(&mwave_mutex);
0233         }
0234             break;
0235     
0236         case IOCTL_MW_WRITE_DATA: {
0237             MW_READWRITE rWriteData;
0238             unsigned short __user *pusBuffer = NULL;
0239     
0240             if( copy_from_user(&rWriteData, arg,
0241                         sizeof(MW_READWRITE)) )
0242                 return -EFAULT;
0243             pusBuffer = (unsigned short __user *) (rWriteData.pBuf);
0244     
0245             PRINTK_4(TRACE_MWAVE,
0246                 "mwavedd::mwave_ioctl IOCTL_MW_WRITE_DATA,"
0247                 " size %lx, ioarg %lx pusBuffer %p\n",
0248                 rWriteData.ulDataLength, ioarg,
0249                 pusBuffer);
0250             mutex_lock(&mwave_mutex);
0251             retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData,
0252                     iocmd, pusBuffer,
0253                     rWriteData.ulDataLength,
0254                     rWriteData.usDspAddress);
0255             mutex_unlock(&mwave_mutex);
0256         }
0257             break;
0258     
0259         case IOCTL_MW_WRITE_INST: {
0260             MW_READWRITE rWriteData;
0261             unsigned short __user *pusBuffer = NULL;
0262     
0263             if( copy_from_user(&rWriteData, arg,
0264                         sizeof(MW_READWRITE)) )
0265                 return -EFAULT;
0266             pusBuffer = (unsigned short __user *)(rWriteData.pBuf);
0267     
0268             PRINTK_4(TRACE_MWAVE,
0269                 "mwavedd::mwave_ioctl IOCTL_MW_WRITE_INST,"
0270                 " size %lx, ioarg %lx pusBuffer %p\n",
0271                 rWriteData.ulDataLength, ioarg,
0272                 pusBuffer);
0273             mutex_lock(&mwave_mutex);
0274             retval = tp3780I_ReadWriteDspIStore(&pDrvData->rBDData,
0275                     iocmd, pusBuffer,
0276                     rWriteData.ulDataLength,
0277                     rWriteData.usDspAddress);
0278             mutex_unlock(&mwave_mutex);
0279         }
0280             break;
0281     
0282         case IOCTL_MW_REGISTER_IPC: {
0283             unsigned int ipcnum = (unsigned int) ioarg;
0284     
0285             if (ipcnum >= ARRAY_SIZE(pDrvData->IPCs)) {
0286                 PRINTK_ERROR(KERN_ERR_MWAVE
0287                         "mwavedd::mwave_ioctl:"
0288                         " IOCTL_MW_REGISTER_IPC:"
0289                         " Error: Invalid ipcnum %x\n",
0290                         ipcnum);
0291                 return -EINVAL;
0292             }
0293             ipcnum = array_index_nospec(ipcnum,
0294                             ARRAY_SIZE(pDrvData->IPCs));
0295             PRINTK_3(TRACE_MWAVE,
0296                 "mwavedd::mwave_ioctl IOCTL_MW_REGISTER_IPC"
0297                 " ipcnum %x entry usIntCount %x\n",
0298                 ipcnum,
0299                 pDrvData->IPCs[ipcnum].usIntCount);
0300 
0301             mutex_lock(&mwave_mutex);
0302             pDrvData->IPCs[ipcnum].bIsHere = false;
0303             pDrvData->IPCs[ipcnum].bIsEnabled = true;
0304             mutex_unlock(&mwave_mutex);
0305     
0306             PRINTK_2(TRACE_MWAVE,
0307                 "mwavedd::mwave_ioctl IOCTL_MW_REGISTER_IPC"
0308                 " ipcnum %x exit\n",
0309                 ipcnum);
0310         }
0311             break;
0312     
0313         case IOCTL_MW_GET_IPC: {
0314             unsigned int ipcnum = (unsigned int) ioarg;
0315     
0316             if (ipcnum >= ARRAY_SIZE(pDrvData->IPCs)) {
0317                 PRINTK_ERROR(KERN_ERR_MWAVE
0318                         "mwavedd::mwave_ioctl:"
0319                         " IOCTL_MW_GET_IPC: Error:"
0320                         " Invalid ipcnum %x\n", ipcnum);
0321                 return -EINVAL;
0322             }
0323             ipcnum = array_index_nospec(ipcnum,
0324                             ARRAY_SIZE(pDrvData->IPCs));
0325             PRINTK_3(TRACE_MWAVE,
0326                 "mwavedd::mwave_ioctl IOCTL_MW_GET_IPC"
0327                 " ipcnum %x, usIntCount %x\n",
0328                 ipcnum,
0329                 pDrvData->IPCs[ipcnum].usIntCount);
0330     
0331             mutex_lock(&mwave_mutex);
0332             if (pDrvData->IPCs[ipcnum].bIsEnabled == true) {
0333                 DECLARE_WAITQUEUE(wait, current);
0334 
0335                 PRINTK_2(TRACE_MWAVE,
0336                     "mwavedd::mwave_ioctl, thread for"
0337                     " ipc %x going to sleep\n",
0338                     ipcnum);
0339                 add_wait_queue(&pDrvData->IPCs[ipcnum].ipc_wait_queue, &wait);
0340                 pDrvData->IPCs[ipcnum].bIsHere = true;
0341                 set_current_state(TASK_INTERRUPTIBLE);
0342                 /* check whether an event was signalled by */
0343                 /* the interrupt handler while we were gone */
0344                 if (pDrvData->IPCs[ipcnum].usIntCount == 1) {   /* first int has occurred (race condition) */
0345                     pDrvData->IPCs[ipcnum].usIntCount = 2;  /* first int has been handled */
0346                     PRINTK_2(TRACE_MWAVE,
0347                         "mwavedd::mwave_ioctl"
0348                         " IOCTL_MW_GET_IPC ipcnum %x"
0349                         " handling first int\n",
0350                         ipcnum);
0351                 } else {    /* either 1st int has not yet occurred, or we have already handled the first int */
0352                     schedule();
0353                     if (pDrvData->IPCs[ipcnum].usIntCount == 1) {
0354                         pDrvData->IPCs[ipcnum].usIntCount = 2;
0355                     }
0356                     PRINTK_2(TRACE_MWAVE,
0357                         "mwavedd::mwave_ioctl"
0358                         " IOCTL_MW_GET_IPC ipcnum %x"
0359                         " woke up and returning to"
0360                         " application\n",
0361                         ipcnum);
0362                 }
0363                 pDrvData->IPCs[ipcnum].bIsHere = false;
0364                 remove_wait_queue(&pDrvData->IPCs[ipcnum].ipc_wait_queue, &wait);
0365                 set_current_state(TASK_RUNNING);
0366                 PRINTK_2(TRACE_MWAVE,
0367                     "mwavedd::mwave_ioctl IOCTL_MW_GET_IPC,"
0368                     " returning thread for ipc %x"
0369                     " processing\n",
0370                     ipcnum);
0371             }
0372             mutex_unlock(&mwave_mutex);
0373         }
0374             break;
0375     
0376         case IOCTL_MW_UNREGISTER_IPC: {
0377             unsigned int ipcnum = (unsigned int) ioarg;
0378     
0379             PRINTK_2(TRACE_MWAVE,
0380                 "mwavedd::mwave_ioctl IOCTL_MW_UNREGISTER_IPC"
0381                 " ipcnum %x\n",
0382                 ipcnum);
0383             if (ipcnum >= ARRAY_SIZE(pDrvData->IPCs)) {
0384                 PRINTK_ERROR(KERN_ERR_MWAVE
0385                         "mwavedd::mwave_ioctl:"
0386                         " IOCTL_MW_UNREGISTER_IPC:"
0387                         " Error: Invalid ipcnum %x\n",
0388                         ipcnum);
0389                 return -EINVAL;
0390             }
0391             ipcnum = array_index_nospec(ipcnum,
0392                             ARRAY_SIZE(pDrvData->IPCs));
0393             mutex_lock(&mwave_mutex);
0394             if (pDrvData->IPCs[ipcnum].bIsEnabled == true) {
0395                 pDrvData->IPCs[ipcnum].bIsEnabled = false;
0396                 if (pDrvData->IPCs[ipcnum].bIsHere == true) {
0397                     wake_up_interruptible(&pDrvData->IPCs[ipcnum].ipc_wait_queue);
0398                 }
0399             }
0400             mutex_unlock(&mwave_mutex);
0401         }
0402             break;
0403     
0404         default:
0405             return -ENOTTY;
0406     } /* switch */
0407 
0408     PRINTK_2(TRACE_MWAVE, "mwavedd::mwave_ioctl, exit retval %x\n", retval);
0409 
0410     return retval;
0411 }
0412 
0413 
0414 static ssize_t mwave_read(struct file *file, char __user *buf, size_t count,
0415                           loff_t * ppos)
0416 {
0417     PRINTK_5(TRACE_MWAVE,
0418         "mwavedd::mwave_read entry file %p, buf %p, count %zx ppos %p\n",
0419         file, buf, count, ppos);
0420 
0421     return -EINVAL;
0422 }
0423 
0424 
0425 static ssize_t mwave_write(struct file *file, const char __user *buf,
0426                            size_t count, loff_t * ppos)
0427 {
0428     PRINTK_5(TRACE_MWAVE,
0429         "mwavedd::mwave_write entry file %p, buf %p,"
0430         " count %zx ppos %p\n",
0431         file, buf, count, ppos);
0432 
0433     return -EINVAL;
0434 }
0435 
0436 
0437 static int register_serial_portandirq(unsigned int port, int irq)
0438 {
0439     struct uart_8250_port uart;
0440     
0441     switch ( port ) {
0442         case 0x3f8:
0443         case 0x2f8:
0444         case 0x3e8:
0445         case 0x2e8:
0446             /* OK */
0447             break;
0448         default:
0449             PRINTK_ERROR(KERN_ERR_MWAVE
0450                     "mwavedd::register_serial_portandirq:"
0451                     " Error: Illegal port %x\n", port );
0452             return -1;
0453     } /* switch */
0454     /* port is okay */
0455 
0456     switch ( irq ) {
0457         case 3:
0458         case 4:
0459         case 5:
0460         case 7:
0461             /* OK */
0462             break;
0463         default:
0464             PRINTK_ERROR(KERN_ERR_MWAVE
0465                     "mwavedd::register_serial_portandirq:"
0466                     " Error: Illegal irq %x\n", irq );
0467             return -1;
0468     } /* switch */
0469     /* irq is okay */
0470 
0471     memset(&uart, 0, sizeof(uart));
0472     
0473     uart.port.uartclk =  1843200;
0474     uart.port.iobase = port;
0475     uart.port.irq = irq;
0476     uart.port.iotype = UPIO_PORT;
0477     uart.port.flags =  UPF_SHARE_IRQ;
0478     return serial8250_register_8250_port(&uart);
0479 }
0480 
0481 
0482 static const struct file_operations mwave_fops = {
0483     .owner      = THIS_MODULE,
0484     .read       = mwave_read,
0485     .write      = mwave_write,
0486     .unlocked_ioctl = mwave_ioctl,
0487     .open       = mwave_open,
0488     .release    = mwave_close,
0489     .llseek     = default_llseek,
0490 };
0491 
0492 
0493 static struct miscdevice mwave_misc_dev = { MWAVE_MINOR, "mwave", &mwave_fops };
0494 
0495 #if 0 /* totally b0rked */
0496 /*
0497  * sysfs support <paulsch@us.ibm.com>
0498  */
0499 
0500 struct device mwave_device;
0501 
0502 /* Prevent code redundancy, create a macro for mwave_show_* functions. */
0503 #define mwave_show_function(attr_name, format_string, field)        \
0504 static ssize_t mwave_show_##attr_name(struct device *dev, struct device_attribute *attr, char *buf) \
0505 {                                   \
0506     DSP_3780I_CONFIG_SETTINGS *pSettings =              \
0507         &mwave_s_mdd.rBDData.rDspSettings;          \
0508         return sprintf(buf, format_string, pSettings->field);       \
0509 }
0510 
0511 /* All of our attributes are read attributes. */
0512 #define mwave_dev_rd_attr(attr_name, format_string, field)      \
0513     mwave_show_function(attr_name, format_string, field)        \
0514 static DEVICE_ATTR(attr_name, S_IRUGO, mwave_show_##attr_name, NULL)
0515 
0516 mwave_dev_rd_attr (3780i_dma, "%i\n", usDspDma);
0517 mwave_dev_rd_attr (3780i_irq, "%i\n", usDspIrq);
0518 mwave_dev_rd_attr (3780i_io, "%#.4x\n", usDspBaseIO);
0519 mwave_dev_rd_attr (uart_irq, "%i\n", usUartIrq);
0520 mwave_dev_rd_attr (uart_io, "%#.4x\n", usUartBaseIO);
0521 
0522 static struct device_attribute * const mwave_dev_attrs[] = {
0523     &dev_attr_3780i_dma,
0524     &dev_attr_3780i_irq,
0525     &dev_attr_3780i_io,
0526     &dev_attr_uart_irq,
0527     &dev_attr_uart_io,
0528 };
0529 #endif
0530 
0531 /*
0532 * mwave_init is called on module load
0533 *
0534 * mwave_exit is called on module unload
0535 * mwave_exit is also used to clean up after an aborted mwave_init
0536 */
0537 static void mwave_exit(void)
0538 {
0539     pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;
0540 
0541     PRINTK_1(TRACE_MWAVE, "mwavedd::mwave_exit entry\n");
0542 
0543 #if 0
0544     for (i = 0; i < pDrvData->nr_registered_attrs; i++)
0545         device_remove_file(&mwave_device, mwave_dev_attrs[i]);
0546     pDrvData->nr_registered_attrs = 0;
0547 
0548     if (pDrvData->device_registered) {
0549         device_unregister(&mwave_device);
0550         pDrvData->device_registered = false;
0551     }
0552 #endif
0553 
0554     if ( pDrvData->sLine >= 0 ) {
0555         serial8250_unregister_port(pDrvData->sLine);
0556     }
0557     if (pDrvData->bMwaveDevRegistered) {
0558         misc_deregister(&mwave_misc_dev);
0559     }
0560     if (pDrvData->bDSPEnabled) {
0561         tp3780I_DisableDSP(&pDrvData->rBDData);
0562     }
0563     if (pDrvData->bResourcesClaimed) {
0564         tp3780I_ReleaseResources(&pDrvData->rBDData);
0565     }
0566     if (pDrvData->bBDInitialized) {
0567         tp3780I_Cleanup(&pDrvData->rBDData);
0568     }
0569 
0570     PRINTK_1(TRACE_MWAVE, "mwavedd::mwave_exit exit\n");
0571 }
0572 
0573 module_exit(mwave_exit);
0574 
0575 static int __init mwave_init(void)
0576 {
0577     int i;
0578     int retval = 0;
0579     pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;
0580 
0581     PRINTK_1(TRACE_MWAVE, "mwavedd::mwave_init entry\n");
0582 
0583     memset(&mwave_s_mdd, 0, sizeof(MWAVE_DEVICE_DATA));
0584 
0585     pDrvData->bBDInitialized = false;
0586     pDrvData->bResourcesClaimed = false;
0587     pDrvData->bDSPEnabled = false;
0588     pDrvData->bDSPReset = false;
0589     pDrvData->bMwaveDevRegistered = false;
0590     pDrvData->sLine = -1;
0591 
0592     for (i = 0; i < ARRAY_SIZE(pDrvData->IPCs); i++) {
0593         pDrvData->IPCs[i].bIsEnabled = false;
0594         pDrvData->IPCs[i].bIsHere = false;
0595         pDrvData->IPCs[i].usIntCount = 0;   /* no ints received yet */
0596         init_waitqueue_head(&pDrvData->IPCs[i].ipc_wait_queue);
0597     }
0598 
0599     retval = tp3780I_InitializeBoardData(&pDrvData->rBDData);
0600     PRINTK_2(TRACE_MWAVE,
0601         "mwavedd::mwave_init, return from tp3780I_InitializeBoardData"
0602         " retval %x\n",
0603         retval);
0604     if (retval) {
0605         PRINTK_ERROR(KERN_ERR_MWAVE
0606                 "mwavedd::mwave_init: Error:"
0607                 " Failed to initialize board data\n");
0608         goto cleanup_error;
0609     }
0610     pDrvData->bBDInitialized = true;
0611 
0612     retval = tp3780I_CalcResources(&pDrvData->rBDData);
0613     PRINTK_2(TRACE_MWAVE,
0614         "mwavedd::mwave_init, return from tp3780I_CalcResources"
0615         " retval %x\n",
0616         retval);
0617     if (retval) {
0618         PRINTK_ERROR(KERN_ERR_MWAVE
0619                 "mwavedd:mwave_init: Error:"
0620                 " Failed to calculate resources\n");
0621         goto cleanup_error;
0622     }
0623 
0624     retval = tp3780I_ClaimResources(&pDrvData->rBDData);
0625     PRINTK_2(TRACE_MWAVE,
0626         "mwavedd::mwave_init, return from tp3780I_ClaimResources"
0627         " retval %x\n",
0628         retval);
0629     if (retval) {
0630         PRINTK_ERROR(KERN_ERR_MWAVE
0631                 "mwavedd:mwave_init: Error:"
0632                 " Failed to claim resources\n");
0633         goto cleanup_error;
0634     }
0635     pDrvData->bResourcesClaimed = true;
0636 
0637     retval = tp3780I_EnableDSP(&pDrvData->rBDData);
0638     PRINTK_2(TRACE_MWAVE,
0639         "mwavedd::mwave_init, return from tp3780I_EnableDSP"
0640         " retval %x\n",
0641         retval);
0642     if (retval) {
0643         PRINTK_ERROR(KERN_ERR_MWAVE
0644                 "mwavedd:mwave_init: Error:"
0645                 " Failed to enable DSP\n");
0646         goto cleanup_error;
0647     }
0648     pDrvData->bDSPEnabled = true;
0649 
0650     if (misc_register(&mwave_misc_dev) < 0) {
0651         PRINTK_ERROR(KERN_ERR_MWAVE
0652                 "mwavedd:mwave_init: Error:"
0653                 " Failed to register misc device\n");
0654         goto cleanup_error;
0655     }
0656     pDrvData->bMwaveDevRegistered = true;
0657 
0658     pDrvData->sLine = register_serial_portandirq(
0659         pDrvData->rBDData.rDspSettings.usUartBaseIO,
0660         pDrvData->rBDData.rDspSettings.usUartIrq
0661     );
0662     if (pDrvData->sLine < 0) {
0663         PRINTK_ERROR(KERN_ERR_MWAVE
0664                 "mwavedd:mwave_init: Error:"
0665                 " Failed to register serial driver\n");
0666         goto cleanup_error;
0667     }
0668     /* uart is registered */
0669 
0670 #if 0
0671     /* sysfs */
0672     memset(&mwave_device, 0, sizeof (struct device));
0673     dev_set_name(&mwave_device, "mwave");
0674 
0675     if (device_register(&mwave_device))
0676         goto cleanup_error;
0677     pDrvData->device_registered = true;
0678     for (i = 0; i < ARRAY_SIZE(mwave_dev_attrs); i++) {
0679         if(device_create_file(&mwave_device, mwave_dev_attrs[i])) {
0680             PRINTK_ERROR(KERN_ERR_MWAVE
0681                     "mwavedd:mwave_init: Error:"
0682                     " Failed to create sysfs file %s\n",
0683                     mwave_dev_attrs[i]->attr.name);
0684             goto cleanup_error;
0685         }
0686         pDrvData->nr_registered_attrs++;
0687     }
0688 #endif
0689 
0690     /* SUCCESS! */
0691     return 0;
0692 
0693 cleanup_error:
0694     PRINTK_ERROR(KERN_ERR_MWAVE
0695             "mwavedd::mwave_init: Error:"
0696             " Failed to initialize\n");
0697     mwave_exit(); /* clean up */
0698 
0699     return -EIO;
0700 }
0701 
0702 module_init(mwave_init);
0703