aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsjur.brandeland@stericsson.com <sjur.brandeland@stericsson.com>2011-12-04 06:22:53 -0500
committerDavid S. Miller <davem@davemloft.net>2011-12-05 18:27:56 -0500
commit7ad65bf68d705b445ef10b77ab50dab22be185ee (patch)
treeba354482821d658d6b9b6a4214d3dd4ba543ee23
parent63afe12f4be3b08597ae41ce7c0837bfc106b0ac (diff)
caif: Add support for CAIF over CDC NCM USB interface
NCM 1.0 does not support anything but Ethernet framing, hence CAIF payload will be put into Ethernet frames. Discovery is based on fixed USB vendor 0x04cc (ST-Ericsson), product-id 0x230f (NCM). In this variant only CAIF payload is sent over the NCM interface. The CAIF stack (cfusbl.c) will when USB interface register first check if we got a CDC NCM USB interface with the right VID, PID. It will then read the device's Ethernet address and create a 'template' Ethernet TX header, using a broadcast address as the destination address, and EthType 0x88b5 (802.1 Local Experimental - vendor specific). A protocol handler for 0x88b5 is setup for reception of CAIF frames from the CDC NCM USB interface. Signed-off-by: Sjur Brændeland <sjur.brandeland@stericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/caif/Kconfig11
-rw-r--r--net/caif/Makefile1
-rw-r--r--net/caif/caif_dev.c1
-rw-r--r--net/caif/caif_usb.c208
-rw-r--r--net/caif/cfpkt_skbuff.c12
5 files changed, 224 insertions, 9 deletions
diff --git a/net/caif/Kconfig b/net/caif/Kconfig
index 529750da9624..936361e5a2b6 100644
--- a/net/caif/Kconfig
+++ b/net/caif/Kconfig
@@ -40,3 +40,14 @@ config CAIF_NETDEV
40 If you select to build it as a built-in then the main CAIF device must 40 If you select to build it as a built-in then the main CAIF device must
41 also be a built-in. 41 also be a built-in.
42 If unsure say Y. 42 If unsure say Y.
43
44config CAIF_USB
45 tristate "CAIF USB support"
46 depends on CAIF
47 default n
48 ---help---
49 Say Y if you are using CAIF over USB CDC NCM.
50 This can be either built-in or a loadable module,
51 If you select to build it as a built-in then the main CAIF device must
52 also be a built-in.
53 If unsure say N.
diff --git a/net/caif/Makefile b/net/caif/Makefile
index ebcd4e7e6f47..cc2b51154d03 100644
--- a/net/caif/Makefile
+++ b/net/caif/Makefile
@@ -10,5 +10,6 @@ caif-y := caif_dev.o \
10obj-$(CONFIG_CAIF) += caif.o 10obj-$(CONFIG_CAIF) += caif.o
11obj-$(CONFIG_CAIF_NETDEV) += chnl_net.o 11obj-$(CONFIG_CAIF_NETDEV) += chnl_net.o
12obj-$(CONFIG_CAIF) += caif_socket.o 12obj-$(CONFIG_CAIF) += caif_socket.o
13obj-$(CONFIG_CAIF_USB) += caif_usb.o
13 14
14export-y := caif.o 15export-y := caif.o
diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c
index f7e8c70b343c..6acec1921e7f 100644
--- a/net/caif/caif_dev.c
+++ b/net/caif/caif_dev.c
@@ -262,6 +262,7 @@ void caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev,
262 if (rcv_func) 262 if (rcv_func)
263 *rcv_func = receive; 263 *rcv_func = receive;
264} 264}
265EXPORT_SYMBOL(caif_enroll_dev);
265 266
266/* notify Caif of device events */ 267/* notify Caif of device events */
267static int caif_device_notify(struct notifier_block *me, unsigned long what, 268static int caif_device_notify(struct notifier_block *me, unsigned long what,
diff --git a/net/caif/caif_usb.c b/net/caif/caif_usb.c
new file mode 100644
index 000000000000..f5db57c58081
--- /dev/null
+++ b/net/caif/caif_usb.c
@@ -0,0 +1,208 @@
1/*
2 * CAIF USB handler
3 * Copyright (C) ST-Ericsson AB 2011
4 * Author: Sjur Brendeland/sjur.brandeland@stericsson.com
5 * License terms: GNU General Public License (GPL) version 2
6 *
7 */
8
9#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
10
11#include <linux/module.h>
12#include <linux/netdevice.h>
13#include <linux/slab.h>
14#include <linux/netdevice.h>
15#include <linux/mii.h>
16#include <linux/usb.h>
17#include <linux/usb/usbnet.h>
18#include <net/netns/generic.h>
19#include <net/caif/caif_dev.h>
20#include <net/caif/caif_layer.h>
21#include <net/caif/cfpkt.h>
22#include <net/caif/cfcnfg.h>
23
24MODULE_LICENSE("GPL");
25
26#define CFUSB_PAD_DESCR_SZ 1 /* Alignment descriptor length */
27#define CFUSB_ALIGNMENT 4 /* Number of bytes to align. */
28#define CFUSB_MAX_HEADLEN (CFUSB_PAD_DESCR_SZ + CFUSB_ALIGNMENT-1)
29#define STE_USB_VID 0x04cc /* USB Product ID for ST-Ericsson */
30#define STE_USB_PID_CAIF 0x2306 /* Product id for CAIF Modems */
31
32struct cfusbl {
33 struct cflayer layer;
34 u8 tx_eth_hdr[ETH_HLEN];
35};
36
37static bool pack_added;
38
39static int cfusbl_receive(struct cflayer *layr, struct cfpkt *pkt)
40{
41 u8 hpad;
42
43 /* Remove padding. */
44 cfpkt_extr_head(pkt, &hpad, 1);
45 cfpkt_extr_head(pkt, NULL, hpad);
46 return layr->up->receive(layr->up, pkt);
47}
48
49static int cfusbl_transmit(struct cflayer *layr, struct cfpkt *pkt)
50{
51 struct caif_payload_info *info;
52 u8 hpad;
53 u8 zeros[CFUSB_ALIGNMENT];
54 struct sk_buff *skb;
55 struct cfusbl *usbl = container_of(layr, struct cfusbl, layer);
56
57 skb = cfpkt_tonative(pkt);
58
59 skb_reset_network_header(skb);
60 skb->protocol = htons(ETH_P_IP);
61
62 info = cfpkt_info(pkt);
63 hpad = (info->hdr_len + CFUSB_PAD_DESCR_SZ) & (CFUSB_ALIGNMENT - 1);
64
65 if (skb_headroom(skb) < ETH_HLEN + CFUSB_PAD_DESCR_SZ + hpad) {
66 pr_warn("Headroom to small\n");
67 kfree_skb(skb);
68 return -EIO;
69 }
70 memset(zeros, 0, hpad);
71
72 cfpkt_add_head(pkt, zeros, hpad);
73 cfpkt_add_head(pkt, &hpad, 1);
74 cfpkt_add_head(pkt, usbl->tx_eth_hdr, sizeof(usbl->tx_eth_hdr));
75 return layr->dn->transmit(layr->dn, pkt);
76}
77
78static void cfusbl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
79 int phyid)
80{
81 if (layr->up && layr->up->ctrlcmd)
82 layr->up->ctrlcmd(layr->up, ctrl, layr->id);
83}
84
85struct cflayer *cfusbl_create(int phyid, u8 ethaddr[ETH_ALEN],
86 u8 braddr[ETH_ALEN])
87{
88 struct cfusbl *this = kmalloc(sizeof(struct cfusbl), GFP_ATOMIC);
89
90 if (!this) {
91 pr_warn("Out of memory\n");
92 return NULL;
93 }
94 caif_assert(offsetof(struct cfusbl, layer) == 0);
95
96 memset(this, 0, sizeof(struct cflayer));
97 this->layer.receive = cfusbl_receive;
98 this->layer.transmit = cfusbl_transmit;
99 this->layer.ctrlcmd = cfusbl_ctrlcmd;
100 snprintf(this->layer.name, CAIF_LAYER_NAME_SZ, "usb%d", phyid);
101 this->layer.id = phyid;
102
103 /*
104 * Construct TX ethernet header:
105 * 0-5 destination address
106 * 5-11 source address
107 * 12-13 protocol type
108 */
109 memcpy(&this->tx_eth_hdr[ETH_ALEN], braddr, ETH_ALEN);
110 memcpy(&this->tx_eth_hdr[ETH_ALEN], ethaddr, ETH_ALEN);
111 this->tx_eth_hdr[12] = cpu_to_be16(ETH_P_802_EX1) & 0xff;
112 this->tx_eth_hdr[13] = (cpu_to_be16(ETH_P_802_EX1) >> 8) & 0xff;
113 pr_debug("caif ethernet TX-header dst:%pM src:%pM type:%02x%02x\n",
114 this->tx_eth_hdr, this->tx_eth_hdr + ETH_ALEN,
115 this->tx_eth_hdr[12], this->tx_eth_hdr[13]);
116
117 return (struct cflayer *) this;
118}
119
120static struct packet_type caif_usb_type __read_mostly = {
121 .type = cpu_to_be16(ETH_P_802_EX1),
122};
123
124static int cfusbl_device_notify(struct notifier_block *me, unsigned long what,
125 void *arg)
126{
127 struct net_device *dev = arg;
128 struct caif_dev_common common;
129 struct cflayer *layer, *link_support;
130 struct usbnet *usbnet = netdev_priv(dev);
131 struct usb_device *usbdev = usbnet->udev;
132 struct ethtool_drvinfo drvinfo;
133
134 /*
135 * Quirks: High-jack ethtool to find if we have a NCM device,
136 * and find it's VID/PID.
137 */
138 if (dev->ethtool_ops == NULL || dev->ethtool_ops->get_drvinfo == NULL)
139 return 0;
140
141 dev->ethtool_ops->get_drvinfo(dev, &drvinfo);
142 if (strncmp(drvinfo.driver, "cdc_ncm", 7) != 0)
143 return 0;
144
145 pr_debug("USB CDC NCM device VID:0x%4x PID:0x%4x\n",
146 le16_to_cpu(usbdev->descriptor.idVendor),
147 le16_to_cpu(usbdev->descriptor.idProduct));
148
149 /* Check for VID/PID that supports CAIF */
150 if (!(le16_to_cpu(usbdev->descriptor.idVendor) == STE_USB_VID &&
151 le16_to_cpu(usbdev->descriptor.idProduct) == STE_USB_PID_CAIF))
152 return 0;
153
154 if (what == NETDEV_UNREGISTER)
155 module_put(THIS_MODULE);
156
157 if (what != NETDEV_REGISTER)
158 return 0;
159
160 __module_get(THIS_MODULE);
161
162 memset(&common, 0, sizeof(common));
163 common.use_frag = false;
164 common.use_fcs = false;
165 common.use_stx = false;
166 common.link_select = CAIF_LINK_HIGH_BANDW;
167 common.flowctrl = NULL;
168
169 link_support = cfusbl_create(dev->ifindex, dev->dev_addr,
170 dev->broadcast);
171
172 if (!link_support)
173 return -ENOMEM;
174
175 if (dev->num_tx_queues > 1)
176 pr_warn("USB device uses more than one tx queue\n");
177
178 caif_enroll_dev(dev, &common, link_support, CFUSB_MAX_HEADLEN,
179 &layer, &caif_usb_type.func);
180 if (!pack_added)
181 dev_add_pack(&caif_usb_type);
182 pack_added = 1;
183
184 strncpy(layer->name, dev->name,
185 sizeof(layer->name) - 1);
186 layer->name[sizeof(layer->name) - 1] = 0;
187
188 return 0;
189}
190
191static struct notifier_block caif_device_notifier = {
192 .notifier_call = cfusbl_device_notify,
193 .priority = 0,
194};
195
196static int __init cfusbl_init(void)
197{
198 return register_netdevice_notifier(&caif_device_notifier);
199}
200
201static void __exit cfusbl_exit(void)
202{
203 unregister_netdevice_notifier(&caif_device_notifier);
204 dev_remove_pack(&caif_usb_type);
205}
206
207module_init(cfusbl_init);
208module_exit(cfusbl_exit);
diff --git a/net/caif/cfpkt_skbuff.c b/net/caif/cfpkt_skbuff.c
index de5390700cfe..e335ba859b97 100644
--- a/net/caif/cfpkt_skbuff.c
+++ b/net/caif/cfpkt_skbuff.c
@@ -63,7 +63,6 @@ static inline struct cfpkt *skb_to_pkt(struct sk_buff *skb)
63 return (struct cfpkt *) skb; 63 return (struct cfpkt *) skb;
64} 64}
65 65
66
67struct cfpkt *cfpkt_fromnative(enum caif_direction dir, void *nativepkt) 66struct cfpkt *cfpkt_fromnative(enum caif_direction dir, void *nativepkt)
68{ 67{
69 struct cfpkt *pkt = skb_to_pkt(nativepkt); 68 struct cfpkt *pkt = skb_to_pkt(nativepkt);
@@ -105,14 +104,12 @@ void cfpkt_destroy(struct cfpkt *pkt)
105 kfree_skb(skb); 104 kfree_skb(skb);
106} 105}
107 106
108
109inline bool cfpkt_more(struct cfpkt *pkt) 107inline bool cfpkt_more(struct cfpkt *pkt)
110{ 108{
111 struct sk_buff *skb = pkt_to_skb(pkt); 109 struct sk_buff *skb = pkt_to_skb(pkt);
112 return skb->len > 0; 110 return skb->len > 0;
113} 111}
114 112
115
116int cfpkt_peek_head(struct cfpkt *pkt, void *data, u16 len) 113int cfpkt_peek_head(struct cfpkt *pkt, void *data, u16 len)
117{ 114{
118 struct sk_buff *skb = pkt_to_skb(pkt); 115 struct sk_buff *skb = pkt_to_skb(pkt);
@@ -148,6 +145,7 @@ int cfpkt_extr_head(struct cfpkt *pkt, void *data, u16 len)
148 memcpy(data, from, len); 145 memcpy(data, from, len);
149 return 0; 146 return 0;
150} 147}
148EXPORT_SYMBOL(cfpkt_extr_head);
151 149
152int cfpkt_extr_trail(struct cfpkt *pkt, void *dta, u16 len) 150int cfpkt_extr_trail(struct cfpkt *pkt, void *dta, u16 len)
153{ 151{
@@ -171,13 +169,11 @@ int cfpkt_extr_trail(struct cfpkt *pkt, void *dta, u16 len)
171 return 0; 169 return 0;
172} 170}
173 171
174
175int cfpkt_pad_trail(struct cfpkt *pkt, u16 len) 172int cfpkt_pad_trail(struct cfpkt *pkt, u16 len)
176{ 173{
177 return cfpkt_add_body(pkt, NULL, len); 174 return cfpkt_add_body(pkt, NULL, len);
178} 175}
179 176
180
181int cfpkt_add_body(struct cfpkt *pkt, const void *data, u16 len) 177int cfpkt_add_body(struct cfpkt *pkt, const void *data, u16 len)
182{ 178{
183 struct sk_buff *skb = pkt_to_skb(pkt); 179 struct sk_buff *skb = pkt_to_skb(pkt);
@@ -256,21 +252,19 @@ int cfpkt_add_head(struct cfpkt *pkt, const void *data2, u16 len)
256 memcpy(to, data, len); 252 memcpy(to, data, len);
257 return 0; 253 return 0;
258} 254}
259 255EXPORT_SYMBOL(cfpkt_add_head);
260 256
261inline int cfpkt_add_trail(struct cfpkt *pkt, const void *data, u16 len) 257inline int cfpkt_add_trail(struct cfpkt *pkt, const void *data, u16 len)
262{ 258{
263 return cfpkt_add_body(pkt, data, len); 259 return cfpkt_add_body(pkt, data, len);
264} 260}
265 261
266
267inline u16 cfpkt_getlen(struct cfpkt *pkt) 262inline u16 cfpkt_getlen(struct cfpkt *pkt)
268{ 263{
269 struct sk_buff *skb = pkt_to_skb(pkt); 264 struct sk_buff *skb = pkt_to_skb(pkt);
270 return skb->len; 265 return skb->len;
271} 266}
272 267
273
274inline u16 cfpkt_iterate(struct cfpkt *pkt, 268inline u16 cfpkt_iterate(struct cfpkt *pkt,
275 u16 (*iter_func)(u16, void *, u16), 269 u16 (*iter_func)(u16, void *, u16),
276 u16 data) 270 u16 data)
@@ -288,7 +282,6 @@ inline u16 cfpkt_iterate(struct cfpkt *pkt,
288 return iter_func(data, pkt->skb.data, cfpkt_getlen(pkt)); 282 return iter_func(data, pkt->skb.data, cfpkt_getlen(pkt));
289} 283}
290 284
291
292int cfpkt_setlen(struct cfpkt *pkt, u16 len) 285int cfpkt_setlen(struct cfpkt *pkt, u16 len)
293{ 286{
294 struct sk_buff *skb = pkt_to_skb(pkt); 287 struct sk_buff *skb = pkt_to_skb(pkt);
@@ -400,3 +393,4 @@ struct caif_payload_info *cfpkt_info(struct cfpkt *pkt)
400{ 393{
401 return (struct caif_payload_info *)&pkt_to_skb(pkt)->cb; 394 return (struct caif_payload_info *)&pkt_to_skb(pkt)->cb;
402} 395}
396EXPORT_SYMBOL(cfpkt_info);