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