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