blob: fc159cc235a7d9f1ce06128bb8a02a46a3249dcd [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/*
2 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/kernel.h>
15#include <linux/interrupt.h>
16#include <linux/device.h>
17#include <linux/delay.h>
18#include <linux/slab.h>
19#include <linux/termios.h>
20#include <mach/msm_smd.h>
21#include <linux/debugfs.h>
22#include <linux/bitops.h>
23#include <linux/termios.h>
24
25#include "u_rmnet.h"
26
Manu Gautam2b0234a2011-09-07 16:47:52 +053027#define NR_CTRL_SMD_PORTS 1
28static int n_rmnet_ctrl_ports;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070029static char *rmnet_ctrl_names[] = { "DATA40_CNTL" };
30static struct workqueue_struct *grmnet_ctrl_wq;
31
32#define SMD_CH_MAX_LEN 20
33#define CH_OPENED 0
34#define CH_READY 1
35struct smd_ch_info {
36 struct smd_channel *ch;
37 char *name;
38 unsigned long flags;
39 wait_queue_head_t wait;
40 unsigned dtr;
41
42 struct list_head tx_q;
43 unsigned long tx_len;
44
45 struct work_struct read_w;
46 struct work_struct write_w;
47
48 struct rmnet_ctrl_port *port;
49
50 int cbits_tomodem;
51 /* stats */
52 unsigned long to_modem;
53 unsigned long to_host;
54};
55
56struct rmnet_ctrl_port {
57 struct smd_ch_info ctrl_ch;
58 unsigned int port_num;
59 struct grmnet *port_usb;
60
61 spinlock_t port_lock;
62 struct work_struct connect_w;
63};
64
65static struct rmnet_ctrl_ports {
66 struct rmnet_ctrl_port *port;
67 struct platform_driver pdrv;
Manu Gautam2b0234a2011-09-07 16:47:52 +053068} ctrl_smd_ports[NR_CTRL_SMD_PORTS];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070069
70
71/*---------------misc functions---------------- */
72
Manu Gautam2b0234a2011-09-07 16:47:52 +053073static struct rmnet_ctrl_pkt *alloc_rmnet_ctrl_pkt(unsigned len, gfp_t flags)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070074{
75 struct rmnet_ctrl_pkt *pkt;
76
77 pkt = kzalloc(sizeof(struct rmnet_ctrl_pkt), flags);
78 if (!pkt)
79 return ERR_PTR(-ENOMEM);
80
81 pkt->buf = kmalloc(len, flags);
82 if (!pkt->buf) {
83 kfree(pkt);
84 return ERR_PTR(-ENOMEM);
85 }
86 pkt->len = len;
87
88 return pkt;
89}
90
Manu Gautam2b0234a2011-09-07 16:47:52 +053091static void free_rmnet_ctrl_pkt(struct rmnet_ctrl_pkt *pkt)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070092{
93 kfree(pkt->buf);
94 kfree(pkt);
95}
96
97/*--------------------------------------------- */
98
99/*---------------control/smd channel functions---------------- */
100
101static void grmnet_ctrl_smd_read_w(struct work_struct *w)
102{
103 struct smd_ch_info *c = container_of(w, struct smd_ch_info, read_w);
104 struct rmnet_ctrl_port *port = c->port;
105 int sz;
106 struct rmnet_ctrl_pkt *cpkt;
107 unsigned long flags;
108
109 while (1) {
110 sz = smd_cur_packet_size(c->ch);
111 if (sz == 0)
112 break;
113
114 if (smd_read_avail(c->ch) < sz)
115 break;
116
Manu Gautam2b0234a2011-09-07 16:47:52 +0530117 cpkt = alloc_rmnet_ctrl_pkt(sz, GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700118 if (IS_ERR(cpkt)) {
119 pr_err("%s: unable to allocate rmnet control pkt\n",
120 __func__);
121 return;
122 }
123 cpkt->len = smd_read(c->ch, cpkt->buf, sz);
124
125 /* send it to USB here */
126 spin_lock_irqsave(&port->port_lock, flags);
127 if (port->port_usb && port->port_usb->send_cpkt_response) {
128 port->port_usb->send_cpkt_response(
129 port->port_usb,
130 cpkt);
131 c->to_host++;
132 }
133 spin_unlock_irqrestore(&port->port_lock, flags);
134 }
135}
136
137static void grmnet_ctrl_smd_write_w(struct work_struct *w)
138{
139 struct smd_ch_info *c = container_of(w, struct smd_ch_info, write_w);
140 struct rmnet_ctrl_port *port = c->port;
141 unsigned long flags;
142 struct rmnet_ctrl_pkt *cpkt;
143 int ret;
144
145 spin_lock_irqsave(&port->port_lock, flags);
146 while (1) {
147 if (list_empty(&c->tx_q))
148 break;
149
150 cpkt = list_first_entry(&c->tx_q, struct rmnet_ctrl_pkt, list);
151
152 if (smd_write_avail(c->ch) < cpkt->len)
153 break;
154
155 list_del(&cpkt->list);
156 spin_unlock_irqrestore(&port->port_lock, flags);
157 ret = smd_write(c->ch, cpkt->buf, cpkt->len);
158 spin_lock_irqsave(&port->port_lock, flags);
159 if (ret != cpkt->len) {
160 pr_err("%s: smd_write failed err:%d\n",
161 __func__, ret);
Manu Gautam2b0234a2011-09-07 16:47:52 +0530162 free_rmnet_ctrl_pkt(cpkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700163 break;
164 }
Manu Gautam2b0234a2011-09-07 16:47:52 +0530165 free_rmnet_ctrl_pkt(cpkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700166 c->to_modem++;
167 }
168 spin_unlock_irqrestore(&port->port_lock, flags);
169}
170
171static int
172grmnet_ctrl_smd_send_cpkt_tomodem(struct grmnet *gr, u8 portno,
173 struct rmnet_ctrl_pkt *cpkt)
174{
175 unsigned long flags;
176 struct rmnet_ctrl_port *port;
177 struct smd_ch_info *c;
178
Manu Gautam2b0234a2011-09-07 16:47:52 +0530179 if (portno >= n_rmnet_ctrl_ports) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700180 pr_err("%s: Invalid portno#%d\n", __func__, portno);
181 return -ENODEV;
182 }
183
184 if (!gr) {
185 pr_err("%s: grmnet is null\n", __func__);
186 return -ENODEV;
187 }
188
Manu Gautam2b0234a2011-09-07 16:47:52 +0530189 port = ctrl_smd_ports[portno].port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700190
191 spin_lock_irqsave(&port->port_lock, flags);
192 c = &port->ctrl_ch;
193
194 /* drop cpkt if ch is not open */
195 if (!test_bit(CH_OPENED, &c->flags)) {
Manu Gautam2b0234a2011-09-07 16:47:52 +0530196 free_rmnet_ctrl_pkt(cpkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197 spin_unlock_irqrestore(&port->port_lock, flags);
198 return 0;
199 }
200
201 list_add_tail(&cpkt->list, &c->tx_q);
202 queue_work(grmnet_ctrl_wq, &c->write_w);
203 spin_unlock_irqrestore(&port->port_lock, flags);
204
205 return 0;
206}
207
Manu Gautam2b0234a2011-09-07 16:47:52 +0530208#define RMNET_CTRL_DTR 0x01
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700209static void
210gsmd_ctrl_send_cbits_tomodem(struct grmnet *gr, u8 portno, int cbits)
211{
212 struct rmnet_ctrl_port *port;
213 struct smd_ch_info *c;
214 int set_bits = 0;
215 int clear_bits = 0;
216 int temp = 0;
217
Manu Gautam2b0234a2011-09-07 16:47:52 +0530218 if (portno >= n_rmnet_ctrl_ports) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700219 pr_err("%s: Invalid portno#%d\n", __func__, portno);
220 return;
221 }
222
223 if (!gr) {
224 pr_err("%s: grmnet is null\n", __func__);
225 return;
226 }
227
Manu Gautam2b0234a2011-09-07 16:47:52 +0530228 port = ctrl_smd_ports[portno].port;
229 cbits = cbits & RMNET_CTRL_DTR;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700230 c = &port->ctrl_ch;
231
232 /* host driver will only send DTR, but to have generic
233 * set and clear bit implementation using two separate
234 * checks
235 */
Manu Gautam2b0234a2011-09-07 16:47:52 +0530236 if (cbits & RMNET_CTRL_DTR)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700237 set_bits |= TIOCM_DTR;
238 else
239 clear_bits |= TIOCM_DTR;
240
241 temp |= set_bits;
242 temp &= ~clear_bits;
243
244 if (temp == c->cbits_tomodem)
245 return;
246
247 c->cbits_tomodem = temp;
248
249 if (!test_bit(CH_OPENED, &c->flags))
250 return;
251
252 pr_debug("%s: ctrl_tomodem:%d ctrl_bits:%d setbits:%d clearbits:%d\n",
253 __func__, temp, cbits, set_bits, clear_bits);
254
255 smd_tiocmset(c->ch, set_bits, clear_bits);
256}
257
258static char *get_smd_event(unsigned event)
259{
260 switch (event) {
261 case SMD_EVENT_DATA:
262 return "DATA";
263 case SMD_EVENT_OPEN:
264 return "OPEN";
265 case SMD_EVENT_CLOSE:
266 return "CLOSE";
267 }
268
269 return "UNDEFINED";
270}
271
272static void grmnet_ctrl_smd_notify(void *p, unsigned event)
273{
274 struct rmnet_ctrl_port *port = p;
275 struct smd_ch_info *c = &port->ctrl_ch;
Vamsi Krishna9e9921a2011-10-04 16:09:31 -0700276 struct rmnet_ctrl_pkt *cpkt;
277 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700278
279 pr_debug("%s: EVENT_(%s)\n", __func__, get_smd_event(event));
280
281 switch (event) {
282 case SMD_EVENT_DATA:
283 if (smd_read_avail(c->ch))
284 queue_work(grmnet_ctrl_wq, &c->read_w);
285 if (smd_write_avail(c->ch))
286 queue_work(grmnet_ctrl_wq, &c->write_w);
287 break;
288 case SMD_EVENT_OPEN:
289 set_bit(CH_OPENED, &c->flags);
Vamsi Krishna9e9921a2011-10-04 16:09:31 -0700290
291 if (port && port->port_usb && port->port_usb->connect)
292 port->port_usb->connect(port->port_usb);
293
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700294 break;
295 case SMD_EVENT_CLOSE:
296 clear_bit(CH_OPENED, &c->flags);
Vamsi Krishna9e9921a2011-10-04 16:09:31 -0700297
298 if (port && port->port_usb && port->port_usb->disconnect)
299 port->port_usb->disconnect(port->port_usb);
300
301 spin_lock_irqsave(&port->port_lock, flags);
302 while (!list_empty(&c->tx_q)) {
303 cpkt = list_first_entry(&c->tx_q,
304 struct rmnet_ctrl_pkt, list);
305
306 list_del(&cpkt->list);
307 free_rmnet_ctrl_pkt(cpkt);
308 }
309 spin_unlock_irqrestore(&port->port_lock, flags);
310
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700311 break;
312 }
313}
314/*------------------------------------------------------------ */
315
316static void grmnet_ctrl_smd_connect_w(struct work_struct *w)
317{
318 struct rmnet_ctrl_port *port =
319 container_of(w, struct rmnet_ctrl_port, connect_w);
320 struct smd_ch_info *c = &port->ctrl_ch;
321 unsigned long flags;
322 int ret;
323
324 pr_debug("%s:\n", __func__);
325
326 if (!test_bit(CH_READY, &c->flags))
327 return;
328
329 ret = smd_open(c->name, &c->ch, port, grmnet_ctrl_smd_notify);
330 if (ret) {
331 pr_err("%s: Unable to open smd ch:%s err:%d\n",
332 __func__, c->name, ret);
333 return;
334 }
335
336 spin_lock_irqsave(&port->port_lock, flags);
337 if (port->port_usb)
338 smd_tiocmset(c->ch, c->cbits_tomodem, ~c->cbits_tomodem);
339 spin_unlock_irqrestore(&port->port_lock, flags);
340}
341
342int gsmd_ctrl_connect(struct grmnet *gr, int port_num)
343{
344 struct rmnet_ctrl_port *port;
345 struct smd_ch_info *c;
346 unsigned long flags;
347
348 pr_debug("%s: grmnet:%p port#%d\n", __func__, gr, port_num);
349
Manu Gautam2b0234a2011-09-07 16:47:52 +0530350 if (port_num >= n_rmnet_ctrl_ports) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700351 pr_err("%s: invalid portno#%d\n", __func__, port_num);
352 return -ENODEV;
353 }
354
355 if (!gr) {
356 pr_err("%s: grmnet port is null\n", __func__);
357 return -ENODEV;
358 }
359
Manu Gautam2b0234a2011-09-07 16:47:52 +0530360 port = ctrl_smd_ports[port_num].port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700361 c = &port->ctrl_ch;
362
363 spin_lock_irqsave(&port->port_lock, flags);
364 port->port_usb = gr;
365 gr->send_cpkt_request = grmnet_ctrl_smd_send_cpkt_tomodem;
366 gr->send_cbits_tomodem = gsmd_ctrl_send_cbits_tomodem;
367 spin_unlock_irqrestore(&port->port_lock, flags);
368
369 queue_work(grmnet_ctrl_wq, &port->connect_w);
370
371 return 0;
372}
373
374void gsmd_ctrl_disconnect(struct grmnet *gr, u8 port_num)
375{
376 struct rmnet_ctrl_port *port;
377 unsigned long flags;
378 struct smd_ch_info *c;
Vamsi Krishna9e9921a2011-10-04 16:09:31 -0700379 struct rmnet_ctrl_pkt *cpkt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700380
381 pr_debug("%s: grmnet:%p port#%d\n", __func__, gr, port_num);
382
Manu Gautam2b0234a2011-09-07 16:47:52 +0530383 if (port_num >= n_rmnet_ctrl_ports) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700384 pr_err("%s: invalid portno#%d\n", __func__, port_num);
385 return;
386 }
387
388 if (!gr) {
389 pr_err("%s: grmnet port is null\n", __func__);
390 return;
391 }
392
Manu Gautam2b0234a2011-09-07 16:47:52 +0530393 port = ctrl_smd_ports[port_num].port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700394 c = &port->ctrl_ch;
395
396 spin_lock_irqsave(&port->port_lock, flags);
397 port->port_usb = 0;
398 gr->send_cpkt_request = 0;
399 gr->send_cbits_tomodem = 0;
400 c->cbits_tomodem = 0;
Vamsi Krishna9e9921a2011-10-04 16:09:31 -0700401
402 while (!list_empty(&c->tx_q)) {
403 cpkt = list_first_entry(&c->tx_q, struct rmnet_ctrl_pkt, list);
404
405 list_del(&cpkt->list);
406 free_rmnet_ctrl_pkt(cpkt);
407 }
408
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700409 spin_unlock_irqrestore(&port->port_lock, flags);
410
411 if (test_bit(CH_OPENED, &c->flags)) {
412 /* this should send the dtr zero */
413 smd_close(c->ch);
414 clear_bit(CH_OPENED, &c->flags);
415 }
416}
417
418#define SMD_CH_MAX_LEN 20
419static int grmnet_ctrl_smd_ch_probe(struct platform_device *pdev)
420{
421 struct rmnet_ctrl_port *port;
422 struct smd_ch_info *c;
423 int i;
424 unsigned long flags;
425
426 pr_debug("%s: name:%s\n", __func__, pdev->name);
427
Manu Gautam2b0234a2011-09-07 16:47:52 +0530428 for (i = 0; i < n_rmnet_ctrl_ports; i++) {
429 port = ctrl_smd_ports[i].port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700430 c = &port->ctrl_ch;
431
432 if (!strncmp(c->name, pdev->name, SMD_CH_MAX_LEN)) {
433 set_bit(CH_READY, &c->flags);
434
435 /* if usb is online, try opening smd_ch */
436 spin_lock_irqsave(&port->port_lock, flags);
437 if (port->port_usb)
438 queue_work(grmnet_ctrl_wq, &port->connect_w);
439 spin_unlock_irqrestore(&port->port_lock, flags);
440
441 break;
442 }
443 }
444
445 return 0;
446}
447
448static int grmnet_ctrl_smd_ch_remove(struct platform_device *pdev)
449{
450 struct rmnet_ctrl_port *port;
451 struct smd_ch_info *c;
452 int i;
453
454 pr_debug("%s: name:%s\n", __func__, pdev->name);
455
Manu Gautam2b0234a2011-09-07 16:47:52 +0530456 for (i = 0; i < n_rmnet_ctrl_ports; i++) {
457 port = ctrl_smd_ports[i].port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700458 c = &port->ctrl_ch;
459
460 if (!strncmp(c->name, pdev->name, SMD_CH_MAX_LEN)) {
461 clear_bit(CH_READY, &c->flags);
462 clear_bit(CH_OPENED, &c->flags);
463 smd_close(c->ch);
464 break;
465 }
466 }
467
468 return 0;
469}
470
471
472static void grmnet_ctrl_smd_port_free(int portno)
473{
Manu Gautam2b0234a2011-09-07 16:47:52 +0530474 struct rmnet_ctrl_port *port = ctrl_smd_ports[portno].port;
Jack Phameffd4ae2011-08-03 16:49:36 -0700475 struct platform_driver *pdrv = &ctrl_smd_ports[portno].pdrv;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700476
Jack Phameffd4ae2011-08-03 16:49:36 -0700477 if (port) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700478 kfree(port);
Jack Phameffd4ae2011-08-03 16:49:36 -0700479 platform_driver_unregister(pdrv);
480 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700481}
482
483static int grmnet_ctrl_smd_port_alloc(int portno)
484{
485 struct rmnet_ctrl_port *port;
486 struct smd_ch_info *c;
487 struct platform_driver *pdrv;
488
489 port = kzalloc(sizeof(struct rmnet_ctrl_port), GFP_KERNEL);
490 if (!port)
491 return -ENOMEM;
492
493 port->port_num = portno;
494
495 spin_lock_init(&port->port_lock);
496 INIT_WORK(&port->connect_w, grmnet_ctrl_smd_connect_w);
497
498 c = &port->ctrl_ch;
499 c->name = rmnet_ctrl_names[portno];
500 c->port = port;
501 init_waitqueue_head(&c->wait);
502 INIT_LIST_HEAD(&c->tx_q);
503 INIT_WORK(&c->read_w, grmnet_ctrl_smd_read_w);
504 INIT_WORK(&c->write_w, grmnet_ctrl_smd_write_w);
505
Manu Gautam2b0234a2011-09-07 16:47:52 +0530506 ctrl_smd_ports[portno].port = port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700507
Manu Gautam2b0234a2011-09-07 16:47:52 +0530508 pdrv = &ctrl_smd_ports[portno].pdrv;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700509 pdrv->probe = grmnet_ctrl_smd_ch_probe;
510 pdrv->remove = grmnet_ctrl_smd_ch_remove;
511 pdrv->driver.name = c->name;
512 pdrv->driver.owner = THIS_MODULE;
513
514 platform_driver_register(pdrv);
515
516 pr_debug("%s: port:%p portno:%d\n", __func__, port, portno);
517
518 return 0;
519}
520
521int gsmd_ctrl_setup(unsigned int count)
522{
523 int i;
524 int ret;
525
526 pr_debug("%s: requested ports:%d\n", __func__, count);
527
Manu Gautam2b0234a2011-09-07 16:47:52 +0530528 if (!count || count > NR_CTRL_SMD_PORTS) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700529 pr_err("%s: Invalid num of ports count:%d\n",
530 __func__, count);
531 return -EINVAL;
532 }
533
534 grmnet_ctrl_wq = alloc_workqueue("gsmd_ctrl",
535 WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
536 if (!grmnet_ctrl_wq) {
537 pr_err("%s: Unable to create workqueue grmnet_ctrl\n",
538 __func__);
539 return -ENOMEM;
540 }
541
542 for (i = 0; i < count; i++) {
543 ret = grmnet_ctrl_smd_port_alloc(i);
544 if (ret) {
545 pr_err("%s: Unable to alloc port:%d\n", __func__, i);
Manu Gautam2b0234a2011-09-07 16:47:52 +0530546 goto free_ctrl_smd_ports;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700547 }
Manu Gautam2b0234a2011-09-07 16:47:52 +0530548 n_rmnet_ctrl_ports++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700549 }
550
551 return 0;
552
Manu Gautam2b0234a2011-09-07 16:47:52 +0530553free_ctrl_smd_ports:
554 for (i = 0; i < n_rmnet_ctrl_ports; i++)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700555 grmnet_ctrl_smd_port_free(i);
556
557 destroy_workqueue(grmnet_ctrl_wq);
558
559 return ret;
560}
561
562#if defined(CONFIG_DEBUG_FS)
563#define DEBUG_BUF_SIZE 1024
564static ssize_t gsmd_ctrl_read_stats(struct file *file, char __user *ubuf,
565 size_t count, loff_t *ppos)
566{
567 struct rmnet_ctrl_port *port;
568 struct smd_ch_info *c;
569 char *buf;
570 unsigned long flags;
571 int ret;
572 int i;
573 int temp = 0;
574
575 buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
576 if (!buf)
577 return -ENOMEM;
578
Manu Gautam2b0234a2011-09-07 16:47:52 +0530579 for (i = 0; i < n_rmnet_ctrl_ports; i++) {
580 port = ctrl_smd_ports[i].port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700581 if (!port)
582 continue;
583 spin_lock_irqsave(&port->port_lock, flags);
584
585 c = &port->ctrl_ch;
586
587 temp += scnprintf(buf + temp, DEBUG_BUF_SIZE - temp,
588 "#PORT:%d port:%p ctrl_ch:%p#\n"
589 "to_usbhost: %lu\n"
590 "to_modem: %lu\n"
591 "DTR: %s\n"
592 "ch_open: %d\n"
593 "ch_ready: %d\n"
594 "read_avail: %d\n"
595 "write_avail:%d\n",
596 i, port, &port->ctrl_ch,
597 c->to_host, c->to_modem,
598 c->cbits_tomodem ? "HIGH" : "LOW",
599 test_bit(CH_OPENED, &c->flags),
600 test_bit(CH_READY, &c->flags),
601 smd_read_avail(c->ch),
602 smd_write_avail(c->ch));
603
604 spin_unlock_irqrestore(&port->port_lock, flags);
605 }
606
607 ret = simple_read_from_buffer(ubuf, count, ppos, buf, temp);
608
609 kfree(buf);
610
611 return ret;
612}
613
614static ssize_t gsmd_ctrl_reset_stats(struct file *file, const char __user *buf,
615 size_t count, loff_t *ppos)
616{
617 struct rmnet_ctrl_port *port;
618 struct smd_ch_info *c;
619 int i;
620 unsigned long flags;
621
Manu Gautam2b0234a2011-09-07 16:47:52 +0530622 for (i = 0; i < n_rmnet_ctrl_ports; i++) {
623 port = ctrl_smd_ports[i].port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700624 if (!port)
625 continue;
626
627 spin_lock_irqsave(&port->port_lock, flags);
628
629 c = &port->ctrl_ch;
630
631 c->to_host = 0;
632 c->to_modem = 0;
633
634 spin_unlock_irqrestore(&port->port_lock, flags);
635 }
636 return count;
637}
638
639const struct file_operations gsmd_ctrl_stats_ops = {
640 .read = gsmd_ctrl_read_stats,
641 .write = gsmd_ctrl_reset_stats,
642};
643
644struct dentry *smd_ctrl_dent;
645struct dentry *smd_ctrl_dfile;
646static void gsmd_ctrl_debugfs_init(void)
647{
648 smd_ctrl_dent = debugfs_create_dir("usb_rmnet_ctrl_smd", 0);
649 if (IS_ERR(smd_ctrl_dent))
650 return;
651
652 smd_ctrl_dfile = debugfs_create_file("status", 0444, smd_ctrl_dent, 0,
653 &gsmd_ctrl_stats_ops);
654 if (!smd_ctrl_dfile || IS_ERR(smd_ctrl_dfile))
655 debugfs_remove(smd_ctrl_dent);
656}
657
658static void gsmd_ctrl_debugfs_exit(void)
659{
660 debugfs_remove(smd_ctrl_dfile);
661 debugfs_remove(smd_ctrl_dent);
662}
663
664#else
665static void gsmd_ctrl_debugfs_init(void) { }
666static void gsmd_ctrl_debugfs_exit(void) { }
667#endif
668
669static int __init gsmd_ctrl_init(void)
670{
671 gsmd_ctrl_debugfs_init();
672
673 return 0;
674}
675module_init(gsmd_ctrl_init);
676
677static void __exit gsmd_ctrl_exit(void)
678{
679 gsmd_ctrl_debugfs_exit();
680}
681module_exit(gsmd_ctrl_exit);
682MODULE_DESCRIPTION("smd control driver");
683MODULE_LICENSE("GPL v2");