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