⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 maple.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Core maple bus functionality * *  Copyright (C) 2007 Adrian McMenamin * * Based on 2.4 code by: * *  Copyright (C) 2000-2001 YAEGASHI Takeshi *  Copyright (C) 2001 M. R. Brown *  Copyright (C) 2001 Paul Mundt * * and others. * * This file is subject to the terms and conditions of the GNU General Public * License.  See the file "COPYING" in the main directory of this archive * for more details. */#include <linux/init.h>#include <linux/kernel.h>#include <linux/device.h>#include <linux/module.h>#include <linux/interrupt.h>#include <linux/list.h>#include <linux/io.h>#include <linux/slab.h>#include <linux/maple.h>#include <linux/dma-mapping.h>#include <asm/cacheflush.h>#include <asm/dma.h>#include <asm/io.h>#include <asm/mach/dma.h>#include <asm/mach/sysasic.h>#include <asm/mach/maple.h>MODULE_AUTHOR("Yaegshi Takeshi, Paul Mundt, M.R. Brown, Adrian McMenamin");MODULE_DESCRIPTION("Maple bus driver for Dreamcast");MODULE_LICENSE("GPL v2");MODULE_SUPPORTED_DEVICE("{{SEGA, Dreamcast/Maple}}");static void maple_dma_handler(struct work_struct *work);static void maple_vblank_handler(struct work_struct *work);static DECLARE_WORK(maple_dma_process, maple_dma_handler);static DECLARE_WORK(maple_vblank_process, maple_vblank_handler);static LIST_HEAD(maple_waitq);static LIST_HEAD(maple_sentq);static DEFINE_MUTEX(maple_list_lock);static struct maple_driver maple_dummy_driver;static struct device maple_bus;static int subdevice_map[MAPLE_PORTS];static unsigned long *maple_sendbuf, *maple_sendptr, *maple_lastptr;static unsigned long maple_pnp_time;static int started, scanning, liststatus;static struct kmem_cache *maple_queue_cache;struct maple_device_specify {       int port;       int unit;};/** *  maple_driver_register - register a device driver *  automatically makes the driver bus a maple bus *  @drv: the driver to be registered */int maple_driver_register(struct device_driver *drv){       if (!drv)               return -EINVAL;       drv->bus = &maple_bus_type;       return driver_register(drv);}EXPORT_SYMBOL_GPL(maple_driver_register);/* set hardware registers to enable next round of dma */static void maplebus_dma_reset(void){       ctrl_outl(MAPLE_MAGIC, MAPLE_RESET);       /* set trig type to 0 for software trigger, 1 for hardware (VBLANK) */       ctrl_outl(1, MAPLE_TRIGTYPE);       ctrl_outl(MAPLE_2MBPS | MAPLE_TIMEOUT(50000), MAPLE_SPEED);       ctrl_outl(PHYSADDR(maple_sendbuf), MAPLE_DMAADDR);       ctrl_outl(1, MAPLE_ENABLE);}/** * maple_getcond_callback - setup handling MAPLE_COMMAND_GETCOND * @dev: device responding * @callback: handler callback * @interval: interval in jiffies between callbacks * @function: the function code for the device */void maple_getcond_callback(struct maple_device *dev,                           void (*callback) (struct mapleq * mq),                           unsigned long interval, unsigned long function){       dev->callback = callback;       dev->interval = interval;       dev->function = cpu_to_be32(function);       dev->when = jiffies;}EXPORT_SYMBOL_GPL(maple_getcond_callback);static int maple_dma_done(void){       return (ctrl_inl(MAPLE_STATE) & 1) == 0;}static void maple_release_device(struct device *dev){       if (dev->type) {               kfree(dev->type->name);               kfree(dev->type);       }}/** * maple_add_packet - add a single instruction to the queue * @mq: instruction to add to waiting queue */void maple_add_packet(struct mapleq *mq){       mutex_lock(&maple_list_lock);       list_add(&mq->list, &maple_waitq);       mutex_unlock(&maple_list_lock);}EXPORT_SYMBOL_GPL(maple_add_packet);static struct mapleq *maple_allocq(struct maple_device *dev){       struct mapleq *mq;       mq = kmalloc(sizeof(*mq), GFP_KERNEL);       if (!mq)               return NULL;       mq->dev = dev;       mq->recvbufdcsp = kmem_cache_zalloc(maple_queue_cache, GFP_KERNEL);       mq->recvbuf = (void *) P2SEGADDR(mq->recvbufdcsp);       if (!mq->recvbuf) {               kfree(mq);               return NULL;       }       return mq;}static struct maple_device *maple_alloc_dev(int port, int unit){       struct maple_device *dev;       dev = kzalloc(sizeof(*dev), GFP_KERNEL);       if (!dev)               return NULL;       dev->port = port;       dev->unit = unit;       dev->mq = maple_allocq(dev);       if (!dev->mq) {               kfree(dev);               return NULL;       }       return dev;}static void maple_free_dev(struct maple_device *mdev){       if (!mdev)               return;       if (mdev->mq) {               kmem_cache_free(maple_queue_cache, mdev->mq->recvbufdcsp);               kfree(mdev->mq);       }       kfree(mdev);}/* process the command queue into a maple command block * terminating command has bit 32 of first long set to 0 */static void maple_build_block(struct mapleq *mq){       int port, unit, from, to, len;       unsigned long *lsendbuf = mq->sendbuf;       port = mq->dev->port & 3;       unit = mq->dev->unit;       len = mq->length;       from = port << 6;       to = (port << 6) | (unit > 0 ? (1 << (unit - 1)) & 0x1f : 0x20);       *maple_lastptr &= 0x7fffffff;       maple_lastptr = maple_sendptr;       *maple_sendptr++ = (port << 16) | len | 0x80000000;       *maple_sendptr++ = PHYSADDR(mq->recvbuf);       *maple_sendptr++ =           mq->command | (to << 8) | (from << 16) | (len << 24);       while (len-- > 0)               *maple_sendptr++ = *lsendbuf++;}/* build up command queue */static void maple_send(void){       int i;       int maple_packets;       struct mapleq *mq, *nmq;       if (!list_empty(&maple_sentq))               return;       if (list_empty(&maple_waitq) || !maple_dma_done())               return;       maple_packets = 0;       maple_sendptr = maple_lastptr = maple_sendbuf;       list_for_each_entry_safe(mq, nmq, &maple_waitq, list) {               maple_build_block(mq);               list_move(&mq->list, &maple_sentq);               if (maple_packets++ > MAPLE_MAXPACKETS)                       break;       }       if (maple_packets > 0) {               for (i = 0; i < (1 << MAPLE_DMA_PAGES); i++)                       dma_cache_sync(0, maple_sendbuf + i * PAGE_SIZE,                                      PAGE_SIZE, DMA_BIDIRECTIONAL);       }}static int attach_matching_maple_driver(struct device_driver *driver,                                       void *devptr){       struct maple_driver *maple_drv;       struct maple_device *mdev;       mdev = devptr;       maple_drv = to_maple_driver(driver);       if (mdev->devinfo.function & be32_to_cpu(maple_drv->function)) {               if (maple_drv->connect(mdev) == 0) {                       mdev->driver = maple_drv;                       return 1;               }       }       return 0;}static void maple_detach_driver(struct maple_device *mdev){       if (!mdev)               return;       if (mdev->driver) {               if (mdev->driver->disconnect)                       mdev->driver->disconnect(mdev);       }       mdev->driver = NULL;       if (mdev->registered) {               maple_release_device(&mdev->dev);               device_unregister(&mdev->dev);       }       mdev->registered = 0;       maple_free_dev(mdev);}/* process initial MAPLE_COMMAND_DEVINFO for each device or port */static void maple_attach_driver(struct maple_device *dev){       char *p;       char *recvbuf;       unsigned long function;       int matched, retval;       recvbuf = dev->mq->recvbuf;       memcpy(&dev->devinfo, recvbuf + 4, sizeof(dev->devinfo));       memcpy(dev->product_name, dev->devinfo.product_name, 30);       memcpy(dev->product_licence, dev->devinfo.product_licence, 60);       dev->product_name[30] = '\0';       dev->product_licence[60] = '\0';       for (p = dev->product_name + 29; dev->product_name <= p; p--)               if (*p == ' ')                       *p = '\0';               else                       break;       for (p = dev->product_licence + 59; dev->product_licence <= p; p--)               if (*p == ' ')                       *p = '\0';               else                       break;       function = be32_to_cpu(dev->devinfo.function);       if (function > 0x200) {               /* Do this silently - as not a real device */               function = 0;               dev->driver = &maple_dummy_driver;               sprintf(dev->dev.bus_id, "%d:0.port", dev->port);       } else {               printk(KERN_INFO                      "Maple bus at (%d, %d): Connected function 0x%lX\n",                      dev->port, dev->unit, function);               matched =                   bus_for_each_drv(&maple_bus_type, NULL, dev,                                    attach_matching_maple_driver);               if (matched == 0) {                       /* Driver does not exist yet */                       printk(KERN_INFO                              "No maple driver found for this device\n");                       dev->driver = &maple_dummy_driver;               }               sprintf(dev->dev.bus_id, "%d:0%d.%lX", dev->port,                       dev->unit, function);       }       dev->function = function;       dev->dev.bus = &maple_bus_type;       dev->dev.parent = &maple_bus;       dev->dev.release = &maple_release_device;       retval = device_register(&dev->dev);       if (retval) {               printk(KERN_INFO                      "Maple bus: Attempt to register device (%x, %x) failed.\n",                      dev->port, dev->unit);               maple_free_dev(dev);       }       dev->registered = 1;}/* * if device has been registered for the given * port and unit then return 1 - allows identification * of which devices need to be attached or detached */static int detach_maple_device(struct device *device, void *portptr){       struct maple_device_specify *ds;       struct maple_device *mdev;       ds = portptr;       mdev = to_maple_dev(device);       if (mdev->port == ds->port && mdev->unit == ds->unit)               return 1;       return 0;}static int setup_maple_commands(struct device *device, void *ignored){       struct maple_device *maple_dev = to_maple_dev(device);       if ((maple_dev->interval > 0)           && time_after(jiffies, maple_dev->when)) {               maple_dev->when = jiffies + maple_dev->interval;               maple_dev->mq->command = MAPLE_COMMAND_GETCOND;               maple_dev->mq->sendbuf = &maple_dev->function;               maple_dev->mq->length = 1;               maple_add_packet(maple_dev->mq);               liststatus++;       } else {               if (time_after(jiffies, maple_pnp_time)) {                       maple_dev->mq->command = MAPLE_COMMAND_DEVINFO;                       maple_dev->mq->length = 0;

⌨️ 快捷键说明

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