blob: 8b08b7a07be63259c6aaec1f1c9c9c8a613b1573 [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 }
Hemant Kumarf60c0252011-11-03 12:37:07 -070086
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070087 pkt->len = len;
88
89 return pkt;
90}
91
Manu Gautam2b0234a2011-09-07 16:47:52 +053092static void free_rmnet_ctrl_pkt(struct rmnet_ctrl_pkt *pkt)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070093{
94 kfree(pkt->buf);
95 kfree(pkt);
96}
97
98/*--------------------------------------------- */
99
100/*---------------control/smd channel functions---------------- */
101
102static void grmnet_ctrl_smd_read_w(struct work_struct *w)
103{
104 struct smd_ch_info *c = container_of(w, struct smd_ch_info, read_w);
105 struct rmnet_ctrl_port *port = c->port;
106 int sz;
Hemant Kumarf60c0252011-11-03 12:37:07 -0700107 size_t len;
108 void *buf;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700109 unsigned long flags;
110
111 while (1) {
112 sz = smd_cur_packet_size(c->ch);
113 if (sz == 0)
114 break;
115
116 if (smd_read_avail(c->ch) < sz)
117 break;
118
Hemant Kumarf60c0252011-11-03 12:37:07 -0700119 buf = kmalloc(sz, GFP_KERNEL);
120 if (!buf)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700121 return;
Hemant Kumarf60c0252011-11-03 12:37:07 -0700122
123 len = smd_read(c->ch, buf, sz);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700124
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) {
Hemant Kumarf60c0252011-11-03 12:37:07 -0700128 port->port_usb->send_cpkt_response(port->port_usb,
129 buf, len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700130 c->to_host++;
131 }
Hemant Kumarf60c0252011-11-03 12:37:07 -0700132 kfree(buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700133 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) {
Hemant Kumarf60c0252011-11-03 12:37:07 -0700160 pr_err("%s: smd_write failed err:%d\n", __func__, ret);
Manu Gautam2b0234a2011-09-07 16:47:52 +0530161 free_rmnet_ctrl_pkt(cpkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700162 break;
163 }
Manu Gautam2b0234a2011-09-07 16:47:52 +0530164 free_rmnet_ctrl_pkt(cpkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700165 c->to_modem++;
166 }
167 spin_unlock_irqrestore(&port->port_lock, flags);
168}
169
170static int
Hemant Kumarf60c0252011-11-03 12:37:07 -0700171grmnet_ctrl_smd_send_cpkt_tomodem(u8 portno,
172 void *buf, size_t len)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700173{
174 unsigned long flags;
175 struct rmnet_ctrl_port *port;
176 struct smd_ch_info *c;
Hemant Kumarf60c0252011-11-03 12:37:07 -0700177 struct rmnet_ctrl_pkt *cpkt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700178
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
Hemant Kumarf60c0252011-11-03 12:37:07 -0700184 port = ctrl_smd_ports[portno].port;
185
186 cpkt = alloc_rmnet_ctrl_pkt(len, GFP_ATOMIC);
187 if (IS_ERR(cpkt)) {
188 pr_err("%s: Unable to allocate ctrl pkt\n", __func__);
189 return -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700190 }
191
Hemant Kumarf60c0252011-11-03 12:37:07 -0700192 memcpy(cpkt->buf, buf, len);
193 cpkt->len = len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700194
195 spin_lock_irqsave(&port->port_lock, flags);
196 c = &port->ctrl_ch;
197
198 /* drop cpkt if ch is not open */
199 if (!test_bit(CH_OPENED, &c->flags)) {
Manu Gautam2b0234a2011-09-07 16:47:52 +0530200 free_rmnet_ctrl_pkt(cpkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700201 spin_unlock_irqrestore(&port->port_lock, flags);
202 return 0;
203 }
204
205 list_add_tail(&cpkt->list, &c->tx_q);
206 queue_work(grmnet_ctrl_wq, &c->write_w);
207 spin_unlock_irqrestore(&port->port_lock, flags);
208
209 return 0;
210}
211
Manu Gautam2b0234a2011-09-07 16:47:52 +0530212#define RMNET_CTRL_DTR 0x01
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700213static void
Hemant Kumarf60c0252011-11-03 12:37:07 -0700214gsmd_ctrl_send_cbits_tomodem(void *gptr, u8 portno, int cbits)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700215{
216 struct rmnet_ctrl_port *port;
217 struct smd_ch_info *c;
218 int set_bits = 0;
219 int clear_bits = 0;
220 int temp = 0;
221
Manu Gautam2b0234a2011-09-07 16:47:52 +0530222 if (portno >= n_rmnet_ctrl_ports) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700223 pr_err("%s: Invalid portno#%d\n", __func__, portno);
224 return;
225 }
226
Hemant Kumarf60c0252011-11-03 12:37:07 -0700227 if (!gptr) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700228 pr_err("%s: grmnet is null\n", __func__);
229 return;
230 }
231
Manu Gautam2b0234a2011-09-07 16:47:52 +0530232 port = ctrl_smd_ports[portno].port;
233 cbits = cbits & RMNET_CTRL_DTR;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700234 c = &port->ctrl_ch;
235
236 /* host driver will only send DTR, but to have generic
237 * set and clear bit implementation using two separate
238 * checks
239 */
Manu Gautam2b0234a2011-09-07 16:47:52 +0530240 if (cbits & RMNET_CTRL_DTR)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700241 set_bits |= TIOCM_DTR;
242 else
243 clear_bits |= TIOCM_DTR;
244
245 temp |= set_bits;
246 temp &= ~clear_bits;
247
248 if (temp == c->cbits_tomodem)
249 return;
250
251 c->cbits_tomodem = temp;
252
253 if (!test_bit(CH_OPENED, &c->flags))
254 return;
255
256 pr_debug("%s: ctrl_tomodem:%d ctrl_bits:%d setbits:%d clearbits:%d\n",
257 __func__, temp, cbits, set_bits, clear_bits);
258
259 smd_tiocmset(c->ch, set_bits, clear_bits);
260}
261
262static char *get_smd_event(unsigned event)
263{
264 switch (event) {
265 case SMD_EVENT_DATA:
266 return "DATA";
267 case SMD_EVENT_OPEN:
268 return "OPEN";
269 case SMD_EVENT_CLOSE:
270 return "CLOSE";
271 }
272
273 return "UNDEFINED";
274}
275
276static void grmnet_ctrl_smd_notify(void *p, unsigned event)
277{
278 struct rmnet_ctrl_port *port = p;
279 struct smd_ch_info *c = &port->ctrl_ch;
Vamsi Krishna9e9921a2011-10-04 16:09:31 -0700280 struct rmnet_ctrl_pkt *cpkt;
281 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700282
283 pr_debug("%s: EVENT_(%s)\n", __func__, get_smd_event(event));
284
285 switch (event) {
286 case SMD_EVENT_DATA:
287 if (smd_read_avail(c->ch))
288 queue_work(grmnet_ctrl_wq, &c->read_w);
289 if (smd_write_avail(c->ch))
290 queue_work(grmnet_ctrl_wq, &c->write_w);
291 break;
292 case SMD_EVENT_OPEN:
293 set_bit(CH_OPENED, &c->flags);
Vamsi Krishna9e9921a2011-10-04 16:09:31 -0700294
295 if (port && port->port_usb && port->port_usb->connect)
296 port->port_usb->connect(port->port_usb);
297
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700298 break;
299 case SMD_EVENT_CLOSE:
300 clear_bit(CH_OPENED, &c->flags);
Vamsi Krishna9e9921a2011-10-04 16:09:31 -0700301
302 if (port && port->port_usb && port->port_usb->disconnect)
303 port->port_usb->disconnect(port->port_usb);
304
305 spin_lock_irqsave(&port->port_lock, flags);
306 while (!list_empty(&c->tx_q)) {
307 cpkt = list_first_entry(&c->tx_q,
308 struct rmnet_ctrl_pkt, list);
309
310 list_del(&cpkt->list);
311 free_rmnet_ctrl_pkt(cpkt);
312 }
313 spin_unlock_irqrestore(&port->port_lock, flags);
314
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315 break;
316 }
317}
318/*------------------------------------------------------------ */
319
320static void grmnet_ctrl_smd_connect_w(struct work_struct *w)
321{
322 struct rmnet_ctrl_port *port =
323 container_of(w, struct rmnet_ctrl_port, connect_w);
324 struct smd_ch_info *c = &port->ctrl_ch;
325 unsigned long flags;
326 int ret;
327
328 pr_debug("%s:\n", __func__);
329
330 if (!test_bit(CH_READY, &c->flags))
331 return;
332
333 ret = smd_open(c->name, &c->ch, port, grmnet_ctrl_smd_notify);
334 if (ret) {
335 pr_err("%s: Unable to open smd ch:%s err:%d\n",
336 __func__, c->name, ret);
337 return;
338 }
339
340 spin_lock_irqsave(&port->port_lock, flags);
341 if (port->port_usb)
342 smd_tiocmset(c->ch, c->cbits_tomodem, ~c->cbits_tomodem);
343 spin_unlock_irqrestore(&port->port_lock, flags);
344}
345
346int gsmd_ctrl_connect(struct grmnet *gr, int port_num)
347{
348 struct rmnet_ctrl_port *port;
349 struct smd_ch_info *c;
350 unsigned long flags;
351
352 pr_debug("%s: grmnet:%p port#%d\n", __func__, gr, port_num);
353
Manu Gautam2b0234a2011-09-07 16:47:52 +0530354 if (port_num >= n_rmnet_ctrl_ports) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700355 pr_err("%s: invalid portno#%d\n", __func__, port_num);
356 return -ENODEV;
357 }
358
359 if (!gr) {
360 pr_err("%s: grmnet port is null\n", __func__);
361 return -ENODEV;
362 }
363
Manu Gautam2b0234a2011-09-07 16:47:52 +0530364 port = ctrl_smd_ports[port_num].port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700365 c = &port->ctrl_ch;
366
367 spin_lock_irqsave(&port->port_lock, flags);
368 port->port_usb = gr;
Hemant Kumarf60c0252011-11-03 12:37:07 -0700369 gr->send_encap_cmd = grmnet_ctrl_smd_send_cpkt_tomodem;
370 gr->notify_modem = gsmd_ctrl_send_cbits_tomodem;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700371 spin_unlock_irqrestore(&port->port_lock, flags);
372
373 queue_work(grmnet_ctrl_wq, &port->connect_w);
374
375 return 0;
376}
377
378void gsmd_ctrl_disconnect(struct grmnet *gr, u8 port_num)
379{
380 struct rmnet_ctrl_port *port;
381 unsigned long flags;
382 struct smd_ch_info *c;
Vamsi Krishna9e9921a2011-10-04 16:09:31 -0700383 struct rmnet_ctrl_pkt *cpkt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700384
385 pr_debug("%s: grmnet:%p port#%d\n", __func__, gr, port_num);
386
Manu Gautam2b0234a2011-09-07 16:47:52 +0530387 if (port_num >= n_rmnet_ctrl_ports) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700388 pr_err("%s: invalid portno#%d\n", __func__, port_num);
389 return;
390 }
391
392 if (!gr) {
393 pr_err("%s: grmnet port is null\n", __func__);
394 return;
395 }
396
Manu Gautam2b0234a2011-09-07 16:47:52 +0530397 port = ctrl_smd_ports[port_num].port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700398 c = &port->ctrl_ch;
399
400 spin_lock_irqsave(&port->port_lock, flags);
401 port->port_usb = 0;
Hemant Kumarf60c0252011-11-03 12:37:07 -0700402 gr->send_encap_cmd = 0;
403 gr->notify_modem = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700404 c->cbits_tomodem = 0;
Vamsi Krishna9e9921a2011-10-04 16:09:31 -0700405
406 while (!list_empty(&c->tx_q)) {
407 cpkt = list_first_entry(&c->tx_q, struct rmnet_ctrl_pkt, list);
408
409 list_del(&cpkt->list);
410 free_rmnet_ctrl_pkt(cpkt);
411 }
412
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700413 spin_unlock_irqrestore(&port->port_lock, flags);
414
415 if (test_bit(CH_OPENED, &c->flags)) {
416 /* this should send the dtr zero */
417 smd_close(c->ch);
418 clear_bit(CH_OPENED, &c->flags);
419 }
420}
421
422#define SMD_CH_MAX_LEN 20
423static int grmnet_ctrl_smd_ch_probe(struct platform_device *pdev)
424{
425 struct rmnet_ctrl_port *port;
426 struct smd_ch_info *c;
427 int i;
428 unsigned long flags;
429
430 pr_debug("%s: name:%s\n", __func__, pdev->name);
431
Manu Gautam2b0234a2011-09-07 16:47:52 +0530432 for (i = 0; i < n_rmnet_ctrl_ports; i++) {
433 port = ctrl_smd_ports[i].port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700434 c = &port->ctrl_ch;
435
436 if (!strncmp(c->name, pdev->name, SMD_CH_MAX_LEN)) {
437 set_bit(CH_READY, &c->flags);
438
439 /* if usb is online, try opening smd_ch */
440 spin_lock_irqsave(&port->port_lock, flags);
441 if (port->port_usb)
442 queue_work(grmnet_ctrl_wq, &port->connect_w);
443 spin_unlock_irqrestore(&port->port_lock, flags);
444
445 break;
446 }
447 }
448
449 return 0;
450}
451
452static int grmnet_ctrl_smd_ch_remove(struct platform_device *pdev)
453{
454 struct rmnet_ctrl_port *port;
455 struct smd_ch_info *c;
456 int i;
457
458 pr_debug("%s: name:%s\n", __func__, pdev->name);
459
Manu Gautam2b0234a2011-09-07 16:47:52 +0530460 for (i = 0; i < n_rmnet_ctrl_ports; i++) {
461 port = ctrl_smd_ports[i].port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700462 c = &port->ctrl_ch;
463
464 if (!strncmp(c->name, pdev->name, SMD_CH_MAX_LEN)) {
465 clear_bit(CH_READY, &c->flags);
466 clear_bit(CH_OPENED, &c->flags);
467 smd_close(c->ch);
468 break;
469 }
470 }
471
472 return 0;
473}
474
475
476static void grmnet_ctrl_smd_port_free(int portno)
477{
Manu Gautam2b0234a2011-09-07 16:47:52 +0530478 struct rmnet_ctrl_port *port = ctrl_smd_ports[portno].port;
Jack Phameffd4ae2011-08-03 16:49:36 -0700479 struct platform_driver *pdrv = &ctrl_smd_ports[portno].pdrv;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700480
Jack Phameffd4ae2011-08-03 16:49:36 -0700481 if (port) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700482 kfree(port);
Jack Phameffd4ae2011-08-03 16:49:36 -0700483 platform_driver_unregister(pdrv);
484 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700485}
486
487static int grmnet_ctrl_smd_port_alloc(int portno)
488{
489 struct rmnet_ctrl_port *port;
490 struct smd_ch_info *c;
491 struct platform_driver *pdrv;
492
493 port = kzalloc(sizeof(struct rmnet_ctrl_port), GFP_KERNEL);
494 if (!port)
495 return -ENOMEM;
496
497 port->port_num = portno;
498
499 spin_lock_init(&port->port_lock);
500 INIT_WORK(&port->connect_w, grmnet_ctrl_smd_connect_w);
501
502 c = &port->ctrl_ch;
503 c->name = rmnet_ctrl_names[portno];
504 c->port = port;
505 init_waitqueue_head(&c->wait);
506 INIT_LIST_HEAD(&c->tx_q);
507 INIT_WORK(&c->read_w, grmnet_ctrl_smd_read_w);
508 INIT_WORK(&c->write_w, grmnet_ctrl_smd_write_w);
509
Manu Gautam2b0234a2011-09-07 16:47:52 +0530510 ctrl_smd_ports[portno].port = port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700511
Manu Gautam2b0234a2011-09-07 16:47:52 +0530512 pdrv = &ctrl_smd_ports[portno].pdrv;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700513 pdrv->probe = grmnet_ctrl_smd_ch_probe;
514 pdrv->remove = grmnet_ctrl_smd_ch_remove;
515 pdrv->driver.name = c->name;
516 pdrv->driver.owner = THIS_MODULE;
517
518 platform_driver_register(pdrv);
519
520 pr_debug("%s: port:%p portno:%d\n", __func__, port, portno);
521
522 return 0;
523}
524
525int gsmd_ctrl_setup(unsigned int count)
526{
527 int i;
528 int ret;
529
530 pr_debug("%s: requested ports:%d\n", __func__, count);
531
Manu Gautam2b0234a2011-09-07 16:47:52 +0530532 if (!count || count > NR_CTRL_SMD_PORTS) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700533 pr_err("%s: Invalid num of ports count:%d\n",
534 __func__, count);
535 return -EINVAL;
536 }
537
538 grmnet_ctrl_wq = alloc_workqueue("gsmd_ctrl",
539 WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
540 if (!grmnet_ctrl_wq) {
541 pr_err("%s: Unable to create workqueue grmnet_ctrl\n",
542 __func__);
543 return -ENOMEM;
544 }
545
546 for (i = 0; i < count; i++) {
547 ret = grmnet_ctrl_smd_port_alloc(i);
548 if (ret) {
549 pr_err("%s: Unable to alloc port:%d\n", __func__, i);
Manu Gautam2b0234a2011-09-07 16:47:52 +0530550 goto free_ctrl_smd_ports;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700551 }
Manu Gautam2b0234a2011-09-07 16:47:52 +0530552 n_rmnet_ctrl_ports++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700553 }
554
555 return 0;
556
Manu Gautam2b0234a2011-09-07 16:47:52 +0530557free_ctrl_smd_ports:
558 for (i = 0; i < n_rmnet_ctrl_ports; i++)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700559 grmnet_ctrl_smd_port_free(i);
560
561 destroy_workqueue(grmnet_ctrl_wq);
562
563 return ret;
564}
565
566#if defined(CONFIG_DEBUG_FS)
567#define DEBUG_BUF_SIZE 1024
568static ssize_t gsmd_ctrl_read_stats(struct file *file, char __user *ubuf,
569 size_t count, loff_t *ppos)
570{
571 struct rmnet_ctrl_port *port;
572 struct smd_ch_info *c;
573 char *buf;
574 unsigned long flags;
575 int ret;
576 int i;
577 int temp = 0;
578
579 buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
580 if (!buf)
581 return -ENOMEM;
582
Manu Gautam2b0234a2011-09-07 16:47:52 +0530583 for (i = 0; i < n_rmnet_ctrl_ports; i++) {
584 port = ctrl_smd_ports[i].port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700585 if (!port)
586 continue;
587 spin_lock_irqsave(&port->port_lock, flags);
588
589 c = &port->ctrl_ch;
590
591 temp += scnprintf(buf + temp, DEBUG_BUF_SIZE - temp,
592 "#PORT:%d port:%p ctrl_ch:%p#\n"
593 "to_usbhost: %lu\n"
594 "to_modem: %lu\n"
595 "DTR: %s\n"
596 "ch_open: %d\n"
597 "ch_ready: %d\n"
598 "read_avail: %d\n"
599 "write_avail:%d\n",
600 i, port, &port->ctrl_ch,
601 c->to_host, c->to_modem,
602 c->cbits_tomodem ? "HIGH" : "LOW",
603 test_bit(CH_OPENED, &c->flags),
604 test_bit(CH_READY, &c->flags),
605 smd_read_avail(c->ch),
606 smd_write_avail(c->ch));
607
608 spin_unlock_irqrestore(&port->port_lock, flags);
609 }
610
611 ret = simple_read_from_buffer(ubuf, count, ppos, buf, temp);
612
613 kfree(buf);
614
615 return ret;
616}
617
618static ssize_t gsmd_ctrl_reset_stats(struct file *file, const char __user *buf,
619 size_t count, loff_t *ppos)
620{
621 struct rmnet_ctrl_port *port;
622 struct smd_ch_info *c;
623 int i;
624 unsigned long flags;
625
Manu Gautam2b0234a2011-09-07 16:47:52 +0530626 for (i = 0; i < n_rmnet_ctrl_ports; i++) {
627 port = ctrl_smd_ports[i].port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700628 if (!port)
629 continue;
630
631 spin_lock_irqsave(&port->port_lock, flags);
632
633 c = &port->ctrl_ch;
634
635 c->to_host = 0;
636 c->to_modem = 0;
637
638 spin_unlock_irqrestore(&port->port_lock, flags);
639 }
640 return count;
641}
642
643const struct file_operations gsmd_ctrl_stats_ops = {
644 .read = gsmd_ctrl_read_stats,
645 .write = gsmd_ctrl_reset_stats,
646};
647
648struct dentry *smd_ctrl_dent;
649struct dentry *smd_ctrl_dfile;
650static void gsmd_ctrl_debugfs_init(void)
651{
652 smd_ctrl_dent = debugfs_create_dir("usb_rmnet_ctrl_smd", 0);
653 if (IS_ERR(smd_ctrl_dent))
654 return;
655
656 smd_ctrl_dfile = debugfs_create_file("status", 0444, smd_ctrl_dent, 0,
657 &gsmd_ctrl_stats_ops);
658 if (!smd_ctrl_dfile || IS_ERR(smd_ctrl_dfile))
659 debugfs_remove(smd_ctrl_dent);
660}
661
662static void gsmd_ctrl_debugfs_exit(void)
663{
664 debugfs_remove(smd_ctrl_dfile);
665 debugfs_remove(smd_ctrl_dent);
666}
667
668#else
669static void gsmd_ctrl_debugfs_init(void) { }
670static void gsmd_ctrl_debugfs_exit(void) { }
671#endif
672
673static int __init gsmd_ctrl_init(void)
674{
675 gsmd_ctrl_debugfs_init();
676
677 return 0;
678}
679module_init(gsmd_ctrl_init);
680
681static void __exit gsmd_ctrl_exit(void)
682{
683 gsmd_ctrl_debugfs_exit();
684}
685module_exit(gsmd_ctrl_exit);
686MODULE_DESCRIPTION("smd control driver");
687MODULE_LICENSE("GPL v2");