blob: 2972af00576ffe92343fcd35df4d1b87f4beea08 [file] [log] [blame]
Praveena Pachipulusu263467d2011-12-22 18:07:16 +05301/* Copyright (c) 2011-2012, Code Aurora Forum. 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
13#include <linux/slab.h>
14#include <linux/kernel.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070015#include <linux/module.h>
Hemant Kumar37c35e42011-09-14 23:44:19 -070016#include <linux/device.h>
17#include <linux/uaccess.h>
18#include <linux/termios.h>
19#include <linux/ratelimit.h>
20#include <linux/debugfs.h>
21#include "rmnet_usb_ctrl.h"
22
23#define DEVICE_NAME "hsicctl"
24#define NUM_CTRL_CHANNELS 4
25#define DEFAULT_READ_URB_LENGTH 0x1000
26
27/*Output control lines.*/
28#define ACM_CTRL_DTR BIT(0)
29#define ACM_CTRL_RTS BIT(1)
30
31
32/*Input control lines.*/
33#define ACM_CTRL_DSR BIT(0)
34#define ACM_CTRL_CTS BIT(1)
35#define ACM_CTRL_RI BIT(2)
36#define ACM_CTRL_CD BIT(3)
37
38/* polling interval for Interrupt ep */
39#define HS_INTERVAL 7
40#define FS_LS_INTERVAL 3
41
42/*echo modem_wait > /sys/class/hsicctl/hsicctlx/modem_wait*/
43static ssize_t modem_wait_store(struct device *d, struct device_attribute *attr,
44 const char *buf, size_t n)
45{
46 unsigned int mdm_wait;
47 struct rmnet_ctrl_dev *dev = dev_get_drvdata(d);
48
49 if (!dev)
50 return -ENODEV;
51
52 sscanf(buf, "%u", &mdm_wait);
53
54 dev->mdm_wait_timeout = mdm_wait;
55
56 return n;
57}
58
59static ssize_t modem_wait_show(struct device *d, struct device_attribute *attr,
60 char *buf)
61{
62 struct rmnet_ctrl_dev *dev = dev_get_drvdata(d);
63
64 if (!dev)
65 return -ENODEV;
66
67 return snprintf(buf, PAGE_SIZE, "%u\n", dev->mdm_wait_timeout);
68}
69
Praveena Pachipulusu263467d2011-12-22 18:07:16 +053070static DEVICE_ATTR(modem_wait, 0664, modem_wait_show, modem_wait_store);
Hemant Kumar37c35e42011-09-14 23:44:19 -070071
72static int ctl_msg_dbg_mask;
73module_param_named(dump_ctrl_msg, ctl_msg_dbg_mask, int,
74 S_IRUGO | S_IWUSR | S_IWGRP);
75
76enum {
77 MSM_USB_CTL_DEBUG = 1U << 0,
78 MSM_USB_CTL_DUMP_BUFFER = 1U << 1,
79};
80
81#define DUMP_BUFFER(prestr, cnt, buf) \
82do { \
83 if (ctl_msg_dbg_mask & MSM_USB_CTL_DUMP_BUFFER) \
84 print_hex_dump(KERN_INFO, prestr, DUMP_PREFIX_NONE, \
85 16, 1, buf, cnt, false); \
86} while (0)
87
88#define DBG(x...) \
89 do { \
90 if (ctl_msg_dbg_mask & MSM_USB_CTL_DEBUG) \
91 pr_info(x); \
92 } while (0)
93
94struct rmnet_ctrl_dev *ctrl_dev[NUM_CTRL_CHANNELS];
95struct class *ctrldev_classp;
96static dev_t ctrldev_num;
97
98struct ctrl_pkt {
99 size_t data_size;
100 void *data;
101};
102
103struct ctrl_pkt_list_elem {
104 struct list_head list;
105 struct ctrl_pkt cpkt;
106};
107
108static void resp_avail_cb(struct urb *);
109
110static int is_dev_connected(struct rmnet_ctrl_dev *dev)
111{
112 if (dev) {
113 mutex_lock(&dev->dev_lock);
Hemant Kumar4a466c32012-06-25 14:52:24 -0700114 if (!dev->is_connected) {
Hemant Kumar37c35e42011-09-14 23:44:19 -0700115 mutex_unlock(&dev->dev_lock);
116 return 0;
117 }
118 mutex_unlock(&dev->dev_lock);
119 return 1;
120 }
121 return 0;
122}
123
124static void notification_available_cb(struct urb *urb)
125{
126 int status;
127 struct usb_cdc_notification *ctrl;
128 struct usb_device *udev;
129 struct rmnet_ctrl_dev *dev = urb->context;
130
131 udev = interface_to_usbdev(dev->intf);
132
133 switch (urb->status) {
134 case 0:
135 /*success*/
136 break;
137
138 /*do not resubmit*/
139 case -ESHUTDOWN:
140 case -ENOENT:
141 case -ECONNRESET:
142 case -EPROTO:
143 return;
144 case -EPIPE:
145 pr_err_ratelimited("%s: Stall on int endpoint\n", __func__);
146 /* TBD : halt to be cleared in work */
147 return;
148
149 /*resubmit*/
150 case -EOVERFLOW:
151 pr_err_ratelimited("%s: Babble error happened\n", __func__);
152 default:
153 pr_debug_ratelimited("%s: Non zero urb status = %d\n",
154 __func__, urb->status);
155 goto resubmit_int_urb;
156 }
157
158 ctrl = urb->transfer_buffer;
159
160 switch (ctrl->bNotificationType) {
161 case USB_CDC_NOTIFY_RESPONSE_AVAILABLE:
162 dev->resp_avail_cnt++;
163 usb_fill_control_urb(dev->rcvurb, udev,
164 usb_rcvctrlpipe(udev, 0),
165 (unsigned char *)dev->in_ctlreq,
166 dev->rcvbuf,
167 DEFAULT_READ_URB_LENGTH,
168 resp_avail_cb, dev);
169
170 status = usb_submit_urb(dev->rcvurb, GFP_ATOMIC);
171 if (status) {
172 dev_err(dev->devicep,
173 "%s: Error submitting Read URB %d\n", __func__, status);
174 goto resubmit_int_urb;
175 }
176
Hemant Kumar2a700f32012-06-15 20:16:55 -0700177 usb_mark_last_busy(udev);
178
Hemant Kumar37c35e42011-09-14 23:44:19 -0700179 if (!dev->resp_available) {
180 dev->resp_available = true;
181 wake_up(&dev->open_wait_queue);
182 }
183
184 return;
185 default:
186 dev_err(dev->devicep,
187 "%s:Command not implemented\n", __func__);
188 }
189
190resubmit_int_urb:
191 status = usb_submit_urb(urb, GFP_ATOMIC);
192 if (status)
193 dev_err(dev->devicep, "%s: Error re-submitting Int URB %d\n",
194 __func__, status);
195
196 return;
197}
198
199static void resp_avail_cb(struct urb *urb)
200{
201 struct usb_device *udev;
202 struct ctrl_pkt_list_elem *list_elem = NULL;
203 struct rmnet_ctrl_dev *dev = urb->context;
204 void *cpkt;
205 int status = 0;
206 size_t cpkt_size = 0;
207
208 udev = interface_to_usbdev(dev->intf);
209
210 switch (urb->status) {
211 case 0:
212 /*success*/
213 dev->get_encap_resp_cnt++;
214 break;
215
216 /*do not resubmit*/
217 case -ESHUTDOWN:
218 case -ENOENT:
219 case -ECONNRESET:
220 case -EPROTO:
221 return;
222
223 /*resubmit*/
224 case -EOVERFLOW:
225 pr_err_ratelimited("%s: Babble error happened\n", __func__);
226 default:
227 pr_debug_ratelimited("%s: Non zero urb status = %d\n",
228 __func__, urb->status);
229 goto resubmit_int_urb;
230 }
231
232 dev_dbg(dev->devicep, "Read %d bytes for %s\n",
233 urb->actual_length, dev->name);
234
235 cpkt = urb->transfer_buffer;
236 cpkt_size = urb->actual_length;
Hemant Kumare1757762012-04-13 16:53:09 -0700237 if (!cpkt_size) {
238 dev->zlp_cnt++;
239 dev_dbg(dev->devicep, "%s: zero length pkt received\n",
240 __func__);
241 goto resubmit_int_urb;
242 }
Hemant Kumar37c35e42011-09-14 23:44:19 -0700243
244 list_elem = kmalloc(sizeof(struct ctrl_pkt_list_elem), GFP_ATOMIC);
245 if (!list_elem) {
246 dev_err(dev->devicep, "%s: list_elem alloc failed\n", __func__);
247 return;
248 }
249 list_elem->cpkt.data = kmalloc(cpkt_size, GFP_ATOMIC);
250 if (!list_elem->cpkt.data) {
251 dev_err(dev->devicep, "%s: list_elem->data alloc failed\n",
252 __func__);
253 kfree(list_elem);
254 return;
255 }
256 memcpy(list_elem->cpkt.data, cpkt, cpkt_size);
257 list_elem->cpkt.data_size = cpkt_size;
258 spin_lock(&dev->rx_lock);
259 list_add_tail(&list_elem->list, &dev->rx_list);
260 spin_unlock(&dev->rx_lock);
261
262 wake_up(&dev->read_wait_queue);
263
264resubmit_int_urb:
265 /*re-submit int urb to check response available*/
Hemant Kumar2a700f32012-06-15 20:16:55 -0700266 usb_mark_last_busy(udev);
Hemant Kumar37c35e42011-09-14 23:44:19 -0700267 status = usb_submit_urb(dev->inturb, GFP_ATOMIC);
268 if (status)
269 dev_err(dev->devicep, "%s: Error re-submitting Int URB %d\n",
270 __func__, status);
271}
272
273static int rmnet_usb_ctrl_start_rx(struct rmnet_ctrl_dev *dev)
274{
275 int retval = 0;
276
Hemant Kumar37c35e42011-09-14 23:44:19 -0700277 retval = usb_submit_urb(dev->inturb, GFP_KERNEL);
278 if (retval < 0)
279 dev_err(dev->devicep, "%s Intr submit %d\n", __func__, retval);
280
Hemant Kumar37c35e42011-09-14 23:44:19 -0700281 return retval;
282}
283
284int rmnet_usb_ctrl_stop_rx(struct rmnet_ctrl_dev *dev)
285{
286 if (!is_dev_connected(dev)) {
287 dev_dbg(dev->devicep, "%s: Ctrl device disconnected\n",
288 __func__);
289 return -ENODEV;
290 }
291
292 dev_dbg(dev->devicep, "%s\n", __func__);
293
294 usb_kill_urb(dev->rcvurb);
295 usb_kill_urb(dev->inturb);
296
297 return 0;
298}
299
300int rmnet_usb_ctrl_start(struct rmnet_ctrl_dev *dev)
301{
302 int status = 0;
303
304 mutex_lock(&dev->dev_lock);
305 if (dev->is_opened)
306 status = rmnet_usb_ctrl_start_rx(dev);
307 mutex_unlock(&dev->dev_lock);
308
309 return status;
310}
311
312static int rmnet_usb_ctrl_alloc_rx(struct rmnet_ctrl_dev *dev)
313{
314 int retval = -ENOMEM;
315
316 dev->rcvurb = usb_alloc_urb(0, GFP_KERNEL);
317 if (!dev->rcvurb) {
318 pr_err("%s: Error allocating read urb\n", __func__);
319 goto nomem;
320 }
321
322 dev->rcvbuf = kmalloc(DEFAULT_READ_URB_LENGTH, GFP_KERNEL);
323 if (!dev->rcvbuf) {
324 pr_err("%s: Error allocating read buffer\n", __func__);
325 goto nomem;
326 }
327
328 dev->in_ctlreq = kmalloc(sizeof(*dev->in_ctlreq), GFP_KERNEL);
329 if (!dev->in_ctlreq) {
330 pr_err("%s: Error allocating setup packet buffer\n", __func__);
331 goto nomem;
332 }
333
334 return 0;
335
336nomem:
337 usb_free_urb(dev->rcvurb);
338 kfree(dev->rcvbuf);
339 kfree(dev->in_ctlreq);
340
341 return retval;
342
343}
344static int rmnet_usb_ctrl_write_cmd(struct rmnet_ctrl_dev *dev)
345{
Hemant Kumar37c35e42011-09-14 23:44:19 -0700346 struct usb_device *udev;
347
348 if (!is_dev_connected(dev))
349 return -ENODEV;
350
351 udev = interface_to_usbdev(dev->intf);
Hemant Kumar37c35e42011-09-14 23:44:19 -0700352 dev->set_ctrl_line_state_cnt++;
Jack Phamf77b9962012-02-23 18:45:43 -0800353 return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
Hemant Kumar37c35e42011-09-14 23:44:19 -0700354 USB_CDC_REQ_SET_CONTROL_LINE_STATE,
355 (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE),
356 dev->cbits_tomdm,
357 dev->intf->cur_altsetting->desc.bInterfaceNumber,
358 NULL, 0, USB_CTRL_SET_TIMEOUT);
Hemant Kumar37c35e42011-09-14 23:44:19 -0700359}
360
361static void ctrl_write_callback(struct urb *urb)
362{
363 struct rmnet_ctrl_dev *dev = urb->context;
364
365 if (urb->status) {
366 dev->tx_ctrl_err_cnt++;
367 pr_debug_ratelimited("Write status/size %d/%d\n",
368 urb->status, urb->actual_length);
369 }
370
371 kfree(urb->setup_packet);
372 kfree(urb->transfer_buffer);
373 usb_free_urb(urb);
374 usb_autopm_put_interface_async(dev->intf);
375}
376
377static int rmnet_usb_ctrl_write(struct rmnet_ctrl_dev *dev, char *buf,
378 size_t size)
379{
380 int result;
381 struct urb *sndurb;
382 struct usb_ctrlrequest *out_ctlreq;
383 struct usb_device *udev;
384
385 if (!is_dev_connected(dev))
386 return -ENETRESET;
387
388 udev = interface_to_usbdev(dev->intf);
389
390 sndurb = usb_alloc_urb(0, GFP_KERNEL);
391 if (!sndurb) {
392 dev_err(dev->devicep, "Error allocating read urb\n");
393 return -ENOMEM;
394 }
395
396 out_ctlreq = kmalloc(sizeof(*out_ctlreq), GFP_KERNEL);
397 if (!out_ctlreq) {
398 usb_free_urb(sndurb);
399 dev_err(dev->devicep, "Error allocating setup packet buffer\n");
400 return -ENOMEM;
401 }
402
403 /* CDC Send Encapsulated Request packet */
404 out_ctlreq->bRequestType = (USB_DIR_OUT | USB_TYPE_CLASS |
405 USB_RECIP_INTERFACE);
406 out_ctlreq->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND;
407 out_ctlreq->wValue = 0;
408 out_ctlreq->wIndex = dev->intf->cur_altsetting->desc.bInterfaceNumber;
409 out_ctlreq->wLength = cpu_to_le16(size);
410
411 usb_fill_control_urb(sndurb, udev,
412 usb_sndctrlpipe(udev, 0),
413 (unsigned char *)out_ctlreq, (void *)buf, size,
414 ctrl_write_callback, dev);
415
Jack Phamf77b9962012-02-23 18:45:43 -0800416 result = usb_autopm_get_interface(dev->intf);
Hemant Kumar37c35e42011-09-14 23:44:19 -0700417 if (result < 0) {
418 dev_err(dev->devicep, "%s: Unable to resume interface: %d\n",
419 __func__, result);
420
421 /*
422 * Revisit: if (result == -EPERM)
423 * rmnet_usb_suspend(dev->intf, PMSG_SUSPEND);
424 */
425
426 usb_free_urb(sndurb);
427 kfree(out_ctlreq);
428 return result;
429 }
430
431 usb_anchor_urb(sndurb, &dev->tx_submitted);
432 dev->snd_encap_cmd_cnt++;
433 result = usb_submit_urb(sndurb, GFP_KERNEL);
434 if (result < 0) {
435 dev_err(dev->devicep, "%s: Submit URB error %d\n",
436 __func__, result);
437 dev->snd_encap_cmd_cnt--;
Jack Phamf77b9962012-02-23 18:45:43 -0800438 usb_autopm_put_interface(dev->intf);
Hemant Kumar37c35e42011-09-14 23:44:19 -0700439 usb_unanchor_urb(sndurb);
440 usb_free_urb(sndurb);
441 kfree(out_ctlreq);
442 return result;
443 }
444
445 return size;
446}
447
448static int rmnet_ctl_open(struct inode *inode, struct file *file)
449{
450 int retval = 0;
451 struct rmnet_ctrl_dev *dev =
452 container_of(inode->i_cdev, struct rmnet_ctrl_dev, cdev);
453
454 if (!dev)
455 return -ENODEV;
456
457 if (dev->is_opened)
458 goto already_opened;
459
Hemant Kumar37c35e42011-09-14 23:44:19 -0700460 /*block open to get first response available from mdm*/
461 if (dev->mdm_wait_timeout && !dev->resp_available) {
462 retval = wait_event_interruptible_timeout(
463 dev->open_wait_queue,
Hemant Kumard08c2762012-04-19 19:49:12 -0700464 dev->resp_available,
Hemant Kumar37c35e42011-09-14 23:44:19 -0700465 msecs_to_jiffies(dev->mdm_wait_timeout *
466 1000));
467 if (retval == 0) {
468 dev_err(dev->devicep, "%s: Timeout opening %s\n",
469 __func__, dev->name);
470 return -ETIMEDOUT;
471 } else if (retval < 0) {
472 dev_err(dev->devicep, "%s: Error waiting for %s\n",
473 __func__, dev->name);
474 return retval;
475 }
Hemant Kumar37c35e42011-09-14 23:44:19 -0700476 }
477
478 if (!dev->resp_available) {
479 dev_dbg(dev->devicep, "%s: Connection timedout opening %s\n",
480 __func__, dev->name);
481 return -ETIMEDOUT;
482 }
483
484 mutex_lock(&dev->dev_lock);
485 dev->is_opened = 1;
486 mutex_unlock(&dev->dev_lock);
487
488 file->private_data = dev;
489
490already_opened:
491 DBG("%s: Open called for %s\n", __func__, dev->name);
492
493 return 0;
494}
495
496static int rmnet_ctl_release(struct inode *inode, struct file *file)
497{
498 struct ctrl_pkt_list_elem *list_elem = NULL;
499 struct rmnet_ctrl_dev *dev;
500 unsigned long flag;
501
502 dev = file->private_data;
503 if (!dev)
504 return -ENODEV;
505
506 DBG("%s Called on %s device\n", __func__, dev->name);
507
508 spin_lock_irqsave(&dev->rx_lock, flag);
509 while (!list_empty(&dev->rx_list)) {
510 list_elem = list_first_entry(
511 &dev->rx_list,
512 struct ctrl_pkt_list_elem,
513 list);
514 list_del(&list_elem->list);
515 kfree(list_elem->cpkt.data);
516 kfree(list_elem);
517 }
518 spin_unlock_irqrestore(&dev->rx_lock, flag);
519
520 mutex_lock(&dev->dev_lock);
521 dev->is_opened = 0;
522 mutex_unlock(&dev->dev_lock);
523
Hemant Kumar37c35e42011-09-14 23:44:19 -0700524 if (is_dev_connected(dev))
525 usb_kill_anchored_urbs(&dev->tx_submitted);
526
527 file->private_data = NULL;
528
529 return 0;
530}
531
532static ssize_t rmnet_ctl_read(struct file *file, char __user *buf, size_t count,
533 loff_t *ppos)
534{
535 int retval = 0;
536 int bytes_to_read;
537 struct rmnet_ctrl_dev *dev;
538 struct ctrl_pkt_list_elem *list_elem = NULL;
539 unsigned long flags;
540
541 dev = file->private_data;
542 if (!dev)
543 return -ENODEV;
544
545 DBG("%s: Read from %s\n", __func__, dev->name);
546
547ctrl_read:
548 if (!is_dev_connected(dev)) {
Hemant Kumar4fa3ac52012-02-29 18:09:23 -0800549 dev_dbg(dev->devicep, "%s: Device not connected\n",
Hemant Kumar37c35e42011-09-14 23:44:19 -0700550 __func__);
551 return -ENETRESET;
552 }
553 spin_lock_irqsave(&dev->rx_lock, flags);
554 if (list_empty(&dev->rx_list)) {
555 spin_unlock_irqrestore(&dev->rx_lock, flags);
556
557 retval = wait_event_interruptible(dev->read_wait_queue,
558 !list_empty(&dev->rx_list) ||
559 !is_dev_connected(dev));
560 if (retval < 0)
561 return retval;
562
563 goto ctrl_read;
564 }
565
566 list_elem = list_first_entry(&dev->rx_list,
567 struct ctrl_pkt_list_elem, list);
568 bytes_to_read = (uint32_t)(list_elem->cpkt.data_size);
569 if (bytes_to_read > count) {
570 spin_unlock_irqrestore(&dev->rx_lock, flags);
571 dev_err(dev->devicep, "%s: Packet size %d > buf size %d\n",
572 __func__, bytes_to_read, count);
573 return -ENOMEM;
574 }
575 spin_unlock_irqrestore(&dev->rx_lock, flags);
576
577 if (copy_to_user(buf, list_elem->cpkt.data, bytes_to_read)) {
578 dev_err(dev->devicep,
579 "%s: copy_to_user failed for %s\n",
580 __func__, dev->name);
581 return -EFAULT;
582 }
583 spin_lock_irqsave(&dev->rx_lock, flags);
584 list_del(&list_elem->list);
585 spin_unlock_irqrestore(&dev->rx_lock, flags);
586
587 kfree(list_elem->cpkt.data);
588 kfree(list_elem);
589 DBG("%s: Returning %d bytes to %s\n", __func__, bytes_to_read,
590 dev->name);
591 DUMP_BUFFER("Read: ", bytes_to_read, buf);
592
593 return bytes_to_read;
594}
595
596static ssize_t rmnet_ctl_write(struct file *file, const char __user * buf,
597 size_t size, loff_t *pos)
598{
599 int status;
600 void *wbuf;
601 struct rmnet_ctrl_dev *dev = file->private_data;
602
603 if (!dev)
604 return -ENODEV;
605
606 if (size <= 0)
607 return -EINVAL;
608
609 if (!is_dev_connected(dev))
610 return -ENETRESET;
611
612 DBG("%s: Writing %i bytes on %s\n", __func__, size, dev->name);
613
614 wbuf = kmalloc(size , GFP_KERNEL);
615 if (!wbuf)
616 return -ENOMEM;
617
618 status = copy_from_user(wbuf , buf, size);
619 if (status) {
620 dev_err(dev->devicep,
621 "%s: Unable to copy data from userspace %d\n",
622 __func__, status);
623 kfree(wbuf);
624 return status;
625 }
626 DUMP_BUFFER("Write: ", size, buf);
627
628 status = rmnet_usb_ctrl_write(dev, wbuf, size);
629 if (status == size)
630 return size;
631
632 return status;
633}
634
635static int rmnet_ctrl_tiocmset(struct rmnet_ctrl_dev *dev, unsigned int set,
636 unsigned int clear)
637{
Jack Phamf77b9962012-02-23 18:45:43 -0800638 int retval;
639
Hemant Kumar37c35e42011-09-14 23:44:19 -0700640 mutex_lock(&dev->dev_lock);
641 if (set & TIOCM_DTR)
642 dev->cbits_tomdm |= ACM_CTRL_DTR;
643
644 /*
645 * TBD if (set & TIOCM_RTS)
646 * dev->cbits_tomdm |= ACM_CTRL_RTS;
647 */
648
649 if (clear & TIOCM_DTR)
650 dev->cbits_tomdm &= ~ACM_CTRL_DTR;
651
652 /*
653 * (clear & TIOCM_RTS)
654 * dev->cbits_tomdm &= ~ACM_CTRL_RTS;
655 */
656
657 mutex_unlock(&dev->dev_lock);
658
Jack Phamf77b9962012-02-23 18:45:43 -0800659 retval = usb_autopm_get_interface(dev->intf);
660 if (retval < 0) {
661 dev_err(dev->devicep, "%s: Unable to resume interface: %d\n",
662 __func__, retval);
663 return retval;
664 }
665
666 retval = rmnet_usb_ctrl_write_cmd(dev);
667
668 usb_autopm_put_interface(dev->intf);
669 return retval;
Hemant Kumar37c35e42011-09-14 23:44:19 -0700670}
671
672static int rmnet_ctrl_tiocmget(struct rmnet_ctrl_dev *dev)
673{
674 int ret;
675
676 mutex_lock(&dev->dev_lock);
677 ret =
678 /*
679 * TBD(dev->cbits_tolocal & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
680 * (dev->cbits_tolocal & ACM_CTRL_CTS ? TIOCM_CTS : 0) |
681 */
682 (dev->cbits_tolocal & ACM_CTRL_CD ? TIOCM_CD : 0) |
683 /*
684 * TBD (dev->cbits_tolocal & ACM_CTRL_RI ? TIOCM_RI : 0) |
685 *(dev->cbits_tomdm & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
686 */
687 (dev->cbits_tomdm & ACM_CTRL_DTR ? TIOCM_DTR : 0);
688 mutex_unlock(&dev->dev_lock);
689
690 return ret;
691}
692
693static long rmnet_ctrl_ioctl(struct file *file, unsigned int cmd,
694 unsigned long arg)
695{
696 int ret;
697 struct rmnet_ctrl_dev *dev;
698
699 dev = file->private_data;
700 if (!dev)
701 return -ENODEV;
702
703 switch (cmd) {
704 case TIOCMGET:
705
706 ret = rmnet_ctrl_tiocmget(dev);
707 break;
708 case TIOCMSET:
709 ret = rmnet_ctrl_tiocmset(dev, arg, ~arg);
710 break;
711 default:
712 ret = -EINVAL;
713 }
714
715 return ret;
716}
717
718static const struct file_operations ctrldev_fops = {
719 .owner = THIS_MODULE,
720 .read = rmnet_ctl_read,
721 .write = rmnet_ctl_write,
722 .unlocked_ioctl = rmnet_ctrl_ioctl,
723 .open = rmnet_ctl_open,
724 .release = rmnet_ctl_release,
725};
726
727int rmnet_usb_ctrl_probe(struct usb_interface *intf,
728 struct usb_host_endpoint *int_in, struct rmnet_ctrl_dev *dev)
729{
730 u16 wMaxPacketSize;
731 struct usb_endpoint_descriptor *ep;
732 struct usb_device *udev;
733 int interval;
734 int ret = 0;
735
736 udev = interface_to_usbdev(intf);
737
738 if (!dev) {
739 pr_err("%s: Ctrl device not found\n", __func__);
740 return -ENODEV;
741 }
742 dev->int_pipe = usb_rcvintpipe(udev,
743 int_in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
744
745 mutex_lock(&dev->dev_lock);
746 dev->intf = intf;
747
748 /*TBD: for now just update CD status*/
749 dev->cbits_tolocal = ACM_CTRL_CD;
750
751 /*send DTR high to modem*/
752 dev->cbits_tomdm = ACM_CTRL_DTR;
753 mutex_unlock(&dev->dev_lock);
754
755 dev->resp_available = false;
756 dev->snd_encap_cmd_cnt = 0;
757 dev->get_encap_resp_cnt = 0;
758 dev->resp_avail_cnt = 0;
759 dev->tx_ctrl_err_cnt = 0;
760 dev->set_ctrl_line_state_cnt = 0;
761
Hemant Kumar4a466c32012-06-25 14:52:24 -0700762 ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
763 USB_CDC_REQ_SET_CONTROL_LINE_STATE,
764 (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE),
765 dev->cbits_tomdm,
766 dev->intf->cur_altsetting->desc.bInterfaceNumber,
767 NULL, 0, USB_CTRL_SET_TIMEOUT);
Jack Phamf77b9962012-02-23 18:45:43 -0800768 if (ret < 0)
769 return ret;
770
Hemant Kumar4a466c32012-06-25 14:52:24 -0700771 dev->set_ctrl_line_state_cnt++;
772
Hemant Kumar37c35e42011-09-14 23:44:19 -0700773 dev->inturb = usb_alloc_urb(0, GFP_KERNEL);
774 if (!dev->inturb) {
775 dev_err(dev->devicep, "Error allocating int urb\n");
776 return -ENOMEM;
777 }
778
779 /*use max pkt size from ep desc*/
780 ep = &dev->intf->cur_altsetting->endpoint[0].desc;
781 wMaxPacketSize = le16_to_cpu(ep->wMaxPacketSize);
782
783 dev->intbuf = kmalloc(wMaxPacketSize, GFP_KERNEL);
784 if (!dev->intbuf) {
785 usb_free_urb(dev->inturb);
786 dev_err(dev->devicep, "Error allocating int buffer\n");
787 return -ENOMEM;
788 }
789
790 dev->in_ctlreq->bRequestType =
791 (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
792 dev->in_ctlreq->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE;
793 dev->in_ctlreq->wValue = 0;
794 dev->in_ctlreq->wIndex =
795 dev->intf->cur_altsetting->desc.bInterfaceNumber;
796 dev->in_ctlreq->wLength = cpu_to_le16(DEFAULT_READ_URB_LENGTH);
797
Jack Phamf77b9962012-02-23 18:45:43 -0800798 interval = max((int)int_in->desc.bInterval,
799 (udev->speed == USB_SPEED_HIGH) ? HS_INTERVAL
800 : FS_LS_INTERVAL);
Hemant Kumar37c35e42011-09-14 23:44:19 -0700801
802 usb_fill_int_urb(dev->inturb, udev,
803 dev->int_pipe,
804 dev->intbuf, wMaxPacketSize,
805 notification_available_cb, dev, interval);
806
Hemant Kumar2a700f32012-06-15 20:16:55 -0700807 usb_mark_last_busy(udev);
Hemant Kumar4a466c32012-06-25 14:52:24 -0700808 ret = rmnet_usb_ctrl_start_rx(dev);
809 if (!ret)
810 dev->is_connected = true;
811
812 return ret;
Hemant Kumar37c35e42011-09-14 23:44:19 -0700813}
814
815void rmnet_usb_ctrl_disconnect(struct rmnet_ctrl_dev *dev)
816{
817 rmnet_usb_ctrl_stop_rx(dev);
818
819 mutex_lock(&dev->dev_lock);
820
821 /*TBD: for now just update CD status*/
822 dev->cbits_tolocal = ~ACM_CTRL_CD;
823
824 dev->cbits_tomdm = ~ACM_CTRL_DTR;
Hemant Kumar4a466c32012-06-25 14:52:24 -0700825 dev->is_connected = false;
Hemant Kumar37c35e42011-09-14 23:44:19 -0700826 mutex_unlock(&dev->dev_lock);
827
Hemant Kumar4fa3ac52012-02-29 18:09:23 -0800828 wake_up(&dev->read_wait_queue);
829
Hemant Kumar37c35e42011-09-14 23:44:19 -0700830 usb_free_urb(dev->inturb);
831 dev->inturb = NULL;
832
833 kfree(dev->intbuf);
834 dev->intbuf = NULL;
835
836 usb_kill_anchored_urbs(&dev->tx_submitted);
837}
838
839#if defined(CONFIG_DEBUG_FS)
Hemant Kumar889bf232012-04-16 14:36:05 -0700840#define DEBUG_BUF_SIZE 4096
Hemant Kumar37c35e42011-09-14 23:44:19 -0700841static ssize_t rmnet_usb_ctrl_read_stats(struct file *file, char __user *ubuf,
842 size_t count, loff_t *ppos)
843{
844 struct rmnet_ctrl_dev *dev;
845 char *buf;
846 int ret;
847 int i;
848 int temp = 0;
849
850 buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
851 if (!buf)
852 return -ENOMEM;
853
854 for (i = 0; i < NUM_CTRL_CHANNELS; i++) {
855 dev = ctrl_dev[i];
856 if (!dev)
857 continue;
858
859 temp += scnprintf(buf + temp, DEBUG_BUF_SIZE - temp,
860 "\n#ctrl_dev: %p Name: %s#\n"
861 "snd encap cmd cnt %u\n"
862 "resp avail cnt: %u\n"
863 "get encap resp cnt: %u\n"
864 "set ctrl line state cnt: %u\n"
865 "tx_err_cnt: %u\n"
866 "cbits_tolocal: %d\n"
867 "cbits_tomdm: %d\n"
868 "mdm_wait_timeout: %u\n"
Hemant Kumare1757762012-04-13 16:53:09 -0700869 "zlp_cnt: %u\n"
Hemant Kumar37c35e42011-09-14 23:44:19 -0700870 "dev opened: %s\n",
871 dev, dev->name,
872 dev->snd_encap_cmd_cnt,
873 dev->resp_avail_cnt,
874 dev->get_encap_resp_cnt,
875 dev->set_ctrl_line_state_cnt,
876 dev->tx_ctrl_err_cnt,
877 dev->cbits_tolocal,
878 dev->cbits_tomdm,
879 dev->mdm_wait_timeout,
Hemant Kumare1757762012-04-13 16:53:09 -0700880 dev->zlp_cnt,
Hemant Kumar37c35e42011-09-14 23:44:19 -0700881 dev->is_opened ? "OPEN" : "CLOSE");
882
883 }
884
885 ret = simple_read_from_buffer(ubuf, count, ppos, buf, temp);
886
887 kfree(buf);
888
889 return ret;
890}
891
892static ssize_t rmnet_usb_ctrl_reset_stats(struct file *file, const char __user *
893 buf, size_t count, loff_t *ppos)
894{
895 struct rmnet_ctrl_dev *dev;
896 int i;
897
898 for (i = 0; i < NUM_CTRL_CHANNELS; i++) {
899 dev = ctrl_dev[i];
900 if (!dev)
901 continue;
902
903 dev->snd_encap_cmd_cnt = 0;
904 dev->resp_avail_cnt = 0;
905 dev->get_encap_resp_cnt = 0;
906 dev->set_ctrl_line_state_cnt = 0;
907 dev->tx_ctrl_err_cnt = 0;
Hemant Kumare1757762012-04-13 16:53:09 -0700908 dev->zlp_cnt = 0;
Hemant Kumar37c35e42011-09-14 23:44:19 -0700909 }
910 return count;
911}
912
913const struct file_operations rmnet_usb_ctrl_stats_ops = {
914 .read = rmnet_usb_ctrl_read_stats,
915 .write = rmnet_usb_ctrl_reset_stats,
916};
917
918struct dentry *usb_ctrl_dent;
919struct dentry *usb_ctrl_dfile;
920static void rmnet_usb_ctrl_debugfs_init(void)
921{
922 usb_ctrl_dent = debugfs_create_dir("rmnet_usb_ctrl", 0);
923 if (IS_ERR(usb_ctrl_dent))
924 return;
925
926 usb_ctrl_dfile = debugfs_create_file("status", 0644, usb_ctrl_dent, 0,
927 &rmnet_usb_ctrl_stats_ops);
928 if (!usb_ctrl_dfile || IS_ERR(usb_ctrl_dfile))
929 debugfs_remove(usb_ctrl_dent);
930}
931
932static void rmnet_usb_ctrl_debugfs_exit(void)
933{
934 debugfs_remove(usb_ctrl_dfile);
935 debugfs_remove(usb_ctrl_dent);
936}
937
938#else
939static void rmnet_usb_ctrl_debugfs_init(void) { }
940static void rmnet_usb_ctrl_debugfs_exit(void) { }
941#endif
942
943int rmnet_usb_ctrl_init(void)
944{
945 struct rmnet_ctrl_dev *dev;
946 int n;
947 int status;
948
949 for (n = 0; n < NUM_CTRL_CHANNELS; ++n) {
950
951 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
952 if (!dev) {
953 status = -ENOMEM;
954 goto error0;
955 }
956 /*for debug purpose*/
957 snprintf(dev->name, CTRL_DEV_MAX_LEN, "hsicctl%d", n);
958
959 mutex_init(&dev->dev_lock);
960 spin_lock_init(&dev->rx_lock);
961 init_waitqueue_head(&dev->read_wait_queue);
962 init_waitqueue_head(&dev->open_wait_queue);
963 INIT_LIST_HEAD(&dev->rx_list);
964 init_usb_anchor(&dev->tx_submitted);
965
966 status = rmnet_usb_ctrl_alloc_rx(dev);
967 if (status < 0) {
968 kfree(dev);
969 goto error0;
970 }
971
972 ctrl_dev[n] = dev;
973 }
974
975 status = alloc_chrdev_region(&ctrldev_num, 0, NUM_CTRL_CHANNELS,
976 DEVICE_NAME);
977 if (IS_ERR_VALUE(status)) {
978 pr_err("ERROR:%s: alloc_chrdev_region() ret %i.\n",
979 __func__, status);
980 goto error0;
981 }
982
983 ctrldev_classp = class_create(THIS_MODULE, DEVICE_NAME);
984 if (IS_ERR(ctrldev_classp)) {
985 pr_err("ERROR:%s: class_create() ENOMEM\n", __func__);
986 status = -ENOMEM;
987 goto error1;
988 }
989 for (n = 0; n < NUM_CTRL_CHANNELS; ++n) {
990 cdev_init(&ctrl_dev[n]->cdev, &ctrldev_fops);
991 ctrl_dev[n]->cdev.owner = THIS_MODULE;
992
993 status = cdev_add(&ctrl_dev[n]->cdev, (ctrldev_num + n), 1);
994
995 if (IS_ERR_VALUE(status)) {
996 pr_err("%s: cdev_add() ret %i\n", __func__, status);
997 kfree(ctrl_dev[n]);
998 goto error2;
999 }
1000
1001 ctrl_dev[n]->devicep =
1002 device_create(ctrldev_classp, NULL,
1003 (ctrldev_num + n), NULL,
1004 DEVICE_NAME "%d", n);
1005
1006 if (IS_ERR(ctrl_dev[n]->devicep)) {
1007 pr_err("%s: device_create() ENOMEM\n", __func__);
1008 status = -ENOMEM;
1009 cdev_del(&ctrl_dev[n]->cdev);
1010 kfree(ctrl_dev[n]);
1011 goto error2;
1012 }
1013 /*create /sys/class/hsicctl/hsicctlx/modem_wait*/
1014 status = device_create_file(ctrl_dev[n]->devicep,
1015 &dev_attr_modem_wait);
1016 if (status) {
1017 device_destroy(ctrldev_classp,
1018 MKDEV(MAJOR(ctrldev_num), n));
1019 cdev_del(&ctrl_dev[n]->cdev);
1020 kfree(ctrl_dev[n]);
1021 goto error2;
1022 }
1023 dev_set_drvdata(ctrl_dev[n]->devicep, ctrl_dev[n]);
1024 }
1025
1026 rmnet_usb_ctrl_debugfs_init();
1027 pr_info("rmnet usb ctrl Initialized.\n");
1028 return 0;
1029
1030error2:
1031 while (--n >= 0) {
1032 cdev_del(&ctrl_dev[n]->cdev);
1033 device_destroy(ctrldev_classp,
1034 MKDEV(MAJOR(ctrldev_num), n));
1035 }
1036
1037 class_destroy(ctrldev_classp);
1038 n = NUM_CTRL_CHANNELS;
1039error1:
1040 unregister_chrdev_region(MAJOR(ctrldev_num), NUM_CTRL_CHANNELS);
1041error0:
1042 while (--n >= 0)
1043 kfree(ctrl_dev[n]);
1044
1045 return status;
1046}
1047
1048void rmnet_usb_ctrl_exit(void)
1049{
1050 int i;
1051
1052 for (i = 0; i < NUM_CTRL_CHANNELS; ++i) {
1053 if (!ctrl_dev[i])
1054 return;
1055
1056 kfree(ctrl_dev[i]->in_ctlreq);
1057 kfree(ctrl_dev[i]->rcvbuf);
1058 kfree(ctrl_dev[i]->intbuf);
1059 usb_free_urb(ctrl_dev[i]->rcvurb);
1060 usb_free_urb(ctrl_dev[i]->inturb);
1061#if defined(DEBUG)
1062 device_remove_file(ctrl_dev[i]->devicep, &dev_attr_modem_wait);
1063#endif
1064 cdev_del(&ctrl_dev[i]->cdev);
1065 kfree(ctrl_dev[i]);
1066 ctrl_dev[i] = NULL;
1067 device_destroy(ctrldev_classp, MKDEV(MAJOR(ctrldev_num), i));
1068 }
1069
1070 class_destroy(ctrldev_classp);
1071 unregister_chrdev_region(MAJOR(ctrldev_num), NUM_CTRL_CHANNELS);
1072 rmnet_usb_ctrl_debugfs_exit();
1073}