dm9000.c

来自「《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序」· C语言 代码 · 共 1,308 行 · 第 1/3 页

C
1,308
字号
		printk("%s: could not allocate device.\n", CARDNAME);		return -ENOMEM;	}		SET_MODULE_OWNER(ndev);	SET_NETDEV_DEV(ndev, &pdev->dev);		PRINTK2("dm9000_probe()");		/* setup board info structure */	db = (struct board_info *) ndev->priv;	memset(db, 0, sizeof (*db));		spin_lock_init(&db->lock);		if (pdev->num_resources < 2) {		ret = -ENODEV;		goto out;	} else if (pdev->num_resources == 2) {		base = pdev->resource[0].start;				if (!request_mem_region(base, 4, ndev->name)) {			ret = -EBUSY;			goto out;		}				ndev->base_addr = base;		ndev->irq = pdev->resource[1].start;		db->io_addr = (void  *)base;		db->io_data = (void  *)(base + 4);			} else {		db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);		db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);		db->irq_res  = platform_get_resource(pdev, IORESOURCE_IRQ, 0);				if (db->addr_res == NULL || db->data_res == NULL ||			db->irq_res == NULL) {			printk(KERN_ERR PFX "insufficient resources\n");			ret = -ENOENT;			goto out;		}				i = res_size(db->addr_res);		db->addr_req = request_mem_region(db->addr_res->start, i,			pdev->name);				if (db->addr_req == NULL) {			printk(KERN_ERR PFX "cannot claim address reg area\n");			ret = -EIO;			goto out;		}				db->io_addr = ioremap(db->addr_res->start, i);				if (db->io_addr == NULL) {			printk(KERN_ERR "failed to ioremap address reg\n");			ret = -EINVAL;			goto out;		}				iosize = res_size(db->data_res);		db->data_req = request_mem_region(db->data_res->start, iosize,			pdev->name);				if (db->data_req == NULL) {			printk(KERN_ERR PFX "cannot claim data reg area\n");			ret = -EIO;			goto out;		}				db->io_data = ioremap(db->data_res->start, iosize);				if (db->io_data == NULL) {			printk(KERN_ERR "failed to ioremap data reg\n");			ret = -EINVAL;			goto out;		}				/* fill in parameters for net-dev structure */				ndev->base_addr = (unsigned long)db->io_addr;		ndev->irq	= db->irq_res->start;				/* ensure at least we have a default set of IO routines */		dm9000_set_io(db, iosize);	}		/* check to see if anything is being over-ridden */	if (pdata != NULL) {	/* check to see if the driver wants to over-ride the		* default IO width */				if (pdata->flags & DM9000_PLATF_8BITONLY)			dm9000_set_io(db, 1);				if (pdata->flags & DM9000_PLATF_16BITONLY)			dm9000_set_io(db, 2);				if (pdata->flags & DM9000_PLATF_32BITONLY)			dm9000_set_io(db, 4);					/* check to see if there are any IO routine		* over-rides */				if (pdata->inblk != NULL)			db->inblk = pdata->inblk;				if (pdata->outblk != NULL)			db->outblk = pdata->outblk;				if (pdata->dumpblk != NULL)			db->dumpblk = pdata->dumpblk;	}		dm9000_reset(db);		/* try two times, DM9000 sometimes gets the first read wrong */	for (i = 0; i < 2; i++) {		id_val  = ior(db, DM9000_VIDL);		id_val |= (u32)ior(db, DM9000_VIDH) << 8;		id_val |= (u32)ior(db, DM9000_PIDL) << 16;		id_val |= (u32)ior(db, DM9000_PIDH) << 24;				if (id_val == DM9000_ID)			break;		printk("%s: read wrong id 0x%08x\n", CARDNAME, id_val);	}		if (id_val != DM9000_ID) {		printk("%s: wrong id: 0x%08x\n", CARDNAME, id_val);		goto release;	}		/* from this point we assume that we have found a DM9000 */		/* driver system function */	ether_setup(ndev);		ndev->open		 = &dm9000_open;	ndev->hard_start_xmit    = &dm9000_start_xmit;	ndev->tx_timeout         = &dm9000_timeout;	ndev->watchdog_timeo = msecs_to_jiffies(watchdog);	ndev->stop		 = &dm9000_stop;	ndev->get_stats		 = &dm9000_get_stats;	ndev->set_multicast_list = &dm9000_hash_table;#ifdef CONFIG_NET_POLL_CONTROLLER	ndev->poll_controller	 = &dm9000_poll_controller;#endif	#ifdef DM9000_PROGRAM_EEPROM	program_eeprom(db);#endif	db->msg_enable       = NETIF_MSG_LINK;	db->mii.phy_id_mask  = 0x1f;	db->mii.reg_num_mask = 0x1f;	db->mii.force_media  = 0;	db->mii.full_duplex  = 0;	db->mii.dev	     = ndev;	db->mii.mdio_read    = dm9000_phy_read;	db->mii.mdio_write   = dm9000_phy_write;		/* Read SROM content */	for (i = 0; i < 64; i++)		((u16 *) db->srom)[i] = read_srom_word(db, i);		/* Set Node Address */	for (i = 0; i < 6; i++)		ndev->dev_addr[i] = db->srom[i];		if (!is_valid_ether_addr(ndev->dev_addr)) {		/* try reading from mac */				for (i = 0; i < 6; i++)			ndev->dev_addr[i] = ior(db, i+DM9000_PAR);	}		if (!is_valid_ether_addr(ndev->dev_addr))		printk("%s: Invalid ethernet MAC address.  Please "		"set using ifconfig\n", ndev->name);		dev_set_drvdata(dev, ndev);	ret = register_netdev(ndev);		if (ret == 0) {		printk("%s: dm9000 at %p,%p IRQ %d MAC: ",			ndev->name,  db->io_addr, db->io_data, ndev->irq);		for (i = 0; i < 5; i++)			printk("%02x:", ndev->dev_addr[i]);		printk("%02x\n", ndev->dev_addr[5]);	}	return 0;	release:out:	printk("%s: not found (%d).\n", CARDNAME, ret);		dm9000_release_board(pdev, db);	kfree(ndev);		return ret;}/**  Open the interface.*  The interface is opened whenever "ifconfig" actives it.*/static int  dm9000_open(struct net_device *dev){	board_info_t *db = (board_info_t *) dev->priv;		PRINTK2("entering dm9000_open\n");		if (request_irq(dev->irq, &dm9000_interrupt, SA_INTERRUPT, dev->name, dev))		return -EAGAIN;		/* Initialize DM9000 board */	dm9000_reset(db);	dm9000_init_dm9000(dev);		/* Init driver variable */	db->dbug_cnt = 0;		/* set and active a timer process */	init_timer(&db->timer);	db->timer.expires  = DM9000_TIMER_WUT;	db->timer.data     = (unsigned long) dev;	db->timer.function = &dm9000_timer;	add_timer(&db->timer);		mii_check_media(&db->mii, netif_msg_link(db), 1);	netif_start_queue(dev);		return 0;}/** Initilize dm9000 board*/static voiddm9000_init_dm9000(struct net_device *dev){	board_info_t *db = (board_info_t *) dev->priv;		PRINTK1("entering %s\n",__FUNCTION__);		/* I/O mode */	db->io_mode = ior(db, DM9000_ISR) >> 6;	/* ISR bit7:6 keeps I/O mode */		/* GPIO0 on pre-activate PHY */	iow(db, DM9000_GPR, 0);	/* REG_1F bit0 activate phyxcer */	iow(db, DM9000_GPCR, GPCR_GEP_CNTL);	/* Let GPIO0 output */	iow(db, DM9000_GPR, 0);	/* Enable PHY */		/* Program operating register */	iow(db, DM9000_TCR, 0);	        /* TX Polling clear */	iow(db, DM9000_BPTR, 0x3f);	/* Less 3Kb, 200us */	iow(db, DM9000_FCR, 0xff);	/* Flow Control */	iow(db, DM9000_SMCR, 0);        /* Special Mode */	/* clear TX status */	iow(db, DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);	iow(db, DM9000_ISR, ISR_CLR_STATUS); /* Clear interrupt status */		/* Set address filter table */	dm9000_hash_table(dev);		/* Activate DM9000 */	iow(db, DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);	/* Enable TX/RX interrupt mask */	iow(db, DM9000_IMR, IMR_PAR | IMR_PTM | IMR_PRM);		/* Init Driver variable */	db->tx_pkt_cnt = 0;	db->queue_pkt_len = 0;	dev->trans_start = 0;}/**  Hardware start transmission.*  Send a packet to media from the upper layer.*/static intdm9000_start_xmit(struct sk_buff *skb, struct net_device *dev){	board_info_t *db = (board_info_t *) dev->priv;		PRINTK3("dm9000_start_xmit\n");		if (db->tx_pkt_cnt > 1)		return 1;		netif_stop_queue(dev);		/* Disable all interrupts */	iow(db, DM9000_IMR, IMR_PAR);		/* Move data to DM9000 TX RAM */	writeb(DM9000_MWCMD, db->io_addr);		(db->outblk)(db->io_data, skb->data, skb->len);	db->stats.tx_bytes += skb->len;		/* TX control: First packet immediately send, second packet queue */	if (db->tx_pkt_cnt == 0) {				/* First Packet */		db->tx_pkt_cnt++;				/* Set TX length to DM9000 */		iow(db, DM9000_TXPLL, skb->len & 0xff);		iow(db, DM9000_TXPLH, (skb->len >> 8) & 0xff);				/* Issue TX polling command */		iow(db, DM9000_TCR, TCR_TXREQ);	/* Cleared after TX complete */				dev->trans_start = jiffies;	/* save the time stamp */			} else {		/* Second packet */		db->tx_pkt_cnt++;		db->queue_pkt_len = skb->len;	}		/* free this SKB */	dev_kfree_skb(skb);		/* Re-enable resource check */	if (db->tx_pkt_cnt == 1)		netif_wake_queue(dev);		/* Re-enable interrupt */	iow(db, DM9000_IMR, IMR_PAR | IMR_PTM | IMR_PRM);		return 0;}static voiddm9000_shutdown(struct net_device *dev){	board_info_t *db = (board_info_t *) dev->priv;		/* RESET device */	dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET);	/* PHY RESET */	iow(db, DM9000_GPR, 0x01);	/* Power-Down PHY */	iow(db, DM9000_IMR, IMR_PAR);	/* Disable all interrupt */	iow(db, DM9000_RCR, 0x00);	/* Disable RX */}/** Stop the interface.* The interface is stopped when it is brought.*/static intdm9000_stop(struct net_device *ndev){	board_info_t *db = (board_info_t *) ndev->priv;		PRINTK1("entering %s\n",__FUNCTION__);		/* deleted timer */	del_timer(&db->timer);		netif_stop_queue(ndev);	netif_carrier_off(ndev);		/* free interrupt */	free_irq(ndev->irq, ndev);		dm9000_shutdown(ndev);		return 0;}/** DM9000 interrupt handler* receive the packet to upper layer, free the transmitted packet*/static voiddm9000_tx_done(struct net_device *dev, board_info_t * db){	int tx_status = ior(db, DM9000_NSR);	/* Got TX status */		if (tx_status & (NSR_TX2END | NSR_TX1END)) {		/* One packet sent complete */		db->tx_pkt_cnt--;		db->stats.tx_packets++;				/* Queue packet check & send */		if (db->tx_pkt_cnt > 0) {			iow(db, DM9000_TXPLL, db->queue_pkt_len & 0xff);			iow(db, DM9000_TXPLH, (db->queue_pkt_len >> 8) & 0xff);			iow(db, DM9000_TCR, TCR_TXREQ);			dev->trans_start = jiffies;		}		netif_wake_queue(dev);	}}//static irqreturn_t//dm9000_interrupt(int irq, void *dev_id)static irqreturn_t dm9000_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct net_device *dev = dev_id;	board_info_t *db;	int int_status;	u8 reg_save;		PRINTK3("entering %s\n",__FUNCTION__);		if (!dev) {		PRINTK1("dm9000_interrupt() without DEVICE arg\n");		return IRQ_HANDLED;	}		/* A real interrupt coming */	db = (board_info_t *) dev->priv;	spin_lock(&db->lock);		/* Save previous register address */	reg_save = readb(db->io_addr);		/* Disable all interrupts */	iow(db, DM9000_IMR, IMR_PAR);		/* Got DM9000 interrupt status */	int_status = ior(db, DM9000_ISR);	/* Got ISR */	iow(db, DM9000_ISR, int_status);	/* Clear ISR status */		/* Received the coming packet */	if (int_status & ISR_PRS)		dm9000_rx(dev);		/* Trnasmit Interrupt check */	if (int_status & ISR_PTS)		dm9000_tx_done(dev, db);

⌨️ 快捷键说明

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