Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 278363
b: refs/heads/master
c: 7ad65bf
h: refs/heads/master
i:
  278361: 2c4dd8f
  278359: 8d3bfab
v: v3
  • Loading branch information
sjur.brandeland@stericsson.com authored and David S. Miller committed Dec 5, 2011
1 parent 5f7c790 commit cd67613
Show file tree
Hide file tree
Showing 6 changed files with 225 additions and 10 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 63afe12f4be3b08597ae41ce7c0837bfc106b0ac
refs/heads/master: 7ad65bf68d705b445ef10b77ab50dab22be185ee
11 changes: 11 additions & 0 deletions trunk/net/caif/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,14 @@ config CAIF_NETDEV
If you select to build it as a built-in then the main CAIF device must
also be a built-in.
If unsure say Y.

config CAIF_USB
tristate "CAIF USB support"
depends on CAIF
default n
---help---
Say Y if you are using CAIF over USB CDC NCM.
This can be either built-in or a loadable module,
If you select to build it as a built-in then the main CAIF device must
also be a built-in.
If unsure say N.
1 change: 1 addition & 0 deletions trunk/net/caif/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ caif-y := caif_dev.o \
obj-$(CONFIG_CAIF) += caif.o
obj-$(CONFIG_CAIF_NETDEV) += chnl_net.o
obj-$(CONFIG_CAIF) += caif_socket.o
obj-$(CONFIG_CAIF_USB) += caif_usb.o

export-y := caif.o
1 change: 1 addition & 0 deletions trunk/net/caif/caif_dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ void caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev,
if (rcv_func)
*rcv_func = receive;
}
EXPORT_SYMBOL(caif_enroll_dev);

/* notify Caif of device events */
static int caif_device_notify(struct notifier_block *me, unsigned long what,
Expand Down
208 changes: 208 additions & 0 deletions trunk/net/caif/caif_usb.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
/*
* CAIF USB handler
* Copyright (C) ST-Ericsson AB 2011
* Author: Sjur Brendeland/sjur.brandeland@stericsson.com
* License terms: GNU General Public License (GPL) version 2
*
*/

#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__

#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/slab.h>
#include <linux/netdevice.h>
#include <linux/mii.h>
#include <linux/usb.h>
#include <linux/usb/usbnet.h>
#include <net/netns/generic.h>
#include <net/caif/caif_dev.h>
#include <net/caif/caif_layer.h>
#include <net/caif/cfpkt.h>
#include <net/caif/cfcnfg.h>

MODULE_LICENSE("GPL");

#define CFUSB_PAD_DESCR_SZ 1 /* Alignment descriptor length */
#define CFUSB_ALIGNMENT 4 /* Number of bytes to align. */
#define CFUSB_MAX_HEADLEN (CFUSB_PAD_DESCR_SZ + CFUSB_ALIGNMENT-1)
#define STE_USB_VID 0x04cc /* USB Product ID for ST-Ericsson */
#define STE_USB_PID_CAIF 0x2306 /* Product id for CAIF Modems */

struct cfusbl {
struct cflayer layer;
u8 tx_eth_hdr[ETH_HLEN];
};

static bool pack_added;

static int cfusbl_receive(struct cflayer *layr, struct cfpkt *pkt)
{
u8 hpad;

/* Remove padding. */
cfpkt_extr_head(pkt, &hpad, 1);
cfpkt_extr_head(pkt, NULL, hpad);
return layr->up->receive(layr->up, pkt);
}

static int cfusbl_transmit(struct cflayer *layr, struct cfpkt *pkt)
{
struct caif_payload_info *info;
u8 hpad;
u8 zeros[CFUSB_ALIGNMENT];
struct sk_buff *skb;
struct cfusbl *usbl = container_of(layr, struct cfusbl, layer);

skb = cfpkt_tonative(pkt);

skb_reset_network_header(skb);
skb->protocol = htons(ETH_P_IP);

info = cfpkt_info(pkt);
hpad = (info->hdr_len + CFUSB_PAD_DESCR_SZ) & (CFUSB_ALIGNMENT - 1);

if (skb_headroom(skb) < ETH_HLEN + CFUSB_PAD_DESCR_SZ + hpad) {
pr_warn("Headroom to small\n");
kfree_skb(skb);
return -EIO;
}
memset(zeros, 0, hpad);

cfpkt_add_head(pkt, zeros, hpad);
cfpkt_add_head(pkt, &hpad, 1);
cfpkt_add_head(pkt, usbl->tx_eth_hdr, sizeof(usbl->tx_eth_hdr));
return layr->dn->transmit(layr->dn, pkt);
}

static void cfusbl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
int phyid)
{
if (layr->up && layr->up->ctrlcmd)
layr->up->ctrlcmd(layr->up, ctrl, layr->id);
}

struct cflayer *cfusbl_create(int phyid, u8 ethaddr[ETH_ALEN],
u8 braddr[ETH_ALEN])
{
struct cfusbl *this = kmalloc(sizeof(struct cfusbl), GFP_ATOMIC);

if (!this) {
pr_warn("Out of memory\n");
return NULL;
}
caif_assert(offsetof(struct cfusbl, layer) == 0);

memset(this, 0, sizeof(struct cflayer));
this->layer.receive = cfusbl_receive;
this->layer.transmit = cfusbl_transmit;
this->layer.ctrlcmd = cfusbl_ctrlcmd;
snprintf(this->layer.name, CAIF_LAYER_NAME_SZ, "usb%d", phyid);
this->layer.id = phyid;

/*
* Construct TX ethernet header:
* 0-5 destination address
* 5-11 source address
* 12-13 protocol type
*/
memcpy(&this->tx_eth_hdr[ETH_ALEN], braddr, ETH_ALEN);
memcpy(&this->tx_eth_hdr[ETH_ALEN], ethaddr, ETH_ALEN);
this->tx_eth_hdr[12] = cpu_to_be16(ETH_P_802_EX1) & 0xff;
this->tx_eth_hdr[13] = (cpu_to_be16(ETH_P_802_EX1) >> 8) & 0xff;
pr_debug("caif ethernet TX-header dst:%pM src:%pM type:%02x%02x\n",
this->tx_eth_hdr, this->tx_eth_hdr + ETH_ALEN,
this->tx_eth_hdr[12], this->tx_eth_hdr[13]);

return (struct cflayer *) this;
}

static struct packet_type caif_usb_type __read_mostly = {
.type = cpu_to_be16(ETH_P_802_EX1),
};

static int cfusbl_device_notify(struct notifier_block *me, unsigned long what,
void *arg)
{
struct net_device *dev = arg;
struct caif_dev_common common;
struct cflayer *layer, *link_support;
struct usbnet *usbnet = netdev_priv(dev);
struct usb_device *usbdev = usbnet->udev;
struct ethtool_drvinfo drvinfo;

/*
* Quirks: High-jack ethtool to find if we have a NCM device,
* and find it's VID/PID.
*/
if (dev->ethtool_ops == NULL || dev->ethtool_ops->get_drvinfo == NULL)
return 0;

dev->ethtool_ops->get_drvinfo(dev, &drvinfo);
if (strncmp(drvinfo.driver, "cdc_ncm", 7) != 0)
return 0;

pr_debug("USB CDC NCM device VID:0x%4x PID:0x%4x\n",
le16_to_cpu(usbdev->descriptor.idVendor),
le16_to_cpu(usbdev->descriptor.idProduct));

/* Check for VID/PID that supports CAIF */
if (!(le16_to_cpu(usbdev->descriptor.idVendor) == STE_USB_VID &&
le16_to_cpu(usbdev->descriptor.idProduct) == STE_USB_PID_CAIF))
return 0;

if (what == NETDEV_UNREGISTER)
module_put(THIS_MODULE);

if (what != NETDEV_REGISTER)
return 0;

__module_get(THIS_MODULE);

memset(&common, 0, sizeof(common));
common.use_frag = false;
common.use_fcs = false;
common.use_stx = false;
common.link_select = CAIF_LINK_HIGH_BANDW;
common.flowctrl = NULL;

link_support = cfusbl_create(dev->ifindex, dev->dev_addr,
dev->broadcast);

if (!link_support)
return -ENOMEM;

if (dev->num_tx_queues > 1)
pr_warn("USB device uses more than one tx queue\n");

caif_enroll_dev(dev, &common, link_support, CFUSB_MAX_HEADLEN,
&layer, &caif_usb_type.func);
if (!pack_added)
dev_add_pack(&caif_usb_type);
pack_added = 1;

strncpy(layer->name, dev->name,
sizeof(layer->name) - 1);
layer->name[sizeof(layer->name) - 1] = 0;

return 0;
}

static struct notifier_block caif_device_notifier = {
.notifier_call = cfusbl_device_notify,
.priority = 0,
};

static int __init cfusbl_init(void)
{
return register_netdevice_notifier(&caif_device_notifier);
}

static void __exit cfusbl_exit(void)
{
unregister_netdevice_notifier(&caif_device_notifier);
dev_remove_pack(&caif_usb_type);
}

module_init(cfusbl_init);
module_exit(cfusbl_exit);
12 changes: 3 additions & 9 deletions trunk/net/caif/cfpkt_skbuff.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ static inline struct cfpkt *skb_to_pkt(struct sk_buff *skb)
return (struct cfpkt *) skb;
}


struct cfpkt *cfpkt_fromnative(enum caif_direction dir, void *nativepkt)
{
struct cfpkt *pkt = skb_to_pkt(nativepkt);
Expand Down Expand Up @@ -105,14 +104,12 @@ void cfpkt_destroy(struct cfpkt *pkt)
kfree_skb(skb);
}


inline bool cfpkt_more(struct cfpkt *pkt)
{
struct sk_buff *skb = pkt_to_skb(pkt);
return skb->len > 0;
}


int cfpkt_peek_head(struct cfpkt *pkt, void *data, u16 len)
{
struct sk_buff *skb = pkt_to_skb(pkt);
Expand Down Expand Up @@ -148,6 +145,7 @@ int cfpkt_extr_head(struct cfpkt *pkt, void *data, u16 len)
memcpy(data, from, len);
return 0;
}
EXPORT_SYMBOL(cfpkt_extr_head);

int cfpkt_extr_trail(struct cfpkt *pkt, void *dta, u16 len)
{
Expand All @@ -171,13 +169,11 @@ int cfpkt_extr_trail(struct cfpkt *pkt, void *dta, u16 len)
return 0;
}


int cfpkt_pad_trail(struct cfpkt *pkt, u16 len)
{
return cfpkt_add_body(pkt, NULL, len);
}


int cfpkt_add_body(struct cfpkt *pkt, const void *data, u16 len)
{
struct sk_buff *skb = pkt_to_skb(pkt);
Expand Down Expand Up @@ -256,21 +252,19 @@ int cfpkt_add_head(struct cfpkt *pkt, const void *data2, u16 len)
memcpy(to, data, len);
return 0;
}

EXPORT_SYMBOL(cfpkt_add_head);

inline int cfpkt_add_trail(struct cfpkt *pkt, const void *data, u16 len)
{
return cfpkt_add_body(pkt, data, len);
}


inline u16 cfpkt_getlen(struct cfpkt *pkt)
{
struct sk_buff *skb = pkt_to_skb(pkt);
return skb->len;
}


inline u16 cfpkt_iterate(struct cfpkt *pkt,
u16 (*iter_func)(u16, void *, u16),
u16 data)
Expand All @@ -288,7 +282,6 @@ inline u16 cfpkt_iterate(struct cfpkt *pkt,
return iter_func(data, pkt->skb.data, cfpkt_getlen(pkt));
}


int cfpkt_setlen(struct cfpkt *pkt, u16 len)
{
struct sk_buff *skb = pkt_to_skb(pkt);
Expand Down Expand Up @@ -400,3 +393,4 @@ struct caif_payload_info *cfpkt_info(struct cfpkt *pkt)
{
return (struct caif_payload_info *)&pkt_to_skb(pkt)->cb;
}
EXPORT_SYMBOL(cfpkt_info);

0 comments on commit cd67613

Please sign in to comment.