#include "pci.h" #include #include #include #include "char.h" #include "harddoom.h" #include "util.h" #include "harddoomdev.h" #include "private_data.h" void handle_pong_sync(struct doom_data *doom_data) { up(&doom_data->pong_sem); } irqreturn_t doom_irq(int irq, void *dev) { uint32_t interrupts; struct doom_data *doom_data; void __iomem *iomem; doom_data = dev; iomem = doom_data->iomem; interrupts = ioread32(iomem + HARDDOOM_INTR) & ioread32(iomem + HARDDOOM_INTR_ENABLE); iowrite32(interrupts, iomem + HARDDOOM_INTR); if (!interrupts) { return IRQ_NONE; } if (interrupts & HARDDOOM_INTR_PONG_SYNC) { handle_pong_sync(doom_data); interrupts &= ~HARDDOOM_INTR_PONG_SYNC; } if (interrupts & HARDDOOM_INTR_PONG_ASYNC) { up(&doom_data->pong_async_sem); iowrite32(HARDDOOM_INTR_MASK & (~HARDDOOM_INTR_PONG_ASYNC), iomem + HARDDOOM_INTR_ENABLE); } return IRQ_HANDLED; } int init_pci(struct pci_dev *dev) { struct doom_data *doom_data; int err = 0; ORFAIL(pci_enable_device(dev), error_enable); ORFAIL(pci_request_regions(dev, "harddoom"), error_regions); doom_data = kmalloc(sizeof(*doom_data), GFP_KERNEL); if (doom_data == NULL) { err = -ENOMEM; goto error_kmalloc; } pci_set_drvdata(dev, doom_data); doom_data->iomem = pci_iomap(dev, 0, 0); ORFAIL_NULL(doom_data->iomem, -ENOMEM, error_iomem); doom_data->pci_device = &dev->dev; pci_set_master(dev); pci_set_dma_mask(dev, DMA_BIT_MASK(32)); pci_set_consistent_dma_mask(dev, DMA_BIT_MASK(32)); mutex_init(&doom_data->cmd_mutex); mutex_init(&doom_data->ping_mutex); sema_init(&doom_data->pong_sem, 0); sema_init(&doom_data->pong_async_sem, 0); doom_data->cmd_counter = 0; ORFAIL(request_irq(dev->irq, doom_irq, IRQF_SHARED, "doom", doom_data), error_irq); return 0; error_irq: pci_clear_master(dev); pci_iounmap(dev, doom_data->iomem); error_iomem: kfree(doom_data); error_kmalloc: pci_release_regions(dev); error_regions: pci_disable_device(dev); error_enable: return err; } void cleanup_pci(struct pci_dev *dev) { struct doom_data *doom_data; doom_data = pci_get_drvdata(dev); free_irq(dev->irq, doom_data); pci_clear_master(dev); pci_iounmap(dev, doom_data->iomem); kfree(doom_data); pci_release_regions(dev); pci_disable_device(dev); } int doom_probe(struct pci_dev *dev, const struct pci_device_id *id) { int err = 0; ORFAIL(init_pci(dev), error_pci); start_dev(dev); ORFAIL(new_doomdev(dev), error_doomdev); return 0; error_doomdev: shutdown_dev(dev); cleanup_pci(dev); error_pci: return err; } void doom_remove (struct pci_dev *dev) { struct doom_data *doom_data; doom_data = pci_get_drvdata(dev); destroy_doomdev(doom_data); shutdown_dev(dev); cleanup_pci(dev); } int doom_suspend (struct pci_dev *dev, pm_message_t state) { return 0; } int doom_suspend_late (struct pci_dev *dev, pm_message_t state) { return 0; } int doom_resume_early (struct pci_dev *dev) { return 0; } int doom_resume (struct pci_dev *dev) { return 0; } void doom_shutdown (struct pci_dev *dev) { } struct pci_device_id device_ids[1] = { { PCI_DEVICE(HARDDOOM_VENDOR_ID, HARDDOOM_DEVICE_ID) } }; struct pci_driver driver = { .name = "harddoom", .id_table = device_ids, .probe = doom_probe, .remove = doom_remove, .suspend = doom_suspend, .suspend_late = doom_suspend_late, .resume_early = doom_resume_early, .resume = doom_resume, .shutdown = doom_shutdown }; int pci_init(void) { return pci_register_driver(&driver); } void pci_cleanup(void) { pci_unregister_driver(&driver); }