static void ilo_remove(struct pci_dev *pdev) { int i, minor; struct ilo_hwinfo *ilo_hw = pci_get_drvdata(pdev); clear_device(ilo_hw); minor = MINOR(ilo_hw->cdev.dev); for (i = minor; i < minor + MAX_CCB; i++) device_destroy(ilo_class, MKDEV(ilo_major, i)); cdev_del(&ilo_hw->cdev); ilo_disable_interrupts(ilo_hw); free_irq(pdev->irq, ilo_hw); ilo_unmap_device(pdev, ilo_hw); pci_release_regions(pdev); /* * pci_disable_device(pdev) used to be here. But this PCI device has * two functions with interrupt lines connected to a single pin. The * other one is a USB host controller. So when we disable the PIN here * e.g. by rmmod hpilo, the controller stops working. It is because * the interrupt link is disabled in ACPI since it is not refcounted * yet. See acpi_pci_link_free_irq called from acpi_pci_irq_disable. */ kfree(ilo_hw); ilo_hwdev[(minor / MAX_CCB)] = 0; }
static void ilo_remove(struct pci_dev *pdev) { int i, minor; struct ilo_hwinfo *ilo_hw = pci_get_drvdata(pdev); clear_device(ilo_hw); minor = MINOR(ilo_hw->cdev.dev); for (i = minor; i < minor + MAX_CCB; i++) device_destroy(ilo_class, MKDEV(ilo_major, i)); cdev_del(&ilo_hw->cdev); ilo_disable_interrupts(ilo_hw); free_irq(pdev->irq, ilo_hw); ilo_unmap_device(pdev, ilo_hw); pci_release_regions(pdev); pci_disable_device(pdev); kfree(ilo_hw); ilo_hwdev[(minor / MAX_CCB)] = 0; }
static int __devinit ilo_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int devnum, minor, start, error; struct ilo_hwinfo *ilo_hw; /* find a free range for device files */ for (devnum = 0; devnum < MAX_ILO_DEV; devnum++) { if (ilo_hwdev[devnum] == 0) { ilo_hwdev[devnum] = 1; break; } } if (devnum == MAX_ILO_DEV) { dev_err(&pdev->dev, "Error finding free device\n"); return -ENODEV; } /* track global allocations for this device */ error = -ENOMEM; ilo_hw = kzalloc(sizeof(*ilo_hw), GFP_KERNEL); if (!ilo_hw) goto out; ilo_hw->ilo_dev = pdev; spin_lock_init(&ilo_hw->alloc_lock); spin_lock_init(&ilo_hw->fifo_lock); spin_lock_init(&ilo_hw->open_lock); error = pci_enable_device(pdev); if (error) goto free; pci_set_master(pdev); error = pci_request_regions(pdev, ILO_NAME); if (error) goto disable; error = ilo_map_device(pdev, ilo_hw); if (error) goto free_regions; pci_set_drvdata(pdev, ilo_hw); clear_device(ilo_hw); error = request_irq(pdev->irq, ilo_isr, IRQF_SHARED, "hpilo", ilo_hw); if (error) goto unmap; ilo_enable_interrupts(ilo_hw); cdev_init(&ilo_hw->cdev, &ilo_fops); ilo_hw->cdev.owner = THIS_MODULE; start = devnum * MAX_CCB; error = cdev_add(&ilo_hw->cdev, MKDEV(ilo_major, start), MAX_CCB); if (error) { dev_err(&pdev->dev, "Could not add cdev\n"); goto remove_isr; } for (minor = 0 ; minor < MAX_CCB; minor++) { struct device *dev; dev = device_create(ilo_class, &pdev->dev, MKDEV(ilo_major, minor), NULL, "hpilo!d%dccb%d", devnum, minor); if (IS_ERR(dev)) dev_err(&pdev->dev, "Could not create files\n"); } return 0; remove_isr: ilo_disable_interrupts(ilo_hw); free_irq(pdev->irq, ilo_hw); unmap: ilo_unmap_device(pdev, ilo_hw); free_regions: pci_release_regions(pdev); disable: /* pci_disable_device(pdev); see comment in ilo_remove */ free: kfree(ilo_hw); out: ilo_hwdev[devnum] = 0; return error; }