diff options
Diffstat (limited to 'drivers/net/usb/sierra_net.c')
| -rw-r--r-- | drivers/net/usb/sierra_net.c | 130 |
1 files changed, 64 insertions, 66 deletions
diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c index 8e22417fa6c..a251588762e 100644 --- a/drivers/net/usb/sierra_net.c +++ b/drivers/net/usb/sierra_net.c @@ -21,8 +21,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #define DRIVER_VERSION "v.2.0" @@ -68,9 +67,8 @@ static atomic_t iface_counter = ATOMIC_INIT(0); */ #define SIERRA_NET_USBCTL_BUF_LEN 1024 -struct sierra_net_info_data { - u16 rx_urb_size; -}; +/* Overriding the default usbnet rx_urb_size */ +#define SIERRA_NET_RX_URB_SIZE (8 * 1024) /* Private data structure */ struct sierra_net_data { @@ -312,10 +310,9 @@ static int sierra_net_send_cmd(struct usbnet *dev, struct sierra_net_data *priv = sierra_net_get_private(dev); int status; - status = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), - USB_CDC_SEND_ENCAPSULATED_COMMAND, - USB_DIR_OUT|USB_TYPE_CLASS|USB_RECIP_INTERFACE, 0, - priv->ifnum, cmd, cmdlen, USB_CTRL_SET_TIMEOUT); + status = usbnet_write_cmd(dev, USB_CDC_SEND_ENCAPSULATED_COMMAND, + USB_DIR_OUT|USB_TYPE_CLASS|USB_RECIP_INTERFACE, + 0, priv->ifnum, cmd, cmdlen); if (status != cmdlen && status != -ENODEV) netdev_err(dev->net, "Submit %s failed %d\n", cmd_name, status); @@ -341,7 +338,7 @@ static void sierra_net_set_ctx_index(struct sierra_net_data *priv, u8 ctx_ix) dev_dbg(&(priv->usbnet->udev->dev), "%s %d", __func__, ctx_ix); priv->tx_hdr_template[0] = 0x3F; priv->tx_hdr_template[1] = ctx_ix; - *((u16 *)&priv->tx_hdr_template[2]) = + *((__be16 *)&priv->tx_hdr_template[2]) = cpu_to_be16(SIERRA_NET_HIP_EXT_IP_OUT_ID); } @@ -415,11 +412,10 @@ static void sierra_net_handle_lsi(struct usbnet *dev, char *data, if (link_up) { sierra_net_set_ctx_index(priv, hh->msgspecific.byte); priv->link_up = 1; - netif_carrier_on(dev->net); } else { priv->link_up = 0; - netif_carrier_off(dev->net); } + usbnet_link_change(dev, link_up, 0); } static void sierra_net_dosync(struct usbnet *dev) @@ -429,6 +425,13 @@ static void sierra_net_dosync(struct usbnet *dev) dev_dbg(&dev->udev->dev, "%s", __func__); + /* The SIERRA_NET_HIP_MSYNC_ID command appears to request that the + * firmware restart itself. After restarting, the modem will respond + * with the SIERRA_NET_HIP_RESTART_ID indication. The driver continues + * sending MSYNC commands every few seconds until it receives the + * RESTART event from the firmware + */ + /* tell modem we are ready */ status = sierra_net_send_sync(dev); if (status < 0) @@ -461,11 +464,9 @@ static void sierra_net_kevent(struct work_struct *work) /* Query the modem for the LSI message */ buf = kzalloc(SIERRA_NET_USBCTL_BUF_LEN, GFP_KERNEL); - if (!buf) { - netdev_err(dev->net, - "failed to allocate buf for LS msg\n"); + if (!buf) return; - } + ifnum = priv->ifnum; len = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), USB_CDC_GET_ENCAPSULATED_RESPONSE, @@ -560,7 +561,7 @@ static void sierra_net_defer_kevent(struct usbnet *dev, int work) /* * Sync Retransmit Timer Handler. On expiry, kick the work queue */ -void sierra_sync_timer(unsigned long syncdata) +static void sierra_sync_timer(unsigned long syncdata) { struct usbnet *dev = (struct usbnet *)syncdata; @@ -600,8 +601,8 @@ static void sierra_net_get_drvinfo(struct net_device *net, { /* Inherit standard device info */ usbnet_get_drvinfo(net, info); - strncpy(info->driver, driver_name, sizeof info->driver); - strncpy(info->version, DRIVER_VERSION, sizeof info->version); + strlcpy(info->driver, driver_name, sizeof(info->driver)); + strlcpy(info->version, DRIVER_VERSION, sizeof(info->version)); } static u32 sierra_net_get_link(struct net_device *net) @@ -633,32 +634,22 @@ static int sierra_net_change_mtu(struct net_device *net, int new_mtu) static int sierra_net_get_fw_attr(struct usbnet *dev, u16 *datap) { int result = 0; - u16 *attrdata; - - attrdata = kmalloc(sizeof(*attrdata), GFP_KERNEL); - if (!attrdata) - return -ENOMEM; - - result = usb_control_msg( - dev->udev, - usb_rcvctrlpipe(dev->udev, 0), - /* _u8 vendor specific request */ - SWI_USB_REQUEST_GET_FW_ATTR, - USB_DIR_IN | USB_TYPE_VENDOR, /* __u8 request type */ - 0x0000, /* __u16 value not used */ - 0x0000, /* __u16 index not used */ - attrdata, /* char *data */ - sizeof(*attrdata), /* __u16 size */ - USB_CTRL_SET_TIMEOUT); /* int timeout */ - - if (result < 0) { - kfree(attrdata); + __le16 attrdata; + + result = usbnet_read_cmd(dev, + /* _u8 vendor specific request */ + SWI_USB_REQUEST_GET_FW_ATTR, + USB_DIR_IN | USB_TYPE_VENDOR, /* __u8 request type */ + 0x0000, /* __u16 value not used */ + 0x0000, /* __u16 index not used */ + &attrdata, /* char *data */ + sizeof(attrdata) /* __u16 size */ + ); + + if (result < 0) return -EIO; - } - *datap = le16_to_cpu(*attrdata); - - kfree(attrdata); + *datap = le16_to_cpu(attrdata); return result; } @@ -678,9 +669,6 @@ static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf) static const u8 shdwn_tmplate[sizeof(priv->shdwn_msg)] = { 0x00, 0x00, SIERRA_NET_HIP_SHUTD_ID, 0x00}; - struct sierra_net_info_data *data = - (struct sierra_net_info_data *)dev->driver_info->data; - dev_dbg(&dev->udev->dev, "%s", __func__); ifacenum = intf->cur_altsetting->desc.bInterfaceNumber; @@ -701,10 +689,8 @@ static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf) } /* Initialize sierra private data */ priv = kzalloc(sizeof *priv, GFP_KERNEL); - if (!priv) { - dev_err(&dev->udev->dev, "No memory"); + if (!priv) return -ENOMEM; - } priv->usbnet = dev; priv->ifnum = ifacenum; @@ -724,10 +710,13 @@ static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf) /* set context index initially to 0 - prepares tx hdr template */ sierra_net_set_ctx_index(priv, 0); + /* prepare sync message template */ + memcpy(priv->sync_msg, sync_tmplate, sizeof(priv->sync_msg)); + /* decrease the rx_urb_size and max_tx_size to 4k on USB 1.1 */ - dev->rx_urb_size = data->rx_urb_size; + dev->rx_urb_size = SIERRA_NET_RX_URB_SIZE; if (dev->udev->speed != USB_SPEED_HIGH) - dev->rx_urb_size = min_t(size_t, 4096, data->rx_urb_size); + dev->rx_urb_size = min_t(size_t, 4096, SIERRA_NET_RX_URB_SIZE); dev->net->hard_header_len += SIERRA_NET_HIP_EXT_HDR_LEN; dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; @@ -759,11 +748,6 @@ static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf) kfree(priv); return -ENODEV; } - /* prepare sync message from template */ - memcpy(priv->sync_msg, sync_tmplate, sizeof(priv->sync_msg)); - - /* initiate the sync sequence */ - sierra_net_dosync(dev); return 0; } @@ -786,8 +770,9 @@ static void sierra_net_unbind(struct usbnet *dev, struct usb_interface *intf) netdev_err(dev->net, "usb_control_msg failed, status %d\n", status); - sierra_net_set_private(dev, NULL); + usbnet_status_stop(dev); + sierra_net_set_private(dev, NULL); kfree(priv); } @@ -842,7 +827,7 @@ static int sierra_net_rx_fixup(struct usbnet *dev, struct sk_buff *skb) netdev_err(dev->net, "HIP/ETH: Invalid pkt\n"); dev->net->stats.rx_frame_errors++; - /* dev->net->stats.rx_errors incremented by caller */; + /* dev->net->stats.rx_errors incremented by caller */ return 0; } @@ -866,8 +851,8 @@ static int sierra_net_rx_fixup(struct usbnet *dev, struct sk_buff *skb) } /* ---------------------------- Transmit data path ----------------------*/ -struct sk_buff *sierra_net_tx_fixup(struct usbnet *dev, struct sk_buff *skb, - gfp_t flags) +static struct sk_buff *sierra_net_tx_fixup(struct usbnet *dev, + struct sk_buff *skb, gfp_t flags) { struct sierra_net_data *priv = sierra_net_get_private(dev); u16 len; @@ -918,10 +903,6 @@ struct sk_buff *sierra_net_tx_fixup(struct usbnet *dev, struct sk_buff *skb, return NULL; } -static const struct sierra_net_info_data sierra_net_info_data_direct_ip = { - .rx_urb_size = 8 * 1024, -}; - static const struct driver_info sierra_net_info_direct_ip = { .description = "Sierra Wireless USB-to-WWAN Modem", .flags = FLAG_WWAN | FLAG_SEND_ZLP, @@ -930,9 +911,26 @@ static const struct driver_info sierra_net_info_direct_ip = { .status = sierra_net_status, .rx_fixup = sierra_net_rx_fixup, .tx_fixup = sierra_net_tx_fixup, - .data = (unsigned long)&sierra_net_info_data_direct_ip, }; +static int +sierra_net_probe(struct usb_interface *udev, const struct usb_device_id *prod) +{ + int ret; + + ret = usbnet_probe(udev, prod); + if (ret == 0) { + struct usbnet *dev = usb_get_intfdata(udev); + + ret = usbnet_status_start(dev, GFP_KERNEL); + if (ret == 0) { + /* Interrupt URB now set up; initiate sync sequence */ + sierra_net_dosync(dev); + } + } + return ret; +} + #define DIRECT_IP_DEVICE(vend, prod) \ {USB_DEVICE_INTERFACE_NUMBER(vend, prod, 7), \ .driver_info = (unsigned long)&sierra_net_info_direct_ip}, \ @@ -955,7 +953,7 @@ MODULE_DEVICE_TABLE(usb, products); static struct usb_driver sierra_net_driver = { .name = "sierra_net", .id_table = products, - .probe = usbnet_probe, + .probe = sierra_net_probe, .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, |
