com90xx.c

来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 703 行 · 第 1/2 页

C
703
字号
			if (airq <= 0) {				BUGMSG2(D_INIT_REASONS, "(airq=%d)\n", airq);				BUGMSG2(D_INIT_REASONS, "S5: ");				BUGLVL(D_INIT_REASONS) numprint = 0;				release_region(*port, ARCNET_TOTAL_SIZE);				*port-- = ports[--numports];				continue;			}		} else {			airq = irq;		}		BUGMSG2(D_INIT, "(%d,", airq);		openparen = 1;		/* Everything seems okay.  But which shmem, if any, puts		 * back its signature byte when the card is reset?		 *		 * If there are multiple cards installed, there might be		 * multiple shmems still in the list.		 */#ifdef FAST_PROBE		if (numports > 1 || numshmems > 1) {			inb(_RESET);			mdelay(RESETtime);		} else {			/* just one shmem and port, assume they match */			writeb(TESTvalue, iomem[0]);		}#else		inb(_RESET);		mdelay(RESETtime);#endif		for (index = 0; index < numshmems; index++) {			u_long ptr = shmems[index];			void __iomem *base = iomem[index];			if (readb(base) == TESTvalue) {	/* found one */				BUGMSG2(D_INIT, "%lXh)\n", *p);				openparen = 0;				/* register the card */				if (com90xx_found(*port, airq, ptr, base) == 0)					found = 1;				numprint = -1;				/* remove shmem from the list */				shmems[index] = shmems[--numshmems];				iomem[index] = iomem[numshmems];				break;	/* go to the next I/O port */			} else {				BUGMSG2(D_INIT_REASONS, "%Xh-", readb(base));			}		}		if (openparen) {			BUGLVL(D_INIT) printk("no matching shmem)\n");			BUGLVL(D_INIT_REASONS) printk("S5: ");			BUGLVL(D_INIT_REASONS) numprint = 0;		}		if (!found)			release_region(*port, ARCNET_TOTAL_SIZE);		*port-- = ports[--numports];	}	BUGLVL(D_INIT_REASONS) printk("\n");	/* Now put back TESTvalue on all leftover shmems. */	for (index = 0; index < numshmems; index++) {		writeb(TESTvalue, iomem[index]);		iounmap(iomem[index]);		release_mem_region(shmems[index], MIRROR_SIZE);	}	kfree(shmems);	kfree(iomem);}static int check_mirror(unsigned long addr, size_t size){	void __iomem *p;	int res = -1;	if (!request_mem_region(addr, size, "arcnet (90xx)"))		return -1;	p = ioremap(addr, size);	if (p) {		if (readb(p) == TESTvalue)			res = 1;		else			res = 0;		iounmap(p);	}	release_mem_region(addr, size);	return res;}/* Set up the struct net_device associated with this card.  Called after * probing succeeds. */static int __init com90xx_found(int ioaddr, int airq, u_long shmem, void __iomem *p){	struct net_device *dev = NULL;	struct arcnet_local *lp;	u_long first_mirror, last_mirror;	int mirror_size;	/* allocate struct net_device */	dev = alloc_arcdev(device);	if (!dev) {		BUGMSG2(D_NORMAL, "com90xx: Can't allocate device!\n");		iounmap(p);		release_mem_region(shmem, MIRROR_SIZE);		return -ENOMEM;	}	lp = dev->priv;	/* find the real shared memory start/end points, including mirrors */	/* guess the actual size of one "memory mirror" - the number of	 * bytes between copies of the shared memory.  On most cards, it's	 * 2k (or there are no mirrors at all) but on some, it's 4k.	 */	mirror_size = MIRROR_SIZE;	if (readb(p) == TESTvalue &&	    check_mirror(shmem - MIRROR_SIZE, MIRROR_SIZE) == 0 &&	    check_mirror(shmem - 2 * MIRROR_SIZE, MIRROR_SIZE) == 1)		mirror_size = 2 * MIRROR_SIZE;	first_mirror = shmem - mirror_size;	while (check_mirror(first_mirror, mirror_size) == 1)		first_mirror -= mirror_size;	first_mirror += mirror_size;	last_mirror = shmem + mirror_size;	while (check_mirror(last_mirror, mirror_size) == 1)		last_mirror += mirror_size;	last_mirror -= mirror_size;	dev->mem_start = first_mirror;	dev->mem_end = last_mirror + MIRROR_SIZE - 1;	iounmap(p);	release_mem_region(shmem, MIRROR_SIZE);	if (!request_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1, "arcnet (90xx)"))		goto err_free_dev;	/* reserve the irq */	if (request_irq(airq, &arcnet_interrupt, 0, "arcnet (90xx)", dev)) {		BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", airq);		goto err_release_mem;	}	dev->irq = airq;	/* Initialize the rest of the device structure. */	lp->card_name = "COM90xx";	lp->hw.command = com90xx_command;	lp->hw.status = com90xx_status;	lp->hw.intmask = com90xx_setmask;	lp->hw.reset = com90xx_reset;	lp->hw.owner = THIS_MODULE;	lp->hw.copy_to_card = com90xx_copy_to_card;	lp->hw.copy_from_card = com90xx_copy_from_card;	lp->mem_start = ioremap(dev->mem_start, dev->mem_end - dev->mem_start + 1);	if (!lp->mem_start) {		BUGMSG(D_NORMAL, "Can't remap device memory!\n");		goto err_free_irq;	}	/* get and check the station ID from offset 1 in shmem */	dev->dev_addr[0] = readb(lp->mem_start + 1);	dev->base_addr = ioaddr;	BUGMSG(D_NORMAL, "COM90xx station %02Xh found at %03lXh, IRQ %d, "	       "ShMem %lXh (%ld*%xh).\n",	       dev->dev_addr[0],	       dev->base_addr, dev->irq, dev->mem_start,	 (dev->mem_end - dev->mem_start + 1) / mirror_size, mirror_size);	if (register_netdev(dev))		goto err_unmap;	cards[numcards++] = dev;	return 0;err_unmap:	iounmap(lp->mem_start);err_free_irq:	free_irq(dev->irq, dev);err_release_mem:	release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1);err_free_dev:	free_netdev(dev);	return -EIO;}static void com90xx_command(struct net_device *dev, int cmd){	short ioaddr = dev->base_addr;	ACOMMAND(cmd);}static int com90xx_status(struct net_device *dev){	short ioaddr = dev->base_addr;	return ASTATUS();}static void com90xx_setmask(struct net_device *dev, int mask){	short ioaddr = dev->base_addr;	AINTMASK(mask);}/* * Do a hardware reset on the card, and set up necessary registers. *  * This should be called as little as possible, because it disrupts the * token on the network (causes a RECON) and requires a significant delay. * * However, it does make sure the card is in a defined state. */int com90xx_reset(struct net_device *dev, int really_reset){	struct arcnet_local *lp = dev->priv;	short ioaddr = dev->base_addr;	BUGMSG(D_INIT, "Resetting (status=%02Xh)\n", ASTATUS());	if (really_reset) {		/* reset the card */		inb(_RESET);		mdelay(RESETtime);	}	ACOMMAND(CFLAGScmd | RESETclear);	/* clear flags & end reset */	ACOMMAND(CFLAGScmd | CONFIGclear);	/* don't do this until we verify that it doesn't hurt older cards! */	/* outb(inb(_CONFIG) | ENABLE16flag, _CONFIG); */	/* verify that the ARCnet signature byte is present */	if (readb(lp->mem_start) != TESTvalue) {		if (really_reset)			BUGMSG(D_NORMAL, "reset failed: TESTvalue not present.\n");		return 1;	}	/* enable extended (512-byte) packets */	ACOMMAND(CONFIGcmd | EXTconf);	/* clean out all the memory to make debugging make more sense :) */	BUGLVL(D_DURING)	    memset_io(lp->mem_start, 0x42, 2048);	/* done!  return success. */	return 0;}static void com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset,				 void *buf, int count){	struct arcnet_local *lp = dev->priv;	void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset;	TIME("memcpy_toio", count, memcpy_toio(memaddr, buf, count));}static void com90xx_copy_from_card(struct net_device *dev, int bufnum, int offset,				   void *buf, int count){	struct arcnet_local *lp = dev->priv;	void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset;	TIME("memcpy_fromio", count, memcpy_fromio(buf, memaddr, count));}MODULE_LICENSE("GPL");static int __init com90xx_init(void){	if (irq == 2)		irq = 9;	com90xx_probe();	if (!numcards)		return -EIO;	return 0;}static void __exit com90xx_exit(void){	struct net_device *dev;	struct arcnet_local *lp;	int count;	for (count = 0; count < numcards; count++) {		dev = cards[count];		lp = dev->priv;		unregister_netdev(dev);		free_irq(dev->irq, dev);		iounmap(lp->mem_start);		release_region(dev->base_addr, ARCNET_TOTAL_SIZE);		release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1);		free_netdev(dev);	}}module_init(com90xx_init);module_exit(com90xx_exit);#ifndef MODULEstatic int __init com90xx_setup(char *s){	int ints[8];	s = get_options(s, 8, ints);	if (!ints[0] && !*s) {		printk("com90xx: Disabled.\n");		return 1;	}	switch (ints[0]) {	default:		/* ERROR */		printk("com90xx: Too many arguments.\n");	case 3:		/* Mem address */		shmem = ints[3];	case 2:		/* IRQ */		irq = ints[2];	case 1:		/* IO address */		io = ints[1];	}	if (*s)		snprintf(device, sizeof(device), "%s", s);	return 1;}__setup("com90xx=", com90xx_setup);#endif

⌨️ 快捷键说明

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