xsysace.c

来自「linux 内核源代码」· C语言 代码 · 共 1,288 行 · 第 1/3 页

C
1,288
字号
	dev_dbg(ace->dev, "ace_revalidate_disk()\n");	if (ace->media_change) {		dev_dbg(ace->dev, "requesting cf id and scheduling tasklet\n");		spin_lock_irqsave(&ace->lock, flags);		ace->id_req_count++;		spin_unlock_irqrestore(&ace->lock, flags);		tasklet_schedule(&ace->fsm_tasklet);		wait_for_completion(&ace->id_completion);	}	dev_dbg(ace->dev, "revalidate complete\n");	return ace->id_result;}static int ace_open(struct inode *inode, struct file *filp){	struct ace_device *ace = inode->i_bdev->bd_disk->private_data;	unsigned long flags;	dev_dbg(ace->dev, "ace_open() users=%i\n", ace->users + 1);	filp->private_data = ace;	spin_lock_irqsave(&ace->lock, flags);	ace->users++;	spin_unlock_irqrestore(&ace->lock, flags);	check_disk_change(inode->i_bdev);	return 0;}static int ace_release(struct inode *inode, struct file *filp){	struct ace_device *ace = inode->i_bdev->bd_disk->private_data;	unsigned long flags;	u16 val;	dev_dbg(ace->dev, "ace_release() users=%i\n", ace->users - 1);	spin_lock_irqsave(&ace->lock, flags);	ace->users--;	if (ace->users == 0) {		val = ace_in(ace, ACE_CTRL);		ace_out(ace, ACE_CTRL, val & ~ACE_CTRL_LOCKREQ);	}	spin_unlock_irqrestore(&ace->lock, flags);	return 0;}static int ace_getgeo(struct block_device *bdev, struct hd_geometry *geo){	struct ace_device *ace = bdev->bd_disk->private_data;	dev_dbg(ace->dev, "ace_getgeo()\n");	geo->heads = ace->cf_id.heads;	geo->sectors = ace->cf_id.sectors;	geo->cylinders = ace->cf_id.cyls;	return 0;}static struct block_device_operations ace_fops = {	.owner = THIS_MODULE,	.open = ace_open,	.release = ace_release,	.media_changed = ace_media_changed,	.revalidate_disk = ace_revalidate_disk,	.getgeo = ace_getgeo,};/* -------------------------------------------------------------------- * SystemACE device setup/teardown code */static int __devinit ace_setup(struct ace_device *ace){	u16 version;	u16 val;	int rc;	dev_dbg(ace->dev, "ace_setup(ace=0x%p)\n", ace);	dev_dbg(ace->dev, "physaddr=0x%lx irq=%i\n", ace->physaddr, ace->irq);	spin_lock_init(&ace->lock);	init_completion(&ace->id_completion);	/*	 * Map the device	 */	ace->baseaddr = ioremap(ace->physaddr, 0x80);	if (!ace->baseaddr)		goto err_ioremap;	/*	 * Initialize the state machine tasklet and stall timer	 */	tasklet_init(&ace->fsm_tasklet, ace_fsm_tasklet, (unsigned long)ace);	setup_timer(&ace->stall_timer, ace_stall_timer, (unsigned long)ace);	/*	 * Initialize the request queue	 */	ace->queue = blk_init_queue(ace_request, &ace->lock);	if (ace->queue == NULL)		goto err_blk_initq;	blk_queue_hardsect_size(ace->queue, 512);	/*	 * Allocate and initialize GD structure	 */	ace->gd = alloc_disk(ACE_NUM_MINORS);	if (!ace->gd)		goto err_alloc_disk;	ace->gd->major = ace_major;	ace->gd->first_minor = ace->id * ACE_NUM_MINORS;	ace->gd->fops = &ace_fops;	ace->gd->queue = ace->queue;	ace->gd->private_data = ace;	snprintf(ace->gd->disk_name, 32, "xs%c", ace->id + 'a');	/* set bus width */	if (ace->bus_width == ACE_BUS_WIDTH_16) {		/* 0x0101 should work regardless of endianess */		ace_out_le16(ace, ACE_BUSMODE, 0x0101);		/* read it back to determine endianess */		if (ace_in_le16(ace, ACE_BUSMODE) == 0x0001)			ace->reg_ops = &ace_reg_le16_ops;		else			ace->reg_ops = &ace_reg_be16_ops;	} else {		ace_out_8(ace, ACE_BUSMODE, 0x00);		ace->reg_ops = &ace_reg_8_ops;	}	/* Make sure version register is sane */	version = ace_in(ace, ACE_VERSION);	if ((version == 0) || (version == 0xFFFF))		goto err_read;	/* Put sysace in a sane state by clearing most control reg bits */	ace_out(ace, ACE_CTRL, ACE_CTRL_FORCECFGMODE |		ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ);	/* Now we can hook up the irq handler */	if (ace->irq != NO_IRQ) {		rc = request_irq(ace->irq, ace_interrupt, 0, "systemace", ace);		if (rc) {			/* Failure - fall back to polled mode */			dev_err(ace->dev, "request_irq failed\n");			ace->irq = NO_IRQ;		}	}	/* Enable interrupts */	val = ace_in(ace, ACE_CTRL);	val |= ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ;	ace_out(ace, ACE_CTRL, val);	/* Print the identification */	dev_info(ace->dev, "Xilinx SystemACE revision %i.%i.%i\n",		 (version >> 12) & 0xf, (version >> 8) & 0x0f, version & 0xff);	dev_dbg(ace->dev, "physaddr 0x%lx, mapped to 0x%p, irq=%i\n",		ace->physaddr, ace->baseaddr, ace->irq);	ace->media_change = 1;	ace_revalidate_disk(ace->gd);	/* Make the sysace device 'live' */	add_disk(ace->gd);	return 0;err_read:	put_disk(ace->gd);err_alloc_disk:	blk_cleanup_queue(ace->queue);err_blk_initq:	iounmap(ace->baseaddr);err_ioremap:	dev_info(ace->dev, "xsysace: error initializing device at 0x%lx\n",	       ace->physaddr);	return -ENOMEM;}static void __devexit ace_teardown(struct ace_device *ace){	if (ace->gd) {		del_gendisk(ace->gd);		put_disk(ace->gd);	}	if (ace->queue)		blk_cleanup_queue(ace->queue);	tasklet_kill(&ace->fsm_tasklet);	if (ace->irq != NO_IRQ)		free_irq(ace->irq, ace);	iounmap(ace->baseaddr);}static int __devinitace_alloc(struct device *dev, int id, unsigned long physaddr,	  int irq, int bus_width){	struct ace_device *ace;	int rc;	dev_dbg(dev, "ace_alloc(%p)\n", dev);	if (!physaddr) {		rc = -ENODEV;		goto err_noreg;	}	/* Allocate and initialize the ace device structure */	ace = kzalloc(sizeof(struct ace_device), GFP_KERNEL);	if (!ace) {		rc = -ENOMEM;		goto err_alloc;	}	ace->dev = dev;	ace->id = id;	ace->physaddr = physaddr;	ace->irq = irq;	ace->bus_width = bus_width;	/* Call the setup code */	rc = ace_setup(ace);	if (rc)		goto err_setup;	dev_set_drvdata(dev, ace);	return 0;err_setup:	dev_set_drvdata(dev, NULL);	kfree(ace);err_alloc:err_noreg:	dev_err(dev, "could not initialize device, err=%i\n", rc);	return rc;}static void __devexit ace_free(struct device *dev){	struct ace_device *ace = dev_get_drvdata(dev);	dev_dbg(dev, "ace_free(%p)\n", dev);	if (ace) {		ace_teardown(ace);		dev_set_drvdata(dev, NULL);		kfree(ace);	}}/* --------------------------------------------------------------------- * Platform Bus Support */static int __devinit ace_probe(struct platform_device *dev){	unsigned long physaddr = 0;	int bus_width = ACE_BUS_WIDTH_16; /* FIXME: should not be hard coded */	int id = dev->id;	int irq = NO_IRQ;	int i;	dev_dbg(&dev->dev, "ace_probe(%p)\n", dev);	for (i = 0; i < dev->num_resources; i++) {		if (dev->resource[i].flags & IORESOURCE_MEM)			physaddr = dev->resource[i].start;		if (dev->resource[i].flags & IORESOURCE_IRQ)			irq = dev->resource[i].start;	}	/* Call the bus-independant setup code */	return ace_alloc(&dev->dev, id, physaddr, irq, bus_width);}/* * Platform bus remove() method */static int __devexit ace_remove(struct platform_device *dev){	ace_free(&dev->dev);	return 0;}static struct platform_driver ace_platform_driver = {	.probe = ace_probe,	.remove = __devexit_p(ace_remove),	.driver = {		.owner = THIS_MODULE,		.name = "xsysace",	},};/* --------------------------------------------------------------------- * OF_Platform Bus Support */#if defined(CONFIG_OF)static int __devinitace_of_probe(struct of_device *op, const struct of_device_id *match){	struct resource res;	unsigned long physaddr;	const u32 *id;	int irq, bus_width, rc;	dev_dbg(&op->dev, "ace_of_probe(%p, %p)\n", op, match);	/* device id */	id = of_get_property(op->node, "port-number", NULL);	/* physaddr */	rc = of_address_to_resource(op->node, 0, &res);	if (rc) {		dev_err(&op->dev, "invalid address\n");		return rc;	}	physaddr = res.start;	/* irq */	irq = irq_of_parse_and_map(op->node, 0);	/* bus width */	bus_width = ACE_BUS_WIDTH_16;	if (of_find_property(op->node, "8-bit", NULL))		bus_width = ACE_BUS_WIDTH_8;	/* Call the bus-independant setup code */	return ace_alloc(&op->dev, id ? *id : 0, physaddr, irq, bus_width);}static int __devexit ace_of_remove(struct of_device *op){	ace_free(&op->dev);	return 0;}/* Match table for of_platform binding */static struct of_device_id __devinit ace_of_match[] = {	{ .compatible = "xilinx,xsysace", },	{},};MODULE_DEVICE_TABLE(of, ace_of_match);static struct of_platform_driver ace_of_driver = {	.owner = THIS_MODULE,	.name = "xsysace",	.match_table = ace_of_match,	.probe = ace_of_probe,	.remove = __devexit_p(ace_of_remove),	.driver = {		.name = "xsysace",	},};/* Registration helpers to keep the number of #ifdefs to a minimum */static inline int __init ace_of_register(void){	pr_debug("xsysace: registering OF binding\n");	return of_register_platform_driver(&ace_of_driver);}static inline void __exit ace_of_unregister(void){	of_unregister_platform_driver(&ace_of_driver);}#else /* CONFIG_OF *//* CONFIG_OF not enabled; do nothing helpers */static inline int __init ace_of_register(void) { return 0; }static inline void __exit ace_of_unregister(void) { }#endif /* CONFIG_OF *//* --------------------------------------------------------------------- * Module init/exit routines */static int __init ace_init(void){	int rc;	ace_major = register_blkdev(ace_major, "xsysace");	if (ace_major <= 0) {		rc = -ENOMEM;		goto err_blk;	}	rc = ace_of_register();	if (rc)		goto err_of;	pr_debug("xsysace: registering platform binding\n");	rc = platform_driver_register(&ace_platform_driver);	if (rc)		goto err_plat;	pr_info("Xilinx SystemACE device driver, major=%i\n", ace_major);	return 0;err_plat:	ace_of_unregister();err_of:	unregister_blkdev(ace_major, "xsysace");err_blk:	printk(KERN_ERR "xsysace: registration failed; err=%i\n", rc);	return rc;}static void __exit ace_exit(void){	pr_debug("Unregistering Xilinx SystemACE driver\n");	platform_driver_unregister(&ace_platform_driver);	ace_of_unregister();	unregister_blkdev(ace_major, "xsysace");}module_init(ace_init);module_exit(ace_exit);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?