aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Zhu <r65037@freescale.com>2014-06-26 03:56:24 -0400
committerRichard Zhu <r65037@freescale.com>2014-06-30 21:33:35 -0400
commit58ad81506e01e6a9625bc096595113f1f6bbe521 (patch)
treef53548e416f4ff241bf96ea0d811fca39c77cdc6
parent3c16fd041fa430bd4b601964b944daa2bc474c20 (diff)
ENGR00320327 mcc: mcc posix pty interface demo driver
- /dev/ttyMCCp0 can be created. - use schedule delayed work to kick off the demo - one simple test app(mxc_mcc_tty_test.out) used to do the mcc pty interface demo tests. - m4 part of the mcc pingpong demo is required to be run on m4. - up to now, only the unsigned int decimal number is used in the tests. test how-to by the simple test app: ./mxc_mcc_tty_test.out /dev/ttyMCCp0 115200 R 1 512 & echo <your input> > /dev/ttyMCCp0 then <your input + 1> would be received the test app. Signed-off-by: Richard Zhu <r65037@freescale.com>
-rw-r--r--drivers/char/imx_mcc/Kconfig8
-rw-r--r--drivers/char/imx_mcc/Makefile1
-rw-r--r--drivers/char/imx_mcc/imx_mcc_tty.c253
3 files changed, 262 insertions, 0 deletions
diff --git a/drivers/char/imx_mcc/Kconfig b/drivers/char/imx_mcc/Kconfig
index d60cf66cd8fd..9625efa2df7f 100644
--- a/drivers/char/imx_mcc/Kconfig
+++ b/drivers/char/imx_mcc/Kconfig
@@ -13,3 +13,11 @@ config IMX_MCC_DEMO
13 depends on SOC_IMX6SX && IMX_SEMA4 13 depends on SOC_IMX6SX && IMX_SEMA4
14 help 14 help
15 Support for IMX MCC DEMO, most people should say N here. 15 Support for IMX MCC DEMO, most people should say N here.
16
17config IMX_MCC_TTY
18 bool "imx pty for mcc interface"
19 depends on SOC_IMX6SX && IMX_SEMA4
20 help
21 This enables a pty node for imx6sx mcc interface.
22
23#end imx mcc
diff --git a/drivers/char/imx_mcc/Makefile b/drivers/char/imx_mcc/Makefile
index a0d60f341d07..f5bda928e23c 100644
--- a/drivers/char/imx_mcc/Makefile
+++ b/drivers/char/imx_mcc/Makefile
@@ -4,3 +4,4 @@
4# 4#
5obj-$(CONFIG_IMX_SEMA4) += imx_sema4.o 5obj-$(CONFIG_IMX_SEMA4) += imx_sema4.o
6obj-$(CONFIG_IMX_MCC_DEMO) += imx_mcc_demo.o 6obj-$(CONFIG_IMX_MCC_DEMO) += imx_mcc_demo.o
7obj-$(CONFIG_IMX_MCC_TTY) += imx_mcc_tty.o
diff --git a/drivers/char/imx_mcc/imx_mcc_tty.c b/drivers/char/imx_mcc/imx_mcc_tty.c
new file mode 100644
index 000000000000..843b5fcbd010
--- /dev/null
+++ b/drivers/char/imx_mcc/imx_mcc_tty.c
@@ -0,0 +1,253 @@
1/*
2 * imx_mcc_tty.c - pty demo driver used to test imx mcc
3 * posix pty interface.
4 *
5 * Copyright (C) 2014 Freescale Semiconductor, Inc.
6 */
7
8/*
9 * The code contained herein is licensed under the GNU General Public
10 * License. You may obtain a copy of the GNU General Public License
11 * Version 2 or later at the following locations:
12 *
13 * http://www.opensource.org/licenses/gpl-license.html
14 * http://www.gnu.org/copyleft/gpl.html
15 */
16
17#include <linux/delay.h>
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/slab.h>
21#include <linux/tty.h>
22#include <linux/tty_driver.h>
23#include <linux/tty_flip.h>
24#include <linux/mcc_common.h>
25#include <linux/mcc_api.h>
26
27/**
28 * struct mcctty_port - Wrapper struct for imx mcc pty port.
29 * @port: TTY port data
30 * @rx_lock: Lock for rx_buf.
31 * @rx_buf: Read buffer
32 */
33struct mcctty_port {
34 struct delayed_work read;
35 struct tty_port port;
36 spinlock_t rx_lock;
37 char *rx_buf;
38};
39
40static struct mcctty_port mcc_tty_port;
41
42enum {
43 MCC_NODE_A9 = 0,
44 MCC_NODE_M4 = 0,
45
46 MCC_A9_PORT = 1,
47 MCC_M4_PORT = 2,
48};
49
50/* mcc tty/pingpong demo */
51static MCC_ENDPOINT mcc_endpoint_a9_pingpong = {0, MCC_NODE_A9, MCC_A9_PORT};
52static MCC_ENDPOINT mcc_endpoint_m4_pingpong = {1, MCC_NODE_M4, MCC_M4_PORT};
53struct mcc_pp_msg {
54 unsigned int data;
55};
56
57static void mcctty_delay_work(struct work_struct *work)
58{
59 struct mcctty_port *cport = &mcc_tty_port;
60 int ret, space;
61 unsigned char *cbuf;
62 struct mcc_pp_msg pp_msg;
63 MCC_MEM_SIZE num_of_received_bytes;
64 MCC_INFO_STRUCT mcc_info;
65
66 /* start mcc tty recv here */
67 ret = mcc_initialize(MCC_NODE_A9);
68 if (ret)
69 pr_err("failed to initialize mcc.\n");
70
71 ret = mcc_get_info(MCC_NODE_A9, &mcc_info);
72 if (ret)
73 pr_err("failed to get mcc info.\n");
74 pr_info("\nA9 mcc prepares run, MCC version is %s\n",
75 mcc_info.version_string);
76
77 pr_info("imx mcc tty/pingpong demo begin.\n");
78 ret = mcc_create_endpoint(&mcc_endpoint_a9_pingpong,
79 MCC_A9_PORT);
80 if (ret)
81 pr_err("failed to create a9 mcc ep.\n");
82
83 while (1) {
84 ret = mcc_recv_copy(&mcc_endpoint_a9_pingpong, &pp_msg,
85 sizeof(struct mcc_pp_msg),
86 &num_of_received_bytes, 0xffffffff);
87
88 if (MCC_SUCCESS != ret) {
89 pr_err("A9 Main task receive error: %d\n", ret);
90 } else {
91 /* flush the recv-ed data to tty node */
92 spin_lock_bh(&cport->rx_lock);
93 space = tty_prepare_flip_string(&cport->port, &cbuf,
94 num_of_received_bytes);
95 if ((space <= 0) || (cport->rx_buf == NULL))
96 goto pp_unlock;
97
98 memcpy(cport->rx_buf, &pp_msg.data,
99 num_of_received_bytes);
100 memcpy(cbuf, cport->rx_buf, space);
101 tty_flip_buffer_push(&cport->port);
102pp_unlock:
103 spin_unlock_bh(&cport->rx_lock);
104 }
105 }
106}
107
108static struct tty_port_operations mcctty_port_ops = { };
109
110static int mcctty_install(struct tty_driver *driver, struct tty_struct *tty)
111{
112 return tty_port_install(&mcc_tty_port.port, driver, tty);
113}
114
115static int mcctty_open(struct tty_struct *tty, struct file *filp)
116{
117 return tty_port_open(tty->port, tty, filp);
118}
119
120static void mcctty_close(struct tty_struct *tty, struct file *filp)
121{
122 return tty_port_close(tty->port, tty, filp);
123}
124
125static int mcctty_write(struct tty_struct *tty, const unsigned char *buf,
126 int total)
127{
128 int i, ret = 0;
129 struct mcc_pp_msg pp_msg;
130
131 if (NULL == buf)
132 return 0;
133
134 for (i = 0; i < total; i++) {
135 pp_msg.data = (unsigned int)buf[i];
136
137 /*
138 * wait until the remote endpoint is created by
139 * the other core
140 */
141 ret = mcc_send(&mcc_endpoint_m4_pingpong, &pp_msg,
142 sizeof(struct mcc_pp_msg),
143 0xffffffff);
144
145 while (MCC_ERR_ENDPOINT == ret) {
146 pr_err("\n send err ret %d, re-send\n", ret);
147 ret = mcc_send(&mcc_endpoint_m4_pingpong, &pp_msg,
148 sizeof(struct mcc_pp_msg),
149 0xffffffff);
150 msleep(5000);
151 }
152 }
153
154 return total;
155}
156
157static int mcctty_write_room(struct tty_struct *tty)
158{
159 int room;
160
161 /* report the space in the mcc buffer */
162 room = MCC_ATTR_BUFFER_SIZE_IN_BYTES;
163
164 return room;
165}
166
167static const struct tty_operations imxmcctty_ops = {
168 .install = mcctty_install,
169 .open = mcctty_open,
170 .close = mcctty_close,
171 .write = mcctty_write,
172 .write_room = mcctty_write_room,
173};
174
175static struct tty_driver *mcctty_driver;
176
177static int __init imxmcctty_init(void)
178{
179 int ret;
180 struct mcctty_port *cport = &mcc_tty_port;
181
182 mcctty_driver = tty_alloc_driver(1,
183 TTY_DRIVER_RESET_TERMIOS |
184 TTY_DRIVER_UNNUMBERED_NODE);
185 if (IS_ERR(mcctty_driver))
186 return PTR_ERR(mcctty_driver);
187
188 mcctty_driver->driver_name = "mcc_tty";
189 mcctty_driver->name = "ttyMCC";
190 mcctty_driver->major = TTYAUX_MAJOR;
191 mcctty_driver->minor_start = 3;
192 mcctty_driver->type = TTY_DRIVER_TYPE_PTY;
193 mcctty_driver->init_termios = tty_std_termios;
194 mcctty_driver->init_termios.c_cflag |= CLOCAL;
195
196 tty_set_operations(mcctty_driver, &imxmcctty_ops);
197
198 tty_port_init(&cport->port);
199 cport->port.ops = &mcctty_port_ops;
200 spin_lock_init(&cport->rx_lock);
201 spin_lock_init(&cport->tx_lock);
202
203 ret = tty_register_driver(mcctty_driver);
204 if (ret < 0) {
205 pr_err("Couldn't install mcc tty driver: err %d\n", ret);
206 goto error;
207 } else
208 pr_info("Install mcc tty driver!\n");
209
210 /* Allocate the buffer we use for reading data */
211 cport->rx_buf = kzalloc(MCC_ATTR_BUFFER_SIZE_IN_BYTES,
212 GFP_KERNEL);
213 if (!cport->rx_buf) {
214 ret = -ENOMEM;
215 goto error;
216 }
217
218 INIT_DELAYED_WORK(&cport->read, mcctty_delay_work);
219 schedule_delayed_work(&cport->read, HZ/100);
220 return 0;
221
222error:
223 tty_unregister_driver(mcctty_driver);
224 put_tty_driver(mcctty_driver);
225 tty_port_destroy(&cport->port);
226 mcctty_driver = NULL;
227
228 return ret;
229}
230
231static void imxmcctty_exit(void)
232{
233 int ret = 0;
234 struct mcctty_port *cport = &mcc_tty_port;
235
236 /* stop reading, null the read buffer. */
237 kfree(cport->rx_buf);
238 cport->rx_buf = NULL;
239
240 /* destory the mcc tty endpoint here */
241 ret = mcc_destroy_endpoint(&mcc_endpoint_a9_pingpong);
242 if (ret)
243 pr_err("failed to destory a9 mcc ep.\n");
244 else
245 pr_info("destory a9 mcc ep.\n");
246
247 tty_unregister_driver(mcctty_driver);
248 tty_port_destroy(&cport->port);
249 put_tty_driver(mcctty_driver);
250}
251
252module_init(imxmcctty_init);
253module_exit(imxmcctty_exit);