yenta_socket.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,148 行 · 第 1/3 页
C
1,148 行
exca_writeb(socket, I365_CSCINT, I365_CSC_STSCHG | (i << 4)); cb_writel(socket, CB_SOCKET_FORCE, CB_FCARDSTS); udelay(100); cb_writel(socket, CB_SOCKET_EVENT, -1); } cb_writel(socket, CB_SOCKET_MASK, 0); exca_writeb(socket, I365_CSCINT, 0); mask = probe_irq_mask(val) & 0xffff; bridge_ctrl &= ~CB_BRIDGE_INTR; config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl); return mask;}/* interrupt handler, only used during probing */static irqreturn_t yenta_probe_handler(int irq, void *dev_id, struct pt_regs *regs){ struct yenta_socket *socket = (struct yenta_socket *) dev_id; u8 csc; u32 cb_event; /* Clear interrupt status for the event */ cb_event = cb_readl(socket, CB_SOCKET_EVENT); cb_writel(socket, CB_SOCKET_EVENT, -1); csc = exca_readb(socket, I365_CSC); if (cb_event || csc) { socket->probe_status = 1; return IRQ_HANDLED; } return IRQ_NONE;}/* probes the PCI interrupt, use only on override functions */static int yenta_probe_cb_irq(struct yenta_socket *socket){ u16 bridge_ctrl; if (!socket->cb_irq) return -1; socket->probe_status = 0; /* disable ISA interrupts */ bridge_ctrl = config_readw(socket, CB_BRIDGE_CONTROL); bridge_ctrl &= ~CB_BRIDGE_INTR; config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl); if (request_irq(socket->cb_irq, yenta_probe_handler, SA_SHIRQ, "yenta", socket)) { printk(KERN_WARNING "Yenta: request_irq() in yenta_probe_cb_irq() failed!\n"); return -1; } /* generate interrupt, wait */ exca_writeb(socket, I365_CSCINT, I365_CSC_STSCHG); cb_writel(socket, CB_SOCKET_EVENT, -1); cb_writel(socket, CB_SOCKET_MASK, CB_CSTSMASK); cb_writel(socket, CB_SOCKET_FORCE, CB_FCARDSTS); set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/10); /* disable interrupts */ cb_writel(socket, CB_SOCKET_MASK, 0); exca_writeb(socket, I365_CSCINT, 0); cb_writel(socket, CB_SOCKET_EVENT, -1); exca_readb(socket, I365_CSC); free_irq(socket->cb_irq, socket); return (int) socket->probe_status;}/* * Set static data that doesn't need re-initializing.. */static void yenta_get_socket_capabilities(struct yenta_socket *socket, u32 isa_irq_mask){ socket->socket.features |= SS_CAP_PAGE_REGS | SS_CAP_PCCARD | SS_CAP_CARDBUS; socket->socket.map_size = 0x1000; socket->socket.pci_irq = socket->cb_irq; socket->socket.irq_mask = yenta_probe_irq(socket, isa_irq_mask); socket->socket.cb_dev = socket->dev; printk(KERN_INFO "Yenta: ISA IRQ mask 0x%04x, PCI irq %d\n", socket->socket.irq_mask, socket->cb_irq);}/* * Initialize the standard cardbus registers */static void yenta_config_init(struct yenta_socket *socket){ u16 bridge; struct pci_dev *dev = socket->dev; pci_set_power_state(socket->dev, 0); config_writel(socket, CB_LEGACY_MODE_BASE, 0); config_writel(socket, PCI_BASE_ADDRESS_0, dev->resource[0].start); config_writew(socket, PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_WAIT); /* MAGIC NUMBERS! Fixme */ config_writeb(socket, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES / 4); config_writeb(socket, PCI_LATENCY_TIMER, 168); config_writel(socket, PCI_PRIMARY_BUS, (176 << 24) | /* sec. latency timer */ (dev->subordinate->subordinate << 16) | /* subordinate bus */ (dev->subordinate->secondary << 8) | /* secondary bus */ dev->subordinate->primary); /* primary bus */ /* * Set up the bridging state: * - enable write posting. * - memory window 0 prefetchable, window 1 non-prefetchable * - PCI interrupts enabled if a PCI interrupt exists.. */ bridge = config_readw(socket, CB_BRIDGE_CONTROL); bridge &= ~(CB_BRIDGE_CRST | CB_BRIDGE_PREFETCH1 | CB_BRIDGE_INTR | CB_BRIDGE_ISAEN | CB_BRIDGE_VGAEN); bridge |= CB_BRIDGE_PREFETCH0 | CB_BRIDGE_POSTEN | CB_BRIDGE_INTR; config_writew(socket, CB_BRIDGE_CONTROL, bridge);}/* * Initialize a cardbus controller. Make sure we have a usable * interrupt, and that we can map the cardbus area. Fill in the * socket information structure.. */static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_id *id){ struct yenta_socket *socket; int ret; socket = kmalloc(sizeof(struct yenta_socket), GFP_KERNEL); if (!socket) return -ENOMEM; memset(socket, 0, sizeof(*socket)); /* prepare pcmcia_socket */ socket->socket.ops = ¥ta_socket_operations; socket->socket.dev.dev = &dev->dev; socket->socket.driver_data = socket; socket->socket.owner = THIS_MODULE; /* prepare struct yenta_socket */ socket->dev = dev; pci_set_drvdata(dev, socket); /* * Do some basic sanity checking.. */ if (pci_enable_device(dev)) { ret = -EBUSY; goto free; } ret = pci_request_regions(dev, "yenta_socket"); if (ret) goto disable; if (!pci_resource_start(dev, 0)) { printk(KERN_ERR "No cardbus resource!\n"); ret = -ENODEV; goto release; } /* * Ok, start setup.. Map the cardbus registers, * and request the IRQ. */ socket->base = ioremap(pci_resource_start(dev, 0), 0x1000); if (!socket->base) { ret = -ENOMEM; goto release; } /* * report the subsystem vendor and device for help debugging * the irq stuff... */ printk(KERN_INFO "Yenta: CardBus bridge found at %s [%04x:%04x]\n", dev->slot_name, dev->subsystem_vendor, dev->subsystem_device); yenta_config_init(socket); /* Disable all events */ cb_writel(socket, CB_SOCKET_MASK, 0x0); /* Set up the bridge regions.. */ yenta_allocate_resources(socket); socket->cb_irq = dev->irq; /* Do we have special options for the device? */ if (id->driver_data != CARDBUS_TYPE_DEFAULT && id->driver_data < ARRAY_SIZE(cardbus_type)) { socket->type = &cardbus_type[id->driver_data]; ret = socket->type->override(socket); if (ret < 0) goto unmap; } /* We must finish initialization here */ if (!socket->cb_irq || request_irq(socket->cb_irq, yenta_interrupt, SA_SHIRQ, "yenta", socket)) { /* No IRQ or request_irq failed. Poll */ socket->cb_irq = 0; /* But zero is a valid IRQ number. */ init_timer(&socket->poll_timer); socket->poll_timer.function = yenta_interrupt_wrapper; socket->poll_timer.data = (unsigned long)socket; socket->poll_timer.expires = jiffies + HZ; add_timer(&socket->poll_timer); } /* Figure out what the dang thing can do for the PCMCIA layer... */ yenta_get_socket_capabilities(socket, isa_interrupts); printk(KERN_INFO "Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE)); /* Register it with the pcmcia layer.. */ ret = pcmcia_register_socket(&socket->socket); if (ret == 0) goto out; unmap: iounmap(socket->base); release: pci_release_regions(dev); disable: pci_disable_device(dev); free: kfree(socket); out: return ret;}static int yenta_dev_suspend (struct pci_dev *dev, u32 state){ struct yenta_socket *socket = pci_get_drvdata(dev); int ret; ret = pcmcia_socket_dev_suspend(&dev->dev, state); if (socket) { if (socket->type && socket->type->save_state) socket->type->save_state(socket); /* FIXME: pci_save_state needs to have a better interface */ pci_save_state(dev, socket->saved_state); pci_read_config_dword(dev, 16*4, &socket->saved_state[16]); pci_read_config_dword(dev, 17*4, &socket->saved_state[17]); pci_set_power_state(dev, 3); } return ret;}static int yenta_dev_resume (struct pci_dev *dev){ struct yenta_socket *socket = pci_get_drvdata(dev); if (socket) { pci_set_power_state(dev, 0); /* FIXME: pci_restore_state needs to have a better interface */ pci_restore_state(dev, socket->saved_state); pci_write_config_dword(dev, 16*4, socket->saved_state[16]); pci_write_config_dword(dev, 17*4, socket->saved_state[17]); if (socket->type && socket->type->restore_state) socket->type->restore_state(socket); } return pcmcia_socket_dev_resume(&dev->dev);}#define CB_ID(vend,dev,type) \ { \ .vendor = vend, \ .device = dev, \ .subvendor = PCI_ANY_ID, \ .subdevice = PCI_ANY_ID, \ .class = PCI_CLASS_BRIDGE_CARDBUS << 8, \ .class_mask = ~0, \ .driver_data = CARDBUS_TYPE_##type, \ }static struct pci_device_id yenta_table [] = { CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1031, TI), /* * TBD: Check if these TI variants can use more * advanced overrides instead. (I can't get the * data sheets for these devices. --rmk) */ CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1210, TI), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1130, TI113X), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1131, TI113X), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1211, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1220, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1221, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1225, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1251A, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1251B, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1420, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1450, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1451A, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1510, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1520, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1620, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4410, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4450, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4451, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4520, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1250, TI1250), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1410, TI1250), CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1211, TI12XX), CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1225, TI12XX), CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1410, TI1250), CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1420, TI12XX), CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C465, RICOH), CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C466, RICOH), CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C475, RICOH), CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, RICOH), CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C478, RICOH), CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC97, TOPIC97), CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC100, TOPIC97), CB_ID(PCI_VENDOR_ID_O2, PCI_ANY_ID, O2MICRO), /* match any cardbus bridge */ CB_ID(PCI_ANY_ID, PCI_ANY_ID, DEFAULT), { /* all zeroes */ }};MODULE_DEVICE_TABLE(pci, yenta_table);static struct pci_driver yenta_cardbus_driver = { .name = "yenta_cardbus", .id_table = yenta_table, .probe = yenta_probe, .remove = __devexit_p(yenta_close), .suspend = yenta_dev_suspend, .resume = yenta_dev_resume,};static int __init yenta_socket_init(void){ return pci_register_driver (¥ta_cardbus_driver);}static void __exit yenta_socket_exit (void){ pci_unregister_driver (¥ta_cardbus_driver);}module_init(yenta_socket_init);module_exit(yenta_socket_exit);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?