linux/drivers/staging/crystalhd/crystalhd_lnx.c
<<
>>
Prefs
   1/***************************************************************************
   2  BCM70010 Linux driver
   3  Copyright (c) 2005-2009, Broadcom Corporation.
   4
   5  This driver is free software; you can redistribute it and/or modify
   6  it under the terms of the GNU General Public License as published by
   7  the Free Software Foundation, version 2 of the License.
   8
   9  This driver is distributed in the hope that it will be useful,
  10  but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  GNU General Public License for more details.
  13
  14  You should have received a copy of the GNU General Public License
  15  along with this driver.  If not, see <http://www.gnu.org/licenses/>.
  16***************************************************************************/
  17
  18#include "crystalhd.h"
  19
  20#include <linux/mutex.h>
  21#include <linux/slab.h>
  22
  23
  24static DEFINE_MUTEX(chd_dec_mutex);
  25static struct class *crystalhd_class;
  26
  27static struct crystalhd_adp *g_adp_info;
  28
  29static irqreturn_t chd_dec_isr(int irq, void *arg)
  30{
  31        struct crystalhd_adp *adp = (struct crystalhd_adp *) arg;
  32        int rc = 0;
  33        if (adp)
  34                rc = crystalhd_cmd_interrupt(&adp->cmds);
  35
  36        return IRQ_RETVAL(rc);
  37}
  38
  39static int chd_dec_enable_int(struct crystalhd_adp *adp)
  40{
  41        int rc = 0;
  42
  43        if (!adp || !adp->pdev) {
  44                BCMLOG_ERR("Invalid arg!!\n");
  45                return -EINVAL;
  46        }
  47
  48        if (adp->pdev->msi_enabled)
  49                adp->msi = 1;
  50        else
  51                adp->msi = pci_enable_msi(adp->pdev);
  52
  53        rc = request_irq(adp->pdev->irq, chd_dec_isr, IRQF_SHARED,
  54                         adp->name, (void *)adp);
  55        if (rc) {
  56                BCMLOG_ERR("Interrupt request failed..\n");
  57                pci_disable_msi(adp->pdev);
  58        }
  59
  60        return rc;
  61}
  62
  63static int chd_dec_disable_int(struct crystalhd_adp *adp)
  64{
  65        if (!adp || !adp->pdev) {
  66                BCMLOG_ERR("Invalid arg!!\n");
  67                return -EINVAL;
  68        }
  69
  70        free_irq(adp->pdev->irq, adp);
  71
  72        if (adp->msi)
  73                pci_disable_msi(adp->pdev);
  74
  75        return 0;
  76}
  77
  78struct crystalhd_ioctl_data *chd_dec_alloc_iodata(struct crystalhd_adp *adp, bool isr)
  79{
  80        unsigned long flags = 0;
  81        struct crystalhd_ioctl_data *temp;
  82
  83        if (!adp)
  84                return NULL;
  85
  86        spin_lock_irqsave(&adp->lock, flags);
  87
  88        temp = adp->idata_free_head;
  89        if (temp) {
  90                adp->idata_free_head = adp->idata_free_head->next;
  91                memset(temp, 0, sizeof(*temp));
  92        }
  93
  94        spin_unlock_irqrestore(&adp->lock, flags);
  95        return temp;
  96}
  97
  98void chd_dec_free_iodata(struct crystalhd_adp *adp, struct crystalhd_ioctl_data *iodata,
  99                         bool isr)
 100{
 101        unsigned long flags = 0;
 102
 103        if (!adp || !iodata)
 104                return;
 105
 106        spin_lock_irqsave(&adp->lock, flags);
 107        iodata->next = adp->idata_free_head;
 108        adp->idata_free_head = iodata;
 109        spin_unlock_irqrestore(&adp->lock, flags);
 110}
 111
 112static inline int crystalhd_user_data(unsigned long ud, void *dr, int size, int set)
 113{
 114        int rc;
 115
 116        if (!ud || !dr) {
 117                BCMLOG_ERR("Invalid arg\n");
 118                return -EINVAL;
 119        }
 120
 121        if (set)
 122                rc = copy_to_user((void *)ud, dr, size);
 123        else
 124                rc = copy_from_user(dr, (void *)ud, size);
 125
 126        if (rc) {
 127                BCMLOG_ERR("Invalid args for command\n");
 128                rc = -EFAULT;
 129        }
 130
 131        return rc;
 132}
 133
 134static int chd_dec_fetch_cdata(struct crystalhd_adp *adp, struct crystalhd_ioctl_data *io,
 135                               uint32_t m_sz, unsigned long ua)
 136{
 137        unsigned long ua_off;
 138        int rc = 0;
 139
 140        if (!adp || !io || !ua || !m_sz) {
 141                BCMLOG_ERR("Invalid Arg!!\n");
 142                return -EINVAL;
 143        }
 144
 145        io->add_cdata = vmalloc(m_sz);
 146        if (!io->add_cdata) {
 147                BCMLOG_ERR("kalloc fail for sz:%x\n", m_sz);
 148                return -ENOMEM;
 149        }
 150
 151        io->add_cdata_sz = m_sz;
 152        ua_off = ua + sizeof(io->udata);
 153        rc = crystalhd_user_data(ua_off, io->add_cdata, io->add_cdata_sz, 0);
 154        if (rc) {
 155                BCMLOG_ERR("failed to pull add_cdata sz:%x ua_off:%x\n",
 156                           io->add_cdata_sz, (unsigned int)ua_off);
 157                kfree(io->add_cdata);
 158                io->add_cdata = NULL;
 159                return -ENODATA;
 160        }
 161
 162        return rc;
 163}
 164
 165static int chd_dec_release_cdata(struct crystalhd_adp *adp,
 166                                 struct crystalhd_ioctl_data *io, unsigned long ua)
 167{
 168        unsigned long ua_off;
 169        int rc;
 170
 171        if (!adp || !io || !ua) {
 172                BCMLOG_ERR("Invalid Arg!!\n");
 173                return -EINVAL;
 174        }
 175
 176        if (io->cmd != BCM_IOC_FW_DOWNLOAD) {
 177                ua_off = ua + sizeof(io->udata);
 178                rc = crystalhd_user_data(ua_off, io->add_cdata,
 179                                        io->add_cdata_sz, 1);
 180                if (rc) {
 181                        BCMLOG_ERR("failed to push add_cdata sz:%x ua_off:%x\n",
 182                                   io->add_cdata_sz, (unsigned int)ua_off);
 183                        return -ENODATA;
 184                }
 185        }
 186
 187        if (io->add_cdata) {
 188                vfree(io->add_cdata);
 189                io->add_cdata = NULL;
 190        }
 191
 192        return 0;
 193}
 194
 195static int chd_dec_proc_user_data(struct crystalhd_adp *adp,
 196                                  struct crystalhd_ioctl_data *io,
 197                                  unsigned long ua, int set)
 198{
 199        int rc;
 200        uint32_t m_sz = 0;
 201
 202        if (!adp || !io || !ua) {
 203                BCMLOG_ERR("Invalid Arg!!\n");
 204                return -EINVAL;
 205        }
 206
 207        rc = crystalhd_user_data(ua, &io->udata, sizeof(io->udata), set);
 208        if (rc) {
 209                BCMLOG_ERR("failed to %s iodata\n", (set ? "set" : "get"));
 210                return rc;
 211        }
 212
 213        switch (io->cmd) {
 214        case BCM_IOC_MEM_RD:
 215        case BCM_IOC_MEM_WR:
 216        case BCM_IOC_FW_DOWNLOAD:
 217                m_sz = io->udata.u.devMem.NumDwords * 4;
 218                if (set)
 219                        rc = chd_dec_release_cdata(adp, io, ua);
 220                else
 221                        rc = chd_dec_fetch_cdata(adp, io, m_sz, ua);
 222                break;
 223        default:
 224                break;
 225        }
 226
 227        return rc;
 228}
 229
 230static int chd_dec_api_cmd(struct crystalhd_adp *adp, unsigned long ua,
 231                           uint32_t uid, uint32_t cmd, crystalhd_cmd_proc func)
 232{
 233        int rc;
 234        struct crystalhd_ioctl_data *temp;
 235        enum BC_STATUS sts = BC_STS_SUCCESS;
 236
 237        temp = chd_dec_alloc_iodata(adp, 0);
 238        if (!temp) {
 239                BCMLOG_ERR("Failed to get iodata..\n");
 240                return -EINVAL;
 241        }
 242
 243        temp->u_id = uid;
 244        temp->cmd  = cmd;
 245
 246        rc = chd_dec_proc_user_data(adp, temp, ua, 0);
 247        if (!rc) {
 248                sts = func(&adp->cmds, temp);
 249                if (sts == BC_STS_PENDING)
 250                        sts = BC_STS_NOT_IMPL;
 251                temp->udata.RetSts = sts;
 252                rc = chd_dec_proc_user_data(adp, temp, ua, 1);
 253        }
 254
 255        if (temp) {
 256                chd_dec_free_iodata(adp, temp, 0);
 257                temp = NULL;
 258        }
 259
 260        return rc;
 261}
 262
 263/* API interfaces */
 264static long chd_dec_ioctl(struct file *fd, unsigned int cmd, unsigned long ua)
 265{
 266        struct crystalhd_adp *adp = chd_get_adp();
 267        crystalhd_cmd_proc cproc;
 268        struct crystalhd_user *uc;
 269        int ret;
 270
 271        if (!adp || !fd) {
 272                BCMLOG_ERR("Invalid adp\n");
 273                return -EINVAL;
 274        }
 275
 276        uc = fd->private_data;
 277        if (!uc) {
 278                BCMLOG_ERR("Failed to get uc\n");
 279                return -ENODATA;
 280        }
 281
 282        mutex_lock(&chd_dec_mutex);
 283        cproc = crystalhd_get_cmd_proc(&adp->cmds, cmd, uc);
 284        if (!cproc) {
 285                BCMLOG_ERR("Unhandled command: %d\n", cmd);
 286                mutex_unlock(&chd_dec_mutex);
 287                return -EINVAL;
 288        }
 289
 290        ret = chd_dec_api_cmd(adp, ua, uc->uid, cmd, cproc);
 291        mutex_unlock(&chd_dec_mutex);
 292        return ret;
 293}
 294
 295static int chd_dec_open(struct inode *in, struct file *fd)
 296{
 297        struct crystalhd_adp *adp = chd_get_adp();
 298        int rc = 0;
 299        enum BC_STATUS sts = BC_STS_SUCCESS;
 300        struct crystalhd_user *uc = NULL;
 301
 302        if (!adp) {
 303                BCMLOG_ERR("Invalid adp\n");
 304                return -EINVAL;
 305        }
 306
 307        if (adp->cfg_users >= BC_LINK_MAX_OPENS) {
 308                BCMLOG(BCMLOG_INFO, "Already in use.%d\n", adp->cfg_users);
 309                return -EBUSY;
 310        }
 311
 312        sts = crystalhd_user_open(&adp->cmds, &uc);
 313        if (sts != BC_STS_SUCCESS) {
 314                BCMLOG_ERR("cmd_user_open - %d\n", sts);
 315                rc = -EBUSY;
 316        }
 317
 318        adp->cfg_users++;
 319
 320        fd->private_data = uc;
 321
 322        return rc;
 323}
 324
 325static int chd_dec_close(struct inode *in, struct file *fd)
 326{
 327        struct crystalhd_adp *adp = chd_get_adp();
 328        struct crystalhd_user *uc;
 329
 330        if (!adp) {
 331                BCMLOG_ERR("Invalid adp\n");
 332                return -EINVAL;
 333        }
 334
 335        uc = fd->private_data;
 336        if (!uc) {
 337                BCMLOG_ERR("Failed to get uc\n");
 338                return -ENODATA;
 339        }
 340
 341        crystalhd_user_close(&adp->cmds, uc);
 342
 343        adp->cfg_users--;
 344
 345        return 0;
 346}
 347
 348static const struct file_operations chd_dec_fops = {
 349        .owner   = THIS_MODULE,
 350        .unlocked_ioctl = chd_dec_ioctl,
 351        .open    = chd_dec_open,
 352        .release = chd_dec_close,
 353        .llseek = noop_llseek,
 354};
 355
 356static int __devinit chd_dec_init_chdev(struct crystalhd_adp *adp)
 357{
 358        struct crystalhd_ioctl_data *temp;
 359        struct device *dev;
 360        int rc = -ENODEV, i = 0;
 361
 362        if (!adp)
 363                goto fail;
 364
 365        adp->chd_dec_major = register_chrdev(0, CRYSTALHD_API_NAME,
 366                                             &chd_dec_fops);
 367        if (adp->chd_dec_major < 0) {
 368                BCMLOG_ERR("Failed to create config dev\n");
 369                rc = adp->chd_dec_major;
 370                goto fail;
 371        }
 372
 373        /* register crystalhd class */
 374        crystalhd_class = class_create(THIS_MODULE, "crystalhd");
 375        if (IS_ERR(crystalhd_class)) {
 376                BCMLOG_ERR("failed to create class\n");
 377                goto fail;
 378        }
 379
 380        dev = device_create(crystalhd_class, NULL, MKDEV(adp->chd_dec_major, 0),
 381                            NULL, "crystalhd");
 382        if (IS_ERR(dev)) {
 383                BCMLOG_ERR("failed to create device\n");
 384                goto device_create_fail;
 385        }
 386
 387        rc = crystalhd_create_elem_pool(adp, BC_LINK_ELEM_POOL_SZ);
 388        if (rc) {
 389                BCMLOG_ERR("failed to create device\n");
 390                goto elem_pool_fail;
 391        }
 392
 393        /* Allocate general purpose ioctl pool. */
 394        for (i = 0; i < CHD_IODATA_POOL_SZ; i++) {
 395                temp = kzalloc(sizeof(struct crystalhd_ioctl_data), GFP_KERNEL);
 396                if (!temp) {
 397                        BCMLOG_ERR("ioctl data pool kzalloc failed\n");
 398                        rc = -ENOMEM;
 399                        goto kzalloc_fail;
 400                }
 401                /* Add to global pool.. */
 402                chd_dec_free_iodata(adp, temp, 0);
 403        }
 404
 405        return 0;
 406
 407kzalloc_fail:
 408        crystalhd_delete_elem_pool(adp);
 409elem_pool_fail:
 410        device_destroy(crystalhd_class, MKDEV(adp->chd_dec_major, 0));
 411device_create_fail:
 412        class_destroy(crystalhd_class);
 413fail:
 414        return rc;
 415}
 416
 417static void __devexit chd_dec_release_chdev(struct crystalhd_adp *adp)
 418{
 419        struct crystalhd_ioctl_data *temp = NULL;
 420        if (!adp)
 421                return;
 422
 423        if (adp->chd_dec_major > 0) {
 424                /* unregister crystalhd class */
 425                device_destroy(crystalhd_class, MKDEV(adp->chd_dec_major, 0));
 426                unregister_chrdev(adp->chd_dec_major, CRYSTALHD_API_NAME);
 427                BCMLOG(BCMLOG_INFO, "released api device - %d\n",
 428                       adp->chd_dec_major);
 429                class_destroy(crystalhd_class);
 430        }
 431        adp->chd_dec_major = 0;
 432
 433        /* Clear iodata pool.. */
 434        do {
 435                temp = chd_dec_alloc_iodata(adp, 0);
 436                kfree(temp);
 437        } while (temp);
 438
 439        crystalhd_delete_elem_pool(adp);
 440}
 441
 442static int __devinit chd_pci_reserve_mem(struct crystalhd_adp *pinfo)
 443{
 444        int rc;
 445        unsigned long bar2 = pci_resource_start(pinfo->pdev, 2);
 446        uint32_t mem_len   = pci_resource_len(pinfo->pdev, 2);
 447        unsigned long bar0 = pci_resource_start(pinfo->pdev, 0);
 448        uint32_t i2o_len   = pci_resource_len(pinfo->pdev, 0);
 449
 450        BCMLOG(BCMLOG_SSTEP, "bar2:0x%lx-0x%08x  bar0:0x%lx-0x%08x\n",
 451               bar2, mem_len, bar0, i2o_len);
 452
 453        rc = check_mem_region(bar2, mem_len);
 454        if (rc) {
 455                BCMLOG_ERR("No valid mem region...\n");
 456                return -ENOMEM;
 457        }
 458
 459        pinfo->addr = ioremap_nocache(bar2, mem_len);
 460        if (!pinfo->addr) {
 461                BCMLOG_ERR("Failed to remap mem region...\n");
 462                return -ENOMEM;
 463        }
 464
 465        pinfo->pci_mem_start = bar2;
 466        pinfo->pci_mem_len   = mem_len;
 467
 468        rc = check_mem_region(bar0, i2o_len);
 469        if (rc) {
 470                BCMLOG_ERR("No valid mem region...\n");
 471                return -ENOMEM;
 472        }
 473
 474        pinfo->i2o_addr = ioremap_nocache(bar0, i2o_len);
 475        if (!pinfo->i2o_addr) {
 476                BCMLOG_ERR("Failed to remap mem region...\n");
 477                return -ENOMEM;
 478        }
 479
 480        pinfo->pci_i2o_start = bar0;
 481        pinfo->pci_i2o_len   = i2o_len;
 482
 483        rc = pci_request_regions(pinfo->pdev, pinfo->name);
 484        if (rc < 0) {
 485                BCMLOG_ERR("Region request failed: %d\n", rc);
 486                return rc;
 487        }
 488
 489        BCMLOG(BCMLOG_SSTEP, "Mapped addr:0x%08lx  i2o_addr:0x%08lx\n",
 490               (unsigned long)pinfo->addr, (unsigned long)pinfo->i2o_addr);
 491
 492        return 0;
 493}
 494
 495static void __devexit chd_pci_release_mem(struct crystalhd_adp *pinfo)
 496{
 497        if (!pinfo)
 498                return;
 499
 500        if (pinfo->addr)
 501                iounmap(pinfo->addr);
 502
 503        if (pinfo->i2o_addr)
 504                iounmap(pinfo->i2o_addr);
 505
 506        pci_release_regions(pinfo->pdev);
 507}
 508
 509
 510static void __devexit chd_dec_pci_remove(struct pci_dev *pdev)
 511{
 512        struct crystalhd_adp *pinfo;
 513        enum BC_STATUS sts = BC_STS_SUCCESS;
 514
 515        pinfo = pci_get_drvdata(pdev);
 516        if (!pinfo) {
 517                BCMLOG_ERR("could not get adp\n");
 518                return;
 519        }
 520
 521        sts = crystalhd_delete_cmd_context(&pinfo->cmds);
 522        if (sts != BC_STS_SUCCESS)
 523                BCMLOG_ERR("cmd delete :%d\n", sts);
 524
 525        chd_dec_release_chdev(pinfo);
 526
 527        chd_dec_disable_int(pinfo);
 528
 529        chd_pci_release_mem(pinfo);
 530        pci_disable_device(pinfo->pdev);
 531
 532        kfree(pinfo);
 533        g_adp_info = NULL;
 534}
 535
 536static int __devinit chd_dec_pci_probe(struct pci_dev *pdev,
 537                             const struct pci_device_id *entry)
 538{
 539        struct crystalhd_adp *pinfo;
 540        int rc;
 541        enum BC_STATUS sts = BC_STS_SUCCESS;
 542
 543        BCMLOG(BCMLOG_DBG, "PCI_INFO: Vendor:0x%04x Device:0x%04x "
 544               "s_vendor:0x%04x s_device: 0x%04x\n",
 545               pdev->vendor, pdev->device, pdev->subsystem_vendor,
 546               pdev->subsystem_device);
 547
 548        pinfo = kzalloc(sizeof(struct crystalhd_adp), GFP_KERNEL);
 549        if (!pinfo) {
 550                BCMLOG_ERR("Failed to allocate memory\n");
 551                return -ENOMEM;
 552        }
 553
 554        pinfo->pdev = pdev;
 555
 556        rc = pci_enable_device(pdev);
 557        if (rc) {
 558                BCMLOG_ERR("Failed to enable PCI device\n");
 559                goto err;
 560        }
 561
 562        snprintf(pinfo->name, sizeof(pinfo->name), "crystalhd_pci_e:%d:%d:%d",
 563                 pdev->bus->number, PCI_SLOT(pdev->devfn),
 564                 PCI_FUNC(pdev->devfn));
 565
 566        rc = chd_pci_reserve_mem(pinfo);
 567        if (rc) {
 568                BCMLOG_ERR("Failed to setup memory regions.\n");
 569                pci_disable_device(pdev);
 570                rc = -ENOMEM;
 571                goto err;
 572        }
 573
 574        pinfo->present  = 1;
 575        pinfo->drv_data = entry->driver_data;
 576
 577        /* Setup adapter level lock.. */
 578        spin_lock_init(&pinfo->lock);
 579
 580        /* setup api stuff.. */
 581        chd_dec_init_chdev(pinfo);
 582        rc = chd_dec_enable_int(pinfo);
 583        if (rc) {
 584                BCMLOG_ERR("_enable_int err:%d\n", rc);
 585                pci_disable_device(pdev);
 586                rc = -ENODEV;
 587                goto err;
 588        }
 589
 590        /* Set dma mask... */
 591        if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
 592                pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
 593                pinfo->dmabits = 64;
 594        } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
 595                pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
 596                pinfo->dmabits = 32;
 597        } else {
 598                BCMLOG_ERR("Unabled to setup DMA %d\n", rc);
 599                pci_disable_device(pdev);
 600                rc = -ENODEV;
 601                goto err;
 602        }
 603
 604        sts = crystalhd_setup_cmd_context(&pinfo->cmds, pinfo);
 605        if (sts != BC_STS_SUCCESS) {
 606                BCMLOG_ERR("cmd setup :%d\n", sts);
 607                pci_disable_device(pdev);
 608                rc = -ENODEV;
 609                goto err;
 610        }
 611
 612        pci_set_master(pdev);
 613
 614        pci_set_drvdata(pdev, pinfo);
 615
 616        g_adp_info = pinfo;
 617
 618        return 0;
 619
 620err:
 621        kfree(pinfo);
 622        return rc;
 623}
 624
 625#ifdef CONFIG_PM
 626int chd_dec_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 627{
 628        struct crystalhd_adp *adp;
 629        struct crystalhd_ioctl_data *temp;
 630        enum BC_STATUS sts = BC_STS_SUCCESS;
 631
 632        adp = pci_get_drvdata(pdev);
 633        if (!adp) {
 634                BCMLOG_ERR("could not get adp\n");
 635                return -ENODEV;
 636        }
 637
 638        temp = chd_dec_alloc_iodata(adp, false);
 639        if (!temp) {
 640                BCMLOG_ERR("could not get ioctl data\n");
 641                return -ENODEV;
 642        }
 643
 644        sts = crystalhd_suspend(&adp->cmds, temp);
 645        if (sts != BC_STS_SUCCESS) {
 646                BCMLOG_ERR("BCM70012 Suspend %d\n", sts);
 647                return -ENODEV;
 648        }
 649
 650        chd_dec_free_iodata(adp, temp, false);
 651        chd_dec_disable_int(adp);
 652        pci_save_state(pdev);
 653
 654        /* Disable IO/bus master/irq router */
 655        pci_disable_device(pdev);
 656        pci_set_power_state(pdev, pci_choose_state(pdev, state));
 657        return 0;
 658}
 659
 660int chd_dec_pci_resume(struct pci_dev *pdev)
 661{
 662        struct crystalhd_adp *adp;
 663        enum BC_STATUS sts = BC_STS_SUCCESS;
 664        int rc;
 665
 666        adp = pci_get_drvdata(pdev);
 667        if (!adp) {
 668                BCMLOG_ERR("could not get adp\n");
 669                return -ENODEV;
 670        }
 671
 672        pci_set_power_state(pdev, PCI_D0);
 673        pci_restore_state(pdev);
 674
 675        /* device's irq possibly is changed, driver should take care */
 676        if (pci_enable_device(pdev)) {
 677                BCMLOG_ERR("Failed to enable PCI device\n");
 678                return 1;
 679        }
 680
 681        pci_set_master(pdev);
 682
 683        rc = chd_dec_enable_int(adp);
 684        if (rc) {
 685                BCMLOG_ERR("_enable_int err:%d\n", rc);
 686                pci_disable_device(pdev);
 687                return -ENODEV;
 688        }
 689
 690        sts = crystalhd_resume(&adp->cmds);
 691        if (sts != BC_STS_SUCCESS) {
 692                BCMLOG_ERR("BCM70012 Resume %d\n", sts);
 693                pci_disable_device(pdev);
 694                return -ENODEV;
 695        }
 696
 697        return 0;
 698}
 699#endif
 700
 701static DEFINE_PCI_DEVICE_TABLE(chd_dec_pci_id_table) = {
 702        { PCI_VDEVICE(BROADCOM, 0x1612), 8 },
 703        { 0, },
 704};
 705MODULE_DEVICE_TABLE(pci, chd_dec_pci_id_table);
 706
 707static struct pci_driver bc_chd_70012_driver = {
 708        .name     = "Broadcom 70012 Decoder",
 709        .probe    = chd_dec_pci_probe,
 710        .remove   = __devexit_p(chd_dec_pci_remove),
 711        .id_table = chd_dec_pci_id_table,
 712#ifdef CONFIG_PM
 713        .suspend  = chd_dec_pci_suspend,
 714        .resume   = chd_dec_pci_resume
 715#endif
 716};
 717
 718void chd_set_log_level(struct crystalhd_adp *adp, char *arg)
 719{
 720        if ((!arg) || (strlen(arg) < 3))
 721                g_linklog_level = BCMLOG_ERROR | BCMLOG_DATA;
 722        else if (!strncmp(arg, "sstep", 5))
 723                g_linklog_level = BCMLOG_INFO | BCMLOG_DATA | BCMLOG_DBG |
 724                                  BCMLOG_SSTEP | BCMLOG_ERROR;
 725        else if (!strncmp(arg, "info", 4))
 726                g_linklog_level = BCMLOG_ERROR | BCMLOG_DATA | BCMLOG_INFO;
 727        else if (!strncmp(arg, "debug", 5))
 728                g_linklog_level = BCMLOG_ERROR | BCMLOG_DATA | BCMLOG_INFO |
 729                                  BCMLOG_DBG;
 730        else if (!strncmp(arg, "pball", 5))
 731                g_linklog_level = 0xFFFFFFFF & ~(BCMLOG_SPINLOCK);
 732        else if (!strncmp(arg, "silent", 6))
 733                g_linklog_level = 0;
 734        else
 735                g_linklog_level = 0;
 736}
 737
 738struct crystalhd_adp *chd_get_adp(void)
 739{
 740        return g_adp_info;
 741}
 742
 743static int __init chd_dec_module_init(void)
 744{
 745        int rc;
 746
 747        chd_set_log_level(NULL, "debug");
 748        BCMLOG(BCMLOG_DATA, "Loading crystalhd %d.%d.%d\n",
 749               crystalhd_kmod_major, crystalhd_kmod_minor, crystalhd_kmod_rev);
 750
 751        rc = pci_register_driver(&bc_chd_70012_driver);
 752
 753        if (rc < 0)
 754                BCMLOG_ERR("Could not find any devices. err:%d\n", rc);
 755
 756        return rc;
 757}
 758module_init(chd_dec_module_init);
 759
 760static void __exit chd_dec_module_cleanup(void)
 761{
 762        BCMLOG(BCMLOG_DATA, "unloading crystalhd %d.%d.%d\n",
 763               crystalhd_kmod_major, crystalhd_kmod_minor, crystalhd_kmod_rev);
 764
 765        pci_unregister_driver(&bc_chd_70012_driver);
 766}
 767module_exit(chd_dec_module_cleanup);
 768
 769MODULE_AUTHOR("Naren Sankar <nsankar@broadcom.com>");
 770MODULE_AUTHOR("Prasad Bolisetty <prasadb@broadcom.com>");
 771MODULE_DESCRIPTION(CRYSTAL_HD_NAME);
 772MODULE_LICENSE("GPL");
 773MODULE_ALIAS("bcm70012");
 774