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/smp_lock.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*/
  76int mwave_debug = 0;
  77int mwave_3780i_irq = 0;
  78int mwave_3780i_io = 0;
  79int mwave_uart_irq = 0;
  80int mwave_uart_io = 0;
  81module_param(mwave_debug, int, 0);
  82module_param(mwave_3780i_irq, int, 0);
  83module_param(mwave_3780i_io, int, 0);
  84module_param(mwave_uart_irq, int, 0);
  85module_param(mwave_uart_io, int, 0);
  86
  87static int mwave_open(struct inode *inode, struct file *file);
  88static int mwave_close(struct inode *inode, struct file *file);
  89static long mwave_ioctl(struct file *filp, unsigned int iocmd,
  90                                                        unsigned long ioarg);
  91
  92MWAVE_DEVICE_DATA mwave_s_mdd;
  93
  94static int mwave_open(struct inode *inode, struct file *file)
  95{
  96        unsigned int retval = 0;
  97
  98        PRINTK_3(TRACE_MWAVE,
  99                "mwavedd::mwave_open, entry inode %p file %p\n",
 100                 inode, file);
 101        PRINTK_2(TRACE_MWAVE,
 102                "mwavedd::mwave_open, exit return retval %x\n", retval);
 103
 104        cycle_kernel_lock();
 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                        lock_kernel();
 140                        retval = tp3780I_ResetDSP(&pDrvData->rBDData);
 141                        unlock_kernel();
 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                        lock_kernel();
 153                        retval = tp3780I_StartDSP(&pDrvData->rBDData);
 154                        unlock_kernel();
 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                        lock_kernel();
 169                        retval = tp3780I_QueryAbilities(&pDrvData->rBDData,
 170                                        &rAbilities);
 171                        unlock_kernel();
 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                        lock_kernel();
 203                        retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData,
 204                                        iocmd,
 205                                        pusBuffer,
 206                                        rReadData.ulDataLength,
 207                                        rReadData.usDspAddress);
 208                        unlock_kernel();
 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                        lock_kernel();
 227                        retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData,
 228                                iocmd, pusBuffer,
 229                                rReadData.ulDataLength / 2,
 230                                rReadData.usDspAddress);
 231                        unlock_kernel();
 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                        lock_kernel();
 250                        retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData,
 251                                        iocmd, pusBuffer,
 252                                        rWriteData.ulDataLength,
 253                                        rWriteData.usDspAddress);
 254                        unlock_kernel();
 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                        lock_kernel();
 273                        retval = tp3780I_ReadWriteDspIStore(&pDrvData->rBDData,
 274                                        iocmd, pusBuffer,
 275                                        rWriteData.ulDataLength,
 276                                        rWriteData.usDspAddress);
 277                        unlock_kernel();
 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                        lock_kernel();
 299                        pDrvData->IPCs[ipcnum].bIsHere = FALSE;
 300                        pDrvData->IPCs[ipcnum].bIsEnabled = TRUE;
 301                        unlock_kernel();
 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                        lock_kernel();
 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                        unlock_kernel();
 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                        lock_kernel();
 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                        unlock_kernel();
 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_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(struct uart_port));
 466        
 467        uart.uartclk =  1843200;
 468        uart.iobase = port;
 469        uart.irq = irq;
 470        uart.iotype = UPIO_PORT;
 471        uart.flags =  UPF_SHARE_IRQ;
 472        return serial8250_register_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};
 484
 485
 486static struct miscdevice mwave_misc_dev = { MWAVE_MINOR, "mwave", &mwave_fops };
 487
 488#if 0 /* totally b0rked */
 489/*
 490 * sysfs support <paulsch@us.ibm.com>
 491 */
 492
 493struct device mwave_device;
 494
 495/* Prevent code redundancy, create a macro for mwave_show_* functions. */
 496#define mwave_show_function(attr_name, format_string, field)            \
 497static ssize_t mwave_show_##attr_name(struct device *dev, struct device_attribute *attr, char *buf)     \
 498{                                                                       \
 499        DSP_3780I_CONFIG_SETTINGS *pSettings =                          \
 500                &mwave_s_mdd.rBDData.rDspSettings;                      \
 501        return sprintf(buf, format_string, pSettings->field);           \
 502}
 503
 504/* All of our attributes are read attributes. */
 505#define mwave_dev_rd_attr(attr_name, format_string, field)              \
 506        mwave_show_function(attr_name, format_string, field)            \
 507static DEVICE_ATTR(attr_name, S_IRUGO, mwave_show_##attr_name, NULL)
 508
 509mwave_dev_rd_attr (3780i_dma, "%i\n", usDspDma);
 510mwave_dev_rd_attr (3780i_irq, "%i\n", usDspIrq);
 511mwave_dev_rd_attr (3780i_io, "%#.4x\n", usDspBaseIO);
 512mwave_dev_rd_attr (uart_irq, "%i\n", usUartIrq);
 513mwave_dev_rd_attr (uart_io, "%#.4x\n", usUartBaseIO);
 514
 515static struct device_attribute * const mwave_dev_attrs[] = {
 516        &dev_attr_3780i_dma,
 517        &dev_attr_3780i_irq,
 518        &dev_attr_3780i_io,
 519        &dev_attr_uart_irq,
 520        &dev_attr_uart_io,
 521};
 522#endif
 523
 524/*
 525* mwave_init is called on module load
 526*
 527* mwave_exit is called on module unload
 528* mwave_exit is also used to clean up after an aborted mwave_init
 529*/
 530static void mwave_exit(void)
 531{
 532        pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;
 533
 534        PRINTK_1(TRACE_MWAVE, "mwavedd::mwave_exit entry\n");
 535
 536#if 0
 537        for (i = 0; i < pDrvData->nr_registered_attrs; i++)
 538                device_remove_file(&mwave_device, mwave_dev_attrs[i]);
 539        pDrvData->nr_registered_attrs = 0;
 540
 541        if (pDrvData->device_registered) {
 542                device_unregister(&mwave_device);
 543                pDrvData->device_registered = FALSE;
 544        }
 545#endif
 546
 547        if ( pDrvData->sLine >= 0 ) {
 548                serial8250_unregister_port(pDrvData->sLine);
 549        }
 550        if (pDrvData->bMwaveDevRegistered) {
 551                misc_deregister(&mwave_misc_dev);
 552        }
 553        if (pDrvData->bDSPEnabled) {
 554                tp3780I_DisableDSP(&pDrvData->rBDData);
 555        }
 556        if (pDrvData->bResourcesClaimed) {
 557                tp3780I_ReleaseResources(&pDrvData->rBDData);
 558        }
 559        if (pDrvData->bBDInitialized) {
 560                tp3780I_Cleanup(&pDrvData->rBDData);
 561        }
 562
 563        PRINTK_1(TRACE_MWAVE, "mwavedd::mwave_exit exit\n");
 564}
 565
 566module_exit(mwave_exit);
 567
 568static int __init mwave_init(void)
 569{
 570        int i;
 571        int retval = 0;
 572        pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;
 573
 574        PRINTK_1(TRACE_MWAVE, "mwavedd::mwave_init entry\n");
 575
 576        memset(&mwave_s_mdd, 0, sizeof(MWAVE_DEVICE_DATA));
 577
 578        pDrvData->bBDInitialized = FALSE;
 579        pDrvData->bResourcesClaimed = FALSE;
 580        pDrvData->bDSPEnabled = FALSE;
 581        pDrvData->bDSPReset = FALSE;
 582        pDrvData->bMwaveDevRegistered = FALSE;
 583        pDrvData->sLine = -1;
 584
 585        for (i = 0; i < ARRAY_SIZE(pDrvData->IPCs); i++) {
 586                pDrvData->IPCs[i].bIsEnabled = FALSE;
 587                pDrvData->IPCs[i].bIsHere = FALSE;
 588                pDrvData->IPCs[i].usIntCount = 0;       /* no ints received yet */
 589                init_waitqueue_head(&pDrvData->IPCs[i].ipc_wait_queue);
 590        }
 591
 592        retval = tp3780I_InitializeBoardData(&pDrvData->rBDData);
 593        PRINTK_2(TRACE_MWAVE,
 594                "mwavedd::mwave_init, return from tp3780I_InitializeBoardData"
 595                " retval %x\n",
 596                retval);
 597        if (retval) {
 598                PRINTK_ERROR(KERN_ERR_MWAVE
 599                                "mwavedd::mwave_init: Error:"
 600                                " Failed to initialize board data\n");
 601                goto cleanup_error;
 602        }
 603        pDrvData->bBDInitialized = TRUE;
 604
 605        retval = tp3780I_CalcResources(&pDrvData->rBDData);
 606        PRINTK_2(TRACE_MWAVE,
 607                "mwavedd::mwave_init, return from tp3780I_CalcResources"
 608                " retval %x\n",
 609                retval);
 610        if (retval) {
 611                PRINTK_ERROR(KERN_ERR_MWAVE
 612                                "mwavedd:mwave_init: Error:"
 613                                " Failed to calculate resources\n");
 614                goto cleanup_error;
 615        }
 616
 617        retval = tp3780I_ClaimResources(&pDrvData->rBDData);
 618        PRINTK_2(TRACE_MWAVE,
 619                "mwavedd::mwave_init, return from tp3780I_ClaimResources"
 620                " retval %x\n",
 621                retval);
 622        if (retval) {
 623                PRINTK_ERROR(KERN_ERR_MWAVE
 624                                "mwavedd:mwave_init: Error:"
 625                                " Failed to claim resources\n");
 626                goto cleanup_error;
 627        }
 628        pDrvData->bResourcesClaimed = TRUE;
 629
 630        retval = tp3780I_EnableDSP(&pDrvData->rBDData);
 631        PRINTK_2(TRACE_MWAVE,
 632                "mwavedd::mwave_init, return from tp3780I_EnableDSP"
 633                " retval %x\n",
 634                retval);
 635        if (retval) {
 636                PRINTK_ERROR(KERN_ERR_MWAVE
 637                                "mwavedd:mwave_init: Error:"
 638                                " Failed to enable DSP\n");
 639                goto cleanup_error;
 640        }
 641        pDrvData->bDSPEnabled = TRUE;
 642
 643        if (misc_register(&mwave_misc_dev) < 0) {
 644                PRINTK_ERROR(KERN_ERR_MWAVE
 645                                "mwavedd:mwave_init: Error:"
 646                                " Failed to register misc device\n");
 647                goto cleanup_error;
 648        }
 649        pDrvData->bMwaveDevRegistered = TRUE;
 650
 651        pDrvData->sLine = register_serial_portandirq(
 652                pDrvData->rBDData.rDspSettings.usUartBaseIO,
 653                pDrvData->rBDData.rDspSettings.usUartIrq
 654        );
 655        if (pDrvData->sLine < 0) {
 656                PRINTK_ERROR(KERN_ERR_MWAVE
 657                                "mwavedd:mwave_init: Error:"
 658                                " Failed to register serial driver\n");
 659                goto cleanup_error;
 660        }
 661        /* uart is registered */
 662
 663#if 0
 664        /* sysfs */
 665        memset(&mwave_device, 0, sizeof (struct device));
 666        dev_set_name(&mwave_device, "mwave");
 667
 668        if (device_register(&mwave_device))
 669                goto cleanup_error;
 670        pDrvData->device_registered = TRUE;
 671        for (i = 0; i < ARRAY_SIZE(mwave_dev_attrs); i++) {
 672                if(device_create_file(&mwave_device, mwave_dev_attrs[i])) {
 673                        PRINTK_ERROR(KERN_ERR_MWAVE
 674                                        "mwavedd:mwave_init: Error:"
 675                                        " Failed to create sysfs file %s\n",
 676                                        mwave_dev_attrs[i]->attr.name);
 677                        goto cleanup_error;
 678                }
 679                pDrvData->nr_registered_attrs++;
 680        }
 681#endif
 682
 683        /* SUCCESS! */
 684        return 0;
 685
 686cleanup_error:
 687        PRINTK_ERROR(KERN_ERR_MWAVE
 688                        "mwavedd::mwave_init: Error:"
 689                        " Failed to initialize\n");
 690        mwave_exit(); /* clean up */
 691
 692        return -EIO;
 693}
 694
 695module_init(mwave_init);
 696
 697