cops.c

来自「linux 内核源代码」· C语言 代码 · 共 1,039 行 · 第 1/2 页

C
1,039
字号
        int ioaddr=dev->base_addr;	int length, i = 0;        strcpy(ifr.ifr_name,"lt0");        /* Get card's firmware code and do some checks on it. */#ifdef CONFIG_COPS_DAYNA                if(lp->board==DAYNA)        {                ltf->length=sizeof(ffdrv_code);                ltf->data=ffdrv_code;        }        else#endif        #ifdef CONFIG_COPS_TANGENT        if(lp->board==TANGENT)        {                ltf->length=sizeof(ltdrv_code);                ltf->data=ltdrv_code;        }        else#endif	{		printk(KERN_INFO "%s; unsupported board type.\n", dev->name);		return;	}	        /* Check to make sure firmware is correct length. */        if(lp->board==DAYNA && ltf->length!=5983)        {                printk(KERN_WARNING "%s: Firmware is not length of FFDRV.BIN.\n", dev->name);                return;        }        if(lp->board==TANGENT && ltf->length!=2501)        {                printk(KERN_WARNING "%s: Firmware is not length of DRVCODE.BIN.\n", dev->name);                return;        }        if(lp->board==DAYNA)        {                /*                 *      We must wait for a status response                 *      with the DAYNA board.                 */                while(++i<65536)                {                       if((inb(ioaddr+DAYNA_CARD_STATUS)&3)==1)                                break;                }                if(i==65536)                        return;        }        /*         *      Upload the firmware and kick. Byte-by-byte works nicely here.         */	i=0;        length = ltf->length;        while(length--)        {                outb(ltf->data[i], ioaddr);                i++;        }	if(cops_debug > 1)		printk("%s: Uploaded firmware - %d bytes of %d bytes.\n", 			dev->name, i, ltf->length);        if(lp->board==DAYNA) 	/* Tell Dayna to run the firmware code. */                outb(1, ioaddr+DAYNA_INT_CARD);	else			/* Tell Tang to run the firmware code. */		inb(ioaddr);        if(lp->board==TANGENT)        {                tangent_wait_reset(ioaddr);                inb(ioaddr);	/* Clear initial ready signal. */        }        return;}/* * 	Get the LocalTalk Nodeid from the card. We can suggest *	any nodeid 1-254. The card will try and get that exact *	address else we can specify 0 as the nodeid and the card *	will autoprobe for a nodeid. */static int cops_nodeid (struct net_device *dev, int nodeid){	struct cops_local *lp = netdev_priv(dev);	int ioaddr = dev->base_addr;	if(lp->board == DAYNA)        {        	/* Empty any pending adapter responses. */                while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0)                {			outb(0, ioaddr+COPS_CLEAR_INT);	/* Clear interrupts. */        		if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST)                		cops_rx(dev);	/* Kick any packets waiting. */			schedule();                }                outb(2, ioaddr);       	/* Output command packet length as 2. */                outb(0, ioaddr);                outb(LAP_INIT, ioaddr);	/* Send LAP_INIT command byte. */                outb(nodeid, ioaddr);  	/* Suggest node address. */        }	if(lp->board == TANGENT)        {                /* Empty any pending adapter responses. */                while(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY)                {			outb(0, ioaddr+COPS_CLEAR_INT);	/* Clear interrupt. */                	cops_rx(dev);          	/* Kick out packets waiting. */			schedule();                }		/* Not sure what Tangent does if nodeid picked is used. */                if(nodeid == 0)	         		/* Seed. */                	nodeid = jiffies&0xFF;		/* Get a random try */                outb(2, ioaddr);        		/* Command length LSB */                outb(0, ioaddr);       			/* Command length MSB */                outb(LAP_INIT, ioaddr); 		/* Send LAP_INIT byte */                outb(nodeid, ioaddr); 		  	/* LAP address hint. */                outb(0xFF, ioaddr);     		/* Int. level to use */        }	lp->node_acquire=0;		/* Set nodeid holder to 0. */        while(lp->node_acquire==0)	/* Get *True* nodeid finally. */	{		outb(0, ioaddr+COPS_CLEAR_INT);	/* Clear any interrupt. */		if(lp->board == DAYNA)		{                	if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST)                		cops_rx(dev);	/* Grab the nodeid put in lp->node_acquire. */		}		if(lp->board == TANGENT)		{				if(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY)                                cops_rx(dev);   /* Grab the nodeid put in lp->node_acquire. */		}		schedule();	}	if(cops_debug > 1)		printk(KERN_DEBUG "%s: Node ID %d has been acquired.\n", 			dev->name, lp->node_acquire);	lp->nodeid=1;	/* Set got nodeid to 1. */        return 0;}/* *	Poll the Tangent type cards to see if we have work. */ static void cops_poll(unsigned long ltdev){	int ioaddr, status;	int boguscount = 0;	struct net_device *dev = (struct net_device *)ltdev;	del_timer(&cops_timer);	if(dev == NULL)		return;	/* We've been downed */	ioaddr = dev->base_addr;	do {		status=inb(ioaddr+TANG_CARD_STATUS);		if(status & TANG_RX_READY)			cops_rx(dev);		if(status & TANG_TX_READY)			netif_wake_queue(dev);		status = inb(ioaddr+TANG_CARD_STATUS);	} while((++boguscount < 20) && (status&(TANG_RX_READY|TANG_TX_READY)));	/* poll 20 times per second */	cops_timer.expires = jiffies + HZ/20;	add_timer(&cops_timer);	return;}/* *      The typical workload of the driver: *      Handle the network interface interrupts. */static irqreturn_t cops_interrupt(int irq, void *dev_id){        struct net_device *dev = dev_id;        struct cops_local *lp;        int ioaddr, status;        int boguscount = 0;        ioaddr = dev->base_addr;        lp = netdev_priv(dev);	if(lp->board==DAYNA)	{		do {			outb(0, ioaddr + COPS_CLEAR_INT);                       	status=inb(ioaddr+DAYNA_CARD_STATUS);                       	if((status&0x03)==DAYNA_RX_REQUEST)                       	        cops_rx(dev);                	netif_wake_queue(dev);		} while(++boguscount < 20);	}	else	{		do {                       	status=inb(ioaddr+TANG_CARD_STATUS);			if(status & TANG_RX_READY)				cops_rx(dev);			if(status & TANG_TX_READY)				netif_wake_queue(dev);			status=inb(ioaddr+TANG_CARD_STATUS);		} while((++boguscount < 20) && (status&(TANG_RX_READY|TANG_TX_READY)));	}        return IRQ_HANDLED;}/* *      We have a good packet(s), get it/them out of the buffers. */static void cops_rx(struct net_device *dev){        int pkt_len = 0;        int rsp_type = 0;        struct sk_buff *skb = NULL;        struct cops_local *lp = netdev_priv(dev);        int ioaddr = dev->base_addr;        int boguscount = 0;        unsigned long flags;	spin_lock_irqsave(&lp->lock, flags);	        if(lp->board==DAYNA)        {                outb(0, ioaddr);                /* Send out Zero length. */                outb(0, ioaddr);                outb(DATA_READ, ioaddr);        /* Send read command out. */                /* Wait for DMA to turn around. */                while(++boguscount<1000000)                {			barrier();                        if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_READY)                                break;                }                if(boguscount==1000000)                {                        printk(KERN_WARNING "%s: DMA timed out.\n",dev->name);			spin_unlock_irqrestore(&lp->lock, flags);                        return;                }        }        /* Get response length. */	if(lp->board==DAYNA)        	pkt_len = inb(ioaddr) & 0xFF;	else		pkt_len = inb(ioaddr) & 0x00FF;        pkt_len |= (inb(ioaddr) << 8);        /* Input IO code. */        rsp_type=inb(ioaddr);        /* Malloc up new buffer. */        skb = dev_alloc_skb(pkt_len);        if(skb == NULL)        {                printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n",			dev->name);                lp->stats.rx_dropped++;                while(pkt_len--)        /* Discard packet */                        inb(ioaddr);                spin_unlock_irqrestore(&lp->lock, flags);                return;        }        skb->dev = dev;        skb_put(skb, pkt_len);        skb->protocol = htons(ETH_P_LOCALTALK);        insb(ioaddr, skb->data, pkt_len);               /* Eat the Data */        if(lp->board==DAYNA)                outb(1, ioaddr+DAYNA_INT_CARD);         /* Interrupt the card */        spin_unlock_irqrestore(&lp->lock, flags);  /* Restore interrupts. */        /* Check for bad response length */        if(pkt_len < 0 || pkt_len > MAX_LLAP_SIZE)        {		printk(KERN_WARNING "%s: Bad packet length of %d bytes.\n", 			dev->name, pkt_len);                lp->stats.tx_errors++;                dev_kfree_skb_any(skb);                return;        }        /* Set nodeid and then get out. */        if(rsp_type == LAP_INIT_RSP)        {	/* Nodeid taken from received packet. */                lp->node_acquire = skb->data[0];                dev_kfree_skb_any(skb);                return;        }        /* One last check to make sure we have a good packet. */        if(rsp_type != LAP_RESPONSE)        {                printk(KERN_WARNING "%s: Bad packet type %d.\n", dev->name, rsp_type);                lp->stats.tx_errors++;                dev_kfree_skb_any(skb);                return;        }        skb_reset_mac_header(skb);    /* Point to entire packet. */        skb_pull(skb,3);        skb_reset_transport_header(skb);    /* Point to data (Skip header). */        /* Update the counters. */        lp->stats.rx_packets++;        lp->stats.rx_bytes += skb->len;        /* Send packet to a higher place. */        netif_rx(skb);	dev->last_rx = jiffies;}static void cops_timeout(struct net_device *dev){        struct cops_local *lp = netdev_priv(dev);        int ioaddr = dev->base_addr;	lp->stats.tx_errors++;        if(lp->board==TANGENT)        {		if((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0)               		printk(KERN_WARNING "%s: No TX complete interrupt.\n", dev->name);	}	printk(KERN_WARNING "%s: Transmit timed out.\n", dev->name);	cops_jumpstart(dev);	/* Restart the card. */	dev->trans_start = jiffies;	netif_wake_queue(dev);}/* *	Make the card transmit a LocalTalk packet. */static int cops_send_packet(struct sk_buff *skb, struct net_device *dev){        struct cops_local *lp = netdev_priv(dev);        int ioaddr = dev->base_addr;        unsigned long flags;        /*         * Block a timer-based transmit from overlapping. 	 */	 	netif_stop_queue(dev);	spin_lock_irqsave(&lp->lock, flags);	if(lp->board == DAYNA)	 /* Wait for adapter transmit buffer. */		while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0)			cpu_relax();	if(lp->board == TANGENT) /* Wait for adapter transmit buffer. */		while((inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0)			cpu_relax();	/* Output IO length. */	outb(skb->len, ioaddr);	if(lp->board == DAYNA)               	outb(skb->len >> 8, ioaddr);	else		outb((skb->len >> 8)&0x0FF, ioaddr);	/* Output IO code. */	outb(LAP_WRITE, ioaddr);	if(lp->board == DAYNA)	/* Check the transmit buffer again. */        	while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0);	outsb(ioaddr, skb->data, skb->len);	/* Send out the data. */	if(lp->board==DAYNA)	/* Dayna requires you kick the card */		outb(1, ioaddr+DAYNA_INT_CARD);	spin_unlock_irqrestore(&lp->lock, flags);	/* Restore interrupts. */	/* Done sending packet, update counters and cleanup. */	lp->stats.tx_packets++;	lp->stats.tx_bytes += skb->len;	dev->trans_start = jiffies;	dev_kfree_skb (skb);        return 0;}/* *	Dummy function to keep the Appletalk layer happy. */ static void set_multicast_list(struct net_device *dev){        if(cops_debug >= 3)		printk("%s: set_multicast_list executed\n", dev->name);}/* *      System ioctls for the COPS LocalTalk card. */ static int cops_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){        struct cops_local *lp = netdev_priv(dev);        struct sockaddr_at *sa = (struct sockaddr_at *)&ifr->ifr_addr;        struct atalk_addr *aa = (struct atalk_addr *)&lp->node_addr;        switch(cmd)        {                case SIOCSIFADDR:			/* Get and set the nodeid and network # atalkd wants. */			cops_nodeid(dev, sa->sat_addr.s_node);			aa->s_net               = sa->sat_addr.s_net;                        aa->s_node              = lp->node_acquire;			/* Set broardcast address. */                        dev->broadcast[0]       = 0xFF;						/* Set hardware address. */                        dev->dev_addr[0]        = aa->s_node;                        dev->addr_len           = 1;                        return 0;                case SIOCGIFADDR:                        sa->sat_addr.s_net      = aa->s_net;                        sa->sat_addr.s_node     = aa->s_node;                        return 0;                default:                        return -EOPNOTSUPP;        }}/* *	The inverse routine to cops_open(). */ static int cops_close(struct net_device *dev){	struct cops_local *lp = netdev_priv(dev);	/* If we were running polled, yank the timer.	 */	if(lp->board==TANGENT && dev->irq==0)		del_timer(&cops_timer);	netif_stop_queue(dev);        return 0;}/* *      Get the current statistics. *      This may be called with the card open or closed. */static struct net_device_stats *cops_get_stats(struct net_device *dev){        struct cops_local *lp = netdev_priv(dev);        return &lp->stats;}#ifdef MODULEstatic struct net_device *cops_dev;MODULE_LICENSE("GPL");module_param(io, int, 0);module_param(irq, int, 0);module_param(board_type, int, 0);int __init init_module(void){	if (io == 0)		printk(KERN_WARNING "%s: You shouldn't autoprobe with insmod\n",			cardname);	cops_dev = cops_probe(-1);	if (IS_ERR(cops_dev))		return PTR_ERR(cops_dev);        return 0;}void __exit cleanup_module(void){	unregister_netdev(cops_dev);	cleanup_card(cops_dev);	free_netdev(cops_dev);}#endif /* MODULE *//* * Local variables: *  compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -c cops.c" *  c-basic-offset: 4 *  c-file-offsets: ((substatement-open . 0)) * End: */

⌨️ 快捷键说明

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