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 + -
显示快捷键?