/* free the skbuf structure before aborting */ 
priv->statistics.tx_dropped++; spin_unlock_irqrestore(&priv->slock, flags); 
islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev){	islpci_private *priv = netdev_priv(ndev);	isl38xx_control_block *cb = priv->control_block;	u32 index;	dma_addr_t pci_map_address;	int frame_size;	isl38xx_fragment *fragment;	int offset;	struct sk_buff *newskb;	int newskb_offset;	unsigned long flags;	unsigned char wds_mac[6];	u32 curr_frag;	int err = 0;#if VERBOSE > SHOW_ERROR_MESSAGES	DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_transmit \n");#endif	/* lock the driver code */	spin_lock_irqsave(&priv->slock, flags);	/* check whether the destination queue has enough fragments for the frame */	curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ]);	if (unlikely(curr_frag - priv->free_data_tx >= ISL38XX_CB_TX_QSIZE)) {		printk(KERN_ERR "%s: transmit device queue full when awake\n",		       ndev->name);		netif_stop_queue(ndev);		/* trigger the device */		isl38xx_w32_flush(priv->device_base, ISL38XX_DEV_INT_UPDATE,				  ISL38XX_DEV_INT_REG);		udelay(ISL38XX_WRITEIO_DELAY);		err = -EBUSY;		goto drop_free;	}	/* Check alignment and WDS frame formatting. The start of the packet should	 * be aligned on a 4-byte boundary. If WDS is enabled add another 6 bytes	 * and add WDS address information */	if (likely(((long) skb->data & 0x03) | init_wds)) {		/* get the number of bytes to add and re-allign */		offset = (4 - (long) skb->data) & 0x03;		offset += init_wds ? 6 : 0;		/* check whether the current skb can be used  */		if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) {			unsigned char *src = skb->data;#if VERBOSE > SHOW_ERROR_MESSAGES			DEBUG(SHOW_TRACING, "skb offset %i wds %i\n", offset,			      init_wds);#endif			/* align the buffer on 4-byte boundary */			skb_reserve(skb, (4 - (long) skb->data) & 0x03);			if (init_wds) {				/* wds requires an additional address field of 6 bytes */				skb_put(skb, 6);#ifdef ISLPCI_ETH_DEBUG				printk("islpci_eth_transmit:wds_mac\n");#endif				memmove(skb->data + 6, src, skb->len);				memcpy(skb->data, wds_mac, 6);			} else {				memmove(skb->data, src, skb->len);			}#if VERBOSE > SHOW_ERROR_MESSAGES			DEBUG(SHOW_TRACING, "memmove %p %p %i \n", skb->data,			      src, skb->len);#endif		} else {			newskb =			    dev_alloc_skb(init_wds ? skb->len + 6 : skb->len);			if (unlikely(newskb == NULL)) {				printk(KERN_ERR "%s: Cannot allocate skb\n",				       ndev->name);				err = -ENOMEM;				goto drop_free;			}			newskb_offset = (4 - (long) newskb->data) & 0x03;			/* Check if newskb->data is aligned */			if (newskb_offset)				skb_reserve(newskb, newskb_offset);			skb_put(newskb, init_wds ? skb->len + 6 : skb->len);			if (init_wds) {				memcpy(newskb->data + 6, skb->data, skb->len);				memcpy(newskb->data, wds_mac, 6);#ifdef ISLPCI_ETH_DEBUG				printk("islpci_eth_transmit:wds_mac\n");#endif			} else				memcpy(newskb->data, skb->data, skb->len);#if VERBOSE > SHOW_ERROR_MESSAGES			DEBUG(SHOW_TRACING, "memcpy %p %p %i wds %i\n",			      newskb->data, skb->data, skb->len, init_wds);#endif			newskb->dev = skb->dev;			dev_kfree_skb(skb);			skb = newskb;		}	}	/* display the buffer contents for debugging */#if VERBOSE > SHOW_ERROR_MESSAGES	DEBUG(SHOW_BUFFER_CONTENTS, "\ntx %p ", skb->data);	display_buffer((char *) skb->data, skb->len);#endif	/* map the skb buffer to pci memory for DMA operation */	pci_map_address = pci_map_single(priv->pdev,					 (void *) skb->data, skb->len,					 PCI_DMA_TODEVICE);	if (unlikely(pci_map_address == 0)) {		printk(KERN_WARNING "%s: cannot map buffer to PCI\n",		       ndev->name);		err = -EIO;		goto drop_free;	}	/* Place the fragment in the control block structure. */	index = curr_frag % ISL38XX_CB_TX_QSIZE;	fragment = &cb->tx_data_low[index];	priv->pci_map_tx_address[index] = pci_map_address;	/* store the skb address for future freeing  */	priv->data_low_tx[index] = skb;	/* set the proper fragment start address and size information */	frame_size = skb->len;	fragment->size = cpu_to_le16(frame_size);	fragment->flags = cpu_to_le16(0);	/* set to 1 if more fragments */	fragment->address = cpu_to_le32(pci_map_address);	curr_frag++;	/* The fragment address in the control block must have been	 * written before announcing the frame buffer to device. */	wmb();	cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ] = cpu_to_le32(curr_frag);	if (curr_frag - priv->free_data_tx + ISL38XX_MIN_QTHRESHOLD	    > ISL38XX_CB_TX_QSIZE) {		/* stop sends from upper layers */		netif_stop_queue(ndev);		/* set the full flag for the transmission queue */		priv->data_low_tx_full = 1;	}	/* trigger the device */	islpci_trigger(priv);	/* unlock the driver code */	spin_unlock_irqrestore(&priv->slock, flags);	/* set the transmission time */	ndev->trans_start = jiffies;	priv->statistics.tx_packets++;	priv->statistics.tx_bytes += skb->len;	return 0;      drop_free:	/* free the skbuf structure before aborting */	dev_kfree_skb(skb);	skb = NULL;	priv->statistics.tx_dropped++;	spin_unlock_irqrestore(&priv->slock, flags);	return err;}
4520	/local/tlutelli/issta_data/temp/c/2005_temp/2005/4520/e71180f3689e00c5a1095925352a72dacdd62e34/islpci_eth.c/clean/drivers/net/wireless/prism54/islpci_eth.c