blob: a55fc7777996f8a364d1e0a21fa7c4a294f75fa3 [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
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;
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
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 =
Chiranjeevi Velempati40608bb2012-01-27 14:09:47 +0530323 container_of(w, struct rmnet_ctrl_port, connect_w.work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700324 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) {
Chiranjeevi Velempati40608bb2012-01-27 14:09:47 +0530335 if (ret == -EAGAIN) {
336 /* port not ready - retry */
337 pr_debug("%s: SMD port not ready - rescheduling:%s err:%d\n",
338 __func__, c->name, ret);
339 queue_delayed_work(grmnet_ctrl_wq, &port->connect_w,
340 msecs_to_jiffies(250));
341 } else {
342 pr_err("%s: unable to open smd port:%s err:%d\n",
343 __func__, c->name, ret);
344 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700345 return;
346 }
347
348 spin_lock_irqsave(&port->port_lock, flags);
349 if (port->port_usb)
350 smd_tiocmset(c->ch, c->cbits_tomodem, ~c->cbits_tomodem);
351 spin_unlock_irqrestore(&port->port_lock, flags);
352}
353
354int gsmd_ctrl_connect(struct grmnet *gr, int port_num)
355{
356 struct rmnet_ctrl_port *port;
357 struct smd_ch_info *c;
358 unsigned long flags;
359
360 pr_debug("%s: grmnet:%p port#%d\n", __func__, gr, port_num);
361
Manu Gautam2b0234a2011-09-07 16:47:52 +0530362 if (port_num >= n_rmnet_ctrl_ports) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700363 pr_err("%s: invalid portno#%d\n", __func__, port_num);
364 return -ENODEV;
365 }
366
367 if (!gr) {
368 pr_err("%s: grmnet port is null\n", __func__);
369 return -ENODEV;
370 }
371
Manu Gautam2b0234a2011-09-07 16:47:52 +0530372 port = ctrl_smd_ports[port_num].port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700373 c = &port->ctrl_ch;
374
375 spin_lock_irqsave(&port->port_lock, flags);
376 port->port_usb = gr;
Hemant Kumarf60c0252011-11-03 12:37:07 -0700377 gr->send_encap_cmd = grmnet_ctrl_smd_send_cpkt_tomodem;
378 gr->notify_modem = gsmd_ctrl_send_cbits_tomodem;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700379 spin_unlock_irqrestore(&port->port_lock, flags);
380
Chiranjeevi Velempati40608bb2012-01-27 14:09:47 +0530381 queue_delayed_work(grmnet_ctrl_wq, &port->connect_w, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700382
383 return 0;
384}
385
386void gsmd_ctrl_disconnect(struct grmnet *gr, u8 port_num)
387{
388 struct rmnet_ctrl_port *port;
389 unsigned long flags;
390 struct smd_ch_info *c;
Vamsi Krishna9e9921a2011-10-04 16:09:31 -0700391 struct rmnet_ctrl_pkt *cpkt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700392
393 pr_debug("%s: grmnet:%p port#%d\n", __func__, gr, port_num);
394
Manu Gautam2b0234a2011-09-07 16:47:52 +0530395 if (port_num >= n_rmnet_ctrl_ports) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700396 pr_err("%s: invalid portno#%d\n", __func__, port_num);
397 return;
398 }
399
400 if (!gr) {
401 pr_err("%s: grmnet port is null\n", __func__);
402 return;
403 }
404
Manu Gautam2b0234a2011-09-07 16:47:52 +0530405 port = ctrl_smd_ports[port_num].port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700406 c = &port->ctrl_ch;
407
408 spin_lock_irqsave(&port->port_lock, flags);
409 port->port_usb = 0;
Hemant Kumarf60c0252011-11-03 12:37:07 -0700410 gr->send_encap_cmd = 0;
411 gr->notify_modem = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700412 c->cbits_tomodem = 0;
Vamsi Krishna9e9921a2011-10-04 16:09:31 -0700413
414 while (!list_empty(&c->tx_q)) {
415 cpkt = list_first_entry(&c->tx_q, struct rmnet_ctrl_pkt, list);
416
417 list_del(&cpkt->list);
418 free_rmnet_ctrl_pkt(cpkt);
419 }
420
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700421 spin_unlock_irqrestore(&port->port_lock, flags);
422
Jack Phamc02d4812012-01-25 15:52:04 -0800423 if (test_and_clear_bit(CH_OPENED, &c->flags))
424 /* send dtr zero */
425 smd_tiocmset(c->ch, c->cbits_tomodem, ~c->cbits_tomodem);
426
427 if (c->ch) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700428 smd_close(c->ch);
Jack Phamc02d4812012-01-25 15:52:04 -0800429 c->ch = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700430 }
431}
432
433#define SMD_CH_MAX_LEN 20
434static int grmnet_ctrl_smd_ch_probe(struct platform_device *pdev)
435{
436 struct rmnet_ctrl_port *port;
437 struct smd_ch_info *c;
438 int i;
439 unsigned long flags;
440
441 pr_debug("%s: name:%s\n", __func__, pdev->name);
442
Manu Gautam2b0234a2011-09-07 16:47:52 +0530443 for (i = 0; i < n_rmnet_ctrl_ports; i++) {
444 port = ctrl_smd_ports[i].port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700445 c = &port->ctrl_ch;
446
447 if (!strncmp(c->name, pdev->name, SMD_CH_MAX_LEN)) {
448 set_bit(CH_READY, &c->flags);
449
450 /* if usb is online, try opening smd_ch */
451 spin_lock_irqsave(&port->port_lock, flags);
452 if (port->port_usb)
Chiranjeevi Velempati40608bb2012-01-27 14:09:47 +0530453 queue_delayed_work(grmnet_ctrl_wq,
454 &port->connect_w, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700455 spin_unlock_irqrestore(&port->port_lock, flags);
456
457 break;
458 }
459 }
460
461 return 0;
462}
463
464static int grmnet_ctrl_smd_ch_remove(struct platform_device *pdev)
465{
466 struct rmnet_ctrl_port *port;
467 struct smd_ch_info *c;
468 int i;
469
470 pr_debug("%s: name:%s\n", __func__, pdev->name);
471
Manu Gautam2b0234a2011-09-07 16:47:52 +0530472 for (i = 0; i < n_rmnet_ctrl_ports; i++) {
473 port = ctrl_smd_ports[i].port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700474 c = &port->ctrl_ch;
475
476 if (!strncmp(c->name, pdev->name, SMD_CH_MAX_LEN)) {
477 clear_bit(CH_READY, &c->flags);
478 clear_bit(CH_OPENED, &c->flags);
Jack Phamc02d4812012-01-25 15:52:04 -0800479 if (c->ch) {
480 smd_close(c->ch);
481 c->ch = NULL;
482 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700483 break;
484 }
485 }
486
487 return 0;
488}
489
490
491static void grmnet_ctrl_smd_port_free(int portno)
492{
Manu Gautam2b0234a2011-09-07 16:47:52 +0530493 struct rmnet_ctrl_port *port = ctrl_smd_ports[portno].port;
Jack Phameffd4ae2011-08-03 16:49:36 -0700494 struct platform_driver *pdrv = &ctrl_smd_ports[portno].pdrv;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700495
Jack Phameffd4ae2011-08-03 16:49:36 -0700496 if (port) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700497 kfree(port);
Jack Phameffd4ae2011-08-03 16:49:36 -0700498 platform_driver_unregister(pdrv);
499 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700500}
501
502static int grmnet_ctrl_smd_port_alloc(int portno)
503{
504 struct rmnet_ctrl_port *port;
505 struct smd_ch_info *c;
506 struct platform_driver *pdrv;
507
508 port = kzalloc(sizeof(struct rmnet_ctrl_port), GFP_KERNEL);
509 if (!port)
510 return -ENOMEM;
511
512 port->port_num = portno;
513
514 spin_lock_init(&port->port_lock);
Chiranjeevi Velempati40608bb2012-01-27 14:09:47 +0530515 INIT_DELAYED_WORK(&port->connect_w, grmnet_ctrl_smd_connect_w);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700516
517 c = &port->ctrl_ch;
518 c->name = rmnet_ctrl_names[portno];
519 c->port = port;
520 init_waitqueue_head(&c->wait);
521 INIT_LIST_HEAD(&c->tx_q);
522 INIT_WORK(&c->read_w, grmnet_ctrl_smd_read_w);
523 INIT_WORK(&c->write_w, grmnet_ctrl_smd_write_w);
524
Manu Gautam2b0234a2011-09-07 16:47:52 +0530525 ctrl_smd_ports[portno].port = port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700526
Manu Gautam2b0234a2011-09-07 16:47:52 +0530527 pdrv = &ctrl_smd_ports[portno].pdrv;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700528 pdrv->probe = grmnet_ctrl_smd_ch_probe;
529 pdrv->remove = grmnet_ctrl_smd_ch_remove;
530 pdrv->driver.name = c->name;
531 pdrv->driver.owner = THIS_MODULE;
532
533 platform_driver_register(pdrv);
534
535 pr_debug("%s: port:%p portno:%d\n", __func__, port, portno);
536
537 return 0;
538}
539
540int gsmd_ctrl_setup(unsigned int count)
541{
542 int i;
543 int ret;
544
545 pr_debug("%s: requested ports:%d\n", __func__, count);
546
Manu Gautam2b0234a2011-09-07 16:47:52 +0530547 if (!count || count > NR_CTRL_SMD_PORTS) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700548 pr_err("%s: Invalid num of ports count:%d\n",
549 __func__, count);
550 return -EINVAL;
551 }
552
553 grmnet_ctrl_wq = alloc_workqueue("gsmd_ctrl",
554 WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
555 if (!grmnet_ctrl_wq) {
556 pr_err("%s: Unable to create workqueue grmnet_ctrl\n",
557 __func__);
558 return -ENOMEM;
559 }
560
561 for (i = 0; i < count; i++) {
Ofir Cohena1c2a872011-12-14 10:26:34 +0200562 n_rmnet_ctrl_ports++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700563 ret = grmnet_ctrl_smd_port_alloc(i);
564 if (ret) {
565 pr_err("%s: Unable to alloc port:%d\n", __func__, i);
Ofir Cohena1c2a872011-12-14 10:26:34 +0200566 n_rmnet_ctrl_ports--;
Manu Gautam2b0234a2011-09-07 16:47:52 +0530567 goto free_ctrl_smd_ports;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700568 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700569 }
570
571 return 0;
572
Manu Gautam2b0234a2011-09-07 16:47:52 +0530573free_ctrl_smd_ports:
574 for (i = 0; i < n_rmnet_ctrl_ports; i++)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700575 grmnet_ctrl_smd_port_free(i);
576
577 destroy_workqueue(grmnet_ctrl_wq);
578
579 return ret;
580}
581
582#if defined(CONFIG_DEBUG_FS)
583#define DEBUG_BUF_SIZE 1024
584static ssize_t gsmd_ctrl_read_stats(struct file *file, char __user *ubuf,
585 size_t count, loff_t *ppos)
586{
587 struct rmnet_ctrl_port *port;
588 struct smd_ch_info *c;
589 char *buf;
590 unsigned long flags;
591 int ret;
592 int i;
593 int temp = 0;
594
595 buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
596 if (!buf)
597 return -ENOMEM;
598
Manu Gautam2b0234a2011-09-07 16:47:52 +0530599 for (i = 0; i < n_rmnet_ctrl_ports; i++) {
600 port = ctrl_smd_ports[i].port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700601 if (!port)
602 continue;
603 spin_lock_irqsave(&port->port_lock, flags);
604
605 c = &port->ctrl_ch;
606
607 temp += scnprintf(buf + temp, DEBUG_BUF_SIZE - temp,
608 "#PORT:%d port:%p ctrl_ch:%p#\n"
609 "to_usbhost: %lu\n"
610 "to_modem: %lu\n"
611 "DTR: %s\n"
612 "ch_open: %d\n"
613 "ch_ready: %d\n"
614 "read_avail: %d\n"
615 "write_avail:%d\n",
616 i, port, &port->ctrl_ch,
617 c->to_host, c->to_modem,
618 c->cbits_tomodem ? "HIGH" : "LOW",
619 test_bit(CH_OPENED, &c->flags),
620 test_bit(CH_READY, &c->flags),
Jack Phamc02d4812012-01-25 15:52:04 -0800621 c->ch ? smd_read_avail(c->ch) : 0,
622 c->ch ? smd_write_avail(c->ch) : 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700623
624 spin_unlock_irqrestore(&port->port_lock, flags);
625 }
626
627 ret = simple_read_from_buffer(ubuf, count, ppos, buf, temp);
628
629 kfree(buf);
630
631 return ret;
632}
633
634static ssize_t gsmd_ctrl_reset_stats(struct file *file, const char __user *buf,
635 size_t count, loff_t *ppos)
636{
637 struct rmnet_ctrl_port *port;
638 struct smd_ch_info *c;
639 int i;
640 unsigned long flags;
641
Manu Gautam2b0234a2011-09-07 16:47:52 +0530642 for (i = 0; i < n_rmnet_ctrl_ports; i++) {
643 port = ctrl_smd_ports[i].port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700644 if (!port)
645 continue;
646
647 spin_lock_irqsave(&port->port_lock, flags);
648
649 c = &port->ctrl_ch;
650
651 c->to_host = 0;
652 c->to_modem = 0;
653
654 spin_unlock_irqrestore(&port->port_lock, flags);
655 }
656 return count;
657}
658
659const struct file_operations gsmd_ctrl_stats_ops = {
660 .read = gsmd_ctrl_read_stats,
661 .write = gsmd_ctrl_reset_stats,
662};
663
664struct dentry *smd_ctrl_dent;
665struct dentry *smd_ctrl_dfile;
666static void gsmd_ctrl_debugfs_init(void)
667{
668 smd_ctrl_dent = debugfs_create_dir("usb_rmnet_ctrl_smd", 0);
669 if (IS_ERR(smd_ctrl_dent))
670 return;
671
672 smd_ctrl_dfile = debugfs_create_file("status", 0444, smd_ctrl_dent, 0,
673 &gsmd_ctrl_stats_ops);
674 if (!smd_ctrl_dfile || IS_ERR(smd_ctrl_dfile))
675 debugfs_remove(smd_ctrl_dent);
676}
677
678static void gsmd_ctrl_debugfs_exit(void)
679{
680 debugfs_remove(smd_ctrl_dfile);
681 debugfs_remove(smd_ctrl_dent);
682}
683
684#else
685static void gsmd_ctrl_debugfs_init(void) { }
686static void gsmd_ctrl_debugfs_exit(void) { }
687#endif
688
689static int __init gsmd_ctrl_init(void)
690{
691 gsmd_ctrl_debugfs_init();
692
693 return 0;
694}
695module_init(gsmd_ctrl_init);
696
697static void __exit gsmd_ctrl_exit(void)
698{
699 gsmd_ctrl_debugfs_exit();
700}
701module_exit(gsmd_ctrl_exit);
702MODULE_DESCRIPTION("smd control driver");
703MODULE_LICENSE("GPL v2");