rack-meter.c
来自「linux 内核源代码」· C语言 代码 · 共 616 行 · 第 1/2 页
C
616 行
/* XXX FIXME: No PWM yet, this is 0/1 */static u32 rackmeter_calc_sample(struct rackmeter *rm, unsigned int index){ int led; u32 sample = 0; for (led = 0; led < 16; led++) { sample >>= 1; sample |= ((rm->ubuf[led] >= 0x80) << 15); } return (sample << 17) | (sample >> 15);}static irqreturn_t rackmeter_irq(int irq, void *arg){ struct rackmeter *rm = arg; struct rackmeter_dma *db = rm->dma_buf_v; unsigned int mark, i; u32 *buf; /* Flush PCI buffers with an MMIO read. Maybe we could actually * check the status one day ... in case things go wrong, though * this never happened to me */ (void)in_le32(&rm->dma_regs->status); /* Make sure the CPU gets us in order */ rmb(); /* Read mark */ mark = db->mark; if (mark != 1 && mark != 2) { printk(KERN_WARNING "rackmeter: Incorrect DMA mark 0x%08x\n", mark); /* We allow for 3 errors like that (stale DBDMA irqs) */ if (++rm->stale_irq > 3) { printk(KERN_ERR "rackmeter: Too many errors," " stopping DMA\n"); DBDMA_DO_RESET(rm->dma_regs); } return IRQ_HANDLED; } /* Next buffer we need to fill is mark value */ buf = mark == 1 ? db->buf1 : db->buf2; /* Fill it now. This routine converts the 8 bits depth sample array * into the PWM bitmap for each LED. */ for (i = 0; i < SAMPLE_COUNT; i++) buf[i] = rackmeter_calc_sample(rm, i); return IRQ_HANDLED;}static int __devinit rackmeter_probe(struct macio_dev* mdev, const struct of_device_id *match){ struct device_node *i2s = NULL, *np = NULL; struct rackmeter *rm = NULL; struct resource ri2s, rdma; int rc = -ENODEV; pr_debug("rackmeter_probe()\n"); /* Get i2s-a node */ while ((i2s = of_get_next_child(mdev->ofdev.node, i2s)) != NULL) if (strcmp(i2s->name, "i2s-a") == 0) break; if (i2s == NULL) { pr_debug(" i2s-a child not found\n"); goto bail; } /* Get lightshow or virtual sound */ while ((np = of_get_next_child(i2s, np)) != NULL) { if (strcmp(np->name, "lightshow") == 0) break; if ((strcmp(np->name, "sound") == 0) && of_get_property(np, "virtual", NULL) != NULL) break; } if (np == NULL) { pr_debug(" lightshow or sound+virtual child not found\n"); goto bail; } /* Create and initialize our instance data */ rm = kzalloc(sizeof(struct rackmeter), GFP_KERNEL); if (rm == NULL) { printk(KERN_ERR "rackmeter: failed to allocate memory !\n"); rc = -ENOMEM; goto bail_release; } rm->mdev = mdev; rm->i2s = i2s; mutex_init(&rm->sem); dev_set_drvdata(&mdev->ofdev.dev, rm); /* Check resources availability. We need at least resource 0 and 1 */#if 0 /* Use that when i2s-a is finally an mdev per-se */ if (macio_resource_count(mdev) < 2 || macio_irq_count(mdev) < 2) { printk(KERN_ERR "rackmeter: found match but lacks resources: %s" " (%d resources, %d interrupts)\n", mdev->ofdev.node->full_name); rc = -ENXIO; goto bail_free; } if (macio_request_resources(mdev, "rackmeter")) { printk(KERN_ERR "rackmeter: failed to request resources: %s\n", mdev->ofdev.node->full_name); rc = -EBUSY; goto bail_free; } rm->irq = macio_irq(mdev, 1);#else rm->irq = irq_of_parse_and_map(i2s, 1); if (rm->irq == NO_IRQ || of_address_to_resource(i2s, 0, &ri2s) || of_address_to_resource(i2s, 1, &rdma)) { printk(KERN_ERR "rackmeter: found match but lacks resources: %s", mdev->ofdev.node->full_name); rc = -ENXIO; goto bail_free; }#endif pr_debug(" i2s @0x%08x\n", (unsigned int)ri2s.start); pr_debug(" dma @0x%08x\n", (unsigned int)rdma.start); pr_debug(" irq %d\n", rm->irq); rm->ubuf = (u8 *)__get_free_page(GFP_KERNEL); if (rm->ubuf == NULL) { printk(KERN_ERR "rackmeter: failed to allocate samples page !\n"); rc = -ENOMEM; goto bail_release; } rm->dma_buf_v = dma_alloc_coherent(&macio_get_pci_dev(mdev)->dev, sizeof(struct rackmeter_dma), &rm->dma_buf_p, GFP_KERNEL); if (rm->dma_buf_v == NULL) { printk(KERN_ERR "rackmeter: failed to allocate dma buffer !\n"); rc = -ENOMEM; goto bail_free_samples; }#if 0 rm->i2s_regs = ioremap(macio_resource_start(mdev, 0), 0x1000);#else rm->i2s_regs = ioremap(ri2s.start, 0x1000);#endif if (rm->i2s_regs == NULL) { printk(KERN_ERR "rackmeter: failed to map i2s registers !\n"); rc = -ENXIO; goto bail_free_dma; }#if 0 rm->dma_regs = ioremap(macio_resource_start(mdev, 1), 0x100);#else rm->dma_regs = ioremap(rdma.start, 0x100);#endif if (rm->dma_regs == NULL) { printk(KERN_ERR "rackmeter: failed to map dma registers !\n"); rc = -ENXIO; goto bail_unmap_i2s; } rc = rackmeter_setup(rm); if (rc) { printk(KERN_ERR "rackmeter: failed to initialize !\n"); rc = -ENXIO; goto bail_unmap_dma; } rc = request_irq(rm->irq, rackmeter_irq, 0, "rackmeter", rm); if (rc != 0) { printk(KERN_ERR "rackmeter: failed to request interrupt !\n"); goto bail_stop_dma; } of_node_put(np); return 0; bail_stop_dma: DBDMA_DO_RESET(rm->dma_regs); bail_unmap_dma: iounmap(rm->dma_regs); bail_unmap_i2s: iounmap(rm->i2s_regs); bail_free_dma: dma_free_coherent(&macio_get_pci_dev(mdev)->dev, sizeof(struct rackmeter_dma), rm->dma_buf_v, rm->dma_buf_p); bail_free_samples: free_page((unsigned long)rm->ubuf); bail_release:#if 0 macio_release_resources(mdev);#endif bail_free: kfree(rm); bail: of_node_put(i2s); of_node_put(np); dev_set_drvdata(&mdev->ofdev.dev, NULL); return rc;}static int __devexit rackmeter_remove(struct macio_dev* mdev){ struct rackmeter *rm = dev_get_drvdata(&mdev->ofdev.dev); /* Stop CPU sniffer timer & work queues */ rackmeter_stop_cpu_sniffer(rm); /* Clear reference to private data */ dev_set_drvdata(&mdev->ofdev.dev, NULL); /* Stop/reset dbdma */ DBDMA_DO_RESET(rm->dma_regs); /* Release the IRQ */ free_irq(rm->irq, rm); /* Unmap registers */ iounmap(rm->dma_regs); iounmap(rm->i2s_regs); /* Free DMA */ dma_free_coherent(&macio_get_pci_dev(mdev)->dev, sizeof(struct rackmeter_dma), rm->dma_buf_v, rm->dma_buf_p); /* Free samples */ free_page((unsigned long)rm->ubuf);#if 0 /* Release resources */ macio_release_resources(mdev);#endif /* Get rid of me */ kfree(rm); return 0;}static int rackmeter_shutdown(struct macio_dev* mdev){ struct rackmeter *rm = dev_get_drvdata(&mdev->ofdev.dev); if (rm == NULL) return -ENODEV; /* Stop CPU sniffer timer & work queues */ rackmeter_stop_cpu_sniffer(rm); /* Stop/reset dbdma */ DBDMA_DO_RESET(rm->dma_regs); return 0;}static struct of_device_id rackmeter_match[] = { { .name = "i2s" }, { }};static struct macio_driver rackmeter_drv = { .name = "rackmeter", .owner = THIS_MODULE, .match_table = rackmeter_match, .probe = rackmeter_probe, .remove = rackmeter_remove, .shutdown = rackmeter_shutdown,};static int __init rackmeter_init(void){ pr_debug("rackmeter_init()\n"); return macio_register_driver(&rackmeter_drv);}static void __exit rackmeter_exit(void){ pr_debug("rackmeter_exit()\n"); macio_unregister_driver(&rackmeter_drv);}module_init(rackmeter_init);module_exit(rackmeter_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");MODULE_DESCRIPTION("RackMeter: Support vu-meter on XServe front panel");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?