41 #include <linux/module.h>
43 #include <linux/netdevice.h>
44 #include <linux/ctype.h>
45 #include <linux/ethtool.h>
47 #include <linux/mii.h>
50 #include <linux/hrtimer.h>
55 #define DRIVER_VERSION "14-Mar-2012"
58 #define USB_CDC_NCM_NDP16_LENGTH_MIN 0x10
61 #define CDC_NCM_NTB_MAX_SIZE_TX 32768
62 #define CDC_NCM_NTB_MAX_SIZE_RX 32768
65 #define CDC_NCM_MIN_DATAGRAM_SIZE 1514
67 #define CDC_NCM_MIN_TX_PKT 512
70 #define CDC_NCM_MAX_DATAGRAM_SIZE 8192
76 #define CDC_NCM_DPT_DATAGRAMS_MAX 40
79 #define CDC_NCM_RESTART_TIMER_DATAGRAM_CNT 3
80 #define CDC_NCM_TIMER_PENDING_CNT 2
81 #define CDC_NCM_TIMER_INTERVAL (400UL * NSEC_PER_USEC)
84 #define CDC_NCM_MIN_HDR_SIZE \
85 (sizeof(struct usb_cdc_ncm_nth16) + sizeof(struct usb_cdc_ncm_ndp16) + \
86 (CDC_NCM_DPT_DATAGRAMS_MAX + 1) * sizeof(struct usb_cdc_ncm_dpe16))
138 static void cdc_ncm_txpath_bh(
unsigned long param);
141 static struct usb_driver cdc_ncm_driver;
161 u16 ntb_fmt_supported;
163 iface_no = ctx->
control->cur_altsetting->desc.bInterfaceNumber;
166 usb_rcvctrlpipe(ctx->
udev, 0),
173 pr_debug(
"failed GET_NTB_PARAMETERS\n");
188 flags = ctx->
func_desc->bmNetworkCapabilities;
192 pr_debug(
"dwNtbInMaxSize=%u dwNtbOutMaxSize=%u "
193 "wNdpOutPayloadRemainder=%u wNdpOutDivisor=%u "
194 "wNdpOutAlignment=%u wNtbOutMaxDatagrams=%u flags=0x%x\n",
205 pr_debug(
"Using min receive length=%d\n",
211 pr_debug(
"Using default maximum receive length=%d\n",
222 ndp_in_sz = kzalloc(
sizeof(*ndp_in_sz),
GFP_KERNEL);
229 usb_sndctrlpipe(ctx->
udev, 0),
233 0, iface_no, ndp_in_sz, 8, 1000);
237 dwNtbInMaxSize = kzalloc(
sizeof(*dwNtbInMaxSize),
239 if (!dwNtbInMaxSize) {
246 usb_sndctrlpipe(ctx->
udev, 0),
250 0, iface_no, dwNtbInMaxSize, 4, 1000);
251 kfree(dwNtbInMaxSize);
255 pr_debug(
"Setting NTB Input Size failed\n");
262 pr_debug(
"Using default maximum transmit length=%d\n",
276 (val != ((-val) & val)) || (val >= ctx->
tx_max)) {
277 pr_debug(
"Using default alignment: 4 bytes\n");
290 (val != ((-val) & val)) || (val >= ctx->
tx_max)) {
291 pr_debug(
"Using default transmit modulus: 4 bytes\n");
297 pr_debug(
"Using default transmit remainder: 0 bytes\n");
314 iface_no,
NULL, 0, 1000);
316 pr_debug(
"Setting CRC mode off failed\n");
325 iface_no,
NULL, 0, 1000);
327 pr_debug(
"Setting NTB format to 16-bit failed\n");
334 __le16 *max_datagram_size;
337 max_datagram_size = kzalloc(
sizeof(*max_datagram_size),
339 if (!max_datagram_size) {
348 0, iface_no, max_datagram_size,
351 pr_debug(
"GET_MAX_DATAGRAM_SIZE failed, use size=%u\n",
372 usb_sndctrlpipe(ctx->
udev, 0),
377 iface_no, max_datagram_size,
380 pr_debug(
"SET_MAX_DGRAM_SIZE failed\n");
383 kfree(max_datagram_size);
396 struct usb_host_endpoint *
e;
399 for (ep = 0; ep < intf->cur_altsetting->desc.bNumEndpoints; ep++) {
401 e = intf->cur_altsetting->endpoint + ep;
404 if (usb_endpoint_dir_in(&e->desc)) {
411 if (usb_endpoint_dir_in(&e->desc)) {
444 static const struct ethtool_ops cdc_ncm_ethtool_ops = {
445 .get_drvinfo = cdc_ncm_get_drvinfo,
457 struct usb_driver *
driver;
468 ctx->
tx_timer.function = &cdc_ncm_tx_timer_cb;
469 ctx->
bh.data = (
unsigned long)ctx;
470 ctx->
bh.func = cdc_ncm_txpath_bh;
479 driver = driver_of(intf);
480 buf = intf->cur_altsetting->extra;
481 len = intf->cur_altsetting->extralen;
487 while ((len > 0) && (buf[0] > 2) && (buf[0] <= len)) {
550 iface_no = ctx->
data->cur_altsetting->desc.bInterfaceNumber;
558 if (cdc_ncm_setup(ctx))
566 cdc_ncm_find_endpoints(ctx, ctx->
data);
567 cdc_ncm_find_endpoints(ctx, ctx->
control);
573 dev->
net->ethtool_ops = &cdc_ncm_ethtool_ops;
575 usb_set_intfdata(ctx->
data, dev);
576 usb_set_intfdata(ctx->
control, dev);
577 usb_set_intfdata(ctx->
intf, dev);
585 dev->
in = usb_rcvbulkpipe(dev->
udev,
587 dev->
out = usb_sndbulkpipe(dev->
udev,
616 struct usb_driver *driver = driver_of(intf);
656 memset(ptr + first, 0, end - first);
694 if (skb_out ==
NULL) {
697 ctx->
netdev->stats.tx_dropped++;
706 (ctx->tx_max_datagrams + 1) *
714 cdc_ncm_zero_fill(skb_out->
data, 0, offset, offset);
721 if (offset >= ctx->
tx_max) {
737 if (skb->
len > rem) {
742 ctx->
netdev->stats.tx_dropped++;
747 ctx->
netdev->stats.tx_dropped++;
771 cdc_ncm_zero_fill(skb_out->
data, last_offset, offset,
781 ctx->
netdev->stats.tx_dropped++;
794 }
else if ((n < ctx->tx_max_datagrams) && (ready2send == 0)) {
811 if (last_offset > ctx->
tx_max)
812 last_offset = ctx->
tx_max;
815 offset = last_offset;
827 cdc_ncm_zero_fill(skb_out->
data, last_offset, offset, ctx->
tx_max);
832 if (((last_offset < ctx->tx_max) && ((last_offset %
838 *(((
u8 *)skb_out->
data) + last_offset) = 0;
844 ctx->
tx_ncm.dpe16[
n].wDatagramLength = 0;
845 ctx->
tx_ncm.dpe16[
n].wDatagramIndex = 0;
850 ctx->
tx_ncm.nth16.wHeaderLength =
861 ctx->
tx_ncm.ndp16.dwSignature =
866 ctx->
tx_ncm.ndp16.wNextNdpIndex = 0;
870 sizeof(ctx->
tx_ncm.ndp16));
888 cdc_ncm_tx_timeout_start(ctx);
892 static void cdc_ncm_tx_timeout_start(
struct cdc_ncm_ctx *ctx)
907 tasklet_schedule(&ctx->
bh);
911 static void cdc_ncm_txpath_bh(
unsigned long param)
915 spin_lock_bh(&ctx->
mtx);
918 cdc_ncm_tx_timeout_start(ctx);
919 spin_unlock_bh(&ctx->
mtx);
921 spin_unlock_bh(&ctx->
mtx);
922 netif_tx_lock_bh(ctx->
netdev);
924 netif_tx_unlock_bh(ctx->
netdev);
944 spin_lock_bh(&ctx->
mtx);
945 skb_out = cdc_ncm_fill_tx_frame(ctx, skb);
946 spin_unlock_bh(&ctx->
mtx);
956 static int cdc_ncm_rx_fixup(
struct usbnet *dev,
struct sk_buff *skb_in)
980 pr_debug(
"invalid NTH16 signature <%u>\n",
987 pr_debug(
"unsupported NTB block length %u/%u\n", len,
995 pr_debug(
"sequence number glitch prev=%d curr=%d\n",
1002 pr_debug(
"invalid DPT16 index <%u>\n",
1010 pr_debug(
"invalid DPT16 signature <%u>\n",
1016 pr_debug(
"invalid DPT16 length <%u>\n",
1030 pr_debug(
"Invalid nframes = %d\n", nframes);
1036 for (
x = 0;
x < nframes;
x++,
dpe16++) {
1044 if ((offset == 0) || (len == 0)) {
1051 if (((offset + len) > skb_in->
len) ||
1053 pr_debug(
"invalid frame detected (ignored)"
1054 "offset[%u]=%u, length=%u, skb=%p\n",
1055 x, offset, len, skb_in);
1066 skb_set_tail_pointer(skb, len);
1090 if ((tx_speed > 1000000) && (rx_speed > 1000000)) {
1092 ": %s: %u mbit/s downlink "
1093 "%u mbit/s uplink\n",
1095 (
unsigned int)(rx_speed / 1000000
U),
1096 (
unsigned int)(tx_speed / 1000000
U));
1099 ": %s: %u kbit/s downlink "
1100 "%u kbit/s uplink\n",
1102 (
unsigned int)(rx_speed / 1000
U),
1103 (
unsigned int)(tx_speed / 1000
U));
1108 static void cdc_ncm_status(
struct usbnet *dev,
struct urb *
urb)
1115 if (urb->actual_length <
sizeof(*event))
1120 cdc_ncm_speed_change(ctx,
1125 event = urb->transfer_buffer;
1149 if (urb->actual_length < (
sizeof(*event) +
1153 cdc_ncm_speed_change(ctx,
1164 static int cdc_ncm_check_connect(
struct usbnet *dev)
1183 struct usbnet *dev = usb_get_intfdata(intf);
1191 static int cdc_ncm_manage_power(
struct usbnet *dev,
int status)
1198 .description =
"CDC NCM",
1200 .bind = cdc_ncm_bind,
1201 .unbind = cdc_ncm_unbind,
1202 .check_connect = cdc_ncm_check_connect,
1203 .manage_power = cdc_ncm_manage_power,
1204 .status = cdc_ncm_status,
1205 .rx_fixup = cdc_ncm_rx_fixup,
1206 .tx_fixup = cdc_ncm_tx_fixup,
1211 .description =
"Mobile Broadband Network Device",
1214 .bind = cdc_ncm_bind,
1215 .unbind = cdc_ncm_unbind,
1216 .check_connect = cdc_ncm_check_connect,
1217 .manage_power = cdc_ncm_manage_power,
1218 .status = cdc_ncm_status,
1219 .rx_fixup = cdc_ncm_rx_fixup,
1220 .tx_fixup = cdc_ncm_tx_fixup,
1225 { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
1231 .driver_info = (
unsigned long) &wwan_info,
1235 { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
1241 .driver_info = (
unsigned long) &wwan_info,
1245 { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
1251 .driver_info = (
unsigned long) &wwan_info,
1255 { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x16),
1256 .driver_info = (
unsigned long)&wwan_info,
1258 { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x46),
1259 .driver_info = (
unsigned long)&wwan_info,
1265 .driver_info = (
unsigned long)&cdc_ncm_info,
1272 static struct usb_driver cdc_ncm_driver = {
1274 .id_table = cdc_devs,
1275 .probe = cdc_ncm_probe,
1276 .disconnect = cdc_ncm_disconnect,
1280 .supports_autosuspend = 1,
1281 .disable_hub_initiated_lpm = 1,