blob: 169008bd4eb972b90df831ec9db6370967ec0cbb [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/*
Chiranjeevi Velempati40608bb2012-01-27 14:09:47 +05302 * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003 *
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
Anna Perel21515162012-02-02 20:50:02 +020027#define NR_CTRL_SMD_PORTS 3
Manu Gautam2b0234a2011-09-07 16:47:52 +053028static int n_rmnet_ctrl_ports;
Anna Perel21515162012-02-02 20:50:02 +020029static char *rmnet_ctrl_names[] = {"DATA40_CNTL", "DATA39_CNTL", "DATA38_CNTL"};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070030static 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;
Chiranjeevi Velempati40608bb2012-01-27 14:09:47 +053062 struct delayed_work connect_w;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070063};
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
Jack Pham1b236d12012-03-19 15:27:18 -0700111 spin_lock_irqsave(&port->port_lock, flags);
112 while (c->ch) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700113 sz = smd_cur_packet_size(c->ch);
Jack Pham1b236d12012-03-19 15:27:18 -0700114 if (sz <= 0)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700115 break;
116
117 if (smd_read_avail(c->ch) < sz)
118 break;
119
Jack Pham1b236d12012-03-19 15:27:18 -0700120 spin_unlock_irqrestore(&port->port_lock, flags);
121
Hemant Kumarf60c0252011-11-03 12:37:07 -0700122 buf = kmalloc(sz, GFP_KERNEL);
123 if (!buf)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700124 return;
Hemant Kumarf60c0252011-11-03 12:37:07 -0700125
126 len = smd_read(c->ch, buf, sz);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700127
128 /* send it to USB here */
129 spin_lock_irqsave(&port->port_lock, flags);
130 if (port->port_usb && port->port_usb->send_cpkt_response) {
Hemant Kumarf60c0252011-11-03 12:37:07 -0700131 port->port_usb->send_cpkt_response(port->port_usb,
132 buf, len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700133 c->to_host++;
134 }
Hemant Kumarf60c0252011-11-03 12:37:07 -0700135 kfree(buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700136 }
Jack Pham1b236d12012-03-19 15:27:18 -0700137 spin_unlock_irqrestore(&port->port_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138}
139
140static void grmnet_ctrl_smd_write_w(struct work_struct *w)
141{
142 struct smd_ch_info *c = container_of(w, struct smd_ch_info, write_w);
143 struct rmnet_ctrl_port *port = c->port;
144 unsigned long flags;
145 struct rmnet_ctrl_pkt *cpkt;
146 int ret;
147
148 spin_lock_irqsave(&port->port_lock, flags);
Jack Pham1b236d12012-03-19 15:27:18 -0700149 while (c->ch) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700150 if (list_empty(&c->tx_q))
151 break;
152
153 cpkt = list_first_entry(&c->tx_q, struct rmnet_ctrl_pkt, list);
154
155 if (smd_write_avail(c->ch) < cpkt->len)
156 break;
157
158 list_del(&cpkt->list);
159 spin_unlock_irqrestore(&port->port_lock, flags);
160 ret = smd_write(c->ch, cpkt->buf, cpkt->len);
161 spin_lock_irqsave(&port->port_lock, flags);
162 if (ret != cpkt->len) {
Hemant Kumarf60c0252011-11-03 12:37:07 -0700163 pr_err("%s: smd_write failed err:%d\n", __func__, ret);
Manu Gautam2b0234a2011-09-07 16:47:52 +0530164 free_rmnet_ctrl_pkt(cpkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700165 break;
166 }
Manu Gautam2b0234a2011-09-07 16:47:52 +0530167 free_rmnet_ctrl_pkt(cpkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700168 c->to_modem++;
169 }
170 spin_unlock_irqrestore(&port->port_lock, flags);
171}
172
173static int
Hemant Kumarf60c0252011-11-03 12:37:07 -0700174grmnet_ctrl_smd_send_cpkt_tomodem(u8 portno,
175 void *buf, size_t len)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700176{
177 unsigned long flags;
178 struct rmnet_ctrl_port *port;
179 struct smd_ch_info *c;
Hemant Kumarf60c0252011-11-03 12:37:07 -0700180 struct rmnet_ctrl_pkt *cpkt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700181
Manu Gautam2b0234a2011-09-07 16:47:52 +0530182 if (portno >= n_rmnet_ctrl_ports) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700183 pr_err("%s: Invalid portno#%d\n", __func__, portno);
184 return -ENODEV;
185 }
186
Hemant Kumarf60c0252011-11-03 12:37:07 -0700187 port = ctrl_smd_ports[portno].port;
188
189 cpkt = alloc_rmnet_ctrl_pkt(len, GFP_ATOMIC);
190 if (IS_ERR(cpkt)) {
191 pr_err("%s: Unable to allocate ctrl pkt\n", __func__);
192 return -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700193 }
194
Hemant Kumarf60c0252011-11-03 12:37:07 -0700195 memcpy(cpkt->buf, buf, len);
196 cpkt->len = len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197
198 spin_lock_irqsave(&port->port_lock, flags);
199 c = &port->ctrl_ch;
200
201 /* drop cpkt if ch is not open */
202 if (!test_bit(CH_OPENED, &c->flags)) {
Manu Gautam2b0234a2011-09-07 16:47:52 +0530203 free_rmnet_ctrl_pkt(cpkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700204 spin_unlock_irqrestore(&port->port_lock, flags);
205 return 0;
206 }
207
208 list_add_tail(&cpkt->list, &c->tx_q);
209 queue_work(grmnet_ctrl_wq, &c->write_w);
210 spin_unlock_irqrestore(&port->port_lock, flags);
211
212 return 0;
213}
214
Manu Gautam2b0234a2011-09-07 16:47:52 +0530215#define RMNET_CTRL_DTR 0x01
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700216static void
Hemant Kumarf60c0252011-11-03 12:37:07 -0700217gsmd_ctrl_send_cbits_tomodem(void *gptr, u8 portno, int cbits)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700218{
219 struct rmnet_ctrl_port *port;
220 struct smd_ch_info *c;
221 int set_bits = 0;
222 int clear_bits = 0;
223 int temp = 0;
224
Manu Gautam2b0234a2011-09-07 16:47:52 +0530225 if (portno >= n_rmnet_ctrl_ports) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700226 pr_err("%s: Invalid portno#%d\n", __func__, portno);
227 return;
228 }
229
Hemant Kumarf60c0252011-11-03 12:37:07 -0700230 if (!gptr) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700231 pr_err("%s: grmnet is null\n", __func__);
232 return;
233 }
234
Manu Gautam2b0234a2011-09-07 16:47:52 +0530235 port = ctrl_smd_ports[portno].port;
236 cbits = cbits & RMNET_CTRL_DTR;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700237 c = &port->ctrl_ch;
238
239 /* host driver will only send DTR, but to have generic
240 * set and clear bit implementation using two separate
241 * checks
242 */
Manu Gautam2b0234a2011-09-07 16:47:52 +0530243 if (cbits & RMNET_CTRL_DTR)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700244 set_bits |= TIOCM_DTR;
245 else
246 clear_bits |= TIOCM_DTR;
247
248 temp |= set_bits;
249 temp &= ~clear_bits;
250
251 if (temp == c->cbits_tomodem)
252 return;
253
254 c->cbits_tomodem = temp;
255
256 if (!test_bit(CH_OPENED, &c->flags))
257 return;
258
259 pr_debug("%s: ctrl_tomodem:%d ctrl_bits:%d setbits:%d clearbits:%d\n",
260 __func__, temp, cbits, set_bits, clear_bits);
261
262 smd_tiocmset(c->ch, set_bits, clear_bits);
263}
264
265static char *get_smd_event(unsigned event)
266{
267 switch (event) {
268 case SMD_EVENT_DATA:
269 return "DATA";
270 case SMD_EVENT_OPEN:
271 return "OPEN";
272 case SMD_EVENT_CLOSE:
273 return "CLOSE";
274 }
275
276 return "UNDEFINED";
277}
278
279static void grmnet_ctrl_smd_notify(void *p, unsigned event)
280{
281 struct rmnet_ctrl_port *port = p;
282 struct smd_ch_info *c = &port->ctrl_ch;
Vamsi Krishna9e9921a2011-10-04 16:09:31 -0700283 struct rmnet_ctrl_pkt *cpkt;
284 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700285
286 pr_debug("%s: EVENT_(%s)\n", __func__, get_smd_event(event));
287
288 switch (event) {
289 case SMD_EVENT_DATA:
290 if (smd_read_avail(c->ch))
291 queue_work(grmnet_ctrl_wq, &c->read_w);
292 if (smd_write_avail(c->ch))
293 queue_work(grmnet_ctrl_wq, &c->write_w);
294 break;
295 case SMD_EVENT_OPEN:
296 set_bit(CH_OPENED, &c->flags);
Vamsi Krishna9e9921a2011-10-04 16:09:31 -0700297
298 if (port && port->port_usb && port->port_usb->connect)
299 port->port_usb->connect(port->port_usb);
300
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700301 break;
302 case SMD_EVENT_CLOSE:
303 clear_bit(CH_OPENED, &c->flags);
Vamsi Krishna9e9921a2011-10-04 16:09:31 -0700304
305 if (port && port->port_usb && port->port_usb->disconnect)
306 port->port_usb->disconnect(port->port_usb);
307
308 spin_lock_irqsave(&port->port_lock, flags);
309 while (!list_empty(&c->tx_q)) {
310 cpkt = list_first_entry(&c->tx_q,
311 struct rmnet_ctrl_pkt, list);
312
313 list_del(&cpkt->list);
314 free_rmnet_ctrl_pkt(cpkt);
315 }
316 spin_unlock_irqrestore(&port->port_lock, flags);
317
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700318 break;
319 }
320}
321/*------------------------------------------------------------ */
322
323static void grmnet_ctrl_smd_connect_w(struct work_struct *w)
324{
325 struct rmnet_ctrl_port *port =
Chiranjeevi Velempati40608bb2012-01-27 14:09:47 +0530326 container_of(w, struct rmnet_ctrl_port, connect_w.work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700327 struct smd_ch_info *c = &port->ctrl_ch;
328 unsigned long flags;
Amit Blayc2b01792012-07-11 18:37:35 +0300329 int set_bits = 0;
330 int clear_bits = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700331 int ret;
332
333 pr_debug("%s:\n", __func__);
334
335 if (!test_bit(CH_READY, &c->flags))
336 return;
337
338 ret = smd_open(c->name, &c->ch, port, grmnet_ctrl_smd_notify);
339 if (ret) {
Chiranjeevi Velempati40608bb2012-01-27 14:09:47 +0530340 if (ret == -EAGAIN) {
341 /* port not ready - retry */
342 pr_debug("%s: SMD port not ready - rescheduling:%s err:%d\n",
343 __func__, c->name, ret);
344 queue_delayed_work(grmnet_ctrl_wq, &port->connect_w,
345 msecs_to_jiffies(250));
346 } else {
347 pr_err("%s: unable to open smd port:%s err:%d\n",
348 __func__, c->name, ret);
349 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700350 return;
351 }
352
Amit Blayc2b01792012-07-11 18:37:35 +0300353 set_bits = c->cbits_tomodem;
354 clear_bits = ~(c->cbits_tomodem | TIOCM_RTS);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700355 spin_lock_irqsave(&port->port_lock, flags);
356 if (port->port_usb)
Amit Blayc2b01792012-07-11 18:37:35 +0300357 smd_tiocmset(c->ch, set_bits, clear_bits);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700358 spin_unlock_irqrestore(&port->port_lock, flags);
359}
360
361int gsmd_ctrl_connect(struct grmnet *gr, int port_num)
362{
363 struct rmnet_ctrl_port *port;
364 struct smd_ch_info *c;
365 unsigned long flags;
366
367 pr_debug("%s: grmnet:%p port#%d\n", __func__, gr, port_num);
368
Manu Gautam2b0234a2011-09-07 16:47:52 +0530369 if (port_num >= n_rmnet_ctrl_ports) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700370 pr_err("%s: invalid portno#%d\n", __func__, port_num);
371 return -ENODEV;
372 }
373
374 if (!gr) {
375 pr_err("%s: grmnet port is null\n", __func__);
376 return -ENODEV;
377 }
378
Manu Gautam2b0234a2011-09-07 16:47:52 +0530379 port = ctrl_smd_ports[port_num].port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700380 c = &port->ctrl_ch;
381
382 spin_lock_irqsave(&port->port_lock, flags);
383 port->port_usb = gr;
Hemant Kumarf60c0252011-11-03 12:37:07 -0700384 gr->send_encap_cmd = grmnet_ctrl_smd_send_cpkt_tomodem;
385 gr->notify_modem = gsmd_ctrl_send_cbits_tomodem;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700386 spin_unlock_irqrestore(&port->port_lock, flags);
387
Chiranjeevi Velempati40608bb2012-01-27 14:09:47 +0530388 queue_delayed_work(grmnet_ctrl_wq, &port->connect_w, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700389
390 return 0;
391}
392
393void gsmd_ctrl_disconnect(struct grmnet *gr, u8 port_num)
394{
395 struct rmnet_ctrl_port *port;
396 unsigned long flags;
397 struct smd_ch_info *c;
Vamsi Krishna9e9921a2011-10-04 16:09:31 -0700398 struct rmnet_ctrl_pkt *cpkt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700399
400 pr_debug("%s: grmnet:%p port#%d\n", __func__, gr, port_num);
401
Manu Gautam2b0234a2011-09-07 16:47:52 +0530402 if (port_num >= n_rmnet_ctrl_ports) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700403 pr_err("%s: invalid portno#%d\n", __func__, port_num);
404 return;
405 }
406
407 if (!gr) {
408 pr_err("%s: grmnet port is null\n", __func__);
409 return;
410 }
411
Manu Gautam2b0234a2011-09-07 16:47:52 +0530412 port = ctrl_smd_ports[port_num].port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700413 c = &port->ctrl_ch;
414
415 spin_lock_irqsave(&port->port_lock, flags);
416 port->port_usb = 0;
Hemant Kumarf60c0252011-11-03 12:37:07 -0700417 gr->send_encap_cmd = 0;
418 gr->notify_modem = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700419 c->cbits_tomodem = 0;
Vamsi Krishna9e9921a2011-10-04 16:09:31 -0700420
421 while (!list_empty(&c->tx_q)) {
422 cpkt = list_first_entry(&c->tx_q, struct rmnet_ctrl_pkt, list);
423
424 list_del(&cpkt->list);
425 free_rmnet_ctrl_pkt(cpkt);
426 }
427
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700428 spin_unlock_irqrestore(&port->port_lock, flags);
429
Jack Phamc02d4812012-01-25 15:52:04 -0800430 if (test_and_clear_bit(CH_OPENED, &c->flags))
431 /* send dtr zero */
432 smd_tiocmset(c->ch, c->cbits_tomodem, ~c->cbits_tomodem);
433
434 if (c->ch) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700435 smd_close(c->ch);
Jack Phamc02d4812012-01-25 15:52:04 -0800436 c->ch = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700437 }
438}
439
440#define SMD_CH_MAX_LEN 20
441static int grmnet_ctrl_smd_ch_probe(struct platform_device *pdev)
442{
443 struct rmnet_ctrl_port *port;
444 struct smd_ch_info *c;
445 int i;
446 unsigned long flags;
447
448 pr_debug("%s: name:%s\n", __func__, pdev->name);
449
Manu Gautam2b0234a2011-09-07 16:47:52 +0530450 for (i = 0; i < n_rmnet_ctrl_ports; i++) {
451 port = ctrl_smd_ports[i].port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700452 c = &port->ctrl_ch;
453
454 if (!strncmp(c->name, pdev->name, SMD_CH_MAX_LEN)) {
455 set_bit(CH_READY, &c->flags);
456
457 /* if usb is online, try opening smd_ch */
458 spin_lock_irqsave(&port->port_lock, flags);
459 if (port->port_usb)
Chiranjeevi Velempati40608bb2012-01-27 14:09:47 +0530460 queue_delayed_work(grmnet_ctrl_wq,
461 &port->connect_w, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700462 spin_unlock_irqrestore(&port->port_lock, flags);
463
464 break;
465 }
466 }
467
468 return 0;
469}
470
471static int grmnet_ctrl_smd_ch_remove(struct platform_device *pdev)
472{
473 struct rmnet_ctrl_port *port;
474 struct smd_ch_info *c;
475 int i;
476
477 pr_debug("%s: name:%s\n", __func__, pdev->name);
478
Manu Gautam2b0234a2011-09-07 16:47:52 +0530479 for (i = 0; i < n_rmnet_ctrl_ports; i++) {
480 port = ctrl_smd_ports[i].port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700481 c = &port->ctrl_ch;
482
483 if (!strncmp(c->name, pdev->name, SMD_CH_MAX_LEN)) {
484 clear_bit(CH_READY, &c->flags);
485 clear_bit(CH_OPENED, &c->flags);
Jack Phamc02d4812012-01-25 15:52:04 -0800486 if (c->ch) {
487 smd_close(c->ch);
488 c->ch = NULL;
489 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700490 break;
491 }
492 }
493
494 return 0;
495}
496
497
498static void grmnet_ctrl_smd_port_free(int portno)
499{
Manu Gautam2b0234a2011-09-07 16:47:52 +0530500 struct rmnet_ctrl_port *port = ctrl_smd_ports[portno].port;
Jack Phameffd4ae2011-08-03 16:49:36 -0700501 struct platform_driver *pdrv = &ctrl_smd_ports[portno].pdrv;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700502
Jack Phameffd4ae2011-08-03 16:49:36 -0700503 if (port) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700504 kfree(port);
Jack Phameffd4ae2011-08-03 16:49:36 -0700505 platform_driver_unregister(pdrv);
506 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700507}
508
509static int grmnet_ctrl_smd_port_alloc(int portno)
510{
511 struct rmnet_ctrl_port *port;
512 struct smd_ch_info *c;
513 struct platform_driver *pdrv;
514
515 port = kzalloc(sizeof(struct rmnet_ctrl_port), GFP_KERNEL);
516 if (!port)
517 return -ENOMEM;
518
519 port->port_num = portno;
520
521 spin_lock_init(&port->port_lock);
Chiranjeevi Velempati40608bb2012-01-27 14:09:47 +0530522 INIT_DELAYED_WORK(&port->connect_w, grmnet_ctrl_smd_connect_w);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700523
524 c = &port->ctrl_ch;
525 c->name = rmnet_ctrl_names[portno];
526 c->port = port;
527 init_waitqueue_head(&c->wait);
528 INIT_LIST_HEAD(&c->tx_q);
529 INIT_WORK(&c->read_w, grmnet_ctrl_smd_read_w);
530 INIT_WORK(&c->write_w, grmnet_ctrl_smd_write_w);
531
Manu Gautam2b0234a2011-09-07 16:47:52 +0530532 ctrl_smd_ports[portno].port = port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700533
Manu Gautam2b0234a2011-09-07 16:47:52 +0530534 pdrv = &ctrl_smd_ports[portno].pdrv;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700535 pdrv->probe = grmnet_ctrl_smd_ch_probe;
536 pdrv->remove = grmnet_ctrl_smd_ch_remove;
537 pdrv->driver.name = c->name;
538 pdrv->driver.owner = THIS_MODULE;
539
540 platform_driver_register(pdrv);
541
542 pr_debug("%s: port:%p portno:%d\n", __func__, port, portno);
543
544 return 0;
545}
546
547int gsmd_ctrl_setup(unsigned int count)
548{
549 int i;
550 int ret;
551
552 pr_debug("%s: requested ports:%d\n", __func__, count);
553
Manu Gautam2b0234a2011-09-07 16:47:52 +0530554 if (!count || count > NR_CTRL_SMD_PORTS) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700555 pr_err("%s: Invalid num of ports count:%d\n",
556 __func__, count);
557 return -EINVAL;
558 }
559
560 grmnet_ctrl_wq = alloc_workqueue("gsmd_ctrl",
561 WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
562 if (!grmnet_ctrl_wq) {
563 pr_err("%s: Unable to create workqueue grmnet_ctrl\n",
564 __func__);
565 return -ENOMEM;
566 }
567
568 for (i = 0; i < count; i++) {
Ofir Cohena1c2a872011-12-14 10:26:34 +0200569 n_rmnet_ctrl_ports++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700570 ret = grmnet_ctrl_smd_port_alloc(i);
571 if (ret) {
572 pr_err("%s: Unable to alloc port:%d\n", __func__, i);
Ofir Cohena1c2a872011-12-14 10:26:34 +0200573 n_rmnet_ctrl_ports--;
Manu Gautam2b0234a2011-09-07 16:47:52 +0530574 goto free_ctrl_smd_ports;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700575 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700576 }
577
578 return 0;
579
Manu Gautam2b0234a2011-09-07 16:47:52 +0530580free_ctrl_smd_ports:
581 for (i = 0; i < n_rmnet_ctrl_ports; i++)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700582 grmnet_ctrl_smd_port_free(i);
583
584 destroy_workqueue(grmnet_ctrl_wq);
585
586 return ret;
587}
588
589#if defined(CONFIG_DEBUG_FS)
590#define DEBUG_BUF_SIZE 1024
591static ssize_t gsmd_ctrl_read_stats(struct file *file, char __user *ubuf,
592 size_t count, loff_t *ppos)
593{
594 struct rmnet_ctrl_port *port;
595 struct smd_ch_info *c;
596 char *buf;
597 unsigned long flags;
598 int ret;
599 int i;
600 int temp = 0;
601
602 buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
603 if (!buf)
604 return -ENOMEM;
605
Manu Gautam2b0234a2011-09-07 16:47:52 +0530606 for (i = 0; i < n_rmnet_ctrl_ports; i++) {
607 port = ctrl_smd_ports[i].port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700608 if (!port)
609 continue;
610 spin_lock_irqsave(&port->port_lock, flags);
611
612 c = &port->ctrl_ch;
613
614 temp += scnprintf(buf + temp, DEBUG_BUF_SIZE - temp,
615 "#PORT:%d port:%p ctrl_ch:%p#\n"
616 "to_usbhost: %lu\n"
617 "to_modem: %lu\n"
618 "DTR: %s\n"
619 "ch_open: %d\n"
620 "ch_ready: %d\n"
621 "read_avail: %d\n"
622 "write_avail:%d\n",
623 i, port, &port->ctrl_ch,
624 c->to_host, c->to_modem,
625 c->cbits_tomodem ? "HIGH" : "LOW",
626 test_bit(CH_OPENED, &c->flags),
627 test_bit(CH_READY, &c->flags),
Jack Phamc02d4812012-01-25 15:52:04 -0800628 c->ch ? smd_read_avail(c->ch) : 0,
629 c->ch ? smd_write_avail(c->ch) : 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700630
631 spin_unlock_irqrestore(&port->port_lock, flags);
632 }
633
634 ret = simple_read_from_buffer(ubuf, count, ppos, buf, temp);
635
636 kfree(buf);
637
638 return ret;
639}
640
641static ssize_t gsmd_ctrl_reset_stats(struct file *file, const char __user *buf,
642 size_t count, loff_t *ppos)
643{
644 struct rmnet_ctrl_port *port;
645 struct smd_ch_info *c;
646 int i;
647 unsigned long flags;
648
Manu Gautam2b0234a2011-09-07 16:47:52 +0530649 for (i = 0; i < n_rmnet_ctrl_ports; i++) {
650 port = ctrl_smd_ports[i].port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700651 if (!port)
652 continue;
653
654 spin_lock_irqsave(&port->port_lock, flags);
655
656 c = &port->ctrl_ch;
657
658 c->to_host = 0;
659 c->to_modem = 0;
660
661 spin_unlock_irqrestore(&port->port_lock, flags);
662 }
663 return count;
664}
665
666const struct file_operations gsmd_ctrl_stats_ops = {
667 .read = gsmd_ctrl_read_stats,
668 .write = gsmd_ctrl_reset_stats,
669};
670
671struct dentry *smd_ctrl_dent;
672struct dentry *smd_ctrl_dfile;
673static void gsmd_ctrl_debugfs_init(void)
674{
675 smd_ctrl_dent = debugfs_create_dir("usb_rmnet_ctrl_smd", 0);
676 if (IS_ERR(smd_ctrl_dent))
677 return;
678
679 smd_ctrl_dfile = debugfs_create_file("status", 0444, smd_ctrl_dent, 0,
680 &gsmd_ctrl_stats_ops);
681 if (!smd_ctrl_dfile || IS_ERR(smd_ctrl_dfile))
682 debugfs_remove(smd_ctrl_dent);
683}
684
685static void gsmd_ctrl_debugfs_exit(void)
686{
687 debugfs_remove(smd_ctrl_dfile);
688 debugfs_remove(smd_ctrl_dent);
689}
690
691#else
692static void gsmd_ctrl_debugfs_init(void) { }
693static void gsmd_ctrl_debugfs_exit(void) { }
694#endif
695
696static int __init gsmd_ctrl_init(void)
697{
698 gsmd_ctrl_debugfs_init();
699
700 return 0;
701}
702module_init(gsmd_ctrl_init);
703
704static void __exit gsmd_ctrl_exit(void)
705{
706 gsmd_ctrl_debugfs_exit();
707}
708module_exit(gsmd_ctrl_exit);
709MODULE_DESCRIPTION("smd control driver");
710MODULE_LICENSE("GPL v2");