📄 maple.c
字号:
maple_add_packet(maple_dev->mq); liststatus++; } } return 0;}/* VBLANK bottom half - implemented via workqueue */static void maple_vblank_handler(struct work_struct *work){ if (!maple_dma_done()) return; if (!list_empty(&maple_sentq)) return; ctrl_outl(0, MAPLE_ENABLE); liststatus = 0; bus_for_each_dev(&maple_bus_type, NULL, NULL, setup_maple_commands); if (time_after(jiffies, maple_pnp_time)) maple_pnp_time = jiffies + MAPLE_PNP_INTERVAL; if (liststatus && list_empty(&maple_sentq)) { INIT_LIST_HEAD(&maple_sentq); maple_send(); } maplebus_dma_reset();}/* handle devices added via hotplugs - placing them on queue for DEVINFO*/static void maple_map_subunits(struct maple_device *mdev, int submask){ int retval, k, devcheck; struct maple_device *mdev_add; struct maple_device_specify ds; for (k = 0; k < 5; k++) { ds.port = mdev->port; ds.unit = k + 1; retval = bus_for_each_dev(&maple_bus_type, NULL, &ds, detach_maple_device); if (retval) { submask = submask >> 1; continue; } devcheck = submask & 0x01; if (devcheck) { mdev_add = maple_alloc_dev(mdev->port, k + 1); if (!mdev_add) return; mdev_add->mq->command = MAPLE_COMMAND_DEVINFO; mdev_add->mq->length = 0; maple_add_packet(mdev_add->mq); scanning = 1; } submask = submask >> 1; }}/* mark a device as removed */static void maple_clean_submap(struct maple_device *mdev){ int killbit; killbit = (mdev->unit > 0 ? (1 << (mdev->unit - 1)) & 0x1f : 0x20); killbit = ~killbit; killbit &= 0xFF; subdevice_map[mdev->port] = subdevice_map[mdev->port] & killbit;}/* handle empty port or hotplug removal */static void maple_response_none(struct maple_device *mdev, struct mapleq *mq){ if (mdev->unit != 0) { list_del(&mq->list); maple_clean_submap(mdev); printk(KERN_INFO "Maple bus device detaching at (%d, %d)\n", mdev->port, mdev->unit); maple_detach_driver(mdev); return; } if (!started) { printk(KERN_INFO "No maple devices attached to port %d\n", mdev->port); return; } maple_clean_submap(mdev);}/* preprocess hotplugs or scans */static void maple_response_devinfo(struct maple_device *mdev, char *recvbuf){ char submask; if ((!started) || (scanning == 2)) { maple_attach_driver(mdev); return; } if (mdev->unit == 0) { submask = recvbuf[2] & 0x1F; if (submask ^ subdevice_map[mdev->port]) { maple_map_subunits(mdev, submask); subdevice_map[mdev->port] = submask; } }}/* maple dma end bottom half - implemented via workqueue */static void maple_dma_handler(struct work_struct *work){ struct mapleq *mq, *nmq; struct maple_device *dev; char *recvbuf; enum maple_code code; if (!maple_dma_done()) return; ctrl_outl(0, MAPLE_ENABLE); if (!list_empty(&maple_sentq)) { list_for_each_entry_safe(mq, nmq, &maple_sentq, list) { recvbuf = mq->recvbuf; code = recvbuf[0]; dev = mq->dev; switch (code) { case MAPLE_RESPONSE_NONE: maple_response_none(dev, mq); break; case MAPLE_RESPONSE_DEVINFO: maple_response_devinfo(dev, recvbuf); break; case MAPLE_RESPONSE_DATATRF: if (dev->callback) dev->callback(mq); break; case MAPLE_RESPONSE_FILEERR: case MAPLE_RESPONSE_AGAIN: case MAPLE_RESPONSE_BADCMD: case MAPLE_RESPONSE_BADFUNC: printk(KERN_DEBUG "Maple non-fatal error 0x%X\n", code); break; case MAPLE_RESPONSE_ALLINFO: printk(KERN_DEBUG "Maple - extended device information not supported\n"); break; case MAPLE_RESPONSE_OK: break; default: break; } } INIT_LIST_HEAD(&maple_sentq); if (scanning == 1) { maple_send(); scanning = 2; } else scanning = 0; if (started == 0) started = 1; } maplebus_dma_reset();}static irqreturn_t maplebus_dma_interrupt(int irq, void *dev_id){ /* Load everything into the bottom half */ schedule_work(&maple_dma_process); return IRQ_HANDLED;}static irqreturn_t maplebus_vblank_interrupt(int irq, void *dev_id){ schedule_work(&maple_vblank_process); return IRQ_HANDLED;}static struct irqaction maple_dma_irq = { .name = "maple bus DMA handler", .handler = maplebus_dma_interrupt, .flags = IRQF_SHARED,};static struct irqaction maple_vblank_irq = { .name = "maple bus VBLANK handler", .handler = maplebus_vblank_interrupt, .flags = IRQF_SHARED,};static int maple_set_dma_interrupt_handler(void){ return setup_irq(HW_EVENT_MAPLE_DMA, &maple_dma_irq);}static int maple_set_vblank_interrupt_handler(void){ return setup_irq(HW_EVENT_VSYNC, &maple_vblank_irq);}static int maple_get_dma_buffer(void){ maple_sendbuf = (void *) __get_free_pages(GFP_KERNEL | __GFP_ZERO, MAPLE_DMA_PAGES); if (!maple_sendbuf) return -ENOMEM; return 0;}static int match_maple_bus_driver(struct device *devptr, struct device_driver *drvptr){ struct maple_driver *maple_drv; struct maple_device *maple_dev; maple_drv = container_of(drvptr, struct maple_driver, drv); maple_dev = container_of(devptr, struct maple_device, dev); /* Trap empty port case */ if (maple_dev->devinfo.function == 0xFFFFFFFF) return 0; else if (maple_dev->devinfo.function & be32_to_cpu(maple_drv->function)) return 1; return 0;}static int maple_bus_uevent(struct device *dev, struct kobj_uevent_env *env){ return 0;}static void maple_bus_release(struct device *dev){}static struct maple_driver maple_dummy_driver = { .drv = { .name = "maple_dummy_driver", .bus = &maple_bus_type, },};struct bus_type maple_bus_type = { .name = "maple", .match = match_maple_bus_driver, .uevent = maple_bus_uevent,};EXPORT_SYMBOL_GPL(maple_bus_type);static struct device maple_bus = { .bus_id = "maple", .release = maple_bus_release,};static int __init maple_bus_init(void){ int retval, i; struct maple_device *mdev[MAPLE_PORTS]; ctrl_outl(0, MAPLE_STATE); retval = device_register(&maple_bus); if (retval) goto cleanup; retval = bus_register(&maple_bus_type); if (retval) goto cleanup_device; retval = driver_register(&maple_dummy_driver.drv); if (retval) goto cleanup_bus; /* allocate memory for maple bus dma */ retval = maple_get_dma_buffer(); if (retval) { printk(KERN_INFO "Maple bus: Failed to allocate Maple DMA buffers\n"); goto cleanup_basic; } /* set up DMA interrupt handler */ retval = maple_set_dma_interrupt_handler(); if (retval) { printk(KERN_INFO "Maple bus: Failed to grab maple DMA IRQ\n"); goto cleanup_dma; } /* set up VBLANK interrupt handler */ retval = maple_set_vblank_interrupt_handler(); if (retval) { printk(KERN_INFO "Maple bus: Failed to grab VBLANK IRQ\n"); goto cleanup_irq; } maple_queue_cache = kmem_cache_create("maple_queue_cache", 0x400, 0, SLAB_HWCACHE_ALIGN, NULL); if (!maple_queue_cache) goto cleanup_bothirqs; /* setup maple ports */ for (i = 0; i < MAPLE_PORTS; i++) { mdev[i] = maple_alloc_dev(i, 0); if (!mdev[i]) { while (i-- > 0) maple_free_dev(mdev[i]); goto cleanup_cache; } mdev[i]->registered = 0; mdev[i]->mq->command = MAPLE_COMMAND_DEVINFO; mdev[i]->mq->length = 0; maple_attach_driver(mdev[i]); maple_add_packet(mdev[i]->mq); subdevice_map[i] = 0; } /* setup maplebus hardware */ maplebus_dma_reset(); /* initial detection */ maple_send(); maple_pnp_time = jiffies; printk(KERN_INFO "Maple bus core now registered.\n"); return 0;cleanup_cache: kmem_cache_destroy(maple_queue_cache);cleanup_bothirqs: free_irq(HW_EVENT_VSYNC, 0);cleanup_irq: free_irq(HW_EVENT_MAPLE_DMA, 0);cleanup_dma: free_pages((unsigned long) maple_sendbuf, MAPLE_DMA_PAGES);cleanup_basic: driver_unregister(&maple_dummy_driver.drv);cleanup_bus: bus_unregister(&maple_bus_type);cleanup_device: device_unregister(&maple_bus);cleanup: printk(KERN_INFO "Maple bus registration failed\n"); return retval;}subsys_initcall(maple_bus_init);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -