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
9 #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
11 #include <linux/module.h>
12 #include <linux/netdevice.h>
13 #include <linux/slab.h>
14 #include <linux/mii.h>
15 #include <linux/usb.h>
16 #include <linux/usb/usbnet.h>
17 #include <net/netns/generic.h>
18 #include <net/caif/caif_dev.h>
19 #include <net/caif/caif_layer.h>
20 #include <net/caif/cfpkt.h>
21 #include <net/caif/cfcnfg.h>
23 MODULE_LICENSE("GPL");
25 #define CFUSB_PAD_DESCR_SZ 1 /* Alignment descriptor length */
26 #define CFUSB_ALIGNMENT 4 /* Number of bytes to align. */
27 #define CFUSB_MAX_HEADLEN (CFUSB_PAD_DESCR_SZ + CFUSB_ALIGNMENT-1)
28 #define STE_USB_VID 0x04cc /* USB Product ID for ST-Ericsson */
29 #define STE_USB_PID_CAIF 0x230f /* Product id for CAIF Modems */
33 u8 tx_eth_hdr
[ETH_HLEN
];
36 static bool pack_added
;
38 static int cfusbl_receive(struct cflayer
*layr
, struct cfpkt
*pkt
)
43 cfpkt_extr_head(pkt
, &hpad
, 1);
44 cfpkt_extr_head(pkt
, NULL
, hpad
);
45 return layr
->up
->receive(layr
->up
, pkt
);
48 static int cfusbl_transmit(struct cflayer
*layr
, struct cfpkt
*pkt
)
50 struct caif_payload_info
*info
;
52 u8 zeros
[CFUSB_ALIGNMENT
];
54 struct cfusbl
*usbl
= container_of(layr
, struct cfusbl
, layer
);
56 skb
= cfpkt_tonative(pkt
);
58 skb_reset_network_header(skb
);
59 skb
->protocol
= htons(ETH_P_IP
);
61 info
= cfpkt_info(pkt
);
62 hpad
= (info
->hdr_len
+ CFUSB_PAD_DESCR_SZ
) & (CFUSB_ALIGNMENT
- 1);
64 if (skb_headroom(skb
) < ETH_HLEN
+ CFUSB_PAD_DESCR_SZ
+ hpad
) {
65 pr_warn("Headroom to small\n");
69 memset(zeros
, 0, hpad
);
71 cfpkt_add_head(pkt
, zeros
, hpad
);
72 cfpkt_add_head(pkt
, &hpad
, 1);
73 cfpkt_add_head(pkt
, usbl
->tx_eth_hdr
, sizeof(usbl
->tx_eth_hdr
));
74 return layr
->dn
->transmit(layr
->dn
, pkt
);
77 static void cfusbl_ctrlcmd(struct cflayer
*layr
, enum caif_ctrlcmd ctrl
,
80 if (layr
->up
&& layr
->up
->ctrlcmd
)
81 layr
->up
->ctrlcmd(layr
->up
, ctrl
, layr
->id
);
84 struct cflayer
*cfusbl_create(int phyid
, u8 ethaddr
[ETH_ALEN
],
87 struct cfusbl
*this = kmalloc(sizeof(struct cfusbl
), GFP_ATOMIC
);
90 pr_warn("Out of memory\n");
93 caif_assert(offsetof(struct cfusbl
, layer
) == 0);
95 memset(this, 0, sizeof(struct cflayer
));
96 this->layer
.receive
= cfusbl_receive
;
97 this->layer
.transmit
= cfusbl_transmit
;
98 this->layer
.ctrlcmd
= cfusbl_ctrlcmd
;
99 snprintf(this->layer
.name
, CAIF_LAYER_NAME_SZ
, "usb%d", phyid
);
100 this->layer
.id
= phyid
;
103 * Construct TX ethernet header:
104 * 0-5 destination address
105 * 5-11 source address
106 * 12-13 protocol type
108 memcpy(&this->tx_eth_hdr
[ETH_ALEN
], braddr
, ETH_ALEN
);
109 memcpy(&this->tx_eth_hdr
[ETH_ALEN
], ethaddr
, ETH_ALEN
);
110 this->tx_eth_hdr
[12] = cpu_to_be16(ETH_P_802_EX1
) & 0xff;
111 this->tx_eth_hdr
[13] = (cpu_to_be16(ETH_P_802_EX1
) >> 8) & 0xff;
112 pr_debug("caif ethernet TX-header dst:%pM src:%pM type:%02x%02x\n",
113 this->tx_eth_hdr
, this->tx_eth_hdr
+ ETH_ALEN
,
114 this->tx_eth_hdr
[12], this->tx_eth_hdr
[13]);
116 return (struct cflayer
*) this;
119 static struct packet_type caif_usb_type __read_mostly
= {
120 .type
= cpu_to_be16(ETH_P_802_EX1
),
123 static int cfusbl_device_notify(struct notifier_block
*me
, unsigned long what
,
126 struct net_device
*dev
= arg
;
127 struct caif_dev_common common
;
128 struct cflayer
*layer
, *link_support
;
129 struct usbnet
*usbnet
= netdev_priv(dev
);
130 struct usb_device
*usbdev
= usbnet
->udev
;
131 struct ethtool_drvinfo drvinfo
;
134 * Quirks: High-jack ethtool to find if we have a NCM device,
135 * and find it's VID/PID.
137 if (dev
->ethtool_ops
== NULL
|| dev
->ethtool_ops
->get_drvinfo
== NULL
)
140 dev
->ethtool_ops
->get_drvinfo(dev
, &drvinfo
);
141 if (strncmp(drvinfo
.driver
, "cdc_ncm", 7) != 0)
144 pr_debug("USB CDC NCM device VID:0x%4x PID:0x%4x\n",
145 le16_to_cpu(usbdev
->descriptor
.idVendor
),
146 le16_to_cpu(usbdev
->descriptor
.idProduct
));
148 /* Check for VID/PID that supports CAIF */
149 if (!(le16_to_cpu(usbdev
->descriptor
.idVendor
) == STE_USB_VID
&&
150 le16_to_cpu(usbdev
->descriptor
.idProduct
) == STE_USB_PID_CAIF
))
153 if (what
== NETDEV_UNREGISTER
)
154 module_put(THIS_MODULE
);
156 if (what
!= NETDEV_REGISTER
)
159 __module_get(THIS_MODULE
);
161 memset(&common
, 0, sizeof(common
));
162 common
.use_frag
= false;
163 common
.use_fcs
= false;
164 common
.use_stx
= false;
165 common
.link_select
= CAIF_LINK_HIGH_BANDW
;
166 common
.flowctrl
= NULL
;
168 link_support
= cfusbl_create(dev
->ifindex
, dev
->dev_addr
,
174 if (dev
->num_tx_queues
> 1)
175 pr_warn("USB device uses more than one tx queue\n");
177 caif_enroll_dev(dev
, &common
, link_support
, CFUSB_MAX_HEADLEN
,
178 &layer
, &caif_usb_type
.func
);
180 dev_add_pack(&caif_usb_type
);
183 strncpy(layer
->name
, dev
->name
,
184 sizeof(layer
->name
) - 1);
185 layer
->name
[sizeof(layer
->name
) - 1] = 0;
190 static struct notifier_block caif_device_notifier
= {
191 .notifier_call
= cfusbl_device_notify
,
195 static int __init
cfusbl_init(void)
197 return register_netdevice_notifier(&caif_device_notifier
);
200 static void __exit
cfusbl_exit(void)
202 unregister_netdevice_notifier(&caif_device_notifier
);
203 dev_remove_pack(&caif_usb_type
);
206 module_init(cfusbl_init
);
207 module_exit(cfusbl_exit
);