aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorwonhee <wonhee48.seo@samsung.com>2011-08-12 03:35:50 -0700
committerBenoit Goby <benoit@android.com>2011-08-12 14:15:03 -0700
commit17e32f463b790dd539cde6daef6711a94f64206a (patch)
tree6ca06d75018ab68d859626ff89c8b527c84be2ed /drivers
parent555c7ee2d929f634f896cb5a65bedbd7ae61984a (diff)
downloadkernel_samsung_tuna-17e32f463b790dd539cde6daef6711a94f64206a.tar.gz
kernel_samsung_tuna-17e32f463b790dd539cde6daef6711a94f64206a.tar.bz2
kernel_samsung_tuna-17e32f463b790dd539cde6daef6711a94f64206a.zip
misc: modem_if: Add NET bridge driver
1. Add net bridge driver. - modem_bridge_device.c 2. Add handling net data for tx and rx in io device. - need to include ether header structure 3. Requirement for bridge driver. a. need ril binary which is enabled bridge func b. need radio permission for '/dev/modem_br' : ril needs to flow control, protocol-suspend(stop) and protocol-resume(start) : this is for ioctl func that ril will access c. tuna_defconfig : 'CONFIG_BRIDGE=y' => 802.1d Ethernet Bridging : '# CONFIG_BRIDGE_IGMP_SNOOPING is not set' => to prevent ip4 packet data goes IPv6 only PDN, cannot get ipv6 address 4. Use platform data to check network type. - patch set 2. 5. Change modem_bridge_device.c -> modem_net_flowcontrol_device.c - patch set 3 - remove unnecessary dummy net device 6. Not use CONFIG_BRIDGE in io_device code. - use platform data 7. Change suspend/resume ioctl command number. - patch set 4 - need to update ril Change-Id: I2c7b4bb53bad154f52b39ccf4d0d3133d055361a Signed-off-by: wonhee <wonhee48.seo@samsung.com>
Diffstat (limited to 'drivers')
-rwxr-xr-xdrivers/misc/modem_if/Makefile2
-rw-r--r--drivers/misc/modem_if/modem.c6
-rwxr-xr-xdrivers/misc/modem_if/modem_io_device.c62
-rwxr-xr-xdrivers/misc/modem_if/modem_net_flowcontrol_device.c115
-rwxr-xr-xdrivers/misc/modem_if/modem_prj.h11
5 files changed, 189 insertions, 7 deletions
diff --git a/drivers/misc/modem_if/Makefile b/drivers/misc/modem_if/Makefile
index d2d0d5b7a63..e76c8b28a18 100755
--- a/drivers/misc/modem_if/Makefile
+++ b/drivers/misc/modem_if/Makefile
@@ -1,4 +1,4 @@
-obj-y += modem.o modem_io_device.o lte_modem_bootloader.o
+obj-y += modem.o modem_io_device.o modem_net_flowcontrol_device.o
obj-$(CONFIG_UMTS_MODEM_XMM6260) += modem_modemctl_device_xmm6260.o
obj-$(CONFIG_UMTS_LINK_MIPI) += modem_link_device_mipi.o
obj-$(CONFIG_UMTS_LINK_HSIC) += modem_link_device_hsic.o
diff --git a/drivers/misc/modem_if/modem.c b/drivers/misc/modem_if/modem.c
index 0642b238e8b..3d5bd0c8fe5 100644
--- a/drivers/misc/modem_if/modem.c
+++ b/drivers/misc/modem_if/modem.c
@@ -67,7 +67,7 @@ static struct modem_ctl *create_modemctl_device(struct platform_device *pdev)
}
static struct io_device *create_io_device(struct modem_io_t *io_t,
- struct modem_ctl *modemctl)
+ struct modem_ctl *modemctl, enum modem_network modem_net)
{
int ret = 0;
struct io_device *iod = NULL;
@@ -82,6 +82,7 @@ static struct io_device *create_io_device(struct modem_io_t *io_t,
iod->id = io_t->id;
iod->format = io_t->format;
iod->io_typ = io_t->io_type;
+ iod->net_typ = modem_net;
/* link between io device and modem control */
iod->mc = modemctl;
@@ -126,7 +127,8 @@ static int __devinit modem_probe(struct platform_device *pdev)
/* create io deivces and connect to modemctl device */
for (i = 0; i < pdata->num_iodevs; i++) {
- iod[i] = create_io_device(&pdata->iodevs[i], modemctl);
+ iod[i] = create_io_device(&pdata->iodevs[i], modemctl,
+ pdata->modem_net);
if (!iod[i])
goto err_free_modemctl;
diff --git a/drivers/misc/modem_if/modem_io_device.c b/drivers/misc/modem_if/modem_io_device.c
index 8ce60d89b85..f1c9fe30e95 100755
--- a/drivers/misc/modem_if/modem_io_device.c
+++ b/drivers/misc/modem_if/modem_io_device.c
@@ -22,6 +22,7 @@
#include <linux/gpio.h>
#include <linux/if_arp.h>
#include <linux/ip.h>
+#include <linux/if_ether.h>
#include <linux/platform_data/modem.h>
#include "modem_prj.h"
@@ -243,6 +244,20 @@ static int rx_hdlc_data_check(struct io_device *iod, char *buf, unsigned rest)
/* copy the RFS haeder to skb->data */
memcpy(skb_put(skb, head_size), hdr->hdr, head_size);
break;
+
+ case IPC_MULTI_RAW:
+ if (iod->net_typ == UMTS_NETWORK)
+ skb = alloc_skb(alloc_size, GFP_ATOMIC);
+ else
+ skb = alloc_skb(alloc_size +
+ sizeof(struct ethhdr), GFP_ATOMIC);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ if (iod->net_typ != UMTS_NETWORK)
+ skb_reserve(skb, sizeof(struct ethhdr));
+ break;
+
default:
skb = alloc_skb(alloc_size, GFP_ATOMIC);
if (unlikely(!skb))
@@ -295,6 +310,9 @@ static int rx_iodev_skb_raw(struct io_device *iod)
struct sk_buff *skb = iod->skb_recv;
struct net_device *ndev;
struct iphdr *ip_header;
+ struct ethhdr *ehdr;
+ const char source[ETH_ALEN] = SOURCE_MAC_ADDR;
+ const char dest[ETH_ALEN] = {BRIDGE_MAC_ADDR, 0, 0, 0, 0, 0};
switch (iod->io_typ) {
case IODEV_MISC:
@@ -318,7 +336,21 @@ static int rx_iodev_skb_raw(struct io_device *iod)
else
skb->protocol = htons(ETH_P_IP);
- err = netif_rx(skb);
+ if (iod->net_typ == UMTS_NETWORK)
+ err = netif_rx(skb);
+ else {
+ skb_push(skb, sizeof(struct ethhdr));
+ ehdr = (void *)skb->data;
+ memcpy(ehdr->h_dest, dest, ETH_ALEN);
+ memcpy(ehdr->h_source, source, ETH_ALEN);
+ ehdr->h_proto = skb->protocol;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb_reset_mac_header(skb);
+
+ skb_pull(skb, sizeof(struct ethhdr));
+ err = netif_rx_ni(skb);
+ }
+
if (err != NET_RX_SUCCESS)
dev_err(&ndev->dev, "rx error: %d\n", err);
return err;
@@ -702,6 +734,13 @@ static int vnet_xmit(struct sk_buff *skb, struct net_device *ndev)
struct vnet *vnet = netdev_priv(ndev);
struct io_device *iod = vnet->iod;
+ /* umts doesn't need to discard ethernet header */
+ if (iod->net_typ != UMTS_NETWORK) {
+ if (iod->id >= PSD_DATA_CHID_BEGIN &&
+ iod->id <= PSD_DATA_CHID_END)
+ skb_pull(skb, sizeof(struct ethhdr));
+ }
+
hd.len = skb->len + sizeof(hd);
hd.control = 0;
hd.channel = iod->id & 0x1F;
@@ -743,8 +782,21 @@ static void vnet_setup(struct net_device *ndev)
ndev->netdev_ops = &vnet_ops;
ndev->type = ARPHRD_PPP;
ndev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
- ndev->hard_header_len = 0;
ndev->addr_len = 0;
+ ndev->hard_header_len = 0;
+ ndev->tx_queue_len = 1000;
+ ndev->mtu = ETH_DATA_LEN;
+ ndev->watchdog_timeo = 5 * HZ;
+}
+
+static void vnet_setup_ether(struct net_device *ndev)
+{
+ ndev->netdev_ops = &vnet_ops;
+ ndev->type = ARPHRD_ETHER;
+ ndev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST | IFF_SLAVE;
+ ndev->addr_len = ETH_ALEN;
+ ndev->dev_addr[0] = BRIDGE_MAC_ADDR;
+ ndev->hard_header_len = 0;
ndev->tx_queue_len = 1000;
ndev->mtu = ETH_DATA_LEN;
ndev->watchdog_timeo = 5 * HZ;
@@ -780,7 +832,11 @@ int init_io_device(struct io_device *iod)
break;
case IODEV_NET:
- iod->ndev = alloc_netdev(0, iod->name, vnet_setup);
+ if (iod->net_typ == UMTS_NETWORK)
+ iod->ndev = alloc_netdev(0, iod->name, vnet_setup);
+ else
+ iod->ndev = alloc_netdev(0, iod->name,
+ vnet_setup_ether);
if (!iod->ndev) {
pr_err("failed to alloc netdev\n");
return -ENOMEM;
diff --git a/drivers/misc/modem_if/modem_net_flowcontrol_device.c b/drivers/misc/modem_if/modem_net_flowcontrol_device.c
new file mode 100755
index 00000000000..9397eddf7e1
--- /dev/null
+++ b/drivers/misc/modem_if/modem_net_flowcontrol_device.c
@@ -0,0 +1,115 @@
+/* /linux/drivers/misc/modem_if/modem_net_flowcontrol_device.c
+ *
+ * Copyright (C) 2011 Google, Inc.
+ * Copyright (C) 2011 Samsung Electronics.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/platform_data/modem.h>
+
+#include "modem_prj.h"
+
+
+#define NET_FLOWCONTROL_DEV_NAME_LEN 8
+
+static int modem_net_flowcontrol_device_open(
+ struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+static int modem_net_flowcontrol_device_release(
+ struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+static long modem_net_flowcontrol_device_ioctl(
+ struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ struct net *this_net;
+ struct net_device *ndev;
+ char dev_name[NET_FLOWCONTROL_DEV_NAME_LEN];
+ u8 chan;
+
+ if (copy_from_user(&chan, (void __user *)arg, sizeof(char)))
+ return -EFAULT;
+
+ if (chan > 15)
+ return -ENODEV;
+
+ snprintf(dev_name, NET_FLOWCONTROL_DEV_NAME_LEN, "rmnet%d", (int)chan);
+ this_net = get_net_ns_by_pid(current->pid);
+ ndev = __dev_get_by_name(this_net, dev_name);
+ if (ndev == NULL) {
+ pr_err("[MODEM_IF] %s: device = %s not exist\n", __func__,
+ dev_name);
+ return -ENODEV;
+ }
+
+ switch (cmd) {
+ case IOCTL_MODEM_NET_SUSPEND:
+ netif_stop_queue(ndev);
+ pr_info("[MODEM_IF] NET SUSPEND(%s)\n", dev_name);
+ break;
+ case IOCTL_MODEM_NET_RESUME:
+ netif_wake_queue(ndev);
+ pr_info("[MODEM_IF] NET RESUME(%s)\n", dev_name);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const struct file_operations modem_net_flowcontrol_device_fops = {
+ .owner = THIS_MODULE,
+ .open = modem_net_flowcontrol_device_open,
+ .release = modem_net_flowcontrol_device_release,
+ .unlocked_ioctl = modem_net_flowcontrol_device_ioctl,
+};
+
+static int __init modem_net_flowcontrol_device_init(void)
+{
+ int ret = 0;
+ struct io_device *net_flowcontrol_dev;
+
+ net_flowcontrol_dev = kzalloc(sizeof(struct io_device), GFP_KERNEL);
+ if (!net_flowcontrol_dev) {
+ pr_err("[MODEM_IF] net_flowcontrol_dev io device memory alloc fail\n");
+ return -ENOMEM;
+ }
+
+ net_flowcontrol_dev->miscdev.minor = MISC_DYNAMIC_MINOR;
+ net_flowcontrol_dev->miscdev.name = "modem_br";
+ net_flowcontrol_dev->miscdev.fops = &modem_net_flowcontrol_device_fops;
+
+ ret = misc_register(&net_flowcontrol_dev->miscdev);
+ if (ret)
+ pr_err("[MODEM_IF] failed to register misc br device : %s\n",
+ net_flowcontrol_dev->miscdev.name);
+
+ return ret;
+}
+
+module_init(modem_net_flowcontrol_device_init);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Samsung Modem IF Net Flowcontrol Driver");
diff --git a/drivers/misc/modem_if/modem_prj.h b/drivers/misc/modem_if/modem_prj.h
index 2ca9f7679fc..79a5d8002f8 100755
--- a/drivers/misc/modem_if/modem_prj.h
+++ b/drivers/misc/modem_if/modem_prj.h
@@ -35,10 +35,12 @@
#define IOCTL_MODEM_SEND _IO('o', 0x25)
#define IOCTL_MODEM_RECV _IO('o', 0x26)
-#define IOCTL_MODEM_STATUS _IO('o', 0x27)
+#define IOCTL_MODEM_STATUS _IO('o', 0x27)
#define IOCTL_MODEM_GOTA_START _IO('o', 0x28)
#define IOCTL_MODEM_FW_UPDATE _IO('o', 0x29)
+#define IOCTL_MODEM_NET_SUSPEND _IO('o', 0x30)
+#define IOCTL_MODEM_NET_RESUME _IO('o', 0x31)
/* modem status */
#define MODEM_OFF 0
@@ -52,8 +54,14 @@
#define IPC_HEADER_MAX_SIZE 6 /* fmt 3, raw 6, rfs 6 */
+#define PSD_DATA_CHID_BEGIN 0x2A
+#define PSD_DATA_CHID_END 0x38
+
#define IP6VERSION 6
+#define BRIDGE_MAC_ADDR 0x12
+#define SOURCE_MAC_ADDR {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}
+
/* Does modem ctl structure will use state ? or status defined below ?*/
enum modem_state {
STATE_OFFLINE,
@@ -103,6 +111,7 @@ struct io_device {
unsigned id;
enum dev_format format;
enum modem_io io_typ;
+ enum modem_network net_typ;
struct sk_buff_head sk_rx_q;