u_ctrl_hsuart.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601
  1. /* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. */
  12. #include <linux/kernel.h>
  13. #include <linux/interrupt.h>
  14. #include <linux/device.h>
  15. #include <linux/delay.h>
  16. #include <linux/slab.h>
  17. #include <linux/termios.h>
  18. #include <linux/debugfs.h>
  19. #include <linux/smux.h>
  20. #include <linux/completion.h>
  21. #include <mach/usb_gadget_xport.h>
  22. #define CH_OPENED 0
  23. #define CH_READY 1
  24. #define CH_CONNECTED 2
  25. static unsigned int num_ctrl_ports;
  26. static const char *ghsuart_ctrl_names[] = {
  27. "SMUX_RMNET_CTL_HSUART"
  28. };
  29. struct ghsuart_ctrl_port {
  30. /* port */
  31. unsigned port_num;
  32. /* gadget */
  33. enum gadget_type gtype;
  34. spinlock_t port_lock;
  35. void *port_usb;
  36. struct completion close_complete;
  37. /* work queue*/
  38. struct workqueue_struct *wq;
  39. struct work_struct connect_w;
  40. struct work_struct disconnect_w;
  41. /*ctrl pkt response cb*/
  42. int (*send_cpkt_response)(void *g, void *buf, size_t len);
  43. void *ctxt;
  44. unsigned int ch_id;
  45. /* flow control bits */
  46. unsigned long flags;
  47. int (*send_pkt)(void *, void *, size_t actual);
  48. /* Channel status */
  49. unsigned long channel_sts;
  50. /* control bits */
  51. unsigned cbits_tomodem;
  52. /* counters */
  53. unsigned long to_modem;
  54. unsigned long to_host;
  55. unsigned long drp_cpkt_cnt;
  56. };
  57. static struct {
  58. struct ghsuart_ctrl_port *port;
  59. struct platform_driver pdrv;
  60. } ghsuart_ctrl_ports[NUM_HSUART_PORTS];
  61. static int ghsuart_ctrl_receive(void *dev, void *buf, size_t actual);
  62. static void smux_control_event(void *priv, int event_type, const void *metadata)
  63. {
  64. struct grmnet *gr = NULL;
  65. struct ghsuart_ctrl_port *port = priv;
  66. void *buf;
  67. unsigned long flags;
  68. size_t len;
  69. switch (event_type) {
  70. case SMUX_LOCAL_CLOSED:
  71. clear_bit(CH_OPENED, &port->channel_sts);
  72. complete(&port->close_complete);
  73. break;
  74. case SMUX_CONNECTED:
  75. spin_lock_irqsave(&port->port_lock, flags);
  76. if (!port->port_usb) {
  77. spin_unlock_irqrestore(&port->port_lock, flags);
  78. return;
  79. }
  80. spin_unlock_irqrestore(&port->port_lock, flags);
  81. set_bit(CH_CONNECTED, &port->channel_sts);
  82. if (port->gtype == USB_GADGET_RMNET) {
  83. gr = port->port_usb;
  84. if (gr && gr->connect)
  85. gr->connect(gr);
  86. }
  87. break;
  88. case SMUX_DISCONNECTED:
  89. clear_bit(CH_CONNECTED, &port->channel_sts);
  90. break;
  91. case SMUX_READ_DONE:
  92. len = ((struct smux_meta_read *)metadata)->len;
  93. buf = ((struct smux_meta_read *)metadata)->buffer;
  94. ghsuart_ctrl_receive(port, buf, len);
  95. break;
  96. case SMUX_READ_FAIL:
  97. buf = ((struct smux_meta_read *)metadata)->buffer;
  98. kfree(buf);
  99. break;
  100. case SMUX_WRITE_DONE:
  101. case SMUX_WRITE_FAIL:
  102. buf = ((struct smux_meta_write *)metadata)->buffer;
  103. kfree(buf);
  104. break;
  105. case SMUX_LOW_WM_HIT:
  106. case SMUX_HIGH_WM_HIT:
  107. case SMUX_TIOCM_UPDATE:
  108. break;
  109. default:
  110. pr_err("%s Event %d not supported\n", __func__, event_type);
  111. };
  112. }
  113. static int rx_control_buffer(void *priv, void **pkt_priv, void **buffer,
  114. int size)
  115. {
  116. void *rx_buf;
  117. rx_buf = kmalloc(size, GFP_KERNEL);
  118. if (!rx_buf)
  119. return -EAGAIN;
  120. *buffer = rx_buf;
  121. *pkt_priv = NULL;
  122. return 0;
  123. }
  124. static int ghsuart_ctrl_receive(void *dev, void *buf, size_t actual)
  125. {
  126. struct ghsuart_ctrl_port *port = dev;
  127. int retval = 0;
  128. pr_debug_ratelimited("%s: read complete bytes read: %d\n",
  129. __func__, actual);
  130. /* send it to USB here */
  131. if (port && port->send_cpkt_response) {
  132. retval = port->send_cpkt_response(port->port_usb, buf, actual);
  133. port->to_host++;
  134. }
  135. kfree(buf);
  136. return retval;
  137. }
  138. static int
  139. ghsuart_send_cpkt_tomodem(u8 portno, void *buf, size_t len)
  140. {
  141. void *cbuf;
  142. struct ghsuart_ctrl_port *port;
  143. int ret;
  144. if (portno >= num_ctrl_ports) {
  145. pr_err("%s: Invalid portno#%d\n", __func__, portno);
  146. return -ENODEV;
  147. }
  148. port = ghsuart_ctrl_ports[portno].port;
  149. if (!port) {
  150. pr_err("%s: port is null\n", __func__);
  151. return -ENODEV;
  152. }
  153. /* drop cpkt if ch is not open */
  154. if (!test_bit(CH_CONNECTED, &port->channel_sts)) {
  155. port->drp_cpkt_cnt++;
  156. return 0;
  157. }
  158. cbuf = kmalloc(len, GFP_ATOMIC);
  159. if (!cbuf)
  160. return -ENOMEM;
  161. memcpy(cbuf, buf, len);
  162. pr_debug("%s: ctrl_pkt:%d bytes\n", __func__, len);
  163. ret = msm_smux_write(port->ch_id, port, (void *)cbuf, len);
  164. if (ret < 0) {
  165. pr_err_ratelimited("%s: write error:%d\n",
  166. __func__, ret);
  167. port->drp_cpkt_cnt++;
  168. kfree(cbuf);
  169. return ret;
  170. }
  171. port->to_modem++;
  172. return 0;
  173. }
  174. static void
  175. ghsuart_send_cbits_tomodem(void *gptr, u8 portno, int cbits)
  176. {
  177. struct ghsuart_ctrl_port *port;
  178. if (portno >= num_ctrl_ports || !gptr) {
  179. pr_err("%s: Invalid portno#%d\n", __func__, portno);
  180. return;
  181. }
  182. port = ghsuart_ctrl_ports[portno].port;
  183. if (!port) {
  184. pr_err("%s: port is null\n", __func__);
  185. return;
  186. }
  187. if (cbits == port->cbits_tomodem)
  188. return;
  189. port->cbits_tomodem = cbits;
  190. if (!test_bit(CH_CONNECTED, &port->channel_sts))
  191. return;
  192. pr_debug("%s: ctrl_tomodem:%d\n", __func__, cbits);
  193. /* Send the control bits to the Modem */
  194. msm_smux_tiocm_set(port->ch_id, cbits, ~cbits);
  195. }
  196. static void ghsuart_ctrl_connect_w(struct work_struct *w)
  197. {
  198. struct ghsuart_ctrl_port *port =
  199. container_of(w, struct ghsuart_ctrl_port, connect_w);
  200. int retval;
  201. if (!port || !test_bit(CH_READY, &port->channel_sts))
  202. return;
  203. pr_debug("%s: port:%pK\n", __func__, port);
  204. if (test_bit(CH_OPENED, &port->channel_sts)) {
  205. retval = wait_for_completion_timeout(
  206. &port->close_complete, 3 * HZ);
  207. if (retval == 0) {
  208. pr_err("%s: smux close timedout\n", __func__);
  209. return;
  210. }
  211. }
  212. retval = msm_smux_open(port->ch_id, port->ctxt, smux_control_event,
  213. rx_control_buffer);
  214. if (retval < 0) {
  215. pr_err(" %s smux_open failed\n", __func__);
  216. return;
  217. }
  218. set_bit(CH_OPENED, &port->channel_sts);
  219. }
  220. int ghsuart_ctrl_connect(void *gptr, int port_num)
  221. {
  222. struct ghsuart_ctrl_port *port;
  223. struct grmnet *gr;
  224. unsigned long flags;
  225. pr_debug("%s: port#%d\n", __func__, port_num);
  226. if (port_num > num_ctrl_ports || !gptr) {
  227. pr_err("%s: invalid portno#%d\n", __func__, port_num);
  228. return -ENODEV;
  229. }
  230. port = ghsuart_ctrl_ports[port_num].port;
  231. if (!port) {
  232. pr_err("%s: port is null\n", __func__);
  233. return -ENODEV;
  234. }
  235. spin_lock_irqsave(&port->port_lock, flags);
  236. gr = gptr;
  237. port->send_cpkt_response = gr->send_cpkt_response;
  238. gr->send_encap_cmd = ghsuart_send_cpkt_tomodem;
  239. gr->notify_modem = ghsuart_send_cbits_tomodem;
  240. port->port_usb = gptr;
  241. port->to_host = 0;
  242. port->to_modem = 0;
  243. port->drp_cpkt_cnt = 0;
  244. spin_unlock_irqrestore(&port->port_lock, flags);
  245. if (test_bit(CH_READY, &port->channel_sts))
  246. queue_work(port->wq, &port->connect_w);
  247. return 0;
  248. }
  249. static void ghsuart_ctrl_disconnect_w(struct work_struct *w)
  250. {
  251. struct ghsuart_ctrl_port *port =
  252. container_of(w, struct ghsuart_ctrl_port, disconnect_w);
  253. if (!test_bit(CH_OPENED, &port->channel_sts))
  254. return;
  255. INIT_COMPLETION(port->close_complete);
  256. msm_smux_close(port->ch_id);
  257. clear_bit(CH_CONNECTED, &port->channel_sts);
  258. }
  259. void ghsuart_ctrl_disconnect(void *gptr, int port_num)
  260. {
  261. struct ghsuart_ctrl_port *port;
  262. struct grmnet *gr = NULL;
  263. unsigned long flags;
  264. pr_debug("%s: port#%d\n", __func__, port_num);
  265. if (port_num > num_ctrl_ports) {
  266. pr_err("%s: invalid portno#%d\n", __func__, port_num);
  267. return;
  268. }
  269. port = ghsuart_ctrl_ports[port_num].port;
  270. if (!gptr || !port) {
  271. pr_err("%s: grmnet port is null\n", __func__);
  272. return;
  273. }
  274. gr = gptr;
  275. spin_lock_irqsave(&port->port_lock, flags);
  276. gr->send_encap_cmd = 0;
  277. gr->notify_modem = 0;
  278. port->cbits_tomodem = 0;
  279. port->port_usb = 0;
  280. port->send_cpkt_response = 0;
  281. spin_unlock_irqrestore(&port->port_lock, flags);
  282. queue_work(port->wq, &port->disconnect_w);
  283. }
  284. static int ghsuart_ctrl_probe(struct platform_device *pdev)
  285. {
  286. struct ghsuart_ctrl_port *port;
  287. unsigned long flags;
  288. pr_debug("%s: name:%s\n", __func__, pdev->name);
  289. port = ghsuart_ctrl_ports[pdev->id].port;
  290. set_bit(CH_READY, &port->channel_sts);
  291. /* if usb is online, start read */
  292. spin_lock_irqsave(&port->port_lock, flags);
  293. if (port->port_usb)
  294. queue_work(port->wq, &port->connect_w);
  295. spin_unlock_irqrestore(&port->port_lock, flags);
  296. return 0;
  297. }
  298. static int ghsuart_ctrl_remove(struct platform_device *pdev)
  299. {
  300. struct ghsuart_ctrl_port *port;
  301. struct grmnet *gr = NULL;
  302. unsigned long flags;
  303. pr_debug("%s: name:%s\n", __func__, pdev->name);
  304. port = ghsuart_ctrl_ports[pdev->id].port;
  305. spin_lock_irqsave(&port->port_lock, flags);
  306. if (!port->port_usb) {
  307. spin_unlock_irqrestore(&port->port_lock, flags);
  308. goto not_ready;
  309. }
  310. gr = port->port_usb;
  311. spin_unlock_irqrestore(&port->port_lock, flags);
  312. if (gr && gr->disconnect)
  313. gr->disconnect(gr);
  314. clear_bit(CH_OPENED, &port->channel_sts);
  315. clear_bit(CH_CONNECTED, &port->channel_sts);
  316. not_ready:
  317. clear_bit(CH_READY, &port->channel_sts);
  318. return 0;
  319. }
  320. static void ghsuart_ctrl_port_free(int portno)
  321. {
  322. struct ghsuart_ctrl_port *port = ghsuart_ctrl_ports[portno].port;
  323. struct platform_driver *pdrv = &ghsuart_ctrl_ports[portno].pdrv;
  324. destroy_workqueue(port->wq);
  325. if (pdrv)
  326. platform_driver_unregister(pdrv);
  327. kfree(port);
  328. }
  329. static int ghsuart_ctrl_port_alloc(int portno, enum gadget_type gtype)
  330. {
  331. struct ghsuart_ctrl_port *port;
  332. struct platform_driver *pdrv;
  333. int err;
  334. port = kzalloc(sizeof(struct ghsuart_ctrl_port), GFP_KERNEL);
  335. if (!port)
  336. return -ENOMEM;
  337. port->wq = create_singlethread_workqueue(ghsuart_ctrl_names[portno]);
  338. if (!port->wq) {
  339. pr_err("%s: Unable to create workqueue:%s\n",
  340. __func__, ghsuart_ctrl_names[portno]);
  341. kfree(port);
  342. return -ENOMEM;
  343. }
  344. port->port_num = portno;
  345. port->gtype = gtype;
  346. spin_lock_init(&port->port_lock);
  347. init_completion(&port->close_complete);
  348. INIT_WORK(&port->connect_w, ghsuart_ctrl_connect_w);
  349. INIT_WORK(&port->disconnect_w, ghsuart_ctrl_disconnect_w);
  350. port->ch_id = SMUX_USB_RMNET_CTL_0;
  351. port->ctxt = port;
  352. port->send_pkt = ghsuart_ctrl_receive;
  353. ghsuart_ctrl_ports[portno].port = port;
  354. pdrv = &ghsuart_ctrl_ports[portno].pdrv;
  355. pdrv->probe = ghsuart_ctrl_probe;
  356. pdrv->remove = ghsuart_ctrl_remove;
  357. pdrv->driver.name = ghsuart_ctrl_names[portno];
  358. pdrv->driver.owner = THIS_MODULE;
  359. err = platform_driver_register(pdrv);
  360. if (unlikely(err < 0))
  361. return err;
  362. pr_debug("%s: port:%pK portno:%d\n", __func__, port, portno);
  363. return 0;
  364. }
  365. int ghsuart_ctrl_setup(unsigned int num_ports, enum gadget_type gtype)
  366. {
  367. int first_port_id = num_ctrl_ports;
  368. int total_num_ports = num_ports + num_ctrl_ports;
  369. int i;
  370. int ret = 0;
  371. if (!num_ports || total_num_ports > NUM_HSUART_PORTS) {
  372. pr_err("%s: Invalid num of ports count:%d\n",
  373. __func__, num_ports);
  374. return -EINVAL;
  375. }
  376. pr_debug("%s: requested ports:%d\n", __func__, num_ports);
  377. for (i = first_port_id; i < (first_port_id + num_ports); i++) {
  378. num_ctrl_ports++;
  379. ret = ghsuart_ctrl_port_alloc(i, gtype);
  380. if (ret) {
  381. num_ctrl_ports--;
  382. pr_err("%s: Unable to alloc port:%d\n", __func__, i);
  383. goto free_ports;
  384. }
  385. }
  386. return first_port_id;
  387. free_ports:
  388. for (i = first_port_id; i < num_ctrl_ports; i++)
  389. ghsuart_ctrl_port_free(i);
  390. num_ctrl_ports = first_port_id;
  391. return ret;
  392. }
  393. #if defined(CONFIG_DEBUG_FS)
  394. #define DEBUG_BUF_SIZE 1024
  395. static ssize_t ghsuart_ctrl_read_stats(struct file *file, char __user *ubuf,
  396. size_t count, loff_t *ppos)
  397. {
  398. struct ghsuart_ctrl_port *port;
  399. char *buf;
  400. unsigned long flags;
  401. int ret;
  402. int i;
  403. int temp = 0;
  404. buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
  405. if (!buf)
  406. return -ENOMEM;
  407. for (i = 0; i < num_ctrl_ports; i++) {
  408. port = ghsuart_ctrl_ports[i].port;
  409. if (!port)
  410. continue;
  411. spin_lock_irqsave(&port->port_lock, flags);
  412. temp += scnprintf(buf + temp, DEBUG_BUF_SIZE - temp,
  413. "#PORT:%d port: %pK\n"
  414. "to_usbhost: %lu\n"
  415. "to_modem: %lu\n"
  416. "cpkt_drp_cnt: %lu\n"
  417. "DTR: %s\n",
  418. i, port,
  419. port->to_host, port->to_modem,
  420. port->drp_cpkt_cnt,
  421. port->cbits_tomodem ? "HIGH" : "LOW");
  422. spin_unlock_irqrestore(&port->port_lock, flags);
  423. }
  424. ret = simple_read_from_buffer(ubuf, count, ppos, buf, temp);
  425. kfree(buf);
  426. return ret;
  427. }
  428. static ssize_t ghsuart_ctrl_reset_stats(struct file *file,
  429. const char __user *buf, size_t count, loff_t *ppos)
  430. {
  431. struct ghsuart_ctrl_port *port;
  432. int i;
  433. unsigned long flags;
  434. for (i = 0; i < num_ctrl_ports; i++) {
  435. port = ghsuart_ctrl_ports[i].port;
  436. if (!port)
  437. continue;
  438. spin_lock_irqsave(&port->port_lock, flags);
  439. port->to_host = 0;
  440. port->to_modem = 0;
  441. port->drp_cpkt_cnt = 0;
  442. spin_unlock_irqrestore(&port->port_lock, flags);
  443. }
  444. return count;
  445. }
  446. static const struct file_operations ghsuart_ctrl_stats_ops = {
  447. .read = ghsuart_ctrl_read_stats,
  448. .write = ghsuart_ctrl_reset_stats,
  449. };
  450. static struct dentry *ghsuart_ctrl_dent;
  451. static int ghsuart_ctrl_debugfs_init(void)
  452. {
  453. struct dentry *ghsuart_ctrl_dfile;
  454. ghsuart_ctrl_dent = debugfs_create_dir("ghsuart_ctrl_xport", 0);
  455. if (!ghsuart_ctrl_dent || IS_ERR(ghsuart_ctrl_dent))
  456. return -ENODEV;
  457. ghsuart_ctrl_dfile =
  458. debugfs_create_file("status", S_IRUGO | S_IWUSR,
  459. ghsuart_ctrl_dent, 0, &ghsuart_ctrl_stats_ops);
  460. if (!ghsuart_ctrl_dfile || IS_ERR(ghsuart_ctrl_dfile)) {
  461. debugfs_remove(ghsuart_ctrl_dent);
  462. ghsuart_ctrl_dent = NULL;
  463. return -ENODEV;
  464. }
  465. return 0;
  466. }
  467. static void ghsuart_ctrl_debugfs_exit(void)
  468. {
  469. debugfs_remove_recursive(ghsuart_ctrl_dent);
  470. }
  471. #else
  472. static int ghsuart_ctrl_debugfs_init(void) { return 0; }
  473. static void ghsuart_ctrl_debugfs_exit(void) {}
  474. #endif
  475. static int __init ghsuart_ctrl_init(void)
  476. {
  477. int ret;
  478. ret = ghsuart_ctrl_debugfs_init();
  479. if (ret) {
  480. pr_debug("mode debugfs file is not available\n");
  481. return ret;
  482. }
  483. return 0;
  484. }
  485. module_init(ghsuart_ctrl_init);
  486. static void __exit ghsuart_ctrl_exit(void)
  487. {
  488. ghsuart_ctrl_debugfs_exit();
  489. }
  490. module_exit(ghsuart_ctrl_exit);
  491. MODULE_DESCRIPTION("HSUART control xport for RmNet");
  492. MODULE_LICENSE("GPL v2");