blob: 3c91a470a0f223bb859734ee7948b57aafb2ceaa [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/*
2 * u_smd.c - utilities for USB gadget serial over smd
3 *
4 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
5 *
6 * This code also borrows from drivers/usb/gadget/u_serial.c, which is
7 * Copyright (C) 2000 - 2003 Al Borchers (alborchers@steinerpoint.com)
8 * Copyright (C) 2008 David Brownell
9 * Copyright (C) 2008 by Nokia Corporation
10 * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com)
11 * Copyright (C) 2000 Peter Berger (pberger@brimson.com)
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License version 2 and
15 * only version 2 as published by the Free Software Foundation.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 */
22#include <linux/kernel.h>
23#include <linux/interrupt.h>
24#include <linux/device.h>
25#include <linux/delay.h>
26#include <linux/slab.h>
27#include <linux/termios.h>
28#include <mach/msm_smd.h>
29#include <linux/debugfs.h>
30
31#include "u_serial.h"
32
33#define SMD_RX_QUEUE_SIZE 8
34#define SMD_RX_BUF_SIZE 2048
35
36#define SMD_TX_QUEUE_SIZE 8
37#define SMD_TX_BUF_SIZE 2048
38
39static struct workqueue_struct *gsmd_wq;
40
41#define SMD_N_PORTS 2
42#define CH_OPENED 0
Hemant Kumard3fb9bb2011-07-12 17:20:16 -070043#define CH_READY 1
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070044struct smd_port_info {
45 struct smd_channel *ch;
46 char *name;
47 unsigned long flags;
48 wait_queue_head_t wait;
49};
50
51struct smd_port_info smd_pi[SMD_N_PORTS] = {
52 {
53 .name = "DS",
54 },
55 {
56 .name = "UNUSED",
57 },
58};
59
60struct gsmd_port {
61 unsigned port_num;
62 spinlock_t port_lock;
63
64 unsigned n_read;
65 struct list_head read_pool;
66 struct list_head read_queue;
67 struct work_struct push;
68
69 struct list_head write_pool;
70 struct work_struct pull;
71
72 struct gserial *port_usb;
73
74 struct smd_port_info *pi;
75 struct work_struct connect_work;
76
77 /* At present, smd does not notify
78 * control bit change info from modem
79 */
80 struct work_struct update_modem_ctrl_sig;
81
82#define SMD_ACM_CTRL_DTR 0x01
83#define SMD_ACM_CTRL_RTS 0x02
84 unsigned cbits_to_modem;
85
86#define SMD_ACM_CTRL_DCD 0x01
87#define SMD_ACM_CTRL_DSR 0x02
88#define SMD_ACM_CTRL_BRK 0x04
89#define SMD_ACM_CTRL_RI 0x08
90 unsigned cbits_to_laptop;
91
92 /* pkt counters */
93 unsigned long nbytes_tomodem;
94 unsigned long nbytes_tolaptop;
95};
96
97static struct smd_portmaster {
98 struct mutex lock;
99 struct gsmd_port *port;
Hemant Kumard3fb9bb2011-07-12 17:20:16 -0700100 struct platform_driver pdrv;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700101} smd_ports[SMD_N_PORTS];
102static unsigned n_smd_ports;
103
104static void gsmd_free_req(struct usb_ep *ep, struct usb_request *req)
105{
106 kfree(req->buf);
107 usb_ep_free_request(ep, req);
108}
109
110static void gsmd_free_requests(struct usb_ep *ep, struct list_head *head)
111{
112 struct usb_request *req;
113
114 while (!list_empty(head)) {
115 req = list_entry(head->next, struct usb_request, list);
116 list_del(&req->list);
117 gsmd_free_req(ep, req);
118 }
119}
120
121static struct usb_request *
122gsmd_alloc_req(struct usb_ep *ep, unsigned len, gfp_t flags)
123{
124 struct usb_request *req;
125
126 req = usb_ep_alloc_request(ep, flags);
127 if (!req) {
128 pr_err("%s: usb alloc request failed\n", __func__);
129 return 0;
130 }
131
132 req->length = len;
133 req->buf = kmalloc(len, flags);
134 if (!req->buf) {
135 pr_err("%s: request buf allocation failed\n", __func__);
136 usb_ep_free_request(ep, req);
137 return 0;
138 }
139
140 return req;
141}
142
143static int gsmd_alloc_requests(struct usb_ep *ep, struct list_head *head,
144 int num, int size,
145 void (*cb)(struct usb_ep *ep, struct usb_request *))
146{
147 int i;
148 struct usb_request *req;
149
150 pr_debug("%s: ep:%p head:%p num:%d size:%d cb:%p", __func__,
151 ep, head, num, size, cb);
152
153 for (i = 0; i < num; i++) {
154 req = gsmd_alloc_req(ep, size, GFP_ATOMIC);
155 if (!req) {
156 pr_debug("%s: req allocated:%d\n", __func__, i);
157 return list_empty(head) ? -ENOMEM : 0;
158 }
159 req->complete = cb;
160 list_add(&req->list, head);
161 }
162
163 return 0;
164}
165
166static void gsmd_start_rx(struct gsmd_port *port)
167{
168 struct list_head *pool;
169 struct usb_ep *out;
170 int ret;
171
172 if (!port) {
173 pr_err("%s: port is null\n", __func__);
174 return;
175 }
176
177 spin_lock_irq(&port->port_lock);
178
179 if (!port->port_usb) {
180 pr_debug("%s: USB disconnected\n", __func__);
181 goto start_rx_end;
182 }
183
184 pool = &port->read_pool;
185 out = port->port_usb->out;
186
187 while (!list_empty(pool)) {
188 struct usb_request *req;
189
190 req = list_entry(pool->next, struct usb_request, list);
191 list_del(&req->list);
192 req->length = SMD_RX_BUF_SIZE;
193
194 spin_unlock_irq(&port->port_lock);
195 ret = usb_ep_queue(out, req, GFP_KERNEL);
196 spin_lock_irq(&port->port_lock);
197 if (ret) {
198 pr_err("%s: usb ep out queue failed"
199 "port:%p, port#%d\n",
200 __func__, port, port->port_num);
201 list_add_tail(&req->list, pool);
202 break;
203 }
204 }
205start_rx_end:
206 spin_unlock_irq(&port->port_lock);
207}
208
209static void gsmd_rx_push(struct work_struct *w)
210{
211 struct gsmd_port *port = container_of(w, struct gsmd_port, push);
212 struct list_head *q;
213
214 pr_debug("%s: port:%p port#%d", __func__, port, port->port_num);
215
216 spin_lock_irq(&port->port_lock);
217
218 q = &port->read_queue;
219 while (!list_empty(q)) {
220 struct usb_request *req;
221 int avail;
222 struct smd_port_info *pi = port->pi;
223
224 req = list_first_entry(q, struct usb_request, list);
225
226 switch (req->status) {
227 case -ESHUTDOWN:
228 pr_debug("%s: req status shutdown portno#%d port:%p\n",
229 __func__, port->port_num, port);
230 goto rx_push_end;
231 default:
232 pr_warning("%s: port:%p port#%d"
233 " Unexpected Rx Status:%d\n", __func__,
234 port, port->port_num, req->status);
235 case 0:
236 /* normal completion */
237 break;
238 }
239
240 avail = smd_write_avail(pi->ch);
241 if (!avail)
242 goto rx_push_end;
243
244 if (req->actual) {
245 char *packet = req->buf;
246 unsigned size = req->actual;
247 unsigned n;
248 unsigned count;
249
250 n = port->n_read;
251 if (n) {
252 packet += n;
253 size -= n;
254 }
255
256 count = smd_write(pi->ch, packet, size);
257 if (count < 0) {
258 pr_err("%s: smd write failed err:%d\n",
259 __func__, count);
260 goto rx_push_end;
261 }
262
263 if (count != size) {
264 port->n_read += count;
265 goto rx_push_end;
266 }
267
268 port->nbytes_tomodem += count;
269 }
270
271 port->n_read = 0;
272 list_move(&req->list, &port->read_pool);
273 }
274
275rx_push_end:
276 spin_unlock_irq(&port->port_lock);
277
278 gsmd_start_rx(port);
279}
280
281static void gsmd_read_pending(struct gsmd_port *port)
282{
283 int avail;
284
285 if (!port || !port->pi->ch)
286 return;
287
288 /* passing null buffer discards the data */
289 while ((avail = smd_read_avail(port->pi->ch)))
290 smd_read(port->pi->ch, 0, avail);
291
292 return;
293}
294
295static void gsmd_tx_pull(struct work_struct *w)
296{
297 struct gsmd_port *port = container_of(w, struct gsmd_port, pull);
298 struct list_head *pool = &port->write_pool;
299
300 pr_debug("%s: port:%p port#%d pool:%p\n", __func__,
301 port, port->port_num, pool);
302
303 if (!port->port_usb) {
304 pr_debug("%s: usb is disconnected\n", __func__);
305 gsmd_read_pending(port);
306 return;
307 }
308
309 spin_lock_irq(&port->port_lock);
310 while (!list_empty(pool)) {
311 struct usb_request *req;
312 struct usb_ep *in = port->port_usb->in;
313 struct smd_port_info *pi = port->pi;
314 int avail;
315 int ret;
316
317 avail = smd_read_avail(pi->ch);
318 if (!avail)
319 break;
320
321 avail = avail > SMD_TX_BUF_SIZE ? SMD_TX_BUF_SIZE : avail;
322
323 req = list_entry(pool->next, struct usb_request, list);
324 list_del(&req->list);
325 req->length = smd_read(pi->ch, req->buf, avail);
326
327 spin_unlock_irq(&port->port_lock);
328 ret = usb_ep_queue(in, req, GFP_KERNEL);
329 spin_lock_irq(&port->port_lock);
330 if (ret) {
331 pr_err("%s: usb ep out queue failed"
332 "port:%p, port#%d err:%d\n",
333 __func__, port, port->port_num, ret);
334 /* could be usb disconnected */
335 if (!port->port_usb)
336 gsmd_free_req(in, req);
337 else
338 list_add(&req->list, pool);
339 goto tx_pull_end;
340 }
341
342 port->nbytes_tolaptop += req->length;
343 }
344
345tx_pull_end:
346 /* TBD: Check how code behaves on USB bus suspend */
347 if (port->port_usb && smd_read_avail(port->pi->ch) && !list_empty(pool))
348 queue_work(gsmd_wq, &port->pull);
349
350 spin_unlock_irq(&port->port_lock);
351
352 return;
353}
354
355static void gsmd_read_complete(struct usb_ep *ep, struct usb_request *req)
356{
357 struct gsmd_port *port = ep->driver_data;
358 unsigned long flags;
359
360 pr_debug("%s: ep:%p port:%p\n", __func__, ep, port);
361
362 if (!port) {
363 pr_err("%s: port is null\n", __func__);
364 return;
365 }
366
367 spin_lock_irqsave(&port->port_lock, flags);
368 list_add_tail(&req->list, &port->read_queue);
369 queue_work(gsmd_wq, &port->push);
370 spin_unlock_irqrestore(&port->port_lock, flags);
371
372 return;
373}
374
375static void gsmd_write_complete(struct usb_ep *ep, struct usb_request *req)
376{
377 struct gsmd_port *port = ep->driver_data;
378 unsigned long flags;
379
380 pr_debug("%s: ep:%p port:%p\n", __func__, ep, port);
381
382 if (!port) {
383 pr_err("%s: port is null\n", __func__);
384 return;
385 }
386
387 spin_lock_irqsave(&port->port_lock, flags);
388 list_add(&req->list, &port->write_pool);
389
390 switch (req->status) {
391 default:
392 pr_warning("%s: port:%p port#%d unexpected %s status %d\n",
393 __func__, port, port->port_num,
394 ep->name, req->status);
395 /* FALL THROUGH */
396 case 0:
397 queue_work(gsmd_wq, &port->pull);
398 break;
399
400 case -ESHUTDOWN:
401 /* disconnect */
402 pr_debug("%s: %s shutdown\n", __func__, ep->name);
403 gsmd_free_req(ep, req);
404 break;
405 }
406
407 spin_unlock_irqrestore(&port->port_lock, flags);
408
409 return;
410}
411
412static void gsmd_start_io(struct gsmd_port *port)
413{
414 int ret = -ENODEV;
415 unsigned long flags;
416
417 pr_debug("%s: port: %p\n", __func__, port);
418
419 spin_lock_irqsave(&port->port_lock, flags);
420
421 if (!port->port_usb)
422 goto start_io_out;
423
424 ret = gsmd_alloc_requests(port->port_usb->out,
425 &port->read_pool,
426 SMD_RX_QUEUE_SIZE, SMD_RX_BUF_SIZE,
427 gsmd_read_complete);
428 if (ret) {
429 pr_err("%s: unable to allocate out requests\n",
430 __func__);
431 goto start_io_out;
432 }
433
434 ret = gsmd_alloc_requests(port->port_usb->in,
435 &port->write_pool,
436 SMD_TX_QUEUE_SIZE, SMD_TX_BUF_SIZE,
437 gsmd_write_complete);
438 if (ret) {
439 gsmd_free_requests(port->port_usb->out, &port->read_pool);
440 pr_err("%s: unable to allocate IN requests\n",
441 __func__);
442 goto start_io_out;
443 }
444
445start_io_out:
446 spin_unlock_irqrestore(&port->port_lock, flags);
447
448 if (ret)
449 return;
450
451 gsmd_start_rx(port);
452}
453
454static unsigned int convert_uart_sigs_to_acm(unsigned uart_sig)
455{
456 unsigned int acm_sig = 0;
457
458 /* should this needs to be in calling functions ??? */
459 uart_sig &= (TIOCM_RI | TIOCM_CD | TIOCM_DSR);
460
461 if (uart_sig & TIOCM_RI)
462 acm_sig |= SMD_ACM_CTRL_RI;
463 if (uart_sig & TIOCM_CD)
464 acm_sig |= SMD_ACM_CTRL_DCD;
465 if (uart_sig & TIOCM_DSR)
466 acm_sig |= SMD_ACM_CTRL_DSR;
467
468 return acm_sig;
469}
470
471static unsigned int convert_acm_sigs_to_uart(unsigned acm_sig)
472{
473 unsigned int uart_sig = 0;
474
475 /* should this needs to be in calling functions ??? */
476 acm_sig &= (SMD_ACM_CTRL_DTR | SMD_ACM_CTRL_RTS);
477
478 if (acm_sig & SMD_ACM_CTRL_DTR)
479 uart_sig |= TIOCM_DTR;
480 if (acm_sig & SMD_ACM_CTRL_RTS)
481 uart_sig |= TIOCM_RTS;
482
483 return uart_sig;
484}
485
486static void gsmd_notify(void *priv, unsigned event)
487{
488 struct gsmd_port *port = priv;
489 struct smd_port_info *pi = port->pi;
490 int i;
491
492 switch (event) {
493 case SMD_EVENT_DATA:
494 pr_debug("%s: Event data\n", __func__);
495 if (smd_read_avail(pi->ch))
496 queue_work(gsmd_wq, &port->pull);
497 if (smd_write_avail(pi->ch))
498 queue_work(gsmd_wq, &port->push);
499 break;
500 case SMD_EVENT_OPEN:
501 pr_debug("%s: Event Open\n", __func__);
502 set_bit(CH_OPENED, &pi->flags);
503 wake_up(&pi->wait);
504 break;
505 case SMD_EVENT_CLOSE:
506 pr_debug("%s: Event Close\n", __func__);
507 clear_bit(CH_OPENED, &pi->flags);
508 break;
509 case SMD_EVENT_STATUS:
510 i = smd_tiocmget(port->pi->ch);
511 port->cbits_to_laptop = convert_uart_sigs_to_acm(i);
512 if (port->port_usb && port->port_usb->send_modem_ctrl_bits)
513 port->port_usb->send_modem_ctrl_bits(port->port_usb,
514 port->cbits_to_laptop);
515 break;
516 }
517}
518
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700519static void gsmd_connect_work(struct work_struct *w)
520{
521 struct gsmd_port *port;
522 struct smd_port_info *pi;
523 int ret;
Hemant Kumard3fb9bb2011-07-12 17:20:16 -0700524 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700525
526 port = container_of(w, struct gsmd_port, connect_work);
527 pi = port->pi;
528
529 pr_debug("%s: port:%p port#%d\n", __func__, port, port->port_num);
530
Hemant Kumard3fb9bb2011-07-12 17:20:16 -0700531 if (!test_bit(CH_READY, &pi->flags))
532 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700533
Hemant Kumard3fb9bb2011-07-12 17:20:16 -0700534 ret = smd_named_open_on_edge(pi->name, SMD_APPS_MODEM,
535 &pi->ch, port, gsmd_notify);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700536
537 if (ret) {
538 pr_err("%s: unable to open smd port:%s err:%d\n",
539 __func__, pi->name, ret);
540 return;
541 }
542
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700543 wait_event(pi->wait, test_bit(CH_OPENED, &pi->flags));
544
Hemant Kumard3fb9bb2011-07-12 17:20:16 -0700545 spin_lock_irqsave(&port->port_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700546 /* update usb control signals to modem */
Hemant Kumard3fb9bb2011-07-12 17:20:16 -0700547 if (port->port_usb && port->cbits_to_modem)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700548 smd_tiocmset(port->pi->ch,
549 port->cbits_to_modem,
550 ~port->cbits_to_modem);
Hemant Kumard3fb9bb2011-07-12 17:20:16 -0700551 spin_unlock_irqrestore(&port->port_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700552
553 gsmd_start_io(port);
554}
555
556static void gsmd_notify_modem(struct gserial *gser, u8 portno, int ctrl_bits)
557{
558 struct gsmd_port *port;
559 int temp;
560
561 if (portno >= n_smd_ports) {
562 pr_err("%s: invalid portno#%d\n", __func__, portno);
563 return;
564 }
565
566 if (!gser) {
567 pr_err("%s: gser is null\n", __func__);
568 return;
569 }
570
571 port = smd_ports[portno].port;
572
573 temp = convert_acm_sigs_to_uart(ctrl_bits);
574
575 if (temp == port->cbits_to_modem)
576 return;
577
578 port->cbits_to_modem = temp;
579
580 /* usb could send control signal before smd is ready */
581 if (!test_bit(CH_OPENED, &port->pi->flags))
582 return;
583
584 /* if DTR is high, update latest modem info to laptop */
585 if (port->cbits_to_modem & TIOCM_DTR) {
586 unsigned i;
587
588 i = smd_tiocmget(port->pi->ch);
589 port->cbits_to_laptop = convert_uart_sigs_to_acm(i);
590
591 if (gser->send_modem_ctrl_bits)
592 gser->send_modem_ctrl_bits(
593 port->port_usb,
594 port->cbits_to_laptop);
595 }
596
597 smd_tiocmset(port->pi->ch,
598 port->cbits_to_modem,
599 ~port->cbits_to_modem);
600}
601
602int gsmd_connect(struct gserial *gser, u8 portno)
603{
604 unsigned long flags;
605 int ret;
606 struct gsmd_port *port;
607
608 pr_debug("%s: gserial:%p portno:%u\n", __func__, gser, portno);
609
610 if (portno >= n_smd_ports) {
611 pr_err("%s: Invalid port no#%d", __func__, portno);
612 return -EINVAL;
613 }
614
615 if (!gser) {
616 pr_err("%s: gser is null\n", __func__);
617 return -EINVAL;
618 }
619
620 port = smd_ports[portno].port;
621
622 spin_lock_irqsave(&port->port_lock, flags);
623 port->port_usb = gser;
624 gser->notify_modem = gsmd_notify_modem;
625 port->nbytes_tomodem = 0;
626 port->nbytes_tolaptop = 0;
627 spin_unlock_irqrestore(&port->port_lock, flags);
628
629 ret = usb_ep_enable(gser->in, gser->in_desc);
630 if (ret) {
631 pr_err("%s: usb_ep_enable failed eptype:IN ep:%p",
632 __func__, gser->in);
633 port->port_usb = 0;
634 return ret;
635 }
636 gser->in->driver_data = port;
637
638 ret = usb_ep_enable(gser->out, gser->out_desc);
639 if (ret) {
640 pr_err("%s: usb_ep_enable failed eptype:OUT ep:%p",
641 __func__, gser->out);
642 port->port_usb = 0;
643 gser->in->driver_data = 0;
644 return ret;
645 }
646 gser->out->driver_data = port;
647
648 queue_work(gsmd_wq, &port->connect_work);
649
650 return 0;
651}
652
653void gsmd_disconnect(struct gserial *gser, u8 portno)
654{
655 unsigned long flags;
656 struct gsmd_port *port;
657
658 pr_debug("%s: gserial:%p portno:%u\n", __func__, gser, portno);
659
660 if (portno >= n_smd_ports) {
661 pr_err("%s: invalid portno#%d\n", __func__, portno);
662 return;
663 }
664
665 if (!gser) {
666 pr_err("%s: gser is null\n", __func__);
667 return;
668 }
669
670 port = smd_ports[portno].port;
671
672 spin_lock_irqsave(&port->port_lock, flags);
673 port->port_usb = 0;
674 spin_unlock_irqrestore(&port->port_lock, flags);
675
676 /* disable endpoints, aborting down any active I/O */
677 usb_ep_disable(gser->out);
678 usb_ep_disable(gser->in);
679
680 spin_lock_irqsave(&port->port_lock, flags);
681 gsmd_free_requests(gser->out, &port->read_pool);
682 gsmd_free_requests(gser->out, &port->read_queue);
683 gsmd_free_requests(gser->in, &port->write_pool);
684 port->n_read = 0;
685 spin_unlock_irqrestore(&port->port_lock, flags);
686
687 if (!test_bit(CH_OPENED, &port->pi->flags))
688 return;
689
690 /* lower the dtr */
691 port->cbits_to_modem = 0;
692 smd_tiocmset(port->pi->ch,
693 port->cbits_to_modem,
694 ~port->cbits_to_modem);
695
696 smd_close(port->pi->ch);
Hemant Kumard3fb9bb2011-07-12 17:20:16 -0700697 clear_bit(CH_OPENED, &port->pi->flags);
698}
699
700#define SMD_CH_MAX_LEN 20
701static int gsmd_ch_probe(struct platform_device *pdev)
702{
703 struct gsmd_port *port;
704 struct smd_port_info *pi;
705 int i;
706 unsigned long flags;
707
708 pr_debug("%s: name:%s\n", __func__, pdev->name);
709
710 for (i = 0; i < n_smd_ports; i++) {
711 port = smd_ports[i].port;
712 pi = port->pi;
713
714 if (!strncmp(pi->name, pdev->name, SMD_CH_MAX_LEN)) {
715 set_bit(CH_READY, &pi->flags);
716 spin_lock_irqsave(&port->port_lock, flags);
717 if (port->port_usb)
718 queue_work(gsmd_wq, &port->connect_work);
719 spin_unlock_irqrestore(&port->port_lock, flags);
720 break;
721 }
722 }
723 return 0;
724}
725
726static int gsmd_ch_remove(struct platform_device *pdev)
727{
728 struct gsmd_port *port;
729 struct smd_port_info *pi;
730 int i;
731
732 pr_debug("%s: name:%s\n", __func__, pdev->name);
733
734 for (i = 0; i < n_smd_ports; i++) {
735 port = smd_ports[i].port;
736 pi = port->pi;
737
738 if (!strncmp(pi->name, pdev->name, SMD_CH_MAX_LEN)) {
739 clear_bit(CH_READY, &pi->flags);
740 clear_bit(CH_OPENED, &pi->flags);
741 smd_close(pi->ch);
742 break;
743 }
744 }
745 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700746}
747
748static void gsmd_port_free(int portno)
749{
750 struct gsmd_port *port = smd_ports[portno].port;
751
752 if (!port)
753 kfree(port);
754}
755
756static int gsmd_port_alloc(int portno, struct usb_cdc_line_coding *coding)
757{
758 struct gsmd_port *port;
Hemant Kumard3fb9bb2011-07-12 17:20:16 -0700759 struct platform_driver *pdrv;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700760
761 port = kzalloc(sizeof(struct gsmd_port), GFP_KERNEL);
762 if (!port)
763 return -ENOMEM;
764
765 port->port_num = portno;
766 port->pi = &smd_pi[portno];
767
768 spin_lock_init(&port->port_lock);
769
770 INIT_LIST_HEAD(&port->read_pool);
771 INIT_LIST_HEAD(&port->read_queue);
772 INIT_WORK(&port->push, gsmd_rx_push);
773
774 INIT_LIST_HEAD(&port->write_pool);
775 INIT_WORK(&port->pull, gsmd_tx_pull);
776
777 INIT_WORK(&port->connect_work, gsmd_connect_work);
778 init_waitqueue_head(&port->pi->wait);
779
780 smd_ports[portno].port = port;
Hemant Kumard3fb9bb2011-07-12 17:20:16 -0700781 pdrv = &smd_ports[portno].pdrv;
782 pdrv->probe = gsmd_ch_probe;
783 pdrv->remove = gsmd_ch_remove;
784 pdrv->driver.name = port->pi->name;
785 pdrv->driver.owner = THIS_MODULE;
786 platform_driver_register(pdrv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700787
788 pr_debug("%s: port:%p portno:%d\n", __func__, port, portno);
789
790 return 0;
791}
792
793#if defined(CONFIG_DEBUG_FS)
794static ssize_t debug_smd_read_stats(struct file *file, char __user *ubuf,
795 size_t count, loff_t *ppos)
796{
797 struct gsmd_port *port;
798 char *buf;
799 unsigned long flags;
800 int temp = 0;
801 int i;
802 int ret;
803
804 buf = kzalloc(sizeof(char) * 512, GFP_KERNEL);
805 if (!buf)
806 return -ENOMEM;
807
808 for (i = 0; i < n_smd_ports; i++) {
809 port = smd_ports[i].port;
810 spin_lock_irqsave(&port->port_lock, flags);
811 temp += scnprintf(buf + temp, 512 - temp,
812 "###PORT:%d###\n"
813 "nbytes_tolaptop: %lu\n"
814 "nbytes_tomodem: %lu\n"
815 "cbits_to_modem: %u\n"
816 "cbits_to_laptop: %u\n"
Hemant Kumard3fb9bb2011-07-12 17:20:16 -0700817 "n_read: %u\n"
818 "CH_OPENED: %d\n"
819 "CH_READY: %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700820 i, port->nbytes_tolaptop, port->nbytes_tomodem,
821 port->cbits_to_modem, port->cbits_to_laptop,
Hemant Kumard3fb9bb2011-07-12 17:20:16 -0700822 port->n_read,
823 test_bit(CH_OPENED, &port->pi->flags),
824 test_bit(CH_READY, &port->pi->flags));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700825 spin_unlock_irqrestore(&port->port_lock, flags);
826 }
827
828 ret = simple_read_from_buffer(ubuf, count, ppos, buf, temp);
829
830 kfree(buf);
831
832 return ret;
833
834}
835
836static ssize_t debug_smd_reset_stats(struct file *file, const char __user *buf,
837 size_t count, loff_t *ppos)
838{
839 struct gsmd_port *port;
840 unsigned long flags;
841 int i;
842
843 for (i = 0; i < n_smd_ports; i++) {
844 port = smd_ports[i].port;
845
846 spin_lock_irqsave(&port->port_lock, flags);
847 port->nbytes_tolaptop = 0;
848 port->nbytes_tomodem = 0;
849 spin_unlock_irqrestore(&port->port_lock, flags);
850 }
851
852 return count;
853}
854
855static int debug_smd_open(struct inode *inode, struct file *file)
856{
857 return 0;
858}
859
860static const struct file_operations debug_gsmd_ops = {
861 .open = debug_smd_open,
862 .read = debug_smd_read_stats,
863 .write = debug_smd_reset_stats,
864};
865
866static void gsmd_debugfs_init(void)
867{
868 struct dentry *dent;
869
870 dent = debugfs_create_dir("usb_gsmd", 0);
871 if (IS_ERR(dent))
872 return;
873
874 debugfs_create_file("status", 0444, dent, 0, &debug_gsmd_ops);
875}
876#else
877static void gsmd_debugfs_init(void) {}
878#endif
879
880int gsmd_setup(struct usb_gadget *g, unsigned count)
881{
882 struct usb_cdc_line_coding coding;
883 int ret;
884 int i;
885
886 pr_debug("%s: g:%p count: %d\n", __func__, g, count);
887
888 if (!count || count > SMD_N_PORTS) {
889 pr_err("%s: Invalid num of ports count:%d gadget:%p\n",
890 __func__, count, g);
891 return -EINVAL;
892 }
893
894 coding.dwDTERate = cpu_to_le32(9600);
895 coding.bCharFormat = 8;
896 coding.bParityType = USB_CDC_NO_PARITY;
897 coding.bDataBits = USB_CDC_1_STOP_BITS;
898
899 gsmd_wq = create_singlethread_workqueue("k_gsmd");
900 if (!gsmd_wq) {
901 pr_err("%s: Unable to create workqueue gsmd_wq\n",
902 __func__);
903 return -ENOMEM;
904 }
905
906 for (i = 0; i < count; i++) {
907 mutex_init(&smd_ports[i].lock);
Manu Gautam4bd21422011-09-09 14:55:32 +0530908 n_smd_ports++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700909 ret = gsmd_port_alloc(i, &coding);
910 if (ret) {
Manu Gautam4bd21422011-09-09 14:55:32 +0530911 n_smd_ports--;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700912 pr_err("%s: Unable to alloc port:%d\n", __func__, i);
913 goto free_smd_ports;
914 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700915 }
916
917 gsmd_debugfs_init();
918
919 return 0;
920free_smd_ports:
921 for (i = 0; i < n_smd_ports; i++)
922 gsmd_port_free(i);
923
924 destroy_workqueue(gsmd_wq);
925
926 return ret;
927}
928
929void gsmd_cleanup(struct usb_gadget *g, unsigned count)
930{
931 /* TBD */
932}