Chapter 4. PCI Resource Management

Table of Contents

Full Code Example
Some Hafta's
Resource Allocation
PCI Entries

Full Code Example

In this section, we'll complete the chip-specific constructor, destructor and PCI entries. Example code is shown first, below.

Example 4.1. PCI Resource Management Example


  struct mychip {
          struct snd_card *card;
          struct pci_dev *pci;

          unsigned long port;
          int irq;
  };

  static int snd_mychip_free(struct mychip *chip)
  {
          /* disable hardware here if any */
          .... /* (not implemented in this document) */

          /* release the irq */
          if (chip->irq >= 0)
                  free_irq(chip->irq, chip);
          /* release the I/O ports & memory */
          pci_release_regions(chip->pci);
          /* disable the PCI entry */
          pci_disable_device(chip->pci);
          /* release the data */
          kfree(chip);
          return 0;
  }

  /* chip-specific constructor */
  static int snd_mychip_create(struct snd_card *card,
                               struct pci_dev *pci,
                               struct mychip **rchip)
  {
          struct mychip *chip;
          int err;
          static struct snd_device_ops ops = {
                 .dev_free = snd_mychip_dev_free,
          };

          *rchip = NULL;

          /* initialize the PCI entry */
          err = pci_enable_device(pci);
          if (err < 0)
                  return err;
          /* check PCI availability (28bit DMA) */
          if (pci_set_dma_mask(pci, DMA_BIT_MASK(28)) < 0 ||
              pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(28)) < 0) {
                  printk(KERN_ERR "error to set 28bit mask DMA\n");
                  pci_disable_device(pci);
                  return -ENXIO;
          }

          chip = kzalloc(sizeof(*chip), GFP_KERNEL);
          if (chip == NULL) {
                  pci_disable_device(pci);
                  return -ENOMEM;
          }

          /* initialize the stuff */
          chip->card = card;
          chip->pci = pci;
          chip->irq = -1;

          /* (1) PCI resource allocation */
          err = pci_request_regions(pci, "My Chip");
          if (err < 0) {
                  kfree(chip);
                  pci_disable_device(pci);
                  return err;
          }
          chip->port = pci_resource_start(pci, 0);
          if (request_irq(pci->irq, snd_mychip_interrupt,
                          IRQF_SHARED, KBUILD_MODNAME, chip)) {
                  printk(KERN_ERR "cannot grab irq %d\n", pci->irq);
                  snd_mychip_free(chip);
                  return -EBUSY;
          }
          chip->irq = pci->irq;

          /* (2) initialization of the chip hardware */
          .... /*   (not implemented in this document) */

          err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
          if (err < 0) {
                  snd_mychip_free(chip);
                  return err;
          }

          *rchip = chip;
          return 0;
  }        

  /* PCI IDs */
  static struct pci_device_id snd_mychip_ids[] = {
          { PCI_VENDOR_ID_FOO, PCI_DEVICE_ID_BAR,
            PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
          ....
          { 0, }
  };
  MODULE_DEVICE_TABLE(pci, snd_mychip_ids);

  /* pci_driver definition */
  static struct pci_driver driver = {
          .name = KBUILD_MODNAME,
          .id_table = snd_mychip_ids,
          .probe = snd_mychip_probe,
          .remove = snd_mychip_remove,
  };

  /* module initialization */
  static int __init alsa_card_mychip_init(void)
  {
          return pci_register_driver(&driver);
  }

  /* module clean up */
  static void __exit alsa_card_mychip_exit(void)
  {
          pci_unregister_driver(&driver);
  }

  module_init(alsa_card_mychip_init)
  module_exit(alsa_card_mychip_exit)

  EXPORT_NO_SYMBOLS; /* for old kernels only */