zatm.c

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

C
1,628
字号
			if (reason & 2) poll_rx(dev,1);			if (reason & 4) poll_tx(dev,2);			if (reason & 8) poll_tx(dev,3);		}		/* @@@ handle RCRn */	}	return IRQ_RETVAL(handled);}/*----------------------------- (E)EPROM access -----------------------------*/static void __init eprom_set(struct zatm_dev *zatm_dev,unsigned long value,    unsigned short cmd){	int error;	if ((error = pci_write_config_dword(zatm_dev->pci_dev,cmd,value)))		printk(KERN_ERR DEV_LABEL ": PCI write failed (0x%02x)\n",		    error);}static unsigned long __init eprom_get(struct zatm_dev *zatm_dev,    unsigned short cmd){	unsigned int value;	int error;	if ((error = pci_read_config_dword(zatm_dev->pci_dev,cmd,&value)))		printk(KERN_ERR DEV_LABEL ": PCI read failed (0x%02x)\n",		    error);	return value;}static void __init eprom_put_bits(struct zatm_dev *zatm_dev,    unsigned long data,int bits,unsigned short cmd){	unsigned long value;	int i;	for (i = bits-1; i >= 0; i--) {		value = ZEPROM_CS | (((data >> i) & 1) ? ZEPROM_DI : 0);		eprom_set(zatm_dev,value,cmd);		eprom_set(zatm_dev,value | ZEPROM_SK,cmd);		eprom_set(zatm_dev,value,cmd);	}}static void __init eprom_get_byte(struct zatm_dev *zatm_dev,    unsigned char *byte,unsigned short cmd){	int i;	*byte = 0;	for (i = 8; i; i--) {		eprom_set(zatm_dev,ZEPROM_CS,cmd);		eprom_set(zatm_dev,ZEPROM_CS | ZEPROM_SK,cmd);		*byte <<= 1;		if (eprom_get(zatm_dev,cmd) & ZEPROM_DO) *byte |= 1;		eprom_set(zatm_dev,ZEPROM_CS,cmd);	}}static unsigned char __init eprom_try_esi(struct atm_dev *dev,    unsigned short cmd,int offset,int swap){	unsigned char buf[ZEPROM_SIZE];	struct zatm_dev *zatm_dev;	int i;	zatm_dev = ZATM_DEV(dev);	for (i = 0; i < ZEPROM_SIZE; i += 2) {		eprom_set(zatm_dev,ZEPROM_CS,cmd); /* select EPROM */		eprom_put_bits(zatm_dev,ZEPROM_CMD_READ,ZEPROM_CMD_LEN,cmd);		eprom_put_bits(zatm_dev,i >> 1,ZEPROM_ADDR_LEN,cmd);		eprom_get_byte(zatm_dev,buf+i+swap,cmd);		eprom_get_byte(zatm_dev,buf+i+1-swap,cmd);		eprom_set(zatm_dev,0,cmd); /* deselect EPROM */	}	memcpy(dev->esi,buf+offset,ESI_LEN);	return memcmp(dev->esi,"\0\0\0\0\0",ESI_LEN); /* assumes ESI_LEN == 6 */}static void __init eprom_get_esi(struct atm_dev *dev){	if (eprom_try_esi(dev,ZEPROM_V1_REG,ZEPROM_V1_ESI_OFF,1)) return;	(void) eprom_try_esi(dev,ZEPROM_V2_REG,ZEPROM_V2_ESI_OFF,0);}/*--------------------------------- entries ---------------------------------*/static int __init zatm_init(struct atm_dev *dev){	struct zatm_dev *zatm_dev;	struct pci_dev *pci_dev;	unsigned short command;	unsigned char revision;	int error,i,last;	unsigned long t0,t1,t2;	DPRINTK(">zatm_init\n");	zatm_dev = ZATM_DEV(dev);	spin_lock_init(&zatm_dev->lock);	pci_dev = zatm_dev->pci_dev;	zatm_dev->base = pci_resource_start(pci_dev, 0);	zatm_dev->irq = pci_dev->irq;	if ((error = pci_read_config_word(pci_dev,PCI_COMMAND,&command)) ||	    (error = pci_read_config_byte(pci_dev,PCI_REVISION_ID,&revision))) {		printk(KERN_ERR DEV_LABEL "(itf %d): init error 0x%02x\n",		    dev->number,error);		return -EINVAL;	}	if ((error = pci_write_config_word(pci_dev,PCI_COMMAND,	    command | PCI_COMMAND_IO | PCI_COMMAND_MASTER))) {		printk(KERN_ERR DEV_LABEL "(itf %d): can't enable IO (0x%02x)"		    "\n",dev->number,error);		return -EIO;	}	eprom_get_esi(dev);	printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d,base=0x%x,irq=%d,",	    dev->number,revision,zatm_dev->base,zatm_dev->irq);	/* reset uPD98401 */	zout(0,SWR);	while (!(zin(GSR) & uPD98401_INT_IND));	zout(uPD98401_GMR_ONE /*uPD98401_BURST4*/,GMR);	last = MAX_CRAM_SIZE;	for (i = last-RAM_INCREMENT; i >= 0; i -= RAM_INCREMENT) {		zpokel(zatm_dev,0x55555555,i);		if (zpeekl(zatm_dev,i) != 0x55555555) last = i;		else {			zpokel(zatm_dev,0xAAAAAAAA,i);			if (zpeekl(zatm_dev,i) != 0xAAAAAAAA) last = i;			else zpokel(zatm_dev,i,i);		}	}	for (i = 0; i < last; i += RAM_INCREMENT)		if (zpeekl(zatm_dev,i) != i) break;	zatm_dev->mem = i << 2;	while (i) zpokel(zatm_dev,0,--i);	/* reset again to rebuild memory pointers */	zout(0,SWR);	while (!(zin(GSR) & uPD98401_INT_IND));	zout(uPD98401_GMR_ONE | uPD98401_BURST8 | uPD98401_BURST4 |	    uPD98401_BURST2 | uPD98401_GMR_PM | uPD98401_GMR_DR,GMR);	/* TODO: should shrink allocation now */	printk("mem=%dkB,%s (",zatm_dev->mem >> 10,zatm_dev->copper ? "UTP" :	    "MMF");	for (i = 0; i < ESI_LEN; i++)		printk("%02X%s",dev->esi[i],i == ESI_LEN-1 ? ")\n" : "-");	do {		unsigned long flags;		spin_lock_irqsave(&zatm_dev->lock, flags);		t0 = zpeekl(zatm_dev,uPD98401_TSR);		udelay(10);		t1 = zpeekl(zatm_dev,uPD98401_TSR);		udelay(1010);		t2 = zpeekl(zatm_dev,uPD98401_TSR);		spin_unlock_irqrestore(&zatm_dev->lock, flags);	}	while (t0 > t1 || t1 > t2); /* loop if wrapping ... */	zatm_dev->khz = t2-2*t1+t0;	printk(KERN_NOTICE DEV_LABEL "(itf %d): uPD98401 %d.%d at %d.%03d "	    "MHz\n",dev->number,	    (zin(VER) & uPD98401_MAJOR) >> uPD98401_MAJOR_SHIFT,            zin(VER) & uPD98401_MINOR,zatm_dev->khz/1000,zatm_dev->khz % 1000);	return uPD98402_init(dev);}static int __init zatm_start(struct atm_dev *dev){	struct zatm_dev *zatm_dev;	unsigned long curr;	int pools,vccs,rx;	int error,i,ld;	DPRINTK("zatm_start\n");	zatm_dev = ZATM_DEV(dev);	zatm_dev->rx_map = zatm_dev->tx_map = NULL;	for (i = 0; i < NR_MBX; i++)		zatm_dev->mbx_start[i] = 0;	if (request_irq(zatm_dev->irq,&zatm_int,SA_SHIRQ,DEV_LABEL,dev)) {		printk(KERN_ERR DEV_LABEL "(itf %d): IRQ%d is already in use\n",		    dev->number,zatm_dev->irq);		return -EAGAIN;	}	request_region(zatm_dev->base,uPD98401_PORTS,DEV_LABEL);	/* define memory regions */	pools = NR_POOLS;	if (NR_SHAPERS*SHAPER_SIZE > pools*POOL_SIZE)		pools = NR_SHAPERS*SHAPER_SIZE/POOL_SIZE;	vccs = (zatm_dev->mem-NR_SHAPERS*SHAPER_SIZE-pools*POOL_SIZE)/	    (2*VC_SIZE+RX_SIZE);	ld = -1;	for (rx = 1; rx < vccs; rx <<= 1) ld++;	dev->ci_range.vpi_bits = 0; /* @@@ no VPI for now */	dev->ci_range.vci_bits = ld;	dev->link_rate = ATM_OC3_PCR;	zatm_dev->chans = vccs; /* ??? */	curr = rx*RX_SIZE/4;	DPRINTK("RX pool 0x%08lx\n",curr);	zpokel(zatm_dev,curr,uPD98401_PMA); /* receive pool */	zatm_dev->pool_base = curr;	curr += pools*POOL_SIZE/4;	DPRINTK("Shapers 0x%08lx\n",curr);	zpokel(zatm_dev,curr,uPD98401_SMA); /* shapers */	curr += NR_SHAPERS*SHAPER_SIZE/4;	DPRINTK("Free    0x%08lx\n",curr);	zpokel(zatm_dev,curr,uPD98401_TOS); /* free pool */	printk(KERN_INFO DEV_LABEL "(itf %d): %d shapers, %d pools, %d RX, "	    "%ld VCs\n",dev->number,NR_SHAPERS,pools,rx,	    (zatm_dev->mem-curr*4)/VC_SIZE);	/* create mailboxes */	for (i = 0; i < NR_MBX; i++)		if (mbx_entries[i]) {			unsigned long here;			here = (unsigned long) kmalloc(2*MBX_SIZE(i),			    GFP_KERNEL);			if (!here) {				error = -ENOMEM;				goto out;			}			if ((here^(here+MBX_SIZE(i))) & ~0xffffUL)/* paranoia */				here = (here & ~0xffffUL)+0x10000;			zatm_dev->mbx_start[i] = here;			if ((here^virt_to_bus((void *) here)) & 0xffff) {				printk(KERN_ERR DEV_LABEL "(itf %d): system "				    "bus incompatible with driver\n",				    dev->number);				error = -ENODEV;				goto out;			}			DPRINTK("mbx@0x%08lx-0x%08lx\n",here,here+MBX_SIZE(i));			zatm_dev->mbx_end[i] = (here+MBX_SIZE(i)) & 0xffff;			zout(virt_to_bus((void *) here) >> 16,MSH(i));			zout(virt_to_bus((void *) here),MSL(i));			zout((here+MBX_SIZE(i)) & 0xffff,MBA(i));			zout(here & 0xffff,MTA(i));			zout(here & 0xffff,MWA(i));		}	error = start_tx(dev);	if (error) goto out;	error = start_rx(dev);	if (error) goto out;	error = dev->phy->start(dev);	if (error) goto out;	zout(0xffffffff,IMR); /* enable interrupts */	/* enable TX & RX */	zout(zin(GMR) | uPD98401_GMR_SE | uPD98401_GMR_RE,GMR);	return 0;    out:	for (i = 0; i < NR_MBX; i++)		if (zatm_dev->mbx_start[i] != 0)			kfree((void *) zatm_dev->mbx_start[i]);	if (zatm_dev->rx_map != NULL)		kfree(zatm_dev->rx_map);	if (zatm_dev->tx_map != NULL)		kfree(zatm_dev->tx_map);	free_irq(zatm_dev->irq, dev);	return error;}static void zatm_close(struct atm_vcc *vcc){        DPRINTK(">zatm_close\n");        if (!ZATM_VCC(vcc)) return;	clear_bit(ATM_VF_READY,&vcc->flags);        close_rx(vcc);	EVENT("close_tx\n",0,0);        close_tx(vcc);        DPRINTK("zatm_close: done waiting\n");        /* deallocate memory */        kfree(ZATM_VCC(vcc));	vcc->dev_data = NULL;	clear_bit(ATM_VF_ADDR,&vcc->flags);}static int zatm_open(struct atm_vcc *vcc){	struct zatm_dev *zatm_dev;	struct zatm_vcc *zatm_vcc;	short vpi = vcc->vpi;	int vci = vcc->vci;	int error;	DPRINTK(">zatm_open\n");	zatm_dev = ZATM_DEV(vcc->dev);	if (!test_bit(ATM_VF_PARTIAL,&vcc->flags))		vcc->dev_data = NULL;	if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC)		set_bit(ATM_VF_ADDR,&vcc->flags);	if (vcc->qos.aal != ATM_AAL5) return -EINVAL; /* @@@ AAL0 */	DPRINTK(DEV_LABEL "(itf %d): open %d.%d\n",vcc->dev->number,vcc->vpi,	    vcc->vci);	if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) {		zatm_vcc = kmalloc(sizeof(struct zatm_vcc),GFP_KERNEL);		if (!zatm_vcc) {			clear_bit(ATM_VF_ADDR,&vcc->flags);			return -ENOMEM;		}		vcc->dev_data = zatm_vcc;		ZATM_VCC(vcc)->tx_chan = 0; /* for zatm_close after open_rx */		if ((error = open_rx_first(vcc))) {	                zatm_close(vcc);	                return error;	        }		if ((error = open_tx_first(vcc))) {			zatm_close(vcc);			return error;	        }	}	if (vci == ATM_VPI_UNSPEC || vpi == ATM_VCI_UNSPEC) return 0;	if ((error = open_rx_second(vcc))) {		zatm_close(vcc);		return error;        }	if ((error = open_tx_second(vcc))) {		zatm_close(vcc);		return error;        }	set_bit(ATM_VF_READY,&vcc->flags);        return 0;}static int zatm_change_qos(struct atm_vcc *vcc,struct atm_qos *qos,int flags){	printk("Not yet implemented\n");	return -ENOSYS;	/* @@@ */}static int zatm_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg){	struct zatm_dev *zatm_dev;	unsigned long flags;	zatm_dev = ZATM_DEV(dev);	switch (cmd) {		case ZATM_GETPOOLZ:			if (!capable(CAP_NET_ADMIN)) return -EPERM;			/* fall through */		case ZATM_GETPOOL:			{				struct zatm_pool_info info;				int pool;				if (get_user(pool,				    &((struct zatm_pool_req __user *) arg)->pool_num))					return -EFAULT;				if (pool < 0 || pool > ZATM_LAST_POOL)					return -EINVAL;				spin_lock_irqsave(&zatm_dev->lock, flags);				info = zatm_dev->pool_info[pool];				if (cmd == ZATM_GETPOOLZ) {					zatm_dev->pool_info[pool].rqa_count = 0;					zatm_dev->pool_info[pool].rqu_count = 0;				}				spin_unlock_irqrestore(&zatm_dev->lock, flags);				return copy_to_user(				    &((struct zatm_pool_req __user *) arg)->info,				    &info,sizeof(info)) ? -EFAULT : 0;			}		case ZATM_SETPOOL:			{				struct zatm_pool_info info;				int pool;				if (!capable(CAP_NET_ADMIN)) return -EPERM;				if (get_user(pool,				    &((struct zatm_pool_req __user *) arg)->pool_num))					return -EFAULT;				if (pool < 0 || pool > ZATM_LAST_POOL)					return -EINVAL;				if (copy_from_user(&info,				    &((struct zatm_pool_req __user *) arg)->info,				    sizeof(info))) return -EFAULT;				if (!info.low_water)					info.low_water = zatm_dev->					    pool_info[pool].low_water;				if (!info.high_water)					info.high_water = zatm_dev->					    pool_info[pool].high_water;				if (!info.next_thres)					info.next_thres = zatm_dev->					    pool_info[pool].next_thres;				if (info.low_water >= info.high_water ||				    info.low_water < 0)					return -EINVAL;				spin_lock_irqsave(&zatm_dev->lock, flags);				zatm_dev->pool_info[pool].low_water =				    info.low_water;				zatm_dev->pool_info[pool].high_water =				    info.high_water;				zatm_dev->pool_info[pool].next_thres =				    info.next_thres;				spin_unlock_irqrestore(&zatm_dev->lock, flags);				return 0;			}		default:        		if (!dev->phy->ioctl) return -ENOIOCTLCMD;		        return dev->phy->ioctl(dev,cmd,arg);	}}static int zatm_getsockopt(struct atm_vcc *vcc,int level,int optname,    void __user *optval,int optlen){	return -EINVAL;}static int zatm_setsockopt(struct atm_vcc *vcc,int level,int optname,    void __user *optval,int optlen){	return -EINVAL;}static int zatm_send(struct atm_vcc *vcc,struct sk_buff *skb){	int error;	EVENT(">zatm_send 0x%lx\n",(unsigned long) skb,0);	if (!ZATM_VCC(vcc)->tx_chan || !test_bit(ATM_VF_READY,&vcc->flags)) {		if (vcc->pop) vcc->pop(vcc,skb);		else dev_kfree_skb(skb);		return -EINVAL;	}	if (!skb) {		printk(KERN_CRIT "!skb in zatm_send ?\n");		if (vcc->pop) vcc->pop(vcc,skb);		return -EINVAL;	}	ATM_SKB(skb)->vcc = vcc;	error = do_tx(skb);	if (error != RING_BUSY) return error;	skb_queue_tail(&ZATM_VCC(vcc)->backlog,skb);	return 0;}static void zatm_phy_put(struct atm_dev *dev,unsigned char value,    unsigned long addr){	struct zatm_dev *zatm_dev;	zatm_dev = ZATM_DEV(dev);	zwait;	zout(value,CER);	zout(uPD98401_IND_ACC | uPD98401_IA_B0 |	    (uPD98401_IA_TGT_PHY << uPD98401_IA_TGT_SHIFT) | addr,CMR);}static unsigned char zatm_phy_get(struct atm_dev *dev,unsigned long addr){	struct zatm_dev *zatm_dev;	zatm_dev = ZATM_DEV(dev);	zwait;	zout(uPD98401_IND_ACC | uPD98401_IA_B0 | uPD98401_IA_RW |	  (uPD98401_IA_TGT_PHY << uPD98401_IA_TGT_SHIFT) | addr,CMR);	zwait;	return zin(CER) & 0xff;}static const struct atmdev_ops ops = {	.open		= zatm_open,	.close		= zatm_close,	.ioctl		= zatm_ioctl,	.getsockopt	= zatm_getsockopt,	.setsockopt	= zatm_setsockopt,	.send		= zatm_send,	.phy_put	= zatm_phy_put,	.phy_get	= zatm_phy_get,	.change_qos	= zatm_change_qos,};static int __init zatm_module_init(void){	struct atm_dev *dev;	struct zatm_dev *zatm_dev;	int devs,type;	zatm_dev = (struct zatm_dev *) kmalloc(sizeof(struct zatm_dev),	    GFP_KERNEL);	if (!zatm_dev) return -ENOMEM;	devs = 0;	for (type = 0; type < 2; type++) {		struct pci_dev *pci_dev;		pci_dev = NULL;		while ((pci_dev = pci_find_device(PCI_VENDOR_ID_ZEITNET,type ?		    PCI_DEVICE_ID_ZEITNET_1225 : PCI_DEVICE_ID_ZEITNET_1221,		    pci_dev))) {			if (pci_enable_device(pci_dev)) break;			dev = atm_dev_register(DEV_LABEL,&ops,-1,NULL);			if (!dev) break;			zatm_dev->pci_dev = pci_dev;			dev->dev_data = zatm_dev;			zatm_dev->copper = type;			if (zatm_init(dev) || zatm_start(dev)) {				atm_dev_deregister(dev);				break;			}			zatm_dev->more = zatm_boards;			zatm_boards = dev;			devs++;			zatm_dev = (struct zatm_dev *) kmalloc(sizeof(struct			    zatm_dev),GFP_KERNEL);			if (!zatm_dev) {				printk(KERN_EMERG "zatm.c: memory shortage\n");				goto out;			}		}	}out:	kfree(zatm_dev);	return 0;}MODULE_LICENSE("GPL");module_init(zatm_module_init);/* module_exit not defined so not unloadable */

⌨️ 快捷键说明

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