i82092.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 809 行 · 第 1/2 页

C
809
字号
/*  * Driver for Intel I82092AA PCI-PCMCIA bridge. * * (C) 2001 Red Hat, Inc. * * Author: Arjan Van De Ven <arjanv@redhat.com> * Loosly based on i82365.c from the pcmcia-cs package * * $Id: i82092aa.c,v 1.2 2001/10/23 14:43:34 arjanv Exp $ */#include <linux/kernel.h>#include <linux/config.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/workqueue.h>#include <linux/interrupt.h>#include <linux/device.h>#include <pcmcia/cs_types.h>#include <pcmcia/ss.h>#include <pcmcia/cs.h>#include <asm/system.h>#include <asm/io.h>#include "i82092aa.h"#include "i82365.h"MODULE_LICENSE("GPL");/* PCI core routines */static struct pci_device_id i82092aa_pci_ids[] = {	{	      .vendor = PCI_VENDOR_ID_INTEL,	      .device = PCI_DEVICE_ID_INTEL_82092AA_0,	      .subvendor = PCI_ANY_ID,	      .subdevice = PCI_ANY_ID,	 },	 {} };MODULE_DEVICE_TABLE(pci, i82092aa_pci_ids);static int i82092aa_socket_suspend (struct pci_dev *dev, u32 state){	return pcmcia_socket_dev_suspend(&dev->dev, state);}static int i82092aa_socket_resume (struct pci_dev *dev){	return pcmcia_socket_dev_resume(&dev->dev);}static struct pci_driver i82092aa_pci_drv = {	.name           = "i82092aa",	.id_table       = i82092aa_pci_ids,	.probe          = i82092aa_pci_probe,	.remove         = __devexit_p(i82092aa_pci_remove),	.suspend        = i82092aa_socket_suspend,	.resume         = i82092aa_socket_resume,};/* the pccard structure and its functions */static struct pccard_operations i82092aa_operations = {	.init 		 	= i82092aa_init,	.suspend	   	= i82092aa_suspend,	.get_status		= i82092aa_get_status,	.get_socket		= i82092aa_get_socket,	.set_socket		= i82092aa_set_socket,	.set_io_map		= i82092aa_set_io_map,	.set_mem_map		= i82092aa_set_mem_map,};/* The card can do upto 4 sockets, allocate a structure for each of them */struct socket_info {	int	number;	int	card_state; 	/*  0 = no socket,				    1 = empty socket, 				    2 = card but not initialized,				    3 = operational card */	int 	io_base; 	/* base io address of the socket */		struct pcmcia_socket socket;	struct pci_dev *dev;	/* The PCI device for the socket */};#define MAX_SOCKETS 4static struct socket_info sockets[MAX_SOCKETS];static int socket_count;  /* shortcut */                                  	                                	static int __devinit i82092aa_pci_probe(struct pci_dev *dev, const struct pci_device_id *id){	unsigned char configbyte;	int i, ret;		enter("i82092aa_pci_probe");		if ((ret = pci_enable_device(dev)))		return ret;			pci_read_config_byte(dev, 0x40, &configbyte);  /* PCI Configuration Control */	switch(configbyte&6) {		case 0:			socket_count = 2;			break;		case 2:			socket_count = 1;			break;		case 4:		case 6:			socket_count = 4;			break;					default:			printk(KERN_ERR "i82092aa: Oops, you did something we didn't think of.\n");			ret = -EIO;			goto err_out_disable;	}	printk(KERN_INFO "i82092aa: configured as a %d socket device.\n", socket_count);	if (request_region(pci_resource_start(dev, 0), 2, "i82092aa")) {		ret = -EBUSY;		goto err_out_disable;	}		for (i = 0;i<socket_count;i++) {		sockets[i].card_state = 1; /* 1 = present but empty */		sockets[i].io_base = pci_resource_start(dev, 0);		sockets[i].socket.features |= SS_CAP_PCCARD;		sockets[i].socket.map_size = 0x1000;		sockets[i].socket.irq_mask = 0;		sockets[i].socket.pci_irq  = dev->irq;		sockets[i].socket.owner = THIS_MODULE;		sockets[i].number = i;				if (card_present(i)) {			sockets[i].card_state = 3;			dprintk(KERN_DEBUG "i82092aa: slot %i is occupied\n",i);		} else {			dprintk(KERN_DEBUG "i82092aa: slot %i is vacant\n",i);		}	}			/* Now, specifiy that all interrupts are to be done as PCI interrupts */	configbyte = 0xFF; /* bitmask, one bit per event, 1 = PCI interrupt, 0 = ISA interrupt */	pci_write_config_byte(dev, 0x50, configbyte); /* PCI Interrupt Routing Register */	/* Register the interrupt handler */	dprintk(KERN_DEBUG "Requesting interrupt %i \n",dev->irq);	if ((ret = request_irq(dev->irq, i82092aa_interrupt, SA_SHIRQ, "i82092aa", i82092aa_interrupt))) {		printk(KERN_ERR "i82092aa: Failed to register IRQ %d, aborting\n", dev->irq);		goto err_out_free_res;	}	pci_set_drvdata(dev, &sockets[i].socket);	for (i = 0; i<socket_count; i++) {		sockets[i].socket.dev.dev = &dev->dev;		sockets[i].socket.ops = &i82092aa_operations;		ret = pcmcia_register_socket(&sockets[i].socket);		if (ret) {			goto err_out_free_sockets;		}	}	leave("i82092aa_pci_probe");	return 0;err_out_free_sockets:	if (i) {		for (i--;i>=0;i--) {			pcmcia_unregister_socket(&sockets[i].socket);		}	}	free_irq(dev->irq, i82092aa_interrupt);err_out_free_res:	release_region(pci_resource_start(dev, 0), 2);err_out_disable:	pci_disable_device(dev);	return ret;			}static void __devexit i82092aa_pci_remove(struct pci_dev *dev){	struct pcmcia_socket *socket = pci_get_drvdata(dev);	enter("i82092aa_pci_remove");		free_irq(dev->irq, i82092aa_interrupt);	if (socket)		pcmcia_unregister_socket(socket);	leave("i82092aa_pci_remove");}static spinlock_t port_lock = SPIN_LOCK_UNLOCKED;/* basic value read/write functions */static unsigned char indirect_read(int socket, unsigned short reg){	unsigned short int port;	unsigned char val;	unsigned long flags;	spin_lock_irqsave(&port_lock,flags);	reg += socket * 0x40;	port = sockets[socket].io_base;	outb(reg,port);	val = inb(port+1);	spin_unlock_irqrestore(&port_lock,flags);	return val;}#if 0static unsigned short indirect_read16(int socket, unsigned short reg){	unsigned short int port;	unsigned short tmp;	unsigned long flags;	spin_lock_irqsave(&port_lock,flags);	reg  = reg + socket * 0x40;	port = sockets[socket].io_base;	outb(reg,port);	tmp = inb(port+1);	reg++;	outb(reg,port);	tmp = tmp | (inb(port+1)<<8);	spin_unlock_irqrestore(&port_lock,flags);	return tmp;}#endifstatic void indirect_write(int socket, unsigned short reg, unsigned char value){	unsigned short int port;	unsigned long flags;	spin_lock_irqsave(&port_lock,flags);	reg = reg + socket * 0x40;	port = sockets[socket].io_base; 	outb(reg,port);	outb(value,port+1);	spin_unlock_irqrestore(&port_lock,flags);}static void indirect_setbit(int socket, unsigned short reg, unsigned char mask){	unsigned short int port;	unsigned char val;	unsigned long flags;	spin_lock_irqsave(&port_lock,flags);	reg = reg + socket * 0x40;	port = sockets[socket].io_base; 	outb(reg,port);	val = inb(port+1);	val |= mask;	outb(reg,port);	outb(val,port+1);	spin_unlock_irqrestore(&port_lock,flags);}static void indirect_resetbit(int socket, unsigned short reg, unsigned char mask){	unsigned short int port;	unsigned char val;	unsigned long flags;	spin_lock_irqsave(&port_lock,flags);	reg = reg + socket * 0x40;	port = sockets[socket].io_base; 	outb(reg,port);	val = inb(port+1);	val &= ~mask;	outb(reg,port);	outb(val,port+1);	spin_unlock_irqrestore(&port_lock,flags);}static void indirect_write16(int socket, unsigned short reg, unsigned short value){	unsigned short int port;	unsigned char val;	unsigned long flags;	spin_lock_irqsave(&port_lock,flags);	reg = reg + socket * 0x40;	port = sockets[socket].io_base; 		outb(reg,port);	val = value & 255;	outb(val,port+1);		reg++;		outb(reg,port);	val = value>>8;	outb(val,port+1);	spin_unlock_irqrestore(&port_lock,flags);}/* simple helper functions *//* External clock time, in nanoseconds.  120 ns = 8.33 MHz */static int cycle_time = 120;static int to_cycles(int ns){	if (cycle_time!=0)		return ns/cycle_time;	else		return 0;}    /* Interrupt handler functionality */static irqreturn_t i82092aa_interrupt(int irq, void *dev, struct pt_regs *regs){	int i;	int loopcount = 0;	int handled = 0;	unsigned int events, active=0;	/*	enter("i82092aa_interrupt");*/		while (1) {		loopcount++;		if (loopcount>20) {			printk(KERN_ERR "i82092aa: infinite eventloop in interrupt \n");			break;		}				active = 0;				for (i=0;i<socket_count;i++) {			int csc;			if (sockets[i].card_state==0) /* Inactive socket, should not happen */				continue;						csc = indirect_read(i,I365_CSC); /* card status change register */						if (csc==0)  /* no events on this socket */			   	continue;			handled = 1;			events = 0;			 			if (csc & I365_CSC_DETECT) {				events |= SS_DETECT;				printk("Card detected in socket %i!\n",i);			 }						if (indirect_read(i,I365_INTCTL) & I365_PC_IOCARD) { 				/* For IO/CARDS, bit 0 means "read the card" */				events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0; 			} else {				/* Check for battery/ready events */				events |= (csc & I365_CSC_BVD1) ? SS_BATDEAD : 0;				events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0;				events |= (csc & I365_CSC_READY) ? SS_READY : 0;			}						if (events) {				pcmcia_parse_events(&sockets[i].socket, events);			}			active |= events;		}						if (active==0) /* no more events to handle */			break;							}	return IRQ_RETVAL(handled);/*	leave("i82092aa_interrupt");*/}/* socket functions */static int card_present(int socketno){		unsigned int val;	enter("card_present");		if ((socketno<0) || (socketno >= MAX_SOCKETS))		return 0;	if (sockets[socketno].io_base == 0)		return 0;			val = indirect_read(socketno, 1); /* Interface status register */	if ((val&12)==12) {		leave("card_present 1");		return 1;	}			leave("card_present 0");	return 0;}static void set_bridge_state(int sock)

⌨️ 快捷键说明

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