diff options
Diffstat (limited to 'drivers/net/usb/pegasus.c')
| -rw-r--r-- | drivers/net/usb/pegasus.c | 484 | 
1 files changed, 139 insertions, 345 deletions
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index ef3667690b1..f8408021591 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -1,5 +1,5 @@  /* - *  Copyright (c) 1999-2005 Petko Manolov (petkan@users.sourceforge.net) + *  Copyright (c) 1999-2013 Petko Manolov (petkan@nucleusys.com)   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of the GNU General Public License version 2 as @@ -26,6 +26,9 @@   *		v0.5.1	ethtool support added   *		v0.5.5	rx socket buffers are in a pool and the their allocation   *			is out of the interrupt routine. + *		... + *		v0.9.3	simplified [get|set]_register(s), async update registers + *			logic revisited, receive skb_pool removed.   */  #include <linux/sched.h> @@ -45,8 +48,8 @@  /*   * Version Information   */ -#define DRIVER_VERSION "v0.6.14 (2006/09/27)" -#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>" +#define DRIVER_VERSION "v0.9.3 (2013/04/25)" +#define DRIVER_AUTHOR "Petko Manolov <petkan@nucleusys.com>"  #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"  static const char driver_name[] = "pegasus"; @@ -55,8 +58,8 @@ static const char driver_name[] = "pegasus";  #define	BMSR_MEDIA	(BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | \  			BMSR_100FULL | BMSR_ANEGCAPABLE) -static int loopback; -static int mii_mode; +static bool loopback; +static bool mii_mode;  static char *devid;  static struct usb_eth_dev usb_dev_id[] = { @@ -108,253 +111,137 @@ MODULE_PARM_DESC(msg_level, "Override default message level");  MODULE_DEVICE_TABLE(usb, pegasus_ids);  static const struct net_device_ops pegasus_netdev_ops; -static int update_eth_regs_async(pegasus_t *); -/* Aargh!!! I _really_ hate such tweaks */ -static void ctrl_callback(struct urb *urb) +/*****/ + +static void async_ctrl_callback(struct urb *urb)  { -	pegasus_t *pegasus = urb->context; +	struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;  	int status = urb->status; -	if (!pegasus) -		return; - -	switch (status) { -	case 0: -		if (pegasus->flags & ETH_REGS_CHANGE) { -			pegasus->flags &= ~ETH_REGS_CHANGE; -			pegasus->flags |= ETH_REGS_CHANGED; -			update_eth_regs_async(pegasus); -			return; -		} -		break; -	case -EINPROGRESS: -		return; -	case -ENOENT: -		break; -	default: -		if (net_ratelimit()) -			netif_dbg(pegasus, drv, pegasus->net, -				  "%s, status %d\n", __func__, status); -		break; -	} -	pegasus->flags &= ~ETH_REGS_CHANGED; -	wake_up(&pegasus->ctrl_wait); +	if (status < 0) +		dev_dbg(&urb->dev->dev, "%s failed with %d", __func__, status); +	kfree(req); +	usb_free_urb(urb);  } -static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, -			 void *data) +static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)  {  	int ret; -	char *buffer; -	DECLARE_WAITQUEUE(wait, current); - -	buffer = kmalloc(size, GFP_KERNEL); -	if (!buffer) { -		netif_warn(pegasus, drv, pegasus->net, -			   "out of memory in %s\n", __func__); -		return -ENOMEM; -	} -	add_wait_queue(&pegasus->ctrl_wait, &wait); -	set_current_state(TASK_UNINTERRUPTIBLE); -	while (pegasus->flags & ETH_REGS_CHANGED) -		schedule(); -	remove_wait_queue(&pegasus->ctrl_wait, &wait); -	set_current_state(TASK_RUNNING); - -	pegasus->dr.bRequestType = PEGASUS_REQT_READ; -	pegasus->dr.bRequest = PEGASUS_REQ_GET_REGS; -	pegasus->dr.wValue = cpu_to_le16(0); -	pegasus->dr.wIndex = cpu_to_le16(indx); -	pegasus->dr.wLength = cpu_to_le16(size); -	pegasus->ctrl_urb->transfer_buffer_length = size; - -	usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, -			     usb_rcvctrlpipe(pegasus->usb, 0), -			     (char *) &pegasus->dr, -			     buffer, size, ctrl_callback, pegasus); - -	add_wait_queue(&pegasus->ctrl_wait, &wait); -	set_current_state(TASK_UNINTERRUPTIBLE); - -	/* using ATOMIC, we'd never wake up if we slept */ -	if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { -		set_current_state(TASK_RUNNING); -		if (ret == -ENODEV) -			netif_device_detach(pegasus->net); -		if (net_ratelimit()) -			netif_err(pegasus, drv, pegasus->net, -				  "%s, status %d\n", __func__, ret); -		goto out; -	} - -	schedule(); -out: -	remove_wait_queue(&pegasus->ctrl_wait, &wait); -	memcpy(data, buffer, size); -	kfree(buffer); +	ret = usb_control_msg(pegasus->usb, usb_rcvctrlpipe(pegasus->usb, 0), +			      PEGASUS_REQ_GET_REGS, PEGASUS_REQT_READ, 0, +			      indx, data, size, 1000); +	if (ret < 0) +		netif_dbg(pegasus, drv, pegasus->net, +			  "%s returned %d\n", __func__, ret);  	return ret;  } -static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, -			 void *data) +static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)  {  	int ret; -	char *buffer; -	DECLARE_WAITQUEUE(wait, current); - -	buffer = kmemdup(data, size, GFP_KERNEL); -	if (!buffer) { -		netif_warn(pegasus, drv, pegasus->net, -			   "out of memory in %s\n", __func__); -		return -ENOMEM; -	} - -	add_wait_queue(&pegasus->ctrl_wait, &wait); -	set_current_state(TASK_UNINTERRUPTIBLE); -	while (pegasus->flags & ETH_REGS_CHANGED) -		schedule(); -	remove_wait_queue(&pegasus->ctrl_wait, &wait); -	set_current_state(TASK_RUNNING); - -	pegasus->dr.bRequestType = PEGASUS_REQT_WRITE; -	pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS; -	pegasus->dr.wValue = cpu_to_le16(0); -	pegasus->dr.wIndex = cpu_to_le16(indx); -	pegasus->dr.wLength = cpu_to_le16(size); -	pegasus->ctrl_urb->transfer_buffer_length = size; - -	usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, -			     usb_sndctrlpipe(pegasus->usb, 0), -			     (char *) &pegasus->dr, -			     buffer, size, ctrl_callback, pegasus); - -	add_wait_queue(&pegasus->ctrl_wait, &wait); -	set_current_state(TASK_UNINTERRUPTIBLE); - -	if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { -		if (ret == -ENODEV) -			netif_device_detach(pegasus->net); -		netif_err(pegasus, drv, pegasus->net, -			  "%s, status %d\n", __func__, ret); -		goto out; -	} - -	schedule(); -out: -	remove_wait_queue(&pegasus->ctrl_wait, &wait); -	kfree(buffer); +	ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0), +			      PEGASUS_REQ_SET_REGS, PEGASUS_REQT_WRITE, 0, +			      indx, data, size, 100); +	if (ret < 0) +		netif_dbg(pegasus, drv, pegasus->net, +			  "%s returned %d\n", __func__, ret);  	return ret;  }  static int set_register(pegasus_t *pegasus, __u16 indx, __u8 data)  {  	int ret; -	char *tmp; -	DECLARE_WAITQUEUE(wait, current); - -	tmp = kmemdup(&data, 1, GFP_KERNEL); -	if (!tmp) { -		netif_warn(pegasus, drv, pegasus->net, -			   "out of memory in %s\n", __func__); -		return -ENOMEM; -	} -	add_wait_queue(&pegasus->ctrl_wait, &wait); -	set_current_state(TASK_UNINTERRUPTIBLE); -	while (pegasus->flags & ETH_REGS_CHANGED) -		schedule(); -	remove_wait_queue(&pegasus->ctrl_wait, &wait); -	set_current_state(TASK_RUNNING); - -	pegasus->dr.bRequestType = PEGASUS_REQT_WRITE; -	pegasus->dr.bRequest = PEGASUS_REQ_SET_REG; -	pegasus->dr.wValue = cpu_to_le16(data); -	pegasus->dr.wIndex = cpu_to_le16(indx); -	pegasus->dr.wLength = cpu_to_le16(1); -	pegasus->ctrl_urb->transfer_buffer_length = 1; - -	usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, -			     usb_sndctrlpipe(pegasus->usb, 0), -			     (char *) &pegasus->dr, -			     tmp, 1, ctrl_callback, pegasus); - -	add_wait_queue(&pegasus->ctrl_wait, &wait); -	set_current_state(TASK_UNINTERRUPTIBLE); - -	if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { -		if (ret == -ENODEV) -			netif_device_detach(pegasus->net); -		if (net_ratelimit()) -			netif_err(pegasus, drv, pegasus->net, -				  "%s, status %d\n", __func__, ret); -		goto out; -	} - -	schedule(); -out: -	remove_wait_queue(&pegasus->ctrl_wait, &wait); -	kfree(tmp); +	ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0), +			      PEGASUS_REQ_SET_REG, PEGASUS_REQT_WRITE, data, +			      indx, &data, 1, 1000); +	if (ret < 0) +		netif_dbg(pegasus, drv, pegasus->net, +			  "%s returned %d\n", __func__, ret);  	return ret;  }  static int update_eth_regs_async(pegasus_t *pegasus)  { -	int ret; - -	pegasus->dr.bRequestType = PEGASUS_REQT_WRITE; -	pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS; -	pegasus->dr.wValue = cpu_to_le16(0); -	pegasus->dr.wIndex = cpu_to_le16(EthCtrl0); -	pegasus->dr.wLength = cpu_to_le16(3); -	pegasus->ctrl_urb->transfer_buffer_length = 3; - -	usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, -			     usb_sndctrlpipe(pegasus->usb, 0), -			     (char *) &pegasus->dr, -			     pegasus->eth_regs, 3, ctrl_callback, pegasus); - -	if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { +	int ret = -ENOMEM; +	struct urb *async_urb; +	struct usb_ctrlrequest *req; + +	req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); +	if (req == NULL) +		return ret; + +	async_urb = usb_alloc_urb(0, GFP_ATOMIC); +	if (async_urb == NULL) { +		kfree(req); +		return ret; +	} +	req->bRequestType = PEGASUS_REQT_WRITE; +	req->bRequest = PEGASUS_REQ_SET_REGS; +	req->wValue = cpu_to_le16(0); +	req->wIndex = cpu_to_le16(EthCtrl0); +	req->wLength = cpu_to_le16(3); + +	usb_fill_control_urb(async_urb, pegasus->usb, +			     usb_sndctrlpipe(pegasus->usb, 0), (void *)req, +			     pegasus->eth_regs, 3, async_ctrl_callback, req); + +	ret = usb_submit_urb(async_urb, GFP_ATOMIC); +	if (ret) {  		if (ret == -ENODEV)  			netif_device_detach(pegasus->net);  		netif_err(pegasus, drv, pegasus->net, -			  "%s, status %d\n", __func__, ret); +			  "%s returned %d\n", __func__, ret);  	} -  	return ret;  } -/* Returns 0 on success, error on failure */ -static int read_mii_word(pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd) +static int __mii_op(pegasus_t *p, __u8 phy, __u8 indx, __u16 *regd, __u8 cmd)  {  	int i;  	__u8 data[4] = { phy, 0, 0, indx };  	__le16 regdi; -	int ret; +	int ret = -ETIMEDOUT; -	set_register(pegasus, PhyCtrl, 0); -	set_registers(pegasus, PhyAddr, sizeof(data), data); -	set_register(pegasus, PhyCtrl, (indx | PHY_READ)); +	if (cmd & PHY_WRITE) { +		__le16 *t = (__le16 *) & data[1]; +		*t = cpu_to_le16(*regd); +	} +	set_register(p, PhyCtrl, 0); +	set_registers(p, PhyAddr, sizeof(data), data); +	set_register(p, PhyCtrl, (indx | cmd));  	for (i = 0; i < REG_TIMEOUT; i++) { -		ret = get_registers(pegasus, PhyCtrl, 1, data); -		if (ret == -ESHUTDOWN) +		ret = get_registers(p, PhyCtrl, 1, data); +		if (ret < 0)  			goto fail;  		if (data[0] & PHY_DONE)  			break;  	} -  	if (i >= REG_TIMEOUT)  		goto fail; - -	ret = get_registers(pegasus, PhyData, 2, ®di); -	*regd = le16_to_cpu(regdi); +	if (cmd & PHY_READ) { +		ret = get_registers(p, PhyData, 2, ®di); +		*regd = le16_to_cpu(regdi); +		return ret; +	} +	return 0; +fail: +	netif_dbg(p, drv, p->net, "%s failed\n", __func__);  	return ret; +} -fail: -	netif_warn(pegasus, drv, pegasus->net, "%s failed\n", __func__); +/* Returns non-negative int on success, error on failure */ +static int read_mii_word(pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd) +{ +	return __mii_op(pegasus, phy, indx, regd, PHY_READ); +} -	return ret; +/* Returns zero on success, error on failure */ +static int write_mii_word(pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd) +{ +	return __mii_op(pegasus, phy, indx, regd, PHY_WRITE);  }  static int mdio_read(struct net_device *dev, int phy_id, int loc) @@ -366,40 +253,12 @@ static int mdio_read(struct net_device *dev, int phy_id, int loc)  	return (int)res;  } -static int write_mii_word(pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 regd) -{ -	int i; -	__u8 data[4] = { phy, 0, 0, indx }; -	int ret; - -	data[1] = (u8) regd; -	data[2] = (u8) (regd >> 8); -	set_register(pegasus, PhyCtrl, 0); -	set_registers(pegasus, PhyAddr, sizeof(data), data); -	set_register(pegasus, PhyCtrl, (indx | PHY_WRITE)); -	for (i = 0; i < REG_TIMEOUT; i++) { -		ret = get_registers(pegasus, PhyCtrl, 1, data); -		if (ret == -ESHUTDOWN) -			goto fail; -		if (data[0] & PHY_DONE) -			break; -	} - -	if (i >= REG_TIMEOUT) -		goto fail; - -	return ret; - -fail: -	netif_warn(pegasus, drv, pegasus->net, "%s failed\n", __func__); -	return -ETIMEDOUT; -} -  static void mdio_write(struct net_device *dev, int phy_id, int loc, int val)  {  	pegasus_t *pegasus = netdev_priv(dev); +	u16 data = val; -	write_mii_word(pegasus, phy_id, loc, val); +	write_mii_word(pegasus, phy_id, loc, &data);  }  static int read_eprom_word(pegasus_t *pegasus, __u8 index, __u16 *retdata) @@ -436,7 +295,6 @@ fail:  static inline void enable_eprom_write(pegasus_t *pegasus)  {  	__u8 tmp; -	int ret;  	get_registers(pegasus, EthCtrl2, 1, &tmp);  	set_register(pegasus, EthCtrl2, tmp | EPROM_WR_ENABLE); @@ -445,7 +303,6 @@ static inline void enable_eprom_write(pegasus_t *pegasus)  static inline void disable_eprom_write(pegasus_t *pegasus)  {  	__u8 tmp; -	int ret;  	get_registers(pegasus, EthCtrl2, 1, &tmp);  	set_register(pegasus, EpromCtrl, 0); @@ -517,7 +374,7 @@ static inline int reset_mac(pegasus_t *pegasus)  	for (i = 0; i < REG_TIMEOUT; i++) {  		get_registers(pegasus, EthCtrl1, 1, &data);  		if (~data & 0x08) { -			if (loopback & 1) +			if (loopback)  				break;  			if (mii_mode && (pegasus->features & HAS_HOME_PNA))  				set_register(pegasus, Gpio1, 0x34); @@ -539,7 +396,8 @@ static inline int reset_mac(pegasus_t *pegasus)  	if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_ELCON) {  		__u16 auxmode;  		read_mii_word(pegasus, 3, 0x1b, &auxmode); -		write_mii_word(pegasus, 3, 0x1b, auxmode | 4); +		auxmode |= 4; +		write_mii_word(pegasus, 3, 0x1b, &auxmode);  	}  	return 0; @@ -561,7 +419,7 @@ static int enable_net_traffic(struct net_device *dev, struct usb_device *usb)  		data[1] |= 0x10;	/* set 100 Mbps */  	if (mii_mode)  		data[1] = 0; -	data[2] = (loopback & 1) ? 0x09 : 0x01; +	data[2] = loopback ? 0x09 : 0x01;  	memcpy(pegasus->eth_regs, data, sizeof(data));  	ret = set_registers(pegasus, EthCtrl0, 3, data); @@ -571,57 +429,13 @@ static int enable_net_traffic(struct net_device *dev, struct usb_device *usb)  	    usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) {  		u16 auxmode;  		read_mii_word(pegasus, 0, 0x1b, &auxmode); -		write_mii_word(pegasus, 0, 0x1b, auxmode | 4); +		auxmode |= 4; +		write_mii_word(pegasus, 0, 0x1b, &auxmode);  	}  	return ret;  } -static void fill_skb_pool(pegasus_t *pegasus) -{ -	int i; - -	for (i = 0; i < RX_SKBS; i++) { -		if (pegasus->rx_pool[i]) -			continue; -		pegasus->rx_pool[i] = dev_alloc_skb(PEGASUS_MTU + 2); -		/* -		 ** we give up if the allocation fail. the tasklet will be -		 ** rescheduled again anyway... -		 */ -		if (pegasus->rx_pool[i] == NULL) -			return; -		skb_reserve(pegasus->rx_pool[i], 2); -	} -} - -static void free_skb_pool(pegasus_t *pegasus) -{ -	int i; - -	for (i = 0; i < RX_SKBS; i++) { -		if (pegasus->rx_pool[i]) { -			dev_kfree_skb(pegasus->rx_pool[i]); -			pegasus->rx_pool[i] = NULL; -		} -	} -} - -static inline struct sk_buff *pull_skb(pegasus_t * pegasus) -{ -	int i; -	struct sk_buff *skb; - -	for (i = 0; i < RX_SKBS; i++) { -		if (likely(pegasus->rx_pool[i] != NULL)) { -			skb = pegasus->rx_pool[i]; -			pegasus->rx_pool[i] = NULL; -			return skb; -		} -	} -	return NULL; -} -  static void read_bulk_callback(struct urb *urb)  {  	pegasus_t *pegasus = urb->context; @@ -706,9 +520,8 @@ static void read_bulk_callback(struct urb *urb)  	if (pegasus->flags & PEGASUS_UNPLUG)  		return; -	spin_lock(&pegasus->rx_pool_lock); -	pegasus->rx_skb = pull_skb(pegasus); -	spin_unlock(&pegasus->rx_pool_lock); +	pegasus->rx_skb = __netdev_alloc_skb_ip_align(pegasus->net, PEGASUS_MTU, +						      GFP_ATOMIC);  	if (pegasus->rx_skb == NULL)  		goto tl_sched; @@ -736,24 +549,23 @@ tl_sched:  static void rx_fixup(unsigned long data)  {  	pegasus_t *pegasus; -	unsigned long flags;  	int status;  	pegasus = (pegasus_t *) data;  	if (pegasus->flags & PEGASUS_UNPLUG)  		return; -	spin_lock_irqsave(&pegasus->rx_pool_lock, flags); -	fill_skb_pool(pegasus);  	if (pegasus->flags & PEGASUS_RX_URB_FAIL)  		if (pegasus->rx_skb)  			goto try_again;  	if (pegasus->rx_skb == NULL) -		pegasus->rx_skb = pull_skb(pegasus); +		pegasus->rx_skb = __netdev_alloc_skb_ip_align(pegasus->net, +							      PEGASUS_MTU, +							      GFP_ATOMIC);  	if (pegasus->rx_skb == NULL) {  		netif_warn(pegasus, rx_err, pegasus->net, "low on memory\n");  		tasklet_schedule(&pegasus->rx_tl); -		goto done; +		return;  	}  	usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb,  			  usb_rcvbulkpipe(pegasus->usb, 1), @@ -769,8 +581,6 @@ try_again:  	} else {  		pegasus->flags &= ~PEGASUS_RX_URB_FAIL;  	} -done: -	spin_unlock_irqrestore(&pegasus->rx_pool_lock, flags);  }  static void write_bulk_callback(struct urb *urb) @@ -965,7 +775,6 @@ static void free_all_urbs(pegasus_t *pegasus)  	usb_free_urb(pegasus->intr_urb);  	usb_free_urb(pegasus->tx_urb);  	usb_free_urb(pegasus->rx_urb); -	usb_free_urb(pegasus->ctrl_urb);  }  static void unlink_all_urbs(pegasus_t *pegasus) @@ -973,48 +782,42 @@ static void unlink_all_urbs(pegasus_t *pegasus)  	usb_kill_urb(pegasus->intr_urb);  	usb_kill_urb(pegasus->tx_urb);  	usb_kill_urb(pegasus->rx_urb); -	usb_kill_urb(pegasus->ctrl_urb);  }  static int alloc_urbs(pegasus_t *pegasus)  { -	pegasus->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); -	if (!pegasus->ctrl_urb) -		return 0; +	int res = -ENOMEM; +  	pegasus->rx_urb = usb_alloc_urb(0, GFP_KERNEL);  	if (!pegasus->rx_urb) { -		usb_free_urb(pegasus->ctrl_urb); -		return 0; +		return res;  	}  	pegasus->tx_urb = usb_alloc_urb(0, GFP_KERNEL);  	if (!pegasus->tx_urb) {  		usb_free_urb(pegasus->rx_urb); -		usb_free_urb(pegasus->ctrl_urb); -		return 0; +		return res;  	}  	pegasus->intr_urb = usb_alloc_urb(0, GFP_KERNEL);  	if (!pegasus->intr_urb) {  		usb_free_urb(pegasus->tx_urb);  		usb_free_urb(pegasus->rx_urb); -		usb_free_urb(pegasus->ctrl_urb); -		return 0; +		return res;  	} -	return 1; +	return 0;  }  static int pegasus_open(struct net_device *net)  {  	pegasus_t *pegasus = netdev_priv(net); -	int res; +	int res=-ENOMEM;  	if (pegasus->rx_skb == NULL) -		pegasus->rx_skb = pull_skb(pegasus); -	/* -	 ** Note: no point to free the pool.  it is empty :-) -	 */ +		pegasus->rx_skb = __netdev_alloc_skb_ip_align(pegasus->net, +							      PEGASUS_MTU, +							      GFP_KERNEL);  	if (!pegasus->rx_skb) -		return -ENOMEM; +		goto exit;  	res = set_registers(pegasus, EthID, 6, net->dev_addr); @@ -1040,13 +843,13 @@ static int pegasus_open(struct net_device *net)  		usb_kill_urb(pegasus->rx_urb);  		goto exit;  	} -	if ((res = enable_net_traffic(net, pegasus->usb))) { +	res = enable_net_traffic(net, pegasus->usb); +	if (res < 0) {  		netif_dbg(pegasus, ifup, net,  			  "can't enable_net_traffic() - %d\n", res);  		res = -EIO;  		usb_kill_urb(pegasus->rx_urb);  		usb_kill_urb(pegasus->intr_urb); -		free_skb_pool(pegasus);  		goto exit;  	}  	set_carrier(net); @@ -1074,8 +877,9 @@ static void pegasus_get_drvinfo(struct net_device *dev,  				struct ethtool_drvinfo *info)  {  	pegasus_t *pegasus = netdev_priv(dev); -	strncpy(info->driver, driver_name, sizeof(info->driver) - 1); -	strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1); + +	strlcpy(info->driver, driver_name, sizeof(info->driver)); +	strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));  	usb_make_path(pegasus->usb, info->bus_info, sizeof(info->bus_info));  } @@ -1096,6 +900,7 @@ pegasus_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)  {  	pegasus_t	*pegasus = netdev_priv(dev);  	u8		reg78 = 0x04; +	int		ret;  	if (wol->wolopts & ~WOL_SUPPORTED)  		return -EINVAL; @@ -1110,7 +915,12 @@ pegasus_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)  	else  		pegasus->eth_regs[0] &= ~0x10;  	pegasus->wolopts = wol->wolopts; -	return set_register(pegasus, WakeupControl, reg78); + +	ret = set_register(pegasus, WakeupControl, reg78); +	if (!ret) +		ret = device_set_wakeup_enable(&pegasus->usb->dev, +						wol->wolopts); +	return ret;  }  static inline void pegasus_reset_wol(struct net_device *dev) @@ -1190,7 +1000,7 @@ static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd)  	case SIOCDEVPRIVATE + 2:  		if (!capable(CAP_NET_ADMIN))  			return -EPERM; -		write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]); +		write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, &data[2]);  		res = 0;  		break;  	default: @@ -1214,11 +1024,7 @@ static void pegasus_set_multicast(struct net_device *net)  		pegasus->eth_regs[EthCtrl0] &= ~RX_MULTICAST;  		pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;  	} - -	pegasus->ctrl_urb->status = 0; - -	pegasus->flags |= ETH_REGS_CHANGE; -	ctrl_callback(pegasus->ctrl_urb); +	update_eth_regs_async(pegasus);  }  static __u8 mii_phy_probe(pegasus_t *pegasus) @@ -1329,19 +1135,15 @@ static int pegasus_probe(struct usb_interface *intf,  	}  	pegasus_count++; -	usb_get_dev(dev); -  	net = alloc_etherdev(sizeof(struct pegasus)); -	if (!net) { -		dev_err(&intf->dev, "can't allocate %s\n", "device"); +	if (!net)  		goto out; -	}  	pegasus = netdev_priv(net);  	pegasus->dev_index = dev_index; -	init_waitqueue_head(&pegasus->ctrl_wait); -	if (!alloc_urbs(pegasus)) { +	res = alloc_urbs(pegasus); +	if (res < 0) {  		dev_err(&intf->dev, "can't allocate %s\n", "urbs");  		goto out1;  	} @@ -1357,13 +1159,12 @@ static int pegasus_probe(struct usb_interface *intf,  	net->watchdog_timeo = PEGASUS_TX_TIMEOUT;  	net->netdev_ops = &pegasus_netdev_ops; -	SET_ETHTOOL_OPS(net, &ops); +	net->ethtool_ops = &ops;  	pegasus->mii.dev = net;  	pegasus->mii.mdio_read = mdio_read;  	pegasus->mii.mdio_write = mdio_write;  	pegasus->mii.phy_id_mask = 0x1f;  	pegasus->mii.reg_num_mask = 0x1f; -	spin_lock_init(&pegasus->rx_pool_lock);  	pegasus->msg_enable = netif_msg_init(msg_level, NETIF_MSG_DRV  				| NETIF_MSG_PROBE | NETIF_MSG_LINK); @@ -1375,7 +1176,6 @@ static int pegasus_probe(struct usb_interface *intf,  		goto out2;  	}  	set_ethernet_addr(pegasus); -	fill_skb_pool(pegasus);  	if (pegasus->features & PEGASUS_II) {  		dev_info(&intf->dev, "setup Pegasus II specific registers\n");  		setup_pegasus_II(pegasus); @@ -1393,23 +1193,18 @@ static int pegasus_probe(struct usb_interface *intf,  	if (res)  		goto out3;  	queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, -				CARRIER_CHECK_DELAY); - -	dev_info(&intf->dev, "%s, %s, %pM\n", -		 net->name, -		 usb_dev_id[dev_index].name, -		 net->dev_addr); +			   CARRIER_CHECK_DELAY); +	dev_info(&intf->dev, "%s, %s, %pM\n", net->name, +		 usb_dev_id[dev_index].name, net->dev_addr);  	return 0;  out3:  	usb_set_intfdata(intf, NULL); -	free_skb_pool(pegasus);  out2:  	free_all_urbs(pegasus);  out1:  	free_netdev(net);  out: -	usb_put_dev(dev);  	pegasus_dec_workqueue();  	return res;  } @@ -1427,10 +1222,8 @@ static void pegasus_disconnect(struct usb_interface *intf)  	pegasus->flags |= PEGASUS_UNPLUG;  	cancel_delayed_work(&pegasus->carrier_check);  	unregister_netdev(pegasus->net); -	usb_put_dev(interface_to_usbdev(intf));  	unlink_all_urbs(pegasus);  	free_all_urbs(pegasus); -	free_skb_pool(pegasus);  	if (pegasus->rx_skb != NULL) {  		dev_kfree_skb(pegasus->rx_skb);  		pegasus->rx_skb = NULL; @@ -1476,7 +1269,7 @@ static const struct net_device_ops pegasus_netdev_ops = {  	.ndo_stop =			pegasus_close,  	.ndo_do_ioctl =			pegasus_ioctl,  	.ndo_start_xmit =		pegasus_start_xmit, -	.ndo_set_multicast_list =	pegasus_set_multicast, +	.ndo_set_rx_mode =		pegasus_set_multicast,  	.ndo_get_stats =		pegasus_netdev_stats,  	.ndo_tx_timeout =		pegasus_tx_timeout,  	.ndo_change_mtu =		eth_change_mtu, @@ -1491,6 +1284,7 @@ static struct usb_driver pegasus_driver = {  	.id_table = pegasus_ids,  	.suspend = pegasus_suspend,  	.resume = pegasus_resume, +	.disable_hub_initiated_lpm = 1,  };  static void __init parse_id(char *id)  | 
