Commit bd0d7aa6b20a9e78def76a0ba8c414daf253c295
Committed by
David S. Miller
1 parent
6d1a3e042f
Exists in
master
and in
6 other branches
drivers/net: static should be at beginning of declaration
Make sure that the 'static' keywork is at the beginning of declaration for drivers/net/usb/kalmia.c This gets rid of warnings like warning: ‘static’ is not at beginning of declaration when building with -Wold-style-declaration (and/or -Wextra which also enables it). Signed-off-by: Jesper Juhl <jj@chaosbits.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 1 changed file with 6 additions and 6 deletions Inline Diff
drivers/net/usb/kalmia.c
1 | /* | 1 | /* |
2 | * USB network interface driver for Samsung Kalmia based LTE USB modem like the | 2 | * USB network interface driver for Samsung Kalmia based LTE USB modem like the |
3 | * Samsung GT-B3730 and GT-B3710. | 3 | * Samsung GT-B3730 and GT-B3710. |
4 | * | 4 | * |
5 | * Copyright (C) 2011 Marius Bjoernstad Kotsbak <marius@kotsbak.com> | 5 | * Copyright (C) 2011 Marius Bjoernstad Kotsbak <marius@kotsbak.com> |
6 | * | 6 | * |
7 | * Sponsored by Quicklink Video Distribution Services Ltd. | 7 | * Sponsored by Quicklink Video Distribution Services Ltd. |
8 | * | 8 | * |
9 | * Based on the cdc_eem module. | 9 | * Based on the cdc_eem module. |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
13 | * the Free Software Foundation; either version 2 of the License, or | 13 | * the Free Software Foundation; either version 2 of the License, or |
14 | * (at your option) any later version. | 14 | * (at your option) any later version. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
19 | #include <linux/netdevice.h> | 19 | #include <linux/netdevice.h> |
20 | #include <linux/etherdevice.h> | 20 | #include <linux/etherdevice.h> |
21 | #include <linux/ctype.h> | 21 | #include <linux/ctype.h> |
22 | #include <linux/ethtool.h> | 22 | #include <linux/ethtool.h> |
23 | #include <linux/workqueue.h> | 23 | #include <linux/workqueue.h> |
24 | #include <linux/mii.h> | 24 | #include <linux/mii.h> |
25 | #include <linux/usb.h> | 25 | #include <linux/usb.h> |
26 | #include <linux/crc32.h> | 26 | #include <linux/crc32.h> |
27 | #include <linux/usb/cdc.h> | 27 | #include <linux/usb/cdc.h> |
28 | #include <linux/usb/usbnet.h> | 28 | #include <linux/usb/usbnet.h> |
29 | #include <linux/gfp.h> | 29 | #include <linux/gfp.h> |
30 | 30 | ||
31 | /* | 31 | /* |
32 | * The Samsung Kalmia based LTE USB modems have a CDC ACM port for modem control | 32 | * The Samsung Kalmia based LTE USB modems have a CDC ACM port for modem control |
33 | * handled by the "option" module and an ethernet data port handled by this | 33 | * handled by the "option" module and an ethernet data port handled by this |
34 | * module. | 34 | * module. |
35 | * | 35 | * |
36 | * The stick must first be switched into modem mode by usb_modeswitch | 36 | * The stick must first be switched into modem mode by usb_modeswitch |
37 | * or similar tool. Then the modem gets sent two initialization packets by | 37 | * or similar tool. Then the modem gets sent two initialization packets by |
38 | * this module, which gives the MAC address of the device. User space can then | 38 | * this module, which gives the MAC address of the device. User space can then |
39 | * connect the modem using AT commands through the ACM port and then use | 39 | * connect the modem using AT commands through the ACM port and then use |
40 | * DHCP on the network interface exposed by this module. Network packets are | 40 | * DHCP on the network interface exposed by this module. Network packets are |
41 | * sent to and from the modem in a proprietary format discovered after watching | 41 | * sent to and from the modem in a proprietary format discovered after watching |
42 | * the behavior of the windows driver for the modem. | 42 | * the behavior of the windows driver for the modem. |
43 | * | 43 | * |
44 | * More information about the use of the modem is available in usb_modeswitch | 44 | * More information about the use of the modem is available in usb_modeswitch |
45 | * forum and the project page: | 45 | * forum and the project page: |
46 | * | 46 | * |
47 | * http://www.draisberghof.de/usb_modeswitch/bb/viewtopic.php?t=465 | 47 | * http://www.draisberghof.de/usb_modeswitch/bb/viewtopic.php?t=465 |
48 | * https://github.com/mkotsbak/Samsung-GT-B3730-linux-driver | 48 | * https://github.com/mkotsbak/Samsung-GT-B3730-linux-driver |
49 | */ | 49 | */ |
50 | 50 | ||
51 | /* #define DEBUG */ | 51 | /* #define DEBUG */ |
52 | /* #define VERBOSE */ | 52 | /* #define VERBOSE */ |
53 | 53 | ||
54 | #define KALMIA_HEADER_LENGTH 6 | 54 | #define KALMIA_HEADER_LENGTH 6 |
55 | #define KALMIA_ALIGN_SIZE 4 | 55 | #define KALMIA_ALIGN_SIZE 4 |
56 | #define KALMIA_USB_TIMEOUT 10000 | 56 | #define KALMIA_USB_TIMEOUT 10000 |
57 | 57 | ||
58 | /*-------------------------------------------------------------------------*/ | 58 | /*-------------------------------------------------------------------------*/ |
59 | 59 | ||
60 | static int | 60 | static int |
61 | kalmia_send_init_packet(struct usbnet *dev, u8 *init_msg, u8 init_msg_len, | 61 | kalmia_send_init_packet(struct usbnet *dev, u8 *init_msg, u8 init_msg_len, |
62 | u8 *buffer, u8 expected_len) | 62 | u8 *buffer, u8 expected_len) |
63 | { | 63 | { |
64 | int act_len; | 64 | int act_len; |
65 | int status; | 65 | int status; |
66 | 66 | ||
67 | netdev_dbg(dev->net, "Sending init packet"); | 67 | netdev_dbg(dev->net, "Sending init packet"); |
68 | 68 | ||
69 | status = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 0x02), | 69 | status = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 0x02), |
70 | init_msg, init_msg_len, &act_len, KALMIA_USB_TIMEOUT); | 70 | init_msg, init_msg_len, &act_len, KALMIA_USB_TIMEOUT); |
71 | if (status != 0) { | 71 | if (status != 0) { |
72 | netdev_err(dev->net, | 72 | netdev_err(dev->net, |
73 | "Error sending init packet. Status %i, length %i\n", | 73 | "Error sending init packet. Status %i, length %i\n", |
74 | status, act_len); | 74 | status, act_len); |
75 | return status; | 75 | return status; |
76 | } | 76 | } |
77 | else if (act_len != init_msg_len) { | 77 | else if (act_len != init_msg_len) { |
78 | netdev_err(dev->net, | 78 | netdev_err(dev->net, |
79 | "Did not send all of init packet. Bytes sent: %i", | 79 | "Did not send all of init packet. Bytes sent: %i", |
80 | act_len); | 80 | act_len); |
81 | } | 81 | } |
82 | else { | 82 | else { |
83 | netdev_dbg(dev->net, "Successfully sent init packet."); | 83 | netdev_dbg(dev->net, "Successfully sent init packet."); |
84 | } | 84 | } |
85 | 85 | ||
86 | status = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, 0x81), | 86 | status = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, 0x81), |
87 | buffer, expected_len, &act_len, KALMIA_USB_TIMEOUT); | 87 | buffer, expected_len, &act_len, KALMIA_USB_TIMEOUT); |
88 | 88 | ||
89 | if (status != 0) | 89 | if (status != 0) |
90 | netdev_err(dev->net, | 90 | netdev_err(dev->net, |
91 | "Error receiving init result. Status %i, length %i\n", | 91 | "Error receiving init result. Status %i, length %i\n", |
92 | status, act_len); | 92 | status, act_len); |
93 | else if (act_len != expected_len) | 93 | else if (act_len != expected_len) |
94 | netdev_err(dev->net, "Unexpected init result length: %i\n", | 94 | netdev_err(dev->net, "Unexpected init result length: %i\n", |
95 | act_len); | 95 | act_len); |
96 | 96 | ||
97 | return status; | 97 | return status; |
98 | } | 98 | } |
99 | 99 | ||
100 | static int | 100 | static int |
101 | kalmia_init_and_get_ethernet_addr(struct usbnet *dev, u8 *ethernet_addr) | 101 | kalmia_init_and_get_ethernet_addr(struct usbnet *dev, u8 *ethernet_addr) |
102 | { | 102 | { |
103 | const static char init_msg_1[] = | 103 | static const char init_msg_1[] = |
104 | { 0x57, 0x50, 0x04, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, | 104 | { 0x57, 0x50, 0x04, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, |
105 | 0x00, 0x00 }; | 105 | 0x00, 0x00 }; |
106 | const static char init_msg_2[] = | 106 | static const char init_msg_2[] = |
107 | { 0x57, 0x50, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xf4, | 107 | { 0x57, 0x50, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xf4, |
108 | 0x00, 0x00 }; | 108 | 0x00, 0x00 }; |
109 | const static int buflen = 28; | 109 | static const int buflen = 28; |
110 | char *usb_buf; | 110 | char *usb_buf; |
111 | int status; | 111 | int status; |
112 | 112 | ||
113 | usb_buf = kmalloc(buflen, GFP_DMA | GFP_KERNEL); | 113 | usb_buf = kmalloc(buflen, GFP_DMA | GFP_KERNEL); |
114 | if (!usb_buf) | 114 | if (!usb_buf) |
115 | return -ENOMEM; | 115 | return -ENOMEM; |
116 | 116 | ||
117 | memcpy(usb_buf, init_msg_1, 12); | 117 | memcpy(usb_buf, init_msg_1, 12); |
118 | status = kalmia_send_init_packet(dev, usb_buf, sizeof(init_msg_1) | 118 | status = kalmia_send_init_packet(dev, usb_buf, sizeof(init_msg_1) |
119 | / sizeof(init_msg_1[0]), usb_buf, 24); | 119 | / sizeof(init_msg_1[0]), usb_buf, 24); |
120 | if (status != 0) | 120 | if (status != 0) |
121 | return status; | 121 | return status; |
122 | 122 | ||
123 | memcpy(usb_buf, init_msg_2, 12); | 123 | memcpy(usb_buf, init_msg_2, 12); |
124 | status = kalmia_send_init_packet(dev, usb_buf, sizeof(init_msg_2) | 124 | status = kalmia_send_init_packet(dev, usb_buf, sizeof(init_msg_2) |
125 | / sizeof(init_msg_2[0]), usb_buf, 28); | 125 | / sizeof(init_msg_2[0]), usb_buf, 28); |
126 | if (status != 0) | 126 | if (status != 0) |
127 | return status; | 127 | return status; |
128 | 128 | ||
129 | memcpy(ethernet_addr, usb_buf + 10, ETH_ALEN); | 129 | memcpy(ethernet_addr, usb_buf + 10, ETH_ALEN); |
130 | 130 | ||
131 | kfree(usb_buf); | 131 | kfree(usb_buf); |
132 | return status; | 132 | return status; |
133 | } | 133 | } |
134 | 134 | ||
135 | static int | 135 | static int |
136 | kalmia_bind(struct usbnet *dev, struct usb_interface *intf) | 136 | kalmia_bind(struct usbnet *dev, struct usb_interface *intf) |
137 | { | 137 | { |
138 | int status; | 138 | int status; |
139 | u8 ethernet_addr[ETH_ALEN]; | 139 | u8 ethernet_addr[ETH_ALEN]; |
140 | 140 | ||
141 | /* Don't bind to AT command interface */ | 141 | /* Don't bind to AT command interface */ |
142 | if (intf->cur_altsetting->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC) | 142 | if (intf->cur_altsetting->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC) |
143 | return -EINVAL; | 143 | return -EINVAL; |
144 | 144 | ||
145 | dev->in = usb_rcvbulkpipe(dev->udev, 0x81 & USB_ENDPOINT_NUMBER_MASK); | 145 | dev->in = usb_rcvbulkpipe(dev->udev, 0x81 & USB_ENDPOINT_NUMBER_MASK); |
146 | dev->out = usb_sndbulkpipe(dev->udev, 0x02 & USB_ENDPOINT_NUMBER_MASK); | 146 | dev->out = usb_sndbulkpipe(dev->udev, 0x02 & USB_ENDPOINT_NUMBER_MASK); |
147 | dev->status = NULL; | 147 | dev->status = NULL; |
148 | 148 | ||
149 | dev->net->hard_header_len += KALMIA_HEADER_LENGTH; | 149 | dev->net->hard_header_len += KALMIA_HEADER_LENGTH; |
150 | dev->hard_mtu = 1400; | 150 | dev->hard_mtu = 1400; |
151 | dev->rx_urb_size = dev->hard_mtu * 10; // Found as optimal after testing | 151 | dev->rx_urb_size = dev->hard_mtu * 10; // Found as optimal after testing |
152 | 152 | ||
153 | status = kalmia_init_and_get_ethernet_addr(dev, ethernet_addr); | 153 | status = kalmia_init_and_get_ethernet_addr(dev, ethernet_addr); |
154 | 154 | ||
155 | if (status < 0) { | 155 | if (status < 0) { |
156 | usb_set_intfdata(intf, NULL); | 156 | usb_set_intfdata(intf, NULL); |
157 | usb_driver_release_interface(driver_of(intf), intf); | 157 | usb_driver_release_interface(driver_of(intf), intf); |
158 | return status; | 158 | return status; |
159 | } | 159 | } |
160 | 160 | ||
161 | memcpy(dev->net->dev_addr, ethernet_addr, ETH_ALEN); | 161 | memcpy(dev->net->dev_addr, ethernet_addr, ETH_ALEN); |
162 | memcpy(dev->net->perm_addr, ethernet_addr, ETH_ALEN); | 162 | memcpy(dev->net->perm_addr, ethernet_addr, ETH_ALEN); |
163 | 163 | ||
164 | return status; | 164 | return status; |
165 | } | 165 | } |
166 | 166 | ||
167 | static struct sk_buff * | 167 | static struct sk_buff * |
168 | kalmia_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) | 168 | kalmia_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) |
169 | { | 169 | { |
170 | struct sk_buff *skb2 = NULL; | 170 | struct sk_buff *skb2 = NULL; |
171 | u16 content_len; | 171 | u16 content_len; |
172 | unsigned char *header_start; | 172 | unsigned char *header_start; |
173 | unsigned char ether_type_1, ether_type_2; | 173 | unsigned char ether_type_1, ether_type_2; |
174 | u8 remainder, padlen = 0; | 174 | u8 remainder, padlen = 0; |
175 | 175 | ||
176 | if (!skb_cloned(skb)) { | 176 | if (!skb_cloned(skb)) { |
177 | int headroom = skb_headroom(skb); | 177 | int headroom = skb_headroom(skb); |
178 | int tailroom = skb_tailroom(skb); | 178 | int tailroom = skb_tailroom(skb); |
179 | 179 | ||
180 | if ((tailroom >= KALMIA_ALIGN_SIZE) && (headroom | 180 | if ((tailroom >= KALMIA_ALIGN_SIZE) && (headroom |
181 | >= KALMIA_HEADER_LENGTH)) | 181 | >= KALMIA_HEADER_LENGTH)) |
182 | goto done; | 182 | goto done; |
183 | 183 | ||
184 | if ((headroom + tailroom) > (KALMIA_HEADER_LENGTH | 184 | if ((headroom + tailroom) > (KALMIA_HEADER_LENGTH |
185 | + KALMIA_ALIGN_SIZE)) { | 185 | + KALMIA_ALIGN_SIZE)) { |
186 | skb->data = memmove(skb->head + KALMIA_HEADER_LENGTH, | 186 | skb->data = memmove(skb->head + KALMIA_HEADER_LENGTH, |
187 | skb->data, skb->len); | 187 | skb->data, skb->len); |
188 | skb_set_tail_pointer(skb, skb->len); | 188 | skb_set_tail_pointer(skb, skb->len); |
189 | goto done; | 189 | goto done; |
190 | } | 190 | } |
191 | } | 191 | } |
192 | 192 | ||
193 | skb2 = skb_copy_expand(skb, KALMIA_HEADER_LENGTH, | 193 | skb2 = skb_copy_expand(skb, KALMIA_HEADER_LENGTH, |
194 | KALMIA_ALIGN_SIZE, flags); | 194 | KALMIA_ALIGN_SIZE, flags); |
195 | if (!skb2) | 195 | if (!skb2) |
196 | return NULL; | 196 | return NULL; |
197 | 197 | ||
198 | dev_kfree_skb_any(skb); | 198 | dev_kfree_skb_any(skb); |
199 | skb = skb2; | 199 | skb = skb2; |
200 | 200 | ||
201 | done: | 201 | done: |
202 | header_start = skb_push(skb, KALMIA_HEADER_LENGTH); | 202 | header_start = skb_push(skb, KALMIA_HEADER_LENGTH); |
203 | ether_type_1 = header_start[KALMIA_HEADER_LENGTH + 12]; | 203 | ether_type_1 = header_start[KALMIA_HEADER_LENGTH + 12]; |
204 | ether_type_2 = header_start[KALMIA_HEADER_LENGTH + 13]; | 204 | ether_type_2 = header_start[KALMIA_HEADER_LENGTH + 13]; |
205 | 205 | ||
206 | netdev_dbg(dev->net, "Sending etherType: %02x%02x", ether_type_1, | 206 | netdev_dbg(dev->net, "Sending etherType: %02x%02x", ether_type_1, |
207 | ether_type_2); | 207 | ether_type_2); |
208 | 208 | ||
209 | /* According to empiric data for data packages */ | 209 | /* According to empiric data for data packages */ |
210 | header_start[0] = 0x57; | 210 | header_start[0] = 0x57; |
211 | header_start[1] = 0x44; | 211 | header_start[1] = 0x44; |
212 | content_len = skb->len - KALMIA_HEADER_LENGTH; | 212 | content_len = skb->len - KALMIA_HEADER_LENGTH; |
213 | 213 | ||
214 | put_unaligned_le16(content_len, &header_start[2]); | 214 | put_unaligned_le16(content_len, &header_start[2]); |
215 | header_start[4] = ether_type_1; | 215 | header_start[4] = ether_type_1; |
216 | header_start[5] = ether_type_2; | 216 | header_start[5] = ether_type_2; |
217 | 217 | ||
218 | /* Align to 4 bytes by padding with zeros */ | 218 | /* Align to 4 bytes by padding with zeros */ |
219 | remainder = skb->len % KALMIA_ALIGN_SIZE; | 219 | remainder = skb->len % KALMIA_ALIGN_SIZE; |
220 | if (remainder > 0) { | 220 | if (remainder > 0) { |
221 | padlen = KALMIA_ALIGN_SIZE - remainder; | 221 | padlen = KALMIA_ALIGN_SIZE - remainder; |
222 | memset(skb_put(skb, padlen), 0, padlen); | 222 | memset(skb_put(skb, padlen), 0, padlen); |
223 | } | 223 | } |
224 | 224 | ||
225 | netdev_dbg( | 225 | netdev_dbg( |
226 | dev->net, | 226 | dev->net, |
227 | "Sending package with length %i and padding %i. Header: %02x:%02x:%02x:%02x:%02x:%02x.", | 227 | "Sending package with length %i and padding %i. Header: %02x:%02x:%02x:%02x:%02x:%02x.", |
228 | content_len, padlen, header_start[0], header_start[1], | 228 | content_len, padlen, header_start[0], header_start[1], |
229 | header_start[2], header_start[3], header_start[4], | 229 | header_start[2], header_start[3], header_start[4], |
230 | header_start[5]); | 230 | header_start[5]); |
231 | 231 | ||
232 | return skb; | 232 | return skb; |
233 | } | 233 | } |
234 | 234 | ||
235 | static int | 235 | static int |
236 | kalmia_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | 236 | kalmia_rx_fixup(struct usbnet *dev, struct sk_buff *skb) |
237 | { | 237 | { |
238 | /* | 238 | /* |
239 | * Our task here is to strip off framing, leaving skb with one | 239 | * Our task here is to strip off framing, leaving skb with one |
240 | * data frame for the usbnet framework code to process. | 240 | * data frame for the usbnet framework code to process. |
241 | */ | 241 | */ |
242 | const static u8 HEADER_END_OF_USB_PACKET[] = | 242 | static const u8 HEADER_END_OF_USB_PACKET[] = |
243 | { 0x57, 0x5a, 0x00, 0x00, 0x08, 0x00 }; | 243 | { 0x57, 0x5a, 0x00, 0x00, 0x08, 0x00 }; |
244 | const static u8 EXPECTED_UNKNOWN_HEADER_1[] = | 244 | static const u8 EXPECTED_UNKNOWN_HEADER_1[] = |
245 | { 0x57, 0x43, 0x1e, 0x00, 0x15, 0x02 }; | 245 | { 0x57, 0x43, 0x1e, 0x00, 0x15, 0x02 }; |
246 | const static u8 EXPECTED_UNKNOWN_HEADER_2[] = | 246 | static const u8 EXPECTED_UNKNOWN_HEADER_2[] = |
247 | { 0x57, 0x50, 0x0e, 0x00, 0x00, 0x00 }; | 247 | { 0x57, 0x50, 0x0e, 0x00, 0x00, 0x00 }; |
248 | int i = 0; | 248 | int i = 0; |
249 | 249 | ||
250 | /* incomplete header? */ | 250 | /* incomplete header? */ |
251 | if (skb->len < KALMIA_HEADER_LENGTH) | 251 | if (skb->len < KALMIA_HEADER_LENGTH) |
252 | return 0; | 252 | return 0; |
253 | 253 | ||
254 | do { | 254 | do { |
255 | struct sk_buff *skb2 = NULL; | 255 | struct sk_buff *skb2 = NULL; |
256 | u8 *header_start; | 256 | u8 *header_start; |
257 | u16 usb_packet_length, ether_packet_length; | 257 | u16 usb_packet_length, ether_packet_length; |
258 | int is_last; | 258 | int is_last; |
259 | 259 | ||
260 | header_start = skb->data; | 260 | header_start = skb->data; |
261 | 261 | ||
262 | if (unlikely(header_start[0] != 0x57 || header_start[1] != 0x44)) { | 262 | if (unlikely(header_start[0] != 0x57 || header_start[1] != 0x44)) { |
263 | if (!memcmp(header_start, EXPECTED_UNKNOWN_HEADER_1, | 263 | if (!memcmp(header_start, EXPECTED_UNKNOWN_HEADER_1, |
264 | sizeof(EXPECTED_UNKNOWN_HEADER_1)) || !memcmp( | 264 | sizeof(EXPECTED_UNKNOWN_HEADER_1)) || !memcmp( |
265 | header_start, EXPECTED_UNKNOWN_HEADER_2, | 265 | header_start, EXPECTED_UNKNOWN_HEADER_2, |
266 | sizeof(EXPECTED_UNKNOWN_HEADER_2))) { | 266 | sizeof(EXPECTED_UNKNOWN_HEADER_2))) { |
267 | netdev_dbg( | 267 | netdev_dbg( |
268 | dev->net, | 268 | dev->net, |
269 | "Received expected unknown frame header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n", | 269 | "Received expected unknown frame header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n", |
270 | header_start[0], header_start[1], | 270 | header_start[0], header_start[1], |
271 | header_start[2], header_start[3], | 271 | header_start[2], header_start[3], |
272 | header_start[4], header_start[5], | 272 | header_start[4], header_start[5], |
273 | skb->len - KALMIA_HEADER_LENGTH); | 273 | skb->len - KALMIA_HEADER_LENGTH); |
274 | } | 274 | } |
275 | else { | 275 | else { |
276 | netdev_err( | 276 | netdev_err( |
277 | dev->net, | 277 | dev->net, |
278 | "Received unknown frame header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n", | 278 | "Received unknown frame header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n", |
279 | header_start[0], header_start[1], | 279 | header_start[0], header_start[1], |
280 | header_start[2], header_start[3], | 280 | header_start[2], header_start[3], |
281 | header_start[4], header_start[5], | 281 | header_start[4], header_start[5], |
282 | skb->len - KALMIA_HEADER_LENGTH); | 282 | skb->len - KALMIA_HEADER_LENGTH); |
283 | return 0; | 283 | return 0; |
284 | } | 284 | } |
285 | } | 285 | } |
286 | else | 286 | else |
287 | netdev_dbg( | 287 | netdev_dbg( |
288 | dev->net, | 288 | dev->net, |
289 | "Received header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n", | 289 | "Received header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n", |
290 | header_start[0], header_start[1], header_start[2], | 290 | header_start[0], header_start[1], header_start[2], |
291 | header_start[3], header_start[4], header_start[5], | 291 | header_start[3], header_start[4], header_start[5], |
292 | skb->len - KALMIA_HEADER_LENGTH); | 292 | skb->len - KALMIA_HEADER_LENGTH); |
293 | 293 | ||
294 | /* subtract start header and end header */ | 294 | /* subtract start header and end header */ |
295 | usb_packet_length = skb->len - (2 * KALMIA_HEADER_LENGTH); | 295 | usb_packet_length = skb->len - (2 * KALMIA_HEADER_LENGTH); |
296 | ether_packet_length = get_unaligned_le16(&header_start[2]); | 296 | ether_packet_length = get_unaligned_le16(&header_start[2]); |
297 | skb_pull(skb, KALMIA_HEADER_LENGTH); | 297 | skb_pull(skb, KALMIA_HEADER_LENGTH); |
298 | 298 | ||
299 | /* Some small packets misses end marker */ | 299 | /* Some small packets misses end marker */ |
300 | if (usb_packet_length < ether_packet_length) { | 300 | if (usb_packet_length < ether_packet_length) { |
301 | ether_packet_length = usb_packet_length | 301 | ether_packet_length = usb_packet_length |
302 | + KALMIA_HEADER_LENGTH; | 302 | + KALMIA_HEADER_LENGTH; |
303 | is_last = true; | 303 | is_last = true; |
304 | } | 304 | } |
305 | else { | 305 | else { |
306 | netdev_dbg(dev->net, "Correct package length #%i", i | 306 | netdev_dbg(dev->net, "Correct package length #%i", i |
307 | + 1); | 307 | + 1); |
308 | 308 | ||
309 | is_last = (memcmp(skb->data + ether_packet_length, | 309 | is_last = (memcmp(skb->data + ether_packet_length, |
310 | HEADER_END_OF_USB_PACKET, | 310 | HEADER_END_OF_USB_PACKET, |
311 | sizeof(HEADER_END_OF_USB_PACKET)) == 0); | 311 | sizeof(HEADER_END_OF_USB_PACKET)) == 0); |
312 | if (!is_last) { | 312 | if (!is_last) { |
313 | header_start = skb->data + ether_packet_length; | 313 | header_start = skb->data + ether_packet_length; |
314 | netdev_dbg( | 314 | netdev_dbg( |
315 | dev->net, | 315 | dev->net, |
316 | "End header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n", | 316 | "End header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n", |
317 | header_start[0], header_start[1], | 317 | header_start[0], header_start[1], |
318 | header_start[2], header_start[3], | 318 | header_start[2], header_start[3], |
319 | header_start[4], header_start[5], | 319 | header_start[4], header_start[5], |
320 | skb->len - KALMIA_HEADER_LENGTH); | 320 | skb->len - KALMIA_HEADER_LENGTH); |
321 | } | 321 | } |
322 | } | 322 | } |
323 | 323 | ||
324 | if (is_last) { | 324 | if (is_last) { |
325 | skb2 = skb; | 325 | skb2 = skb; |
326 | } | 326 | } |
327 | else { | 327 | else { |
328 | skb2 = skb_clone(skb, GFP_ATOMIC); | 328 | skb2 = skb_clone(skb, GFP_ATOMIC); |
329 | if (unlikely(!skb2)) | 329 | if (unlikely(!skb2)) |
330 | return 0; | 330 | return 0; |
331 | } | 331 | } |
332 | 332 | ||
333 | skb_trim(skb2, ether_packet_length); | 333 | skb_trim(skb2, ether_packet_length); |
334 | 334 | ||
335 | if (is_last) { | 335 | if (is_last) { |
336 | return 1; | 336 | return 1; |
337 | } | 337 | } |
338 | else { | 338 | else { |
339 | usbnet_skb_return(dev, skb2); | 339 | usbnet_skb_return(dev, skb2); |
340 | skb_pull(skb, ether_packet_length); | 340 | skb_pull(skb, ether_packet_length); |
341 | } | 341 | } |
342 | 342 | ||
343 | i++; | 343 | i++; |
344 | } | 344 | } |
345 | while (skb->len); | 345 | while (skb->len); |
346 | 346 | ||
347 | return 1; | 347 | return 1; |
348 | } | 348 | } |
349 | 349 | ||
350 | static const struct driver_info kalmia_info = { | 350 | static const struct driver_info kalmia_info = { |
351 | .description = "Samsung Kalmia LTE USB dongle", | 351 | .description = "Samsung Kalmia LTE USB dongle", |
352 | .flags = FLAG_WWAN, | 352 | .flags = FLAG_WWAN, |
353 | .bind = kalmia_bind, | 353 | .bind = kalmia_bind, |
354 | .rx_fixup = kalmia_rx_fixup, | 354 | .rx_fixup = kalmia_rx_fixup, |
355 | .tx_fixup = kalmia_tx_fixup | 355 | .tx_fixup = kalmia_tx_fixup |
356 | }; | 356 | }; |
357 | 357 | ||
358 | /*-------------------------------------------------------------------------*/ | 358 | /*-------------------------------------------------------------------------*/ |
359 | 359 | ||
360 | static const struct usb_device_id products[] = { | 360 | static const struct usb_device_id products[] = { |
361 | /* The unswitched USB ID, to get the module auto loaded: */ | 361 | /* The unswitched USB ID, to get the module auto loaded: */ |
362 | { USB_DEVICE(0x04e8, 0x689a) }, | 362 | { USB_DEVICE(0x04e8, 0x689a) }, |
363 | /* The stick swithed into modem (by e.g. usb_modeswitch): */ | 363 | /* The stick swithed into modem (by e.g. usb_modeswitch): */ |
364 | { USB_DEVICE(0x04e8, 0x6889), | 364 | { USB_DEVICE(0x04e8, 0x6889), |
365 | .driver_info = (unsigned long) &kalmia_info, }, | 365 | .driver_info = (unsigned long) &kalmia_info, }, |
366 | { /* EMPTY == end of list */} }; | 366 | { /* EMPTY == end of list */} }; |
367 | MODULE_DEVICE_TABLE( usb, products); | 367 | MODULE_DEVICE_TABLE( usb, products); |
368 | 368 | ||
369 | static struct usb_driver kalmia_driver = { | 369 | static struct usb_driver kalmia_driver = { |
370 | .name = "kalmia", | 370 | .name = "kalmia", |
371 | .id_table = products, | 371 | .id_table = products, |
372 | .probe = usbnet_probe, | 372 | .probe = usbnet_probe, |
373 | .disconnect = usbnet_disconnect, | 373 | .disconnect = usbnet_disconnect, |
374 | .suspend = usbnet_suspend, | 374 | .suspend = usbnet_suspend, |
375 | .resume = usbnet_resume | 375 | .resume = usbnet_resume |
376 | }; | 376 | }; |
377 | 377 | ||
378 | static int __init kalmia_init(void) | 378 | static int __init kalmia_init(void) |
379 | { | 379 | { |
380 | return usb_register(&kalmia_driver); | 380 | return usb_register(&kalmia_driver); |
381 | } | 381 | } |
382 | module_init( kalmia_init); | 382 | module_init( kalmia_init); |
383 | 383 | ||
384 | static void __exit kalmia_exit(void) | 384 | static void __exit kalmia_exit(void) |
385 | { | 385 | { |
386 | usb_deregister(&kalmia_driver); | 386 | usb_deregister(&kalmia_driver); |
387 | } | 387 | } |
388 | module_exit( kalmia_exit); | 388 | module_exit( kalmia_exit); |
389 | 389 | ||
390 | MODULE_AUTHOR("Marius Bjoernstad Kotsbak <marius@kotsbak.com>"); | 390 | MODULE_AUTHOR("Marius Bjoernstad Kotsbak <marius@kotsbak.com>"); |
391 | MODULE_DESCRIPTION("Samsung Kalmia USB network driver"); | 391 | MODULE_DESCRIPTION("Samsung Kalmia USB network driver"); |
392 | MODULE_LICENSE("GPL"); | 392 | MODULE_LICENSE("GPL"); |
393 | 393 |