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 = &yenta_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 (&yenta_cardbus_driver);}static void __exit yenta_socket_exit (void){	pci_unregister_driver (&yenta_cardbus_driver);}module_init(yenta_socket_init);module_exit(yenta_socket_exit);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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