Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
crystalhd_lnx.c
Go to the documentation of this file.
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 
24 static DEFINE_MUTEX(chd_dec_mutex);
25 static struct class *crystalhd_class;
26 
27 static struct crystalhd_adp *g_adp_info;
28 
29 static 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 
39 static 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 
63 static 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 
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 
98 void 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 
112 static 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 
134 static 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 
165 static 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 
195 static 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 
230 static int chd_dec_api_cmd(struct crystalhd_adp *adp, unsigned long ua,
232 {
233  int rc;
234  struct crystalhd_ioctl_data *temp;
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 */
264 static 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 
295 static 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 
325 static 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 
348 static 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 
356 static 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  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, MKDEV(adp->chd_dec_major, 0),
382  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 
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), GFP_KERNEL);
398  if (!temp) {
399  BCMLOG_ERR("ioctl data pool kzalloc failed\n");
400  rc = -ENOMEM;
401  goto kzalloc_fail;
402  }
403  /* Add to global pool.. */
404  chd_dec_free_iodata(adp, temp, 0);
405  }
406 
407  return 0;
408 
409 kzalloc_fail:
411 elem_pool_fail:
412  device_destroy(crystalhd_class, MKDEV(adp->chd_dec_major, 0));
413 device_create_fail:
414  class_destroy(crystalhd_class);
415 class_create_fail:
416  unregister_chrdev(adp->chd_dec_major, CRYSTALHD_API_NAME);
417 fail:
418  return rc;
419 }
420 
421 static void __devexit chd_dec_release_chdev(struct crystalhd_adp *adp)
422 {
423  struct crystalhd_ioctl_data *temp = NULL;
424  if (!adp)
425  return;
426 
427  if (adp->chd_dec_major > 0) {
428  /* unregister crystalhd class */
429  device_destroy(crystalhd_class, MKDEV(adp->chd_dec_major, 0));
430  unregister_chrdev(adp->chd_dec_major, CRYSTALHD_API_NAME);
431  BCMLOG(BCMLOG_INFO, "released api device - %d\n",
432  adp->chd_dec_major);
433  class_destroy(crystalhd_class);
434  }
435  adp->chd_dec_major = 0;
436 
437  /* Clear iodata pool.. */
438  do {
439  temp = chd_dec_alloc_iodata(adp, 0);
440  kfree(temp);
441  } while (temp);
442 
444 }
445 
446 static int __devinit chd_pci_reserve_mem(struct crystalhd_adp *pinfo)
447 {
448  int rc;
449  unsigned long bar2 = pci_resource_start(pinfo->pdev, 2);
450  uint32_t mem_len = pci_resource_len(pinfo->pdev, 2);
451  unsigned long bar0 = pci_resource_start(pinfo->pdev, 0);
452  uint32_t i2o_len = pci_resource_len(pinfo->pdev, 0);
453 
454  BCMLOG(BCMLOG_SSTEP, "bar2:0x%lx-0x%08x bar0:0x%lx-0x%08x\n",
455  bar2, mem_len, bar0, i2o_len);
456 
457  rc = check_mem_region(bar2, mem_len);
458  if (rc) {
459  BCMLOG_ERR("No valid mem region...\n");
460  return -ENOMEM;
461  }
462 
463  pinfo->addr = ioremap_nocache(bar2, mem_len);
464  if (!pinfo->addr) {
465  BCMLOG_ERR("Failed to remap mem region...\n");
466  return -ENOMEM;
467  }
468 
469  pinfo->pci_mem_start = bar2;
470  pinfo->pci_mem_len = mem_len;
471 
472  rc = check_mem_region(bar0, i2o_len);
473  if (rc) {
474  BCMLOG_ERR("No valid mem region...\n");
475  return -ENOMEM;
476  }
477 
478  pinfo->i2o_addr = ioremap_nocache(bar0, i2o_len);
479  if (!pinfo->i2o_addr) {
480  BCMLOG_ERR("Failed to remap mem region...\n");
481  return -ENOMEM;
482  }
483 
484  pinfo->pci_i2o_start = bar0;
485  pinfo->pci_i2o_len = i2o_len;
486 
487  rc = pci_request_regions(pinfo->pdev, pinfo->name);
488  if (rc < 0) {
489  BCMLOG_ERR("Region request failed: %d\n", rc);
490  return rc;
491  }
492 
493  BCMLOG(BCMLOG_SSTEP, "Mapped addr:0x%08lx i2o_addr:0x%08lx\n",
494  (unsigned long)pinfo->addr, (unsigned long)pinfo->i2o_addr);
495 
496  return 0;
497 }
498 
499 static void __devexit chd_pci_release_mem(struct crystalhd_adp *pinfo)
500 {
501  if (!pinfo)
502  return;
503 
504  if (pinfo->addr)
505  iounmap(pinfo->addr);
506 
507  if (pinfo->i2o_addr)
508  iounmap(pinfo->i2o_addr);
509 
510  pci_release_regions(pinfo->pdev);
511 }
512 
513 
514 static void __devexit chd_dec_pci_remove(struct pci_dev *pdev)
515 {
516  struct crystalhd_adp *pinfo;
517  enum BC_STATUS sts = BC_STS_SUCCESS;
518 
519  pinfo = pci_get_drvdata(pdev);
520  if (!pinfo) {
521  BCMLOG_ERR("could not get adp\n");
522  return;
523  }
524 
525  sts = crystalhd_delete_cmd_context(&pinfo->cmds);
526  if (sts != BC_STS_SUCCESS)
527  BCMLOG_ERR("cmd delete :%d\n", sts);
528 
529  chd_dec_release_chdev(pinfo);
530 
531  chd_dec_disable_int(pinfo);
532 
533  chd_pci_release_mem(pinfo);
534  pci_disable_device(pinfo->pdev);
535 
536  kfree(pinfo);
537  g_adp_info = NULL;
538 }
539 
540 static int __devinit chd_dec_pci_probe(struct pci_dev *pdev,
541  const struct pci_device_id *entry)
542 {
543  struct crystalhd_adp *pinfo;
544  int rc;
545  enum BC_STATUS sts = BC_STS_SUCCESS;
546 
547  BCMLOG(BCMLOG_DBG, "PCI_INFO: Vendor:0x%04x Device:0x%04x "
548  "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 
624 err:
625  kfree(pinfo);
626  return rc;
627 }
628 
629 #ifdef CONFIG_PM
630 int 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 
664 int 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 
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 
705 static DEFINE_PCI_DEVICE_TABLE(chd_dec_pci_id_table) = {
706  { PCI_VDEVICE(BROADCOM, 0x1612), 8 },
707  { 0, },
708 };
709 MODULE_DEVICE_TABLE(pci, chd_dec_pci_id_table);
710 
711 static struct pci_driver bc_chd_70012_driver = {
712  .name = "Broadcom 70012 Decoder",
713  .probe = chd_dec_pci_probe,
714  .remove = __devexit_p(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 
722 void chd_set_log_level(struct crystalhd_adp *adp, char *arg)
723 {
724  if ((!arg) || (strlen(arg) < 3))
726  else if (!strncmp(arg, "sstep", 5))
729  else if (!strncmp(arg, "info", 4))
731  else if (!strncmp(arg, "debug", 5))
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 
743 {
744  return g_adp_info;
745 }
746 
747 static 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",
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 }
762 module_init(chd_dec_module_init);
763 
764 static void __exit chd_dec_module_cleanup(void)
765 {
766  BCMLOG(BCMLOG_DATA, "unloading crystalhd %d.%d.%d\n",
768 
769  pci_unregister_driver(&bc_chd_70012_driver);
770 }
771 module_exit(chd_dec_module_cleanup);
772 
773 MODULE_AUTHOR("Naren Sankar <[email protected]>");
774 MODULE_AUTHOR("Prasad Bolisetty <[email protected]>");
776 MODULE_LICENSE("GPL");
777 MODULE_ALIAS("bcm70012");