blob: 2a57b36b4023327d841ddb98f64d284cdbd9fee0 [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
Hemant Kumar37c35e42011-09-14 23:44:19 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
Steve Mucklef132c6c2012-06-06 18:30:57 -070013#include <linux/module.h>
Hemant Kumar37c35e42011-09-14 23:44:19 -070014#include <linux/mii.h>
15#include <linux/if_arp.h>
16#include <linux/etherdevice.h>
Hemant Kumar7bf94262012-04-18 17:25:10 -070017#include <linux/debugfs.h>
18#include <linux/seq_file.h>
Hemant Kumar37c35e42011-09-14 23:44:19 -070019#include <linux/usb.h>
20#include <linux/usb/usbnet.h>
21#include <linux/msm_rmnet.h>
22
23#include "rmnet_usb_ctrl.h"
24
25#define RMNET_DATA_LEN 2000
26#define HEADROOM_FOR_QOS 8
27
Hemant Kumar37c35e42011-09-14 23:44:19 -070028static int data_msg_dbg_mask;
29
30enum {
31 DEBUG_MASK_LVL0 = 1U << 0,
32 DEBUG_MASK_LVL1 = 1U << 1,
33 DEBUG_MASK_LVL2 = 1U << 2,
34};
35
36#define DBG(m, x...) do { \
37 if (data_msg_dbg_mask & m) \
38 pr_info(x); \
39} while (0)
40
41/*echo dbg_mask > /sys/class/net/rmnet_usbx/dbg_mask*/
42static ssize_t dbg_mask_store(struct device *d,
43 struct device_attribute *attr,
44 const char *buf, size_t n)
45{
46 unsigned int dbg_mask;
47 struct net_device *dev = to_net_dev(d);
48 struct usbnet *unet = netdev_priv(dev);
49
50 if (!dev)
51 return -ENODEV;
52
53 sscanf(buf, "%u", &dbg_mask);
54 /*enable dbg msgs for data driver*/
55 data_msg_dbg_mask = dbg_mask;
56
57 /*set default msg level*/
58 unet->msg_enable = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK;
59
60 /*enable netif_xxx msgs*/
61 if (dbg_mask & DEBUG_MASK_LVL0)
62 unet->msg_enable |= NETIF_MSG_IFUP | NETIF_MSG_IFDOWN;
63 if (dbg_mask & DEBUG_MASK_LVL1)
64 unet->msg_enable |= NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR
65 | NETIF_MSG_TX_QUEUED | NETIF_MSG_TX_DONE
66 | NETIF_MSG_RX_STATUS;
67
68 return n;
69}
70
71static ssize_t dbg_mask_show(struct device *d,
72 struct device_attribute *attr, char *buf)
73{
74 return snprintf(buf, PAGE_SIZE, "%d\n", data_msg_dbg_mask);
75}
76
77static DEVICE_ATTR(dbg_mask, 0644, dbg_mask_show, dbg_mask_store);
78
79#define DBG0(x...) DBG(DEBUG_MASK_LVL0, x)
80#define DBG1(x...) DBG(DEBUG_MASK_LVL1, x)
81#define DBG2(x...) DBG(DEBUG_MASK_LVL2, x)
82
83static void rmnet_usb_setup(struct net_device *);
84static int rmnet_ioctl(struct net_device *, struct ifreq *, int);
85
86static int rmnet_usb_suspend(struct usb_interface *iface, pm_message_t message)
87{
88 struct usbnet *unet;
89 struct rmnet_ctrl_dev *dev;
Hemant Kumar37c35e42011-09-14 23:44:19 -070090
91 unet = usb_get_intfdata(iface);
Hemant Kumar37c35e42011-09-14 23:44:19 -070092
93 dev = (struct rmnet_ctrl_dev *)unet->data[1];
Hemant Kumar37c35e42011-09-14 23:44:19 -070094
Hemant Kumarc4659d92012-12-04 15:47:13 -080095 if (work_busy(&dev->get_encap_work))
96 return -EBUSY;
Hemant Kumar37c35e42011-09-14 23:44:19 -070097
Hemant Kumarc4659d92012-12-04 15:47:13 -080098 if (usbnet_suspend(iface, message))
99 return -EBUSY;
100
101 usb_kill_anchored_urbs(&dev->rx_submitted);
102
103 return 0;
Hemant Kumar37c35e42011-09-14 23:44:19 -0700104}
105
106static int rmnet_usb_resume(struct usb_interface *iface)
107{
108 int retval = 0;
Hemant Kumar37c35e42011-09-14 23:44:19 -0700109 struct usbnet *unet;
110 struct rmnet_ctrl_dev *dev;
111
112 unet = usb_get_intfdata(iface);
Hemant Kumar37c35e42011-09-14 23:44:19 -0700113
114 dev = (struct rmnet_ctrl_dev *)unet->data[1];
Hemant Kumar37c35e42011-09-14 23:44:19 -0700115
Hemant Kumarc4659d92012-12-04 15:47:13 -0800116 usbnet_resume(iface);
117 retval = rmnet_usb_ctrl_start_rx(dev);
118
Hemant Kumar37c35e42011-09-14 23:44:19 -0700119 return retval;
120}
121
122static int rmnet_usb_bind(struct usbnet *usbnet, struct usb_interface *iface)
123{
124 struct usb_host_endpoint *endpoint = NULL;
125 struct usb_host_endpoint *bulk_in = NULL;
126 struct usb_host_endpoint *bulk_out = NULL;
127 struct usb_host_endpoint *int_in = NULL;
Hemant Kumar37c35e42011-09-14 23:44:19 -0700128 int status = 0;
129 int i;
130 int numends;
131
Hemant Kumar37c35e42011-09-14 23:44:19 -0700132 numends = iface->cur_altsetting->desc.bNumEndpoints;
133 for (i = 0; i < numends; i++) {
134 endpoint = iface->cur_altsetting->endpoint + i;
135 if (!endpoint) {
Jack Phame8741502012-06-13 17:34:07 -0700136 dev_err(&iface->dev, "%s: invalid endpoint %u\n",
Hemant Kumar37c35e42011-09-14 23:44:19 -0700137 __func__, i);
138 status = -EINVAL;
139 goto out;
140 }
141 if (usb_endpoint_is_bulk_in(&endpoint->desc))
142 bulk_in = endpoint;
143 else if (usb_endpoint_is_bulk_out(&endpoint->desc))
144 bulk_out = endpoint;
145 else if (usb_endpoint_is_int_in(&endpoint->desc))
146 int_in = endpoint;
147 }
148
149 if (!bulk_in || !bulk_out || !int_in) {
Jack Phame8741502012-06-13 17:34:07 -0700150 dev_err(&iface->dev, "%s: invalid endpoints\n", __func__);
Hemant Kumar37c35e42011-09-14 23:44:19 -0700151 status = -EINVAL;
152 goto out;
153 }
154 usbnet->in = usb_rcvbulkpipe(usbnet->udev,
155 bulk_in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
156 usbnet->out = usb_sndbulkpipe(usbnet->udev,
157 bulk_out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
158 usbnet->status = int_in;
159
160 /*change name of net device to rmnet_usbx here*/
161 strlcpy(usbnet->net->name, "rmnet_usb%d", IFNAMSIZ);
162
163 /*TBD: update rx_urb_size, curently set to eth frame len by usbnet*/
164out:
165 return status;
166}
167
168static struct sk_buff *rmnet_usb_tx_fixup(struct usbnet *dev,
169 struct sk_buff *skb, gfp_t flags)
170{
171 struct QMI_QOS_HDR_S *qmih;
172
173 if (test_bit(RMNET_MODE_QOS, &dev->data[0])) {
174 qmih = (struct QMI_QOS_HDR_S *)
175 skb_push(skb, sizeof(struct QMI_QOS_HDR_S));
176 qmih->version = 1;
177 qmih->flags = 0;
178 qmih->flow_id = skb->mark;
179 }
180
181 DBG1("[%s] Tx packet #%lu len=%d mark=0x%x\n",
182 dev->net->name, dev->net->stats.tx_packets, skb->len, skb->mark);
183
184 return skb;
185}
186
187static __be16 rmnet_ip_type_trans(struct sk_buff *skb,
188 struct net_device *dev)
189{
190 __be16 protocol = 0;
191
192 skb->dev = dev;
193
194 switch (skb->data[0] & 0xf0) {
195 case 0x40:
196 protocol = htons(ETH_P_IP);
197 break;
198 case 0x60:
199 protocol = htons(ETH_P_IPV6);
200 break;
201 default:
202 pr_err("[%s] rmnet_recv() L3 protocol decode error: 0x%02x",
203 dev->name, skb->data[0] & 0xf0);
204 }
205
206 return protocol;
207}
208
209static int rmnet_usb_rx_fixup(struct usbnet *dev,
210 struct sk_buff *skb)
211{
212
213 if (test_bit(RMNET_MODE_LLP_IP, &dev->data[0]))
214 skb->protocol = rmnet_ip_type_trans(skb, dev->net);
215 else /*set zero for eth mode*/
216 skb->protocol = 0;
217
218 DBG1("[%s] Rx packet #%lu len=%d\n",
219 dev->net->name, dev->net->stats.rx_packets, skb->len);
220
221 return 1;
222}
223
Jack Phamf77b9962012-02-23 18:45:43 -0800224static int rmnet_usb_manage_power(struct usbnet *dev, int on)
225{
226 dev->intf->needs_remote_wakeup = on;
227 return 0;
228}
229
Hemant Kumar37c35e42011-09-14 23:44:19 -0700230static int rmnet_change_mtu(struct net_device *dev, int new_mtu)
231{
232 if (0 > new_mtu || RMNET_DATA_LEN < new_mtu)
233 return -EINVAL;
234
235 DBG0("[%s] MTU change: old=%d new=%d\n", dev->name, dev->mtu, new_mtu);
236
237 dev->mtu = new_mtu;
238
239 return 0;
240}
241
242static struct net_device_stats *rmnet_get_stats(struct net_device *dev)
243{
244 return &dev->stats;
245}
246
247static const struct net_device_ops rmnet_usb_ops_ether = {
248 .ndo_open = usbnet_open,
249 .ndo_stop = usbnet_stop,
250 .ndo_start_xmit = usbnet_start_xmit,
251 .ndo_get_stats = rmnet_get_stats,
252 /*.ndo_set_multicast_list = rmnet_set_multicast_list,*/
253 .ndo_tx_timeout = usbnet_tx_timeout,
254 .ndo_do_ioctl = rmnet_ioctl,
255 .ndo_change_mtu = usbnet_change_mtu,
256 .ndo_set_mac_address = eth_mac_addr,
257 .ndo_validate_addr = eth_validate_addr,
258};
259
260static const struct net_device_ops rmnet_usb_ops_ip = {
261 .ndo_open = usbnet_open,
262 .ndo_stop = usbnet_stop,
263 .ndo_start_xmit = usbnet_start_xmit,
264 .ndo_get_stats = rmnet_get_stats,
265 /*.ndo_set_multicast_list = rmnet_set_multicast_list,*/
266 .ndo_tx_timeout = usbnet_tx_timeout,
267 .ndo_do_ioctl = rmnet_ioctl,
268 .ndo_change_mtu = rmnet_change_mtu,
269 .ndo_set_mac_address = 0,
270 .ndo_validate_addr = 0,
271};
272
273
274static int rmnet_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
275{
276 struct usbnet *unet = netdev_priv(dev);
277 u32 old_opmode;
278 int prev_mtu = dev->mtu;
279 int rc = 0;
280
281 old_opmode = unet->data[0]; /*data[0] saves operation mode*/
282 /* Process IOCTL command */
283 switch (cmd) {
284 case RMNET_IOCTL_SET_LLP_ETHERNET: /*Set Ethernet protocol*/
285 /* Perform Ethernet config only if in IP mode currently*/
286 if (test_bit(RMNET_MODE_LLP_IP, &unet->data[0])) {
287 ether_setup(dev);
288 random_ether_addr(dev->dev_addr);
289 dev->mtu = prev_mtu;
290 dev->netdev_ops = &rmnet_usb_ops_ether;
291 clear_bit(RMNET_MODE_LLP_IP, &unet->data[0]);
292 set_bit(RMNET_MODE_LLP_ETH, &unet->data[0]);
293 DBG0("[%s] rmnet_ioctl(): set Ethernet protocol mode\n",
294 dev->name);
295 }
296 break;
297
298 case RMNET_IOCTL_SET_LLP_IP: /* Set RAWIP protocol*/
299 /* Perform IP config only if in Ethernet mode currently*/
300 if (test_bit(RMNET_MODE_LLP_ETH, &unet->data[0])) {
301
302 /* Undo config done in ether_setup() */
303 dev->header_ops = 0; /* No header */
304 dev->type = ARPHRD_RAWIP;
305 dev->hard_header_len = 0;
306 dev->mtu = prev_mtu;
307 dev->addr_len = 0;
308 dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST);
309 dev->needed_headroom = HEADROOM_FOR_QOS;
310 dev->netdev_ops = &rmnet_usb_ops_ip;
311 clear_bit(RMNET_MODE_LLP_ETH, &unet->data[0]);
312 set_bit(RMNET_MODE_LLP_IP, &unet->data[0]);
313 DBG0("[%s] rmnet_ioctl(): set IP protocol mode\n",
314 dev->name);
315 }
316 break;
317
318 case RMNET_IOCTL_GET_LLP: /* Get link protocol state */
319 ifr->ifr_ifru.ifru_data = (void *)(unet->data[0]
320 & (RMNET_MODE_LLP_ETH
321 | RMNET_MODE_LLP_IP));
322 break;
323
324 case RMNET_IOCTL_SET_QOS_ENABLE: /* Set QoS header enabled*/
325 set_bit(RMNET_MODE_QOS, &unet->data[0]);
326 DBG0("[%s] rmnet_ioctl(): set QMI QOS header enable\n",
327 dev->name);
328 break;
329
330 case RMNET_IOCTL_SET_QOS_DISABLE: /* Set QoS header disabled */
331 clear_bit(RMNET_MODE_QOS, &unet->data[0]);
332 DBG0("[%s] rmnet_ioctl(): set QMI QOS header disable\n",
333 dev->name);
334 break;
335
336 case RMNET_IOCTL_GET_QOS: /* Get QoS header state */
337 ifr->ifr_ifru.ifru_data = (void *)(unet->data[0]
338 & RMNET_MODE_QOS);
339 break;
340
341 case RMNET_IOCTL_GET_OPMODE: /* Get operation mode*/
342 ifr->ifr_ifru.ifru_data = (void *)unet->data[0];
343 break;
344
345 case RMNET_IOCTL_OPEN: /* Open transport port */
346 rc = usbnet_open(dev);
347 DBG0("[%s] rmnet_ioctl(): open transport port\n", dev->name);
348 break;
349
350 case RMNET_IOCTL_CLOSE: /* Close transport port*/
351 rc = usbnet_stop(dev);
352 DBG0("[%s] rmnet_ioctl(): close transport port\n", dev->name);
353 break;
354
355 default:
Jack Phame8741502012-06-13 17:34:07 -0700356 dev_err(&unet->intf->dev, "[%s] error: "
Hemant Kumar37c35e42011-09-14 23:44:19 -0700357 "rmnet_ioct called for unsupported cmd[%d]",
358 dev->name, cmd);
359 return -EINVAL;
360 }
361
362 DBG2("[%s] %s: cmd=0x%x opmode old=0x%08x new=0x%08lx\n",
363 dev->name, __func__, cmd, old_opmode, unet->data[0]);
364
365 return rc;
366}
367
368static void rmnet_usb_setup(struct net_device *dev)
369{
370 /* Using Ethernet mode by default */
371 dev->netdev_ops = &rmnet_usb_ops_ether;
372
373 /* set this after calling ether_setup */
374 dev->mtu = RMNET_DATA_LEN;
375
376 dev->needed_headroom = HEADROOM_FOR_QOS;
377 random_ether_addr(dev->dev_addr);
378 dev->watchdog_timeo = 1000; /* 10 seconds? */
379}
380
Hemant Kumar7bf94262012-04-18 17:25:10 -0700381static int rmnet_usb_data_status(struct seq_file *s, void *unused)
382{
383 struct usbnet *unet = s->private;
384
385 seq_printf(s, "RMNET_MODE_LLP_IP: %d\n",
386 test_bit(RMNET_MODE_LLP_IP, &unet->data[0]));
387 seq_printf(s, "RMNET_MODE_LLP_ETH: %d\n",
388 test_bit(RMNET_MODE_LLP_ETH, &unet->data[0]));
389 seq_printf(s, "RMNET_MODE_QOS: %d\n",
390 test_bit(RMNET_MODE_QOS, &unet->data[0]));
391 seq_printf(s, "Net MTU: %u\n", unet->net->mtu);
392 seq_printf(s, "rx_urb_size: %u\n", unet->rx_urb_size);
393 seq_printf(s, "rx skb q len: %u\n", unet->rxq.qlen);
394 seq_printf(s, "rx skb done q len: %u\n", unet->done.qlen);
395 seq_printf(s, "rx errors: %lu\n", unet->net->stats.rx_errors);
396 seq_printf(s, "rx over errors: %lu\n",
397 unet->net->stats.rx_over_errors);
398 seq_printf(s, "rx length errors: %lu\n",
399 unet->net->stats.rx_length_errors);
400 seq_printf(s, "rx packets: %lu\n", unet->net->stats.rx_packets);
401 seq_printf(s, "rx bytes: %lu\n", unet->net->stats.rx_bytes);
402 seq_printf(s, "tx skb q len: %u\n", unet->txq.qlen);
403 seq_printf(s, "tx errors: %lu\n", unet->net->stats.tx_errors);
404 seq_printf(s, "tx packets: %lu\n", unet->net->stats.tx_packets);
405 seq_printf(s, "tx bytes: %lu\n", unet->net->stats.tx_bytes);
406 seq_printf(s, "suspend count: %d\n", unet->suspend_count);
407 seq_printf(s, "EVENT_DEV_OPEN: %d\n",
408 test_bit(EVENT_DEV_OPEN, &unet->flags));
409 seq_printf(s, "EVENT_TX_HALT: %d\n",
410 test_bit(EVENT_TX_HALT, &unet->flags));
411 seq_printf(s, "EVENT_RX_HALT: %d\n",
412 test_bit(EVENT_RX_HALT, &unet->flags));
413 seq_printf(s, "EVENT_RX_MEMORY: %d\n",
414 test_bit(EVENT_RX_MEMORY, &unet->flags));
415 seq_printf(s, "EVENT_DEV_ASLEEP: %d\n",
416 test_bit(EVENT_DEV_ASLEEP, &unet->flags));
417
418 return 0;
419}
420
421static int rmnet_usb_data_status_open(struct inode *inode, struct file *file)
422{
423 return single_open(file, rmnet_usb_data_status, inode->i_private);
424}
425
426const struct file_operations rmnet_usb_data_fops = {
427 .open = rmnet_usb_data_status_open,
428 .read = seq_read,
429 .llseek = seq_lseek,
430 .release = single_release,
431};
432
Hemant Kumar7bf94262012-04-18 17:25:10 -0700433static int rmnet_usb_data_debugfs_init(struct usbnet *unet)
434{
Hemant Kumar90b1a472012-04-26 19:59:56 -0700435 struct dentry *rmnet_usb_data_dbg_root;
Hemant Kumar7bf94262012-04-18 17:25:10 -0700436 struct dentry *rmnet_usb_data_dentry;
437
438 rmnet_usb_data_dbg_root = debugfs_create_dir(unet->net->name, NULL);
Hemant Kumar7bf94262012-04-18 17:25:10 -0700439 if (!rmnet_usb_data_dbg_root || IS_ERR(rmnet_usb_data_dbg_root))
440 return -ENODEV;
441
442 rmnet_usb_data_dentry = debugfs_create_file("status",
443 S_IRUGO | S_IWUSR,
444 rmnet_usb_data_dbg_root, unet,
445 &rmnet_usb_data_fops);
446
447 if (!rmnet_usb_data_dentry) {
448 debugfs_remove_recursive(rmnet_usb_data_dbg_root);
449 return -ENODEV;
450 }
451
Hemant Kumar90b1a472012-04-26 19:59:56 -0700452 unet->data[2] = (unsigned long)rmnet_usb_data_dbg_root;
453
Hemant Kumar7bf94262012-04-18 17:25:10 -0700454 return 0;
455}
456
Hemant Kumar90b1a472012-04-26 19:59:56 -0700457static void rmnet_usb_data_debugfs_cleanup(struct usbnet *unet)
Hemant Kumar7bf94262012-04-18 17:25:10 -0700458{
Hemant Kumar90b1a472012-04-26 19:59:56 -0700459 struct dentry *root = (struct dentry *)unet->data[2];
460
461 debugfs_remove_recursive(root);
462 unet->data[2] = 0;
Hemant Kumar7bf94262012-04-18 17:25:10 -0700463}
464
Hemant Kumar37c35e42011-09-14 23:44:19 -0700465static int rmnet_usb_probe(struct usb_interface *iface,
466 const struct usb_device_id *prod)
467{
468 struct usbnet *unet;
Hemant Kumar9d6016c2012-01-05 16:27:24 -0800469 struct driver_info *info;
Jack Pham9bc736e2012-06-19 17:52:51 -0700470 struct usb_device *udev;
Hemant Kumar9d6016c2012-01-05 16:27:24 -0800471 unsigned int iface_num;
472 static int first_rmnet_iface_num = -EINVAL;
473 int status = 0;
Hemant Kumar37c35e42011-09-14 23:44:19 -0700474
Hemant Kumar37c35e42011-09-14 23:44:19 -0700475 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
476 if (iface->num_altsetting != 1) {
Jack Phame8741502012-06-13 17:34:07 -0700477 dev_err(&iface->dev, "%s invalid num_altsetting %u\n",
Hemant Kumar37c35e42011-09-14 23:44:19 -0700478 __func__, iface->num_altsetting);
479 status = -EINVAL;
480 goto out;
481 }
482
Hemant Kumar9d6016c2012-01-05 16:27:24 -0800483 info = (struct driver_info *)prod->driver_info;
484 if (!test_bit(iface_num, &info->data))
485 return -ENODEV;
Hemant Kumar37c35e42011-09-14 23:44:19 -0700486
Hemant Kumar9d6016c2012-01-05 16:27:24 -0800487 status = usbnet_probe(iface, prod);
488 if (status < 0) {
Jack Phame8741502012-06-13 17:34:07 -0700489 dev_err(&iface->dev, "usbnet_probe failed %d\n", status);
Hemant Kumar9d6016c2012-01-05 16:27:24 -0800490 goto out;
Hemant Kumar37c35e42011-09-14 23:44:19 -0700491 }
Hemant Kumar9d6016c2012-01-05 16:27:24 -0800492 unet = usb_get_intfdata(iface);
493
494 /*set rmnet operation mode to eth by default*/
495 set_bit(RMNET_MODE_LLP_ETH, &unet->data[0]);
496
497 /*update net device*/
498 rmnet_usb_setup(unet->net);
499
500 /*create /sys/class/net/rmnet_usbx/dbg_mask*/
501 status = device_create_file(&unet->net->dev, &dev_attr_dbg_mask);
502 if (status)
503 goto out;
504
505 if (first_rmnet_iface_num == -EINVAL)
506 first_rmnet_iface_num = iface_num;
507
508 /*save control device intstance */
509 unet->data[1] = (unsigned long)ctrl_dev \
510 [iface_num - first_rmnet_iface_num];
511
512 status = rmnet_usb_ctrl_probe(iface, unet->status,
513 (struct rmnet_ctrl_dev *)unet->data[1]);
Jack Pham42346cf2012-03-13 12:49:07 -0700514 if (status)
515 goto out;
516
Hemant Kumar7bf94262012-04-18 17:25:10 -0700517 status = rmnet_usb_data_debugfs_init(unet);
518 if (status)
Jack Phame8741502012-06-13 17:34:07 -0700519 dev_dbg(&iface->dev, "mode debugfs file is not available\n");
Hemant Kumar7bf94262012-04-18 17:25:10 -0700520
Jack Pham9bc736e2012-06-19 17:52:51 -0700521 udev = unet->udev;
522
Jack Phambf42e602012-07-03 13:02:37 -0700523 usb_enable_autosuspend(udev);
524
Jack Pham9bc736e2012-06-19 17:52:51 -0700525 if (udev->parent && !udev->parent->parent) {
Jack Pham14680cb2012-08-02 02:33:47 -0700526 /* allow modem and roothub to wake up suspended system */
527 device_set_wakeup_enable(&udev->dev, 1);
528 device_set_wakeup_enable(&udev->parent->dev, 1);
Jack Pham9bc736e2012-06-19 17:52:51 -0700529 }
530
Hemant Kumar37c35e42011-09-14 23:44:19 -0700531out:
532 return status;
533}
534
535static void rmnet_usb_disconnect(struct usb_interface *intf)
536{
537 struct usbnet *unet;
Hemant Kumar37c35e42011-09-14 23:44:19 -0700538 struct rmnet_ctrl_dev *dev;
Hemant Kumar37c35e42011-09-14 23:44:19 -0700539
Hemant Kumar9d6016c2012-01-05 16:27:24 -0800540 unet = usb_get_intfdata(intf);
541 if (!unet) {
Jack Phame8741502012-06-13 17:34:07 -0700542 dev_err(&intf->dev, "%s:data device not found\n", __func__);
Hemant Kumar9d6016c2012-01-05 16:27:24 -0800543 return;
Hemant Kumar37c35e42011-09-14 23:44:19 -0700544 }
Hemant Kumar9d6016c2012-01-05 16:27:24 -0800545
Jack Phame8741502012-06-13 17:34:07 -0700546 device_set_wakeup_enable(&unet->udev->dev, 0);
Hemant Kumar90b1a472012-04-26 19:59:56 -0700547 rmnet_usb_data_debugfs_cleanup(unet);
548
Hemant Kumar9d6016c2012-01-05 16:27:24 -0800549 dev = (struct rmnet_ctrl_dev *)unet->data[1];
550 if (!dev) {
Jack Phame8741502012-06-13 17:34:07 -0700551 dev_err(&intf->dev, "%s:ctrl device not found\n", __func__);
Hemant Kumar9d6016c2012-01-05 16:27:24 -0800552 return;
553 }
554 unet->data[0] = 0;
555 unet->data[1] = 0;
556 rmnet_usb_ctrl_disconnect(dev);
557 device_remove_file(&unet->net->dev, &dev_attr_dbg_mask);
558 usbnet_disconnect(intf);
Hemant Kumar37c35e42011-09-14 23:44:19 -0700559}
560
Hemant Kumar9d6016c2012-01-05 16:27:24 -0800561/*bit position represents interface number*/
562#define PID9034_IFACE_MASK 0xF0
563#define PID9048_IFACE_MASK 0x1E0
Hemant Kumarbf024812012-02-24 12:58:56 -0800564#define PID904C_IFACE_MASK 0x1C0
Hemant Kumar9d6016c2012-01-05 16:27:24 -0800565
566static const struct driver_info rmnet_info_pid9034 = {
Hemant Kumar37c35e42011-09-14 23:44:19 -0700567 .description = "RmNET net device",
Jack Pham5a10c6f2012-06-26 11:41:28 -0700568 .flags = FLAG_SEND_ZLP,
Hemant Kumar37c35e42011-09-14 23:44:19 -0700569 .bind = rmnet_usb_bind,
570 .tx_fixup = rmnet_usb_tx_fixup,
571 .rx_fixup = rmnet_usb_rx_fixup,
Jack Phamf77b9962012-02-23 18:45:43 -0800572 .manage_power = rmnet_usb_manage_power,
Hemant Kumar9d6016c2012-01-05 16:27:24 -0800573 .data = PID9034_IFACE_MASK,
574};
575
576static const struct driver_info rmnet_info_pid9048 = {
577 .description = "RmNET net device",
Jack Pham5a10c6f2012-06-26 11:41:28 -0700578 .flags = FLAG_SEND_ZLP,
Hemant Kumar9d6016c2012-01-05 16:27:24 -0800579 .bind = rmnet_usb_bind,
580 .tx_fixup = rmnet_usb_tx_fixup,
581 .rx_fixup = rmnet_usb_rx_fixup,
Jack Phamf77b9962012-02-23 18:45:43 -0800582 .manage_power = rmnet_usb_manage_power,
Hemant Kumar9d6016c2012-01-05 16:27:24 -0800583 .data = PID9048_IFACE_MASK,
Hemant Kumar37c35e42011-09-14 23:44:19 -0700584};
585
Hemant Kumarbf024812012-02-24 12:58:56 -0800586static const struct driver_info rmnet_info_pid904c = {
587 .description = "RmNET net device",
Jack Pham5a10c6f2012-06-26 11:41:28 -0700588 .flags = FLAG_SEND_ZLP,
Hemant Kumarbf024812012-02-24 12:58:56 -0800589 .bind = rmnet_usb_bind,
590 .tx_fixup = rmnet_usb_tx_fixup,
591 .rx_fixup = rmnet_usb_rx_fixup,
Jack Phamf77b9962012-02-23 18:45:43 -0800592 .manage_power = rmnet_usb_manage_power,
Hemant Kumarbf024812012-02-24 12:58:56 -0800593 .data = PID904C_IFACE_MASK,
594};
595
Hemant Kumar37c35e42011-09-14 23:44:19 -0700596static const struct usb_device_id vidpids[] = {
597 {
Hemant Kumar9d6016c2012-01-05 16:27:24 -0800598 USB_DEVICE(0x05c6, 0x9034), /* MDM9x15*/
599 .driver_info = (unsigned long)&rmnet_info_pid9034,
Hemant Kumar37c35e42011-09-14 23:44:19 -0700600 },
Hemant Kumar9d6016c2012-01-05 16:27:24 -0800601 {
602 USB_DEVICE(0x05c6, 0x9048), /* MDM9x15*/
603 .driver_info = (unsigned long)&rmnet_info_pid9048,
604 },
Hemant Kumarbf024812012-02-24 12:58:56 -0800605 {
606 USB_DEVICE(0x05c6, 0x904c), /* MDM9x15*/
607 .driver_info = (unsigned long)&rmnet_info_pid904c,
608 },
Hemant Kumar9d6016c2012-01-05 16:27:24 -0800609
610 { }, /* Terminating entry */
Hemant Kumar37c35e42011-09-14 23:44:19 -0700611};
612
613MODULE_DEVICE_TABLE(usb, vidpids);
614
615static struct usb_driver rmnet_usb = {
616 .name = "rmnet_usb",
617 .id_table = vidpids,
618 .probe = rmnet_usb_probe,
619 .disconnect = rmnet_usb_disconnect,
620 .suspend = rmnet_usb_suspend,
621 .resume = rmnet_usb_resume,
622 .supports_autosuspend = true,
623};
624
625static int __init rmnet_usb_init(void)
626{
627 int retval;
628
629 retval = usb_register(&rmnet_usb);
630 if (retval) {
631 err("usb_register failed: %d", retval);
632 return retval;
633 }
634 /* initialize rmnet ctrl device here*/
635 retval = rmnet_usb_ctrl_init();
636 if (retval) {
637 usb_deregister(&rmnet_usb);
638 err("rmnet_usb_cmux_init failed: %d", retval);
639 return retval;
640 }
641
642 return 0;
643}
644module_init(rmnet_usb_init);
645
646static void __exit rmnet_usb_exit(void)
647{
648 rmnet_usb_ctrl_exit();
649 usb_deregister(&rmnet_usb);
650}
651module_exit(rmnet_usb_exit);
652
653MODULE_DESCRIPTION("msm rmnet usb device");
654MODULE_LICENSE("GPL v2");