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,
  79                                         bool isr)
  80{
  81        unsigned long flags = 0;
  82        struct crystalhd_ioctl_data *temp;
  83
  84        if (!adp)
  85                return NULL;
  86
  87        spin_lock_irqsave(&adp->lock, flags);
  88
  89        temp = adp->idata_free_head;
  90        if (temp) {
  91                adp->idata_free_head = adp->idata_free_head->next;
  92                memset(temp, 0, sizeof(*temp));
  93        }
  94
  95        spin_unlock_irqrestore(&adp->lock, flags);
  96        return temp;
  97}
  98
  99void chd_dec_free_iodata(struct crystalhd_adp *adp,
 100                         struct crystalhd_ioctl_data *iodata, bool isr)
 101{
 102        unsigned long flags = 0;
 103
 104        if (!adp || !iodata)
 105                return;
 106
 107        spin_lock_irqsave(&adp->lock, flags);
 108        iodata->next = adp->idata_free_head;
 109        adp->idata_free_head = iodata;
 110        spin_unlock_irqrestore(&adp->lock, flags);
 111}
 112
 113static inline int crystalhd_user_data(unsigned long ud, void *dr,
 114                         int size, int set)
 115{
 116        int rc;
 117
 118        if (!ud || !dr) {
 119                BCMLOG_ERR("Invalid arg\n");
 120                return -EINVAL;
 121        }
 122
 123        if (set)
 124                rc = copy_to_user((void *)ud, dr, size);
 125        else
 126                rc = copy_from_user(dr, (void *)ud, size);
 127
 128        if (rc) {
 129                BCMLOG_ERR("Invalid args for command\n");
 130                rc = -EFAULT;
 131        }
 132
 133        return rc;
 134}
 135
 136static int chd_dec_fetch_cdata(struct crystalhd_adp *adp,
 137         struct crystalhd_ioctl_data *io, uint32_t m_sz, unsigned long ua)
 138{
 139        unsigned long ua_off;
 140        int rc = 0;
 141
 142        if (!adp || !io || !ua || !m_sz) {
 143                BCMLOG_ERR("Invalid Arg!!\n");
 144                return -EINVAL;
 145        }
 146
 147        io->add_cdata = vmalloc(m_sz);
 148        if (!io->add_cdata) {
 149                BCMLOG_ERR("kalloc fail for sz:%x\n", m_sz);
 150                return -ENOMEM;
 151        }
 152
 153        io->add_cdata_sz = m_sz;
 154        ua_off = ua + sizeof(io->udata);
 155        rc = crystalhd_user_data(ua_off, io->add_cdata, io->add_cdata_sz, 0);
 156        if (rc) {
 157                BCMLOG_ERR("failed to pull add_cdata sz:%x ua_off:%x\n",
 158                           io->add_cdata_sz, (unsigned int)ua_off);
 159                kfree(io->add_cdata);
 160                io->add_cdata = NULL;
 161                return -ENODATA;
 162        }
 163
 164        return rc;
 165}
 166
 167static int chd_dec_release_cdata(struct crystalhd_adp *adp,
 168                         struct crystalhd_ioctl_data *io, unsigned long ua)
 169{
 170        unsigned long ua_off;
 171        int rc;
 172
 173        if (!adp || !io || !ua) {
 174                BCMLOG_ERR("Invalid Arg!!\n");
 175                return -EINVAL;
 176        }
 177
 178        if (io->cmd != BCM_IOC_FW_DOWNLOAD) {
 179                ua_off = ua + sizeof(io->udata);
 180                rc = crystalhd_user_data(ua_off, io->add_cdata,
 181                                        io->add_cdata_sz, 1);
 182                if (rc) {
 183                        BCMLOG_ERR(
 184                                "failed to push add_cdata sz:%x ua_off:%x\n",
 185                                 io->add_cdata_sz, (unsigned int)ua_off);
 186                        return -ENODATA;
 187                }
 188        }
 189
 190        if (io->add_cdata) {
 191                vfree(io->add_cdata);
 192                io->add_cdata = NULL;
 193        }
 194
 195        return 0;
 196}
 197
 198static int chd_dec_proc_user_data(struct crystalhd_adp *adp,
 199                                  struct crystalhd_ioctl_data *io,
 200                                  unsigned long ua, int set)
 201{
 202        int rc;
 203        uint32_t m_sz = 0;
 204
 205        if (!adp || !io || !ua) {
 206                BCMLOG_ERR("Invalid Arg!!\n");
 207                return -EINVAL;
 208        }
 209
 210        rc = crystalhd_user_data(ua, &io->udata, sizeof(io->udata), set);
 211        if (rc) {
 212                BCMLOG_ERR("failed to %s iodata\n", (set ? "set" : "get"));
 213                return rc;
 214        }
 215
 216        switch (io->cmd) {
 217        case BCM_IOC_MEM_RD:
 218        case BCM_IOC_MEM_WR:
 219        case BCM_IOC_FW_DOWNLOAD:
 220                m_sz = io->udata.u.devMem.NumDwords * 4;
 221                if (set)
 222                        rc = chd_dec_release_cdata(adp, io, ua);
 223                else
 224                        rc = chd_dec_fetch_cdata(adp, io, m_sz, ua);
 225                break;
 226        default:
 227                break;
 228        }
 229
 230        return rc;
 231}
 232
 233static int chd_dec_api_cmd(struct crystalhd_adp *adp, unsigned long ua,
 234                           uint32_t uid, uint32_t cmd, crystalhd_cmd_proc func)
 235{
 236        int rc;
 237        struct crystalhd_ioctl_data *temp;
 238        enum BC_STATUS sts = BC_STS_SUCCESS;
 239
 240        temp = chd_dec_alloc_iodata(adp, 0);
 241        if (!temp) {
 242                BCMLOG_ERR("Failed to get iodata..\n");
 243                return -EINVAL;
 244        }
 245
 246        temp->u_id = uid;
 247        temp->cmd  = cmd;
 248
 249        rc = chd_dec_proc_user_data(adp, temp, ua, 0);
 250        if (!rc) {
 251                sts = func(&adp->cmds, temp);
 252                if (sts == BC_STS_PENDING)
 253                        sts = BC_STS_NOT_IMPL;
 254                temp->udata.RetSts = sts;
 255                rc = chd_dec_proc_user_data(adp, temp, ua, 1);
 256        }
 257
 258        chd_dec_free_iodata(adp, temp, 0);
 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 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                rc = PTR_ERR(crystalhd_class);
 377                BCMLOG_ERR("failed to create class\n");
 378                goto class_create_fail;
 379        }
 380
 381        dev = device_create(crystalhd_class, NULL,
 382                         MKDEV(adp->chd_dec_major, 0), NULL, "crystalhd");
 383        if (IS_ERR(dev)) {
 384                rc = PTR_ERR(dev);
 385                BCMLOG_ERR("failed to create device\n");
 386                goto device_create_fail;
 387        }
 388
 389        rc = crystalhd_create_elem_pool(adp, BC_LINK_ELEM_POOL_SZ);
 390        if (rc) {
 391                BCMLOG_ERR("failed to create device\n");
 392                goto elem_pool_fail;
 393        }
 394
 395        /* Allocate general purpose ioctl pool. */
 396        for (i = 0; i < CHD_IODATA_POOL_SZ; i++) {
 397                temp = kzalloc(sizeof(struct crystalhd_ioctl_data),
 398                                         GFP_KERNEL);
 399                if (!temp) {
 400                        BCMLOG_ERR("ioctl data pool kzalloc failed\n");
 401                        rc = -ENOMEM;
 402                        goto kzalloc_fail;
 403                }
 404                /* Add to global pool.. */
 405                chd_dec_free_iodata(adp, temp, 0);
 406        }
 407
 408        return 0;
 409
 410kzalloc_fail:
 411        crystalhd_delete_elem_pool(adp);
 412elem_pool_fail:
 413        device_destroy(crystalhd_class, MKDEV(adp->chd_dec_major, 0));
 414device_create_fail:
 415        class_destroy(crystalhd_class);
 416class_create_fail:
 417        unregister_chrdev(adp->chd_dec_major, CRYSTALHD_API_NAME);
 418fail:
 419        return rc;
 420}
 421
 422static void chd_dec_release_chdev(struct crystalhd_adp *adp)
 423{
 424        struct crystalhd_ioctl_data *temp = NULL;
 425        if (!adp)
 426                return;
 427
 428        if (adp->chd_dec_major > 0) {
 429                /* unregister crystalhd class */
 430                device_destroy(crystalhd_class, MKDEV(adp->chd_dec_major, 0));
 431                unregister_chrdev(adp->chd_dec_major, CRYSTALHD_API_NAME);
 432                BCMLOG(BCMLOG_INFO, "released api device - %d\n",
 433                       adp->chd_dec_major);
 434                class_destroy(crystalhd_class);
 435        }
 436        adp->chd_dec_major = 0;
 437
 438        /* Clear iodata pool.. */
 439        do {
 440                temp = chd_dec_alloc_iodata(adp, 0);
 441                kfree(temp);
 442        } while (temp);
 443
 444        crystalhd_delete_elem_pool(adp);
 445}
 446
 447static int chd_pci_reserve_mem(struct crystalhd_adp *pinfo)
 448{
 449        int rc;
 450        unsigned long bar2 = pci_resource_start(pinfo->pdev, 2);
 451        uint32_t mem_len   = pci_resource_len(pinfo->pdev, 2);
 452        unsigned long bar0 = pci_resource_start(pinfo->pdev, 0);
 453        uint32_t i2o_len   = pci_resource_len(pinfo->pdev, 0);
 454
 455        BCMLOG(BCMLOG_SSTEP, "bar2:0x%lx-0x%08x  bar0:0x%lx-0x%08x\n",
 456               bar2, mem_len, bar0, i2o_len);
 457
 458        rc = check_mem_region(bar2, mem_len);
 459        if (rc) {
 460                BCMLOG_ERR("No valid mem region...\n");
 461                return -ENOMEM;
 462        }
 463
 464        pinfo->addr = ioremap_nocache(bar2, mem_len);
 465        if (!pinfo->addr) {
 466                BCMLOG_ERR("Failed to remap mem region...\n");
 467                return -ENOMEM;
 468        }
 469
 470        pinfo->pci_mem_start = bar2;
 471        pinfo->pci_mem_len   = mem_len;
 472
 473        rc = check_mem_region(bar0, i2o_len);
 474        if (rc) {
 475                BCMLOG_ERR("No valid mem region...\n");
 476                return -ENOMEM;
 477        }
 478
 479        pinfo->i2o_addr = ioremap_nocache(bar0, i2o_len);
 480        if (!pinfo->i2o_addr) {
 481                BCMLOG_ERR("Failed to remap mem region...\n");
 482                return -ENOMEM;
 483        }
 484
 485        pinfo->pci_i2o_start = bar0;
 486        pinfo->pci_i2o_len   = i2o_len;
 487
 488        rc = pci_request_regions(pinfo->pdev, pinfo->name);
 489        if (rc < 0) {
 490                BCMLOG_ERR("Region request failed: %d\n", rc);
 491                return rc;
 492        }
 493
 494        BCMLOG(BCMLOG_SSTEP, "Mapped addr:0x%08lx  i2o_addr:0x%08lx\n",
 495               (unsigned long)pinfo->addr, (unsigned long)pinfo->i2o_addr);
 496
 497        return 0;
 498}
 499
 500static void chd_pci_release_mem(struct crystalhd_adp *pinfo)
 501{
 502        if (!pinfo)
 503                return;
 504
 505        if (pinfo->addr)
 506                iounmap(pinfo->addr);
 507
 508        if (pinfo->i2o_addr)
 509                iounmap(pinfo->i2o_addr);
 510
 511        pci_release_regions(pinfo->pdev);
 512}
 513
 514
 515static void chd_dec_pci_remove(struct pci_dev *pdev)
 516{
 517        struct crystalhd_adp *pinfo;
 518        enum BC_STATUS sts = BC_STS_SUCCESS;
 519
 520        pinfo = pci_get_drvdata(pdev);
 521        if (!pinfo) {
 522                BCMLOG_ERR("could not get adp\n");
 523                return;
 524        }
 525
 526        sts = crystalhd_delete_cmd_context(&pinfo->cmds);
 527        if (sts != BC_STS_SUCCESS)
 528                BCMLOG_ERR("cmd delete :%d\n", sts);
 529
 530        chd_dec_release_chdev(pinfo);
 531
 532        chd_dec_disable_int(pinfo);
 533
 534        chd_pci_release_mem(pinfo);
 535        pci_disable_device(pinfo->pdev);
 536
 537        kfree(pinfo);
 538        g_adp_info = NULL;
 539}
 540
 541static int chd_dec_pci_probe(struct pci_dev *pdev,
 542                             const struct pci_device_id *entry)
 543{
 544        struct crystalhd_adp *pinfo;
 545        int rc;
 546        enum BC_STATUS sts = BC_STS_SUCCESS;
 547
 548        BCMLOG(BCMLOG_DBG, "PCI_INFO: Vendor:0x%04x Device:0x%04x s_vendor:0x%04x s_device: 0x%04x\n",
 549               pdev->vendor, pdev->device, pdev->subsystem_vendor,
 550               pdev->subsystem_device);
 551
 552        pinfo = kzalloc(sizeof(struct crystalhd_adp), GFP_KERNEL);
 553        if (!pinfo) {
 554                BCMLOG_ERR("Failed to allocate memory\n");
 555                return -ENOMEM;
 556        }
 557
 558        pinfo->pdev = pdev;
 559
 560        rc = pci_enable_device(pdev);
 561        if (rc) {
 562                BCMLOG_ERR("Failed to enable PCI device\n");
 563                goto err;
 564        }
 565
 566        snprintf(pinfo->name, sizeof(pinfo->name), "crystalhd_pci_e:%d:%d:%d",
 567                 pdev->bus->number, PCI_SLOT(pdev->devfn),
 568                 PCI_FUNC(pdev->devfn));
 569
 570        rc = chd_pci_reserve_mem(pinfo);
 571        if (rc) {
 572                BCMLOG_ERR("Failed to setup memory regions.\n");
 573                pci_disable_device(pdev);
 574                rc = -ENOMEM;
 575                goto err;
 576        }
 577
 578        pinfo->present  = 1;
 579        pinfo->drv_data = entry->driver_data;
 580
 581        /* Setup adapter level lock.. */
 582        spin_lock_init(&pinfo->lock);
 583
 584        /* setup api stuff.. */
 585        chd_dec_init_chdev(pinfo);
 586        rc = chd_dec_enable_int(pinfo);
 587        if (rc) {
 588                BCMLOG_ERR("_enable_int err:%d\n", rc);
 589                pci_disable_device(pdev);
 590                rc = -ENODEV;
 591                goto err;
 592        }
 593
 594        /* Set dma mask... */
 595        if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
 596                pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
 597                pinfo->dmabits = 64;
 598        } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
 599                pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
 600                pinfo->dmabits = 32;
 601        } else {
 602                BCMLOG_ERR("Unabled to setup DMA %d\n", rc);
 603                pci_disable_device(pdev);
 604                rc = -ENODEV;
 605                goto err;
 606        }
 607
 608        sts = crystalhd_setup_cmd_context(&pinfo->cmds, pinfo);
 609        if (sts != BC_STS_SUCCESS) {
 610                BCMLOG_ERR("cmd setup :%d\n", sts);
 611                pci_disable_device(pdev);
 612                rc = -ENODEV;
 613                goto err;
 614        }
 615
 616        pci_set_master(pdev);
 617
 618        pci_set_drvdata(pdev, pinfo);
 619
 620        g_adp_info = pinfo;
 621
 622        return 0;
 623
 624err:
 625        kfree(pinfo);
 626        return rc;
 627}
 628
 629#ifdef CONFIG_PM
 630int chd_dec_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 631{
 632        struct crystalhd_adp *adp;
 633        struct crystalhd_ioctl_data *temp;
 634        enum BC_STATUS sts = BC_STS_SUCCESS;
 635
 636        adp = pci_get_drvdata(pdev);
 637        if (!adp) {
 638                BCMLOG_ERR("could not get adp\n");
 639                return -ENODEV;
 640        }
 641
 642        temp = chd_dec_alloc_iodata(adp, false);
 643        if (!temp) {
 644                BCMLOG_ERR("could not get ioctl data\n");
 645                return -ENODEV;
 646        }
 647
 648        sts = crystalhd_suspend(&adp->cmds, temp);
 649        if (sts != BC_STS_SUCCESS) {
 650                BCMLOG_ERR("BCM70012 Suspend %d\n", sts);
 651                return -ENODEV;
 652        }
 653
 654        chd_dec_free_iodata(adp, temp, false);
 655        chd_dec_disable_int(adp);
 656        pci_save_state(pdev);
 657
 658        /* Disable IO/bus master/irq router */
 659        pci_disable_device(pdev);
 660        pci_set_power_state(pdev, pci_choose_state(pdev, state));
 661        return 0;
 662}
 663
 664int chd_dec_pci_resume(struct pci_dev *pdev)
 665{
 666        struct crystalhd_adp *adp;
 667        enum BC_STATUS sts = BC_STS_SUCCESS;
 668        int rc;
 669
 670        adp = pci_get_drvdata(pdev);
 671        if (!adp) {
 672                BCMLOG_ERR("could not get adp\n");
 673                return -ENODEV;
 674        }
 675
 676        pci_set_power_state(pdev, PCI_D0);
 677        pci_restore_state(pdev);
 678
 679        /* device's irq possibly is changed, driver should take care */
 680        if (pci_enable_device(pdev)) {
 681                BCMLOG_ERR("Failed to enable PCI device\n");
 682                return 1;
 683        }
 684
 685        pci_set_master(pdev);
 686
 687        rc = chd_dec_enable_int(adp);
 688        if (rc) {
 689                BCMLOG_ERR("_enable_int err:%d\n", rc);
 690                pci_disable_device(pdev);
 691                return -ENODEV;
 692        }
 693
 694        sts = crystalhd_resume(&adp->cmds);
 695        if (sts != BC_STS_SUCCESS) {
 696                BCMLOG_ERR("BCM70012 Resume %d\n", sts);
 697                pci_disable_device(pdev);
 698                return -ENODEV;
 699        }
 700
 701        return 0;
 702}
 703#endif
 704
 705static DEFINE_PCI_DEVICE_TABLE(chd_dec_pci_id_table) = {
 706        { PCI_VDEVICE(BROADCOM, 0x1612), 8 },
 707        { 0, },
 708};
 709MODULE_DEVICE_TABLE(pci, chd_dec_pci_id_table);
 710
 711static struct pci_driver bc_chd_70012_driver = {
 712        .name     = "Broadcom 70012 Decoder",
 713        .probe    = chd_dec_pci_probe,
 714        .remove   = chd_dec_pci_remove,
 715        .id_table = chd_dec_pci_id_table,
 716#ifdef CONFIG_PM
 717        .suspend  = chd_dec_pci_suspend,
 718        .resume   = chd_dec_pci_resume
 719#endif
 720};
 721
 722void chd_set_log_level(struct crystalhd_adp *adp, char *arg)
 723{
 724        if ((!arg) || (strlen(arg) < 3))
 725                g_linklog_level = BCMLOG_ERROR | BCMLOG_DATA;
 726        else if (!strncmp(arg, "sstep", 5))
 727                g_linklog_level = BCMLOG_INFO | BCMLOG_DATA | BCMLOG_DBG |
 728                                  BCMLOG_SSTEP | BCMLOG_ERROR;
 729        else if (!strncmp(arg, "info", 4))
 730                g_linklog_level = BCMLOG_ERROR | BCMLOG_DATA | BCMLOG_INFO;
 731        else if (!strncmp(arg, "debug", 5))
 732                g_linklog_level = BCMLOG_ERROR | BCMLOG_DATA | BCMLOG_INFO |
 733                                  BCMLOG_DBG;
 734        else if (!strncmp(arg, "pball", 5))
 735                g_linklog_level = 0xFFFFFFFF & ~(BCMLOG_SPINLOCK);
 736        else if (!strncmp(arg, "silent", 6))
 737                g_linklog_level = 0;
 738        else
 739                g_linklog_level = 0;
 740}
 741
 742struct crystalhd_adp *chd_get_adp(void)
 743{
 744        return g_adp_info;
 745}
 746
 747static int __init chd_dec_module_init(void)
 748{
 749        int rc;
 750
 751        chd_set_log_level(NULL, "debug");
 752        BCMLOG(BCMLOG_DATA, "Loading crystalhd %d.%d.%d\n",
 753               crystalhd_kmod_major, crystalhd_kmod_minor, crystalhd_kmod_rev);
 754
 755        rc = pci_register_driver(&bc_chd_70012_driver);
 756
 757        if (rc < 0)
 758                BCMLOG_ERR("Could not find any devices. err:%d\n", rc);
 759
 760        return rc;
 761}
 762module_init(chd_dec_module_init);
 763
 764static void __exit chd_dec_module_cleanup(void)
 765{
 766        BCMLOG(BCMLOG_DATA, "unloading crystalhd %d.%d.%d\n",
 767               crystalhd_kmod_major, crystalhd_kmod_minor, crystalhd_kmod_rev);
 768
 769        pci_unregister_driver(&bc_chd_70012_driver);
 770}
 771module_exit(chd_dec_module_cleanup);
 772
 773MODULE_AUTHOR("Naren Sankar <nsankar@broadcom.com>");
 774MODULE_AUTHOR("Prasad Bolisetty <prasadb@broadcom.com>");
 775MODULE_DESCRIPTION(CRYSTAL_HD_NAME);
 776MODULE_LICENSE("GPL");
 777MODULE_ALIAS("bcm70012");
 778